diff --git a/j3d-core/COPYRIGHT.txt b/j3d-core/COPYRIGHT.txt new file mode 100644 index 0000000..dd7d0ec --- /dev/null +++ b/j3d-core/COPYRIGHT.txt @@ -0,0 +1,77 @@ +Copyright 1996-2008 Sun Microsystems, Inc., 4150 Network Circle, Santa +Clara, California 95054, U.S.A. All rights reserved. + +Sun Microsystems, Inc. has intellectual property rights relating to +technology embodied in the product that is described in this +document. In particular, and without limitation, these intellectual +property rights may include one or more of the U.S. patents listed at +http://www.sun.com/patents and one or more additional patents or +pending patent applications in the U.S. and in other countries. + +U.S. Government Rights - Commercial software. Government users are +subject to the Sun Microsystems, Inc. standard license agreement and +applicable provisions of the FAR and its supplements. + +Use is subject to license terms. + +This distribution may include materials developed by third parties. + +Parts of the product may be derived from Berkeley BSD systems, +licensed from the University of California. UNIX is a registered +trademark in the U.S. and in other countries, exclusively licensed +through X/Open Company, Ltd. + +Sun, Sun Microsystems, the Sun logo, Java, Solaris, Java 3D, the 100% +Pure Java logo, the Duke logo and the Java Coffee Cup logo are +trademarks or registered trademarks of Sun Microsystems, Inc. in the +U.S. and other countries. + +This product is covered and controlled by U.S. Export Control laws and +may be subject to the export or import laws in other countries. +Nuclear, missile, chemical biological weapons or nuclear maritime end +uses or end users, whether direct or indirect, are strictly +prohibited. Export or reexport to countries subject to U.S. embargo or +to entities identified on U.S. export exclusion lists, including, but +not limited to, the denied persons and specially designated nationals +lists is strictly prohibited. + +Copyright 1996-2008 Sun Microsystems, Inc., 4150 Network Circle, Santa +Clara, California 95054, Etats-Unis. Tous droits réservés. + +Sun Microsystems, Inc. détient les droits de propriété intellectuels +relatifs à la technologie incorporée dans le produit qui est décrit +dans ce document. En particulier, et ce sans limitation, ces droits de +propriété intellectuelle peuvent inclure un ou plus des brevets +américains listés à l'adresse http://www.sun.com/patents et un ou les +brevets supplémentaires ou les applications de brevet en attente aux +Etats - Unis et dans les autres pays. + +L'utilisation est soumise aux termes de la Licence. + +Cette distribution peut comprendre des composants développés par des +tierces parties. + +Des parties de ce produit pourront être dérivées des systèmes Berkeley +BSD licenciés par l'Université de Californie. UNIX est une marque +déposée aux Etats-Unis et dans d'autres pays et licenciée +exclusivement par X/Open Company, Ltd. + +Sun, Sun Microsystems, le logo Sun, Java, Solaris, Java 3D, le logo +100% Pure Java, le logo Duke et le logo Java Coffee Cup sont des +marques de fabrique ou des marques déposées de Sun Microsystems, +Inc. aux Etats-Unis et dans d'autres pays. + +Ce produit est soumis à la législation américaine en matière de +contrôle des exportations et peut être soumis à la règlementation en +vigueur dans d'autres pays dans le domaine des exportations et +importations. Les utilisations, ou utilisateurs finaux, pour des armes +nucléaires,des missiles, des armes biologiques et chimiques ou du +nucléaire maritime, directement ou indirectement, sont strictement +interdites. Les exportations ou réexportations vers les pays sous +embargo américain, ou vers des entités figurant sur les listes +d'exclusion d'exportation américaines, y compris, mais de manière non +exhaustive, la liste de personnes qui font objet d'un ordre de ne pas +participer, d'une façon directe ou indirecte, aux exportations des +produits ou des services qui sont régis par la législation américaine +en matière de contrôle des exportations et la liste de ressortissants +spécifiquement désignés, sont rigoureusement interdites. diff --git a/j3d-core/LICENSE-SPEC.html b/j3d-core/LICENSE-SPEC.html new file mode 100644 index 0000000..e355f7a --- /dev/null +++ b/j3d-core/LICENSE-SPEC.html @@ -0,0 +1,22 @@ + + + + + 3D Graphics API for the Java Platform + + +

Copyright 1996-2008 Sun Microsystems, Inc. All rights reserved. +Use is subject to license terms. +

+

This javadoc-generated API documentation is not an +official API specification. This documentation may contain references to +Java and Java 3D, both of which are trademarks of Sun Microsystems, Inc. +Any reference to these and other trademarks of Sun Microsystems are +for explanatory purposes only. Their use does impart any rights beyond +those listed in the source code license. In particular, Sun Microsystems +retains all intellectual property and trademark rights as described in +the proprietary rights notice in the COPYRIGHT.txt file. +

+ + diff --git a/j3d-core/LICENSE.txt b/j3d-core/LICENSE.txt new file mode 100644 index 0000000..eeab58c --- /dev/null +++ b/j3d-core/LICENSE.txt @@ -0,0 +1,347 @@ +The GNU General Public License (GPL) + +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. + +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. + + One line to give the program's name and a brief idea of what it does. + + 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. + + signature of Ty Coon, 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. + + +"CLASSPATH" EXCEPTION TO THE GPL + +Certain source files distributed by Sun Microsystems, Inc. are subject to +the following clarification and special exception to the GPL, but only where +Sun has expressly included in the particular source file's header the words +"Sun designates this particular file as subject to the "Classpath" exception +as provided by Sun in the LICENSE file that accompanied this code." + + Linking this library statically or dynamically with other modules is making + a combined work based on this library. Thus, the terms and conditions of + the GNU General Public License cover the whole combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules, + and to copy and distribute the resulting executable under terms of your + choice, provided that you also meet, for each linked independent module, + the terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. If + you modify this library, you may extend this exception to your version of + the library, but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. diff --git a/j3d-core/README-FIRST.txt b/j3d-core/README-FIRST.txt new file mode 100644 index 0000000..dd87e0d --- /dev/null +++ b/j3d-core/README-FIRST.txt @@ -0,0 +1,24 @@ +The source code for the j3d-core project is copyrighted code that is +licensed to individuals or companies who download or otherwise access +the code. + +The copyright notice for this project is in COPYRIGHT.txt + +The source code license information for this project is in LICENSE.txt + +Additional information and license restrictions for third party source +code are found in the THIRDPARTY-LICENSE-*.txt files. + +Instructions for building this project are in README-build.html + +Note that the source code in this directory is untested and presumed +incompatible with the Java 3D(TM) API specification. You must only use +this code in accordance with the terms under which the code is +licensed. No additional rights are granted to you. + +If you prefer to use a tested and certified compatible version of the +code, then you can download a binary release for the Solaris, Linux, +Windows, and Mac OS X operating environments at: + https://java3d.dev.java.net/binary-builds.html +or at: + http://java.sun.com/products/java-media/3D/ diff --git a/j3d-core/README-build.html b/j3d-core/README-build.html new file mode 100644 index 0000000..5884850 --- /dev/null +++ b/j3d-core/README-build.html @@ -0,0 +1,160 @@ + + + + + README-build: build instructions for the j3d-core project + + +

Building +the 3D packages

+

+

To +build the 3D packages, you must checkout the following three +CVS +repositories:
+

+ +

These three top-level directories must be named exactly as +shown above and they must be sibling directories. To ensure this, run +the cvs checkout command for each of the respositories from the same +parent +directory. For example:
+

+ +

NOTE: you must first build the javax.vecmath package before building +the javax.media.j3d and com.sun.j3d.* packages. See the README-build.html file in the +"vecmath" directory for instructions.
+

+

System Requirements

+

+

The +following operating environments have been tested:
+

+ +

The following software must be installed:
+

+ +

Building the 3D packages

+

Before +you start building, your PATH must include the +following directories: +

+ +

The default target, jar-opt, creates an optimized jar files +and native libraries. +

+

On Amd64 platform an OutOfMemoryError can be seen. In this case set +the environment variable ANT_OPTS to -Xmx256m.
+

+

Steps: +

+ +

The above steps build both the Java and native code for +javax.media.j3d and com.sun.j3d.* +packages. +

+

The build will be placed in j3d-core/build/<platform>/opt +where <platform> is determined from the ant +echo command: +

+ +To see other targets that are available, type "ant +-projecthelp". Note that ant must be run from the top-level +directory. +

The default compiler for native code compilation is set to "gcc". +This +value is set in the build.properties +file located +in the j3d-core directory. The compiler property is "build.comp".
+

+

On a Solaris platform with Forte compiler installed, +build.comp +can be set to "forte". On a Windows platform installed Visual C++, +build.properties +can be set to "vc".
+

+

NOTE: For Windows platform only, the property "build.rend" in +build.properties can be modified to use "d3d" (Direct3D API for +rendering) besides the default value "ogl".
+

+

NOTE: You can also modify the properties via command-line options to +ant, +for example, "ant -Dbuild.comp=vc"
+

+

Running +the 3D examples

+

Please refer to README-build.html in +j3d-examples for +details +on building and running the 3D example programs.
+

+ + diff --git a/j3d-core/THIRDPARTY-LICENSE-GLEXT.txt b/j3d-core/THIRDPARTY-LICENSE-GLEXT.txt new file mode 100644 index 0000000..3727809 --- /dev/null +++ b/j3d-core/THIRDPARTY-LICENSE-GLEXT.txt @@ -0,0 +1,27 @@ +The following additional provisions apply to third party software +included as part of this product. + + native/ogl/ + glext.h - glext header file on http://www.opengl.org + wglext.h - wglext header file on http://www.opengl.org + +Copyright (c) 2007 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. diff --git a/j3d-core/THIRDPARTY-LICENSE-PANORAMIX.txt b/j3d-core/THIRDPARTY-LICENSE-PANORAMIX.txt new file mode 100644 index 0000000..ae3d797 --- /dev/null +++ b/j3d-core/THIRDPARTY-LICENSE-PANORAMIX.txt @@ -0,0 +1,31 @@ +The following additional provisions apply to third party software +included as part of this product. + + native/ogl/ + panoramiXext.h - X11 header file + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, +Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software. + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY +CLAIM, DAMAGES, INCLUDING, BUT NOT LIMITED TO CONSEQUENTIAL OR +INCIDENTAL DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment +Corporation shall not be used in advertising or otherwise to promote +the sale, use or other dealings in this Software without prior written +authorization from Digital Equipment Corporation. diff --git a/j3d-core/build-tools/VersionInfo.java b/j3d-core/build-tools/VersionInfo.java new file mode 100644 index 0000000..0628915 --- /dev/null +++ b/j3d-core/build-tools/VersionInfo.java @@ -0,0 +1,323 @@ +/* + * $RCSfile: VersionInfo.java,v $ + * + * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:15 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The VersionInfo class contains strings that describe the implementation + * and specification version of the javax.media.j3d pacakge. These strings + * are made available as properties obtained from the VirtualUniverse class. + * + *

NOTE TO DEVELOPERS:

+ * + *

+ * Developers are strongly encouraged to do the following whenever they + * modify the 3D graphics API for the Java platform: + * + *

    + *
  1. The VENDOR_DEVELOPER string should be modified to + * indicate the name of the individuals or organizations who have + * modified the source code.
  2. + * + *
  3. The VERSION_DEV_STRING may be modified to indicate + * additional information about the particular build, but this is + * not required.
  4. + * + *
  5. The strings denoted as being unmodifiable should not be + * modified.
  6. + *
+ * + *

+ * The tags of the form @STRING@ are populated by ant when the project is built + * + * @see VirtualUniverse#getProperties + */ +class VersionInfo extends Object { + /** + * Developer who has modified the 3D graphics API for the Java platform. + * This string should be modified to indicate the name of the + * individual(s) or organization(s) who modified the code. + */ + private static final String VENDOR_DEVELOPER = null; + + + /** + * An optional string appended to the end of the version string, + * after the time stamp. A space will be automatically prepended + * to this string. This string should be null if no dev string is + * desired. + */ + private static final String VERSION_DEV_STRING = null; + + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + // END OF DEVELOPER-MODIFIABLE PARAMETERS + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + + + // ------------------------------------------------------------------- + // The following set of constants should not be modified by developers. + // ------------------------------------------------------------------- + + /** + * Constant that indicates whether or not this is a debug build. + */ + static final boolean isDebug = @IS_DEBUG@; + + /** + * This static final variable is used to enable debugging and + * assertion checking during the development phase of a particular + * version of 3D graphics API for the Java platform. It is disabled + * for "opt" production builds (beta, release candidate, fcs, and + * patch builds). It is enabled for all "debug" builds and for daily + * and stable "opt" builds. + * + *

+ * This parameter is controlled by ant via the build.xml file. The + * default value is true. + */ + static final boolean isDevPhase = @IS_DEV_PHASE@; + + /** + * This static final variable is used indicate a production + * (beta, release candidate, fcs, or patch) build. + *

+ * This parameter is controlled by ant via the build.xml file. The + * default value is false. + */ + static final boolean isProduction = @IS_PRODUCTION@; + + /** + * If this flag is set to true, the verbose buildtime string + * will be appended to the version string) + *

+ * This parameter is controlled by ant via the build.xml file. The + * default value is true. + */ + private static final boolean useVerboseBuildTime = @USE_VERBOSE_BUILDTIME@; + + /** + * String identifying the type of build, one of: + * "daily", "stable", "beta", "fcs", or "patch". The default value + * is "daily". + */ + private static final String BUILD_TYPE = "@BUILD_TYPE@"; + + /** + * String identifying the build number in the format + * "buildNN", where "NN" is the sequential build number, for + * example, build47. This string contain only letters and + * numbers, It must not contain any other characters or spaces. + * + * For production builds, this string appears parenthetically, + * after the first space. + */ + private static final String VERSION_BUILD = "@VERSION_BUILD@"; + + /** + * String identifying the particular build of the 3D API, for + * example, "-beta1", "-build47", "-rc1", "_01", etc. Note that + * this includes the leading dash or underscore. It will typically + * be empty for FCS builds. This string may only contain letters, + * numbers, periods, dashes, or underscores. It must not contain + * any other characters or spaces. + * + * This us used as part of the j3d.version that appears before the + * optional first space. + */ + private static final String VERSION_SUFFIX = "@VERSION_SUFFIX@"; + + /** + * Date stamp + * + * This is only used for daily builds. + */ + private static final String BUILDTIME = "@BUILDTIME@"; + + /** + * Specification version (major and minor version only). This + * string must not be modified by developers. + */ + private static final String SPECIFICATION_VERSION = "1.5"; + + /** + * Specification vendor. + */ + private static final String SPECIFICATION_VENDOR = "@SPEC_VENDOR@"; + + /** + * Primary implementation vendor. + */ + private static final String VENDOR_PRIMARY = "@IMPL_VENDOR@"; + + /** + * Base version number. This is the major.minor.subminor version + * number. Version qualifiers are specified separately. The + * major and minor version must be the same as the specification + * version. + */ + private static final String VERSION_BASE = "@VERSION_BASE@"; + + /** + * Boolean flag indicating that the version of the 3D API is + * experimental. This must not be modified by developers. + * All non-official builds must contain the string + * "experimental" as part of the release name that + * appears before the optional first space. + */ + private static final boolean isExperimental = !isProduction; + + /** + * The composite version string. This is composed in the static + * initializer for this class. + */ + private static final String VERSION; + + /** + * The composite vendor string. This is composed in the static + * initializer for this class. + */ + private static final String VENDOR; + + /** + * Verbose time and date stamp appended to the end of the version string. + * This is appended to the version string + * after the build identifier (and after the first space, which + * will automatically be added) and before the optional dev + * string. This string is only used for non-fcs builds. + */ + private static final String BUILDTIME_VERBOSE = "@BUILDTIME_VERBOSE@"; + + private static boolean isNonEmpty(String str) { + if ((str == null) || (str.length() == 0)) { + return false; + } + else { + return true; + } + } + + // The static initializer composes the version and vendor strings + static { + final boolean isPatchBuild = BUILD_TYPE.equals("patch"); + final boolean isFcsBuild = BUILD_TYPE.equals("fcs"); + final boolean isBetaBuild = BUILD_TYPE.equals("beta"); + final boolean isStableBuild = BUILD_TYPE.equals("stable"); + final boolean isDailyBuild = BUILD_TYPE.equals("daily"); + + // Assign the vendor by concatenating primary and developer + // vendor strings + String tmpVendor = VENDOR_PRIMARY; + if (isNonEmpty(VENDOR_DEVELOPER)) { + tmpVendor += " & " + VENDOR_DEVELOPER; + } + + String tmpVersion = VERSION_BASE; + if (isNonEmpty(VERSION_SUFFIX)) { + if (isPatchBuild) { + tmpVersion += "_"; + } + else { + tmpVersion += "-"; + } + tmpVersion += VERSION_SUFFIX; + } + + if (isDailyBuild && isNonEmpty(BUILDTIME)) { + tmpVersion += "-" + BUILDTIME; + } + + if (isExperimental) { + tmpVersion += "-experimental"; + } + + // Append the optional fields that follow the first space + + if (isProduction) { + if (isFcsBuild) { + tmpVersion += " fcs"; + } + else if (isPatchBuild) { + tmpVersion += " fcs+patch"; + } + + if (isNonEmpty(VERSION_BUILD)) { + tmpVersion += " (" + VERSION_BUILD + ")"; + } + } + + if (useVerboseBuildTime && isNonEmpty(BUILDTIME_VERBOSE)) { + tmpVersion += " " + BUILDTIME_VERBOSE; + } + + if (isNonEmpty(VERSION_DEV_STRING)) { + tmpVersion += " " + VERSION_DEV_STRING; + } + + VERSION = tmpVersion; + VENDOR = tmpVendor; + } + + /** + * Returns the specification version string. + * @return the specification version string + */ + static String getSpecificationVersion() { + return SPECIFICATION_VERSION; + } + + /** + * Returns the specification vendor string. + * @return the specification vendor string + */ + static String getSpecificationVendor() { + return SPECIFICATION_VENDOR; + } + + + /** + * Returns the implementation version string. + * @return the implementation version string + */ + static String getVersion() { + return VERSION; + } + + /** + * Returns the implementation vendor string. + * @return the implementation vendor string + */ + static String getVendor() { + return VENDOR; + } + +} diff --git a/j3d-core/build-tools/genzip b/j3d-core/build-tools/genzip new file mode 100644 index 0000000..85b0832 --- /dev/null +++ b/j3d-core/build-tools/genzip @@ -0,0 +1,54 @@ +#!/bin/sh + +# usage: genzip [ ... ] + +tmpscr1=script1.$$ +tmpscr2=script2.$$ + +archive=$1 +shift +license=$1 +shift + +echo "zip'ing..." + +zip -r $archive.zip $* + +cat ../unzipsfx $archive.zip > $archive + +echo "Checksumming..." + +sum=`/usr/bin/sum $archive` +index=1 +for s in $sum +do + case $index in + 1) sum1=$s; + index=2; + ;; + 2) sum2=$s; + index=3; + ;; + esac +done +echo sum = $sum1 $sum2 + +cat ../script1.txt $license ../script2.txt > $tmpscr1 + +linecount=`/usr/bin/wc -l < $tmpscr1` +linecount=$(($linecount + 1)) +echo linecount = $linecount + +echo "Generating .bin script..." + +sed -e s/@LINECOUNT@/$linecount/ -e s/@SUM1@/$sum1/ -e s/@SUM2@/$sum2/ < $tmpscr1 > $tmpscr2 +cat $tmpscr2 $archive > ../$archive.bin +chmod +x ../$archive.bin + +echo "Cleaning up..." +rm -f $tmpscr1 +rm -f $tmpscr2 +rm -f $archive.zip +rm -f $archive + +echo "Done" diff --git a/j3d-core/build-tools/linux-amd64/script1.txt b/j3d-core/build-tools/linux-amd64/script1.txt new file mode 100644 index 0000000..05d4088 --- /dev/null +++ b/j3d-core/build-tools/linux-amd64/script1.txt @@ -0,0 +1,4 @@ +#!/bin/sh +PATH=/usr/bin:/bin +more <<"EOF" + diff --git a/j3d-core/build-tools/linux-amd64/script2.txt b/j3d-core/build-tools/linux-amd64/script2.txt new file mode 100644 index 0000000..ea5fb16 --- /dev/null +++ b/j3d-core/build-tools/linux-amd64/script2.txt @@ -0,0 +1,56 @@ + +EOF +agreed= +while [ x$agreed = x ]; do + echo + echo "Do you agree to the above license terms? [yes or no] " + read reply leftover + case $reply in + y* | Y*) + agreed=1;; + n* | n*) + echo "If you don't agree to the license you can't install this sofware"; + exit 1;; + esac +done +if [ ! -w `pwd` ] ; then + echo "You do not have write permission to `pwd`" + echo "3D installation failed" + exit 1 +fi +outname=install.sfx.$$ +echo "Unpacking..." +tail -n +@LINECOUNT@ $0 > $outname +if [ -x /usr/bin/sum ] ; then + echo "Checksumming..." + + sum=`/usr/bin/sum $outname` + index=1 + for s in $sum + do + case $index in + 1) sum1=$s; + index=2; + ;; + 2) sum2=$s; + index=3; + ;; + esac + done + if expr $sum1 != @SUM1@ || expr $sum2 != @SUM2@ ; then + echo "The download file appears to be corrupted. Please refer" + echo "to the Troubleshooting section of the Installation" + echo "Instructions on the download page for more information." + echo "Please do not attempt to install this archive file." + rm -f $outname + exit 1 + fi +else + echo "Can't find /usr/bin/sum to do checksum. Continuing anyway." +fi +echo "Extracting..." +chmod u+x $outname +./$outname +rm -f $outname +echo "Done." +exit 0 diff --git a/j3d-core/build-tools/linux-i586/script1.txt b/j3d-core/build-tools/linux-i586/script1.txt new file mode 100644 index 0000000..05d4088 --- /dev/null +++ b/j3d-core/build-tools/linux-i586/script1.txt @@ -0,0 +1,4 @@ +#!/bin/sh +PATH=/usr/bin:/bin +more <<"EOF" + diff --git a/j3d-core/build-tools/linux-i586/script2.txt b/j3d-core/build-tools/linux-i586/script2.txt new file mode 100644 index 0000000..ea5fb16 --- /dev/null +++ b/j3d-core/build-tools/linux-i586/script2.txt @@ -0,0 +1,56 @@ + +EOF +agreed= +while [ x$agreed = x ]; do + echo + echo "Do you agree to the above license terms? [yes or no] " + read reply leftover + case $reply in + y* | Y*) + agreed=1;; + n* | n*) + echo "If you don't agree to the license you can't install this sofware"; + exit 1;; + esac +done +if [ ! -w `pwd` ] ; then + echo "You do not have write permission to `pwd`" + echo "3D installation failed" + exit 1 +fi +outname=install.sfx.$$ +echo "Unpacking..." +tail -n +@LINECOUNT@ $0 > $outname +if [ -x /usr/bin/sum ] ; then + echo "Checksumming..." + + sum=`/usr/bin/sum $outname` + index=1 + for s in $sum + do + case $index in + 1) sum1=$s; + index=2; + ;; + 2) sum2=$s; + index=3; + ;; + esac + done + if expr $sum1 != @SUM1@ || expr $sum2 != @SUM2@ ; then + echo "The download file appears to be corrupted. Please refer" + echo "to the Troubleshooting section of the Installation" + echo "Instructions on the download page for more information." + echo "Please do not attempt to install this archive file." + rm -f $outname + exit 1 + fi +else + echo "Can't find /usr/bin/sum to do checksum. Continuing anyway." +fi +echo "Extracting..." +chmod u+x $outname +./$outname +rm -f $outname +echo "Done." +exit 0 diff --git a/j3d-core/build-tools/solaris-sparc/script1.txt b/j3d-core/build-tools/solaris-sparc/script1.txt new file mode 100644 index 0000000..05d4088 --- /dev/null +++ b/j3d-core/build-tools/solaris-sparc/script1.txt @@ -0,0 +1,4 @@ +#!/bin/sh +PATH=/usr/bin:/bin +more <<"EOF" + diff --git a/j3d-core/build-tools/solaris-sparc/script2.txt b/j3d-core/build-tools/solaris-sparc/script2.txt new file mode 100644 index 0000000..a9aafa8 --- /dev/null +++ b/j3d-core/build-tools/solaris-sparc/script2.txt @@ -0,0 +1,56 @@ + +EOF +agreed= +while [ x$agreed = x ]; do + echo + echo "Do you agree to the above license terms? [yes or no] " + read reply leftover + case $reply in + y* | Y*) + agreed=1;; + n* | n*) + echo "If you don't agree to the license you can't install this sofware"; + exit 1;; + esac +done +if [ ! -w `pwd` ] ; then + echo "You do not have write permission to `pwd`" + echo "3D installation failed" + exit 1 +fi +outname=install.sfx.$$ +echo "Unpacking..." +tail +@LINECOUNT@ $0 > $outname +if [ -x /usr/bin/sum ] ; then + echo "Checksumming..." + + sum=`/usr/bin/sum $outname` + index=1 + for s in $sum + do + case $index in + 1) sum1=$s; + index=2; + ;; + 2) sum2=$s; + index=3; + ;; + esac + done + if expr $sum1 != @SUM1@ || expr $sum2 != @SUM2@ ; then + echo "The download file appears to be corrupted. Please refer" + echo "to the Troubleshooting section of the Installation" + echo "Instructions on the download page for more information." + echo "Please do not attempt to install this archive file." + rm -f $outname + exit 1 + fi +else + echo "Can't find /usr/bin/sum to do checksum. Continuing anyway." +fi +echo "Extracting..." +chmod u+x $outname +./$outname +rm -f $outname +echo "Done." +exit 0 diff --git a/j3d-core/build-tools/solaris-x86/script1.txt b/j3d-core/build-tools/solaris-x86/script1.txt new file mode 100644 index 0000000..05d4088 --- /dev/null +++ b/j3d-core/build-tools/solaris-x86/script1.txt @@ -0,0 +1,4 @@ +#!/bin/sh +PATH=/usr/bin:/bin +more <<"EOF" + diff --git a/j3d-core/build-tools/solaris-x86/script2.txt b/j3d-core/build-tools/solaris-x86/script2.txt new file mode 100644 index 0000000..a9aafa8 --- /dev/null +++ b/j3d-core/build-tools/solaris-x86/script2.txt @@ -0,0 +1,56 @@ + +EOF +agreed= +while [ x$agreed = x ]; do + echo + echo "Do you agree to the above license terms? [yes or no] " + read reply leftover + case $reply in + y* | Y*) + agreed=1;; + n* | n*) + echo "If you don't agree to the license you can't install this sofware"; + exit 1;; + esac +done +if [ ! -w `pwd` ] ; then + echo "You do not have write permission to `pwd`" + echo "3D installation failed" + exit 1 +fi +outname=install.sfx.$$ +echo "Unpacking..." +tail +@LINECOUNT@ $0 > $outname +if [ -x /usr/bin/sum ] ; then + echo "Checksumming..." + + sum=`/usr/bin/sum $outname` + index=1 + for s in $sum + do + case $index in + 1) sum1=$s; + index=2; + ;; + 2) sum2=$s; + index=3; + ;; + esac + done + if expr $sum1 != @SUM1@ || expr $sum2 != @SUM2@ ; then + echo "The download file appears to be corrupted. Please refer" + echo "to the Troubleshooting section of the Installation" + echo "Instructions on the download page for more information." + echo "Please do not attempt to install this archive file." + rm -f $outname + exit 1 + fi +else + echo "Can't find /usr/bin/sum to do checksum. Continuing anyway." +fi +echo "Extracting..." +chmod u+x $outname +./$outname +rm -f $outname +echo "Done." +exit 0 diff --git a/j3d-core/build.xml b/j3d-core/build.xml new file mode 100644 index 0000000..d429a21 --- /dev/null +++ b/j3d-core/build.xml @@ -0,0 +1,908 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The following ant targets are available ("jar-opt" is the default): + + all - execute targets jar-debug and dist. + + clean - removes build/ and dist/ for current platform + + clean-all - removes build/ and dist/ for all platforms + + clean-dist - removes dist. + + clean-javaonly - removes java portion of build for current platform + + compile - execute targets compile-debug and compile-opt. + + compile-debug - builds all classes and native layer in src into + class files under build/${platform}/debug/classes/ and + native files under build/${platform}/debug/native/ + + compile-opt - builds all classes and native layer in src into + class files under build/${platform}/opt/classes/ and + native files under build/${platform}/opt/native/ + + dist - THIS TARGET IS FOR RELEASE ENGINEERING ONLY; DEVELOPERS NEED NOT + USE THIS TARGET. + Copies the shared jars, and the platform-specific native + libraries, src files, and javadoc to dist/${platform}. + The dist-common target must be run first. + + dist-common - THIS TARGET IS FOR RELEASE ENGINEERING ONLY; DEVELOPERS NEED NOT + USE THIS TARGET. + This target must be run on a 32-bit Linux-x86 system. + Creates the shared jar from the linux-i586 and + windows-i586-vc build directories. + The jar-opt target must be run first. + + docs - builds all classes in src into javadoc under + build/javadocs. + + docs-jcp - builds JCP docs of all classes in src into javadoc + under build/javadocs/docs-jcp. + + docs-private - builds private docs of all classes in src into javadoc + under build/javadocs/docs-private. + + docs-public - builds public docs of all classes in src into javadoc + under build/javadocs/docs-public. + + echo - echo some useful information, such as user.home, + ant.home, java.home and platform. + + jar - execute targets jar-debug and jar-opt. + + jar-debug - creates build/${platform}/debug/lib for all jar + files and libraries from class and native code files under + build/${platform}/debug/classes and + build/${platform}/debug/native. + + jar-debug-javaonly + - compiles only the java portion of j3d and builds + jars in same locations as jar-debug + + jar-opt - creates build/${platform}/opt/lib for all jar + files and libraries from class and native code files under + build/${platform}/opt/classes and + build/${platform}/opt/native. + + jar-opt-javaonly + - compiles only the java portion of j3d and builds + jars in same location as jar-opt + + install-debug - installs the debug build into the JDK pointed to by JAVA_HOME + + src - generate a zip file j3d project source code. + + uninstall - uninstalls j3d from the JDK pointed to by JAVA_HOME + + diff --git a/j3d-core/docs/ChangeLog-1_4.html b/j3d-core/docs/ChangeLog-1_4.html new file mode 100644 index 0000000..abf0615 --- /dev/null +++ b/j3d-core/docs/ChangeLog-1_4.html @@ -0,0 +1,555 @@ + + + + + Java 3D 1.4 Change Log + + +

Java 3D API version 1.4 Change Log

+

Here are the proposed changes for Java 3D version 1.4. These +proposed changes are a results of discussion and collaboration with the +Java 3D community on java.net (see +https://java3d.dev.java.net). +They are already part of daily and periodic stable builds available on +java.net.

+

I. Proposed Changes

+


+

+

II. Accepted Changes

+

Here is the list of accepted changes for the Java 3D 1.4 API:
+

+
    +
  1. Programmable shader support
  2. +
  3. Default values for read capability bits
  4. +
  5. Picking
  6. +
  7. Stencil
  8. +
  9. Rendering attributes
  10. +
  11. Other minor features
  12. +
  13. Deprecated API
    +
  14. +
+

For a complete description of these changes, please see the +proposed API specification (javadoc) for the 1.4 version of the +Java 3D API. +

+

1. Programmable shader +support
+

+

We propose to add programmable shader support to Java 3D 1.4. +This is +the primary new feature of this release.
+

+

The following new classes and interfaces are added in +the javax.media.j3d package:
+

+ +

The following new classes are added in the +javax.vecmath package:
+

+ +

The following new fields, constructors, and methods are added to +existing classes:
+

+ +

The following new constructors are added to +existing GeometryArray subclasses:

+ +


+

+

2. Default values for read capability +bits
+

+

Capability bits control whether data in a Java 3D scene graph +object +may be read or written when it is part of a live or compiled subgraph. +We propose to change the default value for all read capability bits to +true, meaning that all attributes may be read by default (the default +value for all write capability bits will remain false, meaning that no +attributes may be written by default). Note that read capability bits +are defined as those capability bits of the form ALLOW_*_READ, +plus the ALLOW_INTERSECT capability bit.
+

+ +


+

+

3. Picking
+

+

We propose to add a new PickInfo class (with an inner class to hold +intersection information), and new core picking methods that return +objects of this new class type.
+

+

New Classes:
+

+ +

New methods:
+

+ +


+

+

4. Stencil
+

+

We propose new stencil functionality. Here are the proposed new +fields and methods:
+

+ +


+

+

5. Rendering attributes
+

+

We propose to add new rendering attributes/modes to enable +applications to specify the depth test function, additional raster +operations, and additional blending modes. The new fields and methods +are as follows:
+

+ +


+

+

6. Other minor features
+

+

We propose to add the following new features: a name for all scene +graph objects; the ability to get the Locale or parent from a live or +compiled scene graph, a scene graph structure change listener, and a +method to get the tessellated glyph geometry for a character in a 3D +font. +

+

The following new class has been added:

+ +

The new fields and methods are as follows:

+ +


+

+

7. Deprecated API
+

+

We propose to deprecate the following classes:

+ +

We propose to deprecate the following fields and methods:

+ +


+

+

III. Deferred Changes

+


+

+ + diff --git a/j3d-core/docs/ChangeLog-1_5.html b/j3d-core/docs/ChangeLog-1_5.html new file mode 100644 index 0000000..a69ab59 --- /dev/null +++ b/j3d-core/docs/ChangeLog-1_5.html @@ -0,0 +1,244 @@ + + + + + Java 3D 1.5 Change Log + + +

Java 3D API version 1.5 Change Log

+

Here are the proposed changes for Java 3D version 1.5. These +proposed changes are a results of discussion and collaboration with the +Java 3D community on java.net (see +https://java3d.dev.java.net). +They are already part of daily and periodic stable builds available on +java.net.

+

I. Proposed Changes
+

+

Here is the list of proposed changes for the Java 3D 1.5 API:
+

+
    +
  1. Non-power-of-two textures
  2. +
  3. NIO image buffer support for textures
  4. +
  5. By-reference support for geometry +indices
  6. +
  7. Rendering error listeners
    +
  8. +
  9. Vecmath accessors/mutators
  10. +
  11. Deprecated API
  12. +
+

For a complete description of these changes, please see the +proposed API specification (javadoc) for the 1.5 version of the +Java 3D API. +

+

1. Non-power-of-two textures

+

We propose to add non-power-of-two textures to Java 3D 1.5. +Currently, the width, height, and depth of all textures must be an +exact power of two. Most graphics cards now support non-power-of-two +textures, so we propose to allow this in Java 3D. Since not all +graphics drivers support this feature, we will add a new +"textureNonPowerOfTwoAvailable" property to +Canvas3D.queryProperties that will indicate whether or not +non-power-of-two textures are supported. If this +property is set to true, then non-power-of-two textures +are rendered normally. If this property is set to false, +then the graphics driver or card does not support non-power-of-two +textures; texture mapping will be disabled if non-power-of-two +textures are rendered on a Canvas3D that doesn't support them.
+

+


+

+

2. NIO image buffer support for +textures

+

We propose to create a new javax.media.j3d.NioImageBuffer class, a +wrapper for an image whose DataBuffer +is specified via an appropriate subclass of java.nio.Buffer: +ByteBuffer or IntBuffer, +depending on the type of image. When using IntBuffer, +the byte order of the buffer must match the native byte order of the +underlying platform. +

+

New public classes:
+

+ +

New constructors and methods:
+

+ +


+

+

3. By-reference support for geometry +indices
+

+

We propose to add support for setting the coordinate indices +of IndexedGeometryArray objects "by-reference". Currently, the +coordinate indices array is +set "by-copy" even for by-reference geometry, resulting in excessive +memory usage. Though the +excess memory usage is temporary, since it happens only at the time +of creating an internal copy of the user-specified indices array, +nevertheless it can turn out to be of significant concern especially +for very large geometries or for dynamically changing geometry. The +fact that the +graphics drivers have long supported this feature makes the +incorporation of this feature attractive, as +it entails no special hardware support.
+

+

New fields and methods:
+

+ +


+

+

4. Rendering error listener

+

We propose to add a rendering error class and error listener +interface that applications can use to detect rendering errors that are +caught by the Java 3D rendering system. The default error listener, if +no user-specified error listeners are added, prints out the error +message and exits.
+

+

The following new classes and interfaces are proposed:

+ +

The following new methods are proposed:

+ +


+

+

5. Vecmath +accessors/mutators

+

We propose to add accessors and mutators to all vecmath classes with +publicly accessible fields. This follows the bean pattern, and allows +these classes to be read and written by bean-aware tools, for example, +the XMLEncoder. The following +classes need public accessors and mutators (e.g., setX(), getX(), +setY(), and so forth):
+

+ +


+

+

6. Deprecated API

+

We propose to deprecate the following fields and methods relating to +the obsolete texture functionality. +

+ +


+

+

+

+

II. Accepted Changes

+


+

+

III. Deferred Changes

+


+

+ + diff --git a/j3d-core/docs/api-changes-1_4.txt b/j3d-core/docs/api-changes-1_4.txt new file mode 100644 index 0000000..d28aad5 --- /dev/null +++ b/j3d-core/docs/api-changes-1_4.txt @@ -0,0 +1,533 @@ +------------------------------------------------------------------------ +$RCSfile: api-changes-1_4.txt,v $ +$Revision: 1.2 $ +$Date: 2005/10/17 22:54:39 $ +------------------------------------------------------------------------ +This document conatains proposed API changes to the Java 3D 1.4 API +that deviate from the 1.3 API. + +This file must be updated to record the addition or deprecation of any +public or protected class, interface, field, constructor, or method to +the Java 3D API. + +The one exception to this rule is that you don't need to update this +file when adding a non-final (i.e., virtual) method to a class if that +method--with exactly the same signature--already exists in a +superclass. For example, adding a "toString" method to a j3d object +doesn't require an entry in this file. Likewise, adding duplicateNode +or cloneNode methods to Node subclasses doesn't require an entry in +this file. + +No incompatible changes to the Java 3D 1.3 API are allowed. + + +I. New/deprecated fields, constructors, methods + + Canvas3D + -------- + New methods: + public boolean isShadingLanguageSupported(int shadingLanguage) + + + SceneGraphObject + ---------------- + New methods: + public void setName(String name) + public String getName() + + + GeometryArray + ------------- + New fields: + public static final int ALLOW_VERTEX_ATTR_READ + public static final int ALLOW_VERTEX_ATTR_WRITE + public static final int VERTEX_ATTRIBUTES + + New constructors: + public GeometryArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) + + New methods: + public int getVertexAttrCount() + public void getVertexAttrSizes(int[] vertexAttrSizes) + public void setVertexAttr(int vertexAttrNum, int index, + float[] vertexAttr) + public void setVertexAttr(int vertexAttrNum, int index, + Point2f vertexAttr) + public void setVertexAttr(int vertexAttrNum, int index, + Point3f vertexAttr) + public void setVertexAttr(int vertexAttrNum, int index, + Point4f vertexAttr) + public void setVertexAttrs(int vertexAttrNum, int index, + float[] vertexAttrs) + public void setVertexAttrs(int vertexAttrNum, int index, + Point2f[] vertexAttrs) + public void setVertexAttrs(int vertexAttrNum, int index, + Point3f[] vertexAttrs) + public void setVertexAttrs(int vertexAttrNum, int index, + Point4f[] vertexAttrs) + public void setVertexAttrs(int vertexAttrNum, int index, + float[] vertexAttrs, + int start, int length) + public void setVertexAttrs(int vertexAttrNum, int index, + Point2f[] vertexAttrs, + int start, int length) + public void setVertexAttrs(int vertexAttrNum, int index, + Point3f[] vertexAttrs, + int start, int length) + public void setVertexAttrs(int vertexAttrNum, int index, + Point4f[] vertexAttrs, + int start, int length) + public void getVertexAttr(int vertexAttrNum, int index, + float[] vertexAttr) + public void getVertexAttr(int vertexAttrNum, int index, + Point2f vertexAttr) + public void getVertexAttr(int vertexAttrNum, int index, + Point3f vertexAttr) + public void getVertexAttr(int vertexAttrNum, int index, + Point4f vertexAttr) + public void getVertexAttrs(int vertexAttrNum, int index, + float[] vertexAttrs) + public void getVertexAttrs(int vertexAttrNum, int index, + Point2f[] vertexAttrs) + public void getVertexAttrs(int vertexAttrNum, int index, + Point3f[] vertexAttrs) + public void getVertexAttrs(int vertexAttrNum, int index, + Point4f[] vertexAttrs) + public void setInitialVertexAttrIndex(int vertexAttrNum, + int initialVertexAttrIndex) + public int getInitialVertexAttrIndex(int vertexAttrNum) + public void setVertexAttrRefBuffer(int vertexAttrNum, J3DBuffer vertexAttrs) + public J3DBuffer getVertexAttrRefBuffer(int vertexAttrNum) + public void setVertexAttrRefFloat(int vertexAttrNum, float[] vertexAttrs) + public float[] getVertexAttrRefFloat(int vertexAttrNum) + + + PointArray + ---------- + New constructors: + public PointArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) + + + LineArray + --------- + New constructors: + public LineArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) + + + TriangleArray + ------------- + New constructors: + public TriangleArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) + + + QuadArray + --------- + New constructors: + public QuadArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) + + + GeometryStripArray + ------------------ + New constructors: + public GeometryStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int[] stripVertexCounts) + + + LineStripArray + -------------- + New constructors: + public LineStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int[] stripVertexCounts) + + + TriangleStripArray + ------------------ + New constructors: + public TriangleStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int[] stripVertexCounts) + + + TriangleFanArray + ---------------- + New constructors: + public TriangleFanArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int[] stripVertexCounts) + + + IndexedGeometryArray + -------------------- + New constructors: + public IndexedGeometryArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) + + New fields: + public static final int ALLOW_VERTEX_ATTR_INDEX_READ + public static final int ALLOW_VERTEX_ATTR_INDEX_WRITE + + New methods: + public void setInitialVertexAttrIndex(int vertexAttrNum, + int initialVertexAttrIndex) + public void setVertexAttrIndex(int vertexAttrNum, + int index, + int vertexAttrIndex) + public void setVertexAttrIndices(int vertexAttrNum, + int index, + int[] vertexAttrIndices) + public int getVertexAttrIndex(int vertexAttrNum, int index) + public void getVertexAttrIndices(int vertexAttrNum, + int index, + int[] vertexAttrIndices) + + + IndexedPointArray + ---------------- + New constructors: + public IndexedPointArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) + + + IndexedLineArray + ---------------- + New constructors: + public IndexedLineArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) + + + IndexedTriangleArray + ---------------- + New constructors: + public IndexedTriangleArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) + + + IndexedQuadArray + ---------------- + New constructors: + public IndexedQuadArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) + + + IndexedGeometryStripArray + ------------------------- + New constructors: + public IndexedGeometryStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount + int[] stripIndexCounts) + + + IndexedLineStripArray + ------------------------- + New constructors: + public IndexedLineStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount + int[] stripIndexCounts) + + + IndexedTriangleStripArray + ------------------------- + New constructors: + public IndexedTriangleStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount + int[] stripIndexCounts) + + + IndexedTriangleFanArray + ------------------------- + New constructors: + public IndexedTriangleFanArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount + int[] stripIndexCounts) + + + Node + ---- + New fields: + public static final int ALLOW_PARENT_READ + public static final int ALLOW_LOCALE_READ + + New methods: + public Locale getLocale() + + + VirtualUniverse + --------------- + New methods: + public void addGraphStructureChangeListener(GraphStructureChangeListener listener) + public void removeGraphStructureChangeListener(GraphStructureChangeListener listener) + public void addShaderErrorListener(ShaderErrorListener listener) + public void removeShaderErrorListener(ShaderErrorListener listener) + + + Locale + ------ + New methods: + public PickInfo[] pickAll( int mode, int flags, PickShape pickShape ) + public PickInfo[] pickAllSorted( int mode, int flags, PickShape pickShape ) + public PickInfo pickClosest( int mode, int flags, PickShape pickShape ) + public PickInfo pickAny( int mode, int flags, PickShape pickShape ) + + + BranchGroup + ----------- + New methods: + public PickInfo[] pickAll( int mode, int flags, PickShape pickShape ) + public PickInfo[] pickAllSorted( int mode, int flags, PickShape pickShape ) + public PickInfo pickClosest( int mode, int flags, PickShape pickShape ) + public PickInfo pickAny( int mode, int flags, PickShape pickShape ) + + + Sensor + ------ + Deprecated fields: + public static final int PREDICT_NONE + public static final int PREDICT_NEXT_FRAME_TIME + public static final int NO_PREDICTOR + public static final int HEAD_PREDICTOR + public static final int HAND_PREDICTOR + + Deprecated methods: + public void setPredictor(int predictor) + public int getPredictor() + public void setPredictionPolicy(int policy) + public int getPredictionPolicy() + public void getRead(Transform3D read, long deltaT) + + + RenderingAttributes + ------------------- + New fields: + public static final int ALLOW_DEPTH_TEST_FUNCTION_READ + public static final int ALLOW_DEPTH_TEST_FUNCTION_WRITE + public static final int ALLOW_STENCIL_ATTRIBUTES_READ + public static final int ALLOW_STENCIL_ATTRIBUTES_WRITE + public static final int ROP_CLEAR + public static final int ROP_AND + public static final int ROP_AND_REVERSE + public static final int ROP_AND_INVERTED + public static final int ROP_NOOP + public static final int ROP_OR + public static final int ROP_NOR + public static final int ROP_EQUIV + public static final int ROP_INVERT + public static final int ROP_OR_REVERSE + public static final int ROP_COPY_INVERTED + public static final int ROP_OR_INVERTED + public static final int ROP_NAND + public static final int ROP_SET + public static final int STENCIL_KEEP + public static final int STENCIL_ZERO + public static final int STENCIL_REPLACE + public static final int STENCIL_INCR + public static final int STENCIL_DECR + public static final int STENCIL_INVERT + + + New methods: + public void setDepthTestFunction(int function) + public int getDepthTestFunction() + public void setStencilEnable(boolean enable) + public boolean getStencilEnable() + public void setStencilOp(int failOp, int zFailOp, int zPassOp) + public void setStencilOp(int[] stencilOps) + public void getStencilOp(int[] stencilOps) + public void setStencilFunction(int function, int refValue, int compareMask) + public void setStencilFunction(int[] params) + public void getStencilFunction(int[] params) + public void setStencilWriteMask(int mask) + public int getStencilWriteMask() + + + Font3D + ------ + New methods: + public GeometryArray getGlyphGeometry(char c) + + + GraphicsConfigTemplate3D + ------------------------ + New methods: + public void setStencilSize(int value) + public int getStencilSize() + + + TransparencyAttributes + ---------------------- + New fields: + public static final int BLEND_DST_COLOR + public static final int BLEND_ONE_MINUS_DST_COLOR + public static final int BLEND_SRC_COLOR + public static final int BLEND_ONE_MINUS_SRC_COLOR + + +II. Reparented classes + + NONE + + +III. New classes and interfaces (in javax.media.j3d) + + ShaderAppearance + ---------------- + public class ShaderAppearance extends Appearance + + ShaderAttributeSet + ------------------ + public class ShaderAttributeSet extends NodeComponent + + ShaderAttribute + --------------- + public abstract class ShaderAttribute extends NodeComponent + + ShaderAttributeBinding + ---------------------- + public class ShaderAttributeBinding extends ShaderAttribute + + ShaderAttributeObject + --------------------- + public abstract class ShaderAttributeObject extends ShaderAttribute + + ShaderAttributeValue + -------------------- + public class ShaderAttributeValue extends ShaderAttributeObject + + ShaderAttributeArray + -------------------- + public class ShaderAttributeArray extends ShaderAttributeObject + + Shader + ------ + public abstract class Shader extends NodeComponent + + SourceCodeShader + ---------------- + public class SourceCodeShader extends Shader + + ShaderProgram + ------------- + public abstract class ShaderProgram extends NodeComponent + + CgShaderProgram + --------------- + public class CgShaderProgram extends ShaderProgram + + GLSLShaderProgram + ----------------- + public class GLSLShaderProgram extends ShaderProgram + + ShaderError + ----------- + public class ShaderError extends Object + + ShaderErrorListener + ------------------- + public interface ShaderErrorListener + + GraphStructureChangeListener + ---------------------------- + public interface GraphStructureChangeListener + + PickInfo + -------- + public class PickInfo extends Object + + PickInfo.IntersectionInfo + ------------------------- + public class PickInfo.IntersectionInfo extends Object + + +IV. Deprecated classes and interfaces (in javax.media.j3d) + + CompressedGeometry + CompressedGeometryHeader + PickPoint + Morph diff --git a/j3d-core/docs/api-changes-1_5.txt b/j3d-core/docs/api-changes-1_5.txt new file mode 100644 index 0000000..3c90e23 --- /dev/null +++ b/j3d-core/docs/api-changes-1_5.txt @@ -0,0 +1,133 @@ +------------------------------------------------------------------------ +$RCSfile: api-changes-1_5.txt,v $ +$Revision: 1.2 $ +$Date: 2006/09/29 18:03:34 $ +------------------------------------------------------------------------ +This document conatains proposed API changes to the Java 3D 1.5 API +that deviate from the 1.4 API. + +This file must be updated to record the addition or deprecation of any +public or protected class, interface, field, constructor, or method to +the Java 3D API. + +The one exception to this rule is that you don't need to update this +file when adding a non-final (i.e., virtual) method to a class if that +method--with exactly the same signature--already exists in a +superclass. For example, adding a "toString" method to a j3d object +doesn't require an entry in this file. Likewise, adding duplicateNode +or cloneNode methods to Node subclasses doesn't require an entry in +this file. + +No incompatible changes to the Java 3D 1.4 API are allowed. + + +I. New/deprecated fields, constructors, methods + + ImageComponent + -------------- + New enums: + public enum ImageClass { + BUFFERED_IMAGE, RENDERED_IMAGE, NIO_IMAGE_BUFFER + } + + + New methods: + public ImageClass getImageClass() + + + Deprecated methods: + public void setYUp(boolean yUp) + + + ImageComponent2D + ---------------- + New constructors: + public ImageComponent2D(int format, NioImageBuffer image, + boolean byReference, boolean yUp) + + New methods: + public void set(NioImageBuffer image) + public NioImageBuffer getNioImage() + + + ImageComponent3D + ---------------- + New constructors: + public ImageComponent3D(int format, NioImageBuffer[] images, + boolean byReference, boolean yUp) + + New methods: + public void set(NioImageBuffer[] images) + public void set(int index, NioImageBuffer image) + public NioImageBuffer[] getNioImage() + public NioImageBuffer getNioImage(int index) + + + Texture2D + --------- + Deprecated fields: + public static final int ALLOW_DETAIL_TEXTURE_READ + public static final int LINEAR_DETAIL + public static final int LINEAR_DETAIL_RGB + public static final int LINEAR_DETAIL_ALPHA + public static final int DETAIL_ADD + public static final int DETAIL_MODULATE + + Deprecated methods: + public void setDetailImage(ImageComponent2D detailTexture) + public ImageComponent2D getDetailImage() + public void setDetailTextureMode(int mode) + public int getDetailTextureMode() + public void setDetailTextureLevel(int level) + public int getDetailTextureLevel() + public void setDetailTextureFunc(float[] lod, float[] pts) + public void setDetailTextureFunc(Point2f[] pts) + public int getDetailTextureFuncPointsCount() + public void getDetailTextureFunc(float[] lod, float[] pts) + public void getDetailTextureFunc(Point2f[] pts) + + + GeometryArray + ------------- + New fields: + public static final int BY_REFERENCE_INDICES + + + IndexedGeometryArray + -------------------- + New methods: + public void setCoordIndicesRef(int coordIndices[]) + public int[] getCoordIndicesRef() + + + VirtualUniverse + --------------- + New methods: + public static void addRenderingErrorListener( + RenderingErrorListener listener) + public static void removeRenderingErrorListener( + RenderingErrorListener listener) + + +II. Reparented classes + + +III. New classes and interfaces (in javax.media.j3d) + + NioImageBuffer + -------------- + public class NioImageBuffer extends Object + + + RenderingError + -------------- + public class RenderingError extends Object + + + RenderingErrorListener + ---------------------- + public interface RenderingErrorListener + + +IV. Deprecated classes and interfaces (in javax.media.j3d) + diff --git a/j3d-core/docs/perf_guide.txt b/j3d-core/docs/perf_guide.txt new file mode 100644 index 0000000..fa07779 --- /dev/null +++ b/j3d-core/docs/perf_guide.txt @@ -0,0 +1,397 @@ + Performance Guide for Java 3D 1.3 + +I - Introduction + + The Java 3D API was designed with high performance 3D graphics +as a primary goal. This document presents the performance features of +Java 3D in a number of ways. It describes the specific APIs that were +included for performance. It describes which optimizations are currently +implemented in Java 3D 1.3. And, it describes a number of tips and tricks +that application writers can use to improve the performance of their +application. + + +II - Performance in the API + + There are a number of things in the API that were included specifically +to increase performance. This section examines a few of them. + + - Capability bits + Capability bits are the applications way of describing its intentions + to the Java 3D implementation. The implementation examines the + capability bits to determine which objects may change at run time. + Many optimizations are possible with this feature. + + - isFrequent bits + Setting the isFrequent bit indicates that the application may frequently + access or modify those attributes permitted by the associated capability bit. + This can be used by Java 3D as a hint to avoid certain optimizations that + could cause those accesses or modifications to be expensive. By default the + isFrequent bit associated with each capability bit is set. + + - Compile + The are two compile methods in Java 3D. They are in the + BranchGroup and SharedGroup classes. Once an application calls + compile(), only those attributes of objects that have their + capability bits set may be modified. The implementation may then + use this information to "compile" the data into a more efficient + rendering format. + + - Bounds + Many Java 3D object require a bounds associated with them. These + objects include Lights, Behaviors, Fogs, Clips, Backgrounds, + BoundingLeafs, Sounds, Soundscapes, ModelClips, and AlternateAppearance. + The purpose of these bounds is to limit the spatial scope of the + specific object. The implementation may quickly disregard the + processing of any objects that are out of the spatial scope of a + target object. + + - Unordered Rendering + All state required to render a specific object in Java 3D is + completely defined by the direct path from the root node to the + given leaf. That means that leaf nodes have no effect on other + leaf nodes, and therefore may be rendered in any order. There + are a few ordering requirements for direct descendents of + OrderedGroup nodes or Transparent objects. But, most leaf nodes + may be reordered to facilitate more efficient rendering. + + - OrderedGroup + OrderedGroup now supports an indirection table to allow the user to + specify the order that the children should be rendered. This will + speed up order update processing, eliminating the expensive + attach and detach cycle. + + - Appearance Bundles + A Shape3D node has a reference to a Geometry and an Appearance. + An Appearance NodeComponent is simply a collection of other + NodeComponent references that describe the rendering characteristics + of the geometry. Because the Appearance is nothing but a + collection of references, it is much simpler and more efficient for + the implementation to check for rendering characteristic changes when + rendering. This allows the implementation to minimize state changes + in the low level rendering API. + + - NIO buffer support for Geometry by-reference + NOTE: Use of this feature requires version 1.4 of the JavaTM 2 Platform. + + This provides a big win in both memory and performance for applications + that use native C code to generate their geometric data. In many cases, + they will no longer need to maintain two copies of their data (one in + Java and one in C). The performance win comes mainly from not having to + copy the data from their C data structures to the Java array using JNI. + Also, since the array isn't part of the pool of memory managed by the + garbage collector, it should speed up garbage collection. + + +III - Current Optimizations in Java 3D 1.3 + + This section describes a number of optimizations that are currently +implemented in Java 3D 1.3. The purpose of this section is to help +application programmers focus their optimizations on things that will +compliment the current optimizations in Java 3D. + + - Hardware + Java 3D uses OpenGL or Direct3D as its low level rendering + APIs. It relies on the underlying OpenGL or Direct3D drivers + for its low level rendering acceleration. Using a graphics + display adapter that offers OpenGL or Direct3D acceleration is + the best way to increase overall rendering performance in Java 3D. + + - Compile + The following compile optimizations are implemented in the Java 3D + 1.2.1 and 1.3 release: + + . Scene graph flattening: TransformGroup nodes that are + neither readable nor writable are collapsed into a + single transform node. + + . Combining Shape3D nodes: Non-writable Shape3D nodes + that have the same appearance attributes, not pickable, + not collidable, and are under the same TransformGroup + (after flattening) are combined, internally, into a single + Shape3D node that can be rendered with less overhead. + + - State Sorted Rendering + Since Java 3D allows for unordered rendering for most leaf + nodes, the implementation sorts all objects to be rendered on + a number of rendering characteristics. The characteristics + that are sorted on are, in order, Lights, Texture, Geometry + Type, Material, and finally localToVworld transform. The only + 2 exceptions are to (a) any child of an OrderedGroup node, and + (b) any transparent object with View's Transparency sorting policy + set to TRANSPARENCY_SORT_GEOMETRY. There is no state sorting for + those objects. + + - View Frustum Culling + The Java 3D implementation implements view frustum culling. + The view frustum cull is done when an object is processed for + a specific Canvas3D. This cuts down on the number of objects + needed to be processed by the low level graphics API. + + - Multithreading + The Java 3D API was designed with multithreaded environments + in mind. The current implementation is a fully multithreaded + system. At any point in time, there may be parallel threads + running performing various tasks such as visibility detection, + rendering, behavior scheduling, sound scheduling, input + processing, collision detection, and others. Java 3D is + careful to limit the number of threads that can run in + parallel based on the number of CPUs available. + + - Space versus time property + By default, Java3d only builds display list for by-copy geometry. If + an application wishes to have display list build for by-ref geometry + to improve performance at the expense of memory, it can instruct Java3d + by disable the j3d.optimizeForSpace property to false. For example : + + java -Dj3d.optimizeForSpace=false MyProgram + + This will cause Java3d to build display list for by-ref geometry and + infrequently changing geometry. + See also : Part II - isFrequent bits, and Part IV - Geometry by reference. + + +IV - Tips and Tricks + + This section presents a number of tips and tricks for an application +programmer to try when optimizing their application. These tips focus on +improving rendering frame rates, but some may also help overall application +performance. + + - Move Object vs. Move ViewPlatform + If the application simply needs to transform the entire scene, + transform the ViewPlatform instead. This changes the problem + from transforming every object in the scene into only + transforming the ViewPlatform. + + - Capability bits + Only set them when needed. Many optimizations can be done + when they are not set. So, plan out application requirements + and only set the capability bits that are needed. + + - Bounds and Activation Radius + Consider the spatial extent of various leaf nodes in the scene + and assign bounds accordingly. This allows the implementation + to prune processing on objects that are not in close + proximity. Note, this does not apply to Geometric bounds. + Automatic bounds calculations for geometric objects is fine. + In cases such as the influencing or scheduling bounds + encompass the entire scene graph, setting this bounds to + infinite bounds may help improve performance. Java3d will + shortcircuit intersection test on bounds with infinite + volume. A BoundingSphere is a infinite bounds if it's radius + is set to Double.POSITIVE_INFINITY. A BoundingBox is a + infinite bounds if it's lower(x, y, z) are set to + Double.NEGATIVE_INFINITY, and it's upper(x, y, z) are set + Double.POSITIVE_INFINITY. + Bounds computation does consume CPU cycles. If an application + does a lot of geometry coordinate updates, to improve + performance, it is better to turn off auto bounds compute. The + application will have to do the bounds update itself. + + - Change Number of Shape3D Nodes + In the current implementation there is a certain amount of + fixed overhead associated with the use of the Shape3D node. + In general, the fewer Shape3D nodes that an application uses, + the better. However, combining Shape3D nodes without + factoring in the spatial locality of the nodes to be combined + can adversely effect performance by effectively disabling view + frustum culling. An application programmer will need to + experiment to find the right balance of combining Shape3D + nodes while leveraging view frustum culling. The .compile + optimization that combines shape node will do this + automatically, when possible. + + - Geometry Type and Format + Most rendering hardware reaches peak performance when + rendering long triangle strips. Unfortunately, most geometry + data stored in files is organized as independent triangles or + small triangle fans (polygons). The Java 3D utility package + includes a stripifier utility that will try to convert a given + geometry type into long triangle strips. Application + programmers should experiment with the stripifier to see if it + helps with their specific data. If not, any stripification + that the application can do will help. Another option is that + most rendering hardware can process a long list of independent + triangles faster than a long list of single triangle triangle + fans. The stripifier in the Java 3D utility package will be + continually updated to provided better stripification. + + - Sharing Appearance/Texture/Material NodeComponents + To assist the implementation in efficient state sorting, and + allow more shape nodes to be combined during compilation, + applications can help by sharing Appearance/Texture/Material + NodeComponent objects when possible. + + - Geometry by reference + Using geometry by reference reduces the memory needed to store + a scene graph, since Java 3D avoids creating a copy in some + cases. However, using this features prevents Java 3D from + creating display lists (unless the scene graph is compiled), + so rendering performance can suffer in some cases. It is + appropriate if memory is a concern or if the geometry is + writable and may change frequently. The interleaved format + will perform better than the non-interleaved formats, and + should be used where possible. In by-reference mode, an + application should use arrays of native data types; referring + to TupleXX[] arrays should be avoided. + See also : Part III - Space versus time property. + + - Texture by reference and Y-up + Using texture by reference and Y-up format may reduce the + memory needed to store a texture object, since Java 3D avoids + creating a copy in some cases. When a copy of the by-reference + data is made in Java3D, users should be aware that this case + will use twice as much memory as the by copy case. This is due + to the fact that Java3D internally makes a copy in addition to + the user's copy to the reference data. Currently, Java3D will not + make a copy of texture image for the following combinations of + BufferedImage format and ImageComponent format (byReference + and Yup should both be set to true): + + On both Solaris and Win32 OpenGL: + + BufferedImage.TYPE_CUSTOM ImageComponent.FORMAT_RGB8 or + of form 3BYTE_RGB ImageComponent.FORMAT_RGB + + BufferedImage.TYPE_CUSTOM ImageComponent.FORMAT_RGBA8 or + of form 4BYTE_RGBA ImageComponent.FORMAT_RGBA + + BufferedImage.TYPE_BYTE_GRAY ImageComponent.FORMAT_CHANNEL8 + + On Win32/OpenGL: + + BufferedImage format ImageComponentFormat + ---------------------- ---------------------- + BufferedImage.TYPE_3BYTE_BGR ImageComponent.FORMAT_RGB8 or + ImageComponent.FORMAT_RGB + + On Solaris/OpenGL: + + BufferedImage format ImageComponentFormat + ---------------------- ---------------------- + BufferedImage.TYPE_4BYTE_ABGR ImageComponent.FORMAT_RGBA8 or + ImageComponent.FORMAT_RGBA + + - Drawing 2D graphics using J3DGraphics2D + The J3DGraphics2D class allows you to mix 2D and 3D drawing + into the same window. However, this can be very slow in many + cases because Java 3D needs to buffer up all of the data and + then composite it into the back buffer of the Canvas3D. A new + method, drawAndFlushImage, is provided to accelerate the + drawing of 2D images into a Canvas3D. To use this, it is + recommended that an application create their own BufferedImage + of the desired size, use Java2D to render into their + BufferedImage, and then use the new drawAndFlushImage method + to draw the image into the Canvas3D. + + This has the advantage of only compositing the minimum area + and, in some cases, can be done without making an extra copy + of the data. For the image to not be copied, this method must + be called within a Canvas3D callback, the specified + BufferedImage must be of the format + BufferedImage.TYPE_4BYTE_ABGR, and the GL_ABGR_EXT extension + must be supported by OpenGL. If these conditions are not met, + the image will be copied, and then flushed. + + The following methods have also been optimized : all drawImage() + routines, drawRenderableImage(), draw(Shape s), fill(Shape s), + drawString(), drawLine() without strokeSet to copy only the + minimum affected region without the restriction imposed in + drawAndFlushImage method. + + - Application Threads + The built in threads support in the Java language is very + powerful, but can be deadly to performance if it is not + controlled. Applications need to be very careful in their + threads usage. There are a few things to be careful of when + using Java threads. First, try to use them in a demand driven + fashion. Only let the thread run when it has a task to do. + Free running threads can take a lot of cpu cycles from the + rest of the threads in the system - including Java 3D threads. + Next, be sure the priority of the threads are appropriate. + Most Java Virtual Machines will enforce priorities + aggressively. Too low a priority will starve the thread and + too high a priority will starve the rest of the system. If in + doubt, use the default thread priority. Finally, see if the + application thread really needs to be a thread. Would the + task that the thread performs be all right if it only ran once + per frame? If so, consider changing the task to a Behavior + that wakes up each frame. + + - Java 3D Threads + Java 3D uses many threads in its implementation, so it also + needs to implement the precautions listed above. In almost + all cases, Java 3D manages its threads efficiently. They are + demand driven with default priorities. There are a few cases + that don't follow these guidelines completely. + + - Behaviors + One of these cases is the Behavior scheduler when there + are pending WakeupOnElapsedTime criteria. In this case, + it needs to wakeup when the minimum WakeupOnElapsedTime + criteria is about to expire. So, application use of + WakeupOnElapsedTime can cause the Behavior scheduler to + run more often than might be necessary. + + - Sounds + The final special case for Java 3D threads is the Sound + subsystem. Due to some limitations in the current sound + rendering engine, enabling sounds cause the sound engine + to potentially run at a higher priority than other + threads. This may adversely effect performance. + + - Threads in General + There is one last comment to make on threads is general. + Since Java 3D is a fully multithreaded system, applications + may see significant performance improvements by increasing the + number of CPUs in the system. For an application that does + strictly animation, then two CPUs should be sufficient. As + more features are added to the application (Sound, Collision, + etc.), more CPUs could be utilized. + + - Switch Nodes for Occlusion Culling + If the application is a first person point of view + application, and the environment is well known, Switch nodes + may be used to implement simple occlusion culling. The + children of the switch node that are not currently visible may + be turned off. If the application has this kind of knowledge, + this can be a very useful technique. + + - Switch Nodes for Animation + Most animation is accomplished by changing the transformations + that effect an object. If the animation is fairly simple and + repeatable, the flip-book trick can be used to display the + animation. Simply put all the animation frames under one + switch node and use a SwitchValueInterpolator on the switch + node. This increases memory consumption in favor of smooth + animations. + + - OrderedGroup Nodes + OrderedGroup and its subclasses are not as high performing as + the unordered group nodes. They disable any state sorting + optimizations that are possible. If the application can find + alternative solutions, performance will improve. + + - LOD Behaviors + For complex scenes, using LOD Behaviors can improve + performance by reducing geometry needed to render objects that + don't need high level of detail. This is another option that + increases memory consumption for faster render rates. + + - Picking + If the application doesn't need the accuracy of geometry based + picking, use bounds based picking. For more accurate picking + and better picking performance, use PickRay instead of + PickCone/PickCylnder unless you need to pick line/point. + PickCanvas with a tolerance of 0 will use PickRay for picking. + + - D3D user only + Using Quad with Polygon line mode is very slow. This is because + DirectX doesn't support Quad. Breaking down the Quad + into two triangles causes the the diagonal line to be displayed. + Instead Java 3D draws the polygon line and does the hidden surface + removal manually. + + Automatic texture generation mode Eye Linear is slower + because D3D doesn't support this mode. diff --git a/j3d-core/nbproject/project.xml b/j3d-core/nbproject/project.xml new file mode 100644 index 0000000..7716e3f --- /dev/null +++ b/j3d-core/nbproject/project.xml @@ -0,0 +1,96 @@ + + + org.netbeans.modules.ant.freeform + + + + j3d-1.5.2 + + + + + ../j3d-core-utils/src/classes/share + + + + java + src/classes/share + + + + java + ../j3d-core-utils/src/classes/share + + + + java + build/default/debug/gen/classes + + + + + jar-debug + + + clean + + + docs-public + + + clean + jar-debug + + + + jar + build/default/debug/lib/ext/j3dcore.jar + jar-debug + + + jar + build/default/debug/lib/ext/j3dutils.jar + jar-debug + + + + + + src/classes/share + + + + ../j3d-core-utils/src/classes/share + + + + build/default/debug/gen/classes + + + build.xml + + + + + + + + + + + ../vecmath + + + + + src/classes/share + ../j3d-core-utils/src/classes/share + build/default/debug/gen/classes + ../vecmath/build/debug/lib/ext/vecmath.jar + build/default/debug/lib/ext/j3dcore.jar + build/default/debug/lib/ext/j3dutils.jar + 1.5 + + + + diff --git a/j3d-core/release-info/fcs-1_3_1/BINARY-CODE-LICENSE.txt b/j3d-core/release-info/fcs-1_3_1/BINARY-CODE-LICENSE.txt new file mode 100644 index 0000000..2d19b8b --- /dev/null +++ b/j3d-core/release-info/fcs-1_3_1/BINARY-CODE-LICENSE.txt @@ -0,0 +1,196 @@ + Sun Microsystems, Inc. + Binary Code License Agreement + JAVA 3D[TM] API, VERSION 1.3.1, FCS RELEASE + +READ THE TERMS OF THIS AGREEMENT AND ANY PROVIDED SUPPLEMENTAL LICENSE +TERMS (COLLECTIVELY "AGREEMENT") CAREFULLY BEFORE OPENING THE SOFTWARE +MEDIA PACKAGE. BY OPENING THE SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE +TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING THE SOFTWARE +ELECTRONICALLY, INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE +"ACCEPT" BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO +ALL THESE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF +PURCHASE FOR A REFUND OR, IF THE SOFTWARE IS ACCESSED ELECTRONICALLY, +SELECT THE "DECLINE" BUTTON AT THE END OF THIS AGREEMENT. + +1. LICENSE TO USE. Sun Microsystems, Inc. ("Sun") grants you a +non-exclusive and non-transferable license for the internal use only of +the accompanying software and documentation and any error corrections +provided by Sun (collectively "Software"), by the number of users and +the class of computer hardware for which the corresponding fee has been +paid. + +2. RESTRICTIONS. Software is confidential and copyrighted. Title to +Software and all associated intellectual property rights is retained by +Sun and/or its licensors. Except as specifically authorized in any +Supplemental License Terms, you may not make copies of Software, other +than a single copy of Software for archival purposes. Unless +enforcement is prohibited by applicable law, you may not modify, +decompile, or reverse engineer Software. You acknowledge that Software +is not designed, licensed or intended for use in the design, +construction, operation or maintenance of any nuclear facility. Sun +disclaims any express or implied warranty of fitness for such uses. No +right, title or interest in or to any trademark, service mark, logo or +trade name of Sun or its licensors is granted under this Agreement. + +3. LIMITED WARRANTY. Sun warrants to you that for a period of ninety +(90) days from the date of purchase, as evidenced by a copy of the +receipt, the media on which Software is furnished (if any) will be free +of defects in materials and workmanship under normal use. Except for +the foregoing, Software is provided "AS IS". Your exclusive remedy and +Sun's entire liability under this limited warranty will be at Sun's +option to replace Software media or refund the fee paid for Software. + +4. DISCLAIMER OF WARRANTY. UNLESS SPECIFIED IN THIS AGREEMENT, ALL +EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING +ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT +THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID. + +5. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO +EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT +OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE +DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISING +OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF +SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event +will Sun's liability to you, whether in contract, tort (including +negligence), or otherwise, exceed the amount paid by you for Software +under this Agreement. The foregoing limitations will apply even if the +above stated warranty fails of its essential purpose. + +6. Termination. This Agreement is effective until terminated. You may +terminate this Agreement at any time by destroying all copies of +Software. This Agreement will terminate immediately without notice from +Sun if you fail to comply with any provision of this Agreement. Upon +Termination, you must destroy all copies of Software. + +7. Export Regulations. All Software and technical data delivered under +this Agreement are subject to US export control laws and may be subject +to export or import regulations in other countries. You agree to comply +strictly with all such laws and regulations and acknowledge that you +have the responsibility to obtain such licenses to export, re-export, or +import as may be required after delivery to you. + +8. U.S. Government Restricted Rights. If Software is being acquired +by or on behalf of the U.S. Government or by a U.S. Government prime +contractor or subcontractor (at any tier), then the Government's rights +in Software and accompanying documentation will be only as set forth in +this Agreement; this is in accordance with 48 CFR 227.7201 through +227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 +CFR 2.101 and 12.212 (for non-DOD acquisitions). + +9. Governing Law. Any action related to this Agreement will be +governed by California law and controlling U.S. federal law. No choice +of law rules of any jurisdiction will apply. + +10. Severability. If any provision of this Agreement is held to be +unenforceable, this Agreement will remain in effect with the provision +omitted, unless omission would frustrate the intent of the parties, in +which case this Agreement will immediately terminate. + +11. Integration. This Agreement is the entire agreement between you +and Sun relating to its subject matter. It supersedes all prior or +contemporaneous oral or written communications, proposals, +representations and warranties and prevails over any conflicting or +additional terms of any quote, order, acknowledgment, or other +communication between the parties relating to its subject matter during +the term of this Agreement. No modification of this Agreement will be +binding, unless in writing and signed by an authorized representative of +each party. + + DEVELOPMENT TOOLS + JAVA 3D[TM], VERSION 1.3.1, FCS RELEASE + SUPPLEMENTAL LICENSE TERMS + +These supplemental license terms ("Supplemental Terms") add to or modify +the terms of the Binary Code License Agreement (collectively, the +"Agreement"). Capitalized terms not defined in these Supplemental Terms +shall have the same meanings ascribed to them in the Agreement. These +Supplemental Terms shall supersede any inconsistent or conflicting terms +in the Agreement, or in any license contained within the Software. + +1. Software Internal Use and Development License Grant. Subject to the +terms and conditions of this Agreement, including, but not limited to +Section 3 (Java[TM]; Technology Restrictions) of these Supplemental +Terms, Sun grants you a non-exclusive, non-transferable, limited license +to reproduce internally and use internally the binary form of the +Software complete and unmodified for the sole purpose of designing, +developing and testing your Java applets and applications intended to +run on the Java platform ("Programs"). + +2. License to Distribute Software. In addition to the license granted +in Section 1 (Software Internal Use and Development License Grant) of +these Supplemental Terms, subject to the terms and conditions of this +Agreement, including but not limited to Section 3 (Java Technology +Restrictions) of these Supplemental Terms, Sun grants you a +non-exclusive, non-transferable, limited license to reproduce and +distribute the Software in binary code form only, provided that you: + +(i) distribute the Software complete and unmodified and only bundled as +part of your Programs, + +(ii) do not distribute additional software intended to replace any +component(s) of the Software, + +(iii) do not remove or alter any proprietary legends or notices +contained in the Software, + +(iv) only distribute the Software subject to a license agreement that +protects Sun's interests consistent with the terms contained in this +Agreement, and + +(v) agree to defend and indemnify Sun and its licensors from and against +any damages, costs, liabilities, settlement amounts and/or expenses +(including attorneys' fees) incurred in connection with any claim, +lawsuit or action by any third party that arises or results from the use +or distribution of any and all Programs and/or Software. + +3. Java Technology Restrictions. You may not modify the Java Platform +Interface ("JPI", identified as classes contained within the "java" +package or any subpackages of the "java" package), by creating +additional classes within the JPI or otherwise causing the addition to +or modification of the classes in the JPI. In the event that you create +an additional class and associated API(s) which + +(i) extends the functionality of the Java platform, and + +(ii) is exposed to third party software developers for the purpose of +developing additional software which invokes such additional API, you +must promptly publish broadly an accurate specification for such API for +free use by all developers. You may not create, or authorize your +licensees to create, additional classes, interfaces, or subpackages that +are in any way identified as "java", "javax", "sun" or similar +convention as specified by Sun in any naming convention designation. + +4. Java Runtime Availability. Refer to the appropriate version of the +Java Runtime Environment binary code license (currently located at +http://www.java.sun.com/jdk/index.html) for the availability of runtime +code which may be distributed with Java applets and applications. + +5. Trademarks and Logos. You acknowledge and agree as between you and +Sun that Sun owns the SUN, SOLARIS, JAVA, JAVA 3D, JINI, FORTE, +STAROFFICE, STARPORTAL and iPLANET trademarks and all SUN, SOLARIS, +JAVA, JAVA 3D, JINI, FORTE, STAROFFICE, STARPORTAL and iPLANET-related +trademarks, service marks, logos and other brand designations ("Sun +Marks"), and you agree to comply with the Sun Trademark and Logo Usage +Requirements currently located at +http://www.sun.com/policies/trademarks. Any use you make of the Sun +Marks inures to Sun's benefit. + +6. Source Code. Software may contain source code that is provided solely +for reference purposes pursuant to the terms of this Agreement. Source +code may not be redistributed unless expressly provided for in this +Agreement. + +7. Termination for Infringement. Either party may terminate this +Agreement immediately should any Software become, or in either party's +opinion be likely to become, the subject of a claim of infringement of +any intellectual property right. + +Note: Some portions of Software are provided with notices and/or +licenses from other parties that govern the use of those portions, +including the README file named README-LICENSE. + +For inquiries please contact: Sun Microsystems, Inc. 4150 Network +Circle, Santa Clara, California 95054. +(Form ID#011801) + diff --git a/j3d-core/release-info/fcs-1_3_1/README.release.cpp b/j3d-core/release-info/fcs-1_3_1/README.release.cpp new file mode 100644 index 0000000..f3d1c7e --- /dev/null +++ b/j3d-core/release-info/fcs-1_3_1/README.release.cpp @@ -0,0 +1,961 @@ +#if 0 +/* + * $RCSfile: README.release.cpp,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:17:46 $ + * $State: Exp $ + */ +#endif +Java 3D(TM) 1.3.1 +#if defined(WIN32OGL) +README file for Win32/OpenGL + +This file contains important information for users of Java 3D(TM). +The first four sections (Requirements, Installation, Shared +Contexts, and Running Java 3D(TM) in a Browser) are of interest +to all Java 3D(TM) users. The rest of this file applies only to +developers of Java 3D(TM) applications. + +** It is recommended that any previous version of Java 3D(TM) be +** uninstalled before installing this version. +#elif defined(SOLARIS) +README file for Solaris/SPARC/OpenGL + +This file contains important information for users of Java 3D(TM). +The first four sections (Requirements, Installation, Shared +Contexts, and Running Java 3D(TM) in a Browser) are of interest +to all Java 3D(TM) users. The rest of this file applies only to +developers of Java 3D(TM) applications. + +** It is recommended that any previous version of Java 3D(TM) be +** removed before installing this version. +#else +README file for Win32/DirectX + +This file contains important information for users of Java 3D(TM). +The first three sections (Requirements, Installation, and Running +Java 3D(TM) in a Browser) are of interest to all Java 3D(TM) users. +The rest of this file applies only to developers of Java 3D(TM) +applications. + +** It is recommended that any previous version of Java 3D(TM) be +** uninstalled before installing this version. +#endif +============ +REQUIREMENTS +============ +#if defined(SOLARIS) +This version of Java 3D(TM) for Solaris/SPARC requires the following: + + Java 2 Runtime or SDK version 1.3.1 or later from Sun Microsystems. + (http://java.sun.com/j2se/) + + Frame Buffer with OpenGL support (XVR-500, XVR-1000, XVR1200, XVR-4000, + Expert3D, Elite3D, Creator3D, and PGX). + + Solaris 7 or later. + + OpenGL 1.2.2 for Solaris or later. Depending on type of frame buffer, + a higher OpenGL version might be needed, such as XVR-1000 requires + OpenGL 1.2.3. + To find your current version, use `pkginfo -l SUNWglrt` + OpenGL for Solaris can be obtained at + http://www.sun.com/solaris/opengl + + PATCHES + + There are no patches required for Solaris 8. However, Java 2 + versions 1.3.1, 1.4 and 1.4.1 do require patches. These patches must be + installed before trying to install Java 3D. + + + Solaris 7 requires the Kernel Update patch (106541-06 or later) + which fixes a bug on multi-processor systems that can lock up + the window system when running a Java 3D program with more than + one active window. Also, Java 2 versions 1.3.1, 1.4 and 1.4.1 require + patches. These patches must be installed before trying to install + Java 3D. + + + Use `showrev -p` to list installed patches. Patches can be + downloaded for free from http://sunsolve.sun.com/. +#elif defined(WIN32OGL) +This version of Java 3D(TM) for WindowsNT 4.0, +Windows 98, Windows ME and Windows 2000 requires the following: + + Java 2 (Runtime or SDK) version 1.3.1 or later from Sun + Microsystems (http://java.sun.com/jdk/). This includes + the Java Plug-In (JPI) to update Java(TM) in your browser. + + OpenGL 1.1 or later, available from Microsoft or from + your graphics card manufacturer (see below). + + NT 4.0 only: Service Pack 3 or later. +#elif defined(WIN32D3D) +This version of Java 3D(TM) for Windows 98, Mindows ME and Windows 2000 +requires the following: + + Java 2 (Runtime or SDK) version 1.3.1 or later from Sun + Microsystems (http://java.sun.com/jdk/). This includes + the Java Plug-In (JPI) to update Java(TM) in your browser. + + DirectX 8.0 or later, available from Microsoft + (http://www.microsoft.com/directx/default.asp). +#endif +============ +INSTALLATION +============ + +You must have permission to write files in your Java(TM) Runtime +Environment and/or SDK directories. If you do not have this +permission, the installer will run to completion but Java 3D(TM) +will not be installed. Make sure you are running Java(TM) from +your local machine and that you are the same user who installed +Java. +#if defined(SOLARIS) +To install Java 3D(TM), execute the appropriate self-extracting +shell script. + + Runtime only: java3d-1_3_1-solaris-sparc-rt.bin + Runtime and SDK: java3d-1_3_1-solaris-sparc-sdk.bin + 64 bit Runtime: java3d-1_3_1-solaris-sparcv9.bin + +For the two runtime versions, execute the script in the destination +jre directories. Note: The 64 bit runtime only contains the nessesary +64 bit components. Install it in the jre directory after installing the +regular runtime files. + +For the runtime and sdk bundle, execute the script in the destination +sdk directory. + +The Java 3D(TM) SDK includes several demo programs that can +verify correct installation. Assuming your Java 2 SDK is installed +at /usr/j2se, try the following: + + cd /usr/j2se/demo/java3d/HelloUniverse + java HelloUniverse + + Note: Many more demos are available under the demo/java3d/ + directory. Some of the demos require a maximum memory + pool larger than the default in java. To increase the + maximum memory pool to 64 megabytes, add the following + command line options to java or appletviewer: + java: -mx64m + appletviewer: -J-mx64m + +Make sure you have the SUNWi1of package (optional fonts) installed by +running `pkginfo SUNWi1of`. If not present, you may see error messages +like this: + + Font specified in font.properties not found + [-b&h-lucida sans typewriter-bold-r-normal-sans-*-%d-*-*-m-*-iso8859-1] + ... +#elif defined(WIN32OGL) +To install Java 3D(TM), execute the InstallShield binaries. + + Runtime only: java3d-1_3_1-windows-i586-opengl-rt.exe + Runtime and SDK: java3d-1_3_1-windows-i586-opengl-sdk.exe + +The installers upgrade your most recently installed Java Runtime +Environment and SDK. + +The Java 3D(TM) SDK includes several demo programs that can +verify correct installation. Assuming your Java 2 SDK is installed +at \j2sdk1.4.1, try the following: + + cd \j2sdk1.4.1\demo\java3d\HelloUniverse + java HelloUniverse + + Note: Many more demos are available under the demo\java3d\ + directory. Some of the demos require a maximum memory + pool larger than the default in java. To increase the + maximum memory pool to 64 meg, add the following command + line options to java or appletviewer: + java: -mx64m + appletviewer: -J-mx64m + +If, after installation, you get the following error message while +running a Java 3D program: + + java.lang.UnsatisfiedLinkError: no J3D in shared library path + +it is most likely because OpenGL and/or the OpenGL GLU utilities are +not installed on the machine. + +For information on OpenGL and how to get it, see the OpenGL web page at +http://www.opengl.org/ +#elif defined(WIN32D3D) +To install Java 3D(TM), execute the InstallShield binaries. + + Runtime only: java3d-1_3_1-windows-i586-directx-rt.exe + Runtime and SDK: java3d-1_3_1-windows-i586-directx-sdk.exe + +The installers will upgrade your most recently installed Java +Runtime Environment and SDK. + +The Java 3D(TM) SDK includes several demo programs that can +verify correct installation. Assuming your Java 2 SDK is installed +at \j2sdk1.4.1, try the following: + + cd \j2sdk1.4.1\demo\java3d\HelloUniverse + java HelloUniverse + + Note: Many more demos are available under the demo\java3d\ + directory. Some of the demos require a maximum memory + pool larger than the default in java. To increase the + maximum memory pool to 64 meg, add the following command + line options to java or appletviewer: + java: -mx64m + appletviewer: -J-mx64m + +#endif +Java 3D(TM) consists of four jar files and three shared libraries. +You do not need to include the jar files in your CLASSPATH, +nor do you need to include the shared libraries in your PATH. +You should include "." in your CLASSPATH or ensure that CLASSPATH +is not set. + +Java 3D documentation and tutorials are available from the Java 3D(TM) +Home Page: http://java.sun.com/products/java-media/3D/ +#if defined(WIN32OGL) || defined(SOLARIS) +=============== +SHARED CONTEXTS +=============== + +This version of Java 3D is able to use shared contexts in OpenGL for Display +Lists and Texture Objects. For single canvas applications, there will be no +change in behavior. For multiple canvas applications, memory requirements +will decrease by using this property. By default, this property is set +to false. To enable the use of shared contexts set the j3d.sharedctx property +to true, for example: + + java -Dj3d.sharedctx=true MyProgram + +#endif +#if defined(WIN32OGL) +Some video cards, such as the Riva TNT & TNT2, have problems using shared +contexts. If you are experiencing no rendering, crashes, or no textures +being displayed when shared contexts are enabled, this is the most likely +problem. + +================= +Background Images +================= + +The background image can be rendered in two modes: raster and texture. In windows, +the default mode is texture and in Solaris, the default one is raster. +The property j3d.backgroundtexture can be used to control which mode to use. +If you are experiencing slow rendering of background images, +you can change j3d.backgroundtexture property. For example, to enable +texture mode if your have hardware support for texture rendering, + + java -Dj3d.backgroundtexture=true MyProgram +#endif + +====================== +Compiled Vertex Array +====================== + +Compiled Vertex Array extension is used in IndexedGeometryArray +when it's USE_COORD_INDEX_ONLY flag is set and it is not in display list mode. +You may disable the use of this extension by setting the new property, +j3d.compliedVertexArray, to false. + +Compiled Vertex Array extension is used extensively, on SUN XVR-4000, for +all GeometryArray type when display list mode is not used. +You may disable the use of this extension by setting the new property, +j3d.compliedVertexArray, to false. + + +=========================== +Multisampling Antialiasing +=========================== + +By default, full scene antialiasing is disabled if a +multisampling pixel format (or visual) is chosen. +To honor a display drivers multisample antialiasing +setting (e.g. force scene antialiasing), set the +implicitAntialiasing property to true. +This causes Java3D to ignore its own scene antialias +settings, letting the driver implicitly implement the +feature. + + java -Dj3d.implicitAntialiasing=true MyProgram + +================================ +RUNNING JAVA 3D(TM) IN A BROWSER +================================ +#if defined(WIN32OGL) || defined(WIN32D3D) +You can run Java 3D(TM) programs in your browser. Java 2(TM) +from Sun includes the Java Plug-In (JPI) to upgrade the Java(TM) +in the browser to Java 2(TM). To verify proper installation, +point your browser to file:/j2sdk1.4.1/demo/java3d/index.html + +If you are getting permission exceptions while running the Java 3D +demo programs in your browser, it may be because of bug 4416056. + +First, upgrade your Java SDK to the latest release. The bug may +have been fixed by the time you read this. + +To work around the problem, the path to your JRE must not +contain spaces. By default, it does ("c:\Program Files\JavaSoft\. . ."). +The Java SDK installer automatically installs the JRE in +c:\Program Files\JavaSoft, so you must run the installers in +this order: + Java SDK installer + Java JRE installer (choose a directory with no spaces) + Java 3D SDK installer (will default to the correct directories) + +NOTE: Many Java 3D(TM) programs will require a larger heap size +than the default 16M in the JPI. Run the Java Plug-In Control +Panel from Start/Programs (JPI 1.2.2) or Start/Settings/Control +Panel (JPI 1.3) and in "Java Run Time Parameters" put "mx64m" +for 64M of heap memory. +#elif defined(SOLARIS) +Java 3D programs can be run in Netscape Communicator on Solaris +with the Java(TM) Plug-IN (JPI) installed: + + Solaris 8 includes Netscape and the JPI. + + For Solaris 7 users, Netscape Communicator may be downloaded + for free from http://www.sun.com/solaris/netscape. Patches + may be required (see the website for details). + + Netscape Communicator 6.0 automatically includes the JPI. + + Java 1.3 and higher include the JPI. The Control Panel + will be at $JAVAHOME/jre/ControlPanel.html. + + If you are using Solaris 7, Java 1.2.2, and Netscape 4.51, 4.7, + or 4.74, you need to download and install the JPI from + http://www.sun.com/solaris/netscape/jpis. NOTE: requires + membership to the JDC. More patches may be required + (see the website for details). If you install it in + the default location (/opt/NSCPcom) the control panel + will be at file:/opt/NSCPcom/j2pi/ControlPanel.html. + +You need to set the NPX_PLUGIN_PATH environment variable +to the directory containing the JPI. For example, you you +are using the JPI from Java 1.4.1 installed in /usr/j2se, +do 'setenv NPX_PLUGIN_PATH /usr/j2se/jre/plugin/sparc' +before starting Netscape. The default is /opt/NSCPcom. + +JDK 1.3.1 and higher have different plugin directories for +Netscape 4.x vs. 6.0. For Netscape 4.x you need: + 'setenv NPX_PLUGIN_PATH /usr/j2se/jre/plugin/sparc/ns4' +while for 6.0: + 'setenv NPX_PLUGIN_PATH /usr/j2se/jre/plugin/sparc/ns600' + +There is a bug in the Solaris JPI 1.2.2 that keeps it +from finding Java extensions in the lib/ext/ directory +where they are kept. If you are not using JPI 1.3, you need to +copy the four .jar files from the lib/ext/ directory to the +lib/ directory as follows: + + cd $SDKHOME/jre/lib/ext + cp j3daudio.jar .. + cp j3dcore.jar .. + cp j3dutils.jar .. + cp vecmath.jar .. + +To verify proper installation, point your browser to +file:///usr/j2se/demo/java3d/index.html + +If it seems like Java 3D isn't installed, make sure the JPI +is using the JVM you've upgraded with Java 3D(TM). Run the +JPI Control Panel and click on the "Advanced" tab to change +the JVM associated with the JPI. Under "Java Run Time +Environment" choose "Other..." and Enter the path to your +JVM in the 'Path:' box (for example, +/usr/j2se/jre). Press "Apply." (Note: +choose the directory above the 'bin' directory.) + +NOTE: Many Java 3D(TM) programs will require a larger heap size +than the default 16M in the JPI. In the Control Panel +"Java Run Time Parameters" put "mx64m" for 64M of heap memory. +#endif +To create a web page with Java 3D, you need to use special HTML +code to force the browser to use the JPI VM. Refer to the +following URL for information on using Java Plug-In "HTML +Converter" and running applets using Java Plug-in: + + http://java.sun.com/products/plugin/ + +==================================================== +DISTRIBUTING Java 3D(TM) WITH YOUR JAVA(TM) PROGRAMS +==================================================== + +Sun Microsystems allows vendors to distribute the Java 3D(TM) Runtime +environment with their Java programs, provided they follow the terms +of the Java 3D(TM) Binary Code License and Supplemental License Terms +agreement. + +This document uses the term "vendors" to refer to licensees, +developers, and independent software vendors (ISVs) who license and +distribute Java 3D(TM) with their Java programs. + +REQUIRED vs. OPTIONAL FILES +--------------------------- +Vendors must follow the terms of the Java 3D(TM) Evaluation License +agreement, which includes these terms: + + - Don't arbitrarily subset Java 3D(TM). You may, however, omit those + files that have been designated below as "optional". + + - Include in your product's license the provisions called out + in the Java 3D(TM) Evaluation License. + +BUNDLING Java 3D(TM) +-------------------- +Java 3D(TM) comes with its own installer that makes it suitable for +downloading by end users. Java(TM) application developers have the +option of not bundling Java 3D(TM) with their software. Instead, +they can direct end-users to download and install the Java 3D(TM) +software themselves. + +Required Files +-------------- +#if defined(SOLARIS) +When bundling Java 3D(TM) with your application, the following files +must be included (Solaris): + + /lib/sparc/libJ3D.so + /lib/sparc/libj3daudio.so + /lib/sparc/libJ3DUtils.so + /lib/ext/vecmath.jar + /lib/ext/j3dcore.jar + /lib/ext/j3daudio.jar + /lib/ext/j3dutils.jar +#elif defined(WIN32OGL) || defined(WIN32D3D) + \bin\J3D.dll + \bin\j3daudio.dll + \bin\J3DUtils.dll + \lib\ext\vecmath.jar + \lib\ext\j3dcore.jar + \lib\ext\j3daudio.jar + \lib\ext\j3dutils.jar +#endif +Optional Files +-------------- + +An application developer may include these files and directories +with their Java 3D(TM) application, but is not required to do so: +#if defined(SOLARIS) + /j3d-utils-src.jar + /demo/java3d +#elif defined(WIN32OGL) || defined(WIN32D3D) + \j3d-utils-src.jar + \demo\java3d +#endif + +======================== +CHANGES SINCE 1.3 +======================== + +============ +NEW FEATURES +============ + + A set of new methods is added to the Viewer, a utility class, to + support dynamic video resize, specificially targeted for SUN + framebuffer : XVR-4000. + Dynamic video resize is a new feature in Java 3D 1.3.1. + This feature provides a means for doing swap synchronous resizing + of the area that is to be magnified (or passed through) to the + output video resolution. This functionality allows an application + to draw into a smaller viewport in the framebuffer in order to reduce + the time spent doing pixel fill. The reduced size viewport is then + magnified up to the video output resolution using the SUN_video_resize + extension. This extension is only implemented in XVR-4000 and later + hardware with back end video out resizing capability. + + + +======================= +Constructing a Canvas3D +======================= + +Many Java 3D programs pass null to the Canvas3D constructor. By doing +this, Java 3D will select a default GraphicsConfiguration that is +appropriate for Java 3D. However, this is a bad practice, and can lead +to errors when applications try to run in alternate environments, such as +stereo viewing. Java 3D will now print out a warning if the Canvas3D +constructor is passed in a null argument for the GraphicsConfiguration. + +==================================== +Multipass Texture support limitation +==================================== +If an application has setup more texture unit states than the graphics +hardware can support, COMBINE mode will not be supported and Java 3D will +fallback to the REPLACE mode. + +========= +Utilities +========= + +This release includes utilities for Java 3D. These utilities are still +being defined and under development. Much of the source for these utilities +is also provided. The API for these utilities may change in future releases. + +The following utilities are provided in this release: + + - Some predefined Mouse based behaviors + - Picking utilities including predefined picking behaviors + - Geometry creation classes for Box, Cone, Cylinder, and Sphere + - A Text2D utility + - Universe Builders - SimpleUniverse and ConfiguredUniverse + - An Image Loading utility + - A Normal Generator utility + - A Polygon Triangulator utility + - Triangle stripifier + - Geometry compression utilities + - Spline-based path interpolators + - Wavefront .obj loader + - Lightwave 3D File Loader + - A scenegraph io utility + - A high resolution interval timer + +=================================== +Enabling Stereo with SimpleUniverse +=================================== + +The SimpleUniverse utility does not, by default, request a +GraphicsConfiguration that is capable of Stereo rendering. To enable this, +you need to set a property when running your application. Here is an +example. + +java -Dj3d.stereo=PREFERRED MyProgram + +Some framebuffers only have one Z buffer and share this between the left +and right eyes. If you are experiencing problems using stereo try the +following property: + +java -Dj3d.stereo=PREFERRED -Dj3d.sharedstereozbuffer=true MyProgram + +#if defined(SOLARIS) +========================================================= +Support for disabling X11 Xinerama mode in Solaris OpenGL +========================================================= + +Solaris OpenGL is well optimized in general for single-threaded applications +running in the Xinerama virtual screen environment, but there are two +situations in which significant degradations in graphics performance may be +experienced by multi-threaded OpenGL clients such as Java 3D applications. + +The first is when using GeometryByReference, which is implemented through the +use of OpenGL vertex arrays. This is essentially treated as immediate mode +data by Solaris OpenGL, which in multi-threaded mode incurs the expense of +copying data for multiple graphics pipelines even when a single window on a +single screen is being used. + +The second is for applications using multiple Canvas3D objects. The X11 +Xinerama extension internally creates separate graphics resources on each +physical screen for each window created on the virtual screen. This causes +significant overhead for multi-threaded Solaris OpenGL clients. + +Java 3D provides a new property in this release, j3d.disableXinerama, which +when set to true will disable the use of Xinerama features by Solaris OpenGL. +This increases performance in the two situations up to 75%, equivalent to that +of running in a non-Xinerama environment. + +The drawback of setting this property is that when moving a Canvas3D from one +physical screen to another the graphics rendering will be clipped to the +physical limits of the original screen on which it was created. The property +is primarily intended to benefit fullscreen applications using multiple +physical screens or fullscreen applications using GeometryByReference. To use +it, specify the property value on the command line: + + java -Dj3d.disableXinerama=true + +Disabling Xinerama requires both JDK 1.4 or later and Solaris OpenGL 1.2.2 or +later. Solaris 7 and 8 must be upgraded to the patch level required by JDK +1.4. +#endif +#if defined(WIN32D3D) +===================================================== +Information on the Direct3D Implementation of Java 3D +===================================================== + + Unsupported Features + -------------------- + The following features are currently unsupported in the Direct3D + implementation of Java 3D: + Line width + Line antialiasing + Point antialiasing + PolygonAttributes backFaceNormalFlip + RenderingAttributes ROP_XOR + Stereo + + Texture features not support: + Texture color table + Base/Maximum Level + Max/Minimum LOD + LOD offset + Detail Texture + Sharpen Texture Function + Filter4 Function + Boundary width + Boundary mode CLAMP_TO_EDGE & CLAMP_TO_BOUNDARY + (will fall back to CLAMP) + Texture blend color when multiple pass is used + to simulate multiTexture. + + Limited Support + --------------- + FullScreen antialiasing is supported only if the device returns + D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT in its raster capabilities + list. (OpenGL supports fullscreen antialiasing if an accumulation + buffer exists.) + + TransparencyAttributes.TransparencyMode values FASTEST, NICEST and + SCREEN_DOOR are the same as BLENDED under D3D. + + DepthComponent in certain display mode when stencil buffer + is selected (use for DecalGroup) since depth Buffer Component + Read/write can't coexist with Stencil buffer in DirectX8.0. + + OffScreen rendering with width/height > current desktop size + + Texture coordinates outside the range [0,1] when boundaryModeS + and boundaryModeT are set to CLAMP will not use the Texture Boundary' + color unless BASE_LEVEL_LINEAR filtering is turned on. + + If the driver did not expose D3DPTADDRESSCAPS_BORDER capability bit + (viathe directX SDK utility Caps Viewer). Then it didn't support + Texture Border color mode. Default color as in Clamp mode will be + used in this case. Most driver currently available need to + workaround using reference mode (-Dj3d.d3dDevice=Reference). + + if the driver did not expose D3DPMISCCAPS_LINEPATTERNREP capability + bit then it didn't support line patterns. A solid line will be shown + in this case. Most driver currently available need to workaround + using reference mode. + + Only negative polygon offsets are supported. The limit of this offset + corresponds to the depth of the z-buffer. + + Float anisotripic filter degree did not support. They will round off + to integer value and pass down to the DirectX library. + + Texture environment combiner : + + COMBINE_REPLACE - Support if driver expose TextureOpCaps + D3DTOP_SELECTARG1. Only combine scale 1 is support. + COMBINE_MODULATE - Support if driver expose TextureOpCaps D3DTOP_MODULATE, + D3DTOP_MODULATE2X, D3DTOP_MODULATE4X for scale 1, 2 & 4 + respectively. + COMBINE_ADD - Support if driver expose TextureOpCaps D3DTOP_ADD, + only combine scale 1 is support + COMBINE_ADD_SIGNED - Support if driver expose TextureOpCaps D3DTOP_ADDSIGNED, + D3DTOP_ADDSIGNED2X for scale 1 & 2 respectively. Combine + scale 4 will fall back to 2. + COMBINE_SUBTRACT - Support if driver expose TextureOpCaps D3DTOP_SUBTRACT. + Only combine scale 1 is support. + COMBINE_INTERPOLATE - Support if driver expose TextureOpCaps D3DTOP_LERP. + Only combine scale 1 is support. + COMBINE_DOT3 - Support if driver expose TextureOpCaps + D3DTOP_DOTPRODUCT3 Only combine scale 1 is support. + + Rendering Different between OGL & D3D + -------------------------------------- + - SpotLight formula is different, OGL will normally have a bigger bright spot. + + - TexCoordGeneration Sphere Map formula is different, OGL will normally + has texture map that zoom closer than D3D. + + - Specular hightlight in Texture mapping mode may different. If OGL driver + support separate specular color, then resulting specular highlight in + texture are the same. Otherwise D3D verson will have a brighter and + more obviously specular highlight compare with OGL. + + + Fullscreen Support + ------------------------ + The Direct3D implementation of Java 3D can be run in fullscreen mode. + To start an application in fullscreen mode, use the property j3d.fullscreen. + The values for j3d.fullscreen are: + REQUIRED - A fullscreen canvas is required. If not available, do not + start up the application. + PREFERRED - A fullscreen canvas is desired for this invocation of the + Java 3D application. If a fullscreen canvas cannot be + created, a windowed canvas is acceptable. + UNNECESSARY - States that a fullscreen canvas is not necessary for this + application. Create a windowed application (this is the + same behavior as not setting this property). + + Example: + java -Dj3d.fullscreen=REQUIRED HelloUniverse + + Further, an application can be toggled between fullscreen and windowed mode + by use of the keyboard combination. + + When using JDK1.4 fullscreen API with Java3D DirectX version, it is + necessary to set the following property : + + -Dsun.java2d.noddraw=true + + Direct3D Driver Selection + ------------------------- + + When there is more then one device associated with a + monitor, by default, Java 3D uses the first driver found + on a given display. This order can be found by + using the -Dj3d.debug=true property during Java startup. + + In order to use a 3D only graphics card such as Voodoo1/2 + A new property has been added + + -Dj3d.d3ddriver=idx + + where idx is the driver order number (starting with 1) found + using the debug property above. This will force Java 3D to use + the driver specified by the user (this may fail if the driver is + not compatible with the display). For a typical setup with a 3D + only card attached to a single monitor system, use idx=2. This + will automatically toggle to fullscreen hardware acceleration mode. + + + Direct3D Device Selection + ------------------------- + In order to aid in development and debugging, Java 3D has added a property + to allow the D3DDevice to use for rendering to be selected. The property, + j3d.d3ddevice can have the following values: + tnlhardware - select a device that supports transform and lighting in + hardware, if present. If no such device is present, + a dialog box is displayed to alert the user and the + application will exit. + hardware - select a Direct3D device that performs hardware + rasterization, if present. If no such device is present, + a dialog box is displayed to alert the user and the + application will exit. + reference - use the Direct3D reference pipeline (only available if + the Direct3D SDK is installed). + + By default Java 3D first tries to select a TnLhardaware device, if that fails + a Hardware device, if that also fails then finally Java 3D selects an + Emulation device. + + + Ignored Java 3D Properties + -------------------------- + The following Java 3D properties are ignored by the Direct3D implementation: + j3d.sharedctx + j3d.stereo + j3d.sharedstereozbuffer + j3d.g2ddrawpixel + j3d.usecombiners + j3d.disableSeparateSpecular + j3d.backgroundtexture + j3d.disableXinerama +#endif + +=================================================== +Information on Java 3D Audio Device Implementations +=================================================== + +Java 3D sound is rendered via the use of a specific implementation +of the AudioDevice3D interface. This release includes two AudioDevice3DL2 +implementations: HeadspaceMixer and JavaSoundMixer. Both of these +implementations are included in the j3daudio.jar. + +Please read README.release in program examples Sound directory for details +regarding the feature and format limitations of each of these implementations +and for examples of these use. + +============================================= +HeadspaceMixer AudioDevice3DL2 Implememtation +============================================= + + The HeadspaceMixer implementation is part of the Sun Java 3D + com.sun.j3d.audioengines.headspace package. This implementation + uses a version of the Headspace Audio Engine licensed from Beatnik + which does all rendering in software and pipes the stereo audio image + to the platform's audio device. + + The implemention that was called JavaSoundMixer in previous Sun + releases of Java 3D has been renamed to HeadspaceMixer. + It was renamed in anticipation of the release of a new AudioDevice + implementation that uses the JavaSound API which will be called + JavaSoundMixer (described below). + + The HeadspaceMixer audio device will be created and initialized when the + utility SimpleUniverse.Viewer.createAudioDevice() method is called. + If your application uses this utility, no change will be required to + use the recommended HeadspaceMixer implementation. + + If your application explicitly used the older JavaSoundMixer audio device + implemention from the package com.sun.j3d.audioengines.javasound, you should + change the reference to JavaSoundMixer, at least for this release, + to HeadspaceMixer: + + import com.sun.j3d.audioengines.headspace.HeadspaceMixer; + : + HeadspaceMixer mixer = new HeadspaceMixer(physicalEnvironment); + + Most of the Java 3D Audio features have been implemented but there are + a few exceptions. Additionally, some Java 3D Audio features are only + only partially implemented. Please read the README.release document in + programs/examples/Sound for more information. + + Note that the HeadspaceMixer is not supported in the 64 bit Solaris + version of Java 3D. + +============================================= +JavaSoundMixer AudioDevice3DL2 Implememtation +============================================= + + The JavaSoundMixer implementation is part of the Sun Java 3D + com.sun.j3d.audioengines.javasound package. This implementation uses + the Java Sound API. All low-level access to the platforms audio device + are dependent on the Java Sound mixer implementation(s) installed on + the machine you're running on. + + The JavaSoundMixer Java 3D audio device implementation uses Java Sound + SourceDataLine streams for non-cached data and Java Sound Clips for + cached data. Support for specific sound cards, the exact input formats + that can be passed as data to Java 3D MediaContainers, and which feature + are rendered in software verses accelleration hardware is dependent on + the Java Sound implementation installed on your machine. + There is guarenteed to be at least one Java Sound mixer implementation + available with all J2SE releases (such as Sun's JDK 1.3 and above). + Please read the README.release document in programs/examples/Sound. + +========== +BUGS FIXED +========== + +Core Graphics and Vecmath +------------------------- +4685686 Apps Particles sometimes throws ArrayOfBoundsException at GeometryArrayRetained +4794994 Memory leak when SharedGroup removed +4792478 ArrayIndexOutOfBoundsException with two ViewSpecificGroups with Lights +4793926 Incorrect collison report when geometry close to each other +4794382 NullPointerException if SharedGroup not set in Link under SwitchGroup +4798443 RenderBin findOrderedCollection throws IndexOutOfBoundsException +4800640 D3D: Garbage line appear in TexCubeMap negative & postive Y surface +4805797 View setLocalEyeLightingEnable() does not work +4807209 View setMinimumFrameCycleTime() fail to free CPU time for other applications +4809037 OGL: glLockArrayEXT() should invoke after vertex pointer defined +4826575 J3D fail to run on JDK1.5 +4829457 Missing object when lighting change in SDSC ExHenge +4829458 Texture stage fail to disable in accelerated mode for multiTexture apps +4836232 TextureUnitState setTextureAttributes() & setTexCoordGeneration() may not work +4838311 D3D: TextureAttributes in texture stage need to reset for multitexture +4839757 OGL: Incorrect rescale normal extension use for non-uniform scale +4840952 TransformGroupRetained throws NullPointerException if sharedGroup link set null +4843212 AWTEvent disable if canvas remove from panel and add back later after SG Live +4843221 GraphicsContext3D flush(true) hangs for non-visible Canvas3D +4846822 NullPointerException in MasterControl addFreeImageUpdateInfo + +Utilities +--------- + +4331669 setRectangleScaleFactor will not change text size unless setString called (doc?) +4780878 ConfiguredUniverse needs a way to access multiple behaviors +4801176 Sphere Texture map reverse when GENERATE_NORMALS_INWARD is used +4803241 EdgeTable & Edge.java use by NormalGenerator missing in java3d-utils-src.jar +4822946 Picking throws NullPointerException for BoundingBox/Sphere/Polytope PickShape +4822988 SceneGraphIO throws NullPointerException when Morph Node is read +4827900 TransformInterpolatorState source missing in j3d-utils-src.jar +4830842 Triangulator fails for polygons with holes in YZ or XZ plane + +============== +KNOWN PROBLEMS +============== + +To get the very latest list of known Java 3D bugs, look on the Java +Bug Parade (http://developer.java.sun.com/developer/bugParade/index.html) + +Documentation Bugs +------------------ + +4303056 Docs should specify thread-safety behavior of Java 3D methods +4350033 JFTC: possible conflict between implementation and spec on PolygonOffset +4391492 Rotation matrix of Transform3D constructor not extract +4514880 results of changing geometry and texture are not well documented +4632391 Typo in doc j3d_tutorial_ch2.pdf +4698350 Spec. did not mention alpha component for Texture Mode REPLACE, MODULATE clearly + +Core Graphics and Vecmath +------------------------- + +4509357 example program - raster image incorrect until mouse moved into window +4512179 Undeterminable behavior caussed by Appearance.setTexture +4516005 AddRemoveCanvas2 fail to show cube intermittently +4518080 Light scoping sometimes not working for compiled geometry +4529297 TCK: Group.removeAllChildren() inconsistent with expected behavior +4667088 sas applications gets VerifyError running with 64-bit JVM +4669211 SharedGroup.getLinks().length is always zero for non-live Link node. +4674146 Background texture fail to render for RenderedImage and byref ImageComponent2D +4674843 ImageComponent3D byReference always make an internal copy +4676035 Off screen rendering has off-center view +4676483 Geometry by Reference change alpha color component of user data +4680305 Detaches of SharedGroups from user threads is not Mt-Safe +4681750 Texture3D throws ArrayIndexOutOfBoundsException when scaleImage +4681863 OGL: OffScreen canvas ignore GraphicsConfigTemplate under windows +4684405 j3d holds a reference to user's bounds (via setBounds()) for use in getBounds(). +4684807 NullPointerException in NodeComponent during setAppearance() +4686527 Deadlock between MasterControl and user thread when using ByRef updateData() +4697155 ByRef USE_COORD_INDEX_ONLY geometry not yet implement for optimizeForSpace=false +4701430 Infrequent NPE at RenderBin.java:544 +4705053 OrientedPtTest example program displays frame lag +4712205 Window panels disappear when BranchGroup.compile() is used. +4714426 compile() removes null child eventhough ALLOW_CHILDREN_READ is set. +4720938 IndexedGeometry shouldn't consider vertex not reference by index in computeBound +4736484 Big alpha value in byRefColor render geometry even though transparency = 1.0 +4740086 Picking cause lots of GC in PickShape intersect() routine +4751162 View TRANSPARENCY_SORT_GEOMETRY throws NullPointerException when viewpoint move +4751283 Transform3D.normalize() and Matrix4d.get(Matrix3d) permute matrix columns +4753957 Morph only consider first GeometryArray when compute bounds +4762021 Transform3D setScale() fail to return negative scale in some case +4762753 Precision problem of OrientedShape3D.ROTATE_ABOUT_POINT if far away from origin +4768237 RuntimeException in pickIntersection.getPointNormal() +4768353 JBrawl does not run smoothly with > 2 cpus +4774341 Locale need a wait between changing HiRes and adding branch graph +4782718 NPE if boundingLeaf in SchedulingBoundLeaf not attach to scenegraph +4783638 WakeupOnAWTEvent does not support MouseWheelEvent +4789101 J3D.dll is accessing jniGetObjectClass inside the critical region +4790016 PickObject generatePickRay return wrong PickShape if View compatibility enable +4794998 hashKey output TROUBLE message when OutOfMemory +4828096 Morph doesn't work correctly with Java3D 1.3 +4828098 Morph doesn't use its weights, when it was cloned with cloneTree() + +Sound +----- + +4634751 BackgroundSound fails to activates with the view intersects it's bounds. +4680280 JavaSoundMixer play sound only once +4760772 BackgroundSounds not looping with HeadspaceMixer mixer + +Utility Bugs +------------ + +4717595 SceneGraph IO bug in J3DFly +4718786 Incorrect coefficients in CubicSplineSegment computeCommonCoefficients() +4805076 Transform3D.get(Matrix3f ) occasionally returns incorrect values + +#if defined(SOLARIS) +Solaris-specific Bugs +--------------------- +none +#elif defined(WIN32OGL) +Windows/OGL-specific Bugs +--------------------- +none + +#elif defined(WIN32D3D) +Direct3D specific Bugs +---------------------- + Problem in the NVidia GForce + ----------------------------- + Make sure you have the latest driver from http://www.nvidia.com/ + + ModelClip did not work under DirectX8.0 debug build, use + Eumulation mode to workaround this. +#endif diff --git a/j3d-core/release-info/fcs-1_3_2/BINARY-CODE-LICENSE.txt b/j3d-core/release-info/fcs-1_3_2/BINARY-CODE-LICENSE.txt new file mode 100644 index 0000000..470999c --- /dev/null +++ b/j3d-core/release-info/fcs-1_3_2/BINARY-CODE-LICENSE.txt @@ -0,0 +1,185 @@ +Sun Microsystems, Inc. +Binary Code License Agreement + +READ THE TERMS OF THIS AGREEMENT AND ANY PROVIDED SUPPLEMENTAL LICENSE +TERMS (COLLECTIVELY "AGREEMENT") CAREFULLY BEFORE OPENING THE SOFTWARE +MEDIA PACKAGE. BY OPENING THE SOFTWARE MEDIA PACKAGE, YOU AGREE +TO THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING THE SOFTWARE +ELECTRONICALLY, INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE +"ACCEPT" BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO +ALL THESE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF +PURCHASE FOR A REFUND OR, IF THE SOFTWARE IS ACCESSED ELECTRONICALLY, +SELECT THE "DECLINE" BUTTON AT THE END OF THIS AGREEMENT. + +1. LICENSE TO USE. Sun grants you a non-exclusive and non-transferable +license for the internal use only of the accompanying software and +documentation and any error corrections provided by Sun (collectively +"Software"), by the number of users and the class of computer hardware +for which the corresponding fee has been paid. + +2. RESTRICTIONS. Software is confidential and copyrighted. Title to +Software and all associated intellectual property rights is retained +by Sun and/or its licensors. Except as specifically authorized in any +Supplemental License Terms, you may not make copies of Software, other +than a single copy of Software for archival purposes. Unless enforcement +is prohibited by applicable law, you may not modify, decompile, or reverse +engineer Software. Licensee acknowledges that Licensed Software is not +designed or intended for use in the design, construction, operation or +maintenance of any nuclear facility. Sun Microsystems, Inc. disclaims +any express or implied warranty of fitness for such uses. No right, +title or interest in or to any trademark, service mark, logo or trade +name of Sun or its licensors is granted under this Agreement. + +3. LIMITED WARRANTY. Sun warrants to you that for a period of ninety +(90) days from the date of purchase, as evidenced by a copy of the +receipt, the media on which Software is furnished (if any) will be free +of defects in materials and workmanship under normal use. Except for +the foregoing, Software is provided "AS IS". Your exclusive remedy +and Sun's entire liability under this limited warranty will be at Sun's +option to replace Software media or refund the fee paid for Software. + +4. DISCLAIMER OF WARRANTY. UNLESS SPECIFIED IN THIS AGREEMENT, +ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, +INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE +EXTENT THAT THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID. + +5. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, +IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, +PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR +PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, +ARISING OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, +EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no +event will Sun's liability to you, whether in contract, tort (including +negligence), or otherwise, exceed the amount paid by you for Software +under this Agreement. The foregoing limitations will apply even if the +above stated warranty fails of its essential purpose. + +6. Termination. This Agreement is effective until terminated. You may +terminate this Agreement at any time by destroying all copies of Software. +This Agreement will terminate immediately without notice from Sun if you +fail to comply with any provision of this Agreement. Upon Termination, +you must destroy all copies of Software. + +7. Export Regulations. All Software and technical data delivered under +this Agreement are subject to US export control laws and may be subject +to export or import regulations in other countries. You agree to comply +strictly with all such laws and regulations and acknowledge that you +have the responsibility to obtain such licenses to export, re-export, +or import as may be required after delivery to you. + +8. U.S. Government Restricted Rights. If Software is being acquired +by or on behalf of the U.S. Government or by a U.S. Government prime +contractor or subcontractor (at any tier), then the Government's rights +in Software and accompanying documentation will be only as set forth +in this Agreement; this is in accordance with 48 CFR 227.7201 through +227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 +CFR 2.101 and 12.212 (for non-DOD acquisitions). + +9. Governing Law. Any action related to this Agreement will be governed +by California law and controlling U.S. federal law. No choice of law +rules of any jurisdiction will apply. + +10. Severability. If any provision of this Agreement is held to be +unenforceable, this Agreement will remain in effect with the provision +omitted, unless omission would frustrate the intent of the parties, +in which case this Agreement will immediately terminate. + +11. Integration. This Agreement is the entire agreement between you +and Sun relating to its subject matter. It supersedes all prior or +contemporaneous oral or written communications, proposals, representations +and warranties and prevails over any conflicting or additional terms +of any quote, order, acknowledgment, or other communication between the +parties relating to its subject matter during the term of this Agreement. +No modification of this Agreement will be binding, unless in writing +and signed by an authorized representative of each party. + +DEVELOPMENT TOOLS +JAVA 3D, VERSION 1.3.2, FCS RELEASE +SUPPLEMENTAL LICENSE TERMS + +These supplemental license terms ("Supplemental Terms") add to or modify +the terms of the Binary Code License Agreement (collectively, the +"Agreement"). Capitalized terms not defined in these Supplemental Terms +shall have the same meanings ascribed to them in the Agreement. These +Supplemental Terms shall supersede any inconsistent or conflicting terms +in the Agreement, or in any license contained within the Software. + +A. Software Internal Use and Development License Grant. Subject to the +terms and conditions of this Agreement, including, but not limited to +Section C (Java Technology Restrictions) of these Supplemental +Terms, Sun grants you a non-exclusive, non-transferable, limited license +to reproduce internally and use internally the binary form of the +Software complete and unmodified for the sole purpose of designing, +developing and testing your Java applets and applications intended to +run on the Java platform ("Programs"). + +B. License to Distribute Software. In addition to the license granted +in Section A (Software Internal Use and Development License Grant) of +these Supplemental Terms, subject to the terms and conditions of this +Agreement, including but not limited to Section C (Java Technology +Restrictions) of these Supplemental Terms, Sun grants you a +non-exclusive, non-transferable, limited license to reproduce and +distribute the Software in binary code form only, provided that you: + +(i) distribute the Software complete and unmodified and only bundled as +part of your Programs, + +(ii) do not distribute additional software intended to replace any +component(s) of the Software, + +(iii) do not remove or alter any proprietary legends or notices +contained in the Software, + +(iv) only distribute the Software subject to a license agreement that +protects Sun's interests consistent with the terms contained in this +Agreement, and + +(v) agree to defend and indemnify Sun and its licensors from and against +any damages, costs, liabilities, settlement amounts and/or expenses +(including attorneys' fees) incurred in connection with any claim, +lawsuit or action by any third party that arises or results from the use +or distribution of any and all Programs and/or Software. + +C. Java Technology Restrictions. You may not create, modify, or change +the behavior of, or authorize your licensees to create, modify, or change +the behavior of, classes, interfaces, or subpackages that are in any way +identified as "java", "javax", "sun" or similar convention as specified +by Sun in any naming convention designation. + +D. Java Runtime Availability. Refer to the appropriate version of the +Java Runtime Environment binary code license (currently located at +http://www.java.sun.com/jdk/index.html) for the availability of runtime +code which may be distributed with Java applets and applications. + +E. Trademarks and Logos. You acknowledge and agree as between you and +Sun that Sun owns the SUN, SOLARIS, JAVA, JAVA 3D, JINI, FORTE, +STAROFFICE, STARPORTAL and iPLANET trademarks and all SUN, SOLARIS, +JAVA, JAVA 3D, JINI, FORTE, STAROFFICE, STARPORTAL and iPLANET-related +trademarks, service marks, logos and other brand designations ("Sun +Marks"), and you agree to comply with the Sun Trademark and Logo Usage +Requirements currently located at +http://www.sun.com/policies/trademarks. Any use you make of the Sun +Marks inures to Sun's benefit. + +F. Source Code. Software may contain source code that is provided solely +for reference purposes pursuant to the terms of this Agreement. Source +code may not be redistributed unless expressly provided for in this +Agreement. + +G. Termination for Infringement. Either party may terminate this +Agreement immediately should any Software become, or in either party's +opinion be likely to become, the subject of a claim of infringement of +any intellectual property right. + +H. Third Party Code. Additional copyright notices and license terms +applicable to portions of the Software are set forth in the +THIRDPARTYLICENSEREADME.txt file. In addition to any terms and +conditions of any third party opensource/freeware license identified +in the THIRDPARTYLICENSEREADME.txt file, the disclaimer of warranty and +limitation of liability provisions in paragraphs 5 and 6 of the Binary +Code License Agreement shall apply to all Software in this distribution. + +For inquiries please contact: Sun Microsystems, Inc. 4150 Network +Circle, Santa Clara, California 95054. +(Form ID#011801) diff --git a/j3d-core/release-info/fcs-1_3_2/README.txt b/j3d-core/release-info/fcs-1_3_2/README.txt new file mode 100644 index 0000000..49a4438 --- /dev/null +++ b/j3d-core/release-info/fcs-1_3_2/README.txt @@ -0,0 +1,11 @@ +This binary release of the Java 3D API, version 1.3.2 is a copyrighted +product that is licensed to individuals or companies who download or +otherwise access the release. + +The copyright notice for this product is in COPYRIGHT.txt + +The binary code license for this product is in BINARY-CODE-LICENSE.txt + +Instructions for installation are in HOW-TO-INSTALL.html + +The release notes for this product are in RELEASE-NOTES.html diff --git a/j3d-core/release-info/fcs-1_4_0/0-USAGE.txt b/j3d-core/release-info/fcs-1_4_0/0-USAGE.txt new file mode 100644 index 0000000..4caa20a --- /dev/null +++ b/j3d-core/release-info/fcs-1_4_0/0-USAGE.txt @@ -0,0 +1,26 @@ +README.html : + Modified RELEASE NOTES (with link to install instructions removed) + used as README file for Windows installer + +LICENSE-Java3D-v1_4_0.rtf : + rtf version of license used for Windows installer + +LICENSE-Java3D-v1_4_0.txt : + text version of license used for Unix installers, the Windows + zip bundle, and in download directory + +README-download.html : + README file used in download directory; includes pointer to + LICENSE-Java3D-v1_4_0.txt plus HOW_TO_INSTALL.html + +README-distribution.txt : + Legal README file that is included with the Windows zip bundle + +README.txt : + README file that is included with the Windows zip bundle; + includes MANIFEST of files in bundle + +README-unzip.html : + README file that is included with the Windows zip bundle; + includes pointer to LICENSE-Java3D-v1_4_0.txt plus instructions + for manually unzipping the zip bundle diff --git a/j3d-core/release-info/fcs-1_4_0/LICENSE-Java3D-v1_4_0.rtf b/j3d-core/release-info/fcs-1_4_0/LICENSE-Java3D-v1_4_0.rtf new file mode 100644 index 0000000..8c7e66c --- /dev/null +++ b/j3d-core/release-info/fcs-1_4_0/LICENSE-Java3D-v1_4_0.rtf @@ -0,0 +1,180 @@ +{\rtf1\ansi\deff0\adeflang1025 +{\fonttbl{\f0\froman\fprq2\fcharset0 Thorndale{\*\falt Times New Roman};}{\f1\froman\fprq2\fcharset0 Thorndale{\*\falt Times New Roman};}{\f2\fmodern\fprq1\fcharset0 Cumberland{\*\falt Courier New};}{\f3\fnil\fprq2\fcharset0 Andale Sans UI{\*\falt Arial Unicode MS};}{\f4\fnil\fprq2\fcharset0 Lucidasans;}{\f5\fnil\fprq0\fcharset0 Lucidasans;}} +{\colortbl;\red0\green0\blue0;\red128\green128\blue128;} +{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\afs24\langfe255\loch\f0\fs24\lang1033\snext1 Default;} +{\s2\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\afs24\langfe255\loch\f0\fs24\lang1033\sbasedon1\snext2 Text body;} +{\s3\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\afs24\langfe255\loch\f0\fs24\lang1033\sbasedon2\snext3 List;} +{\s4\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs20\lang255\ai\ltrch\dbch\af3\afs20\langfe255\ai\loch\f0\fs20\lang1033\i\sbasedon1\snext4 Caption;} +{\s5\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af3\afs24\langfe255\loch\f0\fs24\lang1033\sbasedon1\snext5 Index;} +{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af2\afs20\lang255\ltrch\dbch\af2\afs20\langfe255\loch\f2\fs20\lang1033\sbasedon1\snext6 Preformatted Text;} +} +{\info{\creatim\yr2006\mo2\dy13\hr17\min3}{\operator Kevin Rushforth}{\revtim\yr2006\mo2\dy13\hr17\min4}{\printim\yr1601\mo1\dy1\hr0\min0}{\comment StarWriter}{\vern6450}}\deftab709 +{\*\pgdsctbl +{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440\pgdscnxt0 Default;}} +\paperh15840\paperw12240\margl1800\margr1800\margt1440\margb1440\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc +\pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af3\afs24\langfe255\loch\f0\fs24\lang1033 {\loch\f0\fs24\lang1033\i0\b0 Sun Microsystems, Inc. ("Sun") SOFTWARE LICENSE AGREEMENT and ENTITLEMENT for SOFTWARE} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 A. ENTITLEMENT for SOFTWARE} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Licensee/Company: Entity receiving Software.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Effective Date: Date of delivery of the Software to You.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Software: JAVA 3D, VERSION 1.4.0} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 License Term: Perpetual (subject to termination under the SLA)} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Licensed Unit: Software Copy} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Licensed unit Count: Unlimited} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Permitted Uses: } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 1. You may reproduce and use the Software for Individual, Commercial, or Research and Instructional Use for the purposes of designing, developing, testing, and running Your applets and application("Programs").} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 2. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the Software's documentation, You may reproduce and distribute portions of Software identified as a redistributable in the documentation ("Redistributable +"), provided that:} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (a) you distribute Redistributable complete and unmodified and only bundled as part of Your Programs, } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (b) your Programs add significant and primary functionality to the Redistributable, } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (c) you distribute Redistributable for the sole purpose of running your Programs,} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (d) you do not distribute additional software intended to replace any} +\par {\loch\f0\fs24\lang1033\i0\b0 component(s) of the Redistributable,} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (e) you do not remove or alter any proprietary legends or notices contained in or on the Redistributable.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (f) you only distribute the Redistributable subject to a license agreement that protects Sun's interests consistent with the terms contained in this} +\par {\loch\f0\fs24\lang1033\i0\b0 Agreement, and} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (g) you agree to defend and indemnify Sun and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that a +rises or results from the use or distribution of any and all Programs and/or Redistributable. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 3. Java Technology Restrictions. You may not create, modify, or change the behavior of, or authorize your licensees to create, modify, or change the behavior of, classes, interfaces, or subpackages that are in any way identified as "java", "javax", "sun" +or similar convention as specified by Sun in any naming convention designation.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 B. SOFTWARE LICENSE AGREEMENT} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 READ THE TERMS OF THIS AGREEMENT ("AGREEMENT") CAREFULLY BEFORE OPENING SOFTWARE MEDIA PACKAGE. BY OPENING SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING SOFTWARE ELECTRONICALLY, INDICATE YOUR ACCEPTANCE OF THESE TER +MS BY SELECTING THE "ACCEPT" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF PURCHASE FOR A REFUND OR, IF SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT THE "DE +CLINE" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU HAVE SEPARATELY AGREED TO LICENSE TERMS ("MASTER TERMS") FOR YOUR LICENSE TO THIS SOFTWARE, THEN SECTIONS 1-6 OF THIS AGREEMENT ("SUPPLEMENTAL LICENSE TERMS") SHALL SUPPLEMENT AND SUPERSEDE + THE MASTER TERMS IN RELATION TO THIS SOFTWARE.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 1. Definitions.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (a) "Entitlement" means the collective set of applicable documents authorized by Sun evidencing your obligation to pay associated fees (if any) for the license, associated Services, and the authorized scope of use of Software under this Agreement.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (b) "Licensed Unit" means the unit of measure by which your use of Software and/or Service is licensed, as described in your Entitlement.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (c) "Permitted Use" means the licensed Software use(s) authorized in this Agreement as specified in your Entitlement. The Permitted Use for any bundled Sun software not specified in your Entitlement will be evaluation use as provided in Section 3.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (d) "Service" means the service(s) that Sun or its delegate will provide, if any, as selected in your Entitlement and as further described in the applicable service listings at www.sun.com/service/servicelist.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (e) "Software" means the Sun software described in your Entitlement. Also, certain software may be included for evaluation use under Section 3. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (f) "You" and "Your" means the individual or legal entity specified in the Entitlement, or for evaluation purposes, the entity performing the evaluation.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 2. License Grant and Entitlement.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Subject to the terms of your Entitlement, Sun grants you a nonexclusive, nontransferable limited license to use Software for its Permitted Use for the license term. Your Entitlement will specify (a) Software licensed, (b) the Permitted Use, (c) the license + term, and (d) the Licensed Units. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Additionally, if your Entitlement includes Services, then it will also specify the (e) Service and (f) service term. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 If your rights to Software or Services are limited in duration and the date such rights begin is other than the purchase date, your Entitlement will provide that beginning date(s).} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 The Entitlement may be delivered to you in various ways depending on the manner in which you obtain Software and Services, for example, the Entitlement may be provided in your receipt, invoice or your contract with Sun or authorized Sun reseller. It may al +so be in electronic format if you download Software.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 3. Permitted Use.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 As selected in your Entitlement, one or more of the following Permitted Uses will apply to your use of Software. Unless you have an Entitlement that expressly permits it, you may not use Software for any of the other Permitted Uses. If you don't have an En +titlement, or if your Entitlement doesn't cover additional software delivered to you, then such software is for your Evaluation Use.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (a) Evaluation Use. You may evaluate Software internally for a period of 90 days from your first use. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (b) Research and Instructional Use. You may use Software internally to design, develop and test, and also to provide instruction on such uses.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (c) Individual Use. You may use Software internally for personal, individual use.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (d) Commercial Use. You may use Software internally for your own commercial purposes. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (e) Service Provider Use. You may make Software functionality accessible (but not by providing Software itself or through outsourcing services) to your end users in an extranet deployment, but not to your affiliated companies or to government agencies.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 4. Licensed Units.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Your Permitted Use is limited to the number of Licensed Units stated in your Entitlement. If you require additional Licensed Units, you will need additional Entitlement(s).} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 5. Restrictions.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 (a) The copies of Software provided to you under this Agreement is licensed, not sold, to you by Sun. Sun reserves all rights not expressly granted. (b) You may make a single archival copy of Software, but otherwise may not copy, modify, or distribute Soft +ware. However if the Sun documentation accompanying Software lists specific portions of Software, such as header files, class libraries, reference source code, and/or redistributable files, that may be handled differently, you may do so only as provided in + the Sun documentation. (c) You may not rent, lease, lend or encumber Software. (d) Unless enforcement is prohibited by applicable law, you may not decompile, or reverse engineer Software. (e) The terms and conditions of this Agreement will apply to any So +ftware updates, provided to you at Sun's discretion, that replace and/or supplement the original Software, unless such update contains a separate license. (f) You may not publish or provide the results of any benchmark or comparison tests run on Software t +o any third party without the prior written consent of Sun. (g) Software is confidential and copyrighted. (h) Unless otherwise specified, if Software is delivered with embedded or bundled software that enables functionality of Software, you may not use suc +h software on a stand-alone basis or use any portion of such software to interoperate with any program(s) other than Software. (i) Software may contain programs that perform automated collection of system data and/or automated software updating services. S +ystem data collected through such programs may be used by Sun, its subcontractors, and its service delivery partners for the purpose of providing you with remote system services and/or improving Sun's software and systems. (j) Software is not designed, lic +ensed or intended for use in the design, construction, operation or maintenance of any nuclear facility and Sun and its licensors disclaim any express or implied warranty of fitness for such uses. (k) No right, title or interest in or to any trademark, ser +vice mark, logo or trade name of Sun or its licensors is granted under this Agreement.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 6. Java Compatibility and Open Source.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Software may contain Java technology. You may not create additional classes to, or modifications of, the Java technology, except under compatibility requirements available under a separate agreement available at www.java.net.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Sun supports and benefits from the global community of open source developers, and thanks the community for its important contributions and open standards-based technology, which Sun has adopted into many of its products.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Please note that portions of Software may be provided with notices and open source licenses from such communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may ha +ve under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this Agreement will apply to all Software in this distribution.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 7. Term and Termination. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 The license and service term are set forth in your Entitlement(s). Your rights under this Agreement will terminate immediately without notice from Sun if you materially breach it or take any action in derogation of Sun's and/or its licensors' rights to Sof +tware. Sun may terminate this Agreement should any Software become, or in Sun's reasonable opinion likely to become, the subject of a claim of intellectual property infringement or trade secret misappropriation. Upon termination, you will cease use of, and + destroy, Software and confirm compliance in writing to Sun. Sections 1, 5, 6, 7, and 9-15 will survive termination of the Agreement.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 8. Limited Warranty. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Sun warrants to you that for a period of 90 days from the date of purchase, as evidenced by a copy of the receipt, the media on which Software is furnished (if any) will be free of defects in materials and workmanship under normal use. Except for the foreg +oing, Software is provided "AS IS". Your exclusive remedy and Sun's entire liability under this limited warranty will be at Sun's option to replace Software media or refund the fee paid for Software. Some states do not allow limitations on certain implied +warranties, so the above may not apply to you. This limited warranty gives you specific legal rights. You may have others, which vary from state to state.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 9. Disclaimer of Warranty. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE D +ISCLAIMERS ARE HELD TO BE LEGALLY INVALID. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 10. Limitation of Liability. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISIN +G OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, whether in contract, tort (including negligence), or otherwise, exceed the amount paid + by you for Software under this Agreement. The foregoing limitations will apply even if the above stated warranty fails of its essential purpose. Some states do not allow the exclusion of incidental or consequential damages, so some of the terms above may +not be applicable to you. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 11. Export Regulations. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 All Software, documents, technical data, and any other materials delivered under this Agreement are subject to U.S. export control laws and may be subject to export or import regulations in other countries. You agree to comply strictly with these laws and +regulations and acknowledge that you have the responsibility to obtain any licenses to export, re-export, or import as may be required after delivery to you. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 12. U.S. Government Restricted Rights. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 If Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government's rights in Software and accompanying documentation will be only as set forth in this Agreemen +t; this is in accordance with 48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions). } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 13. Governing Law. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Any action related to this Agreement will be governed by California law and controlling U.S. federal law. No choice of law rules of any jurisdiction will apply. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 14. Severability. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 If any provision of this Agreement is held to be unenforceable, this Agreement will remain in effect with the provision omitted, unless omission would frustrate the intent of the parties, in which case this Agreement will immediately terminate.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 15. Integration. } +\par +\par {\loch\f0\fs24\lang1033\i0\b0 This Agreement, including any terms contained in your Entitlement, is the entire agreement between you and Sun relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, representations and warrant +ies and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement. No modification of this Agreement will be binding, u +nless in writing and signed by an authorized representative of each party.} +\par +\par {\loch\f0\fs24\lang1033\i0\b0 Please contact Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, California 95054 if you have questions.} +\par } diff --git a/j3d-core/release-info/fcs-1_4_0/LICENSE-Java3D-v1_4_0.txt b/j3d-core/release-info/fcs-1_4_0/LICENSE-Java3D-v1_4_0.txt new file mode 100644 index 0000000..d6baa88 --- /dev/null +++ b/j3d-core/release-info/fcs-1_4_0/LICENSE-Java3D-v1_4_0.txt @@ -0,0 +1,298 @@ +Sun Microsystems, Inc. ("Sun") SOFTWARE LICENSE AGREEMENT and +ENTITLEMENT for SOFTWARE + +A. ENTITLEMENT for SOFTWARE + +Licensee/Company: Entity receiving Software. + +Effective Date: Date of delivery of the Software to You. + +Software: JAVA 3D, VERSION 1.4.0 + +License Term: Perpetual (subject to termination under the SLA) + +Licensed Unit: Software Copy + +Licensed unit Count: Unlimited + +Permitted Uses: + +1. You may reproduce and use the Software for Individual, Commercial, or +Research and Instructional Use for the purposes of designing, developing, +testing, and running Your applets and application("Programs"). + +2. Subject to the terms and conditions of this Agreement and +restrictions and exceptions set forth in the Software's documentation, +You may reproduce and distribute portions of Software identified as a +redistributable in the documentation ("Redistributable"), provided that: + +(a) you distribute Redistributable complete and unmodified and only +bundled as part of Your Programs, + +(b) your Programs add significant and primary functionality to the +Redistributable, + +(c) you distribute Redistributable for the sole purpose of running +your Programs, + +(d) you do not distribute additional software intended to replace any +component(s) of the Redistributable, + +(e) you do not remove or alter any proprietary legends or notices +contained in or on the Redistributable. + +(f) you only distribute the Redistributable subject to a license agreement +that protects Sun's interests consistent with the terms contained in +this Agreement, and + +(g) you agree to defend and indemnify Sun and its licensors from and +against any damages, costs, liabilities, settlement amounts and/or +expenses (including attorneys' fees) incurred in connection with any +claim, lawsuit or action by any third party that arises or results from +the use or distribution of any and all Programs and/or Redistributable. + +3. Java Technology Restrictions. You may not create, modify, or change +the behavior of, or authorize your licensees to create, modify, or change +the behavior of, classes, interfaces, or subpackages that are in any way +identified as "java", "javax", "sun" or similar convention as specified +by Sun in any naming convention designation. + +B. SOFTWARE LICENSE AGREEMENT + +READ THE TERMS OF THIS AGREEMENT ("AGREEMENT") CAREFULLY BEFORE OPENING +SOFTWARE MEDIA PACKAGE. BY OPENING SOFTWARE MEDIA PACKAGE, YOU AGREE TO +THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING SOFTWARE ELECTRONICALLY, +INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE "ACCEPT" (OR +EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO +ALL OF THE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF +PURCHASE FOR A REFUND OR, IF SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT +THE "DECLINE" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU +HAVE SEPARATELY AGREED TO LICENSE TERMS ("MASTER TERMS") FOR YOUR LICENSE +TO THIS SOFTWARE, THEN SECTIONS 1-6 OF THIS AGREEMENT ("SUPPLEMENTAL +LICENSE TERMS") SHALL SUPPLEMENT AND SUPERSEDE THE MASTER TERMS IN +RELATION TO THIS SOFTWARE. + +1. Definitions. + +(a) "Entitlement" means the collective set of applicable documents +authorized by Sun evidencing your obligation to pay associated fees (if +any) for the license, associated Services, and the authorized scope of +use of Software under this Agreement. + +(b) "Licensed Unit" means the unit of measure by which your use of +Software and/or Service is licensed, as described in your Entitlement. + +(c) "Permitted Use" means the licensed Software use(s) authorized in +this Agreement as specified in your Entitlement. The Permitted Use +for any bundled Sun software not specified in your Entitlement will be +evaluation use as provided in Section 3. + +(d) "Service" means the service(s) that Sun or its delegate will provide, +if any, as selected in your Entitlement and as further described in the +applicable service listings at www.sun.com/service/servicelist. + +(e) "Software" means the Sun software described in your Entitlement. Also, +certain software may be included for evaluation use under Section 3. + +(f) "You" and "Your" means the individual or legal entity specified +in the Entitlement, or for evaluation purposes, the entity performing +the evaluation. + +2. License Grant and Entitlement. + +Subject to the terms of your Entitlement, Sun grants you a nonexclusive, +nontransferable limited license to use Software for its Permitted Use for +the license term. Your Entitlement will specify (a) Software licensed, +(b) the Permitted Use, (c) the license term, and (d) the Licensed Units. + +Additionally, if your Entitlement includes Services, then it will also +specify the (e) Service and (f) service term. + +If your rights to Software or Services are limited in duration and the +date such rights begin is other than the purchase date, your Entitlement +will provide that beginning date(s). + +The Entitlement may be delivered to you in various ways depending on +the manner in which you obtain Software and Services, for example, the +Entitlement may be provided in your receipt, invoice or your contract +with Sun or authorized Sun reseller. It may also be in electronic format +if you download Software. + +3. Permitted Use. + +As selected in your Entitlement, one or more of the following Permitted +Uses will apply to your use of Software. Unless you have an Entitlement +that expressly permits it, you may not use Software for any of the other +Permitted Uses. If you don't have an Entitlement, or if your Entitlement +doesn't cover additional software delivered to you, then such software +is for your Evaluation Use. + +(a) Evaluation Use. You may evaluate Software internally for a period +of 90 days from your first use. + +(b) Research and Instructional Use. You may use Software internally to +design, develop and test, and also to provide instruction on such uses. + +(c) Individual Use. You may use Software internally for personal, +individual use. + +(d) Commercial Use. You may use Software internally for your own +commercial purposes. + +(e) Service Provider Use. You may make Software functionality accessible +(but not by providing Software itself or through outsourcing services) +to your end users in an extranet deployment, but not to your affiliated +companies or to government agencies. + +4. Licensed Units. + +Your Permitted Use is limited to the number of Licensed Units stated +in your Entitlement. If you require additional Licensed Units, you will +need additional Entitlement(s). + +5. Restrictions. + +(a) The copies of Software provided to you under this Agreement +is licensed, not sold, to you by Sun. Sun reserves all rights not +expressly granted. (b) You may make a single archival copy of Software, +but otherwise may not copy, modify, or distribute Software. However if +the Sun documentation accompanying Software lists specific portions of +Software, such as header files, class libraries, reference source code, +and/or redistributable files, that may be handled differently, you may +do so only as provided in the Sun documentation. (c) You may not rent, +lease, lend or encumber Software. (d) Unless enforcement is prohibited by +applicable law, you may not decompile, or reverse engineer Software. (e) +The terms and conditions of this Agreement will apply to any Software +updates, provided to you at Sun's discretion, that replace and/or +supplement the original Software, unless such update contains a separate +license. (f) You may not publish or provide the results of any benchmark +or comparison tests run on Software to any third party without the prior +written consent of Sun. (g) Software is confidential and copyrighted. (h) +Unless otherwise specified, if Software is delivered with embedded or +bundled software that enables functionality of Software, you may not +use such software on a stand-alone basis or use any portion of such +software to interoperate with any program(s) other than Software. (i) +Software may contain programs that perform automated collection of +system data and/or automated software updating services. System data +collected through such programs may be used by Sun, its subcontractors, +and its service delivery partners for the purpose of providing you with +remote system services and/or improving Sun's software and systems. (j) +Software is not designed, licensed or intended for use in the design, +construction, operation or maintenance of any nuclear facility and Sun +and its licensors disclaim any express or implied warranty of fitness +for such uses. (k) No right, title or interest in or to any trademark, +service mark, logo or trade name of Sun or its licensors is granted +under this Agreement. + +6. Java Compatibility and Open Source. + +Software may contain Java technology. You may not create additional +classes to, or modifications of, the Java technology, except under +compatibility requirements available under a separate agreement available +at www.java.net. + +Sun supports and benefits from the global community of open source +developers, and thanks the community for its important contributions +and open standards-based technology, which Sun has adopted into many of +its products. + +Please note that portions of Software may be provided with notices and +open source licenses from such communities and third parties that govern +the use of those portions, and any licenses granted hereunder do not alter +any rights and obligations you may have under such open source licenses, +however, the disclaimer of warranty and limitation of liability provisions +in this Agreement will apply to all Software in this distribution. + +7. Term and Termination. + +The license and service term are set forth in your Entitlement(s). Your +rights under this Agreement will terminate immediately without notice from +Sun if you materially breach it or take any action in derogation of Sun's +and/or its licensors' rights to Software. Sun may terminate this Agreement +should any Software become, or in Sun's reasonable opinion likely to +become, the subject of a claim of intellectual property infringement or +trade secret misappropriation. Upon termination, you will cease use of, +and destroy, Software and confirm compliance in writing to Sun. Sections +1, 5, 6, 7, and 9-15 will survive termination of the Agreement. + +8. Limited Warranty. + +Sun warrants to you that for a period of 90 days from the date of +purchase, as evidenced by a copy of the receipt, the media on which +Software is furnished (if any) will be free of defects in materials +and workmanship under normal use. Except for the foregoing, Software is +provided "AS IS". Your exclusive remedy and Sun's entire liability under +this limited warranty will be at Sun's option to replace Software media +or refund the fee paid for Software. Some states do not allow limitations +on certain implied warranties, so the above may not apply to you. This +limited warranty gives you specific legal rights. You may have others, +which vary from state to state. + +9. Disclaimer of Warranty. + +UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, +REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT +ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE DISCLAIMERS ARE HELD TO +BE LEGALLY INVALID. + +10. Limitation of Liability. + +TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS +BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS +OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO THE USE OF +OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, +whether in contract, tort (including negligence), or otherwise, exceed +the amount paid by you for Software under this Agreement. The foregoing +limitations will apply even if the above stated warranty fails of its +essential purpose. Some states do not allow the exclusion of incidental +or consequential damages, so some of the terms above may not be applicable +to you. + +11. Export Regulations. + +All Software, documents, technical data, and any other materials delivered +under this Agreement are subject to U.S. export control laws and may be +subject to export or import regulations in other countries. You agree +to comply strictly with these laws and regulations and acknowledge that +you have the responsibility to obtain any licenses to export, re-export, +or import as may be required after delivery to you. + +12. U.S. Government Restricted Rights. + +If Software is being acquired by or on behalf of the U.S. Government or +by a U.S. Government prime contractor or subcontractor (at any tier), +then the Government's rights in Software and accompanying documentation +will be only as set forth in this Agreement; this is in accordance with +48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) +acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions). + +13. Governing Law. + +Any action related to this Agreement will be governed by California +law and controlling U.S. federal law. No choice of law rules of any +jurisdiction will apply. + +14. Severability. + +If any provision of this Agreement is held to be unenforceable, this +Agreement will remain in effect with the provision omitted, unless +omission would frustrate the intent of the parties, in which case this +Agreement will immediately terminate. + +15. Integration. + +This Agreement, including any terms contained in your Entitlement, is the +entire agreement between you and Sun relating to its subject matter. It +supersedes all prior or contemporaneous oral or written communications, +proposals, representations and warranties and prevails over any +conflicting or additional terms of any quote, order, acknowledgment, or +other communication between the parties relating to its subject matter +during the term of this Agreement. No modification of this Agreement will +be binding, unless in writing and signed by an authorized representative +of each party. + +Please contact Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, +California 95054 if you have questions. diff --git a/j3d-core/release-info/fcs-1_4_0/README-distribution.txt b/j3d-core/release-info/fcs-1_4_0/README-distribution.txt new file mode 100644 index 0000000..2a6b3ce --- /dev/null +++ b/j3d-core/release-info/fcs-1_4_0/README-distribution.txt @@ -0,0 +1,39 @@ +DistributionREADME + +DISTRIBUTION BY DEVELOPERS. Subject to the terms and conditions of +the Software License Agreement and the obligations, restrictions, and +exceptions set forth below, You may reproduce and distribute the Software +(and also portions of Software identified below as Redistributable), +provided that: + +(a) you distribute the Software complete and unmodified and only bundled +as part of Your applets and applications ("Programs"), + +(b) your Programs add significant and primary functionality to the +Software + +(c) your Programs are only intended to run on Java-enabled general +purpose desktop computers and servers, + +(d) you distribute Software for the sole purpose of running your Programs, + +(e) you do not distribute additional software intended to replace any +component(s) of the Software, + +(f) you do not remove or alter any proprietary legends or notices +contained in or on the Software. + +(g) you only distribute the Software subject to a license agreement +that protects Sun's interests consistent with the terms contained in +this Agreement, and + +(h) you agree to defend and indemnify Sun and its licensors from and +against any damages, costs, liabilities, settlement amounts and/or +expenses (including attorneys' fees) incurred in connection with any +claim, lawsuit or action by any third party that arises or results from +the use or distribution of any and all Programs and/or Software. + +Redistributables: +JAVA 3D, VERSION 1.4.0 + + diff --git a/j3d-core/release-info/fcs-1_4_0/README-download.html b/j3d-core/release-info/fcs-1_4_0/README-download.html new file mode 100644 index 0000000..69c578a --- /dev/null +++ b/j3d-core/release-info/fcs-1_4_0/README-download.html @@ -0,0 +1,70 @@ + + + + + Java 3D 1.4.0 Installation Instructions + + +

Java 3DTM 1.4.0 Release

+

This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_4_0.txt +file. You +must only use this software in accordance with the terms under which +the +code is licensed.

+

Instructions for Installing Java 3D 1.4.0

+

The 1.4.0 version of the Java 3DTM +API runs on JDK version 1.4.2 and higher. It has been released for +the Solaris, Linux, and Windows operating +environments. See the release +notes +for more information.
+

+

Linux

+

This release of Java 3D runs on JDK version 1.4.2 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Linux/x86 platform and your JDK is +installed +in /usr/java/jdk1.5.0_06, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_06/jre
    +sh /path-to-download-files/java3d-1_4_0-linux-i586.bin
    +
+

You may need to be "root" to do this on Linux.
+

+

Solaris

+

This release of Java 3D runs on JDK version 1.4.2 and +higher (JDK 1.5.0 or higher for Solaris/x86). +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Solaris/x86 platform (including amd64) +and your JDK is +installed +in /usr/java/jdk1.5.0_06, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_06/jre
    +sh /path-to-download-files/java3d-1_4_0-solaris-x86.bin
    +
+

You may need to be "root" to do this on Solaris.
+

+

Windows

+

+This release of Java 3D runs on JDK version 1.4.2 and +higher. To install +this build, execute the binary installer that you downloaded, by +double-clicking on the java3d-1_4_0-windows-i586.exe icon.
+

+

Alternatively, you can download the java3d-1_4_0-windows-i586.zip +file and manually install +the +necessary files into your JRE. In this case, unzip the file, and follow +the instructions in the unzipped README.txt file.

+ + diff --git a/j3d-core/release-info/fcs-1_4_0/README-unzip.html b/j3d-core/release-info/fcs-1_4_0/README-unzip.html new file mode 100644 index 0000000..cadfa5f --- /dev/null +++ b/j3d-core/release-info/fcs-1_4_0/README-unzip.html @@ -0,0 +1,87 @@ + + + + + Java 3D 1.4.0 Installation Instructions + + +

Java 3DTM 1.4.0 Release

+

This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_4_0.txt +file. You +must only use this software in accordance with the terms under which +the +code is licensed.

+

Instructions for Unzipping Java 3D 1.4.0

+

The 1.4.0 version of the Java 3DTM +API for Windows/XP and Windows 2000 runs on JDK version 1.4.2 and +higher. See the release +notes +for more information.
+

+
+

NOTE: This zip +bundle is intended for expert users who do not want to use the +automated installer. Most users will want to download and install the +java3d-1_4_0-windows-i586.exe file instead.
+

+
+

To manually install this build, do the following:

+
    +
  1. Download java3d-1_4_0-windows-i586.zip to a temporary +directory, +for example, "c:\Temp"
  2. +
    +
  3. Unzip java3d-1_4_0-windows-i586.zip (using WinZip or a +similar +tool) into "c:\Temp". This will create a +"java3d-1_4_0-windows-i586" subdirectory in \Temp where the +downloaded files can be found. The file you need for manual +installation is "j3d-140-win.zip".
    +
    +
  4. +
  5. Unzip Java 3D 1.4.0 into your JRE as follows:
    +
    +
  6. +
      +
    • Locate your "JRE". The default location for the current release +is: +"c:\Program Files\Java\jre1.5.0_06"
    • +
      +
    • Unzip j3d-140-win.zip (found in +c:\Temp\java3d-1_4_0-windows-i586) +to the jre directory.
    • +
      +
    • Verify that the j3d*.jar and vecmath.jar files end up in: +"c:\Program Files\Java\jre1.5.0_06\lib\ext"
    • +
      +
    • Verify that the j3d*.dll files end up in: +"c:\Program Files\Java\jre1.5.0_06\bin"
    • +
    +
    +
  7. If you also installed the JDK, unzip Java 3D 1.4.0 into the +"jre" +directory of your JDK as follows:
  8. +
    +
      +
    • Locate the jre directory of your "JDK". The default location +for the +current release is: "c:\Program Files\Java\jdk1.5.0_06\jre"
    • +
      +
    • Unzip j3d-140-win.zip (found in +c:\Temp\java3d-1_4_0-windows-i586) +to the jre directory of the JDK.
    • +
      +
    • Verify that the j3d*.jar and vecmath.jar files end up in: +"c:\Program Files\Java\jdk1.5.0_06\jre\lib\ext"
    • +
      +
    • Verify that the j3d*.dll files end up in: +"c:\Program Files\Java\jdk1.5.0_06\jre\bin"
    • +
    +
+


+

+ + diff --git a/j3d-core/release-info/fcs-1_4_0/README.html b/j3d-core/release-info/fcs-1_4_0/README.html new file mode 100644 index 0000000..1a4a332 --- /dev/null +++ b/j3d-core/release-info/fcs-1_4_0/README.html @@ -0,0 +1,500 @@ + + + + + + Java 3D 1.4.0 Release Notes + + +

Java 3DTM 1.4.0 Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.4.0. +

+ +

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.4.0 version of the Java 3D API has been released +for +Solaris (both sparc and x86), Linux (both x86 and amd64), and Windows +(32-bit). +

+

Solaris/Sparc

+

+The 1.4.0 version of Java 3D for Solaris/SPARC requires the +following: +

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL support (e.g., XVR-1200)
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris/x86

+

+The 1.4.0 version of Java 3D for Solaris/x86 requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
    +
  • +
+

Linux
+

+

The 1.4.0 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.2 or later
    +
  • +
+

Windows
+

+

The 1.4.0 version of Java 3D for Windows 2000, and +Windows/XP (32-bit) +requires the following:
+

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.2 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
+

Changes Since 1.3.2

+

New Features

+

Thw following new features have been added to the 1.4 version of the +Java 3D API. Please refer to the API +documentation, or the JSR-926 +change log for more information.

+
    +
  • Programmable shader support
  • +
  • Changed default values for all read capability bits
  • +
  • Enhanced picking API
    +
  • +
  • Stencil buffer support
    +
  • +
  • New rendering attributes
  • +
  • Other minor features and API changes
    +
  • +
+

System Properties

+

The following system properties were added in Java 3D 1.4.0:
+

+
    +
  • j3d.shadingLanguage – sets the shading language to +use for programmable shaders. Supported values are: "GLSL" or "Cg". The +default value is "GLSL".
    +
  • +
  • j3d.simulatedMultiTexture – If this flag is set to +true, simulation of multi-texturing will be done on systems that don't +have sufficient texture units. The default value is false. This does +not work with programmable shading, and will not be supported in 1.5.0.
    +
  • +
+

Issues Fixed
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
17
+

+
DirectX GraphicsConfiguration Issue
67
+
Transparency mode update didn't +get reflected correctly
78
+

+
Rendering stops if there's an exception in the EventDispatch
100
+
Offscreen Capture crash JVM
109
+
Frame Delays in Mixed Mode +Rendering
116
+
Handling of picking on +OrientatedShape3D needs clarification
117
+
Texture subimage is not +optimized for large subimages
124
+
Improve picking performance / +reduce garbage generation
127
+
Geometry Picking fails when +Shapes use Color4
129
+
NPE when removing an opaque +object that used to be transparent
132
+
BufferedImage getData slow, +causing poor Yup perf with updateSubImage
133
+
NullPointerException, PickCanvas +with GEOMETRY_INTERSECT_INFO and BoundingPolytope
134
+
Canvas3D memory leak
135
+
Java3D 1.3.2+ using DirectX 9.0
137
+
Add new depthTestFunction +attribute
138
+
Add method to retrieve +tessellated geometry from 3D font
139
+
add other rasterOp modes.
140
+
Object Leak in PickResult
 141
+
DirectX 9.0c for Java3D 1.4, +including shaders
144
+
ExponentialFog blending factor +depends on canvas size
145
+
Add stencil buffer support
146
+
Additional blending functions in +TransparencyAttributes
163
+
Regression in view frustum +culling
164
+
Cannot load j3dcore-ogl-cg.dll +library in JRE bin directory
167
+
Transform3D reports matrix with +NaN to be affine
169
+
TextureLoader should throw an +exception instead of printing cryptic message to System.err
170
+
TextureLoader should throw +exception when loading image
175
+
OffScreenRendering: Issue with +Updating Texture Size from Behavior
+
181
+
Performance regression: +j3d.optimizeForSpace=false ignored for some geometry
182
+
ShaderProgram not implemented +for immediate mode rendering
183
+
NPE if +CLOSEST_INTERSECTION_POINT is only flag
184
+
Illegal return value if flag +NODE is omitted
185
+
"Missing" essential methods in +IntersectionInfo
186
+
Using new Pick API with +PickSegment often returns null
187
+
NPE for new PickFast PickInfo +when getting geometries
195
+
Finish CgShader vertex +attributes native methods
196
+
Finish CgShader shader +attributes native methods
199
+
New Picking system only return 1 +result per geometry
201
+
D3D : +UnsatisfiedLinkError encountered with closing windows
202
+
Need to upgrade to latest +glext.h header file
203
+
System.currentTimeMillis is too +inaccurate on Windows for fine-grained timing
207
+
Viewer.java throws exception +with leading \n
208
+
Sound nodes cannot be placed +below Switch groups
212
+
PureImmediate test fails to +rotate
217
+
Compile j3d with +"-g:lines,source" to provide line numbers on stack traces
223
+
JVM crashes when execute +IndexedGeometryArray object with Texture coordinates
+

More Information
+

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/release-info/fcs-1_4_0/README.txt b/j3d-core/release-info/fcs-1_4_0/README.txt new file mode 100644 index 0000000..2ad46e2 --- /dev/null +++ b/j3d-core/release-info/fcs-1_4_0/README.txt @@ -0,0 +1,20 @@ +Java 3D(TM) 1.4.0 Release +------------------------- + +This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_4_0.txt file. You must only use this software in accordance with the terms under which the code is licensed. + + +Instructions for unzipping Java 3D 1.4.0 +---------------------------------------- + +After downloading and unzipping the java3d-1_4_0-windows-i586.zip file into a temporary directory, for example, "c:\Temp", you will see the following files in the java3d-1_4_0-windows-i586 directory: + + COPYRIGHT.txt Copyright notice + LICENSE-Java3D-v1_4_0.txt Software License Agreement + README-distribution.txt Requirements for distribution of Java 3D files + README-unzip.html Instructions for manually installing the release + README.txt README file (you are reading it now) + j3d-140-win.zip Zip file containing the files to be installed + +To manually install Java 3D, open README-unzip.html in your browser and follow the instructions. + diff --git a/j3d-core/release-info/fcs-1_5_0/0-USAGE.txt b/j3d-core/release-info/fcs-1_5_0/0-USAGE.txt new file mode 100644 index 0000000..52872b5 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_0/0-USAGE.txt @@ -0,0 +1,37 @@ +I. Files for Windows Installer + + README.html : + Modified RELEASE NOTES (with link to install instructions removed) + used as README file for Windows installer + + LICENSE-*.rtf : + rtf version of license used for Windows installer + +II. Files for Unix Installers, Zip Bundles, and Download page + + LICENSE-*.txt : + text version of license used for the zip bundles, the Unix + installers, and in download directory (and pointed to by our + java.net download page) + +III. Files for Zip Bundles + + README.txt : + README file that is included with the zip bundles; contains terms + of use, pointer to LICENSE-*.txt, pointer to README-unzip.html, + and MANIFEST of files in bundle + + README-unzip.html : + README file that is included with the zip bundles; contains + pointer to LICENSE-*.txt plus instructions for manually unzipping + the zip bundle. + + README-distribution.txt : + Legal README file that is included with the zip bundles + +IV. Files for Download page + + README-download.html : + README file used in download directory (and pointed to by our + java.net download page); includes pointer to LICENSE-*.txt plus + HOW_TO_INSTALL.html diff --git a/j3d-core/release-info/fcs-1_5_0/LICENSE-Java3D-v1_5_0.rtf b/j3d-core/release-info/fcs-1_5_0/LICENSE-Java3D-v1_5_0.rtf new file mode 100644 index 0000000..eeba280 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_0/LICENSE-Java3D-v1_5_0.rtf @@ -0,0 +1,177 @@ +{\rtf1\ansi\deff0\adeflang1025 +{\fonttbl{\f0\froman\fprq2\fcharset0 Thorndale{\*\falt Times New Roman};}{\f1\froman\fprq2\fcharset0 Thorndale{\*\falt Times New Roman};}{\f2\fswiss\fprq2\fcharset0 Albany{\*\falt Arial};}{\f3\fmodern\fprq1\fcharset0 Cumberland{\*\falt Courier New};}{\f4\fnil\fprq2\fcharset0 Andale Sans UI{\*\falt Arial Unicode MS};}{\f5\fnil\fprq2\fcharset0 Mincho{\*\falt msmincho};}{\f6\fnil\fprq2\fcharset0 Lucidasans;}{\f7\fnil\fprq0\fcharset0 Lucidasans;}} +{\colortbl;\red0\green0\blue0;\red128\green128\blue128;} +{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\snext1 Normal;} +{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\afs28\lang255\ltrch\dbch\af5\langfe255\hich\f2\fs28\lang1033\loch\f2\fs28\lang1033\sbasedon1\snext3 Heading;} +{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext3 Body Text;} +{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af7\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon3\snext4 List;} +{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af7\afs24\lang255\ai\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\i\loch\f0\fs24\lang1033\i\sbasedon1\snext5 caption;} +{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af7\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext6 Index;} +{\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033\sbasedon1\snext7 Preformatted Text;} +} +{\info{\creatim\yr2006\mo11\dy27\hr14\min13}{\revtim\yr1601\mo1\dy1\hr0\min0}{\printim\yr1601\mo1\dy1\hr0\min0}{\comment StarWriter}{\vern6800}}\deftab709 +{\*\pgdsctbl +{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Standard;}} +\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc +\pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Sun Microsystems, Inc. ("Sun") ENTITLEMENT for SOFTWARE} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Licensee/Company: Entity receiving Software.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Effective Date: Date of delivery of the Software to You.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Software: JAVA 3D, VERSION 1.5.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 License Term: Perpetual (subject to termination under the SLA).} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Licensed Unit: Software Copy.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Licensed unit Count: Unlimited.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Permitted Uses:} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 1. You may reproduce and use the Software for Your own Individual, Commercial, and Research and Instructional Use for the purposes of designing, developing, testing, and running Your applets and applications("Programs").} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 2. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the Software's documentation, You may reproduce and distribute portions of Software identified as a redistributable in the documentation ("Redistributable +"), provided that:} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (a) you distribute Redistributable complete and unmodified and only bundled as part of Your Programs,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (b) your Programs add significant and primary functionality to the Redistributable,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (c) you distribute Redistributable for the sole purpose of running your Programs,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (d) you do not distribute additional software intended to replace any component(s) of the Redistributable,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (e) you do not remove or alter any proprietary legends or notices contained in or on the Redistributable.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (f) you only distribute the Redistributable subject to a license agreement that protects Sun's interests consistent with the terms contained in this Agreement, and} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (g) you agree to defend and indemnify Sun and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that ar +ises or results from the use or distribution of any and all Programs and/or Redistributable.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 3. Java Technology Restrictions. You may not create, modify, or change the behavior of, or authorize your licensees to create, modify, or change the behavior of, classes, interfaces, or subpackages that are in any way identified as "java", "javax", "sun" +or similar convention as specified by Sun in any naming convention designation.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 SOFTWARE LICENSE AGREEMENT} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 READ THE TERMS OF THIS AGREEMENT ("AGREEMENT") CAREFULLY BEFORE OPENING SOFTWARE MEDIA PACKAGE. BY OPENING SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING SOFTWARE ELECTRONICALLY, INDICATE YOUR ACCEPTANCE OF THESE TER +MS BY SELECTING THE "ACCEPT" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF PURCHASE FOR A REFUND OR, IF SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT THE "DE +CLINE" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU HAVE SEPARATELY AGREED TO LICENSE TERMS ("MASTER TERMS") FOR YOUR LICENSE TO THIS SOFTWARE, THEN SECTIONS 1-6 OF THIS AGREEMENT ("SUPPLEMENTAL LICENSE TERMS") SHALL SUPPLEMENT AND SUPERSEDE + THE MASTER TERMS IN RELATION TO THIS SOFTWARE.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 1. Definitions.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (a) "Entitlement" means the collective set of applicable documents authorized by Sun evidencing your obligation to pay associated fees (if any) for the license, associated Services, and the authorized scope of use of Software under this Agreement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (b) "Licensed Unit" means the unit of measure by which your use of Software and/or Service is licensed, as described in your Entitlement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (c) "Permitted Use" means the licensed Software use(s) authorized in this Agreement as specified in your Entitlement. The Permitted Use for any bundled Sun software not specified in your Entitlement will be evaluation use as provided in Section 3.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (d) "Service" means the service(s) that Sun or its delegate will provide, if any, as selected in your Entitlement and as further described in the applicable service listings at www.sun.com/service/servicelist.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (e) "Software" means the Sun software described in your Entitlement. Also, certain software may be included for evaluation use under Section 3.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (f) "You" and "Your" means the individual or legal entity specified in the Entitlement, or for evaluation purposes, the entity performing the evaluation.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 2. License Grant and Entitlement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Subject to the terms of your Entitlement, Sun grants you a nonexclusive, nontransferable limited license to use Software for its Permitted Use for the license term. Your Entitlement will specify (a) Software licensed, (b) the Permitted Use, (c) the license + term, and (d) the Licensed Units.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Additionally, if your Entitlement includes Services, then it will also specify the (e) Service and (f) service term.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 If your rights to Software or Services are limited in duration and the date such rights begin is other than the purchase date, your Entitlement will provide that beginning date(s).} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 The Entitlement may be delivered to you in various ways depending on the manner in which you obtain Software and Services, for example, the Entitlement may be provided in your receipt, invoice or your contract with Sun or authorized Sun reseller. It may al +so be in electronic format if you download Software.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 3. Permitted Use.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 As selected in your Entitlement, one or more of the following Permitted Uses will apply to your use of Software. Unless you have an Entitlement that expressly permits it, you may not use Software for any of the other Permitted Uses. If you don't have an En +titlement, or if your Entitlement doesn't cover additional software delivered to you, then such software is for your Evaluation Use.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (a) Evaluation Use. You may evaluate Software internally for a period of 90 days from your first use.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (b) Research and Instructional Use. You may use Software internally to design, develop and test, and also to provide instruction on such uses.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (c) Individual Use. You may use Software internally for personal, individual use.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (d) Commercial Use. You may use Software internally for your own commercial purposes.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (e) Service Provider Use. You may make Software functionality accessible (but not by providing Software itself or through outsourcing services) to your end users in an extranet deployment, but not to your affiliated companies or to government agencies.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 4. Licensed Units.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Your Permitted Use is limited to the number of Licensed Units stated in your Entitlement. If you require additional Licensed Units, you will need additional Entitlement(s).} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 5. Restrictions.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (a) The copies of Software provided to you under this Agreement is licensed, not sold, to you by Sun. Sun reserves all rights not expressly granted. (b) You may make a single archival copy of Software, but otherwise may not copy, modify, or distribute Soft +ware. However if the Sun documentation accompanying Software lists specific portions of Software, such as header files, class libraries, reference source code, and/or redistributable files, that may be handled differently, you may do so only as provided in + the Sun documentation. (c) You may not rent, lease, lend or encumber Software. (d) Unless enforcement is prohibited by applicable law, you may not decompile, or reverse engineer Software. (e) The terms and conditions of this Agreement will apply to any So +ftware updates, provided to you at Sun's discretion, that replace and/or supplement the original Software, unless such update contains a separate license. (f) You may not publish or provide the results of any benchmark or comparison tests run on Software t +o any third party without the prior written consent of Sun. (g) Software is confidential and copyrighted. (h) Unless otherwise specified, if Software is delivered with embedded or bundled software that enables functionality of Software, you may not use suc +h software on a stand-alone basis or use any portion of such software to interoperate with any program(s) other than Software. (i) Software may contain programs that perform automated collection of system data and/or automated software updating services. S +ystem data collected through such programs may be used by Sun, its subcontractors, and its service delivery partners for the purpose of providing you with remote system services and/or improving Sun's software and systems. (j) Software is not designed, lic +ensed or intended for use in the design, construction, operation or maintenance of any nuclear facility and Sun and its licensors disclaim any express or implied warranty of fitness for such uses. (k) No right, title or interest in or to any trademark, ser +vice mark, logo or trade name of Sun or its licensors is granted under this Agreement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 6. Java Compatibility and Open Source.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Software may contain Java technology. You may not create additional classes to, or modifications of, the Java technology, except under compatibility requirements available under a separate agreement available at www.java.net.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Sun supports and benefits from the global community of open source developers, and thanks the community for its important contributions and open standards-based technology, which Sun has adopted into many of its products.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Please note that portions of Software may be provided with notices and open source licenses from such communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may ha +ve under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this Agreement will apply to all Software in this distribution.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 7. Term and Termination.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 The license and service term are set forth in your Entitlement(s). Your rights under this Agreement will terminate immediately without notice from Sun if you materially breach it or take any action in derogation of Sun's and/or its licensors' rights to Sof +tware. Sun may terminate this Agreement should any Software become, or in Sun's reasonable opinion likely to become, the subject of a claim of intellectual property infringement or trade secret misappropriation. Upon termination, you will cease use of, and + destroy, Software and confirm compliance in writing to Sun. Sections 1, 5, 6, 7, and 9-15 will survive termination of the Agreement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 8. Limited Warranty.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Sun warrants to you that for a period of 90 days from the date of purchase, as evidenced by a copy of the receipt, the media on which Software is furnished (if any) will be free of defects in materials and workmanship under normal use. Except for the foreg +oing, Software is provided "AS IS". Your exclusive remedy and Sun's entire liability under this limited warranty will be at Sun's option to replace Software media or refund the fee paid for Software. Some states do not allow limitations on certain implied +warranties, so the above may not apply to you. This limited warranty gives you specific legal rights. You may have others, which vary from state to state.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 9. Disclaimer of Warranty.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE D +ISCLAIMERS ARE HELD TO BE LEGALLY INVALID.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 10. Limitation of Liability.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISIN +G OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, whether in contract, tort (including negligence), or otherwise, exceed the amount paid + by you for Software under this Agreement. The foregoing limitations will apply even if the above stated warranty fails of its essential purpose. Some states do not allow the exclusion of incidental or consequential damages, so some of the terms above may +not be applicable to you.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 11. Export Regulations.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 All Software, documents, technical data, and any other materials delivered under this Agreement are subject to U.S. export control laws and may be subject to export or import regulations in other countries. You agree to comply strictly with these laws and +regulations and acknowledge that you have the responsibility to obtain any licenses to export, re-export, or import as may be required after delivery to you.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 12. U.S. Government Restricted Rights.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 If Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government's rights in Software and accompanying documentation will be only as set forth in this Agreemen +t; this is in accordance with 48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions).} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 13. Governing Law.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Any action related to this Agreement will be governed by California law and controlling U.S. federal law. No choice of law rules of any jurisdiction will apply.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 14. Severability.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 If any provision of this Agreement is held to be unenforceable, this Agreement will remain in effect with the provision omitted, unless omission would frustrate the intent of the parties, in which case this Agreement will immediately terminate.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 15. Integration.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 This Agreement, including any terms contained in your Entitlement, is the entire agreement between you and Sun relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, representations and warrant +ies and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement. No modification of this Agreement will be binding, u +nless in writing and signed by an authorized representative of each party.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af6\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Please contact Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, California 95054 if you have questions.} +\par } diff --git a/j3d-core/release-info/fcs-1_5_0/LICENSE-Java3D-v1_5_0.txt b/j3d-core/release-info/fcs-1_5_0/LICENSE-Java3D-v1_5_0.txt new file mode 100644 index 0000000..79e021d --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_0/LICENSE-Java3D-v1_5_0.txt @@ -0,0 +1,297 @@ +Sun Microsystems, Inc. ("Sun") ENTITLEMENT for SOFTWARE + +Licensee/Company: Entity receiving Software. + +Effective Date: Date of delivery of the Software to You. + +Software: JAVA 3D, VERSION 1.5. + +License Term: Perpetual (subject to termination under the SLA). + +Licensed Unit: Software Copy. + +Licensed unit Count: Unlimited. + +Permitted Uses: + +1. You may reproduce and use the Software for Your own Individual, +Commercial, and Research and Instructional Use for the purposes +of designing, developing, testing, and running Your applets and +applications("Programs"). + +2. Subject to the terms and conditions of this Agreement and +restrictions and exceptions set forth in the Software's documentation, +You may reproduce and distribute portions of Software identified as a +redistributable in the documentation ("Redistributable"), provided that: + +(a) you distribute Redistributable complete and unmodified and only +bundled as part of Your Programs, + +(b) your Programs add significant and primary functionality to the +Redistributable, + +(c) you distribute Redistributable for the sole purpose of running +your Programs, + +(d) you do not distribute additional software intended to replace any +component(s) of the Redistributable, + +(e) you do not remove or alter any proprietary legends or notices +contained in or on the Redistributable. + +(f) you only distribute the Redistributable subject to a license agreement +that protects Sun's interests consistent with the terms contained in +this Agreement, and + +(g) you agree to defend and indemnify Sun and its licensors from and +against any damages, costs, liabilities, settlement amounts and/or +expenses (including attorneys' fees) incurred in connection with any +claim, lawsuit or action by any third party that arises or results from +the use or distribution of any and all Programs and/or Redistributable. + +3. Java Technology Restrictions. You may not create, modify, or change +the behavior of, or authorize your licensees to create, modify, or change +the behavior of, classes, interfaces, or subpackages that are in any way +identified as "java", "javax", "sun" or similar convention as specified +by Sun in any naming convention designation. + + +SOFTWARE LICENSE AGREEMENT + +READ THE TERMS OF THIS AGREEMENT ("AGREEMENT") CAREFULLY BEFORE OPENING +SOFTWARE MEDIA PACKAGE. BY OPENING SOFTWARE MEDIA PACKAGE, YOU AGREE TO +THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING SOFTWARE ELECTRONICALLY, +INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE "ACCEPT" (OR +EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO +ALL OF THE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF +PURCHASE FOR A REFUND OR, IF SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT +THE "DECLINE" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU +HAVE SEPARATELY AGREED TO LICENSE TERMS ("MASTER TERMS") FOR YOUR LICENSE +TO THIS SOFTWARE, THEN SECTIONS 1-6 OF THIS AGREEMENT ("SUPPLEMENTAL +LICENSE TERMS") SHALL SUPPLEMENT AND SUPERSEDE THE MASTER TERMS IN +RELATION TO THIS SOFTWARE. + +1. Definitions. + +(a) "Entitlement" means the collective set of applicable documents +authorized by Sun evidencing your obligation to pay associated fees (if +any) for the license, associated Services, and the authorized scope of +use of Software under this Agreement. + +(b) "Licensed Unit" means the unit of measure by which your use of +Software and/or Service is licensed, as described in your Entitlement. + +(c) "Permitted Use" means the licensed Software use(s) authorized in +this Agreement as specified in your Entitlement. The Permitted Use +for any bundled Sun software not specified in your Entitlement will be +evaluation use as provided in Section 3. + +(d) "Service" means the service(s) that Sun or its delegate will provide, +if any, as selected in your Entitlement and as further described in the +applicable service listings at www.sun.com/service/servicelist. + +(e) "Software" means the Sun software described in your Entitlement. Also, +certain software may be included for evaluation use under Section 3. + +(f) "You" and "Your" means the individual or legal entity specified +in the Entitlement, or for evaluation purposes, the entity performing +the evaluation. + +2. License Grant and Entitlement. + +Subject to the terms of your Entitlement, Sun grants you a nonexclusive, +nontransferable limited license to use Software for its Permitted Use for +the license term. Your Entitlement will specify (a) Software licensed, +(b) the Permitted Use, (c) the license term, and (d) the Licensed Units. + +Additionally, if your Entitlement includes Services, then it will also +specify the (e) Service and (f) service term. + +If your rights to Software or Services are limited in duration and the +date such rights begin is other than the purchase date, your Entitlement +will provide that beginning date(s). + +The Entitlement may be delivered to you in various ways depending on +the manner in which you obtain Software and Services, for example, the +Entitlement may be provided in your receipt, invoice or your contract +with Sun or authorized Sun reseller. It may also be in electronic format +if you download Software. + +3. Permitted Use. + +As selected in your Entitlement, one or more of the following Permitted +Uses will apply to your use of Software. Unless you have an Entitlement +that expressly permits it, you may not use Software for any of the other +Permitted Uses. If you don't have an Entitlement, or if your Entitlement +doesn't cover additional software delivered to you, then such software +is for your Evaluation Use. + +(a) Evaluation Use. You may evaluate Software internally for a period +of 90 days from your first use. + +(b) Research and Instructional Use. You may use Software internally to +design, develop and test, and also to provide instruction on such uses. + +(c) Individual Use. You may use Software internally for personal, +individual use. + +(d) Commercial Use. You may use Software internally for your own +commercial purposes. + +(e) Service Provider Use. You may make Software functionality accessible +(but not by providing Software itself or through outsourcing services) +to your end users in an extranet deployment, but not to your affiliated +companies or to government agencies. + +4. Licensed Units. + +Your Permitted Use is limited to the number of Licensed Units stated +in your Entitlement. If you require additional Licensed Units, you will +need additional Entitlement(s). + +5. Restrictions. + +(a) The copies of Software provided to you under this Agreement +is licensed, not sold, to you by Sun. Sun reserves all rights not +expressly granted. (b) You may make a single archival copy of Software, +but otherwise may not copy, modify, or distribute Software. However if +the Sun documentation accompanying Software lists specific portions of +Software, such as header files, class libraries, reference source code, +and/or redistributable files, that may be handled differently, you may +do so only as provided in the Sun documentation. (c) You may not rent, +lease, lend or encumber Software. (d) Unless enforcement is prohibited by +applicable law, you may not decompile, or reverse engineer Software. (e) +The terms and conditions of this Agreement will apply to any Software +updates, provided to you at Sun's discretion, that replace and/or +supplement the original Software, unless such update contains a separate +license. (f) You may not publish or provide the results of any benchmark +or comparison tests run on Software to any third party without the prior +written consent of Sun. (g) Software is confidential and copyrighted. (h) +Unless otherwise specified, if Software is delivered with embedded or +bundled software that enables functionality of Software, you may not +use such software on a stand-alone basis or use any portion of such +software to interoperate with any program(s) other than Software. (i) +Software may contain programs that perform automated collection of +system data and/or automated software updating services. System data +collected through such programs may be used by Sun, its subcontractors, +and its service delivery partners for the purpose of providing you with +remote system services and/or improving Sun's software and systems. (j) +Software is not designed, licensed or intended for use in the design, +construction, operation or maintenance of any nuclear facility and Sun +and its licensors disclaim any express or implied warranty of fitness +for such uses. (k) No right, title or interest in or to any trademark, +service mark, logo or trade name of Sun or its licensors is granted +under this Agreement. + +6. Java Compatibility and Open Source. + +Software may contain Java technology. You may not create additional +classes to, or modifications of, the Java technology, except under +compatibility requirements available under a separate agreement available +at www.java.net. + +Sun supports and benefits from the global community of open source +developers, and thanks the community for its important contributions +and open standards-based technology, which Sun has adopted into many of +its products. + +Please note that portions of Software may be provided with notices and +open source licenses from such communities and third parties that govern +the use of those portions, and any licenses granted hereunder do not alter +any rights and obligations you may have under such open source licenses, +however, the disclaimer of warranty and limitation of liability provisions +in this Agreement will apply to all Software in this distribution. + +7. Term and Termination. + +The license and service term are set forth in your Entitlement(s). Your +rights under this Agreement will terminate immediately without notice from +Sun if you materially breach it or take any action in derogation of Sun's +and/or its licensors' rights to Software. Sun may terminate this Agreement +should any Software become, or in Sun's reasonable opinion likely to +become, the subject of a claim of intellectual property infringement or +trade secret misappropriation. Upon termination, you will cease use of, +and destroy, Software and confirm compliance in writing to Sun. Sections +1, 5, 6, 7, and 9-15 will survive termination of the Agreement. + +8. Limited Warranty. + +Sun warrants to you that for a period of 90 days from the date of +purchase, as evidenced by a copy of the receipt, the media on which +Software is furnished (if any) will be free of defects in materials +and workmanship under normal use. Except for the foregoing, Software is +provided "AS IS". Your exclusive remedy and Sun's entire liability under +this limited warranty will be at Sun's option to replace Software media +or refund the fee paid for Software. Some states do not allow limitations +on certain implied warranties, so the above may not apply to you. This +limited warranty gives you specific legal rights. You may have others, +which vary from state to state. + +9. Disclaimer of Warranty. + +UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, +REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT +ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE DISCLAIMERS ARE HELD TO +BE LEGALLY INVALID. + +10. Limitation of Liability. + +TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS +BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS +OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO THE USE OF +OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, +whether in contract, tort (including negligence), or otherwise, exceed +the amount paid by you for Software under this Agreement. The foregoing +limitations will apply even if the above stated warranty fails of its +essential purpose. Some states do not allow the exclusion of incidental +or consequential damages, so some of the terms above may not be applicable +to you. + +11. Export Regulations. + +All Software, documents, technical data, and any other materials delivered +under this Agreement are subject to U.S. export control laws and may be +subject to export or import regulations in other countries. You agree +to comply strictly with these laws and regulations and acknowledge that +you have the responsibility to obtain any licenses to export, re-export, +or import as may be required after delivery to you. + +12. U.S. Government Restricted Rights. + +If Software is being acquired by or on behalf of the U.S. Government or +by a U.S. Government prime contractor or subcontractor (at any tier), +then the Government's rights in Software and accompanying documentation +will be only as set forth in this Agreement; this is in accordance with +48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) +acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions). + +13. Governing Law. + +Any action related to this Agreement will be governed by California +law and controlling U.S. federal law. No choice of law rules of any +jurisdiction will apply. + +14. Severability. + +If any provision of this Agreement is held to be unenforceable, this +Agreement will remain in effect with the provision omitted, unless +omission would frustrate the intent of the parties, in which case this +Agreement will immediately terminate. + +15. Integration. + +This Agreement, including any terms contained in your Entitlement, is the +entire agreement between you and Sun relating to its subject matter. It +supersedes all prior or contemporaneous oral or written communications, +proposals, representations and warranties and prevails over any +conflicting or additional terms of any quote, order, acknowledgment, or +other communication between the parties relating to its subject matter +during the term of this Agreement. No modification of this Agreement will +be binding, unless in writing and signed by an authorized representative +of each party. + +Please contact Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, +California 95054 if you have questions. diff --git a/j3d-core/release-info/fcs-1_5_0/README-distribution.txt b/j3d-core/release-info/fcs-1_5_0/README-distribution.txt new file mode 100644 index 0000000..5d6e982 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_0/README-distribution.txt @@ -0,0 +1,35 @@ +DistributionREADME + +DISTRIBUTION BY DEVELOPERS. Subject to the terms and conditions of the Software License Agreement and the obligations, restrictions, and exceptions set forth below, You may reproduce and distribute the portions of Software identified below ("each a Redistributable"), provided that You comply with the following (note that You may be entitled to reproduce and distribute other portions of the Software not defined here as a Redistributable under certain other licenses as described in the THIRDPARTYLICENSEREADME, if applicable) + +(a) You distribute the Software complete and unmodified and only bundled +as part of Your applets and applications ("Programs"), + +(b) Your Programs add significant and primary functionality to the +Software + +(c) Your Programs are only intended to run on Java-enabled general +purpose desktop computers and servers, + +(d) You distribute Software for the sole purpose of running Your Programs, + +(e) You do not distribute additional software intended to replace any +component(s) of the Software, + +(f) You do not remove or alter any proprietary legends or notices +contained in or on the Software. + +(g) You only distribute the Software subject to a license agreement +that protects Sun's interests consistent with the terms contained in +this Agreement, and + +(h) You agree to defend and indemnify Sun and its licensors from and +against any damages, costs, liabilities, settlement amounts and/or +expenses (including attorneys' fees) incurred in connection with any +claim, lawsuit or action by any third party that arises or results from +the use or distribution of any and all Programs and/or Software. + +Redistributables: +JAVA 3D, VERSION 1.5 + + diff --git a/j3d-core/release-info/fcs-1_5_0/README-download.html b/j3d-core/release-info/fcs-1_5_0/README-download.html new file mode 100644 index 0000000..bb44a7f --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_0/README-download.html @@ -0,0 +1,83 @@ + + + + + Java 3D 1.5.0 Installation Instructions + + +

Java 3DTM 1.5.0 Release

+

This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_5_0.txt +file. You +must only use this software in accordance with the terms under which +the +code is licensed.

+

Instructions for Installing Java 3D 1.5.0

+

The 1.5.0 version of the Java 3DTM +API runs on JDK version 1.5.0 and higher. It has been released for +the Solaris, Linux, Windows, and Mac OS X +operating +environments. See the release +notes +for more information.
+

+

Linux

+

This release of Java 3D runs on JDK version 1.5.0 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Linux/x86 platform and your JDK is +installed +in /usr/java/jdk1.5.0_08, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_08/jre
    +sh /path-to-download-files/java3d-1_5_0-linux-i586.bin
    +
+

You may need to be "root" to do this on Linux.
+

+

Solaris

+

This release of Java 3D runs on JDK version 1.5.0 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Solaris/x86 platform (including amd64) +and your JDK is +installed +in /usr/java/jdk1.5.0_08, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_08/jre
    +sh /path-to-download-files/java3d-1_5_0-solaris-x86.bin
    +
+

You may need to be "root" to do this on Solaris.
+

+

Windows

+

+This release of Java 3D runs on JDK version 1.5.0 and +higher. To install +this build, execute the binary installer that you downloaded, by +double-clicking on the java3d-1_5_0-windows-i586.exe (or +java3d-1_5_0-windows-amd64.exe) icon.
+

+

Alternatively, you can download the +java3d-1_5_0-windows-i586.zip +file and manually install +the +necessary files into your JRE. In this case, unzip the file, and follow +the instructions in the unzipped README.txt file.
+

+

Mac OS X
+

+No installer is currently available for the Mac OS X operating +environment. You will need to download the +java3d-1_5_0-macosx.zip +file and manually install +the +necessary files into your JRE. After you unzip this file, follow +the instructions in the unzipped README.txt file. + + diff --git a/j3d-core/release-info/fcs-1_5_0/README-unzip.html b/j3d-core/release-info/fcs-1_5_0/README-unzip.html new file mode 100644 index 0000000..be3b583 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_0/README-unzip.html @@ -0,0 +1,134 @@ + + + + + Java 3D 1.5.0 Installation Instructions + + +

Java 3DTM 1.5.0 Release

+

This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_5_0.txt +file. You +must only use this software in accordance with the terms under which +the +code is licensed.

+

Instructions for Unzipping Java 3D 1.5.0 Release

+The 1.5.0 version of the +Java 3DTM +API runs on JDK version 1.5.0 and higher. It has been released for +the Solaris, Linux, Windows, and Mac OS X +operating +environments.
+
+

Windows

+

The 1.5.0 version of the Java 3DTM +API for Windows/XP and Windows 2000 runs on JDK version 1.5.0 and +higher.
+

+
+

NOTE: This zip +bundle is intended for expert users who do not want to use the +automated installer. Most users will want to download and install the +java3d-1_5_0-windows-i586.exe file instead.
+

+
+

To manually install this build, do the following: +

+
    +
  1. Download java3d-1_5_0-XXX.zip to a temporary +directory, +for example, "c:\Temp"
  2. +
    +
  3. Unzip java3d-1_5_0-XXX.zip (using WinZip or a +similar +tool) into "c:\Temp". This will create a +"java3d-1_5_0-XXX" subdirectory in \Temp where the +downloaded files can be found. The file you need for manual +installation is "j3d-jre.zip".
    +
    +
  4. +
  5. Unzip Java 3D 1.5.0 into your JRE as follows:
    +
    +
  6. +
      +
    • Locate your "JRE". The default location for the current release +is: +"c:\Program Files\Java\jre1.5.0_08"
    • +
      +
    • Unzip j3d-jre.zip (found in +c:\Temp\java3d-1_5_0-XXX) +to the jre directory.
    • +
      +
    • Verify that the j3dcore.jar, j3dutils.jar, and vecmath.jar +files end up in: +"c:\Program Files\Java\jre1.5.0_08\lib\ext"
    • +
      +
    • Verify that the j3d*.dll files end up in: +"c:\Program Files\Java\jre1.5.0_08\bin"
    • +
    +
    +
  7. If you also installed the JDK, unzip Java 3D 1.5.0 into the +"jre" +directory of your JDK as follows:
  8. +
    +
      +
    • Locate the jre directory of your "JDK". The default location +for the +current release is: "c:\Program Files\Java\jdk1.5.0_08\jre"
    • +
      +
    • Unzip j3d-jre.zip (found in +c:\Temp\java3d-1_5_0-XXX) +to the jre directory of the JDK.
    • +
      +
    • Verify that the j3dcore.jar, j3dutils.jar, and vecmath.jar +files end up in: +"c:\Program Files\Java\jdk1.5.0_08\jre\lib\ext"
    • +
      +
    • Verify that the j3d*.dll files end up in: +"c:\Program Files\Java\jdk1.5.0_08\jre\bin"
    • +
    +
+

Linux, +Solaris, Mac OS X
+

+

The 1.5.0 version of the Java 3DTM +API for Linux or Solaris runs on JDK version 1.5.0 and +higher. To manually install this build, do the following:

+
    +
  1. Download java3d-1_5_0-XXX.zip to a temporary +directory, +for example, "/tmp"
  2. +
    +
  3. Unzip java3d-1_5_0-XXX.zip into "/tmp" as follows:
    +
    +
      + cd /tmp
      + unzip java3d-1_5_0-*.zip
      +
    +
    +This will create a +"java3d-1_5_0-XXX" subdirectory in /tmp where the +downloaded files can be found. The file you need for manual +installation is "j3d-jre.zip".
    +
    +
  4. +
  5. Unzip Java 3D 1.5.0 into the +"jre" +directory of your JDK. For example, if your JDK is in +"/usr/java/jdk1.5.0_08/jre", you would do the following:
    +
    +
      + cd /usr/java/jdk1.5.0_08/jre
      + unzip /tmp/java3d-1_5_0-*/j3d-jre.zip
      +
    +
    +Verify that the j3dcore.jar, j3dutils.jar, and vecmath.jar files end up +in +"/usr/java/jdk1.5.0_08/jre/lib/ext"
  6. +
+
+
+ + diff --git a/j3d-core/release-info/fcs-1_5_0/README.html b/j3d-core/release-info/fcs-1_5_0/README.html new file mode 100644 index 0000000..4ea4faf --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_0/README.html @@ -0,0 +1,806 @@ + + + + + + Java 3D 1.5.0 Release Notes + + +

Java 3DTM 1.5.0 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.0. +

+ +

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.0 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.0 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.0 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.0 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.0 version of Java 3D for Windows 2000, and +Windows/XP (x86 or amd64) +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
+

Mac OS X

+

The 1.5.0 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.0

+

New Features / Enhancements

+ +

Issues Fixed in 1.5.0
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
40  Transparency color not correct +on UCIO geometry and OffScreen canvas
75  Memory leak in SetLiveState when +branchGroup remove
84  Rendering pauses after Canvas3D +disposal until AWT event
85  Optimize the downloading of ARGB +textures
92  ImageComponent2D.setSubImage() +uses incorrect image sizes
93  ImageComponent2D.setSubImage() +does not correctly update the display
113  NPE in updateAlphaInVertexData +on multiple screens
121  Stop using finalize() to clean +up state
123  Reduce or eliminate use of +memory free lists
131  Lightweight Canvas3D
147  Need Windows/amd64 port of Java +3D
152  NPE in updateNodeComponent
160  AlternateAppearance behaves +defferently in J3D 1.3.2 comparing to J3D 1.3.1
162  Textures are randomly incorrect +in multi-screen mode with LG3D
172  Texture.setImage fails to check +ImageComponent sizes when not live
180  Frame-dependent Large Texture +Updates leads to OOM Exception
194  Provide NIOBuffer texture +components
198  Need more shader example programs
209  PolygonAttributes.isCompiled() +returns false after the scenegraph's BranchGroup is compiled.
216  J3DTimer should use +clock_gettime on Linux
219  Add support for Non Power of Two +textures
220  Matrix3d.set(AxisAngle4d) sets +incorrectly if axis vector not normalized
221  UnsatisfiedLinkError if shading +language set to Cg on d3d
224  NPE While Toggling Visibility
225  BY_REF Support for +CoordinateIndices To Reduce Memory Bloat
227  Serialization problem with +vecmath
229  Need to implement JOGL renderer
235  Null Pointer in AttributeBin
238  Exception in thread +J3D-MasterControl-1 when setting TextureUnitState to 0-length array
240  Canvas3D.queryProperties reports +stencil available even when it is not
241  Texture3D by Reference Fails
244  ClassCastException in +Group.setChild
245  Problem with +ALLOW_RENDERING_ATTRIBUTES_WRITE in Appearance
246  Move compressed geometry code +from core to utils
247  SHADER_ATTRIBUTE_TYPE_ERROR is +fired when ShaderAttributeArray is used (OpenGL and GLSL shaders used)
248  Wrong spec. on the setFlags() +method of com.sun.j3d.utils.pickfast.PickTool
249  NullpointerException in +MasterControlThread when adding a Light
251  Typo, in spec. PickTool.PickAny +and PickTool.PickClosest return is wrong
252  Offscreen Canvas3D/Screen3D +error reporting (pbuffer allocation)
253  Transform3D's incorrectly +identified as Affine
260  Obsolete graphics library +version kills renderer thread, cannot be detected by app
264  Behaviors that throw an Error +cause the BehaviorScheduler to die
266  Canvas3D should throw NPE by +default for null graphicsConfig
267  TextureLoader should autodetect +alpha and colours
268  Replace native +getNumberOfProcessor() with pure Java equiv?
269  GLSL on nVidia cards: Confict of +a builtin vertex attribute (named gl_Normal) and a bound generic vertex +attribute
275  sleep for +setMinimumFrameCycleTime should not hold lock
279  Intermittent hang in +MasterControl while running lg3d
283  Add Eclipse plugin defs to +manifest
288  Objects in RenderBin free lists +keep reference to user data
295  Texture3D throws +ArrayIndexOutOfBoundsException when scaleImage
308  WakeupOnElapsedTime occasionally +doesn't wake up on elapsed time
311  Broken build for linux on ppc.
312  Exception while detaching +ModelClip from ViewSpecificGroup
313  Geometry Stress Test results in +OOM Error
318  Cannot build on Itanium Linux
320  Shader Appearance update is +asynchronous to transform update
321  bug in +vecmath.Matrix3d.set(AxisAngle a1)
323  Deprecate optional detail +texture functionality
324  Lockup Java3D program and throw +exception using JOGL renderer
325  This Tuple4d is epsilonEquals to +all others: (NaN, NaN, NaN, NaN)
326  PrintCanvas3D on JOGL pipeline +crashes on Linux and Solaris
327  javadoc for VIew class doesn't +list correct clip policy defaults
328  JOGL pipeline : Geometry fails +to render in Cosmic Birdie
331  Add .cvsignore file to root of +vecmath.
336  Unable to redraw when resizing +using JOGL pipeline
338  Bug in glPushAttrib usage in +NativePipeline
339  Java crashes when using GLSL +shaders
340  Resource leak in +setOffScreenBuffer, NPE in JOGL pipeline
341  Initializing audio device using +Webstart throws ClassNotFoundException
342  Raster.setDstOffset() set the +destination pixel offset in opposite direction
344  Too much time to load image as +Texture
349  OffScreen Canvas3D needlessly +forces power-of-two for its buffer
351  Need a new mechanism to free D3D +surface
352  VC compiler generates warning on +Windows AMD64 build
353  GeometryArray Memory Leak
355  IndexedXXXStripArray throws NPE +with ByRef Indices
356  Exception in RenderBin when +removing a Shape3D with no geometry
358  Document that OGL 1.2 is +supported, but at reduced functionality
360  SceneGraphStreamWriter.writeBranchGraph +throws exception
366  Raster appears without image on +systems without NPOT support
367  Clip throws NPE in case of +region = null in a live scene
368  Background texture doesn't work +on system with no NPOT support
370  Deadlock when calling +Raster.setimage from user thread
371  Poor raster quality for systems +that don't support NPOT textures
372  ImageComponent.set(BufferedImage) +ignored when used by Raster
373  ImageComponent.set(BufferedImage) +ignored when used by Background
374  Exception when calling +Background.setImage on live scene graph
379  Needs NPOT support documented in +Texture, Texture3D and TextureCubeMap
380  NPE when uncheck Show Color +Texture in Dot3 demo
383  JCanvas3D's offscreen Canvas3D +is inverted.
392  Texture loading regression for +optimized RGB PNG files
393  TextureLoader regression on +BufferedImage.TYPE_BYTE_INDEXED
395  JCanvas3D / JOGL: Program freezes
400  Lighting differs with various +renderers
403  AssertionError while changing +(offscreen) Texture size
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac +OS X (x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and install it into the JRE along with the Java 3D jar files (or +include it in your PATH/CLASSPATH).
+

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/release-info/fcs-1_5_0/README.txt b/j3d-core/release-info/fcs-1_5_0/README.txt new file mode 100644 index 0000000..1c970c4 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_0/README.txt @@ -0,0 +1,20 @@ +Java 3D(TM) 1.5.0 Release +------------------------- + +This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_5_0.txt file. You must only use this software in accordance with the terms under which the code is licensed. + + +Instructions for unzipping Java 3D 1.5.0 +---------------------------------------- + +After downloading and unzipping the java3d-1_5_0-XXX.zip file into a temporary directory, for example, "c:\Temp", you will see the following files in the java3d-1_5_0-XXX directory: + + COPYRIGHT.txt Copyright notice + LICENSE-Java3D-v1_5_0.txt Software License Agreement + README-distribution.txt Requirements for distribution of Java 3D files + README-unzip.html Instructions for manually installing the release + README.txt README file (you are reading it now) + j3d-jre.zip Zip file containing the files to be installed + +To manually install Java 3D, open README-unzip.html in your browser and follow the instructions. + diff --git a/j3d-core/release-info/fcs-1_5_1/0-USAGE.txt b/j3d-core/release-info/fcs-1_5_1/0-USAGE.txt new file mode 100644 index 0000000..52872b5 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_1/0-USAGE.txt @@ -0,0 +1,37 @@ +I. Files for Windows Installer + + README.html : + Modified RELEASE NOTES (with link to install instructions removed) + used as README file for Windows installer + + LICENSE-*.rtf : + rtf version of license used for Windows installer + +II. Files for Unix Installers, Zip Bundles, and Download page + + LICENSE-*.txt : + text version of license used for the zip bundles, the Unix + installers, and in download directory (and pointed to by our + java.net download page) + +III. Files for Zip Bundles + + README.txt : + README file that is included with the zip bundles; contains terms + of use, pointer to LICENSE-*.txt, pointer to README-unzip.html, + and MANIFEST of files in bundle + + README-unzip.html : + README file that is included with the zip bundles; contains + pointer to LICENSE-*.txt plus instructions for manually unzipping + the zip bundle. + + README-distribution.txt : + Legal README file that is included with the zip bundles + +IV. Files for Download page + + README-download.html : + README file used in download directory (and pointed to by our + java.net download page); includes pointer to LICENSE-*.txt plus + HOW_TO_INSTALL.html diff --git a/j3d-core/release-info/fcs-1_5_1/LICENSE-Java3D-v1_5_1.rtf b/j3d-core/release-info/fcs-1_5_1/LICENSE-Java3D-v1_5_1.rtf new file mode 100644 index 0000000..017aa88 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_1/LICENSE-Java3D-v1_5_1.rtf @@ -0,0 +1,178 @@ +{\rtf1\ansi\deff0\adeflang1025 +{\fonttbl{\f0\froman\fprq2\fcharset0 Nimbus Roman No9 L{\*\falt Times New Roman};}{\f1\froman\fprq2\fcharset0 Nimbus Roman No9 L{\*\falt Times New Roman};}{\f2\fswiss\fprq2\fcharset0 Nimbus Sans L{\*\falt Arial};}{\f3\fmodern\fprq1\fcharset0 Nimbus Mono L{\*\falt Courier New};}{\f4\froman\fprq0\fcharset128 Times New Roman;}{\f5\fnil\fprq2\fcharset0 DejaVu Sans;}} +{\colortbl;\red0\green0\blue0;\red128\green128\blue128;} +{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\snext1 Normal;} +{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\afs28\lang255\ltrch\dbch\langfe255\hich\f2\fs28\lang1033\loch\f2\fs28\lang1033\sbasedon1\snext3 Heading;} +{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext3 Body Text;} +{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon3\snext4 List;} +{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ai\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\i\loch\f0\fs24\lang1033\i\sbasedon1\snext5 caption;} +{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext6 Index;} +{\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033\sbasedon1\snext7 Preformatted Text;} +} +{\info{\creatim\yr2007\mo6\dy25\hr13\min46}{\revtim\yr1601\mo1\dy1\hr0\min0}{\printim\yr1601\mo1\dy1\hr0\min0}{\comment StarWriter}{\vern6800}}\deftab709 +{\*\pgdsctbl +{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Standard;}} +\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc +\pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Sun Microsystems, Inc. ("Sun") ENTITLEMENT for SOFTWARE} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Licensee/Company: Entity receiving Software.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Effective Date: Date of delivery of the Software to You.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Software: JAVA 3D, VERSION 1.5.1.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 License Term: Perpetual (subject to termination under the SLA).} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Licensed Unit: Software Copy.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Licensed unit Count: Unlimited.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Permitted Uses:} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 1. You may reproduce and use the Software for Your own Individual, Commercial, and Research and Instructional Use for the purposes of designing, developing, testing, and running Your applets and applications("Programs").} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 2. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the Software's documentation, You may reproduce and distribute portions of Software identified as a redistributable in the documentation ("Redistributable +"), provided that:} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (a) you distribute Redistributable complete and unmodified and only bundled as part of Your Programs,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (b) your Programs add significant and primary functionality to the Redistributable,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (c) you distribute Redistributable for the sole purpose of running your Programs,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (d) you do not distribute additional software intended to replace any component(s) of the Redistributable,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (e) you do not remove or alter any proprietary legends or notices contained in or on the Redistributable.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (f) you only distribute the Redistributable subject to a license agreement that protects Sun's interests consistent with the terms contained in this Agreement, and} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (g) you agree to defend and indemnify Sun and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that ar +ises or results from the use or distribution of any and all Programs and/or Redistributable.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 3. Java Technology Restrictions. You may not create, modify, or change the behavior of, or authorize your licensees to create, modify, or change the behavior of, classes, interfaces, or subpackages that are in any way identified as "java", "javax", "sun" o +r similar convention as specified by Sun in any naming convention designation.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 SOFTWARE LICENSE AGREEMENT} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 READ THE TERMS OF THIS AGREEMENT ("AGREEMENT") CAREFULLY BEFORE OPENING SOFTWARE MEDIA PACKAGE. BY OPENING SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING SOFTWARE ELECTRONICALLY, INDICATE YOUR ACCEPTANCE OF THESE TER +MS BY SELECTING THE "ACCEPT" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF PURCHASE FOR A REFUND OR, IF SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT THE "DE +CLINE" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU HAVE SEPARATELY AGREED TO LICENSE TERMS ("MASTER TERMS") FOR YOUR LICENSE TO THIS SOFTWARE, THEN SECTIONS 1-6 OF THIS AGREEMENT ("SUPPLEMENTAL LICENSE TERMS") SHALL SUPPLEMENT AND SUPERSEDE + THE MASTER TERMS IN RELATION TO THIS SOFTWARE.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 1. Definitions.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (a) "Entitlement" means the collective set of applicable documents authorized by Sun evidencing your obligation to pay associated fees (if any) for the license, associated Services, and the authorized scope of use of Software under this Agreement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (b) "Licensed Unit" means the unit of measure by which your use of Software and/or Service is licensed, as described in your Entitlement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (c) "Permitted Use" means the licensed Software use(s) authorized in this Agreement as specified in your Entitlement. The Permitted Use for any bundled Sun software not specified in your Entitlement will be evaluation use as provided in Section 3.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (d) "Service" means the service(s) that Sun or its delegate will provide, if any, as selected in your Entitlement and as further described in the applicable service listings at www.sun.com/service/servicelist.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (e) "Software" means the Sun software described in your Entitlement. Also, certain software may be included for evaluation use under Section 3.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (f) "You" and "Your" means the individual or legal entity specified in the Entitlement, or for evaluation purposes, the entity performing the evaluation.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 2. License Grant and Entitlement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Subject to the terms of your Entitlement, Sun grants you a nonexclusive, nontransferable limited license to use Software for its Permitted Use for the license term. Your Entitlement will specify (a) Software licensed, (b) the Permitted Use, (c) the license + term, and (d) the Licensed Units.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Additionally, if your Entitlement includes Services, then it will also specify the (e) Service and (f) service term.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 If your rights to Software or Services are limited in duration and the date such rights begin is other than the purchase date, your Entitlement will provide that beginning date(s).} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 The Entitlement may be delivered to you in various ways depending on the manner in which you obtain Software and Services, for example, the Entitlement may be provided in your receipt, invoice or your contract with Sun or authorized Sun reseller. It may al +so be in electronic format if you download Software.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 3. Permitted Use.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 As selected in your Entitlement, one or more of the following Permitted Uses will apply to your use of Software. Unless you have an Entitlement that expressly permits it, you may not use Software for any of the other Permitted Uses. If you don't have an En +titlement, or if your Entitlement doesn't cover additional software delivered to you, then such software is for your Evaluation Use.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (a) Evaluation Use. You may evaluate Software internally for a period of 90 days from your first use.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (b) Research and Instructional Use. You may use Software internally to design, develop and test, and also to provide instruction on such uses.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (c) Individual Use. You may use Software internally for personal, individual use.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (d) Commercial Use. You may use Software internally for your own commercial purposes.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (e) Service Provider Use. You may make Software functionality accessible (but not by providing Software itself or through outsourcing services) to your end users in an extranet deployment, but not to your affiliated companies or to government agencies.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 4. Licensed Units.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Your Permitted Use is limited to the number of Licensed Units stated in your Entitlement. If you require additional Licensed Units, you will need additional Entitlement(s).} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 5. Restrictions.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 (a) The copies of Software provided to you under this Agreement is licensed, not sold, to you by Sun. Sun reserves all rights not expressly granted. (b) You may make a single archival copy of Software, but otherwise may not copy, modify, or distribute Soft +ware. However if the Sun documentation accompanying Software lists specific portions of Software, such as header files, class libraries, reference source code, and/or redistributable files, that may be handled differently, you may do so only as provided in + the Sun documentation. (c) You may not rent, lease, lend or encumber Software. (d) Unless enforcement is prohibited by applicable law, you may not decompile, or reverse engineer Software. (e) The terms and conditions of this Agreement will apply to any So +ftware updates, provided to you at Sun's discretion, that replace and/or supplement the original Software, unless such update contains a separate license. (f) You may not publish or provide the results of any benchmark or comparison tests run on Software t +o any third party without the prior written consent of Sun. (g) Software is confidential and copyrighted. (h) Unless otherwise specified, if Software is delivered with embedded or bundled software that enables functionality of Software, you may not use suc +h software on a stand-alone basis or use any portion of such software to interoperate with any program(s) other than Software. (i) Software may contain programs that perform automated collection of system data and/or automated software updating services. S +ystem data collected through such programs may be used by Sun, its subcontractors, and its service delivery partners for the purpose of providing you with remote system services and/or improving Sun's software and systems. (j) Software is not designed, lic +ensed or intended for use in the design, construction, operation or maintenance of any nuclear facility and Sun and its licensors disclaim any express or implied warranty of fitness for such uses. (k) No right, title or interest in or to any trademark, ser +vice mark, logo or trade name of Sun or its licensors is granted under this Agreement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 6. Java Compatibility and Open Source.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Software may contain Java technology. You may not create additional classes to, or modifications of, the Java technology, except under compatibility requirements available under a separate agreement available at www.java.net.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Sun supports and benefits from the global community of open source developers, and thanks the community for its important contributions and open standards-based technology, which Sun has adopted into many of its products.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Please note that portions of Software may be provided with notices and open source licenses from such communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may ha +ve under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this Agreement will apply to all Software in this distribution.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 7. Term and Termination.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 The license and service term are set forth in your Entitlement(s). Your rights under this Agreement will terminate immediately without notice from Sun if you materially breach it or take any action in derogation of Sun's and/or its licensors' rights to Sof +tware. Sun may terminate this Agreement should any Software become, or in Sun's reasonable opinion likely to become, the subject of a claim of intellectual property infringement or trade secret misappropriation. Upon termination, you will cease use of, and + destroy, Software and confirm compliance in writing to Sun. Sections 1, 5, 6, 7, and 9-15 will survive termination of the Agreement.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 8. Limited Warranty.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Sun warrants to you that for a period of 90 days from the date of purchase, as evidenced by a copy of the receipt, the media on which Software is furnished (if any) will be free of defects in materials and workmanship under normal use. Except for the foreg +oing, Software is provided "AS IS". Your exclusive remedy and Sun's entire liability under this limited warranty will be at Sun's option to replace Software media or refund the fee paid for Software. Some states do not allow limitations on certain implied +warranties, so the above may not apply to you. This limited warranty gives you specific legal rights. You may have others, which vary from state to state.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 9. Disclaimer of Warranty.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE D +ISCLAIMERS ARE HELD TO BE LEGALLY INVALID.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 10. Limitation of Liability.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISIN +G OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, whether in contract, tort (including negligence), or otherwise, exceed the amount paid + by you for Software under this Agreement. The foregoing limitations will apply even if the above stated warranty fails of its essential purpose. Some states do not allow the exclusion of incidental or consequential damages, so some of the terms above may +not be applicable to you.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 11. Export Regulations.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 All Software, documents, technical data, and any other materials delivered under this Agreement are subject to U.S. export control laws and may be subject to export or import regulations in other countries. You agree to comply strictly with these laws and +regulations and acknowledge that you have the responsibility to obtain any licenses to export, re-export, or import as may be required after delivery to you.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 12. U.S. Government Restricted Rights.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 If Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government's rights in Software and accompanying documentation will be only as set forth in this Agreemen +t; this is in accordance with 48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions).} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 13. Governing Law.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Any action related to this Agreement will be governed by California law and controlling U.S. federal law. No choice of law rules of any jurisdiction will apply.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 14. Severability.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 If any provision of this Agreement is held to be unenforceable, this Agreement will remain in effect with the provision omitted, unless omission would frustrate the intent of the parties, in which case this Agreement will immediately terminate.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 15. Integration.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 This Agreement, including any terms contained in your Entitlement, is the entire agreement between you and Sun relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, representations and warrant +ies and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement. No modification of this Agreement will be binding, u +nless in writing and signed by an authorized representative of each party.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af5\afs24\lang255\ltrch\dbch\af5\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 {\rtlch \ltrch\loch\f0\fs24\lang1033\i0\b0 Please contact Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, California 95054 if you have questions.} +\par } \ No newline at end of file diff --git a/j3d-core/release-info/fcs-1_5_1/LICENSE-Java3D-v1_5_1.txt b/j3d-core/release-info/fcs-1_5_1/LICENSE-Java3D-v1_5_1.txt new file mode 100644 index 0000000..f83f66f --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_1/LICENSE-Java3D-v1_5_1.txt @@ -0,0 +1,297 @@ +Sun Microsystems, Inc. ("Sun") ENTITLEMENT for SOFTWARE + +Licensee/Company: Entity receiving Software. + +Effective Date: Date of delivery of the Software to You. + +Software: JAVA 3D, VERSION 1.5.1. + +License Term: Perpetual (subject to termination under the SLA). + +Licensed Unit: Software Copy. + +Licensed unit Count: Unlimited. + +Permitted Uses: + +1. You may reproduce and use the Software for Your own Individual, +Commercial, and Research and Instructional Use for the purposes +of designing, developing, testing, and running Your applets and +applications("Programs"). + +2. Subject to the terms and conditions of this Agreement and +restrictions and exceptions set forth in the Software's documentation, +You may reproduce and distribute portions of Software identified as a +redistributable in the documentation ("Redistributable"), provided that: + +(a) you distribute Redistributable complete and unmodified and only +bundled as part of Your Programs, + +(b) your Programs add significant and primary functionality to the +Redistributable, + +(c) you distribute Redistributable for the sole purpose of running +your Programs, + +(d) you do not distribute additional software intended to replace any +component(s) of the Redistributable, + +(e) you do not remove or alter any proprietary legends or notices +contained in or on the Redistributable. + +(f) you only distribute the Redistributable subject to a license agreement +that protects Sun's interests consistent with the terms contained in +this Agreement, and + +(g) you agree to defend and indemnify Sun and its licensors from and +against any damages, costs, liabilities, settlement amounts and/or +expenses (including attorneys' fees) incurred in connection with any +claim, lawsuit or action by any third party that arises or results from +the use or distribution of any and all Programs and/or Redistributable. + +3. Java Technology Restrictions. You may not create, modify, or change +the behavior of, or authorize your licensees to create, modify, or change +the behavior of, classes, interfaces, or subpackages that are in any way +identified as "java", "javax", "sun" or similar convention as specified +by Sun in any naming convention designation. + + +SOFTWARE LICENSE AGREEMENT + +READ THE TERMS OF THIS AGREEMENT ("AGREEMENT") CAREFULLY BEFORE OPENING +SOFTWARE MEDIA PACKAGE. BY OPENING SOFTWARE MEDIA PACKAGE, YOU AGREE TO +THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING SOFTWARE ELECTRONICALLY, +INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE "ACCEPT" (OR +EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO +ALL OF THE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF +PURCHASE FOR A REFUND OR, IF SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT +THE "DECLINE" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU +HAVE SEPARATELY AGREED TO LICENSE TERMS ("MASTER TERMS") FOR YOUR LICENSE +TO THIS SOFTWARE, THEN SECTIONS 1-6 OF THIS AGREEMENT ("SUPPLEMENTAL +LICENSE TERMS") SHALL SUPPLEMENT AND SUPERSEDE THE MASTER TERMS IN +RELATION TO THIS SOFTWARE. + +1. Definitions. + +(a) "Entitlement" means the collective set of applicable documents +authorized by Sun evidencing your obligation to pay associated fees (if +any) for the license, associated Services, and the authorized scope of +use of Software under this Agreement. + +(b) "Licensed Unit" means the unit of measure by which your use of +Software and/or Service is licensed, as described in your Entitlement. + +(c) "Permitted Use" means the licensed Software use(s) authorized in +this Agreement as specified in your Entitlement. The Permitted Use +for any bundled Sun software not specified in your Entitlement will be +evaluation use as provided in Section 3. + +(d) "Service" means the service(s) that Sun or its delegate will provide, +if any, as selected in your Entitlement and as further described in the +applicable service listings at www.sun.com/service/servicelist. + +(e) "Software" means the Sun software described in your Entitlement. Also, +certain software may be included for evaluation use under Section 3. + +(f) "You" and "Your" means the individual or legal entity specified +in the Entitlement, or for evaluation purposes, the entity performing +the evaluation. + +2. License Grant and Entitlement. + +Subject to the terms of your Entitlement, Sun grants you a nonexclusive, +nontransferable limited license to use Software for its Permitted Use for +the license term. Your Entitlement will specify (a) Software licensed, +(b) the Permitted Use, (c) the license term, and (d) the Licensed Units. + +Additionally, if your Entitlement includes Services, then it will also +specify the (e) Service and (f) service term. + +If your rights to Software or Services are limited in duration and the +date such rights begin is other than the purchase date, your Entitlement +will provide that beginning date(s). + +The Entitlement may be delivered to you in various ways depending on +the manner in which you obtain Software and Services, for example, the +Entitlement may be provided in your receipt, invoice or your contract +with Sun or authorized Sun reseller. It may also be in electronic format +if you download Software. + +3. Permitted Use. + +As selected in your Entitlement, one or more of the following Permitted +Uses will apply to your use of Software. Unless you have an Entitlement +that expressly permits it, you may not use Software for any of the other +Permitted Uses. If you don't have an Entitlement, or if your Entitlement +doesn't cover additional software delivered to you, then such software +is for your Evaluation Use. + +(a) Evaluation Use. You may evaluate Software internally for a period +of 90 days from your first use. + +(b) Research and Instructional Use. You may use Software internally to +design, develop and test, and also to provide instruction on such uses. + +(c) Individual Use. You may use Software internally for personal, +individual use. + +(d) Commercial Use. You may use Software internally for your own +commercial purposes. + +(e) Service Provider Use. You may make Software functionality accessible +(but not by providing Software itself or through outsourcing services) +to your end users in an extranet deployment, but not to your affiliated +companies or to government agencies. + +4. Licensed Units. + +Your Permitted Use is limited to the number of Licensed Units stated +in your Entitlement. If you require additional Licensed Units, you will +need additional Entitlement(s). + +5. Restrictions. + +(a) The copies of Software provided to you under this Agreement +is licensed, not sold, to you by Sun. Sun reserves all rights not +expressly granted. (b) You may make a single archival copy of Software, +but otherwise may not copy, modify, or distribute Software. However if +the Sun documentation accompanying Software lists specific portions of +Software, such as header files, class libraries, reference source code, +and/or redistributable files, that may be handled differently, you may +do so only as provided in the Sun documentation. (c) You may not rent, +lease, lend or encumber Software. (d) Unless enforcement is prohibited by +applicable law, you may not decompile, or reverse engineer Software. (e) +The terms and conditions of this Agreement will apply to any Software +updates, provided to you at Sun's discretion, that replace and/or +supplement the original Software, unless such update contains a separate +license. (f) You may not publish or provide the results of any benchmark +or comparison tests run on Software to any third party without the prior +written consent of Sun. (g) Software is confidential and copyrighted. (h) +Unless otherwise specified, if Software is delivered with embedded or +bundled software that enables functionality of Software, you may not +use such software on a stand-alone basis or use any portion of such +software to interoperate with any program(s) other than Software. (i) +Software may contain programs that perform automated collection of +system data and/or automated software updating services. System data +collected through such programs may be used by Sun, its subcontractors, +and its service delivery partners for the purpose of providing you with +remote system services and/or improving Sun's software and systems. (j) +Software is not designed, licensed or intended for use in the design, +construction, operation or maintenance of any nuclear facility and Sun +and its licensors disclaim any express or implied warranty of fitness +for such uses. (k) No right, title or interest in or to any trademark, +service mark, logo or trade name of Sun or its licensors is granted +under this Agreement. + +6. Java Compatibility and Open Source. + +Software may contain Java technology. You may not create additional +classes to, or modifications of, the Java technology, except under +compatibility requirements available under a separate agreement available +at www.java.net. + +Sun supports and benefits from the global community of open source +developers, and thanks the community for its important contributions +and open standards-based technology, which Sun has adopted into many of +its products. + +Please note that portions of Software may be provided with notices and +open source licenses from such communities and third parties that govern +the use of those portions, and any licenses granted hereunder do not alter +any rights and obligations you may have under such open source licenses, +however, the disclaimer of warranty and limitation of liability provisions +in this Agreement will apply to all Software in this distribution. + +7. Term and Termination. + +The license and service term are set forth in your Entitlement(s). Your +rights under this Agreement will terminate immediately without notice from +Sun if you materially breach it or take any action in derogation of Sun's +and/or its licensors' rights to Software. Sun may terminate this Agreement +should any Software become, or in Sun's reasonable opinion likely to +become, the subject of a claim of intellectual property infringement or +trade secret misappropriation. Upon termination, you will cease use of, +and destroy, Software and confirm compliance in writing to Sun. Sections +1, 5, 6, 7, and 9-15 will survive termination of the Agreement. + +8. Limited Warranty. + +Sun warrants to you that for a period of 90 days from the date of +purchase, as evidenced by a copy of the receipt, the media on which +Software is furnished (if any) will be free of defects in materials +and workmanship under normal use. Except for the foregoing, Software is +provided "AS IS". Your exclusive remedy and Sun's entire liability under +this limited warranty will be at Sun's option to replace Software media +or refund the fee paid for Software. Some states do not allow limitations +on certain implied warranties, so the above may not apply to you. This +limited warranty gives you specific legal rights. You may have others, +which vary from state to state. + +9. Disclaimer of Warranty. + +UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, +REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT +ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE DISCLAIMERS ARE HELD TO +BE LEGALLY INVALID. + +10. Limitation of Liability. + +TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS +BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS +OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO THE USE OF +OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, +whether in contract, tort (including negligence), or otherwise, exceed +the amount paid by you for Software under this Agreement. The foregoing +limitations will apply even if the above stated warranty fails of its +essential purpose. Some states do not allow the exclusion of incidental +or consequential damages, so some of the terms above may not be applicable +to you. + +11. Export Regulations. + +All Software, documents, technical data, and any other materials delivered +under this Agreement are subject to U.S. export control laws and may be +subject to export or import regulations in other countries. You agree +to comply strictly with these laws and regulations and acknowledge that +you have the responsibility to obtain any licenses to export, re-export, +or import as may be required after delivery to you. + +12. U.S. Government Restricted Rights. + +If Software is being acquired by or on behalf of the U.S. Government or +by a U.S. Government prime contractor or subcontractor (at any tier), +then the Government's rights in Software and accompanying documentation +will be only as set forth in this Agreement; this is in accordance with +48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) +acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions). + +13. Governing Law. + +Any action related to this Agreement will be governed by California +law and controlling U.S. federal law. No choice of law rules of any +jurisdiction will apply. + +14. Severability. + +If any provision of this Agreement is held to be unenforceable, this +Agreement will remain in effect with the provision omitted, unless +omission would frustrate the intent of the parties, in which case this +Agreement will immediately terminate. + +15. Integration. + +This Agreement, including any terms contained in your Entitlement, is the +entire agreement between you and Sun relating to its subject matter. It +supersedes all prior or contemporaneous oral or written communications, +proposals, representations and warranties and prevails over any +conflicting or additional terms of any quote, order, acknowledgment, or +other communication between the parties relating to its subject matter +during the term of this Agreement. No modification of this Agreement will +be binding, unless in writing and signed by an authorized representative +of each party. + +Please contact Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, +California 95054 if you have questions. diff --git a/j3d-core/release-info/fcs-1_5_1/README-distribution.txt b/j3d-core/release-info/fcs-1_5_1/README-distribution.txt new file mode 100644 index 0000000..5b8d865 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_1/README-distribution.txt @@ -0,0 +1,41 @@ +DistributionREADME + +DISTRIBUTION BY DEVELOPERS. Subject to the terms and conditions of +the Software License Agreement and the obligations, restrictions, +and exceptions set forth below, You may reproduce and distribute +the portions of Software identified below ("each a Redistributable"), +provided that You comply with the following (note that You may be entitled +to reproduce and distribute other portions of the Software not defined +here as a Redistributable under certain other licenses as described in +the THIRDPARTYLICENSEREADME, if applicable). + +(a) You distribute the Software complete and unmodified and only bundled +as part of Your applets and applications ("Programs"), + +(b) Your Programs add significant and primary functionality to the +Software + +(c) Your Programs are only intended to run on Java-enabled general +purpose desktop computers and servers, + +(d) You distribute Software for the sole purpose of running Your Programs, + +(e) You do not distribute additional software intended to replace any +component(s) of the Software, + +(f) You do not remove or alter any proprietary legends or notices +contained in or on the Software, + +(g) You only distribute the Software subject to a license agreement +that protects Sun's interests consistent with the terms contained in +this Agreement, and + +(h) You agree to defend and indemnify Sun and its licensors from and +against any damages, costs, liabilities, settlement amounts and/or +expenses (including attorneys' fees) incurred in connection with any +claim, lawsuit or action by any third party that arises or results from +the use or distribution of any and all Programs and/or Software. + +Redistributable: + +JAVA 3D, VERSION 1.5.1 diff --git a/j3d-core/release-info/fcs-1_5_1/README-download.html b/j3d-core/release-info/fcs-1_5_1/README-download.html new file mode 100644 index 0000000..437ba5f --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_1/README-download.html @@ -0,0 +1,148 @@ + + + + + + + + + + Java 3D 1.5.1 Installation Instructions + + + + + + +

Java 3DTM +1.5.1 Release

+ + +

This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_5_1.txt +file. You +must only use this software in accordance with the terms under which +the +code is licensed.

+ + +

Instructions for Installing Java 3D 1.5.1

+ + +

The 1.5.1 version of the Java 3DTM +API runs on JDK version 1.5.0 and higher. It has been released for +the Solaris, Linux, Windows, +and Mac OS X +operating +environments. See the release +notes +for more information.
+ + +

+ + +

Linux

+ + +

This release of Java 3D runs on JDK version 1.5.0 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Linux/x86 platform and your JDK is +installed +in /usr/java/jdk1.6.0_01, you would install Java 3D as +follows: +

+ + +
    + + +cd /usr/java/jdk1.6.0_01/jre
    + + +sh /path-to-download-files/java3d-1_5_1-linux-i586.bin
    + + +
+ + +

You may need to be "root" to do this on Linux.
+ + +

+ + +

Solaris

+ + +

This release of Java 3D runs on JDK version 1.5.0 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Solaris/x86 platform (including amd64) +and your JDK is +installed +in /usr/java/jdk1.6.0_01, you would install Java 3D as +follows: +

+ + +
    + + +cd /usr/java/jdk1.6.0_01/jre
    + + +sh /path-to-download-files/java3d-1_5_1-solaris-x86.bin
    + + +
+ + +

You may need to be "root" to do this on Solaris.
+ + +

+ + +

Windows

+ + +

+This release of Java 3D runs on JDK version 1.5.0 and +higher. To install +this build, execute the binary installer that you downloaded, by +double-clicking on the java3d-1_5_1-windows-i586.exe (or +java3d-1_5_1-windows-amd64.exe) icon.
+ + +

+ + +

Alternatively, you can download the +java3d-1_5_1-windows-i586.zip +file and manually install +the +necessary files into your JRE. In this case, unzip the file, and follow +the instructions in the unzipped README.txt file.
+ + +

+ + +

Mac OS X
+ + +

+ + +No installer is currently available for the Mac OS X operating +environment. You will need to download the +java3d-1_5_1-macosx.zip +file and manually install +the +necessary files into your JRE. After you unzip this file, follow +the instructions in the unzipped README.txt file. + + diff --git a/j3d-core/release-info/fcs-1_5_1/README-unzip.html b/j3d-core/release-info/fcs-1_5_1/README-unzip.html new file mode 100644 index 0000000..d615077 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_1/README-unzip.html @@ -0,0 +1,213 @@ + + + + + + Java 3D 1.5.1 Installation Instructions + + + + + + + +

Java 3DTM +1.5.1 Release

+ +

This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_5_1.txt +file. You +must only use this software in accordance with the terms under which +the +code is licensed.

+ +

Instructions for Unzipping Java 3D 1.5.1 Release

+ +The 1.5.1 version of the +Java 3DTM +API runs on JDK version 1.5.0 and higher. It has been released for +the Solaris, Linux, Windows, +and Mac OS X +operating +environments.
+ +
+ +

Windows

+ +

The 1.5.1 version of the Java 3DTM +API for Windows/XP and Windows 2000 runs on JDK version 1.5.0 and +higher.
+ +

+ +
+

NOTE: +This zip +bundle is intended for expert users who do not want to use the +automated installer. Most users will want to download and install the +java3d-1_5_1-windows-i586.exe file instead.
+ +

+ +
+

To manually install this build, do the following: +

+ +
    + +
  1. Download java3d-1_5_1-XXX.zip to a temporary +directory, +for example, "c:\Temp"
  2. + +
    + +
  3. Unzip java3d-1_5_1-XXX.zip (using WinZip or a +similar +tool) into "c:\Temp". This will create a +"java3d-1_5_1-XXX" subdirectory in \Temp where the +downloaded files can be found. The file you need for manual +installation is "j3d-jre.zip".
    + +
    + +
  4. + +
  5. Unzip Java 3D 1.5.1 into your JRE as follows:
    + +
    + +
  6. + +
      + +
    • Locate your "JRE". The default location for the current +release +is: +"c:\Program Files\Java\jre1.6.0_01"
    • + +
      + +
    • Unzip j3d-jre.zip (found in +c:\Temp\java3d-1_5_1-XXX) +to the jre directory.
    • + +
      + +
    • Verify that the j3dcore.jar, j3dutils.jar, and +vecmath.jar +files end up in: +"c:\Program Files\Java\jre1.6.0_01\lib\ext"
    • + +
      + +
    • Verify that the j3d*.dll files end up in: +"c:\Program Files\Java\jre1.6.0_01\bin"
    • + +
    + +
    + +
  7. If you also installed the JDK, unzip Java 3D 1.5.1 into the +"jre" +directory of your JDK as follows:
  8. + +
    + +
      + +
    • Locate the jre directory of your "JDK". The default +location +for the +current release is: "c:\Program Files\Java\jdk1.6.0_01\jre"
    • + +
      + +
    • Unzip j3d-jre.zip (found in +c:\Temp\java3d-1_5_1-XXX) +to the jre directory of the JDK.
    • + +
      + +
    • Verify that the j3dcore.jar, j3dutils.jar, and +vecmath.jar +files end up in: +"c:\Program Files\Java\jdk1.6.0_01\jre\lib\ext"
    • + +
      + +
    • Verify that the j3d*.dll files end up in: +"c:\Program Files\Java\jdk1.6.0_01\jre\bin"
    • + +
    + +
+ +

Linux, +Solaris, Mac OS X
+ +

+ +

The 1.5.1 version of the Java 3DTM +API for Linux or Solaris runs on JDK version 1.5.0 and +higher. To manually install this build, do the following:

+ +
    + +
  1. Download java3d-1_5_1-XXX.zip to a temporary +directory, +for example, "/tmp"
  2. + +
    + +
  3. Unzip java3d-1_5_1-XXX.zip into "/tmp" as follows:
    + +
    + +
      + + cd /tmp
      + + unzip java3d-1_5_1-*.zip
      + +
    + +
    + +This will create a +"java3d-1_5_1-XXX" subdirectory in /tmp where the +downloaded files can be found. The file you need for manual +installation is "j3d-jre.zip".
    + +
    + +
  4. + +
  5. Unzip Java 3D 1.5.1 into the +"jre" +directory of your JDK. For example, if your JDK is in +"/usr/java/jdk1.6.0_01/jre", you would do the following:
    + +
    + +
      + + cd /usr/java/jdk1.6.0_01/jre
      + + unzip /tmp/java3d-1_5_1-*/j3d-jre.zip
      + +
    + +
    + +Verify that the j3dcore.jar, j3dutils.jar, and vecmath.jar files end up +in +"/usr/java/jdk1.6.0_01/jre/lib/ext"
  6. + +
+ +
+ +
+ + + diff --git a/j3d-core/release-info/fcs-1_5_1/README.html b/j3d-core/release-info/fcs-1_5_1/README.html new file mode 100644 index 0000000..1a7b139 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_1/README.html @@ -0,0 +1,1085 @@ + + + + + + + Java 3D 1.5.1 Release Notes + + + + + + + +

Java 3DTM +1.5.1 +Release Notes

+ +

This file contains important release information for users of +the +Java 3DTM +API, version +1.5.1. +

+ + + +

NOTE: We +recommend that you uninstall +all previous +versions of Java 3D before +installing this version. +

+ +

System +Requirements

+ +

The 1.5.1 version of the Java 3D API has been +released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+ +

Solaris Sparc

+ +

+The 1.5.1 version of Java 3D for Solaris SPARC requires +the +following: +

+ +
    + +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • + +
  • Solaris 9 or later
  • + +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • + +
  • OpenGL 1.3 for Solaris or later. To find your current +version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris +can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • + +
+ +

Solaris x86

+ +

+The 1.5.1 version of Java 3D for Solaris x86/amd64 +requires +the +following: +

+ +
    + +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • + +
  • Solaris 10 or later
  • + +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • + +
+ +

Linux
+ +

+ +

The 1.5.1 version of Java 3D for Linux (x86 or +amd64) +requires +the +following:
+ +

+ +
    + +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • + +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • + +
+ +

Windows
+ +

+ +

The 1.5.1 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+ +

+ +
    + +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • + +
  • Windows 2000, Windows XP, or Windows Vista
  • + +
  • Support for either OpenGL or DirectX as shown below.
    + +
  • + +
+ +
    + + OpenGL version
    + +
      + +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 +or +later, +available from your graphics card manufacturer. +
    + +
+ +
    + + DirectX version
    + +
      + +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" +system +property +to "d3d", +for example: +
        + + java -Dj3d.rend=d3d ClassName +
      + +
    + +
    + +NOTE: The DirectX version of Java 3D is used if a suitable version of +OpenGL cannot be found. Note also that DirectX is chosen by default on +Windows Vista systems with an ATI graphics card (due to ATI driver +bugs). +
+ +

Mac OS X

+ +

The 1.5.1 version of Java 3D for Mac OS X (PPC +or x86) +requires the following:
+ +

+ + + +

Improvements +in 1.5.1

+ +

Enhancements

+ +
    + +
  • Windows Vista Support
  • + +
  • Pack200 Support for Java Web Start Applications
  • + +
  • Logging +Framework
  • + +
  • Added support for JNLPAppletLauncher (will be available +shortly)
  • + +
+ +

Issues Fixed in 1.5.1

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
126  Use OpenGL +automatic mipmap generation
157  Would like a +JOALMixer implementation of AudioEngine3DL2
197  Consider supporting +pack200 for Java Web Start / JNLP
226  D3D : fail on +stress test for the creation and destruction of Canvases
239  Stencil buffer +should be cleared at the start of each frame
257  Java3D Applet +Launcher support
274  NPE With +Simultaneous View and Content Side PickingBehaviors
293  Need better logging +for j3d error, warning, assertion messages.
314  Issue with +Stenciled Transparent Objects
347  OffScreen Canvas3D +always reloads textures, display lists
348  Programmable +shaders do not work for OffScreen Canvas3D
357  Memory leak when +using textures with multiple views
362  dynamic assignment +if Canvas3D to View makes content disappear
364  Canvas3D.setOffScreenBuffer(null) +sometimes hangs
378  Shaders are not +rendered when Canvas3D is created and destroyed
381  ByRef, yDown, +4BYTE_ABGR throws ArrayIndexOOB Exception
396  Off-screen Canvas3D +/ D3D: Resizing crashes VM
402  Off-screen Canvas3D +throws Exception on BufferedImage of TYPE_4BYTE_ABGR and TYPE_INT_ARGB
408  Poor quality of +auto-generated mipmaps
411  Add Primitive flag +to reverse Y for tex coords
412  Exception when +updating Y_UP BY_REFERENCE image
414  D3D: NPOT textures +not properly disabled on card that lacks support
415  Need ability to +disable NPOT textures for raster/background
416  JOGL: +ClassCastException in Renderer with NioImageBuffer
417  JOGL: Mip-mapped +NPOT textures rendered incorrectly
424  JOALMixer requires +the default Viewer's setUserHeadToVworldEnable setting to true
425  NullPointerException +in automatic mipmap generation
427  Method with +constructor name: ObjectFileMaterial
430  Deliver JOALMixer +for JNLP and download bundle
+ +
431  disabled PointSound +starts playing when scheduling bounds are entered
433  JCanvas3D crashed +when using jogl pipe
434  OutOfMemory after +creating millions of RenderAtomListInfo objects
437  SceneGraphStreamWriter +NPE
435  Memory leak when +reusing an Appearance with a single Texture
438  ConfiguredUniverse +& SimpleUniverse constructor missing
441  ArrayIndexOutOfBoundsException +in IndexedTriangleArrayRetained Intersect
444  Transform updates +overly expensive
446  JCanvas3D and focus
447  Enhance Element +Traversal To Improve Pick Hits
449  SceneGraphIO can +not support ImageComponent2DURL
452  Java 3D should fall +back to D3D if OpenGL not available
453  SceneGraphIO does +not support SceneGraphObjects name field
455  Need to disable +NPOT textures for older cards that claim to support it.
456  NPOT background ( +maybe raster) fail to work if HW doesn't support NPOT texture
457  ClassCastException +in MasterControl when updating Texture3D
458  Canvas3D stops +rendering on window close
461  ClassCastException +thrown when using filters with NioImageBuffer
466  NPE when updating +lights with multiple views
467  Add Java3D source +jar file as a separate or part of the distribution
468  SceneGraphStreamReader/Writer +do not close the stream
470  Need informative +error message for mismatched NioImageBuffer
471  Performance +degradation with shader attribute object setValue()
474  Update javadoc for +TextureLoader for ImageException
478  Memory leak in +TransparencySortController
479  JOGL: Screen door +transparency renders incorrectly on JoglPipeline
480  getBounds should +cache results
481  JOALSample: cannot +load if only URLString is given in MediaContainer
485  ClassCastException +when switching shaders in PhongShadingGLSL example
486  Java 3D hangs on +some Windows Vista systems
488  ImageComponent3D +bug with by-reference images
489  AutoOffScreenCanvas3D: +postSwap() is called twice
490  JOALSample fails to +load second sample
491  Refactor +platform-specific classes to use non-overlapping class names
492  ImageComponent2D.setSubImage +throws IllegalArgumentException
494  Group.moveto(null) +throws a NullPointerException
+ +
496  Big performance hit +in VirtualUniverse.getNodeId
+ +
500  Reuse JOAL buffers +where possible
+ +
+ +
+ +

JOGL Rendering +Pipeline

+ +

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac +OS X (x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here +to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+ +

+ +

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+ +
    + + java -Dj3d.rend=jogl ClassName +
+ +

You will need to download +JOGL +and install it into the JRE along with the Java 3D jar files +(or +include it in your PATH/CLASSPATH).
+ +

+ +

NOTE: You must install both Java 3D and +JOGL into the JRE, +or else you must install neither Java 3D nor JOGL +into the +JRE. If you install Java 3D into the JRE and put JOGL on your +CLASSPATH, the JoglPipeline will fail to find the JOGL classes.

+ +

More +Information

+ +

For the latest information on Java 3D, see the main Java 3D +project page +on +java.net.
+ +

+ +

Click here +for a list of open issues.

+ + + diff --git a/j3d-core/release-info/fcs-1_5_1/README.txt b/j3d-core/release-info/fcs-1_5_1/README.txt new file mode 100644 index 0000000..21310cd --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_1/README.txt @@ -0,0 +1,20 @@ +Java 3D(TM) 1.5.1 Release +------------------------- + +This software is licensed by Sun, as specified in the LICENSE-Java3D-v1_5_1.txt file. You must only use this software in accordance with the terms under which the code is licensed. + + +Instructions for unzipping Java 3D 1.5.1 +---------------------------------------- + +After downloading and unzipping the java3d-1_5_1-XXX.zip file into a temporary directory, for example, "c:\Temp", you will see the following files in the java3d-1_5_1-XXX directory: + + COPYRIGHT.txt Copyright notice + LICENSE-Java3D-v1_5_1.txt Software License Agreement + README-distribution.txt Requirements for distribution of Java 3D files + README-unzip.html Instructions for manually installing the release + README.txt README file (you are reading it now) + j3d-jre.zip Zip file containing the files to be installed + +To manually install Java 3D, open README-unzip.html in your browser and follow the instructions. + diff --git a/j3d-core/release-info/fcs-1_5_2/0-USAGE.txt b/j3d-core/release-info/fcs-1_5_2/0-USAGE.txt new file mode 100644 index 0000000..79246b9 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/0-USAGE.txt @@ -0,0 +1,41 @@ +I. Files for Windows Installer + + README.html : + Modified RELEASE NOTES (with link to install instructions removed) + used as README file for Windows installer + + LICENSE-*.rtf : + rtf version of license used for Windows installer + +II. Files for Unix Installers, Zip Bundles, and Download page + + LICENSE-*.txt : + text version of license used for the zip bundles, the Unix + installers, and in download directory (and pointed to by our + java.net download page) + +III. Files for Zip Bundles + + README.txt : + README file that is included with the zip bundles; contains terms + of use, pointer to LICENSE-*.txt, pointer to README-unzip.html, + and MANIFEST of files in bundle + + README-unzip.html : + README file that is included with the zip bundles; contains + pointer to LICENSE-*.txt plus instructions for manually unzipping + the zip bundle. + + README-distribution.txt : + Legal README file that is included with the zip bundles + +IV. Files for Download page + + README-download.html : + README file used in download directory (and pointed to by our + java.net download page); includes pointer to LICENSE-*.txt plus + HOW_TO_INSTALL.html + + THIRDPARTYLICENSEREADME.txt + Combined third-party license files generated by Sun Legal. This is + included on our download page along side the license. diff --git a/j3d-core/release-info/fcs-1_5_2/LICENSE-Java3D-v1_5_2.rtf b/j3d-core/release-info/fcs-1_5_2/LICENSE-Java3D-v1_5_2.rtf new file mode 100644 index 0000000..be45d26 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/LICENSE-Java3D-v1_5_2.rtf @@ -0,0 +1,178 @@ +{\rtf1\ansi\deff0\adeflang1025 +{\fonttbl{\f0\froman\fprq2\fcharset0 Nimbus Roman No9 L{\*\falt Times New Roman};}{\f1\froman\fprq2\fcharset0 Nimbus Roman No9 L{\*\falt Times New Roman};}{\f2\fswiss\fprq2\fcharset0 Nimbus Sans L{\*\falt Arial};}{\f3\fmodern\fprq1\fcharset0 DejaVu Sans Mono;}{\f4\fnil\fprq2\fcharset0 DejaVu Sans;}} +{\colortbl;\red0\green0\blue0;\red128\green128\blue128;} +{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\snext1 Normal;} +{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\afs28\lang255\ltrch\dbch\langfe255\hich\f2\fs28\lang1033\loch\f2\fs28\lang1033\sbasedon1\snext3 Heading;} +{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext3 Body Text;} +{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon3\snext4 List;} +{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ai\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\i\loch\f0\fs24\lang1033\i\sbasedon1\snext5 caption;} +{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext6 Index;} +{\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033\sbasedon1\snext7 Preformatted Text;} +} +{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment StarWriter}{\vern6800}}\deftab709 +{\*\pgdsctbl +{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Standard;}} +\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc +\pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Sun Microsystems, Inc. ("Sun") ENTITLEMENT for SOFTWARE} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Licensee/Company: Entity receiving Software.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Effective Date: Date of delivery of the Software to You.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Software: JAVA 3D, VERSION 1.5.2.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 License Term: Perpetual (subject to termination under the SLA).} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Licensed Unit: Software Copy.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Licensed unit Count: Unlimited.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Permitted Uses:} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 1. You may reproduce and use the Software for Your own Individual, Commercial, and Research and Instructional Use for the purposes of designing, developing, testing, and running Your applets and applications("Programs").} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 2. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the Software's documentation, You may reproduce and distribute portions of Software identified as a redistributable in the documentation ("Redistributable +"), provided that:} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (a) You distribute Redistributable complete and unmodified and only bundled as part of Your Programs,} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (b) Your Programs add significant and primary functionality to the Redistributable,} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (c) You distribute Redistributable for the sole purpose of running Your Programs,} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (d) You do not distribute additional software intended to replace any component(s) of the Redistributable,} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (e) You do not remove or alter any proprietary legends or notices contained in or on the Redistributable.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (f) You only distribute the Redistributable subject to a license agreement that protects Sun's interests consistent with the terms contained in this Agreement, and} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (g) You agree to defend and indemnify Sun and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that ar +ises or results from the use or distribution of any and all Programs and/or Redistributable.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 3. Java Technology Restrictions. You may not create, modify, or change the behavior of, or authorize Your licensees to create, modify, or change the behavior of, classes, interfaces, or subpackages that are in any way identified as "java", "javax", "sun" +or similar convention as specified by Sun in any naming convention designation.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 SOFTWARE LICENSE AGREEMENT} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 READ THE TERMS OF THIS AGREEMENT ("AGREEMENT") CAREFULLY BEFORE OPENING SOFTWARE MEDIA PACKAGE. BY OPENING SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING SOFTWARE ELECTRONICALLY, INDICATE YOUR ACCEPTANCE OF THESE TER +MS BY SELECTING THE "ACCEPT" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF PURCHASE FOR A REFUND OR, IF SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT THE "DE +CLINE" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU HAVE SEPARATELY AGREED TO LICENSE TERMS ("MASTER TERMS") FOR YOUR LICENSE TO THIS SOFTWARE, THEN SECTIONS 1-6 OF THIS AGREEMENT ("SUPPLEMENTAL LICENSE TERMS") SHALL SUPPLEMENT AND SUPERSEDE + THE MASTER TERMS IN RELATION TO THIS SOFTWARE.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 1. Definitions.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (a) "Entitlement" means the collective set of applicable documents authorized by Sun evidencing your obligation to pay associated fees (if any) for the license, associated Services, and the authorized scope of use of Software under this Agreement.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (b) "Licensed Unit" means the unit of measure by which your use of Software and/or Service is licensed, as described in your Entitlement.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (c) "Permitted Use" means the licensed Software use(s) authorized in this Agreement as specified in your Entitlement. The Permitted Use for any bundled Sun software not specified in your Entitlement will be evaluation use as provided in Section 3.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (d) "Service" means the service(s) that Sun or its delegate will provide, if any, as selected in your Entitlement and as further described in the applicable service listings at www.sun.com/service/servicelist.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (e) "Software" means the Sun software described in your Entitlement. Also, certain software may be included for evaluation use under Section 3.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (f) "You" and "Your" means the individual or legal entity specified in the Entitlement, or for evaluation purposes, the entity performing the evaluation.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 2. License Grant and Entitlement.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Subject to the terms of your Entitlement, Sun grants you a nonexclusive, nontransferable limited license to use Software for its Permitted Use for the license term. Your Entitlement will specify (a) Software licensed, (b) the Permitted Use, (c) the license + term, and (d) the Licensed Units.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Additionally, if your Entitlement includes Services, then it will also specify the (e) Service and (f) service term.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 If your rights to Software or Services are limited in duration and the date such rights begin is other than the purchase date, your Entitlement will provide that beginning date(s).} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 The Entitlement may be delivered to you in various ways depending on the manner in which you obtain Software and Services, for example, the Entitlement may be provided in your receipt, invoice or your contract with Sun or authorized Sun reseller. It may al +so be in electronic format if you download Software.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 3. Permitted Use.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 As selected in your Entitlement, one or more of the following Permitted Uses will apply to your use of Software. Unless you have an Entitlement that expressly permits it, you may not use Software for any of the other Permitted Uses. If you don't have an En +titlement, or if your Entitlement doesn't cover additional software delivered to you, then such software is for your Evaluation Use.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (a) Evaluation Use. You may evaluate Software internally for a period of 90 days from your first use.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (b) Research and Instructional Use. You may use Software internally to design, develop and test, and also to provide instruction on such uses.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (c) Individual Use. You may use Software internally for personal, individual use.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (d) Commercial Use. You may use Software internally for your own commercial purposes.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (e) Service Provider Use. You may make Software functionality accessible (but not by providing Software itself or through outsourcing services) to your end users in an extranet deployment, but not to your affiliated companies or to government agencies.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 4. Licensed Units.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Your Permitted Use is limited to the number of Licensed Units stated in your Entitlement. If you require additional Licensed Units, you will need additional Entitlement(s).} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 5. Restrictions.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 (a) The copies of Software provided to you under this Agreement is licensed, not sold, to you by Sun. Sun reserves all rights not expressly granted. (b) You may make a single archival copy of Software, but otherwise may not copy, modify, or distribute Soft +ware. However if the Sun documentation accompanying Software lists specific portions of Software, such as header files, class libraries, reference source code, and/or redistributable files, that may be handled differently, you may do so only as provided in + the Sun documentation. (c) You may not rent, lease, lend or encumber Software. (d) Unless enforcement is prohibited by applicable law, you may not decompile, or reverse engineer Software. (e) The terms and conditions of this Agreement will apply to any So +ftware updates, provided to you at Sun's discretion, that replace and/or supplement the original Software, unless such update contains a separate license. (f) You may not publish or provide the results of any benchmark or comparison tests run on Software t +o any third party without the prior written consent of Sun. (g) Software is confidential and copyrighted. (h) Unless otherwise specified, if Software is delivered with embedded or bundled software that enables functionality of Software, you may not use suc +h software on a stand-alone basis or use any portion of such software to interoperate with any program(s) other than Software. (i) Software may contain programs that perform automated collection of system data and/or automated software updating services. S +ystem data collected through such programs may be used by Sun, its subcontractors, and its service delivery partners for the purpose of providing you with remote system services and/or improving Sun's software and systems. (j) Software is not designed, lic +ensed or intended for use in the design, construction, operation or maintenance of any nuclear facility and Sun and its licensors disclaim any express or implied warranty of fitness for such uses. (k) No right, title or interest in or to any trademark, ser +vice mark, logo or trade name of Sun or its licensors is granted under this Agreement.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 6. Java Compatibility and Open Source.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Software may contain Java technology. You may not create additional classes to, or modifications of, the Java technology, except under compatibility requirements available under a separate agreement available at www.java.net.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Sun supports and benefits from the global community of open source developers, and thanks the community for its important contributions and open standards-based technology, which Sun has adopted into many of its products.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Please note that portions of Software may be provided with notices and open source licenses from such communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may ha +ve under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this Agreement will apply to all Software in this distribution.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 7. Term and Termination.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 The license and service term are set forth in your Entitlement(s). Your rights under this Agreement will terminate immediately without notice from Sun if you materially breach it or take any action in derogation of Sun's and/or its licensors' rights to Sof +tware. Sun may terminate this Agreement should any Software become, or in Sun's reasonable opinion likely to become, the subject of a claim of intellectual property infringement or trade secret misappropriation. Upon termination, you will cease use of, and + destroy, Software and confirm compliance in writing to Sun. Sections 1, 5, 6, 7, and 9-15 will survive termination of the Agreement.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 8. Limited Warranty.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Sun warrants to you that for a period of 90 days from the date of purchase, as evidenced by a copy of the receipt, the media on which Software is furnished (if any) will be free of defects in materials and workmanship under normal use. Except for the foreg +oing, Software is provided "AS IS". Your exclusive remedy and Sun's entire liability under this limited warranty will be at Sun's option to replace Software media or refund the fee paid for Software. Some states do not allow limitations on certain implied +warranties, so the above may not apply to you. This limited warranty gives you specific legal rights. You may have others, which vary from state to state.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 9. Disclaimer of Warranty.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE D +ISCLAIMERS ARE HELD TO BE LEGALLY INVALID.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 10. Limitation of Liability.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISIN +G OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, whether in contract, tort (including negligence), or otherwise, exceed the amount paid + by you for Software under this Agreement. The foregoing limitations will apply even if the above stated warranty fails of its essential purpose. Some states do not allow the exclusion of incidental or consequential damages, so some of the terms above may +not be applicable to you.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 11. Export Regulations.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 All Software, documents, technical data, and any other materials delivered under this Agreement are subject to U.S. export control laws and may be subject to export or import regulations in other countries. You agree to comply strictly with these laws and +regulations and acknowledge that you have the responsibility to obtain any licenses to export, re-export, or import as may be required after delivery to you.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 12. U.S. Government Restricted Rights.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 If Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government's rights in Software and accompanying documentation will be only as set forth in this Agreemen +t; this is in accordance with 48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions).} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 13. Governing Law.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Any action related to this Agreement will be governed by California law and controlling U.S. federal law. No choice of law rules of any jurisdiction will apply.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 14. Severability.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 If any provision of this Agreement is held to be unenforceable, this Agreement will remain in effect with the provision omitted, unless omission would frustrate the intent of the parties, in which case this Agreement will immediately terminate.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 15. Integration.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 This Agreement, including any terms contained in your Entitlement, is the entire agreement between you and Sun relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, representations and warrant +ies and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement. No modification of this Agreement will be binding, u +nless in writing and signed by an authorized representative of each party.} +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 +\par \pard\plain \ltrpar\s7\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs20\lang255\ltrch\dbch\af3\langfe255\hich\f3\fs20\lang1033\loch\f3\fs20\lang1033 {\rtlch \ltrch\loch\f3\fs20\lang1033\i0\b0 Please contact Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, California 95054 if you have questions.} +\par } \ No newline at end of file diff --git a/j3d-core/release-info/fcs-1_5_2/LICENSE-Java3D-v1_5_2.txt b/j3d-core/release-info/fcs-1_5_2/LICENSE-Java3D-v1_5_2.txt new file mode 100644 index 0000000..3667507 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/LICENSE-Java3D-v1_5_2.txt @@ -0,0 +1,297 @@ +Sun Microsystems, Inc. ("Sun") ENTITLEMENT for SOFTWARE + +Licensee/Company: Entity receiving Software. + +Effective Date: Date of delivery of the Software to You. + +Software: JAVA 3D, VERSION 1.5.2. + +License Term: Perpetual (subject to termination under the SLA). + +Licensed Unit: Software Copy. + +Licensed unit Count: Unlimited. + +Permitted Uses: + +1. You may reproduce and use the Software for Your own Individual, +Commercial, and Research and Instructional Use for the purposes +of designing, developing, testing, and running Your applets and +applications("Programs"). + +2. Subject to the terms and conditions of this Agreement and +restrictions and exceptions set forth in the Software's documentation, +You may reproduce and distribute portions of Software identified as a +redistributable in the documentation ("Redistributable"), provided that: + +(a) You distribute Redistributable complete and unmodified and only +bundled as part of Your Programs, + +(b) Your Programs add significant and primary functionality to the +Redistributable, + +(c) You distribute Redistributable for the sole purpose of running +Your Programs, + +(d) You do not distribute additional software intended to replace any +component(s) of the Redistributable, + +(e) You do not remove or alter any proprietary legends or notices +contained in or on the Redistributable. + +(f) You only distribute the Redistributable subject to a license agreement +that protects Sun's interests consistent with the terms contained in +this Agreement, and + +(g) You agree to defend and indemnify Sun and its licensors from and +against any damages, costs, liabilities, settlement amounts and/or +expenses (including attorneys' fees) incurred in connection with any +claim, lawsuit or action by any third party that arises or results from +the use or distribution of any and all Programs and/or Redistributable. + +3. Java Technology Restrictions. You may not create, modify, or change +the behavior of, or authorize Your licensees to create, modify, or change +the behavior of, classes, interfaces, or subpackages that are in any way +identified as "java", "javax", "sun" or similar convention as specified +by Sun in any naming convention designation. + + +SOFTWARE LICENSE AGREEMENT + +READ THE TERMS OF THIS AGREEMENT ("AGREEMENT") CAREFULLY BEFORE OPENING +SOFTWARE MEDIA PACKAGE. BY OPENING SOFTWARE MEDIA PACKAGE, YOU AGREE TO +THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING SOFTWARE ELECTRONICALLY, +INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE "ACCEPT" (OR +EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO +ALL OF THE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF +PURCHASE FOR A REFUND OR, IF SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT +THE "DECLINE" (OR EQUIVALENT) BUTTON AT THE END OF THIS AGREEMENT. IF YOU +HAVE SEPARATELY AGREED TO LICENSE TERMS ("MASTER TERMS") FOR YOUR LICENSE +TO THIS SOFTWARE, THEN SECTIONS 1-6 OF THIS AGREEMENT ("SUPPLEMENTAL +LICENSE TERMS") SHALL SUPPLEMENT AND SUPERSEDE THE MASTER TERMS IN +RELATION TO THIS SOFTWARE. + +1. Definitions. + +(a) "Entitlement" means the collective set of applicable documents +authorized by Sun evidencing your obligation to pay associated fees (if +any) for the license, associated Services, and the authorized scope of +use of Software under this Agreement. + +(b) "Licensed Unit" means the unit of measure by which your use of +Software and/or Service is licensed, as described in your Entitlement. + +(c) "Permitted Use" means the licensed Software use(s) authorized in +this Agreement as specified in your Entitlement. The Permitted Use +for any bundled Sun software not specified in your Entitlement will be +evaluation use as provided in Section 3. + +(d) "Service" means the service(s) that Sun or its delegate will provide, +if any, as selected in your Entitlement and as further described in the +applicable service listings at www.sun.com/service/servicelist. + +(e) "Software" means the Sun software described in your Entitlement. Also, +certain software may be included for evaluation use under Section 3. + +(f) "You" and "Your" means the individual or legal entity specified +in the Entitlement, or for evaluation purposes, the entity performing +the evaluation. + +2. License Grant and Entitlement. + +Subject to the terms of your Entitlement, Sun grants you a nonexclusive, +nontransferable limited license to use Software for its Permitted Use for +the license term. Your Entitlement will specify (a) Software licensed, +(b) the Permitted Use, (c) the license term, and (d) the Licensed Units. + +Additionally, if your Entitlement includes Services, then it will also +specify the (e) Service and (f) service term. + +If your rights to Software or Services are limited in duration and the +date such rights begin is other than the purchase date, your Entitlement +will provide that beginning date(s). + +The Entitlement may be delivered to you in various ways depending on +the manner in which you obtain Software and Services, for example, the +Entitlement may be provided in your receipt, invoice or your contract +with Sun or authorized Sun reseller. It may also be in electronic format +if you download Software. + +3. Permitted Use. + +As selected in your Entitlement, one or more of the following Permitted +Uses will apply to your use of Software. Unless you have an Entitlement +that expressly permits it, you may not use Software for any of the other +Permitted Uses. If you don't have an Entitlement, or if your Entitlement +doesn't cover additional software delivered to you, then such software +is for your Evaluation Use. + +(a) Evaluation Use. You may evaluate Software internally for a period +of 90 days from your first use. + +(b) Research and Instructional Use. You may use Software internally to +design, develop and test, and also to provide instruction on such uses. + +(c) Individual Use. You may use Software internally for personal, +individual use. + +(d) Commercial Use. You may use Software internally for your own +commercial purposes. + +(e) Service Provider Use. You may make Software functionality accessible +(but not by providing Software itself or through outsourcing services) +to your end users in an extranet deployment, but not to your affiliated +companies or to government agencies. + +4. Licensed Units. + +Your Permitted Use is limited to the number of Licensed Units stated +in your Entitlement. If you require additional Licensed Units, you will +need additional Entitlement(s). + +5. Restrictions. + +(a) The copies of Software provided to you under this Agreement +is licensed, not sold, to you by Sun. Sun reserves all rights not +expressly granted. (b) You may make a single archival copy of Software, +but otherwise may not copy, modify, or distribute Software. However if +the Sun documentation accompanying Software lists specific portions of +Software, such as header files, class libraries, reference source code, +and/or redistributable files, that may be handled differently, you may +do so only as provided in the Sun documentation. (c) You may not rent, +lease, lend or encumber Software. (d) Unless enforcement is prohibited by +applicable law, you may not decompile, or reverse engineer Software. (e) +The terms and conditions of this Agreement will apply to any Software +updates, provided to you at Sun's discretion, that replace and/or +supplement the original Software, unless such update contains a separate +license. (f) You may not publish or provide the results of any benchmark +or comparison tests run on Software to any third party without the prior +written consent of Sun. (g) Software is confidential and copyrighted. (h) +Unless otherwise specified, if Software is delivered with embedded or +bundled software that enables functionality of Software, you may not +use such software on a stand-alone basis or use any portion of such +software to interoperate with any program(s) other than Software. (i) +Software may contain programs that perform automated collection of +system data and/or automated software updating services. System data +collected through such programs may be used by Sun, its subcontractors, +and its service delivery partners for the purpose of providing you with +remote system services and/or improving Sun's software and systems. (j) +Software is not designed, licensed or intended for use in the design, +construction, operation or maintenance of any nuclear facility and Sun +and its licensors disclaim any express or implied warranty of fitness +for such uses. (k) No right, title or interest in or to any trademark, +service mark, logo or trade name of Sun or its licensors is granted +under this Agreement. + +6. Java Compatibility and Open Source. + +Software may contain Java technology. You may not create additional +classes to, or modifications of, the Java technology, except under +compatibility requirements available under a separate agreement available +at www.java.net. + +Sun supports and benefits from the global community of open source +developers, and thanks the community for its important contributions +and open standards-based technology, which Sun has adopted into many of +its products. + +Please note that portions of Software may be provided with notices and +open source licenses from such communities and third parties that govern +the use of those portions, and any licenses granted hereunder do not alter +any rights and obligations you may have under such open source licenses, +however, the disclaimer of warranty and limitation of liability provisions +in this Agreement will apply to all Software in this distribution. + +7. Term and Termination. + +The license and service term are set forth in your Entitlement(s). Your +rights under this Agreement will terminate immediately without notice from +Sun if you materially breach it or take any action in derogation of Sun's +and/or its licensors' rights to Software. Sun may terminate this Agreement +should any Software become, or in Sun's reasonable opinion likely to +become, the subject of a claim of intellectual property infringement or +trade secret misappropriation. Upon termination, you will cease use of, +and destroy, Software and confirm compliance in writing to Sun. Sections +1, 5, 6, 7, and 9-15 will survive termination of the Agreement. + +8. Limited Warranty. + +Sun warrants to you that for a period of 90 days from the date of +purchase, as evidenced by a copy of the receipt, the media on which +Software is furnished (if any) will be free of defects in materials +and workmanship under normal use. Except for the foregoing, Software is +provided "AS IS". Your exclusive remedy and Sun's entire liability under +this limited warranty will be at Sun's option to replace Software media +or refund the fee paid for Software. Some states do not allow limitations +on certain implied warranties, so the above may not apply to you. This +limited warranty gives you specific legal rights. You may have others, +which vary from state to state. + +9. Disclaimer of Warranty. + +UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, +REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT +ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE DISCLAIMERS ARE HELD TO +BE LEGALLY INVALID. + +10. Limitation of Liability. + +TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS +BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS +OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO THE USE OF +OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, +whether in contract, tort (including negligence), or otherwise, exceed +the amount paid by you for Software under this Agreement. The foregoing +limitations will apply even if the above stated warranty fails of its +essential purpose. Some states do not allow the exclusion of incidental +or consequential damages, so some of the terms above may not be applicable +to you. + +11. Export Regulations. + +All Software, documents, technical data, and any other materials delivered +under this Agreement are subject to U.S. export control laws and may be +subject to export or import regulations in other countries. You agree +to comply strictly with these laws and regulations and acknowledge that +you have the responsibility to obtain any licenses to export, re-export, +or import as may be required after delivery to you. + +12. U.S. Government Restricted Rights. + +If Software is being acquired by or on behalf of the U.S. Government or +by a U.S. Government prime contractor or subcontractor (at any tier), +then the Government's rights in Software and accompanying documentation +will be only as set forth in this Agreement; this is in accordance with +48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) +acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions). + +13. Governing Law. + +Any action related to this Agreement will be governed by California +law and controlling U.S. federal law. No choice of law rules of any +jurisdiction will apply. + +14. Severability. + +If any provision of this Agreement is held to be unenforceable, this +Agreement will remain in effect with the provision omitted, unless +omission would frustrate the intent of the parties, in which case this +Agreement will immediately terminate. + +15. Integration. + +This Agreement, including any terms contained in your Entitlement, is the +entire agreement between you and Sun relating to its subject matter. It +supersedes all prior or contemporaneous oral or written communications, +proposals, representations and warranties and prevails over any +conflicting or additional terms of any quote, order, acknowledgment, or +other communication between the parties relating to its subject matter +during the term of this Agreement. No modification of this Agreement will +be binding, unless in writing and signed by an authorized representative +of each party. + +Please contact Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, +California 95054 if you have questions. diff --git a/j3d-core/release-info/fcs-1_5_2/README-distribution.txt b/j3d-core/release-info/fcs-1_5_2/README-distribution.txt new file mode 100644 index 0000000..1aa4c45 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/README-distribution.txt @@ -0,0 +1,39 @@ +DistributionREADME + +DISTRIBUTION BY DEVELOPERS. Subject to the terms and conditions of +the Software License Agreement and the obligations, restrictions, +and exceptions set forth below, You may reproduce and distribute +the portions of Software identified below ("each a Redistributable"), +provided that You comply with the following (note that You may be entitled +to reproduce and distribute other portions of the Software not defined +here as a Redistributable under certain other licenses as described in +the THIRDPARTYLICENSEREADME, if applicable): + +(a) You distribute the Redistributable complete and unmodified and only +bundled as part of Your applets and applications ("Programs"), + +(b) Your Programs add significant and primary functionality to the +Software + +(c) You distribute Redistributable for the sole purpose of running +Your Programs, + +(d) You do not distribute additional software intended to replace any +component(s) of the Redistributable, + +(e) You do not remove or alter any proprietary legends or notices +contained in or on the Redistributable. + +(f) You only distribute the Redistributable subject to a license agreement +that protects Sun's interests consistent with the terms contained in +the Software License Agreement, and + +(g) You agree to defend and indemnify Sun and its licensors from and +against any damages, costs, liabilities, settlement amounts and/or +expenses (including attorneys' fees) incurred in connection with any +claim, lawsuit or action by any third party that arises or results from +the use or distribution of any and all Programs and/or Redistributable. + +The following files are each a Redistributable: + +JAVA 3D, VERSION 1.5.2 diff --git a/j3d-core/release-info/fcs-1_5_2/README-download.html b/j3d-core/release-info/fcs-1_5_2/README-download.html new file mode 100644 index 0000000..6a07ee4 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/README-download.html @@ -0,0 +1,79 @@ + + + + + Java 3D 1.5.2 Installation Instructions + + +

Java 3DTM 1.5.2 Release

+

This software is licensed by Sun, as specified in the +LICENSE-Java3D-v1_5_2.txt +file. You must only use this software in accordance with the terms +under which the code is licensed. +

+

Instructions for Installing Java 3D 1.5.2

+

The 1.5.2 version of the Java 3DTM +API runs on JDK version +1.5.0 and higher. It has been released for the Windows, Linux, +Solaris, and Mac OS X operating environments. See the +release +notes for more information. +

+ +

Preferred method

+ +

Developers who wish to develop an application using the Java 3D API +are encouraged to download the j3d-1_5_2-XXX.zip file for +their platform, and manually install the necessary files into a +directory on their local disk. To do this, unzip the downloaded file, +and follow the instructions in the unzipped README.txt file. +

+ +

Alternative method

+ +

Alternatively, you can run the installer as shown below, keeping in +mind that it is not recommended to install the j3d jar files and +native libraries directly into the JRE. +

+ +

Windows

+

To install the Java 3D API on Windows, download the binary +installer and then execute it, by double-clicking on the +j3d-1_5_2-windows-i586.exe (or j3d-1_5_2-windows-amd64.exe) +icon. +

+ +

Linux or Solaris

+

To install the Java 3D API on Linux or Solaris, download the +self-extracting binary file, chdir to the desired directory, and then +execute it. For example, on a 32-bit Linux system: +

+
    +cd /myhome/j3d
    +sh /path-to-download-files/j3d-1_5_2-linux-i586.bin
    +
+ +

After doing this, you will need to modify your CLASSPATH +environment variable to include the full paths to j3dcore.jar, +j3dutils.jar, and vecmath.jar. For example: +

+ +
    +export CLASSPATH=".:/myhome/j3d/lib/ext/j3dcore.jar:/myhome/j3d/lib/ext/j3dutils.jar:/myhome/j3d/lib/ext/vecmath.jar +
+ +

Then modify your LD_LIBRARY_PATH environment variable to contain the +full path to the "lib/ARCH" directory. For example, on 32-bit Linux: +

+ +
    +export LD_LIBRARY_PATH=/myhome/j3d/lib/i386 +
+ +

Mac OS X

+

No installer is available for the Mac OS X operating environment. +You will need to download the j3d-1_5_2-macosx.zip file, unzip it, +and follow the instructions in the unzipped README.txt file. +

+ + diff --git a/j3d-core/release-info/fcs-1_5_2/README-unzip.html b/j3d-core/release-info/fcs-1_5_2/README-unzip.html new file mode 100644 index 0000000..bc17440 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/README-unzip.html @@ -0,0 +1,204 @@ + + + + + Java 3D 1.5.2 Unzip Instructions + + +

Java 3DTM 1.5.2 Release

+

This software is licensed by Sun, as specified in the +LICENSE-Java3D-v1_5_2.txt +file. You must only use this software in accordance with the terms +under which the code is licensed. +

+

Instructions for Unzipping the Java 3D 1.5.2 Release

+

The 1.5.2 version of the +Java 3DTM +API runs on JDK version 1.5.0 and higher. It has been released +for the Windows, Linux, +Solaris, +and Mac OS X +operating environments. +

+

NOTE: Installing the j3d jars and native libs into the "ext" +directory of the JRE is discouraged, especially on +Mac OS X +where JOGL is used as the rendering engine. Doing so can cause +conflicts with third-party applications launched via Java Web Start, +and causes confusion later when upgrading the distribution. +

+

Windows

+

The 1.5.2 release of the Java 3D API for Windows 2000, Windows +XP (x86 or amd64), and Windows Vista runs on JDK version 1.5.0 and +higher. To manually install this release, do the following: +

+
    +
  1. Download and unzip j3d-1_5_2-XXX.zip +(using Windows +Explorer or an unzip tool such as WinZip) to a temporary +download folder, +for example, c:\Downloads. This will +create a j3d-1_5_2-XXX subfolder in +your download folder where the +downloaded files can be found. The file you need for manual +installation is j3d-jre.zip.
    +
    +
  2. +
  3. Create a folder for the j3d jar files and native libraries, +for example, C:\Users\myhome\j3d, and +unzip j3d-jre.zip into this folder.
    +
    +
  4. +
  5. Modify your CLASSPATH environment +variable to include the full paths to j3dcore.jar, + j3dutils.jar, and vecmath.jar. +For example, add the following to your CLASSPATH +variable, +using the System control panel, Advanced tab, Environment Variables +button:
    +
    + .;C:\Users\myhome\j3d\lib\ext\j3dcore.jar;C:\Users\myhome\j3d\lib\ext\j3dutils.jar;C:\Users\myhome\j3d\lib\ext\vecmath.jar +
    +
    +
  6. +
  7. Modify your PATH environment +variable to contain the full path to the lib\i386 +folder (or lib\amd64 for +Windows/x64). For example, on 32-bit Windows, add the following to your + PATH variable, using the System control +panel, Advanced tab, Environment Variables button.
    +
    + C:\Users\myhome\j3d\lib\i386
    +
  8. +
+

At this point your Java installation should be able to see +the j3d class files. Users of IDEs such as NetBeans and Eclipse should +consult the IDE's documentation to see how to add jar files and native +libraries to their current project.
+

+

Linux, +Solaris

+

The 1.5.2 release of the Java 3D API +for Linux or Solaris runs on JDK version 1.5.0 and +higher. To manually install this release, do the following:

+
    +
  1. Download and unzip j3d-1_5_2-XXX.zip +into a temporary +download directory, +for example, /tmp. This will +create a j3d-1_5_2-XXX subdirectory +in /tmp where the +downloaded files can be found. The file you need for manual +installation is j3d-jre.zip.
    +
    +
  2. +
  3. Create a folder for the j3d jar files and native libraries, +for example, /myhome/j3d, and +unzip j3d-jre.zip into this directory +as follows:
    +
    +
      + cd /myhome/j3d
      + unzip /tmp/j3d-1_5_2-*/j3d-jre.zip
      +
    +
    +
  4. +
  5. Modify your CLASSPATH environment +variable to include the full paths to j3dcore.jar, + j3dutils.jar, and vecmath.jar. +For example:
    +
    + export +CLASSPATH=.:/myhome/j3d/lib/ext/j3dcore.jar:/myhome/j3d/lib/ext/j3dutils.jar:/myhome/j3d/lib/ext/vecmath.jar
    +
    +
  6. +
  7. Modify your LD_LIBRARY_PATH +environment +variable to contain the full path to the lib/<ARCH> +directory. For example, on 32-bit Linux:
    +
    + export LD_LIBRARY_PATH=/myhome/j3d/lib/i386
    +
  8. +
+

At this point your Java installation should be able to see +the j3d class files. Users of IDEs such as NetBeans and Eclipse should +consult the IDE's documentation to see how to add jar files and native +libraries to their current project. +

+

Mac OS X

+

The 1.5.2 release of the Java 3D API +for Mac OS X runs on JDK version 1.5.0 and +higher. To manually install this release, do the following:

+
    +
  1. Download and unzip j3d-1_5_2-XXX.zip +into a temporary +download directory, +for example, /tmp. This will +create a j3d-1_5_2-XXX subdirectory +in /tmp where the +downloaded files can be found. The file you need for manual +installation is j3d-jre.zip.
    +
    +
  2. +
  3. Create a folder for the j3d jar files, +for example, /myhome/j3d, and +unzip j3d-jre.zip into this directory +as follows:
    +
    +
      + cd /myhome/j3d
      + unzip /tmp/j3d-1_5_2-*/j3d-jre.zip
      +
    +
    +
  4. +
  5. Modify your CLASSPATH environment +variable to include the full paths to j3dcore.jar, + j3dutils.jar, and vecmath.jar. +For example:
    +
    + export +CLASSPATH=.:/myhome/j3d/lib/ext/j3dcore.jar:/myhome/j3d/lib/ext/j3dutils.jar:/myhome/j3d/lib/ext/vecmath.jar
    +
  6. +
    +
  7. Download a recent version of JOGL for the Mac +platform into a temporary +download directory, +for example, /tmp.
    +
    +
  8. +
  9. Create a folder for the jogl jar files and native +libraries, +for example, /myhome/jogl, and +unzip jogl-*.zip into this directory +as follows:
    +
    +
      + cd /myhome/jogl
      + unzip /tmp/jogl-*.zip
      +
    +
    +
  10. +
  11. Modify your CLASSPATH environment +variable to include the full paths to jogl.jar +and gluegen-rt.jar. +For example:
    +
    + export +CLASSPATH="${CLASSPATH}:/myhome/jogl/lib/jogl.jar:/myhome/jogl/lib/gluegen-rt.jar
    +
  12. +
    +
  13. Modify your DYLD_LIBRARY_PATH +environment +variable to contain the full path to the lib +directory. For example:
    +
    + export DYLD_LIBRARY_PATH=/myhome/jogl/lib
    +
  14. +
+

At this point your Java installation should be able to see +the j3d and jogl class files. Users of IDEs such as NetBeans and +Eclipse should +consult the IDE's documentation to see how to add jar files and native +libraries to their current project.

+ + diff --git a/j3d-core/release-info/fcs-1_5_2/README.html b/j3d-core/release-info/fcs-1_5_2/README.html new file mode 100644 index 0000000..c6bbab4 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/README.html @@ -0,0 +1,335 @@ + + + + + Java 3D 1.5.2 Release Notes + + +

Java 3DTM 1.5.2 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.2. +

+ +

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.2 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.2 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.2 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.2 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.2 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000, Windows XP, or Windows Vista
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
    + NOTE: The DirectX version of Java 3D is used if a suitable version + of OpenGL cannot be found. Note also that DirectX is chosen by + default on Windows Vista systems with an ATI graphics card (due to + ATI driver bugs). +
+

Mac OS X

+

The 1.5.2 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.2

+

Enhancements

+
    +
  • Source code license changed to GPL v2 + CLASSPATH
  • +
+

Issues Fixed in 1.5.2

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
179  OrbitBehavior.setRotationCenter gives spurious view shift
483  NullPointerException when writing Font3D using scenegraph.io
506  NullPointerException: Calling getNominalSensorRotation in WandViewBehavior when internal nominalSensorRotation is null causes a NullPointerException.
510  J3DGraphics2D context lost when canvas changes frame
513  Down-rev D3D driver can cause JVM to crash
514  NPE in Wonderland : triggered in cached bounds computation
519  IntersectionInfo.getGeometry return null for IndexedArrayGeometry
525  JOALMixer only playing one sample
532  Background geometry BG isn't saved with SceneGraphFileWriter
534  ClassNotFoundException when running applet if Java 3D installed into JRE
538  Machine precision bug in AxisAngle4d and Quat4d
540  ArrayIndexOutOfBoundsException when calling setPickable
541  Bound.closest_point() method creates unused Matrix3d
543  J3DClock does not adjust to clock skew
544  GroupRetained.getBounds() should return BoundingBox?
545  Update docs to discourage installing Java 3D into JRE
548  RFE - Disable getLock() / unLock() on non-alive GeometryArray
555  Muting a PointSound causes a ClassCastException
560  Use D3DCREATE_FPU_PRESERVE flag on D3D pipeline
561  Decrease memory footprint of BoundingBox
562  Error occurs when Canvas3D removed from View
563  Background cloneNode() fails with Background geometry
567  Update license to GPL v2 + CLASSPATH
569  ImageComponent.ALLOW_IMAGE_READ is false
583  A disposed Graphics2D remains in Canvas3D after removal and addtion
585  ClassCastException in TransformStructure.java
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac OS X +(x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and include it in your PATH/CLASSPATH along with the Java 3D jar files.
+

+

NOTE: Installing the j3d or jogl jars and native libs into the "ext" +directory of the JRE is strongly discouraged. Doing so can cause +conflicts with third-party applications launched via Java Web Start, +and causes confusion later when upgrading the distribution. +

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/release-info/fcs-1_5_2/README.txt b/j3d-core/release-info/fcs-1_5_2/README.txt new file mode 100644 index 0000000..0155d1c --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/README.txt @@ -0,0 +1,24 @@ +Java 3D(TM) 1.5.2 Release +------------------------- + +This software is licensed by Sun, as specified in the +LICENSE-Java3D-v1_5_2.txt file. You must only use this software in +accordance with the terms under which the code is licensed. + + +Instructions for unzipping Java 3D 1.5.2 +---------------------------------------- + +After downloading and unzipping the java3d-1_5_2-XXX.zip file into a +temporary directory, for example, "c:\Temp", you will see the +following files in the java3d-1_5_2-XXX directory: + + COPYRIGHT.txt Copyright notice + LICENSE-Java3D-v1_5_2.txt Software License Agreement + README-distribution.txt Requirements for distribution of Java 3D files + README-unzip.html Instructions for manually installing the release + README.txt README file (you are reading it now) + j3d-jre.zip Zip file containing the files to be installed + +To manually install Java 3D, open README-unzip.html in your browser +and follow the instructions. diff --git a/j3d-core/release-info/fcs-1_5_2/THIRDPARTYLICENSEREADME.txt b/j3d-core/release-info/fcs-1_5_2/THIRDPARTYLICENSEREADME.txt new file mode 100644 index 0000000..066c2d1 --- /dev/null +++ b/j3d-core/release-info/fcs-1_5_2/THIRDPARTYLICENSEREADME.txt @@ -0,0 +1,193 @@ +DO NOT TRANSLATE OR LOCALIZE + +*************************************************************************** + +%%The following software may be included in this product: +OpenGL Header (aka Include or .h) Files + +Use of any of this software is governed by the terms of the license below: + +/* +** Copyright (c) 2007 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +*************************************************************************** + +%%The following software may be included in this product: +panoramiXext.h,v + +Use of any of this software is governed by the terms of the license below: + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +*************************************************************************** + +%%The following software may be included in this product: +MainFrame + +Use of any of this software is governed by the terms of the license below: + +Copyright (C) 1996 by Jef Poskanzer . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +Visit the ACME Labs Java page for up-to-date versions of this and other +fine Java utilities: http://www.acme.com/java/ + +*************************************************************************** + +%%The following software may be included in this product: +Wild Magic Library v. 1999 + +Use of any of this software is governed by the terms of the license below: + +License Agreement for the Wild Magic (Version 2) Software Library +Revision 1: January 28, 2004 + +THIS WILD MAGIC (VERSION 2) SOFTWARE LICENSE AGREEMENT ("Agreement") +is made by and between Magic Software, Inc. ("We/Us/Our"), a North +Carolina corporation, having its principal place of business at 6006 +Meadow Run Court, Chapel Hill, North Carolina 27516 and any person or +legal entity using or accepting any software governed by this +Agreement ("You/Your"). This Agreement shall be effective on the first +day you use or accept software ("The Software") governed by this +Agreement, whichever is earlier. + +THE PARTIES AGREE as follows: + +1. Grant. We grant you a nonexclusive, nontransferable, and perpetual + license to use The Software subject to the terms and conditions of the + Agreement: + + (a) There is no charge to you for this license. + + (b) The Software may be used, edited, modified, copied, and + distributed by you for noncommercial products. + + (c) The Software may be used, edited, modified, copied, and + distributed by you for commercial products provided that such + products are not intended to wrap The Software solely for the + purposes of selling it as if it were your own product. The + intent of this clause is that you use The Software, in part or + in whole, to assist you in building your own original + products. An example of acceptable use is to incorporate the + graphics portion of The Software in a game to be sold to an end + user. An example that violates this clause is to compile a + library from only The Software, bundle it with the headers + files as a Software Development Kit (SDK), then sell that SDK + to others. If there is any doubt about whether you can use The + Software for a commercial product, contact us and explain what + portions you intend to use. We will consider creating a + separate legal document that grants you permission to use those + portions of The Software in your commercial product. + +2. Limitation of Liability. We will have no liability for special, + incidental or consequential damages even if advised of the + possibility of such damages. We will not be liable for any other + damages or loss in any way connected with The Software. + +3. Warranties. We make no warranties at all. The Software is + transferred to you on an as-is basis. You use The Software at your + own peril. You assume all risk of loss for all claims or + controversies, now existing or hereafter, arising out of use of The + Software. We shall have no liability based on a claim that your use + or combination of The Software with products or data not supplied + by us infringes any patent, copyright, or proprietary right. All + other warranties, expressed or implied, including, without + limitation, any warranty of merchantability or fitness for a + particular purpose are hereby excluded. + +4. Taxes and Duties. You shall pay or reimburse us for federal, state, + provincial, local or other tariffs, duties and taxes not based on + our net income, including all taxes, tariffs, duties, or amounts + levied in lieu thereof, based on charges payable under this + Agreement or based on The Software, its use or any services + performed hereunder, whether such tariffs, duties or taxes are now + or hereafter imposed under the authority of any federal, state, + provincial, local or other jurisdiction. + +5. Entire Agreement, Amendments. This Agreement represents the + complete and exclusive statement of the Agreements between the + parties relating to the licensing of The Software and maintenance + of The Software and supersedes all prior Agreements and + representations between them relating to such + licensing. Modifications to this Agreement shall not be effective + unless in writing and signed by the party against whom enforcement + is sought. The terms of this Agreement shall not be amended or + changed by any purchase order or acknowledgment even if we have + signed such documents. + +6. North Carolina Law, Severability. This Agreement will be governed + by North Carolina law. If any provision of this Agreement shall be + unlawful, void, or for any reason unenforceable, it shall be deemed + severable from and shall in no way affect the validity or + enforceability of the remaining provisions of this Agreement. + +7. Force Majeure. It is herein agreed that neither party to this + Agreement shall be liable for delays for failures in performance + resulting from acts beyond the control of such party. Such acts + include, without limitation, acts of God, strikes, lockouts, riots, + acts of war, epidemics, governmental regulations superimposed after + the fact, fire, power failures, earthquakes or other disasters. + +*************************************************************************** diff --git a/j3d-core/release-info/pre-release/0-USAGE.txt b/j3d-core/release-info/pre-release/0-USAGE.txt new file mode 100644 index 0000000..58358af --- /dev/null +++ b/j3d-core/release-info/pre-release/0-USAGE.txt @@ -0,0 +1,39 @@ +I. Files for Windows Installer + + README.html : + Modified RELEASE NOTES (with link to install instructions removed) + used as README file for Windows installer + + LICENSE-*.rtf : + rtf version of license used for Windows installer + +II. Files for Unix Installers, Zip Bundles, and Download page + + LICENSE-*.txt : + text version of license used for the zip bundles, the Unix + installers, and in download directory (and pointed to by our + java.net download page) + +III. Files for Zip Bundles + + README.txt : + README file that is included with the zip bundles; contains terms + of use, pointer to LICENSE-*.txt, pointer to README-unzip.html, + and MANIFEST of files in bundle + + README-unzip.html : + README file that is included with the zip bundles; contains + pointer to LICENSE-*.txt plus instructions for manually unzipping + the zip bundle. + +#ifdef FCS_ONLY + README-distribution.txt : + Legal README file that is included with the zip bundles +#endif + +IV. Files for Download page + + README-download.html : + README file used in download directory (and pointed to by our + java.net download page); includes pointer to LICENSE-*.txt plus + HOW_TO_INSTALL.html diff --git a/j3d-core/release-info/pre-release/LICENSE-GPLv2.rtf b/j3d-core/release-info/pre-release/LICENSE-GPLv2.rtf new file mode 100644 index 0000000..824ec62 --- /dev/null +++ b/j3d-core/release-info/pre-release/LICENSE-GPLv2.rtf @@ -0,0 +1,192 @@ +{\rtf1\ansi\deff1\adeflang1025 +{\fonttbl{\f0\froman\fprq2\fcharset0 DejaVu Sans;}{\f1\fnil\fprq0\fcharset0 Times{\*\falt Times New Roman};}{\f2\fnil\fprq0\fcharset0 Times{\*\falt Times New Roman};}{\f3\fnil\fprq0\fcharset0 Helvetica;}{\f4\fnil\fprq2\fcharset0 DejaVu Sans;}} +{\colortbl;\red0\green0\blue0;\red128\green128\blue128;} +{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033\snext1 Normal;} +{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\afs28\lang255\ltrch\dbch\langfe255\hich\f3\fs28\lang1033\loch\f3\fs28\lang1033\sbasedon1\snext3 Heading;} +{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033\sbasedon1\snext3 Body Text;} +{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\fs24\lang1033\loch\fs24\lang1033\sbasedon3\snext4 List;} +{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ai\ltrch\dbch\af4\langfe255\hich\fs24\lang1033\i\loch\fs24\lang1033\i\sbasedon1\snext5 caption;} +{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\fs24\lang1033\loch\fs24\lang1033\sbasedon1\snext6 Index;} +} +{\info{\author Administrator}{\creatim\yr2008\mo1\dy7\hr15\min58}{\revtim\yr1601\mo1\dy1\hr0\min0}{\printim\yr1601\mo1\dy1\hr0\min0}{\comment StarWriter}{\vern6800}}\deftab709 +{\*\pgdsctbl +{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Standard;}} +\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc +\pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 The GNU General Public License (GPL)} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Version 2, June 1991} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Copyright (C) 1989, 1991 Free Software Foundation, Inc.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Preamble} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 it +s 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 sourc +e 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 mo +dify it.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 The precise terms and conditions for copying, distribution and modification follow.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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, trans +lation is included without limitation in the term "modification".) Each licensee is addressed as "you".} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 b +ased on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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: +} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.)} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 oth +er licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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:} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 distri +buted under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.)} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 sc +ripts 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 no +t compelled to copy the source along with the object code.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 thi +s 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 L +icense, 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 entir +ely from distribution of the Program.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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, wh +ich 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 o +r she is willing to distribute software through any other system and a licensee cannot impose that choice.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 limita +tion 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 Softw +are 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 NO WARRANTY} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 WAR +RANTY 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 PROGRA +M PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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, INCIDEN +TAL 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 OTH +ER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 END OF TERMS AND CONDITIONS} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 How to Apply These Terms to Your New Programs} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 fu +ll notice is found.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 One line to give the program's name and a brief idea of what it does.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Copyright (C) } +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Also add information on how to contact you by electronic and paper mail.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 If the program is interactive, make it output a short notice like this when it starts in an interactive mode:} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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--whate +ver suits your program.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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:} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Yoyodyne, Inc., hereby disclaims all copyright interest in the program 'Gnomovision' (which makes passes at compilers) written by James Hacker.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 signature of Ty Coon, 1 April 1989} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Ty Coon, President of Vice} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 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 wa +nt to do, use the GNU Library General Public License instead of this License.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 "CLASSPATH" EXCEPTION TO THE GPL} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Certain source files distributed by Sun Microsystems, Inc. are subject to the following clarification and special exception to the GPL, but only where Sun has expressly included in the particular source file's header the words "Sun designates this particu +lar file as subject to the "Classpath" exception as provided by Sun in the LICENSE file that accompanied this code."} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License cover the whole combination.} +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 +\par \pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\li709\ri0\lin709\rin0\fi0\rtlch\af4\afs24\lang255\ltrch\dbch\af4\langfe255\hich\f1\fs24\lang1033\loch\f1\fs24\lang1033 {\rtlch \ltrch\loch\f1\fs24\lang1033\i0\b0 As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting + executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you +modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.} +\par } diff --git a/j3d-core/release-info/pre-release/LICENSE-GPLv2.txt b/j3d-core/release-info/pre-release/LICENSE-GPLv2.txt new file mode 100644 index 0000000..eeab58c --- /dev/null +++ b/j3d-core/release-info/pre-release/LICENSE-GPLv2.txt @@ -0,0 +1,347 @@ +The GNU General Public License (GPL) + +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. + +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. + + One line to give the program's name and a brief idea of what it does. + + 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. + + signature of Ty Coon, 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. + + +"CLASSPATH" EXCEPTION TO THE GPL + +Certain source files distributed by Sun Microsystems, Inc. are subject to +the following clarification and special exception to the GPL, but only where +Sun has expressly included in the particular source file's header the words +"Sun designates this particular file as subject to the "Classpath" exception +as provided by Sun in the LICENSE file that accompanied this code." + + Linking this library statically or dynamically with other modules is making + a combined work based on this library. Thus, the terms and conditions of + the GNU General Public License cover the whole combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules, + and to copy and distribute the resulting executable under terms of your + choice, provided that you also meet, for each linked independent module, + the terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. If + you modify this library, you may extend this exception to your version of + the library, but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. diff --git a/j3d-core/release-info/pre-release/README-download.html b/j3d-core/release-info/pre-release/README-download.html new file mode 100644 index 0000000..b664be8 --- /dev/null +++ b/j3d-core/release-info/pre-release/README-download.html @@ -0,0 +1,78 @@ + + + + + 3D Graphics API for the Java Platform 1.5.2: Installation Instructions + + +

3D Graphics API for the Java Platform 1.5.2-beta2 Pre-Release

+

This software is licensed by Sun, as specified in the +LICENSE-GPLv2.txt file. You must only +use this software in accordance with the terms under which the code is +licensed. +

+

Instructions for installing the 3D Graphics API for the Java Platform

+

The 1.5.2-beta2 version of the j3d package runs on JDK version +1.5.0 and higher. It has been released for the Windows, Linux, +Solaris, and Mac OS X operating environments. See the +release +notes for more information. +

+ +

Preferred method

+ +

Developers who wish to develop an application using the j3d package +are encouraged to download the j3d-1_5_2-beta2-XXX.zip file for +their platform, and manually install the necessary files into a +directory on their local disk. To do this, unzip the downloaded file, +and follow the instructions in the unzipped README.txt file. +

+ +

Alternative method

+ +

Alternatively, you can run the installer as shown below, keeping in +mind that it is not recommended to install the j3d jar files and +native libraries directly into the JRE. +

+ +

Windows

+

To install the j3d package on Windows, download the binary +installer and then execute it, by double-clicking on the +j3d-1_5_2-beta2-windows-i586.exe (or j3d-1_5_2-beta2-windows-amd64.exe) +icon. +

+ +

Linux or Solaris

+

To install the j3d package on Linux or Solaris, download the +self-extracting binary file, chdir to the desired directory, and then +execute it. For example, on a 32-bit Linux system: +

+
    +cd /myhome/j3d
    +sh /path-to-download-files/j3d-1_5_2-beta2-linux-i586.bin
    +
+ +

After doing this, you will need to modify your CLASSPATH +environment variable to include the full paths to j3dcore.jar, +j3dutils.jar, and vecmath.jar. For example: +

+ +
    +export CLASSPATH=".:/myhome/j3d/lib/ext/j3dcore.jar:/myhome/j3d/lib/ext/j3dutils.jar:/myhome/j3d/lib/ext/vecmath.jar +
+ +

Then modify your LD_LIBRARY_PATH environment variable to contain the +full path to the "lib/ARCH" directory. For example, on 32-bit Linux: +

+ +
    +export LD_LIBRARY_PATH=/myhome/j3d/lib/i386 +
+ +

Mac OS X

+

No installer is available for the Mac OS X operating environment. +You will need to download the j3d-1_5_2-beta2-macosx.zip file, unzip it, +and follow the instructions in the unzipped README.txt file. +

+ + diff --git a/j3d-core/release-info/pre-release/README-unzip.html b/j3d-core/release-info/pre-release/README-unzip.html new file mode 100644 index 0000000..d5fa9c1 --- /dev/null +++ b/j3d-core/release-info/pre-release/README-unzip.html @@ -0,0 +1,210 @@ + + + + + 3D Graphics API for the Java Platform 1.5.2: Unzip +Instructions + + +

3D Graphics API for the Java Platform 1.5.2 Pre-Release

+

This software is licensed by Sun, as specified in the +LICENSE-GPLv2.txt +file. You +must only use this software in accordance with the terms under which +the code is licensed. +

+

Instructions for Unzipping 3D Graphics API for the Java +Platform 1.5.2 Pre-Release

+

The 1.5.2-XXX pre-release version of 3D graphics API for the +Java +platform runs on JDK version 1.5.0 and higher. It has been released +for the Windows, Linux, +Solaris, +and Mac OS X +operating environments. +

+

NOTE: Installing the j3d jars and native libs into the "ext" +directory of the JRE is discouraged, especially on +Mac OS X +where JOGL is used as the rendering engine. Doing so can cause +conflicts with third-party applications launched via Java Web Start, +and causes confusion later when upgrading the distribution. +

+

Windows

+

The 1.5.2 pre-release version of 3D graphics API for the Java +platform for Windows 2000, Windows XP (x86 or amd64), and Windows +Vista runs on JDK version 1.5.0 and +higher. To manually install this build, do the following: +

+
    +
  1. Download and unzip j3d-1_5_2-XXX.zip +(using Windows +Explorer or an unzip tool such as WinZip) to a temporary +download folder, +for example, c:\Downloads. This will +create a j3d-1_5_2-XXX subfolder in +your download folder where the +downloaded files can be found. The file you need for manual +installation is j3d-jre.zip.
    +
    +
  2. +
  3. Create a folder for the j3d jar files and native libraries, +for example, C:\Users\myhome\j3d, and +unzip j3d-jre.zip into this folder.
    +
    +
  4. +
  5. Modify your CLASSPATH environment +variable to include the full paths to j3dcore.jar, + j3dutils.jar, and vecmath.jar. +For example, add the following to your CLASSPATH +variable, +using the System control panel, Advanced tab, Environment Variables +button:
    +
    + .;C:\Users\myhome\j3d\lib\ext\j3dcore.jar;C:\Users\myhome\j3d\lib\ext\j3dutils.jar;C:\Users\myhome\j3d\lib\ext\vecmath.jar +
    +
    +
  6. +
  7. Modify your PATH environment +variable to contain the full path to the lib\i386 +folder (or lib\amd64 for +Windows/x64). For example, on 32-bit Windows, add the following to your + PATH variable, using the System control +panel, Advanced tab, Environment Variables button.
    +
    + C:\Users\myhome\j3d\lib\i386
    +
  8. +
+

At this point your Java installation should be able to see +the j3d class files. Users of IDEs such as NetBeans and Eclipse should +consult the IDE's documentation to see how to add jar files and native +libraries to their current project.
+

+

Linux, +Solaris

+

The 1.5.2 pre-release version of 3D graphics API for the Java +platform +for Linux or Solaris runs on JDK version 1.5.0 and +higher. To manually install this build, do the following:

+
    +
  1. Download and unzip j3d-1_5_2-XXX.zip +into a temporary +download directory, +for example, /tmp. This will +create a j3d-1_5_2-XXX subdirectory +in /tmp where the +downloaded files can be found. The file you need for manual +installation is j3d-jre.zip.
    +
    +
  2. +
  3. Create a folder for the j3d jar files and native libraries, +for example, /myhome/j3d, and +unzip j3d-jre.zip into this directory +as follows:
    +
    +
      + cd /myhome/j3d
      + unzip /tmp/j3d-1_5_2-*/j3d-jre.zip
      +
    +
    +
  4. +
  5. Modify your CLASSPATH environment +variable to include the full paths to j3dcore.jar, + j3dutils.jar, and vecmath.jar. +For example:
    +
    + export +CLASSPATH=.:/myhome/j3d/lib/ext/j3dcore.jar:/myhome/j3d/lib/ext/j3dutils.jar:/myhome/j3d/lib/ext/vecmath.jar
    +
    +
  6. +
  7. Modify your LD_LIBRARY_PATH +environment +variable to contain the full path to the lib/<ARCH> +directory. For example, on 32-bit Linux:
    +
    + export LD_LIBRARY_PATH=/myhome/j3d/lib/i386
    +
  8. +
+

At this point your Java installation should be able to see +the j3d class files. Users of IDEs such as NetBeans and Eclipse should +consult the IDE's documentation to see how to add jar files and native +libraries to their current project. +

+

Mac OS X

+

The 1.5.2 pre-release version of 3D graphics API for the Java +platform +for Mac OS X runs on JDK version 1.5.0 and +higher. To manually install this build, do the following:

+
    +
  1. Download and unzip j3d-1_5_2-XXX.zip +into a temporary +download directory, +for example, /tmp. This will +create a j3d-1_5_2-XXX subdirectory +in /tmp where the +downloaded files can be found. The file you need for manual +installation is j3d-jre.zip.
    +
    +
  2. +
  3. Create a folder for the j3d jar files, +for example, /myhome/j3d, and +unzip j3d-jre.zip into this directory +as follows:
    +
    +
      + cd /myhome/j3d
      + unzip /tmp/j3d-1_5_2-*/j3d-jre.zip
      +
    +
    +
  4. +
  5. Modify your CLASSPATH environment +variable to include the full paths to j3dcore.jar, + j3dutils.jar, and vecmath.jar. +For example:
    +
    + export +CLASSPATH=.:/myhome/j3d/lib/ext/j3dcore.jar:/myhome/j3d/lib/ext/j3dutils.jar:/myhome/j3d/lib/ext/vecmath.jar
    +
  6. +
    +
  7. Download a recent version of JOGL for the Mac +platform into a temporary +download directory, +for example, /tmp.
    +
    +
  8. +
  9. Create a folder for the jogl jar files and native +libraries, +for example, /myhome/jogl, and +unzip jogl-*.zip into this directory +as follows:
    +
    +
      + cd /myhome/jogl
      + unzip /tmp/jogl-*.zip
      +
    +
    +
  10. +
  11. Modify your CLASSPATH environment +variable to include the full paths to jogl.jar +and gluegen-rt.jar. +For example:
    +
    + export +CLASSPATH="${CLASSPATH}:/myhome/jogl/lib/jogl.jar:/myhome/jogl/lib/gluegen-rt.jar
    +
  12. +
    +
  13. Modify your DYLD_LIBRARY_PATH +environment +variable to contain the full path to the lib +directory. For example:
    +
    + export DYLD_LIBRARY_PATH=/myhome/jogl/lib
    +
  14. +
+

At this point your Java installation should be able to see +the j3d and jogl class files. Users of IDEs such as NetBeans and +Eclipse should +consult the IDE's documentation to see how to add jar files and native +libraries to their current project.

+ + diff --git a/j3d-core/release-info/pre-release/README.html b/j3d-core/release-info/pre-release/README.html new file mode 100644 index 0000000..43e6579 --- /dev/null +++ b/j3d-core/release-info/pre-release/README.html @@ -0,0 +1,339 @@ + + + + + Java 3D 1.5.2 Pre-Release Notes + + +

Java 3DTM 1.5.2-beta2 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.2-beta2. +

+ +

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.2-beta2 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.2-beta2 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.2-beta2 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.2-beta2 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.2-beta2 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000, Windows XP, or Windows Vista
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
    + NOTE: The DirectX version of Java 3D is used if a suitable version + of OpenGL cannot be found. Note also that DirectX is chosen by + default on Windows Vista systems with an ATI graphics card (due to + ATI driver bugs). +
+

Mac OS X

+

The 1.5.2-beta2 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.2-beta2

+

Issues Fixed in 1.5.2-beta2

+
+ + + + + + + + + + + + + + + + + + +
Issue  Description
543  J3DClock does not adjust to clock skew
583  A disposed Graphics2D remains in Canvas3D after removal and addtion
+

Improvements in 1.5.2-beta1

+

Enhancements

+
    +
  • Source code license changed to GPL v2 + CLASSPATH
  • +
+

Issues Fixed in 1.5.2-beta1
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
179  OrbitBehavior.setRotationCenter gives spurious view shift
483  NullPointerException when writing Font3D using scenegraph.io
506  NullPointerException: Calling getNominalSensorRotation in WandViewBehavior when internal nominalSensorRotation is null causes a NullPointerException.
513  Down-rev D3D driver can cause JVM to crash
514  NPE in Wonderland : triggered in cached bounds computation
519  IntersectionInfo.getGeometry return null for IndexedArrayGeometry
525  JOALMixer only playing one sample
532  Background geometry BG isn't saved with SceneGraphFileWriter
534  ClassNotFoundException when running applet if Java 3D installed into JRE
538  Machine precision bug in AxisAngle4d and Quat4d
540  ArrayIndexOutOfBoundsException when calling setPickable
541  Bound.closest_point() method creates unused Matrix3d
544  GroupRetained.getBounds() should return BoundingBox?
545  Update docs to discourage installing Java 3D into JRE
548  RFE - Disable getLock() / unLock() on non-alive GeometryArray
555  Muting a PointSound causes a ClassCastException
560  Use D3DCREATE_FPU_PRESERVE flag on D3D pipeline
561  Decrease memory footprint of BoundingBox
562  Error occurs when Canvas3D removed from View
563  Background cloneNode() fails with Background geometry
567  Update license to GPL v2 + CLASSPATH
569  ImageComponent.ALLOW_IMAGE_READ is false
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac OS X +(x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and include it in your PATH/CLASSPATH along with the Java 3D jar files.
+

+

NOTE: Installing the j3d or jogl jars and native libs into the "ext" +directory of the JRE is strongly discouraged. Doing so can cause +conflicts with third-party applications launched via Java Web Start, +and causes confusion later when upgrading the distribution. +

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/release-info/pre-release/README.txt b/j3d-core/release-info/pre-release/README.txt new file mode 100644 index 0000000..8b456ea --- /dev/null +++ b/j3d-core/release-info/pre-release/README.txt @@ -0,0 +1,36 @@ +3D Graphics API for the Java Platform 1.5.2 Pre-Release +------------------------------------------------------- + +This software is licensed by Sun under terms of the GNU General +Public License version 2 as specified in the LICENSE-GPLv2.txt +file and on the web at http://openjdk.java.net/legal/gplv2+ce.html + +This binary pre-release of the 3D graphics API for the Java platform +1.5.2 is an intermediate build of the software. The code is untested +and presumed incompatible with the Java 3D(TM) API specification. You +must only use this code in accordance with the terms under which the +code is licensed. + +If you prefer to use a tested and certified compatible version of the +code, then you can download a binary release for the Solaris, Linux, +Windows, and Mac OS X operating environments at: + https://java3d.dev.java.net/binary-builds.html +or at: + http://java.sun.com/products/java-media/3D/ + + +Instructions for unzipping 3D graphics API for the Java platform 1.5.2 +---------------------------------------------------------------------- + +After downloading and unzipping the j3d-1_5_2-XXX.zip file +into a temporary directory, for example, "/tmp", you will see +the following files in the j3d-1_5_2-XXX directory: + + COPYRIGHT.txt Copyright notice + LICENSE-GPLv2.txt Software License Agreement + README-unzip.html Instructions for manually installing the release + README.txt README file (you are reading it now) + j3d-jre.zip Zip file containing the files to be installed + +To manually install 3D graphics API for the Java platform, open +README-unzip.html in your browser and follow the instructions. diff --git a/j3d-core/release-info/src-release/j3d/README.txt b/j3d-core/release-info/src-release/j3d/README.txt new file mode 100644 index 0000000..c859ec1 --- /dev/null +++ b/j3d-core/release-info/src-release/j3d/README.txt @@ -0,0 +1,25 @@ +The source code in this directory is copyrighted code that is licensed +to individuals or companies who download or otherwise access the code. + +The javax subdirectory contains the source code for the j3d-core +project. The com subdirectory contains the source code for the +j3d-core-utils project. + +The copyright notice for the j3d-core source code is in the +javax/COPYRIGHT.txt file. The copyright notice for the j3d-core-utils +source code is in the com/COPYRIGHT.txt file. + +The license terms for the j3d-core and j3d-core-utils projects are +different. A separate source code license is used for each project. +The license for the j3d-core source code is in the javax/LICENSE.txt +file. The license for the j3d-core-utils source code is in the +com/LICENSE.txt file. + +Additional information and license restrictions for third party source +code are found in the javax/THIRDPARTY-LICENSE-*.txt and +com/THIRDPARTY-LICENSE-*.txt files. + +Note that the source files in this directory are not sufficient to +build the 3D graphics packages. If you want to build the 3D packages, +you can use CVS to get a complete source tree. See +https://j3d-core.dev.java.net/build-instr.html for more information. diff --git a/j3d-core/release-info/src-release/vecmath/README.txt b/j3d-core/release-info/src-release/vecmath/README.txt new file mode 100644 index 0000000..ab5e522 --- /dev/null +++ b/j3d-core/release-info/src-release/vecmath/README.txt @@ -0,0 +1,13 @@ +The source code in this directory is copyrighted code that is licensed +to individuals or companies who download or otherwise access the code. + +The copyright notice for the vecmath source code is in the +javax/COPYRIGHT.txt file. + +The license for the vecmath source code is in the javax/LICENSE.txt +file. + +Note that the source files in this directory are not sufficient to +build vecmath. If you want to build vecmath, you can use CVS to get a +complete source tree. See +https://vecmath.dev.java.net/build-instr.html for more information. diff --git a/j3d-core/src/classes/J3dVersion b/j3d-core/src/classes/J3dVersion new file mode 100644 index 0000000..52295ff --- /dev/null +++ b/j3d-core/src/classes/J3dVersion @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Specification-Title: @SPEC_TITLE@ +Specification-Version: 1.5 +Specification-Vendor: @SPEC_VENDOR@ +Implementation-Title: @IMPL_TITLE@ +Implementation-Version: @VERSION_BASE@ +Implementation-Vendor: @IMPL_VENDOR@ +Extension-Name: javax.media.j3d +Implementation-Vendor-Id: @IMPL_VENDOR_ID@ diff --git a/j3d-core/src/classes/build.xml b/j3d-core/src/classes/build.xml new file mode 100644 index 0000000..a5a99bf --- /dev/null +++ b/j3d-core/src/classes/build.xml @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderInfo.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderInfo.java new file mode 100755 index 0000000..37ddb88 --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderInfo.java @@ -0,0 +1,51 @@ +/* + * $RCSfile: JoglCgShaderInfo.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import com.sun.opengl.cg.*; + +class JoglCgShaderInfo extends JoglShaderObject { + private CGprogram cgShader; + private int j3dShaderType; + private int shaderProfile; + + JoglCgShaderInfo() { + super(0); + } + + public void setCgShader(CGprogram shader) { cgShader = shader; } + public CGprogram getCgShader() { return cgShader; } + public void setJ3DShaderType(int type) { j3dShaderType = type; } + public int getJ3DShaderType() { return j3dShaderType; } + public void setShaderProfile(int shaderProfile) { this.shaderProfile = shaderProfile; } + public int getShaderProfile() { return shaderProfile; } +} diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderParameter.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderParameter.java new file mode 100755 index 0000000..a830928 --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderParameter.java @@ -0,0 +1,54 @@ +/* + * $RCSfile: JoglCgShaderParameter.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import com.sun.opengl.cg.*; + +class JoglCgShaderParameter extends JoglShaderObject { + private CGparameter vParam; + private CGparameter fParam; + + JoglCgShaderParameter(CGparameter vParam, + CGparameter fParam) { + super(0); + this.vParam = vParam; + this.fParam = fParam; + } + + CGparameter vParam() { + return vParam; + } + + CGparameter fParam() { + return fParam; + } +} diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderProgramInfo.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderProgramInfo.java new file mode 100755 index 0000000..9db747f --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglCgShaderProgramInfo.java @@ -0,0 +1,57 @@ +/* + * $RCSfile: JoglCgShaderProgramInfo.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import com.sun.opengl.cg.*; + +class JoglCgShaderProgramInfo extends JoglShaderObject { + private JoglCgShaderInfo vShader; // vertex shader + private JoglCgShaderInfo fShader; // fragment shader + // Array of parameters for (varying) vertex attributes + private CGparameter[] vtxAttrs; + + JoglCgShaderProgramInfo() { + super(0); + } + + public JoglCgShaderInfo getVertexShader() { return vShader; } + public void setVertexShader(JoglCgShaderInfo info) { vShader = info; } + public JoglCgShaderInfo getFragmentShader() { return fShader; } + public void setFragmentShader(JoglCgShaderInfo info) { fShader = info; } + public CGparameter[] getVertexAttributes() { return vtxAttrs; } + public void setVertexAttributes(CGparameter[] attrs) { vtxAttrs = attrs; } + public int getNumVertexAttributes() { + if (vtxAttrs == null) + return 0; + return vtxAttrs.length; + } +} diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglContext.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglContext.java new file mode 100644 index 0000000..06443fe --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglContext.java @@ -0,0 +1,250 @@ +/* + * $RCSfile: JoglContext.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.nio.*; +import javax.media.opengl.*; +import com.sun.opengl.cg.*; + +/** + * Graphics context objects for Jogl rendering pipeline. + */ +class JoglContext implements Context { + private GLContext context; + + // Properties we need to keep track of for efficiency + private int maxTexCoordSets; + private float alphaClearValue; + private int currentTextureUnit; + private int currentCombinerUnit; + private boolean hasMultisample; + + // Needed for vertex attribute implementation + private JoglShaderObject shaderProgram; + + // Implementation of vertex attribute methods + static interface VertexAttributeImpl { + public void vertexAttrPointer(GL gl, + int index, int size, int type, int stride, Buffer pointer); + public void enableVertexAttrArray(GL gl, int index); + public void disableVertexAttrArray(GL gl, int index); + public void vertexAttr1fv(GL gl, int index, FloatBuffer buf); + public void vertexAttr2fv(GL gl, int index, FloatBuffer buf); + public void vertexAttr3fv(GL gl, int index, FloatBuffer buf); + public void vertexAttr4fv(GL gl, int index, FloatBuffer buf); + } + private VertexAttributeImpl vertexAttrImpl; + + class CgVertexAttributeImpl implements VertexAttributeImpl { + public void vertexAttrPointer(GL gl, + int index, int size, int type, int stride, Buffer pointer) { + JoglCgShaderProgramInfo shaderProgramInfo = (JoglCgShaderProgramInfo) shaderProgram; + if (shaderProgramInfo != null && index < shaderProgramInfo.getNumVertexAttributes()) { + CgGL.cgGLSetParameterPointer(shaderProgramInfo.getVertexAttributes()[index], + size, type, stride, pointer); + } else { + if (shaderProgramInfo == null) { + System.err.println(" shaderProgramInfo is null"); + } else { + System.err.println(" index (" + index + ") out of range: numVtxAttrs = " + + shaderProgramInfo.getNumVertexAttributes()); + } + } + } + + public void enableVertexAttrArray(GL gl, int index) { + JoglCgShaderProgramInfo shaderProgramInfo = (JoglCgShaderProgramInfo) shaderProgram; + if (shaderProgramInfo != null && index < shaderProgramInfo.getNumVertexAttributes()) { + CgGL.cgGLEnableClientState(shaderProgramInfo.getVertexAttributes()[index]); + } else { + if (shaderProgramInfo == null) { + System.err.println(" shaderProgramInfo is null"); + } else { + System.err.println(" index (" + index + ") out of range: numVtxAttrs = " + + shaderProgramInfo.getNumVertexAttributes()); + } + } + } + + public void disableVertexAttrArray(GL gl, int index) { + JoglCgShaderProgramInfo shaderProgramInfo = (JoglCgShaderProgramInfo) shaderProgram; + if (shaderProgramInfo != null && index < shaderProgramInfo.getNumVertexAttributes()) { + CgGL.cgGLDisableClientState(shaderProgramInfo.getVertexAttributes()[index]); + } else { + if (shaderProgramInfo == null) { + System.err.println(" shaderProgramInfo is null"); + } else { + System.err.println(" index (" + index + ") out of range: numVtxAttrs = " + + shaderProgramInfo.getNumVertexAttributes()); + } + } + } + + // NOTE: we should never get here. These functions are only called + // when building display lists for geometry arrays with vertex + // attributes, and such display lists are disabled in Cg mode. + public void vertexAttr1fv(GL gl, int index, FloatBuffer buf) { + throw new RuntimeException("Java 3D ERROR : Assertion failed: invalid call to cgVertexAttr1fv"); + } + + public void vertexAttr2fv(GL gl, int index, FloatBuffer buf) { + throw new RuntimeException("Java 3D ERROR : Assertion failed: invalid call to cgVertexAttr2fv"); + } + + public void vertexAttr3fv(GL gl, int index, FloatBuffer buf) { + throw new RuntimeException("Java 3D ERROR : Assertion failed: invalid call to cgVertexAttr3fv"); + } + + public void vertexAttr4fv(GL gl, int index, FloatBuffer buf) { + throw new RuntimeException("Java 3D ERROR : Assertion failed: invalid call to cgVertexAttr4fv"); + } + } + + class GLSLVertexAttributeImpl implements VertexAttributeImpl { + public void vertexAttrPointer(GL gl, + int index, int size, int type, int stride, Buffer pointer) { + gl.glVertexAttribPointerARB(index + glslVertexAttrOffset, + size, type, false, stride, pointer); + } + + public void enableVertexAttrArray(GL gl, int index) { + gl.glEnableVertexAttribArrayARB(index + glslVertexAttrOffset); + } + + public void disableVertexAttrArray(GL gl, int index) { + gl.glDisableVertexAttribArrayARB(index + glslVertexAttrOffset); + } + + public void vertexAttr1fv(GL gl, int index, FloatBuffer buf) { + gl.glVertexAttrib1fvARB(index + glslVertexAttrOffset, buf); + } + + public void vertexAttr2fv(GL gl, int index, FloatBuffer buf) { + gl.glVertexAttrib2fvARB(index + glslVertexAttrOffset, buf); + } + + public void vertexAttr3fv(GL gl, int index, FloatBuffer buf) { + gl.glVertexAttrib3fvARB(index + glslVertexAttrOffset, buf); + } + + public void vertexAttr4fv(GL gl, int index, FloatBuffer buf) { + gl.glVertexAttrib4fvARB(index + glslVertexAttrOffset, buf); + } + } + + // Only used when GLSL shader library is active + private int glslVertexAttrOffset; + + // Only used when Cg shader library is active + private CGcontext cgContext; + private int cgVertexProfile; + private int cgFragmentProfile; + + JoglContext(GLContext context) { + this.context = context; + } + + GLContext getGLContext() { + return context; + } + + int getMaxTexCoordSets() { return maxTexCoordSets; } + void setMaxTexCoordSets(int val) { maxTexCoordSets = val; } + float getAlphaClearValue() { return alphaClearValue; } + void setAlphaClearValue(float val) { alphaClearValue = val; } + int getCurrentTextureUnit() { return currentTextureUnit; } + void setCurrentTextureUnit(int val) { currentTextureUnit = val; } + int getCurrentCombinerUnit() { return currentCombinerUnit; } + void setCurrentCombinerUnit(int val) { currentCombinerUnit = val; } + boolean getHasMultisample() { return hasMultisample; } + void setHasMultisample(boolean val){ hasMultisample = val; } + + // Helpers for vertex attribute methods + void initCgVertexAttributeImpl() { + if (vertexAttrImpl != null) { + throw new RuntimeException("Should not initialize the vertex attribute implementation twice"); + } + vertexAttrImpl = new CgVertexAttributeImpl(); + } + + void initGLSLVertexAttributeImpl() { + if (vertexAttrImpl != null) { + throw new RuntimeException("Should not initialize the vertex attribute implementation twice"); + } + vertexAttrImpl = new GLSLVertexAttributeImpl(); + } + + void vertexAttrPointer(GL gl, + int index, int size, int type, int stride, Buffer pointer) { + vertexAttrImpl.vertexAttrPointer(gl, index, size, type, stride, pointer); + } + + void enableVertexAttrArray(GL gl, int index) { + vertexAttrImpl.enableVertexAttrArray(gl, index); + } + + void disableVertexAttrArray(GL gl, int index) { + vertexAttrImpl.disableVertexAttrArray(gl, index); + } + + void vertexAttr1fv(GL gl, int index, FloatBuffer buf) { + vertexAttrImpl.vertexAttr1fv(gl, index, buf); + } + + void vertexAttr2fv(GL gl, int index, FloatBuffer buf) { + vertexAttrImpl.vertexAttr2fv(gl, index, buf); + } + + void vertexAttr3fv(GL gl, int index, FloatBuffer buf) { + vertexAttrImpl.vertexAttr3fv(gl, index, buf); + } + + void vertexAttr4fv(GL gl, int index, FloatBuffer buf) { + vertexAttrImpl.vertexAttr4fv(gl, index, buf); + } + + // Used in vertex attribute implementation + JoglShaderObject getShaderProgram() { return shaderProgram; } + void setShaderProgram(JoglShaderObject object) { shaderProgram = object; } + + // Only used when GLSL shaders are in use + int getGLSLVertexAttrOffset() { return glslVertexAttrOffset; } + void setGLSLVertexAttrOffset(int offset) { glslVertexAttrOffset = offset; } + + // Only used when Cg shaders are in use + CGcontext getCgContext() { return cgContext; } + void setCgContext(CGcontext c) { cgContext = c; } + int getCgVertexProfile() { return cgVertexProfile; } + void setCgVertexProfile(int p) { cgVertexProfile = p; } + int getCgFragmentProfile() { return cgFragmentProfile; } + void setCgFragmentProfile(int p) { cgFragmentProfile = p; } +} diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglDrawable.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglDrawable.java new file mode 100755 index 0000000..b1f49ba --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglDrawable.java @@ -0,0 +1,49 @@ +/* + * $RCSfile: JoglDrawable.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.media.opengl.*; + +/** + * Drawable class for the Jogl rendering pipeline. + */ +class JoglDrawable implements Drawable { + private GLDrawable drawable; + + JoglDrawable(GLDrawable drawable) { + this.drawable = drawable; + } + + GLDrawable getGLDrawable() { + return drawable; + } +} diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglDrawingSurfaceObject.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglDrawingSurfaceObject.java new file mode 100644 index 0000000..ed35952 --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglDrawingSurfaceObject.java @@ -0,0 +1,79 @@ +/* + * $RCSfile: JoglDrawingSurfaceObject.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The DrawingSurfaceObject class is used to manage native drawing surface + */ +class JoglDrawingSurfaceObject extends DrawingSurfaceObject { + + JoglDrawingSurfaceObject(Canvas3D cv) { + super(cv); + + // System.err.println("JoglDrawingSurfaceObject constructed"); + } + + synchronized boolean renderLock() { + // System.err.println("JoglDrawingSurfaceObject.renderLock()"); + gotDsiLock = true; + return true; + } + + synchronized void unLock() { + // System.err.println("JoglDrawingSurfaceObject.unLock()"); + gotDsiLock = false; + } + + synchronized void getDrawingSurfaceObjectInfo() { + // FIXME: we don't have all of the information we need here to + // create a GLDrawable for the Canvas3D, so for now, do nothing + + // FIXME: this mechanism is much too complicated + + /* + System.err.println("JoglDrawingSurfaceObject.getDrawingSurfaceObjectInfo()"); + + if (canvas.drawable == null) { + System.err.println( + "JoglDrawingSurfaceObject.getDrawingSurfaceObjectInfo: window = " + + canvas.drawable); + + // TODO: replace with a real JoglDrawable + canvas.drawable = new JoglDrawable(); + } + */ + } + + synchronized void invalidate() { + System.err.println("JoglDrawingSurfaceObject.invalidate()"); + } +} diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglGraphicsConfiguration.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglGraphicsConfiguration.java new file mode 100755 index 0000000..bdc1b78 --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglGraphicsConfiguration.java @@ -0,0 +1,122 @@ +/* + * $RCSfile: JoglGraphicsConfiguration.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.*; +import java.awt.geom.*; +import java.awt.image.*; +import javax.media.opengl.*; + +/** + * Class implementing the GraphicsConfiguration API, but not a "real" + * GraphicsConfiguration object. Wraps a GLCapabilities object and + * supports either immediate or deferred pixel format / visual + * selection depending on which platform we are running. + */ + +class JoglGraphicsConfiguration extends GraphicsConfiguration { + private GLCapabilities caps; + private int chosenIndex; + private GraphicsDevice device; + // Needed for Screen3D + private int width; + private int height; + + JoglGraphicsConfiguration(GLCapabilities caps, int chosenIndex, GraphicsDevice device) { + super(); + this.caps = caps; + this.chosenIndex = chosenIndex; + this.device = device; + DisplayMode m = device.getDisplayMode(); + width = m.getWidth(); + height = m.getHeight(); + } + + GLCapabilities getGLCapabilities() { + return caps; + } + + int getChosenIndex() { + return chosenIndex; + } + + public BufferedImage createCompatibleImage(int width, int height) { + throw new RuntimeException("Unimplemented"); + } + + public BufferedImage createCompatibleImage(int width, int height, + int transparency) { + throw new RuntimeException("Unimplemented"); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height) { + throw new RuntimeException("Unimplemented"); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency) { + throw new RuntimeException("Unimplemented"); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps) throws AWTException { + throw new RuntimeException("Unimplemented"); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps, int transparency) throws AWTException { + throw new RuntimeException("Unimplemented"); + } + + public Rectangle getBounds() { + return new Rectangle(0, 0, width, height); + } + + public ColorModel getColorModel() { + throw new RuntimeException("Unimplemented"); + } + + public ColorModel getColorModel(int transparency) { + throw new RuntimeException("Unimplemented"); + } + + public AffineTransform getDefaultTransform() { + throw new RuntimeException("Unimplemented"); + } + + public GraphicsDevice getDevice() { + return device; + } + + public AffineTransform getNormalizingTransform() { + throw new RuntimeException("Unimplemented"); + } +} diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglPipeline.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglPipeline.java new file mode 100644 index 0000000..92a5f3c --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglPipeline.java @@ -0,0 +1,9406 @@ +/* + * $RCSfile: JoglPipeline.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.23 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import com.sun.j3d.internal.ByteBufferWrapper; +import java.awt.*; +import java.io.*; +import java.lang.reflect.*; +import java.nio.*; +import java.security.*; +import java.util.*; +import java.util.regex.*; +import javax.media.opengl.*; +import javax.media.opengl.glu.*; +import com.sun.opengl.cg.*; +import com.sun.opengl.util.*; + +/** + * Concrete implementation of Pipeline class for the JOGL rendering + * pipeline. + */ +class JoglPipeline extends Pipeline { + + // Flags indicating whether the Cg or GLSL libraries are available. + private boolean cgLibraryAvailable = false; + + // Currently prints for entry points not yet implemented + private static final boolean DEBUG = true; + // Currently prints for entry points already implemented + private static final boolean VERBOSE = false; + // Debugging output for graphics configuration selection + private static final boolean DEBUG_CONFIG = false; + // Prints extra debugging information + private static final boolean EXTRA_DEBUGGING = false; + // Number of milliseconds to wait for windows to pop up on screen + private static final int WAIT_TIME = 1000; + // Configurable constant just in case we want to change this later + private static final int MIN_FRAME_SIZE = 1; + + /** + * Constructor for singleton JoglPipeline instance + */ + protected JoglPipeline() { + } + + /** + * Initialize the pipeline + */ + void initialize(Pipeline.Type pipelineType) { + super.initialize(pipelineType); + + assert pipelineType == Pipeline.Type.JOGL; + + // Java3D maintains strict control over which threads perform OpenGL work + Threading.disableSingleThreading(); + + // TODO: finish this with any other needed initialization + } + + /** + * Load all of the required libraries + */ + void loadLibraries(int globalShadingLanguage) { + if (globalShadingLanguage == Shader.SHADING_LANGUAGE_CG) { + // Try to load the jogl_cg library and set the + // cgLibraryAvailable flag to true if loads successfully; note + // that successfully performing initialization of this class + // will cause the Cg native library to be loaded on our behalf + try { + Class.forName("com.sun.opengl.cg.CgGL"); + cgLibraryAvailable = true; + } catch (Exception ex) { + System.err.println(ex); + } catch (Error ex) { + System.err.println(ex); + } + } + } + + /** + * Returns true if the Cg library is loaded and available. Note that this + * does not necessarily mean that Cg is supported by the graphics card. + */ + boolean isCgLibraryAvailable() { + return cgLibraryAvailable; + } + + /** + * Returns true if the GLSL library is loaded and available. Note that this + * does not necessarily mean that GLSL is supported by the graphics card. + */ + boolean isGLSLLibraryAvailable() { + return true; + } + + + // --------------------------------------------------------------------- + + // + // GeometryArrayRetained methods + // + + // Used by D3D to free vertex buffer + void freeD3DArray(GeometryArrayRetained geo, boolean deleteVB) { + // Nothing to do + } + + // used for GeometryArrays by Copy or interleaved + void execute(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texUnitOffset, + int numActiveTexUnitState, + int vertexAttrCount, int[] vertexAttrSizes, + float[] varray, float[] carray, int cDirty) { + if (VERBOSE) System.err.println("JoglPipeline.execute()"); + + executeGeometryArray(ctx, geo, geo_type, isNonUniformScale, useAlpha, + ignoreVertexColors, startVIndex, vcount, vformat, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, + texUnitOffset, numActiveTexUnitState, + vertexAttrCount, vertexAttrSizes, + varray, null, carray, cDirty); + } + + // used by GeometryArray by Reference with java arrays + void executeVA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, float[] vfcoords, double[] vdcoords, + int initialColorIndex, float[] cfdata, byte[] cbdata, + int initialNormalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, float[][] vertexAttrData, + int texCoordMapLength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty) { + if (VERBOSE) System.err.println("JoglPipeline.executeVA()"); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = getTexCoordSetBuffer(texCoords); + } + + // get coordinate array + if (floatCoordDefined) { + fverts = getVertexArrayBuffer(vfcoords); + } else if (doubleCoordDefined) { + dverts = getVertexArrayBuffer(vdcoords); + } + + // get color array + if (floatColorsDefined) { + fclrs = getColorArrayBuffer(cfdata); + } else if (byteColorsDefined) { + bclrs = getColorArrayBuffer(cbdata); + } + + // get normal array + if (normalsDefined) { + norms = getNormalArrayBuffer(ndata); + } + + int[] sarray = null; + int[] start_array = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + strip_len = sarray.length; + start_array = ((GeometryStripArrayRetained) geo).stripStartOffsetIndices; + } + + executeGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, + initialCoordIndex, fverts, dverts, + initialColorIndex, fclrs, bclrs, + initialNormalIndex, norms, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrBufs, + texCoordMapLength, + texcoordoffset, numActiveTexUnitState, + texIndex, texstride, texCoordBufs, cdirty, + sarray, strip_len, start_array); + } + + // used by GeometryArray by Reference with NIO buffer + void executeVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, + Object vcoords, + int initialColorIndex, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + int initialNormalIndex, Object ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, Object[] vertexAttrData, + int texCoordMapLength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty) { + if (VERBOSE) System.err.println("JoglPipeline.executeVABuffer()"); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = new FloatBuffer[texCoords.length]; + for (int i = 0; i < texCoords.length; i++) { + texCoordBufs[i] = (FloatBuffer) texCoords[i]; + } + } + + // get coordinate array + if (floatCoordDefined) { + fverts = (FloatBuffer) vcoords; + } else if (doubleCoordDefined) { + dverts = (DoubleBuffer) vcoords; + } + + if (fverts == null && dverts == null) { + return; + } + + // get color array + if (floatColorsDefined) { + if (cfdata != null) + fclrs = getColorArrayBuffer(cfdata); + else + fclrs = (FloatBuffer) cdataBuffer; + } else if (byteColorsDefined) { + if (cbdata != null) + bclrs = getColorArrayBuffer(cbdata); + else + bclrs = (ByteBuffer) cdataBuffer; + } + + // get normal array + if (normalsDefined) { + norms = (FloatBuffer) ndata; + } + + int[] sarray = null; + int[] start_array = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + strip_len = sarray.length; + start_array = ((GeometryStripArrayRetained) geo).stripStartOffsetIndices; + } + + executeGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, + initialCoordIndex, fverts, dverts, + initialColorIndex, fclrs, bclrs, + initialNormalIndex, norms, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrBufs, + texCoordMapLength, + texcoordoffset, numActiveTexUnitState, + texIndex, texstride, texCoordBufs, cdirty, + sarray, strip_len, start_array); + } + + // used by GeometryArray by Reference in interleaved format with NIO buffer + void executeInterleavedBuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texUnitOffset, + int numActiveTexUnit, + Object varray, float[] cdata, int cdirty) { + if (VERBOSE) System.err.println("JoglPipeline.executeInterleavedBuffer()"); + + executeGeometryArray(ctx, geo, geo_type, + isNonUniformScale, useAlpha, ignoreVertexColors, + startVIndex, vcount, vformat, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, + texUnitOffset, numActiveTexUnit, 0, null, + null, (Buffer) varray, cdata, cdirty); + } + + void setVertexFormat(Context ctx, GeometryArrayRetained geo, + int vformat, boolean useAlpha, boolean ignoreVertexColors) { + if (VERBOSE) System.err.println("JoglPipeline.setVertexFormat()"); + + GL gl = context(ctx).getGL(); + + // Enable and disable the appropriate pointers + if ((vformat & GeometryArray.NORMALS) != 0) { + gl.glEnableClientState(GL.GL_NORMAL_ARRAY); + } else { + gl.glDisableClientState(GL.GL_NORMAL_ARRAY); + } + if (!ignoreVertexColors && ((vformat & GeometryArray.COLOR) != 0)) { + gl.glEnableClientState(GL.GL_COLOR_ARRAY); + } else { + gl.glDisableClientState(GL.GL_COLOR_ARRAY); + } + + if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { + if (useAlpha) { + gl.glEnable(GL.GL_GLOBAL_ALPHA_SUN); + } else { + gl.glDisable(GL.GL_GLOBAL_ALPHA_SUN); + } + } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + gl.glEnableClientState(GL.GL_VERTEX_ARRAY); + } else { + gl.glDisableClientState(GL.GL_VERTEX_ARRAY); + } + } + + void disableGlobalAlpha(Context ctx, GeometryArrayRetained geo, int vformat, + boolean useAlpha, boolean ignoreVertexColors) { + if (VERBOSE) System.err.println("JoglPipeline.disableGlobalAlpha()"); + + GL gl = context(ctx).getGL(); + + if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { + if (!ignoreVertexColors && ((vformat & GeometryArray.COLOR) != 0)) { + if (useAlpha) { + gl.glDisable(GL.GL_GLOBAL_ALPHA_SUN); + } + } + } + } + + // used for GeometryArrays + void buildGA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int startVIndex, + int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, int[] texCoordSetMapOffset, + int vertexAttrCount, int[] vertexAttrSizes, + double[] xform, double[] nxform, + float[] varray) { + if (VERBOSE) System.err.println("JoglPipeline.buildGA()"); + JoglContext jctx = (JoglContext) ctx; + GL gl = context(ctx).getGL(); + FloatBuffer verts = null; + int stride = 0, coordoff = 0, normoff = 0, coloroff = 0, texCoordoff = 0; + int texStride = 0; + int vAttrOff = 0; + if ((vformat & GeometryArray.COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GeometryArray.NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + + if ((vformat & GeometryArray.COLOR) != 0) { + if ((vformat & GeometryArray.BY_REFERENCE) != 0) { + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + stride += 4; + normoff += 4; + coordoff += 4; + } else { + stride += 3; + normoff += 3; + coordoff += 3; + } + } else { + stride += 4; + normoff += 4; + coordoff += 4; + } + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texStride = 2 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texStride = 3 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + int vAttrStride = 0; + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + vAttrStride += vertexAttrSizes[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + int bstride = stride * BufferUtil.SIZEOF_FLOAT; + // Start sending down from the startVIndex + int initialOffset = startVIndex * stride; + normoff += initialOffset; + coloroff += initialOffset; + coordoff += initialOffset; + texCoordoff += initialOffset; + vAttrOff += initialOffset; + + // process alpha for geometryArray without alpha + boolean useAlpha = false; + if (updateAlpha && !ignoreVertexColors) { + useAlpha = true; + } + + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + int[] sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + + int primType = 0; + switch (geo_type) { + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET : + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET : + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET : + primType = GL.GL_LINE_STRIP; + break; + } + + if (ignoreVertexColors) { + vformat &= ~GeometryArray.COLOR; + } + + for (int i = 0; i < sarray.length; i++) { + gl.glBegin(primType); + for (int j = 0; j < sarray[i]; j++) { + if ((vformat & GeometryArray.NORMALS) != 0) { + if (nxform != null) { + float nx = (float) (nxform[0] * varray[normoff] + + nxform[1] * varray[normoff+1] + + nxform[2] * varray[normoff+2]); + float ny = (float) (nxform[4] * varray[normoff] + + nxform[5] * varray[normoff+1] + + nxform[6] * varray[normoff+2]); + float nz = (float) (nxform[8] * varray[normoff] + + nxform[9] * varray[normoff+1] + + nxform[10] * varray[normoff+2]); + gl.glNormal3f(nx, ny, nz); + } else { + gl.glNormal3f(varray[normoff], varray[normoff+1], varray[normoff+2]); + } + } + if ((vformat & GeometryArray.COLOR) != 0) { + if (useAlpha) { + gl.glColor4f(varray[coloroff], + varray[coloroff+1], + varray[coloroff+2], + varray[coloroff+3] * alpha); + } else { + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { // alpha is present + gl.glColor4f(varray[coloroff], + varray[coloroff+1], + varray[coloroff+2], + varray[coloroff+3]); + } else { + gl.glColor3f(varray[coloroff], + varray[coloroff+1], + varray[coloroff+2]); + } + } + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vaOff = vAttrOff; + if (verts == null) { + verts = FloatBuffer.wrap(varray); + } + for (int vaIdx = 0; vaIdx < vertexAttrCount; vaIdx++) { + switch (vertexAttrSizes[vaIdx]) { + case 1: + verts.position(vaOff); + jctx.vertexAttr1fv(gl, vaIdx, verts); + break; + case 2: + verts.position(vaOff); + jctx.vertexAttr2fv(gl, vaIdx, verts); + break; + case 3: + verts.position(vaOff); + jctx.vertexAttr3fv(gl, vaIdx, verts); + break; + case 4: + verts.position(vaOff); + jctx.vertexAttr4fv(gl, vaIdx, verts); + break; + } + + vaOff += vertexAttrSizes[vaIdx]; + } + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if (texCoordSetMapLen > 0) { + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord2f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1]); + } + } + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord3f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1], + varray[off + 2]); + } + } + } else { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord4f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1], + varray[off + 2], + varray[off + 3]); + } + } + } + } else { // no multitexture + if (texCoordSetMapOffset[0] != -1) { + int off = texCoordoff + texCoordSetMapOffset[0]; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + gl.glTexCoord2f(varray[off], varray[off + 1]); + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + gl.glTexCoord3f(varray[off], varray[off + 1], varray[off + 2]); + } else { + gl.glTexCoord4f(varray[off], varray[off + 1], varray[off + 2], varray[off + 3]); + } + } + } // no multitexture + } + // texCoordSetMapLen can't be 0 if texture coordinates + // is to be specified + } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + if (xform != null) { + // transform the vertex data with the static transform + float w = (float) (xform[12] * varray[coordoff] + + xform[13] * varray[coordoff+1] + + xform[14] * varray[coordoff+2] + + xform[15]); + float winv = 1.0f/w; + float vx = (float) (xform[0] * varray[coordoff] + + xform[1] * varray[coordoff+1] + + xform[2] * varray[coordoff+2] + + xform[3]) * winv; + float vy = (float) (xform[4] * varray[coordoff] + + xform[5] * varray[coordoff+1] + + xform[6] * varray[coordoff+2] + + xform[7]) * winv; + float vz = (float) (xform[8] * varray[coordoff] + + xform[9] * varray[coordoff+1] + + xform[10] * varray[coordoff+2] + + xform[11]) * winv; + gl.glVertex3f(vx, vy, vz); + } else { + gl.glVertex3f(varray[coordoff], varray[coordoff + 1], varray[coordoff + 2]); + } + } + normoff += stride; + coloroff += stride; + coordoff += stride; + texCoordoff += stride; + vAttrOff += stride; + } + gl.glEnd(); + } + } else if ((geo_type == GeometryRetained.GEO_TYPE_QUAD_SET) || + (geo_type == GeometryRetained.GEO_TYPE_TRI_SET) || + (geo_type == GeometryRetained.GEO_TYPE_POINT_SET) || + (geo_type == GeometryRetained.GEO_TYPE_LINE_SET)) { + int primType = 0; + switch (geo_type) { + case GeometryRetained.GEO_TYPE_QUAD_SET : + primType = GL.GL_QUADS; + break; + case GeometryRetained.GEO_TYPE_TRI_SET : + primType = GL.GL_TRIANGLES; + break; + case GeometryRetained.GEO_TYPE_POINT_SET : + primType = GL.GL_POINTS; + break; + case GeometryRetained.GEO_TYPE_LINE_SET : + primType = GL.GL_LINES; + break; + } + + if (ignoreVertexColors) { + vformat &= ~GeometryArray.COLOR; + } + + gl.glBegin(primType); + for (int j = 0; j < vcount; j++) { + if ((vformat & GeometryArray.NORMALS) != 0) { + if (nxform != null) { + float nx = (float) (nxform[0] * varray[normoff] + + nxform[1] * varray[normoff+1] + + nxform[2] * varray[normoff+2]); + float ny = (float) (nxform[4] * varray[normoff] + + nxform[5] * varray[normoff+1] + + nxform[6] * varray[normoff+2]); + float nz = (float) (nxform[8] * varray[normoff] + + nxform[9] * varray[normoff+1] + + nxform[10] * varray[normoff+2]); + gl.glNormal3f(nx, ny, nz); + } else { + gl.glNormal3f(varray[normoff], varray[normoff + 1], varray[normoff + 2]); + } + } + if ((vformat & GeometryArray.COLOR) != 0) { + if (useAlpha) { + float cr, cg, cb, ca; + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + cr = varray[coloroff]; + cg = varray[coloroff + 1]; + cb = varray[coloroff + 2]; + ca = varray[coloroff + 3] * alpha; + } else { + cr = varray[coloroff]; + cg = varray[coloroff + 1]; + cb = varray[coloroff + 2]; + ca = alpha; + } + gl.glColor4f(cr, cg, cb, ca); + } else { + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { // alpha is present + gl.glColor4f(varray[coloroff], + varray[coloroff + 1], + varray[coloroff + 2], + varray[coloroff + 3]); + } else { + gl.glColor3f(varray[coloroff], + varray[coloroff + 1], + varray[coloroff + 2]); + } + } + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vaOff = vAttrOff; + if (verts == null) { + verts = FloatBuffer.wrap(varray); + } + for (int vaIdx = 0; vaIdx < vertexAttrCount; vaIdx++) { + switch (vertexAttrSizes[vaIdx]) { + case 1: + verts.position(vaOff); + jctx.vertexAttr1fv(gl, vaIdx, verts); + break; + case 2: + verts.position(vaOff); + jctx.vertexAttr2fv(gl, vaIdx, verts); + break; + case 3: + verts.position(vaOff); + jctx.vertexAttr3fv(gl, vaIdx, verts); + break; + case 4: + verts.position(vaOff); + jctx.vertexAttr4fv(gl, vaIdx, verts); + break; + } + + vaOff += vertexAttrSizes[vaIdx]; + } + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if (texCoordSetMapLen > 0) { + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord2f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1]); + } + } + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord3f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1], + varray[off + 2]); + } + } + } else { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord4f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1], + varray[off + 2], + varray[off + 3]); + } + } + } + } else { // no multitexture + if (texCoordSetMapOffset[0] != -1) { + int off = texCoordoff + texCoordSetMapOffset[0]; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + gl.glTexCoord2f(varray[off], varray[off + 1]); + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + gl.glTexCoord3f(varray[off], varray[off + 1], varray[off + 2]); + } else { + gl.glTexCoord4f(varray[off], varray[off + 1], varray[off + 2], varray[off + 3]); + } + } + } // no multitexture + } + // texCoordSetMapLen can't be 0 if texture coordinates is + // to be specified + } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + if (xform != null) { + // transform the vertex data with the static transform + float w = (float) (xform[12] * varray[coordoff] + + xform[13] * varray[coordoff+1] + + xform[14] * varray[coordoff+2] + + xform[15]); + float winv = 1.0f/w; + float vx = (float) (xform[0] * varray[coordoff] + + xform[1] * varray[coordoff+1] + + xform[2] * varray[coordoff+2] + + xform[3]) * winv; + float vy = (float) (xform[4] * varray[coordoff] + + xform[5] * varray[coordoff+1] + + xform[6] * varray[coordoff+2] + + xform[7]) * winv; + float vz = (float) (xform[8] * varray[coordoff] + + xform[9] * varray[coordoff+1] + + xform[10] * varray[coordoff+2] + + xform[11]) * winv; + gl.glVertex3f(vx, vy, vz); + } else { + gl.glVertex3f(varray[coordoff], varray[coordoff + 1], varray[coordoff + 2]); + } + } + normoff += stride; + coloroff += stride; + coordoff += stride; + texCoordoff += stride; + vAttrOff += stride; + } + gl.glEnd(); + } + } + + // used to Build Dlist GeometryArray by Reference with java arrays + void buildGAForByRef(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, float[] vfcoords, double[] vdcoords, + int initialColorIndex, float[] cfdata, byte[] cbdata, + int initialNormalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, float[][] vertexAttrData, + int texCoordMapLength, + int[] tcoordsetmap, + int[] texIndices, int texStride, Object[] texCoords, + double[] xform, double[] nxform) { + if (VERBOSE) System.err.println("JoglPipeline.buildGAForByRef()"); + + GL gl = context(ctx).getGL(); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = getTexCoordSetBuffer(texCoords); + } + + // process alpha for geometryArray without alpha + boolean useAlpha = false; + if (updateAlpha && !ignoreVertexColors) { + useAlpha = true; + } + + int[] sarray = null; + int[] start_array = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + strip_len = sarray.length; + start_array = ((GeometryStripArrayRetained) geo).stripStartOffsetIndices; + } + + if (ignoreVertexColors) { + vformat &= ~GeometryArray.COLOR; + floatColorsDefined = false; + byteColorsDefined = false; + } + + // get coordinate array + if (floatCoordDefined) { + gl.glEnableClientState(GL.GL_VERTEX_ARRAY); + fverts = getVertexArrayBuffer(vfcoords, (xform == null)); + if (xform != null) { + // Must copy in and transform data + for (int i = initialCoordIndex; i < vcount * 3; i += 3) { + fverts.put(i , (float) (xform[0] * vfcoords[i] + + xform[1] * vfcoords[i+1] + + xform[2] * vfcoords[i+2])); + fverts.put(i+1, (float) (xform[4] * vfcoords[i] + + xform[5] * vfcoords[i+1] + + xform[6] * vfcoords[i+2])); + fverts.put(i+2, (float) (xform[8] * vfcoords[i] + + xform[9] * vfcoords[i+1] + + xform[10] * vfcoords[i+2])); + } + } + } else if (doubleCoordDefined) { + gl.glEnableClientState(GL.GL_VERTEX_ARRAY); + dverts = getVertexArrayBuffer(vdcoords, (xform == null)); + if (xform != null) { + // Must copy in and transform data + for (int i = initialCoordIndex; i < vcount * 3; i += 3) { + dverts.put(i , (xform[0] * vdcoords[i] + + xform[1] * vdcoords[i+1] + + xform[2] * vdcoords[i+2])); + dverts.put(i+1, (xform[4] * vdcoords[i] + + xform[5] * vdcoords[i+1] + + xform[6] * vdcoords[i+2])); + dverts.put(i+2, (xform[8] * vdcoords[i] + + xform[9] * vdcoords[i+1] + + xform[10] * vdcoords[i+2])); + } + } + } else { + gl.glDisableClientState(GL.GL_VERTEX_ARRAY); + } + + // get color array + if (floatColorsDefined) { + gl.glEnableClientState(GL.GL_COLOR_ARRAY); + fclrs = getColorArrayBuffer(cfdata, !useAlpha); + if (useAlpha) { + // Must copy in and modify color data + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + for (int i = initialColorIndex; i < vcount * 4; i += 4) { + fclrs.put(i , cfdata[i]); + fclrs.put(i+1, cfdata[i+1]); + fclrs.put(i+2, cfdata[i+2]); + fclrs.put(i+3, alpha * cfdata[i+3]); + } + } else { + int k = 0; + for (int i = initialColorIndex; i < vcount * 4; i += 4) { + fclrs.put(i , cfdata[k++]); + fclrs.put(i+1, cfdata[k++]); + fclrs.put(i+2, cfdata[k++]); + fclrs.put(i+3, alpha); + } + } + vformat |= GeometryArray.WITH_ALPHA; + } + } else if (byteColorsDefined) { + gl.glEnableClientState(GL.GL_COLOR_ARRAY); + bclrs = getColorArrayBuffer(cbdata, !useAlpha); + if (useAlpha) { + // Must copy in and modify color data + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + for (int i = initialColorIndex; i < vcount * 4; i += 4) { + bclrs.put(i , cbdata[i]); + bclrs.put(i+1, cbdata[i+1]); + bclrs.put(i+2, cbdata[i+2]); + bclrs.put(i+3, (byte) (alpha * (int) (cbdata[i+3] & 0xFF))); + } + } else { + int k = 0; + for (int i = initialColorIndex; i < vcount * 4; i += 4) { + bclrs.put(i , cbdata[k++]); + bclrs.put(i+1, cbdata[k++]); + bclrs.put(i+2, cbdata[k++]); + bclrs.put(i+3, (byte) (alpha * 255.0f)); + } + } + vformat |= GeometryArray.WITH_ALPHA; + } + } else { + gl.glDisableClientState(GL.GL_COLOR_ARRAY); + } + + // get normal array + if (normalsDefined) { + gl.glEnableClientState(GL.GL_NORMAL_ARRAY); + norms = getNormalArrayBuffer(ndata, (nxform == null)); + if (nxform != null) { + // Must copy in and transform data + for (int i = initialNormalIndex; i < vcount * 3; i += 3) { + norms.put(i , (float) (nxform[0] * ndata[i] + + nxform[1] * ndata[i+1] + + nxform[2] * ndata[i+2])); + norms.put(i+1, (float) (nxform[4] * ndata[i] + + nxform[5] * ndata[i+1] + + nxform[6] * ndata[i+2])); + norms.put(i+2, (float) (nxform[8] * ndata[i] + + nxform[9] * ndata[i+1] + + nxform[10] * ndata[i+2])); + } + } + } else { + gl.glDisableClientState(GL.GL_NORMAL_ARRAY); + } + + executeGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, + initialCoordIndex, fverts, dverts, + initialColorIndex, fclrs, bclrs, + initialNormalIndex, norms, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrBufs, + texCoordMapLength, + tcoordsetmap, texCoordMapLength, + texIndices, texStride, texCoordBufs, 0, + sarray, strip_len, start_array); + } + + //---------------------------------------------------------------------- + // Private helper methods for GeometryArrayRetained + // + + private void + testForInterleavedArrays(int vformat, + boolean[] useInterleavedArrays, + int[] iaFormat) { + if (VERBOSE) System.err.println("JoglPipeline.testForInterleavedArrays()"); + useInterleavedArrays[0] = true; + switch (vformat) { + case GeometryArray.COORDINATES : + iaFormat[0] = GL.GL_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.NORMALS) : + iaFormat[0] = GL.GL_N3F_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.TEXTURE_COORDINATE_2) : + iaFormat[0] = GL.GL_T2F_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR) : + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR | GeometryArray.WITH_ALPHA) : + iaFormat[0] = GL.GL_C4F_N3F_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATE_2) : + iaFormat[0] = GL.GL_T2F_N3F_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR | GeometryArray.TEXTURE_COORDINATE_2): + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR | GeometryArray.WITH_ALPHA | GeometryArray.TEXTURE_COORDINATE_2): + iaFormat[0] = GL.GL_T2F_C4F_N3F_V3F; break; + default: + useInterleavedArrays[0] = false; break; + } + } + + private void + enableTexCoordPointer(GL gl, + int texUnit, + int texSize, + int texDataType, + int stride, + Buffer pointer) { + if (VERBOSE) System.err.println("JoglPipeline.enableTexCoordPointer()"); + clientActiveTextureUnit(gl, texUnit); + gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY); + gl.glTexCoordPointer(texSize, texDataType, stride, pointer); + } + + private void + disableTexCoordPointer(GL gl, + int texUnit) { + if (VERBOSE) System.err.println("JoglPipeline.disableTexCoordPointer()"); + clientActiveTextureUnit(gl, texUnit); + gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY); + } + + private void + clientActiveTextureUnit(GL gl, + int texUnit) { + if (VERBOSE) System.err.println("JoglPipeline.clientActiveTextureUnit()"); + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glClientActiveTexture(texUnit + GL.GL_TEXTURE0); + } + } + + + private void + executeTexture(int texCoordSetMapLen, + int texSize, int bstride, int texCoordoff, + int[] texCoordSetMapOffset, + int numActiveTexUnit, + FloatBuffer verts, GL gl) { + if (VERBOSE) System.err.println("JoglPipeline.executeTexture()"); + int tus = 0; /* texture unit state index */ + + for (int i = 0; i < numActiveTexUnit; i++) { + + tus = i; + + /* + * it's possible thattexture unit state index (tus) + * is greater than the texCoordSetMapOffsetLen, in this + * case, just disable TexCoordPointer. + */ + if ((tus < texCoordSetMapLen) && + (texCoordSetMapOffset[tus] != -1)) { + if (EXTRA_DEBUGGING) { + System.err.println(" texCoord position " + i + ": " + (texCoordoff + texCoordSetMapOffset[tus])); + } + verts.position(texCoordoff + texCoordSetMapOffset[tus]); + enableTexCoordPointer(gl, i, + texSize, GL.GL_FLOAT, bstride, + verts); + } else { + disableTexCoordPointer(gl, i); + } + } + } + + private void + resetTexture(GL gl, JoglContext ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetTexture()"); + /* Disable texture coordinate arrays for all texture units */ + for (int i = 0; i < ctx.getMaxTexCoordSets(); i++) { + disableTexCoordPointer(gl, i); + } + /* Reset client active texture unit to 0 */ + clientActiveTextureUnit(gl, 0); + } + + private void + executeGeometryArray(Context absCtx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetMapOffset, + int numActiveTexUnitState, + int vertexAttrCount, int[] vertexAttrSizes, + float[] varray, Buffer varrayBuffer, + float[] carray, int cDirty) { + if (VERBOSE) System.err.println("JoglPipeline.executeGeometryArray()"); + JoglContext ctx = (JoglContext) absCtx; + GLContext context = context(ctx); + GL gl = context.getGL(); + + boolean useInterleavedArrays; + int iaFormat = 0; + int primType = 0; + int stride = 0, coordoff = 0, normoff = 0, coloroff = 0, texCoordoff = 0; + int texSize = 0, texStride = 0; + int vAttrOff = 0; + int vAttrStride = 0; + int bstride = 0, cbstride = 0; + FloatBuffer verts = null; + FloatBuffer clrs = null; + int[] sarray = null; + int[] start_array = null; + + if (EXTRA_DEBUGGING) { + System.err.println("Vertex format: " + getVertexDescription(vformat)); + System.err.println("Geometry type: " + getGeometryDescription(geo_type)); + if (carray != null) { + System.err.println(" Separate color array"); + } else { + System.err.println(" Colors (if any) interleaved"); + } + } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GeometryArray.NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + if ((vformat & GeometryArray.COLOR) != 0) { + if ((vformat & GeometryArray.WITH_ALPHA) != 0 ) { + stride += 4; + normoff += 4; + coordoff += 4; + } else { /* Handle the case of executeInterleaved 3f */ + stride += 3; + normoff += 3; + coordoff += 3; + } + } + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if (EXTRA_DEBUGGING) { + System.err.println(" Number of tex coord sets: " + texCoordSetCount); + } + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + vAttrStride += vertexAttrSizes[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride * BufferUtil.SIZEOF_FLOAT; + + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + start_array = ((GeometryStripArrayRetained) geo).stripStartOffsetIndices; + } + + // We have to copy if the data isn't specified using NIO + if (varray != null) { + verts = getVertexArrayBuffer(varray); + } else if (varrayBuffer != null) { + verts = (FloatBuffer) varrayBuffer; + } else { + // This should never happen + throw new AssertionError("Unable to get vertex pointer"); + } + + // using byRef interleaved array and has a separate pointer, then .. + int cstride = stride; + if (carray != null) { + clrs = getColorArrayBuffer(carray); + cstride = 4; + } else { + // FIXME: need to "auto-slice" this buffer later + clrs = verts; + } + + cbstride = cstride * BufferUtil.SIZEOF_FLOAT; + + // Enable normalize for non-uniform scale (which rescale can't handle) + if (isNonUniformScale) { + gl.glEnable(GL.GL_NORMALIZE); + } + + int startVertex = stride * startVIndex; + int startClrs = cstride * startVIndex; + if (clrs == verts) { + startClrs += coloroff; + } + + /*** Handle non-indexed strip GeometryArray first *******/ + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + if (ignoreVertexColors || (carray != null) || + ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0 && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + if (useInterleavedArrays) { + verts.position(startVertex); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(startVertex + normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + if (!ignoreVertexColors && (vformat & GeometryArray.COLOR) != 0) { + if (EXTRA_DEBUGGING) { + System.err.println(" Doing colors"); + } + clrs.position(startClrs); + if ((vformat & GeometryArray.WITH_ALPHA) != 0 || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, cbstride, clrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, cbstride, clrs); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(startVertex + coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + numActiveTexUnitState, + verts, gl); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = startVertex + vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + + switch (geo_type) { + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + + if (gl.isExtensionAvailable("GL_EXT_multi_draw_arrays")) { + gl.glMultiDrawArraysEXT(primType, start_array, 0, sarray, 0, sarray.length); + } else { + for (int i = 0; i < sarray.length; i++) { + gl.glDrawArrays(primType, start_array[i], sarray[i]); + } + } + } else if ((geo_type == GeometryRetained.GEO_TYPE_QUAD_SET) || + (geo_type == GeometryRetained.GEO_TYPE_TRI_SET) || + (geo_type == GeometryRetained.GEO_TYPE_POINT_SET) || + (geo_type == GeometryRetained.GEO_TYPE_LINE_SET)) { + /******* Handle non-indexed non-striped GeometryArray now *****/ + if (ignoreVertexColors || (carray != null) || + ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0 && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + + if (useInterleavedArrays) { + verts.position(startVertex); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if (EXTRA_DEBUGGING) { + System.err.println(" startVertex: " + startVertex); + System.err.println(" stride: " + stride); + System.err.println(" bstride: " + bstride); + System.err.println(" normoff: " + normoff); + System.err.println(" coloroff: " + coloroff); + System.err.println(" coordoff: " + coordoff); + System.err.println(" texCoordoff: " + texCoordoff); + } + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(startVertex + normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + if (!ignoreVertexColors && (vformat & GeometryArray.COLOR) != 0) { + clrs.position(startClrs); + if ((vformat & GeometryArray.WITH_ALPHA) != 0 || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, cbstride, clrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, cbstride, clrs); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(startVertex + coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + numActiveTexUnitState, + verts, gl); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = startVertex + vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + switch (geo_type){ + case GeometryRetained.GEO_TYPE_QUAD_SET : gl.glDrawArrays(GL.GL_QUADS, 0, vcount); break; + case GeometryRetained.GEO_TYPE_TRI_SET : gl.glDrawArrays(GL.GL_TRIANGLES, 0, vcount); break; + case GeometryRetained.GEO_TYPE_POINT_SET: gl.glDrawArrays(GL.GL_POINTS, 0, vcount); break; + case GeometryRetained.GEO_TYPE_LINE_SET : gl.glDrawArrays(GL.GL_LINES, 0, vcount); break; + } + } + + /* clean up if we turned on normalize */ + if (isNonUniformScale) { + gl.glDisable(GL.GL_NORMALIZE); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + resetTexture(gl, ctx); + } + } + + + // glLockArrays() is invoked only for indexed geometry, and the + // vertexCount is guarenteed to be >= 0. + private void lockArray(GL gl, int vertexCount) { + if (gl.isExtensionAvailable("GL_EXT_compiled_vertex_array")) { + gl.glLockArraysEXT(0, vertexCount); + } + } + + private void unlockArray(GL gl) { + if (gl.isExtensionAvailable("GL_EXT_compiled_vertex_array")) { + gl.glUnlockArraysEXT(); + } + } + + private void + executeGeometryArrayVA(Context absCtx, + GeometryArrayRetained geo, + int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, FloatBuffer fverts, DoubleBuffer dverts, + int initialColorIndex, FloatBuffer fclrs, ByteBuffer bclrs, + int initialNormalIndex, FloatBuffer norms, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, FloatBuffer[] vertexAttrData, + int texCoordMapLength, + int[] texCoordSetMap, + int numActiveTexUnit, + int[] texindices, int texStride, FloatBuffer[] texCoords, + int cdirty, + int[] sarray, + int strip_len, + int[] start_array) { + JoglContext ctx = (JoglContext) absCtx; + GLContext context = context(ctx); + GL gl = context.getGL(); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + // Enable normalize for non-uniform scale (which rescale can't handle) + if (isNonUniformScale) { + gl.glEnable(GL.GL_NORMALIZE); + } + + int coordoff = 3 * initialCoordIndex; + // Define the data pointers + if (floatCoordDefined) { + fverts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, 0, fverts); + } else if (doubleCoordDefined){ + dverts.position(coordoff); + gl.glVertexPointer(3, GL.GL_DOUBLE, 0, dverts); + } + + if (floatColorsDefined) { + int coloroff; + int sz; + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + coloroff = 4 * initialColorIndex; + sz = 4; + } else { + coloroff = 3 * initialColorIndex; + sz = 3; + } + fclrs.position(coloroff); + gl.glColorPointer(sz, GL.GL_FLOAT, 0, fclrs); + } else if (byteColorsDefined) { + int coloroff; + int sz; + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + coloroff = 4 * initialColorIndex; + sz = 4; + } else { + coloroff = 3 * initialColorIndex; + sz = 3; + } + bclrs.position(coloroff); + gl.glColorPointer(sz, GL.GL_UNSIGNED_BYTE, 0, bclrs); + } + if (normalsDefined) { + int normoff = 3 * initialNormalIndex; + norms.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, 0, norms); + } + + if (vattrDefined) { + for (int i = 0; i < vertexAttrCount; i++) { + FloatBuffer vertexAttrs = vertexAttrData[i]; + int sz = vertexAttrSizes[i]; + int initIdx = vertexAttrIndices[i]; + ctx.enableVertexAttrArray(gl, i); + vertexAttrs.position(initIdx * sz); + ctx.vertexAttrPointer(gl, i, sz, GL.GL_FLOAT, 0, vertexAttrs); + } + } + + if (textureDefined) { + int texSet = 0; + for (int i = 0; i < numActiveTexUnit; i++) { + if (( i < texCoordMapLength) && + ((texSet = texCoordSetMap[i]) != -1)) { + FloatBuffer buf = texCoords[texSet]; + buf.position(texStride * texindices[texSet]); + enableTexCoordPointer(gl, i, texStride, + GL.GL_FLOAT, 0, buf); + } else { + disableTexCoordPointer(gl, i); + } + } + + // Reset client active texture unit to 0 + clientActiveTextureUnit(gl, 0); + } + + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + int primType = 0; + switch (geo_type) { + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + if (gl.isExtensionAvailable("GL_EXT_multi_draw_arrays")) { + gl.glMultiDrawArraysEXT(primType, start_array, 0, sarray, 0, strip_len); + } else if (gl.isExtensionAvailable("GL_VERSION_1_4")) { + gl.glMultiDrawArrays(primType, start_array, 0, sarray, 0, strip_len); + } else { + for (int i = 0; i < strip_len; i++) { + gl.glDrawArrays(primType, start_array[i], sarray[i]); + } + } + } else { + switch (geo_type){ + case GeometryRetained.GEO_TYPE_QUAD_SET : gl.glDrawArrays(GL.GL_QUADS, 0, vcount); break; + case GeometryRetained.GEO_TYPE_TRI_SET : gl.glDrawArrays(GL.GL_TRIANGLES, 0, vcount); break; + case GeometryRetained.GEO_TYPE_POINT_SET : gl.glDrawArrays(GL.GL_POINTS, 0, vcount); break; + case GeometryRetained.GEO_TYPE_LINE_SET : gl.glDrawArrays(GL.GL_LINES, 0, vcount); break; + } + } + + // clean up if we turned on normalize + if (isNonUniformScale) { + gl.glDisable(GL.GL_NORMALIZE); + } + + if (vattrDefined) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if (textureDefined) { + resetTexture(gl, ctx); + } + } + + private String getVertexDescription(int vformat) { + String res = ""; + if ((vformat & GeometryArray.COORDINATES) != 0) res += "COORDINATES "; + if ((vformat & GeometryArray.NORMALS) != 0) res += "NORMALS "; + if ((vformat & GeometryArray.COLOR) != 0) res += "COLOR "; + if ((vformat & GeometryArray.WITH_ALPHA) != 0) res += "(WITH_ALPHA) "; + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) res += "TEXTURE_COORDINATE "; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) res += "(2) "; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) res += "(3) "; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) res += "(4) "; + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) res += "VERTEX_ATTRIBUTES "; + return res; + } + + private String getGeometryDescription(int geo_type) { + switch (geo_type) { + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET : return "GEO_TYPE_TRI_STRIP_SET"; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET : return "GEO_TYPE_TRI_FAN_SET"; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: return "GEO_TYPE_LINE_STRIP_SET"; + case GeometryRetained.GEO_TYPE_QUAD_SET : return "GEO_TYPE_QUAD_SET"; + case GeometryRetained.GEO_TYPE_TRI_SET : return "GEO_TYPE_TRI_SET"; + case GeometryRetained.GEO_TYPE_POINT_SET : return "GEO_TYPE_POINT_SET"; + case GeometryRetained.GEO_TYPE_LINE_SET : return "GEO_TYPE_LINE_SET"; + default: return "(unknown " + geo_type + ")"; + } + } + + private void resetVertexAttrs(GL gl, JoglContext ctx, int vertexAttrCount) { + // Disable specified vertex attr arrays + for (int i = 0; i < vertexAttrCount; i++) { + ctx.disableVertexAttrArray(gl, i); + } + } + + + // --------------------------------------------------------------------- + + // + // IndexedGeometryArrayRetained methods + // + + // by-copy or interleaved, by reference, Java arrays + void executeIndexedGeometry(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + float[] varray, float[] carray, + int cdirty, + int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.executeIndexedGeometry()"); + + executeIndexedGeometryArray(ctx, geo, geo_type, + isNonUniformScale, useAlpha, ignoreVertexColors, + initialIndexIndex, indexCount, + vertexCount, vformat, + vertexAttrCount, vertexAttrSizes, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, + texCoordSetOffset, + numActiveTexUnitState, + varray, null, carray, + cdirty, indexCoord); + } + + // interleaved, by reference, nio buffer + void executeIndexedGeometryBuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + Object vdata, float[] carray, + int cDirty, + int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.executeIndexedGeometryBuffer()"); + + executeIndexedGeometryArray(ctx, geo, geo_type, + isNonUniformScale, useAlpha, ignoreVertexColors, + initialIndexIndex, indexCount, vertexCount, vformat, + 0, null, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, texCoordSetOffset, + numActiveTexUnitState, + null, (FloatBuffer) vdata, carray, + cDirty, indexCoord); + } + + // non interleaved, by reference, Java arrays + void executeIndexedGeometryVA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + float[] vfcoords, double[] vdcoords, + float[] cfdata, byte[] cbdata, + float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + float[][] vertexAttrData, + int texCoordMapLength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texStride, Object[] texCoords, + int cdirty, + int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.executeIndexedGeometryVA()"); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = getTexCoordSetBuffer(texCoords); + } + + int[] sarray = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + sarray = ((IndexedGeometryStripArrayRetained) geo).stripIndexCounts; + strip_len = sarray.length; + } + + // get coordinate array + if (floatCoordDefined) { + fverts = getVertexArrayBuffer(vfcoords); + } else if (doubleCoordDefined) { + dverts = getVertexArrayBuffer(vdcoords); + } + + // get color array + if (floatColorsDefined) { + fclrs = getColorArrayBuffer(cfdata); + } else if (byteColorsDefined) { + bclrs = getColorArrayBuffer(cbdata); + } + + // get normal array + if (normalsDefined) { + norms = getNormalArrayBuffer(ndata); + } + + executeIndexedGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + initialIndexIndex, validIndexCount, vertexCount, + vformat, vdefined, + fverts, dverts, + fclrs, bclrs, + norms, + vertexAttrCount, vertexAttrSizes, vertexAttrBufs, + texCoordMapLength, texcoordoffset, + numActiveTexUnitState, + texStride, texCoordBufs, + cdirty, indexCoord, + sarray, strip_len); + } + + // non interleaved, by reference, nio buffer + void executeIndexedGeometryVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + Object vcoords, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + Object ndata, + int vertexAttrCount, int[] vertexAttrSizes, + Object[] vertexAttrData, + int texCoordMapLength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texStride, Object[] texCoords, + int cdirty, + int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.executeIndexedGeometryVABuffer()"); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = new FloatBuffer[texCoords.length]; + for (int i = 0; i < texCoords.length; i++) { + texCoordBufs[i] = (FloatBuffer) texCoords[i]; + } + } + + // get coordinate array + if (floatCoordDefined) { + fverts = (FloatBuffer) vcoords; + } else if (doubleCoordDefined) { + dverts = (DoubleBuffer) vcoords; + } + + if (fverts == null && dverts == null) { + return; + } + + int[] sarray = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + sarray = ((IndexedGeometryStripArrayRetained) geo).stripIndexCounts; + strip_len = sarray.length; + } + + // get color array + if (floatColorsDefined) { + if (cfdata != null) + fclrs = getColorArrayBuffer(cfdata); + else + fclrs = (FloatBuffer) cdataBuffer; + } else if (byteColorsDefined) { + if (cbdata != null) + bclrs = getColorArrayBuffer(cbdata); + else + bclrs = (ByteBuffer) cdataBuffer; + } + + // get normal array + if (normalsDefined) { + norms = (FloatBuffer) ndata; + } + + executeIndexedGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + initialIndexIndex, validIndexCount, vertexCount, + vformat, vdefined, + fverts, dverts, + fclrs, bclrs, + norms, + vertexAttrCount, vertexAttrSizes, vertexAttrBufs, + texCoordMapLength, texcoordoffset, + numActiveTexUnitState, + texStride, texCoordBufs, + cdirty, indexCoord, + sarray, strip_len); + } + + // by-copy geometry + void buildIndexedGeometry(Context absCtx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetMapOffset, + double[] xform, double[] nxform, + float[] varray, int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.buildIndexedGeometry()"); + + JoglContext ctx = (JoglContext) absCtx; + GL gl = context(ctx).getGL(); + + boolean useInterleavedArrays; + int iaFormat = 0; + int primType = 0; + int stride = 0, coordoff = 0, normoff = 0, coloroff = 0, texCoordoff = 0; + int texSize = 0, texStride = 0; + int vAttrOff = 0; + int vAttrStride = 0; + int bstride = 0, cbstride = 0; + FloatBuffer verts = null; + FloatBuffer clrs = null; + int[] sarray = null; + int strip_len = 0; + boolean useAlpha = false; + + if ((vformat & GeometryArray.COORDINATES) != 0) { + gl.glEnableClientState(GL.GL_VERTEX_ARRAY); + stride += 3; + } else { + gl.glDisableClientState(GL.GL_VERTEX_ARRAY); + } + + if ((vformat & GeometryArray.NORMALS) != 0) { + gl.glEnableClientState(GL.GL_NORMAL_ARRAY); + stride += 3; + coordoff += 3; + } else { + gl.glDisableClientState(GL.GL_NORMAL_ARRAY); + } + + if ((vformat & GeometryArray.COLOR) != 0) { + gl.glEnableClientState(GL.GL_COLOR_ARRAY); + stride += 4; + normoff += 4; + coordoff += 4; + } else { + gl.glDisableClientState(GL.GL_COLOR_ARRAY); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + vAttrStride += vertexAttrSizes[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride * BufferUtil.SIZEOF_FLOAT; + + // process alpha for geometryArray without alpha + if (updateAlpha && !ignoreVertexColors) { + useAlpha = true; + } + + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + sarray = ((IndexedGeometryStripArrayRetained) geo).stripIndexCounts; + strip_len = sarray.length; + } + + // Copy data into NIO array + verts = getVertexArrayBuffer(varray); + + // Apply normal transform if necessary + if ((vformat & GeometryArray.NORMALS) != 0 && nxform != null) { + int off = normoff; + for (int i = 0; i < vertexCount * 3; i+=3) { + verts.put(off , (float) (nxform[0] * varray[off] + + nxform[1] * varray[off+1] + + nxform[2] * varray[off+2])); + verts.put(off+1, (float) (nxform[4] * varray[off] + + nxform[5] * varray[off+1] + + nxform[6] * varray[off+2])); + verts.put(off+2, (float) (nxform[8] * varray[off] + + nxform[9] * varray[off+1] + + nxform[10] * varray[off+2])); + off += stride; + } + } + + // Apply coordinate transform if necessary + if ((vformat & GeometryArray.COORDINATES) != 0 && xform != null) { + int off = coordoff; + for (int i = 0; i < vertexCount * 3; i+=3) { + verts.put(off , (float) (xform[0] * varray[off] + + xform[1] * varray[off+1] + + xform[2] * varray[off+2])); + verts.put(off+1, (float) (xform[4] * varray[off] + + xform[5] * varray[off+1] + + xform[6] * varray[off+2])); + verts.put(off+2, (float) (xform[8] * varray[off] + + xform[9] * varray[off+1] + + xform[10] * varray[off+2])); + off += stride; + } + } + + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + // Note we can use interleaved arrays even if we have a + // non-null xform since we use the same data layout unlike the + // C code + if (ignoreVertexColors || + (((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + + if (useInterleavedArrays) { + verts.position(0); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + if (!ignoreVertexColors && ((vformat & GeometryArray.COLOR) != 0)) { + verts.position(coloroff); + if (((vformat & GeometryArray.WITH_ALPHA) != 0) || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, bstride, verts); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, bstride, verts); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + texCoordSetMapLen, + verts, gl); + } + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + + switch (geo_type) { + case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + + lockArray(gl, vertexCount); + + // Note: using MultiDrawElements is probably more expensive than + // not in this case due to the need to allocate more temporary + // direct buffers and slice up the incoming indices array + int offset = initialIndexIndex; + IntBuffer indicesBuffer = IntBuffer.wrap(indexCoord); + for (int i = 0; i < strip_len; i++) { + indicesBuffer.position(offset); + int count = sarray[i]; + gl.glDrawElements(primType, count, GL.GL_UNSIGNED_INT, indicesBuffer); + offset += count; + } + } else if ((geo_type == GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_POINT_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_SET)) { + // Note we can use interleaved arrays even if we have a + // non-null xform since we use the same data layout unlike the + // C code + if (ignoreVertexColors || + (((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + + if (useInterleavedArrays) { + verts.position(0); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + + if (!ignoreVertexColors && ((vformat & GeometryArray.COLOR) != 0)) { + verts.position(coloroff); + if (((vformat & GeometryArray.WITH_ALPHA) != 0) || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, bstride, verts); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, bstride, verts); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + texCoordSetMapLen, + verts, gl); + } + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + + switch (geo_type) { + case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET : + primType = GL.GL_QUADS; + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET : + primType = GL.GL_TRIANGLES; + break; + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET : + primType = GL.GL_POINTS; + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET : + primType = GL.GL_LINES; + break; + } + + lockArray(gl, vertexCount); + + IntBuffer indicesBuffer = IntBuffer.wrap(indexCoord); + indicesBuffer.position(initialIndexIndex); + gl.glDrawElements(primType, validIndexCount, GL.GL_UNSIGNED_INT, indicesBuffer); + } + } + + unlockArray(gl); + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + resetTexture(gl, ctx); + } + } + + + //---------------------------------------------------------------------- + // + // Helper routines for IndexedGeometryArrayRetained + // + + private void executeIndexedGeometryArray(Context absCtx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + float[] varray, FloatBuffer vdata, float[] carray, + int cDirty, + int[] indexCoord) { + JoglContext ctx = (JoglContext) absCtx; + GL gl = context(ctx).getGL(); + + boolean useInterleavedArrays; + int iaFormat = 0; + int primType = 0; + int stride = 0, coordoff = 0, normoff = 0, coloroff = 0, texCoordoff = 0; + int texSize = 0, texStride = 0; + int vAttrOff = 0; + int vAttrStride = 0; + int bstride = 0, cbstride = 0; + FloatBuffer verts = null; + FloatBuffer clrs = null; + int[] sarray = null; + int strip_len = 0; + + if ((vformat & GeometryArray.COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GeometryArray.NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + + if ((vformat & GeometryArray.COLOR) != 0) { + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + stride += 4; + normoff += 4; + coordoff += 4; + } else { // Handle the case of executeInterleaved 3f + stride += 3; + normoff += 3; + coordoff += 3; + } + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + vAttrStride += vertexAttrSizes[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride * BufferUtil.SIZEOF_FLOAT; + + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + sarray = ((IndexedGeometryStripArrayRetained) geo).stripIndexCounts; + strip_len = sarray.length; + } + + // We have to copy if the data isn't specified using NIO + if (varray != null) { + verts = getVertexArrayBuffer(varray); + } else if (vdata != null) { + verts = vdata; + } else { + // This should never happen + throw new AssertionError("Unable to get vertex pointer"); + } + + // using byRef interleaved array and has a separate pointer, then .. + int cstride = stride; + if (carray != null) { + clrs = getColorArrayBuffer(carray); + cstride = 4; + } else { + // FIXME: need to "auto-slice" this buffer later + clrs = verts; + } + + cbstride = cstride * BufferUtil.SIZEOF_FLOAT; + + // Enable normalize for non-uniform scale (which rescale can't handle) + if (isNonUniformScale) { + gl.glEnable(GL.GL_NORMALIZE); + } + + /*** Handle non-indexed strip GeometryArray first *******/ + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + if (ignoreVertexColors || (carray != null) || + ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0 && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + if (useInterleavedArrays) { + verts.position(0); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + if (!ignoreVertexColors && (vformat & GeometryArray.COLOR) != 0) { + if (clrs == verts) { + clrs.position(coloroff); + } + if ((vformat & GeometryArray.WITH_ALPHA) != 0 || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, cbstride, clrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, cbstride, clrs); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + /* XXXX: texCoordoff == 0 ???*/ + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetOffset, + numActiveTexUnitState, + verts, gl); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + + switch (geo_type) { + case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + + lockArray(gl, vertexCount); + + // Note: using MultiDrawElements is probably more expensive than + // not in this case due to the need to allocate more temporary + // direct buffers and slice up the incoming indices array + int offset = initialIndexIndex; + IntBuffer indicesBuffer = IntBuffer.wrap(indexCoord); + for (int i = 0; i < strip_len; i++) { + indicesBuffer.position(offset); + int count = sarray[i]; + gl.glDrawElements(primType, count, GL.GL_UNSIGNED_INT, indicesBuffer); + offset += count; + } + } else if ((geo_type == GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_POINT_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_SET)) { + /******* Handle non-indexed non-striped GeometryArray now *****/ + if (ignoreVertexColors || (carray != null) || + ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0 && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + + if (useInterleavedArrays) { + verts.position(0); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + + if (!ignoreVertexColors && (vformat & GeometryArray.COLOR) != 0) { + if (clrs == verts) { + clrs.position(coloroff); + } + if ((vformat & GeometryArray.WITH_ALPHA) != 0 || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, cbstride, clrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, cbstride, clrs); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + /* XXXX: texCoordoff == 0 ???*/ + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetOffset, + numActiveTexUnitState, + verts, gl); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + + lockArray(gl, vertexCount); + IntBuffer buf = IntBuffer.wrap(indexCoord); + buf.position(initialIndexIndex); + switch (geo_type){ + case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET : gl.glDrawElements(GL.GL_QUADS, indexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET : gl.glDrawElements(GL.GL_TRIANGLES, indexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: gl.glDrawElements(GL.GL_POINTS, indexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET : gl.glDrawElements(GL.GL_LINES, indexCount, GL.GL_UNSIGNED_INT, buf); break; + } + } + + unlockArray(gl); + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + resetTexture(gl, ctx); + } + + // clean up if we turned on normalize + if (isNonUniformScale) { + gl.glDisable(GL.GL_NORMALIZE); + } + } + + + private void executeIndexedGeometryArrayVA(Context absCtx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, int vformat, int vdefined, + FloatBuffer fverts, DoubleBuffer dverts, + FloatBuffer fclrs, ByteBuffer bclrs, + FloatBuffer norms, + int vertexAttrCount, int[] vertexAttrSizes, FloatBuffer[] vertexAttrBufs, + int texCoordSetCount, int[] texCoordSetMap, + int numActiveTexUnitState, + int texStride, + FloatBuffer[] texCoords, + int cDirty, int[] indexCoord, int[] sarray, int strip_len) { + JoglContext ctx = (JoglContext) absCtx; + GL gl = context(ctx).getGL(); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + // Enable normalize for non-uniform scale (which rescale can't handle) + if (isNonUniformScale) { + gl.glEnable(GL.GL_NORMALIZE); + } + + // Define the data pointers + if (floatCoordDefined) { + fverts.position(0); + gl.glVertexPointer(3, GL.GL_FLOAT, 0, fverts); + } else if (doubleCoordDefined){ + dverts.position(0); + gl.glVertexPointer(3, GL.GL_DOUBLE, 0, dverts); + } + if (floatColorsDefined) { + fclrs.position(0); + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + gl.glColorPointer(4, GL.GL_FLOAT, 0, fclrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, 0, fclrs); + } + } else if (byteColorsDefined) { + bclrs.position(0); + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + gl.glColorPointer(4, GL.GL_UNSIGNED_BYTE, 0, bclrs); + } else { + gl.glColorPointer(3, GL.GL_UNSIGNED_BYTE, 0, bclrs); + } + } + if (normalsDefined) { + norms.position(0); + gl.glNormalPointer(GL.GL_FLOAT, 0, norms); + } + + if (vattrDefined) { + for (int i = 0; i < vertexAttrCount; i++) { + FloatBuffer vertexAttrs = vertexAttrBufs[i]; + int sz = vertexAttrSizes[i]; + ctx.enableVertexAttrArray(gl, i); + vertexAttrs.position(0); + ctx.vertexAttrPointer(gl, i, sz, GL.GL_FLOAT, 0, vertexAttrs); + } + } + + if (textureDefined) { + int texSet = 0; + for (int i = 0; i < numActiveTexUnitState; i++) { + if ((i < texCoordSetCount) && + ((texSet = texCoordSetMap[i]) != -1)) { + FloatBuffer buf = texCoords[texSet]; + buf.position(0); + enableTexCoordPointer(gl, i, texStride, + GL.GL_FLOAT, 0, buf); + } else { + disableTexCoordPointer(gl, i); + } + } + + // Reset client active texture unit to 0 + clientActiveTextureUnit(gl, 0); + } + + lockArray(gl, vertexCount); + + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + int primType = 0; + switch (geo_type) { + case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + + // Note: using MultiDrawElements is probably more expensive than + // not in this case due to the need to allocate more temporary + // direct buffers and slice up the incoming indices array + int offset = initialIndexIndex; + IntBuffer indicesBuffer = IntBuffer.wrap(indexCoord); + for (int i = 0; i < strip_len; i++) { + indicesBuffer.position(offset); + int count = sarray[i]; + gl.glDrawElements(primType, count, GL.GL_UNSIGNED_INT, indicesBuffer); + offset += count; + } + } else { + IntBuffer buf = IntBuffer.wrap(indexCoord); + buf.position(initialIndexIndex); + switch (geo_type){ + case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET : gl.glDrawElements(GL.GL_QUADS, validIndexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET : gl.glDrawElements(GL.GL_TRIANGLES, validIndexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: gl.glDrawElements(GL.GL_POINTS, validIndexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET : gl.glDrawElements(GL.GL_LINES, validIndexCount, GL.GL_UNSIGNED_INT, buf); break; + } + } + + unlockArray(gl); + + // clean up if we turned on normalize + if (isNonUniformScale) { + gl.glDisable(GL.GL_NORMALIZE); + } + + if (vattrDefined) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if (textureDefined) { + resetTexture(gl, ctx); + } + } + + + // --------------------------------------------------------------------- + + // + // GraphicsContext3D methods + // + + // Native method for readRaster + void readRaster(Context ctx, + int type, int xSrcOffset, int ySrcOffset, + int width, int height, int hCanvas, + int imageDataType, + int imageFormat, + Object imageBuffer, + int depthFormat, + Object depthBuffer) { + + GL gl = context(ctx).getGL(); + gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, width); + gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1); + int yAdjusted = hCanvas - height - ySrcOffset; + + if ((type & Raster.RASTER_COLOR) != 0) { + int oglFormat = 0; + if(imageDataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + oglFormat = GL.GL_BGR; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + oglFormat = GL.GL_RGB; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + oglFormat = GL.GL_ABGR_EXT; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + oglFormat = GL.GL_RGBA; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + oglFormat = GL.GL_LUMINANCE_ALPHA; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + gl.glReadPixels(xSrcOffset, yAdjusted, width, height, + oglFormat, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[]) imageBuffer)); + + + } else if(imageDataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + int intType = GL.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + oglFormat = GL.GL_RGBA; + intType = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + oglFormat = GL.GL_BGRA; + intType = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 1.0f); + } + + gl.glReadPixels(xSrcOffset, yAdjusted, width, height, + oglFormat, intType, IntBuffer.wrap((int[]) imageBuffer)); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 0.0f); + } + + } else { + assert false; + } + } + + if ((type & Raster.RASTER_DEPTH) != 0) { + + if (depthFormat == DepthComponentRetained.DEPTH_COMPONENT_TYPE_INT) { + // yOffset is adjusted for OpenGL - Y upward + gl.glReadPixels(xSrcOffset, yAdjusted, width, height, + GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_INT, IntBuffer.wrap((int[]) depthBuffer)); + } else { + // DEPTH_COMPONENT_TYPE_FLOAT + // yOffset is adjusted for OpenGL - Y upward + gl.glReadPixels(xSrcOffset, yAdjusted, width, height, + GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT, FloatBuffer.wrap((float[]) depthBuffer)); + } + } + + } + + // --------------------------------------------------------------------- + + // + // CgShaderProgramRetained methods + // + + // ShaderAttributeValue methods + + ShaderError setCgUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform1i()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgSetParameter1i(param.vParam(), value); + } + + if (param.fParam() != null) { + CgGL.cgSetParameter1i(param.fParam(), value); + } + + return null; + } + + ShaderError setCgUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform1f()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgSetParameter1f(param.vParam(), value); + } + + if (param.fParam() != null) { + CgGL.cgSetParameter1f(param.fParam(), value); + } + + return null; + } + + ShaderError setCgUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform2i()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgSetParameter2i(param.vParam(), value[0], value[1]); + } + + if (param.fParam() != null) { + CgGL.cgSetParameter2i(param.fParam(), value[0], value[1]); + } + + return null; + } + + ShaderError setCgUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform2f()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgSetParameter2f(param.vParam(), value[0], value[1]); + } + + if (param.fParam() != null) { + CgGL.cgSetParameter2f(param.fParam(), value[0], value[1]); + } + + return null; + } + + ShaderError setCgUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform3i()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgSetParameter3i(param.vParam(), value[0], value[1], value[2]); + } + + if (param.fParam() != null) { + CgGL.cgSetParameter3i(param.fParam(), value[0], value[1], value[2]); + } + + return null; + } + + ShaderError setCgUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform3f()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgSetParameter3f(param.vParam(), value[0], value[1], value[2]); + } + + if (param.fParam() != null) { + CgGL.cgSetParameter3f(param.fParam(), value[0], value[1], value[2]); + } + + return null; + } + + ShaderError setCgUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform4i()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgSetParameter4i(param.vParam(), value[0], value[1], value[2], value[3]); + } + + if (param.fParam() != null) { + CgGL.cgSetParameter4i(param.fParam(), value[0], value[1], value[2], value[3]); + } + + return null; + } + + ShaderError setCgUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform4f()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgSetParameter4f(param.vParam(), value[0], value[1], value[2], value[3]); + } + + if (param.fParam() != null) { + CgGL.cgSetParameter4f(param.fParam(), value[0], value[1], value[2], value[3]); + } + + return null; + } + + ShaderError setCgUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniformMatrix3f()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetMatrixParameterfr(param.vParam(), value, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetMatrixParameterfr(param.fParam(), value, 0); + } + + return null; + } + + ShaderError setCgUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniformMatrix4f()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetMatrixParameterfr(param.vParam(), value, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetMatrixParameterfr(param.fParam(), value, 0); + } + + return null; + } + + // ShaderAttributeArray methods + + ShaderError setCgUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform1iArray()"); + + float[] fval = new float[value.length]; + for (int i = 0; i < value.length; i++) { + fval[i] = value[i]; + } + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetParameterArray1f(param.vParam(), 0, numElements, fval, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetParameterArray1f(param.fParam(), 0, numElements, fval, 0); + } + + return null; + } + + ShaderError setCgUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform1fArray()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetParameterArray1f(param.vParam(), 0, numElements, value, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetParameterArray1f(param.fParam(), 0, numElements, value, 0); + } + + return null; + } + + ShaderError setCgUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform2iArray()"); + + float[] fval = new float[value.length]; + for (int i = 0; i < value.length; i++) { + fval[i] = value[i]; + } + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetParameterArray2f(param.vParam(), 0, numElements, fval, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetParameterArray2f(param.fParam(), 0, numElements, fval, 0); + } + + return null; + } + + ShaderError setCgUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform2fArray()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetParameterArray2f(param.vParam(), 0, numElements, value, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetParameterArray2f(param.fParam(), 0, numElements, value, 0); + } + + return null; + } + + ShaderError setCgUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform3iArray()"); + + float[] fval = new float[value.length]; + for (int i = 0; i < value.length; i++) { + fval[i] = value[i]; + } + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetParameterArray3f(param.vParam(), 0, numElements, fval, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetParameterArray3f(param.fParam(), 0, numElements, fval, 0); + } + + return null; + } + + ShaderError setCgUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform3fArray()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetParameterArray2f(param.vParam(), 0, numElements, value, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetParameterArray2f(param.fParam(), 0, numElements, value, 0); + } + + return null; + } + + ShaderError setCgUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform4iArray()"); + + float[] fval = new float[value.length]; + for (int i = 0; i < value.length; i++) { + fval[i] = value[i]; + } + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetParameterArray4f(param.vParam(), 0, numElements, fval, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetParameterArray4f(param.fParam(), 0, numElements, fval, 0); + } + + return null; + } + + ShaderError setCgUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniform4fArray()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetParameterArray2f(param.vParam(), 0, numElements, value, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetParameterArray2f(param.fParam(), 0, numElements, value, 0); + } + + return null; + } + + ShaderError setCgUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniformMatrix3fArray()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetMatrixParameterArrayfr(param.vParam(), 0, numElements, value, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetMatrixParameterArrayfr(param.fParam(), 0, numElements, value, 0); + } + + return null; + } + + ShaderError setCgUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setCgUniformMatrix4fArray()"); + + JoglCgShaderParameter param = (JoglCgShaderParameter) uniformLocation; + if (param.vParam() != null) { + CgGL.cgGLSetMatrixParameterArrayfr(param.vParam(), 0, numElements, value, 0); + } + + if (param.fParam() != null) { + CgGL.cgGLSetMatrixParameterArrayfr(param.fParam(), 0, numElements, value, 0); + } + + return null; + } + + // interfaces for shader compilation, etc. + ShaderError createCgShader(Context ctx, int shaderType, ShaderId[] shaderId) { + if (VERBOSE) System.err.println("JoglPipeline.createCgShader()"); + + JoglContext jctx = (JoglContext) ctx; + JoglCgShaderInfo info = new JoglCgShaderInfo(); + info.setJ3DShaderType(shaderType); + if (shaderType == Shader.SHADER_TYPE_VERTEX) { + info.setShaderProfile(jctx.getCgVertexProfile()); + } else if (shaderType == Shader.SHADER_TYPE_FRAGMENT) { + info.setShaderProfile(jctx.getCgFragmentProfile()); + } else { + throw new AssertionError("unrecognized shaderType " + shaderType); + } + shaderId[0] = info; + return null; + } + ShaderError destroyCgShader(Context ctx, ShaderId shaderId) { + if (VERBOSE) System.err.println("JoglPipeline.destroyCgShader()"); + + JoglCgShaderInfo info = (JoglCgShaderInfo) shaderId; + CGprogram program = info.getCgShader(); + if (program != null) { + CgGL.cgDestroyProgram(program); + } + return null; + } + ShaderError compileCgShader(Context ctx, ShaderId shaderId, String programString) { + if (VERBOSE) System.err.println("JoglPipeline.compileCgShader()"); + + if (programString == null) + throw new AssertionError("shader program string is null"); + JoglCgShaderInfo info = (JoglCgShaderInfo) shaderId; + JoglContext jctx = (JoglContext) ctx; + CGprogram program = CgGL.cgCreateProgram(jctx.getCgContext(), + CgGL.CG_SOURCE, + programString, + info.getShaderProfile(), + null, + null); + int lastError = 0; + if ((lastError = CgGL.cgGetError()) != 0) { + ShaderError err = new ShaderError(ShaderError.COMPILE_ERROR, + "Cg shader compile error"); + err.setDetailMessage(getCgErrorLog(jctx, lastError)); + return err; + } + info.setCgShader(program); + return null; + } + + ShaderError createCgShaderProgram(Context ctx, ShaderProgramId[] shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.createCgShaderProgram()"); + + JoglCgShaderProgramInfo info = new JoglCgShaderProgramInfo(); + shaderProgramId[0] = info; + return null; + } + ShaderError destroyCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.destroyCgShaderProgram()"); + // Nothing to do in pure Java port + return null; + } + ShaderError linkCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId, + ShaderId[] shaderIds) { + if (VERBOSE) System.err.println("JoglPipeline.linkCgShaderProgram()"); + + JoglCgShaderProgramInfo shaderProgramInfo = (JoglCgShaderProgramInfo) shaderProgramId; + // NOTE: we assume that the caller has already verified that there + // is at most one vertex program and one fragment program + shaderProgramInfo.setVertexShader(null); + shaderProgramInfo.setFragmentShader(null); + for (int i = 0; i < shaderIds.length; i++) { + JoglCgShaderInfo shader = (JoglCgShaderInfo) shaderIds[i]; + if (shader.getJ3DShaderType() == Shader.SHADER_TYPE_VERTEX) { + shaderProgramInfo.setVertexShader(shader); + } else { + shaderProgramInfo.setFragmentShader(shader); + } + + CgGL.cgGLLoadProgram(shader.getCgShader()); + int lastError = 0; + if ((lastError = CgGL.cgGetError()) != 0) { + ShaderError err = new ShaderError(ShaderError.LINK_ERROR, + "Cg shader link/load error"); + err.setDetailMessage(getCgErrorLog((JoglContext) ctx, + lastError)); + return err; + } + + CgGL.cgGLBindProgram(shader.getCgShader()); + if ((lastError = CgGL.cgGetError()) != 0) { + ShaderError err = new ShaderError(ShaderError.LINK_ERROR, + "Cg shader link/bind error"); + err.setDetailMessage(getCgErrorLog((JoglContext) ctx, + lastError)); + return err; + } + } + + return null; + } + void lookupCgVertexAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, boolean[] errArr) { + if (VERBOSE) System.err.println("JoglPipeline.lookupCgVertexAttrNames()"); + + JoglCgShaderProgramInfo shaderProgramInfo = (JoglCgShaderProgramInfo) shaderProgramId; + if (shaderProgramInfo.getVertexShader() == null) { + // If there if no vertex shader, no attributes can be looked up, so all fail + for (int i = 0; i < errArr.length; i++) { + errArr[i] = false; + } + return; + } + + shaderProgramInfo.setVertexAttributes(new CGparameter[numAttrNames]); + for (int i = 0; i < numAttrNames; i++) { + String attrName = attrNames[i]; + shaderProgramInfo.getVertexAttributes()[i] = + CgGL.cgGetNamedParameter(shaderProgramInfo.getVertexShader().getCgShader(), + attrName); + if (shaderProgramInfo.getVertexAttributes()[i] == null) { + errArr[i] = true; + } + } + } + void lookupCgShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, ShaderAttrLoc[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr) { + if (VERBOSE) System.err.println("JoglPipeline.lookupCgShaderAttrNames()"); + + JoglCgShaderProgramInfo shaderProgramInfo = + (JoglCgShaderProgramInfo) shaderProgramId; + + // Set the loc, type, and size arrays to out-of-bounds values + for (int i = 0; i < numAttrNames; i++) { + locArr[i] = null; + typeArr[i] = -1; + sizeArr[i] = -1; + } + + int[] vType = new int[1]; + int[] vSize = new int[1]; + boolean[] vIsArray = new boolean[1]; + int[] fType = new int[1]; + int[] fSize = new int[1]; + boolean[] fIsArray = new boolean[1]; + + boolean err = false; + + // Now lookup the location of each name in the attrNames array + for (int i = 0; i < numAttrNames; i++) { + String attrName = attrNames[i]; + // Get uniform attribute location -- note that we need to + // lookup the name in both the vertex and fragment shader + // (although we will generalize it to look at the list of "N" + // shaders). If all parameter locations are NULL, then no + // struct will be allocated and -1 will be stored for this + // attribute. If there is more than one non-NULL parameter, + // then all must be of the same type and dimensionality, + // otherwise an error will be generated and -1 will be stored + // for this attribute. If all non-NULL parameters are of the + // same type and dimensionality, then a struct is allocated + // containing the list of parameters. + // + // When any of the setCgUniform methods are called, the + // attribute will be set for each parameter in the list. + CGparameter vLoc = null; + if (shaderProgramInfo.getVertexShader() != null) { + vLoc = lookupCgParams(shaderProgramInfo.getVertexShader(), + attrName, + vType, vSize, vIsArray); + if (vLoc != null) { + sizeArr[i] = vSize[0]; + isArrayArr[i] = vIsArray[0]; + typeArr[i] = cgToJ3dType(vType[0]); + } + } + + CGparameter fLoc = null; + if (shaderProgramInfo.getVertexShader() != null) { + fLoc = lookupCgParams(shaderProgramInfo.getFragmentShader(), + attrName, + fType, fSize, fIsArray); + if (fLoc != null) { + sizeArr[i] = fSize[0]; + isArrayArr[i] = fIsArray[0]; + typeArr[i] = cgToJ3dType(fType[0]); + } + } + + // If the name lookup found an entry in both vertex and + // fragment program, verify that the type and size are the + // same. + if (vLoc != null && fLoc != null) { + if (vType != fType || vSize != fSize || vIsArray != fIsArray) { + // TODO: the following needs to be propagated to ShaderError + System.err.println("JAVA 3D : error shader attribute type mismatch: " + attrName); + System.err.println(" 1 : type = " + vType[0] + ", size = " + vSize[0] + ", isArray = " + vIsArray[0]); + System.err.println(" 0 : type = " + fType[0] + ", size = " + fSize[0] + ", isArray = " + fIsArray[0]); + err = true; + } + } + + // Report an error if we got a mismatch or if the attribute + // was not found in either the vertex or the fragment program + if (err || (vLoc == null && fLoc == null)) { + // TODO: distinguish between (err) and (vParam and fParam both NULL) + // so we can report a more helpful error message + // locPtr[i] = (jlong)-1; + } else { + // TODO: need to store the cgParamInfo pointers in the + // shader program so we can free them later. + // + // NOTE: WE CURRENTLY HAVE A MEMORY LEAK. + locArr[i] = new JoglCgShaderParameter(vLoc, fLoc); + } + } + } + + ShaderError useCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.useCgShaderProgram()"); + + JoglCgShaderProgramInfo shaderProgramInfo = + (JoglCgShaderProgramInfo) shaderProgramId; + JoglContext jctx = (JoglContext) ctx; + + // Disable shader profiles + CgGL.cgGLDisableProfile(jctx.getCgVertexProfile()); + CgGL.cgGLDisableProfile(jctx.getCgFragmentProfile()); + if (shaderProgramInfo != null) { + if (shaderProgramInfo.getVertexShader() != null) { + CgGL.cgGLBindProgram(shaderProgramInfo.getVertexShader().getCgShader()); + CgGL.cgGLEnableProfile(shaderProgramInfo.getVertexShader().getShaderProfile()); + } else { + CgGL.cgGLUnbindProgram(jctx.getCgVertexProfile()); + } + + if (shaderProgramInfo.getFragmentShader() != null) { + CgGL.cgGLBindProgram(shaderProgramInfo.getFragmentShader().getCgShader()); + CgGL.cgGLEnableProfile(shaderProgramInfo.getFragmentShader().getShaderProfile()); + } else { + CgGL.cgGLUnbindProgram(jctx.getCgFragmentProfile()); + } + } else { + CgGL.cgGLUnbindProgram(jctx.getCgVertexProfile()); + CgGL.cgGLUnbindProgram(jctx.getCgFragmentProfile()); + } + + jctx.setShaderProgram(shaderProgramInfo); + return null; + } + + // + // Helper methods for above + // + private String getCgErrorLog(JoglContext ctx, int lastError) { + if (lastError == 0) + throw new AssertionError("lastError == 0"); + String errString = CgGL.cgGetErrorString(lastError); + String listing = CgGL.cgGetLastListing(ctx.getCgContext()); + return (errString + System.getProperty("line.separator") + listing); + } + + private int cgToJ3dType(int type) { + switch (type) { + case CgGL.CG_BOOL: + case CgGL.CG_BOOL1: + case CgGL.CG_FIXED: + case CgGL.CG_FIXED1: + case CgGL.CG_HALF: + case CgGL.CG_HALF1: + case CgGL.CG_INT: + case CgGL.CG_INT1: + return ShaderAttributeObjectRetained.TYPE_INTEGER; + + // XXXX: add ShaderAttribute support for setting samplers. In the + // mean time, the binding between sampler and texture unit will + // need to be specified in the shader itself (which it already is + // in most example shaders). + // + // case CgGL.CG_SAMPLER2D: + // case CgGL.CG_SAMPLER3D: + // case CgGL.CG_SAMPLERCUBE: + + case CgGL.CG_BOOL2: + case CgGL.CG_FIXED2: + case CgGL.CG_HALF2: + case CgGL.CG_INT2: + return ShaderAttributeObjectRetained.TYPE_TUPLE2I; + + case CgGL.CG_BOOL3: + case CgGL.CG_FIXED3: + case CgGL.CG_HALF3: + case CgGL.CG_INT3: + return ShaderAttributeObjectRetained.TYPE_TUPLE3I; + + case CgGL.CG_BOOL4: + case CgGL.CG_FIXED4: + case CgGL.CG_HALF4: + case CgGL.CG_INT4: + return ShaderAttributeObjectRetained.TYPE_TUPLE4I; + + case CgGL.CG_FLOAT: + case CgGL.CG_FLOAT1: + return ShaderAttributeObjectRetained.TYPE_FLOAT; + + case CgGL.CG_FLOAT2: + return ShaderAttributeObjectRetained.TYPE_TUPLE2F; + + case CgGL.CG_FLOAT3: + return ShaderAttributeObjectRetained.TYPE_TUPLE3F; + + case CgGL.CG_FLOAT4: + return ShaderAttributeObjectRetained.TYPE_TUPLE4F; + + case CgGL.CG_FLOAT3x3: + return ShaderAttributeObjectRetained.TYPE_MATRIX3F; + + case CgGL.CG_FLOAT4x4: + return ShaderAttributeObjectRetained.TYPE_MATRIX4F; + + // Java 3D does not support the following sampler types: + // + // case CgGL.CG_SAMPLER1D: + // case CgGL.CG_SAMPLERRECT: + } + + return -1; + } + + private CGparameter lookupCgParams(JoglCgShaderInfo shader, + String attrNameString, + int[] type, + int[] size, + boolean[] isArray) { + CGparameter loc = CgGL.cgGetNamedParameter(shader.getCgShader(), attrNameString); + if (loc != null) { + type[0] = CgGL.cgGetParameterType(loc); + if (type[0] == CgGL.CG_ARRAY) { + isArray[0] = true; + size[0] = CgGL.cgGetArraySize(loc, 0); + CGparameter firstElem = CgGL.cgGetArrayParameter(loc, 0); + type[0] = CgGL.cgGetParameterType(firstElem); + } else { + isArray[0] = false; + size[0] = 1; + } + } + return loc; + } + + + + // --------------------------------------------------------------------- + + // + // GLSLShaderProgramRetained methods + // + + // ShaderAttributeValue methods + + ShaderError setGLSLUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform1i()"); + + context(ctx).getGL().glUniform1iARB(unbox(uniformLocation), value); + return null; + } + + ShaderError setGLSLUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform1f()"); + + context(ctx).getGL().glUniform1fARB(unbox(uniformLocation), value); + return null; + } + + ShaderError setGLSLUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform2i()"); + + context(ctx).getGL().glUniform2iARB(unbox(uniformLocation), value[0], value[1]); + return null; + } + + ShaderError setGLSLUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform2f()"); + + context(ctx).getGL().glUniform2fARB(unbox(uniformLocation), value[0], value[1]); + return null; + } + + ShaderError setGLSLUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform3i()"); + + context(ctx).getGL().glUniform3iARB(unbox(uniformLocation), value[0], value[1], value[2]); + return null; + } + + ShaderError setGLSLUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform3f()"); + + context(ctx).getGL().glUniform3fARB(unbox(uniformLocation), value[0], value[1], value[2]); + return null; + } + + ShaderError setGLSLUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform4i()"); + + context(ctx).getGL().glUniform4iARB(unbox(uniformLocation), value[0], value[1], value[2], value[3]); + return null; + } + + ShaderError setGLSLUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform4f()"); + + context(ctx).getGL().glUniform4fARB(unbox(uniformLocation), value[0], value[1], value[2], value[3]); + return null; + } + + ShaderError setGLSLUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniformMatrix3f()"); + + // Load attribute + // transpose is true : each matrix is supplied in row major order + context(ctx).getGL().glUniformMatrix3fvARB(unbox(uniformLocation), 1, true, value, 0); + return null; + } + + ShaderError setGLSLUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniformMatrix4f()"); + + // Load attribute + // transpose is true : each matrix is supplied in row major order + context(ctx).getGL().glUniformMatrix4fvARB(unbox(uniformLocation), 1, true, value, 0); + return null; + } + + // ShaderAttributeArray methods + + ShaderError setGLSLUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform1iArray()"); + + context(ctx).getGL().glUniform1ivARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform1fArray()"); + + context(ctx).getGL().glUniform1fvARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform2iArray()"); + + context(ctx).getGL().glUniform2ivARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform2fArray()"); + + context(ctx).getGL().glUniform2fvARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform3iArray()"); + + context(ctx).getGL().glUniform3ivARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform3fArray()"); + + context(ctx).getGL().glUniform3fvARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform4iArray()"); + + context(ctx).getGL().glUniform4ivARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform4fArray()"); + + context(ctx).getGL().glUniform4fvARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniformMatrix3fArray()"); + + // Load attribute + // transpose is true : each matrix is supplied in row major order + context(ctx).getGL().glUniformMatrix3fvARB(unbox(uniformLocation), numElements, true, value, 0); + return null; + } + + ShaderError setGLSLUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniformMatrix4fArray()"); + + // Load attribute + // transpose is true : each matrix is supplied in row major order + context(ctx).getGL().glUniformMatrix4fvARB(unbox(uniformLocation), numElements, true, value, 0); + return null; + } + + // interfaces for shader compilation, etc. + ShaderError createGLSLShader(Context ctx, int shaderType, ShaderId[] shaderId) { + if (VERBOSE) System.err.println("JoglPipeline.createGLSLShader()"); + + GL gl = context(ctx).getGL(); + + int shaderHandle = 0; + if (shaderType == Shader.SHADER_TYPE_VERTEX) { + shaderHandle = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB); + } else if (shaderType == Shader.SHADER_TYPE_FRAGMENT) { + shaderHandle = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB); + } + + if (shaderHandle == 0) { + return new ShaderError(ShaderError.COMPILE_ERROR, + "Unable to create native shader object"); + } + + shaderId[0] = new JoglShaderObject(shaderHandle); + return null; + } + ShaderError destroyGLSLShader(Context ctx, ShaderId shaderId) { + if (VERBOSE) System.err.println("JoglPipeline.destroyGLSLShader()"); + + GL gl = context(ctx).getGL(); + gl.glDeleteObjectARB(unbox(shaderId)); + return null; + } + ShaderError compileGLSLShader(Context ctx, ShaderId shaderId, String program) { + if (VERBOSE) System.err.println("JoglPipeline.compileGLSLShader()"); + + int id = unbox(shaderId); + if (id == 0) { + throw new AssertionError("shaderId == 0"); + } + + if (program == null) { + throw new AssertionError("shader program string is null"); + } + + GL gl = context(ctx).getGL(); + gl.glShaderSourceARB(id, 1, new String[] { program }, null, 0); + gl.glCompileShaderARB(id); + int[] status = new int[1]; + gl.glGetObjectParameterivARB(id, GL.GL_OBJECT_COMPILE_STATUS_ARB, status, 0); + if (status[0] == 0) { + String detailMsg = getInfoLog(gl, id); + ShaderError res = new ShaderError(ShaderError.COMPILE_ERROR, + "GLSL shader compile error"); + res.setDetailMessage(detailMsg); + return res; + } + return null; + } + + ShaderError createGLSLShaderProgram(Context ctx, ShaderProgramId[] shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.createGLSLShaderProgram()"); + + GL gl = context(ctx).getGL(); + + int shaderProgramHandle = gl.glCreateProgramObjectARB(); + if (shaderProgramHandle == 0) { + return new ShaderError(ShaderError.LINK_ERROR, + "Unable to create native shader program object"); + } + shaderProgramId[0] = new JoglShaderObject(shaderProgramHandle); + return null; + } + ShaderError destroyGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.destroyGLSLShaderProgram()"); + context(ctx).getGL().glDeleteObjectARB(unbox(shaderProgramId)); + return null; + } + ShaderError linkGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId, + ShaderId[] shaderIds) { + if (VERBOSE) System.err.println("JoglPipeline.linkGLSLShaderProgram()"); + + GL gl = context(ctx).getGL(); + int id = unbox(shaderProgramId); + for (int i = 0; i < shaderIds.length; i++) { + gl.glAttachObjectARB(id, unbox(shaderIds[i])); + } + gl.glLinkProgramARB(id); + int[] status = new int[1]; + gl.glGetObjectParameterivARB(id, GL.GL_OBJECT_LINK_STATUS_ARB, status, 0); + if (status[0] == 0) { + String detailMsg = getInfoLog(gl, id); + ShaderError res = new ShaderError(ShaderError.LINK_ERROR, + "GLSL shader program link error"); + res.setDetailMessage(detailMsg); + return res; + } + return null; + } + ShaderError bindGLSLVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, + String attrName, int attrIndex) { + if (VERBOSE) System.err.println("JoglPipeline.bindGLSLVertexAttrName()"); + + JoglContext jctx = (JoglContext) ctx; + context(ctx).getGL().glBindAttribLocationARB(unbox(shaderProgramId), + attrIndex + VirtualUniverse.mc.glslVertexAttrOffset, + attrName); + return null; + } + void lookupGLSLShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, ShaderAttrLoc[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr) { + if (VERBOSE) System.err.println("JoglPipeline.lookupGLSLShaderAttrNames()"); + + // set the loc, type, and size arrays to out-of-bound values + for (int i = 0; i < attrNames.length; i++) { + locArr[i] = null; + typeArr[i] = -1; + sizeArr[i] = -1; + } + + // Loop through the list of active uniform variables, one at a + // time, searching for a match in the attrNames array. + // + // NOTE: Since attrNames isn't sorted, and we don't have a + // hashtable of names to index locations, we will do a + // brute-force, linear search of the array. This leads to an + // O(n^2) algorithm (actually O(n*m) where n is attrNames.length + // and m is the number of uniform variables), but since we expect + // N to be small, we will not optimize this at this time. + int id = unbox(shaderProgramId); + int[] tmp = new int[1]; + int[] tmp2 = new int[1]; + int[] tmp3 = new int[1]; + GL gl = context(ctx).getGL(); + gl.glGetObjectParameterivARB(id, + GL.GL_OBJECT_ACTIVE_UNIFORMS_ARB, + tmp, 0); + int numActiveUniforms = tmp[0]; + gl.glGetObjectParameterivARB(id, + GL.GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, + tmp, 0); + int maxStrLen = tmp[0]; + byte[] nameBuf = new byte[maxStrLen]; + + for (int i = 0; i < numActiveUniforms; i++) { + gl.glGetActiveUniformARB(id, i, maxStrLen, tmp3, 0, + tmp, 0, + tmp2, 0, + nameBuf, 0); + int size = tmp[0]; + int type = tmp2[0]; + String name = null; + try { + // TODO KCR : Shouldn't this use the default locale? + name = new String(nameBuf, 0, tmp3[0], "US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + + // Issue 247 - we need to workaround an ATI bug where they erroneously + // report individual elements of arrays rather than the array itself + if (name.length() >= 3 && name.endsWith("]")) { + if (name.endsWith("[0]")) { + name = name.substring(0, name.length() - 3); + } else { + // Ignore this name + continue; + } + } + + // Now try to find the name + for (int j = 0; j < numAttrNames; j++) { + if (name.equals(attrNames[j])) { + sizeArr[j] = size; + isArrayArr[j] = (size > 1); + typeArr[j] = glslToJ3dType(type); + break; + } + } + } + + // Now lookup the location of each name in the attrNames array + for (int i = 0; i < numAttrNames; i++) { + // Get uniform attribute location + int loc = gl.glGetUniformLocationARB(id, attrNames[i]); + locArr[i] = new JoglShaderObject(loc); + } + } + + ShaderError useGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.useGLSLShaderProgram()"); + + context(ctx).getGL().glUseProgramObjectARB(unbox(shaderProgramId)); + ((JoglContext) ctx).setShaderProgram((JoglShaderObject) shaderProgramId); + return null; + } + + //---------------------------------------------------------------------- + // Helper methods for above shader routines + // + private int unbox(ShaderAttrLoc loc) { + if (loc == null) + return 0; + return ((JoglShaderObject) loc).getValue(); + } + + private int unbox(ShaderProgramId id) { + if (id == null) + return 0; + return ((JoglShaderObject) id).getValue(); + } + + private int unbox(ShaderId id) { + if (id == null) + return 0; + return ((JoglShaderObject) id).getValue(); + } + + private String getInfoLog(GL gl, int id) { + int[] infoLogLength = new int[1]; + gl.glGetObjectParameterivARB(id, GL.GL_OBJECT_INFO_LOG_LENGTH_ARB, infoLogLength, 0); + if (infoLogLength[0] > 0) { + byte[] storage = new byte[infoLogLength[0]]; + int[] len = new int[1]; + gl.glGetInfoLogARB(id, infoLogLength[0], len, 0, storage, 0); + try { + // TODO KCR : Shouldn't this use the default locale? + return new String(storage, 0, len[0], "US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + return null; + } + + private int glslToJ3dType(int type) { + switch (type) { + case GL.GL_BOOL_ARB: + case GL.GL_INT: + case GL.GL_SAMPLER_2D_ARB: + case GL.GL_SAMPLER_3D_ARB: + case GL.GL_SAMPLER_CUBE_ARB: + return ShaderAttributeObjectRetained.TYPE_INTEGER; + + case GL.GL_FLOAT: + return ShaderAttributeObjectRetained.TYPE_FLOAT; + + case GL.GL_INT_VEC2_ARB: + case GL.GL_BOOL_VEC2_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE2I; + + case GL.GL_FLOAT_VEC2_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE2F; + + case GL.GL_INT_VEC3_ARB: + case GL.GL_BOOL_VEC3_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE3I; + + case GL.GL_FLOAT_VEC3_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE3F; + + case GL.GL_INT_VEC4_ARB: + case GL.GL_BOOL_VEC4_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE4I; + + case GL.GL_FLOAT_VEC4_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE4F; + + // case GL.GL_FLOAT_MAT2_ARB: + + case GL.GL_FLOAT_MAT3_ARB: + return ShaderAttributeObjectRetained.TYPE_MATRIX3F; + + case GL.GL_FLOAT_MAT4_ARB: + return ShaderAttributeObjectRetained.TYPE_MATRIX4F; + + // Java 3D does not support the following sampler types: + // + // case GL.GL_SAMPLER_1D_ARB: + // case GL.GL_SAMPLER_1D_SHADOW_ARB: + // case GL.GL_SAMPLER_2D_SHADOW_ARB: + // case GL.GL_SAMPLER_2D_RECT_ARB: + // case GL.GL_SAMPLER_2D_RECT_SHADOW_ARB: + } + + return -1; + } + + // --------------------------------------------------------------------- + + // + // Renderer methods + // + + void cleanupRenderer() { + // Nothing to do + } + + + // --------------------------------------------------------------------- + + // + // ColoringAttributesRetained methods + // + + void updateColoringAttributes(Context ctx, + float dRed, float dGreen, float dBlue, + float red, float green, float blue, + float alpha, + boolean lightEnable, + int shadeModel) { + if (VERBOSE) System.err.println("JoglPipeline.updateColoringAttributes()"); + + GL gl = context(ctx).getGL(); + + float cr, cg, cb; + + if (lightEnable) { + cr = dRed; cg = dGreen; cb = dBlue; + } else { + cr = red; cg = green; cb = blue; + } + gl.glColor4f(cr, cg, cb, alpha); + if (shadeModel == ColoringAttributes.SHADE_FLAT) { + gl.glShadeModel(GL.GL_FLAT); + } else { + gl.glShadeModel(GL.GL_SMOOTH); + } + } + + + // --------------------------------------------------------------------- + + // + // DirectionalLightRetained methods + // + + private static final float[] black = new float[4]; + void updateDirectionalLight(Context ctx, + int lightSlot, float red, float green, + float blue, float dirx, float diry, float dirz) { + if (VERBOSE) System.err.println("JoglPipeline.updateDirectionalLight()"); + + GL gl = context(ctx).getGL(); + + int lightNum = GL.GL_LIGHT0 + lightSlot; + float[] values = new float[4]; + + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + gl.glLightfv(lightNum, GL.GL_DIFFUSE, values, 0); + gl.glLightfv(lightNum, GL.GL_SPECULAR, values, 0); + values[0] = -dirx; + values[1] = -diry; + values[2] = -dirz; + values[3] = 0.0f; + gl.glLightfv(lightNum, GL.GL_POSITION, values, 0); + gl.glLightfv(lightNum, GL.GL_AMBIENT, black, 0); + gl.glLightf(lightNum, GL.GL_CONSTANT_ATTENUATION, 1.0f); + gl.glLightf(lightNum, GL.GL_LINEAR_ATTENUATION, 0.0f); + gl.glLightf(lightNum, GL.GL_QUADRATIC_ATTENUATION, 0.0f); + gl.glLightf(lightNum, GL.GL_SPOT_EXPONENT, 0.0f); + gl.glLightf(lightNum, GL.GL_SPOT_CUTOFF, 180.0f); + } + + + // --------------------------------------------------------------------- + + // + // PointLightRetained methods + // + + void updatePointLight(Context ctx, + int lightSlot, float red, float green, + float blue, float attenx, float atteny, float attenz, + float posx, float posy, float posz) { + if (VERBOSE) System.err.println("JoglPipeline.updatePointLight()"); + + GL gl = context(ctx).getGL(); + + int lightNum = GL.GL_LIGHT0 + lightSlot; + float[] values = new float[4]; + + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + gl.glLightfv(lightNum, GL.GL_DIFFUSE, values, 0); + gl.glLightfv(lightNum, GL.GL_SPECULAR, values, 0); + gl.glLightfv(lightNum, GL.GL_AMBIENT, black, 0); + values[0] = posx; + values[1] = posy; + values[2] = posz; + gl.glLightfv(lightNum, GL.GL_POSITION, values, 0); + gl.glLightf(lightNum, GL.GL_CONSTANT_ATTENUATION, attenx); + gl.glLightf(lightNum, GL.GL_LINEAR_ATTENUATION, atteny); + gl.glLightf(lightNum, GL.GL_QUADRATIC_ATTENUATION, attenz); + gl.glLightf(lightNum, GL.GL_SPOT_EXPONENT, 0.0f); + gl.glLightf(lightNum, GL.GL_SPOT_CUTOFF, 180.0f); + } + + + // --------------------------------------------------------------------- + + // + // SpotLightRetained methods + // + + void updateSpotLight(Context ctx, + int lightSlot, float red, float green, + float blue, float attenx, float atteny, float attenz, + float posx, float posy, float posz, float spreadAngle, + float concentration, float dirx, float diry, + float dirz) { + if (VERBOSE) System.err.println("JoglPipeline.updateSpotLight()"); + + GL gl = context(ctx).getGL(); + + int lightNum = GL.GL_LIGHT0 + lightSlot; + float[] values = new float[4]; + + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + gl.glLightfv(lightNum, GL.GL_DIFFUSE, values, 0); + gl.glLightfv(lightNum, GL.GL_SPECULAR, values, 0); + gl.glLightfv(lightNum, GL.GL_AMBIENT, black, 0); + values[0] = posx; + values[1] = posy; + values[2] = posz; + gl.glLightfv(lightNum, GL.GL_POSITION, values, 0); + gl.glLightf(lightNum, GL.GL_CONSTANT_ATTENUATION, attenx); + gl.glLightf(lightNum, GL.GL_LINEAR_ATTENUATION, atteny); + gl.glLightf(lightNum, GL.GL_QUADRATIC_ATTENUATION, attenz); + values[0] = dirx; + values[1] = diry; + values[2] = dirz; + gl.glLightfv(lightNum, GL.GL_SPOT_DIRECTION, values, 0); + gl.glLightf(lightNum, GL.GL_SPOT_EXPONENT, concentration); + gl.glLightf(lightNum, GL.GL_SPOT_CUTOFF, (float) (spreadAngle * 180.0f / Math.PI)); + } + + + // --------------------------------------------------------------------- + + // + // ExponentialFogRetained methods + // + + void updateExponentialFog(Context ctx, + float red, float green, float blue, + float density) { + if (VERBOSE) System.err.println("JoglPipeline.updateExponentialFog()"); + + GL gl = context(ctx).getGL(); + + float[] color = new float[3]; + color[0] = red; + color[1] = green; + color[2] = blue; + gl.glFogi(GL.GL_FOG_MODE, GL.GL_EXP); + gl.glFogfv(GL.GL_FOG_COLOR, color, 0); + gl.glFogf(GL.GL_FOG_DENSITY, density); + gl.glEnable(GL.GL_FOG); + } + + + // --------------------------------------------------------------------- + + // + // LinearFogRetained methods + // + + void updateLinearFog(Context ctx, + float red, float green, float blue, + double fdist, double bdist) { + if (VERBOSE) System.err.println("JoglPipeline.updateLinearFog()"); + + GL gl = context(ctx).getGL(); + + float[] color = new float[3]; + color[0] = red; + color[1] = green; + color[2] = blue; + gl.glFogi(GL.GL_FOG_MODE, GL.GL_LINEAR); + gl.glFogfv(GL.GL_FOG_COLOR, color, 0); + gl.glFogf(GL.GL_FOG_START, (float) fdist); + gl.glFogf(GL.GL_FOG_END, (float) bdist); + gl.glEnable(GL.GL_FOG); + } + + + // --------------------------------------------------------------------- + + // + // LineAttributesRetained methods + // + + void updateLineAttributes(Context ctx, + float lineWidth, int linePattern, + int linePatternMask, + int linePatternScaleFactor, + boolean lineAntialiasing) { + if (VERBOSE) System.err.println("JoglPipeline.updateLineAttributes()"); + + GL gl = context(ctx).getGL(); + gl.glLineWidth(lineWidth); + + if (linePattern == LineAttributes.PATTERN_SOLID) { + gl.glDisable(GL.GL_LINE_STIPPLE); + } else { + if (linePattern == LineAttributes.PATTERN_DASH) { // dashed lines + gl.glLineStipple(1, (short) 0x00ff); + } else if (linePattern == LineAttributes.PATTERN_DOT) { // dotted lines + gl.glLineStipple(1, (short) 0x0101); + } else if (linePattern == LineAttributes.PATTERN_DASH_DOT) { // dash-dotted lines + gl.glLineStipple(1, (short) 0x087f); + } else if (linePattern == LineAttributes.PATTERN_USER_DEFINED) { // user-defined mask + gl.glLineStipple(linePatternScaleFactor, (short) linePatternMask); + } + gl.glEnable(GL.GL_LINE_STIPPLE); + } + + /* XXXX: Polygon Mode check, blend enable */ + if (lineAntialiasing) { + gl.glEnable(GL.GL_LINE_SMOOTH); + } else { + gl.glDisable(GL.GL_LINE_SMOOTH); + } + } + + + // --------------------------------------------------------------------- + + // + // MaterialRetained methods + // + + void updateMaterial(Context ctx, + float red, float green, float blue, float alpha, + float aRed, float aGreen, float aBlue, + float eRed, float eGreen, float eBlue, + float dRed, float dGreen, float dBlue, + float sRed, float sGreen, float sBlue, + float shininess, int colorTarget, boolean lightEnable) { + if (VERBOSE) System.err.println("JoglPipeline.updateMaterial()"); + + float[] color = new float[4]; + + GL gl = context(ctx).getGL(); + + gl.glMaterialf(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, shininess); + switch (colorTarget) { + case Material.DIFFUSE: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE); + break; + case Material.AMBIENT: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT); + break; + case Material.EMISSIVE: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION); + break; + case Material.SPECULAR: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR); + break; + case Material.AMBIENT_AND_DIFFUSE: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE); + break; + } + + color[0] = eRed; color[1] = eGreen; color[2] = eBlue; + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION, color, 0); + + color[0] = aRed; color[1] = aGreen; color[2] = aBlue; + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, color, 0); + + color[0] = sRed; color[1] = sGreen; color[2] = sBlue; + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, color, 0); + + float cr, cg, cb; + + if (lightEnable) { + color[0] = dRed; color[1] = dGreen; color[2] = dBlue; + } else { + color[0] = red; color[1] = green; color[2] = blue; + } + color[3] = alpha; + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, color, 0); + gl.glColor4f(color[0], color[1], color[2], color[3]); + + if (lightEnable) { + gl.glEnable(GL.GL_LIGHTING); + } else { + gl.glDisable(GL.GL_LIGHTING); + } + } + + + // --------------------------------------------------------------------- + + // + // ModelClipRetained methods + // + + void updateModelClip(Context ctx, int planeNum, boolean enableFlag, + double A, double B, double C, double D) { + if (VERBOSE) System.err.println("JoglPipeline.updateModelClip()"); + + GL gl = context(ctx).getGL(); + + double[] equation = new double[4]; + int pl = GL.GL_CLIP_PLANE0 + planeNum; + + // OpenGL clip planes are opposite to J3d clip planes + if (enableFlag) { + equation[0] = -A; + equation[1] = -B; + equation[2] = -C; + equation[3] = -D; + gl.glClipPlane(pl, DoubleBuffer.wrap(equation)); + gl.glEnable(pl); + } else { + gl.glDisable(pl); + } + } + + + // --------------------------------------------------------------------- + + // + // PointAttributesRetained methods + // + + void updatePointAttributes(Context ctx, float pointSize, boolean pointAntialiasing) { + if (VERBOSE) System.err.println("JoglPipeline.updatePointAttributes()"); + + GL gl = context(ctx).getGL(); + gl.glPointSize(pointSize); + + // XXXX: Polygon Mode check, blend enable + if (pointAntialiasing) { + gl.glEnable(GL.GL_POINT_SMOOTH); + } else { + gl.glDisable(GL.GL_POINT_SMOOTH); + } + } + + + // --------------------------------------------------------------------- + + // + // PolygonAttributesRetained methods + // + + void updatePolygonAttributes(Context ctx, + int polygonMode, int cullFace, + boolean backFaceNormalFlip, + float polygonOffset, + float polygonOffsetFactor) { + if (VERBOSE) System.err.println("JoglPipeline.updatePolygonAttributes()"); + + GL gl = context(ctx).getGL(); + + if (cullFace == PolygonAttributes.CULL_NONE) { + gl.glDisable(GL.GL_CULL_FACE); + } else { + if (cullFace == PolygonAttributes.CULL_BACK) { + gl.glCullFace(GL.GL_BACK); + } else { + gl.glCullFace(GL.GL_FRONT); + } + gl.glEnable(GL.GL_CULL_FACE); + } + + if (backFaceNormalFlip && (cullFace != PolygonAttributes.CULL_BACK)) { + gl.glLightModeli(GL.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_TRUE); + } else { + gl.glLightModeli(GL.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_FALSE); + } + + if (polygonMode == PolygonAttributes.POLYGON_POINT) { + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_POINT); + } else if (polygonMode == PolygonAttributes.POLYGON_LINE) { + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE); + } else { + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); + } + + gl.glPolygonOffset(polygonOffsetFactor, polygonOffset); + + if ((polygonOffsetFactor != 0.0) || (polygonOffset != 0.0)) { + switch (polygonMode) { + case PolygonAttributes.POLYGON_POINT: + gl.glEnable(GL.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL.GL_POLYGON_OFFSET_LINE); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + break; + case PolygonAttributes.POLYGON_LINE: + gl.glEnable(GL.GL_POLYGON_OFFSET_LINE); + gl.glDisable(GL.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + break; + case PolygonAttributes.POLYGON_FILL: + gl.glEnable(GL.GL_POLYGON_OFFSET_FILL); + gl.glDisable(GL.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL.GL_POLYGON_OFFSET_LINE); + break; + } + } else { + gl.glDisable(GL.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL.GL_POLYGON_OFFSET_LINE); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + } + } + + + // --------------------------------------------------------------------- + + // + // RenderingAttributesRetained methods + // + + void updateRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride, + boolean depthBufferEnable, + boolean depthBufferWriteEnable, + int depthTestFunction, + float alphaTestValue, int alphaTestFunction, + boolean ignoreVertexColors, + boolean rasterOpEnable, int rasterOp, + boolean userStencilAvailable, boolean stencilEnable, + int stencilFailOp, int stencilZFailOp, int stencilZPassOp, + int stencilFunction, int stencilReferenceValue, + int stencilCompareMask, int stencilWriteMask ) { + if (VERBOSE) System.err.println("JoglPipeline.updateRenderingAttributes()"); + + GL gl = context(ctx).getGL(); + + if (!depthBufferEnableOverride) { + if (depthBufferEnable) { + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glDepthFunc(getFunctionValue(depthTestFunction)); + } else { + gl.glDisable(GL.GL_DEPTH_TEST); + } + } + + if (!depthBufferWriteEnableOverride) { + if (depthBufferWriteEnable) { + gl.glDepthMask(true); + } else { + gl.glDepthMask(false); + } + } + + if (alphaTestFunction == RenderingAttributes.ALWAYS) { + gl.glDisable(GL.GL_ALPHA_TEST); + } else { + gl.glEnable(GL.GL_ALPHA_TEST); + gl.glAlphaFunc(getFunctionValue(alphaTestFunction), alphaTestValue); + } + + if (ignoreVertexColors) { + gl.glDisable(GL.GL_COLOR_MATERIAL); + } else { + gl.glEnable(GL.GL_COLOR_MATERIAL); + } + + if (rasterOpEnable) { + gl.glEnable(GL.GL_COLOR_LOGIC_OP); + switch (rasterOp) { + case RenderingAttributes.ROP_CLEAR: + gl.glLogicOp(GL.GL_CLEAR); + break; + case RenderingAttributes.ROP_AND: + gl.glLogicOp(GL.GL_AND); + break; + case RenderingAttributes.ROP_AND_REVERSE: + gl.glLogicOp(GL.GL_AND_REVERSE); + break; + case RenderingAttributes.ROP_COPY: + gl.glLogicOp(GL.GL_COPY); + break; + case RenderingAttributes.ROP_AND_INVERTED: + gl.glLogicOp(GL.GL_AND_INVERTED); + break; + case RenderingAttributes.ROP_NOOP: + gl.glLogicOp(GL.GL_NOOP); + break; + case RenderingAttributes.ROP_XOR: + gl.glLogicOp(GL.GL_XOR); + break; + case RenderingAttributes.ROP_OR: + gl.glLogicOp(GL.GL_OR); + break; + case RenderingAttributes.ROP_NOR: + gl.glLogicOp(GL.GL_NOR); + break; + case RenderingAttributes.ROP_EQUIV: + gl.glLogicOp(GL.GL_EQUIV); + break; + case RenderingAttributes.ROP_INVERT: + gl.glLogicOp(GL.GL_INVERT); + break; + case RenderingAttributes.ROP_OR_REVERSE: + gl.glLogicOp(GL.GL_OR_REVERSE); + break; + case RenderingAttributes.ROP_COPY_INVERTED: + gl.glLogicOp(GL.GL_COPY_INVERTED); + break; + case RenderingAttributes.ROP_OR_INVERTED: + gl.glLogicOp(GL.GL_OR_INVERTED); + break; + case RenderingAttributes.ROP_NAND: + gl.glLogicOp(GL.GL_NAND); + break; + case RenderingAttributes.ROP_SET: + gl.glLogicOp(GL.GL_SET); + break; + } + } else { + gl.glDisable(GL.GL_COLOR_LOGIC_OP); + } + + if (userStencilAvailable) { + if (stencilEnable) { + gl.glEnable(GL.GL_STENCIL_TEST); + + gl.glStencilOp(getStencilOpValue(stencilFailOp), + getStencilOpValue(stencilZFailOp), + getStencilOpValue(stencilZPassOp)); + + gl.glStencilFunc(getFunctionValue(stencilFunction), + stencilReferenceValue, stencilCompareMask); + + gl.glStencilMask(stencilWriteMask); + + } else { + gl.glDisable(GL.GL_STENCIL_TEST); + } + } + } + + private int getFunctionValue(int func) { + switch (func) { + case RenderingAttributes.ALWAYS: + func = GL.GL_ALWAYS; + break; + case RenderingAttributes.NEVER: + func = GL.GL_NEVER; + break; + case RenderingAttributes.EQUAL: + func = GL.GL_EQUAL; + break; + case RenderingAttributes.NOT_EQUAL: + func = GL.GL_NOTEQUAL; + break; + case RenderingAttributes.LESS: + func = GL.GL_LESS; + break; + case RenderingAttributes.LESS_OR_EQUAL: + func = GL.GL_LEQUAL; + break; + case RenderingAttributes.GREATER: + func = GL.GL_GREATER; + break; + case RenderingAttributes.GREATER_OR_EQUAL: + func = GL.GL_GEQUAL; + break; + } + + return func; + } + + private int getStencilOpValue(int op) { + switch (op) { + case RenderingAttributes.STENCIL_KEEP: + op = GL.GL_KEEP; + break; + case RenderingAttributes.STENCIL_ZERO: + op = GL.GL_ZERO; + break; + case RenderingAttributes.STENCIL_REPLACE: + op = GL.GL_REPLACE; + break; + case RenderingAttributes.STENCIL_INCR: + op = GL.GL_INCR; + break; + case RenderingAttributes.STENCIL_DECR: + op = GL.GL_DECR; + break; + case RenderingAttributes.STENCIL_INVERT: + op = GL.GL_INVERT; + break; + } + + return op; + } + + + // --------------------------------------------------------------------- + + // + // TexCoordGenerationRetained methods + // + + /** + * This method updates the native context: + * trans contains eyeTovworld transform in d3d + * trans contains vworldToEye transform in ogl + */ + void updateTexCoordGeneration(Context ctx, + boolean enable, int genMode, int format, + float planeSx, float planeSy, float planeSz, float planeSw, + float planeTx, float planeTy, float planeTz, float planeTw, + float planeRx, float planeRy, float planeRz, float planeRw, + float planeQx, float planeQy, float planeQz, float planeQw, + double[] vworldToEc) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexCoordGeneration()"); + + GL gl = context(ctx).getGL(); + + float[] planeS = new float[4]; + float[] planeT = new float[4]; + float[] planeR = new float[4]; + float[] planeQ = new float[4]; + + if (enable) { + gl.glEnable(GL.GL_TEXTURE_GEN_S); + gl.glEnable(GL.GL_TEXTURE_GEN_T); + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glEnable(GL.GL_TEXTURE_GEN_R); + gl.glDisable(GL.GL_TEXTURE_GEN_Q); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glEnable(GL.GL_TEXTURE_GEN_R); + gl.glEnable(GL.GL_TEXTURE_GEN_Q); + } else { + gl.glDisable(GL.GL_TEXTURE_GEN_R); + gl.glDisable(GL.GL_TEXTURE_GEN_Q); + } + + if (genMode != TexCoordGeneration.SPHERE_MAP) { + planeS[0] = planeSx; planeS[1] = planeSy; + planeS[2] = planeSz; planeS[3] = planeSw; + planeT[0] = planeTx; planeT[1] = planeTy; + planeT[2] = planeTz; planeT[3] = planeTw; + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + planeR[0] = planeRx; planeR[1] = planeRy; + planeR[2] = planeRz; planeR[3] = planeRw; + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + planeR[0] = planeRx; planeR[1] = planeRy; + planeR[2] = planeRz; planeR[3] = planeRw; + planeQ[0] = planeQx; planeQ[1] = planeQy; + planeQ[2] = planeQz; planeQ[3] = planeQw; + } + } + + switch (genMode) { + case TexCoordGeneration.OBJECT_LINEAR: + gl.glTexGeni(GL.GL_S, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR); + gl.glTexGeni(GL.GL_T, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR); + gl.glTexGenfv(GL.GL_S, GL.GL_OBJECT_PLANE, planeS, 0); + gl.glTexGenfv(GL.GL_T, GL.GL_OBJECT_PLANE, planeT, 0); + + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR); + gl.glTexGenfv(GL.GL_R, GL.GL_OBJECT_PLANE, planeR, 0); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR); + gl.glTexGenfv(GL.GL_R, GL.GL_OBJECT_PLANE, planeR, 0); + gl.glTexGeni(GL.GL_Q, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR); + gl.glTexGenfv(GL.GL_Q, GL.GL_OBJECT_PLANE, planeQ, 0); + } + break; + case TexCoordGeneration.EYE_LINEAR: + + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glPushMatrix(); + + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glLoadTransposeMatrixd(vworldToEc, 0); + } else { + double[] v = new double[16]; + copyTranspose(vworldToEc, v); + gl.glLoadMatrixd(v, 0); + } + + gl.glTexGeni(GL.GL_S, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR); + gl.glTexGeni(GL.GL_T, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR); + gl.glTexGenfv(GL.GL_S, GL.GL_EYE_PLANE, planeS, 0); + gl.glTexGenfv(GL.GL_T, GL.GL_EYE_PLANE, planeT, 0); + + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR); + gl.glTexGenfv(GL.GL_R, GL.GL_EYE_PLANE, planeR, 0); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR); + gl.glTexGenfv(GL.GL_R, GL.GL_EYE_PLANE, planeR, 0); + gl.glTexGeni(GL.GL_Q, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR); + gl.glTexGenfv(GL.GL_Q, GL.GL_EYE_PLANE, planeQ, 0); + } + gl.glPopMatrix(); + break; + case TexCoordGeneration.SPHERE_MAP: + gl.glTexGeni(GL.GL_S, GL.GL_TEXTURE_GEN_MODE, GL.GL_SPHERE_MAP); + gl.glTexGeni(GL.GL_T, GL.GL_TEXTURE_GEN_MODE, GL.GL_SPHERE_MAP); + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_SPHERE_MAP); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_SPHERE_MAP); + gl.glTexGeni(GL.GL_Q, GL.GL_TEXTURE_GEN_MODE, GL.GL_SPHERE_MAP); + } + + break; + case TexCoordGeneration.NORMAL_MAP: + gl.glTexGeni(GL.GL_S, GL.GL_TEXTURE_GEN_MODE, GL.GL_NORMAL_MAP); + gl.glTexGeni(GL.GL_T, GL.GL_TEXTURE_GEN_MODE, GL.GL_NORMAL_MAP); + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_NORMAL_MAP); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_NORMAL_MAP); + gl.glTexGeni(GL.GL_Q, GL.GL_TEXTURE_GEN_MODE, GL.GL_NORMAL_MAP); + } + break; + case TexCoordGeneration.REFLECTION_MAP: + gl.glTexGeni(GL.GL_S, GL.GL_TEXTURE_GEN_MODE, GL.GL_REFLECTION_MAP); + gl.glTexGeni(GL.GL_T, GL.GL_TEXTURE_GEN_MODE, GL.GL_REFLECTION_MAP); + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_REFLECTION_MAP); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_REFLECTION_MAP); + gl.glTexGeni(GL.GL_Q, GL.GL_TEXTURE_GEN_MODE, GL.GL_REFLECTION_MAP); + } + break; + } + } else { + gl.glDisable(GL.GL_TEXTURE_GEN_S); + gl.glDisable(GL.GL_TEXTURE_GEN_T); + gl.glDisable(GL.GL_TEXTURE_GEN_R); + gl.glDisable(GL.GL_TEXTURE_GEN_Q); + } + } + + + // --------------------------------------------------------------------- + + // + // TransparencyAttributesRetained methods + // + + private static final int screen_door[][] = { + /* 0 / 16 */ + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + /* 1 / 16 */ + { + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + }, + /* 2 / 16 */ + { + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + }, + /* 3 / 16 */ + { + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + }, + /* 4 / 16 */ + { + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + }, + /* 5 / 16 */ + { + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + }, + /* 6 / 16 */ + { + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + }, + /* 7 / 16 */ + { + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + }, + /* 8 / 16 */ + { + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + }, + /* 9 / 16 */ + { + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + }, + /* 10 / 16 */ + { + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + }, + /* 11 / 16 */ + { + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + }, + /* 12 / 16 */ + { + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + }, + /* 13 / 16 */ + { + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + }, + /* 14 / 16 */ + { + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + }, + /* 15 / 16 */ + { + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + }, + /* 16 / 16 */ + { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }; + private static final ByteBuffer[] screen_door_table = new ByteBuffer[screen_door.length]; + static { + int eachLen = screen_door[0].length * BufferUtil.SIZEOF_INT; + ByteBuffer buf = BufferUtil.newByteBuffer(screen_door.length * eachLen); + IntBuffer intBuf = buf.asIntBuffer(); + for (int i = 0; i < screen_door.length; i++) { + intBuf.put(screen_door[i]); + } + buf.rewind(); + for (int i = 0; i < screen_door.length; i++) { + buf.position(i * eachLen); + buf.limit((i+1) * eachLen); + screen_door_table[i] = buf.slice(); + } + } + + private static final int[] blendFunctionTable = new int[TransparencyAttributes.MAX_BLEND_FUNC_TABLE_SIZE]; + static { + blendFunctionTable[TransparencyAttributes.BLEND_ZERO] = GL.GL_ZERO; + blendFunctionTable[TransparencyAttributes.BLEND_ONE] = GL.GL_ONE; + blendFunctionTable[TransparencyAttributes.BLEND_SRC_ALPHA] = GL.GL_SRC_ALPHA; + blendFunctionTable[TransparencyAttributes.BLEND_ONE_MINUS_SRC_ALPHA] = GL.GL_ONE_MINUS_SRC_ALPHA; + blendFunctionTable[TransparencyAttributes.BLEND_DST_COLOR] = GL.GL_DST_COLOR; + blendFunctionTable[TransparencyAttributes.BLEND_ONE_MINUS_DST_COLOR] = GL.GL_ONE_MINUS_DST_COLOR; + blendFunctionTable[TransparencyAttributes.BLEND_SRC_COLOR] = GL.GL_SRC_COLOR; + blendFunctionTable[TransparencyAttributes.BLEND_ONE_MINUS_SRC_COLOR] = GL.GL_ONE_MINUS_SRC_COLOR; + blendFunctionTable[TransparencyAttributes.BLEND_CONSTANT_COLOR] = GL.GL_CONSTANT_COLOR; + } + + void updateTransparencyAttributes(Context ctx, + float alpha, int geometryType, + int polygonMode, + boolean lineAA, boolean pointAA, + int transparencyMode, + int srcBlendFunction, + int dstBlendFunction) { + if (VERBOSE) System.err.println("JoglPipeline.updateTransparencyAttributes()"); + + GL gl = context(ctx).getGL(); + + if (transparencyMode != TransparencyAttributes.SCREEN_DOOR) { + gl.glDisable(GL.GL_POLYGON_STIPPLE); + } else { + gl.glEnable(GL.GL_POLYGON_STIPPLE); + gl.glPolygonStipple(screen_door_table[(int)(alpha * 16)]); + } + + if ((transparencyMode < TransparencyAttributes.SCREEN_DOOR) || + ((((geometryType & RenderMolecule.LINE) != 0) || + (polygonMode == PolygonAttributes.POLYGON_LINE)) + && lineAA) || + ((((geometryType & RenderMolecule.POINT) != 0) || + (polygonMode == PolygonAttributes.POLYGON_POINT)) + && pointAA)) { + gl.glEnable(GL.GL_BLEND); + // valid range of blendFunction 0..3 is already verified in shared code. + gl.glBlendFunc(blendFunctionTable[srcBlendFunction], blendFunctionTable[dstBlendFunction]); + } else { + gl.glDisable(GL.GL_BLEND); + } + } + + + // --------------------------------------------------------------------- + + // + // TextureAttributesRetained methods + // + + void updateTextureAttributes(Context ctx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, + float textureBlendColorRed, + float textureBlendColorGreen, + float textureBlendColorBlue, + float textureBlendColorAlpha, + int textureFormat) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureAttributes()"); + + GL gl = context(ctx).getGL(); + gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, + (perspCorrectionMode == TextureAttributes.NICEST) ? GL.GL_NICEST : GL.GL_FASTEST); + + // set OGL texture matrix + gl.glPushAttrib(GL.GL_TRANSFORM_BIT); + gl.glMatrixMode(GL.GL_TEXTURE); + + if (isIdentity) { + gl.glLoadIdentity(); + } else if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glLoadTransposeMatrixd(transform, 0); + } else { + double[] mx = new double[16]; + copyTranspose(transform, mx); + gl.glLoadMatrixd(mx, 0); + } + + gl.glPopAttrib(); + + // set texture color + float[] color = new float[4]; + color[0] = textureBlendColorRed; + color[1] = textureBlendColorGreen; + color[2] = textureBlendColorBlue; + color[3] = textureBlendColorAlpha; + gl.glTexEnvfv(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_COLOR, color, 0); + + // set texture environment mode + + switch (textureMode) { + case TextureAttributes.MODULATE: + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); + break; + case TextureAttributes.DECAL: + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_DECAL); + break; + case TextureAttributes.BLEND: + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_BLEND); + break; + case TextureAttributes.REPLACE: + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); + break; + case TextureAttributes.COMBINE: + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_COMBINE); + break; + } + + if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) { + gl.glDisable(GL.GL_TEXTURE_COLOR_TABLE_SGI); + } + } + + void updateRegisterCombiners(Context absCtx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, + float textureBlendColorRed, + float textureBlendColorGreen, + float textureBlendColorBlue, + float textureBlendColorAlpha, + int textureFormat, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale) { + if (VERBOSE) System.err.println("JoglPipeline.updateRegisterCombiners()"); + + JoglContext ctx = (JoglContext) absCtx; + GL gl = context(ctx).getGL(); + + if (perspCorrectionMode == TextureAttributes.NICEST) { + gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); + } else { + gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_FASTEST); + } + + // set OGL texture matrix + gl.glPushAttrib(GL.GL_TRANSFORM_BIT); + gl.glMatrixMode(GL.GL_TEXTURE); + + if (isIdentity) { + gl.glLoadIdentity(); + } else if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glLoadTransposeMatrixd(transform, 0); + } else { + double[] mx = new double[16]; + copyTranspose(transform, mx); + gl.glLoadMatrixd(mx, 0); + } + + gl.glPopAttrib(); + + // set texture color + float[] color = new float[4]; + color[0] = textureBlendColorRed; + color[1] = textureBlendColorGreen; + color[2] = textureBlendColorBlue; + color[3] = textureBlendColorAlpha; + gl.glTexEnvfv(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_COLOR, color, 0); + + // set texture environment mode + gl.glEnable(GL.GL_REGISTER_COMBINERS_NV); + int textureUnit = ctx.getCurrentTextureUnit(); + int combinerUnit = ctx.getCurrentCombinerUnit(); + int fragment; + if (combinerUnit == GL.GL_COMBINER0_NV) { + fragment = GL.GL_PRIMARY_COLOR_NV; + } else { + fragment = GL.GL_SPARE0_NV; + } + + switch (textureMode) { + case TextureAttributes.MODULATE: + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_A_NV, fragment, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_B_NV, textureUnit, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_A_NV, fragment, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_B_NV, textureUnit, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); + + gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, + GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, + GL.GL_NONE, GL.GL_NONE, false, false, false); + gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, + GL.GL_NONE, GL.GL_NONE, false, false, false); + break; + + case TextureAttributes.DECAL: + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_A_NV, fragment, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_B_NV, textureUnit, + GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_C_NV, textureUnit, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_D_NV, textureUnit, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); + + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_A_NV, fragment, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_B_NV, GL.GL_ZERO, + GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); + + gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, + GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, GL.GL_SPARE0_NV, + GL.GL_NONE, GL.GL_NONE, false, false, false); + gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, + GL.GL_NONE, GL.GL_NONE, false, false, false); + break; + + case TextureAttributes.BLEND: + gl.glCombinerParameterfvNV(GL.GL_CONSTANT_COLOR0_NV, color, 0); + + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_A_NV, fragment, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_B_NV, textureUnit, + GL.GL_UNSIGNED_INVERT_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_C_NV, GL.GL_CONSTANT_COLOR0_NV, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_D_NV, textureUnit, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_A_NV, fragment, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_B_NV, textureUnit, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); + + gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, + GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, GL.GL_SPARE0_NV, + GL.GL_NONE, GL.GL_NONE, false, false, false); + gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, + GL.GL_NONE, GL.GL_NONE, false, false, false); + break; + + case TextureAttributes.REPLACE: + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_A_NV, textureUnit, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_B_NV, GL.GL_ZERO, + GL.GL_UNSIGNED_INVERT_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_A_NV, textureUnit, + GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_B_NV, GL.GL_ZERO, + GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); + + gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, + GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, + GL.GL_NONE, GL.GL_NONE, false, false, false); + gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, + GL.GL_NONE, GL.GL_NONE, false, false, false); + break; + + case TextureAttributes.COMBINE: + if (combineRgbMode == TextureAttributes.COMBINE_DOT3) { + int color1 = getCombinerArg(gl, combineRgbSrc[0], textureUnit, combinerUnit); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_A_NV, color1, + GL.GL_EXPAND_NORMAL_NV, GL.GL_RGB); + int color2 = getCombinerArg(gl, combineRgbSrc[1], textureUnit, combinerUnit); + gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, + GL.GL_VARIABLE_B_NV, color2, + GL.GL_EXPAND_NORMAL_NV, GL.GL_RGB); + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_A_NV, GL.GL_ZERO, + GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); + gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_VARIABLE_B_NV, GL.GL_ZERO, + GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); + + gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, + GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, + GL.GL_NONE/*SCALE_BY_FOUR_NV*/, GL.GL_NONE, true, + false, false); + gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, + GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, + GL.GL_NONE, GL.GL_NONE, false, + false, false); + } + break; + } + + gl.glFinalCombinerInputNV(GL.GL_VARIABLE_A_NV, + GL.GL_SPARE0_NV, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glFinalCombinerInputNV(GL.GL_VARIABLE_B_NV, + GL.GL_ZERO, GL.GL_UNSIGNED_INVERT_NV, GL.GL_RGB); + gl.glFinalCombinerInputNV(GL.GL_VARIABLE_C_NV, + GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glFinalCombinerInputNV(GL.GL_VARIABLE_D_NV, + GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glFinalCombinerInputNV(GL.GL_VARIABLE_E_NV, + GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glFinalCombinerInputNV(GL.GL_VARIABLE_F_NV, + GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); + gl.glFinalCombinerInputNV(GL.GL_VARIABLE_G_NV, + GL.GL_SPARE0_NV, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); + + if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) + gl.glDisable(GL.GL_TEXTURE_COLOR_TABLE_SGI); + // GL_SGI_texture_color_table + } + + void updateTextureColorTable(Context ctx, int numComponents, + int colorTableSize, + int[] textureColorTable) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureColorTable()"); + + GL gl = context(ctx).getGL(); + if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) { + if (numComponents == 3) { + gl.glColorTable(GL.GL_TEXTURE_COLOR_TABLE_SGI, GL.GL_RGB, + colorTableSize, GL.GL_RGB, GL.GL_INT, IntBuffer.wrap(textureColorTable)); + } else { + gl.glColorTable(GL.GL_TEXTURE_COLOR_TABLE_SGI, GL.GL_RGBA, + colorTableSize, GL.GL_RGBA, GL.GL_INT, IntBuffer.wrap(textureColorTable)); + } + gl.glEnable(GL.GL_TEXTURE_COLOR_TABLE_SGI); + } + } + + void updateCombiner(Context ctx, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale) { + if (VERBOSE) System.err.println("JoglPipeline.updateCombiner()"); + + GL gl = context(ctx).getGL(); + int[] GLrgbMode = new int[1]; + int[] GLalphaMode = new int[1]; + getGLCombineMode(gl, combineRgbMode, combineAlphaMode, + GLrgbMode, GLalphaMode); + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_RGB, GLrgbMode[0]); + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_ALPHA, GLalphaMode[0]); + + int nargs; + if (combineRgbMode == TextureAttributes.COMBINE_REPLACE) { + nargs = 1; + } else if (combineRgbMode == TextureAttributes.COMBINE_INTERPOLATE) { + nargs = 3; + } else { + nargs = 2; + } + + for (int i = 0; i < nargs; i++) { + gl.glTexEnvi(GL.GL_TEXTURE_ENV, _gl_combineRgbSrcIndex[i], + _gl_combineSrc[combineRgbSrc[i]]); + gl.glTexEnvi(GL.GL_TEXTURE_ENV, _gl_combineRgbOpIndex[i], + _gl_combineFcn[combineRgbFcn[i]]); + } + + if (combineAlphaMode == TextureAttributes.COMBINE_REPLACE) { + nargs = 1; + } else if (combineAlphaMode == TextureAttributes.COMBINE_INTERPOLATE) { + nargs = 3; + } else { + nargs = 2; + } + + for (int i = 0; i < nargs; i++) { + gl.glTexEnvi(GL.GL_TEXTURE_ENV, _gl_combineAlphaSrcIndex[i], + _gl_combineSrc[combineAlphaSrc[i]]); + gl.glTexEnvi(GL.GL_TEXTURE_ENV, _gl_combineAlphaOpIndex[i], + _gl_combineFcn[combineAlphaFcn[i]]); + } + + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_RGB_SCALE, combineRgbScale); + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_ALPHA_SCALE, combineAlphaScale); + } + + // Helper routines for above + + private void getGLCombineMode(GL gl, int combineRgbMode, int combineAlphaMode, + int[] GLrgbMode, int[] GLalphaMode) { + switch (combineRgbMode) { + case TextureAttributes.COMBINE_REPLACE: + GLrgbMode[0] = GL.GL_REPLACE; + break; + case TextureAttributes.COMBINE_MODULATE: + GLrgbMode[0] = GL.GL_MODULATE; + break; + case TextureAttributes.COMBINE_ADD: + GLrgbMode[0] = GL.GL_ADD; + break; + case TextureAttributes.COMBINE_ADD_SIGNED: + GLrgbMode[0] = GL.GL_ADD_SIGNED; + break; + case TextureAttributes.COMBINE_SUBTRACT: + GLrgbMode[0] = GL.GL_SUBTRACT; + break; + case TextureAttributes.COMBINE_INTERPOLATE: + GLrgbMode[0] = GL.GL_INTERPOLATE; + break; + case TextureAttributes.COMBINE_DOT3: + GLrgbMode[0] = GL.GL_DOT3_RGB; + break; + default: + break; + } + + switch (combineAlphaMode) { + case TextureAttributes.COMBINE_REPLACE: + GLalphaMode[0] = GL.GL_REPLACE; + break; + case TextureAttributes.COMBINE_MODULATE: + GLalphaMode[0] = GL.GL_MODULATE; + break; + case TextureAttributes.COMBINE_ADD: + GLalphaMode[0] = GL.GL_ADD; + break; + case TextureAttributes.COMBINE_ADD_SIGNED: + GLalphaMode[0] = GL.GL_ADD_SIGNED; + break; + case TextureAttributes.COMBINE_SUBTRACT: + GLalphaMode[0] = GL.GL_SUBTRACT; + break; + case TextureAttributes.COMBINE_INTERPOLATE: + GLalphaMode[0] = GL.GL_INTERPOLATE; + break; + case TextureAttributes.COMBINE_DOT3: + // dot3 will only make sense for alpha if rgb is also + // doing dot3. So if rgb is not doing dot3, fallback to replace + if (combineRgbMode == TextureAttributes.COMBINE_DOT3) { + GLrgbMode[0] = GL.GL_DOT3_RGBA; + } else { + GLalphaMode[0] = GL.GL_REPLACE; + } + break; + default: + break; + } + } + + // mapping from java enum to gl enum + private static final int[] _gl_combineRgbSrcIndex = { + GL.GL_SOURCE0_RGB, + GL.GL_SOURCE1_RGB, + GL.GL_SOURCE2_RGB, + }; + + private static final int[] _gl_combineAlphaSrcIndex = { + GL.GL_SOURCE0_ALPHA, + GL.GL_SOURCE1_ALPHA, + GL.GL_SOURCE2_ALPHA, + }; + + private static final int[] _gl_combineRgbOpIndex = { + GL.GL_OPERAND0_RGB, + GL.GL_OPERAND1_RGB, + GL.GL_OPERAND2_RGB, + }; + + private static final int[] _gl_combineAlphaOpIndex = { + GL.GL_OPERAND0_ALPHA, + GL.GL_OPERAND1_ALPHA, + GL.GL_OPERAND2_ALPHA, + }; + + private static final int[] _gl_combineSrc = { + GL.GL_PRIMARY_COLOR, // TextureAttributes.COMBINE_OBJECT_COLOR + GL.GL_TEXTURE, // TextureAttributes.COMBINE_TEXTURE + GL.GL_CONSTANT, // TextureAttributes.COMBINE_CONSTANT_COLOR + GL.GL_PREVIOUS, // TextureAttributes.COMBINE_PREVIOUS_TEXTURE_UNIT_STATE + }; + + private static final int[] _gl_combineFcn = { + GL.GL_SRC_COLOR, // TextureAttributes.COMBINE_SRC_COLOR + GL.GL_ONE_MINUS_SRC_COLOR, // TextureAttributes.COMBINE_ONE_MINUS_SRC_COLOR + GL.GL_SRC_ALPHA, // TextureAttributes.COMBINE_SRC_ALPHA + GL.GL_ONE_MINUS_SRC_ALPHA, // TextureAttributes.COMBINE_ONE_MINUS_SRC_ALPHA + }; + + private int getCombinerArg(GL gl, int arg, int textureUnit, int combUnit) { + int comb = 0; + + switch (arg) { + case TextureAttributes.COMBINE_OBJECT_COLOR: + if (combUnit == GL.GL_COMBINER0_NV) { + comb = GL.GL_PRIMARY_COLOR_NV; + } else { + comb = GL.GL_SPARE0_NV; + } + break; + case TextureAttributes.COMBINE_TEXTURE_COLOR: + comb = textureUnit; + break; + case TextureAttributes.COMBINE_CONSTANT_COLOR: + comb = GL.GL_CONSTANT_COLOR0_NV; + break; + case TextureAttributes.COMBINE_PREVIOUS_TEXTURE_UNIT_STATE: + comb = textureUnit -1; + break; + } + + return comb; + } + + + // --------------------------------------------------------------------- + + // + // TextureUnitStateRetained methods + // + + void updateTextureUnitState(Context ctx, int index, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureUnitState()"); + + GL gl = context(ctx).getGL(); + JoglContext jctx = (JoglContext) ctx; + + if (index >= 0 && gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glActiveTexture(index + GL.GL_TEXTURE0); + gl.glClientActiveTexture(GL.GL_TEXTURE0 + index); + if (gl.isExtensionAvailable("GL_NV_register_combiners")) { + jctx.setCurrentTextureUnit(index + GL.GL_TEXTURE0); + jctx.setCurrentCombinerUnit(index + GL.GL_COMBINER0_NV); + gl.glCombinerParameteriNV(GL.GL_NUM_GENERAL_COMBINERS_NV, index + 1); + } + } + + if (!enable) { + // if not enabled, then don't enable any tex mapping + gl.glDisable(GL.GL_TEXTURE_1D); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glDisable(GL.GL_TEXTURE_3D); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + } + + // if it is enabled, the enable flag will be taken care of + // in the bindTexture call + } + + + // --------------------------------------------------------------------- + + // + // TextureRetained methods + // Texture2DRetained methods + // + + void bindTexture2D(Context ctx, int objectId, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.bindTexture2D(objectId=" + objectId + ",enable=" + enable + ")"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + gl.glDisable(GL.GL_TEXTURE_3D); + + if (!enable) { + gl.glDisable(GL.GL_TEXTURE_2D); + } else { + gl.glBindTexture(GL.GL_TEXTURE_2D, objectId); + gl.glEnable(GL.GL_TEXTURE_2D); + } + } + + void updateTexture2DImage(Context ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int dataType, Object data, boolean useAutoMipMap) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DImage(width=" + width + ",height=" + height + ",level=" + level + ")"); + + updateTexture2DImage(ctx, GL.GL_TEXTURE_2D, + numLevels, level, textureFormat, imageFormat, + width, height, boundaryWidth, dataType, data, useAutoMipMap); + } + + void updateTexture2DSubImage(Context ctx, + int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int dataType, Object data, boolean useAutoMipMap) { + + /* Note: useAutoMipMap is not use for SubImage in the jogl pipe */ + + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DSubImage()"); + + updateTexture2DSubImage(ctx, GL.GL_TEXTURE_2D, + level, xoffset, yoffset, + textureFormat, imageFormat, + imgXOffset, imgYOffset, tilew, width, height, + dataType, data); + } + + void updateTexture2DLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLOD, float maximumLOD) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DLodRange()"); + + updateTextureLodRange(ctx, GL.GL_TEXTURE_2D, + baseLevel, maximumLevel, + minimumLOD, maximumLOD); + } + + void updateTexture2DLodOffset(Context ctx, + float lodOffsetS, float lodOffsetT, + float lodOffsetR) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DLodOffset()"); + + updateTextureLodOffset(ctx, GL.GL_TEXTURE_2D, + lodOffsetS, lodOffsetT, lodOffsetR); + } + + void updateTexture2DBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DBoundary()"); + + updateTextureBoundary(ctx, GL.GL_TEXTURE_2D, + boundaryModeS, boundaryModeT, -1, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTexture2DFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DFilterModes()"); + + updateTextureFilterModes(ctx, GL.GL_TEXTURE_2D, minFilter, magFilter); + } + + void updateTexture2DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DSharpenFunc()"); + + updateTextureSharpenFunc(ctx, GL.GL_TEXTURE_2D, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTexture2DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DFilter4Func()"); + + updateTextureFilter4Func(ctx, GL.GL_TEXTURE_2D, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTexture2DAnisotropicFilter(Context ctx, float degree) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DAnisotropicFilter()"); + + updateTextureAnisotropicFilter(ctx, GL.GL_TEXTURE_2D, degree); + } + + private void updateTextureLodRange(Context ctx, + int target, + int baseLevel, int maximumLevel, + float minimumLOD, float maximumLOD) { + GL gl = context(ctx).getGL(); + // checking of the availability of the extension is already done + // in the shared code + gl.glTexParameteri(target, GL.GL_TEXTURE_BASE_LEVEL, baseLevel); + gl.glTexParameteri(target, GL.GL_TEXTURE_MAX_LEVEL, maximumLevel); + gl.glTexParameterf(target, GL.GL_TEXTURE_MIN_LOD, minimumLOD); + gl.glTexParameterf(target, GL.GL_TEXTURE_MAX_LOD, maximumLOD); + } + + private void updateTextureLodOffset(Context ctx, + int target, + float lodOffsetS, float lodOffsetT, + float lodOffsetR) { + GL gl = context(ctx).getGL(); + // checking of the availability of the extension is already done + // in the shared code + gl.glTexParameterf(target, GL.GL_TEXTURE_LOD_BIAS_S_SGIX, lodOffsetS); + gl.glTexParameterf(target, GL.GL_TEXTURE_LOD_BIAS_T_SGIX, lodOffsetT); + gl.glTexParameterf(target, GL.GL_TEXTURE_LOD_BIAS_R_SGIX, lodOffsetR); + } + + private void updateTextureAnisotropicFilter(Context ctx, int target, float degree) { + GL gl = context(ctx).getGL(); + // checking of the availability of anisotropic filter functionality + // is already done in the shared code + gl.glTexParameterf(target, + GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, + degree); + } + + // --------------------------------------------------------------------- + + // + // Texture3DRetained methods + // + + void bindTexture3D(Context ctx, int objectId, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.bindTexture3D()"); + + GL gl = context(ctx).getGL(); + // textureCubeMap will take precedure over 3D Texture + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + + if (!enable) { + gl.glDisable(GL.GL_TEXTURE_3D); + } else { + gl.glBindTexture(GL.GL_TEXTURE_3D, objectId); + gl.glEnable(GL.GL_TEXTURE_3D); + } + } + + void updateTexture3DImage(Context ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, int depth, + int boundaryWidth, + int dataType, Object data, boolean useAutoMipMap) { + + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DImage()"); + + GL gl = context(ctx).getGL(); + + int format = 0; + int internalFormat = 0; + int type = GL.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + + switch (textureFormat) { + case Texture.INTENSITY: + internalFormat = GL.GL_INTENSITY; + break; + case Texture.LUMINANCE: + internalFormat = GL.GL_LUMINANCE; + break; + case Texture.ALPHA: + internalFormat = GL.GL_ALPHA; + break; + case Texture.LUMINANCE_ALPHA: + internalFormat = GL.GL_LUMINANCE_ALPHA; + break; + case Texture.RGB: + internalFormat = GL.GL_RGB; + break; + case Texture.RGBA: + internalFormat = GL.GL_RGBA; + break; + default: + assert false; + return; + } + + if (useAutoMipMap) { + gl.glTexParameteri(GL.GL_TEXTURE_3D, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); + } + else { + gl.glTexParameteri(GL.GL_TEXTURE_3D, GL.GL_GENERATE_MIPMAP, GL.GL_FALSE); + } + + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + format = GL.GL_BGR; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + format = GL.GL_RGB; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + format = GL.GL_ABGR_EXT; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + format = GL.GL_RGBA; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + format = GL.GL_LUMINANCE_ALPHA; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + if (internalFormat == GL.GL_ALPHA) { + format = GL.GL_ALPHA; + } else { + format = GL.GL_LUMINANCE; + } + break; + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + + gl.glTexImage3D(GL.GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[]) data)); + } + else { + gl.glTexImage3D(GL.GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, GL.GL_UNSIGNED_BYTE, (ByteBuffer) data); + } + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + format = GL.GL_RGBA; + type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + format = GL.GL_BGRA; + type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 1.0f); + } + + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + gl.glTexImage3D(GL.GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, type, IntBuffer.wrap((int[]) data)); + } else { + gl.glTexImage3D(GL.GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, type, (Buffer) data); + } + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 0.0f); + } + } else { + assert false; + } + } + + void updateTexture3DSubImage(Context ctx, + int level, + int xoffset, int yoffset, int zoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, int imgZOffset, + int tilew, int tileh, + int width, int height, int depth, + int dataType, Object data, boolean useAutoMipMap) { + + /* Note: useAutoMipMap is not use for SubImage in the jogl pipe */ + + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DSubImage()"); + + GL gl = context(ctx).getGL(); + + int format = 0; + int internalFormat = 0; + int type = GL.GL_UNSIGNED_INT_8_8_8_8; + int numBytes = 0; + boolean forceAlphaToOne = false; + boolean pixelStore = false; + + if (imgXOffset > 0 || (width < tilew)) { + pixelStore = true; + gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, tilew); + } + + switch (textureFormat) { + case Texture.INTENSITY: + internalFormat = GL.GL_INTENSITY; + break; + case Texture.LUMINANCE: + internalFormat = GL.GL_LUMINANCE; + break; + case Texture.ALPHA: + internalFormat = GL.GL_ALPHA; + break; + case Texture.LUMINANCE_ALPHA: + internalFormat = GL.GL_LUMINANCE_ALPHA; + break; + case Texture.RGB: + internalFormat = GL.GL_RGB; + break; + case Texture.RGBA: + internalFormat = GL.GL_RGBA; + break; + default: + assert false; + } + + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + format = GL.GL_BGR; + numBytes = 3; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + format = GL.GL_RGB; + numBytes = 3; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + format = GL.GL_ABGR_EXT; + numBytes = 4; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + format = GL.GL_RGBA; + numBytes = 4; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + format = GL.GL_LUMINANCE_ALPHA; + numBytes = 2; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + if (internalFormat == GL.GL_ALPHA) { + format = GL.GL_ALPHA; + numBytes = 1; + } else { + format = GL.GL_LUMINANCE; + numBytes = 1; + } + break; + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + ByteBuffer buf = null; + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + buf = ByteBuffer.wrap((byte[]) data); + } + else { + buf = (ByteBuffer) data; + } + + int offset = (tilew * tileh * imgZOffset + + tilew * imgYOffset + imgXOffset) * numBytes; + buf.position(offset); + gl.glTexSubImage3D(GL.GL_TEXTURE_3D, + level, xoffset, yoffset, zoffset, + width, height, depth, + format, GL.GL_UNSIGNED_BYTE, + buf); + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + format = GL.GL_RGBA; + type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + format = GL.GL_BGRA; + type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 1.0f); + } + + IntBuffer buf = null; + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + buf = IntBuffer.wrap((int[]) data); + } + else { + buf = (IntBuffer) data; + } + + int offset = tilew * tileh * imgZOffset + + tilew * imgYOffset + imgXOffset; + buf.position(offset); + gl.glTexSubImage3D(GL.GL_TEXTURE_3D, + level, xoffset, yoffset, zoffset, + width, height, depth, + format, type, + buf); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 0.0f); + } + } else { + assert false; + return; + } + + if (pixelStore) { + gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, 0); + } + + } + + + void updateTexture3DLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DLodRange()"); + + updateTextureLodRange(ctx, GL.GL_TEXTURE_3D, + baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + void updateTexture3DLodOffset(Context ctx, + float lodOffsetS, float lodOffsetT, + float lodOffsetR) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DLodOffset()"); + + updateTextureLodOffset(ctx, GL.GL_TEXTURE_3D, + lodOffsetS, lodOffsetT, lodOffsetR); + } + + void updateTexture3DBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + int boundaryModeR, float boundaryRed, + float boundaryGreen, float boundaryBlue, + float boundaryAlpha) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DBoundary()"); + + updateTextureBoundary(ctx, GL.GL_TEXTURE_2D, + boundaryModeS, boundaryModeT, boundaryModeR, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTexture3DFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DFilterModes()"); + + updateTextureFilterModes(ctx, GL.GL_TEXTURE_3D, + minFilter, magFilter); + } + + void updateTexture3DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DSharpenFunc()"); + + updateTextureSharpenFunc(ctx, GL.GL_TEXTURE_3D, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTexture3DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DFilter4Func()"); + + updateTextureFilter4Func(ctx, GL.GL_TEXTURE_3D, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTexture3DAnisotropicFilter(Context ctx, float degree) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DAnisotropicFilter()"); + + updateTextureAnisotropicFilter(ctx, GL.GL_TEXTURE_3D, degree); + } + + + // --------------------------------------------------------------------- + + // + // TextureCubeMapRetained methods + // + + void bindTextureCubeMap(Context ctx, int objectId, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.bindTextureCubeMap()"); + + GL gl = context(ctx).getGL(); + // TextureCubeMap will take precedure over 3D Texture so + // there is no need to disable 3D Texture here. + if (!enable) { + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + } else { + gl.glBindTexture(GL.GL_TEXTURE_CUBE_MAP, objectId); + gl.glEnable(GL.GL_TEXTURE_CUBE_MAP); + } + } + + void updateTextureCubeMapImage(Context ctx, + int face, int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int dataType, Object data, boolean useAutoMipMap) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapImage()"); + + updateTexture2DImage(ctx, _gl_textureCubeMapFace[face], + numLevels, level, textureFormat, imageFormat, + width, height, boundaryWidth, dataType, data, useAutoMipMap); + } + + void updateTextureCubeMapSubImage(Context ctx, + int face, int level, int xoffset, int yoffset, + int textureFormat,int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int dataType, Object data, boolean useAutoMipMap) { + + /* Note: useAutoMipMap is not use for SubImage in the jogl pipe */ + + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapSubImage()"); + + updateTexture2DSubImage(ctx, _gl_textureCubeMapFace[face], + level, xoffset, yoffset, textureFormat, + imageFormat, imgXOffset, imgYOffset, tilew, + width, height, dataType, data); + } + + void updateTextureCubeMapLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapLodRange()"); + + updateTextureLodRange(ctx, + GL.GL_TEXTURE_CUBE_MAP, + baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + void updateTextureCubeMapLodOffset(Context ctx, + float lodOffsetS, float lodOffsetT, + float lodOffsetR) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapLodOffset()"); + + updateTextureLodOffset(ctx, + GL.GL_TEXTURE_CUBE_MAP, + lodOffsetS, lodOffsetT, lodOffsetR); + } + + void updateTextureCubeMapBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapBoundary()"); + + updateTextureBoundary(ctx, + GL.GL_TEXTURE_CUBE_MAP, + boundaryModeS, boundaryModeT, -1, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTextureCubeMapFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapFilterModes()"); + + updateTextureFilterModes(ctx, + GL.GL_TEXTURE_CUBE_MAP, + minFilter, magFilter); + } + + void updateTextureCubeMapSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapSharpenFunc()"); + + updateTextureSharpenFunc(ctx, + GL.GL_TEXTURE_CUBE_MAP, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTextureCubeMapFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapFilter4Func()"); + + updateTextureFilter4Func(ctx, + GL.GL_TEXTURE_CUBE_MAP, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTextureCubeMapAnisotropicFilter(Context ctx, float degree) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapAnisotropicFilter()"); + + updateTextureAnisotropicFilter(ctx, + GL.GL_TEXTURE_CUBE_MAP, + degree); + } + + //---------------------------------------------------------------------- + // + // Helper routines for above texture methods + // + + private void updateTexture2DImage(Context ctx, + int target, + int numLevels, + int level, + int textureFormat, + int imageFormat, + int width, + int height, + int boundaryWidth, + int dataType, + Object data, + boolean useAutoMipMap) { + GL gl = context(ctx).getGL(); + + int format = 0, internalFormat = 0; + int type = GL.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + + switch (textureFormat) { + case Texture.INTENSITY: + internalFormat = GL.GL_INTENSITY; + break; + case Texture.LUMINANCE: + internalFormat = GL.GL_LUMINANCE; + break; + case Texture.ALPHA: + internalFormat = GL.GL_ALPHA; + break; + case Texture.LUMINANCE_ALPHA: + internalFormat = GL.GL_LUMINANCE_ALPHA; + break; + case Texture.RGB: + internalFormat = GL.GL_RGB; + break; + case Texture.RGBA: + internalFormat = GL.GL_RGBA; + break; + default: + assert false; + } + + if (useAutoMipMap) { + gl.glTexParameteri(target, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); + } + else { + gl.glTexParameteri(target, GL.GL_GENERATE_MIPMAP, GL.GL_FALSE); + } + + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + format = GL.GL_BGR; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + format = GL.GL_RGB; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + format = GL.GL_ABGR_EXT; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + format = GL.GL_RGBA; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + format = GL.GL_LUMINANCE_ALPHA; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + if (internalFormat == GL.GL_ALPHA) { + format = GL.GL_ALPHA; + } else { + format = GL.GL_LUMINANCE; + } + break; + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + + gl.glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[])data)); + } else { + gl.glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, GL.GL_UNSIGNED_BYTE, (Buffer) data); + } + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + format = GL.GL_RGBA; + type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + format = GL.GL_BGRA; + type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 1.0f); + } + + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + gl.glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, type, IntBuffer.wrap((int[])data)); + } else { + gl.glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, type, (Buffer) data); + } + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 0.0f); + } + } else { + assert false; + } + } + + private void updateTexture2DSubImage(Context ctx, + int target, + int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int dataType, Object data) { + GL gl = context(ctx).getGL(); + + int format = 0, internalFormat=0; + int numBytes = 0; + int type = GL.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + boolean pixelStore = false; + + if (imgXOffset > 0 || (width < tilew)) { + pixelStore = true; + gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, tilew); + } + + switch (textureFormat) { + case Texture.INTENSITY: + internalFormat = GL.GL_INTENSITY; + break; + case Texture.LUMINANCE: + internalFormat = GL.GL_LUMINANCE; + break; + case Texture.ALPHA: + internalFormat = GL.GL_ALPHA; + break; + case Texture.LUMINANCE_ALPHA: + internalFormat = GL.GL_LUMINANCE_ALPHA; + break; + case Texture.RGB: + internalFormat = GL.GL_RGB; + break; + case Texture.RGBA: + internalFormat = GL.GL_RGBA; + break; + default: + assert false; + } + + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + format = GL.GL_BGR; + numBytes = 3; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + format = GL.GL_RGB; + numBytes = 3; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + format = GL.GL_ABGR_EXT; + numBytes = 4; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + format = GL.GL_RGBA; + numBytes = 4; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + format = GL.GL_LUMINANCE_ALPHA; + numBytes = 2; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + if (internalFormat == GL.GL_ALPHA) { + format = GL.GL_ALPHA; + numBytes = 1; + } else { + format = GL.GL_LUMINANCE; + numBytes = 1; + } + break; + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + ByteBuffer buf = null; + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + buf = ByteBuffer.wrap((byte[]) data); + } + else { + buf = (ByteBuffer) data; + } + + // offset by the imageOffset + buf.position((tilew * imgYOffset + imgXOffset) * numBytes); + gl.glTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, GL.GL_UNSIGNED_BYTE, buf); + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + format = GL.GL_RGBA; + type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + format = GL.GL_BGRA; + type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 1.0f); + } + + IntBuffer buf = null; + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + buf = IntBuffer.wrap((int[]) data); + } + else { + buf = (IntBuffer) data; + } + + // offset by the imageOffset + buf.position(tilew * imgYOffset + imgXOffset); + gl.glTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, type, buf); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 0.0f); + } + } else { + assert false; + return; + } + + if (pixelStore) { + gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, 0); + } + + } + + void updateTextureFilterModes(Context ctx, + int target, + int minFilter, + int magFilter) { + GL gl = context(ctx).getGL(); + + if (EXTRA_DEBUGGING) { + System.err.println("minFilter: " + getFilterName(minFilter) + + " magFilter: " + getFilterName(magFilter)); + } + + // FIXME: unclear whether we really need to set up the enum values + // in the JoglContext as is done in the native code depending on + // extension availability; maybe this is the defined fallback + // behavior of the various Java3D modes + + // set texture min filter + switch (minFilter) { + case Texture.FASTEST: + case Texture.BASE_LEVEL_POINT: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + break; + case Texture.BASE_LEVEL_LINEAR: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + break; + case Texture.MULTI_LEVEL_POINT: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_NEAREST_MIPMAP_NEAREST); + break; + case Texture.NICEST: + case Texture.MULTI_LEVEL_LINEAR: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_LINEAR_MIPMAP_LINEAR); + break; + case Texture.FILTER4: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_FILTER4_SGIS); + break; + } + + // set texture mag filter + switch (magFilter) { + case Texture.FASTEST: + case Texture.BASE_LEVEL_POINT: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + break; + case Texture.NICEST: + case Texture.BASE_LEVEL_LINEAR: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + break; + case Texture.LINEAR_SHARPEN: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_LINEAR_SHARPEN_SGIS); + break; + case Texture.LINEAR_SHARPEN_RGB: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_LINEAR_SHARPEN_COLOR_SGIS); + break; + case Texture.LINEAR_SHARPEN_ALPHA: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_LINEAR_SHARPEN_ALPHA_SGIS); + break; + case Texture2D.LINEAR_DETAIL: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_LINEAR_DETAIL_SGIS); + break; + case Texture2D.LINEAR_DETAIL_RGB: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_LINEAR_DETAIL_COLOR_SGIS); + break; + case Texture2D.LINEAR_DETAIL_ALPHA: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_LINEAR_DETAIL_ALPHA_SGIS); + break; + case Texture.FILTER4: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_FILTER4_SGIS); + break; + } + } + + void updateTextureBoundary(Context ctx, + int target, + int boundaryModeS, + int boundaryModeT, + int boundaryModeR, + float boundaryRed, + float boundaryGreen, + float boundaryBlue, + float boundaryAlpha) { + GL gl = context(ctx).getGL(); + + // set texture wrap parameter + switch (boundaryModeS) { + case Texture.WRAP: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); + break; + case Texture.CLAMP: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP); + break; + case Texture.CLAMP_TO_EDGE: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, + GL.GL_CLAMP_TO_EDGE); + break; + case Texture.CLAMP_TO_BOUNDARY: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, + GL.GL_CLAMP_TO_BORDER); + break; + } + + switch (boundaryModeT) { + case Texture.WRAP: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); + break; + case Texture.CLAMP: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP); + break; + case Texture.CLAMP_TO_EDGE: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, + GL.GL_CLAMP_TO_EDGE); + break; + case Texture.CLAMP_TO_BOUNDARY: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, + GL.GL_CLAMP_TO_BORDER); + break; + } + + // applies to Texture3D only + if (boundaryModeR != -1) { + switch (boundaryModeR) { + case Texture.WRAP: + gl.glTexParameteri(target, + GL.GL_TEXTURE_WRAP_R, GL.GL_REPEAT); + break; + + case Texture.CLAMP: + gl.glTexParameteri(target, + GL.GL_TEXTURE_WRAP_R, GL.GL_CLAMP); + break; + case Texture.CLAMP_TO_EDGE: + gl.glTexParameteri(target, + GL.GL_TEXTURE_WRAP_R, + GL.GL_CLAMP_TO_EDGE); + break; + case Texture.CLAMP_TO_BOUNDARY: + gl.glTexParameteri(target, + GL.GL_TEXTURE_WRAP_R, + GL.GL_CLAMP_TO_BORDER); + break; + } + } + + if (boundaryModeS == Texture.CLAMP || + boundaryModeT == Texture.CLAMP || + boundaryModeR == Texture.CLAMP) { + // set texture border color + float[] color = new float[4]; + color[0] = boundaryRed; + color[1] = boundaryGreen; + color[2] = boundaryBlue; + color[3] = boundaryAlpha; + gl.glTexParameterfv(target, GL.GL_TEXTURE_BORDER_COLOR, color, 0); + } + } + + private static final String getFilterName(int filter) { + switch (filter) { + case Texture.FASTEST: + return "Texture.FASTEST"; + case Texture.NICEST: + return "Texture.NICEST"; + case Texture.BASE_LEVEL_POINT: + return "Texture.BASE_LEVEL_POINT"; + case Texture.BASE_LEVEL_LINEAR: + return "Texture.BASE_LEVEL_LINEAR"; + case Texture.MULTI_LEVEL_POINT: + return "Texture.MULTI_LEVEL_POINT"; + case Texture.MULTI_LEVEL_LINEAR: + return "Texture.MULTI_LEVEL_LINEAR"; + case Texture.FILTER4: + return "Texture.FILTER4"; + case Texture.LINEAR_SHARPEN: + return "Texture.LINEAR_SHARPEN"; + case Texture.LINEAR_SHARPEN_RGB: + return "Texture.LINEAR_SHARPEN_RGB"; + case Texture.LINEAR_SHARPEN_ALPHA: + return "Texture.LINEAR_SHARPEN_ALPHA"; + case Texture2D.LINEAR_DETAIL: + return "Texture.LINEAR_DETAIL"; + case Texture2D.LINEAR_DETAIL_RGB: + return "Texture.LINEAR_DETAIL_RGB"; + case Texture2D.LINEAR_DETAIL_ALPHA: + return "Texture.LINEAR_DETAIL_ALPHA"; + default: + return "(unknown)"; + } + } + + private void updateTextureSharpenFunc(Context ctx, + int target, + int numPts, + float[] pts) { + // checking of the availability of sharpen texture functionality + // is already done in shared code + GL gl = context(ctx).getGL(); + gl.glSharpenTexFuncSGIS(target, numPts, pts, 0); + } + + private void updateTextureFilter4Func(Context ctx, + int target, + int numPts, + float[] pts) { + // checking of the availability of filter4 functionality + // is already done in shared code + GL gl = context(ctx).getGL(); + gl.glTexFilterFuncSGIS(target, GL.GL_FILTER4_SGIS, + numPts, pts, 0); + } + + // mapping from java enum to gl enum + private static final int[] _gl_textureCubeMapFace = { + GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + }; + + // --------------------------------------------------------------------- + + // + // MasterControl methods + // + + // Method to return the AWT object + long getAWT() { + if (VERBOSE) System.err.println("JoglPipeline.getAWT()"); + + // FIXME: probably completely unneeded in this implementation, + // but should probably remove this dependence in the shared code + return 0; + } + + // Method to initialize the native J3D library + boolean initializeJ3D(boolean disableXinerama) { + // Dummy method in JOGL pipeline + return true; + } + + // Maximum lights supported by the native API + int getMaximumLights() { + if (VERBOSE) System.err.println("JoglPipeline.getMaximumLights()"); + + // FIXME: this isn't quite what the NativePipeline returns but + // is probably close enough + return 8; + } + + + // --------------------------------------------------------------------- + + // + // Canvas3D methods - native wrappers + // + + // This is the native method for creating the underlying graphics context. + Context createNewContext(Canvas3D cv, long display, Drawable drawable, + long fbConfig, Context shareCtx, boolean isSharedCtx, + boolean offScreen, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + if (VERBOSE) System.err.println("JoglPipeline.createNewContext()"); + GLDrawable draw = null; + GLCapabilitiesChooser indexChooser = null; + JoglGraphicsConfiguration config = (JoglGraphicsConfiguration) cv.graphicsConfiguration; + if (config.getChosenIndex() >= 0) { + indexChooser = new IndexCapabilitiesChooser(config.getChosenIndex()); + } + if (cv.drawable == null) { + draw = + GLDrawableFactory.getFactory().getGLDrawable(cv, + config.getGLCapabilities(), + indexChooser); + cv.drawable = new JoglDrawable(draw); + } else { + draw = drawable(cv.drawable); + } + + // FIXME: assuming that this only gets called after addNotify has been called + draw.setRealized(true); + GLContext context = draw.createContext(context(shareCtx)); + + // Apparently we are supposed to make the context current at + // this point and set up a bunch of properties + + // Work around for some low end graphics driver bug, such as Intel Chipset. + // Issue 324 : Lockup Java3D program and throw exception using JOGL renderer + boolean failed = false; + int failCount = 0; + int MAX_FAIL_COUNT = 5; + do { + failed = false; + int res = context.makeCurrent(); + if (res == GLContext.CONTEXT_NOT_CURRENT) { + // System.err.println("makeCurrent fail : " + failCount); + failed = true; + ++failCount; + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + } while (failed && (failCount < MAX_FAIL_COUNT)); + if (failCount == MAX_FAIL_COUNT) { + throw new IllegalRenderingStateException("Unable to make new context current after " + failCount + "tries"); + } + + GL gl = context.getGL(); + JoglContext ctx = new JoglContext(context); + + try { + if (!getPropertiesFromCurrentContext(ctx)) { + throw new IllegalRenderingStateException("Unable to fetch properties from current OpenGL context"); + } + + if(!isSharedCtx){ + // Set up fields in Canvas3D + setupCanvasProperties(cv, ctx, gl, glslLibraryAvailable, cgLibraryAvailable); + } + + // Enable rescale normal + gl.glEnable(GL.GL_RESCALE_NORMAL); + + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE); + gl.glDepthFunc(GL.GL_LEQUAL); + gl.glEnable(GL.GL_COLOR_MATERIAL); + gl.glReadBuffer(GL.GL_FRONT); + + // Issue 417: JOGL: Mip-mapped NPOT textures rendered incorrectly + // Java 3D images are aligned to 1 byte + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + + // Workaround for issue 400: Enable separate specular by default + gl.glLightModeli(GL.GL_LIGHT_MODEL_COLOR_CONTROL, GL.GL_SEPARATE_SPECULAR_COLOR); + } finally { + context.release(); + } + + return ctx; + } + + void createQueryContext(Canvas3D cv, long display, Drawable drawable, + long fbConfig, boolean offScreen, int width, int height, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + if (VERBOSE) System.err.println("JoglPipeline.createQueryContext()"); + + // FIXME: for now, ignoring the "offscreen" flag -- unclear how + // to create an offscreen buffer at this point -- very likely + // need Canvas3D.offScreenBufferInfo promoted to an Object -- + // this logic will need to be revisited to make sure we capture + // all of the functionality of the NativePipeline + + Frame f = new Frame(); + f.setUndecorated(true); + f.setLayout(new BorderLayout()); + GLCapabilities caps = new GLCapabilities(); + ContextQuerier querier = new ContextQuerier(cv, + glslLibraryAvailable, + cgLibraryAvailable); + // FIXME: should know what GraphicsDevice on which to create + // this Canvas / Frame, and this should probably be known from + // the incoming "display" parameter + QueryCanvas canvas = new QueryCanvas(caps, querier, null); + f.add(canvas, BorderLayout.CENTER); + f.setSize(MIN_FRAME_SIZE, MIN_FRAME_SIZE); + f.setVisible(true); + canvas.doQuery(); + // Attempt to wait for the frame to become visible, but don't block the EDT + if (!EventQueue.isDispatchThread()) { + synchronized(querier) { + if (!querier.done()) { + try { + querier.wait(WAIT_TIME); + } catch (InterruptedException e) { + } + } + } + } + + disposeOnEDT(f); + } + + // This is the native for creating an offscreen buffer + Drawable createOffScreenBuffer(Canvas3D cv, Context ctx, long display, long fbConfig, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.createOffScreenBuffer()"); + + // Note 1: when this is called, the incoming Context argument is + // null because (obviously) no drawable or context has been + // created for the Canvas3D yet. + + // Note 2: we ignore the global j3d.usePbuffer flag; JOGL + // doesn't expose pixmap/bitmap surfaces in its public API. + + // First pick up the JoglGraphicsConfiguration and from there + // the GLCapabilities from the Canvas3D + JoglGraphicsConfiguration jcfg = (JoglGraphicsConfiguration) cv.graphicsConfiguration; + // Note that we ignore any chosen index from a prior call to getBestConfiguration(); + // those only enumerate the on-screen visuals, and we need to find one which is + // pbuffer capable + GLCapabilities caps = jcfg.getGLCapabilities(); + if (!GLDrawableFactory.getFactory().canCreateGLPbuffer()) { + // FIXME: do anything else here? Throw exception? + return null; + } + + GLPbuffer pbuffer = GLDrawableFactory.getFactory().createGLPbuffer(caps, null, + width, height, null); + return new JoglDrawable(pbuffer); + } + + void destroyOffScreenBuffer(Canvas3D cv, Context ctx, long display, long fbConfig, Drawable drawable) { + if (VERBOSE) System.err.println("JoglPipeline.destroyOffScreenBuffer()"); + + JoglDrawable jdraw = (JoglDrawable) drawable; + GLPbuffer pbuffer = (GLPbuffer) jdraw.getGLDrawable(); + pbuffer.destroy(); + } + + // This is the native for reading the image from the offscreen buffer + void readOffScreenBuffer(Canvas3D cv, Context ctx, int format, int dataType, Object data, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.readOffScreenBuffer()"); + + GL gl = context(ctx).getGL(); + gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, width); + gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1); + + int type = 0; + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (format) { + // GL_BGR + case ImageComponentRetained.TYPE_BYTE_BGR: + type = GL.GL_BGR; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + type = GL.GL_RGB; + break; + // GL_ABGR_EXT + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If false, should never come here! + type = GL.GL_ABGR_EXT; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + type = GL.GL_RGBA; + break; + + /* This method only supports 3 and 4 components formats and BYTE types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + throw new AssertionError("illegal format " + format); + } + + gl.glReadPixels(0, 0, width, height, type, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[]) data)); + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + int intType = GL.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + + switch (format) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + type = GL.GL_RGBA; + intType = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + type = GL.GL_BGRA; + intType = GL.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and BYTE types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + throw new AssertionError("illegal format " + format); + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 1.0f); + } + + gl.glReadPixels(0, 0, width, height, type, intType, IntBuffer.wrap((int[]) data)); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 0.0f); + } + + } else { + throw new AssertionError("illegal image data type " + dataType); + + } + } + + // The native method for swapBuffers + int swapBuffers(Canvas3D cv, Context ctx, long dpy, Drawable drawable) { + if (VERBOSE) System.err.println("JoglPipeline.swapBuffers()"); + GLDrawable draw = drawable(drawable); + draw.swapBuffers(); + return 0; + } + + // notify D3D that Canvas is resize + int resizeD3DCanvas(Canvas3D cv, Context ctx) { + // Dummy method in JOGL pipeline + return 0; + } + + // notify D3D to toggle between FullScreen and window mode + int toggleFullScreenMode(Canvas3D cv, Context ctx) { + // Dummy method in JOGL pipeline + return 0; + } + + // native method for setting Material when no material is present + void updateMaterialColor(Context ctx, float r, float g, float b, float a) { + if (VERBOSE) System.err.println("JoglPipeline.updateMaterialColor()"); + + GL gl = context(ctx).getGL(); + gl.glColor4f(r, g, b, a); + gl.glDisable(GL.GL_LIGHTING); + } + + void destroyContext(long display, Drawable drawable, Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.destroyContext()"); + GLDrawable draw = drawable(drawable); + GLContext context = context(ctx); + if (GLContext.getCurrent() == context) { + context.release(); + } + context.destroy(); + // FIXME: assuming this is the right point at which to make this call + draw.setRealized(false); + } + + // This is the native method for doing accumulation. + void accum(Context ctx, float value) { + if (VERBOSE) System.err.println("JoglPipeline.accum()"); + + GL gl = context(ctx).getGL(); + gl.glReadBuffer(GL.GL_BACK); + gl.glAccum(GL.GL_ACCUM, value); + gl.glReadBuffer(GL.GL_FRONT); + } + + // This is the native method for doing accumulation return. + void accumReturn(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.accumReturn()"); + + GL gl = context(ctx).getGL(); + gl.glAccum(GL.GL_RETURN, 1.0f); + } + + // This is the native method for clearing the accumulation buffer. + void clearAccum(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.clearAccum()"); + + GL gl = context(ctx).getGL(); + gl.glClear(GL.GL_ACCUM_BUFFER_BIT); + } + + // This is the native method for getting the number of lights the underlying + // native library can support. + int getNumCtxLights(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.getNumCtxLights()"); + + GL gl = context(ctx).getGL(); + int[] res = new int[1]; + gl.glGetIntegerv(GL.GL_MAX_LIGHTS, res, 0); + return res[0]; + } + + // Native method for decal 1st child setup + boolean decal1stChildSetup(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.decal1stChildSetup()"); + + GL gl = context(ctx).getGL(); + gl.glEnable(GL.GL_STENCIL_TEST); + gl.glClearStencil(0x0); + gl.glClear(GL.GL_STENCIL_BUFFER_BIT); + gl.glStencilFunc(GL.GL_ALWAYS, 0x1, 0x1); + gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_REPLACE); + if (gl.glIsEnabled(GL.GL_DEPTH_TEST)) + return true; + else + return false; + } + + // Native method for decal nth child setup + void decalNthChildSetup(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.decalNthChildSetup()"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL.GL_DEPTH_TEST); + gl.glStencilFunc(GL.GL_EQUAL, 0x1, 0x1); + gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_KEEP); + } + + // Native method for decal reset + void decalReset(Context ctx, boolean depthBufferEnable) { + if (VERBOSE) System.err.println("JoglPipeline.decalReset()"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL.GL_STENCIL_TEST); + if (depthBufferEnable) + gl.glEnable(GL.GL_DEPTH_TEST); + } + + // Native method for eye lighting + void ctxUpdateEyeLightingEnable(Context ctx, boolean localEyeLightingEnable) { + if (VERBOSE) System.err.println("JoglPipeline.ctxUpdateEyeLightingEnable()"); + + GL gl = context(ctx).getGL(); + + if (localEyeLightingEnable) { + gl.glLightModeli(GL.GL_LIGHT_MODEL_LOCAL_VIEWER, GL.GL_TRUE); + } else { + gl.glLightModeli(GL.GL_LIGHT_MODEL_LOCAL_VIEWER, GL.GL_FALSE); + } + } + + // The following three methods are used in multi-pass case + + // native method for setting blend color + void setBlendColor(Context ctx, float red, float green, + float blue, float alpha) { + if (VERBOSE) System.err.println("JoglPipeline.setBlendColor()"); + + GL gl = context(ctx).getGL(); + if (gl.isExtensionAvailable("GL_ARB_imaging")) { + gl.glBlendColor(red, green, blue, alpha); + } + } + + // native method for setting blend func + void setBlendFunc(Context ctx, int srcBlendFunction, int dstBlendFunction) { + if (VERBOSE) System.err.println("JoglPipeline.setBlendFunc()"); + + GL gl = context(ctx).getGL(); + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(blendFunctionTable[srcBlendFunction], + blendFunctionTable[dstBlendFunction]); + } + + // native method for setting fog enable flag + void setFogEnableFlag(Context ctx, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.setFogEnableFlag()"); + + GL gl = context(ctx).getGL(); + + if (enable) + gl.glEnable(GL.GL_FOG); + else + gl.glDisable(GL.GL_FOG); + } + + // Setup the full scene antialising in D3D and ogl when GL_ARB_multisamle supported + void setFullSceneAntialiasing(Context absCtx, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.setFullSceneAntialiasing()"); + + JoglContext ctx = (JoglContext) absCtx; + GL gl = context(ctx).getGL(); + if (ctx.getHasMultisample() && !VirtualUniverse.mc.implicitAntialiasing) { + if (enable) { + gl.glEnable(GL.GL_MULTISAMPLE); + } else { + gl.glDisable(GL.GL_MULTISAMPLE); + } + } + } + + void setGlobalAlpha(Context ctx, float alpha) { + if (VERBOSE) System.err.println("JoglPipeline.setGlobalAlpha()"); + + GL gl = context(ctx).getGL(); + if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { + gl.glEnable(GL.GL_GLOBAL_ALPHA_SUN); + gl.glGlobalAlphaFactorfSUN(alpha); + } + } + + // Native method to update separate specular color control + void updateSeparateSpecularColorEnable(Context ctx, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.updateSeparateSpecularColorEnable()"); + + GL gl = context(ctx).getGL(); + + if (enable) { + gl.glLightModeli(GL.GL_LIGHT_MODEL_COLOR_CONTROL, GL.GL_SEPARATE_SPECULAR_COLOR); + } else { + gl.glLightModeli(GL.GL_LIGHT_MODEL_COLOR_CONTROL, GL.GL_SINGLE_COLOR); + } + } + + // Initialization for D3D when scene begins and ends + void beginScene(Context ctx) { + } + void endScene(Context ctx) { + } + + // True under Solaris, + // False under windows when display mode <= 8 bit + boolean validGraphicsMode() { + if (VERBOSE) System.err.println("JoglPipeline.validGraphicsMode()"); + + // FIXME: believe this should do exactly what the native code + // used to, but not 100% sure (also in theory should only run + // this code on the Windows platform? What about Mac OS X?) + DisplayMode currentMode = + GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode(); + // Note: on X11 platforms, a bit depth < 0 simply indicates that + // multiple visuals are supported on the current display mode + + if (VERBOSE) System.err.println(" Returning " + (currentMode.getBitDepth() < 0 || + currentMode.getBitDepth() > 8)); + + return (currentMode.getBitDepth() < 0 || + currentMode.getBitDepth() > 8); + } + + // native method for setting light enables + void setLightEnables(Context ctx, long enableMask, int maxLights) { + if (VERBOSE) System.err.println("JoglPipeline.setLightEnables()"); + + GL gl = context(ctx).getGL(); + + for (int i = 0; i < maxLights; i++) { + if ((enableMask & (1 << i)) != 0) { + gl.glEnable(GL.GL_LIGHT0 + i); + } else { + gl.glDisable(GL.GL_LIGHT0 + i); + } + } + } + + // native method for setting scene ambient + void setSceneAmbient(Context ctx, float red, float green, float blue) { + if (VERBOSE) System.err.println("JoglPipeline.setSceneAmbient()"); + + GL gl = context(ctx).getGL(); + + float[] color = new float[4]; + color[0] = red; + color[1] = green; + color[2] = blue; + color[3] = 1.0f; + gl.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT, color, 0); + } + + // native method for disabling fog + void disableFog(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.disableFog()"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL.GL_FOG); + } + + // native method for disabling modelClip + void disableModelClip(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.disableModelClip()"); + + GL gl = context(ctx).getGL(); + + gl.glDisable(GL.GL_CLIP_PLANE0); + gl.glDisable(GL.GL_CLIP_PLANE1); + gl.glDisable(GL.GL_CLIP_PLANE2); + gl.glDisable(GL.GL_CLIP_PLANE3); + gl.glDisable(GL.GL_CLIP_PLANE4); + gl.glDisable(GL.GL_CLIP_PLANE5); + } + + // native method for setting default RenderingAttributes + void resetRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride) { + if (VERBOSE) System.err.println("JoglPipeline.resetRenderingAttributes()"); + + GL gl = context(ctx).getGL(); + + if (!depthBufferWriteEnableOverride) { + gl.glDepthMask(true); + } + if (!depthBufferEnableOverride) { + gl.glEnable(GL.GL_DEPTH_TEST); + } + gl.glAlphaFunc(GL.GL_ALWAYS, 0.0f); + gl.glDepthFunc(GL.GL_LEQUAL); + gl.glEnable(GL.GL_COLOR_MATERIAL); + gl.glDisable(GL.GL_COLOR_LOGIC_OP); + } + + // native method for setting default texture + void resetTextureNative(Context ctx, int texUnitIndex) { + if (VERBOSE) System.err.println("JoglPipeline.resetTextureNative()"); + + GL gl = context(ctx).getGL(); + if (texUnitIndex >= 0 && + gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glActiveTexture(texUnitIndex + GL.GL_TEXTURE0); + gl.glClientActiveTexture(texUnitIndex + GL.GL_TEXTURE0); + } + + gl.glDisable(GL.GL_TEXTURE_1D); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glDisable(GL.GL_TEXTURE_3D); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + } + + // native method for activating a particular texture unit + void activeTextureUnit(Context ctx, int texUnitIndex) { + if (VERBOSE) System.err.println("JoglPipeline.activeTextureUnit()"); + + GL gl = context(ctx).getGL(); + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glActiveTexture(texUnitIndex + GL.GL_TEXTURE0); + gl.glClientActiveTexture(texUnitIndex + GL.GL_TEXTURE0); + } + } + + // native method for setting default TexCoordGeneration + void resetTexCoordGeneration(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetTexCoordGeneration()"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL.GL_TEXTURE_GEN_S); + gl.glDisable(GL.GL_TEXTURE_GEN_T); + gl.glDisable(GL.GL_TEXTURE_GEN_R); + gl.glDisable(GL.GL_TEXTURE_GEN_Q); + } + + // native method for setting default TextureAttributes + void resetTextureAttributes(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetTextureAttributes()"); + + GL gl = context(ctx).getGL(); + + float[] color = new float[4]; + + gl.glPushAttrib(GL.GL_TRANSFORM_BIT); + gl.glMatrixMode(GL.GL_TEXTURE); + gl.glLoadIdentity(); + gl.glPopAttrib(); + gl.glTexEnvfv(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_COLOR, color, 0); + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); + gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); + + if (gl.isExtensionAvailable("GL_NV_register_combiners")) { + gl.glDisable(GL.GL_REGISTER_COMBINERS_NV); + } + + if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) { + gl.glDisable(GL.GL_TEXTURE_COLOR_TABLE_SGI); + } + } + + // native method for setting default PolygonAttributes + void resetPolygonAttributes(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetPolygonAttributes()"); + + GL gl = context(ctx).getGL(); + + gl.glCullFace(GL.GL_BACK); + gl.glEnable(GL.GL_CULL_FACE); + + gl.glLightModeli(GL.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_FALSE); + + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); + + gl.glPolygonOffset(0.0f, 0.0f); + gl.glDisable(GL.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL.GL_POLYGON_OFFSET_LINE); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + } + + // native method for setting default LineAttributes + void resetLineAttributes(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetLineAttributes()"); + + GL gl = context(ctx).getGL(); + gl.glLineWidth(1.0f); + gl.glDisable(GL.GL_LINE_STIPPLE); + + // XXXX: Polygon Mode check, blend enable + gl.glDisable(GL.GL_LINE_SMOOTH); + } + + // native method for setting default PointAttributes + void resetPointAttributes(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetPointAttributes()"); + + GL gl = context(ctx).getGL(); + gl.glPointSize(1.0f); + + // XXXX: Polygon Mode check, blend enable + gl.glDisable(GL.GL_POINT_SMOOTH); + } + + // native method for setting default TransparencyAttributes + void resetTransparency(Context ctx, int geometryType, + int polygonMode, boolean lineAA, + boolean pointAA) { + if (VERBOSE) System.err.println("JoglPipeline.resetTransparency()"); + + GL gl = context(ctx).getGL(); + + if (((((geometryType & RenderMolecule.LINE) != 0) || + (polygonMode == PolygonAttributes.POLYGON_LINE)) + && lineAA) || + ((((geometryType & RenderMolecule.POINT) != 0) || + (polygonMode == PolygonAttributes.POLYGON_POINT)) + && pointAA)) { + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); + } else { + gl.glDisable(GL.GL_BLEND); + } + gl.glDisable(GL.GL_POLYGON_STIPPLE); + } + + // native method for setting default ColoringAttributes + void resetColoringAttributes(Context ctx, + float r, float g, + float b, float a, + boolean enableLight) { + if (VERBOSE) System.err.println("JoglPipeline.resetColoringAttributes()"); + + GL gl = context(ctx).getGL(); + + if (!enableLight) { + gl.glColor4f(r, g, b, a); + } + gl.glShadeModel(GL.GL_SMOOTH); + } + + /** + * This native method makes sure that the rendering for this canvas + * gets done now. + */ + void syncRender(Context ctx, boolean wait) { + if (VERBOSE) System.err.println("JoglPipeline.syncRender()"); + + GL gl = context(ctx).getGL(); + + if (wait) + gl.glFinish(); + else + gl.glFlush(); + } + + // The native method that sets this ctx to be the current one + boolean useCtx(Context ctx, long display, Drawable drawable) { + if (VERBOSE) System.err.println("JoglPipeline.useCtx()"); + GLContext context = context(ctx); + int res = context.makeCurrent(); + return (res != GLContext.CONTEXT_NOT_CURRENT); + } + + // Optionally release the context. Returns true if the context was released. + boolean releaseCtx(Context ctx, long dpy) { + if (VERBOSE) System.err.println("JoglPipeline.releaseCtx()"); + GLContext context = context(ctx); + context.release(); + return true; + } + + void clear(Context ctx, float r, float g, float b, boolean clearStencil) { + if (VERBOSE) System.err.println("JoglPipeline.clear()"); + + JoglContext jctx = (JoglContext) ctx; + GLContext context = context(ctx); + GL gl = context.getGL(); + + // OBSOLETE CLEAR CODE + /* + gl.glClearColor(r, g, b, jctx.getAlphaClearValue()); + gl.glClear(GL.GL_COLOR_BUFFER_BIT); + + // Java 3D always clears the Z-buffer + gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT); + gl.glDepthMask(true); + gl.glClear(GL.GL_DEPTH_BUFFER_BIT); + gl.glPopAttrib(); + + // Issue 239 - clear stencil if specified + if (clearStencil) { + gl.glPushAttrib(GL.GL_STENCIL_BUFFER_BIT); + gl.glClearStencil(0); + gl.glStencilMask(~0); + gl.glClear(GL.GL_STENCIL_BUFFER_BIT); + gl.glPopAttrib(); + } + */ + + // Mask of which buffers to clear, this always includes color & depth + int clearMask = GL.GL_DEPTH_BUFFER_BIT | GL.GL_COLOR_BUFFER_BIT; + + // Issue 239 - clear stencil if specified + if (clearStencil) { + gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT); + + gl.glClearStencil(0); + gl.glStencilMask(~0); + clearMask |= GL.GL_STENCIL_BUFFER_BIT; + } else { + gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT); + } + + gl.glDepthMask(true); + gl.glClearColor(r, g, b, jctx.getAlphaClearValue()); + gl.glClear(clearMask); + gl.glPopAttrib(); + + } + + void textureFillBackground(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, boolean useBilinearFilter) { + if (VERBOSE) System.err.println("JoglPipeline.textureFillBackground()"); + + GLContext context = context(ctx); + GL gl = context.getGL(); + + // Temporarily disable fragment and most 3D operations + gl.glPushAttrib(GL.GL_ENABLE_BIT | GL.GL_TEXTURE_BIT | GL.GL_POLYGON_BIT); + + disableAttribFor2D(gl); + gl.glDepthMask(false); + gl.glEnable(GL.GL_TEXTURE_2D); + + /* Setup filter mode if needed */ + if(useBilinearFilter) { + // System.err.println("JoglPipeline - Background : use bilinear filter\n"); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + } + + // reset the polygon mode + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + + // load identity modelview and projection matrix + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + gl.glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + gl.glMatrixMode(GL.GL_TEXTURE); + gl.glPushMatrix(); + gl.glLoadIdentity(); + + gl.glBegin(GL.GL_QUADS); + gl.glTexCoord2f(texMinU, texMinV); gl.glVertex2f(mapMinX,mapMinY); + gl.glTexCoord2f(texMaxU, texMinV); gl.glVertex2f(mapMaxX,mapMinY); + gl.glTexCoord2f(texMaxU, texMaxV); gl.glVertex2f(mapMaxX,mapMaxY); + gl.glTexCoord2f(texMinU, texMaxV); gl.glVertex2f(mapMinX,mapMaxY); + gl.glEnd(); + + // Restore texture Matrix transform + gl.glPopMatrix(); + + gl.glMatrixMode(GL.GL_MODELVIEW); + // Restore attributes + gl.glPopAttrib(); + + } + + void textureFillRaster(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, float mapZ, float alpha, + boolean useBilinearFilter) { + + if (VERBOSE) System.err.println("JoglPipeline.textureFillRaster()"); + + GLContext context = context(ctx); + GL gl = context.getGL(); + + // Temporarily disable fragment and most 3D operations + gl.glPushAttrib(GL.GL_ENABLE_BIT | GL.GL_TEXTURE_BIT | GL.GL_POLYGON_BIT | + GL.GL_CURRENT_BIT ); + + disableAttribForRaster(gl); + + /* Setup filter mode if needed */ + if(useBilinearFilter) { + // System.err.println("JoglPipeline - Raster : use bilinear filter\n"); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + } + + gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); + gl.glColor4f(1.0f, 1.0f, 1.0f, alpha); + + // reset the polygon mode + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + + // load identity modelview and projection matrix + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glPushMatrix(); + gl.glLoadIdentity(); + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glPushMatrix(); + gl.glLoadIdentity(); + gl.glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0); + + gl.glBegin(GL.GL_QUADS); + gl.glTexCoord2f(texMinU, texMinV); gl.glVertex3f(mapMinX,mapMinY, mapZ); + gl.glTexCoord2f(texMaxU, texMinV); gl.glVertex3f(mapMaxX,mapMinY, mapZ); + gl.glTexCoord2f(texMaxU, texMaxV); gl.glVertex3f(mapMaxX,mapMaxY, mapZ); + gl.glTexCoord2f(texMinU, texMaxV); gl.glVertex3f(mapMinX,mapMaxY, mapZ); + gl.glEnd(); + + // Restore matrices + gl.glPopMatrix(); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glPopMatrix(); + // Restore attributes + gl.glPopAttrib(); + + } + + void executeRasterDepth(Context ctx, float posX, float posY, float posZ, + int srcOffsetX, int srcOffsetY, int rasterWidth, int rasterHeight, + int depthWidth, int depthHeight, int depthFormat, Object depthData) { + if (VERBOSE) System.err.println("JoglPipeline.executeRasterDepth()"); + GLContext context = context(ctx); + GL gl = context.getGL(); + + + gl.glRasterPos3f(posX, posY, posZ); + + int[] drawBuf = new int[1]; + gl.glGetIntegerv(GL.GL_DRAW_BUFFER, drawBuf, 0); + /* disable draw buffer */ + gl.glDrawBuffer(GL.GL_NONE); + + /* + * raster position is upper left corner, default for Java3D + * ImageComponent currently has the data reverse in Y + */ + gl.glPixelZoom(1.0f, -1.0f); + gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, depthWidth); + if (srcOffsetX >= 0) { + gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, srcOffsetX); + if (srcOffsetX + rasterWidth > depthWidth) { + rasterWidth = depthWidth - srcOffsetX; + } + } else { + rasterWidth += srcOffsetX; + if (rasterWidth > depthWidth) { + rasterWidth = depthWidth; + } + } + if (srcOffsetY >= 0) { + gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, srcOffsetY); + if (srcOffsetY + rasterHeight > rasterHeight) { + rasterHeight = rasterHeight - srcOffsetY; + } + } else { + rasterHeight += srcOffsetY; + if (rasterHeight > rasterHeight) { + rasterHeight = rasterHeight; + } + } + + + if (depthFormat == DepthComponentRetained.DEPTH_COMPONENT_TYPE_INT) { + gl.glDrawPixels(rasterWidth, rasterHeight, GL.GL_DEPTH_COMPONENT, + GL.GL_UNSIGNED_INT, IntBuffer.wrap((int[]) depthData)); + } else { /* DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT */ + gl.glDrawPixels(rasterWidth, rasterHeight, GL.GL_DEPTH_COMPONENT, + GL.GL_FLOAT, FloatBuffer.wrap((float[]) depthData)); + } + + /* re-enable draw buffer */ + gl.glDrawBuffer(drawBuf[0]); + + gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, 0); + gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, 0); + gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, 0); + + } + + // The native method for setting the ModelView matrix. + void setModelViewMatrix(Context ctx, double[] viewMatrix, double[] modelMatrix) { + if (VERBOSE) System.err.println("JoglPipeline.setModelViewMatrix()"); + GLContext context = context(ctx); + GL gl = context.getGL(); + + gl.glMatrixMode(GL.GL_MODELVIEW); + + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glLoadTransposeMatrixd(viewMatrix, 0); + gl.glMultTransposeMatrixd(modelMatrix, 0); + } else { + double[] v = new double[16]; + double[] m = new double[16]; + copyTranspose(viewMatrix, v); + copyTranspose(modelMatrix, m); + gl.glLoadMatrixd(v, 0); + gl.glMultMatrixd(m, 0); + } + } + + // The native method for setting the Projection matrix. + void setProjectionMatrix(Context ctx, double[] projMatrix) { + if (VERBOSE) System.err.println("JoglPipeline.setProjectionMatrix()"); + GLContext context = context(ctx); + GL gl = context.getGL(); + + gl.glMatrixMode(GL.GL_PROJECTION); + + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + // Invert the Z value in clipping coordinates because OpenGL uses + // left-handed clipping coordinates, while Java3D defines right-handed + // coordinates everywhere. + projMatrix[8] *= -1.0; + projMatrix[9] *= -1.0; + projMatrix[10] *= -1.0; + projMatrix[11] *= -1.0; + gl.glLoadTransposeMatrixd(projMatrix, 0); + projMatrix[8] *= -1.0; + projMatrix[9] *= -1.0; + projMatrix[10] *= -1.0; + projMatrix[11] *= -1.0; + } else { + double[] p = new double[16]; + copyTranspose(projMatrix, p); + // Invert the Z value in clipping coordinates because OpenGL uses + // left-handed clipping coordinates, while Java3D defines right-handed + // coordinates everywhere. + p[2] *= -1.0; + p[6] *= -1.0; + p[10] *= -1.0; + p[14] *= -1.0; + gl.glLoadMatrixd(p, 0); + } + } + + // The native method for setting the Viewport. + void setViewport(Context ctx, int x, int y, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.setViewport()"); + GL gl = context(ctx).getGL(); + gl.glViewport(x, y, width, height); + } + + // used for display Lists + void newDisplayList(Context ctx, int displayListId) { + if (VERBOSE) System.err.println("JoglPipeline.newDisplayList()"); + if (displayListId <= 0) { + System.err.println("JAVA 3D ERROR : glNewList(" + displayListId + ") -- IGNORED"); + } + + GL gl = context(ctx).getGL(); + gl.glNewList(displayListId, GL.GL_COMPILE); + } + + void endDisplayList(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.endDisplayList()"); + GL gl = context(ctx).getGL(); + gl.glEndList(); + } + + int numInvalidLists = 0; + void callDisplayList(Context ctx, int id, boolean isNonUniformScale) { + if (VERBOSE) System.err.println("JoglPipeline.callDisplayList()"); + if (id <= 0) { + if (numInvalidLists < 3) { + ++numInvalidLists; + System.err.println("JAVA 3D ERROR : glCallList(" + id + ") -- IGNORED"); + } else if (numInvalidLists == 3) { + ++numInvalidLists; + System.err.println("JAVA 3D : further glCallList error messages discarded"); + } + return; + } + + GL gl = context(ctx).getGL(); + // Set normalization if non-uniform scale + if (isNonUniformScale) { + gl.glEnable(GL.GL_NORMALIZE); + } + + gl.glCallList(id); + + // Turn normalization back off + if (isNonUniformScale) { + gl.glDisable(GL.GL_NORMALIZE); + } + } + + void freeDisplayList(Context ctx, int id) { + if (VERBOSE) System.err.println("JoglPipeline.freeDisplayList()"); + if (id <= 0) { + System.err.println("JAVA 3D ERROR : glDeleteLists(" + id + ",1) -- IGNORED"); + } + + GL gl = context(ctx).getGL(); + gl.glDeleteLists(id, 1); + } + void freeTexture(Context ctx, int id) { + if (VERBOSE) System.err.println("JoglPipeline.freeTexture()"); + + GL gl = context(ctx).getGL(); + + if (id > 0) { + int[] tmp = new int[1]; + tmp[0] = id; + gl.glDeleteTextures(1, tmp, 0); + } else { + System.err.println("tried to delete tex with texid <= 0"); + } + } + + + void texturemapping(Context ctx, + int px, int py, + int minX, int minY, int maxX, int maxY, + int texWidth, int texHeight, + int rasWidth, + int format, int objectId, + byte[] imageYdown, + int winWidth, int winHeight) { + if (VERBOSE) System.err.println("JoglPipeline.texturemapping()"); + + GL gl = context(ctx).getGL(); + + int glType = GL.GL_RGBA; + + // Temporarily disable fragment and most 3D operations + gl.glPushAttrib(GL.GL_ENABLE_BIT | GL.GL_TEXTURE_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_POLYGON_BIT); + disableAttribFor2D(gl); + + // Reset the polygon mode + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); + + gl.glDepthMask(false); + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + gl.glBindTexture(GL.GL_TEXTURE_2D, objectId); + // set up texture parameter + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); + + gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); + + gl.glEnable(GL.GL_TEXTURE_2D); + + // loaded identity modelview and projection matrix + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + + gl.glOrtho(0.0, winWidth, 0.0, winHeight, 0.0, 0.0); + + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + + if (gl.isExtensionAvailable("GL_EXT_abgr")) { + glType = GL.GL_ABGR_EXT; + } else { + switch (format) { + case ImageComponentRetained.TYPE_BYTE_RGBA: + glType = GL.GL_RGBA; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + glType = GL.GL_RGB; + break; + } + } + gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, rasWidth); + gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, minX); + gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, minY); + gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, minX, minY, + maxX - minX, maxY - minY, + glType, GL.GL_UNSIGNED_BYTE, + ByteBuffer.wrap(imageYdown)); + gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, 0); + gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, 0); + gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, 0); + + float texMinU = (float) minX/ (float) texWidth; + float texMinV = (float) minY/ (float) texHeight; + float texMaxU = (float) maxX/ (float) texWidth; + float texMaxV = (float) maxY/ (float) texHeight; + float halfWidth = (float)winWidth/2.0f; + float halfHeight = (float)winHeight/2.0f; + + float mapMinX = (float) (((px + minX)- halfWidth)/halfWidth); + float mapMinY = (float) ((halfHeight - (py + maxY))/halfHeight); + float mapMaxX = (float) ((px + maxX - halfWidth)/halfWidth); + float mapMaxY = (float) ((halfHeight - (py + minY))/halfHeight); + + gl.glBegin(GL.GL_QUADS); + + gl.glTexCoord2f(texMinU, texMaxV); gl.glVertex2f(mapMinX,mapMinY); + gl.glTexCoord2f(texMaxU, texMaxV); gl.glVertex2f(mapMaxX,mapMinY); + gl.glTexCoord2f(texMaxU, texMinV); gl.glVertex2f(mapMaxX,mapMaxY); + gl.glTexCoord2f(texMinU, texMinV); gl.glVertex2f(mapMinX,mapMaxY); + gl.glEnd(); + + // Java 3D always clears the Z-buffer + gl.glDepthMask(true); + gl.glClear(GL.GL_DEPTH_BUFFER_BIT); + gl.glPopAttrib(); + } + + boolean initTexturemapping(Context ctx, int texWidth, + int texHeight, int objectId) { + if (VERBOSE) System.err.println("JoglPipeline.initTexturemapping()"); + + GL gl = context(ctx).getGL(); + + int glType = (gl.isExtensionAvailable("GL_EXT_abgr") ? GL.GL_ABGR_EXT : GL.GL_RGBA); + + gl.glBindTexture(GL.GL_TEXTURE_2D, objectId); + + gl.glTexImage2D(GL.GL_PROXY_TEXTURE_2D, 0, GL.GL_RGBA, texWidth, + texHeight, 0, glType, GL.GL_UNSIGNED_BYTE, null); + + int[] width = new int[1]; + gl.glGetTexLevelParameteriv(GL.GL_PROXY_TEXTURE_2D, 0, + GL.GL_TEXTURE_WIDTH, width, 0); + + if (width[0] <= 0) { + return false; + } + + // init texture size only without filling the pixels + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, texWidth, + texHeight, 0, glType, GL.GL_UNSIGNED_BYTE, null); + + return true; + } + + + // Set internal render mode to one of FIELD_ALL, FIELD_LEFT or + // FIELD_RIGHT. Note that it is up to the caller to ensure that + // stereo is available before setting the mode to FIELD_LEFT or + // FIELD_RIGHT. The boolean isTRUE for double buffered mode, FALSE + // foe single buffering. + void setRenderMode(Context ctx, int mode, boolean doubleBuffer) { + if (VERBOSE) System.err.println("JoglPipeline.setRenderMode()"); + + GL gl = context(ctx).getGL(); + int drawBuf = 0; + if (doubleBuffer) { + drawBuf = GL.GL_BACK; + switch (mode) { + case Canvas3D.FIELD_LEFT: + drawBuf = GL.GL_BACK_LEFT; + break; + case Canvas3D.FIELD_RIGHT: + drawBuf = GL.GL_BACK_RIGHT; + break; + case Canvas3D.FIELD_ALL: + drawBuf = GL.GL_BACK; + break; + } + } else { + drawBuf = GL.GL_FRONT; + switch (mode) { + case Canvas3D.FIELD_LEFT: + drawBuf = GL.GL_FRONT_LEFT; + break; + case Canvas3D.FIELD_RIGHT: + drawBuf = GL.GL_FRONT_RIGHT; + break; + case Canvas3D.FIELD_ALL: + drawBuf = GL.GL_FRONT; + break; + } + } + + gl.glDrawBuffer(drawBuf); + } + + // Set glDepthMask. + void setDepthBufferWriteEnable(Context ctx, boolean mode) { + if (VERBOSE) System.err.println("JoglPipeline.setDepthBufferWriteEnable()"); + + GL gl = context(ctx).getGL(); + if (mode) { + gl.glDepthMask(true); + } else { + gl.glDepthMask(false); + } + } + + //---------------------------------------------------------------------- + // Helper private functions for Canvas3D + // + + private boolean getPropertiesFromCurrentContext(JoglContext ctx) { + GL gl = GLU.getCurrentGL(); + // FIXME: this is a heavily abridged set of the stuff in Canvas3D.c; + // probably need to pull much more in + int[] tmp = new int[1]; + gl.glGetIntegerv(GL.GL_MAX_TEXTURE_UNITS, tmp, 0); + ctx.setMaxTexCoordSets(tmp[0]); + if (VirtualUniverse.mc.transparentOffScreen) { + ctx.setAlphaClearValue(0.0f); + } else { + ctx.setAlphaClearValue(1.0f); + } + if (gl.isExtensionAvailable("GL_ARB_vertex_shader")) { + gl.glGetIntegerv(GL.GL_MAX_TEXTURE_COORDS_ARB, tmp, 0); + ctx.setMaxTexCoordSets(tmp[0]); + } + return true; + } + + private int[] extractVersionInfo(String versionString) { + StringTokenizer tok = new StringTokenizer(versionString, ". "); + int major = Integer.valueOf(tok.nextToken()).intValue(); + int minor = Integer.valueOf(tok.nextToken()).intValue(); + + // See if there's vendor-specific information which might + // imply a more recent OpenGL version + tok = new StringTokenizer(versionString, " "); + if (tok.hasMoreTokens()) { + tok.nextToken(); + if (tok.hasMoreTokens()) { + Pattern p = Pattern.compile("\\D*(\\d+)\\.(\\d+)\\.?(\\d*).*"); + Matcher m = p.matcher(tok.nextToken()); + if (m.matches()) { + int altMajor = Integer.valueOf(m.group(1)).intValue(); + int altMinor = Integer.valueOf(m.group(2)).intValue(); + // Avoid possibly confusing situations by requiring + // major version to match + if (altMajor == major && + altMinor > minor) { + minor = altMinor; + } + } + } + } + return new int[] { major, minor }; + } + + private int getTextureColorTableSize(GL gl) { + if (!gl.isExtensionAvailable("GL_ARB_imaging")) { + return 0; + } + + gl.glColorTable(GL.GL_PROXY_TEXTURE_COLOR_TABLE_SGI, GL.GL_RGBA, 256, GL.GL_RGB, + GL.GL_INT, null); + int[] tmp = new int[1]; + gl.glGetColorTableParameteriv(GL.GL_PROXY_TEXTURE_COLOR_TABLE_SGI, + GL.GL_COLOR_TABLE_WIDTH, tmp, 0); + return tmp[0]; + } + + + private void checkTextureExtensions(Canvas3D cv, + JoglContext ctx, + GL gl, + boolean gl13) { + if (gl13) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_MULTI_TEXTURE; + cv.multiTexAccelerated = true; + int[] tmp = new int[1]; + gl.glGetIntegerv(GL.GL_MAX_TEXTURE_UNITS, tmp, 0); + cv.maxTextureUnits = tmp[0]; + cv.maxTexCoordSets = cv.maxTextureUnits; + if (gl.isExtensionAvailable("GL_ARB_vertex_shader")) { + gl.glGetIntegerv(GL.GL_MAX_TEXTURE_COORDS_ARB, tmp, 0); + cv.maxTexCoordSets = tmp[0]; + } + } + + if (gl.isExtensionAvailable("GL_SGI_texture_color_table") || + gl.isExtensionAvailable("GL_ARB_imaging")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COLOR_TABLE; + + // get texture color table size + // need to check later + cv.textureColorTableSize = getTextureColorTableSize(gl); + if (cv.textureColorTableSize <= 0) { + cv.textureExtendedFeatures &= ~Canvas3D.TEXTURE_COLOR_TABLE; + } + if (cv.textureColorTableSize > 256) { + cv.textureColorTableSize = 256; + } + } + + if (gl.isExtensionAvailable("GL_ARB_texture_env_combine")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COMBINE; + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COMBINE_SUBTRACT; + } else if (gl.isExtensionAvailable("GL_EXT_texture_env_combine")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COMBINE; + } + + if (gl.isExtensionAvailable("GL_NV_register_combiners")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_REGISTER_COMBINERS; + } + + if (gl.isExtensionAvailable("GL_ARB_texture_env_dot3") || + gl.isExtensionAvailable("GL_EXT_texture_env_dot3")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COMBINE_DOT3; + } + + if (gl13) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_CUBE_MAP; + } + + if (gl.isExtensionAvailable("GL_SGIS_sharpen_texture")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_SHARPEN; + } + + if (gl.isExtensionAvailable("GL_SGIS_detail_texture")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_DETAIL; + } + + if (gl.isExtensionAvailable("GL_SGIS_texture_filter4")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_FILTER4; + } + + if (gl.isExtensionAvailable("GL_EXT_texture_filter_anisotropic")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_ANISOTROPIC_FILTER; + float[] tmp = new float[1]; + gl.glGetFloatv(GL. GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, tmp, 0); + cv.anisotropicDegreeMax = tmp[0]; + } + + if (gl.isExtensionAvailable("GL_SGIX_texture_lod_bias")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_LOD_OFFSET; + } + + if (!VirtualUniverse.mc.enforcePowerOfTwo && + gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_NON_POWER_OF_TWO; + } + + if (gl.isExtensionAvailable("GL_SGIS_generate_mipmap")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_AUTO_MIPMAP_GENERATION; + } + + } + + + private void checkGLSLShaderExtensions(Canvas3D cv, + JoglContext ctx, + GL gl, + boolean glslLibraryAvailable) { + if (glslLibraryAvailable && + gl.isExtensionAvailable("GL_ARB_shader_objects") && + gl.isExtensionAvailable("GL_ARB_shading_language_100")) { + // Initialize shader vertex attribute function pointers + ctx.initGLSLVertexAttributeImpl(); + + // FIXME: this isn't complete and would need to set up the + // JoglContext for dispatch of various routines such as those + // related to vertex attributes + int[] tmp = new int[1]; + gl.glGetIntegerv(GL. GL_MAX_TEXTURE_IMAGE_UNITS_ARB, tmp, 0); + cv.maxTextureImageUnits = tmp[0]; + gl.glGetIntegerv(GL. GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, tmp, 0); + cv.maxVertexTextureImageUnits = tmp[0]; + gl.glGetIntegerv(GL. GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, tmp, 0); + cv.maxCombinedTextureImageUnits = tmp[0]; + int vertexAttrOffset = VirtualUniverse.mc.glslVertexAttrOffset; + ctx.setGLSLVertexAttrOffset(vertexAttrOffset); + gl.glGetIntegerv(GL. GL_MAX_VERTEX_ATTRIBS_ARB, tmp, 0); + cv.maxVertexAttrs = tmp[0]; + // decr count to allow for reserved vertex attrs + cv.maxVertexAttrs -= vertexAttrOffset; + if (cv.maxVertexAttrs < 0) { + cv.maxVertexAttrs = 0; + } + cv.shadingLanguageGLSL = true; + } + } + + private boolean createCgContext(JoglContext ctx) { + CGcontext cgContext = CgGL.cgCreateContext(); + + int err = CgGL.cgGetError(); + if (err != 0) { + String detail = CgGL.cgGetErrorString(err); + System.err.println("JAVA 3D ERROR : Fatal error in creating Cg context: \"" + + detail + "\""); + return false; + } + + if (cgContext == null) { + System.err.println("JAVA 3D ERROR : Invalid null Cg context"); + return false; + } + + ctx.setCgContext(cgContext); + + // Use GL_ARB_vertex_program extension if supported by video card + if (CgGL.cgGLIsProfileSupported(CgGL.CG_PROFILE_ARBVP1)) { + ctx.setCgVertexProfile(CgGL.CG_PROFILE_ARBVP1); + } else if (CgGL.cgGLIsProfileSupported(CgGL.CG_PROFILE_VP20)) { + ctx.setCgVertexProfile(CgGL.CG_PROFILE_VP20); + } else { + System.err.println("JAVA 3D ERROR : No CG vertex program profile is supported"); + ctx.setCgContext(null); + return false; + } + + // Use GL_ARB_fragment_program extension if supported by video card + if (CgGL.cgGLIsProfileSupported(CgGL.CG_PROFILE_ARBFP1)) { + ctx.setCgFragmentProfile(CgGL.CG_PROFILE_ARBFP1); + } else if (CgGL.cgGLIsProfileSupported(CgGL.CG_PROFILE_FP20)) { + ctx.setCgFragmentProfile(CgGL.CG_PROFILE_FP20); + } else { + System.err.println("JAVA 3D ERROR : No CG fragment program profile is supported"); + ctx.setCgContext(null); + return false; + } + + return true; + } + + private void checkCgShaderExtensions(Canvas3D cv, + JoglContext ctx, + GL gl, + boolean cgLibraryAvailable) { + if (cgLibraryAvailable) { + if (!createCgContext(ctx)) { + return; + } + cv.shadingLanguageCg = true; + // TODO: Query Cg texture sampler limits + cv.maxTextureImageUnits = cv.maxTextureUnits; + cv.maxVertexTextureImageUnits = 0; + cv.maxCombinedTextureImageUnits = cv.maxTextureUnits; + // TODO: Query max vertex attrs + cv.maxVertexAttrs = 7; + // Initialize shader vertex attribute function pointers + ctx.initCgVertexAttributeImpl(); + } + } + + private void setupCanvasProperties(Canvas3D cv, + JoglContext ctx, + GL gl, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + // Note: this includes relevant portions from both the + // NativePipeline's getPropertiesFromCurrentContext and setupCanvasProperties + + // Reset all fields + cv.multiTexAccelerated = false; + cv.maxTextureUnits = 1; + cv.maxTexCoordSets = 1; + cv.maxTextureImageUnits = 0; + cv.maxVertexTextureImageUnits = 0; + cv.maxCombinedTextureImageUnits = 0; + cv.maxVertexAttrs = 0; + cv.extensionsSupported = 0; + cv.textureExtendedFeatures = 0; + cv.textureColorTableSize = 0; + cv.anisotropicDegreeMax = 0; + cv.textureBoundaryWidthMax = 0; + cv.textureWidthMax = 0; + cv.textureHeightMax = 0; + cv.texture3DWidthMax = 0; + cv.texture3DHeightMax = 0; + cv.texture3DDepthMax = 0; + cv.shadingLanguageGLSL = false; + cv.shadingLanguageCg = false; + + // Now make queries and set up these fields + String glVersion = gl.glGetString(GL.GL_VERSION); + String glVendor = gl.glGetString(GL.GL_VENDOR); + String glRenderer = gl.glGetString(GL.GL_RENDERER); + cv.nativeGraphicsVersion = glVersion; + cv.nativeGraphicsVendor = glVendor; + cv.nativeGraphicsRenderer = glRenderer; + + // find out the version, major and minor version number + int[] versionNumbers = extractVersionInfo(glVersion); + int major = versionNumbers[0]; + int minor = versionNumbers[1]; + + /////////////////////////////////////////// + // setup the graphics context properties // + + // NOTE: Java 3D now requires OpenGL 1.3 for full functionality. + // For backwards compatibility with certain older graphics cards and + // drivers (e.g., the Linux DRI driver for older ATI cards), + // we will try to run on OpenGL 1.2 in an unsupported manner. However, + // we will not attempt to use OpenGL extensions for any features that + // are available in OpenGL 1.3, specifically multitexture, multisample, + // and cube map textures. + + if (major < 1 || (major == 1 && minor < 2)) { + throw new IllegalRenderingStateException( + "Java 3D ERROR : OpenGL 1.2 or better is required (GL_VERSION=" + + major + "." + minor + ")"); + } + + boolean gl20 = false; + boolean gl14 = false; + boolean gl13 = false; + + if (major == 1) { + if (minor == 2) { + System.err.println("JAVA 3D: OpenGL 1.2 detected; will run with reduced functionality"); + } + if (minor >= 3) { + gl13 = true; + } + if (minor >= 4) { + gl14 = true; + } + } else /* major >= 2 */ { + gl13 = true; + gl14 = true; + gl20 = true; + } + + if (gl20) { + assert gl13; + assert gl14; + assert gl.isExtensionAvailable("GL_VERSION_2_0"); + } + + if (gl14) { + assert gl13; + assert gl.isExtensionAvailable("GL_VERSION_1_4"); + } + + if (gl13) { + assert gl.isExtensionAvailable("GL_VERSION_1_3"); + } + + // Set up properties for OpenGL 1.3 + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_3D; + + // Note that we don't query for GL_ARB_imaging here + + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_LOD_RANGE; + + if (gl14) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_AUTO_MIPMAP_GENERATION; + } + + // look for OpenGL 2.0 features + // Fix to Issue 455 : Need to disable NPOT textures for older cards that claim to support it. + // Some older cards (e.g., Nvidia fx500 and ATI 9800) claim to support OpenGL 2.0. + // This means that these cards have to support non-power-of-two (NPOT) texture, + // but their lack the necessary HW force the vendors the emulate this feature in software. + // The result is a ~100x slower down compare to power-of-two textures. + // Do not check for gl20 but instead check of GL_ARB_texture_non_power_of_two extension string + // if (gl20) { + // if(!VirtualUniverse.mc.enforcePowerOfTwo) { + // cv.textureExtendedFeatures |= Canvas3D.TEXTURE_NON_POWER_OF_TWO; + // } + // } + + + // Setup GL_EXT_abgr + if (gl.isExtensionAvailable("GL_EXT_abgr")) { + cv.extensionsSupported |= Canvas3D.EXT_ABGR; + } + + // GL_BGR is always supported + cv.extensionsSupported |= Canvas3D.EXT_BGR; + + // Setup multisample + // FIXME: this is not correct for the Windows platform yet + if (gl13) { + cv.extensionsSupported |= Canvas3D.MULTISAMPLE; + ctx.setHasMultisample(true); + } + + if ((cv.extensionsSupported & Canvas3D.MULTISAMPLE) != 0 && + !VirtualUniverse.mc.implicitAntialiasing) { + gl.glDisable(GL.GL_MULTISAMPLE); + } + + // Check texture extensions + checkTextureExtensions(cv, ctx, gl, gl13); + + // Check shader extensions + if (gl13) { + checkGLSLShaderExtensions(cv, ctx, gl, glslLibraryAvailable); + checkCgShaderExtensions(cv, ctx, gl, cgLibraryAvailable); + } else { + // Force shaders to be disabled, since no multitexture support + checkGLSLShaderExtensions(cv, ctx, gl, false); + checkCgShaderExtensions(cv, ctx, gl, false); + } + + // Setup GL_SUN_gloabl_alpha + if (gl.isExtensionAvailable("GL_SUN_gloabl_alpha")) { + cv.extensionsSupported |= Canvas3D.SUN_GLOBAL_ALPHA; + } + + cv.textureBoundaryWidthMax = 1; + { + int[] tmp = new int[1]; + gl.glGetIntegerv(GL.GL_MAX_TEXTURE_SIZE, tmp, 0); + cv.textureWidthMax = tmp[0]; + cv.textureHeightMax = tmp[0]; + + tmp[0] = -1; + gl.glGetIntegerv(GL.GL_MAX_3D_TEXTURE_SIZE, tmp, 0); + cv.texture3DWidthMax = tmp[0]; + cv.texture3DHeightMax = tmp[0]; + cv.texture3DDepthMax = tmp[0]; + } + } + + /* + * Function to disable most rendering attributes when doing a 2D + * clear, image copy, or image composite operation. Note that the + * caller must save/restore the attributes with + * pushAttrib(GL_ENABLE_BIT|...) and popAttrib() + */ + private void disableAttribFor2D(GL gl) { + gl.glDisable(GL.GL_ALPHA_TEST); + gl.glDisable(GL.GL_BLEND); + gl.glDisable(GL.GL_COLOR_LOGIC_OP); + gl.glDisable(GL.GL_COLOR_MATERIAL); + gl.glDisable(GL.GL_CULL_FACE); + gl.glDisable(GL.GL_DEPTH_TEST); + gl.glDisable(GL.GL_FOG); + gl.glDisable(GL.GL_LIGHTING); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + gl.glDisable(GL.GL_POLYGON_STIPPLE); + gl.glDisable(GL.GL_STENCIL_TEST); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glDisable(GL.GL_TEXTURE_GEN_Q); + gl.glDisable(GL.GL_TEXTURE_GEN_R); + gl.glDisable(GL.GL_TEXTURE_GEN_S); + gl.glDisable(GL.GL_TEXTURE_GEN_T); + + + for (int i = 0; i < 6; i++) { + gl.glDisable(GL.GL_CLIP_PLANE0 + i); + } + + gl.glDisable(GL.GL_TEXTURE_3D); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + + if (gl.isExtensionAvailable("GL_NV_register_combiners")) { + gl.glDisable(GL.GL_REGISTER_COMBINERS_NV); + } + + if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) { + gl.glDisable(GL.GL_TEXTURE_COLOR_TABLE_SGI); + } + + if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { + gl.glDisable(GL.GL_GLOBAL_ALPHA_SUN); + } + + } + + private void disableAttribForRaster(GL gl) { + + gl.glDisable(GL.GL_COLOR_MATERIAL); + gl.glDisable(GL.GL_CULL_FACE); + gl.glDisable(GL.GL_LIGHTING); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + gl.glDisable(GL.GL_POLYGON_STIPPLE); + + // TODO: Disable if Raster.CLIP_POSITION is true +// for (int i = 0; i < 6; i++) { +// gl.glDisable(GL.GL_CLIP_PLANE0 + i); +// } + + if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { + gl.glDisable(GL.GL_GLOBAL_ALPHA_SUN); + } + } + + private void copyTranspose(double[] src, double[] dst) { + dst[0] = src[0]; + dst[1] = src[4]; + dst[2] = src[8]; + dst[3] = src[12]; + dst[4] = src[1]; + dst[5] = src[5]; + dst[6] = src[9]; + dst[7] = src[13]; + dst[8] = src[2]; + dst[9] = src[6]; + dst[10] = src[10]; + dst[11] = src[14]; + dst[12] = src[3]; + dst[13] = src[7]; + dst[14] = src[11]; + dst[15] = src[15]; + } + + // --------------------------------------------------------------------- + + // + // Canvas3D / GraphicsConfigTemplate3D methods - logic dealing with + // native graphics configuration or drawing surface + // + + // Return a graphics config based on the one passed in. Note that we can + // assert that the input config is non-null and was created from a + // GraphicsConfigTemplate3D. + // This method must return a valid GraphicsConfig, or else it must throw + // an exception if one cannot be returned. + GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) { + if (VERBOSE) System.err.println("JoglPipeline.getGraphicsConfig()"); + JoglGraphicsConfiguration config = (JoglGraphicsConfiguration) gconfig; + GLCapabilitiesChooser indexChooser = null; + if (config.getChosenIndex() >= 0) { + indexChooser = new IndexCapabilitiesChooser(config.getChosenIndex()); + } + + AbstractGraphicsConfiguration absConfig = + GLDrawableFactory.getFactory().chooseGraphicsConfiguration(config.getGLCapabilities(), + indexChooser, + new AWTGraphicsDevice(config.getDevice())); + if (absConfig == null) { + return null; + } + return ((AWTGraphicsConfiguration) absConfig).getGraphicsConfiguration(); + + /* + + System.err.println("JoglPipeline.getGraphicsConfig()"); + // Just return the input graphics config for now. eventually, we will + // use the input graphics config to get the GraphicsConfigTemplate3D + // parameters, which we will use to create a new graphics config with JOGL. + return gconfig; + */ + } + + // Get the native FBconfig pointer + long getFbConfig(GraphicsConfigInfo gcInfo) { + if (VERBOSE) System.err.println("JoglPipeline.getFbConfig()"); + return 0L; // Dummy method in JOGL + } + + + private static final int DISABLE_STEREO = 1; + private static final int DISABLE_AA = 2; + private static final int DISABLE_DOUBLE_BUFFER = 3; + + // Get best graphics config from pipeline + GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate3D gct, + GraphicsConfiguration[] gc) { + if (VERBOSE) System.err.println("JoglPipeline.getBestConfiguration()"); + /* + System.err.println("gct.getDoubleBuffer(): " + gct.getDoubleBuffer()); + System.err.println("gct.getStereo(): " + gct.getStereo()); + System.err.println("gct.getDepthBits(): " + gct.getDepthSize()); + System.err.println("gct.getRedSize(): " + gct.getRedSize()); + System.err.println("gct.getGreenSize(): " + gct.getGreenSize()); + System.err.println("gct.getBlueSize(): " + gct.getBlueSize()); + System.err.println("gct.getSceneAntialiasing(): " + gct.getSceneAntialiasing()); + */ + + // Create a GLCapabilities based on the GraphicsConfigTemplate3D + GLCapabilities caps = new GLCapabilities(); + caps.setDoubleBuffered(gct.getDoubleBuffer() <= GraphicsConfigTemplate.PREFERRED); + caps.setStereo (gct.getStereo() <= GraphicsConfigTemplate.PREFERRED); + caps.setDepthBits (gct.getDepthSize()); + caps.setStencilBits (gct.getStencilSize()); + caps.setRedBits (Math.max(5, gct.getRedSize())); + caps.setGreenBits (Math.max(5, gct.getGreenSize())); + caps.setBlueBits (Math.max(5, gct.getBlueSize())); + caps.setSampleBuffers(gct.getSceneAntialiasing() <= GraphicsConfigTemplate.PREFERRED); + // FIXME: should be smarter about choosing the number of samples + // (Java3D's native code has a loop trying 8, 6, 4, 3, and 2 samples) + caps.setNumSamples(4); + + // Issue 399: Request alpha buffer if transparentOffScreen is set + if (VirtualUniverse.mc.transparentOffScreen) { + caps.setAlphaBits(1); + } + + java.util.List capsToDisable = new ArrayList(); + // Add PREFERRED capabilities in order we will try disabling them + if (gct.getStereo() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(new Integer(DISABLE_STEREO)); + } + if (gct.getSceneAntialiasing() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(new Integer(DISABLE_AA)); + } + if (gct.getDoubleBuffer() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(new Integer(DISABLE_DOUBLE_BUFFER)); + } + + // Pick the GraphicsDevice from a random configuration + GraphicsDevice dev = gc[0].getDevice(); + + // Create a Frame and dummy GLCanvas to perform eager pixel format selection + + // Note that we loop in similar fashion to the NativePipeline's + // native code in the situation where we need to disable certain + // capabilities which aren't required + boolean tryAgain = true; + CapabilitiesCapturer capturer = null; + while (tryAgain) { + Frame f = new Frame(dev.getDefaultConfiguration()); + f.setUndecorated(true); + f.setLayout(new BorderLayout()); + capturer = new CapabilitiesCapturer(); + try { + QueryCanvas canvas = new QueryCanvas(caps, capturer, dev); + f.add(canvas, BorderLayout.CENTER); + f.setSize(MIN_FRAME_SIZE, MIN_FRAME_SIZE); + f.setVisible(true); + canvas.doQuery(); + if (DEBUG_CONFIG) { + System.err.println("Waiting for CapabilitiesCapturer"); + } + // Try to wait for result without blocking EDT + if (!EventQueue.isDispatchThread()) { + synchronized(capturer) { + if (!capturer.done()) { + try { + capturer.wait(WAIT_TIME); + } catch (InterruptedException e) { + } + } + } + } + disposeOnEDT(f); + tryAgain = false; + } catch (GLException e) { + // Failure to select a pixel format; try switching off one + // of the only-preferred capabilities + if (capsToDisable.size() == 0) { + tryAgain = false; + } else { + int whichToDisable = capsToDisable.remove(0).intValue(); + switch (whichToDisable) { + case DISABLE_STEREO: + caps.setStereo(false); + break; + + case DISABLE_AA: + caps.setSampleBuffers(false); + break; + + case DISABLE_DOUBLE_BUFFER: + caps.setDoubleBuffered(false); + break; + + default: + throw new AssertionError("missing case statement"); + } + } + } + } + int chosenIndex = capturer.getChosenIndex(); + GLCapabilities chosenCaps = null; + if (chosenIndex < 0) { + if (DEBUG_CONFIG) { + System.err.println("CapabilitiesCapturer returned invalid index"); + } + // It's possible some platforms or implementations might not + // support the GLCapabilitiesChooser mechanism; feed in the + // same GLCapabilities later which we gave to the selector + chosenCaps = caps; + } else { + if (DEBUG_CONFIG) { + System.err.println("CapabilitiesCapturer returned index=" + chosenIndex); + } + chosenCaps = capturer.getCapabilities(); + } + + JoglGraphicsConfiguration config = new JoglGraphicsConfiguration(chosenCaps, chosenIndex, dev); + + // FIXME: because of the fact that JoglGraphicsConfiguration + // doesn't override hashCode() or equals(), we will basically be + // creating a new one each time getBestConfiguration() is + // called; in theory, we should probably map the same + // GLCapabilities on the same GraphicsDevice to the same + // JoglGraphicsConfiguration object + + // Cache the GraphicsTemplate3D + synchronized (Canvas3D.graphicsConfigTable) { + GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(gct); + // We don't need this + // gcInfo.setPrivateData(privateData); + Canvas3D.graphicsConfigTable.put(config, gcInfo); + } + + return config; + + /* + + // TODO: implement this + + // TODO: construct a unique GraphicsConfiguration object that will be + // used the key in the hashmap so we can lookup the GraphicsTemplate3D + GraphicsConfiguration gc1 = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + + // Cache the GraphicsTemplate3D + synchronized (Canvas3D.graphicsConfigTable) { + if (Canvas3D.graphicsConfigTable.get(gc1) == null) { + GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(gct); + // gcInfo.setPrivateData(privateData); + Canvas3D.graphicsConfigTable.put(gc1, gcInfo); + } + } + return gc1; + + */ + } + + // Determine whether specified graphics config is supported by pipeline + boolean isGraphicsConfigSupported(GraphicsConfigTemplate3D gct, + GraphicsConfiguration gc) { + if (VERBOSE) System.err.println("JoglPipeline.isGraphicsConfigSupported()"); + + // FIXME: it looks like this method is implemented incorrectly + // in the existing NativePipeline in both the Windows and X11 + // ports. According to the semantics of the javadoc, it looks + // like this method is supposed to figure out the OpenGL + // capabilities which would be requested by the passed + // GraphicsConfiguration object were it to be used, and see + // whether it is possible to create a context with them. + // Instead, on both platforms, the implementations basically set + // up a query based on the contents of the + // GraphicsConfigTemplate3D object, using the + // GraphicsConfiguration object only to figure out on which + // GraphicsDevice and screen we're making the request, and see + // whether it's possible to choose an OpenGL pixel format based + // on that information. This makes this method less useful and + // we can probably just safely return true here uniformly + // without breaking anything. + return true; + } + + // Methods to get actual capabilities from Canvas3D + boolean hasDoubleBuffer(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasDoubleBuffer()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getDoubleBuffered()); + return caps(cv).getDoubleBuffered(); + } + + boolean hasStereo(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasStereo()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getStereo()); + return caps(cv).getStereo(); + } + + int getStencilSize(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.getStencilSize()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getStencilBits()); + return caps(cv).getStencilBits(); + } + + boolean hasSceneAntialiasingMultisample(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasSceneAntialiasingMultisample()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getSampleBuffers()); + + return caps(cv).getSampleBuffers(); + } + + boolean hasSceneAntialiasingAccum(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasSceneAntialiasingAccum()"); + GLCapabilities caps = caps(cv); + if (VERBOSE) System.err.println(" Returning " + (caps.getAccumRedBits() > 0 && + caps.getAccumGreenBits() > 0 && + caps.getAccumBlueBits() > 0)); + return (caps.getAccumRedBits() > 0 && + caps.getAccumGreenBits() > 0 && + caps.getAccumBlueBits() > 0); + } + + // Methods to get native WS display and screen + long getDisplay() { + if (VERBOSE) System.err.println("JoglPipeline.getDisplay()"); + return 0L; // Dummy method in JOGL + } + + private boolean checkedForGetScreenMethod = false; + private Method getScreenMethod = null; + int getScreen(final GraphicsDevice graphicsDevice) { + if (VERBOSE) System.err.println("JoglPipeline.getScreen()"); + + if (!checkedForGetScreenMethod) { + // All of the Sun GraphicsDevice implementations have a method + // int getScreen(); + // which we want to call reflectively if it's available. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + getScreenMethod = graphicsDevice.getClass().getDeclaredMethod("getScreen", new Class[] {}); + getScreenMethod.setAccessible(true); + } catch (Exception e) { + } + checkedForGetScreenMethod = true; + return null; + } + }); + } + + if (getScreenMethod != null) { + try { + return ((Integer) getScreenMethod.invoke(graphicsDevice, (Object[]) null)).intValue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return 0; + } + + //---------------------------------------------------------------------- + // Helper classes and methods to support query context functionality + // and pixel format selection + + interface ExtendedCapabilitiesChooser extends GLCapabilitiesChooser { + public void init(GLContext context); + } + + // Canvas subclass to help with various query operations such as the + // "query context" mechanism and pixel format selection. + // Must defeat and simplify the single-threading behavior of JOGL's + // GLCanvas in order to be able to set up a temporary pixel format + // and OpenGL context. Apparently simply turning off the + // single-threaded mode isn't enough to do this. + class QueryCanvas extends Canvas { + private GLDrawable drawable; + private ExtendedCapabilitiesChooser chooser; + private boolean alreadyRan; + + public QueryCanvas(GLCapabilities capabilities, + ExtendedCapabilitiesChooser chooser, + GraphicsDevice device) { + // The platform-specific GLDrawableFactory will only provide a + // non-null GraphicsConfiguration on platforms where this is + // necessary (currently only X11, as Windows allows the pixel + // format of the window to be set later and Mac OS X seems to + // handle this very differently than all other platforms). On + // other platforms this method returns null; it is the case (at + // least in the Sun AWT implementation) that this will result in + // equivalent behavior to calling the no-arg super() constructor + // for Canvas. + super(unwrap((AWTGraphicsConfiguration) + GLDrawableFactory.getFactory().chooseGraphicsConfiguration(capabilities, + chooser, + new AWTGraphicsDevice(device)))); + drawable = GLDrawableFactory.getFactory().getGLDrawable(this, capabilities, chooser); + this.chooser = chooser; + } + + public void addNotify() { + super.addNotify(); + drawable.setRealized(true); + } + + // It seems that at least on Mac OS X we need to do the OpenGL + // context-related work outside of the addNotify call because the + // Canvas hasn't been resized to a non-zero size by that point + public void doQuery() { + if (alreadyRan) + return; + GLContext context = drawable.createContext(null); + int res = context.makeCurrent(); + if (res != GLContext.CONTEXT_NOT_CURRENT) { + try { + chooser.init(context); + } finally { + context.release(); + } + } + context.destroy(); + alreadyRan = true; + } + } + + private static GraphicsConfiguration unwrap(AWTGraphicsConfiguration config) { + if (config == null) { + return null; + } + return config.getGraphicsConfiguration(); + } + + // Used in conjunction with IndexCapabilitiesChooser in pixel format + // selection -- see getBestConfiguration + class CapabilitiesCapturer extends DefaultGLCapabilitiesChooser implements ExtendedCapabilitiesChooser { + private boolean done; + private GLCapabilities capabilities; + private int chosenIndex = -1; + + public boolean done() { + return done; + } + + public GLCapabilities getCapabilities() { + return capabilities; + } + + public int getChosenIndex() { + return chosenIndex; + } + + public int chooseCapabilities(GLCapabilities desired, + GLCapabilities[] available, + int windowSystemRecommendedChoice) { + int res = super.chooseCapabilities(desired, available, windowSystemRecommendedChoice); + capabilities = available[res]; + chosenIndex = res; + markDone(); + return res; + } + + public void init(GLContext context) { + // Avoid hanging things up for several seconds + kick(); + } + + private void markDone() { + synchronized (this) { + done = true; + notifyAll(); + } + } + + private void kick() { + synchronized (this) { + notifyAll(); + } + } + } + + // Used to support the query context mechanism -- needs to be more + // than just a GLCapabilitiesChooser + class ContextQuerier extends DefaultGLCapabilitiesChooser implements ExtendedCapabilitiesChooser { + private Canvas3D canvas; + private boolean glslLibraryAvailable; + private boolean cgLibraryAvailable; + private boolean done; + + public ContextQuerier(Canvas3D canvas, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + this.canvas = canvas; + this.glslLibraryAvailable = glslLibraryAvailable; + this.cgLibraryAvailable = cgLibraryAvailable; + } + + public boolean done() { + return done; + } + + public void init(GLContext context) { + // This is basically a temporary + JoglContext jctx = new JoglContext(context); + // Set up various properties + if (getPropertiesFromCurrentContext(jctx)) { + setupCanvasProperties(canvas, jctx, context.getGL(), + glslLibraryAvailable, + cgLibraryAvailable); + } + markDone(); + } + + private void markDone() { + synchronized (this) { + done = true; + notifyAll(); + } + } + } + + // Used in two phases of pixel format selection: transforming the + // JoglGraphicsConfiguration to a real AWT GraphicsConfiguration and + // during context creation to select exactly the same graphics + // configuration as was done during getBestConfiguration. + class IndexCapabilitiesChooser implements GLCapabilitiesChooser { + private int indexToChoose; + + IndexCapabilitiesChooser(int indexToChoose) { + this.indexToChoose = indexToChoose; + } + + public int chooseCapabilities(GLCapabilities desired, + GLCapabilities[] available, + int windowSystemRecommendedChoice) { + if (DEBUG_CONFIG) { + System.err.println("IndexCapabilitiesChooser returning index=" + indexToChoose); + } + return indexToChoose; + } + } + + private void disposeOnEDT(final Frame f) { + Runnable r = new Runnable() { + public void run() { + f.setVisible(false); + f.dispose(); + } + }; + if (!EventQueue.isDispatchThread()) { + EventQueue.invokeLater(r); + } else { + r.run(); + } + } + + + // --------------------------------------------------------------------- + + // + // DrawingSurfaceObject methods + // + + // Method to construct a new DrawingSurfaceObject + DrawingSurfaceObject createDrawingSurfaceObject(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.createDrawingSurfaceObject()"); + return new JoglDrawingSurfaceObject(cv); + } + + // Method to free the drawing surface object + void freeDrawingSurface(Canvas3D cv, DrawingSurfaceObject drawingSurfaceObject) { + if (VERBOSE) System.err.println("JoglPipeline.freeDrawingSurface()"); + // This method is a no-op + } + + // Method to free the native drawing surface object + void freeDrawingSurfaceNative(Object o) { + if (VERBOSE) System.err.println("JoglPipeline.freeDrawingSurfaceNative()"); + // This method is a no-op + } + + //---------------------------------------------------------------------- + // Context-related routines + // + + // Helper used everywhere + GLContext context(Context ctx) { + if (ctx == null) + return null; + return ((JoglContext) ctx).getGLContext(); + } + + // Helper used everywhere + GLDrawable drawable(Drawable drawable) { + if (drawable == null) + return null; + return ((JoglDrawable) drawable).getGLDrawable(); + } + + GLCapabilities caps(Canvas3D ctx) { + return ((JoglGraphicsConfiguration) ctx.graphicsConfiguration).getGLCapabilities(); + } + + //---------------------------------------------------------------------- + // General helper routines + // + + private static ThreadLocal nioVertexTemp = new ThreadLocal(); + private static ThreadLocal nioVertexDoubleTemp = new ThreadLocal(); + private static ThreadLocal nioColorTemp = new ThreadLocal(); + private static ThreadLocal nioColorByteTemp = new ThreadLocal(); + private static ThreadLocal nioNormalTemp = new ThreadLocal(); + private static ThreadLocal nioTexCoordSetTemp = new ThreadLocal(); + private static ThreadLocal nioVertexAttrSetTemp = new ThreadLocal(); + + private static FloatBuffer getVertexArrayBuffer(float[] vertexArray) { + return getVertexArrayBuffer(vertexArray, true); + } + + private static FloatBuffer getVertexArrayBuffer(float[] vertexArray, boolean copyData) { + return getNIOBuffer(vertexArray, nioVertexTemp, copyData); + } + + private static DoubleBuffer getVertexArrayBuffer(double[] vertexArray) { + return getVertexArrayBuffer(vertexArray, true); + } + + private static DoubleBuffer getVertexArrayBuffer(double[] vertexArray, boolean copyData) { + return getNIOBuffer(vertexArray, nioVertexDoubleTemp, true); + } + + private static FloatBuffer getColorArrayBuffer(float[] colorArray) { + return getColorArrayBuffer(colorArray, true); + } + + private static FloatBuffer getColorArrayBuffer(float[] colorArray, boolean copyData) { + return getNIOBuffer(colorArray, nioColorTemp, true); + } + + private static ByteBuffer getColorArrayBuffer(byte[] colorArray) { + return getColorArrayBuffer(colorArray, true); + } + + private static ByteBuffer getColorArrayBuffer(byte[] colorArray, boolean copyData) { + return getNIOBuffer(colorArray, nioColorByteTemp, true); + } + + private static FloatBuffer getNormalArrayBuffer(float[] normalArray) { + return getNormalArrayBuffer(normalArray, true); + } + + private static FloatBuffer getNormalArrayBuffer(float[] normalArray, boolean copyData) { + return getNIOBuffer(normalArray, nioNormalTemp, true); + } + + private static FloatBuffer[] getTexCoordSetBuffer(Object[] texCoordSet) { + return getNIOBuffer(texCoordSet, nioTexCoordSetTemp); + } + + private static FloatBuffer[] getVertexAttrSetBuffer(Object[] vertexAttrSet) { + return getNIOBuffer(vertexAttrSet, nioVertexAttrSetTemp); + } + + private static FloatBuffer getNIOBuffer(float[] array, ThreadLocal threadLocal, boolean copyData) { + if (array == null) { + return null; + } + FloatBuffer buf = (FloatBuffer) threadLocal.get(); + if (buf == null) { + buf = BufferUtil.newFloatBuffer(array.length); + threadLocal.set(buf); + } else { + buf.rewind(); + if (buf.remaining() < array.length) { + int newSize = Math.max(2 * buf.remaining(), array.length); + buf = BufferUtil.newFloatBuffer(newSize); + threadLocal.set(buf); + } + } + if (copyData) { + buf.put(array); + buf.rewind(); + } + return buf; + } + + private static DoubleBuffer getNIOBuffer(double[] array, ThreadLocal threadLocal, boolean copyData) { + if (array == null) { + return null; + } + DoubleBuffer buf = (DoubleBuffer) threadLocal.get(); + if (buf == null) { + buf = BufferUtil.newDoubleBuffer(array.length); + threadLocal.set(buf); + } else { + buf.rewind(); + if (buf.remaining() < array.length) { + int newSize = Math.max(2 * buf.remaining(), array.length); + buf = BufferUtil.newDoubleBuffer(newSize); + threadLocal.set(buf); + } + } + if (copyData) { + buf.put(array); + buf.rewind(); + } + return buf; + } + + private static ByteBuffer getNIOBuffer(byte[] array, ThreadLocal threadLocal, boolean copyData) { + if (array == null) { + return null; + } + ByteBuffer buf = (ByteBuffer) threadLocal.get(); + if (buf == null) { + buf = BufferUtil.newByteBuffer(array.length); + threadLocal.set(buf); + } else { + buf.rewind(); + if (buf.remaining() < array.length) { + int newSize = Math.max(2 * buf.remaining(), array.length); + buf = BufferUtil.newByteBuffer(newSize); + threadLocal.set(buf); + } + } + if (copyData) { + buf.put(array); + buf.rewind(); + } + return buf; + } + + private static FloatBuffer[] getNIOBuffer(Object[] array, ThreadLocal threadLocal) { + if (array == null) { + return null; + } + FloatBuffer[] bufs = (FloatBuffer[]) threadLocal.get(); + + // First resize array of FloatBuffers + if (bufs == null) { + bufs = new FloatBuffer[array.length]; + threadLocal.set(bufs); + } else if (bufs.length < array.length) { + FloatBuffer[] newBufs = new FloatBuffer[array.length]; + System.arraycopy(bufs, 0, newBufs, 0, bufs.length); + bufs = newBufs; + threadLocal.set(bufs); + } + + // Now go down array of arrays, converting each into a direct FloatBuffer + for (int i = 0; i < array.length; i++) { + float[] cur = (float[]) array[i]; + FloatBuffer buf = bufs[i]; + if (buf == null) { + buf = BufferUtil.newFloatBuffer(cur.length); + bufs[i] = buf; + } else { + buf.rewind(); + if (buf.remaining() < cur.length) { + int newSize = Math.max(2 * buf.remaining(), cur.length); + buf = BufferUtil.newFloatBuffer(newSize); + bufs[i] = buf; + } + } + buf.put(cur); + buf.rewind(); + } + + return bufs; + } +} diff --git a/j3d-core/src/classes/jogl/javax/media/j3d/JoglShaderObject.java b/j3d-core/src/classes/jogl/javax/media/j3d/JoglShaderObject.java new file mode 100755 index 0000000..fe085a8 --- /dev/null +++ b/j3d-core/src/classes/jogl/javax/media/j3d/JoglShaderObject.java @@ -0,0 +1,44 @@ +/* + * $RCSfile: JoglShaderObject.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:18 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class JoglShaderObject implements ShaderProgramId, ShaderId, ShaderAttrLoc { + private int val; + + JoglShaderObject(int val) { + this.val = val; + } + + int getValue() { + return val; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Alpha.java b/j3d-core/src/classes/share/javax/media/j3d/Alpha.java new file mode 100644 index 0000000..ef5d1ad --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Alpha.java @@ -0,0 +1,1027 @@ +/* + * $RCSfile: Alpha.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * The alpha NodeComponent object provides common methods for + * converting a time value into an alpha value (a value in the range 0 + * to 1). The Alpha object is effectively a function of time that + * generates alpha values in the range [0,1] when sampled: f(t) = + * [0,1]. A primary use of the Alpha object is to provide alpha + * values for Interpolator behaviors. The function f(t) and the + * characteristics of the Alpha object are determined by + * user-definable parameters: + * + *

+ *

    + * + * loopCount -- This is the number of times to run this + * Alpha; a value of -1 specifies that the Alpha loops + * indefinitely.

    + * + * triggerTime -- This is the time in milliseconds since + * the start time that this object first triggers. If (startTime + + * triggerTime >= currentTime) then the Alpha object starts running.

    + * + * phaseDelayDuration -- This is an additional number of + * milliseconds to wait after triggerTime before actually starting + * this Alpha.

    + * + * mode -- This can be set to INCREASING_ENABLE, + * DECREASING_ENABLE, or the Or'ed value of the two. + * INCREASING_ENABLE activates the increasing Alpha parameters listed + * below; DECREASING_ENABLE activates the decreasing Alpha parameters + * listed below.

    + * + *

Increasing Alpha parameters:

    + * + * increasingAlphaDuration -- This is the period of time + * during which Alpha goes from zero to one.

    + * + * increasingAlphaRampDuration -- This is the period of + * time during which the Alpha step size increases at the beginning of + * the increasingAlphaDuration and, correspondingly, decreases at the + * end of the increasingAlphaDuration. This parameter is clamped to + * half of increasingAlphaDuration. When this parameter is non-zero, + * one gets constant acceleration while it is in effect; constant + * positive acceleration at the beginning of the ramp and constant + * negative acceleration at the end of the ramp. If this parameter is + * zero, then the effective velocity of the Alpha value is constant + * and the acceleration is zero (ie, a linearly increasing alpha + * ramp).

    + * + * alphaAtOneDuration -- This is the period of time that + * Alpha stays at one.

Decreasing Alpha parameters:

    + * + * decreasingAlphaDuration -- This is the period of time + * during which Alpha goes from one to zero.

    + * + * decreasingAlphaRampDuration -- This is the period of + * time during which the Alpha step size increases at the beginning of + * the decreasingAlphaDuration and, correspondingly, decreases at the + * end of the decreasingAlphaDuration. This parameter is clamped to + * half of decreasingAlphaDuration. When this parameter is non-zero, + * one gets constant acceleration while it is in effect; constant + * positive acceleration at the beginning of the ramp and constant + * negative acceleration at the end of the ramp. If this parameter is + * zero, the effective velocity of the Alpha value is constant and the + * acceleration is zero (i.e., a linearly-decreasing alpha ramp).

    + * + * alphaAtZeroDuration -- This is the period of time that + * Alpha stays at zero. + * + *

+ * + * @see Interpolator + */ + +public class Alpha extends NodeComponent { + + // loopCount < -1 --> reserved + // loopCount == -1 --> repeat forever + // loopCount >= 0 --> repeat count + private int loopCount; + + /** + * Specifies that the increasing component of the alpha is used. + */ + public static final int INCREASING_ENABLE = 1; + + /** + * Specifies that the decreasing component of the alpha is used + */ + public static final int DECREASING_ENABLE = 2; + + /** + * This alpha's mode, specifies whether to process + * increasing and decreasing alphas. + */ + private int mode; + + private float triggerTime; + private float phaseDelay; + private float increasingAlpha; + private long increasingAlphaRamp; + private float incAlphaRampInternal; + private float alphaAtOne; + private float decreasingAlpha; + private long decreasingAlphaRamp; + private float decAlphaRampInternal; + private float alphaAtZero; + + // For pausing and resuming Alpha + private long pauseTime = 0L; + private boolean paused = false; + + // Stop time gets used only for loopCount > 0 + private float stopTime; + + // Start time in milliseconds + private long startTime = MasterControl.systemStartTime; + + /** + * Constructs an Alpha object with default parameters. The default + * values are as follows: + *
    + * loopCount : -1
    + * mode : INCREASING_ENABLE
    + * startTime : system start time
    + * triggerTime : 0
    + * phaseDelayDuration : 0
    + * increasingAlphaDuration : 1000
    + * increasingAlphaRampDuration : 0
    + * alphaAtOneDuration : 0
    + * decreasingAlphaDuration : 0
    + * decreasingAlphaRampDuration : 0
    + * alphaAtZeroDuration : 0
    + * isPaused : false
    + * pauseTime : 0
    + *
+ */ + public Alpha() { + loopCount = -1; + mode = INCREASING_ENABLE; + increasingAlpha = 1.0f; // converted to seconds internally + /* + // Java initialize them to zero by default + triggerTime = 0L; + phaseDelay = 0.0f; + increasingAlphaRamp = 0.0f; + alphaAtOne = 0.0f; + decreasingAlpha = 0.0f; + decreasingAlphaRamp = 0.0f; + alphaAtZero = 0.0f; + */ + } + + + /** + * This constructor takes all of the Alpha user-definable parameters. + * @param loopCount number of times to run this alpha; a value + * of -1 specifies that the alpha loops indefinitely + * @param mode indicates whether the increasing alpha parameters or + * the decreasing alpha parameters or both are active. This parameter + * accepts the following values, INCREASING_ENABLE or + * DECREASING_ENABLE, which may be ORed together to specify + * that both are active. + * The increasing alpha parameters are increasingAlphaDuration, + * increasingAlphaRampDuration, and alphaAtOneDuration. + * The decreasing alpha parameters are decreasingAlphaDuration, + * decreasingAlphaRampDuration, and alphaAtZeroDuration. + * @param triggerTime time in milliseconds since the start time + * that this object first triggers + * @param phaseDelayDuration number of milliseconds to wait after + * triggerTime before actually starting this alpha + * @param increasingAlphaDuration period of time during which alpha goes + * from zero to one + * @param increasingAlphaRampDuration period of time during which + * the alpha step size increases at the beginning of the + * increasingAlphaDuration and, correspondingly, decreases at the end + * of the increasingAlphaDuration. This value is clamped to half of + * increasingAlphaDuration. NOTE: a value of zero means that the alpha + * step size remains constant during the entire increasingAlphaDuration. + * @param alphaAtOneDuration period of time that alpha stays at one + * @param decreasingAlphaDuration period of time during which alpha goes + * from one to zero + * @param decreasingAlphaRampDuration period of time during which + * the alpha step size increases at the beginning of the + * decreasingAlphaDuration and, correspondingly, decreases at the end + * of the decreasingAlphaDuration. This value is clamped to half of + * decreasingAlphaDuration. NOTE: a value of zero means that the alpha + * step size remains constant during the entire decreasingAlphaDuration. + * @param alphaAtZeroDuration period of time that alpha stays at zero + */ + public Alpha(int loopCount, int mode, + long triggerTime, long phaseDelayDuration, + long increasingAlphaDuration, + long increasingAlphaRampDuration, + long alphaAtOneDuration, + long decreasingAlphaDuration, + long decreasingAlphaRampDuration, + long alphaAtZeroDuration) { + + this.loopCount = loopCount; + this.mode = mode; + this.triggerTime = (float) triggerTime * .001f; + phaseDelay = (float) phaseDelayDuration * .001f; + + increasingAlpha = (float) increasingAlphaDuration * .001f; + alphaAtOne = (float)alphaAtOneDuration * .001f; + increasingAlphaRamp = increasingAlphaRampDuration; + incAlphaRampInternal = increasingAlphaRampDuration * .001f; + if (incAlphaRampInternal > (0.5f * increasingAlpha)) { + incAlphaRampInternal = 0.5f * increasingAlpha; + } + + decreasingAlpha = (float)decreasingAlphaDuration * .001f; + alphaAtZero = (float)alphaAtZeroDuration * .001f; + decreasingAlphaRamp = decreasingAlphaRampDuration; + decAlphaRampInternal = decreasingAlphaRampDuration * .001f; + if (decAlphaRampInternal > (0.5f * decreasingAlpha)) { + decAlphaRampInternal = 0.5f * decreasingAlpha; + } + computeStopTime(); + } + + + /** + * Constructs a new Alpha object that assumes that the mode is + * INCREASING_ENABLE. + * + * @param loopCount number of times to run this alpha; a value + * of -1 specifies that the alpha loops indefinitely. + * @param triggerTime time in milliseconds since the start time + * that this object first triggers + * @param phaseDelayDuration number of milliseconds to wait after + * triggerTime before actually starting this alpha + * @param increasingAlphaDuration period of time during which alpha goes + * from zero to one + * @param increasingAlphaRampDuration period of time during which + * the alpha step size increases at the beginning of the + * increasingAlphaDuration and, correspondingly, decreases at the end + * of the increasingAlphaDuration. This value is clamped to half of + * increasingAlphaDuration. NOTE: a value of zero means that the alpha + * step size remains constant during the entire increasingAlphaDuration. + * @param alphaAtOneDuration period of time that alpha stays at one + */ + + public Alpha(int loopCount, + long triggerTime, long phaseDelayDuration, + long increasingAlphaDuration, + long increasingAlphaRampDuration, + long alphaAtOneDuration) { + this(loopCount, INCREASING_ENABLE, + triggerTime, phaseDelayDuration, + increasingAlphaDuration, increasingAlphaRampDuration, + alphaAtOneDuration, 0, 0, 0); + } + + + /** + * This constructor takes only the loopCount and increasingAlphaDuration + * as parameters and assigns the default values to all of the other + * parameters. + * @param loopCount number of times to run this alpha; a value + * of -1 specifies that the alpha loops indefinitely + * @param increasingAlphaDuration period of time during which alpha goes + * from zero to one + */ + public Alpha(int loopCount, long increasingAlphaDuration) { + // defaults + mode = INCREASING_ENABLE; + increasingAlpha = (float) increasingAlphaDuration * .001f; + this.loopCount = loopCount; + + if (loopCount >= 0) { + stopTime = loopCount*increasingAlpha; + } + } + + + /** + * Pauses this alpha object. The current system time when this + * method is called will be used in place of the actual current + * time when calculating subsequent alpha values. This has the + * effect of freezing the interpolator at the time the method is + * called. + * + * @since Java 3D 1.3 + */ + public void pause() { + pause(J3dClock.currentTimeMillis()); + } + + /** + * Pauses this alpha object as of the specified time. The specified + * time will be used in place of the actual current time when + * calculating subsequent alpha values. This has the effect of freezing + * the interpolator at the specified time. Note that specifying a + * time in the future (that is, a time greater than + * System.currentTimeMillis()) will cause the alpha to immediately + * advance to that point before pausing. Similarly, specifying a + * time in the past (that is, a time less than + * System.currentTimeMillis()) will cause the alpha to immediately + * revert to that point before pausing. + * + * @param time the time at which to pause the alpha + * + * @exception IllegalArgumentException if time <= 0 + * + * @since Java 3D 1.3 + */ + public void pause(long time) { + if (time <= 0L) { + throw new IllegalArgumentException(J3dI18N.getString("Alpha0")); + } + + paused = true; + pauseTime = time; + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Resumes this alpha object. If the alpha + * object was paused, the difference between the current + * time and the pause time will be used to adjust the startTime of + * this alpha. The equation is as follows: + * + *
    + * startTime += System.currentTimeMillis() - pauseTime + *
+ * + * Since the alpha object is no longer paused, this has the effect + * of resuming the interpolator as of the current time. If the + * alpha object is not paused when this method is called, then this + * method does nothing--the start time is not adjusted in this case. + * + * @since Java 3D 1.3 + */ + public void resume() { + resume(J3dClock.currentTimeMillis()); + } + + /** + * Resumes this alpha object as of the specified time. If the alpha + * object was paused, the difference between the specified + * time and the pause time will be used to adjust the startTime of + * this alpha. The equation is as follows: + * + *
    startTime += time - pauseTime
+ * + * Since the alpha object is no longer paused, this has the effect + * of resuming the interpolator as of the specified time. If the + * alpha object is not paused when this method is called, then this + * method does nothing--the start time is not adjusted in this case. + * + * @param time the time at which to resume the alpha + * + * @exception IllegalArgumentException if time <= 0 + * + * @since Java 3D 1.3 + */ + public void resume(long time) { + if (time <= 0L) { + throw new IllegalArgumentException(J3dI18N.getString("Alpha0")); + } + + if (paused) { + long newStartTime = startTime + time - pauseTime; + paused = false; + pauseTime = 0L; + setStartTime(newStartTime); + } + } + + /** + * Returns true if this alpha object is paused. + * @return true if this alpha object is paused, false otherwise + * + * @since Java 3D 1.3 + */ + public boolean isPaused() { + return paused; + } + + /** + * Returns the time at which this alpha was paused. + * @return the pause time; returns 0 if this alpha is not paused + * + * @since Java 3D 1.3 + */ + public long getPauseTime() { + return pauseTime; + } + + + /** + * This method returns a value between 0.0 and 1.0 inclusive, + * based on the current time and the time-to-alpha parameters + * established for this alpha. If this alpha object is paused, + * the value will be based on the pause time rather than the + * current time. + * This method will return the starting alpha value if the alpha + * has not yet started (that is, if the current time is less + * than startTime + triggerTime + phaseDelayDuration). This + * method will return the ending alpha value if the alpha has + * finished (that is, if the loop count has expired). + * + * @return a value between 0.0 and 1.0 based on the current time + */ + public float value() { + long currentTime = paused ? pauseTime : J3dClock.currentTimeMillis(); + return this.value(currentTime); + } + + /** + * This method returns a value between 0.0 and 1.0 inclusive, + * based on the specified time and the time-to-alpha parameters + * established for this alpha. + * This method will return the starting alpha value if the alpha + * has not yet started (that is, if the specified time is less + * than startTime + triggerTime + phaseDelayDuration). This + * method will return the ending alpha value if the alpha has + * finished (that is, if the loop count has expired). + * + * @param atTime The time for which we wish to compute alpha + * @return a value between 0.0 and 1.0 based on the specified time + */ + public float value(long atTime) { + float interpolatorTime + = (float)(atTime - startTime) * .001f; // startTime is in millisec + float alpha, a1, a2, dt, alphaRampDuration; + + // System.err.println("alpha mode: " + mode); + + // If non-looping and before start + // if ((loopCount != -1) && + // interpolatorTime <= ( triggerTime + phaseDelay)) { + // + // if (( mode & INCREASING_ENABLE ) == 0 && + // ( mode & DECREASING_ENABLE) != 0) + // alpha = 1.0f; + // else + // alpha = 0.0f; + // return alpha; + // } + + + // Case of {constantly} moving forward, snap back, forward again + if (( mode & INCREASING_ENABLE ) != 0 && + ( mode & DECREASING_ENABLE) == 0) { + + if(interpolatorTime <= (triggerTime + phaseDelay)) + return 0.0f; + + if((loopCount != -1) && (interpolatorTime >= stopTime)) + return 1.0f; + + // Constant velocity case + if (incAlphaRampInternal == 0.0f) { + + alpha = mfmod((interpolatorTime - triggerTime - phaseDelay) + + 6.0f*( increasingAlpha + alphaAtOne), + (increasingAlpha + alphaAtOne))/ increasingAlpha; + + if ( alpha > 1.0f) alpha = 1.0f; + return alpha; + } + + // Ramped velocity case + alphaRampDuration = incAlphaRampInternal; + + dt = mfmod((interpolatorTime - triggerTime - phaseDelay) + + 6.0f*( increasingAlpha + alphaAtOne), + ( increasingAlpha + alphaAtOne)); + if (dt >= increasingAlpha) { alpha = 1.0f; return alpha; } + + // Original equation kept to help understand + // computation logic - simplification saves + // a multiply and an add + // a1 = 1.0f/(alphaRampDuration*alphaRampDuration + + // ( increasingAlpha - 2*alphaRampDuration)* + // alphaRampDuration); + + a1 = 1.0f/(increasingAlpha * alphaRampDuration - + alphaRampDuration * alphaRampDuration); + + if (dt < alphaRampDuration) { + alpha = 0.5f*a1*dt*dt; + } else if (dt < increasingAlpha - alphaRampDuration) { + alpha = 0.5f*a1*alphaRampDuration* + alphaRampDuration + + (dt - alphaRampDuration)*a1* + alphaRampDuration; + } else { + alpha = a1*alphaRampDuration*alphaRampDuration + + ( increasingAlpha - 2.0f*alphaRampDuration)*a1* + alphaRampDuration - + 0.5f*a1*( increasingAlpha - dt)* + ( increasingAlpha - dt); + } + return alpha; + + } else + + + // Case of {constantly} moving backward, snap forward, backward + // again + if (( mode & INCREASING_ENABLE ) == 0 && + ( mode & DECREASING_ENABLE) != 0) { + + // If non-looping and past end + // if ((loopCount != -1) + // && (interpolatorTime + // >= (triggerTime + phaseDelay + decreasingAlpha))) { + // alpha = 0.0f; + // return alpha; + // } + + if(interpolatorTime <= (triggerTime + phaseDelay)) + return 1.0f; + + if((loopCount != -1) && (interpolatorTime >= stopTime) ) + return 0.0f; + + + + // Constant velocity case + if (decAlphaRampInternal == 0.0f) { + alpha = mfmod((interpolatorTime - triggerTime - + phaseDelay) + + 6.0f*( decreasingAlpha + alphaAtZero), + (decreasingAlpha + alphaAtZero))/ decreasingAlpha; + if ( alpha > 1.0f) { alpha = 0.0f; return alpha; } + alpha = 1.0f - alpha; + return alpha; + } + + // Ramped velocity case + alphaRampDuration = decAlphaRampInternal; + + dt = mfmod((interpolatorTime - triggerTime - phaseDelay) + + 6.0f*( decreasingAlpha + alphaAtZero), + ( decreasingAlpha + alphaAtZero)); + if (dt >= decreasingAlpha) { alpha = 0.0f; return alpha; } + + // Original equation kept to help understand + // computation logic - simplification saves + // a multiply and an add + // a1 = 1.0f/(alphaRampDuration*alphaRampDuration + + // ( decreasingAlpha - 2*alphaRampDuration)* + // alphaRampDuration); + + a1 = 1.0f/(decreasingAlpha * alphaRampDuration - + alphaRampDuration * alphaRampDuration); + + if (dt < alphaRampDuration) { + alpha = 0.5f*a1*dt*dt; + } else if (dt < decreasingAlpha - alphaRampDuration) { + alpha = 0.5f*a1*alphaRampDuration* + alphaRampDuration + + (dt - alphaRampDuration)*a1* + alphaRampDuration; + } else { + alpha = a1*alphaRampDuration*alphaRampDuration + + ( decreasingAlpha - 2.0f*alphaRampDuration)*a1* + alphaRampDuration - + 0.5f*a1*( decreasingAlpha - dt)* + ( decreasingAlpha - dt); + } + alpha = 1.0f - alpha; + return alpha; + + } else + + + // Case of {osscilating} increasing and decreasing alpha + if (( mode & INCREASING_ENABLE) != 0 && + ( mode & DECREASING_ENABLE) != 0) { + + // If non-looping and past end + // if ((loopCount != -1) && + // (interpolatorTime >= + // (triggerTime + phaseDelay + increasingAlpha + + // alphaAtOne + decreasingAlpha))) { + // alpha = 0.0f; + // return alpha; + // } + + + // If non-looping and past end, we always end up at zero since + // decreasing alpha has been requested. + if(interpolatorTime <= (triggerTime + phaseDelay)) + return 0.0f; + + if( (loopCount != -1) && (interpolatorTime >= stopTime)) + return 0.0f; + + // Constant velocity case + if (incAlphaRampInternal == 0.0f + && decAlphaRampInternal == 0.0f) { + dt = mfmod(interpolatorTime - triggerTime - phaseDelay + + 6.0f*(increasingAlpha + alphaAtOne + + decreasingAlpha + alphaAtZero), + increasingAlpha + alphaAtOne + + decreasingAlpha + alphaAtZero); + alpha = dt / increasingAlpha; + if ( alpha < 1.0f) return alpha; + // sub all increasing alpha time + dt -= increasingAlpha; + if (dt < alphaAtOne) { alpha = 1.0f; return alpha; } + // sub out alpha @ 1 time + dt -= alphaAtOne; + alpha = dt/ decreasingAlpha; + if ( alpha < 1.0f) alpha = 1.0f - alpha; + else alpha = 0.0f; + return alpha; + } + + // Ramped velocity case + alphaRampDuration = incAlphaRampInternal; + + // work around for bug 4308308 + if (alphaRampDuration == 0.0f) + alphaRampDuration = .00001f; + + dt = mfmod(interpolatorTime - triggerTime - phaseDelay + + 6.0f*( increasingAlpha + alphaAtOne + + decreasingAlpha + alphaAtZero), + increasingAlpha + alphaAtOne + + decreasingAlpha + alphaAtZero); + if (dt <= increasingAlpha) { + + // Original equation kept to help understand + // computation logic - simplification saves + // a multiply and an add + // a1 = 1.0f/(alphaRampDuration*alphaRampDuration + + // ( increasingAlpha - 2*alphaRampDuration)* + // alphaRampDuration); + + a1 = 1.0f/(increasingAlpha * alphaRampDuration - + alphaRampDuration * alphaRampDuration); + + if (dt < alphaRampDuration) { + alpha = 0.5f*a1*dt*dt; + } else if (dt < increasingAlpha - alphaRampDuration) { + alpha = 0.5f*a1*alphaRampDuration* + alphaRampDuration + + (dt - alphaRampDuration)*a1* + alphaRampDuration; + } else { + alpha = a1*alphaRampDuration*alphaRampDuration+ + ( increasingAlpha - 2.0f*alphaRampDuration)*a1* + alphaRampDuration - + 0.5f*a1*( increasingAlpha - dt)* + ( increasingAlpha - dt); + } + return alpha; + } + else if (dt <= increasingAlpha + alphaAtOne) { + alpha = 1.0f; return alpha; + } + else if (dt >= increasingAlpha + alphaAtOne + decreasingAlpha) { + alpha = 0.0f; return alpha; + } + else { + dt -= increasingAlpha + alphaAtOne; + + alphaRampDuration = decAlphaRampInternal; + + // work around for bug 4308308 + if (alphaRampDuration == 0.0f) + alphaRampDuration = .00001f; + + // Original equation kept to help understand + // computation logic - simplification saves + // a multiply and an add + // a1 = 1.0f/(alphaRampDuration*alphaRampDuration + + // ( decreasingAlpha - 2*alphaRampDuration)* + // alphaRampDuration); + + a1 = 1.0f/(decreasingAlpha * alphaRampDuration - + alphaRampDuration * alphaRampDuration); + + if (dt < alphaRampDuration) { + alpha = 0.5f*a1*dt*dt; + } else if (dt < decreasingAlpha - alphaRampDuration) { + alpha = 0.5f*a1*alphaRampDuration* + alphaRampDuration + + (dt - alphaRampDuration)*a1* + alphaRampDuration; + } else { + alpha = + a1*alphaRampDuration*alphaRampDuration + + (decreasingAlpha - 2.0f*alphaRampDuration)*a1* + alphaRampDuration - + 0.5f*a1*( decreasingAlpha - dt)* + (decreasingAlpha - dt); + } + alpha = 1.0f - alpha; + return alpha; + } + + } + return 0.0f; + } + + float mfmod(float a, float b) { + float fm, ta = (a), tb = (b); + int fmint; + if (tb < 0.0f) tb = -tb; + if (ta < 0.0f) ta = -ta; + + fmint =(int)( ta/tb); + fm = ta - (float)fmint * tb; + + if ((a) < 0.0f) return ((b) - fm); + else return fm; + } + + /** + * Retrieves this alpha's startTime, the base + * for all relative time specifications; the default value + * for startTime is the system start time. + * @return this alpha's startTime. + */ + public long getStartTime() { + return this.startTime; + } + + /** + * Sets this alpha's startTime to that specified in the argument; + * startTime sets the base (or zero) for all relative time + * computations; the default value for startTime is the system + * start time. + * @param startTime the new startTime value + */ + public void setStartTime(long startTime) { + this.startTime = startTime; + // This is used for passive wakeupOnElapsedFrame in + // Interpolator to restart behavior after alpha.finished() + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's loopCount. + * @return this alpha's loopCount. + */ + public int getLoopCount() { + return this.loopCount; + } + + /** + * Set this alpha's loopCount to that specified in the argument. + * @param loopCount the new loopCount value + */ + public void setLoopCount(int loopCount) { + this.loopCount = loopCount; + computeStopTime(); + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's mode. + * @return this alpha's mode: any combination of + * INCREASING_ENABLE and DECREASING_ENABLE + */ + public int getMode() { + return this.mode; + } + + /** + * Set this alpha's mode to that specified in the argument. + * @param mode indicates whether the increasing alpha parameters or + * the decreasing alpha parameters or both are active. This parameter + * accepts the following values, INCREASING_ENABLE or + * DECREASING_ENABLE, which may be ORed together to specify + * that both are active. + * The increasing alpha parameters are increasingAlphaDuration, + * increasingAlphaRampDuration, and alphaAtOneDuration. + * The decreasing alpha parameters are decreasingAlphaDuration, + * decreasingAlphaRampDuration, and alphaAtZeroDuration. + */ + public void setMode(int mode) { + this.mode = mode; + computeStopTime(); + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's triggerTime. + * @return this alpha's triggerTime. + */ + public long getTriggerTime() { + return (long) (this.triggerTime * 1000f); + } + + /** + * Set this alpha's triggerTime to that specified in the argument. + * @param triggerTime the new triggerTime + */ + public void setTriggerTime(long triggerTime) { + this.triggerTime = (float) triggerTime * .001f; + computeStopTime(); + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's phaseDelayDuration. + * @return this alpha's phaseDelayDuration. + */ + public long getPhaseDelayDuration() { + return (long)(this.phaseDelay * 1000f); + } + + /** + * Set this alpha's phaseDelayDuration to that specified in + * the argument. + * @param phaseDelayDuration the new phaseDelayDuration + */ + public void setPhaseDelayDuration(long phaseDelayDuration) { + this.phaseDelay = (float) phaseDelayDuration * .001f; + computeStopTime(); + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's increasingAlphaDuration. + * @return this alpha's increasingAlphaDuration. + */ + public long getIncreasingAlphaDuration() { + return (long)(this.increasingAlpha * 1000f); + } + + /** + * Set this alpha's increasingAlphaDuration to that specified in + * the argument. + * @param increasingAlphaDuration the new increasingAlphaDuration + */ + public void setIncreasingAlphaDuration(long increasingAlphaDuration) { + this.increasingAlpha = (float) increasingAlphaDuration * .001f; + computeStopTime(); + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's increasingAlphaRampDuration. + * @return this alpha's increasingAlphaRampDuration. + */ + public long getIncreasingAlphaRampDuration() { + return increasingAlphaRamp; + } + + /** + * Set this alpha's increasingAlphaRampDuration to that specified + * in the argument. + * @param increasingAlphaRampDuration the new increasingAlphaRampDuration + */ + public void setIncreasingAlphaRampDuration(long increasingAlphaRampDuration) { + increasingAlphaRamp = increasingAlphaRampDuration; + incAlphaRampInternal = (float) increasingAlphaRampDuration * .001f; + if (incAlphaRampInternal > (0.5f * increasingAlpha)) { + incAlphaRampInternal = 0.5f * increasingAlpha; + } + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's alphaAtOneDuration. + * @return this alpha's alphaAtOneDuration. + */ + public long getAlphaAtOneDuration() { + return (long)(this.alphaAtOne * 1000f); + } + + /** + * Set this alpha object's alphaAtOneDuration to the specified + * value. + * @param alphaAtOneDuration the new alphaAtOneDuration + */ + public void setAlphaAtOneDuration(long alphaAtOneDuration) { + this.alphaAtOne = (float) alphaAtOneDuration * .001f; + computeStopTime(); + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's decreasingAlphaDuration. + * @return this alpha's decreasingAlphaDuration. + */ + public long getDecreasingAlphaDuration() { + return (long)(this.decreasingAlpha * 1000f); + } + + /** + * Set this alpha's decreasingAlphaDuration to that specified in + * the argument. + * @param decreasingAlphaDuration the new decreasingAlphaDuration + */ + public void setDecreasingAlphaDuration(long decreasingAlphaDuration) { + this.decreasingAlpha = (float) decreasingAlphaDuration * .001f; + computeStopTime(); + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's decreasingAlphaRampDuration. + * @return this alpha's decreasingAlphaRampDuration. + */ + public long getDecreasingAlphaRampDuration() { + return decreasingAlphaRamp; + } + + /** + * Set this alpha's decreasingAlphaRampDuration to that specified + * in the argument. + * @param decreasingAlphaRampDuration the new decreasingAlphaRampDuration + */ + public void setDecreasingAlphaRampDuration(long decreasingAlphaRampDuration) { + decreasingAlphaRamp = decreasingAlphaRampDuration; + decAlphaRampInternal = (float) decreasingAlphaRampDuration * .001f; + if (decAlphaRampInternal > (0.5f * decreasingAlpha)) { + decAlphaRampInternal = 0.5f * decreasingAlpha; + } + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Retrieves this alpha's alphaAtZeroDuration. + * @return this alpha's alphaAtZeroDuration. + */ + public long getAlphaAtZeroDuration() { + return (long)(this.alphaAtZero * 1000f); + } + + /** + * Set this alpha object's alphaAtZeroDuration to the specified + * value. + * @param alphaAtZeroDuration the new alphaAtZeroDuration + */ + public void setAlphaAtZeroDuration(long alphaAtZeroDuration) { + this.alphaAtZero = (float) alphaAtZeroDuration * .001f; + computeStopTime(); + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + /** + * Query to test if this alpha object is past its activity window, + * that is, if it has finished looping. + * @return true if no longer looping, false otherwise + */ + public boolean finished() { + long currentTime = paused ? pauseTime : J3dClock.currentTimeMillis(); + return ((loopCount != -1) && + ((float)(currentTime - startTime) * .001f > stopTime)); + } + + final private void computeStopTime() { + if (loopCount >= 0) { + float sum = 0; + if (( mode & INCREASING_ENABLE ) != 0) { + sum = increasingAlpha+alphaAtOne; + } + if ((mode & DECREASING_ENABLE) != 0) { + sum += decreasingAlpha+alphaAtZero; + } + stopTime = this.triggerTime + phaseDelay + loopCount*sum; + } else { + stopTime = 0; + } + } + + /** + * This internal method returns a clone of the Alpha + * + * @return a duplicate of this Alpha + */ + Alpha cloneAlpha() { + Alpha a = new Alpha(); + a.setStartTime(getStartTime()); + a.setLoopCount(getLoopCount()); + a.setMode(getMode()); + a.setTriggerTime(getTriggerTime()); + a.setPhaseDelayDuration(getPhaseDelayDuration()); + a.setIncreasingAlphaDuration(getIncreasingAlphaDuration()); + a.setIncreasingAlphaRampDuration(getIncreasingAlphaRampDuration()); + a.setAlphaAtOneDuration(getAlphaAtOneDuration()); + a.setDecreasingAlphaDuration(getDecreasingAlphaDuration()); + a.setDecreasingAlphaRampDuration(getDecreasingAlphaRampDuration()); + a.setAlphaAtZeroDuration(getAlphaAtZeroDuration()); + return a; + } + + static { + VirtualUniverse.loadLibraries(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AlternateAppearance.java b/j3d-core/src/classes/share/javax/media/j3d/AlternateAppearance.java new file mode 100644 index 0000000..16f82b4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AlternateAppearance.java @@ -0,0 +1,621 @@ +/* + * $RCSfile: AlternateAppearance.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Enumeration; + + +/** + * The AlternateAppearance leaf node is used for overriding the + * Appearance component of selected nodes. It defines an Appearance + * component object and a region of influence in which this + * AlternateAppearance node is active. An AlternateAppearance node + * also contains a list of Group nodes that specifies the hierarchical + * scope of this AlternateAppearance. If the scope list is empty, + * then the AlternateAppearance node has universe scope: all nodes + * within the region of influence are affected by this + * AlternateAppearance node. If the scope list is non-empty, then + * only those Leaf nodes under the Group nodes in the scope list are + * affected by this AlternateAppearance node (subject to the + * influencing bounds). + * + *

+ * An AlternateAppearance node affects Shape3D and Morph nodes by + * overriding their appearance component with the appearance + * component in this AlternateAppearance node. Only those Shape3D and + * Morph nodes that explicitly allow their appearance to be + * overridden are affected. The AlternateAppearance node has no + * effect on Shape3D and Morph nodes that do not allow their + * appearance to be overridden. + * + *

+ * If the regions of influence of multiple AlternateAppearance nodes + * overlap, the Java 3D system will choose a single alternate + * appearance for those objects that lie in the intersection. This is + * done in an implementation-dependent manner, but in general, the + * AlternateAppearance node that is "closest" to the object is chosen. + * + * @since Java 3D 1.2 + */ + +public class AlternateAppearance extends Leaf { + /** + * Specifies that this AlternateAppearance node allows read access to its + * influencing bounds and bounds leaf information. + */ + public static final int ALLOW_INFLUENCING_BOUNDS_READ = + CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_INFLUENCING_BOUNDS_READ; + + /** + * Specifies that this AlternateAppearance node allows write access to its + * influencing bounds and bounds leaf information. + */ + public static final int ALLOW_INFLUENCING_BOUNDS_WRITE = + CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_INFLUENCING_BOUNDS_WRITE; + + /** + * Specifies that this AlternateAppearance node allows read access to + * its appearance information. + */ + public static final int ALLOW_APPEARANCE_READ = + CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_APPEARANCE_READ; + + /** + * Specifies that this AlternateAppearance node allows write access to + * its appearance information. + * information. + */ + public static final int ALLOW_APPEARANCE_WRITE = + CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_APPEARANCE_WRITE; + + /** + * Specifies that this AlternateAppearance node allows read access + * to its scope information at runtime. + */ + public static final int ALLOW_SCOPE_READ = + CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_SCOPE_READ; + + /** + * Specifies that this AlternateAppearance node allows write access + * to its scope information at runtime. + */ + public static final int ALLOW_SCOPE_WRITE = + CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_SCOPE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_INFLUENCING_BOUNDS_READ, + ALLOW_APPEARANCE_READ, + ALLOW_SCOPE_READ + }; + + /** + * Constructs an AlternateAppearance node with default + * parameters. The default values are as follows: + * + *

    + * appearance : null
    + * scope : empty (universe scope)
    + * influencing bounds : null
    + * influencing bounding leaf : null
    + *
+ */ + public AlternateAppearance() { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + } + + /** + * Constructs an AlternateAppearance node with the specified appearance. + * @param appearance the appearance that is used for those nodes affected + * by this AlternateAppearance node. + */ + public AlternateAppearance(Appearance appearance) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + ((AlternateAppearanceRetained)retained).initAppearance(appearance); + } + + /** + * Creates the retained mode AlternateAppearanceRetained object that this + * Alternate Appearance component object will point to. + */ + void createRetained() { + this.retained = new AlternateAppearanceRetained(); + this.retained.setSource(this); + } + + /** + * Sets the appearance of this AlternateAppearance node. + * This appearance overrides the appearance in those Shape3D and + * Morph nodes affected by this AlternateAppearance node. + * @param appearance the new appearance. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAppearance(Appearance appearance) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPEARANCE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance0")); + + if (isLive()) + ((AlternateAppearanceRetained)this.retained).setAppearance(appearance); + else + ((AlternateAppearanceRetained)this.retained).initAppearance(appearance); + } + + + /** + * Retrieves the appearance from this AlternateAppearance node. + * @return the current appearance. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Appearance getAppearance() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPEARANCE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance2")); + + return ((AlternateAppearanceRetained)this.retained).getAppearance(); + + } + + /** + * Sets the AlternateAppearance's influencing region to the specified + * bounds. + * This is used when the influencing bounding leaf is set to null. + * @param region the bounds that contains the AlternateAppearance's + * new influencing region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInfluencingBounds(Bounds region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance3")); + + + if (isLive()) + ((AlternateAppearanceRetained)this.retained).setInfluencingBounds(region); + else + ((AlternateAppearanceRetained)this.retained).initInfluencingBounds(region); + } + + /** + * Retrieves the AlternateAppearance node's influencing bounds. + * @return this AlternateAppearance's influencing bounds information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getInfluencingBounds() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance4")); + + + return ((AlternateAppearanceRetained)this.retained).getInfluencingBounds(); + } + + + /** + * Sets the AlternateAppearance's influencing region to the specified + * bounding leaf. + * When set to a value other than null, this overrides the influencing + * bounds object. + * @param region the bounding leaf node used to specify the + * AlternateAppearance node's new influencing region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInfluencingBoundingLeaf(BoundingLeaf region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance3")); + + + if (isLive()) + ((AlternateAppearanceRetained)this.retained).setInfluencingBoundingLeaf(region); + else + ((AlternateAppearanceRetained)this.retained).initInfluencingBoundingLeaf(region); + } + + + /** + * Retrieves the AlternateAppearance node's influencing bounding leaf. + * @return this AlternateAppearance's influencing bounding leaf information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BoundingLeaf getInfluencingBoundingLeaf() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance4")); + + + return ((AlternateAppearanceRetained)this.retained).getInfluencingBoundingLeaf(); + } + + + /** + * Replaces the node at the specified index in this + * AlternateAppearance node's + * list of scopes with the specified Group node. + * By default, AlternateAppearance nodes are scoped only by their + * influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be stored at the specified index. + * @param index the index of the Group node to be replaced. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void setScope(Group scope, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance7")); + + + + if (isLive()) + ((AlternateAppearanceRetained)this.retained).setScope(scope, index); + else + ((AlternateAppearanceRetained)this.retained).initScope(scope, index); + } + + + /** + * Retrieves the Group node at the specified index from + * this AlternateAppearance node's list of scopes. + * @param index the index of the Group node to be returned. + * @return the Group node at the specified index. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Group getScope(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance8")); + + + return ((AlternateAppearanceRetained)this.retained).getScope(index); + } + + + /** + * Inserts the specified Group node into this AlternateAppearance node's + * list of scopes at the specified index. + * By default, AlternateAppearance nodes are scoped only by their + * influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be inserted at the specified index. + * @param index the index at which the Group node is inserted. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void insertScope(Group scope, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance9")); + + + if (isLive()) + ((AlternateAppearanceRetained)this.retained).insertScope(scope, index); + else + ((AlternateAppearanceRetained)this.retained).initInsertScope(scope, index); + } + + + /** + * Removes the node at the specified index from this AlternateAppearance + * node's + * list of scopes. If this operation causes the list of scopes to + * become empty, then this AlternateAppearance will have universe scope: + * all nodes + * within the region of influence will be affected by this + * AlternateAppearance node. + * @param index the index of the Group node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the group node at the + * specified index is part of a compiled scene graph + */ + public void removeScope(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance10")); + + + if (isLive()) + ((AlternateAppearanceRetained)this.retained).removeScope(index); + else + ((AlternateAppearanceRetained)this.retained).initRemoveScope(index); + } + + + /** + * Returns an enumeration of this AlternateAppearance node's list + * of scopes. + * @return an Enumeration object containing all nodes in this + * AlternateAppearance node's list of scopes. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Enumeration getAllScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance11")); + + + return (Enumeration) ((AlternateAppearanceRetained)this.retained).getAllScopes(); + } + + + /** + * Appends the specified Group node to this AlternateAppearance node's + * list of scopes. + * By default, AlternateAppearance nodes are scoped only by their + * influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be appended. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void addScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance12")); + + + if (isLive()) + ((AlternateAppearanceRetained)this.retained).addScope(scope); + else + ((AlternateAppearanceRetained)this.retained).initAddScope(scope); + } + + + /** + * Returns the number of nodes in this AlternateAppearance node's list + * of scopes. + * If this number is 0, then the list of scopes is empty and this + * AlternateAppearance node has universe scope: all nodes within the + * region of + * influence are affected by this AlternateAppearance node. + * @return the number of nodes in this AlternateAppearance node's list + * of scopes. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int numScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance11")); + + + return ((AlternateAppearanceRetained)this.retained).numScopes(); + } + + + /** + * Retrieves the index of the specified Group node in this + * AlternateAppearance node's list of scopes. + * + * @param scope the Group node to be looked up. + * @return the index of the specified Group node; + * returns -1 if the object is not in the list. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int indexOfScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance8")); + + return ((AlternateAppearanceRetained)this.retained).indexOfScope(scope); + } + + + /** + * Removes the specified Group node from this AlternateAppearance + * node's list of scopes. If the specified object is not in the + * list, the list is not modified. If this operation causes the + * list of scopes to become empty, then this AlternateAppearance + * will have universe scope: all nodes within the region of + * influence will be affected by this AlternateAppearance node. + * + * @param scope the Group node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance10")); + + if (isLive()) + ((AlternateAppearanceRetained)this.retained).removeScope(scope); + else + ((AlternateAppearanceRetained)this.retained).initRemoveScope(scope); + } + + + /** + * Removes all Group nodes from this AlternateAppearance node's + * list of scopes. The AlternateAppearance node will then have + * universe scope: all nodes within the region of influence will + * be affected by this AlternateAppearance node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if any group node in this + * node's list of scopes is part of a compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeAllScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AlternateAppearance10")); + if (isLive()) + ((AlternateAppearanceRetained)this.retained).removeAllScopes(); + else + ((AlternateAppearanceRetained)this.retained).initRemoveAllScopes(); + } + + + /** + * Copies all AlternateAppearance information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + AlternateAppearanceRetained attr = (AlternateAppearanceRetained) + originalNode.retained; + AlternateAppearanceRetained rt = (AlternateAppearanceRetained) retained; + + rt.initAppearance((Appearance) getNodeComponent( + attr.getAppearance(), + forceDuplicate, + originalNode.nodeHashtable)); + + rt.initInfluencingBounds(attr.getInfluencingBounds()); + + Enumeration elm = attr.getAllScopes(); + while (elm.hasMoreElements()) { + // this reference will set correctly in updateNodeReferences() callback + rt.initAddScope((Group) elm.nextElement()); + } + + // correct value will set in updateNodeReferences + rt.initInfluencingBoundingLeaf(attr.getInfluencingBoundingLeaf()); + + } + + /** + * Callback used to allow a node to check if any nodes referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any node references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding Node in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * node is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + + AlternateAppearanceRetained rt = (AlternateAppearanceRetained) + retained; + + BoundingLeaf bl = rt.getInfluencingBoundingLeaf(); + + if (bl != null) { + Object o = referenceTable.getNewObjectReference(bl); + rt.initInfluencingBoundingLeaf((BoundingLeaf) o); + } + + int num = rt.numScopes(); + for (int i=0; i < num; i++) { + rt.initScope((Group) referenceTable. + getNewObjectReference(rt.getScope(i)), i); + } + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + AlternateAppearance app = new AlternateAppearance(); + app.duplicateNode(this, forceDuplicate); + return app; + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/AlternateAppearanceRetained.java b/j3d-core/src/classes/share/javax/media/j3d/AlternateAppearanceRetained.java new file mode 100644 index 0000000..a5f2d92 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AlternateAppearanceRetained.java @@ -0,0 +1,881 @@ +/* + * $RCSfile: AlternateAppearanceRetained.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +import javax.vecmath.*; +import java.util.Enumeration; +import java.util.Vector; +import java.util.ArrayList; + + +class AlternateAppearanceRetained extends LeafRetained { + + + // Statics used when something in the alternate app changes + static final int APPEARANCE_CHANGED = 0x0001; + static final int SCOPE_CHANGED = 0x0002; + static final int BOUNDS_CHANGED = 0x0004; + static final int BOUNDINGLEAF_CHANGED = 0x0008; + static final int INIT_MIRROR = 0x0010; // setLive + static final int CLEAR_MIRROR = 0x0020; // clearLive + + + /** + * The Boundary object defining the lights's region of influence. + */ + Bounds regionOfInfluence = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * Vector of GroupRetained nodes that scopes this alternate app . + */ + Vector scopes = new Vector(); + + // This is true when this alternate app is referenced in an immediate mode context + boolean inImmCtx = false; + + // Target threads to be notified when light changes + static final int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_RENDER; + + // Boolean to indicate if this object is scoped (only used for mirror objects + boolean isScoped = false; + + // The object that contains the dynamic HashKey - a string type object + // Used in scoping + HashKey tempKey = new HashKey(250); + + /** + * The transformed value of the applicationRegion. + */ + Bounds region = null; + + /** + * mirror Alternate appearance + */ + AlternateAppearanceRetained mirrorAltApp = null; + + /** + * Appearance for this object + */ + AppearanceRetained appearance; + + /** + * A reference to the scene graph alternateApp + */ + AlternateAppearanceRetained sgAltApp = null; + + /** + * Is true, if the mirror altapp is viewScoped + */ + boolean isViewScoped = false; + + AlternateAppearanceRetained() { + this.nodeType = NodeRetained.ALTERNATEAPPEARANCE; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + /** + * Initializes the appearance + */ + void initAppearance(Appearance app) { + if (app != null) + appearance = (AppearanceRetained) app.retained; + else + appearance = null; + } + + + /** + * sets the appearance and send a message + */ + void setAppearance(Appearance app) { + if (appearance != null) + synchronized(appearance.liveStateLock) { + appearance.clearLive(refCount); + } + initAppearance(app); + if (appearance != null) { + synchronized(appearance.liveStateLock) { + appearance.setLive(inBackgroundGroup, refCount); + } + } + // There is no need to clone the appearance's mirror + sendMessage(APPEARANCE_CHANGED, + (appearance != null ? appearance.mirror: null)); + } + + + + Appearance getAppearance() { + return (appearance == null ? null: (Appearance) appearance.source); + } + + + /** + * Set the alternate's region of influence. + */ + void initInfluencingBounds(Bounds region) { + if (region != null) { + this.regionOfInfluence = (Bounds) region.clone(); + } else { + this.regionOfInfluence = null; + } + } + + /** + * Set the alternate's region of influence and send message + */ + void setInfluencingBounds(Bounds region) { + initInfluencingBounds(region); + sendMessage(BOUNDS_CHANGED, + (region != null ? region.clone() : null)); + } + + /** + * Get the alternate's region of Influence. + */ + Bounds getInfluencingBounds() { + return (regionOfInfluence != null ? + (Bounds) regionOfInfluence.clone() : null); + } + + /** + * Set the alternate's region of influence to the specified Leaf node. + */ + void initInfluencingBoundingLeaf(BoundingLeaf region) { + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + } else { + boundingLeaf = null; + } + } + + /** + * Set the alternate's region of influence to the specified Leaf node. + */ + void setInfluencingBoundingLeaf(BoundingLeaf region) { + if (boundingLeaf != null) + boundingLeaf.mirrorBoundingLeaf.removeUser(mirrorAltApp); + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + boundingLeaf.mirrorBoundingLeaf.addUser(mirrorAltApp); + } else { + boundingLeaf = null; + } + sendMessage(BOUNDINGLEAF_CHANGED, + (boundingLeaf != null ? + boundingLeaf.mirrorBoundingLeaf : null)); + } + + /** + * Get the alternate's region of influence. + */ + BoundingLeaf getInfluencingBoundingLeaf() { + return (boundingLeaf != null ? + (BoundingLeaf)boundingLeaf.source : null); + } + + + + /** + * Replaces the specified scope with the scope provided. + * @param scope the new scope + * @param index which scope to replace + */ + void initScope(Group scope, int index) { + scopes.setElementAt((GroupRetained)(scope.retained), index); + + } + + /** + * Replaces the specified scope with the scope provided. + * @param scope the new scope + * @param index which scope to replace + */ + void setScope(Group scope, int index) { + + ArrayList removeScopeList = new ArrayList(); + GroupRetained group; + ArrayList addScopeList = new ArrayList(); + Object[] scopeInfo = new Object[3]; + + group = (GroupRetained) scopes.get(index); + tempKey.reset(); + group.removeAllNodesForScopedAltApp(mirrorAltApp, removeScopeList, tempKey); + + group = (GroupRetained)scope.retained; + initScope(scope, index); + tempKey.reset(); + + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + group.addAllNodesForScopedAltApp(mirrorAltApp,addScopeList, tempKey); + scopeInfo[0] = addScopeList; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE:Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + Group getScope(int index) { + return (Group)(((GroupRetained)(scopes.elementAt(index))).source); + } + + + /** + * Inserts the specified scope at specified index.before the + * alt app is live + * @param scope the new scope + * @param index position to insert new scope at + */ + void initInsertScope(Node scope, int index) { + GroupRetained group = (GroupRetained)scope.retained; + scopes.insertElementAt((GroupRetained)(scope.retained), index); + group.setAltAppScope(); + } + + /** + * Inserts the specified scope at specified index and sends + * a message + * @param scope the new scope + * @param index position to insert new scope at + */ + void insertScope(Node scope, int index) { + Object[] scopeInfo = new Object[3]; + ArrayList addScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scope.retained; + + initInsertScope(scope, index); + group = (GroupRetained)scope.retained; + tempKey.reset(); + group.addAllNodesForScopedAltApp(mirrorAltApp,addScopeList, tempKey); + + scopeInfo[0] = addScopeList; + scopeInfo[1] = null; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + + + void initRemoveScope(int index) { + GroupRetained group = (GroupRetained)scopes.elementAt(index); + scopes.removeElementAt(index); + group.removeAltAppScope(); + + } + + void removeScope(int index) { + + Object[] scopeInfo = new Object[3]; + ArrayList removeScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scopes.elementAt(index); + + tempKey.reset(); + group.removeAllNodesForScopedAltApp(mirrorAltApp, removeScopeList, tempKey); + + initRemoveScope(index); + scopeInfo[0] = null; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + /** + * Removes the specified Group node from this node's list of scopes. + * Method is a no-op if the + * specified node is not found + * @param The Group node to be removed + */ + void removeScope(Group scope) { + int ind = indexOfScope(scope); + if(ind >= 0) + removeScope(ind); + } + + void initRemoveScope(Group scope) { + int ind = indexOfScope(scope); + if(ind >= 0) + initRemoveScope(ind); + } + + void removeAllScopes() { + GroupRetained group; + ArrayList removeScopeList = new ArrayList(); + int n = scopes.size(); + for(int index = n-1; index >= 0; index--) { + group = (GroupRetained)scopes.elementAt(index); + tempKey.reset(); + group.removeAllNodesForScopedAltApp(mirrorAltApp, removeScopeList, tempKey); + initRemoveScope(index); + } + Object[] scopeInfo = new Object[3]; + scopeInfo[0] = null; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + void initRemoveAllScopes() { + int n = scopes.size(); + for(int i = n-1; i >= 0; i--) + initRemoveScope(i); + } + + /** + * Returns an enumeration object of the scoperen. + * @return an enumeration object of the scoperen + */ + Enumeration getAllScopes() { + Enumeration elm = scopes.elements(); + Vector v = new Vector(scopes.size()); + while (elm.hasMoreElements()) { + v.add( ((GroupRetained) elm.nextElement()).source); + } + return v.elements(); + } + + /** + * Returns the index of the specified Group node in this node's list of scopes. + * @param scope the Group node whose index is needed + */ + int indexOfScope(Group scope) { + if(scope != null) + return scopes.indexOf((GroupRetained)scope.retained); + else + return scopes.indexOf(null); + } + + /** + * Appends the specified scope to this node's list of scopes before + * the alt app is alive + * @param scope the scope to add to this node's list of scopes + */ + void initAddScope(Group scope) { + GroupRetained group = (GroupRetained)scope.retained; + scopes.addElement((GroupRetained)(scope.retained)); + group.setAltAppScope(); + } + + /** + * Appends the specified scope to this node's list of scopes. + * @param scope the scope to add to this node's list of scopes + */ + void addScope(Group scope) { + + Object[] scopeInfo = new Object[3]; + ArrayList addScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scope.retained; + + initAddScope(scope); + tempKey.reset(); + group.addAllNodesForScopedAltApp(mirrorAltApp,addScopeList, tempKey); + scopeInfo[0] = addScopeList; + scopeInfo[1] = null; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + + + /** + * Returns a count of this nodes' scopes. + * @return the number of scopes descendant from this node + */ + int numScopes() { + return scopes.size(); + } + + + /** + * This sets the immedate mode context flag + */ + void setInImmCtx(boolean inCtx) { + inImmCtx = inCtx; + } + + /** + * This gets the immedate mode context flag + */ + boolean getInImmCtx() { + return (inImmCtx); + } + + boolean isScoped() { + return (scopes != null); + } + + + void updateImmediateMirrorObject(Object[] objs) { + GroupRetained group; + Vector currentScopes; + int i, nscopes; + Transform3D trans; + + int component = ((Integer)objs[1]).intValue(); + if ((component & APPEARANCE_CHANGED) != 0) { + mirrorAltApp.appearance = (AppearanceRetained)objs[2]; + } + if ((component & BOUNDS_CHANGED) != 0) { + mirrorAltApp.regionOfInfluence = (Bounds) objs[2]; + if (mirrorAltApp.boundingLeaf == null) { + if (objs[2] != null) { + mirrorAltApp.region = (Bounds)mirrorAltApp.regionOfInfluence.copy(mirrorAltApp.region); + mirrorAltApp.region.transform( + mirrorAltApp.regionOfInfluence, + getCurrentLocalToVworld()); + } + else { + mirrorAltApp.region = null; + } + } + } + else if ((component & BOUNDINGLEAF_CHANGED) != 0) { + mirrorAltApp.boundingLeaf = (BoundingLeafRetained)objs[2]; + if (objs[2] != null) { + mirrorAltApp.region = (Bounds)mirrorAltApp.boundingLeaf.transformedRegion; + } + else { + if (mirrorAltApp.regionOfInfluence != null) { + mirrorAltApp.region = mirrorAltApp.regionOfInfluence.copy(mirrorAltApp.region); + mirrorAltApp.region.transform( + mirrorAltApp.regionOfInfluence, + getCurrentLocalToVworld()); + } + else { + mirrorAltApp.region = null; + } + + } + } + else if ((component & SCOPE_CHANGED) != 0) { + Object[] scopeList = (Object[])objs[2]; + ArrayList addList = (ArrayList)scopeList[0]; + ArrayList removeList = (ArrayList)scopeList[1]; + boolean isScoped = ((Boolean)scopeList[2]).booleanValue(); + + if (addList != null) { + mirrorAltApp.isScoped = isScoped; + for (i = 0; i < addList.size(); i++) { + Shape3DRetained obj = ((GeometryAtom)addList.get(i)).source; + obj.addAltApp(mirrorAltApp); + } + } + + if (removeList != null) { + mirrorAltApp.isScoped = isScoped; + for (i = 0; i < removeList.size(); i++) { + Shape3DRetained obj = ((GeometryAtom)removeList.get(i)).source; + obj.removeAltApp(mirrorAltApp); + } + } + } + + + } + + + /** Note: This routine will only be called on + * the mirror object - will update the object's + * cached region and transformed region + */ + + void updateBoundingLeaf() { + if (boundingLeaf != null && boundingLeaf.switchState.currentSwitchOn) { + region = boundingLeaf.transformedRegion; + } else { + if (regionOfInfluence != null) { + region = regionOfInfluence.copy(region); + region.transform(regionOfInfluence, getCurrentLocalToVworld()); + } else { + region = null; + } + } + } + + void setLive(SetLiveState s) { + GroupRetained group; + Vector currentScopes; + int i, nscopes; + TransformGroupRetained[] tlist; + + if (inImmCtx) { + throw new IllegalSharingException(J3dI18N.getString("AlternateAppearanceRetained13")); + } + + if (inSharedGroup) { + throw new + IllegalSharingException(J3dI18N.getString("AlternateAppearanceRetained15")); + } + + if (inBackgroundGroup) { + throw new + IllegalSceneGraphException(J3dI18N.getString("AlternateAppearanceRetained16")); + } + + super.doSetLive(s); + + if (appearance != null) { + if (appearance.getInImmCtx()) { + throw new IllegalSharingException(J3dI18N.getString("AlternateAppearanceRetained14")); + } + synchronized(appearance.liveStateLock) { + appearance.setLive(inBackgroundGroup, s.refCount); + } + } + + // Create the mirror object + // Initialization of the mirror object during the INSERT_NODE + // message (in updateMirrorObject) + if (mirrorAltApp == null) { + mirrorAltApp = (AlternateAppearanceRetained)this.clone(); + // Assign the bounding leaf of this mirror object as null + // it will later be assigned to be the mirror of the alternate app + // bounding leaf object + mirrorAltApp.boundingLeaf = null; + mirrorAltApp.sgAltApp = this; + } + // If bounding leaf is not null, add the mirror object as a user + // so that any changes to the bounding leaf will be received + if (boundingLeaf != null) { + boundingLeaf.mirrorBoundingLeaf.addUser(mirrorAltApp); + } + + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(mirrorAltApp); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(mirrorAltApp); + } + + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(mirrorAltApp, + Targets.ENV_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + + // process switch leaf + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(mirrorAltApp, Targets.ENV_TARGETS); + } + mirrorAltApp.switchState = (SwitchState)s.switchStates.get(0); + + s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER; + + // At the end make it live + super.markAsLive(); + + // Initialize the mirror object, this needs to be done, when + // renderBin is not accessing any of the fields + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.universe = universe; + createMessage.type = J3dMessage.ALTERNATEAPPEARANCE_CHANGED; + createMessage.args[0] = this; + // a snapshot of all attributes that needs to be initialized + // in the mirror object + createMessage.args[1]= new Integer(INIT_MIRROR); + ArrayList addScopeList = new ArrayList(); + for (i = 0; i < scopes.size(); i++) { + group = (GroupRetained)scopes.get(i); + tempKey.reset(); + group.addAllNodesForScopedAltApp(mirrorAltApp, addScopeList, tempKey); + } + Object[] scopeInfo = new Object[2]; + scopeInfo[0] = ((scopes.size() > 0) ? Boolean.TRUE:Boolean.FALSE); + scopeInfo[1] = addScopeList; + createMessage.args[2] = scopeInfo; + if (appearance != null) { + createMessage.args[3] = appearance.mirror; + } + else { + createMessage.args[3] = null; + } + Object[] obj = new Object[2]; + obj[0] = boundingLeaf; + obj[1] = (regionOfInfluence != null?regionOfInfluence.clone():null); + createMessage.args[4] = obj; + VirtualUniverse.mc.processMessage(createMessage); + + + + + + } + + /** + * This is called on the parent object + */ + void initMirrorObject(Object[] args) { + Shape3DRetained shape; + Object[] scopeInfo = (Object[]) args[2]; + Boolean scoped = (Boolean)scopeInfo[0]; + ArrayList shapeList = (ArrayList)scopeInfo[1]; + AppearanceRetained app = (AppearanceRetained)args[3]; + BoundingLeafRetained bl=(BoundingLeafRetained)((Object[])args[4])[0]; + Bounds bnds = (Bounds)((Object[])args[4])[1]; + + for (int i = 0; i < shapeList.size(); i++) { + shape = ((GeometryAtom)shapeList.get(i)).source; + shape.addAltApp(mirrorAltApp); + } + mirrorAltApp.isScoped = scoped.booleanValue(); + + if (app != null) + mirrorAltApp.appearance = app; + + if (bl != null) { + mirrorAltApp.boundingLeaf = bl.mirrorBoundingLeaf; + mirrorAltApp.region = boundingLeaf.transformedRegion; + } else { + mirrorAltApp.boundingLeaf = null; + mirrorAltApp.region = null; + } + + if (bnds != null) { + mirrorAltApp.regionOfInfluence = bnds; + if (mirrorAltApp.region == null) { + mirrorAltApp.region = (Bounds)regionOfInfluence.clone(); + mirrorAltApp.region.transform(regionOfInfluence, getLastLocalToVworld()); + } + } + else { + mirrorAltApp.regionOfInfluence = null; + } + + } + + void clearMirrorObject(Object[] args) { + Shape3DRetained shape; + ArrayList shapeList = (ArrayList)args[2]; + ArrayList removeScopeList = new ArrayList(); + + for (int i = 0; i < shapeList.size(); i++) { + shape = ((GeometryAtom)shapeList.get(i)).source; + shape.removeAltApp(mirrorAltApp); + } + mirrorAltApp.isScoped = false; + + + + } + + + /** + * This clearLive routine first calls the superclass's method, then + * it removes itself to the list of alt app + */ + void clearLive(SetLiveState s) { + int i, j; + GroupRetained group; + + if (appearance != null) { + synchronized(appearance.liveStateLock) { + appearance.clearLive(s.refCount); + } + } + + super.clearLive(s); + s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER; + + // Remove this mirror light as users of the bounding leaf + if (mirrorAltApp.boundingLeaf != null) + mirrorAltApp.boundingLeaf.removeUser(mirrorAltApp); + + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(mirrorAltApp); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(mirrorAltApp); + } + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(mirrorAltApp, + Targets.ENV_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(mirrorAltApp, Targets.ENV_TARGETS); + } + + + if (scopes.size() > 0) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.universe = universe; + createMessage.type = J3dMessage.ALTERNATEAPPEARANCE_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(CLEAR_MIRROR); + ArrayList removeScopeList = new ArrayList(); + for (i = 0; i < scopes.size(); i++) { + group = (GroupRetained)scopes.get(i); + tempKey.reset(); + group.removeAllNodesForScopedAltApp(mirrorAltApp, removeScopeList, tempKey); + } + createMessage.args[2] = removeScopeList; + VirtualUniverse.mc.processMessage(createMessage); + } + } + + + + void updateTransformChange() { + } + + /** + * Called on mirror object + */ + void updateImmediateTransformChange() { + // If bounding leaf is null, tranform the bounds object + if (boundingLeaf == null) { + if (regionOfInfluence != null) { + region = regionOfInfluence.copy(region); + region.transform(regionOfInfluence, + sgAltApp.getCurrentLocalToVworld()); + } + + } + } + + final void sendMessage(int attrMask, Object attr) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.universe = universe; + createMessage.type = J3dMessage.ALTERNATEAPPEARANCE_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + VirtualUniverse.mc.processMessage(createMessage); + } + + + void getMirrorObjects(ArrayList leafList, HashKey key) { + leafList.add(mirrorAltApp); + } + + + /** + * Copies all AlternateAppearance information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + throw new RuntimeException("method not implemented"); + +// super.duplicateAttributes(originalNode, forceDuplicate); + +// AlternateAppearance alternate appearance = (AlternateAppearance) originalNode; + +// // XXXX: clone appearance + +// setInfluencingBounds(alternate appearance.getInfluencingBounds()); + +// Enumeration elm = alternate appearance.getAllScopes(); +// while (elm.hasMoreElements()) { +// // this reference will set correctly in updateNodeReferences() callback +// addScope((Group) elm.nextElement()); +// } + +// // this reference will set correctly in updateNodeReferences() callback +// setInfluencingBoundingLeaf(alternate appearance.getInfluencingBoundingLeaf()); + } + +// /** +// * Callback used to allow a node to check if any nodes referenced +// * by that node have been duplicated via a call to cloneTree. +// * This method is called by cloneTree after all nodes in +// * the sub-graph have been duplicated. The cloned Leaf node's method +// * will be called and the Leaf node can then look up any node references +// * by using the getNewObjectReference method found in the +// * NodeReferenceTable object. If a match is found, a +// * reference to the corresponding Node in the newly cloned sub-graph +// * is returned. If no corresponding reference is found, either a +// * DanglingReferenceException is thrown or a reference to the original +// * node is returned depending on the value of the +// * allowDanglingReferences parameter passed in the +// * cloneTree call. +// *

+// * NOTE: Applications should not call this method directly. +// * It should only be called by the cloneTree method. +// * +// * @param referenceTable a NodeReferenceTableObject that contains the +// * getNewObjectReference method needed to search for +// * new object instances. +// * @see NodeReferenceTable +// * @see Node#cloneTree +// * @see DanglingReferenceException +// */ +// public void updateNodeReferences(NodeReferenceTable referenceTable) { +// throw new RuntimeException("method not implemented"); +// +// Object o; +// +// BoundingLeaf bl = getInfluencingBoundingLeaf(); +// if (bl != null) { +// o = referenceTable.getNewObjectReference(bl); +// setInfluencingBoundingLeaf((BoundingLeaf) o); +// } +// +// for (int i=0; i < numScopes(); i++) { +// o = referenceTable.getNewObjectReference(getScope(i)); +// setScope((Group) o, i); +// } +// } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AmbientLight.java b/j3d-core/src/classes/share/javax/media/j3d/AmbientLight.java new file mode 100644 index 0000000..0c65b45 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AmbientLight.java @@ -0,0 +1,109 @@ +/* + * $RCSfile: AmbientLight.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; + +/** + * An ambient light source object. Ambient light is that light + * that seems to come from all directions. The AmbientLight object + * has the same attributes as a Light node, including color, + * influencing bounds, scopes, and + * a flag indicating whether this light source is on or off. + * Ambient reflections do not depend on the orientation or + * position of a surface. + * Ambient light has only an ambient reflection component. + * It does not have diffuse or specular reflection components. + *

+ * For more information on Java 3D lighting, see the class description + * for Light. + *

+ */ + +public class AmbientLight extends Light { + /** + * Constructs and initializes an ambient light using default parameters. + */ + public AmbientLight() { + } + + + /** + * Constructs and initializes an ambient light using the specified + * parameters. + * @param color the color of the light source. + */ + public AmbientLight(Color3f color) { + super(color); + } + + + /** + * Constructs and initializes an ambient light using the specified + * parameters. + * @param lightOn flag indicating whether this light is on or off. + * @param color the color of the light source. + */ + public AmbientLight(boolean lightOn, Color3f color) { + super(lightOn, color); + } + + /** + * Creates the retained mode AmbientLightRetained object that this + * AmbientLight component object will point to. + */ + void createRetained() { + this.retained = new AmbientLightRetained(); + this.retained.setSource(this); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + AmbientLight a = new AmbientLight(); + a.duplicateNode(this, forceDuplicate); + return a; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AmbientLightRetained.java b/j3d-core/src/classes/share/javax/media/j3d/AmbientLightRetained.java new file mode 100644 index 0000000..37b9b4e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AmbientLightRetained.java @@ -0,0 +1,58 @@ +/* + * $RCSfile: AmbientLightRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * An ambient light source object. + */ + +class AmbientLightRetained extends LightRetained { + + AmbientLightRetained() { + this.nodeType = NodeRetained.AMBIENTLIGHT; + lightType = 1; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + void setLive(SetLiveState s) { + super.setLive(s); + J3dMessage createMessage = super.initMessage(7); + VirtualUniverse.mc.processMessage(createMessage); + } + + void update(Context ctx, int lightSlot, double scale) { + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Appearance.java b/j3d-core/src/classes/share/javax/media/j3d/Appearance.java new file mode 100644 index 0000000..2e276a6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Appearance.java @@ -0,0 +1,1032 @@ +/* + * $RCSfile: Appearance.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Hashtable; + +/** + * The Appearance object defines all rendering state that can be set + * as a component object of a Shape3D node. The rendering state + * consists of the following:

+ *

    + *
  • Coloring attributes - defines attributes used in color selection + * and shading. These attributes are defined in a ColoringAttributes + * object.
  • + * + *

  • Line attributes - defines attributes used to define lines, including + * the pattern, width, and whether antialiasing is to be used. These + * attributes are defined in a LineAttributes object.
  • + * + *

  • Point attributes - defines attributes used to define points, + * including the size and whether antialiasing is to be used. These + * attributes are defined in a PointAttributes object.
  • + * + *

  • Polygon attributes - defines the attributes used to define + * polygons, including culling, rasterization mode (filled, lines, + * or points), constant offset, offset factor, and whether back + * back facing normals are flipped. These attributes are defined + * in a PolygonAttributes object.
  • + * + *

  • Rendering attributes - defines rendering operations, + * including the alpha test function and test value, the raster + * operation, whether vertex colors are ignored, whether invisible + * objects are rendered, and whether the depth buffer is enabled. + * These attributes are defined in a RenderingAttributes + * object.
  • + * + *

  • Transparency attributes - defines the attributes that affect + * transparency of the object, such as the transparency mode + * (blended, screen-door), blending function (used in transparency + * and antialiasing operations), and a blend value that defines + * the amount of transparency to be applied to this Appearance + * component object.
  • + * + *

  • Material - defines the appearance of an object under illumination, + * such as the ambient color, diffuse color, specular color, emissive + * color, and shininess. These attributes are defined in a Material + * object.
  • + * + *

  • Texture - defines the texture image and filtering + * parameters used when texture mapping is enabled. These attributes + * are defined in a Texture object.
  • + * + *

  • Texture attributes - defines the attributes that apply to + * texture mapping, such as the texture mode, texture transform, + * blend color, and perspective correction mode. These attributes + * are defined in a TextureAttributes object.
  • + * + *

  • Texture coordinate generation - defines the attributes + * that apply to texture coordinate generation, such as whether + * texture coordinate generation is enabled, coordinate format + * (2D or 3D coordinates), coordinate generation mode (object + * linear, eye linear, or spherical reflection mapping), and the + * R, S, and T coordinate plane equations. These attributes + * are defined in a TexCoordGeneration object.
  • + * + *

  • Texture unit state - array that defines texture state for each + * of N separate texture units. This allows multiple textures + * to be applied to geometry. Each TextureUnitState object contains a + * Texture object, TextureAttributes, and TexCoordGeneration object + * for one texture unit. If the length of the texture unit state + * array is greater than 0, then the array is used for all texture + * state; the individual Texture, TextureAttributes, and + * TexCoordGeneration objects in this Appearance object are not used + * and and must not be set by an application. If the length of the + * texture unit state array is 0, the multi-texture is disabled and + * the Texture, TextureAttributes, and TexCoordGeneration objects + * in the Appearance object are used. If the application sets the + * existing Texture, TextureAttributes, and TexCoordGeneration + * objects to non-null values, they effectively define the state + * for texture unit 0. If the TextureUnitState array is set to a + * non-null, non-empty array, the individual TextureUnitState + * objects define the state for texture units 0 through n + * -1. If both the old and new values are set, an exception is thrown. + * + *
  • + *
+ * + * @see ColoringAttributes + * @see LineAttributes + * @see PointAttributes + * @see PolygonAttributes + * @see RenderingAttributes + * @see TransparencyAttributes + * @see Material + * @see Texture + * @see TextureAttributes + * @see TexCoordGeneration + * @see TextureUnitState + */ +public class Appearance extends NodeComponent { + + /** + * Specifies that this Appearance object + * allows reading its coloringAttributes component + * information. + */ + public static final int + ALLOW_COLORING_ATTRIBUTES_READ = CapabilityBits.APPEARANCE_ALLOW_COLORING_ATTRIBUTES_READ; + + /** + * Specifies that this Appearance object + * allows writing its coloringAttributes component + * information. + */ + public static final int + ALLOW_COLORING_ATTRIBUTES_WRITE = CapabilityBits.APPEARANCE_ALLOW_COLORING_ATTRIBUTES_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its transparency component + * information. + */ + public static final int + ALLOW_TRANSPARENCY_ATTRIBUTES_READ = CapabilityBits.APPEARANCE_ALLOW_TRANSPARENCY_ATTRIBUTES_READ; + + /** + * Specifies that this Appearance object + * allows writing its transparency component + * information. + */ + public static final int + ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE = CapabilityBits.APPEARANCE_ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its rendering/rasterization component + * information. + */ + public static final int + ALLOW_RENDERING_ATTRIBUTES_READ = CapabilityBits.APPEARANCE_ALLOW_RENDERING_ATTRIBUTES_READ; + + /** + * Specifies that this Appearance object + * allows writing its rendering/rasterization component + * information. + */ + public static final int + ALLOW_RENDERING_ATTRIBUTES_WRITE = CapabilityBits.APPEARANCE_ALLOW_RENDERING_ATTRIBUTES_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its polygon component + * information. + */ + public static final int + ALLOW_POLYGON_ATTRIBUTES_READ = CapabilityBits.APPEARANCE_ALLOW_POLYGON_ATTRIBUTES_READ; + + /** + * Specifies that this Appearance object + * allows writing its polygon component + * information. + */ + public static final int + ALLOW_POLYGON_ATTRIBUTES_WRITE = CapabilityBits.APPEARANCE_ALLOW_POLYGON_ATTRIBUTES_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its line component + * information. + */ + public static final int + ALLOW_LINE_ATTRIBUTES_READ = CapabilityBits.APPEARANCE_ALLOW_LINE_ATTRIBUTES_READ; + + /** + * Specifies that this Appearance object + * allows writing its line component + * information. + */ + public static final int + ALLOW_LINE_ATTRIBUTES_WRITE = CapabilityBits.APPEARANCE_ALLOW_LINE_ATTRIBUTES_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its point component + * information. + */ + public static final int + ALLOW_POINT_ATTRIBUTES_READ = CapabilityBits.APPEARANCE_ALLOW_POINT_ATTRIBUTES_READ; + + /** + * Specifies that this Appearance object + * allows writing its point component + * information. + */ + public static final int + ALLOW_POINT_ATTRIBUTES_WRITE = CapabilityBits.APPEARANCE_ALLOW_POINT_ATTRIBUTES_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its material component information. + */ + public static final int + ALLOW_MATERIAL_READ = CapabilityBits.APPEARANCE_ALLOW_MATERIAL_READ; + + /** + * Specifies that this Appearance object + * allows writing its material component information. + */ + public static final int + ALLOW_MATERIAL_WRITE = CapabilityBits.APPEARANCE_ALLOW_MATERIAL_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its texture component information. + */ + public static final int + ALLOW_TEXTURE_READ = CapabilityBits.APPEARANCE_ALLOW_TEXTURE_READ; + + /** + * Specifies that this Appearance object + * allows writing its texture component information. + */ + public static final int + ALLOW_TEXTURE_WRITE = CapabilityBits.APPEARANCE_ALLOW_TEXTURE_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its textureAttributes component + * information. + */ + public static final int + ALLOW_TEXTURE_ATTRIBUTES_READ = CapabilityBits.APPEARANCE_ALLOW_TEXTURE_ATTRIBUTES_READ; + + /** + * Specifies that this Appearance object + * allows writing its textureAttributes component + * information. + */ + public static final int + ALLOW_TEXTURE_ATTRIBUTES_WRITE = CapabilityBits.APPEARANCE_ALLOW_TEXTURE_ATTRIBUTES_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its texture coordinate generation component + * information. + */ + public static final int + ALLOW_TEXGEN_READ = CapabilityBits.APPEARANCE_ALLOW_TEXGEN_READ; + + /** + * Specifies that this Appearance object + * allows writing its texture coordinate generation component + * information. + */ + public static final int + ALLOW_TEXGEN_WRITE = CapabilityBits.APPEARANCE_ALLOW_TEXGEN_WRITE; + + /** + * Specifies that this Appearance object + * allows reading its texture unit state component + * information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_TEXTURE_UNIT_STATE_READ = + CapabilityBits.APPEARANCE_ALLOW_TEXTURE_UNIT_STATE_READ; + + /** + * Specifies that this Appearance object + * allows writing its texture unit state component + * information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_TEXTURE_UNIT_STATE_WRITE = + CapabilityBits.APPEARANCE_ALLOW_TEXTURE_UNIT_STATE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_COLORING_ATTRIBUTES_READ, + ALLOW_LINE_ATTRIBUTES_READ, + ALLOW_MATERIAL_READ, + ALLOW_POINT_ATTRIBUTES_READ, + ALLOW_POLYGON_ATTRIBUTES_READ, + ALLOW_RENDERING_ATTRIBUTES_READ, + ALLOW_TEXGEN_READ, + ALLOW_TEXTURE_ATTRIBUTES_READ, + ALLOW_TEXTURE_READ, + ALLOW_TEXTURE_UNIT_STATE_READ, + ALLOW_TRANSPARENCY_ATTRIBUTES_READ + }; + + /** + * Constructs an Appearance component object using defaults for all + * state variables. All component object references are initialized + * to null. + */ + public Appearance() { + // Just use default values + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Creates the retained mode AppearanceRetained object that this + * Appearance component object will point to. + */ + void createRetained() { + this.retained = new AppearanceRetained(); + this.retained.setSource(this); + } + + /** + * Sets the material object to the specified object. + * Setting it to null disables lighting. + * @param material object that specifies the desired material + * properties + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setMaterial(Material material) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MATERIAL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance0")); + ((AppearanceRetained)this.retained).setMaterial(material); + } + + /** + * Retrieves the current material object. + * @return the material object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Material getMaterial() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MATERIAL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance1")); + return ((AppearanceRetained)this.retained).getMaterial(); + } + + /** + * Sets the coloringAttributes object to the specified object. + * Setting it to null will result in default attribute usage. + * @param coloringAttributes object that specifies the desired + * coloringAttributes parameters + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setColoringAttributes(ColoringAttributes coloringAttributes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLORING_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance6")); + ((AppearanceRetained)this.retained).setColoringAttributes(coloringAttributes); + } + + /** + * Retrieves the current coloringAttributes object. + * @return the coloringAttributes object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ColoringAttributes getColoringAttributes() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLORING_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance7")); + return ((AppearanceRetained)this.retained).getColoringAttributes(); + } + + /** + * Sets the transparencyAttributes object to the specified object. + * Setting it to null will result in default attribute usage. + * @param transparencyAttributes object that specifies the desired + * transparencyAttributes parameters + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setTransparencyAttributes(TransparencyAttributes transparencyAttributes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance8")); + ((AppearanceRetained)this.retained).setTransparencyAttributes(transparencyAttributes); + } + + /** + * Retrieves the current transparencyAttributes object. + * @return the transparencyAttributes object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public TransparencyAttributes getTransparencyAttributes() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TRANSPARENCY_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance9")); + return ((AppearanceRetained)this.retained).getTransparencyAttributes(); + } + + /** + * Sets the renderingAttributes object to the specified object. + * Setting it to null will result in default attribute usage. + * @param renderingAttributes object that specifies the desired + * renderingAttributes parameters + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setRenderingAttributes(RenderingAttributes renderingAttributes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_RENDERING_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance10")); + ((AppearanceRetained)this.retained).setRenderingAttributes(renderingAttributes); + } + + /** + * Retrieves the current renderingAttributes object. + * @return the renderingAttributes object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public RenderingAttributes getRenderingAttributes() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_RENDERING_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance11")); + return ((AppearanceRetained)this.retained).getRenderingAttributes(); + } + + /** + * Sets the polygonAttributes object to the specified object. + * Setting it to null will result in default attribute usage. + * @param polygonAttributes object that specifies the desired + * polygonAttributes parameters + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPolygonAttributes(PolygonAttributes polygonAttributes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_POLYGON_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance12")); + ((AppearanceRetained)this.retained).setPolygonAttributes(polygonAttributes); + } + + /** + * Retrieves the current polygonAttributes object. + * @return the polygonAttributes object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public PolygonAttributes getPolygonAttributes() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_POLYGON_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance13")); + return ((AppearanceRetained)this.retained).getPolygonAttributes(); + } + + /** + * Sets the lineAttributes object to the specified object. + * Setting it to null will result in default attribute usage. + * @param lineAttributes object that specifies the desired + * lineAttributes parameters + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setLineAttributes(LineAttributes lineAttributes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_LINE_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance14")); + ((AppearanceRetained)this.retained).setLineAttributes(lineAttributes); + } + + /** + * Retrieves the current lineAttributes object. + * @return the lineAttributes object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public LineAttributes getLineAttributes() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_LINE_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance15")); + return ((AppearanceRetained)this.retained).getLineAttributes(); + } + + /** + * Sets the pointAttributes object to the specified object. + * Setting it to null will result in default attribute usage. + * @param pointAttributes object that specifies the desired + * pointAttributes parameters + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPointAttributes(PointAttributes pointAttributes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_POINT_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance16")); + ((AppearanceRetained)this.retained).setPointAttributes(pointAttributes); + } + + /** + * Retrieves the current pointAttributes object. + * @return the pointAttributes object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public PointAttributes getPointAttributes() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_POINT_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance17")); + return ((AppearanceRetained)this.retained).getPointAttributes(); + } + + /** + * Sets the texture object to the specified object. + * Setting it to null disables texture mapping. + * + *

+ * Applications must not set individual texture component objects + * (texture, textureAttributes, or texCoordGeneration) and + * the texture unit state array in the same Appearance object. + * Doing so will result in an exception being thrown. + * + * @param texture object that specifies the desired texture + * map and texture parameters + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the specified texture + * object is non-null and the texture unit state array in this + * appearance object is already non-null. + * + * @exception IllegalSharingException if this Appearance is live and + * the specified texture refers to an ImageComponent2D that is being used + * by a Canvas3D as an off-screen buffer. + * + * @exception IllegalSharingException if this Appearance is + * being used by an immediate mode context and + * the specified texture refers to an ImageComponent2D that is being used + * by a Canvas3D as an off-screen buffer. + */ + public void setTexture(Texture texture) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXTURE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance2")); + + // Do illegal sharing check + if(texture != null) { + ImageComponent[] images = ((TextureRetained)(texture.retained)).getImages(); + if(images != null) { + for(int i=0; i + * Applications must not set individual texture component objects + * (texture, textureAttributes, or texCoordGeneration) and + * the texture unit state array in the same Appearance object. + * Doing so will result in an exception being thrown. + * + * @param textureAttributes object that specifies the desired + * textureAttributes map and textureAttributes parameters + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the specified textureAttributes + * object is non-null and the texture unit state array in this + * appearance object is already non-null. + */ + public void setTextureAttributes(TextureAttributes textureAttributes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXTURE_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance4")); + ((AppearanceRetained)this.retained).setTextureAttributes(textureAttributes); + } + + /** + * Retrieves the current textureAttributes object. + * @return the textureAttributes object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public TextureAttributes getTextureAttributes() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXTURE_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance5")); + return ((AppearanceRetained)this.retained).getTextureAttributes(); + } + + /** + * Sets the texCoordGeneration object to the specified object. + * Setting it to null disables texture coordinate generation. + * + *

+ * Applications must not set individual texture component objects + * (texture, textureAttributes, or texCoordGeneration) and + * the texture unit state array in the same Appearance object. + * Doing so will result in an exception being thrown. + * + * @param texCoordGeneration object that specifies the texture coordinate + * generation parameters + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the specified texCoordGeneration + * object is non-null and the texture unit state array in this + * appearance object is already non-null. + */ + public void setTexCoordGeneration(TexCoordGeneration texCoordGeneration) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXGEN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance18")); + ((AppearanceRetained)this.retained).setTexCoordGeneration(texCoordGeneration); + } + + /** + * Retrieves the current texCoordGeneration object. + * @return the texCoordGeneration object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public TexCoordGeneration getTexCoordGeneration() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXGEN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance19")); + return ((AppearanceRetained)this.retained).getTexCoordGeneration(); + } + + /** + * Sets the texture unit state array for this appearance object to the + * specified array. A shallow copy of the array of references to + * the TextureUnitState objects is made. If the specified array + * is null or if the length of the array is 0, multi-texture is + * disabled. Within the array, a null TextureUnitState element + * disables the corresponding texture unit. + * + *

+ * Applications must not set individual texture component objects + * (texture, textureAttributes, or texCoordGeneration) and + * the texture unit state array in the same Appearance object. + * Doing so will result in an exception being thrown. + * + * @param stateArray array of TextureUnitState objects that + * specify the desired texture state for each unit. The length of + * this array specifies the maximum number of texture units that + * will be used by this appearance object. The texture units are + * numbered from 0 through + * stateArray.length-1. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the specified array is + * non-null and any of the texture object, textureAttributes + * object, or texCoordGeneration object in this appearance object + * is already non-null. + * + * @exception IllegalSharingException if this Appearance is live and + * any of the specified textures refers to an ImageComponent2D that is + * being used by a Canvas3D as an off-screen buffer. + * + * @exception IllegalSharingException if this Appearance is + * being used by an immediate mode context and + * any of the specified textures refers to an ImageComponent2D that is + * being used by a Canvas3D as an off-screen buffer. + * + * @since Java 3D 1.2 + */ + public void setTextureUnitState(TextureUnitState[] stateArray) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXTURE_UNIT_STATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance20")); + + // Do illegal sharing check + if (stateArray != null) { + for(int j=0; j[0, stateArray.length-1]. + * + * @param index the array index of the object to be set + * + * @param state new texture unit state object + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception NullPointerException if the texture unit state array is + * null. + * @exception ArrayIndexOutOfBoundsException if index >= + * stateArray.length. + * + * @exception IllegalSharingException if this Appearance is live and + * the specified texture refers to an ImageComponent2D that is being used + * by a Canvas3D as an off-screen buffer. + * + * @exception IllegalSharingException if this Appearance is + * being used by an immediate mode context and + * the specified texture refers to an ImageComponent2D that is being used + * by a Canvas3D as an off-screen buffer. + * + * @since Java 3D 1.2 + */ + public void setTextureUnitState(int index, TextureUnitState state) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXTURE_UNIT_STATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance20")); + + // Do illegal sharing check + if (state != null) { + TextureRetained texRetained = + ((TextureUnitStateRetained)state.retained).texture; + if(texRetained != null) { + ImageComponent[] images = texRetained.getImages(); + if(images != null) { + for(int i=0; i[0, stateArray.length-1]. + * + * @param index the array index of the object to be retrieved + * + * @return the texture unit state object at the specified index + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public TextureUnitState getTextureUnitState(int index) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXTURE_UNIT_STATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance21")); + + return ((AppearanceRetained)this.retained).getTextureUnitState(index); + } + + /** + * Retrieves the length of the texture unit state array from + * this appearance object. The length of this array specifies the + * maximum number of texture units that will be used by this + * appearance object. If the array is null, a count of 0 is + * returned. + * + * @return the length of the texture unit state array + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getTextureUnitCount() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TEXTURE_UNIT_STATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Appearance21")); + + return ((AppearanceRetained)this.retained).getTextureUnitCount(); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + Appearance a = new Appearance(); + a.duplicateNodeComponent(this); + return a; + } + + /** + * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @deprecated replaced with duplicateNodeComponent( + * NodeComponent originalNodeComponent, boolean forceDuplicate) + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent) { + checkDuplicateNodeComponent(originalNodeComponent); + } + + /** + * Copies all Appearance information from + * originalNodeComponent into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + Hashtable hashtable = originalNodeComponent.nodeHashtable; + + AppearanceRetained app = (AppearanceRetained) originalNodeComponent.retained; + + AppearanceRetained rt = (AppearanceRetained) retained; + + rt.setMaterial((Material) getNodeComponent(app.getMaterial(), + forceDuplicate, + hashtable)); + + rt.setColoringAttributes((ColoringAttributes) getNodeComponent( + app.getColoringAttributes(), + forceDuplicate, + hashtable)); + + + rt.setTransparencyAttributes((TransparencyAttributes) getNodeComponent( + app.getTransparencyAttributes(), + forceDuplicate, + hashtable)); + + + rt.setRenderingAttributes((RenderingAttributes) getNodeComponent( + app.getRenderingAttributes(), + forceDuplicate, + hashtable)); + + + rt.setPolygonAttributes((PolygonAttributes) getNodeComponent( + app.getPolygonAttributes(), + forceDuplicate, + hashtable)); + + + rt.setLineAttributes((LineAttributes) getNodeComponent( + app.getLineAttributes(), + forceDuplicate, + hashtable)); + + + rt.setPointAttributes((PointAttributes) getNodeComponent( + app.getPointAttributes(), + forceDuplicate, + hashtable)); + + rt.setTexture((Texture) getNodeComponent(app.getTexture(), + forceDuplicate, + hashtable)); + + rt.setTextureAttributes((TextureAttributes) getNodeComponent( + app.getTextureAttributes(), + forceDuplicate, + hashtable)); + + rt.setTexCoordGeneration((TexCoordGeneration) getNodeComponent( + app.getTexCoordGeneration(), + forceDuplicate, + hashtable)); + + TextureUnitState state[] = app.getTextureUnitState(); + if (state != null) { + rt.setTextureUnitState(state); + for (int i=0; i < state.length; i++) { + rt.setTextureUnitState(i, (TextureUnitState) + getNodeComponent(state[i], + forceDuplicate, + hashtable)); + } + } + + } + + /** + * This function is called from getNodeComponent() to see if any of + * the sub-NodeComponents duplicateOnCloneTree flag is true. + * If it is the case, current NodeComponent needs to + * duplicate also even though current duplicateOnCloneTree flag is false. + * This should be overwrite by NodeComponent which contains sub-NodeComponent. + */ + boolean duplicateChild() { + if (getDuplicateOnCloneTree()) + return true; + + AppearanceRetained rt = (AppearanceRetained) retained; + + NodeComponent nc; + + nc = rt.getMaterial(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getColoringAttributes(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getTransparencyAttributes(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getPolygonAttributes(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getLineAttributes(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getPointAttributes(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getTexture(); + if ((nc != null) && nc.duplicateChild()) + return true; + + nc = rt.getTextureAttributes(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getTexCoordGeneration(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + // XXXX: TextureUnitState + + return false; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AppearanceRetained.java b/j3d-core/src/classes/share/javax/media/j3d/AppearanceRetained.java new file mode 100644 index 0000000..f1b9029 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AppearanceRetained.java @@ -0,0 +1,1417 @@ +/* + * $RCSfile: AppearanceRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.11 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; +import java.util.BitSet; +import java.util.ArrayList; + + +/** + * The Appearance object defines all rendering state that can be set + * as a component object of a Shape3D node. + */ +class AppearanceRetained extends NodeComponentRetained { + + // + // State variables: these should all be initialized to approproate + // Java 3D defaults. + // + + // Material object used when lighting is enabled + MaterialRetained material = null; + + // Texture object used to apply a texture map to an object + TextureRetained texture = null; + + // Texture coordinate generation object + TexCoordGenerationRetained texCoordGeneration = null; + + // Texture Attributes bundle object + TextureAttributesRetained textureAttributes = null; + + TextureUnitStateRetained texUnitState[] = null; + + // Coloring Attributes bundle object + ColoringAttributesRetained coloringAttributes = null; + + // Transparency Attributes bundle object + TransparencyAttributesRetained transparencyAttributes = null; + + // Rendering Attributes bundle object + RenderingAttributesRetained renderingAttributes = null; + + // Polygon Attributes bundle object + PolygonAttributesRetained polygonAttributes = null; + + // Line Attributes bundle object + LineAttributesRetained lineAttributes = null; + + // Point Attributes bundle object + PointAttributesRetained pointAttributes = null; + + + // Lock used for synchronization of live state + Object liveStateLock = new Object(); + + // NOTE: Consider grouping random state into common objects + + // Cache used during compilation. If map == compState, then + // mapAppearance can be used for this appearance + CompileState map = null; + AppearanceRetained mapAppearance = null; + + static final int MATERIAL = 0x0001; + static final int TEXTURE = 0x0002; + static final int TEXCOORD_GEN = 0x0004; + static final int TEXTURE_ATTR = 0x0008; + static final int COLOR = 0x0010; + static final int TRANSPARENCY = 0x0020; + static final int RENDERING = 0x0040; + static final int POLYGON = 0x0080; + static final int LINE = 0x0100; + static final int POINT = 0x0200; + static final int TEXTURE_UNIT_STATE = 0x0400; + + static final int ALL_SOLE_USERS = 0; + + // A pointer to the scene graph appearance object + AppearanceRetained sgApp = null; + + // The object level hashcode for this appearance + // int objHashCode = super.hashCode(); + + /** + * Set the material object to the specified object. + * @param material object that specifies the desired material + * @exception IllegalSharingException + * properties + */ + void setMaterial(Material material) { + + synchronized(liveStateLock) { + if (source.isLive()) { + + if (this.material != null) { + this.material.clearLive(refCount); + this.material.removeMirrorUsers(this); + } + if (material != null) { + ((MaterialRetained)material.retained).setLive(inBackgroundGroup, refCount); + // If appearance is live, then copy all the users of this + // appaearance as users of this material + ((MaterialRetained)material.retained).copyMirrorUsers(this); + } + sendMessage(MATERIAL, + (material != null ? + ((MaterialRetained)material.retained).mirror : null), true); + } + if (material == null) { + this.material = null; + } else { + this.material = (MaterialRetained)material.retained; + } + } + } + + /** + * Retrieve the current material object. + * @return the material object + */ + Material getMaterial() { + return (material == null ? null : (Material)material.source); + } + + /** + * Sets the texture object to the specified object. + * @param texture object that specifies the desired texture + * map and texture parameters + */ + void setTexture(Texture texture) { + synchronized(liveStateLock) { + if (source.isLive()) { + + if (this.texture != null) { + this.texture.clearLive(refCount); + this.texture.removeMirrorUsers(this); + } + + if (texture != null) { + ((TextureRetained)texture.retained).setLive(inBackgroundGroup, refCount); + ((TextureRetained)texture.retained).copyMirrorUsers(this); + } + sendMessage(TEXTURE, + (texture != null ? + ((TextureRetained)texture.retained).mirror : null), true); + + } + + + if (texture == null) { + this.texture = null; + } else { + this.texture = (TextureRetained)texture.retained; + } + } + } + + /** + * Retrieves the current texture object. + * @return the texture object + */ + Texture getTexture() { + return (texture == null ? null : (Texture)texture.source); + } + + /** + * Sets the textureAttrbutes object to the specified object. + * @param textureAttributes object that specifies the desired texture + * attributes + */ + void setTextureAttributes(TextureAttributes textureAttributes) { + + synchronized(liveStateLock) { + if (source.isLive()) { + + if (this.textureAttributes != null) { + this.textureAttributes.clearLive(refCount); + this.textureAttributes.removeMirrorUsers(this); + } + + if (textureAttributes != null) { + ((TextureAttributesRetained)textureAttributes.retained).setLive(inBackgroundGroup, refCount); + ((TextureAttributesRetained)textureAttributes.retained).copyMirrorUsers(this); + } + sendMessage(TEXTURE_ATTR, + (textureAttributes != null ? + ((TextureAttributesRetained)textureAttributes.retained).mirror: + null), true); + + } + + + if (textureAttributes == null) { + this.textureAttributes = null; + } else { + this.textureAttributes = (TextureAttributesRetained)textureAttributes.retained; + } + } + } + + /** + * Retrieves the current textureAttributes object. + * @return the textureAttributes object + */ + TextureAttributes getTextureAttributes() { + return (textureAttributes == null ? null : + (TextureAttributes)textureAttributes.source); + } + + /** + * Sets the coloringAttrbutes object to the specified object. + * @param coloringAttributes object that specifies the desired texture + * attributes + */ + void setColoringAttributes(ColoringAttributes coloringAttributes) { + + synchronized(liveStateLock) { + if (source.isLive()) { + + if (this.coloringAttributes != null) { + this.coloringAttributes.clearLive(refCount); + this.coloringAttributes.removeMirrorUsers(this); + } + + if (coloringAttributes != null) { + ((ColoringAttributesRetained)coloringAttributes.retained).setLive(inBackgroundGroup, refCount); + ((ColoringAttributesRetained)coloringAttributes.retained).copyMirrorUsers(this); + } + sendMessage(COLOR, + (coloringAttributes != null ? + ((ColoringAttributesRetained)coloringAttributes.retained).mirror: + null), true); + } + + + if (coloringAttributes == null) { + this.coloringAttributes = null; + } else { + this.coloringAttributes = (ColoringAttributesRetained)coloringAttributes.retained; + } + } + } + + /** + * Retrieves the current coloringAttributes object. + * @return the coloringAttributes object + */ + ColoringAttributes getColoringAttributes() { + return (coloringAttributes == null ? null : + (ColoringAttributes)coloringAttributes.source); + } + + /** + * Sets the transparencyAttrbutes object to the specified object. + * @param transparencyAttributes object that specifies the desired texture + * attributes + */ + void setTransparencyAttributes(TransparencyAttributes transparencyAttributes) { + + synchronized(liveStateLock) { + if (source.isLive()) { + + if (this.transparencyAttributes != null) { + this.transparencyAttributes.clearLive(refCount); + this.transparencyAttributes.removeMirrorUsers(this); + } + + if (transparencyAttributes != null) { + ((TransparencyAttributesRetained)transparencyAttributes.retained).setLive(inBackgroundGroup, refCount); + ((TransparencyAttributesRetained)transparencyAttributes.retained).copyMirrorUsers(this); + } + + sendMessage(TRANSPARENCY, + (transparencyAttributes != null ? + ((TransparencyAttributesRetained)transparencyAttributes.retained).mirror: null), true); + } + + + if (transparencyAttributes == null) { + this.transparencyAttributes = null; + } else { + this.transparencyAttributes = (TransparencyAttributesRetained)transparencyAttributes.retained; + + } + } + } + + /** + * Retrieves the current transparencyAttributes object. + * @return the transparencyAttributes object + */ + TransparencyAttributes getTransparencyAttributes() { + return (transparencyAttributes == null ? null : + (TransparencyAttributes)transparencyAttributes.source); + } + + /** + * Sets the renderingAttrbutes object to the specified object. + * @param renderingAttributes object that specifies the desired texture + * attributes + */ + void setRenderingAttributes(RenderingAttributes renderingAttributes) { + + synchronized(liveStateLock) { + if (source.isLive()) { + if (this.renderingAttributes != null) { + this.renderingAttributes.clearLive(refCount); + this.renderingAttributes.removeMirrorUsers(this); + } + + if (renderingAttributes != null) { + ((RenderingAttributesRetained)renderingAttributes.retained).setLive(inBackgroundGroup, refCount); + ((RenderingAttributesRetained)renderingAttributes.retained).copyMirrorUsers(this); + } + Object m = null; + boolean v = true; + if (renderingAttributes != null) { + m = ((RenderingAttributesRetained)renderingAttributes.retained).mirror; + v = ((RenderingAttributesRetained)renderingAttributes.retained).visible; + } + sendMessage(RENDERING,m, v); + // Also need to send a message to GeometryStructure. + sendRenderingAttributesChangedMessage( v); + } + if (renderingAttributes == null) { + this.renderingAttributes = null; + } else { + this.renderingAttributes = (RenderingAttributesRetained)renderingAttributes.retained; + + } + } + } + + /** + * Retrieves the current renderingAttributes object. + * @return the renderingAttributes object + */ + RenderingAttributes getRenderingAttributes() { + if (renderingAttributes == null) + return null; + + return (RenderingAttributes)renderingAttributes.source; + } + + /** + * Sets the polygonAttrbutes object to the specified object. + * @param polygonAttributes object that specifies the desired texture + * attributes + */ + void setPolygonAttributes(PolygonAttributes polygonAttributes) { + + synchronized(liveStateLock) { + if (source.isLive()) { + if (this.polygonAttributes != null) { + this.polygonAttributes.clearLive(refCount); + this.polygonAttributes.removeMirrorUsers(this); + } + + if (polygonAttributes != null) { + ((PolygonAttributesRetained)polygonAttributes.retained).setLive(inBackgroundGroup, refCount); + ((PolygonAttributesRetained)polygonAttributes.retained).copyMirrorUsers(this); + } + sendMessage(POLYGON, + (polygonAttributes != null ? + ((PolygonAttributesRetained)polygonAttributes.retained).mirror : + null), true); + + } + + if (polygonAttributes == null) { + this.polygonAttributes = null; + } else { + this.polygonAttributes = (PolygonAttributesRetained)polygonAttributes.retained; + } + } + } + + /** + * Retrieves the current polygonAttributes object. + * @return the polygonAttributes object + */ + PolygonAttributes getPolygonAttributes() { + return (polygonAttributes == null ? null: + (PolygonAttributes)polygonAttributes.source); + } + + /** + * Sets the lineAttrbutes object to the specified object. + * @param lineAttributes object that specifies the desired texture + * attributes + */ + void setLineAttributes(LineAttributes lineAttributes) { + + synchronized(liveStateLock) { + if (source.isLive()) { + + if (this.lineAttributes != null) { + this.lineAttributes.clearLive(refCount); + this.lineAttributes.removeMirrorUsers(this); + } + + if (lineAttributes != null) { + ((LineAttributesRetained)lineAttributes.retained).setLive(inBackgroundGroup, refCount); + ((LineAttributesRetained)lineAttributes.retained).copyMirrorUsers(this); + } + sendMessage(LINE, + (lineAttributes != null ? + ((LineAttributesRetained)lineAttributes.retained).mirror: null), true); + } + + + if (lineAttributes == null) { + this.lineAttributes = null; + } else { + this.lineAttributes = (LineAttributesRetained)lineAttributes.retained; + } + } + } + + /** + * Retrieves the current lineAttributes object. + * @return the lineAttributes object + */ + LineAttributes getLineAttributes() { + return (lineAttributes == null ? null : + (LineAttributes)lineAttributes.source); + } + + /** + * Sets the pointAttrbutes object to the specified object. + * @param pointAttributes object that specifies the desired texture + * attributes + */ + void setPointAttributes(PointAttributes pointAttributes) { + + synchronized(liveStateLock) { + if (source.isLive()) { + + if (this.pointAttributes != null) { + this.pointAttributes.clearLive(refCount); + this.pointAttributes.removeMirrorUsers(this); + } + if (pointAttributes != null) { + ((PointAttributesRetained)pointAttributes.retained).setLive(inBackgroundGroup, refCount); + ((PointAttributesRetained)pointAttributes.retained).copyMirrorUsers(this); + } + sendMessage(POINT, + (pointAttributes != null ? + ((PointAttributesRetained)pointAttributes.retained).mirror: + null), true); + } + + + if (pointAttributes == null) { + this.pointAttributes = null; + } else { + this.pointAttributes = (PointAttributesRetained)pointAttributes.retained; + } + } + } + + /** + * Retrieves the current pointAttributes object. + * @return the pointAttributes object + */ + PointAttributes getPointAttributes() { + return (pointAttributes == null? null : (PointAttributes)pointAttributes.source); + } + + /** + * Sets the texCoordGeneration object to the specified object. + * @param texCoordGeneration object that specifies the texture coordinate + * generation parameters + */ + void setTexCoordGeneration(TexCoordGeneration texGen) { + + synchronized(liveStateLock) { + if (source.isLive()) { + + if (this.texCoordGeneration != null) { + this.texCoordGeneration.clearLive(refCount); + this.texCoordGeneration.removeMirrorUsers(this); + } + + if (texGen != null) { + ((TexCoordGenerationRetained)texGen.retained).setLive(inBackgroundGroup, refCount); + ((TexCoordGenerationRetained)texGen.retained).copyMirrorUsers(this); + } + sendMessage(TEXCOORD_GEN, + (texGen != null ? + ((TexCoordGenerationRetained)texGen.retained).mirror : null), true); + } + + if (texGen == null) { + this.texCoordGeneration = null; + } else { + this.texCoordGeneration = (TexCoordGenerationRetained)texGen.retained; + } + } + } + + /** + * Retrieves the current texCoordGeneration object. + * @return the texCoordGeneration object + */ + TexCoordGeneration getTexCoordGeneration() { + return (texCoordGeneration == null ? null : + (TexCoordGeneration)texCoordGeneration.source); + } + + + /** + * Sets the texture unit state array to the specified array. + * @param textureUnitState array that specifies the texture unit state + */ + void setTextureUnitState(TextureUnitState[] stateArray) { + + int i; + + synchronized(liveStateLock) { + if (source.isLive()) { + + // remove the existing texture unit states from this appearance + if (this.texUnitState != null) { + for (i = 0; i < this.texUnitState.length; i++) { + if (this.texUnitState[i] != null) { + this.texUnitState[i].clearLive(refCount); + this.texUnitState[i].removeMirrorUsers(this); + } + } + } + + // add the specified texture unit states to this appearance + // also make a copy of the array of references to the units + if (stateArray != null && stateArray.length > 0) { + + Object [] args = new Object[2]; + + // -1 index means the entire array is to be set + args[0] = new Integer(-1); + + // make a copy of the array for the message, + TextureUnitStateRetained mirrorStateArray[] = + new TextureUnitStateRetained[stateArray.length]; + + args[1] = (Object) mirrorStateArray; + + for (i = 0; i < stateArray.length; i++) { + TextureUnitState tu = stateArray[i]; + if (tu != null) { + ((TextureUnitStateRetained)tu.retained).setLive( + inBackgroundGroup, refCount); + ((TextureUnitStateRetained)tu.retained).copyMirrorUsers( + this); + mirrorStateArray[i] = (TextureUnitStateRetained) + ((TextureUnitStateRetained)tu.retained).mirror; + } else { + mirrorStateArray[i] = null; + } + } + sendMessage(TEXTURE_UNIT_STATE, args, true); + + } else { + sendMessage(TEXTURE_UNIT_STATE, null, true); + } + } + + // assign the retained copy of the texture unit state to the + // appearance + if (stateArray == null) { + this.texUnitState = null; + } else { + + // make another copy of the array for the retained object + // itself if it doesn't have a copy or the array size is + // not the same + if ((this.texUnitState == null) || + (this.texUnitState.length != stateArray.length)) { + this.texUnitState = new TextureUnitStateRetained[ + stateArray.length]; + } + for (i = 0; i < stateArray.length; i++) { + if (stateArray[i] != null) { + this.texUnitState[i] = + (TextureUnitStateRetained)stateArray[i].retained; + } else { + this.texUnitState[i] = null; + } + } + } + } + } + + void setTextureUnitState(int index, TextureUnitState state) { + + synchronized(liveStateLock) { + if (source.isLive()) { + + // remove the existing texture unit states from this appearance + // Note: Let Java throw an exception if texUnitState is null + // or index is >= texUnitState.length. + if (this.texUnitState[index] != null) { + this.texUnitState[index].clearLive(refCount); + this.texUnitState[index].removeMirrorUsers(this); + } + + // add the specified texture unit states to this appearance + // also make a copy of the array of references to the units + Object args[] = new Object[2]; + args[0] = new Integer(index); + + if (state != null) { + ((TextureUnitStateRetained)state.retained).setLive( + inBackgroundGroup, refCount); + ((TextureUnitStateRetained)state.retained).copyMirrorUsers(this); + args[1] = ((TextureUnitStateRetained)state.retained).mirror; + sendMessage(TEXTURE_UNIT_STATE, args, true); + } else { + args[1] = null; + sendMessage(TEXTURE_UNIT_STATE, args, true); + } + } + + // assign the retained copy of the texture unit state to the + // appearance + if (state != null) { + this.texUnitState[index] = (TextureUnitStateRetained)state.retained; + } else { + this.texUnitState[index] = null; + } + } + } + + + + /** + * Retrieves the array of texture unit state objects from this + * Appearance object. A shallow copy of the array of references to + * the TextureUnitState objects is returned. + * + */ + TextureUnitState[] getTextureUnitState() { + if (texUnitState == null) { + return null; + } else { + TextureUnitState tus[] = + new TextureUnitState[texUnitState.length]; + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null) { + tus[i] = (TextureUnitState) texUnitState[i].source; + } else { + tus[i] = null; + } + } + return tus; + } + } + + /** + * Retrieves the texture unit state object at the specified + * index within the texture unit state array. + */ + TextureUnitState getTextureUnitState(int index) { + + // let Java throw an exception if texUnitState == null or + // index is >= length + if (texUnitState[index] != null) + return (TextureUnitState)texUnitState[index].source; + else + return null; + } + + + /** + * Retrieves the length of the texture unit state array from + * this appearance object. The length of this array specifies the + * maximum number of texture units that will be used by this + * appearance object. If the array is null, a count of 0 is + * returned. + */ + + int getTextureUnitCount() { + if (texUnitState == null) + return 0; + else + return texUnitState.length; + } + + + synchronized void createMirrorObject() { + if (mirror == null) { + // we can't check isStatic() since it sub-NodeComponent + // create a new one, we should create a + // new AppearanceRetained() even though isStatic() = true. + // For simplicity, always create a retained side. + mirror = new AppearanceRetained(); + } + initMirrorObject(); + } + + /** + * This routine updates the mirror appearance for this appearance. + * It also calls the update method for each node component if it + * is not null. + */ + synchronized void initMirrorObject() { + + AppearanceRetained mirrorApp = (AppearanceRetained)mirror; + + mirrorApp.source = source; + mirrorApp.sgApp = this; + + // Fix for Issue 33: copy the changedFrequent mask to mirror + mirrorApp.changedFrequent = changedFrequent; + + if (material != null) { + mirrorApp.material = (MaterialRetained)material.mirror; + } else { + mirrorApp.material = null; + } + + if (texture != null) { + mirrorApp.texture = (TextureRetained)texture.mirror; + } else { + mirrorApp.texture = null; + } + if (texCoordGeneration != null) { + mirrorApp.texCoordGeneration = (TexCoordGenerationRetained)texCoordGeneration.mirror; + } else { + mirrorApp.texCoordGeneration = null; + } + + if (textureAttributes != null) { + mirrorApp.textureAttributes = (TextureAttributesRetained)textureAttributes.mirror; + } else { + mirrorApp.textureAttributes = null; + } + + // TextureUnitState supercedes the single texture interface + if (texUnitState != null && texUnitState.length > 0) { + mirrorApp.texUnitState = + new TextureUnitStateRetained[texUnitState.length]; + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null) { + mirrorApp.texUnitState[i] = + (TextureUnitStateRetained)texUnitState[i].mirror; + } + } + } else if (mirrorApp.texture != null || + mirrorApp.textureAttributes != null || + mirrorApp.texCoordGeneration != null) { + + mirrorApp.texUnitState = new TextureUnitStateRetained[1]; + mirrorApp.texUnitState[0] = new TextureUnitStateRetained(); + mirrorApp.texUnitState[0].set( + mirrorApp.texture, + mirrorApp.textureAttributes, + mirrorApp.texCoordGeneration); + } + + if (coloringAttributes != null) { + mirrorApp.coloringAttributes = (ColoringAttributesRetained)coloringAttributes.mirror; + } else { + mirrorApp.coloringAttributes = null; + } + if (transparencyAttributes != null) { + mirrorApp.transparencyAttributes = (TransparencyAttributesRetained)transparencyAttributes.mirror; + } else { + mirrorApp.transparencyAttributes = null; + } + + if (renderingAttributes != null) { + mirrorApp.renderingAttributes = (RenderingAttributesRetained)renderingAttributes.mirror; + } else { + mirrorApp.renderingAttributes = null; + } + + if (polygonAttributes != null) { + mirrorApp.polygonAttributes = (PolygonAttributesRetained)polygonAttributes.mirror; + } else { + mirrorApp.polygonAttributes = null; + } + + if (lineAttributes != null) { + mirrorApp.lineAttributes = (LineAttributesRetained)lineAttributes.mirror; + } else { + mirrorApp.lineAttributes = null; + } + + if (pointAttributes != null) { + mirrorApp.pointAttributes = (PointAttributesRetained)pointAttributes.mirror; + } else { + mirrorApp.pointAttributes = null; + } + } + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + AppearanceRetained mirrorApp = (AppearanceRetained)mirror; + if ((component & MATERIAL) != 0) { + mirrorApp.material = (MaterialRetained)value; + } + else if ((component & TEXTURE) != 0) { + // Issue 435: set mirror texture + mirrorApp.texture = (TextureRetained)value; + if (mirrorApp.texUnitState == null) { + mirrorApp.texUnitState = new TextureUnitStateRetained[1]; + mirrorApp.texUnitState[0] = new TextureUnitStateRetained(); + } + mirrorApp.texUnitState[0].texture = (TextureRetained)value; + } + else if ((component & TEXCOORD_GEN) != 0) { + if (mirrorApp.texUnitState == null) { + mirrorApp.texUnitState = new TextureUnitStateRetained[1]; + mirrorApp.texUnitState[0] = new TextureUnitStateRetained(); + } + mirrorApp.texUnitState[0].texGen = (TexCoordGenerationRetained)value; + } + else if ((component & TEXTURE_ATTR) != 0) { + if (mirrorApp.texUnitState == null) { + mirrorApp.texUnitState = new TextureUnitStateRetained[1]; + mirrorApp.texUnitState[0] = new TextureUnitStateRetained(); + } + mirrorApp.texUnitState[0].texAttrs = (TextureAttributesRetained)value; + } + else if ((component & TEXTURE_UNIT_STATE) != 0) { + Object [] args = (Object [])value; + + if (args == null) { + mirrorApp.texUnitState = null; + } else { + int index = ((Integer)args[0]).intValue(); + if (index == -1) { + mirrorApp.texUnitState = + (TextureUnitStateRetained [])args[1]; + } else { + mirrorApp.texUnitState[index] = + (TextureUnitStateRetained)args[1]; + } + } + } + else if ((component & COLOR) != 0) { + mirrorApp.coloringAttributes = (ColoringAttributesRetained)value; + } + else if ((component & TRANSPARENCY) != 0) { + mirrorApp.transparencyAttributes = (TransparencyAttributesRetained)value; + } + else if ((component & RENDERING) != 0) { + mirrorApp.renderingAttributes = (RenderingAttributesRetained)value; + } + else if ((component & POLYGON) != 0) { + mirrorApp.polygonAttributes = (PolygonAttributesRetained)value; + } + else if ((component & LINE) != 0) { + mirrorApp.lineAttributes = (LineAttributesRetained)value; + } + else if ((component & POINT) != 0) { + mirrorApp.pointAttributes = (PointAttributesRetained)value; + } + + } + + void setLive(boolean backgroundGroup, int refCount) { + // System.err.println("AppearceRetained.setLive()"); + doSetLive(backgroundGroup, refCount); + markAsLive(); + } + + /** + * This method calls the setLive method of all appearance bundle + * objects. + */ + void doSetLive(boolean backgroundGroup, int refCount) { + // System.err.println("AppearceRetained.doSetLive()"); + + if (material != null) { + + material.setLive(backgroundGroup, refCount); + } + + if (texture != null) { + + texture.setLive(backgroundGroup, refCount); + } + + if (texCoordGeneration != null) { + + texCoordGeneration.setLive(backgroundGroup, refCount); + } + + if (textureAttributes != null) { + + textureAttributes.setLive(backgroundGroup, refCount); + } + + if (texUnitState != null) { + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null) + texUnitState[i].setLive(backgroundGroup, refCount); + } + } + + + if (coloringAttributes != null) { + coloringAttributes.setLive(backgroundGroup, refCount); + } + + if (transparencyAttributes != null) { + transparencyAttributes.setLive(backgroundGroup, refCount); + } + + if (renderingAttributes != null) { + renderingAttributes.setLive(backgroundGroup, refCount); + } + + if (polygonAttributes != null) { + polygonAttributes.setLive(backgroundGroup, refCount); + } + + if (lineAttributes != null) { + lineAttributes.setLive(backgroundGroup, refCount); + } + + if (pointAttributes != null) { + pointAttributes.setLive(backgroundGroup, refCount); + } + + + // Increment the reference count and initialize the appearance + // mirror object + super.doSetLive(backgroundGroup, refCount); + } + + /** + * This method calls the clearLive method of all appearance bundle + * objects. + */ + void clearLive(int refCount) { + super.clearLive(refCount); + + if (texture != null) { + texture.clearLive(refCount); + } + + if (texCoordGeneration != null) { + texCoordGeneration.clearLive(refCount); + } + + if (textureAttributes != null) { + textureAttributes.clearLive(refCount); + } + + if (texUnitState != null) { + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null) + texUnitState[i].clearLive(refCount); + } + } + + if (coloringAttributes != null) { + coloringAttributes.clearLive(refCount); + } + + if (transparencyAttributes != null) { + transparencyAttributes.clearLive(refCount); + } + + if (renderingAttributes != null) { + renderingAttributes.clearLive(refCount); + } + + if (polygonAttributes != null) { + polygonAttributes.clearLive(refCount); + } + + if (lineAttributes != null) { + lineAttributes.clearLive(refCount); + } + + if (pointAttributes != null) { + pointAttributes.clearLive(refCount); + } + + if (material != null) { + material.clearLive(refCount); + } + } + + + boolean isStatic() { + boolean flag; + + flag = (source.capabilityBitsEmpty() && + ((texture == null) || + texture.source.capabilityBitsEmpty()) && + ((texCoordGeneration == null) || + texCoordGeneration.source.capabilityBitsEmpty()) && + ((textureAttributes == null) || + textureAttributes.source.capabilityBitsEmpty()) && + ((coloringAttributes == null) || + coloringAttributes.source.capabilityBitsEmpty()) && + ((transparencyAttributes == null) || + transparencyAttributes.source.capabilityBitsEmpty()) && + ((renderingAttributes == null) || + renderingAttributes.source.capabilityBitsEmpty()) && + ((polygonAttributes == null) || + polygonAttributes.source.capabilityBitsEmpty()) && + ((lineAttributes == null) || + lineAttributes.source.capabilityBitsEmpty()) && + ((pointAttributes == null) || + pointAttributes.source.capabilityBitsEmpty()) && + ((material == null) || + material.source.capabilityBitsEmpty())); + + if (!flag) + return flag; + + if (texUnitState != null) { + for (int i = 0; i < texUnitState.length && flag; i++) { + if (texUnitState[i] != null) { + flag = flag && texUnitState[i].isStatic(); + } + } + } + + return flag; + } + + // Issue 209 - enable this method (was previously commented out) + // Simply pass along to the NodeComponents + void compile(CompileState compState) { + setCompiled(); + + if (texture != null) { + texture.compile(compState); + } + + if (texCoordGeneration != null) { + texCoordGeneration.compile(compState); + } + + if (textureAttributes != null) { + textureAttributes.compile(compState); + } + + if (texUnitState != null) { + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null) + texUnitState[i].compile(compState); + } + } + + if (coloringAttributes != null) { + coloringAttributes.compile(compState); + } + + if (transparencyAttributes != null) { + transparencyAttributes.compile(compState); + } + + if (renderingAttributes != null) { + renderingAttributes.compile(compState); + } + + if (polygonAttributes != null) { + polygonAttributes.compile(compState); + } + + if (lineAttributes != null) { + lineAttributes.compile(compState); + } + + if (pointAttributes != null) { + pointAttributes.compile(compState); + } + + if (material != null) { + material.compile(compState); + } + } + + /** + * Returns the hashcode for this object. + * hashcode should be constant for object but same for two objects + * if .equals() is true. For an appearance (where .equals() is going + * to use the values in the appearance), the only way to have a + * constant value is for all appearances to have the same hashcode, so + * we use the hashcode of the class obj. + * + * Since hashCode is only used by AppearanceMap (at present) we may be + * able to improve efficency by calcing a hashCode from the values. + */ + public int hashCode() { + return getClass().hashCode(); + } + + public boolean equals(Object obj) { + return ((obj instanceof AppearanceRetained) && + equals((AppearanceRetained) obj)); + } + + boolean equals(AppearanceRetained app) { + boolean flag; + + flag = (app == this) || + ((app != null) && + (((material == app.material) || + ((material != null) && material.equivalent(app.material))) && + ((texture == app.texture) || + ((texture != null) && texture.equals(app.texture))) && + ((renderingAttributes == app.renderingAttributes) || + ((renderingAttributes != null) && + renderingAttributes.equivalent( + app.renderingAttributes))) && + ((polygonAttributes == app.polygonAttributes) || + ((polygonAttributes != null) && + polygonAttributes.equivalent(app.polygonAttributes))) && + ((texCoordGeneration == app.texCoordGeneration) || + ((texCoordGeneration != null) && + texCoordGeneration.equivalent(app.texCoordGeneration))) && + ((textureAttributes == app.textureAttributes) || + ((textureAttributes != null) && + textureAttributes.equivalent(app.textureAttributes))) && + ((coloringAttributes == app.coloringAttributes) || + ((coloringAttributes != null) && + coloringAttributes.equivalent(app.coloringAttributes))) && + ((transparencyAttributes == app.transparencyAttributes) || + ((transparencyAttributes != null) && + transparencyAttributes.equivalent( + app.transparencyAttributes))) && + ((lineAttributes == app.lineAttributes) || + ((lineAttributes != null) && + lineAttributes.equivalent(app.lineAttributes))) && + ((pointAttributes == app.pointAttributes) || + ((pointAttributes != null) && + pointAttributes.equivalent(app.pointAttributes))))); + + if (!flag) + return (flag); + + if (texUnitState == app.texUnitState) + return (flag); + + if (texUnitState == null || app.texUnitState == null || + texUnitState.length != app.texUnitState.length) + return (false); + + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] == app.texUnitState[i]) + continue; + + if (texUnitState[i] == null || app.texUnitState[i] == null || + !texUnitState[i].equals(app.texUnitState[i])) + return (false); + } + return (true); + } + + + + + synchronized void addAMirrorUser(Shape3DRetained shape) { + + super.addAMirrorUser(shape); + if (material != null) + material.addAMirrorUser(shape); + + if (texture != null) + texture.addAMirrorUser(shape); + if (texCoordGeneration != null) + texCoordGeneration.addAMirrorUser(shape); + if (textureAttributes != null) + textureAttributes.addAMirrorUser(shape); + + if (texUnitState != null) { + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null) + texUnitState[i].addAMirrorUser(shape); + } + } + + if (coloringAttributes != null) + coloringAttributes.addAMirrorUser(shape); + if (transparencyAttributes != null) + transparencyAttributes.addAMirrorUser(shape); + if (renderingAttributes != null) + renderingAttributes.addAMirrorUser(shape); + if (polygonAttributes != null) + polygonAttributes.addAMirrorUser(shape); + if (lineAttributes != null) + lineAttributes.addAMirrorUser(shape); + if (pointAttributes != null) + pointAttributes.addAMirrorUser(shape); + } + + synchronized void removeAMirrorUser(Shape3DRetained shape) { + super.removeAMirrorUser(shape); + if (material != null) + material.removeAMirrorUser(shape); + if (texture != null) + texture.removeAMirrorUser(shape); + if (texCoordGeneration != null) + texCoordGeneration.removeAMirrorUser(shape); + if (textureAttributes != null) + textureAttributes.removeAMirrorUser(shape); + + if (texUnitState != null) { + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null) + texUnitState[i].removeAMirrorUser(shape); + } + } + + if (coloringAttributes != null) + coloringAttributes.removeAMirrorUser(shape); + if (transparencyAttributes != null) + transparencyAttributes.removeAMirrorUser(shape); + if (renderingAttributes != null) + renderingAttributes.removeAMirrorUser(shape); + if (polygonAttributes != null) + polygonAttributes.removeAMirrorUser(shape); + if (lineAttributes != null) + lineAttributes.removeAMirrorUser(shape); + if (pointAttributes != null) + pointAttributes.removeAMirrorUser(shape); + } + + // 3rd argument used only when Rendering Attr comp changes + final void sendMessage(int attrMask, Object attr, boolean visible) { + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.APPEARANCE_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + + VirtualUniverse.mc.processMessage(createMessage); + + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i + * A Java3D application running on a particular machine could have one of + * several options available to it for playing the audio image created by the + * sound renderer. Perhaps the machine Java3D is executing on has more than + * one sound card (e.g., one that is a Wave Table Synthesis card and the other + * with accelerated sound spatialization hardware). Furthermore, suppose there + * are Java3D audio device drivers that execute Java3D audio methods on each of + * these specific cards. In such a case the application would have at least two + * audio device drivers through which the audio could be produced. For such a + * case the Java3D application must choose the audio device driver with which + * sound rendering is to be performed. Once this audio device is chosen, the + * application can additionally select the type of audio playback type the + * rendered sound image is to be output on. The playback device (headphones or + * speaker(s)) is physically connected to the port the selected device driver + * outputs to. + *

+ * AudioDevice Interface + *

+ *

    The selection of this device driver is done through methods in the + * PhysicalEnvironment object - see PhysicalEnvironment class. + * The application would query how many audio devices are available. For + * each device, the user can get the AudioDevice object that describes it + * and query its characteristics. Once a decision is made about which of + * the available audio devices to use for a PhysicalEnvironment, the + * particular device is set into this PhysicalEnvironment's fields. Each + * PhysicalEnvironment object may use only a single audio device. + *

    + * The AudioDevice object interface specifies an abstract input device + * that creators of Java3D class libraries would implement for a particular + * device. Java3D's uses several methods to interact with specific devices. + * Since all audio devices implement this consistent interface, the user + * could have a portable means of initialize, set particular audio device + * elements and query generic characteristics for any audio device. + *

    + *Initialization + *

      + * Each audio device driver must be initialized. + * The chosen device driver should be initialized before any Java3D + * Sound methods are executed because the implementation of the Sound + * methods, in general, are potentially device driver dependent.
    + *

    + * Audio Playback Type + *

      + * These methods set and retrieve the audio playback type used to output + * the analog audio from rendering Java3D Sound nodes. + * The audio playback type specifies that playback will be through: + * stereo headphones, a monaural speaker, or a pair of speakers. + * For the stereo speakers, it is assumed that the two output speakers are + * equally distant from the listener, both at same angle from the head + * axis (thus oriented symmetrically about the listener), and at the same + * elevation. + * The type of playback chosen affects the sound image generated. + * Cross-talk cancellation is applied to the audio image if playback over + * stereo speakers is selected.
    + *

    + * Distance to Speaker + *

      + * These methods set and retrieve the distance in meters from the center + * ear (the midpoint between the left and right ears) and one of the + * speakers in the listener's environment. For monaural speaker playback, + * a typical distance from the listener to the speaker in a workstation + * cabinet is 0.76 meters. For stereo speakers placed at the sides of the + * display, this might be 0.82 meters.
    + *

    + * Angular Offset of Speakers + *

      + * These methods set and retrieve the angle in radians between the vectors + * from the center ear to each of the speaker transducers and the vectors + * from the center ear parallel to the head coordinate's Z axis. Speakers + * placed at the sides of the computer display typically range between + * 0.28 to 0.35 radians (between 10 and 20 degrees).
    + *

    + * Device Driver Specific Data + *

      + * While the sound image created for final output to the playback system + * is either only mono or stereo (for this version of Java3D) most device + * driver implementations will mix the left and right image signals + * generated for each rendered sound source before outputting the final + * playback image. Each sound source will use N input channels of this + * internal mixer. Each implemented Java3D audio device driver will have + * its own limitations and driver-specific characteristics. These include + * channel availability and usage (during rendering). Methods for + * querying these device-driver specific characteristics are provided.
+ *

+ * Instantiating and Registering a New Device + *

+ *

    A browser or applications developer must instantiate whatever system- + * specific audio devices that he or she needs and that exist on the system. + * This device information typically exists in a site configuration file. + * The browser or application will instantiate the physical environment as + * requested by the end-user. + *

    + * The API for instantiating devices is site-specific, but it consists of + * a device object with a constructor and at least all of the methods + * specified in the AudioDevice interface. + *

    + * Once instantiated, the browser or application must register the device + * with the Java3D sound scheduler by associating this device with a + * PhysicalEnvironment. The setAudioDevice method introduces new devices + * to the Java3D environment and the allAudioDevices method produces an + * enumeration that allows examining all available devices within a Java3D + * environment. See PhysicalEnvironment class for more details.

+ *

+ * General Rules for calling AudioDevice methods: + * It is illegal for an application to call any non-query AudioDevice method + * if the AudioDevice is created then explicitly assigned to a + * PhysicalEnvironment using PhysicalEnvironment.setAudioDevice(); + * When either PhysicalEnvironment.setAudioDevice() is called - including + * when implicitly called by SimpleUniverse.getViewer().createAudioDevice() + * - the Core creates a SoundScheduler thread which makes calls to + * the AudioDevice. + *

+ * If an application creates it's own instance of an AudioDevice and + * initializes it directly, rather than using PhysicalEnvironment. + * setAudioDevice(), that application may make any AudioDevice3D methods calls + * without fear of the Java 3D Core also trying to control the AudioDevice. + * Under this condition it is safe to call AudioDevice non-query methods. + */ + +public interface AudioDevice { + + /** ************* + * + * Constants + * + ****************/ + /** + * Audio Playback Types + * + * Types of audio output device Java3D sound is played over: + * Headphones, MONO_SPEAKER, STEREO_SPEAKERS + */ + /** + * Choosing Headphones as the audio playback type + * specifies that the audio playback will be through stereo headphones. + */ + public static final int HEADPHONES = 0; + + /** + * Choosing a + * single near-field monoaural speaker + * as the audio playback type + * specifies that the audio playback will be through a single speaker + * some supplied distance away from the listener. + */ + public static final int MONO_SPEAKER = 1; + + /** + * Choosing a + * two near-field stereo speakers + * as the audio playback type + * specifies that the audio playback will be through stereo speakers + * some supplied distance away from, and at some given angle to + * the listener. + */ + public static final int STEREO_SPEAKERS = 2; + + /** + * Initialize the audio device. + * Exactly what occurs during initialization is implementation dependent. + * This method provides explicit control by the user over when this + * initialization occurs. + * Initialization must be initiated before any other AudioDevice + * methods are called. + * @return true if initialization was successful without errors + */ + public abstract boolean initialize(); + + /** + * Code to close the device and release resources. + * @return true if close of device was successful without errors + */ + public abstract boolean close(); + + /** + * Set Type of Audio Playback physical transducer(s) sound is output to. + * Valid types are HEADPHONES, MONO_SPEAKER, STEREO_SPEAKERS + * @param type audio playback type + */ + public abstract void setAudioPlaybackType(int type); + + /** + * Get Type of Audio Playback Output Device. + * @return audio playback type + */ + public abstract int getAudioPlaybackType(); + + /** + * Set Distance from interaural mid-point between Ears to a Speaker. + * @param distance from interaural midpoint between the ears to closest speaker + */ + public abstract void setCenterEarToSpeaker(float distance); + + /** + * Get Distance from interaural mid-point between Ears to a Speaker. + * @return distance from interaural midpoint between the ears to closest speaker + */ + public abstract float getCenterEarToSpeaker(); + + /** + * Set Angle Offset (in radians) To Speaker. + * @param angle in radians from head Z axis and vector from center ear to speaker + */ + public abstract void setAngleOffsetToSpeaker(float angle); + + /** + * Get Angle Offset (in radians) To Speaker. + * @return angle in radians from head Z axis and vector from center ear to speaker + */ + public abstract float getAngleOffsetToSpeaker(); + + /** + * Query total number of channels available for sound rendering + * for this audio device. This returns the maximum number of channels + * available for Java3D sound rendering for all sound sources. + * @return total number of channels that can be used for this audio device + */ + public abstract int getTotalChannels(); + + /** + * Query number of channels currently available for use. + * During rendering, when sound nodes are playing, this method returns the + * number of channels still available to Java3D for rendering additional + * sound nodes. + * @return total number of channels current available + */ + public abstract int getChannelsAvailable(); + + /** + * Query number of channels that are used, or would be used to render + * a particular sound node. This method returns the number of channels + * needed to render a particular Sound node. The return value is the same + * no matter if the Sound is currently active and enabled (being played) or + * is inactive. + * @return number of channels a particular Sound node is using or would used + * if enabled and activated (rendered). + */ + public abstract int getChannelsUsedForSound(Sound node); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AudioDevice3D.java b/j3d-core/src/classes/share/javax/media/j3d/AudioDevice3D.java new file mode 100644 index 0000000..4a01fb0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AudioDevice3D.java @@ -0,0 +1,534 @@ +/* + * $RCSfile: AudioDevice3D.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + + +/** + * The AudioDevice3D class defines a 3D audio device that is used to set + * sound and aural attributes. + *

+ * After the application chooses the AudioDevice3D that Java3D sound + * is to be rendered on, the Java 3D Sound Scheduler will call these + * methods for all active sounds to render them on the audio device. + *

+ * The intent is for this interface to be implemented by AudioDevice Driver + * developers using a software or hardware sound engine of their choice. + *

+ * Methods in this interface provide the Java3D Core a generic way to + * set and query the audio device the application has chosen audio rendering + * to be performed on. Methods in this interface include: + *

    + * Set up and clear the sound as a sample on the device. + *

    + * Start, stop, pause, unpause, mute, and unmute of sample on the device. + *

    + * Set parameters for each sample corresponding to the fields in the + * Sound node. + *

    + * Set the current active aural parameters that affect all positional samples. + *

+ *

+ * Sound Types + *

+ * Sound types match the Sound node classes defined for Java 3D core + * for BackgroundSound, PointSound, and ConeSound. The type of sound + * a sample is loaded as determines which methods affect it. + * + *

+ * Sound Data Types + *

+ * Samples can be processed as streaming or buffered data. + * Fully spatializing sound sources may require data to be buffered. + * + */ + +public interface AudioDevice3D extends AudioDevice { + + /** + * Specifies the sound type as background sound. + */ + public static final int BACKGROUND_SOUND = 1; + + /** + * Specifies the sound type as point sound. + */ + public static final int POINT_SOUND = 2; + + /** + * Specifies the sound type as cone sound. + */ + + public static final int CONE_SOUND = 3; + + /** + * Sound data specified as Streaming is not copied by the AudioDevice + * driver implementation. It is up to the application to ensure that + * this data is continuously accessible during sound rendering. + * Furthermore, full sound spatialization may not be possible, for + * all AudioDevice3D implementations on unbuffered sound data. + */ + public static final int STREAMING_AUDIO_DATA = 1; + /** + * Sound data specified as Buffered is copied by the AudioDevice + * driver implementation. + */ + public static final int BUFFERED_AUDIO_DATA = 2; + + + /** + * Accepts a reference to the current View. + * Passes reference to current View Object. The PhysicalEnvironment + * parameters (with playback type and speaker placement), and the + * PhysicalBody parameters (position/orientation of ears) + * can be obtained from this object, and the transformations to/from + * ViewPlatform coordinate (space the listener's head is in) and + * Virtual World coordinates (space sounds are in). + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param reference the current View + */ + public abstract void setView(View reference); + + /** + * Accepts a reference to the MediaContainer + * which contains a reference to sound data and information about the + * type of data it is. A "sound type" input parameter denotes if the + * Java 3D sound associated with this sample is a Background, Point, or + * Cone Sound node. + * Depending on the type of MediaContainer the sound data is and on the + * implementation of the AudioDevice used, sound data preparation could + * consist of opening, attaching, or loading sound data into the device. + * Unless the cached flag is true, this sound data should NOT be copied, + * if possible, into host or device memory. + *

+ * Once this preparation is complete for the sound sample, an AudioDevice + * specific index, used to reference the sample in future method calls, + * is returned. All the rest of the methods described below require + * this index as a parameter. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param soundType defines the type of Sound Node: Background, Point, and + * Cone + * @param soundData reference to MediaContainer sound data and cached flag + * @return device specific sample index used for referencing this sound + */ + public abstract int prepareSound(int soundType, MediaContainer soundData); + + /** + * Requests that the AudioDevice free all + * resources associated with sample with index id. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + */ + public abstract void clearSound(int index); + + /** + * Returns the duration in milliseconds of the sound sample, + * if this information can be determined. + * For non-cached + * streams, this method returns Sound.DURATION_UNKNOWN. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @return sound duration in milliseconds if this can be determined, + * otherwise (for non-cached streams) Sound.DURATION_UNKNOWN is returned + */ + public abstract long getSampleDuration(int index); + + /** + * + * Retrieves the number of channels (on executing audio device) that + * this sound is using, if it is playing, or is expected to use + * if it were begun to be played. This form of this method takes the + * sound's current state (including whether it is muted or unmuted) + * into account. + *

+ * For some AudioDevice3D implementations: + *

    + * Muted sound take channels up on the systems mixer (because they're + * rendered as samples playing with gain zero. + *

    + * A single sound could be rendered using multiple samples, each taking + * up mixer channels. + *

+ *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @return number of channels used by sound if it were playing + */ + public abstract int getNumberOfChannelsUsed(int index); + + /** + * + * Retrieves the number of channels (on executing audio device) that + * this sound is using, if it is playing, or is projected to use if + * it were to be started playing. Rather than using the actual current + * muted/unmuted state of the sound, the muted parameter is used in + * making the determination. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @param muted flag to use as the current muted state ignoring current + * mute state + * @return number of channels used by sound if it were playing + */ + public abstract int getNumberOfChannelsUsed(int index, boolean muted); + + /** + * Begins a sound playing on the AudioDevice. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @return flag denoting if sample was started; 1 if true, 0 if false + */ + public abstract int startSample(int index); + + /** + * Returns the system time of when the sound + * was last "started". Note that this start time will be as accurate + * as the AudioDevice implementation can make it - but that it is not + * guaranteed to be exact. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @return system time in milliseconds of the last time sound was started + */ + public abstract long getStartTime(int index); + + /** + * Stops the sound on the AudioDevice. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * associated with sound data to be played + * @return flag denoting if sample was stopped; 1 if true, 0 if false + */ + public abstract int stopSample(int index); + + /** + * Sets the overall gain scale factor applied to data associated with this + * source to increase or decrease its overall amplitude. + * The gain scale factor value passed into this method is the combined value + * of the Sound node's Initial Gain and the current AuralAttribute Gain + * scale factors. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @param scaleFactor amplitude (gain) scale factor + */ + public abstract void setSampleGain(int index, float scaleFactor); + + /** + * Sets a sound's loop count. + * A full description of this parameter and how it is used is in + * the documentation for Sound.setLoop. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @param count number of times sound is looped during play + * @see Sound#setLoop + */ + public abstract void setLoop(int index, int count); + + /** + * Passes a reference to the concatenated transformation to be applied to + * local sound position and direction parameters. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @param trans transformation matrix applied to local coordinate parameters + */ + public abstract void setVworldXfrm(int index, Transform3D trans); + + + /** + * Sets this sound's location (in Local coordinates) from specified + * Point. The form of the position parameter matches those of the PointSound + * method of the same name. + * A full description of this parameter and how it is used is in + * the documentation for PointSound class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @param position location of Point or Cone Sound in Virtual World + * coordinates + * @see PointSound#setPosition(float x, float y, float z) + * @see PointSound#setPosition(Point3f position) + */ + public abstract void setPosition(int index, Point3d position); + + /** + * Sets this sound's distance gain elliptical attenuation (not + * including filter cutoff frequency) by defining corresponding + * arrays containing distances from the sound's origin and gain + * scale factors applied to all active positional sounds. + * Gain scale factor is applied to sound based on the distance + * the listener + * is from sound source. + * These attenuation parameters are ignored for BackgroundSound nodes. + * The back attenuation parameter is ignored for PointSound nodes. + *

+ * The form of the attenuation parameters match that of the ConeSound method + * of the same name. + * A full description of this parameter and how it is used is in + * the documentation for ConeSound class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @param frontDistance defines an array of distance along positive axis + * through which ellipses pass + * @param frontAttenuationScaleFactor gain scale factors + * @param backDistance defines an array of distance along the negative axis + * through which ellipses pass + * @param backAttenuationScaleFactor gain scale factors + * @see ConeSound#setDistanceGain(float[] frontDistance, float[] frontGain, + * float[] backDistance, float[] backGain) + * @see ConeSound#setDistanceGain(Point2f[] frontAttenuation, + * Point2f[] backAttenuation) + */ + public abstract void setDistanceGain(int index, + double[] frontDistance, float[] frontAttenuationScaleFactor, + double[] backDistance, float[] backAttenuationScaleFactor); + /** + * Sets this sound's direction from the local coordinate vector provided. + * The form of the direction parameter matches that of the ConeSound method + * of the same name. + * A full description of this parameter and how it is used is in + * the documentation for the ConeSound class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @param direction the new direction vector in local coordinates + * @see ConeSound#setDirection(float x, float y, float z) + * @see ConeSound#setDirection(Vector3f direction) + */ + public abstract void setDirection(int index, Vector3d direction); + + /** + * Sets this sound's angular gain attenuation (including filter) + * by defining corresponding arrays containing angular offsets from + * the sound's axis, gain scale factors, and frequency cutoff applied + * to all active directional sounds. + * Gain scale factor is applied to sound based on the angle between the + * sound's axis and the ray from the sound source origin to the listener. + * The form of the attenuation parameter matches that of the ConeSound + * method of the same name. + * A full description of this parameter and how it is used is in + * the documentation for the ConeSound class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + * @param filterType describes type (if any) of filtering defined by attenuation + * @param angle array containing angular distances from sound axis + * @param attenuationScaleFactor array containing gain scale factor + * @param filterCutoff array containing filter cutoff frequencies. + * The filter values for each tuples can be set to Sound.NO_FILTER. + * @see ConeSound#setAngularAttenuation(float[] distance, float[] gain, + * float[] filter) + * @see ConeSound#setAngularAttenuation(Point3f[] attenuation) + * @see ConeSound#setAngularAttenuation(Point2f[] attenuation) + */ + public abstract void setAngularAttenuation(int index, int filterType, + double[] angle, float[] attenuationScaleFactor, float[] filterCutoff); + + /** + * Changes the speed of sound factor. + * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param rolloff atmospheric gain scale factor (changing speed of sound) + * @see AuralAttributes#setRolloff + */ + public abstract void setRolloff(float rolloff); + + /** + * Sets the Reflective Coefficient scale factor applied to distinct + * low-order early reflections of sound off the surfaces in the region + * defined by the current listening region. + *

+ * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param coefficient reflection/absorption factor applied to reverb + * @see AuralAttributes#setReflectionCoefficient + */ + public abstract void setReflectionCoefficient(float coefficient); + + /** + * Sets the reverberation delay time. + * In this form, while reverberation is being rendered, the parameter + * specifies the delay time between each order of late reflections + * explicitly given in milliseconds. + * A value for delay time of 0.0 disables + * reverberation. + *

+ * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param reverbDelay time between each order of late reflection + * @see AuralAttributes#setReverbDelay(float reverbDelay) + */ + public abstract void setReverbDelay(float reverbDelay); + + /** + * Sets the reverberation order of reflections. + * The reverbOrder parameter specifies the number of times reflections are added to + * reverberation being calculated. A value of -1 specifies an unbounded + * number of reverberations. + * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param reverbOrder number of times reflections added to reverb signal + * @see AuralAttributes#setReverbOrder + */ + public abstract void setReverbOrder(int reverbOrder); + + /** + * Sets Distance Filter corresponding arrays containing distances and + * frequency cutoff applied to all active positional sounds. + * Gain scale factor is applied to sound based on the distance the listener + * is from the sound source. + * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param filterType denotes the type of filtering to be applied + * @param distance array of offset distances from sound origin + * @param filterCutoff array of frequency cutoff + * @see AuralAttributes#setDistanceFilter(float[] distance, + * float[] frequencyCutoff) + * @see AuralAttributes#setDistanceFilter(Point2f[] attenuation) + */ + public abstract void setDistanceFilter(int filterType, + double[] distance, float[] filterCutoff); + + /** + * Specifies a scale factor applied to the frequency (or + * wavelength). A value less than 1.0 will result of slowing the playback + * rate of the sample. A value greater than 1.0 will increase the playback + * rate. + * This parameter is also used to expand or contract the usual + * frequency shift applied to the sound source due to Doppler effect + * calculations. Valid values are >= 0.0. + * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param frequencyScaleFactor factor applied to change of frequency + * @see AuralAttributes#setFrequencyScaleFactor + */ + public abstract void setFrequencyScaleFactor(float frequencyScaleFactor); + + /** + * Sets the Velocity scale factor applied during Doppler Effect calculation. + * This parameter specifies a scale factor applied to the velocity of sound + * relative to the listener's position and movement in relation to the sound's + * position and movement. This scale factor is multipled by the calculated + * velocity portion of the Doppler effect equation used during sound rendering. + * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param velocityScaleFactor applied to velocity of sound in relation + * to listener + * @see AuralAttributes#setVelocityScaleFactor + */ + public abstract void setVelocityScaleFactor(float velocityScaleFactor); + + /** + * Makes the sample 'play silently'. + * This method implements (as efficiently as possible) the muting + * of a playing sound sample. Ideally this is implemented by + * stopping a sample and freeing channel resources (rather than + * just setting the gain of the sample to zero). + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + */ + public abstract void muteSample(int index); + + /** + * Makes a silently playing sample audible. + * In the ideal, this restarts a muted sample by offset from the + * beginning by the number of milliseconds since the time the sample + * began playing (rather than setting gain to current non-zero gain). + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + */ + public abstract void unmuteSample(int index); + + /** + * Temporarily stops a cached sample from playing without resetting the + * sample's current pointer back to the beginning of the sound data so + * that it can be unpaused at a later time from the same location in the + * sample when the pause was initiated. Pausing a streaming, non-cached + * sound sample will be treated as a mute. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + */ + public abstract void pauseSample(int index); + + /** + * Restarts the paused sample from the location in the sample where + * paused. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + */ + public abstract void unpauseSample(int index); + + /** + * + * Explicitly updates a Sample. + * This method is called when a Sound is to be explicitly updated. + * It is only called when all a sounds parameters are known to have + * been passed to the audio device. In this way, an implementation + * can choose to perform lazy-evaluation of a sample, rather than + * updating the rendering state of the sample after every individual + * parameter changed. + * This method can be left as a null method if the implementor so chooses. + *

+ * This method should only be called by Java3D Core and NOT by any application. + * @param index device specific reference number to device driver sample + */ + public abstract void updateSample(int index); + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AudioDevice3DL2.java b/j3d-core/src/classes/share/javax/media/j3d/AudioDevice3DL2.java new file mode 100644 index 0000000..caa5c72 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AudioDevice3DL2.java @@ -0,0 +1,324 @@ +/* + * $RCSfile: AudioDevice3DL2.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * Extends AudioDevice3D to include reverb and environmental audio parameters + * that are defined in the MIDI Manufactures' Association Interactive Audio + * Special Interest Group (MMA IASIG) Level 2 Specification. + *

+ * The reverberation methods of AudioDevice3DL2 interface augment the + * reverberation methods defined in AudioDevice3D. + *

+ * The intent is for this interface to be implemented by AudioDevice Driver + * developers using a software or hardware sound engine of their choice. + *

+ * Methods in this interface provide the Java3D Core a generic way to + * set and query the audio device the application has chosen audio rendering + * to be performed on. + *

+ * The non-query methods of this interface should only be called by + * an application if the AudioDevice instance + * is not referenced by any PhysicalEnvironment + * explicitly with .setAudioDevice() or implicitly through Universe + * utility method in which case these are called by Core Java 3D + * Sound classes and Sound Scheduler thread(s). + *

+ * After the application chooses the AudioDevice3DL2 implementation + * that Java3D sound is to be rendered on, the Java 3D Sound Scheduler + * will call these methods for all active sounds to render them on the + * audio device. + *

+ * The AudioDevice3DL2 methods should not be call by any application if the + * audio device is associated with a Physical Environment and thus used by + * Java3D Core. + *

+ * Filtering for this extended AudioDevice interface is defined uniformly as + * a simple low-pass filter defined by a cutoff frequency. This will allow the + * same type of high-frequency attenuation that the MMA IASIG Level 2 filtering + * model with its 'reference frequency' and 'attenuation ratio' parameters + * affords. Use of a cutoff frequency is consistent with the filtering type + * for distance and angular attenuation for ConeSound and AuralAttributes. + * The filter methods will likely be overloaded in some future extension of this + * interface. + * + * @see Sound + * @see AuralAttributes + * @see AudioDevice3D + * @since Java 3D 1.3 + */ + +public interface AudioDevice3DL2 extends AudioDevice3D { + + /** + * Pause audio device engine (thread/server) without closing the device. + * Causes all cached sounds to be paused and all streaming sounds to be + * stopped. + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * This method will be implicitly called when View (associated with this + * device) is deactivated. + */ + public abstract void pause(); + + /** + * Resumes audio device engine (if previously paused) without reinitializing + * the device. + * Causes all paused cached sounds to be resumed and all streaming sounds + * restarted. + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * This method will be implicitly called when View (associated with this + * device) is actived. + */ + public abstract void resume(); + + /** + * Set overall gain control of all sounds playing on the audio device. + * Default: 1.0f = no attenuation. + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * @param scaleFactor scale factor applied to calculated amplitudes for + * all sounds playing on this device + */ + public abstract void setGain(float scaleFactor); + + /** + * Set scale factor applied to sample playback rate for a particular sound + * associated with the audio device. + * Changing the device sample rate affects both the pitch and speed. + * This scale factor is applied to ALL sound types. + * Changes (scales) the playback rate of a sound independent of + * Doppler rate changes. + * Default: 1.0f = original sample rate is unchanged + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * @param sampleId device specific reference number to device driver sample + * @param scaleFactor non-negative factor applied to calculated + * amplitudes for all sounds playing on this device + */ + public abstract void setRateScaleFactor(int sampleId, float scaleFactor); + + + /** + * Set late reflection (referred to as 'reverb') attenuation. + * This scale factor is applied to iterative, indistinguishable + * late reflections that constitute the tail of reverberated sound in + * the aural environment. + * This parameter, along with the early reflection coefficient, defines + * the reflective/absorptive characteristic of the surfaces in the + * current listening region. + * A coefficient value of 0 disables reverberation. + * Valid values of parameters range from 0.0 to 1.0. + * Default: 0.0f. + *

+ * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * @param coefficient late reflection attenuation factor + * @see AuralAttributes#setReverbCoefficient + */ + public abstract void setReverbCoefficient(float coefficient); + + + /** + * Sets the early reflection delay time. + * In this form, the parameter specifies the delay time between each order + * of reflection (while reverberation is being rendered) explicitly given + * in milliseconds. + * Valid values are non-negative floats. + * There may be limitations imposed by the device on how small or large this + * value can be made. + * A value of 0.0 would result in early reflections being added as soon as + * possible after the sound begins. + * Default = 20.0 milliseconds. + *

+ * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * @param reflectionDelay time between each order of early reflection + * @see AuralAttributes#setReflectionDelay + */ + public abstract void setReflectionDelay(float reflectionDelay); + + /** + * Set reverb decay time. + * Defines the reverberation decay curve. + * Default: 1000.0 milliseconds. + *

+ * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * @param time decay time in milliseconds + * @see AuralAttributes#setDecayTime + */ + public abstract void setDecayTime(float time); + + /** + * Set reverb decay filter. + * This provides for frequencies above the given cutoff frequency to be + * attenuated during reverb decay at a different rate than frequencies + * below this value. Thus, defining a different reverb decay curve for + * frequencies above the cutoff value. + * Default: 1.0 decay is uniform for all frequencies. + *

+ * There is no corresponding Core AuralAttributes method at this time. + * Until high frequency attenuation is supported by new Core API, + * this will be set by the Core with the value 1.0. + * It is highly recommended that this method should NOT be + * called by any application if the audio device is associated with + * a Physical Environment used by Java3D Core. + * @param frequencyCutoff value of frequencies in Hertz above which a + * low-pass filter is applied. + * @see AuralAttributes#setDecayFilter + */ + public abstract void setDecayFilter(float frequencyCutoff); + + /** + * Set reverb diffusion. + * This defines the echo dispersement (also referred to as 'echo density'). + * The value of this reverb parameter is expressed as a percent of the + * audio device's minimum-to-maximum values. + * Default: 1.0f - maximum diffusion on device. + *

+ * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * @param diffusion percentage expressed within the range of 0.0 and 1.0 + * @see AuralAttributes#setDiffusion + */ + public abstract void setDiffusion(float diffusion); + + /** + * Set reverb density. + * This defines the modal density (also referred to as 'spectral + * coloration'). + * The value of this parameter is expressed as a percent of the audio + * device's minimum-to-maximum values for this reverb parameter. + * Default: 1.0f - maximum density on device. + *

+ * A full description of this parameter and how it is used is in + * the documentation for the AuralAttributes class. + *

+ * This method should NOT be called by any application if the audio device + * is associated with a Physical Environment used by Java3D Core. + * @param density reverb density expressed as a percentage, + * within the range of 0.0 and 1.0 + * @see AuralAttributes#setDensity + */ + public abstract void setDensity(float density); + + + /** + * Set the obstruction gain control. This method allows for attenuating + * sound waves traveling between the sound source and the listener + * obstructed by objects. Direct sound signals/waves for obstructed sound + * source are attenuated but not indirect (reflected) waves. + * Default: 1.0 - gain is not attenuated; obstruction is not occurring. + *

+ * There is no corresponding Core AuralAttributes method at this time. + * Even so, this method should NOT be called by any application if the + * audio device is associated with a Physical Environment used by Java3D + * Core. + * @param sampleId device specific reference number to device driver sample + * @param scaleFactor non-negative factor applied to direct sound gain + */ + public abstract void setObstructionGain(int sampleId, float scaleFactor); + + /** + * Set the obstruction filter control. + * This provides for frequencies above the given cutoff frequency + * to be attenuated, during while the gain of an obstruction signal + * is being calculated, at a different rate than frequencies + * below this value. + * Default: 1.0 - filtering is uniform for all frequencies. + *

+ * There is no corresponding Core AuralAttributes method at this time. + * Until high frequency attenuation is supported by new Core API + * this will be set by the Core with the value 1.0. + * It is highly recommended that this method should NOT be + * called by any application if the audio device is associated with + * a Physical Environment used by Java3D Core. + * @param frequencyCutoff value of frequencies in Hertz above which a + * low-pass filter is applied. + */ + + public abstract void setObstructionFilter(int sampleId, float frequencyCutoff); + + /** + * Set the occlusion gain control. This method allows for attenuating + * sound waves traveling between the sound source and the listener + * occluded by objects. Both direct and indirect sound signals/waves + * for occluded sound sources are attenuated. + * Default: 1.0 - gain is not attenuated; occlusion is not occurring. + *

+ * There is no corresponding Core AuralAttributes method at this time. + * Even so, this method should NOT be called by any application if the + * audio device is associated with a Physical Environment used by Java3D + * Core. + * @param sampleId device specific reference number to device driver sample + * @param scaleFactor non-negative factor applied to direct sound gain + */ + public abstract void setOcclusionGain(int sampleId, float scaleFactor); + + /** + * Set the occlusion filter control. + * This provides for frequencies above the given cutoff frequency + * to be attenuated, during while the gain of an occluded signal + * is being calculated, at a different rate than frequencies below + * this value. + * Default: 1.0 - filtering is uniform for all frequencies. + *

+ * There is no corresponding Core AuralAttributes method at this time. + * Until high frequency attenuation is supported by new Core API + * this will be set by the Core with the value 1.0. + * It is highly recommended that this method should NOT be + * called by any application if the audio device is associated with + * a Physical Environment used by Java3D Core. + * @param frequencyCutoff value of frequencies in Hertz above which a + * low-pass filter is applied. + */ + public abstract void setOcclusionFilter(int sampleId, float frequencyCutoff); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AudioDeviceEnumerator.java b/j3d-core/src/classes/share/javax/media/j3d/AudioDeviceEnumerator.java new file mode 100644 index 0000000..ed8fb66 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AudioDeviceEnumerator.java @@ -0,0 +1,86 @@ +/* + * $RCSfile: AudioDeviceEnumerator.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * The class that enumerates all AudioDevices defined in the environment + * + * An AudioDeviceEnumerator generates the audio devices defined with the + * execution environment of the currently running Java 3D application. + */ + +class AudioDeviceEnumerator implements Enumeration { + + boolean endOfList; // NOTE: list length always equals one or zero + AudioDevice device; + + AudioDeviceEnumerator(PhysicalEnvironment physicalEnvironment) { + device = physicalEnvironment.getAudioDevice(); + if(device == null) + endOfList = true; + else + endOfList = false; + } + + void reset() { + if(device != null) + endOfList = false; + } + + + /** + * Query that tells whether the enumerator has more elements + * @return true if the enumerator has more elements, false otherwise + */ + public boolean hasMoreElements() { + if(endOfList == false) + return true; + else + return false; + } + + /** + * Return the next element in the enumerators + * @return the next element in this enumerator + */ + public Object nextElement() { + if (this.hasMoreElements()) { + endOfList = true; + return ((Object) device); + } else { + throw new NoSuchElementException(J3dI18N.getString("AudioDeviceEnumerator0")); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AuralAttributes.java b/j3d-core/src/classes/share/javax/media/j3d/AuralAttributes.java new file mode 100644 index 0000000..02d82b2 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AuralAttributes.java @@ -0,0 +1,1309 @@ +/* + * $RCSfile: AuralAttributes.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Point2f; + +/** + * The AuralAttributes object is a component object of a Soundscape node that + * defines environmental audio parameters that affect sound rendering. These + * attributes include gain scale factor, atmospheric rolloff, and parameters + * controlling reverberation, distance frequency filtering, and velocity-based + * Doppler effect. + *

+ * Attribute Gain + *

    + * Scale factor applied to all sound's amplitude active within this region. + * This factor attenuates both direct and reflected/reverbered amplitudes. + * Valid values are >= 0.0 + *
+ *

+ * Attribute Gain Rolloff + *

    + * Rolloff scale factor is used to model atmospheric changes from normal + * speed of sound. The base value, 0.344 meters/millisecond is used + * to approximate the speed of sound through air at room temperature, + * is multipled by this scale factor whenever the speed of sound is + * applied during spatialization calculations. + * Valid values are >= 0.0. Values > 1.0 increase the speed of sound, + * while values < 1.0 decrease its speed. A value of zero makes sound + * silent (but it continues to play). + *
+ *

+ * Auralization

+ *

    + * Auralization is the environmental modeling of sound iteratively + * reflecting off the surfaces of the bounded region the listener is in. + * Auralization components include + * early, distinct, low-order reflections and later, dense, + * higher-order reflections referred to as reverberation. + * These reflections are attenuated relative to the direct, unreflected + * sound. The difference in gain between direct and reflected sound + * gives the listener a sense of the surface material and + * the relative distance of the sound. + * The delay between the start of the direct sound and start of + * reverberation (as detected by the listener), + * as well as the length of time reverberation is audible as it + * exponentially decays, give the listener a sense of the size of the + * listening space. + *

    + * In Java3D's model for auralization there are several parameters + * that approximate sound reflection and reverberation for a particular + * listening space: + *

      Reflection Coefficient
        Gain attenuation of the initial + * reflections across all frequencies.
    + *
      (Early) Reflection Delay
        The time it takes for the first + * low-order reflected sound to reach the listener.
    + *
      Reverb Coefficient
        Gain attenuation of the late reflections + * (referred to as 'reverb') across all frequencies.
    + *
      Reverb Delay
        The time it takes for reverbered sound + * to reach the listener.
    + *
      Decay Time
        Describes the reverb decay curve by defining the + * length of time reverb takes to decay to effective zero. + *
    + *
      Decay Filter
        High-frequencies of the late reverberation + * can be attenuated at a different rate.
    + *
      Density
        Modal density (spectral coloration) of + * reverberation.
    + *
      Diffusion
        Echo dispersement of reverberation.
    + *
      Reverb Bounds
        Approximates the volume of the listening space. + * If specified, it defines the reverberation delay.
    + *
      Reverb Order
        Optionally limits the amount of times during + * reverb calculation that a sound is recursively reflected off the + * bounding region.
    + *

    + * Reflection Coefficient + *

      + * The reflection coefficient is an amplitude scale factor used to + * approximate the average reflective or absorptive characteristics + * for early reflections + * of the composite surfaces in the region the listener is in. + * This scale factor is applied to the sound's amplitude regardless of the + * sound's position. + * The range of valid values is 0.0 to 1.0. + * A value of 1.0 denotes that reflections are unattenuated - + * the amplitude of reflected sound waves are not decreased. + * A value of 0.0 represents full absorption of reflections + * by the surfaces in the listening space (no reflections occur + * thus reverberation is disabled). + *
    + *

    + * Reflection Delay + *

      + * The early reflection delay time (in milliseconds) can be explicitly + * set. Well-defined values are floats > 0.0. + * A value of 0.0 results in reverberation being added as soon as + * possible after the sound begins. + *
    + *

    + * Reverberation Coefficient + *

      + * The reverb coefficient is an amplitude scale factor used to + * approximate the average reflective or absorptive characteristics + * of late reflections. + * A value of 0.0 represents full absorption of reflections + * by the surfaces in the listening space (no reflections occur + * thus reverberation is disabled). + *
    + *

    + * Reverberation Delay + *

      + * The reverb delay time (in milliseconds) is set either explicitly, + * or implicitly by supplying a reverb bounds volume (from which the + * delay time can be calculated). Well-defined values are floats > 0.0. + * A value of 0.0 results in reverberation being added as soon as + * possible after the sound begins. Reverb delay, as calculated from non- + * null reverb bounds, takes precedence over explicitly set delay time. + *
    + *

    + * Reverberation Bounds + *

      + * The reverb bounding region defines the overall size of space + * that reverberation is calculated for. + * This optional bounds does not have to be the same as the application + * region of the Soundscape node referencing this AuralAttributes object. + * If this bounding region is specified then reverb decay and delay are + * internally calculated from this bounds. + *
    + *

    + * Reverberation Order + *

      + * The reverb order is a hint that can be used during reverberation + * to limit the number of late reflections required in calculation of + * reverb decay. + * All positive values can be interpreted during reverb rendering + * as the maximum order of reflections to be calculated. + * A non-positive value signifies that no limit is placed on the order of + * reflections calculated during reverberation rendering. + * In the case where reverb order is not limited, reverb decay is defined + * strictly by the Reverberation Decay Time parameter. + *
    + *

    + * Decay Time + *

      + * The reverberation decay time explicitly defines the length of time in + * milliseconds it takes for the amplitude of late reflections to + * exponentally decrease to effective zero. + * In the case where reverb delay is set non-positive + * the renderer will perform the shortest reverberation decay + * possible. + * If ReverbOrder is set, this parameter is clamped by the reverb + * time calculated as time = reverb Delay * reverb Order. + * If ReverbOrder is 0, the decay time parameter is not clamped. + *
    + *

    + * Decay Filter + *

      + * The reverberation decay filter defines how frequencies above a given + * value are attenuated by the listening space. This allows for modelling + * materials on surfaces that absorb high frequencies at a faster rate + * than low frequencies. + *
    + *

    + * Reverberation Diffusion + *

      + * The reverberation diffusion explicitly defines echo dispersement + * (sometimes refered to as echo density). The value for diffusion + * is proportional to the number of echos per second heard in late + * reverberation, especially noticable at the tail of the reverberation + * decay. The greater the diffusion the more 'natural' the reverberation + * decay sounds. Reducing diffusion makes the decay sound hollow as + * produced in a small highly reflecive space (such as a bathroom). + *
    + *

    + * Reverberation Density + *

      + * The reverberation density explicitly defines modal reverb density + * The value for this modal density is proportional to the number of + * resonances heard in late reverberation perceived as spectral + * coloration. The greater the density, the smoother, less grainy the + * later reverberation decay. + *
    + *
+ *

+ * Distance Filter + *

    + * This parameter specifies a (distance, filter) attenuation pairs array. + * If this is not set, no distance filtering is performed (equivalent to + * using a distance filter of Sound.NO_FILTER for all distances). Currently, + * this filter is a low-pass cutoff frequency. This array of pairs defines + * a piece-wise linear slope for range of values. This attenuation array is + * similar to the PointSound node's distanceAttenuation pair array, except + * paired with distances in this list are frequency values. Using these + * pairs, distance-based low-pass frequency filtering can be applied during + * sound rendering. Distances, specified in the local coordinate system in + * meters, must be > 0. Frequencies (in Hz) must be > 0. + *

    + * If the distance from the listener to the sound source is less than the + * first distance in the array, the first filter is applied to the sound + * source. This creates a spherical region around the listener within + * which a sound is uniformly attenuated by the first filter in the array. + * If the distance from the listener to the sound source is greater than + * the last distance in the array, the last filter is applied to the sound + * source. + *

    + * Distance elements in these array of pairs is a monotonically-increasing + * set of floating point numbers measured from the location of the sound + * source. FrequencyCutoff elements in this list of pairs can be any + * positive float. While for most applications this list of values will + * usually be monotonically-decreasing, they do not have to be. + *

    + * The getDistanceFilterLength method returns the length of the distance filter + * arrays. Arrays passed into getDistanceFilter methods should all be at + * least this size.

+ *

+ * Doppler Effect Model + *

    + * Doppler effect can be used to create a greater sense of movement of + * sound sources, and can help reduce front-back localization errors. + * The frequency of sound waves emanating from the source are raised or + * lowered based on the speed of the source in relation to the listener, + * and several AuralAttribute parameters. + *

    + * The FrequencyScaleFactor can be used to increase or reduce the change + * of frequency associated with normal Doppler calculation, or to shift + * the pitch of the sound directly if Doppler effect is disabled. + * Values must be > zero for sounds to be heard. If the value is zero, + * sounds affected by this AuralAttribute object are paused. + *

    + * To simulate Doppler effect, the relative velocity (change in + * distance in the local coordinate system between the sound source and + * the listener over time, in meters per second) is calculated. This + * calculated velocity is multipled by the given VelocityScaleFactor. + * Values must be >= zero. If is a scale factor value of zero is given, + * Doppler effect is not calculated or applied to sound.

+ */ +public class AuralAttributes extends NodeComponent { + + /** + * + * Constants + * + * These flags, when enabled using the setCapability method, allow an + * application to invoke methods that read or write its parameters. + * + */ + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's attribute gain scale factor information. + */ + public static final int + ALLOW_ATTRIBUTE_GAIN_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_ATTRIBUTE_GAIN_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's attribute gain scale factor information. + */ + public static final int + ALLOW_ATTRIBUTE_GAIN_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_ATTRIBUTE_GAIN_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's atmospheric rolloff. + */ + public static final int + ALLOW_ROLLOFF_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_ROLLOFF_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's atmospheric rolloff. + */ + public static final int + ALLOW_ROLLOFF_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_ROLLOFF_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reflection coefficient. + */ + public static final int + ALLOW_REFLECTION_COEFFICIENT_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REFLECTION_COEFFICIENT_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reflection coefficient. + */ + public static final int + ALLOW_REFLECTION_COEFFICIENT_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REFLECTION_COEFFICIENT_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reflection delay information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_REFLECTION_DELAY_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REFLECTION_DELAY_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reflection delay information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_REFLECTION_DELAY_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REFLECTION_DELAY_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reverb coefficient. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_REVERB_COEFFICIENT_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REVERB_COEFFICIENT_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reverb coefficient. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_REVERB_COEFFICIENT_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REVERB_COEFFICIENT_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reverberation delay information. + */ + public static final int + ALLOW_REVERB_DELAY_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REVERB_DELAY_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reverberation delay information. + */ + public static final int + ALLOW_REVERB_DELAY_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REVERB_DELAY_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reverb order (feedback loop) information. + */ + public static final int + ALLOW_REVERB_ORDER_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REVERB_ORDER_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reverb order (feedback loop) information. + */ + public static final int + ALLOW_REVERB_ORDER_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_REVERB_ORDER_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reverb decay time information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DECAY_TIME_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DECAY_TIME_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reverb decay time information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DECAY_TIME_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DECAY_TIME_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reverb decay filter information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DECAY_FILTER_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DECAY_FILTER_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reverb decay filter information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DECAY_FILTER_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DECAY_FILTER_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reverb diffusion information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DIFFUSION_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DIFFUSION_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reverb diffusion information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DIFFUSION_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DIFFUSION_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's reverb density information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DENSITY_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DENSITY_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's reverb density information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DENSITY_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DENSITY_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's frequency cutoff information. + */ + public static final int + ALLOW_DISTANCE_FILTER_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DISTANCE_FILTER_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's frequency cutoff information. + */ + public static final int + ALLOW_DISTANCE_FILTER_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_DISTANCE_FILTER_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's frequency scale factor information. + */ + public static final int + ALLOW_FREQUENCY_SCALE_FACTOR_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_FREQUENCY_SCALE_FACTOR_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's frequency scale factor information. + */ + public static final int + ALLOW_FREQUENCY_SCALE_FACTOR_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_FREQUENCY_SCALE_FACTOR_WRITE; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the reading of it's velocity scale factor information. + */ + public static final int + ALLOW_VELOCITY_SCALE_FACTOR_READ = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_VELOCITY_SCALE_FACTOR_READ; + + /** + * For AuralAttributes component objects, specifies that this object + * allows the writing of it's velocity scale factor information. + */ + public static final int + ALLOW_VELOCITY_SCALE_FACTOR_WRITE = CapabilityBits.AURAL_ATTRIBUTES_ALLOW_VELOCITY_SCALE_FACTOR_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_ATTRIBUTE_GAIN_READ, + ALLOW_DECAY_FILTER_READ, + ALLOW_DECAY_TIME_READ, + ALLOW_DENSITY_READ, + ALLOW_DIFFUSION_READ, + ALLOW_DISTANCE_FILTER_READ, + ALLOW_FREQUENCY_SCALE_FACTOR_READ, + ALLOW_REFLECTION_COEFFICIENT_READ, + ALLOW_REFLECTION_DELAY_READ, + ALLOW_REVERB_COEFFICIENT_READ, + ALLOW_REVERB_DELAY_READ, + ALLOW_REVERB_ORDER_READ, + ALLOW_ROLLOFF_READ, + ALLOW_VELOCITY_SCALE_FACTOR_READ + }; + + /** ***************** + * + * Constructors + * + * ******************/ + /** + * Constructs and initializes a new AuralAttributes object using default + * parameters. The following default values are used: + *
    + * attribute gain: 1.0
    + * rolloff: 1.0
    + * reflection coeff: 0.0
    + * reflection delay: 20.0
    + * reverb coeff: 1.0
    + * reverb delay: 40.0
    + * decay time: 1000.0
    + * decay filter: 5000.0<> + * diffusion: 1.0
    + * density: 1.0
    + * reverb bounds: null
    + * reverb order: 0
    + * distance filtering: null (no filtering performed)
    + * frequency scale factor: 1.0
    + * velocity scale factor: 0.0
    + *
+ */ + public AuralAttributes() { + // Just use default values + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a new AuralAttributes object using specified + * parameters including an array of Point2f for the distanceFilter. + * @param gain amplitude scale factor + * @param rolloff atmospheric (changing speed of sound) scale factor + * @param reflectionCoefficient reflective/absorptive factor applied to reflections + * @param reverbDelay delay time before start of reverberation + * @param reverbOrder limit to number of reflections added to reverb signal + * @param distanceFilter frequency cutoff + * @param frequencyScaleFactor applied to change of pitch + * @param velocityScaleFactor applied to velocity of sound in relation to listener + */ + public AuralAttributes(float gain, + float rolloff, + float reflectionCoefficient, + float reverbDelay, + int reverbOrder, + Point2f[] distanceFilter, + float frequencyScaleFactor, + float velocityScaleFactor) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((AuralAttributesRetained)this.retained).setAttributeGain(gain); + ((AuralAttributesRetained)this.retained).setRolloff(rolloff); + ((AuralAttributesRetained)this.retained).setReflectionCoefficient( + reflectionCoefficient); + ((AuralAttributesRetained)this.retained).setReverbDelay(reverbDelay); + ((AuralAttributesRetained)this.retained).setReverbOrder(reverbOrder); + ((AuralAttributesRetained)this.retained).setDistanceFilter( + distanceFilter); + ((AuralAttributesRetained)this.retained).setFrequencyScaleFactor( + frequencyScaleFactor); + ((AuralAttributesRetained)this.retained).setVelocityScaleFactor( + velocityScaleFactor); + } + /** + * Constructs and initializes a new AuralAttributes object using specified + * parameters with separate float arrays for components of distanceFilter. + * @param gain amplitude scale factor + * @param rolloff atmospheric (changing speed of sound) scale factor + * @param reflectionCoefficient reflection/absorption factor applied to reflections + * @param reverbDelay delay time before start of reverberation + * @param reverbOrder limit to number of reflections added to reverb signal + * @param distance filter frequency cutoff distances + * @param frequencyCutoff distance filter frequency cutoff + * @param frequencyScaleFactor applied to velocity/wave-length + * @param velocityScaleFactor applied to velocity of sound in relation to listener + */ + public AuralAttributes(float gain, + float rolloff, + float reflectionCoefficient, + float reverbDelay, + int reverbOrder, + float[] distance, + float[] frequencyCutoff, + float frequencyScaleFactor, + float velocityScaleFactor) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((AuralAttributesRetained)this.retained).setAttributeGain(gain); + ((AuralAttributesRetained)this.retained).setRolloff(rolloff); + ((AuralAttributesRetained)this.retained).setReflectionCoefficient( + reflectionCoefficient); + ((AuralAttributesRetained)this.retained).setReverbDelay(reverbDelay); + ((AuralAttributesRetained)this.retained).setReverbOrder(reverbOrder); + ((AuralAttributesRetained)this.retained).setDistanceFilter(distance, + frequencyCutoff); + ((AuralAttributesRetained)this.retained).setFrequencyScaleFactor( + frequencyScaleFactor); + ((AuralAttributesRetained)this.retained).setVelocityScaleFactor( + velocityScaleFactor); + } + + /** + * Constructs and initializes a new AuralAttributes object using specified + * parameters with separate float arrays for components of distanceFilter + * and full reverb parameters. + * @param gain amplitude scale factor + * @param rolloff atmospheric (changing speed of sound) scale factor + * @param reflectionCoefficient factor applied to early reflections + * @param reflectionDelay delay time before start of early reflections + * @param reverbCoefficient factor applied to late reflections + * @param reverbDelay delay time before start of late reverberation + * @param decayTime time (in milliseconds) reverb takes to decay to -60bD + * @param decayFilter reverb decay filter frequency cutoff + * @param diffusion percentage of echo dispersement between min and max + * @param density percentage of modal density between min and max + * @param distance filter frequency cutoff distances + * @param frequencyCutoff distance filter frequency cutoff + * @param frequencyScaleFactor applied to velocity/wave-length + * @param velocityScaleFactor applied to velocity of sound in relation to listener + * @since Java 3D 1.3 + */ + public AuralAttributes(float gain, + float rolloff, + float reflectionCoefficient, + float reflectionDelay, + float reverbCoefficient, + float reverbDelay, + float decayTime, + float decayFilter, + float diffusion, + float density, + float[] distance, + float[] frequencyCutoff, + float frequencyScaleFactor, + float velocityScaleFactor) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((AuralAttributesRetained)this.retained).setAttributeGain(gain); + ((AuralAttributesRetained)this.retained).setRolloff(rolloff); + ((AuralAttributesRetained)this.retained).setReflectionCoefficient( + reflectionCoefficient); + ((AuralAttributesRetained)this.retained).setReflectionDelay( + reflectionDelay); + ((AuralAttributesRetained)this.retained).setReverbCoefficient( + reverbCoefficient); + ((AuralAttributesRetained)this.retained).setReverbDelay( + reverbDelay); + ((AuralAttributesRetained)this.retained).setDecayTime(decayTime); + ((AuralAttributesRetained)this.retained).setDecayFilter(decayFilter); + ((AuralAttributesRetained)this.retained).setDiffusion(diffusion); + ((AuralAttributesRetained)this.retained).setDensity(density); + ((AuralAttributesRetained)this.retained).setDistanceFilter(distance, + frequencyCutoff); + ((AuralAttributesRetained)this.retained).setFrequencyScaleFactor( + frequencyScaleFactor); + ((AuralAttributesRetained)this.retained).setVelocityScaleFactor( + velocityScaleFactor); + } + + /** + * Creates the retained mode AuralAttributesRetained object that this + * component object will point to. + */ + void createRetained() { + this.retained = new AuralAttributesRetained(); + this.retained.setSource(this); + } + + /** **************************************** + * + * Attribute Gain + * + * ****************************************/ + /** + * Set Attribute Gain (amplitude) scale factor. + * @param gain scale factor applied to amplitude of direct and reflected sound + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAttributeGain(float gain) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTE_GAIN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes0")); + ((AuralAttributesRetained)this.retained).setAttributeGain(gain); + } + + /** + * Retrieve Attribute Gain (amplitude). + * @return gain amplitude scale factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getAttributeGain() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTE_GAIN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes1")); + return ((AuralAttributesRetained)this.retained).getAttributeGain(); + } + + /** + * Set Attribute Gain Rolloff. + * @param rolloff atmospheric gain scale factor (changing speed of sound) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setRolloff(float rolloff) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ROLLOFF_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes2")); + ((AuralAttributesRetained)this.retained).setRolloff(rolloff); + } + + /** + * Retrieve Attribute Gain Rolloff. + * @return rolloff atmospheric gain scale factor (changing speed of sound) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getRolloff() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ROLLOFF_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes3")); + return ((AuralAttributesRetained)this.retained).getRolloff(); + } + + /** + * Set Reflective Coefficient. + * Scales the amplitude of the early reflections of reverberated sounds + * @param coefficient reflection/absorption factor applied to reflections + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setReflectionCoefficient(float coefficient) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REFLECTION_COEFFICIENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes4")); + ((AuralAttributesRetained)this.retained).setReflectionCoefficient(coefficient); + } + + /** + * Retrieve Reflective Coefficient. + * @return reflection coeff reflection/absorption factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getReflectionCoefficient() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REFLECTION_COEFFICIENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes21")); + return ((AuralAttributesRetained)this.retained).getReflectionCoefficient(); + } + + /********************* + * + * Early Reflection Delay + * + ********************/ + /** + * Set early Refection Delay Time. + * In this form, the parameter specifies the time between the start of the + * direct, unreflected sound and the start of first order early reflections. + * In this method, this time is explicitly given in milliseconds. + * @param reflectionDelay delay time before start of reverberation + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setReflectionDelay(float reflectionDelay) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REFLECTION_DELAY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes22")); + ((AuralAttributesRetained)this.retained).setReflectionDelay(reflectionDelay); + } + + /** + * Retrieve Reflection Delay Time. + * @return reflection delay time + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public float getReflectionDelay() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REFLECTION_DELAY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes23")); + return ((AuralAttributesRetained)this.retained).getReflectionDelay(); + } + + /** ****************** + * + * Reverb Coefficient + * + ********************/ + /** + * Set Reverb Coefficient. + * Scale the amplitude of the late reflections including the decaying tail + * of reverberated sound. + * @param coefficient reflective/absorptive factor applied to late reflections + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setReverbCoefficient(float coefficient) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REVERB_COEFFICIENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes24")); + ((AuralAttributesRetained)this.retained).setReverbCoefficient(coefficient); + } + + /** + * Retrieve Reverb Coefficient. + * @return late reflection coeff. reflection/absorption factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public float getReverbCoefficient() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REVERB_COEFFICIENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes25")); + return ((AuralAttributesRetained)this.retained).getReverbCoefficient(); + } + + /********************* + * + * Reverberation Delay + * + ********************/ + /** + * Set Reverberation Delay Time. + * In this form, the parameter specifies the time between the start of the + * direct, unreflected sound and the start of reverberation. In this + * method, this time is explicitly given in milliseconds. + * @param reverbDelay delay time before start of reverberation + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setReverbDelay(float reverbDelay) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REVERB_DELAY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes5")); + ((AuralAttributesRetained)this.retained).setReverbDelay(reverbDelay); + } + + /** + * Retrieve Reverberation Delay Time. + * @return reverb delay time + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getReverbDelay() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REVERB_DELAY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes7")); + return ((AuralAttributesRetained)this.retained).getReverbDelay(); + } + + /** ****************** + * + * Decay Time + * + ********************/ + /** + * Set Decay Time + * Length of time from the start of late reflections reverberation volume + * takes to decay to effective zero (-60 dB of initial signal amplitude). + * @param decayTime of late reflections (reverb) in milliseconds + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setDecayTime(float decayTime) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DECAY_TIME_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes28")); + ((AuralAttributesRetained)this.retained).setDecayTime(decayTime); + } + + /** + * Retrieve Decay Time. + * @return reverb decay time + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public float getDecayTime() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DECAY_TIME_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes29")); + return ((AuralAttributesRetained)this.retained).getDecayTime(); + } + + /** ****************** + * + * Decay Filter + * + ********************/ + /** + * Set Decay Filter + * In this form, reverberation decay filtering is defined as a low-pass + * filter, starting at the given reference frequency. This allows for + * higher frequencies to be attenuated at a different (typically faster) + * rate than lower frequencies. + * @param frequencyCutoff of reverberation decay low-pass filter + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setDecayFilter(float frequencyCutoff) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DECAY_FILTER_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes30")); + ((AuralAttributesRetained)this.retained).setDecayFilter(frequencyCutoff); + } + + /** + * Retrieve Decay Filter. + * @return reverb decay filter cutoff frequency + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public float getDecayFilter() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DECAY_FILTER_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes31")); + return ((AuralAttributesRetained)this.retained).getDecayFilter(); + } + + /** ****************** + * + * Diffusion + * + ********************/ + /** + * Set Diffusion. + * Sets the echo dispersement of reverberation to an amount between + * the minimum (0.0) to the maximum (1.0) available. Changing this + * increases/decreases the 'smoothness' of reverb decay. + * @param ratio reverberation echo dispersement factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setDiffusion(float ratio) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DIFFUSION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes32")); + ((AuralAttributesRetained)this.retained).setDiffusion(ratio); + } + + /** + * Retrieve Diffusion. + * @return reverb diffusion ratio + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public float getDiffusion() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIFFUSION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes33")); + return ((AuralAttributesRetained)this.retained).getDiffusion(); + } + + /** ****************** + * + * Density + * + ********************/ + /** + * Set Density. + * Sets the density of reverberation to an amount between + * the minimum (0.0) to the maximum (1.0) available. Changing this + * effects the spectral coloration (timbre) of late reflections. + * @param ratio reverberation modal density factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setDensity(float ratio) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DENSITY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes34")); + ((AuralAttributesRetained)this.retained).setDensity(ratio); + } + + /** + * Retrieve Density. + * @return reverb density + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public float getDensity() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DENSITY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes35")); + return ((AuralAttributesRetained)this.retained).getDensity(); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setReverbBounds(Bounds) + */ + public void setReverbDelay(Bounds reverbVolume) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REVERB_DELAY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes5")); + ((AuralAttributesRetained)this.retained).setReverbBounds(reverbVolume); + } + + /** + * Set Reverberation Bounds volume. + * In this form, the reverberation bounds volume parameter is used to + * calculate the reverberation Delay and Decay times. Specification + * of a non-null bounding volume causes the explicit values given for + * Reverb Delay and Decay to be overridden by the implicit values + * calculated from these bounds. + * ALLOW_REVERB_DELAY_WRITE flag used setting capability of this method. + * @param reverbVolume the bounding region + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.2 + */ + public void setReverbBounds(Bounds reverbVolume) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REVERB_DELAY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes26")); + ((AuralAttributesRetained)this.retained).setReverbBounds(reverbVolume); + } + + /** + * Retrieve Reverberation Delay Bounds volume. + * @return reverb bounds volume that defines the Reverberation space and + * indirectly the delay/decay + * ALLOW_REVERB_DELAY_READ flag used setting capability of this method. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.2 + */ + public Bounds getReverbBounds() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REVERB_DELAY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes27")); + return ((AuralAttributesRetained)this.retained).getReverbBounds(); + } + + /** ******************* + * + * Reverberation Order + * + ********************/ + /** + * Set Reverberation Order + * This parameter limits the number of times reflections are added + * to the reverberation being rendered. + * A non-positive value specifies an unbounded number of reflections. + * @param reverbOrder limit to the number of times reflections added to reverb signal + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setReverbOrder(int reverbOrder) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REVERB_ORDER_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes8")); + ((AuralAttributesRetained)this.retained).setReverbOrder(reverbOrder); + } + + /** + * Retrieve Reverberation Order + * @return reverb order + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getReverbOrder() { + if (!this.getCapability(ALLOW_REVERB_ORDER_READ)) + if (isLiveOrCompiled()) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes9")); + return ((AuralAttributesRetained)this.retained).getReverbOrder(); + } + + /** + * Set Distance Filter using a single array containing distances and + * frequency cutoff as pairs of values as a single array of Point2f. + * @param attenuation array of pairs of distance and frequency cutoff + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDistanceFilter(Point2f[] attenuation) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DISTANCE_FILTER_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes10")); + ((AuralAttributesRetained)this.retained).setDistanceFilter(attenuation); + } + + /** + * Set Distance Filter using separate arrays for distances and frequency + * cutoff. The distance and frequencyCutoff arrays should be of the same + * length. If the frequencyCutoff array length is greater than the distance + * array length, the frequencyCutoff array elements beyond the length of + * the distance array are ignored. If the frequencyCutoff array is shorter + * than the distance array, the last frequencyCutoff array value is repeated + * to fill an array of length equal to distance array. + * @param distance array of float distance with corresponding cutoff values + * @param frequencyCutoff array of frequency cutoff values in Hertz + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDistanceFilter(float[] distance, + float[] frequencyCutoff) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DISTANCE_FILTER_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes10")); + ((AuralAttributesRetained)this.retained).setDistanceFilter( + distance, frequencyCutoff ); + } + + /** + * Retrieve Distance Filter array length. + * @return attenuation array length + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getDistanceFilterLength() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DISTANCE_FILTER_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes12")); + return (((AuralAttributesRetained)this.retained).getDistanceFilterLength()); + } + /** + * Retrieve Distance Filter as a single array containing distances + * and frequency cutoff. The distance filter is copied into + * the specified array. + * The array must be large enough to hold all of the points. + * The individual array elements must be allocated by the caller. + * @param attenuation array of pairs of distance and frequency cutoff values + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDistanceFilter(Point2f[] attenuation) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DISTANCE_FILTER_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes12")); + ((AuralAttributesRetained)this.retained).getDistanceFilter(attenuation); + } + + /** + * Retrieve Distance Filter in separate distance and frequency cutoff arrays. + * The arrays must be large enough to hold all of the distance + * and frequency cutoff values. + * @param distance array + * @param frequencyCutoff cutoff array + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDistanceFilter(float[] distance, + float[] frequencyCutoff) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DISTANCE_FILTER_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes12")); + ((AuralAttributesRetained)this.retained).getDistanceFilter( + distance, frequencyCutoff); + } + + /** + * This parameter specifies a scale factor applied to the frequency + * of sound during rendering playback. If the Doppler effect is + * disabled, this scale factor can be used to increase or + * decrease the original pitch of the sound. During rendering, + * this scale factor expands or contracts the usual frequency shift + * applied to the sound source due to Doppler calculations. + * Valid values are >= 0.0. + * A value of zero causes playing sounds to pause. + * @param frequencyScaleFactor factor applied to change of frequency + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setFrequencyScaleFactor(float frequencyScaleFactor) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_FREQUENCY_SCALE_FACTOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes15")); + ((AuralAttributesRetained)this.retained).setFrequencyScaleFactor( + frequencyScaleFactor); + } + + /** + * Retrieve Frequency Scale Factor. + * @return scaleFactor factor applied to change of frequency + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getFrequencyScaleFactor() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_FREQUENCY_SCALE_FACTOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes17")); + return ((AuralAttributesRetained)this.retained).getFrequencyScaleFactor(); + } + + /** ****************************** + * + * Velocity Scale Factor + * + *********************************/ + /** + * Set Velocity scale factor applied during Doppler Effect calculation. + * This parameter specifies a scale factor applied to the velocity of + * the sound relative to the listener's position and movement in relation + * to the sound's position and movement. This scale factor is multipled + * by the calculated velocity portion of the Doppler effect equation used + * during sound rendering. + * A value of zero disables Doppler calculations. + * @param velocityScaleFactor applied to velocity of sound in relation + * to listener + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setVelocityScaleFactor(float velocityScaleFactor) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VELOCITY_SCALE_FACTOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes19")); + ((AuralAttributesRetained)this.retained).setVelocityScaleFactor( + velocityScaleFactor); + } + + /** + * Retrieve Velocity Scale Factor used to calculate Doppler Effect. + * @return scale factor applied to Doppler velocity of sound + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getVelocityScaleFactor() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VELOCITY_SCALE_FACTOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("AuralAttributes20")); + return ((AuralAttributesRetained)this.retained).getVelocityScaleFactor(); + } + + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + AuralAttributes a = new AuralAttributes(); + a.duplicateNodeComponent(this, this.forceDuplicate); + return a; + } + + + /** + * Copies all AuralAttributes information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, + forceDuplicate); + + AuralAttributesRetained aural = (AuralAttributesRetained) originalNodeComponent.retained; + AuralAttributesRetained rt = (AuralAttributesRetained) retained; + + rt.setAttributeGain(aural.getAttributeGain()); + rt.setRolloff(aural.getRolloff()); + rt.setReflectionCoefficient(aural.getReflectionCoefficient()); + rt.setReverbDelay(aural.getReverbDelay()); + rt.setReverbOrder(aural.getReverbOrder()); + rt.setReverbBounds(aural.getReverbBounds()); + rt.setFrequencyScaleFactor(aural.getFrequencyScaleFactor()); + rt.setVelocityScaleFactor(aural.getVelocityScaleFactor()); + int len = aural.getDistanceFilterLength(); + float distance[] = new float[len]; + float frequencyCutoff[] = new float[len]; + aural.getDistanceFilter(distance, frequencyCutoff); + rt.setDistanceFilter(distance, frequencyCutoff); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/AuralAttributesRetained.java b/j3d-core/src/classes/share/javax/media/j3d/AuralAttributesRetained.java new file mode 100644 index 0000000..5d038c0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/AuralAttributesRetained.java @@ -0,0 +1,673 @@ +/* + * $RCSfile: AuralAttributesRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Hashtable; +import javax.vecmath.Point2f; + +/** + * The AuralAttributesRetained object defines all rendering state that can + * be set as a component object of a retained Soundscape node. + */ +class AuralAttributesRetained extends NodeComponentRetained { + + /** + * Gain Scale Factor applied to source with this attribute + */ + float attributeGain = 1.0f; // Valid values are >= 0.0. + + /** + * Atmospheric Rolloff - speed of sound - coeff + * Normal gain attenuation based on distance of sound from + * listener is scaled by a rolloff factor, which can increase + * or decrease the usual inverse-distance-square value. + */ + float rolloff = 1.0f; // Valid values are >= 0.0 + static final float SPEED_OF_SOUND = 0.344f; // in meters/milliseconds + + /* + * Reverberation + * + * Within Java 3D's model for auralization, the components to + * reverberation for a particular space are: + * Reflection and Reverb Coefficients - + * attenuation of sound (uniform for all frequencies) due to + * absorption of reflected sound off materials within the + * listening space. + * Reflection and Reverb Delay - + * approximating time from the start of the direct sound that + * initial early and late reflection waves take to reach listener. + * Reverb Decay - + * approximating time from the start of the direct sound that + * reverberation is audible. + */ + + /** + * Coefficients for reverberation + * The (early) Reflection and Reverberation coefficient scale factors + * are used to approximate the reflective/absorptive characteristics + * of the surfaces in this bounded Auralizaton environment. + * Theses scale factors is applied to sound's amplitude regardless + * of sound's position. + * Value of 1.0 represents complete (unattenuated) sound reflection. + * Value of 0.0 represents full absorption; reverberation is disabled. + */ + float reflectionCoefficient = 0.0f; // Range of values 0.0 to 1.0 + float reverbCoefficient = 1.0f; // Range of values 0.0 to 1.0 + + /** + * Time Delays in milliseconds + * Set with either explicitly with time, or impliciticly by supplying + * bounds volume and having the delay time calculated. + * Bounds of reverberation space does not have to be the same as + * Attribute bounds. + */ + float reflectionDelay = 20.0f; // in milliseconds + float reverbDelay = 40.0f; // in milliseconds + Bounds reverbBounds = null; + + /** + * Decay parameters + * Length and timbre of reverb decay tail + */ + float decayTime = 1000.0f; // in milliseconds + float decayFilter = 5000.0f; // low-pass cutoff frequency + + /** + * Reverb Diffusion and Density ratios (0=min, 1=max) + */ + float diffusion = 1.0f; + float density = 1.0f; + + /** + * Reverberation order + * This limits the number of Reverberation iterations executed while + * sound is being reverberated. As long as reflection coefficient is + * small enough, the reverberated sound decreases (as it would naturally) + * each successive iteration. + * Value of > zero defines the greatest reflection order to be used by + * the reverberator. + * All positive values are used as the number of loop iteration. + * Value of <= zero signifies that reverberation is to loop until reverb + * gain reaches zero (-60dB or 1/1000 of sound amplitude). + */ + int reverbOrder = 0; + + /** + * Distance Filter + * Each sound source is attenuated by a filter based on it's distance + * from the listener. + * For now the only supported filterType will be LOW_PASS frequency cutoff. + * At some time full FIR filtering will be supported. + */ + static final int NO_FILTERING = -1; + static final int LOW_PASS = 1; + + int filterType = NO_FILTERING; + float[] distance = null; + float[] frequencyCutoff = null; + + /** + * Doppler Effect parameters + * Between two snapshots of the head and sound source positions some + * delta time apart, the distance between head and source is compared. + * If there has been no change in the distance between head and sound + * source over this delta time: + * f' = f + * + * If there has been a change in the distance between head and sound: + * f' = f * Af * v + * + * When head and sound are moving towards each other then + * | (S * Ar) + (deltaV(h,t) * Av) | + * v = | -------------------------------- | + * | (S * Ar) - (deltaV(s,t) * Av) | + * + * When head and sound are moving away from each other then + * | (S * Ar) - (deltaV(h,t) * Av) | + * v = | -------------------------------- | + * | (S * Ar) + (deltaV(s,t) * Av) | + * + * + * Af = AuralAttribute frequency scalefactor + * Ar = AuralAttribute rolloff scalefactor + * Av = AuralAttribute velocity scalefactor + * deltaV = delta velocity + * f = frequency of sound + * h = Listeners head position + * v = Ratio of delta velocities + * Vh = Vector from center ear to sound source + * S = Speed of sound + * s = Sound source position + * t = time + * + * If adjusted velocity of head or adjusted velocity of sound is + * greater than adjusted speed of sound, f' is undefined. + */ + /** + * Frequency Scale Factor + * used to increase or reduce the change of frequency associated + * with normal rate of playback. + * Value of zero causes sounds to be paused. + */ + float frequencyScaleFactor = 1.0f; + /** + * Velocity Scale Factor + * Float value applied to the Change of distance between Sound Source + * and Listener over some delta time. Non-zero if listener moving + * even if sound is not. Value of zero implies no Doppler applied. + */ + float velocityScaleFactor = 0.0f; + + /** + * This boolean is set when something changes in the attributes + */ + boolean aaDirty = true; + + /** + * The mirror copy of this AuralAttributes. + */ + AuralAttributesRetained mirrorAa = null; + + /** + ** Debug print mechanism for Sound nodes + **/ + static final // 'static final' so compiler doesn't include debugPrint calls + boolean debugFlag = false; + + static final // 'static final' so internal error message are not compiled + boolean internalErrors = false; + + void debugPrint(String message) { + if (debugFlag) // leave test in in case debugFlag made non-static final + System.err.println(message); + } + + + // **************************************** + // + // Set and Get individual attribute values + // + // **************************************** + + /** + * Set Attribute Gain (amplitude) + * @param gain scale factor applied to amplitude + */ + void setAttributeGain(float gain) { + this.attributeGain = gain; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Attribute Gain (amplitude) + * @return gain amplitude scale factor + */ + float getAttributeGain() { + return this.attributeGain; + } + + /** + * Set Attribute Gain Rolloff + * @param rolloff atmospheric gain scale factor (changing speed of sound) + */ + void setRolloff(float rolloff) { + this.rolloff = rolloff; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Attribute Gain Rolloff + * @return rolloff atmospheric gain scale factor (changing speed of sound) + */ + float getRolloff() { + return this.rolloff; + } + + /** + * Set Reflective Coefficient + * @param reflectionCoefficient reflection/absorption factor applied to + * early reflections. + */ + void setReflectionCoefficient(float reflectionCoefficient) { + this.reflectionCoefficient = reflectionCoefficient; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Reflective Coefficient + * @return reflection coeff reflection/absorption factor applied to + * early reflections. + */ + float getReflectionCoefficient() { + return this.reflectionCoefficient; + } + + /** + * Set Reflection Delay Time + * @param reflectionDelay time before the start of early (first order) + * reflections. + */ + void setReflectionDelay(float reflectionDelay) { + this.reflectionDelay = reflectionDelay; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Reflection Delay Time + * @return reflection delay time + */ + float getReflectionDelay() { + return this.reflectionDelay; + } + + /** + * Set Reverb Coefficient + * @param reverbCoefficient reflection/absorption factor applied to + * late reflections. + */ + void setReverbCoefficient(float reverbCoefficient) { + this.reverbCoefficient = reverbCoefficient; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Reverb Coefficient + * @return reverb coeff reflection/absorption factor applied to late + * reflections. + */ + float getReverbCoefficient() { + return this.reverbCoefficient; + } + + /** + * Set Revereration Delay Time + * @param reverbDelay time between each order of reflection + */ + void setReverbDelay(float reverbDelay) { + this.reverbDelay = reverbDelay; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Revereration Delay Time + * @return reverb delay time between each order of reflection + */ + float getReverbDelay() { + return this.reverbDelay; + } + /** + * Set Decay Time + * @param decayTime length of time reverb takes to decay + */ + void setDecayTime(float decayTime) { + this.decayTime = decayTime; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Revereration Decay Time + * @return reverb delay time + */ + float getDecayTime() { + return this.decayTime; + } + + /** + * Set Decay Filter + * @param decayFilter frequency referenced used in low-pass filtering + */ + void setDecayFilter(float decayFilter) { + this.decayFilter = decayFilter; + this.aaDirty = true; + notifyUsers(); + } + + /** + * Retrieve Revereration Decay Filter + * @return reverb delay Filter + */ + float getDecayFilter() { + return this.decayFilter; + } + + /** + * Set Reverb Diffusion + * @param diffusion ratio between min and max device diffusion settings + */ + void setDiffusion(float diffusion) { + this.diffusion = diffusion; + this.aaDirty = true; + notifyUsers(); + } + + /** + * Retrieve Revereration Decay Diffusion + * @return reverb diffusion + */ + float getDiffusion() { + return this.diffusion; + } + + /** + * Set Reverb Density + * @param density ratio between min and max device density settings + */ + void setDensity(float density) { + this.density = density; + this.aaDirty = true; + notifyUsers(); + } + + /** + * Retrieve Revereration Density + * @return reverb density + */ + float getDensity() { + return this.density; + } + + + /** + * Set Revereration Bounds + * @param reverbVolume bounds used to approximate reverb time. + */ + synchronized void setReverbBounds(Bounds reverbVolume) { + this.reverbBounds = reverbVolume; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Revereration Delay Bounds volume + * @return reverb bounds volume that defines the Reverberation space and + * indirectly the delay + */ + Bounds getReverbBounds() { + return this.reverbBounds; + } + + /** + * Set Reverberation Order of Reflections + * @param reverbOrder number of times reflections added to reverb signal + */ + void setReverbOrder(int reverbOrder) { + this.reverbOrder = reverbOrder; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Reverberation Order of Reflections + * @return reverb order number of times reflections added to reverb signal + */ + int getReverbOrder() { + return this.reverbOrder; + } + + /** + * Set Distance Filter (based on distances and frequency cutoff) + * @param attenuation array of pairs defining distance frequency cutoff + */ + synchronized void setDistanceFilter(Point2f[] attenuation) { + if (attenuation == null) { + this.filterType = NO_FILTERING; + return; + } + int attenuationLength = attenuation.length; + if (attenuationLength == 0) { + this.filterType = NO_FILTERING; + return; + } + this.filterType = LOW_PASS; + // Reallocate every time unless size of new array equal old array + if ( distance == null || + (distance != null && (distance.length != attenuationLength) ) ) { + this.distance = new float[attenuationLength]; + this.frequencyCutoff = new float[attenuationLength]; + } + for (int i = 0; i< attenuationLength; i++) { + this.distance[i] = attenuation[i].x; + this.frequencyCutoff[i] = attenuation[i].y; + } + this.aaDirty = true; + notifyUsers(); + } + /** + * Set Distance Filter (based on distances and frequency cutoff) using + * separate arrays + * @param distance array containing distance values + * @param filter array containing low-pass frequency cutoff values + */ + synchronized void setDistanceFilter(float[] distance, float[] filter) { + if (distance == null || filter == null) { + this.filterType = NO_FILTERING; + return; + } + int distanceLength = distance.length; + int filterLength = filter.length; + if (distanceLength == 0 || filterLength == 0) { + this.filterType = NO_FILTERING; + return; + } + // Reallocate every time unless size of new array equal old array + if ( this.distance == null || + ( this.distance != null && + (this.distance.length != filterLength) ) ) { + this.distance = new float[distanceLength]; + this.frequencyCutoff = new float[distanceLength]; + } + this.filterType = LOW_PASS; + // Copy the distance array into nodes field + System.arraycopy(distance, 0, this.distance, 0, distanceLength); + // Copy the filter array an array of same length as the distance array + if (distanceLength <= filterLength) { + System.arraycopy(filter, 0, this.frequencyCutoff,0, distanceLength); + } + else { + System.arraycopy(filter, 0, this.frequencyCutoff, 0, filterLength); + // Extend filter array to length of distance array by + // replicate last filter values. + for (int i=filterLength; i< distanceLength; i++) { + this.frequencyCutoff[i] = filter[filterLength - 1]; + } + } + if (debugFlag) { + debugPrint("AAR setDistanceFilter(D,F)"); + for (int jj=0;jj attenuation.length) + distanceLength = attenuation.length; + for (int i=0; i< distanceLength; i++) { + attenuation[i].x = this.distance[i]; + if (filterType == NO_FILTERING) + attenuation[i].y = Sound.NO_FILTER; + else if (filterType == LOW_PASS) + attenuation[i].y = this.frequencyCutoff[i]; + if (debugFlag) + debugPrint("AAR: getDistF: " + attenuation[i].x + ", " + + attenuation[i].y); + } + } + /** + * Retrieve Distance Filter as arrays distances and frequency cutoff array + * @param distance array of float values + * @param frequencyCutoff array of float cutoff filter values in Hertz + */ + void getDistanceFilter(float[] distance, float[] filter) { + // Write into existing param arrays already allocated + if (distance == null || filter == null) + return; + if (this.distance == null || this.frequencyCutoff == null) + return; + int distanceLength = this.distance.length; + // check that distance parameter large enough to contain auralAttribute + // distance array + // We can assume that distance and filter lengths are the same + // and are non-zero. + if (distance.length < distanceLength) + // parameter array not large enough to hold all this.distance data + distanceLength = distance.length; + System.arraycopy(this.distance, 0, distance, 0, distanceLength); + if (debugFlag) + debugPrint("AAR getDistanceFilter(D,F) " + this.distance[0]); + int filterLength = this.frequencyCutoff.length; + if (filter.length < filterLength) + // parameter array not large enough to hold all this.filter data + filterLength = filter.length; + if (filterType == NO_FILTERING) { + for (int i=0; i< filterLength; i++) + filter[i] = Sound.NO_FILTER; + } + if (filterType == LOW_PASS) { + System.arraycopy(this.frequencyCutoff, 0, filter, 0, filterLength); + } + if (debugFlag) + debugPrint(", " + this.frequencyCutoff[0]); + } + + /** + * Set Frequency Scale Factor + * @param frequencyScaleFactor factor applied to sound's base frequency + */ + void setFrequencyScaleFactor(float frequencyScaleFactor) { + this.frequencyScaleFactor = frequencyScaleFactor; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Frequency Scale Factor + * @return frequency scale factor applied to sound's base frequency + */ + float getFrequencyScaleFactor() { + return this.frequencyScaleFactor; + } + + /** + * Set Velocity ScaleFactor used in calculating Doppler Effect + * @param velocityScaleFactor applied to velocity of sound in relation to listener + */ + void setVelocityScaleFactor(float velocityScaleFactor) { + this.velocityScaleFactor = velocityScaleFactor; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Velocity ScaleFactor used in calculating Doppler Effect + * @return velocity scale factor + */ + float getVelocityScaleFactor() { + return this.velocityScaleFactor; + } + + synchronized void reset(AuralAttributesRetained aa) { + int i; + + this.attributeGain = aa.attributeGain; + this.rolloff = aa.rolloff; + this.reflectionCoefficient = aa.reflectionCoefficient; + this.reverbCoefficient = aa.reverbCoefficient; + this.reflectionDelay = aa.reflectionDelay; + this.reverbDelay = aa.reverbDelay; + this.reverbBounds = aa.reverbBounds; + this.reverbOrder = aa.reverbOrder; + this.decayTime = aa.decayTime; + this.decayFilter = aa.decayFilter; + this.diffusion = aa.diffusion; + this.density = aa.density; + this.frequencyScaleFactor = aa.frequencyScaleFactor; + this.velocityScaleFactor = aa.velocityScaleFactor; + + if (aa.distance != null) { + this.distance = new float[aa.distance.length]; + if (debugFlag) + debugPrint("reset aa; aa.distance.length = " + this.distance.length); + System.arraycopy(aa.distance, 0, this.distance, 0, this.distance.length); + } + else + if (debugFlag) + debugPrint("reset aa; aa.distance = null"); + if (aa.frequencyCutoff != null) { + this.frequencyCutoff = new float[aa.frequencyCutoff.length]; + if (debugFlag) + debugPrint("reset aa; aa.frequencyCutoff.length = " + this.frequencyCutoff.length); + System.arraycopy(aa.frequencyCutoff, 0, this.frequencyCutoff, 0, + this.frequencyCutoff.length); + } + else + if (debugFlag) + debugPrint("reset aa; aa.frequencyCutoff = null"); + // XXXX: (Enhancement) Why are these dirtyFlag cleared rather than aa->this + this.aaDirty = false; + aa.aaDirty = false; + } + + void update(AuralAttributesRetained aa) { + this.reset(aa); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BHInsertStructure.java b/j3d-core/src/classes/share/javax/media/j3d/BHInsertStructure.java new file mode 100644 index 0000000..3261b28 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BHInsertStructure.java @@ -0,0 +1,158 @@ +/* + * $RCSfile: BHInsertStructure.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +class BHInsertStructure { + + static boolean debug = false; + static boolean debug2 = false; + + Random randomNumber; + ArrayList[] bhListArr = null; + ArrayList[] oldBhListArr = null; + BHNode[] bhListArrRef = null; + BHNode[] oldBhListArrRef = null; + int bhListArrCnt = 0; + int bhListArrMaxCnt = 0; + int blockSize = 0; + + BHInsertStructure(int length) { + randomNumber = new Random(0); + + if(length > 50) { + length = 50; + } + + blockSize = 50; + bhListArr = new ArrayList[length]; + bhListArrRef = new BHNode[length]; + bhListArrCnt = 0; + bhListArrMaxCnt = length; + + } + + void clear() { + + for(int i=0; i< bhListArrCnt; i++) { + bhListArr[i].clear(); + bhListArrRef[i] = null; + } + bhListArrCnt = 0; + } + + void lookupAndInsert(BHNode parent, BHNode child) { + boolean found = false; + + for ( int i=0; i= bhListArrMaxCnt) { + // allocate a bigger array here.... + if(debug) + System.err.println("(1) Expanding bhListArr array ..."); + bhListArrMaxCnt += blockSize; + oldBhListArr = bhListArr; + oldBhListArrRef = bhListArrRef; + + bhListArr = new ArrayList[bhListArrMaxCnt]; + bhListArrRef = new BHNode[bhListArrMaxCnt]; + System.arraycopy(oldBhListArr, 0, bhListArr, 0, oldBhListArr.length); + System.arraycopy(oldBhListArrRef, 0, bhListArrRef, 0, + oldBhListArrRef.length); + } + + bhListArrRef[bhListArrCnt] = parent; + bhListArr[bhListArrCnt] = new ArrayList(); + bhListArr[bhListArrCnt].add(child); + bhListArrCnt++; + } + + } + + void updateBoundingTree(BHTree bhTree) { + + // based on the data in this stucture, update the tree such that + // all things work out now .. i.e for each element of the array list + // of bhListArr ... create a new reclustered tree. + int size, cnt; + BHNode child1, child2; + + for ( int i=0; i < bhListArrCnt; i++ ) { + // extract and form an array of all children : l, r, and n1 ... nk + cnt = 0; + child1 = ((BHInternalNode)(bhListArrRef[i])).getLeftChild(); + child2 = ((BHInternalNode)(bhListArrRef[i])).getRightChild(); + if(child1 != null) cnt++; + if(child2 != null) cnt++; + + size = bhListArr[i].size(); + + BHNode bhArr[] = new BHNode[cnt + size]; + + bhListArr[i].toArray(bhArr); + + //reset cnt, so that we can reuse it. + cnt = 0; + if(child1 != null) { + bhArr[size] = child1; + cnt++; + bhArr[size + cnt] = child2; + } + + if(debug2) + if((child1 == null) || (child2 == null)) { + System.err.println("child1 or child2 is null ..."); + System.err.println("This is bad, it shouldn't happen"); + + } + + ((BHInternalNode)(bhListArrRef[i])).setRightChild(null); + ((BHInternalNode)(bhListArrRef[i])).setLeftChild(null); + + bhTree.cluster((BHInternalNode)bhListArrRef[i], bhArr); + } + } + +} + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/BHInternalNode.java b/j3d-core/src/classes/share/javax/media/j3d/BHInternalNode.java new file mode 100644 index 0000000..656ccf7 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BHInternalNode.java @@ -0,0 +1,212 @@ +/* + * $RCSfile: BHInternalNode.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +class BHInternalNode extends BHNode { + + static boolean debug2 = true; + + BHNode rChild; + BHNode lChild; + + BHInternalNode() { + super(); + nodeType = BH_TYPE_INTERNAL; + this.rChild = null; + this.lChild = null; + } + + BHInternalNode(BHNode parent) { + super(parent); + nodeType = BH_TYPE_INTERNAL; + this.rChild = null; + this.lChild = null; + } + + BHInternalNode(BHNode parent, BHNode rChild, BHNode lChild) { + super(parent); + nodeType = BH_TYPE_INTERNAL; + this.rChild = rChild; + this.lChild = lChild; + } + + BHInternalNode(BHNode parent, BoundingBox bHull) { + super(parent, bHull); + nodeType = BH_TYPE_INTERNAL; + this.rChild = null; + this.lChild = null; + } + + BHInternalNode(BHNode parent, BHNode rChild, BHNode lChild, BoundingBox bHull) { + super(parent, bHull); + nodeType = BH_TYPE_INTERNAL; + this.rChild = rChild; + this.lChild = lChild; + } + + BHNode getLeftChild() { + return (BHNode) lChild; + } + + BHNode getRightChild() { + return (BHNode) rChild; + } + + void setLeftChild(BHNode child) { + lChild = child; + } + + void setRightChild(BHNode child) { + rChild = child; + } + + void computeBoundingHull(BoundingBox bHull) { + computeBoundingHull(); + bHull.set(this.bHull); + } + + void computeBoundingHull() { + BoundingBox rChildBound = null; + BoundingBox lChildBound = null; + int i; + + if((lChild==null) && (rChild==null)) { + bHull = null; + return; + } + + if(lChild != null) + lChildBound = lChild.getBoundingHull(); + + if(rChild != null) + rChildBound = rChild.getBoundingHull(); + + if(bHull == null) + bHull = new BoundingBox(); + + // Since left child is null. bHull is equal to right child's Hull. + if(lChild == null) { + bHull.set(rChildBound); + return; + } + + // Since right child is null. bHull is equal to left child's Hull. + if(rChild == null) { + bHull.set(lChildBound); + return; + } + + // Compute the combined bounds of the children. + bHull.set(rChildBound); + bHull.combine(lChildBound); + + } + + void updateMarkedBoundingHull() { + + if(mark == false) + return; + + rChild.updateMarkedBoundingHull(); + lChild.updateMarkedBoundingHull(); + computeBoundingHull(); + mark = false; + + } + + // this method inserts a single element into the tree given the stipulation + // that the current tree node already contains the child ... 3 cases + // one --node is inside the left child, and not inside the right + // so recurse placing it inside the left child + // two -- node is not inside the left but is inside the right + // recurse placing it inside the right child + // three -- node is not inside either one, added it to the current + // element + + void insert( BHNode node, BHInsertStructure insertStructure ) { + // NOTE: the node must already be inside this node if its not then fail. + if(debug2) + if ( !this.isInside(node.bHull) ) { + System.err.println("Incorrect use of insertion, current node"); + System.err.println("must contain the input element ..."); + } + + boolean insideRightChild = false; + boolean insideLeftChild = false; + + // leaf children are considered inpenetrable for insert so returns false + if(this.rChild.nodeType == BHNode.BH_TYPE_LEAF) { + insideRightChild = false; + } else { + insideRightChild = this.rChild.isInside(node.bHull); + } + if(this.lChild.nodeType == BHNode.BH_TYPE_LEAF) { + insideLeftChild = false; + } else { + insideLeftChild = this.lChild.isInside(node.bHull); + } + + if ( insideLeftChild && !insideRightChild ) { + ((BHInternalNode)this.lChild).insert(node, insertStructure); + } else if ( !insideLeftChild && insideRightChild ) { + ((BHInternalNode)this.rChild).insert(node, insertStructure); + } else if ( insideLeftChild && insideRightChild ) { + // choose randomly to put it in the left or right + if ( insertStructure.randomNumber.nextBoolean() ) { + ((BHInternalNode)this.lChild).insert(node, insertStructure); + } else { + ((BHInternalNode)this.rChild).insert(node, insertStructure); + } + } else { + // doesn't fit in either one .... + // lookup the current node this in the auxilaryInsertStructure + // if it appears then add element to the array of sub elements + // if not then allocate a new element to the array + insertStructure.lookupAndInsert(this, node); + } + } + + void destroyTree(BHNode[] bhArr, int[] index) { + + if(rChild != null) + rChild.destroyTree(bhArr, index); + + if(lChild != null) + lChild.destroyTree(bhArr, index); + + rChild = null; + lChild = null; + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/BHLeafInterface.java b/j3d-core/src/classes/share/javax/media/j3d/BHLeafInterface.java new file mode 100644 index 0000000..62e45ad --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BHLeafInterface.java @@ -0,0 +1,45 @@ +/* + * $RCSfile: BHLeafInterface.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +interface BHLeafInterface { + + abstract BoundingBox computeBoundingHull(); + + abstract boolean isEnable(); + + abstract boolean isEnable(int visibilityPolicy); + + // Can't use getLocale, it is used by BranchGroupRetained + abstract Locale getLocale2(); + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BHLeafNode.java b/j3d-core/src/classes/share/javax/media/j3d/BHLeafNode.java new file mode 100644 index 0000000..83ea687 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BHLeafNode.java @@ -0,0 +1,110 @@ +/* + * $RCSfile: BHLeafNode.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +class BHLeafNode extends BHNode { + + BHLeafInterface leafIF; + + BHLeafNode() { + super(); + nodeType = BH_TYPE_LEAF; + leafIF = null; + } + + BHLeafNode(BHNode parent) { + super(parent); + nodeType = BH_TYPE_LEAF; + } + + BHLeafNode(BHLeafInterface lIF) { + super(); + nodeType = BH_TYPE_LEAF; + leafIF = lIF; + } + + BHLeafNode(BHNode parent, BHLeafInterface lIF) { + super(parent); + leafIF = lIF; + nodeType = BH_TYPE_LEAF; + } + + BHLeafNode(BHNode parent, BoundingBox bHull) { + super(parent, bHull); + nodeType = BH_TYPE_LEAF; + } + + BHLeafNode(BHNode parent, BHLeafInterface lIF, BoundingBox bHull) { + super(parent, bHull); + leafIF = lIF; + nodeType = BH_TYPE_LEAF; + } + + void computeBoundingHull() { + bHull = leafIF.computeBoundingHull(); + } + + void updateMarkedBoundingHull() { + + if(mark == false) + return; + + computeBoundingHull(); + mark = false; + } + + boolean isEnable() { + return leafIF.isEnable(); + } + + boolean isEnable(int vis) { + return leafIF.isEnable(vis); + } + + Locale getLocale() { + return leafIF.getLocale2(); + } + + void destroyTree(BHNode[] bhArr, int[] index) { + if(bhArr.length <= index[0]) { + // System.err.println("BHLeafNode : Problem bhArr overflow!!!"); + return; + } + + parent = null; + bhArr[index[0]] = this; + index[0]++; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BHNode.java b/j3d-core/src/classes/share/javax/media/j3d/BHNode.java new file mode 100644 index 0000000..d25f8d2 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BHNode.java @@ -0,0 +1,287 @@ +/* + * $RCSfile: BHNode.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +abstract class BHNode { + + static final byte BH_TYPE_INTERNAL = 1; + static final byte BH_TYPE_LEAF = 2; + + static final int NUMBER_OF_PLANES = 6; + + static final boolean debug = false; + static final boolean debug2 = false; + + BHNode parent; + byte nodeType; + BoundingBox bHull = null; + boolean mark; + + BHNode () { + this.parent = null; + mark = false; + } + + BHNode (BHNode parent) { + this.parent = parent; + mark = false; + } + + BHNode (BHNode parent, BoundingBox bHull) { + this.parent = parent; + mark = false; + + this.bHull = bHull; + } + + BHNode getParent () { + return (this.parent) ; + } + + abstract void computeBoundingHull(); + abstract void updateMarkedBoundingHull(); + abstract void destroyTree(BHNode[] bhArr, int[] index); + + void setParent (BHNode node) { + this.parent = node; + } + + BoundingBox getBoundingHull() { + return (this.bHull); + } + + void setBoundingHull(BoundingBox bHull) { + this.bHull = bHull; + } + + // given two nodes determine the bHull surrounding them, ie. the parent hull + void combineBHull(BHNode node1, BHNode node2 ) { + BoundingBox bHull1 = null; + BoundingBox bHull2 = null; + + bHull1 = node1.getBoundingHull(); + bHull2 = node2.getBoundingHull(); + + if(this.bHull==null) + this.bHull = new BoundingBox(bHull1); + else + this.bHull.set(bHull1); + + this.bHull.combine(bHull2); + + } + + // returns true iff the bHull is completely inside this + // bounding hull i.e. bHull values are strictly less + // than or equal to all this.bHull values + boolean isInside(BoundingBox bHull) { + if(bHull == null) + return false; + + if( this.bHull.isEmpty() || bHull.isEmpty() ) { + return false; + } + + if( this.bHull.upper.x < bHull.upper.x || + this.bHull.upper.y < bHull.upper.y || + this.bHull.upper.z < bHull.upper.z || + this.bHull.lower.x > bHull.lower.x || + this.bHull.lower.y > bHull.lower.y || + this.bHull.lower.z > bHull.lower.z ) + return false; + else + return true; + } + + // finds the node matching the search element in the tree and returns + // the node if found, else it returns null if the node couldn't be found + BHNode findNode(BHNode node) { + BHNode fNode = null; + + if ( this.nodeType == BHNode.BH_TYPE_LEAF) { + if ( this == node ) { + return this; + } + } + else { + if (((BHInternalNode) this).rChild.isInside(node.bHull)) { + fNode = ((BHInternalNode)this).rChild.findNode(node); + if(fNode != null) { + return fNode; + } + } + if (((BHInternalNode)this).lChild.isInside(node.bHull)) { + return ((BHInternalNode)this).lChild.findNode(node); + } + } + return null; + } + + void deleteFromParent() { + BHInternalNode parent; + + // System.err.println("deleteFromParent - this " + this ); + parent = (BHInternalNode) (this.parent); + if(parent != null) { + if(parent.rChild == this) + parent.rChild = null; + else if(parent.lChild == this) + parent.lChild = null; + else { + if(debug2) { + System.err.println("BHNode.java: Trouble! No match found. This can't happen."); + System.err.println("this " + this ); + if ( this.nodeType == BHNode.BH_TYPE_INTERNAL) { + System.err.println("rChild " + ((BHInternalNode)this).rChild + + " lChild " + ((BHInternalNode)this).lChild); + } + System.err.println("parent " + parent + + " parent.rChild " + parent.rChild + + " parent.lChild " + parent.lChild); + } + } + } + } + + // delete all leaf nodes marked with DELETE_UPDATE and update the + // bounds of the parents node + BHNode deleteAndUpdateMarkedNodes() { + + if (this.mark == true) { + if (this.nodeType == BH_TYPE_LEAF) { + this.deleteFromParent(); + return null; + + } else { + if(debug) + if(((BHInternalNode)(this)).rChild == ((BHInternalNode)(this)).lChild) + System.err.println("rChild " + ((BHInternalNode)(this)).rChild + + " lChild " + ((BHInternalNode)(this)).lChild); + + + if(((BHInternalNode)(this)).rChild != null) + ((BHInternalNode)(this)).rChild = + ((BHInternalNode)(this)).rChild.deleteAndUpdateMarkedNodes(); + if(((BHInternalNode)(this)).lChild != null) + ((BHInternalNode)(this)).lChild = + ((BHInternalNode)(this)).lChild.deleteAndUpdateMarkedNodes(); + + if ((((BHInternalNode)(this)).rChild == null) && + (((BHInternalNode)(this)).lChild == null)) { + this.deleteFromParent(); + return null; + } else { + if ( ((BHInternalNode)this).rChild == null ) { + BHNode leftChild = ((BHInternalNode)this).lChild; + leftChild.parent = this.parent; + // delete self, return lChild + this.deleteFromParent(); + return leftChild; + } else if ( ((BHInternalNode)this).lChild == null ) { + BHNode rightChild = ((BHInternalNode)this).rChild; + rightChild.parent = this.parent; + // delete self, return rChild + this.deleteFromParent(); + return rightChild; + } else { + // recompute your bounds and return yourself + this.combineBHull(((BHInternalNode)this).rChild, + ((BHInternalNode)this).lChild); + // update the parent's pointers + ((BHInternalNode)this).rChild.parent = this; + ((BHInternalNode)this).lChild.parent = this; + this.mark = false; + return this; + } + } + } + } else { + // mark is NOT set, simply return self + return this; + } + } + + + // generic tree gathering statistics operations + + int countNumberOfInternals() { + if ( this.nodeType == BHNode.BH_TYPE_LEAF ) { + return 0; + } else { + return (((BHInternalNode)this).rChild.countNumberOfInternals() + + ((BHInternalNode)this).lChild.countNumberOfInternals() + 1 ); + } + } + + // recursively traverse the tree and compute the total number of leaves + int countNumberOfLeaves() { + if ( this.nodeType == BHNode.BH_TYPE_LEAF ) { + return 1; + } else { + return ( ((BHInternalNode)this).rChild.countNumberOfLeaves() + + ((BHInternalNode)this).lChild.countNumberOfLeaves() ); + } + } + + + // traverse tree and compute the maximum depth to a leaf + int computeMaxDepth (int currentDepth) { + if ( this.nodeType == BHNode.BH_TYPE_LEAF ) { + return (currentDepth); + } else { + int rightDepth = ((BHInternalNode)this).rChild.computeMaxDepth(currentDepth + 1); + int leftDepth = ((BHInternalNode)this).lChild.computeMaxDepth(currentDepth + 1); + if( rightDepth > leftDepth ) + return rightDepth; + return leftDepth; + } + } + + // compute the average depth of the leaves ... + float computeAverageLeafDepth ( int numberOfLeaves, int currentDepth ) { + int sumOfDepths = this.computeSumOfDepths(0); + return ( (float)sumOfDepths / (float)numberOfLeaves ); + } + + int computeSumOfDepths ( int currentDepth ) { + if ( this.nodeType == BHNode.BH_TYPE_LEAF ) { + return ( currentDepth ); + } else { + return (((BHInternalNode)this).rChild.computeSumOfDepths(currentDepth + 1) + + ((BHInternalNode)this).lChild.computeSumOfDepths(currentDepth + 1) ) ; + } + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BHTree.java b/j3d-core/src/classes/share/javax/media/j3d/BHTree.java new file mode 100644 index 0000000..3a030d4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BHTree.java @@ -0,0 +1,1158 @@ +/* + * $RCSfile: BHTree.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; +import java.util.Vector; +import javax.vecmath.Point4d; + +class BHTree { + + Locale locale; + + private BHNode root; + private BHInsertStructure insertStructure = null; + + // Temporary point, so we dont generate garbage + Point4d tPoint4d = new Point4d(); + + // A flag to signal that number of renderAtoms sent to RenderBin is stable. + private boolean stable = false; + + // An estimate of the maxmium depth of this tree (upper bound). + int estMaxDepth; + + static final double LOG_OF_2 = Math.log(2); + + // Assume that the size avg. leaf node is 256 bytes. For a 64bit system, we'll + // down with max depth of 56 for an ideal balance tree. + static final int DEPTH_UPPER_BOUND = 56; + static final int INCR_DEPTH_BOUND = 5; + int depthUpperBound = DEPTH_UPPER_BOUND; + + BHTree() { + locale = null; + root = null; + } + + BHTree(Locale loc) { + locale = loc; + root = null; + } + + BHTree(BHNode bhArr[]) { + locale = null; + root = null; + create(bhArr); + } + + void setLocale(Locale loc) { + locale = loc; + } + + Locale getLocale() { + return locale; + } + + void cluster(BHInternalNode root, BHNode[] bhArr) { + + if(J3dDebug.devPhase) { + if(J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4, + "BHTree.java :In cluster length is " + bhArr.length + + "\n")) { + + for(int i=0; i= bBox.upper.x) && + (aBox.upper.y >= bBox.upper.y) && + (aBox.upper.z >= bBox.upper.z) && + (aBox.lower.x <= bBox.lower.x) && + (aBox.lower.y <= bBox.lower.y) && + (aBox.lower.z <= bBox.lower.z)); + } + + + BHLeafInterface selectAny(GeometryAtom atom, int accurancyMode) { + if (atom.source.geometryList == null) + return null; + BHNode bhNode = doSelectAny(atom, root, accurancyMode); + if (bhNode == null) { + return null; + } + + return ((BHLeafNode) bhNode).leafIF; + } + + + BHLeafInterface selectAny(GeometryAtom atoms[], int size, int accurancyMode) { + BHNode bhNode = doSelectAny(atoms, size, root, accurancyMode); + if (bhNode == null) { + return null; + } + + return ((BHLeafNode) bhNode).leafIF; + } + + + private BHNode doSelectAny(GeometryAtom atoms[],int atomSize, + BHNode bh, int accurancyMode) { + if ((bh == null) || (bh.bHull.isEmpty())) { + return null; + } + switch (bh.nodeType) { + case BHNode.BH_TYPE_LEAF: + BHLeafInterface leaf = ((BHLeafNode) bh).leafIF; + GeometryAtom atom; + int i; + + if (leaf instanceof GeometryAtom) { + GeometryAtom leafAtom = (GeometryAtom) leaf; + + if (((BHLeafNode) bh).isEnable() && + leafAtom.source.isCollidable) { + + // atom self intersection between atoms[] + for (i=atomSize-1; i >=0; i--) { + if (atoms[i] == leafAtom) { + return null; + } + } + for (i=atomSize-1; i >=0; i--) { + atom = atoms[i]; + if ((atom.source.sourceNode != leafAtom.source.sourceNode) && + (atom.source.collisionVwcBound.intersect(leafAtom.source.collisionVwcBound)) && + ((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) || + ((leafAtom.source.geometryList != null) && + (atom.source.intersectGeometryList(leafAtom.source))))) { + return bh; + } + } + } + } else if (leaf instanceof GroupRetained) { + if (((BHLeafNode) bh).isEnable() && + ((GroupRetained) leaf).sourceNode.collidable) { + for (i=atomSize-1; i >=0; i--) { + atom = atoms[i]; + if (atom.source.collisionVwcBound.intersect(bh.bHull) && + ((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) || + (atom.source.intersectGeometryList( + atom.source.getCurrentLocalToVworld(0), bh.bHull)))) { + return bh; + } + } + } + } + return null; + case BHNode.BH_TYPE_INTERNAL: + for (i=atomSize-1; i >=0; i--) { + atom = atoms[i]; + if (atom.source.collisionVwcBound.intersect(bh.bHull)) + { + BHNode hitNode = doSelectAny(atoms, + atomSize, + ((BHInternalNode) bh).getRightChild(), + accurancyMode); + if (hitNode != null) + return hitNode; + + return doSelectAny(atoms, atomSize, + ((BHInternalNode) bh).getLeftChild(), + accurancyMode); + } + } + return null; + } + return null; + } + + + private BHNode doSelectAny(GeometryAtom atom, BHNode bh, int accurancyMode) { + if ((bh == null) || (bh.bHull.isEmpty())) { + return null; + } + switch (bh.nodeType) { + case BHNode.BH_TYPE_LEAF: + BHLeafInterface leaf = ((BHLeafNode) bh).leafIF; + if (leaf instanceof GeometryAtom) { + GeometryAtom leafAtom = (GeometryAtom) leaf; + if ((atom.source.sourceNode != leafAtom.source.sourceNode) && + (((BHLeafNode) bh).isEnable()) && + (leafAtom.source.isCollidable) && + (atom.source.collisionVwcBound.intersect(leafAtom.source.collisionVwcBound)) && + ((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) || + ((leafAtom.source.geometryList != null) && + (atom.source.intersectGeometryList(leafAtom.source))))) { + return bh; + } + } else if (leaf instanceof GroupRetained) { + if (((BHLeafNode) bh).isEnable() && + ((GroupRetained) leaf).sourceNode.collidable && + atom.source.collisionVwcBound.intersect(bh.bHull) && + ((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) || + (atom.source.intersectGeometryList( + atom.source.getCurrentLocalToVworld(0), bh.bHull)))) { + return bh; + } + } + return null; + case BHNode.BH_TYPE_INTERNAL: + if (atom.source.collisionVwcBound.intersect(bh.bHull)) { + BHNode hitNode = doSelectAny(atom, + ((BHInternalNode) bh).getRightChild(), + accurancyMode); + if (hitNode != null) + return hitNode; + + return doSelectAny(atom, + ((BHInternalNode) bh).getLeftChild(), + accurancyMode); + } + return null; + } + return null; + } + + BHLeafInterface selectAny(Bounds bound, int accurancyMode, + NodeRetained armingNode) { + if (bound == null) { + return null; + } + BHNode bhNode = doSelectAny(bound, root, accurancyMode, armingNode); + if (bhNode == null) { + return null; + } + return ((BHLeafNode) bhNode).leafIF; + } + + private BHNode doSelectAny(Bounds bound, BHNode bh, int accurancyMode, + NodeRetained armingNode) { + if ((bh == null) || (bh.bHull.isEmpty())) { + return null; + } + + switch (bh.nodeType) { + case BHNode.BH_TYPE_LEAF: + BHLeafInterface leaf = ((BHLeafNode) bh).leafIF; + if (leaf instanceof GeometryAtom) { + GeometryAtom leafAtom = (GeometryAtom) leaf; + if ((((BHLeafNode) bh).isEnable()) && + (leafAtom.source.isCollidable) && + (bound.intersect(leafAtom.source.collisionVwcBound)) && + ((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) || + ((leafAtom.source.geometryList != null) && + (leafAtom.source.intersectGeometryList( + leafAtom.source.getCurrentLocalToVworld(0), bound))))) { + return bh; + } + } else if (leaf instanceof GroupRetained) { + if ((leaf != armingNode) && + ((BHLeafNode) bh).isEnable() && + ((GroupRetained) leaf).sourceNode.collidable && + bound.intersect(bh.bHull)) { + return bh; + } + } + return null; + case BHNode.BH_TYPE_INTERNAL: + if (bound.intersect(bh.bHull)) { + BHNode hitNode = doSelectAny(bound, + ((BHInternalNode) bh).getRightChild(), + accurancyMode, + armingNode); + if (hitNode != null) + return hitNode; + + return doSelectAny(bound, + ((BHInternalNode) bh).getLeftChild(), + accurancyMode, + armingNode); + } + return null; + } + return null; + } + + + BHLeafInterface selectAny(Bounds bound, int accurancyMode, + GroupRetained armingGroup) { + if (bound == null) { + return null; + } + BHNode bhNode = doSelectAny(bound, root, accurancyMode, armingGroup); + if (bhNode == null) { + return null; + } + return ((BHLeafNode) bhNode).leafIF; + } + + private BHNode doSelectAny(Bounds bound, BHNode bh, int accurancyMode, + GroupRetained armingGroup) { + if ((bh == null) || (bh.bHull.isEmpty())) { + return null; + } + switch (bh.nodeType) { + case BHNode.BH_TYPE_LEAF: + BHLeafInterface leaf = ((BHLeafNode) bh).leafIF; + + if (leaf instanceof GeometryAtom) { + GeometryAtom leafAtom = (GeometryAtom) leaf; + if ((((BHLeafNode) bh).isEnable()) && + (leafAtom.source.isCollidable) && + (bound.intersect(leafAtom.source.collisionVwcBound)) && + (!isDescendent(leafAtom.source.sourceNode, + armingGroup, leafAtom.source.key)) && + ((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) || + ((leafAtom.source.geometryList != null) && + (leafAtom.source.intersectGeometryList( + leafAtom.source.getCurrentLocalToVworld(0), bound))))) { + return bh; + } + } else if (leaf instanceof GroupRetained) { + GroupRetained group = (GroupRetained) leaf; + if (((BHLeafNode) bh).isEnable() && + group.sourceNode.collidable && + bound.intersect(bh.bHull) && + !isDescendent(group.sourceNode, armingGroup, group.key)) { + return bh; + } + } + return null; + case BHNode.BH_TYPE_INTERNAL: + if (bound.intersect(bh.bHull)) { + BHNode hitNode = doSelectAny(bound, + ((BHInternalNode) bh).getRightChild(), + accurancyMode, + armingGroup); + if (hitNode != null) + return hitNode; + + return doSelectAny(bound, + ((BHInternalNode) bh).getLeftChild(), + accurancyMode, + armingGroup); + } + return null; + } + return null; + } + + // Return true if node is a descendent of group + private boolean isDescendent(NodeRetained node, + GroupRetained group, + HashKey key) { + + synchronized (group.universe.sceneGraphLock) { + if (node.inSharedGroup) { + // getlastNodeId() will destroy this key + if (key != null) { + key = new HashKey(key); + } + } + + do { + if (node == group) { + return true; + } + if (node instanceof SharedGroupRetained) { + // retrieve the last node ID + String nodeId = key.getLastNodeId(); + NodeRetained prevNode = node; + Vector parents = ((SharedGroupRetained) node).parents; + for(int i=parents.size()-1; i >=0; i--) { + NodeRetained link = (NodeRetained) parents.elementAt(i); + if (link.nodeId.equals(nodeId)) { + node = link; + break; + } + } + if (prevNode == node) { + // branch is already detach + return true; + } + } + node = node.parent; + } while (node != null); // reach Locale + } + return false; + } + + + void select(PickShape pickShape, UnorderList hitArrList) { + + if((pickShape == null)||(root == null)) + return; + + doSelect(pickShape, hitArrList, root, tPoint4d); + + } + + + private void doSelect(PickShape pickShape, UnorderList hitArrList, + BHNode bh, Point4d pickPos) { + + if ((bh == null) || (bh.bHull.isEmpty())) { + return; + } + + switch(bh.nodeType) { + case BHNode.BH_TYPE_LEAF: + if (((BHLeafNode)(bh)).isEnable() && + (((BHLeafNode) bh).leafIF instanceof GeometryAtom) && + ((GeometryAtom) (((BHLeafNode) + bh).leafIF)).source.isPickable && + pickShape.intersect(bh.bHull, pickPos)) { + hitArrList.add(bh); + } + break; + case BHNode.BH_TYPE_INTERNAL: + if (pickShape.intersect(bh.bHull, pickPos)) { + doSelect(pickShape, + hitArrList, + ((BHInternalNode)bh).getRightChild(), + pickPos); + doSelect(pickShape, + hitArrList, + ((BHInternalNode)bh).getLeftChild(), + pickPos); + } + break; + } + } + + BHNode selectAny(PickShape pickShape) { + + if((pickShape == null)||(root == null)) + return null; + + return doSelectAny(pickShape, root, tPoint4d); + + } + + + private BHNode doSelectAny(PickShape pickShape, BHNode bh, Point4d pickPos) { + + BHNode hitNode = null; + + if((bh == null) || (bh.bHull.isEmpty())) + return null; + + switch(bh.nodeType) { + case BHNode.BH_TYPE_LEAF: + if (((BHLeafNode)(bh)).isEnable() && + (((BHLeafNode) bh).leafIF instanceof GeometryAtom) && + ((GeometryAtom) (((BHLeafNode) + bh).leafIF)).source.isPickable && + pickShape.intersect(bh.bHull, pickPos)) { + return bh; + } + break; + case BHNode.BH_TYPE_INTERNAL: + if (pickShape.intersect(bh.bHull, pickPos)) { + hitNode = doSelectAny(pickShape, + ((BHInternalNode)bh).getRightChild(), + pickPos); + + if (hitNode != null) { + return hitNode; + } + + return doSelectAny(pickShape, + ((BHInternalNode)bh).getLeftChild(), + pickPos); + } + break; + } + return null; + } + + + private void create(BHNode bhArr[]) { + int i; + + if(bhArr == null) { + root = null; + return; + } + + if(bhArr.length == 1) { + bhArr[0].computeBoundingHull(); + root = (BHNode)bhArr[0]; + return; + } + + int centerValuesIndex[] = new int[bhArr.length]; + float centerValues[][] = computeCenterValues(bhArr, centerValuesIndex); + + /* + System.err.println("Length of array is " + bhArr.length); + for(int kk=0; kk depthUpperBound) { + int maxDepth = root.computeMaxDepth(0); + int leafCount = root.countNumberOfLeaves(); + double compDepth = Math.log(leafCount)/LOG_OF_2; + /* + System.err.println("BHTree - evaluate for reConstructTree ..."); + System.err.println("compDepth " + compDepth); + System.err.println("maxDepth " + maxDepth); + System.err.println("leafCount " + leafCount); + */ + + // Upper bound guard. + if(maxDepth > depthUpperBound) { + reConstructTree(leafCount); + maxDepth = root.computeMaxDepth(0); + /* + System.err.println("BHTree - Did reConstructTree ..."); + System.err.println("compDepth " + compDepth); + System.err.println("maxDepth " + maxDepth); + */ + } + + // Adjust depthUpperBound according to app. need. + // If we encounter lots of overlapping bounds, the re-balanced + // tree may not be an ideal balance tree. So there might be a + // likehood of maxDepth exceeding the preset depthUpperBound. + if(maxDepth > depthUpperBound) { + depthUpperBound = depthUpperBound + INCR_DEPTH_BOUND; + }else if((depthUpperBound != DEPTH_UPPER_BOUND) && + (maxDepth * 1.5 < depthUpperBound)) { + depthUpperBound = depthUpperBound - INCR_DEPTH_BOUND; + + if(depthUpperBound < DEPTH_UPPER_BOUND) { + // Be sure that DEPTH_UPPER_BOUND is the min. + depthUpperBound = DEPTH_UPPER_BOUND; + } + } + + // This is the only place for resetting estMaxDepth to the tree real + // maxDepth. Hence in cases where tree may get deteriorate fast, such + // as multiple inserts and deletes frequently. estMaxDepth is accuminated, + // and will lead to tree re-evaluation and possibly re-balancing. + estMaxDepth = maxDepth; + } + + } + + + // mark all elements of the node and its parent as needing updating + private void markParentChain(BHNode[] nArr, int size) { + BHNode node; + + for(int i=0; i=0; i--) { + sumCenters[i] = 0.0f; + ss[i] = 0.0f; + } + + for(i=arrLen-1; i>=0 ; i--) { + sumCenters[0] += centerValues[centerValuesIndex[i]][0]; + sumCenters[1] += centerValues[centerValuesIndex[i]][1]; + sumCenters[2] += centerValues[centerValuesIndex[i]][2]; + } + + means[0] = sumCenters[0]/(float)arrLen; + means[1] = sumCenters[1]/(float)arrLen; + means[2] = sumCenters[2]/(float)arrLen; + + for(i=arrLen-1; i>=0 ; i--) { + temp = (centerValues[centerValuesIndex[i]][0] - means[0]); + ss[0] += (temp*temp); + temp = (centerValues[centerValuesIndex[i]][1] - means[1]); + ss[1] += (temp*temp); + temp = (centerValues[centerValuesIndex[i]][2] - means[2]); + ss[2] += (temp*temp); + + } + + } + + // find the split axis (the highest ss and return its index) for + // a given set of ss values + int findSplitAxis ( float ss[] ) { + int splitAxis = -1; + float maxSS = 0.0f; + + // the largest ss index value + for (int i=0; i < 3; i++) { + if ( ss[i] > maxSS ) { + maxSS = ss[i]; + splitAxis = i; + } + } + return splitAxis; + } + + // Recursive method for constructing a binary tree. + void constructTree( BHInternalNode parent, BHNode bhArr[], + float[][] centerValues, + int[] centerValuesIndex ){ + + int i, splitAxis; + int rightSetCount = 0; + int leftSetCount = 0; + float means[] = new float[3]; + float ss[] = new float[3]; + + if(J3dDebug.devPhase) + if ( bhArr.length <= 1 ) { + // this is only here for debugging can be removed after testing + // to ensure that it never gets called + J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_1, + "constructTree - bhArr.length <= 1. Bad !!!\n"); + } + + computeMeansAndSumSquares(centerValues, centerValuesIndex, means, ss); + + splitAxis = findSplitAxis(ss); + + // an array of decision variables for storing the values of inside + // the right or left set for a particular element of bhArr. + // true if its in the left set, false if its in the right set + boolean leftOrRightSet[] = new boolean[bhArr.length]; + + if ( splitAxis == -1 ) { + // This is bad. Since we can't find a split axis, the best thing + // to do is to split the set in two sets; each with about the + // same number of elements. By doing this we can avoid constructing + // a skew tree. + + // split elements into half. + for ( i=0; i < bhArr.length; i++) { + if(leftSetCount > rightSetCount) { + rightSetCount++; + leftOrRightSet[i] = false; + } else { + leftSetCount++; + leftOrRightSet[i] = true; + } + } + } + else { + for ( i=0; i < bhArr.length; i++) { + // the split criterion, special multiple equals cases added + if ( centerValues[centerValuesIndex[i]][splitAxis] < + means[splitAxis]) { + + if(J3dDebug.devPhase) + J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4, + "Found a left element\n"); + leftSetCount++; + leftOrRightSet[i] = true; + } else if ( centerValues[centerValuesIndex[i]][splitAxis] > + means[splitAxis]) { + if(J3dDebug.devPhase) + J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4, + "Found a right element\n"); + rightSetCount++; + leftOrRightSet[i] = false; + } else { + if(J3dDebug.devPhase) + J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4, + "Found an equal element\n"); + if(leftSetCount > rightSetCount) { + rightSetCount++; + leftOrRightSet[i] = false; + } else { + leftSetCount++; + leftOrRightSet[i] = true; + } + } + } + } + + if(J3dDebug.devPhase) + J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_2, + "LeftSetCount " + leftSetCount + " RightSetCount "+ + rightSetCount + "\n"); + + + // Don't think that this guard is needed, but still like to have it. + // Just in case, bad means and the sum of squares might lead us into the guard. + if (leftSetCount == bhArr.length) { + if(J3dDebug.devPhase) + J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_1, + "Split Axis of = " + splitAxis + " didn't yield "+ + "any split among the objects ?\n"); + // split elements into half + rightSetCount = 0; + leftSetCount = 0; + for ( i=0; i < bhArr.length; i++) { + if(leftSetCount > rightSetCount) { + rightSetCount++; + leftOrRightSet[i] = false; + } else { + leftSetCount++; + leftOrRightSet[i] = true; + } + } + } else if (rightSetCount == bhArr.length) { + if(J3dDebug.devPhase) + J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_1, + "Split Axis of = " + splitAxis + " didn't yield "+ + "any split among the objects ?\n"); + // split elements into half + rightSetCount = 0; + leftSetCount = 0; + for ( i=0; i < bhArr.length; i++) { + if(leftSetCount > rightSetCount) { + rightSetCount++; + leftOrRightSet[i] = false; + } else { + leftSetCount++; + leftOrRightSet[i] = true; + } + } + } + + if(J3dDebug.devPhase) + if(J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4)) + // check to make sure that rightSet and leftSet sum to the + // number of elements in the original array. + if ( bhArr.length != (rightSetCount + leftSetCount) ) { + System.err.println("An error has occurred in spliting"); + } + + BHNode rightSet[] = new BHNode[rightSetCount]; + BHNode leftSet[] = new BHNode[leftSetCount]; + int centerValuesIndexR[] = new int[rightSetCount]; + int centerValuesIndexL[] = new int[leftSetCount]; + + rightSetCount = 0; + leftSetCount = 0; + + for (i=0; i < bhArr.length; i++) { + if ( leftOrRightSet[i] ) { // element in left set + leftSet[leftSetCount] = bhArr[i]; + centerValuesIndexL[leftSetCount] = centerValuesIndex[i]; + leftSetCount++; + } else { + rightSet[rightSetCount] = bhArr[i]; + centerValuesIndexR[rightSetCount] = centerValuesIndex[i]; + rightSetCount++; + } + } + + if (rightSet.length != 1) { + parent.rChild = new BHInternalNode(); + parent.rChild.setParent(parent); + constructTree((BHInternalNode)(parent.rChild), rightSet, centerValues, + centerValuesIndexR); + } else { + parent.rChild = rightSet[0]; + parent.rChild.setParent(parent); + } + + if (leftSet.length != 1) { + parent.lChild = new BHInternalNode(); + parent.lChild.setParent(parent); + constructTree((BHInternalNode)(parent.lChild), leftSet, centerValues, + centerValuesIndexL); + } else { + parent.lChild = leftSet[0]; + parent.lChild.setParent(parent); + } + + parent.combineBHull(parent.rChild, parent.lChild); + } + + + void reConstructTree(int numOfLeaf) { + if(root == null) + return; + + BHNode bhArr[] = new BHNode[numOfLeaf]; + int index[] = new int[1]; + index[0] = 0; + root.destroyTree(bhArr, index); + + /* + if(bhArr.length != index[0]) + System.err.println("BHTree - This isn't right!!! - bhArr.length " + + bhArr.length + " index " + index[0]); + */ + + create(bhArr); + + } + + void gatherTreeStatistics() { + + int leafCount = root.countNumberOfLeaves(); + int internalCount = root.countNumberOfInternals(); + int maxDepth = root.computeMaxDepth(0); + float averageDepth = root.computeAverageLeafDepth ( leafCount, 0); + + + System.err.println("Statistics for tree = " + this); + System.err.println("Total Number of nodes in tree = " + + (leafCount + internalCount) ); + System.err.println("Number of Leaf Nodes = " + leafCount ); + System.err.println("Number of Internal Nodes = " + internalCount ); + System.err.println("Maximum Leaf depth = " + maxDepth ); + System.err.println("Average Leaf depth = " + averageDepth ); + System.err.println("root.bHull = " + root.bHull); + // printTree(root); + + } + + + void printTree(BHNode bh) { + if(bh!= null) { + if(bh.nodeType == BHNode.BH_TYPE_INTERNAL) { + System.err.println("BH_TYPE_INTERNAL - bHull : " + bh); + System.err.println(bh.bHull); + System.err.println("rChild : " + ((BHInternalNode)bh).rChild + + " lChild : " + ((BHInternalNode)bh).lChild); + printTree(((BHInternalNode)bh).rChild); + printTree(((BHInternalNode)bh).lChild); + } + else if(bh.nodeType == BHNode.BH_TYPE_LEAF) { + System.err.println("BH_TYPE_LEAF - bHull : " + bh); + System.err.println(bh.bHull); + } + + } + + + } +} + + + + + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/Background.java b/j3d-core/src/classes/share/javax/media/j3d/Background.java new file mode 100644 index 0000000..180ceb6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Background.java @@ -0,0 +1,789 @@ +/* + * $RCSfile: Background.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The Background leaf node defines a solid background color + * and a background image that are used to fill the window at the + * beginning of each new frame. The background image may be null. + * It optionally allows background + * geometry---which is pre-tessellated onto a unit sphere and is drawn + * at infinity---to be referenced. It also specifies an application + * region in which this background is active. A Background node is + * active when its application region intersects the ViewPlatform's + * activation volume. If multiple Background nodes are active, the + * Background node that is "closest" to the eye will be used. If no + * Background nodes are active, then the window is cleared to black. + * + *

+ * The set of nodes that can be added to a BranchGroup associated with + * a Background node is limited. All Group nodes except + * ViewSpecificGroup are legal in a background geometry branch + * graph. The only Leaf nodes that are legal are Shape3D (except + * OrientedShape3D), Morph, Light, and Fog. The presence of any other + * Leaf node, including OrientedShape3D, or of a ViewSpecificGroup + * node will cause an IllegalSceneGraphException to be thrown. Note + * that Link nodes are not allowed; a background geometry branch graph + * must not reference shared subgraphs. NodeComponent objects can be + * shared between background branches and ordinary (non-background) + * branches or among different background branches, however. + * + *

+ * Light and Fog nodes in a background geometry branch graph do not + * affect nodes outside of the background geometry branch graph, and + * vice versa. Light and Fog nodes that appear in a background + * geometry branch graph must not be hierarchically scoped to any + * group node outside of that background geometry branch graph. + * Conversely, Light and Fog nodes that appear outside of a particular + * background geometry branch graph must not be hierarchically scoped + * to any group node in that background geometry branch graph. Any + * attempt to do so will be ignored. + * + *

+ * The influencing bounds of any Light or Fog node in a background + * geometry branch graph is effectively infinite (meaning that all + * lights can affect all geometry objects nodes within the background + * geometry graph, and that an arbitrary fog is selected). An + * application wishing to limit the scope of a Light or Fog node must + * use hierarchical scoping. + * + *

+ * Picking and collision is ignored for nodes inside a background + * geometry branch graph. + */ +public class Background extends Leaf { + /** + * Specifies that the Background allows read access to its application + * bounds and bounding leaf at runtime. + */ + public static final int + ALLOW_APPLICATION_BOUNDS_READ = CapabilityBits.BACKGROUND_ALLOW_APPLICATION_BOUNDS_READ; + + /** + * Specifies that the Background allows write access to its application + * bounds and bounding leaf at runtime. + */ + public static final int + ALLOW_APPLICATION_BOUNDS_WRITE = CapabilityBits.BACKGROUND_ALLOW_APPLICATION_BOUNDS_WRITE; + + /** + * Specifies that the Background allows read access to its image + * at runtime. + */ + public static final int + ALLOW_IMAGE_READ = CapabilityBits.BACKGROUND_ALLOW_IMAGE_READ; + + /** + * Specifies that the Background allows write access to its image + * at runtime. + */ + public static final int + ALLOW_IMAGE_WRITE = CapabilityBits.BACKGROUND_ALLOW_IMAGE_WRITE; + + /** + * Specifies that the Background allows read access to its color + * at runtime. + */ + public static final int + ALLOW_COLOR_READ = CapabilityBits.BACKGROUND_ALLOW_COLOR_READ; + + /** + * Specifies that the Background allows write access to its color + * at runtime. + */ + public static final int + ALLOW_COLOR_WRITE = CapabilityBits.BACKGROUND_ALLOW_COLOR_WRITE; + + /** + * Specifies that the Background allows read access to its + * background geometry at runtime. + */ + public static final int + ALLOW_GEOMETRY_READ = CapabilityBits.BACKGROUND_ALLOW_GEOMETRY_READ; + + /** + * Specifies that the Background allows write access to its + * background geometry at runtime. + */ + public static final int + ALLOW_GEOMETRY_WRITE = CapabilityBits.BACKGROUND_ALLOW_GEOMETRY_WRITE; + + /** + * Specifies that the Background allows read access to its image + * scale mode at runtime. + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_IMAGE_SCALE_MODE_READ = + CapabilityBits.BACKGROUND_ALLOW_IMAGE_SCALE_MODE_READ; + + /** + * Specifies that the Background allows write access to its image + * scale mode at runtime. + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_IMAGE_SCALE_MODE_WRITE = + CapabilityBits.BACKGROUND_ALLOW_IMAGE_SCALE_MODE_WRITE; + + + /** + * Indicates that no scaling of the background image is done. The + * image will be drawn in its actual size. If the window is + * smaller than the image, the image will be clipped. If the + * window is larger than the image, the portion of the window not + * filled by the image will be filled with the background color. + * In all cases, the upper left corner of the image is anchored at + * the upper-left corner of the window. + * This is the default mode. + * + * @see #setImageScaleMode + * + * @since Java 3D 1.3 + */ + public static final int SCALE_NONE = 0; + + /** + * Indicates that the background image is uniformly scaled to fit + * the window such that the entire image is visible. The image is + * scaled by the smaller of window.width/image.width + * and window.height/image.height. The image will + * exactly fill either the width or height of the window, but not + * necessarily both. The portion of the window not filled by the + * image will be filled with the background color. + * The upper left corner of the image is anchored at the + * upper-left corner of the window. + * + * @see #setImageScaleMode + * + * @since Java 3D 1.3 + */ + public static final int SCALE_FIT_MIN = 1; + + /** + * Indicates that the background image is uniformly scaled to fit + * the window such that the entire window is filled. The image is + * scaled by the larger of window.width/image.width + * and window.height/image.height. The image will + * entirely fill the window, but may by clipped either in X + * or Y. + * The upper left corner of the image is anchored at the + * upper-left corner of the window. + * + * @see #setImageScaleMode + * + * @since Java 3D 1.3 + */ + public static final int SCALE_FIT_MAX = 2; + + + /** + * Indicates that the background image is scaled to fit the + * window. The image is scaled non-uniformly in x and + * y by window.width/image.width and and + * window.height/image.height, respectively. The + * image will entirely fill the window. + * + * @see #setImageScaleMode + * + * @since Java 3D 1.3 + */ + public static final int SCALE_FIT_ALL = 3; + + /** + * Indicates that the background image is tiled to fill the entire + * window. The image is not scaled. + * The upper left corner of the image is anchored at the + * upper-left corner of the window. + * + * @see #setImageScaleMode + * + * @since Java 3D 1.3 + */ + public static final int SCALE_REPEAT = 4; + + /** + * Indicates that the background image is centered in the window + * and that no scaling of the image is done. The image will be + * drawn in its actual size. If the window is smaller than the + * image, the image will be clipped. If the window is larger than + * the image, the portion of the window not filled by the image + * will be filled with the background color. + * + * @see #setImageScaleMode + * + * @since Java 3D 1.3 + */ + public static final int SCALE_NONE_CENTER = 5; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_APPLICATION_BOUNDS_READ, + ALLOW_COLOR_READ, + ALLOW_GEOMETRY_READ, + ALLOW_IMAGE_READ, + ALLOW_IMAGE_SCALE_MODE_READ + }; + + + /** + * Constructs a Background node with default parameters. The default + * values are as follows: + *

    + * color : black (0,0,0)
    + * image : null
    + * geometry : null
    + * image scale mode : SCALE_NONE
    + * application bounds : null
    + * application bounding leaf : null
    + *
+ */ + public Background () { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a Background node with the specified color. + * This color is used to fill the window prior to drawing any + * objects in the scene. + */ + public Background(Color3f color) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((BackgroundRetained)this.retained).setColor(color); + } + + /** + * Constructs a Background node with the specified color. + * This color is used to fill the window prior to drawing any + * objects in the scene. + */ + public Background(float r, float g, float b) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((BackgroundRetained)this.retained).setColor(r, g, b); + } + + /** + * Constructs a Background node with the specified image. If this + * image is non-null, it is rendered to the window prior to + * drawing any objects in the scene. If the image is smaller + * than the window, + * then that portion of the window not covered by the image is + * filled with the background color. + * + * @param image pixel array object used as the background image + * + * @exception IllegalArgumentException if the image class of the specified + * ImageComponent2D is ImageClass.NIO_IMAGE_BUFFER. + */ + public Background(ImageComponent2D image) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + if((image != null) && + (image.getImageClass() == ImageComponent.ImageClass.NIO_IMAGE_BUFFER)) { + throw new IllegalArgumentException(J3dI18N.getString("Background14")); + } + + ((BackgroundRetained)this.retained).setImage(image); + } + + /** + * Constructs a Background node with the specified geometry. + * If non-null, this background geometry is drawn on top of + * the background color and image using a projection + * matrix that essentially puts the geometry at infinity. The geometry + * should be pre-tessellated onto a unit sphere. + * @param branch the root of the background geometry + * @exception IllegalSharingException if the BranchGroup node + * is a child of any Group node, or is already attached to a Locale, + * or is already referenced by another Background node. + * @exception IllegalSceneGraphException if specified branch graph + * contains an illegal node. + */ + public Background(BranchGroup branch) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((BackgroundRetained)this.retained).setGeometry(branch); + } + + /** + * Sets the background color to the specified color. + * This color is used to fill the window prior to drawing any + * objects in the scene. + * @param color the new background color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setColor(Color3f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Background0")); + + if (isLive()) + ((BackgroundRetained)this.retained).setColor(color); + else + ((BackgroundRetained)this.retained).initColor(color); + + } + + /** + * Sets the background color to the specified color. + * This color is used to fill the window prior to drawing any + * objects in the scene. + * @param r the red component of the background color + * @param g the green component of the background color + * @param b the blue component of the background color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setColor(float r, float g, float b) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Background0")); + + if (isLive()) + ((BackgroundRetained)this.retained).setColor(r, g, b); + else + ((BackgroundRetained)this.retained).initColor(r, g, b); + } + + /** + * Retrieves the background color. + * @param color the vector that will receive the current background color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getColor(Color3f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Background2")); + + ((BackgroundRetained)this.retained).getColor(color); + } + + /** + * Sets the background image to the specified image. If this + * image is non-null, it is rendered to the window prior to + * drawing any objects in the scene. If the image is smaller + * than the window, + * then that portion of the window not covered by the image is + * filled with the background color. + * + * @param image new pixel array object used as the background image + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalSharingException if this Background is live and + * the specified image is being used by a Canvas3D as an off-screen buffer. + * + * @exception IllegalSharingException if this Background is + * being used by an immediate mode context and + * the specified image is being used by a Canvas3D as an off-screen buffer. + * + * @exception IllegalArgumentException if the image class of the specified + * ImageComponent2D is ImageClass.NIO_IMAGE_BUFFER. + */ + public void setImage(ImageComponent2D image) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_IMAGE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Background3")); + + BackgroundRetained bgRetained = (BackgroundRetained)this.retained; + + if((image != null) && + (image.getImageClass() == ImageComponent.ImageClass.NIO_IMAGE_BUFFER)) { + throw new IllegalArgumentException(J3dI18N.getString("Background14")); + } + + // Do illegal sharing check + if(image != null) { + ImageComponent2DRetained imageRetained = (ImageComponent2DRetained) image.retained; + if(imageRetained.getUsedByOffScreen()) { + if(isLive()) { + throw new IllegalSharingException(J3dI18N.getString("Background12")); + } + if(bgRetained.getInImmCtx()) { + throw new IllegalSharingException(J3dI18N.getString("Background13")); + } + } + } + + if (isLive()) + bgRetained.setImage(image); + else + bgRetained.initImage(image); + } + + /** + * Retrieves the background image. + * @return the current background image + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ImageComponent2D getImage() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_IMAGE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Background4")); + + return ((BackgroundRetained)this.retained).getImage(); + } + + /** + * Sets the image scale mode for this Background node. + * + * @param imageScaleMode the new image scale mode, one of: + * SCALE_NONE, SCALE_FIT_MIN, SCALE_FIT_MAX, SCALE_FIT_ALL, + * SCALE_REPEAT, or SCALE_NONE_CENTER. + * + * @exception IllegalArgumentException if imageScaleMode + * is a value other than SCALE_NONE, SCALE_FIT_MIN, SCALE_FIT_MAX, + * SCALE_FIT_ALL, SCALE_REPEAT, or SCALE_NONE_CENTER. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setImageScaleMode(int imageScaleMode) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_IMAGE_SCALE_MODE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Background9")); + + switch (imageScaleMode) { + case SCALE_NONE: + case SCALE_FIT_MIN: + case SCALE_FIT_MAX: + case SCALE_FIT_ALL: + case SCALE_REPEAT: + case SCALE_NONE_CENTER: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("Background11")); + } + + if (isLive()) + ((BackgroundRetained)this.retained).setImageScaleMode(imageScaleMode); + else + ((BackgroundRetained)this.retained).initImageScaleMode(imageScaleMode); + + } + + /** + * Retrieves the current image scale mode. + * @return the current image scale mode, one of: + * SCALE_NONE, SCALE_FIT_MIN, SCALE_FIT_MAX, SCALE_FIT_ALL, + * SCALE_REPEAT, or SCALE_NONE_CENTER. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getImageScaleMode() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_IMAGE_SCALE_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Background10")); + return ((BackgroundRetained)this.retained).getImageScaleMode(); + } + + /** + * Sets the background geometry to the specified BranchGroup node. + * If non-null, this background geometry is drawn on top of + * the background color and image using a projection + * matrix that essentially puts the geometry at infinity. The geometry + * should be pre-tessellated onto a unit sphere. + * @param branch the root of the background geometry + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalSharingException if the BranchGroup node + * is a child of any Group node, or is already attached to a Locale, + * or is already referenced by another Background node. + * @exception IllegalSceneGraphException if specified branch graph + * contains an illegal node. + */ + public void setGeometry(BranchGroup branch) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_GEOMETRY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Background5")); + + if (isLive()) + ((BackgroundRetained)this.retained).setGeometry(branch); + else + ((BackgroundRetained)this.retained).initGeometry(branch); + } + + /** + * Retrieves the background geometry. + * @return the BranchGroup node that is the root of the background + * geometry + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BranchGroup getGeometry() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Background6")); + + return ((BackgroundRetained)this.retained).getGeometry(); + } + + /** + * Set the Background's application region to the specified bounds. + * This is used when the application bounding leaf is set to null. + * @param region the bounds that contains the Background's new application + * region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setApplicationBounds(Bounds region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Background7")); + + if (isLive()) + ((BackgroundRetained)this.retained).setApplicationBounds(region); + else + ((BackgroundRetained)this.retained).initApplicationBounds(region); + } + + /** + * Retrieves the Background node's application bounds. + * @return this Background's application bounds information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getApplicationBounds() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Background8")); + + return ((BackgroundRetained)this.retained).getApplicationBounds(); + } + + /** + * Set the Background's application region to the specified bounding leaf. + * When set to a value other than null, this overrides the application + * bounds object. + * @param region the bounding leaf node used to specify the Background + * node's new application region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setApplicationBoundingLeaf(BoundingLeaf region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Background7")); + + if (isLive()) + ((BackgroundRetained)this.retained).setApplicationBoundingLeaf(region); + else + ((BackgroundRetained)this.retained).initApplicationBoundingLeaf(region); + } + + /** + * Retrieves the Background node's application bounding leaf. + * @return this Background's application bounding leaf information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BoundingLeaf getApplicationBoundingLeaf() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Background8")); + + return ((BackgroundRetained)this.retained).getApplicationBoundingLeaf(); + } + + /** + * Creates the retained mode BackgroundRetained object that this + * Background component object will point to. + */ + void createRetained() { + this.retained = new BackgroundRetained(); + this.retained.setSource(this); + } + + + /** + * Creates a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied.
+ * Background geometry will not clone in this operation. + * It is the user's responsibility + * to call cloneTree on that branchGroup. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Background b = new Background(); + b.duplicateNode(this, forceDuplicate); + return b; + } + + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @exception ClassCastException if originalNode is not an instance of + * Background + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean + forceDuplicate) { + checkDuplicateNode(originalNode, forceDuplicate); + } + + + /** + * Copies all Background information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + BackgroundRetained attr = (BackgroundRetained) originalNode.retained; + BackgroundRetained rt = (BackgroundRetained) retained; + + Color3f c = new Color3f(); + attr.getColor(c); + rt.initColor(c); + rt.initApplicationBounds(attr.getApplicationBounds()); + rt.initGeometry(attr.getGeometry()); + // issue # 563: add call to cloneTree() + rt.initGeometry((BranchGroup) (attr.getGeometry() == null ? null : attr.getGeometry().cloneTree(true))); + rt.initImage((ImageComponent2D) getNodeComponent( + attr.getImage(), + forceDuplicate, + originalNode.nodeHashtable)); + + // this will be updated in updateNodeReferences + rt.initApplicationBoundingLeaf(attr.getApplicationBoundingLeaf()); + } + + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances + * + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + super.updateNodeReferences(referenceTable); + + BackgroundRetained rt = (BackgroundRetained) retained; + BoundingLeaf bl= rt.getApplicationBoundingLeaf(); + + if (bl != null) { + Object o = referenceTable.getNewObjectReference(bl); + rt.initApplicationBoundingLeaf((BoundingLeaf) o); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BackgroundRetained.java b/j3d-core/src/classes/share/javax/media/j3d/BackgroundRetained.java new file mode 100644 index 0000000..d21930e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BackgroundRetained.java @@ -0,0 +1,795 @@ +/* + * $RCSfile: BackgroundRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; + + +/** + * The Background leaf node defines either a solid background color + * or a background image that is used to fill the window at the + * beginning of each new frame. It also specifies an application + * region in which this background is active. + */ +class BackgroundRetained extends LeafRetained { + + static final int COLOR_CHANGED = 0x00001; + static final int IMAGE_CHANGED = 0x00002; + static final int GEOMETRY_CHANGED = 0x00004; + static final int BOUNDS_CHANGED = 0x00008; + static final int BOUNDINGLEAF_CHANGED = 0x00010; + static final int IMAGE_SCALE_CHANGED = 0x00020; + // Background color or image. If non-null, the image overrides the + // color. + Color3f color = new Color3f(0.0f, 0.0f, 0.0f); + ImageComponent2DRetained image = null; + Texture2DRetained texture = null; + + // the image scale mode if image is used. + int imageScaleMode = Background.SCALE_NONE; + + /** + * The Boundary object defining the lights's application region. + */ + Bounds applicationRegion = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * Background geometry branch group + */ + BranchGroup geometryBranch = null; + + /** + * The transformed value of the applicationRegion. + */ + Bounds transformedRegion = null; + + /** + * The state structure used for Background Geometry + */ + SetLiveState setLiveState = null; + + /** + * The locale of this Background node since we don't have mirror object + * when clearLive is called + * locale is set to null, we still want locale to have a + * non-null value, since renderingEnv structure may be using the + * locale + */ + Locale cachedLocale = null; + + // This is true when this background is referenced in an immediate mode context + boolean inImmCtx = false; + + // list of light nodes for background geometry + ArrayList lights = new ArrayList(); + + // list of fog nodes for background geometry + ArrayList fogs = new ArrayList(); + + // a list of background geometry atoms + ArrayList bgGeometryAtomList = new ArrayList(); + + // false is background geometry atoms list has changed + boolean bgGeometryAtomListDirty = true; + + // an array of background geometry atoms + GeometryAtom[] bgGeometryAtoms = null; + + // Target threads to be notified when light changes + // Note, the rendering env structure only get notified + // when there is a bounds related change + final static int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_RENDER; + + // Is true, if the background is viewScoped + boolean isViewScoped = false; + + BackgroundRetained () { + this.nodeType = NodeRetained.BACKGROUND; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + /** + * Initializes the background color to the specified color. + * This color is used + * if the image is null. + * @param color the new background color + */ + final void initColor(Color3f color) { + this.color.set(color); + } + + + /** + * Sets the background color to the specified color. This color is used + * if the image is null. + * @param color the new background color + */ + final void setColor(Color3f color) { + initColor(color); + if (source.isLive()) { + sendMessage(COLOR_CHANGED, new Color3f(color)); + } + } + + /** + * Initializes the background color to the specified color. + * This color is used + * if the image is null. + * @param r the red component of the background color + * @param g the green component of the background color + * @param b the blue component of the background color + */ + final void initColor(float r, float g, float b) { + this.color.x = r; + this.color.y = g; + this.color.z = b; + } + + + + /** + * Sets the background color to the specified color. This color is used + * if the image is null. + * @param r the red component of the background color + * @param g the green component of the background color + * @param b the blue component of the background color + */ + final void setColor(float r, float g, float b) { + setColor(new Color3f(r, g, b)); + } + + + /** + * Retrieves the background color. + * @param color the vector that will receive the current background color + */ + final void getColor(Color3f color) { + color.set(this.color); + } + + /** + * Initialize the image scale mode to the specified mode + * @imageScaleMode the image scale mode to the used + */ + final void initImageScaleMode(int imageScaleMode){ + this.imageScaleMode = imageScaleMode; + } + + /** + * Sets the image scale mode for this Background node. + * @param imageScaleMode the image scale mode + */ + final void setImageScaleMode(int imageScaleMode){ + initImageScaleMode(imageScaleMode); + if(source.isLive()){ + sendMessage(IMAGE_SCALE_CHANGED, new Integer(imageScaleMode)); + } + } + + /** + * gets the image scale mode for this Background node. + */ + final int getImageScaleMode(){ + return imageScaleMode; + } + + /** + * Initializes the background image to the specified image. + * @param image new ImageCompoent2D object used as the background image + */ + final void initImage(ImageComponent2D img) { + int texFormat; + + if (img == null) { + image = null; + texture = null; + return; + } + + if (img.retained != image ) { + image = (ImageComponent2DRetained) img.retained; + image.setEnforceNonPowerOfTwoSupport(true); + switch(image.getNumberOfComponents()) { + case 1: + texFormat = Texture.INTENSITY; + break; + case 2: + texFormat = Texture.LUMINANCE_ALPHA; + break; + case 3: + texFormat = Texture.RGB; + break; + case 4: + texFormat = Texture.RGBA; + break; + default: + assert false; + return; + } + + Texture2D tex2D = new Texture2D(Texture.BASE_LEVEL, texFormat, + img.getWidth(), img.getHeight()); + texture = (Texture2DRetained) tex2D.retained; + // Background is special case of Raster. + texture.setUseAsRaster(true); + // Fix to issue 373 : ImageComponent.set(BufferedImage) ignored when used by Background + image.addUser(texture); + texture.initImage(0,img); + } + } + + /** + * Sets the background image to the specified image. + * @param image new ImageCompoent3D object used as the background image + */ + final void setImage(ImageComponent2D img) { + if (source.isLive()) { + if (texture != null) { + texture.clearLive(refCount); + } + } + initImage(img); + if (source.isLive()) { + if (texture != null) { + texture.setLive(inBackgroundGroup, refCount); + } + + sendMessage(IMAGE_CHANGED, + (texture != null ? texture.mirror : null)); + + } + } + + /** + * Retrieves the background image. + * @return the current background image + */ + final ImageComponent2D getImage() { + return (image == null ? null : + (ImageComponent2D)image.source); + } + + /** + * Initializes the background geometry branch group to the specified branch. + * @param branch new branch group object used for background geometry + */ + final void initGeometry(BranchGroup branch) { + geometryBranch = branch; + } + + + /** + * Sets the background geometry branch group to the specified branch. + * @param branch new branch group object used for background geometry + */ + final void setGeometry(BranchGroup branch) { + int numMessages = 0; + int i; + + if (source.isLive()) { + J3dMessage m[]; + if (geometryBranch != null) + numMessages+=2; // REMOVE_NODES, ORDERED_GROUP_REMOVED + if (branch != null) + numMessages+=2; // INSERT_NODES, ORDERED_GROUP_INSERTED + m = new J3dMessage[numMessages]; + for (i=0; icloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + BackgroundSound b = new BackgroundSound(); + b.duplicateNode(this, forceDuplicate); + return b; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @exception ClassCastException if originalNode is not an instance of + * Sound + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + checkDuplicateNode(originalNode, forceDuplicate); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BackgroundSoundRetained.java b/j3d-core/src/classes/share/javax/media/j3d/BackgroundSoundRetained.java new file mode 100644 index 0000000..8643f68 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BackgroundSoundRetained.java @@ -0,0 +1,47 @@ +/* + * $RCSfile: BackgroundSoundRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * BackgroundSound is a class for sounds that are not spatially rendered. + * These sounds are simply added to the stereo sound mix without modification. + * These could be used to play mono or stereo music, or ambient sound effects. + */ +class BackgroundSoundRetained extends SoundRetained { + + BackgroundSoundRetained() { + this.nodeType = NodeRetained.BACKGROUNDSOUND; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BadTransformException.java b/j3d-core/src/classes/share/javax/media/j3d/BadTransformException.java new file mode 100644 index 0000000..911a046 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BadTransformException.java @@ -0,0 +1,74 @@ +/* + * $RCSfile: BadTransformException.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates an attempt to use a Tranform3D object that is + * inappropriate for the object in which it is being used. + * For example: + *

    + *
  • + * Transforms that are used in the scene graph, within a TransformGroup + * node, must be affine. They may optionally contain a non-uniform + * scale and/or a shear, subject to other listed restrictions. + *
  • + * All transforms in the TransformGroup nodes above a ViewPlatform + * object must be congruent. This ensures that the Vworld coordinates to + * ViewPlatform coordinates transform is angle and length-preserving with + * no shear and only uniform scale. + *
  • + * Most viewing transforms other than those in the scene graph can + * only contain translation and rotation. + *
  • + * The projection transform is allowed to be non-affine, but it + * must either be a single point perspective projection or a parallel + * projection. + *
+ */ +public class BadTransformException extends RuntimeException{ + +/** + * Create the exception object with default values. + */ + public BadTransformException(){ + } + +/** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public BadTransformException(String str){ + + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Behavior.java b/j3d-core/src/classes/share/javax/media/j3d/Behavior.java new file mode 100644 index 0000000..e825e37 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Behavior.java @@ -0,0 +1,527 @@ +/* + * $RCSfile: Behavior.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +import java.util.Enumeration; + +/** + * The Behavior leaf node provides a framework for adding user-defined + * actions into the scene graph. Behavior is an abstract class that + * defines two methods that must be overridden by a subclass: An + * initialization method, called once when the behavior + * becomes "live," and a processStimulus method called + * whenever appropriate by the Java 3D behavior scheduler. The + * Behavior node also contains an enable flag, a scheduling region, + * a scheduling interval, and a wakeup condition. + * + *

+ * The scheduling region defines a spatial volume that serves + * to enable the scheduling of Behavior nodes. A Behavior node is + * active (can receive stimuli) whenever an active ViewPlatform's + * activation volume intersects a Behavior object's scheduling + * region. Only active behaviors can receive stimuli. + * + *

+ * The scheduling interval defines a partial order of execution + * for behaviors that wake up in response to the same wakeup condition + * (that is, those behaviors that are processed at the same "time"). + * Given a set of behaviors whose wakeup conditions are satisfied at + * the same time, the behavior scheduler will execute all behaviors in + * a lower scheduling interval before executing any behavior in a + * higher scheduling interval. Within a scheduling interval, + * behaviors can be executed in any order, or in parallel. Note that + * this partial ordering is only guaranteed for those behaviors that + * wake up at the same time in response to the same wakeup condition, + * for example, the set of behaviors that wake up every frame in + * response to a WakeupOnElapsedFrames(0) wakeup condition. + * + *

+ * The initialize method allows a Behavior object to + * initialize its internal state and specify its initial wakeup + * condition(s). Java 3D invokes a behavior's initialize code when the + * behavior's containing BranchGroup node is added to the virtual + * universe. Java 3D does not invoke the initialize method in a new + * thread. Thus, for Java 3D to regain control, the initialize method + * must not execute an infinite loop; it must return. Furthermore, a + * wakeup condition must be set or else the behavior's processStimulus + * method is never executed. + * + *

+ * The processStimulus method receives and processes a + * behavior's ongoing messages. The Java 3D behavior scheduler invokes + * a Behavior node's processStimulus method when an active ViewPlatform's + * activation volume intersects a Behavior object's scheduling region + * and all of that behavior's wakeup criteria are satisfied. The + * processStimulus method performs its computations and actions + * (possibly including the registration of state change information + * that could cause Java 3D to wake other Behavior objects), + * establishes its next wakeup condition, and finally exits. + * A typical behavior will modify one or more nodes or node components + * in the scene graph. These modifications can happen in parallel + * with rendering. In general, applications cannot count on behavior + * execution being synchronized with rendering. There are two + * exceptions to this general rule: + *

    + *
  1. All modifications to scene graph objects (not including geometry + * by-reference or texture by-reference) made from the + * processStimulus method of a single behavior instance + * are guaranteed to take effect in the same rendering frame.
  2. + *
  3. All modifications to scene graph objects (not including geometry + * by-reference or texture by-reference) made from the + * processStimulus methods of the set of behaviors that + * wake up in response to a WakeupOnElapsedFrames(0) wakeup condition + * are guaranteed to take effect in the same rendering frame.
  4. + *
+ * + * Note that modifications to geometry by-reference or texture + * by-reference are not guaranteed to show up in the same frame as + * other scene graph changes. + * + *

+ * Code Structure + *

+ * When the Java 3D behavior scheduler invokes a Behavior object's + * processStimulus method, that method may perform any computation it + * wishes. Usually, it will change its internal state and specify its + * new wakeup conditions. Most probably, it will manipulate scene + * graph elements. However, the behavior code can only change those + * aspects of a scene graph element permitted by the capabilities + * associated with that scene graph element. A scene graph's + * capabilities restrict behavioral manipulation to those + * manipulations explicitly allowed. + * + *

+ * The application must provide the Behavior object with references to + * those scene graph elements that the Behavior object will + * manipulate. The application provides those references as arguments + * to the behavior's constructor when it creates the Behavior + * object. Alternatively, the Behavior object itself can obtain access + * to the relevant scene graph elements either when Java 3D invokes + * its initialize method or each time Java 3D invokes its + * processStimulus method. + * + *

+ * Behavior methods have a very rigid structure. Java 3D assumes that + * they always run to completion (if needed, they can spawn + * threads). Each method's basic structure consists of the following: + * + *

+ *

    + *
  • Code to decode and extract references from the WakeupCondition + * enumeration that caused the object's awakening.
  • + *
  • Code to perform the manipulations associated with the + * WakeupCondition
  • + *
  • Code to establish this behavior's new WakeupCondition
  • + *
  • A path to Exit (so that execution returns to the Java 3D + * behavior scheduler)
  • + *
+ * + *

+ * WakeupCondition Object + *

+ * A WakeupCondition object is an abstract class specialized to + * fourteen different WakeupCriterion objects and to four combining + * objects containing multiple WakeupCriterion objects. A Behavior + * node provides the Java 3D behavior scheduler with a WakeupCondition + * object. When that object's WakeupCondition has been satisfied, the + * behavior scheduler hands that same WakeupCondition back to the + * Behavior via an enumeration. + * + *

+ * WakeupCriterion Object + *

+ * Java 3D provides a rich set of wakeup criteria that Behavior + * objects can use in specifying a complex WakeupCondition. These + * wakeup criteria can cause Java 3D's behavior scheduler to invoke a + * behavior's processStimulus method whenever + * + *

    + *
  • The center of a ViewPlatform enters a specified region
  • + *
  • The center of a ViewPlatform exits a specified region
  • + *
  • A behavior is activated
  • + *
  • A behavior is deactivated
  • + *
  • A specified TransformGroup node's transform changes
  • + *
  • Collision is detected between a specified Shape3D node's + * Geometry object and any other object
  • + *
  • Movement occurs between a specified Shape3D node's Geometry + * object and any other object with which it collides
  • + *
  • A specified Shape3D node's Geometry object no longer collides + * with any other object
  • + *
  • A specified Behavior object posts a specific event
  • + *
  • A specified AWT event occurs
  • + *
  • A specified time interval elapses
  • + *
  • A specified number of frames have been drawn
  • + *
  • The center of a specified Sensor enters a specified region
  • + *
  • The center of a specified Sensor exits a specified region
  • + *
+ * + *

+ * A Behavior object constructs a WakeupCriterion by constructing the + * appropriate criterion object. The Behavior object must provide the + * appropriate arguments (usually a reference to some scene graph + * object and possibly a region of interest). Thus, to specify a + * WakeupOnViewPlatformEntry, a behavior would specify the region that + * will cause the behavior to execute if an active ViewPlatform enters it. + * + *

+ * Note that a unique WakeupCriterion object must be used with each + * instance of a Behavior. Sharing wakeup criteria among different + * instances of a Behavior is illegal. + * + *

+ * Additional Information + *

+ * For more information, see the + * Introduction to the Java 3D API and + * Behaviors and Interpolators + * documents. + * + * @see WakeupCondition + */ + +public abstract class Behavior extends Leaf { + + /** + * Constructs a Behavior node with default parameters. The default + * values are as follows: + *

    + * enable flag : true
    + * scheduling bounds : null
    + * scheduling bounding leaf : null
    + * scheduling interval : numSchedulingIntervals / 2
    + *
+ */ + public Behavior() { + } + + /** + * Initialize this behavior. Classes that extend Behavior must + * provide their own initialize method. + *
+ * NOTE: Applications should not call this method. It is called + * by the Java 3D behavior scheduler. + */ + public abstract void initialize(); + + /** + * Process a stimulus meant for this behavior. This method is invoked + * if the Behavior's wakeup criteria are satisfied and an active + * ViewPlatform's + * activation volume intersects with the Behavior's scheduling region. + * Classes that extend Behavior must provide their own processStimulus + * method. + *
+ * NOTE: Applications should not call this method. It is called + * by the Java 3D behavior scheduler. + * @param criteria an enumeration of triggered wakeup criteria for this + * behavior + */ + public abstract void processStimulus(Enumeration criteria); + + /** + * Set the Behavior's scheduling region to the specified bounds. + * This is used when the scheduling bounding leaf is set to null. + * @param region the bounds that contains the Behavior's new scheduling + * region + */ + public void setSchedulingBounds(Bounds region) { + ((BehaviorRetained)this.retained).setSchedulingBounds(region); + } + + /** + * Retrieves the Behavior node's scheduling bounds. + * @return this Behavior's scheduling bounds information + */ + public Bounds getSchedulingBounds() { + return ((BehaviorRetained)this.retained).getSchedulingBounds(); + } + + /** + * Set the Behavior's scheduling region to the specified bounding leaf. + * When set to a value other than null, this overrides the scheduling + * bounds object. + * @param region the bounding leaf node used to specify the Behavior + * node's new scheduling region + */ + public void setSchedulingBoundingLeaf(BoundingLeaf region) { + ((BehaviorRetained)this.retained).setSchedulingBoundingLeaf(region); + } + + /** + * Retrieves the Behavior node's scheduling bounding leaf. + * @return this Behavior's scheduling bounding leaf information + */ + public BoundingLeaf getSchedulingBoundingLeaf() { + return ((BehaviorRetained)this.retained).getSchedulingBoundingLeaf(); + } + + /** + * Creates the retained mode BehaviorRetained object that this + * Behavior object will point to. + */ + void createRetained() { + this.retained = new BehaviorRetained(); + this.retained.setSource(this); + } + + /** + * Defines this behavior's wakeup criteria. This method + * may only be called from a Behavior object's initialize + * or processStimulus methods to (re)arm the next wakeup. + * It should be the last thing done by those methods. + * @param criteria the wakeup criteria for this behavior + * @exception IllegalStateException if this method is called by + * a method other than initialize or processStimulus + */ + protected void wakeupOn(WakeupCondition criteria) { + BehaviorRetained behavret = (BehaviorRetained) this.retained; + synchronized (behavret) { + if (!behavret.inCallback) { + throw new IllegalStateException(J3dI18N.getString("Behavior0")); + } + } + behavret.wakeupOn(criteria); + } + + /** + * Retrieves this behavior's current wakeup condition as set by + * the wakeupOn method. If no wakeup condition is currently + * active, null will be returned. In particular, this means that + * null will be returned if Java 3D is executing this behavior's + * processStimulus routine and wakeupOn has not yet been called to + * re-arm the wakeup condition for next time. + * + * @return the current wakeup condition for this behavior + * + * @since Java 3D 1.3 + */ + protected WakeupCondition getWakeupCondition() { + return ((BehaviorRetained)this.retained).getWakeupCondition(); + } + + /** + * Posts the specified postId to the Behavior Scheduler. All behaviors + * that have registered WakeupOnBehaviorPost with this postId, or a postId + * of 0, and with this behavior, or a null behavior, will have that wakeup + * condition met. + *

+ * This feature allows applications to send arbitrary events into the + * behavior scheduler stream. It can be used as a notification scheme + * for communicating events to behaviors in the system. + *

+ * @param postId the Id being posted + * + * @see WakeupOnBehaviorPost + */ + public void postId(int postId){ + ((BehaviorRetained)this.retained).postId(postId); + } + + /** + * Enables or disables this Behavior. The default state is enabled. + * @param state true or false to enable or disable this Behavior + */ + public void setEnable(boolean state) { + ((BehaviorRetained)this.retained).setEnable(state); + } + + /** + * Retrieves the state of the Behavior enable flag. + * @return the Behavior enable state + */ + public boolean getEnable() { + return ((BehaviorRetained)this.retained).getEnable(); + } + + /** + * Returns the number of scheduling intervals supported by this + * implementation of Java 3D. The minimum number of supported + * intervals must be at least 10. The default scheduling interval + * for each behavior instance is set to + * numSchedulingIntervals / 2. + * + * @return the number of supported scheduling intervals + * + * @since Java 3D 1.3 + */ + public static int getNumSchedulingIntervals() { + return BehaviorRetained.NUM_SCHEDULING_INTERVALS; + } + + + /** + * Sets the scheduling interval of this Behavior node to the + * specified value. + * + * The scheduling interval defines a partial order of execution + * for behaviors that wake up in response to the same wakeup + * condition (that is, those behaviors that are processed at the + * same "time"). Given a set of behaviors whose wakeup conditions + * are satisfied at the same time, the behavior scheduler will + * execute all behaviors in a lower scheduling interval before + * executing any behavior in a higher scheduling interval. Within + * a scheduling interval, behaviors can be executed in any order, + * or in parallel. Note that this partial ordering is only + * guaranteed for those behaviors that wake up at the same time in + * response to the same wakeup condition, for example, the set of + * behaviors that wake up every frame in response to a + * WakeupOnElapsedFrames(0) wakeup condition. + * + * The default value is numSchedulingIntervals / 2. + * + * @param schedulingInterval the new scheduling interval + * + * @exception IllegalArgumentException if + * schedulingInterval < 0 or + * schedulingInterval >= + * numSchedulingIntervals + * + * @since Java 3D 1.3 + */ + public void setSchedulingInterval(int schedulingInterval) { + if (schedulingInterval < 0 || + schedulingInterval >= getNumSchedulingIntervals()) { + + throw new IllegalStateException(J3dI18N.getString("Behavior1")); + } + + ((BehaviorRetained)this.retained). + setSchedulingInterval(schedulingInterval); + } + + /** + * Retrieves the current scheduling interval of this Behavior + * node. + * + * @return the current scheduling interval + * + * @since Java 3D 1.3 + */ + public int getSchedulingInterval() { + return ((BehaviorRetained)this.retained).getSchedulingInterval(); + } + + /** + * Returns the primary view associated with this behavior. This method + * is useful with certain types of behaviors (e.g., Billboard, LOD) that + * rely on per-View information and with behaviors in general in regards + * to scheduling (the distance from the view platform determines the + * active behaviors). The "primary" view is defined to be the first + * View attached to a live ViewPlatform, if there is more than one active + * View. So, for instance, Billboard behaviors would be oriented toward + * this primary view, in the case of multiple active views into the same + * scene graph. + */ + protected View getView() { + return ((BehaviorRetained)this.retained).getView(); + } + + + /** + * Copies all Behavior information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + BehaviorRetained attr = (BehaviorRetained) originalNode.retained; + BehaviorRetained rt = (BehaviorRetained) retained; + + rt.setEnable(attr.getEnable()); + rt.setSchedulingBounds(attr.getSchedulingBounds()); + rt.setSchedulingInterval(attr.getSchedulingInterval()); + // will set to the correct one in updateNodeReferences + rt.setSchedulingBoundingLeaf(attr.getSchedulingBoundingLeaf()); + + } + + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + super.updateNodeReferences(referenceTable); + + BehaviorRetained rt = (BehaviorRetained) retained; + BoundingLeaf bl= rt.getSchedulingBoundingLeaf(); + + // check for schedulingBoundingLeaf + if (bl != null) { + Object o = referenceTable.getNewObjectReference(bl); + rt.setSchedulingBoundingLeaf((BoundingLeaf) o); + + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BehaviorRetained.java b/j3d-core/src/classes/share/javax/media/j3d/BehaviorRetained.java new file mode 100644 index 0000000..61c45ab --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BehaviorRetained.java @@ -0,0 +1,530 @@ +/* + * $RCSfile: BehaviorRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.ArrayList; + +/** + * Behavior is an abstract class that contains the framework for all + * behavioral components in Java 3D. + */ + +class BehaviorRetained extends LeafRetained { + // These bitmasks are used to quickly tell what conditions this behavior + // is waiting for. Currently BehaviorStructure only used 4 of them. + static final int WAKEUP_ACTIVATE_INDEX = 0; + static final int WAKEUP_DEACTIVATE_INDEX = 1; + static final int WAKEUP_VP_ENTRY_INDEX = 2; + static final int WAKEUP_VP_EXIT_INDEX = 3; + static final int WAKEUP_TIME_INDEX = 4; + + static final int NUM_WAKEUPS = 5; + + static final int WAKEUP_ACTIVATE = 0x0001; + static final int WAKEUP_DEACTIVATE = 0x0002; + static final int WAKEUP_VP_ENTRY = 0x0004; + static final int WAKEUP_VP_EXIT = 0x0008; + static final int WAKEUP_TIME = 0x0010; + + /** + * The number of scheduling intervals supported by this + * implementation. This is fixed for a particular implementation + * and must be at least 10. + */ + static final int NUM_SCHEDULING_INTERVALS = 10; + + // different types of IndexedUnorderedSet that use in BehaviorStructure + static final int BEHAIVORS_IN_BS_LIST = 0; + static final int SCHEDULE_IN_BS_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + /** + * The Boundary object defining the behavior's scheduling region. + */ + Bounds schedulingRegion = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * The current wakeup condition. + */ + WakeupCondition wakeupCondition = null; + + /** + * This is the new WakeupCondition to be set in + * initialize wakeupOn() + */ + WakeupCondition newWakeupCondition = null; + + /** + * The current view platform for this behavior; this value is + * false until it comes into range of a view platform. + */ + ViewPlatformRetained vp = null; + + /** + * The current activation status for this behavior; this value + * is false until it comes into range of a view platform. + */ + boolean active = false; + + /** + * Flag indicating whether the behavior is enabled. + */ + boolean enable = true; + + /** + * Current scheduling interval. + */ + int schedulingInterval = NUM_SCHEDULING_INTERVALS / 2; + + /** + * This is a flag that tells the behavior scheduler whether the + * user-programmed process stimulus called wakeupOn, if it did + * not, then the wakeupCondition will be set to null. + */ + boolean conditionSet = false; + + /** + * This is a flag that indicates whether we are in an initialize or + * processStimulus callback. If wakeupOn is called for this behavior + * when this flag is not set, an exception will be thrown. + */ + boolean inCallback = false; + + /** + * This is a flag that indicates whether we are in initialize + * callback. If wakeupOn is called for this behavior when + * this flag is true, then its + * buildTree() will delay until insert nodes message + * is get. This is because some localToVworld[] that wakeup + * depends may not initialize when this behavior setLive(). + */ + boolean inInitCallback = false; + + /** + * The transformed schedulingRegion + */ + Bounds transformedRegion = null; + + // A bitmask that indicates that the scheduling region has changed. + int isDirty = 0xffff; + + /** + * A bitmask that represents all conditions that this behavior is waiting on. + */ + int wakeupMask = 0; + + /** + * An array of ints that count how many of each wakup is present + */ + int[] wakeupArray = new int[NUM_WAKEUPS]; + + // use to post message when bounds change, always point to this + Object targets[] = new Object[1]; + + BehaviorRetained() { + this.nodeType = NodeRetained.BEHAVIOR; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + targets[0] = this; + IndexedUnorderSet.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Get the Behavior's scheduling region. + * @return this Behavior's scheduling region information + */ + Bounds getSchedulingBounds() { + Bounds b = null; + + if (schedulingRegion != null) { + b = (Bounds) schedulingRegion.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + } + return b; + } + + /** + * Set the Behavior's scheduling region. + * @param region a region that contains the Behavior's new scheduling + * bounds + */ + synchronized void setSchedulingBounds(Bounds region) { + + if (region != null) { + schedulingRegion = (Bounds) region.clone(); + if (staticTransform != null) { + schedulingRegion.transform(staticTransform.transform); + } + } else { + schedulingRegion = null; + } + + if (source != null && source.isLive()) { + sendMessage(J3dMessage.REGION_BOUND_CHANGED); + } + } + + /** + * Set the Sound's scheduling region to the specified Leaf node. + */ + synchronized void setSchedulingBoundingLeaf(BoundingLeaf region) { + + if (source != null && source.isLive()) { + if (boundingLeaf != null) + boundingLeaf.mirrorBoundingLeaf.removeUser(this); + } + + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + } else { + boundingLeaf = null; + } + + if (source != null && source.isLive()) { + if (boundingLeaf != null) + boundingLeaf.mirrorBoundingLeaf.addUser(this); + sendMessage(J3dMessage.REGION_BOUND_CHANGED); + } + } + + /** + * Enables or disables this Behavior. The default state is enabled. + * @param state true or false to enable or disable this Behavior + */ + void setEnable(boolean state) { + if (enable != state) { + enable = state; + if (source != null && source.isLive()) { + sendMessage(state ? J3dMessage.BEHAVIOR_ENABLE: + J3dMessage.BEHAVIOR_DISABLE); + } + } + } + + + /** + * Retrieves the state of the Behavior enable flag. + * @return the Behavior enable state + */ + boolean getEnable() { + return enable; + } + + + /** + * Sets the scheduling interval of this Behavior node to the + * specified value. + * @param schedulingInterval the new scheduling interval + */ + void setSchedulingInterval(int schedulingInterval) { + + if ((source != null) && source.isLive() + && !inCallback) { + // avoid MT safe problem when user thread setting + // this while behavior scheduling using this. + sendMessage(J3dMessage.SCHEDULING_INTERVAL_CHANGED, + new Integer(schedulingInterval)); + } else { + // garantee this setting reflect in next frame + this.schedulingInterval = schedulingInterval; + } + } + + + /** + * Retrieves the current scheduling interval of this Behavior + * node. + * + * @return the current scheduling interval + */ + int getSchedulingInterval() { + return schedulingInterval; + } + + + /** + * Get the Behavior's scheduling region + */ + BoundingLeaf getSchedulingBoundingLeaf() { + return (boundingLeaf != null ? + (BoundingLeaf)boundingLeaf.source : null); + } + + /** + * This setLive routine first calls the superclass's method, then + * it activates all canvases that are associated with the attached + * view. + */ + synchronized void setLive(SetLiveState s) { + + super.doSetLive(s); + if (inBackgroundGroup) { + throw new + IllegalSceneGraphException(J3dI18N.getString("BehaviorRetained0")); + } + if (inSharedGroup) { + throw new + IllegalSharingException(J3dI18N.getString("BehaviorRetained1")); + } + + s.nodeList.add(this); + s.behaviorNodes.add(this); + s.notifyThreads |= J3dThread.UPDATE_BEHAVIOR; + // process switch leaf + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(this, Targets.BEH_TARGETS); + } + switchState = (SwitchState)s.switchStates.get(0); + + if (boundingLeaf != null) { + boundingLeaf.mirrorBoundingLeaf.addUser(this); + } + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(this, Targets.BEH_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + super.markAsLive(); + } + + /** + * This clearLive routine first calls the superclass's method, then + * it deactivates all canvases that are associated with the attached + * view. + */ + synchronized void clearLive(SetLiveState s) { + super.clearLive(s); + s.nodeList.add(this); + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(this, Targets.BEH_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + s.notifyThreads |= J3dThread.UPDATE_BEHAVIOR; + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(this, Targets.BEH_TARGETS); + } + if (boundingLeaf != null) { + boundingLeaf.mirrorBoundingLeaf.removeUser(this); + } + // BehaviorStructure removeBehavior() will do the + // wakeupCondition.cleanTree() over there. + } + + /** + * This routine execute the user's initialize method + */ + void executeInitialize() { + + synchronized (this) { + boolean inCallbackSaved = inCallback; + boolean inInitCallbackSaved = inInitCallback; + + inCallback = true; + inInitCallback = true; + try { + ((Behavior)this.source).initialize(); + } + catch (RuntimeException e) { + System.err.println("Exception occurred during Behavior initialization:"); + e.printStackTrace(); + } + catch (Error e) { + // Issue 264 - catch Error + System.err.println("Error occurred during Behavior initialization:"); + e.printStackTrace(); + } + inCallback = inCallbackSaved; + inInitCallback = inInitCallbackSaved; + } + } + + /** + * Defines this behavior's wakeup criteria. + * @param criteria The wakeup criterion for this object + */ + void wakeupOn(WakeupCondition criteria) { + // If not call by initialize(), buildTree will + // delay until insertNodes in BehaviorStructure + // Otherwise BehaviorScheduler will invoke + // handleLastWakeupOn() + if (criteria == null) { + throw new NullPointerException(J3dI18N.getString("BehaviorRetained2")); + } + + if (!inInitCallback) { + conditionSet = true; + wakeupCondition = criteria; + } else { + // delay setting wakeup condition in BehaviorStructure + // activateBehaviors(). This is because there may have + // previously wakeupCondition attach to it and + // scheduling even after clearLive() due to message + // delay processing. It is not MT safe to set it + // in user thread. + newWakeupCondition = criteria; + } + + } + + // The above wakeupOn() just remember the reference + // We only need to handle (and ignore the rest) the + // last wakeupOn() condition set in the behavior. + // This handle the case when multiple wakeupOn() + // are invoked in the same processStimulus() + void handleLastWakeupOn(WakeupCondition prevWakeupCond, + BehaviorStructure bs) { + + if (bs == universe.behaviorStructure) { + if (wakeupCondition == prevWakeupCond) { + // reuse the same wakeupCondition + wakeupCondition.resetTree(); + } else { + if (prevWakeupCond != null) { + prevWakeupCond.cleanTree(bs); + } + wakeupCondition.buildTree(null, 0, this); + } + } else { + // No need to do prevWakeupCond.cleanTree(bs) + // since removeBehavior() will do so + } + } + + + /** + * Returns this behavior's wakeup criteria. + * @return criteria The wakeup criteria of this object + */ + WakeupCondition getWakeupCondition() { + return wakeupCondition; + } + + /** + * Post the specified Id. Behaviors use this method to cause sequential + * scheduling of other behavior object. + * @param postId The Id being posted + */ + + void postId(int postId){ + if (source != null && source.isLive()) { + universe.behaviorStructure.handleBehaviorPost((Behavior) source, postId); + } + } + + protected View getView() { + return (universe != null ? + universe.getCurrentView() : null); + } + + synchronized void updateTransformRegion(Bounds bound) { + if (boundingLeaf == null) { + updateTransformRegion(); + } else { + if (bound == null) { + transformedRegion = null; + } else { + transformedRegion = (Bounds) bound.clone(); + transformedRegion.transform( + boundingLeaf.mirrorBoundingLeaf.getCurrentLocalToVworld()); + } + } + } + + synchronized void updateTransformRegion() { + if (boundingLeaf == null || + !boundingLeaf.mirrorBoundingLeaf.switchState.currentSwitchOn) { + if (schedulingRegion == null) { + transformedRegion = null; + } else { + // use schedulingRegion + if (transformedRegion != null) { + transformedRegion.set(schedulingRegion); + } else { + transformedRegion = (Bounds) schedulingRegion.clone(); + } + transformedRegion.transform(getCurrentLocalToVworld()); + + } + } else { + // use boundingLeaf + transformedRegion = + boundingLeaf.mirrorBoundingLeaf.transformedRegion; + + } + } + + + // Note: This routine will only to update the object's + // transformed region + void updateBoundingLeaf(long refTime) { + transformedRegion = (Bounds)boundingLeaf.mirrorBoundingLeaf.transformedRegion; + } + + + void addWakeupCondition() {} + + final void sendMessage(int mtype, Object arg) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_BEHAVIOR; + createMessage.type = mtype; + createMessage.universe = universe; + createMessage.args[0] = targets; + createMessage.args[1]= this; + createMessage.args[2]= arg; + VirtualUniverse.mc.processMessage(createMessage); + } + + final void sendMessage(int mtype) { + sendMessage(mtype, null); + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + if (schedulingRegion != null) { + schedulingRegion.transform(xform.transform); + } + if (source instanceof DistanceLOD) { + ((DistanceLOD)source).mergeTransform(xform); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BehaviorScheduler.java b/j3d-core/src/classes/share/javax/media/j3d/BehaviorScheduler.java new file mode 100644 index 0000000..8a05d3e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BehaviorScheduler.java @@ -0,0 +1,248 @@ +/* + * $RCSfile: BehaviorScheduler.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; +import java.util.logging.Level; + +class BehaviorScheduler extends J3dThread { + + /** + * The virtual universe that owns this BehaviorScheduler + */ + VirtualUniverse univ = null; + + // reference to behaviourStructure processList + UnorderList processList[]; + + // reference to scheduleList; + IndexedUnorderSet scheduleList; + + // reference to universe.behaviorStructure + BehaviorStructure behaviorStructure; + + // A count for BehaviorScheduler start/stop + int stopCount = -1; + + /** + * These are used for start/stop BehaviorScheduler + */ + long lastStartTime; + long lastStopTime; + + // lock to ensure consistency of interval values read + Object intervalTimeLock = new Object(); + + /** + * Some variables used to name threads correctly + */ + private static int numInstances = 0; + private int instanceNum = -1; + + private synchronized int newInstanceNum() { + return (++numInstances); + } + + int getInstanceNum() { + if (instanceNum == -1) + instanceNum = newInstanceNum(); + return instanceNum; + } + + + BehaviorScheduler(ThreadGroup t, VirtualUniverse universe) { + super(t); + setName("J3D-BehaviorScheduler-" + getInstanceNum()); + this.univ = universe; + behaviorStructure = universe.behaviorStructure; + scheduleList = behaviorStructure.scheduleList; + processList = behaviorStructure.processList; + type = J3dThread.BEHAVIOR_SCHEDULER; + } + + void stopBehaviorScheduler(long[] intervalTime) { + + stopCount = 2; + VirtualUniverse.mc.sendRunMessage(univ, J3dThread.BEHAVIOR_SCHEDULER); + while (!userStop ) { + MasterControl.threadYield(); + } + synchronized (intervalTimeLock) { + intervalTime[0] = lastStartTime; + intervalTime[1] = lastStopTime; + } + } + + void startBehaviorScheduler() { + // don't allow scheduler start until intervalTime is read + synchronized (intervalTimeLock) { + stopCount = -1; + userStop = false; + VirtualUniverse.mc.setWork(); + } + } + + void deactivate() { + active = false; + if (stopCount >= 0) { + userStop = true; + } + } + + /** + * The main loop for the Behavior Scheduler. + * Main method for firing off vector of satisfied conditions that + * are contained in the condMet vector. Method is synchronized + * because it is modifying the current wakeup vectors in the + * clean (emptying out satisfied conditions) and processStimulus + * (adding conditions again if wakeupOn called) calls. + */ + void doWork(long referenceTime) { + BehaviorRetained arr[]; + UnorderList list; + int i, size, interval; + + lastStartTime = J3dClock.currentTimeMillis(); + + if (stopCount >= 0) { + VirtualUniverse.mc.sendRunMessage(univ, J3dThread.BEHAVIOR_SCHEDULER); + if (--stopCount == 0) { + userStop = true; + } + } + + + for (interval = 0; + interval < BehaviorRetained.NUM_SCHEDULING_INTERVALS; + interval++) { + + list = processList[interval]; + + if (list.isEmpty()) { + continue; + } + arr = (BehaviorRetained []) list.toArray(false); + + size = list.arraySize(); + + for (i = 0; i < size ; i++) { + BehaviorRetained behavret = arr[i]; + + + synchronized (behavret) { + Behavior behav = (Behavior) behavret.source; + + if (!behav.isLive() || + !behavret.conditionSet || + (behavret.wakeupCondition == null)) { + continue; + } + + if (behavret.wakeupCondition.trigEnum == null) { + behavret.wakeupCondition.trigEnum = + new WakeupCriteriaEnumerator(behavret.wakeupCondition, + WakeupCondition.TRIGGERED_ELEMENTS); + } else { + behavret.wakeupCondition.trigEnum.reset( + behavret.wakeupCondition, + WakeupCondition.TRIGGERED_ELEMENTS); + } + + // BehaviorRetained now cache the old + // wakeupCondition in order to + // reuse it without the heavyweight cleanTree() + // behavret.wakeupCondition.cleanTree(); + + behavret.conditionSet = false; + WakeupCondition wakeupCond = behavret.wakeupCondition; + + synchronized (behavret) { + behavret.inCallback = true; + univ.inBehavior = true; + try { + behav.processStimulus(wakeupCond.trigEnum); + } + catch (RuntimeException e) { + // Force behavior condition to be unset + // Issue 21: don't call cleanTree here + behavret.conditionSet = false; + System.err.println("Exception occurred during Behavior execution:"); + e.printStackTrace(); + } + catch (Error e) { + // Force behavior condition to be unset + // Fix for issue 264 + behavret.conditionSet = false; + System.err.println("Error occurred during Behavior execution:"); + e.printStackTrace(); + } + univ.inBehavior = false; + behavret.inCallback = false; + } + // note that if the behavior wasn't reset, we need to make the + // wakeupcondition equal to null + if (behavret.conditionSet == false) { + if (wakeupCond != null) { + wakeupCond.cleanTree(behaviorStructure); + } + behavret.wakeupCondition = null; + behavret.active = false; + scheduleList.remove(behavret); + } else { + behavret.handleLastWakeupOn(wakeupCond, + behaviorStructure); + } + } + } + list.clear(); + } + + behaviorStructure.handleAWTEvent(); + behaviorStructure.handleBehaviorPost(); + lastStopTime = J3dClock.currentTimeMillis(); + + if (MasterControl.isStatsLoggable(Level.FINE)) { + VirtualUniverse.mc.recordTime(MasterControl.TimeType.BEHAVIOR, (lastStopTime-lastStartTime)*1000000); + } + } + + void free() { + behaviorStructure = null; + getThreadData(null, null).thread = null; + univ = null; + for (int i=BehaviorRetained.NUM_SCHEDULING_INTERVALS-1; + i >= 0; i--) { + processList[i].clear(); + } + scheduleList.clear(); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BehaviorStructure.java b/j3d-core/src/classes/share/javax/media/j3d/BehaviorStructure.java new file mode 100644 index 0000000..faa1fca --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BehaviorStructure.java @@ -0,0 +1,1679 @@ +/* + * $RCSfile: BehaviorStructure.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; +import java.awt.*; +import java.awt.event.*; +import java.util.Arrays; + +/** + * A behavior structure is a object that organizes behaviors, + * wakeup conditions, and other behavior scheduler entities. + */ + +class BehaviorStructure extends J3dStructure { + + /** + * The list of behaviors + */ + IndexedUnorderSet behaviors; + + /** + * The list of view platforms + */ + IndexedUnorderSet viewPlatforms; + + /** + * An array of schedulable behaviors, use in + * removeViewPlatform() to go through only active behaviors + */ + IndexedUnorderSet scheduleList; + + /** + * An array of process behaviors + */ + UnorderList processList[] = new UnorderList[BehaviorRetained.NUM_SCHEDULING_INTERVALS]; + + /** + * A bounds used for getting a view platform scheduling BoundingSphere + */ + // BoundingSphere tempSphere = new BoundingSphere(); + // BoundingSphere vpsphere = new BoundingSphere(); + Point3d vpCenter = new Point3d(); + Point3d vpTransCenter = new Point3d(); + + /** + * A list of bounds WakeupOnViewPlatformEntry objects that + * have seen ViewPlatformEntry + */ + WakeupIndexedList boundsEntryList; + + /** + * A list of bounds WakeupOnViewPlatformExit objects that have + * seen ViewPlatformEntry + */ + WakeupIndexedList boundsExitList; + + /** + * A list of WakeupOnSensorEntry objects that have seen a sensor + */ + WakeupIndexedList currentSensorEntryList; + + /** + * A list of WakeupOnSensorExit objects that have seen a sensor + */ + WakeupIndexedList currentSensorExitList; + + /** + * The lists of the WakeupCriterion objects that the + * behavior scheduler keeps. + */ + WakeupIndexedList wakeupOnAWTEvent; + WakeupIndexedList wakeupOnActivation; + WakeupIndexedList wakeupOnDeactivation; + WakeupIndexedList wakeupOnBehaviorPost; + WakeupIndexedList wakeupOnElapsedFrames; + WakeupIndexedList wakeupOnViewPlatformEntry; + WakeupIndexedList wakeupOnViewPlatformExit; + WakeupIndexedList wakeupOnSensorEntry; + WakeupIndexedList wakeupOnSensorExit; + + // Temporary array for processTransformChanged() + UnorderList transformViewPlatformList = new UnorderList(ViewPlatformRetained.class); + + + // The number of active wakeup condition in wakeupOnElapsedFrames + int activeWakeupOnFrameCount = 0; + + // The number of active wakeup condition in wakeupOnSensorEntry/Exit + int activeWakeupOnSensorCount = 0; + + /** + * Buffers to hold events when user thread is in processStimulus() + * while this event is receiving. This avoid any lost of event. + * We did not remove individual element from the following list + * (except clear()) so the order is still preserve. + */ + UnorderList awtEventsBuffer = new UnorderList(AWTEvent.class); + + // Use generic integer array to avoid new Integer() for individual element + int postIDBuffer[] = new int[10]; // size of default UnorderList + int clonePostIDBuffer[] = new int[postIDBuffer.length]; + + UnorderList behaviorPostBuffer = new UnorderList(Behavior.class); + + // temp values for transformed hotspot used in + // wakeupOnSensorEntry/ExitupdateSensorsHotspot + Transform3D sensorTransform = new Transform3D(); + Vector3d sensorLoc = new Vector3d(); + Point3d ptSensorLoc = new Point3d(); + + // list of active physical environments + UnorderList physicalEnvironments = new UnorderList(1, PhysicalEnvironment.class); + + + // list of Behavior waiting to be add to behavior list and buildTree() + UnorderList pendingBehaviors = new UnorderList(BehaviorRetained.class); + + // true if branch detach + boolean branchDetach = false; + + // This is used to notify WakeupOnAWTEvent re-enable Canvas3D events + long awtEventTimestamp = 1; + + // used to process transform messages + boolean transformMsg = false; + UpdateTargets targets = null; + + BehaviorStructure(VirtualUniverse u) { + super(u, J3dThread.UPDATE_BEHAVIOR); + + for (int i=BehaviorRetained.NUM_SCHEDULING_INTERVALS-1; + i >= 0; i--) { + processList[i] = new UnorderList(BehaviorRetained.class); + } + behaviors = new IndexedUnorderSet(BehaviorRetained.class, + BehaviorRetained.BEHAIVORS_IN_BS_LIST, u); + viewPlatforms = new IndexedUnorderSet(ViewPlatformRetained.class, + ViewPlatformRetained.VP_IN_BS_LIST, u); + scheduleList = new IndexedUnorderSet(BehaviorRetained.class, + BehaviorRetained.SCHEDULE_IN_BS_LIST, u); + boundsEntryList = new WakeupIndexedList(WakeupOnViewPlatformEntry.class, + WakeupOnViewPlatformEntry.BOUNDSENTRY_IN_BS_LIST, u); + boundsExitList = new WakeupIndexedList(WakeupOnViewPlatformExit.class, + WakeupOnViewPlatformExit.BOUNDSEXIT_IN_BS_LIST, u); + currentSensorEntryList = new WakeupIndexedList(WakeupOnSensorEntry.class, + WakeupOnSensorEntry.SENSORENTRY_IN_BS_LIST, u); + currentSensorExitList = new WakeupIndexedList(WakeupOnSensorExit.class, + WakeupOnSensorExit.SENSOREXIT_IN_BS_LIST, u); + wakeupOnAWTEvent = new WakeupIndexedList(WakeupOnAWTEvent.class, + WakeupOnAWTEvent.COND_IN_BS_LIST, u); + wakeupOnActivation = new WakeupIndexedList(WakeupOnActivation.class, + WakeupOnActivation.COND_IN_BS_LIST, u); + wakeupOnDeactivation = new WakeupIndexedList(WakeupOnDeactivation.class, + WakeupOnDeactivation.COND_IN_BS_LIST, u); + wakeupOnBehaviorPost = new WakeupIndexedList(WakeupOnBehaviorPost.class, + WakeupOnBehaviorPost.COND_IN_BS_LIST, u); + wakeupOnElapsedFrames = new WakeupIndexedList(WakeupOnElapsedFrames.class, + WakeupOnElapsedFrames.COND_IN_BS_LIST, u); + wakeupOnViewPlatformEntry = new WakeupIndexedList(WakeupOnViewPlatformEntry.class, + WakeupOnViewPlatformEntry.COND_IN_BS_LIST, u); + wakeupOnViewPlatformExit = new WakeupIndexedList(WakeupOnViewPlatformExit.class, + WakeupOnViewPlatformExit.COND_IN_BS_LIST, u); + wakeupOnSensorEntry = new WakeupIndexedList(WakeupOnSensorEntry.class, + WakeupOnSensorEntry.COND_IN_BS_LIST, u); + wakeupOnSensorExit = new WakeupIndexedList(WakeupOnSensorExit.class, + WakeupOnSensorExit.COND_IN_BS_LIST, u); + + } + + void processMessages(long referenceTime) { + + J3dMessage[] messages = getMessages(referenceTime); + int nMsg = getNumMessage(); + J3dMessage m; + + if (nMsg > 0) { + for (int i=0; i 0) { + // Wakeup render thread when there is pending wakeupOnElapsedFrames + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.BEHAVIOR_SCHEDULER| + J3dThread.RENDER_THREAD); + + } else { + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.BEHAVIOR_SCHEDULER); + } + } else { + checkSensorEntryExit(); + // we have to invoke checkSensorEntryExit() next time + if (activeWakeupOnFrameCount > 0) { + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.UPDATE_BEHAVIOR| + J3dThread.BEHAVIOR_SCHEDULER| + J3dThread.RENDER_THREAD); + + } else { + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.UPDATE_BEHAVIOR| + J3dThread.BEHAVIOR_SCHEDULER); + } + } + } + + void insertNodes(Object[] nodes) { + for (int i=0; i=0; i--) { + behav = behavArr[i]; + behav.wakeupCondition = behav.newWakeupCondition; + if (behav.wakeupCondition != null) { + behav.wakeupCondition.buildTree(null, 0, behav); + behav.conditionSet = true; + behaviors.add(behav); + behav.updateTransformRegion(); + addToScheduleList(behav); + } + } + pendingBehaviors.clear(); + } + + void addViewPlatform(ViewPlatformRetained vp) { + int i; + BehaviorRetained behav; + BehaviorRetained behavArr[] = (BehaviorRetained []) behaviors.toArray(false); + + viewPlatforms.add(vp); + vp.updateTransformRegion(); + + if (!vp.isActiveViewPlatform()) { + return; + } + + // re-evaulate all behaviors to see if we need to put + // more behaviors in scheduleList + + for (i=behaviors.arraySize()-1; i>=0; i--) { + addToScheduleList(behavArr[i]); + } + + // handle ViewPlatform Entry + WakeupOnViewPlatformEntry wakeupOnViewPlatformEntryArr[] = + (WakeupOnViewPlatformEntry []) wakeupOnViewPlatformEntry.toArray(false); + WakeupOnViewPlatformEntry wentry; + + for (i=wakeupOnViewPlatformEntry.arraySize()-1; i >=0; i--) { + wentry = wakeupOnViewPlatformEntryArr[i]; + if (!boundsEntryList.contains(wentry) && + wentry.transformedRegion.intersect(vp.center)) { + boundsEntryList.add(wentry); + wentry.triggeredVP = vp; + wentry.setTriggered(); + } + } + + // handle ViewPlatform Exit + WakeupOnViewPlatformExit wakeupOnViewPlatformExitArr[] = + (WakeupOnViewPlatformExit []) wakeupOnViewPlatformExit.toArray(false); + WakeupOnViewPlatformExit wexit; + + for (i=wakeupOnViewPlatformExit.arraySize()-1; i >=0; i--) { + wexit = wakeupOnViewPlatformExitArr[i]; + if (!boundsExitList.contains(wexit) && + wexit.transformedRegion.intersect(vp.center)) { + wexit.triggeredVP = vp; + boundsExitList.add(wexit); + } + } + + } + + void removeNodes(J3dMessage m) { + Object[] nodes = (Object[]) m.args[0]; + boolean behavRemove = false; + + for (int i=0; i= FocusEvent.FOCUS_FIRST && awtId <= FocusEvent.FOCUS_LAST) || + (eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0) { + focusEnable = true; + } + if ((awtId >= KeyEvent.KEY_FIRST && awtId <= KeyEvent.KEY_LAST) || + (eventMask & AWTEvent.KEY_EVENT_MASK) != 0) { + keyEnable = true; + } + if ((awtId >= MouseEvent.MOUSE_FIRST) && + (awtId <= MouseEvent.MOUSE_LAST)) { + if ((awtId == MouseEvent.MOUSE_DRAGGED) || + (awtId == MouseEvent.MOUSE_MOVED)) { + mouseMotionEnable = true; + } + else if ((awtId == MouseEvent.MOUSE_ENTERED) || + (awtId == MouseEvent.MOUSE_EXITED) || + (awtId == MouseEvent.MOUSE_CLICKED) || + (awtId == MouseEvent.MOUSE_PRESSED) || + (awtId == MouseEvent.MOUSE_RELEASED) ) { + mouseEnable = true; + } + else if (awtId == MouseEvent.MOUSE_WHEEL) { + mouseWheelEnable = true; + } + } else { + if ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0) { + mouseEnable = true; + } + if ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0) { + mouseMotionEnable = true; + } + if ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0) { + mouseWheelEnable = true; + } + } + } + + if (!focusEnable && universe.enableFocus) { + incTimestamp = true; + universe.disableFocusEvents(); + } + if (!VirtualUniverse.mc.isD3D() && !keyEnable && universe.enableKey) { + // key event use for toggle to fullscreen/window mode + incTimestamp = true; + universe.disableKeyEvents(); + } + if (!mouseWheelEnable && universe.enableMouseWheel) { + incTimestamp = true; + universe.disableMouseWheelEvents(); + } + if (!mouseMotionEnable && universe.enableMouseMotion) { + incTimestamp = true; + universe.disableMouseMotionEvents(); + } + if (!mouseEnable && universe.enableMouse) { + incTimestamp = true; + universe.disableMouseEvents(); + } + if (incTimestamp) { + awtEventTimestamp++; + } + } + } + + void removeViewPlatform(ViewPlatformRetained vp) { + BehaviorRetained behav; + int i; + + viewPlatforms.remove(vp); + + BehaviorRetained scheduleArr[] = (BehaviorRetained []) + scheduleList.toArray(false); + + // handle Deactive + for (i=scheduleList.arraySize()-1; i >=0 ; i--) { + behav = scheduleArr[i]; + // This vp may contribute to the reason that + // behavior is in schedule list + if (!intersectVPRegion(behav.transformedRegion)) { + removeFromScheduleList(behav); + } + } + + // handle ViewPlatform Entry + WakeupOnViewPlatformEntry boundsEntryArr[] = + (WakeupOnViewPlatformEntry []) boundsEntryList.toArray(false); + WakeupOnViewPlatformEntry wentry; + ViewPlatformRetained triggeredVP; + + for (i=boundsEntryList.arraySize()-1; i >=0; i--) { + wentry = boundsEntryArr[i]; + // only this thread can modify wentry.transformedRegion, so + // no need to getWithLock() + triggeredVP = intersectVPCenter(wentry.transformedRegion); + if (triggeredVP == null) { + boundsEntryList.remove(wentry); + } + } + + // handle ViewPlatform Exit + WakeupOnViewPlatformExit boundsExitArr[] = + (WakeupOnViewPlatformExit []) boundsExitList.toArray(false); + WakeupOnViewPlatformExit wexit; + + for (i=boundsExitList.arraySize()-1; i >=0; i--) { + wexit = boundsExitArr[i]; + // only this thread can modify wentry.transformedRegion, so + // no need to getWithLock() + triggeredVP = intersectVPCenter(wexit.transformedRegion); + if (triggeredVP == null) { + boundsExitList.remove(wexit); + wexit.setTriggered(); + } + } + } + + void removeBehavior(BehaviorRetained behav) { + behaviors.remove(behav); + + if ((behav.wakeupCondition != null) && + (behav.wakeupCondition.behav != null)) { + behav.wakeupCondition.cleanTree(this); + if (behav.universe == universe) { + behav.conditionSet = false; + } + } + + // cleanup boundsEntryList + // since we didn't remove it on removeVPEntryCondition + WakeupOnViewPlatformEntry boundsEntryArr[] = + (WakeupOnViewPlatformEntry []) boundsEntryList.toArray(false); + WakeupOnViewPlatformEntry wentry; + + for (int i=boundsEntryList.arraySize()-1; i>=0; i--) { + wentry = boundsEntryArr[i]; + if (wentry.behav == behav) { + boundsEntryList.remove(wentry); + } + } + + // cleanup boundsExitList + // since we didn't remove it on removeVPExitCondition + WakeupOnViewPlatformExit boundsExitArr[] = + (WakeupOnViewPlatformExit []) boundsExitList.toArray(false); + WakeupOnViewPlatformExit wexit; + + for (int i=boundsExitList.arraySize()-1; i>=0; i--) { + wexit = boundsExitArr[i]; + if (wexit.behav == behav) { + boundsExitList.remove(wexit); + } + } + + + // cleanup currentSensorEntryList + // since we didn't remove it on removeSensorEntryCondition + WakeupOnSensorEntry currentSensorEntryArr[] = + (WakeupOnSensorEntry []) currentSensorEntryList.toArray(false); + WakeupOnSensorEntry sentry; + + for (int i=currentSensorEntryList.arraySize()-1; i>=0; i--) { + sentry = currentSensorEntryArr[i]; + if (sentry.behav == behav) { + currentSensorEntryList.remove(sentry); + } + } + + + // cleanup currentSensorExitList + // since we didn't remove it on removeSensorExitCondition + WakeupOnSensorExit currentSensorExitArr[] = + (WakeupOnSensorExit []) currentSensorExitList.toArray(false); + WakeupOnSensorExit sexit; + + for (int i=currentSensorExitList.arraySize()-1; i>=0; i--) { + sexit = currentSensorExitArr[i]; + if (sexit.behav == behav) { + currentSensorExitList.remove(sexit); + } + } + removeFromScheduleList(behav); + + } + + + void handleAWTEvent(AWTEvent evt) { + awtEventsBuffer.add(evt); + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.BEHAVIOR_SCHEDULER); + } + + /** + * This routine takes the awt event list and gives then to the awt event + * conditions + */ + void handleAWTEvent() { + WakeupOnAWTEvent awtConds[] = (WakeupOnAWTEvent []) + wakeupOnAWTEvent.toArray(); + AWTEvent events[]; + int eventSize = wakeupOnAWTEvent.arraySize(); + int awtBufferSize; + + synchronized (awtEventsBuffer) { + events = (AWTEvent []) awtEventsBuffer.toArray(); + awtBufferSize = awtEventsBuffer.size(); + awtEventsBuffer.clear(); + } + WakeupOnAWTEvent awtCond; + AWTEvent evt; + int id; + + for (int i=0; i < eventSize; i++) { + awtCond = awtConds[i]; + for (int j=0; j < awtBufferSize; j++) { + evt = events[j]; + id = evt.getID(); + + if (awtCond.AwtId != 0) { + if (awtCond.AwtId == id) { + // XXXX: how do we clone this event (do we need to?) + // Bug: 4181321 + awtCond.addAWTEvent(evt); + } + } else { + if (id >= ComponentEvent.COMPONENT_FIRST && + id <= ComponentEvent.COMPONENT_LAST && + (awtCond.EventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) { + awtCond.addAWTEvent(evt); + } + else if (id >= FocusEvent.FOCUS_FIRST && + id <= FocusEvent.FOCUS_LAST && + (awtCond.EventMask & AWTEvent.FOCUS_EVENT_MASK) != 0) { + awtCond.addAWTEvent(evt); + } + else if (id >= KeyEvent.KEY_FIRST && + id <= KeyEvent.KEY_LAST && + (awtCond.EventMask & AWTEvent.KEY_EVENT_MASK) != 0) { + awtCond.addAWTEvent(evt); + } + else if ((id == MouseEvent.MOUSE_CLICKED || + id == MouseEvent.MOUSE_ENTERED || + id == MouseEvent.MOUSE_EXITED || + id == MouseEvent.MOUSE_PRESSED || + id == MouseEvent.MOUSE_RELEASED) && + (awtCond.EventMask & AWTEvent.MOUSE_EVENT_MASK) != 0) { + awtCond.addAWTEvent(evt); + } + else if ((id == MouseEvent.MOUSE_DRAGGED || + id == MouseEvent.MOUSE_MOVED) && + (awtCond.EventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0) { + awtCond.addAWTEvent(evt); + } + else if ((id == MouseEvent.MOUSE_WHEEL) && + (awtCond.EventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0) { + awtCond.addAWTEvent(evt); + } + } + } + } + + + + } + + + void handleBehaviorPost(Behavior behav, int postid) { + + synchronized (behaviorPostBuffer) { + int size = behaviorPostBuffer.size(); + if (postIDBuffer.length == size) { + int oldbuffer[] = postIDBuffer; + postIDBuffer = new int[size << 1]; + System.arraycopy(oldbuffer, 0, postIDBuffer, 0, size); + } + postIDBuffer[size] = postid; + behaviorPostBuffer.add(behav); + } + VirtualUniverse.mc.sendRunMessage(universe, J3dThread.BEHAVIOR_SCHEDULER); + } + + /** + * This goes through all of the criteria waiting for Behavior Posts + * and notifys them. + */ + void handleBehaviorPost() { + Behavior behav; + int postid; + WakeupOnBehaviorPost wakeup; + WakeupOnBehaviorPost wakeupConds[] = (WakeupOnBehaviorPost []) + wakeupOnBehaviorPost.toArray(); + Behavior behavArr[]; + int behavBufferSize; + + synchronized (behaviorPostBuffer) { + behavArr = (Behavior []) behaviorPostBuffer.toArray(); + behavBufferSize = behaviorPostBuffer.size(); + if (clonePostIDBuffer.length < behavBufferSize) { + clonePostIDBuffer = new int[behavBufferSize]; + } + System.arraycopy(postIDBuffer, 0, clonePostIDBuffer, 0, + behavBufferSize); + behaviorPostBuffer.clear(); + } + + int size = wakeupOnBehaviorPost.arraySize(); + for (int i=0; i < size; i++) { + wakeup = wakeupConds[i]; + for (int j=0; j < behavBufferSize; j++) { + behav = behavArr[j]; + postid = clonePostIDBuffer[j]; + if ((wakeup.post == postid || wakeup.post == 0) && + (behav == wakeup.armingBehavior || wakeup.armingBehavior == null)) { + wakeup.triggeringBehavior = behav; + wakeup.triggeringPost = postid; + wakeup.setTriggered(); + } + } + } + + } + + /** + * This goes through all of the criteria waiting for Elapsed Frames + * and notified them. + */ + void incElapsedFrames() { + + WakeupOnElapsedFrames wakeupConds[] = (WakeupOnElapsedFrames []) + wakeupOnElapsedFrames.toArray(true); + int size = wakeupOnElapsedFrames.arraySize(); + int i = 0; + + while (i < size) { + wakeupConds[i++].newFrame(); + } + + if ( size > 0) { + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.BEHAVIOR_SCHEDULER|J3dThread.UPDATE_BEHAVIOR); + } + + if (branchDetach) { + // Since this procedure may call by immediate mode user + // thread, we can't just clear it in removeNodes() + wakeupOnElapsedFrames.clearMirror(); + branchDetach = false; + } + + } + + void removeVPEntryCondition(WakeupCondition w) { + wakeupOnViewPlatformEntry.remove(w); + // don't remove boundsEntryList, it is use next time + // when addVPExitCondition invoke to determine whether to + // trigger an event or not. + + } + + void addVPEntryCondition(WakeupOnViewPlatformEntry w) { + boolean needTrigger = true; + + // see if the matching wakeupOnViewPlatformEntry + // condition exists & do cleanup + WakeupOnViewPlatformEntry boundsEntryArr[] = + (WakeupOnViewPlatformEntry []) boundsEntryList.toArray(false); + WakeupOnViewPlatformEntry wentry; + + for (int i=boundsEntryList.arraySize()-1; i>=0; i--) { + wentry = boundsEntryArr[i]; + if ((wentry.behav == w.behav) && + (wentry.region.equals(w.region))) { + boundsEntryList.remove(i); + // Case where we wakeOr() both condition together. + // we should avoid calling setTrigger() every time. + needTrigger = false; + break; + } + } + + wakeupOnViewPlatformEntry.add(w); + + ViewPlatformRetained triggeredVP = intersectVPCenter(w.transformedRegion); + if (triggeredVP != null) { + boundsEntryList.add(w); + } + + // we always trigger bound is inside during initialize + if (needTrigger && (triggeredVP != null)) { + w.triggeredVP = triggeredVP; + w.setTriggered(); + } + } + + void removeVPExitCondition(WakeupOnViewPlatformExit w) { + wakeupOnViewPlatformExit.remove(w); + // don't remove boundsExitList, it is use next time + // when addVPEntryCondition invoke to determine whether to + // trigger an event or not. + } + + void addVPExitCondition(WakeupOnViewPlatformExit w) { + // Cleanup, since collideEntryList did not remove + // its condition in removeVPEntryCondition + boolean needTrigger = true; + WakeupOnViewPlatformExit boundsExitArr[] = + (WakeupOnViewPlatformExit []) boundsExitList.toArray(false); + WakeupOnViewPlatformExit wexit; + for (int i=boundsExitList.arraySize()-1; i>=0; i--) { + wexit = boundsExitArr[i]; + if ((wexit.behav == w.behav) && + (wexit.region.equals(w.region))) { + boundsExitList.remove(i); + needTrigger = false; + break; + } + } + + ViewPlatformRetained triggeredVP = intersectVPCenter(w.transformedRegion); + wakeupOnViewPlatformExit.add(w); + + if (triggeredVP != null) { + w.triggeredVP = triggeredVP; + boundsExitList.add(w); + } + + if (!needTrigger) { + return; + } + + // see if the matching wakeupOnViewPlatformEntry + // condition exists + + WakeupOnViewPlatformEntry boundsEntryArr[] = + (WakeupOnViewPlatformEntry []) boundsEntryList.toArray(false); + WakeupOnViewPlatformEntry wentry; + + for (int i=boundsEntryList.arraySize()-1; i>=0; i--) { + wentry = boundsEntryArr[i]; + if ((wentry.behav == w.behav) && + (wentry.region.equals(w.region))) { + // Don't remove this since if user wakeupOr() + // Entry and Exit condition together we may have trouble + // boundsEntryList.remove(i); + if (triggeredVP == null) { + w.setTriggered(); + } + break; + } + } + + } + + + void removeSensorEntryCondition(WakeupOnSensorEntry w) { + wakeupOnSensorEntry.remove(w); + // don't remove currentSensorEntryList, it is use next time + // when addSensorExitCondition invoke to determine whether to + // trigger an event or not. + } + + void addSensorEntryCondition(WakeupOnSensorEntry w) { + boolean needTrigger = true; + + // see if the matching wakeupOnSensorEntry + // condition exists + WakeupOnSensorEntry sensorEntryArr[] = + (WakeupOnSensorEntry []) currentSensorEntryList.toArray(false); + WakeupOnSensorEntry wentry; + + for (int i=currentSensorEntryList.arraySize()-1; i>=0; i--) { + wentry = sensorEntryArr[i]; + if ((wentry.behav == w.behav) && + (wentry.region.equals(w.region))) { + currentSensorEntryList.remove(i); + needTrigger = false; + break; + } + } + + wakeupOnSensorEntry.add(w); + + w.updateTransformRegion(); + Sensor target = sensorIntersect(w.transformedRegion); + if (target != null) { + w.setTarget(target); + currentSensorEntryList.add(w); + } + + if (needTrigger && (target != null)) { + w.setTriggered(); + + } + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.UPDATE_BEHAVIOR); + } + + void removeSensorExitCondition(WakeupOnSensorExit w) { + wakeupOnSensorExit.remove(w); + // don't remove currentSensorExitList, it is use next time + // when addSensorEntryCondition invoke to determine whether to + // trigger an event or not + } + + void addSensorExitCondition(WakeupOnSensorExit w) { + // Cleanup + boolean needTrigger = true; + + WakeupOnSensorExit currentSensorExitArr[] = + (WakeupOnSensorExit []) currentSensorExitList.toArray(false); + WakeupOnSensorExit wexit; + for (int i=currentSensorExitList.arraySize()-1; i>=0; i--) { + wexit = currentSensorExitArr[i]; + if ((wexit.behav == w.behav) && + (wexit.region.equals(w.region))) { + currentSensorExitList.remove(i); + needTrigger = false; + break; + } + } + + w.updateTransformRegion(); + Sensor target = sensorIntersect(w.transformedRegion); + wakeupOnSensorExit.add(w); + + if (target != null) { + w.setTarget(target); + currentSensorExitList.add(w); + } + + if (!needTrigger) { + return; + } + // see if the matching wakeupOnSensorEntry + // condition exists + WakeupOnSensorEntry sensorEntryArr[] = + (WakeupOnSensorEntry []) currentSensorEntryList.toArray(false); + WakeupOnSensorEntry wentry; + + for (int i=currentSensorEntryList.arraySize()-1; i>=0; i--) { + wentry = sensorEntryArr[i]; + if ((wentry.behav == w.behav) && + (wentry.region.equals(w.region))) { + // No need to invoke currentSensorEntryList.remove(i); + if (target == null) { + w.setTriggered(); + } + break; + } + } + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.UPDATE_BEHAVIOR); + } + + void processConditionMet(BehaviorRetained behav, + Boolean checkSchedulingRegion) { + + // Since we reuse wakeup condition, the old wakeupCondition + // will not reactivate again while processStimulus is running + // which may set another wakeupCondition. + // Previously we don't reuse wakeupCondition and cleanTree() + // everytime before calling processStimulus() so the flag + // inCallback is not necessary to check. + if (!behav.inCallback && + ((checkSchedulingRegion == Boolean.FALSE) || + behav.active)) { + processList[behav.schedulingInterval].add(behav); + } else { + if (((behav.wakeupMask & + BehaviorRetained.WAKEUP_TIME) != 0) && + (behav.source != null) && + (behav.source.isLive()) && + (behav.wakeupCondition != null)) { + // need to add back wakeupOnElapsedTime condition + // to TimerThread + behav.wakeupCondition.reInsertElapseTimeCond(); + } + } + } + + final void processBehXformChanged(UnorderList arrList) { + BehaviorRetained beh; + Object[] nodes, nodesArr; + + int size = arrList.size(); + nodesArr = arrList.toArray(false); + + for (int i = 0; i < size; i++) { + nodes = (Object[])nodesArr[i]; + for (int j=0; j 0) { + ViewPlatformRetained vpArr[] = (ViewPlatformRetained []) + transformViewPlatformList.toArray(false); + + int size = transformViewPlatformList.arraySize(); + for (i=0; i < size; i++) { + processViewPlatformTransform((ViewPlatformRetained) + vpArr[i]); + } + transformViewPlatformList.clear(); + } + } + + + // assume behav.updateTransformRegion() invoke before + final void processBehaviorTransform(BehaviorRetained behav) { + if ((behav.wakeupMask & BehaviorRetained.WAKEUP_VP_ENTRY) != 0) { + updateVPEntryTransformRegion(behav); + } + + if ((behav.wakeupMask & BehaviorRetained.WAKEUP_VP_EXIT) != 0) { + updateVPExitTransformRegion(behav); + } + + if (behav.active) { + if (!intersectVPRegion(behav.transformedRegion)) { + removeFromScheduleList(behav); + } + } else { + addToScheduleList(behav); + } + } + + + void processViewPlatformTransform(ViewPlatformRetained vp) { + int i; + BehaviorRetained behav; + + vp.updateTransformRegion(); + + if (!vp.isActiveViewPlatform()) { + return; + } + + BehaviorRetained behavArr[] = (BehaviorRetained []) behaviors.toArray(false); + + // re-evaulate all behaviors affected by this vp + for (i=behaviors.arraySize()-1; i>=0; i--) { + behav = behavArr[i]; + if (behav.active) { + if (!intersectVPRegion(behav.transformedRegion)) { + removeFromScheduleList(behav); + } + } else { + addToScheduleList(behav); + } + } + + // handle wakeupOnViewPlatformEntry + WakeupOnViewPlatformEntry wakeupOnViewPlatformEntryArr[] = + (WakeupOnViewPlatformEntry []) wakeupOnViewPlatformEntry.toArray(false); + WakeupOnViewPlatformEntry wentry; + int idx; + ViewPlatformRetained triggeredVP; + + for (i=wakeupOnViewPlatformEntry.arraySize()-1; i >=0; i--) { + wentry = wakeupOnViewPlatformEntryArr[i]; + idx = boundsEntryList.indexOf(wentry); + if (idx < 0) { + if (wentry.transformedRegion.intersect(vp.center)) { + boundsEntryList.add(wentry); + wentry.triggeredVP = vp; + wentry.setTriggered(); + } + } else { + triggeredVP = intersectVPCenter(wentry.transformedRegion); + if (triggeredVP == null) { + boundsEntryList.remove(idx); + } + } + } + + // handle wakeupOnViewPlatformExit; + WakeupOnViewPlatformExit wakeupOnViewPlatformExitArr[] = + (WakeupOnViewPlatformExit []) wakeupOnViewPlatformExit.toArray(false); + WakeupOnViewPlatformExit wexit; + + for (i=wakeupOnViewPlatformExit.arraySize()-1; i >=0; i--) { + wexit = wakeupOnViewPlatformExitArr[i]; + idx = boundsExitList.indexOf(wexit); + if (idx < 0) { + if (wexit.transformedRegion.intersect(vp.center)) { + wexit.triggeredVP = vp; + boundsExitList.add(wexit); + + } + } else { + triggeredVP = intersectVPCenter(wexit.transformedRegion); + if (triggeredVP == null) { + boundsExitList.remove(idx); + wexit.setTriggered(); + } + } + } + } + + void updateVPEntryTransformRegion(BehaviorRetained behav) { + WakeupOnViewPlatformEntry wakeupOnViewPlatformEntryArr[] = + (WakeupOnViewPlatformEntry []) wakeupOnViewPlatformEntry.toArray(false); + WakeupOnViewPlatformEntry wentry; + ViewPlatformRetained triggeredVP; + + for (int i=wakeupOnViewPlatformEntry.arraySize()-1; i >=0; i--) { + wentry = wakeupOnViewPlatformEntryArr[i]; + if (wentry.behav == behav) { + wentry.updateTransformRegion(behav); + int idx = boundsEntryList.indexOf(wentry); + + triggeredVP = intersectVPCenter(wentry.transformedRegion); + if (triggeredVP != null) { + if (idx < 0) { + boundsEntryList.add(wentry); + wentry.triggeredVP = triggeredVP; + wentry.setTriggered(); + } + } else { + if (idx >=0) { + boundsEntryList.remove(idx); + } + } + } + + } + } + + + + void updateVPExitTransformRegion(BehaviorRetained behav) { + WakeupOnViewPlatformExit wakeupOnViewPlatformExitArr[] = + (WakeupOnViewPlatformExit []) wakeupOnViewPlatformExit.toArray(false); + WakeupOnViewPlatformExit wexit; + ViewPlatformRetained triggeredVP; + + for (int i=wakeupOnViewPlatformExit.arraySize()-1; i >=0; i--) { + wexit = wakeupOnViewPlatformExitArr[i]; + if (wexit.behav == behav) { + wexit.updateTransformRegion(behav); + wexit = wakeupOnViewPlatformExitArr[i]; + int idx = boundsExitList.indexOf(wexit); + triggeredVP = intersectVPCenter(wexit.transformedRegion); + if (triggeredVP != null) { + if (idx < 0) { + wexit.triggeredVP = triggeredVP; + boundsExitList.add(wexit); + } + } else { + if (idx >= 0) { + boundsExitList.remove(idx); + wexit.setTriggered(); + } + } + } + } + } + + + void reEvaluatePhysicalEnvironments() { + // we can't just add or remove from the list since + // physicalEnvironment may be share by multiple view + View v; + View views[]; + ViewPlatform vp; + ArrayList vpList = universe.viewPlatforms; + + physicalEnvironments.clear(); + + for (int i=vpList.size()-1; i>=0; i--) { + views = ((ViewPlatformRetained) vpList.get(i)).getViewList(); + for (int j=views.length-1; j>=0; j--) { + v = views[j]; + if (v.active && + !physicalEnvironments.contains(v.physicalEnvironment)) { + physicalEnvironments.add(v.physicalEnvironment); + } + } + } + } + + void checkSensorEntryExit() { + int i, idx; + Sensor target; + + // handle WakeupOnSensorEntry + WakeupOnSensorEntry wentry; + WakeupOnSensorEntry wentryArr[] = (WakeupOnSensorEntry []) + wakeupOnSensorEntry.toArray(); + + for (i=wakeupOnSensorEntry.arraySize()-1; i>=0; i--) { + wentry = wentryArr[i]; + idx = currentSensorEntryList.indexOf(wentry); + wentry.updateTransformRegion(); + target = sensorIntersect(wentry.transformedRegion); + if (target != null) { + if (idx < 0) { + currentSensorEntryList.add(wentry); + wentry.setTarget(target); + wentry.setTriggered(); + } + } else { + if (idx >= 0) { + currentSensorEntryList.remove(idx); + } + } + } + + // handle WakeupOnSensorExit + WakeupOnSensorExit wexit; + WakeupOnSensorExit wexitArr[] = (WakeupOnSensorExit []) + wakeupOnSensorExit.toArray(); + + for (i=wakeupOnSensorExit.arraySize()-1; i>=0; i--) { + wexit = wexitArr[i]; + idx = currentSensorExitList.indexOf(wexit); + wexit.updateTransformRegion(); + target = sensorIntersect(wexit.transformedRegion); + if (target != null) { + if (idx < 0) { + currentSensorExitList.add(wexit); + wexit.setTarget(target); + } + } else { + if (idx >= 0) { + currentSensorExitList.remove(idx); + wexit.setTriggered(); + } + } + } + + } + + + /** + * return the Senor that intersect with behregion or null + */ + Sensor sensorIntersect(Bounds behregion) { + + if (behregion == null) + return null; + + PhysicalEnvironment env[] = (PhysicalEnvironment []) + physicalEnvironments.toArray(false); + Sensor sensors[]; + Sensor s; + View v; + for (int i=physicalEnvironments.arraySize()-1; i>=0; i--) { + if (env[i].activeViewRef > 0) { + sensors = env[i].getSensorList(); + if (sensors != null) { + for (int j= env[i].users.size()-1; j>=0; j--) { + v = (View) env[i].users.get(j); + synchronized (sensors) { + for (int k=sensors.length-1; k >=0; k--) { + s = sensors[k]; + if (s != null) { + v.getSensorToVworld(s, sensorTransform); + sensorTransform.get(sensorLoc); + ptSensorLoc.set(sensorLoc); + if (behregion.intersect(ptSensorLoc)) { + return s; + } + } + } + } + } + } + } + } + return null; + } + + + /** + * return true if one of ViewPlatforms intersect behregion + */ + final boolean intersectVPRegion(Bounds behregion) { + if (behregion == null) { + return false; + } + + ViewPlatformRetained vp; + ViewPlatformRetained vpLists[] = (ViewPlatformRetained []) + viewPlatforms.toArray(false); + + for (int i=viewPlatforms.arraySize()- 1; i>=0; i--) { + vp = vpLists[i]; + if (vp.isActiveViewPlatform() && + vp.schedSphere.intersect(behregion)) { + return true; + } + } + return false; + } + + /** + * return true if one of ViewPlatforms center intersect behregion + */ + final ViewPlatformRetained intersectVPCenter(Bounds behregion) { + if (behregion == null) { + return null; + } + + ViewPlatformRetained vp; + ViewPlatformRetained vpLists[] = (ViewPlatformRetained []) + viewPlatforms.toArray(false); + + + for (int i=viewPlatforms.arraySize()- 1; i>=0; i--) { + vp = vpLists[i]; + if (vp.isActiveViewPlatform() && + behregion.intersect(vp.center)) { + return vp; + } + } + return null; + } + + void notifyDeactivationCondition(BehaviorRetained behav) { + WakeupOnDeactivation wakeup; + WakeupOnDeactivation wakeupConds[] = (WakeupOnDeactivation []) + wakeupOnDeactivation.toArray(false); + + for (int i=wakeupOnDeactivation.arraySize()-1; i>=0; i--) { + wakeup = wakeupConds[i]; + if (wakeup.behav == behav) { + wakeup.setTriggered(); + } + } + } + + void notifyActivationCondition(BehaviorRetained behav) { + WakeupOnActivation wakeup; + WakeupOnActivation wakeupConds[] = (WakeupOnActivation []) + wakeupOnActivation.toArray(false); + + for (int i=wakeupOnActivation.arraySize()-1; i>=0; i--) { + wakeup = wakeupConds[i]; + if (wakeup.behav == behav) { + wakeup.setTriggered(); + } + } + } + + + void processSwitchChanged(J3dMessage m) { + + int i,j; + UnorderList arrList; + int size; + Object[] nodes, nodesArr; + + UpdateTargets targets = (UpdateTargets)m.args[0]; + arrList = targets.targetList[Targets.VPF_TARGETS]; + + if (arrList != null) { + ViewPlatformRetained vp; + size = arrList.size(); + nodesArr = arrList.toArray(false); + + for (j=0; j=0; i--) { + vp = (ViewPlatformRetained) nodes[i]; + vp.processSwitchChanged(); + } + } + } + + arrList = targets.targetList[Targets.BEH_TARGETS]; + + if (arrList != null) { + BehaviorRetained behav; + size = arrList.size(); + nodesArr = arrList.toArray(false); + + for (j=0; j=0; i--) { + behav = (BehaviorRetained) nodes[i]; + if (behav.switchState.currentSwitchOn) { + addToScheduleList(behav); + } else { + removeFromScheduleList(behav); + } + } + } + } + + arrList = targets.targetList[Targets.BLN_TARGETS]; + if (arrList != null) { + size = arrList.size(); + nodesArr = arrList.toArray(false); + Object[] objArr = (Object[])m.args[1]; + Object[] obj; + BoundingLeafRetained mbleaf; + + for (int h=0; h=0; i--) { + + Object[] users = (Object[])obj[i]; + Object[] leafObj = new Object[1]; + mbleaf = (BoundingLeafRetained)nodes[i]; + for (j = 0; j < users.length; j++) { + if (users[j] instanceof BehaviorRetained) { + leafObj[0] = users[j]; + processTransformChanged(leafObj); + } + } + } + } + } + } + + void processBoundingLeafChanged(Object users[], + Bounds bound) { + Object leaf; + BehaviorRetained behav; + + for (int i=users.length-1; i>=0; i--) { + leaf = users[i]; + if (leaf instanceof BehaviorRetained) { + behav = (BehaviorRetained) leaf; + behav.updateTransformRegion(bound); + processBehaviorTransform(behav); + } + } + } + + final void removeFromScheduleList(BehaviorRetained behav) { + if (behav.active) { + if ((behav.wakeupMask & + BehaviorRetained.WAKEUP_DEACTIVATE) != 0) { + notifyDeactivationCondition(behav); + } + scheduleList.remove(behav); + behav.active = false; + if (behav.universe != universe) { + J3dMessage m = new J3dMessage(); + m.threads = J3dThread.UPDATE_BEHAVIOR; + m.type = J3dMessage.BEHAVIOR_REEVALUATE; + m.universe = behav.universe; + m.args[0] = behav; + VirtualUniverse.mc.processMessage(m); + } + } + } + + final void addToScheduleList(BehaviorRetained behav) { + + if (!behav.inCallback && + !behav.active && + behav.enable && + behav.switchState.currentSwitchOn && + (behav.wakeupCondition != null) && + ((Behavior) behav.source).isLive() && + intersectVPRegion(behav.transformedRegion)) { + + scheduleList.add(behav); + behav.active = true; + if ((behav.wakeupMask & + BehaviorRetained.WAKEUP_ACTIVATE) != 0) { + notifyActivationCondition(behav); + } + + if (behav.wakeupCondition != null) { + // This reset the conditionMet, otherwise + // if conditionMet is true then WakeupCondition + // will never post message to BehaviorStructure + behav.wakeupCondition.conditionMet = false; + } + } + } + + /** + * This prevents wakeupCondition sent out message and sets + * conditionMet to true, but the + * BehaviorStructure/BehaviorScheduler is not fast enough to + * process the message and reset conditionMet to false + * when view deactivate/unregister. + */ + void resetConditionMet() { + resetConditionMet(wakeupOnAWTEvent); + resetConditionMet(wakeupOnActivation); + resetConditionMet(wakeupOnDeactivation); + resetConditionMet(wakeupOnBehaviorPost); + resetConditionMet(wakeupOnElapsedFrames); + resetConditionMet(wakeupOnViewPlatformEntry); + resetConditionMet(wakeupOnViewPlatformExit); + resetConditionMet(wakeupOnSensorEntry); + resetConditionMet(wakeupOnSensorExit); + } + + static void resetConditionMet(WakeupIndexedList list) { + WakeupCondition wakeups[] = (WakeupCondition []) list.toArray(false); + int i = list.size()-1; + while (i >= 0) { + wakeups[i--].conditionMet = false; + } + } + + void reEvaluateWakeupCount() { + WakeupOnElapsedFrames wakeupConds[] = (WakeupOnElapsedFrames []) + wakeupOnElapsedFrames.toArray(true); + int size = wakeupOnElapsedFrames.arraySize(); + int i = 0; + WakeupOnElapsedFrames cond; + + activeWakeupOnFrameCount = 0; + + while (i < size) { + cond = wakeupConds[i++]; + if (!cond.passive && + (cond.behav != null) && + cond.behav.enable) { + activeWakeupOnFrameCount++; + } + } + + + activeWakeupOnSensorCount = 0; + WakeupOnSensorEntry wentry; + WakeupOnSensorEntry wentryArr[] = (WakeupOnSensorEntry []) + wakeupOnSensorEntry.toArray(); + + for (i=wakeupOnSensorEntry.arraySize()-1; i>=0; i--) { + wentry = wentryArr[i]; + if ((wentry.behav != null) && + (wentry.behav.enable)) { + activeWakeupOnSensorCount++; + } + } + + WakeupOnSensorExit wexit; + WakeupOnSensorExit wexitArr[] = (WakeupOnSensorExit []) + wakeupOnSensorExit.toArray(); + + for (i=wakeupOnSensorExit.arraySize()-1; i>=0; i--) { + wexit = wexitArr[i]; + if ((wexit.behav != null) && + (wexit.behav.enable)) { + activeWakeupOnSensorCount++; + } + } + + } + + void cleanup() { + behaviors.clear(); + viewPlatforms.clear(); + scheduleList.clear(); + boundsEntryList.clear(); + boundsExitList.clear(); + currentSensorEntryList.clear(); + currentSensorExitList.clear(); + wakeupOnAWTEvent.clear(); + wakeupOnActivation.clear(); + wakeupOnDeactivation.clear(); + wakeupOnBehaviorPost.clear(); + wakeupOnElapsedFrames.clear(); + wakeupOnViewPlatformEntry.clear(); + wakeupOnViewPlatformExit.clear(); + wakeupOnSensorEntry.clear(); + wakeupOnSensorExit.clear(); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Billboard.java b/j3d-core/src/classes/share/javax/media/j3d/Billboard.java new file mode 100644 index 0000000..55a1b49 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Billboard.java @@ -0,0 +1,675 @@ +/* + * $RCSfile: Billboard.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Enumeration; +import javax.vecmath.Point3f; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; +import javax.vecmath.Vector3f; +import javax.vecmath.AxisAngle4d; + +/** + * The Billboard behavior node operates on the TransformGroup node + * to cause the local +z axis of the TransformGroup to point at + * the viewer's eye position. This is done regardless of the transforms + * above the specified TransformGroup node in the scene graph. + * + *

+ * If the alignment mode is ROTATE_ABOUT_AXIS, the rotation will be + * around the specified axis. If the alignment mode is + * ROTATE_ABOUT_POINT, the rotation will be about the specified + * point, with an additional rotation to align the +y axis of the + * TransformGroup with the +y axis in the View. + * + *

+ * Note that in a multiple View system, the alignment is done to + * the primary View only. + * + *

+ * Billboard nodes are ideal for drawing screen aligned-text or + * for drawing roughly-symmetrical objects. A typical use might + * consist of a quadrilateral that contains a texture of a tree. + * + * @see OrientedShape3D + */ +public class Billboard extends Behavior { + /** + * Specifies that rotation should be about the specified axis. + */ + public static final int ROTATE_ABOUT_AXIS = 0; + + /** + * Specifies that rotation should be about the specified point and + * that the children's Y-axis should match the view object's Y-axis. + */ + public static final int ROTATE_ABOUT_POINT = 1; + + // Wakeup condition for Billboard node + WakeupOnElapsedFrames wakeupFrame = new WakeupOnElapsedFrames(0, true); + + + // Specifies the billboard's mode of operation. One of ROTATE_AXIAL, + // ROTATE_POINT_VIEW, or ROTATE_POINT_WORLD. + int mode = ROTATE_ABOUT_AXIS; + + // Axis about which to rotate. + Vector3f axis = new Vector3f(0.0f, 1.0f, 0.0f); + Point3f rotationPoint = new Point3f(0.0f, 0.0f, 1.0f); + private Vector3d nAxis = new Vector3d(0.0, 1.0, 0.0); // normalized axis + + // TransformGroup to operate on. + TransformGroup tg = null; + + + // reused temporaries + private Point3d viewPosition = new Point3d(); + private Point3d yUpPoint = new Point3d(); + + private Vector3d eyeVec = new Vector3d(); + private Vector3d yUp = new Vector3d(); + private Vector3d zAxis = new Vector3d(); + private Vector3d yAxis = new Vector3d(); + private Vector3d vector = new Vector3d(); + + private AxisAngle4d aa = new AxisAngle4d(); + + static final double EPSILON = 1.0e-6; + + /** + * Constructs a Billboard node with default parameters. + * The default values are as follows: + *

    + * alignment mode : ROTATE_ABOUT_AXIS
    + * alignment axis : Y-axis (0,1,0)
    + * rotation point : (0,0,1)
    + * target transform group: null
    + *
+ */ + public Billboard() { + nAxis.x = 0.0; + nAxis.y = 1.0; + nAxis.z = 0.0; + } + + + /** + * Constructs a Billboard node with default parameters that operates + * on the specified TransformGroup node. + * The default alignment mode is ROTATE_ABOUT_AXIS rotation with the axis + * pointing along the Y axis. + * @param tg the TransformGroup node that this Billboard + * node operates upon + */ + public Billboard(TransformGroup tg) { + this.tg = tg; + nAxis.x = 0.0; + nAxis.y = 1.0; + nAxis.z = 0.0; + + } + + + /** + * Constructs a Billboard node with the specified axis and mode + * that operates on the specified TransformGroup node. + * The specified axis must not be parallel to the Z + * axis--(0,0,z) for any value of z. It is not + * possible for the +Z axis to point at the viewer's eye + * position by rotating about itself. The target transform will + * be set to the identity if the axis is (0,0,z). + * + * @param tg the TransformGroup node that this Billboard + * node operates upon + * @param mode alignment mode, one of ROTATE_ABOUT_AXIS or + * ROTATE_ABOUT_POINT + * @param axis the ray about which the billboard rotates + */ + public Billboard(TransformGroup tg, int mode, Vector3f axis) { + this.tg = tg; + this.mode = mode; + this.axis.set(axis); + double invMag; + invMag = 1.0/Math.sqrt(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); + nAxis.x = (double)axis.x*invMag; + nAxis.y = (double)axis.y*invMag; + nAxis.z = (double)axis.z*invMag; + + } + + /** + * Constructs a Billboard node with the specified rotation point and mode + * that operates on the specified TransformGroup node. + * @param tg the TransformGroup node that this Billboard + * node operates upon + * @param mode alignment mode, one of ROTATE_ABOUT_AXIS or + * ROTATE_ABOUT_POINT + * @param point the position about which the billboard rotates + */ + public Billboard(TransformGroup tg, int mode, Point3f point) { + this.tg = tg; + this.mode = mode; + this.rotationPoint.set(point); + } + + /** + * Sets the alignment mode. + * @param mode one of: ROTATE_ABOUT_AXIS or ROTATE_ABOUT_POINT + */ + public void setAlignmentMode(int mode) { + this.mode = mode; + } + + + /** + * Gets the alignment mode. + * @return one of: ROTATE_ABOUT_AXIS or ROTATE_ABOUT_POINT + */ + public int getAlignmentMode() { + return this.mode; + } + + + /** + * Sets the alignment axis. + * The specified axis must not be parallel to the Z + * axis--(0,0,z) for any value of z. It is not + * possible for the +Z axis to point at the viewer's eye + * position by rotating about itself. The target transform will + * be set to the identity if the axis is (0,0,z). + * + * @param axis the ray about which the billboard rotates + */ + public void setAlignmentAxis(Vector3f axis) { + this.axis.set(axis); + double invMag; + invMag = 1.0/Math.sqrt(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); + nAxis.x = (double)axis.x*invMag; + nAxis.y = (double)axis.y*invMag; + nAxis.z = (double)axis.z*invMag; + + } + + + /** + * Sets the alignment axis. + * The specified axis must not be parallel to the Z + * axis--(0,0,z) for any value of z. It is not + * possible for the +Z axis to point at the viewer's eye + * position by rotating about itself. The target transform will + * be set to the identity if the axis is (0,0,z). + * + * @param x the x component of the ray about which the billboard rotates + * @param y the y component of the ray about which the billboard rotates + * @param z the z component of the ray about which the billboard rotates + */ + public void setAlignmentAxis(float x, float y, float z) { + this.axis.set(x, y, z); + this.axis.set(axis); + double invMag; + invMag = 1.0/Math.sqrt(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); + nAxis.x = (double)axis.x*invMag; + nAxis.y = (double)axis.y*invMag; + nAxis.z = (double)axis.z*invMag; + + } + + + /** + * Gets the alignment axis and sets the parameter to this value. + * @param axis the vector that will contain the ray about which + * the billboard rotates + */ + public void getAlignmentAxis(Vector3f axis) { + axis.set(this.axis); + } + + /** + * Sets the rotation point. + * @param point the point about which the billboard rotates + */ + public void setRotationPoint(Point3f point) { + this.rotationPoint.set(point); + } + + + /** + * Sets the rotation point. + * @param x the x component of the point about which the billboard rotates + * @param y the y component of the point about which the billboard rotates + * @param z the z component of the point about which the billboard rotates + */ + public void setRotationPoint(float x, float y, float z) { + this.rotationPoint.set(x, y, z); + } + + + /** + * Gets the rotation point and sets the parameter to this value. + * @param point the position the Billboard rotates about + */ + public void getRotationPoint(Point3f point) { + point.set(this.rotationPoint); + } + /** + * Sets the tranformGroup for this Billboard object. + * @param tg the transformGroup node which replaces the current + * transformGroup node for this Billboard + */ + public void setTarget(TransformGroup tg ) { + this.tg = tg; + } + + /** + * Returns a copy of the transformGroup associated with this Billboard. + * @return the TranformGroup for this Billboard + */ + public TransformGroup getTarget() { + return(tg); + } + + + /** + * Initialize method that sets up initial wakeup criteria. + */ + public void initialize() { + // Insert wakeup condition into queue + wakeupOn(wakeupFrame); + } + + + /** + * Process stimulus method that computes appropriate transform. + * @param criteria an enumeration of the criteria that caused the + * stimulus + */ + public void processStimulus(Enumeration criteria) { + double angle = 0.0; + double mag,sign; + double tx,ty,tz; + + if( tg == null ){ + wakeupOn(wakeupFrame); + return; + } + + // get viewplatforms's location in virutal world + View v = this.getView(); + if( v == null ) { + wakeupOn(wakeupFrame); + return; + } + Canvas3D canvas = (Canvas3D)v.getCanvas3D(0); + boolean status; + + Transform3D xform = new Transform3D(); + Transform3D bbXform = new Transform3D(); + Transform3D prevTransform = new Transform3D(); + + ((TransformGroupRetained) tg.retained).getTransform(prevTransform); + + if (mode == ROTATE_ABOUT_AXIS ) { // rotate about axis + canvas.getCenterEyeInImagePlate(viewPosition); + canvas.getImagePlateToVworld(xform); // xform is imagePlateToLocal + xform.transform(viewPosition); + + // get billboard's transform + + // since we are using getTransform() to get the transform + // of the transformGroup, we need to use getLocalToVworld() + // to get the localToVworld which includes the static transform + + ((NodeRetained)tg.retained).getLocalToVworld(xform); + + xform.invert(); // xform is now vWorldToLocal + + // transform the eye position into the billboard's coordinate system + xform.transform(viewPosition); + + // eyeVec is a vector from the local origin to the eye pt in local + eyeVec.set(viewPosition); + eyeVec.normalize(); + + // project the eye into the rotation plane + status = projectToPlane(eyeVec, nAxis); + + // If the first project was successful .. + if (status) { + // project the z axis into the rotation plane + zAxis.x = 0.0; + zAxis.y = 0.0; + zAxis.z = 1.0; + status = projectToPlane(zAxis, nAxis); + } + + + ((TransformGroupRetained) tg.retained).getTransform(xform); + if (status) { + // compute the sign of the angle by checking if the cross product + // of the two vectors is in the same direction as the normal axis + vector.cross(eyeVec, zAxis); + if (vector.dot(nAxis) > 0.0) { + sign = 1.0; + } else { + sign = -1.0; + } + + // compute the angle between the projected eye vector and the + // projected z + double dot = eyeVec.dot(zAxis); + + if (dot > 1.0f) { + dot = 1.0f; + } else if (dot < -1.0f) { + dot = -1.0f; + } + + angle = sign*Math.acos(dot); + + // use -angle because xform is to *undo* rotation by angle + aa.x = nAxis.x; + aa.y = nAxis.y; + aa.z = nAxis.z; + aa.angle = -angle; + bbXform.set(aa); + if( !prevTransform.epsilonEquals(bbXform, EPSILON)) { + // Optimization for Billboard since it use passive + // behavior + // set the transform on the Billboard TG + tg.setTransform(bbXform); + } + } + else { + bbXform.setIdentity(); + if (!prevTransform.epsilonEquals(bbXform, EPSILON)) { + tg.setTransform(bbXform); + } + } + + } else { // rotate about point + // Need to rotate Z axis to point to eye, and Y axis to be + // parallel to view platform Y axis, rotating around rotation pt + + Transform3D zRotate = new Transform3D(); + + // get the eye point + canvas.getCenterEyeInImagePlate(viewPosition); + + // derive the yUp point + yUpPoint.set(viewPosition); + yUpPoint.y += 0.01; // one cm in Physical space + + // transform the points to the Billboard's space + canvas.getImagePlateToVworld(xform); // xform is ImagePlateToVworld + + xform.transform(viewPosition); + xform.transform(yUpPoint); + + // get billboard's transform + + // since we are using getTransform() to get the transform + // of the transformGroup, we need to use getLocalToVworld() + // to get the localToVworld which includes the static transform + + ((NodeRetained)tg.retained).getLocalToVworld(xform); + + xform.invert(); // xform is vWorldToLocal + + // transfom points to local coord sys + xform.transform(viewPosition); + xform.transform(yUpPoint); + + // Make a vector from viewPostion to 0,0,0 in the BB coord sys + eyeVec.set(viewPosition); + eyeVec.normalize(); + + // create a yUp vector + yUp.set(yUpPoint); + yUp.sub(viewPosition); + yUp.normalize(); + + + // find the plane to rotate z + zAxis.x = 0.0; + zAxis.y = 0.0; + zAxis.z = 1.0; + + // rotation axis is cross product of eyeVec and zAxis + vector.cross(eyeVec, zAxis); // vector is cross product + + // if cross product is non-zero, vector is rotation axis and + // rotation angle is acos(eyeVec.dot(zAxis))); + double length = vector.length(); + + if (length > 0.0001) { + double dot = eyeVec.dot(zAxis); + + if (dot > 1.0f) { + dot = 1.0f; + } else if (dot < -1.0f) { + dot = -1.0f; + } + + angle = Math.acos(dot); + aa.x = vector.x; + aa.y = vector.y; + aa.z = vector.z; + aa.angle = -angle; + zRotate.set(aa); + } else { + // no rotation needed, set to identity (scale = 1.0) + zRotate.set(1.0); + } + + // Transform the yAxis by zRotate + yAxis.x = 0.0; + yAxis.y = 1.0; + yAxis.z = 0.0; + zRotate.transform(yAxis); + + // project the yAxis onto the plane perp to the eyeVec + status = projectToPlane(yAxis, eyeVec); + + if (status) { + // project the yUp onto the plane perp to the eyeVec + status = projectToPlane(yUp, eyeVec); + } + + ((TransformGroupRetained) tg.retained).getTransform(xform); + if (status) { + // rotation angle is acos(yUp.dot(yAxis)); + double dot = yUp.dot(yAxis); + + // Fix numerical error, otherwise acos return NULL + if (dot > 1.0f) { + dot = 1.0f; + } else if (dot < -1.0f) { + dot = -1.0f; + } + + angle = Math.acos(dot); + + // check the sign by looking a the cross product vs the eyeVec + vector.cross(yUp, yAxis); // vector is cross product + if (eyeVec.dot(vector) < 0) { + angle *= -1; + } + aa.x = eyeVec.x; + aa.y = eyeVec.y; + aa.z = eyeVec.z; + aa.angle = -angle; + + xform.set(aa); // xform is now yRotate + + // rotate around the rotation point + vector.x = rotationPoint.x; + vector.y = rotationPoint.y; + vector.z = rotationPoint.z; // vector to translate to RP + bbXform.set(vector); // translate to RP + bbXform.mul(xform); // yRotate + bbXform.mul(zRotate); // zRotate + vector.scale(-1.0); // vector to translate back + xform.set(vector); // xform to translate back + bbXform.mul(xform); // translate back + + + if (!prevTransform.epsilonEquals(bbXform, EPSILON)) { + // set the transform on the Billboard TG + tg.setTransform(bbXform); + } + } + else { + bbXform.setIdentity(); + if (!prevTransform.epsilonEquals(bbXform, EPSILON)) { + tg.setTransform(bbXform); + } + } + } + + // Insert wakeup condition into queue + wakeupOn(wakeupFrame); +} + +private boolean projectToPlane(Vector3d projVec, Vector3d planeVec) { + double dis = planeVec.dot(projVec); + projVec.x = projVec.x - planeVec.x*dis; + projVec.y = projVec.y - planeVec.y*dis; + projVec.z = projVec.z - planeVec.z*dis; + + double length = projVec.length(); + + if (length < EPSILON) { + return false; + } + projVec.scale(1 / length); + return true; +} + + /** + * Creates a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Billboard b = new Billboard(); + b.duplicateNode(this, forceDuplicate); + return b; + } + + + /** + * Copies all Billboard information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + Billboard bb = (Billboard) originalNode; + + setAlignmentMode(bb.getAlignmentMode()); + + Vector3f v = new Vector3f(); + bb.getAlignmentAxis(v); + setAlignmentAxis(v); + + Point3f p = new Point3f(); + bb.getRotationPoint(p); + setRotationPoint(p); + + // this will be updated by updateNodeReferences() later + setTarget(bb.getTarget()); + } + + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + super.updateNodeReferences(referenceTable); + + // check for new TransformGroup + TransformGroup g = getTarget(); + if (g != null) { + setTarget((TransformGroup) referenceTable.getNewObjectReference(g)); + } + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/BoundingBox.java b/j3d-core/src/classes/share/javax/media/j3d/BoundingBox.java new file mode 100644 index 0000000..a87ed4c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BoundingBox.java @@ -0,0 +1,1955 @@ +/* + * $RCSfile: BoundingBox.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:19 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import com.sun.j3d.internal.HashCodeUtil; + +/** + * This class defines an axis aligned bounding box which is used for + * bounding regions. + * + */ + +public class BoundingBox extends Bounds { + + /** + * The corner of the bounding box with the numerically smallest + * values. + */ + Point3d lower; + + /** + * The corner of the bounding box with the numerically largest + * values. + */ + Point3d upper; + + private Point3d centroid = null; + private static final double EPS = 1.0E-8; + + // reusable temp objects + private BoundingSphere tmpSphere = null; + private BoundingBox tmpBox = null; + private BoundingPolytope tmpPolytope = null; + private Point3d tmpP3d = null; + + + /** + * Constructs and initializes a BoundingBox given min,max in x,y,z. + * @param lower the "small" corner + * @param upper the "large" corner + */ + public BoundingBox(Point3d lower, Point3d upper) { + boundId = BOUNDING_BOX; + this.lower = new Point3d(lower); + this.upper = new Point3d(upper); + updateBoundsStates(); + } + + /** + * Constructs and initializes a 2X bounding box about the + * origin. The lower corner is initialized to (-1.0d, -1.0d, -1.0d) + * and the opper corner is initialized to (1.0d, 1.0d, 1.0d). + */ + public BoundingBox() { + boundId = BOUNDING_BOX; + lower = new Point3d(-1.0d, -1.0d, -1.0d); + upper = new Point3d( 1.0d, 1.0d, 1.0d); + updateBoundsStates(); + } + + /** + * Constructs a BoundingBox from a bounding object. + * @param boundsObject a bounds object + */ + public BoundingBox(Bounds boundsObject) { + int i; + boundId = BOUNDING_BOX; + if( boundsObject == null ) { + // Negative volume. + lower = new Point3d( 1.0d, 1.0d, 1.0d); + upper = new Point3d(-1.0d, -1.0d, -1.0d); + } + else if( boundsObject.boundsIsInfinite ) { + lower = new Point3d( Double.NEGATIVE_INFINITY, + Double.NEGATIVE_INFINITY, + Double.NEGATIVE_INFINITY); + upper = new Point3d(Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY); + } + else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + + lower = new Point3d(box.lower.x, box.lower.y, box.lower.z); + upper = new Point3d(box.upper.x, box.upper.y, box.upper.z); + + } + else if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + + lower = new Point3d(sphere.center.x-sphere.radius, + sphere.center.y-sphere.radius, + sphere.center.z-sphere.radius); + + upper = new Point3d(sphere.center.x+sphere.radius, + sphere.center.y+sphere.radius, + sphere.center.z+sphere.radius); + + } + else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + if( polytope.nVerts < 1 ) { // handle degenerate case + lower = new Point3d(-1.0d, -1.0d, -1.0d); + upper = new Point3d( 1.0d, 1.0d, 1.0d); + } else { + lower = new Point3d( polytope.verts[0].x, polytope.verts[0].y, + polytope.verts[0].z); + upper = new Point3d( polytope.verts[0].x, polytope.verts[0].y, + polytope.verts[0].z); + + for(i=1;i upper.x ) + upper.x = polytope.verts[i].x; + if( polytope.verts[i].y > upper.y ) + upper.y = polytope.verts[i].y; + if( polytope.verts[i].z > upper.z ) + upper.z = polytope.verts[i].z; + } + } + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox0")); + } + + updateBoundsStates(); + } + + /** + * Constructs a BoundingBox from an array of bounding objects. + * @param bounds an array of bounding objects + */ + public BoundingBox(Bounds[] bounds) { + int i=0; + + upper = new Point3d(); + lower = new Point3d(); + boundId = BOUNDING_BOX; + + if( bounds == null || bounds.length <= 0 ) { + // Negative volume. + lower = new Point3d( 1.0d, 1.0d, 1.0d); + upper = new Point3d(-1.0d, -1.0d, -1.0d); + updateBoundsStates(); + return; + } + + // find first non empty bounds object + while( bounds[i] == null && i < bounds.length) { + i++; + } + + if( i >= bounds.length ) { // all bounds objects were empty + // Negative volume. + lower = new Point3d( 1.0d, 1.0d, 1.0d); + upper = new Point3d(-1.0d, -1.0d, -1.0d); + updateBoundsStates(); + return; + } + + this.set(bounds[i++]); + if(boundsIsInfinite) + return; + + for(;i box.lower.x) lower.x = box.lower.x; + if( lower.y > box.lower.y) lower.y = box.lower.y; + if( lower.z > box.lower.z) lower.z = box.lower.z; + if( upper.x < box.upper.x) upper.x = box.upper.x; + if( upper.y < box.upper.y) upper.y = box.upper.y; + if( upper.z < box.upper.z) upper.z = box.upper.z; + + } + else if(bounds[i].boundId == BOUNDING_SPHERE) { + BoundingSphere sphere = (BoundingSphere)bounds[i]; + if( lower.x > (sphere.center.x - sphere.radius)) + lower.x = sphere.center.x - sphere.radius; + if( lower.y > (sphere.center.y - sphere.radius)) + lower.y = sphere.center.y - sphere.radius; + if( lower.z > (sphere.center.z - sphere.radius)) + lower.z = sphere.center.z - sphere.radius; + if( upper.x < (sphere.center.x + sphere.radius)) + upper.x = sphere.center.x + sphere.radius; + if( upper.y < (sphere.center.y + sphere.radius)) + upper.y = sphere.center.y + sphere.radius; + if( upper.z < (sphere.center.z + sphere.radius)) + upper.z = sphere.center.z + sphere.radius; + } + else if(bounds[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)bounds[i]; + + for(i=0;i upper.x ) + upper.x = polytope.verts[i].x; + if( polytope.verts[i].y > upper.y ) + upper.y = polytope.verts[i].y; + if( polytope.verts[i].z > upper.z ) + upper.z = polytope.verts[i].z; + } + } + else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox1")); + } + } + updateBoundsStates(); + } + + /** + * Gets the lower corner of this bounding box. + * @param p1 a Point to receive the lower corner of the bounding box + */ + public void getLower(Point3d p1) { + p1.x = lower.x; + p1.y = lower.y; + p1.z = lower.z; + } + + /** + * Sets the lower corner of this bounding box. + * @param xmin minimum x value of boundining box + * @param ymin minimum y value of boundining box + * @param zmin minimum z value of boundining box + */ + public void setLower(double xmin, double ymin, double zmin ) { + lower.x = xmin; + lower.y = ymin; + lower.z = zmin; + + updateBoundsStates(); + } + + /** + * Sets the lower corner of this bounding box. + * @param p1 a Point defining the new lower corner of the bounding box + */ + public void setLower(Point3d p1) { + + lower.x = p1.x; + lower.y = p1.y; + lower.z = p1.z; + + updateBoundsStates(); + } + + /** + * Gets the upper corner of this bounding box. + * @param p1 a Point to receive the upper corner of the bounding box + */ + public void getUpper(Point3d p1) { + p1.x = upper.x; + p1.y = upper.y; + p1.z = upper.z; + } + + /** + * Sets the upper corner of this bounding box. + * @param xmax max x value of boundining box + * @param ymax max y value of boundining box + * @param zmax max z value of boundining box + */ + public void setUpper(double xmax, double ymax, double zmax ) { + upper.x = xmax; + upper.y = ymax; + upper.z = zmax; + + updateBoundsStates(); + } + + /** + * Sets the upper corner of this bounding box. + * @param p1 a Point defining the new upper corner of the bounding box + */ + public void setUpper(Point3d p1) { + upper.x = p1.x; + upper.y = p1.y; + upper.z = p1.z; + + updateBoundsStates(); + } + + /** + * Sets the the value of this BoundingBox + * @param boundsObject another bounds object + */ + public void set(Bounds boundsObject) { + int i; + + if(( boundsObject == null ) ||( boundsObject.boundsIsEmpty)) { + // Negative volume. + lower.x = lower.y = lower.z = 1.0d; + upper.x = upper.y = upper.z = -1.0d; + + } else if( boundsObject.boundsIsInfinite ) { + lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY; + upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY; + + } else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + + lower.x = box.lower.x; + lower.y = box.lower.y; + lower.z = box.lower.z; + upper.x = box.upper.x; + upper.y = box.upper.y; + upper.z = box.upper.z; + + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + lower.x = sphere.center.x - sphere.radius; + lower.y = sphere.center.y - sphere.radius; + lower.z = sphere.center.z - sphere.radius; + upper.x = sphere.center.x + sphere.radius; + upper.y = sphere.center.y + sphere.radius; + upper.z = sphere.center.z + sphere.radius; + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + lower.x = upper.x = polytope.verts[0].x; + lower.y = upper.y = polytope.verts[0].y; + lower.z = upper.z = polytope.verts[0].z; + + for(i=1;i upper.x ) upper.x = polytope.verts[i].x; + if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y; + if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z; + } + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox0")); + } + + updateBoundsStates(); + } + + + /** + * Creates a copy of this bounding box. + * @return a new bounding box + */ + public Object clone() { + return new BoundingBox(this.lower, this.upper); + } + + + /** + * Indicates whether the specified bounds object is + * equal to this BoundingBox object. They are equal if the + * specified bounds object is an instance of + * BoundingBox and all of the data + * members of bounds are equal to the corresponding + * data members in this BoundingBox. + * @param bounds the object with which the comparison is made. + * @return true if this BoundingBox is equal to bounds; + * otherwise false + * + * @since Java 3D 1.2 + */ + public boolean equals(Object bounds) { + try { + BoundingBox box = (BoundingBox)bounds; + return (lower.equals(box.lower) && + upper.equals(box.upper)); + } + catch (NullPointerException e) { + return false; + } + catch (ClassCastException e) { + return false; + } + } + + + /** + * Returns a hash code value for this BoundingBox object + * based on the data values in this object. Two different + * BoundingBox objects with identical data values (i.e., + * BoundingBox.equals returns true) will return the same hash + * code value. Two BoundingBox objects with different data + * members may return the same hash code value, although this is + * not likely. + * @return a hash code value for this BoundingBox object. + * + * @since Java 3D 1.2 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.x); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.y); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(lower.z); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.x); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.y); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(upper.z); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Combines this bounding box with a bounding object so that the + * resulting bounding box encloses the original bounding box and the + * specified bounds object. + * @param boundsObject another bounds object + */ + public void combine(Bounds boundsObject) { + + if((boundsObject == null) || (boundsObject.boundsIsEmpty) + || (boundsIsInfinite)) + return; + + if((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) { + this.set(boundsObject); + return; + } + + if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + + if( lower.x > box.lower.x) lower.x = box.lower.x; + if( lower.y > box.lower.y) lower.y = box.lower.y; + if( lower.z > box.lower.z) lower.z = box.lower.z; + if( upper.x < box.upper.x) upper.x = box.upper.x; + if( upper.y < box.upper.y) upper.y = box.upper.y; + if( upper.z < box.upper.z) upper.z = box.upper.z; + + } + else if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + if( lower.x > (sphere.center.x - sphere.radius)) + lower.x = sphere.center.x - sphere.radius; + if( lower.y > (sphere.center.y - sphere.radius)) + lower.y = sphere.center.y - sphere.radius; + if( lower.z > (sphere.center.z - sphere.radius)) + lower.z = sphere.center.z - sphere.radius; + if( upper.x < (sphere.center.x + sphere.radius)) + upper.x = sphere.center.x + sphere.radius; + if( upper.y < (sphere.center.y + sphere.radius)) + upper.y = sphere.center.y + sphere.radius; + if( upper.z < (sphere.center.z + sphere.radius)) + upper.z = sphere.center.z + sphere.radius; + + } + else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + int i; + for(i=1;i upper.x ) upper.x = polytope.verts[i].x; + if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y; + if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z; + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox3")); + } + + updateBoundsStates(); + } + + /** + * Combines this bounding box with an array of bounding objects + * so that the resulting bounding box encloses the original bounding + * box and the array of bounding objects. + * @param bounds an array of bounds objects + */ + public void combine(Bounds[] bounds) { + int i=0; + + if( (bounds == null) || (bounds.length <= 0) + || (boundsIsInfinite)) + return; + + // find first non empty bounds object + while( (i= bounds.length) + return; // no non empty bounds so do not modify current bounds + + if(boundsIsEmpty) + this.set(bounds[i++]); + + if(boundsIsInfinite) + return; + + for(;i box.lower.x) lower.x = box.lower.x; + if( lower.y > box.lower.y) lower.y = box.lower.y; + if( lower.z > box.lower.z) lower.z = box.lower.z; + if( upper.x < box.upper.x) upper.x = box.upper.x; + if( upper.y < box.upper.y) upper.y = box.upper.y; + if( upper.z < box.upper.z) upper.z = box.upper.z; + } + else if( bounds[i].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)bounds[i]; + if( lower.x > (sphere.center.x - sphere.radius)) + lower.x = sphere.center.x - sphere.radius; + if( lower.y > (sphere.center.y - sphere.radius)) + lower.y = sphere.center.y - sphere.radius; + if( lower.z > (sphere.center.z - sphere.radius)) + lower.z = sphere.center.z - sphere.radius; + if( upper.x < (sphere.center.x + sphere.radius)) + upper.x = sphere.center.x + sphere.radius; + if( upper.y < (sphere.center.y + sphere.radius)) + upper.y = sphere.center.y + sphere.radius; + if( upper.z < (sphere.center.z + sphere.radius)) + upper.z = sphere.center.z + sphere.radius; + } + else if(bounds[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)bounds[i]; + for(i=1;i upper.x ) upper.x = polytope.verts[i].x; + if( polytope.verts[i].y > upper.y ) upper.y = polytope.verts[i].y; + if( polytope.verts[i].z > upper.z ) upper.z = polytope.verts[i].z; + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox4")); + } + } + + updateBoundsStates(); + } + + /** + * Combines this bounding box with a point so that the resulting + * bounding box encloses the original bounding box and the point. + * @param point a 3d point in space + */ + public void combine(Point3d point) { + + if( boundsIsInfinite) { + return; + } + + if( boundsIsEmpty) { + upper.x = lower.x = point.x; + upper.y = lower.y = point.y; + upper.z = lower.z = point.z; + } else { + if( point.x > upper.x) upper.x = point.x; + if( point.y > upper.y) upper.y = point.y; + if( point.z > upper.z) upper.z = point.z; + + if( point.x < lower.x) lower.x = point.x; + if( point.y < lower.y) lower.y = point.y; + if( point.z < lower.z) lower.z = point.z; + } + + updateBoundsStates(); + } + + /** + * Combines this bounding box with an array of points so that the + * resulting bounding box encloses the original bounding box and the + * array of points. + * @param points an array of 3d points in space + */ + public void combine(Point3d[] points) { + + int i; + + if( boundsIsInfinite) { + return; + } + + if( boundsIsEmpty) { + this.setUpper(points[0]); + this.setLower(points[0]); + } + + for(i=0;i upper.x) upper.x = points[i].x; + if( points[i].y > upper.y) upper.y = points[i].y; + if( points[i].z > upper.z) upper.z = points[i].z; + + if( points[i].x < lower.x) lower.x = points[i].x; + if( points[i].y < lower.y) lower.y = points[i].y; + if( points[i].z < lower.z) lower.z = points[i].z; + } + + updateBoundsStates(); + } + + /** + * Modifies the bounding box so that it bounds the volume + * generated by transforming the given bounding object. + * @param boundsObject the bounding object to be transformed + * @param matrix a transformation matrix + */ + public void transform( Bounds boundsObject, Transform3D matrix) { + + if( boundsObject == null || boundsObject.boundsIsEmpty) { + // Negative volume. + lower.x = lower.y = lower.z = 1.0d; + upper.x = upper.y = upper.z = -1.0d; + updateBoundsStates(); + return; + } + + if(boundsObject.boundsIsInfinite) { + lower.x = lower.y = lower.z = Double.NEGATIVE_INFINITY; + upper.x = upper.y = upper.z = Double.POSITIVE_INFINITY; + updateBoundsStates(); + return; + } + + if(boundsObject.boundId == BOUNDING_BOX){ + if (tmpBox == null) { + tmpBox = new BoundingBox( (BoundingBox)boundsObject); + } else { + tmpBox.set((BoundingBox)boundsObject); + } + tmpBox.transform(matrix); + this.set(tmpBox); + } + else if(boundsObject.boundId == BOUNDING_SPHERE) { + if (tmpSphere == null) { + tmpSphere = new BoundingSphere( (BoundingSphere)boundsObject); + } else { + tmpSphere.set((BoundingSphere)boundsObject); + } + tmpSphere.transform(matrix); + this.set(tmpSphere); + } + else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + if (tmpPolytope == null) { + tmpPolytope = + new BoundingPolytope((BoundingPolytope) boundsObject); + } else { + tmpPolytope.set((BoundingPolytope)boundsObject); + } + tmpPolytope.transform(matrix); + this.set(tmpPolytope); + + } + else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox5")); + } + + // Release the temporary fields: + if (VirtualUniverse.mc.releaseBoundingBoxMemory) { + tmpSphere = null; + tmpBox = null; + tmpPolytope = null; + } + } + + /** + * Transforms this bounding box by the given matrix. + * @param matrix a transformation matrix + */ + public void transform(Transform3D matrix) { + + if(boundsIsInfinite) + return; + + if (tmpP3d == null) { + tmpP3d = new Point3d(); + } + + double ux, uy, uz, lx, ly, lz; + ux = upper.x; uy = upper.y; uz = upper.z; + lx = lower.x; ly = lower.y; lz = lower.z; + + tmpP3d.set(ux, uy, uz); + matrix.transform( tmpP3d ); + upper.x = tmpP3d.x; + upper.y = tmpP3d.y; + upper.z = tmpP3d.z; + lower.x = tmpP3d.x; + lower.y = tmpP3d.y; + lower.z = tmpP3d.z; + + tmpP3d.set(lx, uy, uz); + matrix.transform( tmpP3d ); + if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; + if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; + if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; + if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; + if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; + if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; + + tmpP3d.set(lx, ly, uz); + matrix.transform( tmpP3d ); + if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; + if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; + if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; + if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; + if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; + if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; + + tmpP3d.set(ux, ly, uz); + matrix.transform( tmpP3d ); + if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; + if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; + if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; + if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; + if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; + if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; + + tmpP3d.set(lx, uy, lz); + matrix.transform( tmpP3d ); + if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; + if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; + if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; + if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; + if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; + if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; + + tmpP3d.set(ux, uy, lz); + matrix.transform( tmpP3d ); + if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; + if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; + if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; + if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; + if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; + if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; + + tmpP3d.set(lx, ly, lz); + matrix.transform( tmpP3d ); + if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; + if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; + if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; + if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; + if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; + if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; + + tmpP3d.set(ux, ly, lz); + matrix.transform( tmpP3d ); + if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x; + if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y; + if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z; + if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x; + if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y; + if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z; + + if (VirtualUniverse.mc.releaseBoundingBoxMemory) { + // Free memory + tmpP3d = null; + } + + } + + /** + * Test for intersection with a ray. + * @param origin the starting point of the ray + * @param direction the direction of the ray + * @param position3 a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + boolean intersect(Point3d origin, Vector3d direction, Point4d position ) { + double t1,t2,tmp,tnear,tfar,invDir,invMag; + double dirx, diry, dirz; + + /* + System.err.println("BoundingBox.intersect(p,d,p) called\n"); + System.err.println("bounds = " + lower + " -> " + upper); + */ + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = origin.x; + position.y = origin.y; + position.z = origin.z; + position.w = 0.0; + return true; + } + + double dirLen = direction.x*direction.x + direction.y*direction.y + + direction.z*direction.z; + + // Handle zero length direction vector. + if(dirLen == 0.0) + return intersect(origin, position); + + invMag = 1.0/Math.sqrt(dirLen); + dirx = direction.x*invMag; + diry = direction.y*invMag; + dirz = direction.z*invMag; + + /* + System.err.println("dir = " + dirx + ", " + diry + ", " + dirz); + System.err.println("origin = " + origin); + */ + + // initialize tnear and tfar to handle dir.? == 0 cases + tnear = -Double.MAX_VALUE; + tfar = Double.MAX_VALUE; + + if(dirx == 0.0) { + //System.err.println("dirx == 0.0"); + if (origin.x < lower.x || origin.x > upper.x ) { + //System.err.println( "parallel to x plane and outside"); + return false; + } + } else { + invDir = 1.0/dirx; + t1 = (lower.x-origin.x)*invDir; + t2 = (upper.x-origin.x)*invDir; + + //System.err.println("x t1 = " + t1 + " t2 = " + t2); + if( t1 > t2) { + tnear = t2; + tfar = t1; + }else { + tnear = t1; + tfar = t2; + } + if( tfar < 0.0 ) { + //System.err.println( "x failed: tnear="+tnear+" tfar="+tfar); + return false; + } + //System.err.println("x tnear = " + tnear + " tfar = " + tfar); + } + // y + if (diry == 0.0) { + //System.err.println("diry == 0.0"); + if( origin.y < lower.y || origin.y > upper.y ){ + //System.err.println( "parallel to y plane and outside"); + return false; + } + } else { + invDir = 1.0/diry; + //System.err.println("invDir = " + invDir); + t1 = (lower.y-origin.y)*invDir; + t2 = (upper.y-origin.y)*invDir; + + if( t1 > t2) { + tmp = t1; + t1 = t2; + t2 = tmp; + } + //System.err.println("y t1 = " + t1 + " t2 = " + t2); + if( t1 > tnear) tnear = t1; + if( t2 < tfar ) tfar = t2; + + if( (tfar < 0.0) || (tnear > tfar)){ + //System.err.println( "y failed: tnear="+tnear+" tfar="+tfar); + return false; + } + //System.err.println("y tnear = " + tnear + " tfar = " + tfar); + } + + // z + if (dirz == 0.0) { + //System.err.println("dirz == 0.0"); + if( origin.z < lower.z || origin.z > upper.z ) { + //System.err.println( "parallel to z plane and outside"); + return false; + } + } else { + invDir = 1.0/dirz; + t1 = (lower.z-origin.z)*invDir; + t2 = (upper.z-origin.z)*invDir; + + if( t1 > t2) { + tmp = t1; + t1 = t2; + t2 = tmp; + } + //System.err.println("z t1 = " + t1 + " t2 = " + t2); + if( t1 > tnear) tnear = t1; + if( t2 < tfar ) tfar = t2; + + if( (tfar < 0.0) || (tnear > tfar)){ + //System.err.println( "z failed: tnear="+tnear+" tfar="+tfar); + return false; + } + //System.err.println("z tnear = " + tnear + " tfar = " + tfar); + } + + if((tnear < 0.0) && (tfar >= 0.0)) { + // origin is inside the BBox. + position.x = origin.x + dirx*tfar; + position.y = origin.y + diry*tfar; + position.z = origin.z + dirz*tfar; + position.w = tfar; + } + else { + position.x = origin.x + dirx*tnear; + position.y = origin.y + diry*tnear; + position.z = origin.z + dirz*tnear; + position.w = tnear; + } + + return true; + + } + + + /** + * Test for intersection with a point. + * @param point the pick point + * @param position a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + boolean intersect(Point3d point, Point4d position ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = point.x; + position.y = point.y; + position.z = point.z; + position.w = 0.0; + return true; + } + + if( point.x <= upper.x && point.x >= lower.x && + point.y <= upper.y && point.y >= lower.y && + point.z <= upper.z && point.z >= lower.z) { + position.x = point.x; + position.y = point.y; + position.z = point.z; + position.w = 0.0; + return true; + } else + return false; + + } + + /** + * Test for intersection with a segment. + * @param start a point defining the start of the line segment + * @param end a point defining the end of the line segment + * @param position a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + boolean intersect( Point3d start, Point3d end, Point4d position ) { + double t1,t2,tmp,tnear,tfar,invDir,invMag; + double dirx, diry, dirz; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = start.x; + position.y = start.y; + position.z = start.z; + position.w = 0.0; + return true; + } + + dirx = end.x - start.x; + diry = end.y - start.y; + dirz = end.z - start.z; + + double dirLen = dirx*dirx + diry*diry + dirz*dirz; + + // Optimization : Handle zero length direction vector. + if(dirLen == 0.0) + return intersect(start, position); + + dirLen = Math.sqrt(dirLen); + // System.err.println("dirLen is " + dirLen); + invMag = 1.0/dirLen; + dirx = dirx*invMag; + diry = diry*invMag; + dirz = dirz*invMag; + + /* + System.err.println("dir = " + dir); + System.err.println("start = " + start); + System.err.println("lower = " + lower); + System.err.println("upper = " + upper); + */ + + // initialize tnear and tfar to handle dir.? == 0 cases + tnear = -Double.MAX_VALUE; + tfar = Double.MAX_VALUE; + + if(dirx == 0.0) { + //System.err.println("dirx == 0.0"); + if (start.x < lower.x || start.x > upper.x ) { + //System.err.println( "parallel to x plane and outside"); + return false; + } + } else { + invDir = 1.0/dirx; + t1 = (lower.x-start.x)*invDir; + t2 = (upper.x-start.x)*invDir; + + //System.err.println("x t1 = " + t1 + " t2 = " + t2); + if( t1 > t2) { + tnear = t2; + tfar = t1; + }else { + tnear = t1; + tfar = t2; + } + if( tfar < 0.0 ) { + //System.err.println( "x failed: tnear="+tnear+" tfar="+tfar); + return false; + } + //System.err.println("x tnear = " + tnear + " tfar = " + tfar); + } + // y + if (diry == 0.0) { + //System.err.println("diry == 0.0"); + if( start.y < lower.y || start.y > upper.y ){ + //System.err.println( "parallel to y plane and outside"); + return false; + } + } else { + invDir = 1.0/diry; + //System.err.println("invDir = " + invDir); + t1 = (lower.y-start.y)*invDir; + t2 = (upper.y-start.y)*invDir; + + if( t1 > t2) { + tmp = t1; + t1 = t2; + t2 = tmp; + } + //System.err.println("y t1 = " + t1 + " t2 = " + t2); + if( t1 > tnear) tnear = t1; + if( t2 < tfar ) tfar = t2; + + if( (tfar < 0.0) || (tnear > tfar)){ + //System.err.println( "y failed: tnear="+tnear+" tfar="+tfar); + return false; + } + //System.err.println("y tnear = " + tnear + " tfar = " + tfar); + } + + // z + if (dirz == 0.0) { + //System.err.println("dirz == 0.0"); + if( start.z < lower.z || start.z > upper.z ) { + //System.err.println( "parallel to z plane and outside"); + return false; + } + } else { + invDir = 1.0/dirz; + t1 = (lower.z-start.z)*invDir; + t2 = (upper.z-start.z)*invDir; + + if( t1 > t2) { + tmp = t1; + t1 = t2; + t2 = tmp; + } + //System.err.println("z t1 = " + t1 + " t2 = " + t2); + if( t1 > tnear) tnear = t1; + if( t2 < tfar ) tfar = t2; + + if( (tfar < 0.0) || (tnear > tfar)){ + //System.err.println( "z failed: tnear="+tnear+" tfar="+tfar); + return false; + } + //System.err.println("z tnear = " + tnear + " tfar = " + tfar); + } + + if((tnear < 0.0) && (tfar >= 0.0)) { + // origin is inside the BBox. + position.x = start.x + dirx*tfar; + position.y = start.y + diry*tfar; + position.z = start.z + dirz*tfar; + position.w = tfar; + } + else { + if(tnear>dirLen) { + // Segment is behind BBox. + /* + System.err.println("PickSegment : intersected postion : " + position + + " tnear " + tnear + " tfar " + tfar ); + */ + return false; + } + position.x = start.x + dirx*tnear; + position.y = start.y + diry*tnear; + position.z = start.z + dirz*tnear; + + position.w = tnear; + } + + /* + System.err.println("tnear = " + tnear + " tfar = " + tfar + " w " + + position.w); + System.err.println("lower = " + lower); + System.err.println("upper = " + upper + "\n"); + */ + return true; + + } + + /** + * Test for intersection with a ray. + * @param origin the starting point of the ray + * @param direction the direction of the ray + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Point3d origin, Vector3d direction ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + return true; + } + + Point3d p=new Point3d(); + return intersect( origin, direction, p ); + } + + /** + * A protected intersect method that returns the point of intersection. + * Used by Picking methods to sort or return closest picked item. + */ + boolean intersect(Point3d origin, Vector3d direction, Point3d intersect ) { + double theta=0.0; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + intersect.x = origin.x; + intersect.y = origin.y; + intersect.z = origin.z; + return true; + } + + if (direction.x > 0.0 ) + theta = Math.max( theta, (lower.x - origin.x)/direction.x ); + if (direction.x < 0.0 ) + theta = Math.max( theta, (upper.x - origin.x)/direction.x ); + if (direction.y > 0.0 ) + theta = Math.max( theta, (lower.y - origin.y)/direction.y ); + if (direction.y < 0.0 ) + theta = Math.max( theta, (upper.y - origin.y)/direction.y ); + if (direction.z > 0.0 ) + theta = Math.max( theta, (lower.z - origin.z)/direction.z ); + if (direction.z < 0.0 ) + theta = Math.max( theta, (upper.z - origin.z)/direction.z ); + + intersect.x = origin.x + theta*direction.x; + intersect.y = origin.y + theta*direction.y; + intersect.z = origin.z + theta*direction.z; + + if (intersect.x < (lower.x-EPS)) return false; + if (intersect.x > (upper.x+EPS)) return false; + if (intersect.y < (lower.y-EPS)) return false; + if (intersect.y > (upper.y+EPS)) return false; + if (intersect.z < (lower.z-EPS)) return false; + if (intersect.z > (upper.z+EPS)) return false; + + return true; + + } + + /** + * Test for intersection with a point. + * @param point a point defining a position in 3-space + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Point3d point ) { + + if( boundsIsEmpty ) { + return false; + } + if( boundsIsInfinite ) { + return true; + } + + if( point.x <= upper.x && point.x >= lower.x && + point.y <= upper.y && point.y >= lower.y && + point.z <= upper.z && point.z >= lower.z) + return true; + else + return false; + } + /** + * Tests whether the bounding box is empty. A bounding box is + * empty if it is null (either by construction or as the result of + * a null intersection) or if its volume is negative. A bounding box + * with a volume of zero is not empty. + * @return true if the bounding box is empty; otherwise, it returns false + */ + public boolean isEmpty() { + + return boundsIsEmpty; + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occured + */ + boolean intersect(Bounds boundsObject, Point4d position) { + return intersect(boundsObject); + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds boundsObject) { + + if( boundsObject == null ) { + return false; + } + + if( boundsIsEmpty || boundsObject.boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite || boundsObject.boundsIsInfinite ) { + return true; + } + + if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + // both boxes are axis aligned + if( upper.x > box.lower.x && box.upper.x > lower.x && + upper.y > box.lower.y && box.upper.y > lower.y && + upper.z > box.lower.z && box.upper.z > lower.z ) + return true; + else + return false; + } else if( boundsObject.boundId == BOUNDING_SPHERE) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + double rad_sq = sphere.radius*sphere.radius; + double dis = 0.0; + + if( sphere.center.x < lower.x ) + dis = (sphere.center.x-lower.x)*(sphere.center.x-lower.x); + else + if( sphere.center.x > upper.x ) + dis = (sphere.center.x-upper.x)*(sphere.center.x-upper.x); + + if( sphere.center.y < lower.y ) + dis += (sphere.center.y-lower.y)*(sphere.center.y-lower.y); + else + if( sphere.center.y > upper.y ) + dis += (sphere.center.y-upper.y)*(sphere.center.y-upper.y); + + if( sphere.center.z < lower.z ) + dis += (sphere.center.z-lower.z)*(sphere.center.z-lower.z); + else + if( sphere.center.z > upper.z ) + dis += (sphere.center.z-upper.z)*(sphere.center.z-upper.z); + + if( dis <= rad_sq ) + return true; + else + return false; + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + // intersect an axis aligned box with a polytope + return intersect_ptope_abox ( (BoundingPolytope)boundsObject, this ); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox6")); + } + + } + + /** + * Test for intersection with an array of bounds objects. + * @param boundsObjects an array of bounding objects + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds[] boundsObjects) { + + double distsq, radsq; + int i; + + if( boundsObjects == null || boundsObjects.length <= 0 ) { + return false; + } + + if( boundsIsEmpty ) { + return false; + } + + for(i = 0; i < boundsObjects.length; i++){ + if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ; + else if( boundsIsInfinite || boundsObjects[i].boundsIsInfinite ) { + return true; // We're done here. + } + else if( boundsObjects[i].boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObjects[i]; + // both boxes are axis aligned + if( upper.x > box.lower.x && box.upper.x > lower.x && + upper.y > box.lower.y && box.upper.y > lower.y && + upper.z > box.lower.z && box.upper.z > lower.z ) + return true; + } + else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + double rad_sq = sphere.radius*sphere.radius; + double dis = 0.0; + + if( sphere.center.x < lower.x ) + dis = (sphere.center.x-lower.x)*(sphere.center.x-lower.x); + else + if( sphere.center.x > upper.x ) + dis = (sphere.center.x-upper.x)*(sphere.center.x-upper.x); + + if( sphere.center.y < lower.y ) + dis += (sphere.center.y-lower.y)*(sphere.center.y-lower.y); + else + if( sphere.center.y > upper.y ) + dis += (sphere.center.y-upper.y)*(sphere.center.y-upper.y); + + if( sphere.center.z < lower.z ) + dis += (sphere.center.z-lower.z)*(sphere.center.z-lower.z); + else + if( sphere.center.z > upper.z ) + dis += (sphere.center.z-upper.z)*(sphere.center.z-upper.z); + + if( dis <= rad_sq ) + return true; + + } + else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + if( intersect_ptope_abox ( (BoundingPolytope)boundsObjects[i], this )) + return true; + } + else { + // System.err.println("intersect ?? "); + } + } + + return false; + } + + /** + * Test for intersection with another bounding box. + * @param boundsObject another bounding object + * @param newBoundBox the new bounding box which is the intersection of + * the boundsObject and this BoundingBox + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds boundsObject, BoundingBox newBoundBox) { + + if((boundsObject == null) || boundsIsEmpty || boundsObject.boundsIsEmpty ) { + // Negative volume. + newBoundBox.setLower( 1.0d, 1.0d, 1.0d); + newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); + return false; + } + + + if(boundsIsInfinite && (!boundsObject.boundsIsInfinite)) { + newBoundBox.set(boundsObject); + return true; + } + else if((!boundsIsInfinite) && boundsObject.boundsIsInfinite) { + newBoundBox.set(this); + return true; + } + else if(boundsIsInfinite && boundsObject.boundsIsInfinite) { + newBoundBox.set(this); + return true; + } + else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + // both boxes are axis aligned + if( upper.x > box.lower.x && box.upper.x > lower.x && + upper.y > box.lower.y && box.upper.y > lower.y && + upper.z > box.lower.z && box.upper.z > lower.z ){ + + + if(upper.x > box.upper.x) + newBoundBox.upper.x = box.upper.x; + else + newBoundBox.upper.x = upper.x; + + if(upper.y > box.upper.y) + newBoundBox.upper.y = box.upper.y; + else + newBoundBox.upper.y = upper.y; + + if(upper.z > box.upper.z) + newBoundBox.upper.z = box.upper.z; + else + newBoundBox.upper.z = upper.z; + + if(lower.x < box.lower.x) + newBoundBox.lower.x = box.lower.x; + else + newBoundBox.lower.x = lower.x; + + if(lower.y < box.lower.y) + newBoundBox.lower.y = box.lower.y; + else + newBoundBox.lower.y = lower.y; + + if(lower.z < box.lower.z) + newBoundBox.lower.z = box.lower.z; + else + newBoundBox.lower.z = lower.z; + + newBoundBox.updateBoundsStates(); + return true; + } else { + // Negative volume. + newBoundBox.setLower( 1.0d, 1.0d, 1.0d); + newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); + return false; + } + } + else if( boundsObject.boundId == BOUNDING_SPHERE) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + if( this.intersect( sphere) ) { + BoundingBox sbox = new BoundingBox( sphere ); + this.intersect( sbox, newBoundBox ); + return true; + } else { + // Negative volume. + newBoundBox.setLower( 1.0d, 1.0d, 1.0d); + newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); + return false; + } + + // System.err.println("intersect Sphere "); + } + else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + if( this.intersect( polytope)) { + BoundingBox pbox = new BoundingBox( polytope); // convert polytope to box + this.intersect( pbox, newBoundBox ); + return true; + } else { + // Negative volume. + newBoundBox.setLower( 1.0d, 1.0d, 1.0d); + newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); + return false; + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox7")); + } + } + + /** + * Test for intersection with an array of bounds objects. + * @param boundsObjects an array of bounds objects + * @param newBoundBox the new bounding box which is the intersection of + * the boundsObject and this BoundingBox + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds[] boundsObjects, BoundingBox newBoundBox) { + + if( boundsObjects == null || boundsObjects.length <= 0 || boundsIsEmpty ) { + // Negative volume. + newBoundBox.setLower( 1.0d, 1.0d, 1.0d); + newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); + return false; + } + + int i=0; + // find first non null bounds object + while( boundsObjects[i] == null && i < boundsObjects.length) { + i++; + } + + if( i >= boundsObjects.length ) { // all bounds objects were empty + // Negative volume. + newBoundBox.setLower( 1.0d, 1.0d, 1.0d); + newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); + return false; + } + + + boolean status = false; + BoundingBox tbox = new BoundingBox(); + + for(;i box.lower.x && box.upper.x > lower.x && + upper.y > box.lower.y && box.upper.y > lower.y && + upper.z > box.lower.z && box.upper.z > lower.z ){ + + if(upper.x > box.upper.x) + newBoundBox.upper.x = box.upper.x; + else + newBoundBox.upper.x = upper.x; + + if(upper.y > box.upper.y) + newBoundBox.upper.y = box.upper.y; + else + newBoundBox.upper.y = upper.y; + + if(upper.z > box.upper.z) + newBoundBox.upper.z = box.upper.z; + else + newBoundBox.upper.z = upper.z; + + if(lower.x < box.lower.x) + newBoundBox.lower.x = box.lower.x; + else + newBoundBox.lower.x = lower.x; + + if(lower.y < box.lower.y) + newBoundBox.lower.y = box.lower.y; + else + newBoundBox.lower.y = lower.y; + + if(lower.z < box.lower.z) + newBoundBox.lower.z = box.lower.z; + else + newBoundBox.lower.z = lower.z; + status = true; + newBoundBox.updateBoundsStates(); + } + } + else if( boundsObjects[i].boundId == BOUNDING_SPHERE) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + if( this.intersect(sphere)) { + BoundingBox sbox = new BoundingBox( sphere ); // convert sphere to box + this.intersect(sbox,tbox); // insersect two boxes + if( status ) { + newBoundBox.combine( tbox ); + } else { + newBoundBox.set( tbox ); + status = true; + } + } + + } + else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + if( this.intersect( polytope)) { + BoundingBox pbox = new BoundingBox( polytope ); // convert polytope to box + this.intersect(pbox,tbox); // insersect two boxes + if ( status ) { + newBoundBox.combine( tbox ); + } else { + newBoundBox.set( tbox ); + status = true; + } + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox6")); + } + + if(newBoundBox.boundsIsInfinite) + break; // We're done. + } + if( status == false ) { + // Negative volume. + newBoundBox.setLower( 1.0d, 1.0d, 1.0d); + newBoundBox.setUpper(-1.0d, -1.0d, -1.0d); + } + return status; + } + + + /** + * Finds closest bounding object that intersects this bounding box. + * @param boundsObjects an array of bounds objects + * @return closest bounding object + */ + public Bounds closestIntersection( Bounds[] boundsObjects) { + + if( boundsObjects == null || boundsObjects.length <= 0 ) { + return null; + } + + if( boundsIsEmpty ) { + return null; + } + + getCenter(); + + double dis,far_dis,pdist,x,y,z,rad_sq; + double cenX = 0.0, cenY = 0.0, cenZ = 0.0; + boolean contains = false; + boolean inside; + boolean intersect = false; + double smallest_distance = Double.MAX_VALUE; + int i,j,index=0; + + for(i = 0; i < boundsObjects.length; i++){ + if( boundsObjects[i] == null ) ; + + else if( this.intersect( boundsObjects[i])) { + intersect = true; + if( boundsObjects[i].boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObjects[i]; + cenX = (box.upper.x+box.lower.x)/2.0; + cenY = (box.upper.y+box.lower.y)/2.0; + cenZ = (box.upper.z+box.lower.z)/2.0; + dis = Math.sqrt( (centroid.x-cenX)*(centroid.x-cenX) + + (centroid.y-cenY)*(centroid.y-cenY) + + (centroid.z-cenZ)*(centroid.z-cenZ) ); + inside = false; + + if( lower.x <= box.lower.x && + lower.y <= box.lower.y && + lower.z <= box.lower.z && + upper.x >= box.upper.x && + upper.y >= box.upper.y && + upper.z >= box.upper.z ) { // box is contained + inside = true; + } + if( inside ) { + if( !contains ){ // initialize smallest_distance for the first containment + index = i; + smallest_distance = dis; + contains = true; + } else{ + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if (!contains) { + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + + } + else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + dis = Math.sqrt( (centroid.x-sphere.center.x)* + (centroid.x-sphere.center.x) + + (centroid.y-sphere.center.y)* + (centroid.y-sphere.center.y) + + (centroid.z-sphere.center.z)* + (centroid.z-sphere.center.z) ); + + inside = false; + + // sphere sphere.center is inside box + if(sphere.center.x <= upper.x && sphere.center.x >= lower.x && + sphere.center.y <= upper.y && sphere.center.y >= lower.y && + sphere.center.z <= upper.z && sphere.center.z >= lower.z ) { + // check if sphere intersects any side + if (sphere.center.x - lower.x >= sphere.radius && + upper.x - sphere.center.x >= sphere.radius && + sphere.center.y - lower.y >= sphere.radius && + upper.y - sphere.center.y >= sphere.radius && + sphere.center.z - lower.z >= sphere.radius && + upper.z - sphere.center.z >= sphere.radius ) { + // contains the sphere + inside = true; + } + } + if (inside ) { + // initialize smallest_distance for the first containment + if( !contains ){ + index = i; + smallest_distance = dis; + contains = true; + } else{ + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if (!contains) { + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } + else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = + (BoundingPolytope)boundsObjects[i]; + dis = Math.sqrt( (centroid.x-polytope.centroid.x)* + (centroid.x-polytope.centroid.x) + + (centroid.y-polytope.centroid.y)* + (centroid.y-polytope.centroid.y) + + (centroid.z-polytope.centroid.z)* + (centroid.z-polytope.centroid.z) ); + inside = true; + for(j=0;j upper.x || + polytope.verts[j].y > upper.y || + polytope.verts[j].z > upper.z ) { // box contains polytope + inside = false; + + } + + } + if( inside ) { + if( !contains ){ // initialize smallest_distance for the first containment + index = i; + smallest_distance = dis; + contains = true; + } else{ + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if (!contains) { + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingBox9")); + } + } + } + + if ( intersect ) + return boundsObjects[index]; + else + return null; + } + + /** + * Tests for intersection of box and frustum. + * @param frustum + * @return true if they intersect + */ + boolean intersect(CachedFrustum frustum ) { + + if (boundsIsEmpty) + return false; + + if(boundsIsInfinite) + return true; + + // System.err.println("intersect frustum with box="+this.toString()); + // System.err.println("frustum "+frustum.toString()); + // check if box and bounding box of frustum intersect + if ((upper.x < frustum.lower.x) || + (lower.x > frustum.upper.x) || + (upper.y < frustum.lower.y) || + (lower.y > frustum.upper.y) || + (upper.z < frustum.lower.z) || + (lower.z > frustum.upper.z) ) { + + // System.err.println("*** box and bounding box of frustum do not intersect"); + return false; + } + + // check if all box points out any frustum plane + int i = 5; + while (i>=0){ + Vector4d vc = frustum.clipPlanes[i--]; + if ((( upper.x*vc.x + upper.y*vc.y + + upper.z*vc.z + vc.w ) < 0.0 ) && + (( upper.x*vc.x + lower.y*vc.y + + upper.z*vc.z + vc.w ) < 0.0 ) && + (( upper.x*vc.x + lower.y*vc.y + + lower.z*vc.z + vc.w ) < 0.0 ) && + (( upper.x*vc.x + upper.y*vc.y + + lower.z*vc.z + vc.w ) < 0.0 ) && + (( lower.x*vc.x + upper.y*vc.y + + upper.z*vc.z + vc.w ) < 0.0 ) && + (( lower.x*vc.x + lower.y*vc.y + + upper.z*vc.z + vc.w ) < 0.0 ) && + (( lower.x*vc.x + lower.y*vc.y + + lower.z*vc.z + vc.w ) < 0.0 ) && + (( lower.x*vc.x + upper.y*vc.y + + lower.z*vc.z + vc.w ) < 0.0 )) { + // all corners outside this frustum plane + // System.err.println("*** all corners outside this frustum plane"); + return false; + } + } + + return true; + } + + /** + * Returns a string representation of this class. + */ + public String toString() { + return new String( "Bounding box: Lower="+lower.x+" "+ + lower.y+" "+lower.z+" Upper="+upper.x+" "+ + upper.y+" "+upper.z ); + } + + private void updateBoundsStates() { + if((lower.x == Double.NEGATIVE_INFINITY) && + (lower.y == Double.NEGATIVE_INFINITY) && + (lower.z == Double.NEGATIVE_INFINITY) && + (upper.x == Double.POSITIVE_INFINITY) && + (upper.y == Double.POSITIVE_INFINITY) && + (upper.z == Double.POSITIVE_INFINITY)) { + boundsIsEmpty = false; + boundsIsInfinite = true; + return; + } + + if (checkBoundsIsNaN()) { + boundsIsEmpty = true; + boundsIsInfinite = false; + return; + } + else { + boundsIsInfinite = false; + if( lower.x > upper.x || + lower.y > upper.y || + lower.z > upper.z ) { + boundsIsEmpty = true; + } else { + boundsIsEmpty = false; + } + } + } + + // For a infinite bounds. What is the centroid ? + Point3d getCenter() { + if(centroid == null) { + centroid = new Point3d(); + } + + centroid.x = (upper.x+lower.x)*0.5; + centroid.y = (upper.y+lower.y)*0.5; + centroid.z = (upper.z+lower.z)*0.5; + + return centroid; + } + + void translate(BoundingBox bbox, Vector3d value) { + if (bbox == null || bbox.boundsIsEmpty) { + // Negative volume. + setLower( 1.0d, 1.0d, 1.0d); + setUpper(-1.0d, -1.0d, -1.0d); + return; + } + if(bbox.boundsIsInfinite) { + this.set(bbox); + return; + } + + lower.x = bbox.lower.x + value.x; + lower.y = bbox.lower.y + value.y; + lower.z = bbox.lower.z + value.z; + upper.x = bbox.upper.x + value.x; + upper.y = bbox.upper.y + value.y; + upper.z = bbox.upper.z + value.z; + } + + + /** + * if the passed the "region" is same type as this object + * then do a copy, otherwise clone the Bounds and + * return + */ + Bounds copy(Bounds r) { + if (r != null && this.boundId == r.boundId) { + BoundingBox region = (BoundingBox) r; + region.lower.x = lower.x; + region.lower.y = lower.y; + region.lower.z = lower.z; + region.upper.x = upper.x; + region.upper.y = upper.y; + region.upper.z = upper.z; + region.boundsIsEmpty = boundsIsEmpty; + region.boundsIsInfinite = boundsIsInfinite; + return region; + } + else { + return (Bounds) this.clone(); + } + } + + // Check is any of the bounds is a NaN, if yes, then + // set it an empty bounds + boolean checkBoundsIsNaN() { + if (Double.isNaN(lower.x+lower.y+lower.z+upper.x+upper.y+upper.z)) { + return true; + } + + return false; + } + + int getPickType() { + return PickShape.PICKBOUNDINGBOX; + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/BoundingLeaf.java b/j3d-core/src/classes/share/javax/media/j3d/BoundingLeaf.java new file mode 100644 index 0000000..6437fdf --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BoundingLeaf.java @@ -0,0 +1,189 @@ +/* + * $RCSfile: BoundingLeaf.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The BoundingLeaf node defines a bounding region object that can be + * referenced by other nodes to define a region of influence + * (Fog and Light nodes), an application region (Background, Clip, + * and Soundscape nodes), or a scheduling region (Sound and + * Behavior nodes). The bounding region is defined in the local + * coordinate system of the BoundingLeaf node. A reference to a + * BoundingLeaf node can be used in place + * of a locally defined bounds object for any of the aforementioned regions. + *

+ * This allows an application to specify a bounding region in one coordinate system + * (the local coordinate system of the BoundingLeaf node) other than the local + * coordinate system of the node that references the bounds. For an example of how + * this might be used, consider a closed room with a number of track lights. Each + * light can move independent of the other lights and, as such, needs its own local + * coordinate system. However, the bounding volume is used by all the lights in the + * boundary of the room, which doesn't move when the lights move. In this example, + * the BoundingLeaf node allows the bounding region to be defined in the local + * coordinate system of the room, rather than in the local coordinate system of a + * particular light. All lights can then share this single bounding volume. + */ +public class BoundingLeaf extends Leaf { + /** + * Specifies that this BoundingLeaf node allows read access to its + * bounding region object. + */ + public static final int + ALLOW_REGION_READ = CapabilityBits.BOUNDING_LEAF_ALLOW_REGION_READ; + + /** + * Specifies that this BoundingLeaf node allows write access to its + * bounding region object. + */ + public static final int + ALLOW_REGION_WRITE = CapabilityBits.BOUNDING_LEAF_ALLOW_REGION_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_REGION_READ + }; + + /** + * Constructs a BoundingLeaf node with a null (empty) bounding region. + */ + public BoundingLeaf() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((BoundingLeafRetained)this.retained).createBoundingLeaf(); + } + + /** + * Constructs a BoundingLeaf node with the specified bounding region. + * @param region the bounding region of this leaf node + */ + public BoundingLeaf(Bounds region) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((BoundingLeafRetained)this.retained).createBoundingLeaf(); + ((BoundingLeafRetained)this.retained).initRegion(region); + } + + /** + * Sets this BoundingLeaf node's bounding region. + * @param region the bounding region of this leaf node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setRegion(Bounds region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_REGION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("BoundingLeaf0")); + + if (isLive()) + ((BoundingLeafRetained)this.retained).setRegion(region); + else + ((BoundingLeafRetained)this.retained).initRegion(region); + } + + /** + * Retrieves this BoundingLeaf's bounding region. + * @return the bounding region of this leaf node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getRegion() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_REGION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("BoundingLeaf1")); + + return ((BoundingLeafRetained)this.retained).getRegion(); + } + + /** + * Creates the BoundingLeafRetained object that this + * BoundingLeaf object will point to. + */ + void createRetained() { + this.retained = new BoundingLeafRetained(); + this.retained.setSource(this); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + BoundingLeaf bl = new BoundingLeaf(); + bl.duplicateNode(this, forceDuplicate); + return bl; + } + + + + /** + * Copies all BoundingLeaf information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + ((BoundingLeafRetained) retained).initRegion( + ((BoundingLeafRetained) originalNode.retained).getRegion()); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BoundingLeafRetained.java b/j3d-core/src/classes/share/javax/media/j3d/BoundingLeafRetained.java new file mode 100644 index 0000000..5a4e588 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BoundingLeafRetained.java @@ -0,0 +1,288 @@ +/* + * $RCSfile: BoundingLeafRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; + +/** + * The BoundingLeaf node defines a bounding region object that can be + * referenced by other nodes to define a region of influence, an + * application region, or a scheduling region. + */ +class BoundingLeafRetained extends LeafRetained { + // Statics used when something in the boundingleaf changes + static final int REGION_CHANGED = 0x0001; + static final Integer REGION_CHANGED_MESSAGE = new Integer(REGION_CHANGED); + + // The bounding region object defined by this node + Bounds region = null; + + + // For the mirror object, this region is the transformed region + // (the region of the original bounding leaf object transformed + // by the cache transform) + Bounds transformedRegion = null; + + BoundingLeafRetained mirrorBoundingLeaf; + + // A list of Objects that refer, directly or indirectly, to this + // bounding leaf object + ArrayList users = new ArrayList(); + + // Target threads to be notified when light changes + int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_RENDER; + + + // Target threads for tranform change + int transformTargetThreads = + J3dThread.UPDATE_RENDERING_ENVIRONMENT | J3dThread.UPDATE_GEOMETRY; + + BoundingLeafRetained() { + this.nodeType = NodeRetained.BOUNDINGLEAF; + } + + void createBoundingLeaf() { + this.nodeType = NodeRetained.BOUNDINGLEAF; + mirrorBoundingLeaf = new BoundingLeafRetained(); + } + + /** + * Initialize the bounding region + */ + void initRegion(Bounds region) { + if (region != null) { + this.region = (Bounds) region.clone(); + } + else { + this.region = null; + } + if (staticTransform != null) { + this.region.transform(staticTransform.transform); + } + } + + /** + * Set the bounding region + */ + void setRegion(Bounds region) { + initRegion(region); + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = mirrorBoundingLeaf.targetThreads; + createMessage.type = J3dMessage.BOUNDINGLEAF_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= REGION_CHANGED_MESSAGE; + if (region != null) { + createMessage.args[2] = (Bounds)(region.clone()); + } else { + createMessage.args[2] = null; + } + createMessage.args[3] = mirrorBoundingLeaf.users.toArray(); + VirtualUniverse.mc.processMessage(createMessage); + } + + + /** + * Get the bounding region + */ + Bounds getRegion() { + Bounds b = null; + if (this.region != null) { + b = (Bounds) this.region.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + } + return b; + } + + + void setLive(SetLiveState s) { + super.doSetLive(s); + + if (inBackgroundGroup) { + throw new + IllegalSceneGraphException(J3dI18N.getString("BoundingLeafRetained0")); + } + + if (inSharedGroup) { + throw new + IllegalSharingException(J3dI18N.getString("BoundingLeafRetained1")); + } + + + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(mirrorBoundingLeaf, + Targets.BLN_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + mirrorBoundingLeaf.localToVworld = new Transform3D[1][]; + mirrorBoundingLeaf.localToVworldIndex = new int[1][]; + mirrorBoundingLeaf.localToVworld[0] = this.localToVworld[0]; + mirrorBoundingLeaf.localToVworldIndex[0] = this.localToVworldIndex[0]; + mirrorBoundingLeaf.parent = parent; + if (region != null) { + mirrorBoundingLeaf.region = (Bounds)region.clone(); + mirrorBoundingLeaf.transformedRegion = (Bounds)region.clone(); + mirrorBoundingLeaf.transformedRegion.transform( + mirrorBoundingLeaf.getCurrentLocalToVworld()); + } else { + mirrorBoundingLeaf.region = null; + mirrorBoundingLeaf.transformedRegion = null; + } + // process switch leaf + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(mirrorBoundingLeaf, + Targets.BLN_TARGETS); + } + mirrorBoundingLeaf.switchState = (SwitchState)s.switchStates.get(0); + super.markAsLive(); + } + + + /** Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateImmediateMirrorObject(Object[] objs) { + + int component = ((Integer)objs[1]).intValue(); + Bounds b = ((Bounds)objs[2]); + Transform3D t; + + if ((component & REGION_CHANGED) != 0) { + mirrorBoundingLeaf.region = b; + if (b != null) { + mirrorBoundingLeaf.transformedRegion = (Bounds)b.clone(); + t = mirrorBoundingLeaf.getCurrentLocalToVworld(); + mirrorBoundingLeaf.transformedRegion.transform(b, t); + } + else { + mirrorBoundingLeaf.transformedRegion = null; + } + + } + } + + /** + * Add a user to the list of users. + * There is no if (node.source.isLive()) check since + * mirror objects are the users of the mirror bounding leaf + * and they do not have a source. + */ + synchronized void addUser(LeafRetained node) { + users.add(node); + if (node.nodeType == NodeRetained.BACKGROUND || + node.nodeType == NodeRetained.CLIP || + node.nodeType == NodeRetained.ALTERNATEAPPEARANCE || + node instanceof FogRetained || + node instanceof LightRetained) { + transformTargetThreads |= J3dThread.UPDATE_RENDER; + } + else if (node instanceof BehaviorRetained) { + transformTargetThreads |= J3dThread.UPDATE_BEHAVIOR; + targetThreads |= J3dThread.UPDATE_BEHAVIOR; + } + else if (node instanceof SoundRetained || + node.nodeType == NodeRetained.SOUNDSCAPE) { + transformTargetThreads |= J3dThread.UPDATE_SOUND; + } + + } + + /** + * Remove user from the list of users. + * There is no if (node.source.isLive()) check since + * mirror objects are the users of the mirror bounding leaf + * and they do not have a source. + */ + synchronized void removeUser(LeafRetained u) { + int i; + users.remove(users.indexOf(u)); + // For now reconstruct the transform target threads from scratch + transformTargetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_RENDER; + + for (i =0; i < users.size(); i++) { + LeafRetained node = (LeafRetained)users.get(i); + if (node.nodeType == NodeRetained.BACKGROUND || + node.nodeType == NodeRetained.CLIP || + node.nodeType == NodeRetained.ALTERNATEAPPEARANCE || + node instanceof FogRetained || + node instanceof LightRetained) { + transformTargetThreads |= J3dThread.UPDATE_RENDER; + } + else if (node.nodeType == NodeRetained.BEHAVIOR) { + transformTargetThreads |= J3dThread.UPDATE_BEHAVIOR; + targetThreads |= J3dThread.UPDATE_BEHAVIOR; + } + else if (node instanceof SoundRetained || + node.nodeType == NodeRetained.SOUNDSCAPE) { + transformTargetThreads |= J3dThread.UPDATE_SOUND; + } + } + } + + + // This function is called on the mirror bounding leaf + void updateImmediateTransformChange() { + Transform3D t; + t = getCurrentLocalToVworld(); + if (region != null) { + transformedRegion.transform(region, t); + } + } + + void clearLive(SetLiveState s) { + super.clearLive(); + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(mirrorBoundingLeaf, + Targets.BLN_TARGETS); + } + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(mirrorBoundingLeaf, + Targets.BLN_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + region.transform(xform.transform); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BoundingPolytope.java b/j3d-core/src/classes/share/javax/media/j3d/BoundingPolytope.java new file mode 100644 index 0000000..b1618c3 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BoundingPolytope.java @@ -0,0 +1,1759 @@ +/* + * $RCSfile: BoundingPolytope.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; +import com.sun.j3d.internal.HashCodeUtil; + +/** + * A BoundingPolytope defines a polyhedral bounding region using the + * intersection of four or more half spaces. The region defined by a + * BoundingPolytope is always convex and must be closed. + *

+ * Each plane in the BoundingPolytope specifies a half-space defined + * by the equation: + *

    + * Ax + By + Cz + D <= 0 + *
+ * where A, B, C, D are the parameters that specify the plane. The + * parameters are passed in the x, y, z, and w fields, respectively, + * of a Vector4d object. The intersection of the set of half-spaces + * corresponding to the planes in this BoundingPolytope defines the + * bounding region. + */ + +public class BoundingPolytope extends Bounds { + + /** + * An array of bounding planes. + */ + Vector4d[] planes; + double[] mag; // magnitude of plane vector + double[] pDotN; // point on plane dotted with normal + Point3d[] verts; // vertices of polytope + int nVerts; // number of verts in polytope + Point3d centroid = new Point3d(); // centroid of polytope + + Point3d boxVerts[]; + boolean allocBoxVerts = false; + + /** + * Constructs a BoundingPolytope using the specified planes. + * @param planes a set of planes defining the polytope. + * @exception IllegalArgumentException if the length of the + * specified array of planes is less than 4. + */ + public BoundingPolytope(Vector4d[] planes) { + if (planes.length < 4) { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope11")); + } + + boundId = BOUNDING_POLYTOPE; + int i; + double invMag; + this.planes = new Vector4d[planes.length]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + for(i=0;i + * planes[0] : x <= 1 (1,0,0,-1)
+ * planes[1] : -x <= 1 (-1,0,0,-1)
+ * planes[2] : y <= 1 (0,1,0,-1)
+ * planes[3] : -y <= 1 (0,-1,0,-1)
+ * planes[4] : z <= 1 (0,0,1,-1)
+ * planes[5] : -z <= 1 (0,0,-1,-1)
+ * + */ + public BoundingPolytope() { + boundId = BOUNDING_POLYTOPE; + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -1.0 ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, -1.0 ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -1.0 ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, -1.0 ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -1.0 ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, -1.0 ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + + computeAllVerts(); // XXXX: lazy evaluate + } + + + /** + * Constructs a BoundingPolytope from the specified bounds object. + * The new polytope will circumscribe the region specified by the + * input bounds. + * @param boundsObject the bounds object from which this polytope + * is constructed. + */ + public BoundingPolytope(Bounds boundsObject ) { + int i; + + boundId = BOUNDING_POLYTOPE; + + if( boundsObject == null ) { + boundsIsEmpty = true; + boundsIsInfinite = false; + initEmptyPolytope(); + computeAllVerts(); // XXXX: lazy evaluate + return; + } + + boundsIsEmpty = boundsObject.boundsIsEmpty; + boundsIsInfinite = boundsObject.boundsIsInfinite; + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -(sphere.center.x+sphere.radius) ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, sphere.center.x-sphere.radius ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -(sphere.center.y+sphere.radius) ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, sphere.center.y-sphere.radius ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -(sphere.center.z+sphere.radius) ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, sphere.center.z-sphere.radius ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + computeAllVerts(); // XXXX: lazy evaluate + + } else if( boundsObject.boundId == BOUNDING_BOX ){ + BoundingBox box = (BoundingBox)boundsObject; + planes = new Vector4d[6]; + pDotN = new double[planes.length]; + mag = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -box.upper.x ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, box.lower.x ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -box.upper.y ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, box.lower.y ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -box.upper.z ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, box.lower.z ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + computeAllVerts(); // XXXX: lazy evaluate + + } else if( boundsObject.boundId == BOUNDING_POLYTOPE ) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + planes = new Vector4d[polytope.planes.length]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + nVerts = polytope.nVerts; + verts = new Point3d[nVerts]; + for(i=0;i= boundsObjects.length ) { // all bounds objects were empty + boundsIsEmpty = true; + boundsIsInfinite = false; + initEmptyPolytope(); + computeAllVerts(); // XXXX: lazy evaluate + return; + } + + boundsIsEmpty = boundsObjects[i].boundsIsEmpty; + boundsIsInfinite = boundsObjects[i].boundsIsInfinite; + + if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -(sphere.center.x+sphere.radius) ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, sphere.center.x-sphere.radius ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -(sphere.center.y+sphere.radius) ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, sphere.center.y-sphere.radius ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -(sphere.center.z+sphere.radius) ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, sphere.center.z-sphere.radius ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + + computeAllVerts(); // XXXX: lazy evaluate + } else if( boundsObjects[i].boundId == BOUNDING_BOX ){ + BoundingBox box = (BoundingBox)boundsObjects[i]; + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -box.upper.x ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, box.lower.x ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -box.upper.y ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, box.lower.y ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -box.upper.z ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, box.lower.z ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + + computeAllVerts(); // XXXX: lazy evaluate + } else if( boundsObjects[i].boundId == BOUNDING_POLYTOPE ) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + planes = new Vector4d[polytope.planes.length]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + nVerts = polytope.nVerts; + verts = new Point3d[nVerts]; + for(i=0;i 0.0) planes[i].w = -newD; + if( (newD = ux + ly + uz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = ux + ly + lz ) + planes[i].w > 0.0) planes[i].w = -newD; + + if( (newD = lx + uy + uz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = lx + uy + lz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = lx + ly + uz ) + planes[i].w > 0.0) planes[i].w = -newD; + if( (newD = lx + ly + lz ) + planes[i].w > 0.0) planes[i].w = -newD; + } + + boundsIsEmpty = boundsObject.boundsIsEmpty; + boundsIsInfinite = boundsObject.boundsIsInfinite; + computeAllVerts(); // XXXX: lazy evaluate + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + if( planes.length != polytope.planes.length) { + planes = new Vector4d[polytope.planes.length]; + for(k=0;kbounds object is + * equal to this BoundingPolytope object. They are equal if the + * specified bounds object is an instance of + * BoundingPolytope and all of the data + * members of bounds are equal to the corresponding + * data members in this BoundingPolytope. + * @param bounds the object with which the comparison is made. + * @return true if this BoundingPolytope is equal to bounds; + * otherwise false + * + * @since Java 3D 1.2 + */ + public boolean equals(Object bounds) { + try { + BoundingPolytope polytope = (BoundingPolytope)bounds; + if (planes.length != polytope.planes.length) + return false; + for (int i = 0; i < planes.length; i++) + if (!planes[i].equals(polytope.planes[i])) + return false; + + return true; + } + catch (NullPointerException e) { + return false; + } + catch (ClassCastException e) { + return false; + } + } + + + /** + * Returns a hash code value for this BoundingPolytope object + * based on the data values in this object. Two different + * BoundingPolytope objects with identical data values (i.e., + * BoundingPolytope.equals returns true) will return the same hash + * code value. Two BoundingPolytope objects with different data + * members may return the same hash code value, although this is + * not likely. + * @return a hash code value for this BoundingPolytope object. + * + * @since Java 3D 1.2 + */ + public int hashCode() { + long bits = 1L; + + for (int i = 0; i < planes.length; i++) { + bits = 31L * bits + HashCodeUtil.doubleToLongBits(planes[i].x); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(planes[i].y); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(planes[i].z); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(planes[i].w); + } + + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Combines this bounding polytope with a bounding object so that the + * resulting bounding polytope encloses the original bounding polytope and the + * given bounds object. + * @param boundsObject another bounds object + */ + public void combine(Bounds boundsObject) { + BoundingSphere sphere; + + if((boundsObject == null) || (boundsObject.boundsIsEmpty) + || (boundsIsInfinite)) + return; + + + if((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) { + this.set(boundsObject); + return; + } + + boundsIsEmpty = boundsObject.boundsIsEmpty; + boundsIsInfinite = boundsObject.boundsIsInfinite; + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObject; + int i; + double dis; + for(i = 0; i < planes.length; i++){ + dis = sphere.radius+ sphere.center.x*planes[i].x + + sphere.center.y*planes[i].y + sphere.center.z * + planes[i].z + planes[i].w; + if( dis > 0.0 ) { + planes[i].w += -dis; + } + } + } else if( boundsObject instanceof BoundingBox){ + BoundingBox b = (BoundingBox)boundsObject; + if( !allocBoxVerts){ + boxVerts = new Point3d[8]; + for(int j=0;j<8;j++)boxVerts[j] = new Point3d(); + allocBoxVerts = true; + } + boxVerts[0].set(b.lower.x, b.lower.y, b.lower.z ); + boxVerts[1].set(b.lower.x, b.upper.y, b.lower.z ); + boxVerts[2].set(b.upper.x, b.lower.y, b.lower.z ); + boxVerts[3].set(b.upper.x, b.upper.y, b.lower.z ); + boxVerts[4].set(b.lower.x, b.lower.y, b.upper.z ); + boxVerts[5].set(b.lower.x, b.upper.y, b.upper.z ); + boxVerts[6].set(b.upper.x, b.lower.y, b.upper.z ); + boxVerts[7].set(b.upper.x, b.upper.y, b.upper.z ); + this.combine(boxVerts); + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + this.combine(polytope.verts); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope3")); + } + + computeAllVerts(); + } + + /** + * Combines this bounding polytope with an array of bounding objects so that the + * resulting bounding polytope encloses the original bounding polytope and the + * given array of bounds object. + * @param boundsObjects an array of bounds objects + */ + public void combine(Bounds[] boundsObjects) { + int i=0; + double dis; + + if( (boundsObjects == null) || (boundsObjects.length <= 0) + || (boundsIsInfinite)) + return; + + // find first non empty bounds object + while( (i= boundsObjects.length) + return; // no non empty bounds so do not modify current bounds + + if(boundsIsEmpty) + this.set(boundsObjects[i++]); + + if(boundsIsInfinite) + return; + + for(;i 0.0 ) { + planes[j].w += -dis; + } + } + } else if( boundsObjects[i].boundId == BOUNDING_BOX){ + BoundingBox b = (BoundingBox)boundsObjects[i]; + if( !allocBoxVerts){ + boxVerts = new Point3d[8]; + for(int j=0;j<8;j++)boxVerts[j] = new Point3d(); + allocBoxVerts = true; + } + boxVerts[0].set(b.lower.x, b.lower.y, b.lower.z ); + boxVerts[1].set(b.lower.x, b.upper.y, b.lower.z ); + boxVerts[2].set(b.upper.x, b.lower.y, b.lower.z ); + boxVerts[3].set(b.upper.x, b.upper.y, b.lower.z ); + boxVerts[4].set(b.lower.x, b.lower.y, b.upper.z ); + boxVerts[5].set(b.lower.x, b.upper.y, b.upper.z ); + boxVerts[6].set(b.upper.x, b.lower.y, b.upper.z ); + boxVerts[7].set(b.upper.x, b.upper.y, b.upper.z ); + this.combine(boxVerts); + + } else if(boundsObjects[i] instanceof BoundingPolytope) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + this.combine(polytope.verts); + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope4")); + } + + computeAllVerts(); + } + } + + /** + * Combines this bounding polytope with a point. + * @param point a 3d point in space + */ + public void combine(Point3d point) { + int i; + double dis; + + if(boundsIsInfinite) { + return; + } + + if( boundsIsEmpty ){ + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + nVerts = 1; + verts = new Point3d[nVerts]; + verts[0] = new Point3d( point.x, point.y, point.z); + + for(i=0;i 0.0 ) { + planes[i].w += -dis; + } + } + computeAllVerts(); + } + } + + /** + * Combines this bounding polytope with an array of points. + * @param points an array of 3d points in space + */ + public void combine(Point3d[] points) { + int i,j; + double dis; + + if( boundsIsInfinite) { + return; + } + + if( boundsIsEmpty ){ + planes = new Vector4d[6]; + mag = new double[planes.length]; + pDotN = new double[planes.length]; + nVerts = points.length; + verts = new Point3d[nVerts]; + verts[0] = new Point3d( points[0].x, points[0].y, points[0].z); + + for(i=0;i 0.0 ) { + planes[i].w += -dis; + } + } + } + + computeAllVerts(); + } + + /** + * Modifies the bounding polytope so that it bounds the volume + * generated by transforming the given bounding object. + * @param boundsObject the bounding object to be transformed + * @param matrix a transformation matrix + */ + public void transform( Bounds boundsObject, Transform3D matrix) { + + if( boundsObject == null || boundsObject.boundsIsEmpty) { + boundsIsEmpty = true; + boundsIsInfinite = false; + computeAllVerts(); + return; + } + + if(boundsObject.boundsIsInfinite) { + this.set(boundsObject); + return; + } + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = new BoundingSphere((BoundingSphere)boundsObject); + sphere.transform(matrix); + this.set(sphere); + } else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = new BoundingBox( (BoundingBox)boundsObject); + box.transform(matrix); + this.set(box); + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = new BoundingPolytope( (BoundingPolytope)boundsObject); + polytope.transform(matrix); + this.set(polytope); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope5")); + } + } + + /** + * Transforms this bounding polytope by the given transformation matrix. + * @param matrix a transformation matrix + */ + public void transform( Transform3D matrix) { + + if(boundsIsInfinite) + return; + + int i; + double invMag; + Transform3D invTrans = new Transform3D(matrix); + + invTrans.invert(); + invTrans.transpose(); + + for(i = 0; i < planes.length; i++){ + planes[i].x = planes[i].x * mag[i]; + planes[i].y = planes[i].y * mag[i]; + planes[i].z = planes[i].z * mag[i]; + planes[i].w = planes[i].w * mag[i]; + invTrans.transform( planes[i] ); + } + + for(i=0;i= 0.0) { // plane is behind origin + + x = origin.x + dx*t; // compute intersection point + y = origin.y + dy*t; + z = origin.z + dz*t; + + if( pointInPolytope(x,y,z) ) { + intersectPoint.x = x; + intersectPoint.y = y; + intersectPoint.z = z; + return true; // ray intersects a face of polytope + } + } + } + } + + return false; + } + + /** + * Test for intersection with a ray + * @param origin is a the starting point of the ray + * @param direction is the direction of the ray + * @param position is a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + boolean intersect(Point3d origin, Vector3d direction, Point4d position ) { + double t,v0,vd,x,y,z,invMag; + double dx, dy, dz; + int i,j; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = origin.x; + position.y = origin.y; + position.z = origin.z; + position.w = 0.0; + return true; + } + + invMag = 1.0/Math.sqrt(direction.x*direction.x + direction.y* + direction.y + direction.z*direction.z); + dx = direction.x*invMag; + dy = direction.y*invMag; + dz = direction.z*invMag; + + for(i=0;i 0.0 ) + return false; + + } + return true; + + } + + /** + * Test for intersection with a segment + * @param start is a point defining the start of the line segment + * @param end is a point defining the end of the line segment + * @param position is a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + boolean intersect( Point3d start, Point3d end, Point4d position ) { + double t,v0,vd,x,y,z; + int i,j; + + //System.err.println("line segment intersect : planes.length " + planes.length); + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = start.x; + position.y = start.y; + position.z = start.z; + position.w = 0.0; + return true; + } + + Point3d direction = new Point3d(); + + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + for(i=0;i= 0.0) { // plane is behind start + + x = start.x + direction.x*t; // compute intersection point + y = start.y + direction.y*t; + z = start.z + direction.z*t; + // System.err.println("t="+t+" point="+x+" "+y+" "+z); + + if( pointInPolytope(x,y,z) ) { + // if((t*t) > (end.x-start.x)*(end.x-start.x) + + // (end.y-start.y)*(end.y-start.y) + + // (end.z-start.z)*(end.z-start.z)) { + if(t <= 1.0) { + position.x = x; + position.y = y; + position.z = z; + position.w = t; + return true; // ray intersects a face of polytope + } + } + } + } + } + + return false; + + } + + /** + * Test for intersection with a ray. + * @param origin the starting point of the ray + * @param direction the direction of the ray + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Point3d origin, Vector3d direction ) { + + // compute intersection point of ray and each plane then test if point is in polytope + + double t,v0,vd,x,y,z; + int i,j; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + return true; + } + + for(i=0;i= 0.0) { // plane is behind origin + + x = origin.x + direction.x*t; // compute intersection point + y = origin.y + direction.y*t; + z = origin.z + direction.z*t; + + if( pointInPolytope(x,y,z) ) { + return true; // ray intersects a face of polytope + } else { + // System.err.println("point outside polytope"); + } + } + } + } + + return false; + + } + + /** + * Tests whether the bounding polytope is empty. A bounding polytope is + * empty if it is null (either by construction or as the result of + * a null intersection) or if its volume is negative. A bounding polytope + * with a volume of zero is not empty. + * @return true if the bounding polytope is empty; + * otherwise, it returns false + */ + public boolean isEmpty() { + // if nVerts > 0 after computeAllVerts(), that means + // there is some intersection between 3 planes. + return (boundsIsEmpty || (nVerts <= 0)); + } + + /** + * Test for intersection with a point. + * @param point a Point defining a position in 3-space + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Point3d point ) { + + int i; + if( boundsIsEmpty ) { + return false; + } + if( boundsIsInfinite ) { + return true; + } + + for(i = 0; i < this.planes.length; i++){ + if(( point.x*this.planes[i].x + + point.y*this.planes[i].y + + point.z*this.planes[i].z + planes[i].w ) > 0.0 ) + return false; + + } + return true; + } + + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occured + */ + boolean intersect(Bounds boundsObject, Point4d position) { + return intersect(boundsObject); + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds boundsObject) { + + if( boundsObject == null ) { + return false; + } + + if( boundsIsEmpty || boundsObject.boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite || boundsObject.boundsIsInfinite ) { + return true; + } + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + return intersect_ptope_sphere( this, (BoundingSphere)boundsObject); + } else if( boundsObject.boundId == BOUNDING_BOX){ + return intersect_ptope_abox( this, (BoundingBox)boundsObject); + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + return intersect_ptope_ptope( this, (BoundingPolytope)boundsObject); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope6")); + } + } + + /** + * Test for intersection with another bounds object. + * @param boundsObjects an array of bounding objects + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds[] boundsObjects) { + + double distsq, radsq; + BoundingSphere sphere; + int i; + if( boundsObjects == null || boundsObjects.length <= 0 ) { + return false; + } + + if( boundsIsEmpty ) { + return false; + } + + for(i = 0; i < boundsObjects.length; i++){ + if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty) ; + else if( boundsIsInfinite || boundsObjects[i].boundsIsInfinite ) { + return true; // We're done here. + } + if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObjects[i]; + radsq = sphere.radius; + radsq *= radsq; + distsq = sphere.center.distanceSquared(sphere.center); + if (distsq < radsq) { + return true; + } + } else if(boundsObjects[i].boundId == BOUNDING_BOX){ + if( this.intersect(boundsObjects[i])) return true; + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + if( this.intersect(boundsObjects[i])) return true; + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingPolytope7")); + } + } + + return false; + } + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @param newBoundPolytope the new bounding polytope, which is the intersection of + * the boundsObject and this BoundingPolytope + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds boundsObject, BoundingPolytope newBoundPolytope) { + int i; + + if((boundsObject == null) || boundsIsEmpty || boundsObject.boundsIsEmpty ) { + newBoundPolytope.boundsIsEmpty = true; + newBoundPolytope.boundsIsInfinite = false; + newBoundPolytope.computeAllVerts(); + return false; + } + if(boundsIsInfinite && (!boundsObject.boundsIsInfinite)) { + newBoundPolytope.set(boundsObject); + return true; + } + else if((!boundsIsInfinite) && boundsObject.boundsIsInfinite) { + newBoundPolytope.set(this); + return true; + } + else if(boundsIsInfinite && boundsObject.boundsIsInfinite) { + newBoundPolytope.set(this); + return true; + } + + + BoundingBox tbox = new BoundingBox(); // convert sphere to box + + if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + if( this.intersect( sphere)) { + BoundingBox sbox = new BoundingBox( sphere ); // convert sphere to box + BoundingBox pbox = new BoundingBox( this ); // convert polytope to box + pbox.intersect(sbox, tbox); // insersect two boxes + newBoundPolytope.set( tbox ); + return true; + } + } else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + if( this.intersect( box)) { + BoundingBox pbox = new BoundingBox( this ); // convert polytope to box + pbox.intersect(box, tbox); // insersect two boxes + newBoundPolytope.set( tbox ); + return true; + } + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + if( this.intersect( polytope)) { + Vector4d newPlanes[] = new Vector4d[planes.length + polytope.planes.length]; + for(i=0;i= boundsObjects.length ) { // all bounds objects were empty + newBoundingPolytope.boundsIsEmpty = true; + newBoundingPolytope.boundsIsInfinite = false; + newBoundingPolytope.computeAllVerts(); + return false; + } + + boolean status = false; + BoundingBox tbox = new BoundingBox(); // convert sphere to box + + for(i=0;i 0.0 ) { // check if sphere center in polytope + disToPlane = sphere.center.x*planes[j].x + + sphere.center.y*planes[j].y + + sphere.center.z*planes[j].z + planes[j].w; + + // check if distance from center to plane is larger than radius + if( disToPlane > sphere.radius ) inside = false; + } + } + if( inside) { // contains the sphere + if( !contains ){ // initialize smallest_distance for the first containment + index = i; + smallest_distance = dis; + contains = true; + } else{ + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if (!contains) { + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if( boundsObjects[i] instanceof BoundingBox){ + BoundingBox box = (BoundingBox)boundsObjects[i]; + cenX = (box.upper.x+box.lower.x)/2.0; + cenY = (box.upper.y+box.lower.y)/2.0; + cenZ = (box.upper.z+box.lower.z)/2.0; + dis = Math.sqrt( (centroid.x-cenX)*(centroid.x-cenX) + + (centroid.y-cenY)*(centroid.y-cenY) + + (centroid.z-cenZ)*(centroid.z-cenZ) ); + inside = true; + if( !pointInPolytope( box.upper.x, box.upper.y, box.upper.z ) ) inside = false; + if( !pointInPolytope( box.upper.x, box.upper.y, box.lower.z ) ) inside = false; + if( !pointInPolytope( box.upper.x, box.lower.y, box.upper.z ) ) inside = false; + if( !pointInPolytope( box.upper.x, box.lower.y, box.lower.z ) ) inside = false; + if( !pointInPolytope( box.lower.x, box.upper.y, box.upper.z ) ) inside = false; + if( !pointInPolytope( box.lower.x, box.upper.y, box.lower.z ) ) inside = false; + if( !pointInPolytope( box.lower.x, box.lower.y, box.upper.z ) ) inside = false; + if( !pointInPolytope( box.lower.x, box.lower.y, box.lower.z ) ) inside = false; + + if( inside ) { // contains box + if( !contains ){ // initialize smallest_distance for the first containment + index = i; + smallest_distance = dis; + contains = true; + } else{ + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if (!contains) { + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + + } else if(boundsObjects[i] instanceof BoundingPolytope) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + dis = Math.sqrt( (centroid.x-polytope.centroid.x)*(centroid.x-polytope.centroid.x) + + (centroid.y-polytope.centroid.y)*(centroid.y-polytope.centroid.y) + + (centroid.z-polytope.centroid.z)*(centroid.z-polytope.centroid.z) ); + inside = true; + for(j=0;j= verts.length) { + Point3d newVerts[] = new Point3d[nVerts << 1]; + for(int i=0;i EPSILON ) { + return false; + } + + } + return true; + } + + private void checkBoundsIsEmpty() { + boundsIsEmpty = (planes.length < 4); + } + + private void initEmptyPolytope() { + planes = new Vector4d[6]; + pDotN = new double[6]; + mag = new double[6]; + verts = new Point3d[planes.length*planes.length]; + nVerts = 0; + + planes[0] = new Vector4d( 1.0, 0.0, 0.0, -1.0 ); + planes[1] = new Vector4d(-1.0, 0.0, 0.0, -1.0 ); + planes[2] = new Vector4d( 0.0, 1.0, 0.0, -1.0 ); + planes[3] = new Vector4d( 0.0,-1.0, 0.0, -1.0 ); + planes[4] = new Vector4d( 0.0, 0.0, 1.0, -1.0 ); + planes[5] = new Vector4d( 0.0, 0.0,-1.0, -1.0 ); + mag[0] = 1.0; + mag[1] = 1.0; + mag[2] = 1.0; + mag[3] = 1.0; + mag[4] = 1.0; + mag[5] = 1.0; + + checkBoundsIsEmpty(); + } + + Point3d getCenter() { + return centroid; + } + + /** + * if the passed the "region" is same type as this object + * then do a copy, otherwise clone the Bounds and + * return + */ + Bounds copy(Bounds r) { + int i, k; + + if (r != null && this.boundId == r.boundId) { + BoundingPolytope region = (BoundingPolytope) r; + if( region.planes.length !=planes.length) { + region.planes = new Vector4d[planes.length]; + + for(k=0;k< region.planes.length;k++) + region.planes[k] = new Vector4d(); + + region.mag = new double[planes.length]; + region.pDotN = new double[planes.length]; + region.verts = new Point3d[nVerts]; + region.nVerts = nVerts; + for(k=0;k rad_sq) { + dis = Math.sqrt( dis_sq); + radius = (radius + dis)*.5; + oldc_to_new_c = dis - radius; + t = oldc_to_new_c/dis; + center.x = center.x + (polytope.verts[i].x - center.x)*t; + center.y = center.y + (polytope.verts[i].y - center.y)*t; + center.z = center.z + (polytope.verts[i].z - center.z)*t; + } + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere0")); + } + + updateBoundsStates(); + } + + /** + * Constructs and initializes a BoundingSphere from an array of bounding objects. + * @param boundsObjects an array of bounds objects + */ + public BoundingSphere(Bounds[] boundsObjects) { + int i=0; + double dis,t,d1; + + boundId = BOUNDING_SPHERE; + center = new Point3d(); + + if( boundsObjects == null || boundsObjects.length <= 0 ) { + // Negative volume. + radius = -1.0; + updateBoundsStates(); + return; + } + + // find first non empty bounds object + while( boundsObjects[i] == null && i < boundsObjects.length) { + i++; + } + + if( i >= boundsObjects.length ) { // all bounds objects were empty + // Negative volume. + radius = -1.0; + updateBoundsStates(); + return; + } + + this.set(boundsObjects[i++]); + if(boundsIsInfinite) + return; + + for(;i sphere.radius) { + if( (dis+sphere.radius) > radius) { + d1 = .5*(radius-sphere.radius+dis); + t = d1/dis; + radius = d1+sphere.radius; + center.x = sphere.center.x + (center.x-sphere.center.x)*t; + center.y = sphere.center.y + (center.y-sphere.center.y)*t; + center.z = sphere.center.z + (center.z-sphere.center.z)*t; + } + }else { + if( (dis+radius) <= sphere.radius) { + center.x = sphere.center.x; + center.y = sphere.center.y; + center.z = sphere.center.z; + radius = sphere.radius; + }else { + d1 = .5*(sphere.radius-radius+dis); + t = d1/dis; + radius = d1+radius; + center.x = center.x + (sphere.center.x-center.x)*t; + center.y = center.y + (sphere.center.y-center.y)*t; + center.z = center.z + (sphere.center.z-center.z)*t; + } + } + } + else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + this.combine(polytope.verts); + + } + else { + if( boundsObjects[i] != null ) + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere0")); + } + } + updateBoundsStates(); + } + + /** + * Returns the radius of this bounding sphere as a double. + * @return the radius of the bounding sphere + */ + public double getRadius() { + return radius; + } + + /** + * Sets the radius of this bounding sphere from a double. + * @param r the new radius for the bounding sphere + */ + public void setRadius(double r) { + radius = r; + updateBoundsStates(); + } + + /** + * Returns the position of this bounding sphere as a point. + * @param center a Point to receive the center of the bounding sphere + + */ + public void getCenter(Point3d center) { + center.x = this.center.x; + center.y = this.center.y; + center.z = this.center.z; + } + + /** + * Sets the position of this bounding sphere from a point. + * @param center a Point defining the new center of the bounding sphere + */ + public void setCenter(Point3d center) { + this.center.x = center.x; + this.center.y = center.y; + this.center.z = center.z; + checkBoundsIsNaN(); + } + + /** + * Sets the value of this BoundingSphere. + * @param boundsObject another bounds object + */ + public void set(Bounds boundsObject){ + int i; + + if ((boundsObject == null) || boundsObject.boundsIsEmpty) { + center.x = 0.0; + center.y = 0.0; + center.z = 0.0; + radius = -1.0; + } else if( boundsObject.boundsIsInfinite ) { + center.x = 0.0; + center.y = 0.0; + center.z = 0.0; + radius = Double.POSITIVE_INFINITY; + } else if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + center.x = (box.upper.x + box.lower.x )/2.0; + center.y = (box.upper.y + box.lower.y )/2.0; + center.z = (box.upper.z + box.lower.z )/2.0; + radius = 0.5*Math.sqrt((box.upper.x-box.lower.x)* + (box.upper.x-box.lower.x)+ + (box.upper.y-box.lower.y)* + (box.upper.y-box.lower.y)+ + (box.upper.z-box.lower.z)* + (box.upper.z-box.lower.z)); + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + radius = sphere.radius; + center.x = sphere.center.x; + center.y = sphere.center.y; + center.z = sphere.center.z; + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + double t,dis,dis_sq,rad_sq,oldc_to_new_c; + center.x = polytope.centroid.x; + center.y = polytope.centroid.y; + center.z = polytope.centroid.z; + radius = Math.sqrt((polytope.verts[0].x - center.x)* + (polytope.verts[0].x - center.x) + + (polytope.verts[0].y - center.y)* + (polytope.verts[0].y - center.y) + + (polytope.verts[0].z - center.z)* + (polytope.verts[0].z - center.z)); + + for(i=1;i rad_sq) { // point is outside sphere + dis = Math.sqrt( dis_sq); + radius = (radius + dis)*.5; + oldc_to_new_c = dis - radius; + t = oldc_to_new_c/dis; + center.x = center.x + (polytope.verts[i].x - center.x)*t; + center.y = center.y + (polytope.verts[i].y - center.y)*t; + center.z = center.z + (polytope.verts[i].z - center.z)*t; + } + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere2")); + } + updateBoundsStates(); + } + + /** + * Creates a copy of the bounding sphere. + * @return a BoundingSphere + */ + public Object clone() { + return new BoundingSphere(this.center, this.radius); + } + + + /** + * Indicates whether the specified bounds object is + * equal to this BoundingSphere object. They are equal if the + * specified bounds object is an instance of + * BoundingSphere and all of the data + * members of bounds are equal to the corresponding + * data members in this BoundingSphere. + * @param bounds the object with which the comparison is made. + * @return true if this BoundingSphere is equal to bounds; + * otherwise false + * + * @since Java 3D 1.2 + */ + public boolean equals(Object bounds) { + try { + BoundingSphere sphere = (BoundingSphere)bounds; + return (center.equals(sphere.center) && + radius == sphere.radius); + } + catch (NullPointerException e) { + return false; + } + catch (ClassCastException e) { + return false; + } + } + + + /** + * Returns a hash code value for this BoundingSphere object + * based on the data values in this object. Two different + * BoundingSphere objects with identical data values (i.e., + * BoundingSphere.equals returns true) will return the same hash + * code value. Two BoundingSphere objects with different data + * members may return the same hash code value, although this is + * not likely. + * @return a hash code value for this BoundingSphere object. + * + * @since Java 3D 1.2 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + HashCodeUtil.doubleToLongBits(radius); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(center.x); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(center.y); + bits = 31L * bits + HashCodeUtil.doubleToLongBits(center.z); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Combines this bounding sphere with a bounding object so that the + * resulting bounding sphere encloses the original bounding sphere and the + * given bounds object. + * @param boundsObject another bounds object + */ + public void combine(Bounds boundsObject) { + double t,dis,d1,u,l,x,y,z,oldc_to_new_c; + BoundingSphere sphere; + + if((boundsObject == null) || (boundsObject.boundsIsEmpty) + || (boundsIsInfinite)) + return; + + if((boundsIsEmpty) || (boundsObject.boundsIsInfinite)) { + this.set(boundsObject); + return; + } + + + if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox b = (BoundingBox)boundsObject; + + // start with point furthest from sphere + u = b.upper.x-center.x; + l = b.lower.x-center.x; + if( u*u > l*l) + x = b.upper.x; + else + x = b.lower.x; + + u = b.upper.y-center.y; + l = b.lower.y-center.y; + if( u*u > l*l) + y = b.upper.y; + else + y = b.lower.y; + + u = b.upper.z-center.z; + l = b.lower.z-center.z; + if( u*u > l*l) + z = b.upper.z; + else + z = b.lower.z; + + dis = Math.sqrt( (x - center.x)*(x - center.x) + + (y - center.y)*(y - center.y) + + (z - center.z)*(z - center.z) ); + + if( dis > radius) { + radius = (dis + radius)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*x)/dis; + center.y = (radius*center.y + oldc_to_new_c*y)/dis; + center.z = (radius*center.z + oldc_to_new_c*z)/dis; + combinePoint( b.upper.x, b.upper.y, b.upper.z); + combinePoint( b.upper.x, b.upper.y, b.lower.z); + combinePoint( b.upper.x, b.lower.y, b.upper.z); + combinePoint( b.upper.x, b.lower.y, b.lower.z); + combinePoint( b.lower.x, b.upper.y, b.upper.z); + combinePoint( b.lower.x, b.upper.y, b.lower.z); + combinePoint( b.lower.x, b.lower.y, b.upper.z); + combinePoint( b.lower.x, b.lower.y, b.lower.z); + } + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObject; + dis = Math.sqrt( (center.x - sphere.center.x)* + (center.x - sphere.center.x) + + (center.y - sphere.center.y)* + (center.y - sphere.center.y) + + (center.z - sphere.center.z)* + (center.z - sphere.center.z) ); + if( radius > sphere.radius) { + if( (dis+sphere.radius) > radius) { + d1 = .5*(radius-sphere.radius+dis); + t = d1/dis; + radius = d1+sphere.radius; + center.x = sphere.center.x + (center.x-sphere.center.x)*t; + center.y = sphere.center.y + (center.y-sphere.center.y)*t; + center.z = sphere.center.z + (center.z-sphere.center.z)*t; + } + }else { + if( (dis+radius) <= sphere.radius) { + center.x = sphere.center.x; + center.y = sphere.center.y; + center.z = sphere.center.z; + radius = sphere.radius; + }else { + d1 = .5*(sphere.radius-radius+dis); + t = d1/dis; + radius = d1+radius; + center.x = center.x + (sphere.center.x-center.x)*t; + center.y = center.y + (sphere.center.y-center.y)*t; + center.z = center.z + (sphere.center.z-center.z)*t; + } + } + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + this.combine(polytope.verts); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere3")); + } + updateBoundsStates(); + } + + private void combinePoint( double x, double y, double z) { + double dis,oldc_to_new_c; + dis = Math.sqrt( (x - center.x)*(x - center.x) + + (y - center.y)*(y - center.y) + + (z - center.z)*(z - center.z) ); + + if( dis > radius) { + radius = (dis + radius)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*x)/dis; + center.y = (radius*center.y + oldc_to_new_c*y)/dis; + center.z = (radius*center.z + oldc_to_new_c*z)/dis; + } + } + + /** + * Combines this bounding sphere with an array of bounding objects so that the + * resulting bounding sphere encloses the original bounding sphere and the + * given array of bounds object. + * @param boundsObjects an array of bounds objects + */ + public void combine(Bounds[] boundsObjects) { + BoundingSphere sphere; + BoundingBox b; + BoundingPolytope polytope; + double t,dis,d1,u,l,x,y,z,oldc_to_new_c; + int i=0; + + + if((boundsObjects == null) || (boundsObjects.length <= 0) + || (boundsIsInfinite)) + return; + + // find first non empty bounds object + while((i= boundsObjects.length) + return; // no non empty bounds so do not modify current bounds + + if( boundsIsEmpty) + this.set(boundsObjects[i++]); + + if(boundsIsInfinite) + return; + + for(;i l*l) + x = b.upper.x; + else + x = b.lower.x; + + u = b.upper.y-center.y; + l = b.lower.y-center.y; + if( u*u > l*l) + y = b.upper.y; + else + y = b.lower.y; + + u = b.upper.z-center.z; + l = b.lower.z-center.z; + if( u*u > l*l) + z = b.upper.z; + else + z = b.lower.z; + + dis = Math.sqrt( (x - center.x)*(x - center.x) + + (y - center.y)*(y - center.y) + + (z - center.z)*(z - center.z) ); + + if( dis > radius) { + radius = (dis + radius)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*x)/dis; + center.y = (radius*center.y + oldc_to_new_c*y)/dis; + center.z = (radius*center.z + oldc_to_new_c*z)/dis; + combinePoint( b.upper.x, b.upper.y, b.upper.z); + combinePoint( b.upper.x, b.upper.y, b.lower.z); + combinePoint( b.upper.x, b.lower.y, b.upper.z); + combinePoint( b.upper.x, b.lower.y, b.lower.z); + combinePoint( b.lower.x, b.upper.y, b.upper.z); + combinePoint( b.lower.x, b.upper.y, b.lower.z); + combinePoint( b.lower.x, b.lower.y, b.upper.z); + combinePoint( b.lower.x, b.lower.y, b.lower.z); + } + } else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObjects[i]; + dis = Math.sqrt( (center.x - sphere.center.x)* + (center.x - sphere.center.x) + + (center.y - sphere.center.y)* + (center.y - sphere.center.y) + + (center.z - sphere.center.z)* + (center.z - sphere.center.z) ); + if( radius > sphere.radius) { + if( (dis+sphere.radius) > radius) { + d1 = .5*(radius-sphere.radius+dis); + t = d1/dis; + radius = d1+sphere.radius; + center.x = sphere.center.x + (center.x-sphere.center.x)*t; + center.y = sphere.center.y + (center.y-sphere.center.y)*t; + center.z = sphere.center.z + (center.z-sphere.center.z)*t; + } + }else { + if( (dis+radius) <= sphere.radius) { + center.x = sphere.center.x; + center.y = sphere.center.y; + center.z = sphere.center.z; + radius = sphere.radius; + }else { + d1 = .5*(sphere.radius-radius+dis); + t = d1/dis; + radius = d1+radius; + center.x = center.x + (sphere.center.x-center.x)*t; + center.y = center.y + (sphere.center.y-center.y)*t; + center.z = center.z + (sphere.center.z-center.z)*t; + } + } + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + polytope = (BoundingPolytope)boundsObjects[i]; + this.combine(polytope.verts); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere4")); + } + } + + updateBoundsStates(); + } + + /** + * Combines this bounding sphere with a point. + * @param point a 3D point in space + */ + public void combine(Point3d point) { + double t,dis,oldc_to_new_c; + + if( boundsIsInfinite) { + return; + } + + if( boundsIsEmpty) { + radius = 0.0; + center.x = point.x; + center.y = point.y; + center.z = point.z; + } else { + dis = Math.sqrt( (point.x - center.x)*(point.x - center.x) + + (point.y - center.y)*(point.y - center.y) + + (point.z - center.z)*(point.z - center.z) ); + + if( dis > radius) { + radius = (dis + radius)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*point.x)/dis; + center.y = (radius*center.y + oldc_to_new_c*point.y)/dis; + center.z = (radius*center.z + oldc_to_new_c*point.z)/dis; + } + } + + updateBoundsStates(); + } + + /** + * Combines this bounding sphere with an array of points. + * @param points an array of 3D points in space + */ + public void combine(Point3d[] points) { + int i; + double dis,dis_sq,rad_sq,oldc_to_new_c; + + if( boundsIsInfinite) { + return; + } + + if( boundsIsEmpty ) { + center.x = points[0].x; + center.y = points[0].y; + center.z = points[0].z; + radius = 0.0; + } + + for(i=0;i rad_sq) { + dis = Math.sqrt( dis_sq); + radius = (radius + dis)*.5; + oldc_to_new_c = dis - radius; + center.x = (radius*center.x + oldc_to_new_c*points[i].x)/dis; + center.y = (radius*center.y + oldc_to_new_c*points[i].y)/dis; + center.z = (radius*center.z + oldc_to_new_c*points[i].z)/dis; + } + } + + updateBoundsStates(); + } + + + /** + * Modifies the bounding sphere so that it bounds the volume + * generated by transforming the given bounding object. + * @param boundsObject the bounding object to be transformed + * @param matrix a transformation matrix + */ + public void transform( Bounds boundsObject, Transform3D matrix) { + double scale; + + if( boundsObject == null || boundsObject.boundsIsEmpty) { + // Negative volume. + center.x = center.y = center.z = 0.0; + radius = -1.0; + updateBoundsStates(); + return; + } + + if(boundsObject.boundsIsInfinite) { + center.x = center.y = center.z = 0.0; + radius = Double.POSITIVE_INFINITY; + updateBoundsStates(); + return; + } + + if( boundsObject.boundId == BOUNDING_BOX){ + if (tmpBox == null) { + tmpBox = new BoundingBox( (BoundingBox)boundsObject); + } else { + tmpBox.set((BoundingBox)boundsObject); + } + tmpBox.transform(matrix); + this.set(tmpBox); + }else if( boundsObject.boundId == BOUNDING_SPHERE ) { + matrix.transform(((BoundingSphere)boundsObject).center, this.center); + // A very simple radius scale. + scale = matrix.getDistanceScale(); + this.radius = ((BoundingSphere)boundsObject).radius * scale; + if (Double.isNaN(radius)) { + // Negative volume. + center.x = center.y = center.z = 0.0; + radius = -1.0; + updateBoundsStates(); + return; + } + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + if (tmpPolytope == null) { + tmpPolytope = new BoundingPolytope((BoundingPolytope)boundsObject); + } else { + tmpPolytope.set((BoundingPolytope)boundsObject); + } + tmpPolytope.transform(matrix); + this.set(tmpPolytope); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere5")); + } + } + + /** + * Transforms this bounding sphere by the given matrix. + */ + public void transform( Transform3D trans) { + double scale; + + if(boundsIsInfinite) + return; + + trans.transform(center); + scale = trans.getDistanceScale(); + radius = radius * scale; + if (Double.isNaN(radius)) { + // Negative volume. + center.x = center.y = center.z = 0.0; + radius = -1.0; + updateBoundsStates(); + return; + } + } + + /** + * Test for intersection with a ray + * @param origin the starting point of the ray + * @param direction the direction of the ray + * @param position3 a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + boolean intersect(Point3d origin, Vector3d direction, Point4d position ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = origin.x; + position.y = origin.y; + position.z = origin.z; + position.w = 0.0; + return true; + } + + double l2oc,rad2,tca,t2hc,mag,t,invMag; + Vector3d dir = new Vector3d(); // normalized direction of ray + Point3d oc = new Point3d(); // vector from sphere center to ray origin + + oc.x = center.x - origin.x; + oc.y = center.y - origin.y; + oc.z = center.z - origin.z; + + l2oc = oc.x*oc.x + oc.y*oc.y + oc.z*oc.z; // center to origin squared + + rad2 = radius*radius; + if( l2oc < rad2 ){ + // System.err.println("ray origin inside sphere" ); + return true; // ray origin inside sphere + } + + invMag = 1.0/Math.sqrt(direction.x*direction.x + + direction.y*direction.y + + direction.z*direction.z); + dir.x = direction.x*invMag; + dir.y = direction.y*invMag; + dir.z = direction.z*invMag; + tca = oc.x*dir.x + oc.y*dir.y + oc.z*dir.z; + + if( tca <= 0.0 ) { + // System.err.println("ray points away from sphere" ); + return false; // ray points away from sphere + } + + t2hc = rad2 - l2oc + tca*tca; + + if( t2hc > 0.0 ){ + t = tca - Math.sqrt(t2hc); + // System.err.println("ray hits sphere:"+this.toString()+" t="+t+" direction="+dir ); + position.x = origin.x + dir.x*t; + position.y = origin.y + dir.y*t; + position.z = origin.z + dir.z*t; + position.w = t; + return true; // ray hits sphere + }else { + // System.err.println("ray does not hit sphere" ); + return false; + } + + } + + /** + * Test for intersection with a point + * @param point the pick point + * @param position a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + boolean intersect(Point3d point, Point4d position ) { + double x,y,z,dist; + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = point.x; + position.y = point.y; + position.z = point.z; + position.w = 0.0; + return true; + } + + x = point.x - center.x; + y = point.y - center.y; + z = point.z - center.z; + + dist = x*x + y*y + z*z; + if( dist > radius*radius) + return false; + else { + position.x = point.x; + position.y = point.y; + position.z = point.z; + position.w = Math.sqrt(dist); + return true; + } + + } + + /** + * Test for intersection with a segment + * @param start a point defining the start of the line segment + * @param end a point defining the end of the line segment + * @param position a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + boolean intersect( Point3d start, Point3d end, Point4d position ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + position.x = start.x; + position.y = start.y; + position.z = start.z; + position.w = 0.0; + return true; + } + + double l2oc,rad2,tca,t2hc,mag,invMag,t; + Vector3d dir = new Vector3d(); // normalized direction of ray + Point3d oc = new Point3d(); // vector from sphere center to ray origin + Vector3d direction = new Vector3d(); + + oc.x = center.x - start.x; + oc.y = center.y - start.y; + oc.z = center.z - start.z; + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + invMag = 1.0/Math.sqrt( direction.x*direction.x + + direction.y*direction.y + + direction.z*direction.z); + dir.x = direction.x*invMag; + dir.y = direction.y*invMag; + dir.z = direction.z*invMag; + + + l2oc = oc.x*oc.x + oc.y*oc.y + oc.z*oc.z; // center to origin squared + + rad2 = radius*radius; + if( l2oc < rad2 ){ + // System.err.println("ray origin inside sphere" ); + return true; // ray origin inside sphere + } + + tca = oc.x*dir.x + oc.y*dir.y + oc.z*dir.z; + + if( tca <= 0.0 ) { + // System.err.println("ray points away from sphere" ); + return false; // ray points away from sphere + } + + t2hc = rad2 - l2oc + tca*tca; + + if( t2hc > 0.0 ){ + t = tca - Math.sqrt(t2hc); + if( t*t <= ((end.x-start.x)*(end.x-start.x)+ + (end.y-start.y)*(end.y-start.y)+ + (end.z-start.z)*(end.z-start.z))){ + + position.x = start.x + dir.x*t; + position.y = start.y + dir.x*t; + position.z = start.z + dir.x*t; + position.w = t; + return true; // segment hits sphere + } + } + return false; + } + + /** + * Test for intersection with a ray. + * @param origin the starting point of the ray + * @param direction the direction of the ray + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Point3d origin, Vector3d direction ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + return true; + } + + double l2oc,rad2,tca,t2hc,mag; + Vector3d dir = new Vector3d(); // normalized direction of ray + Point3d oc = new Point3d(); // vector from sphere center to ray origin + + oc.x = center.x - origin.x; + oc.y = center.y - origin.y; + oc.z = center.z - origin.z; + + l2oc = oc.x*oc.x + oc.y*oc.y + oc.z*oc.z; // center to origin squared + + rad2 = radius*radius; + if( l2oc < rad2 ){ + // System.err.println("ray origin inside sphere" ); + return true; // ray origin inside sphere + } + + mag = Math.sqrt(direction.x*direction.x + + direction.y*direction.y + + direction.z*direction.z); + dir.x = direction.x/mag; + dir.y = direction.y/mag; + dir.z = direction.z/mag; + tca = oc.x*dir.x + oc.y*dir.y + oc.z*dir.z; + + if( tca <= 0.0 ) { + // System.err.println("ray points away from sphere" ); + return false; // ray points away from sphere + } + + t2hc = rad2 - l2oc + tca*tca; + + if( t2hc > 0.0 ){ + // System.err.println("ray hits sphere" ); + return true; // ray hits sphere + }else { + // System.err.println("ray does not hit sphere" ); + return false; + } + } + + + /** + * Returns the position of the intersect point if the ray intersects with + * the sphere. + * + */ + boolean intersect(Point3d origin, Vector3d direction, Point3d intersectPoint ) { + + if( boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite ) { + intersectPoint.x = origin.x; + intersectPoint.y = origin.y; + intersectPoint.z = origin.z; + return true; + } + + double l2oc,rad2,tca,t2hc,mag,t; + Point3d dir = new Point3d(); // normalized direction of ray + Point3d oc = new Point3d(); // vector from sphere center to ray origin + + oc.x = center.x - origin.x; // XXXX: check if this method is still needed + oc.y = center.y - origin.y; + oc.z = center.z - origin.z; + + l2oc = oc.x*oc.x + oc.y*oc.y + oc.z*oc.z; // center to origin squared + + rad2 = radius*radius; + if( l2oc < rad2 ){ + // System.err.println("ray origin inside sphere" ); + return true; // ray origin inside sphere + } + + mag = Math.sqrt(direction.x*direction.x + + direction.y*direction.y + + direction.z*direction.z); + dir.x = direction.x/mag; + dir.y = direction.y/mag; + dir.z = direction.z/mag; + tca = oc.x*dir.x + oc.y*dir.y + oc.z*dir.z; + + if( tca <= 0.0 ) { + // System.err.println("ray points away from sphere" ); + return false; // ray points away from sphere + } + + t2hc = rad2 - l2oc + tca*tca; + + if( t2hc > 0.0 ){ + t = tca - Math.sqrt(t2hc); + intersectPoint.x = origin.x + direction.x*t; + intersectPoint.y = origin.y + direction.y*t; + intersectPoint.z = origin.z + direction.z*t; + // System.err.println("ray hits sphere" ); + return true; // ray hits sphere + }else { + // System.err.println("ray does not hit sphere" ); + return false; + } + } + + + /** + * Test for intersection with a point. + * @param point a point defining a position in 3-space + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Point3d point ) { + double x,y,z,dist; + + if( boundsIsEmpty ) { + return false; + } + if( boundsIsInfinite ) { + return true; + } + + x = point.x - center.x; + y = point.y - center.y; + z = point.z - center.z; + + dist = x*x + y*y + z*z; + if( dist > radius*radius) + return false; + else + return true; + + } + + /** + * Tests whether the bounding sphere is empty. A bounding sphere is + * empty if it is null (either by construction or as the result of + * a null intersection) or if its volume is negative. A bounding sphere + * with a volume of zero is not empty. + * @return true if the bounding sphere is empty; + * otherwise, it returns false + */ + public boolean isEmpty() { + return boundsIsEmpty; + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occured + */ + boolean intersect(Bounds boundsObject, Point4d position) { + return intersect(boundsObject); + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds boundsObject) { + double distsq, radsq; + BoundingSphere sphere; + boolean intersect; + + if( boundsObject == null ) { + return false; + } + + if( boundsIsEmpty || boundsObject.boundsIsEmpty ) { + return false; + } + + if( boundsIsInfinite || boundsObject.boundsIsInfinite ) { + return true; + } + + if( boundsObject.boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObject; + double dis = 0.0; + double rad_sq = radius*radius; + + // find the corner closest to the center of sphere + + if( center.x < box.lower.x ) + dis = (center.x-box.lower.x)*(center.x-box.lower.x); + else + if( center.x > box.upper.x ) + dis = (center.x-box.upper.x)*(center.x-box.upper.x); + + if( center.y < box.lower.y ) + dis += (center.y-box.lower.y)*(center.y-box.lower.y); + else + if( center.y > box.upper.y ) + dis += (center.y-box.upper.y)*(center.y-box.upper.y); + + if( center.z < box.lower.z ) + dis += (center.z-box.lower.z)*(center.z-box.lower.z); + else + if( center.z > box.upper.z ) + dis += (center.z-box.upper.z)*(center.z-box.upper.z); + + return ( dis <= rad_sq ); + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObject; + radsq = radius + sphere.radius; + radsq *= radsq; + distsq = center.distanceSquared(sphere.center); + return (distsq <= radsq); + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + return intersect_ptope_sphere( (BoundingPolytope)boundsObject, this); + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere6")); + } + } + + /** + * Test for intersection with another bounds object. + * @param boundsObjects an array of bounding objects + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds[] boundsObjects) { + double distsq, radsq; + BoundingSphere sphere; + int i; + + if( boundsObjects == null || boundsObjects.length <= 0 ) { + return false; + } + + if( boundsIsEmpty ) { + return false; + } + + for(i = 0; i < boundsObjects.length; i++){ + if( boundsObjects[i] == null || boundsObjects[i].boundsIsEmpty); + else if( boundsIsInfinite || boundsObjects[i].boundsIsInfinite ) { + return true; // We're done here. + } else if( boundsObjects[i].boundId == BOUNDING_BOX){ + if( this.intersect( boundsObjects[i])) return true; + } else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + sphere = (BoundingSphere)boundsObjects[i]; + radsq = radius + sphere.radius; + radsq *= radsq; + distsq = center.distanceSquared(sphere.center); + if (distsq <= radsq) { + return true; + } + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + if( this.intersect( boundsObjects[i])) return true; + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere7")); + } + } + + return false; + + } + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @param newBoundSphere the new bounding sphere which is the intersection of + * the boundsObject and this BoundingSphere + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds boundsObject, BoundingSphere newBoundSphere) { + + if((boundsObject == null ) || boundsIsEmpty || boundsObject.boundsIsEmpty) { + // Negative volume. + newBoundSphere.center.x = newBoundSphere.center.y = + newBoundSphere.center.z = 0.0; + newBoundSphere.radius = -1.0; + newBoundSphere.updateBoundsStates(); + return false; + } + + if(boundsIsInfinite && (!boundsObject.boundsIsInfinite)) { + newBoundSphere.set(boundsObject); + return true; + } + else if((!boundsIsInfinite) && boundsObject.boundsIsInfinite) { + newBoundSphere.set(this); + return true; + } + else if(boundsIsInfinite && boundsObject.boundsIsInfinite) { + newBoundSphere.set(this); + return true; + } else if(boundsObject.boundId == BOUNDING_BOX){ + BoundingBox tbox = new BoundingBox(); + BoundingBox box = (BoundingBox)boundsObject; + if( this.intersect( box) ){ + BoundingBox sbox = new BoundingBox( this ); // convert sphere to box + sbox.intersect(box, tbox); // insersect two boxes + newBoundSphere.set( tbox ); // set sphere to the intersection of 2 boxes + return true; + } else { + // Negative volume. + newBoundSphere.center.x = newBoundSphere.center.y = + newBoundSphere.center.z = 0.0; + newBoundSphere.radius = -1.0; + newBoundSphere.updateBoundsStates(); + return false; + } + } else if( boundsObject.boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObject; + double dis,t,d2; + boolean status; + dis = Math.sqrt( (center.x-sphere.center.x)*(center.x-sphere.center.x) + + (center.y-sphere.center.y)*(center.y-sphere.center.y) + + (center.z-sphere.center.z)*(center.z-sphere.center.z) ); + if ( dis > radius+sphere.radius) { + // Negative volume. + newBoundSphere.center.x = newBoundSphere.center.y = + newBoundSphere.center.z = 0.0; + newBoundSphere.radius = -1.0; + status = false; + } else if( dis+radius <= sphere.radius ) { // this sphere is contained within boundsObject + newBoundSphere.center.x = center.x; + newBoundSphere.center.y = center.y; + newBoundSphere.center.z = center.z; + newBoundSphere.radius = radius; + status = true; + } else if( dis+sphere.radius <= radius ) { // boundsObject is containted within this sphere + newBoundSphere.center.x = sphere.center.x; + newBoundSphere.center.y = sphere.center.y; + newBoundSphere.center.z = sphere.center.z; + newBoundSphere.radius = sphere.radius; + status = true; + } else { + // distance from this center to center of overlapped volume + d2 = (dis*dis + radius*radius - sphere.radius*sphere.radius)/(2.0*dis); + newBoundSphere.radius = Math.sqrt( radius*radius - d2*d2); + t = d2/dis; + newBoundSphere.center.x = center.x + (sphere.center.x - center.x)*t; + newBoundSphere.center.y = center.y + (sphere.center.y - center.y)*t; + newBoundSphere.center.z = center.z + (sphere.center.z - center.z)*t; + status = true; + } + + newBoundSphere.updateBoundsStates(); + return status; + + } else if(boundsObject.boundId == BOUNDING_POLYTOPE) { + BoundingBox tbox = new BoundingBox(); + + BoundingPolytope polytope = (BoundingPolytope)boundsObject; + if( this.intersect( polytope) ){ + BoundingBox sbox = new BoundingBox( this ); // convert sphere to box + BoundingBox pbox = new BoundingBox( polytope ); // convert polytope to box + sbox.intersect(pbox,tbox); // insersect two boxes + newBoundSphere.set( tbox ); // set sphere to the intersection of 2 boxesf + return true; + } else { + // Negative volume. + newBoundSphere.center.x = newBoundSphere.center.y = + newBoundSphere.center.z = 0.0; + newBoundSphere.radius = -1.0; + newBoundSphere.updateBoundsStates(); + return false; + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere8")); + } + } + + /** + * Test for intersection with an array of bounds objects. + * @param boundsObjects an array of bounds objects + * @param newBoundSphere the new bounding sphere which is the intersection of + * the boundsObject and this BoundingSphere + * @return true or false indicating if an intersection occured + */ + public boolean intersect(Bounds[] boundsObjects, BoundingSphere newBoundSphere) { + + if( boundsObjects == null || boundsObjects.length <= 0 || boundsIsEmpty ) { + // Negative volume. + newBoundSphere.center.x = newBoundSphere.center.y = + newBoundSphere.center.z = 0.0; + newBoundSphere.radius = -1.0; + newBoundSphere.updateBoundsStates(); + return false; + } + + int i=0; + + // find first non null bounds object + while( boundsObjects[i] == null && i < boundsObjects.length) { + i++; + } + + if( i >= boundsObjects.length ) { // all bounds objects were empty + // Negative volume. + newBoundSphere.center.x = newBoundSphere.center.y = + newBoundSphere.center.z = 0.0; + newBoundSphere.radius = -1.0; + newBoundSphere.updateBoundsStates(); + return false; + } + + boolean status = false; + double newRadius; + Point3d newCenter = new Point3d(); + BoundingBox tbox = new BoundingBox(); + + for(i=0;i radius+sphere.radius) { + } else if( dis+radius <= sphere.radius ) { // this sphere is contained within boundsObject + if( status ) { + newBoundSphere.combine( this ); + } else { + newBoundSphere.center.x = center.x; + newBoundSphere.center.y = center.y; + newBoundSphere.center.z = center.z; + newBoundSphere.radius = radius; + status = true; + newBoundSphere.updateBoundsStates(); + } + } else if( dis+sphere.radius <= radius ) { // boundsObject is containted within this sphere + if( status ) { + newBoundSphere.combine( sphere ); + } else { + newBoundSphere.center.x = center.x; + newBoundSphere.center.y = center.y; + newBoundSphere.center.z = center.z; + newBoundSphere.radius = sphere.radius; + status = true; + newBoundSphere.updateBoundsStates(); + } + } else { + // distance from this center to center of overlapped volume + d2 = (dis*dis + radius*radius - sphere.radius*sphere.radius)/(2.0*dis); + newRadius = Math.sqrt( radius*radius - d2*d2); + t = d2/dis; + newCenter.x = center.x + (sphere.center.x - center.x)*t; + newCenter.y = center.y + (sphere.center.y - center.y)*t; + newCenter.z = center.z + (sphere.center.z - center.z)*t; + if( status ) { + BoundingSphere newSphere = new BoundingSphere( newCenter, + newRadius ); + newBoundSphere.combine( newSphere ); + } else { + newBoundSphere.setRadius( newRadius ); + newBoundSphere.setCenter( newCenter ); + status = true; + } + } + + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + if( this.intersect( polytope) ){ + BoundingBox sbox = new BoundingBox( this ); // convert sphere to box + BoundingBox pbox = new BoundingBox( polytope ); // convert polytope to box + sbox.intersect(pbox, tbox); // insersect two boxes + if( status ) { + newBoundSphere.combine( tbox ); + } else { + newBoundSphere.set( tbox ); // set sphere to the intersection of 2 boxesf + status = true; + } + } + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere9")); + } + } + if( status == false) { + // Negative volume. + newBoundSphere.center.x = newBoundSphere.center.y = + newBoundSphere.center.z = 0.0; + newBoundSphere.radius = -1.0; + newBoundSphere.updateBoundsStates(); + } + return status; + } + + /** + * Finds closest bounding object that intersects this bounding sphere. + * @param boundsObjects an array of bounds objects + * @return closest bounding object + */ + public Bounds closestIntersection( Bounds[] boundsObjects) { + + if( boundsObjects == null || boundsObjects.length <= 0 ) { + return null; + } + + if( boundsIsEmpty ) { + return null; + } + + double dis,far_dis,pdist,x,y,z,rad_sq; + double cenX = 0.0, cenY = 0.0, cenZ = 0.0; + boolean contains = false; + boolean inside; + boolean intersect = false; + double smallest_distance = Double.MAX_VALUE; + int i,j,index=0; + + + for(i = 0; i < boundsObjects.length; i++){ + if( boundsObjects[i] == null ) ; + + else if( this.intersect( boundsObjects[i])) { + intersect = true; + if(boundsObjects[i].boundId == BOUNDING_BOX){ + BoundingBox box = (BoundingBox)boundsObjects[i]; + cenX = (box.upper.x+box.lower.x)/2.0; + cenY = (box.upper.y+box.lower.y)/2.0; + cenZ = (box.upper.z+box.lower.z)/2.0; + dis = Math.sqrt( (center.x-cenX)*(center.x-cenX) + + (center.y-cenY)*(center.y-cenY) + + (center.z-cenZ)*(center.z-cenZ) ); + if( (center.x-box.lower.x)*(center.x-box.lower.x) > + (center.x-box.upper.x)*(center.x-box.upper.x) ) + far_dis = (center.x-box.lower.x)*(center.x-box.lower.x); + else + far_dis = (center.x-box.upper.x)*(center.x-box.upper.x); + + if( (center.y-box.lower.y)*(center.y-box.lower.y) > + (center.y-box.upper.y)*(center.y-box.upper.y) ) + far_dis += (center.y-box.lower.y)*(center.y-box.lower.y); + else + far_dis += (center.y-box.upper.y)*(center.y-box.upper.y); + + if( (center.z-box.lower.z)*(center.z-box.lower.z) > + (center.z-box.upper.z)*(center.z-box.upper.z) ) + far_dis += (center.z-box.lower.z)*(center.z-box.lower.z); + else + far_dis += (center.z-box.upper.z)*(center.z-box.upper.z); + + rad_sq = radius * radius; + if( far_dis <= rad_sq ) { // contains box + if( !contains ){ // initialize smallest_distance for the first containment + index = i; + smallest_distance = dis; + contains = true; + } else{ + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if (!contains) { + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if( boundsObjects[i].boundId == BOUNDING_SPHERE ) { + BoundingSphere sphere = (BoundingSphere)boundsObjects[i]; + dis = Math.sqrt( (center.x-sphere.center.x)*(center.x-sphere.center.x) + + (center.y-sphere.center.y)*(center.y-sphere.center.y) + + (center.z-sphere.center.z)*(center.z-sphere.center.z) ); + if( (dis+sphere.radius) <= radius) { // contains the sphere + if( !contains ){ // initialize smallest_distance for the first containment + index = i; + smallest_distance = dis; + contains = true; + } else{ + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if (!contains) { + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + + } else if(boundsObjects[i].boundId == BOUNDING_POLYTOPE) { + BoundingPolytope polytope = (BoundingPolytope)boundsObjects[i]; + dis = Math.sqrt( (center.x-polytope.centroid.x)*(center.x-polytope.centroid.x) + + (center.y-polytope.centroid.y)*(center.y-polytope.centroid.y) + + (center.z-polytope.centroid.z)*(center.z-polytope.centroid.z) ); + inside = true; + for(j=0;j radius*radius) + inside=false; + } + if( inside ) { + if( !contains ){ // initialize smallest_distance for the first containment + index = i; + smallest_distance = dis; + contains = true; + } else{ + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + } else if (!contains) { + if( dis < smallest_distance){ + index = i; + smallest_distance = dis; + } + } + + } else { + throw new IllegalArgumentException(J3dI18N.getString("BoundingSphere10")); + } + } + } + + if ( intersect ) + return boundsObjects[index]; + else + return null; + + } + + + /** + * Intersects this bounding sphere with preprocessed frustum. + * @return true if the bounding sphere and frustum intersect. + */ + boolean intersect(CachedFrustum frustum) { + int i; + double dist; + + if( boundsIsEmpty ) { + return false; + } + + if(boundsIsInfinite) + return true; + + for (i=0; i<6; i++) { + dist = frustum.clipPlanes[i].x*center.x + frustum.clipPlanes[i].y*center.y + + frustum.clipPlanes[i].z*center.z + frustum.clipPlanes[i].w; + if (dist < 0.0 && (dist + radius) < 0.0) { + return(false); + } + } + return true; + } + + /** + * This intersects this bounding sphere with 6 frustum plane equations + * @return returns true if the bounding sphere and frustum intersect. + */ + boolean intersect(Vector4d[] planes) { + int i; + double dist; + + if( boundsIsEmpty ) { + return false; + } + + if(boundsIsInfinite) + return true; + + for (i=0; i<6; i++) { + dist = planes[i].x*center.x + planes[i].y*center.y + + planes[i].z*center.z + planes[i].w; + if (dist < 0.0 && (dist + radius) < 0.0) { + //System.err.println("Tossing " + i + " " + dist + " " + radius); + return(false); + } + } + return true; + } + + /** + * Returns a string representation of this class. + */ + public String toString() { + return new String( "Center="+center+" Radius="+radius); + } + + private void updateBoundsStates() { + + if (checkBoundsIsNaN()) { + boundsIsEmpty = true; + boundsIsInfinite = false; + return; + } + + if(radius == Double.POSITIVE_INFINITY) { + boundsIsEmpty = false; + boundsIsInfinite = true; + } + else { + boundsIsInfinite = false; + if( radius < 0.0 ) { + boundsIsEmpty = true; + } else { + boundsIsEmpty = false; + } + } + } + + Point3d getCenter() { + return center; + } + + /** + * if the passed the "region" is same type as this object + * then do a copy, otherwise clone the Bounds and + * return + */ + Bounds copy(Bounds r) { + if (r != null && this.boundId == r.boundId) { + BoundingSphere region = (BoundingSphere)r; + region.radius = radius; + region.center.x = center.x; + region.center.y = center.y; + region.center.z = center.z; + region.boundsIsEmpty = boundsIsEmpty; + region.boundsIsInfinite = boundsIsInfinite; + return region; + } + else { + return (Bounds) this.clone(); + } + } + + boolean checkBoundsIsNaN() { + if (Double.isNaN(radius+center.x+center.y+center.z)) { + return true; + } + return false; + } + + int getPickType() { + return PickShape.PICKBOUNDINGSPHERE; + } +} + + + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/Bounds.java b/j3d-core/src/classes/share/javax/media/j3d/Bounds.java new file mode 100644 index 0000000..8077bb4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Bounds.java @@ -0,0 +1,666 @@ +/* + * $RCSfile: Bounds.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The abstract base class for bounds objects. Bounds objects define + * a convex, closed volume that is used for various intersection and + * culling operations. + */ + +public abstract class Bounds extends Object implements Cloneable { + static final double EPSILON = .000001; + static final boolean debug = false; + + static final int BOUNDING_BOX = 0x1; + static final int BOUNDING_SPHERE = 0x2; + static final int BOUNDING_POLYTOPE = 0x4; + + boolean boundsIsEmpty = false; + boolean boundsIsInfinite = false; + int boundId = 0; + + /** + * Constructs a new Bounds object. + */ + public Bounds() { + } + + + /** + * Makes a copy of a bounds object. + */ + public abstract Object clone(); + + + /** + * Indicates whether the specified bounds object is + * equal to this Bounds object. They are equal if both the + * specified bounds object and this Bounds are + * instances of the same Bounds subclass and all of the data + * members of bounds are equal to the corresponding + * data members in this Bounds. + * @param bounds the object with which the comparison is made. + * @return true if this Bounds object is equal to bounds; + * otherwise false + * + * @since Java 3D 1.2 + */ + public abstract boolean equals(Object bounds); + + + /** + * Returns a hash code for this Bounds object based on the + * data values in this object. Two different Bounds objects of + * the same type with identical data values (i.e., Bounds.equals + * returns true) will return the same hash code. Two Bounds + * objects with different data members may return the same hash code + * value, although this is not likely. + * @return a hash code for this Bounds object. + * + * @since Java 3D 1.2 + */ + public abstract int hashCode(); + + + /** + * Test for intersection with a ray. + * @param origin the starting point of the ray + * @param direction the direction of the ray + * @return true or false indicating if an intersection occured + */ + public abstract boolean intersect( Point3d origin, Vector3d direction ); + + /** + * Test for intersection with a point. + * @param point a point defining a position in 3-space + * @return true or false indicating if an intersection occured + */ + public abstract boolean intersect( Point3d point ); + + /** + * Test for intersection with a ray + * @param origin is a the starting point of the ray + * @param direction is the direction of the ray + * @param position is a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + abstract boolean intersect( Point3d origin, Vector3d direction, Point4d position ); + + /** + * Test for intersection with a point + * @param point is a point defining a position in 3-space + * @param position is a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + abstract boolean intersect( Point3d point, Point4d position); + + /** + * Test for intersection with a segment + * @param start is a point defining the start of the line segment + * @param end is a point defining the end of the line segment + * @param position is a point defining the location of the pick w= distance to pick + * @return true or false indicating if an intersection occured + */ + abstract boolean intersect( Point3d start, Point3d end, Point4d position ); + + /** + * Test for intersection with another bounds object + * + * Test for intersection with another bounds object + * @param boundsObject is another bounds object + * @return true or false indicating if an intersection occured + */ + abstract boolean intersect( Bounds boundsObject, Point4d position ); + + /** + * Test for intersection with another bounds object. + * @param boundsObject another bounds object + * @return true or false indicating if an intersection occurred + */ + public abstract boolean intersect( Bounds boundsObject ); + + /** + * Test for intersection with another bounds object. + * @param boundsObjects an array of bounding objects + * @return true or false indicating if an intersection occured + */ + public abstract boolean intersect( Bounds[] boundsObjects ); + + + /** + * Finds closest bounding object that intersects this bounding object. + * @param boundsObjects an array of bounds objects + * @return closest bounding object + */ + public abstract Bounds closestIntersection( Bounds[] boundsObjects); + + /** + * Returns the center of the bounds + * @return bounds center + */ + abstract Point3d getCenter(); + + /** + * Combines this bounding object with a bounding object so that the + * resulting bounding object encloses the original bounding object and the + * given bounds object. + * @param boundsObject another bounds object + */ + public abstract void combine( Bounds boundsObject ); + + + /** + * Combines this bounding object with an array of bounding objects so that the + * resulting bounding object encloses the original bounding object and the + * given array of bounds object. + * @param boundsObjects an array of bounds objects + */ + public abstract void combine( Bounds[] boundsObjects); + + /** + * Combines this bounding object with a point. + * @param point a 3d point in space + */ + public abstract void combine( Point3d point); + + /** + * Combines this bounding object with an array of points. + * @param points an array of 3d points in space + */ + public abstract void combine( Point3d[] points); + + /** + * Transforms this bounding object by the given matrix. + * @param trans the transformation matrix + */ + public abstract void transform(Transform3D trans); + + /** + * Modifies the bounding object so that it bounds the volume + * generated by transforming the given bounding object. + * @param bounds the bounding object to be transformed + * @param trans the transformation matrix + */ + public abstract void transform( Bounds bounds, Transform3D trans); + + /** + * Tests whether the bounds is empty. A bounds is + * empty if it is null (either by construction or as the result of + * a null intersection) or if its volume is negative. A bounds + * with a volume of zero is not empty. + * @return true if the bounds is empty; otherwise, it returns false + */ + public abstract boolean isEmpty(); + + /** + * Sets the value of this Bounds object. + * @param boundsObject another bounds object. + */ + public abstract void set( Bounds boundsObject); + + + abstract Bounds copy(Bounds region); + + + private void test_point(Vector4d[] planes, Point3d new_point) { + for (int i = 0; i < planes.length; i++){ + double dist = (new_point.x*planes[i].x + new_point.y*planes[i].y + + new_point.z*planes[i].z + planes[i].w ) ; + if (dist > EPSILON ){ + System.err.println("new point is outside of" + + " plane["+i+"] dist = " + dist); + } + } + } + + /** + * computes the closest point from the given point to a set of planes + * (polytope) + * @param g the point + * @param planes array of bounding planes + * @param new_point point on planes closest g + */ + boolean closest_point( Point3d g, Vector4d[] planes, Point3d new_point ) { + + double t,s,dist,w; + boolean converged, inside, firstPoint, firstInside; + int i,count; + double ab,ac,bc,ad,bd,cd,aa,bb,cc; + double b1,b2,b3,d1,d2,d3,y1,y2,y3; + double h11,h12,h13,h22,h23,h33; + double l12,l13,l23; + Point3d n = new Point3d(); + Point3d p = new Point3d(); + Vector3d delta = null; + + // These are temporary until the solve code is working + + + /* + * The algorithm: + * We want to find the point "n", closest to "g", while still within + * the the polytope defined by "planes". We find the solution by + * minimizing the value for a "penalty function"; + * + * f = distance(n,g)^2 + sum for each i: w(distance(n, planes[i])) + * + * Where "w" is a weighting which indicates how much more important + * it is to be close to the planes than it is to be close to "g". + * + * We minimize this function by taking it's derivitive, and then + * solving for the value of n when the derivitive equals 0. + * + * For the 1D case with a single plane (a,b,c,d), x = n.x and g = g.x, + * this looks like: + * + * f(x) = (x - g) ^ 2 + w(ax + d)^2 + * f'(x) = 2x -2g + 2waax + 2wad + * + * (note aa = a^2) setting f'(x) = 0 gives: + * + * (1 + waa)x = g - wad + * + * Note that the solution is just outside the plane [a, d]. With the + * correct choice of w, this should be inside of the EPSILON tolerance + * outside the planes. + * + * Extending to 3D gives the matrix solution: + * + * | (1 + waa) wab wac | + * H = | wab (1 + wbb) wbc | + * | wac wbc (1 + wcc) | + * + * b = [g.x - wad, g.y - wbd, g.z - wcd] + * + * H * n = b + * + * n = b * H.inverse() + * + * The implementation speeds this process up by recognizing that + * H is symmetric, so that it can be decomposed into three matrices: + * + * H = L * D * L.transpose() + * + * 1.0 0.0 0.0 d1 0.0 0.0 + * L = l12 1.0 0.0 D = 0.0 d2 0.0 + * l13 l23 1.0 0.0 0.0 d3 + * + * n can then be derived by back-substitution, where the original + * problem is decomposed as: + * + * H * n = b + * L * D * L.transpose() * n = b + * L * D * y = b; L.transpose() * n = y + * + * We can then multiply out the terms of L * D and solve for y, and + * then use y to solve for n. + */ + + w=100.0 / EPSILON; // must be large enough to ensure that solution + // is within EPSILON of planes + + count = 0; + p.set(g); + + if (debug) { + System.err.println("closest_point():\nincoming g="+" "+g.x+" "+g.y+ + " "+g.z); + } + + converged = false; + firstPoint = true; + firstInside = false; + + Vector4d pln; + + while( !converged ) { + if (debug) { + System.err.println("start: p="+" "+p.x+" "+p.y+" "+p.z); + } + + // test the current point against the planes, for each + // plane that is violated, add it's contribution to the + // penalty function + inside = true; + aa=0.0; bb=0.0; cc=0.0; + ab=0.0; ac=0.0; bc=0.0; ad=0.0; bd=0.0; cd=0.0; + for(i = 0; i < planes.length; i++){ + pln = planes[i]; + dist = (p.x*pln.x + p.y*pln.y + + p.z*pln.z + pln.w ) ; + // if point is outside or within EPSILON of the boundary, add + // the plane to the penalty matrix. We do this even if the + // point is already inside the polytope to prevent numerical + // instablity in cases where the point is just outside the + // boundary of several planes of the polytope + if (dist > -EPSILON ){ + aa = aa + pln.x * pln.x; + bb = bb + pln.y * pln.y; + cc = cc + pln.z * pln.z; + ab = ab + pln.x * pln.y; + ac = ac + pln.x * pln.z; + bc = bc + pln.y * pln.z; + ad = ad + pln.x * pln.w; + bd = bd + pln.y * pln.w; + cd = cd + pln.z * pln.w; + } + // If the point is inside if dist is <= EPSILON + if (dist > EPSILON ){ + inside = false; + if (debug) { + System.err.println("point outside plane["+i+"]=("+ + pln.x+ ","+pln.y+",\n\t"+pln.z+ + ","+ pln.w+")\ndist = " + dist); + } + } + } + // see if we are done + if (inside) { + if (debug) { + System.err.println("p is inside"); + } + if (firstPoint) { + firstInside = true; + } + new_point.set(p); + converged = true; + } else { // solve for a closer point + firstPoint = false; + + // this is the upper right corner of H, which is all we + // need to do the decomposition since the matrix is symetric + h11 = 1.0 + aa * w; + h12 = ab * w; + h13 = ac * w; + h22 = 1.0 + bb * w; + h23 = bc * w; + h33 = 1.0 + cc * w; + + if (debug) { + System.err.println(" hessin= "); + System.err.println(h11+" "+h12+" "+h13); + System.err.println(" "+h22+" "+h23); + System.err.println(" "+h33); + } + + // these are the constant terms + b1 = g.x - w * ad; + b2 = g.y - w * bd; + b3 = g.z - w * cd; + + if (debug) { + System.err.println(" b1,b2,b3 = "+b1+" "+b2+" " +b3); + } + + // solve, d1, d2, d3 actually 1/dx, which is more useful + d1 = 1/h11; + l12 = d1 * h12; + l13 = d1 * h13; + s = h22-l12*h12; + d2 = 1/s; + t = h23-h12*l13; + l23 = d2 * t; + d3 = 1/(h33 - h13*l13 - t*l23); + + if (debug) { + System.err.println(" l12,l13,l23 "+l12+" "+l13+" "+l23); + System.err.println(" d1,d2,d3 "+ d1+" "+d2+" "+d3); + } + + // we have L and D, now solve for y + y1 = d1 * b1; + y2 = d2 * (b2 - h12*y1); + y3 = d3 * (b3 - h13*y1 - t*y2); + + if (debug) { + System.err.println(" y1,y2,y3 = "+y1+" "+y2+" "+y3); + } + + // we have y, solve for n + n.z = y3; + n.y = (y2 - l23*n.z); + n.x = (y1 - l13*n.z - l12*n.y); + + if (debug) { + System.err.println("new point = " + n.x+" " + n.y+" " + + n.z); + test_point(planes, n); + + if (delta == null) delta = new Vector3d(); + delta.sub(n, p); + delta.normalize(); + System.err.println("p->n direction: " + delta); + Matrix3d hMatrix = new Matrix3d(); + // check using the the javax.vecmath routine + hMatrix.m00 = h11; + hMatrix.m01 = h12; + hMatrix.m02 = h13; + hMatrix.m10 = h12; // h21 = h12 + hMatrix.m11 = h22; + hMatrix.m12 = h23; + hMatrix.m20 = h13; // h31 = h13 + hMatrix.m21 = h23; // h32 = h22 + hMatrix.m22 = h33; + hMatrix.invert(); + Point3d check = new Point3d(b1, b2, b3); + hMatrix.transform(check); + + System.err.println("check point = " + check.x+" " + + check.y+" " + check.z); + } + + // see if we have converged yet + dist = (p.x-n.x)*(p.x-n.x) + (p.y-n.y)*(p.y-n.y) + + (p.z-n.z)*(p.z-n.z); + + if (debug) { + System.err.println("p->n distance =" + dist ); + } + + if( dist < EPSILON) { // close enough + converged = true; + new_point.set(n); + } else { + p.set(n); + count++; + if(count > 4 ){ // watch for cycling between two minimums + new_point.set(n); + converged = true; + } + } + } + } + if (debug) { + System.err.println("returning pnt ("+new_point.x+" "+ + new_point.y+" "+new_point.z+")"); + + if(firstInside) System.err.println("input point inside polytope "); + } + return firstInside; + } + + boolean intersect_ptope_sphere( BoundingPolytope polyTope, + BoundingSphere sphere) { + Point3d p = new Point3d(); + boolean inside; + + + if (debug) { + System.err.println("ptope_sphere intersect sphere ="+sphere); + } + inside = closest_point( sphere.center, polyTope.planes, p ); + if (debug) { + System.err.println("ptope sphere intersect point ="+p); + } + if (!inside){ + // if distance between polytope and sphere center is greater than + // radius then no intersection + if (p.distanceSquared( sphere.center) > + sphere.radius*sphere.radius){ + if (debug) { + System.err.println("ptope_sphere returns false"); + } + return false; + } else { + if (debug) { + System.err.println("ptope_sphere returns true"); + } + return true; + } + } else { + if (debug) { + System.err.println("ptope_sphere returns true"); + } + return true; + } + } + + boolean intersect_ptope_abox( BoundingPolytope polyTope, BoundingBox box) { + Vector4d planes[] = new Vector4d[6]; + + if (debug) { + System.err.println("ptope_abox, box = " + box); + } + planes[0] = new Vector4d( -1.0, 0.0, 0.0, box.lower.x); + planes[1] = new Vector4d( 1.0, 0.0, 0.0,-box.upper.x); + planes[2] = new Vector4d( 0.0,-1.0, 0.0, box.lower.y); + planes[3] = new Vector4d( 0.0, 1.0, 0.0,-box.upper.y); + planes[4] = new Vector4d( 0.0, 0.0,-1.0, box.lower.z); + planes[5] = new Vector4d( 0.0, 0.0, 1.0,-box.upper.z); + + + BoundingPolytope pbox = new BoundingPolytope( planes); + + boolean result = intersect_ptope_ptope( polyTope, pbox ); + if (debug) { + System.err.println("ptope_abox returns " + result); + } + return(result); + } + + + boolean intersect_ptope_ptope( BoundingPolytope poly1, + BoundingPolytope poly2) { + boolean intersect; + Point3d p = new Point3d(); + Point3d g = new Point3d(); + Point3d gnew = new Point3d(); + Point3d pnew = new Point3d(); + + intersect = false; + + p.x = 0.0; + p.y = 0.0; + p.z = 0.0; + + // start from an arbitrary point on poly1 + closest_point( p, poly1.planes, g); + + // get the closest points on each polytope + if (debug) { + System.err.println("ptope_ptope: first g = "+g); + } + intersect = closest_point( g, poly2.planes, p); + + if (intersect) { + return true; + } + + if (debug) { + System.err.println("first p = "+p+"\n"); + } + intersect = closest_point( p, poly1.planes, gnew); + if (debug) { + System.err.println("gnew = "+gnew+" intersect="+intersect); + } + + // loop until the closest points on the two polytopes are not changing + + double prevDist = p.distanceSquared(g); + double dist; + + while( !intersect ) { + + dist = p.distanceSquared(gnew); + + if (dist < prevDist) { + g.set(gnew); + intersect = closest_point( g, poly2.planes, pnew ); + if (debug) { + System.err.println("pnew = "+pnew+" intersect="+intersect); + } + } else { + g.set(gnew); + break; + } + prevDist = dist; + dist = pnew.distanceSquared(g); + + if (dist < prevDist) { + p.set(pnew); + if( !intersect ) { + intersect = closest_point( p, poly1.planes, gnew ); + if (debug) { + System.err.println("gnew = "+gnew+" intersect="+ + intersect); + } + } + } else { + p.set(pnew); + break; + } + prevDist = dist; + } + + if (debug) { + System.err.println("gnew="+" "+gnew.x+" "+gnew.y+" "+gnew.z); + System.err.println("pnew="+" "+pnew.x+" "+pnew.y+" "+pnew.z); + } + return intersect; + } + + + synchronized void setWithLock(Bounds b) { + this.set(b); + } + + synchronized void getWithLock(Bounds b) { + b.set(this); + } + + // Return one of Pick Bounds type define in PickShape + abstract int getPickType(); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BranchGroup.java b/j3d-core/src/classes/share/javax/media/j3d/BranchGroup.java new file mode 100644 index 0000000..6b97205 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BranchGroup.java @@ -0,0 +1,583 @@ +/* + * $RCSfile: BranchGroup.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * The BranchGroup serves as a pointer to the root of a + * scene graph branch; BranchGroup objects are the only objects that + * can be inserted into a Locale's set of objects. A subgraph, rooted + * by a BranchGroup node can be thought of as a compile unit. The + * following things may be done with BranchGroup: + *

    + *
  • A BranchGroup may be compiled by calling its compile method. This causes the + * entire subgraph to be compiled. If any BranchGroup nodes are contained within the + * subgraph, they are compiled as well (along with their descendants).
  • + *

    + *

  • A BranchGroup may be inserted into a virtual universe by attaching it to a + * Locale. The entire subgraph is then said to be live.
  • + *

    + *

  • A BranchGroup that is contained within another subgraph may be reparented or + * detached at run time if the appropriate capabilities are set.
  • + *
+ * Note that that if a BranchGroup is included in another subgraph, as a child of + * some other group node, it may not be attached to a Locale. + */ + +public class BranchGroup extends Group { + + /** + * For BranchGroup nodes, specifies that this BranchGroup allows detaching + * from its parent. + */ + public static final int + ALLOW_DETACH = CapabilityBits.BRANCH_GROUP_ALLOW_DETACH; + + /** + * Constructs and initializes a new BranchGroup node object. + */ + public BranchGroup() { + } + + /** + * Creates the retained mode BranchGroupRetained object that this + * BranchGroup component object will point to. + */ + void createRetained() { + this.retained = new BranchGroupRetained(); + this.retained.setSource(this); + } + + + /** + * Compiles the source BranchGroup associated with this object and + * creates and caches a compiled scene graph. + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @exception RestrictedAccessException if the method is called + * when this object is part of a live scene graph. + */ + public void compile() { + if (isLive()) { + throw new RestrictedAccessException( + J3dI18N.getString("BranchGroup0")); + } + + if (isCompiled() == false) { + // will throw SceneGraphCycleException if there is a cycle + // in the scene graph + checkForCycle(); + + ((BranchGroupRetained)this.retained).compile(); + } + } + + /** + * Detaches this BranchGroup from its parent. + */ + public void detach() { + Group parent; + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_DETACH)) + throw new CapabilityNotSetException(J3dI18N.getString("BranchGroup1")); + + if (((BranchGroupRetained)this.retained).parent != null) { + parent = (Group)((BranchGroupRetained)this.retained).parent.source; + if(!parent.getCapability(Group.ALLOW_CHILDREN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("BranchGroup2")); + } + } + + ((BranchGroupRetained)this.retained).detach(); + } + + + void validateModeFlagAndPickShape(int mode, int flags, PickShape pickShape) { + + if(isLive()==false) { + throw new IllegalStateException(J3dI18N.getString("BranchGroup3")); + } + + if((mode != PickInfo.PICK_BOUNDS) && (mode != PickInfo.PICK_GEOMETRY)) { + + throw new IllegalArgumentException(J3dI18N.getString("BranchGroup4")); + } + + if((pickShape instanceof PickPoint) && (mode == PickInfo.PICK_GEOMETRY)) { + throw new IllegalArgumentException(J3dI18N.getString("BranchGroup5")); + } + + if(((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) && + ((flags & PickInfo.ALL_GEOM_INFO) != 0)) { + throw new IllegalArgumentException(J3dI18N.getString("BranchGroup6")); + } + + if((mode == PickInfo.PICK_BOUNDS) && + (((flags & (PickInfo.CLOSEST_GEOM_INFO | + PickInfo.ALL_GEOM_INFO | + PickInfo.CLOSEST_DISTANCE | + PickInfo.CLOSEST_INTERSECTION_POINT)) != 0))) { + + throw new IllegalArgumentException(J3dI18N.getString("BranchGroup7")); + } + + if((pickShape instanceof PickBounds) && + (((flags & (PickInfo.CLOSEST_GEOM_INFO | + PickInfo.ALL_GEOM_INFO | + PickInfo.CLOSEST_DISTANCE | + PickInfo.CLOSEST_INTERSECTION_POINT)) != 0))) { + + throw new IllegalArgumentException(J3dI18N.getString("BranchGroup8")); + } + + } + + /** + * Returns an array referencing all the items that are pickable below this + * BranchGroup that intersect with PickShape. + * The resultant array is unordered. + * + * @param pickShape the PickShape object + * + * @see SceneGraphPath + * @see Locale#pickAll + * @see PickShape + * @exception IllegalStateException if BranchGroup is not live. + * + */ + public SceneGraphPath[] pickAll( PickShape pickShape ) { + + if(isLive()==false) + throw new IllegalStateException(J3dI18N.getString("BranchGroup3")); + + return ((BranchGroupRetained)this.retained).pickAll(pickShape); + + } + + /** + * Returns an array unsorted references to all the PickInfo objects that are + * pickable below this BranchGroup that intersect with PickShape. + * The accuracy of the pick is set by the pick mode. The mode include : + * PickInfo.PICK_BOUNDS and PickInfo.PICK_GEOMETRY. The amount of information returned + * is specified via a masked variable, flags, indicating which components are + * present in each returned PickInfo object. + * + * @param mode picking mode, one of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * + * @param flags a mask indicating which components are present in each PickInfo object. + * This is specified as one or more individual bits that are bitwise "OR"ed together to + * describe the PickInfo data. The flags include : + *
    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalArgumentException if flags contains both CLOSEST_GEOM_INFO and + * ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is a PickPoint and pick mode + * is set to PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is neither PICK_BOUNDS + * nor PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is PICK_BOUNDS + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is PickBounds + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalStateException if BranchGroup is not live. + * + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are as follows : + *
    + *
  • By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ
  • + *
  • By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ
  • + *
  • Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above)
  • + *
+ * + * @see Locale#pickAll(int,int,javax.media.j3d.PickShape) + * @see PickInfo + * + * @since Java 3D 1.4 + * + */ + + public PickInfo[] pickAll( int mode, int flags, PickShape pickShape ) { + + validateModeFlagAndPickShape(mode, flags, pickShape); + return ((BranchGroupRetained)this.retained).pickAll(mode, flags, pickShape); + + } + + + /** + * Returns a sorted array of references to all the Pickable items that + * intersect with the pickShape. Element [0] references the item closest + * to origin of PickShape successive array elements are further + * from the origin + * + * Note: If pickShape is of type PickBounds, the resulting array + * is unordered. + * @param pickShape the PickShape object + * + * @see SceneGraphPath + * @see Locale#pickAllSorted + * @see PickShape + * @exception IllegalStateException if BranchGroup is not live. + * + */ + public SceneGraphPath[] pickAllSorted( PickShape pickShape ) { + + if(isLive()==false) + throw new IllegalStateException(J3dI18N.getString("BranchGroup3")); + + return ((BranchGroupRetained)this.retained).pickAllSorted(pickShape); + + } + + + /** + * Returns a sorted array of PickInfo references to all the pickable + * items that intersect with the pickShape. Element [0] references + * the item closest to origin of PickShape successive array + * elements are further from the origin + * The accuracy of the pick is set by the pick mode. The mode include : + * PickInfo.PICK_BOUNDS and PickInfo.PICK_GEOMETRY. The amount of information returned + * is specified via a masked variable, flags, indicating which components are + * present in each returned PickInfo object. + * + * @param mode picking mode, one of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * + * @param flags a mask indicating which components are present in each PickInfo object. + * This is specified as one or more individual bits that are bitwise "OR"ed together to + * describe the PickInfo data. The flags include : + *
    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalArgumentException if flags contains both CLOSEST_GEOM_INFO and + * ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is a PickPoint and pick mode + * is set to PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is neither PICK_BOUNDS + * nor PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is PICK_BOUNDS + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is PickBounds + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalStateException if BranchGroup is not live. + * + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are as follows : + *
    + *
  • By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ
  • + *
  • By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ
  • + *
  • Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above)
  • + *
+ * + * @see Locale#pickAllSorted(int,int,javax.media.j3d.PickShape) + * @see PickInfo + * + * @since Java 3D 1.4 + * + */ + public PickInfo[] pickAllSorted( int mode, int flags, PickShape pickShape ) { + + validateModeFlagAndPickShape(mode, flags, pickShape); + return ((BranchGroupRetained)this.retained).pickAllSorted(mode, flags, pickShape); + + } + + /** + * Returns a SceneGraphPath that references the pickable item + * closest to the origin of pickShape. + * + * Note: If pickShape is of type PickBounds, the return is any pickable node + * below this BranchGroup. + * @param pickShape the PickShape object + * + * @see SceneGraphPath + * @see Locale#pickClosest + * @see PickShape + * @exception IllegalStateException if BranchGroup is not live. + * + */ + public SceneGraphPath pickClosest( PickShape pickShape ) { + + if(isLive()==false) + throw new IllegalStateException(J3dI18N.getString("BranchGroup3")); + + return ((BranchGroupRetained)this.retained).pickClosest(pickShape); + + } + + /** + * Returns a PickInfo which references the pickable item + * which is closest to the origin of pickShape. + * The accuracy of the pick is set by the pick mode. The mode include : + * PickInfo.PICK_BOUNDS and PickInfo.PICK_GEOMETRY. The amount of information returned + * is specified via a masked variable, flags, indicating which components are + * present in each returned PickInfo object. + * + * @param mode picking mode, one of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * + * @param flags a mask indicating which components are present in each PickInfo object. + * This is specified as one or more individual bits that are bitwise "OR"ed together to + * describe the PickInfo data. The flags include : + *
    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalArgumentException if flags contains both CLOSEST_GEOM_INFO and + * ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is a PickPoint and pick mode + * is set to PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is neither PICK_BOUNDS + * nor PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is PICK_BOUNDS + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is PickBounds + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalStateException if BranchGroup is not live. + * + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are as follows : + *
    + *
  • By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ
  • + *
  • By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ
  • + *
  • Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above)
  • + *
+ * + * @see Locale#pickClosest(int,int,javax.media.j3d.PickShape) + * @see PickInfo + * + * @since Java 3D 1.4 + * + */ + public PickInfo pickClosest( int mode, int flags, PickShape pickShape ) { + + validateModeFlagAndPickShape(mode, flags, pickShape); + return ((BranchGroupRetained)this.retained).pickClosest(mode, flags, pickShape); + + } + + + /** + * Returns a reference to any item that is Pickable below this BranchGroup that + * intersects with pickShape. + * @param pickShape the PickShape object + * + * @see SceneGraphPath + * @see Locale#pickAny + * @see PickShape + * @exception IllegalStateException if BranchGroup is not live. + * + */ + public SceneGraphPath pickAny( PickShape pickShape ) { + + if(isLive()==false) + throw new IllegalStateException(J3dI18N.getString("BranchGroup3")); + + return ((BranchGroupRetained)this.retained).pickAny(pickShape); + + } + + /** + * Returns a PickInfo which references the pickable item below this + * BranchGroup that intersects with pickShape. + * The accuracy of the pick is set by the pick mode. The mode include : + * PickInfo.PICK_BOUNDS and PickInfo.PICK_GEOMETRY. The amount of information returned + * is specified via a masked variable, flags, indicating which components are + * present in each returned PickInfo object. + * + * @param mode picking mode, one of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * + * @param flags a mask indicating which components are present in each PickInfo object. + * This is specified as one or more individual bits that are bitwise "OR"ed together to + * describe the PickInfo data. The flags include : + *
    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalArgumentException if flags contains both CLOSEST_GEOM_INFO and + * ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is a PickPoint and pick mode + * is set to PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is neither PICK_BOUNDS + * nor PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is PICK_BOUNDS + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is PickBounds + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalStateException if BranchGroup is not live. + * + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are as follows : + *
    + *
  • By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ
  • + *
  • By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ
  • + *
  • Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above)
  • + *
+ * + * @see Locale#pickAny(int,int,javax.media.j3d.PickShape) + * @see PickInfo + * + * @since Java 3D 1.4 + * + */ + public PickInfo pickAny( int mode, int flags, PickShape pickShape ) { + + validateModeFlagAndPickShape(mode, flags, pickShape); + return ((BranchGroupRetained)this.retained).pickAny(mode, flags, pickShape); + + } + + /** + * Creates a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + + BranchGroup bg = new BranchGroup(); + bg.duplicateNode(this, forceDuplicate); + return bg; + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/BranchGroupRetained.java b/j3d-core/src/classes/share/javax/media/j3d/BranchGroupRetained.java new file mode 100644 index 0000000..ebe55eb --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/BranchGroupRetained.java @@ -0,0 +1,378 @@ +/* + * $RCSfile: BranchGroupRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * The BranchGroup node provides the ability to insert a branch of + * a scene graph into the virtual world. + */ + +class BranchGroupRetained extends GroupRetained { + + // This boolean is used in a moveTo operation to get transforms to update + boolean isDirty = false; + + // This boolean is used when the BG is inserted into the scene + boolean isNew = false; + + /** + * True, if this branchGroup is directly attached to the locale + */ + boolean attachedToLocale = false; + + + BranchGroupRetained() { + this.nodeType = NodeRetained.BRANCHGROUP; + } + + /** + * This sets the current locale. + */ + void setLocale(Locale loc) { + locale = loc; + } + + /** + * This gets the current locale + */ + Locale getLocale() { + return locale; + } + + /** + * Detaches this BranchGroup from its parent. + */ + void detach() { + dirtyBoundsCache(); + if (universe != null) { + universe.resetWaitMCFlag(); + synchronized (universe.sceneGraphLock) { + boolean isLive = source.isLive(); + if (isLive) { + notifySceneGraphChanged(true); + } + GroupRetained oldParent = (GroupRetained)parent; + do_detach(); + universe.setLiveState.clear(); + if (isLive) { + if (oldParent==null) { + universe.notifyStructureChangeListeners(false,locale,(BranchGroup)this.source); + } else { + universe.notifyStructureChangeListeners(false,oldParent.source, (BranchGroup)this.source); + } + } + } + universe.waitForMC(); + } else { // Not live yet, just do it. + this.do_detach(); + if (universe != null) { + synchronized (universe.sceneGraphLock) { + universe.setLiveState.clear(); + } + } + } + } + + // The method that does the work once the lock is acquired. + void do_detach() { + if (attachedToLocale) { + locale.doRemoveBranchGraph((BranchGroup)this.source, null, 0); + } else if (parent != null) { + GroupRetained g = (GroupRetained)parent; + g.doRemoveChild(g.children.indexOf(this), null, 0); + } + } + + void setNodeData(SetLiveState s) { + // super.setNodeData will set branchGroupPaths + // based on s.parentBranchGroupPaths, we need to + // set it earlier in order to undo the effect. + s.parentBranchGroupPaths = branchGroupPaths; + + super.setNodeData(s); + + if (!inSharedGroup) { + setAuxData(s, 0, 0); + } else { + // For inSharedGroup case. + int j, hkIndex; + for(j=0; j= 0) { + setAuxData(s, j, hkIndex); + + } else { + // XXXX: change this to an assertion exception + MasterControl.getCoreLogger().severe("Can't Find matching hashKey in setNodeData."); + } + } + } + } + + + void setAuxData(SetLiveState s, int index, int hkIndex) { + super.setAuxData(s, index, hkIndex); + + BranchGroupRetained path[] = (BranchGroupRetained[]) + s.branchGroupPaths.get(index); + BranchGroupRetained clonePath[] = + new BranchGroupRetained[path.length+1]; + System.arraycopy(path, 0, clonePath, 0, path.length); + clonePath[path.length] = this; + s.branchGroupPaths.set(index, clonePath); + branchGroupPaths.add(hkIndex, clonePath); + } + + + /** + * remove the localToVworld transform for this node. + */ + void removeNodeData(SetLiveState s) { + + if((!inSharedGroup) || (s.keys.length == localToVworld.length)) { + // restore to default and avoid calling clear() + // that may clear parent reference branchGroupPaths + branchGroupPaths = new ArrayList(1); + } + else { + int i, index; + // Must be in reverse, to preserve right indexing. + for (i = s.keys.length-1; i >= 0; i--) { + index = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length); + if(index >= 0) { + branchGroupPaths.remove(index); + } + } + // Set it back to its parent localToVworld data. This is b/c the parent has + // changed it localToVworld data arrays. + } + super.removeNodeData(s); + } + + void setLive(SetLiveState s) { + // recursively call child + super.doSetLive(s); + super.markAsLive(); + } + + + // Top level compile call + void compile() { + + if (source.isCompiled() || VirtualUniverse.mc.disableCompile) + return; + + if (J3dDebug.devPhase && J3dDebug.debug) { + J3dDebug.doDebug(J3dDebug.compileState, J3dDebug.LEVEL_3, + "BranchGroupRetained.compile()....\n"); + } + + CompileState compState = new CompileState(); + + isRoot = true; + + compile(compState); + merge(compState); + + if (J3dDebug.devPhase && J3dDebug.debug) { + if (J3dDebug.doDebug(J3dDebug.compileState, J3dDebug.LEVEL_3)) { + compState.printStats(); + } + if (J3dDebug.doDebug(J3dDebug.compileState, J3dDebug.LEVEL_5)) { + this.traverse(false, 1); + System.err.println(); + } + } + } + + void compile(CompileState compState) { + // if this branch group is previously compiled, don't + // go any further. Mark the keepTG flag for now. Static + // transform doesn't go beyond previously compiled group. + + if (mergeFlag == SceneGraphObjectRetained.MERGE_DONE) { + compState.keepTG = true; + return; + } + + super.compile(compState); + + // don't remove this node because user can do pickAll on this node + // without any capabilities set + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + } + + SceneGraphPath[] pickAll(PickShape pickShape) { + + PickInfo[] pickInfoArr = pickAll(PickInfo.PICK_BOUNDS, + PickInfo.SCENEGRAPHPATH, pickShape); + + if(pickInfoArr == null) { + return null; + } + + SceneGraphPath[] sgpArr = new SceneGraphPath[pickInfoArr.length]; + for( int i=0; i upper.x) upper.x = verts[i].x; // xmax + if( verts[i].x < lower.x) lower.x = verts[i].x; // xmin + + if( verts[i].y > upper.y) upper.y = verts[i].y; // ymay + if( verts[i].y < lower.y) lower.y = verts[i].y; // ymin + + if( verts[i].z > upper.z) upper.z = verts[i].z; // zmaz + if( verts[i].z < lower.z) lower.z = verts[i].z; // zmin + + center.x += verts[i].x; + center.y += verts[i].y; + center.z += verts[i].z; + } + + center.x = center.x*0.125; + center.y = center.y*0.125; + center.z = center.z*0.125; + + } + + private void computeVertex( int a, int b, int c, Point3d vert) { + double det,x,y,z; + + det = clipPlanes[a].x*clipPlanes[b].y*clipPlanes[c].z + clipPlanes[a].y*clipPlanes[b].z*clipPlanes[c].x + + clipPlanes[a].z*clipPlanes[b].x*clipPlanes[c].y - clipPlanes[a].z*clipPlanes[b].y*clipPlanes[c].x - + clipPlanes[a].y*clipPlanes[b].x*clipPlanes[c].z - clipPlanes[a].x*clipPlanes[b].z*clipPlanes[c].y; + + + if( det*det < EPSILON ){ + // System.err.println("************** Two planes are parallel : det = " + det); + return; // two planes are parallel + } + + det = 1.0/det; + + vert.x = (clipPlanes[b].y*clipPlanes[c].z - clipPlanes[b].z*clipPlanes[c].y) * -clipPlanes[a].w; + vert.y = (clipPlanes[b].z*clipPlanes[c].x - clipPlanes[b].x*clipPlanes[c].z) * -clipPlanes[a].w; + vert.z = (clipPlanes[b].x*clipPlanes[c].y - clipPlanes[b].y*clipPlanes[c].x) * -clipPlanes[a].w; + + vert.x += (clipPlanes[c].y*clipPlanes[a].z - clipPlanes[c].z*clipPlanes[a].y) * -clipPlanes[b].w; + vert.y += (clipPlanes[c].z*clipPlanes[a].x - clipPlanes[c].x*clipPlanes[a].z) * -clipPlanes[b].w; + vert.z += (clipPlanes[c].x*clipPlanes[a].y - clipPlanes[c].y*clipPlanes[a].x) * -clipPlanes[b].w; + + vert.x += (clipPlanes[a].y*clipPlanes[b].z - clipPlanes[a].z*clipPlanes[b].y) * -clipPlanes[c].w; + vert.y += (clipPlanes[a].z*clipPlanes[b].x - clipPlanes[a].x*clipPlanes[b].z) * -clipPlanes[c].w; + vert.z += (clipPlanes[a].x*clipPlanes[b].y - clipPlanes[a].y*clipPlanes[b].x) * -clipPlanes[c].w; + + vert.x = vert.x*det; + vert.y = vert.y*det; + vert.z = vert.z*det; + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CachedTargets.java b/j3d-core/src/classes/share/javax/media/j3d/CachedTargets.java new file mode 100644 index 0000000..cfa31a7 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CachedTargets.java @@ -0,0 +1,128 @@ +/* + * $RCSfile: CachedTargets.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class CachedTargets { + // cached targets, used by J3d threads + + // 0 - Data type is GeometryAtom. + // 1 - Data type is Light, Fog, Background, ModelClip, AlternateAppearance, + // Clip + // 2 - Data type is BehaviorRetained. + // 3 - Data type is Sound or Soundscape + // 4 - Data type is ViewPlatformRetained. + // 5 - Data type is BoundingLeafRetained. + // 6 - Data type is GroupRetained. + + // Order of index is as above. + // The handling of BoundingLeaf isn't optimize. Target threads should be + // more specific. + + static String typeString[] = { + "GEO_TARGETS", + "ENV_TARGETS", + "BEH_TARGETS", + "SND_TARGETS", + "VPF_TARGETS", + "BLN_TARGETS", + "GRP_TARGETS", + }; + + static int updateTargetThreads[] = { + // GEO + J3dThread.UPDATE_TRANSFORM | J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_GEOMETRY, + + // ENV + J3dThread.UPDATE_RENDER | J3dThread.UPDATE_RENDERING_ENVIRONMENT, + + // BEH + J3dThread.UPDATE_BEHAVIOR, + + // SND + J3dThread.UPDATE_SOUND | J3dThread.SOUND_SCHEDULER, + + // VPF + J3dThread.UPDATE_RENDER | J3dThread.UPDATE_BEHAVIOR | + J3dThread.UPDATE_SOUND | J3dThread.SOUND_SCHEDULER, + + // BLN + J3dThread.UPDATE_RENDER | J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_BEHAVIOR | J3dThread.UPDATE_SOUND, + + // GRP + J3dThread.UPDATE_TRANSFORM | J3dThread.UPDATE_GEOMETRY + }; + + + NnuId targetArr[][] = new NnuId[Targets.MAX_NODELIST][]; + + int computeTargetThreads() { + int targetThreads = 0; + + for (int i=0; i < Targets.MAX_NODELIST; i++) { + if (targetArr[i] != null) { + targetThreads |= updateTargetThreads[i]; + } + } + return targetThreads; + } + + void copy( CachedTargets ct ) { + + for(int i=0; i + * The Canvas3D object extends the Canvas object to include + * 3D-related information such as the size of the canvas in pixels, + * the Canvas3D's location, also in pixels, within a Screen3D object, + * and whether or not the canvas has stereo enabled. + *

+ * Because all Canvas3D objects contain a + * reference to a Screen3D object and because Screen3D objects define + * the size of a pixel in physical units, Java 3D can convert a Canvas3D + * size in pixels to a physical world size in meters. It can also + * determine the Canvas3D's position and orientation in the + * physical world. + *

+ * On-screen Rendering vs. Off-screen Rendering + *

+ * The Canvas3D class is used either for on-screen rendering or + * off-screen rendering. + * On-screen Canvas3Ds are added to AWT or Swing Container objects + * like any other canvas. Java 3D automatically and continuously + * renders to all on-screen canvases that are attached to an active + * View object. On-screen Canvas3Ds can be either single or double + * buffered and they can be either stereo or monoscopic. + *

+ * Off-screen Canvas3Ds must not be added to any Container. Java 3D + * renders to off-screen canvases in response to the + * renderOffScreenBuffer method. Off-screen Canvas3Ds + * are single buffered. However, on many systems, the actual + * rendering is done to an off-screen hardware buffer or to a 3D + * library-specific buffer and only copied to the off-screen buffer of + * the Canvas when the rendering is complete, at "buffer swap" time. + * Off-screen Canvas3Ds are monoscopic. + *

+ * The setOffScreenBuffer method sets the off-screen buffer for this + * Canvas3D. The specified image is written into by the Java 3D renderer. + * The size of the specified ImageComponent determines the size, in + * pixels, of this Canvas3D - the size inherited from Component is + * ignored. Note that the size, physical width, and physical height of the + * associated Screen3D must be set + * explicitly prior to rendering. Failure to do so will result in an + * exception. + *

+ * The getOffScreenBuffer method retrieves the off-screen + * buffer for this Canvas3D. + *

+ * The renderOffScreenBuffer method schedules the rendering of a frame + * into this Canvas3D's off-screen buffer. The rendering is done from + * the point of view of the View object to which this Canvas3D has been + * added. No rendering is performed if this Canvas3D object has not been + * added to an active View. This method does not wait for the rendering + * to actually happen. An application that wishes to know when the + * rendering is complete must either subclass Canvas3D and + * override the postSwap method, or call waitForOffScreenRendering. + *

+ * The setOfScreenLocation methods set the location of this off-screen + * Canvas3D. The location is the upper-left corner of the Canvas3D + * relative to the upper-left corner of the corresponding off-screen + * Screen3D. The function of these methods is similar to that of + * Component.setLocation for on-screen Canvas3D objects. The default + * location is (0,0). + *

+ * Accessing and Modifying an Eye's Image Plate Position + *

+ * A Canvas3D object provides sophisticated applications with access + * to the eye's position information in head-tracked, room-mounted + * runtime environments. It also allows applications to manipulate + * the position of an eye relative to an image plate in non-head-tracked + * runtime environments. + *

+ * The setLeftManualEyeInImagePlate and setRightManualEyeInImagePlate + * methods set the position of the manual left and right eyes in image + * plate coordinates. These values determine eye placement when a head + * tracker is not in use and the application is directly controlling the + * eye position in image plate coordinates. In head-tracked mode or + * when the windowEyepointPolicy is RELATIVE_TO_FIELD_OF_VIEW or + * RELATIVE_TO_COEXISTENCE, this + * value is ignored. When the windowEyepointPolicy is RELATIVE_TO_WINDOW, + * only the Z value is used. + *

+ * The getLeftEyeInImagePlate, getRightEyeInImagePlate, and + * getCenterEyeInImagePlate methods retrieve the actual position of the + * left eye, right eye, and center eye in image plate coordinates and + * copy that value into the object provided. The center eye is the + * fictional eye half-way between the left and right eye. These three + * values are a function of the windowEyepointPolicy, the tracking + * enable flag, and the manual left, right, and center eye positions. + *

+ * Monoscopic View Policy + *

+ * The setMonoscopicViewPolicy and getMonoscopicViewPolicy methods + * set and retrieve the policy regarding how Java 3D generates monoscopic + * view. If the policy is set to View.LEFT_EYE_VIEW, the view generated + * corresponds to the view as seen from the left eye. If set to + * View.RIGHT_EYE_VIEW, the view generated corresponds to the view as + * seen from the right eye. If set to View.CYCLOPEAN_EYE_VIEW, the view + * generated corresponds to the view as seen from the "center eye," the + * fictional eye half-way between the left and right eye. The default + * monoscopic view policy is View.CYCLOPEAN_EYE_VIEW. + *

+ * Immediate Mode Rendering + *

+ * Pure immediate-mode rendering provides for those applications and + * applets that do not want Java 3D to do any automatic rendering of + * the scene graph. Such applications may not even wish to build a + * scene graph to represent their graphical data. However, they use + * Java 3D's attribute objects to set graphics state and Java 3D's + * geometric objects to render geometry. + *

+ * A pure immediate mode application must create a minimal set of + * Java 3D objects before rendering. In addition to a Canvas3D object, + * the application must create a View object, with its associated + * PhysicalBody and PhysicalEnvironment objects, and the following + * scene graph elements: a VirtualUniverse object, a high-resolution + * Locale object, a BranchGroup node object, a TransformGroup node + * object with associated transform, and a ViewPlatform + * leaf node object that defines the position and orientation within + * the virtual universe that generates the view. + *

+ * In immediate mode, all rendering is done completely under user + * control. It is necessary for the user to clear the 3D canvas, + * render all geometry, and swap the buffers. Additionally, + * rendering the right and left eye for stereo viewing becomes the + * sole responsibility of the application. In pure immediate mode, + * the user must stop the Java 3D renderer, via the + * Canvas3D object stopRenderer method, prior to adding the + * Canvas3D object to an active View object (that is, one that is + * attached to a live ViewPlatform object). + *

+ * Other Canvas3D methods related to immediate mode rendering are: + *

+ *

    + * getGraphicsContext3D retrieves the immediate-mode + * 3D graphics context associated with this Canvas3D. It creates a + * new graphics context if one does not already exist. + *

    + * getGraphics2D retrieves the + * 2D graphics object associated with this Canvas3D. It creates a + * new 2D graphics object if one does not already exist. + *

    + * swap synchronizes and swaps buffers on a + * double-buffered canvas for this Canvas3D object. This method + * should only be called if the Java 3D renderer has been stopped. + * In the normal case, the renderer automatically swaps + * the buffer. + *

+ * + *

+ * Mixed Mode Rendering + *

+ * Mixing immediate mode and retained or compiled-retained mode + * requires more structure than pure immediate mode. In mixed mode, + * the Java 3D renderer is running continuously, rendering the scene + * graph into the canvas. + * + *

+ * Canvas3D methods related to mixed mode rendering are: + * + *

+ *

    + * preRender called by the Java 3D rendering loop after + * clearing the canvas and before any rendering has been done for + * this frame. + *

    + * postRender called by the Java 3D rendering loop after + * completing all rendering to the canvas for this frame and before + * the buffer swap. + *

    + * postSwap called by the Java 3D rendering loop after + * completing all rendering to the canvas, and all other canvases + * associated with this view, for this frame following the + * buffer swap. + *

    + * renderField called by the Java 3D rendering loop + * during the execution of the rendering loop. It is called once + * for each field (i.e., once per frame on a mono system or once + * each for the right eye and left eye on a two-pass stereo system. + *

+ *

+ * The above callback methods are called by the Java 3D rendering system + * and should not be called by an application directly. + * + *

+ * The basic Java 3D stereo rendering loop, + * executed for each Canvas3D, is as follows: + *

    + * clear canvas (both eyes)
    + * call preRender()                           // user-supplied method
    + * set left eye view
    + * render opaque scene graph objects
    + * call renderField(FIELD_LEFT)               // user-supplied method
    + * render transparent scene graph objects
    + * set right eye view
    + * render opaque scene graph objects again
    + * call renderField(FIELD_RIGHT)              // user-supplied method
    + * render transparent scene graph objects again
    + * call postRender()                          // user-supplied method
    + * synchronize and swap buffers
    + * call postSwap()                            // user-supplied method
    + * 
+ *

+ * The basic Java 3D monoscopic rendering loop is as follows: + *

    + * clear canvas
    + * call preRender()                            // user-supplied method
    + * set view
    + * render opaque scene graph objects
    + * call renderField(FIELD_ALL)                 // user-supplied method
    + * render transparent scene graph objects
    + * call postRender()                           // user-supplied method
    + * synchronize and swap buffers
    + * call postSwap()                             // user-supplied method
    + * 
+ *

+ * In both cases, the entire loop, beginning with clearing the canvas + * and ending with swapping the buffers, defines a frame. The application + * is given the opportunity to render immediate-mode geometry at any of + * the clearly identified spots in the rendering loop. A user specifies + * his or her own rendering methods by extending the Canvas3D class and + * overriding the preRender, postRender, postSwap, and/or renderField + * methods. + * Updates to live Geometry, Texture, and ImageComponent objects + * in the scene graph are not allowed from any of these callback + * methods. + * + *

+ * Serialization + *

+ * Canvas3D does not support serialization. An attempt to + * serialize a Canvas3D object will result in an + * UnsupportedOperationException being thrown. + * + *

+ * Additional Information + *

+ * For more information, see the + * Introduction to the Java 3D API and + * View Model + * documents. + * + * @see Screen3D + * @see View + * @see GraphicsContext3D + */ +public class Canvas3D extends Canvas { + /** + * Specifies the left field of a field-sequential stereo rendering loop. + * A left field always precedes a right field. + */ + public static final int FIELD_LEFT = 0; + + /** + * Specifies the right field of a field-sequential stereo rendering loop. + * A right field always follows a left field. + */ + public static final int FIELD_RIGHT = 1; + + /** + * Specifies a single-field rendering loop. + */ + public static final int FIELD_ALL = 2; + + // + // The following constants are bit masks to specify which of the node + // components are dirty and need updates. + // + // Values for the geometryType field. + static final int POLYGONATTRS_DIRTY = 0x01; + static final int LINEATTRS_DIRTY = 0x02; + static final int POINTATTRS_DIRTY = 0x04; + static final int MATERIAL_DIRTY = 0x08; + static final int TRANSPARENCYATTRS_DIRTY = 0x10; + static final int COLORINGATTRS_DIRTY = 0x20; + + // Values for lightbin, env set, texture, texture setting etc. + static final int LIGHTBIN_DIRTY = 0x40; + static final int LIGHTENABLES_DIRTY = 0x80; + static final int AMBIENTLIGHT_DIRTY = 0x100; + static final int ATTRIBUTEBIN_DIRTY = 0x200; + static final int TEXTUREBIN_DIRTY = 0x400; + static final int TEXTUREATTRIBUTES_DIRTY = 0x800; + static final int RENDERMOLECULE_DIRTY = 0x1000; + static final int FOG_DIRTY = 0x2000; + static final int MODELCLIP_DIRTY = 0x4000; + static final int VIEW_MATRIX_DIRTY = 0x8000; + // static final int SHADER_DIRTY = 0x10000; Not ready for this yet -- JADA + + // Use to notify D3D Canvas when window change + static final int RESIZE = 1; + static final int TOGGLEFULLSCREEN = 2; + static final int NOCHANGE = 0; + static final int RESETSURFACE = 1; + static final int RECREATEDDRAW = 2; + + // + // Flag that indicates whether this Canvas3D is an off-screen Canvas3D + // + boolean offScreen = false; + + // + // Issue 131: Flag that indicates whether this Canvas3D is a manually + // rendered Canvas3D (versus an automatically rendered Canvas3D). + // + // NOTE: manualRendering only applies to off-screen Canvas3Ds at this time. + // We have no plans to ever change this, but if we do, it might be necessary + // to determine which, if any, of the uses of "manualRendering" should be + // changed to "manualRendering&&offScreen" + // + boolean manualRendering = false; + + // user specified offScreen Canvas location + Point offScreenCanvasLoc; + + // user specified offScreen Canvas dimension + Dimension offScreenCanvasSize; + + // + // Flag that indicates whether off-screen rendering is in progress or not + // + volatile boolean offScreenRendering = false; + + // + // Flag that indicates we are waiting for an off-screen buffer to be + // created or destroyed by the Renderer. + // + volatile boolean offScreenBufferPending = false; + + // + // ImageComponent used for off-screen rendering + // + ImageComponent2D offScreenBuffer = null; + + // flag that indicates whether this canvas will use shared context + boolean useSharedCtx = true; + + // + // Read-only flag that indicates whether stereo is supported for this + // canvas. This is always false for off-screen canvases. + // + boolean stereoAvailable; + + // + // Flag to enable stereo rendering, if allowed by the + // stereoAvailable flag. + // + boolean stereoEnable = true; + + // + // This flag is set when stereo mode is both enabled and + // available. Code that looks at stereo mode should use this + // flag. + // + boolean useStereo; + + // Indicate whether it is left or right stereo pass currently + boolean rightStereoPass = false; + + // + // Specifies how Java 3D generates monoscopic view + // (LEFT_EYE_VIEW, RIGHT_EYE_VIEW, or CYCLOPEAN_EYE_VIEW). + // + int monoscopicViewPolicy = View.CYCLOPEAN_EYE_VIEW; + + // User requested stencil size + int requestedStencilSize; + + // Actual stencil size return for this canvas + int actualStencilSize; + + // True if stencil buffer is available for user + boolean userStencilAvailable; + + // True if stencil buffer is available for system ( decal ) + boolean systemStencilAvailable; + + // + // Read-only flag that indicates whether double buffering is supported + // for this canvas. This is always false for off-screen canvases. + // + boolean doubleBufferAvailable; + + // + // Flag to enable double buffered rendering, if allowed by the + // doubleBufferAvailable flag. + // + boolean doubleBufferEnable = true; + + // + // This flag is set when doubleBuffering is both enabled and + // available Code that enables or disables double buffering should + // use this flag. + // + boolean useDoubleBuffer; + + // + // Read-only flag that indicates whether scene antialiasing + // is supported for this canvas. + // + boolean sceneAntialiasingAvailable; + boolean sceneAntialiasingMultiSamplesAvailable; + + // Use to see whether antialiasing is already set + boolean antialiasingSet = false; + + // + // Read-only flag that indicates the size of the texture color + // table for this canvas. A value of 0 indicates that the texture + // color table is not supported. + // + int textureColorTableSize; + + // number of active/enabled texture unit + int numActiveTexUnit = 0; + + // index iof last enabled texture unit + int lastActiveTexUnit = -1; + + // True if shadingLanguage is supported, otherwise false. + boolean shadingLanguageGLSL = false; + boolean shadingLanguageCg = false; + + // Query properties + J3dQueryProps queryProps; + + // Flag indicating a fatal rendering error of some sort + private boolean fatalError = false; + + // + // The positions of the manual left and right eyes in image-plate + // coordinates. + // By default, we will use the center of the screen for X and Y values + // (X values are adjusted for default eye separation), and + // 0.4572 meters (18 inches) for the Z value. + // These match defaults elsewhere in the system. + // + Point3d leftManualEyeInImagePlate = new Point3d(0.142, 0.135, 0.4572); + Point3d rightManualEyeInImagePlate = new Point3d(0.208, 0.135, 0.4572); + + // + // View that is attached to this Canvas3D. + // + View view = null; + + // View waiting to be set + View pendingView; + + // + // View cache for this canvas and its associated view. + // + CanvasViewCache canvasViewCache = null; + + // Issue 109: View cache for this canvas, for computing view frustum planes + CanvasViewCache canvasViewCacheFrustum = null; + + // Since multiple renderAtomListInfo, share the same vecBounds + // we want to do the intersection test only once per renderAtom + // this flag is set to true after the first intersect and set to + // false during checkForCompaction in renderBin + boolean raIsVisible = false; + + RenderAtom ra = null; + + // Stereo related field has changed. + static final int STEREO_DIRTY = 0x01; + // MonoscopicViewPolicy field has changed. + static final int MONOSCOPIC_VIEW_POLICY_DIRTY = 0x02; + // Left/right eye in image plate field has changed. + static final int EYE_IN_IMAGE_PLATE_DIRTY = 0x04; + // Canvas has moved/resized. + static final int MOVED_OR_RESIZED_DIRTY = 0x08; + + // Canvas Background changed (this may affect doInfinite flag) + static final int BACKGROUND_DIRTY = 0x10; + + // Canvas Background Image changed + static final int BACKGROUND_IMAGE_DIRTY = 0x20; + + + // Mask that indicates this Canvas view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + static final int VIEW_INFO_DIRTY = (STEREO_DIRTY | + MONOSCOPIC_VIEW_POLICY_DIRTY | + EYE_IN_IMAGE_PLATE_DIRTY | + MOVED_OR_RESIZED_DIRTY | + BACKGROUND_DIRTY | + BACKGROUND_IMAGE_DIRTY); + + // Issue 163: Array of dirty bits is used because the Renderer and + // RenderBin run asynchronously. Now that they each have a separate + // instance of CanvasViewCache (due to the fix for Issue 109), they + // need separate dirty bits. Array element 0 is used for the Renderer and + // element 1 is used for the RenderBin. + static final int RENDERER_DIRTY_IDX = 0; + static final int RENDER_BIN_DIRTY_IDX = 1; + int[] cvDirtyMask = new int[2]; + + // This boolean informs the J3DGraphics2DImpl that the window is resized + boolean resizeGraphics2D = true; + // + // This boolean allows an application to start and stop the render + // loop on this canvas. + // + volatile boolean isRunning = true; + + // This is used by MasterControl only. MC relay on this in a + // single loop to set renderer thread. During this time, + // the isRunningStatus can't change by user thread. + volatile boolean isRunningStatus = true; + + // This is true when the canvas is ready to be rendered into + boolean active = false; + + // This is true when the canvas is visible + boolean visible = false; + + // This is true if context need to recreate + boolean ctxReset = true; + + // The Screen3D that corresponds to this Canvas3D + Screen3D screen = null; + + // Flag to indicate that image is render completely + // so swap is valid. + boolean imageReady = false; + + + // + // The current fog enable state + // + int fogOn = 0; + + // The 3D Graphics context used for immediate mode rendering + // into this canvas. + GraphicsContext3D graphicsContext3D = null; + boolean waiting = false; + boolean swapDone = false; + + GraphicsConfiguration graphicsConfiguration; + + // The Java 3D Graphics2D object used for Java2D/AWT rendering + // into this Canvas3D + J3DGraphics2DImpl graphics2D = null; + + // Lock used to synchronize the creation of the 2D and 3D + // graphics context objects + Object gfxCreationLock = new Object(); + + // The source of the currently loaded localToVWorld for this Canvas3D + // (used to only update the model matrix when it changes) + // Transform3D localToVWorldSrc = null; + + // The current vworldToEc Transform + Transform3D vworldToEc = new Transform3D(); + + // The view transform (VPC to EC) for the current eye. + // NOTE that this is *read-only* + Transform3D vpcToEc; + + // Opaque object representing the underlying drawable (window). This + // is defined by the Pipeline. + Drawable drawable = null; + + // fbConfig is a pointer to the fbConfig object that is associated with + // the GraphicsConfiguration object used to create this Canvas. + // + // For Unix : Fix for issue 20. + // The fbConfig is only used when running X11. It contains a pointer + // to the native GLXFBConfig structure list, since in some cases the visual id + // alone isn't sufficient for the native OpenGL renderer (e.g., when using + // Solaris OpenGL with Xinerama mode disabled). + // + // For Windows : Fix for issue 76. This is use as a holder of the + // PixelFormat structure ( see also gldef.h ) to allow value such + // as offScreen's pixelformat, and ARB function pointers to be stored. + long fbConfig = 0; + + // offScreenBufferInfo is a pointer to additional information about the + // offScreenBuffer in this Canvas. + // + // For Windows : Fix for issue 76. + long offScreenBufferInfo = 0; + + // graphicsConfigTable is a static hashtable which allows getBestConfiguration() + // in NativeConfigTemplate3D to map a GraphicsConfiguration to the pointer + // to the actual GLXFBConfig that glXChooseFBConfig() returns. The Canvas3D + // doesn't exist at the time getBestConfiguration() is called, and + // X11GraphicsConfig neither maintains this pointer nor provides a public + // constructor to allow Java 3D to extend it. + static Hashtable graphicsConfigTable = + new Hashtable(); + + // The native graphics version, vendor, and renderer information + String nativeGraphicsVersion = ""; + String nativeGraphicsVendor = ""; + String nativeGraphicsRenderer = ""; + + boolean firstPaintCalled = false; + + // This reflects whether or not this canvas has seen an addNotify. It is + // forced to true for off-screen canvases + boolean added = false; + + // Flag indicating whether addNotify has been called (so we don't process it twice). + private boolean addNotifyCalled = false; + + // This is the id for the underlying graphics context structure. + Context ctx = null; + + // since the ctx id can be the same as the previous one, + // we need to keep a time stamp to differentiate the contexts with the + // same id + volatile long ctxTimeStamp = 0; + + // The current context setting for local eye lighting + boolean ctxEyeLightingEnable = false; + + // This AppearanceRetained Object refelects the current state of this + // canvas. It is used to optimize setting of attributes at render time. + AppearanceRetained currentAppear = new AppearanceRetained(); + + // This MaterialRetained Object refelects the current state of this canvas. + // It is used to optimize setting of attributes at render time. + MaterialRetained currentMaterial = new MaterialRetained(); + + /** + * The object used for View Frustum Culling + */ + CachedFrustum viewFrustum = new CachedFrustum(); + + /** + * The RenderBin bundle references used to decide what the underlying + * context contains. + */ + LightBin lightBin = null; + EnvironmentSet environmentSet = null; + AttributeBin attributeBin = null; + ShaderBin shaderBin = null; + RenderMolecule renderMolecule = null; + PolygonAttributesRetained polygonAttributes = null; + LineAttributesRetained lineAttributes = null; + PointAttributesRetained pointAttributes = null; + MaterialRetained material = null; + boolean enableLighting = false; + TransparencyAttributesRetained transparency = null; + ColoringAttributesRetained coloringAttributes = null; + Transform3D modelMatrix = null; + Transform3D projTrans = null; + TextureBin textureBin = null; + + + /** + * cached RenderBin states for lazy native states update + */ + LightRetained lights[] = null; + int frameCount[] = null; + long enableMask = -1; + FogRetained fog = null; + ModelClipRetained modelClip = null; + Color3f sceneAmbient = new Color3f(); + TextureUnitStateRetained[] texUnitState = null; + + /** + * These cached values are only used in Pure Immediate and Mixed Mode rendering + */ + TextureRetained texture = null; + TextureAttributesRetained texAttrs = null; + TexCoordGenerationRetained texCoordGeneration = null; + RenderingAttributesRetained renderingAttrs = null; + AppearanceRetained appearance = null; + + ShaderProgramRetained shaderProgram = null; + + // only used in Mixed Mode rendering + Object appHandle = null; + + /** + * Set to true when any one of texture state use + * Texture Generation linear mode. This is used for D3D + * temporary turn displayList off and do its own coordinate + * generation since D3D don't support it. + * + * TODO aces : is this still true in DX9? + */ + boolean texLinearMode = false; + + /** + * Dirty bit to determine if the NodeComponent needs to be re-sent + * down to the underlying API + */ + int canvasDirty = 0xffff; + + // True when either one of dirtyRenderMoleculeList, + // dirtyDlistPerRinfoList, dirtyRenderAtomList size > 0 + boolean dirtyDisplayList = false; + + ArrayList dirtyRenderMoleculeList = new ArrayList(); + ArrayList dirtyRenderAtomList = new ArrayList(); + // List of (Rm, rInfo) pair of individual dlists that need to be rebuilt + ArrayList dirtyDlistPerRinfoList = new ArrayList(); + + ArrayList displayListResourceFreeList = new ArrayList(); + ArrayList textureIdResourceFreeList = new ArrayList(); + + // an unique bit to identify this canvas + int canvasBit = 0; + // an unique number to identify this canvas : ( canvasBit = 1 << canvasId) + int canvasId = 0; + // Indicates whether the canvasId has been allocated + private boolean canvasIdAlloc = false; + + // Avoid using this as lock, it cause deadlock + Object cvLock = new Object(); + Object evaluateLock = new Object(); + Object dirtyMaskLock = new Object(); + + // Use by D3D when toggle between window/fullscreen mode. + // Note that in fullscreen mode, the width and height get + // by canvas is smaller than expected. + boolean fullScreenMode = false; + int fullscreenWidth; + int fullscreenHeight; + + // For D3D, instead of using the same variable in Renderer, + // each canvas has to build its own displayList. + boolean needToRebuildDisplayList = false; + + // Use by D3D when canvas resize/toggle in pure immediate mode + int reEvaluateCanvasCmd = 0; + + // Read-only flag that indicates whether the following texture features + // are supported for this canvas. + + static final int TEXTURE_3D = 0x0001; + static final int TEXTURE_COLOR_TABLE = 0x0002; + static final int TEXTURE_MULTI_TEXTURE = 0x0004; + static final int TEXTURE_COMBINE = 0x0008; + static final int TEXTURE_COMBINE_DOT3 = 0x0010; + static final int TEXTURE_COMBINE_SUBTRACT = 0x0020; + static final int TEXTURE_REGISTER_COMBINERS = 0x0040; + static final int TEXTURE_CUBE_MAP = 0x0080; + static final int TEXTURE_SHARPEN = 0x0100; + static final int TEXTURE_DETAIL = 0x0200; + static final int TEXTURE_FILTER4 = 0x0400; + static final int TEXTURE_ANISOTROPIC_FILTER = 0x0800; + static final int TEXTURE_LOD_RANGE = 0x1000; + static final int TEXTURE_LOD_OFFSET = 0x2000; + // Use by D3D to indicate using one pass Blend mode + // if Texture interpolation mode is support. + static final int TEXTURE_LERP = 0x4000; + static final int TEXTURE_NON_POWER_OF_TWO = 0x8000; + static final int TEXTURE_AUTO_MIPMAP_GENERATION = 0x10000; + + int textureExtendedFeatures = 0; + + // Extensions supported by the underlying canvas + // + // NOTE: we should remove EXT_BGR and EXT_ABGR when the imaging code is + // rewritten + static final int SUN_GLOBAL_ALPHA = 0x1; + static final int EXT_ABGR = 0x2; + static final int EXT_BGR = 0x4; + static final int MULTISAMPLE = 0x8; + + // The following 10 variables are set by the native + // createNewContext()/createQueryContext() methods + + // Supported Extensions + int extensionsSupported = 0; + + // Anisotropic Filter degree + float anisotropicDegreeMax = 1.0f; + + // Texture Boundary Width Max + int textureBoundaryWidthMax = 0; + + boolean multiTexAccelerated = false; + + // Max number of texture coordinate sets + int maxTexCoordSets = 1; + + // Max number of fixed-function texture units + int maxTextureUnits = 1; + + // Max number of fragment shader texture units + int maxTextureImageUnits = 0; + + // Max number of vertex shader texture units + int maxVertexTextureImageUnits = 0; + + // Max number of combined shader texture units + int maxCombinedTextureImageUnits = 0; + + // Max number of vertex attrs (not counting coord, etc.) + int maxVertexAttrs = 0; + + // End of variables set by createNewContext()/createQueryContext() + + // The total available number of texture units used by either the + // fixed-function or programmable shader pipeline. + // This is computed as: max(maxTextureUnits, maxTextureImageUnits) + int maxAvailableTextureUnits; + + // Texture Width, Height Max + int textureWidthMax = 0; + int textureHeightMax = 0; + + // Texture3D Width, Heigh, Depth Max + int texture3DWidthMax = -1; + int texture3DHeightMax = -1; + int texture3DDepthMax = -1; + + // Cached position & size for CanvasViewCache. + // We don't want to call canvas.getxx method in Renderer + // since it will cause deadlock as removeNotify() need to get + // component lock of Canvas also and need to wait Renderer to + // finish before continue. So we invoke the method now in + // CanvasViewEventCatcher. + Point newPosition = new Point(); + Dimension newSize = new Dimension(); + + // Remember OGL context resources to free + // before context is destroy. + // It is used when sharedCtx = false; + ArrayList textureIDResourceTable = new ArrayList(5); + + // The following variables are used by the lazy download of + // states code to keep track of the set of current to be update bins + + static final int LIGHTBIN_BIT = 0x0; + static final int ENVIRONMENTSET_BIT = 0x1; + static final int ATTRIBUTEBIN_BIT = 0x2; + static final int TEXTUREBIN_BIT = 0x3; + static final int RENDERMOLECULE_BIT = 0x4; + static final int TRANSPARENCY_BIT = 0x5; + static final int SHADERBIN_BIT = 0x6; + + // bitmask to specify if the corresponding "bin" needs to be updated + int stateUpdateMask = 0; + + // the set of current "bins" that is to be updated, the stateUpdateMask + // specifies if each bin in this set is updated or not. + Object curStateToUpdate[] = new Object[7]; + + /** + * The list of lights that are currently being represented in the native + * graphics context. + */ + LightRetained[] currentLights = null; + + /** + * Flag to override RenderAttributes.depthBufferWriteEnable + */ + boolean depthBufferWriteEnableOverride = false; + + /** + * Flag to override RenderAttributes.depthBufferEnable + */ + boolean depthBufferEnableOverride = false; + + // current state of depthBufferWriteEnable + boolean depthBufferWriteEnable = true; + + boolean vfPlanesValid = false; + + // The event catcher for this canvas. + EventCatcher eventCatcher; + + // The view event catcher for this canvas. + private CanvasViewEventCatcher canvasViewEventCatcher; + + // The top-level parent window for this canvas. + private Window windowParent; + + // Issue 458 - list of all parent containers for this canvas + // (includes top-level parent window) + private LinkedList containerParentList = new LinkedList(); + + // flag that indicates if light has changed + boolean lightChanged = false; + + // resource control object + DrawingSurfaceObject drawingSurfaceObject; + + // true if context is valid for rendering + boolean validCtx = false; + + // true if canvas is valid for rendering + boolean validCanvas = false; + + // true if ctx changed between render and swap. In this case + // cv.canvasDirty flag will not reset in Renderer. + // This case happen when GraphicsContext3D invoked doClear() + // and canvas removeNotify() called while Renderer is running + boolean ctxChanged = false; + + // Default graphics configuration + private static GraphicsConfiguration defaultGcfg = null; + + // Returns default graphics configuration if user passes null + // into the Canvas3D constructor + private static synchronized GraphicsConfiguration defaultGraphicsConfiguration() { + if (defaultGcfg == null) { + GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D(); + defaultGcfg = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getBestConfiguration(template); + } + return defaultGcfg; + } + + // Returns true if this is a valid graphics configuration, obtained + // via a GraphicsConfigTemplate3D. + private static boolean isValidConfig(GraphicsConfiguration gconfig) { + // If this is a valid GraphicsConfiguration object, then it will + // be in the graphicsConfigTable + return graphicsConfigTable.containsKey(gconfig); + } + + // Checks the given graphics configuration, and throws an exception if + // the config is null or invalid. + private static synchronized GraphicsConfiguration + checkForValidGraphicsConfig(GraphicsConfiguration gconfig, boolean offScreen) { + + // Issue 266 - for backwards compatibility with legacy applications, + // we will accept a null GraphicsConfiguration for an on-screen Canvas3D + // only if the "allowNullGraphicsConfig" system property is set to true. + if (!offScreen && VirtualUniverse.mc.allowNullGraphicsConfig) { + if (gconfig == null) { + // Print out warning if Canvas3D is called with a + // null GraphicsConfiguration + System.err.println(J3dI18N.getString("Canvas3D7")); + System.err.println(" " + J3dI18N.getString("Canvas3D18")); + + // Use a default graphics config + gconfig = defaultGraphicsConfiguration(); + } + } + + // Validate input graphics config + if (gconfig == null) { + throw new NullPointerException(J3dI18N.getString("Canvas3D19")); + } else if (!isValidConfig(gconfig)) { + throw new IllegalArgumentException(J3dI18N.getString("Canvas3D17")); + } + + return gconfig; + } + + // Return the actual graphics config that will be used to construct + // the AWT Canvas. This is permitted to be non-unique or null. + private static GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) { + return Pipeline.getPipeline().getGraphicsConfig(gconfig); + } + + /** + * Constructs and initializes a new Canvas3D object that Java 3D + * can render into. The following Canvas3D attributes are initialized + * to default values as shown: + *

    + * left manual eye in image plate : (0.142, 0.135, 0.4572)
    + * right manual eye in image plate : (0.208, 0.135, 0.4572)
    + * stereo enable : true
    + * double buffer enable : true
    + * monoscopic view policy : View.CYCLOPEAN_EYE_VIEW
    + * off-screen mode : false
    + * off-screen buffer : null
    + * off-screen location : (0,0)
    + *
+ * + * @param graphicsConfiguration a valid GraphicsConfiguration object that + * will be used to create the canvas. This object should not be null and + * should be created using a GraphicsConfigTemplate3D or the + * getPreferredConfiguration() method of the SimpleUniverse utility. For + * backward compatibility with earlier versions of Java 3D, a null or + * default GraphicsConfiguration will still work when used to create a + * Canvas3D on the default screen, but an error message will be printed. + * A NullPointerException or IllegalArgumentException will be thrown in a + * subsequent release. + * + * @exception IllegalArgumentException if the specified + * GraphicsConfiguration does not support 3D rendering + */ + public Canvas3D(GraphicsConfiguration graphicsConfiguration) { + this(null, checkForValidGraphicsConfig(graphicsConfiguration, false), false); + } + + /** + * Constructs and initializes a new Canvas3D object that Java 3D + * can render into. + * + * @param graphicsConfiguration a valid GraphicsConfiguration object + * that will be used to create the canvas. This must be created either + * with a GraphicsConfigTemplate3D or by using the + * getPreferredConfiguration() method of the SimpleUniverse utility. + * + * @param offScreen a flag that indicates whether this canvas is + * an off-screen 3D rendering canvas. Note that if offScreen + * is set to true, this Canvas3D object cannot be used for normal + * rendering; it should not be added to any Container object. + * + * @exception NullPointerException if the GraphicsConfiguration + * is null. + * + * @exception IllegalArgumentException if the specified + * GraphicsConfiguration does not support 3D rendering + * + * @since Java 3D 1.2 + */ + public Canvas3D(GraphicsConfiguration graphicsConfiguration, boolean offScreen) { + this(null, checkForValidGraphicsConfig(graphicsConfiguration, offScreen), offScreen); + } + + // Private constructor only called by the two public constructors after + // they have validated the graphics config (and possibly constructed a new + // default config). + // The graphics config must be valid, unique, and non-null. + private Canvas3D(Object dummyObj1, + GraphicsConfiguration graphicsConfiguration, + boolean offScreen) { + this(dummyObj1, + graphicsConfiguration, + getGraphicsConfig(graphicsConfiguration), + offScreen); + } + + // Private constructor only called by the previous private constructor. + // The graphicsConfiguration parameter is used by Canvas3D to lookup the + // graphics device and graphics template. The graphicsConfiguration2 + // parameter is generated by the Pipeline from graphicsConfiguration and + // is only used to initialize the java.awt.Canvas. + private Canvas3D(Object dummyObj1, + GraphicsConfiguration graphicsConfiguration, + GraphicsConfiguration graphicsConfiguration2, + boolean offScreen) { + + super(graphicsConfiguration2); + + this.offScreen = offScreen; + this.graphicsConfiguration = graphicsConfiguration; + + // Issue 131: Set the autoOffScreen variable based on whether this + // canvas3d implements the AutoOffScreenCanvas3D tagging interface. + // Eventually, we may replace this with an actual API. + boolean autoOffScreenCanvas3D = false; + if (this instanceof com.sun.j3d.exp.swing.impl.AutoOffScreenCanvas3D) { + autoOffScreenCanvas3D = true; + } + + // Throw an illegal argument exception if an on-screen canvas is tagged + // as an auto-off-screen canvas + if (autoOffScreenCanvas3D && !offScreen) { + throw new IllegalArgumentException(J3dI18N.getString("Canvas3D25")); + } + + // Issue 163 : Set dirty bits for both Renderer and RenderBin + cvDirtyMask[0] = VIEW_INFO_DIRTY; + cvDirtyMask[1] = VIEW_INFO_DIRTY; + + GraphicsConfigInfo gcInfo = graphicsConfigTable.get(graphicsConfiguration); + requestedStencilSize = gcInfo.getGraphicsConfigTemplate3D().getStencilSize(); + + fbConfig = Pipeline.getPipeline().getFbConfig(gcInfo); + + if (offScreen) { + + // Issue 131: set manual rendering flag based on whether this is + // an auto-off-screen Canvas3D. + manualRendering = !autoOffScreenCanvas3D; + + screen = new Screen3D(graphicsConfiguration, offScreen); + + // QUESTION: keep a list of off-screen Screen3D objects? + // Does this list need to be grouped by GraphicsDevice? + + synchronized(dirtyMaskLock) { + cvDirtyMask[0] |= MOVED_OR_RESIZED_DIRTY; + cvDirtyMask[1] |= MOVED_OR_RESIZED_DIRTY; + } + + // this canvas will not receive the paint callback, + // so we need to set the necessary flags here + firstPaintCalled = true; + + if (manualRendering) { + // since this canvas will not receive the addNotify + // callback from AWT, set the added flag here for + // evaluateActive to work correctly + added = true; + } + + evaluateActive(); + + // create the rendererStructure object + //rendererStructure = new RendererStructure(); + offScreenCanvasLoc = new Point(0, 0); + offScreenCanvasSize = new Dimension(0, 0); + + this.setLocation(offScreenCanvasLoc); + this.setSize(offScreenCanvasSize); + newSize = offScreenCanvasSize; + newPosition = offScreenCanvasLoc; + + // Issue 131: create event catchers for auto-offScreen + if (!manualRendering) { + eventCatcher = new EventCatcher(this); + canvasViewEventCatcher = new CanvasViewEventCatcher(this); + } + } else { + + GraphicsDevice graphicsDevice; + graphicsDevice = graphicsConfiguration.getDevice(); + + eventCatcher = new EventCatcher(this); + canvasViewEventCatcher = new CanvasViewEventCatcher(this); + + synchronized(VirtualUniverse.mc.deviceScreenMap) { + screen = (Screen3D) VirtualUniverse.mc. + deviceScreenMap.get(graphicsDevice); + + if (screen == null) { + screen = new Screen3D(graphicsConfiguration, offScreen); + VirtualUniverse.mc.deviceScreenMap.put(graphicsDevice, + screen); + } + } + + } + + lights = new LightRetained[VirtualUniverse.mc.maxLights]; + frameCount = new int[VirtualUniverse.mc.maxLights]; + for (int i=0; i + * Updates to live Geometry, Texture, and ImageComponent objects + * in the scene graph are not allowed from this method. + * + *

+ * NOTE: Applications should not call this method. + */ + public void preRender() { + // Do nothing; the user overrides this to cause some action + } + + /** + * This routine is called by the Java 3D rendering loop after completing + * all rendering to the canvas for this frame and before the buffer swap. + * Applications that wish to perform operations in the rendering loop, + * following any actual rendering may override this function. + * + *

+ * Updates to live Geometry, Texture, and ImageComponent objects + * in the scene graph are not allowed from this method. + * + *

+ * NOTE: Applications should not call this method. + */ + public void postRender() { + // Do nothing; the user overrides this to cause some action + } + + /** + * This routine is called by the Java 3D rendering loop after completing + * all rendering to the canvas, and all other canvases associated with + * this view, for this frame following the buffer swap. + * Applications that wish to perform operations at the very + * end of the rendering loop may override this function. + * In off-screen mode, all rendering is copied to the off-screen + * buffer before this method is called. + * + *

+ * Updates to live Geometry, Texture, and ImageComponent objects + * in the scene graph are not allowed from this method. + * + *

+ * NOTE: Applications should not call this method. + */ + public void postSwap() { + // Do nothing; the user overrides this to cause some action + } + + /** + * This routine is called by the Java 3D rendering loop during the + * execution of the rendering loop. It is called once for each + * field (i.e., once per frame on + * a mono system or once each for the right eye and left eye on a + * two-pass stereo system. This is intended for use by applications that + * want to mix retained/compiled-retained mode rendering with some + * immediate mode rendering. Applications that wish to perform + * operations during the rendering loop, may override this + * function. + * + *

+ * Updates to live Geometry, Texture, and ImageComponent objects + * in the scene graph are not allowed from this method. + * + *

+ * NOTE: Applications should not call this method. + *

+ * + * @param fieldDesc field description, one of: FIELD_LEFT, FIELD_RIGHT or + * FIELD_ALL. Applications that wish to work correctly in stereo mode + * should render the same image for both FIELD_LEFT and FIELD_RIGHT calls. + * If Java 3D calls the renderer with FIELD_ALL then the immediate mode + * rendering only needs to be done once. + */ + public void renderField(int fieldDesc) { + // Do nothing; the user overrides this to cause some action + } + + /** + * Stop the Java 3D renderer on this Canvas3D object. If the + * Java 3D renderer is currently running, the rendering will be + * synchronized before being stopped. No further rendering will be done + * to this canvas by Java 3D until the renderer is started again. + * In pure immediate mode this method should be called prior to adding + * this canvas to an active View object. + * + * @exception IllegalStateException if this Canvas3D is in + * off-screen mode. + */ + public final void stopRenderer() { + // Issue 131: renderer can't be stopped only if it is an offscreen, + // manual canvas. Otherwise, it has to be seen as an onscreen canvas. + if (manualRendering) + throw new IllegalStateException(J3dI18N.getString("Canvas3D14")); + + if (isRunning) { + VirtualUniverse.mc.postRequest(MasterControl.STOP_RENDERER, this); + isRunning = false; + } + } + + + /** + * Start the Java 3D renderer on this Canvas3D object. If the + * Java 3D renderer is not currently running, any rendering to other + * Canvas3D objects sharing the same View will be synchronized before this + * Canvas3D's renderer is (re)started. When a Canvas3D is created, it is + * initially marked as being started. This means that as soon as the + * Canvas3D is added to an active View object, the rendering loop will + * render the scene graph to the canvas. + */ + public final void startRenderer() { + // Issue 260 : ignore attempt to start renderer if fatal error + if (fatalError) { + return; + } + + if (!isRunning) { + VirtualUniverse.mc.postRequest(MasterControl.START_RENDERER, this); + isRunning = true; + redraw(); + } + } + + /** + * Retrieves the state of the renderer for this Canvas3D object. + * @return the state of the renderer + * + * @since Java 3D 1.2 + */ + public final boolean isRendererRunning() { + return isRunning; + } + + // Returns the state of the fatal error flag + boolean isFatalError() { + return fatalError; + } + + // Sets the fatal error flag to true; stop the renderer for this canvas + void setFatalError() { + fatalError = true; + + if (isRunning) { + isRunning = false; + + if (!manualRendering) { + VirtualUniverse.mc.postRequest(MasterControl.STOP_RENDERER, this); + } + } + } + + + /** + * Retrieves a flag indicating whether this Canvas3D is an + * off-screen canvas. + * + * @return true if this Canvas3D is an off-screen canvas; + * false if this is an on-screen canvas. + * + * @since Java 3D 1.2 + */ + public boolean isOffScreen() { + return offScreen; + } + + + /** + * Sets the off-screen buffer for this Canvas3D. The specified + * image is written into by the Java 3D renderer. The size of the + * specified ImageComponent determines the size, in pixels, of + * this Canvas3D--the size inherited from Component is ignored. + *

+ * NOTE: the size, physical width, and physical height of the associated + * Screen3D must be set explicitly prior to rendering. + * Failure to do so will result in an exception. + *

+ * + * @param buffer the image component that will be rendered into by + * subsequent calls to renderOffScreenBuffer. The image component must not + * be part of a live scene graph, nor may it subsequently be made part of a + * live scene graph while being used as an off-screen buffer; an + * IllegalSharingException is thrown in such cases. The buffer may be null, + * indicating that the previous off-screen buffer is released without a new + * buffer being set. + * + * @exception IllegalStateException if this Canvas3D is not in + * off-screen mode. + * + * @exception RestrictedAccessException if an off-screen rendering + * is in process for this Canvas3D. + * + * @exception IllegalSharingException if the specified ImageComponent2D + * is part of a live scene graph + * + * @exception IllegalSharingException if the specified ImageComponent2D is + * being used by an immediate mode context, or by another Canvas3D as + * an off-screen buffer. + * + * @exception IllegalArgumentException if the image class of the specified + * ImageComponent2D is not ImageClass.BUFFERED_IMAGE. + * + * @exception IllegalArgumentException if the specified + * ImageComponent2D is in by-reference mode and its + * RenderedImage is null. + * + * @exception IllegalArgumentException if the ImageComponent2D format + * is not a 3-component format (e.g., FORMAT_RGB) + * or a 4-component format (e.g., FORMAT_RGBA). + * + * @see #renderOffScreenBuffer + * @see Screen3D#setSize(int, int) + * @see Screen3D#setSize(Dimension) + * @see Screen3D#setPhysicalScreenWidth + * @see Screen3D#setPhysicalScreenHeight + * + * @since Java 3D 1.2 + */ + public void setOffScreenBuffer(ImageComponent2D buffer) { + int width, height; + boolean freeCanvasId = false; + + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Canvas3D1")); + + if (offScreenRendering) + throw new RestrictedAccessException(J3dI18N.getString("Canvas3D2")); + + // Check that offScreenBufferPending is not already set + J3dDebug.doAssert(!offScreenBufferPending, "!offScreenBufferPending"); + + if (offScreenBuffer != null && offScreenBuffer != buffer) { + ImageComponent2DRetained i2dRetained = + (ImageComponent2DRetained)offScreenBuffer.retained; + i2dRetained.setUsedByOffScreen(false); + } + + if (buffer != null) { + ImageComponent2DRetained bufferRetained = + (ImageComponent2DRetained)buffer.retained; + + if (bufferRetained.byReference && + !(bufferRetained.getRefImage(0) instanceof BufferedImage)) { + + throw new IllegalArgumentException(J3dI18N.getString("Canvas3D15")); + } + + if (bufferRetained.getNumberOfComponents() < 3 ) { + throw new IllegalArgumentException(J3dI18N.getString("Canvas3D16")); + } + + if (buffer.isLive()) { + throw new IllegalSharingException(J3dI18N.getString("Canvas3D26")); + } + + if (bufferRetained.getInImmCtx()) { + throw new IllegalSharingException(J3dI18N.getString("Canvas3D27")); + } + + if (buffer != offScreenBuffer && bufferRetained.getUsedByOffScreen()) { + throw new IllegalSharingException(J3dI18N.getString("Canvas3D28")); + } + + bufferRetained.setUsedByOffScreen(true); + + width = bufferRetained.width; + height = bufferRetained.height; + + // Issues 347, 348 - assign a canvasId for off-screen Canvas3D + if (manualRendering) { + sendAllocateCanvasId(); + } + } + else { + width = height = 0; + + // Issues 347, 348 - release canvasId for off-screen Canvas3D + if (manualRendering) { + freeCanvasId = true; + } + } + + if ((offScreenCanvasSize.width != width) || + (offScreenCanvasSize.height != height)) { + + if (drawable != null) { + // Fix for Issue 18 and Issue 175 + // Will do destroyOffScreenBuffer in the Renderer thread. + sendDestroyCtxAndOffScreenBuffer(); + drawable = null; + } + // Issue 396. Since context is invalid here, we should set it to null. + ctx = null; + + // set the canvas dimension according to the buffer dimension + offScreenCanvasSize.setSize(width, height); + this.setSize(offScreenCanvasSize); + + if (width > 0 && height > 0) { + sendCreateOffScreenBuffer(); + } + + } + else if (ctx != null) { + removeCtx(); + } + + if (freeCanvasId) { + sendFreeCanvasId(); + } + + offScreenBuffer = buffer; + + synchronized(dirtyMaskLock) { + cvDirtyMask[0] |= MOVED_OR_RESIZED_DIRTY; + cvDirtyMask[1] |= MOVED_OR_RESIZED_DIRTY; + } + } + + /** + * Retrieves the off-screen buffer for this Canvas3D. + * + * @return the current off-screen buffer for this Canvas3D. + * + * @exception IllegalStateException if this Canvas3D is not in + * off-screen mode. + * + * @since Java 3D 1.2 + */ + public ImageComponent2D getOffScreenBuffer() { + + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Canvas3D1")); + + return (offScreenBuffer); + } + + + /** + * Schedules the rendering of a frame into this Canvas3D's + * off-screen buffer. The rendering is done from the point of + * view of the View object to which this Canvas3D has been added. + * No rendering is performed if this Canvas3D object has not been + * added to an active View. This method does not wait for the rendering + * to actually happen. An application that wishes to know when + * the rendering is complete must either subclass Canvas3D and + * override the postSwap method, or call + * waitForOffScreenRendering. + * + * @exception NullPointerException if the off-screen buffer is null. + * @exception IllegalStateException if this Canvas3D is not in + * off-screen mode, or if either the width or the height of + * the associated Screen3D's size is <= 0, or if the associated + * Screen3D's physical width or height is <= 0. + * @exception RestrictedAccessException if an off-screen rendering + * is already in process for this Canvas3D or if the Java 3D renderer + * is stopped. + * + * @see #setOffScreenBuffer + * @see Screen3D#setSize(int, int) + * @see Screen3D#setSize(Dimension) + * @see Screen3D#setPhysicalScreenWidth + * @see Screen3D#setPhysicalScreenHeight + * @see #waitForOffScreenRendering + * @see #postSwap + * + * @since Java 3D 1.2 + */ + public void renderOffScreenBuffer() { + + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Canvas3D1")); + + // Issue 131: Cannot manually render to an automatic canvas. + if (!manualRendering) + throw new IllegalStateException(J3dI18N.getString("Canvas3D24")); + + // Issue 260 : Cannot render if we already have a fatal error + if (fatalError) { + throw new IllegalRenderingStateException(J3dI18N.getString("Canvas3D30")); + } + + if (offScreenBuffer == null) + throw new NullPointerException(J3dI18N.getString("Canvas3D10")); + + Dimension screenSize = screen.getSize(); + + if (screenSize.width <= 0) + throw new IllegalStateException(J3dI18N.getString("Canvas3D8")); + + if (screenSize.height <= 0) + throw new IllegalStateException(J3dI18N.getString("Canvas3D9")); + + if (screen.getPhysicalScreenWidth() <= 0.0) + throw new IllegalStateException(J3dI18N.getString("Canvas3D12")); + + if (screen.getPhysicalScreenHeight() <= 0.0) + throw new IllegalStateException(J3dI18N.getString("Canvas3D13")); + + if (offScreenRendering) + throw new RestrictedAccessException(J3dI18N.getString("Canvas3D2")); + + if (!isRunning) + throw new RestrictedAccessException(J3dI18N.getString("Canvas3D11")); + + // Fix to issue 66 + if ((!active) || (pendingView == null)) { + /* No rendering is performed if this Canvas3D object has not been + added to an active View. */ + return; + } + + // Issue 131: moved code that determines off-screen boundary to separate + // method that is called from the renderer + + offScreenRendering = true; + + // Fix to issue 66. + /* This is an attempt to do the following check in one atomic operation : + ((view != null) && (view.inCanvasCallback)) */ + + boolean inCanvasCallback = false; + try { + inCanvasCallback = view.inCanvasCallback; + + } catch (NullPointerException npe) { + /* Do nothing here */ + } + + if (inCanvasCallback) { + // Here we assume that view is stable if inCanvasCallback + // is true. This assumption is valid among all j3d threads as + // all access to view is synchronized by MasterControl. + // Issue : user threads access to view isn't synchronize hence + // is model will break. + if (screen.renderer == null) { + + // It is possible that screen.renderer = null when this View + // is shared by another onScreen Canvas and this callback + // is from that Canvas. In this case it need one more + // round before the renderer. + screen.renderer = (Renderer) screen.deviceRendererMap.get( + screen.graphicsDevice); + // screen.renderer may equal to null when multiple + // screen is used and this Canvas3D is in different + // screen sharing the same View not yet initialize. + } + + // if called from render call back, send a message directly to + // the renderer message queue, and call renderer doWork + // to do the offscreen rendering now + if (Thread.currentThread() == screen.renderer) { + + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.RENDER_THREAD; + createMessage.type = J3dMessage.RENDER_OFFSCREEN; + createMessage.universe = this.view.universe; + createMessage.view = this.view; + createMessage.args[0] = this; + + screen.renderer.rendererStructure.addMessage(createMessage); + + // modify the args to reflect offScreen rendering + screen.renderer.args = new Object[4]; + ((Object[])screen.renderer.args)[0] = + new Integer(Renderer.REQUESTRENDER); + ((Object[])screen.renderer.args)[1] = this; + ((Object[])screen.renderer.args)[2] = view; + // This extra argument 3 is needed in MasterControl to + // test whether offscreen Rendering is used or not + ((Object[])screen.renderer.args)[3] = null; + + // call renderer doWork directly since we are already in + // the renderer thread + screen.renderer.doWork(0); + } else { + + // XXXX: + // Now we are in trouble, this will cause deadlock if + // waitForOffScreenRendering() is invoked + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.RENDER_THREAD; + createMessage.type = J3dMessage.RENDER_OFFSCREEN; + createMessage.universe = this.view.universe; + createMessage.view = this.view; + createMessage.args[0] = this; + screen.renderer.rendererStructure.addMessage(createMessage); + VirtualUniverse.mc.setWorkForRequestRenderer(); + } + + } else if (Thread.currentThread() instanceof BehaviorScheduler) { + + // If called from behavior scheduler, send a message directly to + // the renderer message queue. + // Note that we didn't use + // currentThread() == view.universe.behaviorScheduler + // since the caller may be another universe Behavior + // scheduler. + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.RENDER_THREAD; + createMessage.type = J3dMessage.RENDER_OFFSCREEN; + createMessage.universe = this.view.universe; + createMessage.view = this.view; + createMessage.args[0] = this; + screen.renderer.rendererStructure.addMessage(createMessage); + VirtualUniverse.mc.setWorkForRequestRenderer(); + + } else { + // send a message to renderBin + // Fix for issue 66 : Since view might not been set yet, + // we have to use pendingView instead. + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDER; + createMessage.type = J3dMessage.RENDER_OFFSCREEN; + createMessage.universe = this.pendingView.universe; + createMessage.view = this.pendingView; + createMessage.args[0] = this; + createMessage.args[1] = offScreenBuffer; + VirtualUniverse.mc.processMessage(createMessage); + } + } + + + /** + * Waits for this Canvas3D's off-screen rendering to be done. + * This method will wait until the postSwap method of this + * off-screen Canvas3D has completed. If this Canvas3D has not + * been added to an active view or if the renderer is stopped for this + * Canvas3D, then this method will return + * immediately. This method must not be called from a render + * callback method of an off-screen Canvas3D. + * + * @exception IllegalStateException if this Canvas3D is not in + * off-screen mode, or if this method is called from a render + * callback method of an off-screen Canvas3D. + * + * @see #renderOffScreenBuffer + * @see #postSwap + * + * @since Java 3D 1.2 + */ + public void waitForOffScreenRendering() { + + if (!offScreen) { + throw new IllegalStateException(J3dI18N.getString("Canvas3D1")); + } + + if (Thread.currentThread() instanceof Renderer) { + throw new IllegalStateException(J3dI18N.getString("Canvas3D31")); + } + + while (offScreenRendering) { + MasterControl.threadYield(); + } + } + + + /** + * Sets the location of this off-screen Canvas3D. The location is + * the upper-left corner of the Canvas3D relative to the + * upper-left corner of the corresponding off-screen Screen3D. + * The function of this method is similar to that of + * Component.setLocation for on-screen Canvas3D + * objects. The default location is (0,0). + * + * @param x the x coordinate of the upper-left corner of + * the new location. + * @param y the y coordinate of the upper-left corner of + * the new location. + * + * @exception IllegalStateException if this Canvas3D is not in + * off-screen mode. + * + * @since Java 3D 1.2 + */ + public void setOffScreenLocation(int x, int y) { + + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Canvas3D1")); + + synchronized(cvLock) { + offScreenCanvasLoc.setLocation(x, y); + } + } + + + /** + * Sets the location of this off-screen Canvas3D. The location is + * the upper-left corner of the Canvas3D relative to the + * upper-left corner of the corresponding off-screen Screen3D. + * The function of this method is similar to that of + * Component.setLocation for on-screen Canvas3D + * objects. The default location is (0,0). + * + * @param p the point defining the upper-left corner of the new + * location. + * + * @exception IllegalStateException if this Canvas3D is not in + * off-screen mode. + * + * @since Java 3D 1.2 + */ + public void setOffScreenLocation(Point p) { + + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Canvas3D1")); + + synchronized(cvLock) { + offScreenCanvasLoc.setLocation(p); + } + } + + + /** + * Retrieves the location of this off-screen Canvas3D. The + * location is the upper-left corner of the Canvas3D relative to + * the upper-left corner of the corresponding off-screen Screen3D. + * The function of this method is similar to that of + * Component.getLocation for on-screen Canvas3D + * objects. + * + * @return a new point representing the upper-left corner of the + * location of this off-screen Canvas3D. + * + * @exception IllegalStateException if this Canvas3D is not in + * off-screen mode. + * + * @since Java 3D 1.2 + */ + public Point getOffScreenLocation() { + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Canvas3D1")); + + return (new Point(offScreenCanvasLoc)); + } + + + /** + * Retrieves the location of this off-screen Canvas3D and stores + * it in the specified Point object. The location is the + * upper-left corner of the Canvas3D relative to the upper-left + * corner of the corresponding off-screen Screen3D. The function + * of this method is similar to that of + * Component.getLocation for on-screen Canvas3D + * objects. This version of getOffScreenLocation is + * useful if the caller wants to avoid allocating a new Point + * object on the heap. + * + * @param rv Point object into which the upper-left corner of the + * location of this off-screen Canvas3D is copied. + * If rv is null, a new Point is allocated. + * + * @return rv + * + * @exception IllegalStateException if this Canvas3D is not in + * off-screen mode. + * + * @since Java 3D 1.2 + */ + public Point getOffScreenLocation(Point rv) { + + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Canvas3D1")); + + if (rv == null) + return (new Point(offScreenCanvasLoc)); + + else { + rv.setLocation(offScreenCanvasLoc); + return rv; + } + } + + void endOffScreenRendering() { + + ImageComponent2DRetained icRetained = (ImageComponent2DRetained)offScreenBuffer.retained; + boolean isByRef = icRetained.isByReference(); + boolean isYUp = icRetained.isYUp(); + ImageComponentRetained.ImageData imageData = icRetained.getImageData(false); + + if(!isByRef) { + // If icRetained has a null image ( BufferedImage) + if (imageData == null) { + assert (!isByRef); + icRetained.createBlankImageData(); + imageData = icRetained.getImageData(false); + } + // Check for possible format conversion in imageData + else { + // Format convert imageData if format is unsupported. + icRetained.evaluateExtensions(this); + } + // read the image from the offscreen buffer + readOffScreenBuffer(ctx, icRetained.getImageFormatTypeIntValue(false), + icRetained.getImageDataTypeIntValue(), imageData.get(), + offScreenCanvasSize.width, offScreenCanvasSize.height); + + } else { + icRetained.geomLock.getLock(); + // Create a copy of format converted image in imageData if format is unsupported. + icRetained.evaluateExtensions(this); + + // read the image from the offscreen buffer + readOffScreenBuffer(ctx, icRetained.getImageFormatTypeIntValue(false), + icRetained.getImageDataTypeIntValue(), imageData.get(), + offScreenCanvasSize.width, offScreenCanvasSize.height); + + // For byRef, we might have to copy buffer back into + // the user's referenced ImageComponent2D + if(!imageData.isDataByRef()) { + if(icRetained.isImageTypeSupported()) { + icRetained.copyToRefImage(0); + } else { + // This method only handle RGBA conversion. + icRetained.copyToRefImageWithFormatConversion(0); + } + } + + icRetained.geomLock.unLock(); + } + } + + /** + * Synchronize and swap buffers on a double buffered canvas for + * this Canvas3D object. This method should only be called if the + * Java 3D renderer has been stopped. In the normal case, the renderer + * automatically swaps the buffer. + * This method calls the flush(true) methods of the + * associated 2D and 3D graphics contexts, if they have been allocated. + * + * @exception RestrictedAccessException if the Java 3D renderer is + * running. + * @exception IllegalStateException if this Canvas3D is in + * off-screen mode. + * + * @see #stopRenderer + * @see GraphicsContext3D#flush + * @see J3DGraphics2D#flush + */ + public void swap() { + if (offScreen) + throw new IllegalStateException(J3dI18N.getString("Canvas3D14")); + + if (isRunning) + throw new RestrictedAccessException(J3dI18N.getString("Canvas3D0")); + + if (!firstPaintCalled) { + return; + } + + if (view != null && graphicsContext3D != null) { + if ((view.universe != null) && + (Thread.currentThread() == view.universe.behaviorScheduler)) { + graphicsContext3D.sendRenderMessage(false, GraphicsContext3D.SWAP, null, null); + } else { + graphicsContext3D.sendRenderMessage(true, GraphicsContext3D.SWAP, null, null); + } + graphicsContext3D.runMonitor(J3dThread.WAIT); + } + } + + void doSwap() { + + if (firstPaintCalled && useDoubleBuffer) { + try { + if (validCtx && (ctx != null) && (view != null)) { + synchronized (drawingSurfaceObject) { + if (validCtx) { + if (!drawingSurfaceObject.renderLock()) { + graphicsContext3D.runMonitor(J3dThread.NOTIFY); + return; + } + this.syncRender(ctx, true); + int status = swapBuffers(ctx, screen.display, drawable); + if (status != NOCHANGE) { + resetImmediateRendering(status); + } + drawingSurfaceObject.unLock(); + } + } + } + } catch (NullPointerException ne) { + drawingSurfaceObject.unLock(); + } + } + // Increment the elapsedFrame for the behavior structure + // to trigger any interpolators + view.universe.behaviorStructure.incElapsedFrames(); + // waitup user thread in PureImmediate mode to continue + if (reEvaluateCanvasCmd != 0) { + int status; + + antialiasingSet = false; + if (reEvaluateCanvasCmd == RESIZE) { + assert VirtualUniverse.mc.isD3D(); + status = resizeD3DCanvas(ctx); + } else { + status = toggleFullScreenMode(ctx); + } + // reset everything + if (status != NOCHANGE) { + resetImmediateRendering(status); + } + reEvaluateCanvasCmd = 0; + } + graphicsContext3D.runMonitor(J3dThread.NOTIFY); + } + + /** + * Wrapper for native createNewContext method. + */ + Context createNewContext(Context shareCtx, boolean isSharedCtx) { + Context retVal = createNewContext(this.screen.display, + this.drawable, + this.fbConfig, + shareCtx, isSharedCtx, + this.offScreen, + VirtualUniverse.mc.glslLibraryAvailable, + VirtualUniverse.mc.cgLibraryAvailable); + // compute the max available texture units + maxAvailableTextureUnits = Math.max(maxTextureUnits, maxTextureImageUnits); + + return retVal; + } + + /** + * Make the context associated with the specified canvas current. + */ + final void makeCtxCurrent() { + makeCtxCurrent(ctx, screen.display, drawable); + } + + /** + * Make the specified context current. + */ + final void makeCtxCurrent(Context ctx) { + makeCtxCurrent(ctx, screen.display, drawable); + } + + final void makeCtxCurrent(Context ctx, long dpy, Drawable drawable) { + if (ctx != screen.renderer.currentCtx || drawable != screen.renderer.currentDrawable) { + if (!drawingSurfaceObject.isLocked()) { + drawingSurfaceObject.renderLock(); + useCtx(ctx, dpy, drawable); + drawingSurfaceObject.unLock(); + } else { + useCtx(ctx, dpy, drawable); + } + screen.renderer.currentCtx = ctx; + screen.renderer.currentDrawable = drawable; + } + } + + // Give the pipeline a chance to release the context; the Pipeline may + // or may not ignore this call. + void releaseCtx() { + if (screen.renderer.currentCtx != null) { + boolean needLock = !drawingSurfaceObject.isLocked(); + if (needLock) { + drawingSurfaceObject.renderLock(); + } + if (releaseCtx(screen.renderer.currentCtx, screen.display)) { + screen.renderer.currentCtx = null; + screen.renderer.currentDrawable = null; + } + if (needLock) { + drawingSurfaceObject.unLock(); + } + } + } + + + /** + * Sets the position of the manual left eye in image-plate + * coordinates. This value determines eye placement when a head + * tracker is not in use and the application is directly controlling + * the eye position in image-plate coordinates. + * In head-tracked mode or when the windowEyePointPolicy is + * RELATIVE_TO_FIELD_OF_VIEW or RELATIVE_TO_COEXISTENCE, this value + * is ignored. When the + * windowEyepointPolicy is RELATIVE_TO_WINDOW only the Z value is + * used. + * @param position the new manual left eye position + */ + public void setLeftManualEyeInImagePlate(Point3d position) { + + this.leftManualEyeInImagePlate.set(position); + synchronized(dirtyMaskLock) { + cvDirtyMask[0] |= EYE_IN_IMAGE_PLATE_DIRTY; + cvDirtyMask[1] |= EYE_IN_IMAGE_PLATE_DIRTY; + } + redraw(); + } + + /** + * Sets the position of the manual right eye in image-plate + * coordinates. This value determines eye placement when a head + * tracker is not in use and the application is directly controlling + * the eye position in image-plate coordinates. + * In head-tracked mode or when the windowEyePointPolicy is + * RELATIVE_TO_FIELD_OF_VIEW or RELATIVE_TO_COEXISTENCE, this value + * is ignored. When the + * windowEyepointPolicy is RELATIVE_TO_WINDOW only the Z value is + * used. + * @param position the new manual right eye position + */ + public void setRightManualEyeInImagePlate(Point3d position) { + + this.rightManualEyeInImagePlate.set(position); + synchronized(dirtyMaskLock) { + cvDirtyMask[0] |= EYE_IN_IMAGE_PLATE_DIRTY; + cvDirtyMask[1] |= EYE_IN_IMAGE_PLATE_DIRTY; + } + redraw(); + } + + /** + * Retrieves the position of the user-specified, manual left eye + * in image-plate + * coordinates and copies that value into the object provided. + * @param position the object that will receive the position + */ + public void getLeftManualEyeInImagePlate(Point3d position) { + position.set(this.leftManualEyeInImagePlate); + } + + /** + * Retrieves the position of the user-specified, manual right eye + * in image-plate + * coordinates and copies that value into the object provided. + * @param position the object that will receive the position + */ + public void getRightManualEyeInImagePlate(Point3d position) { + position.set(this.rightManualEyeInImagePlate); + } + + /** + * Retrieves the actual position of the left eye + * in image-plate + * coordinates and copies that value into the object provided. + * This value is a function of the windowEyepointPolicy, the tracking + * enable flag, and the manual left eye position. + * @param position the object that will receive the position + */ + public void getLeftEyeInImagePlate(Point3d position) { + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + position.set(canvasViewCache.getLeftEyeInImagePlate()); + } + } + else { + position.set(leftManualEyeInImagePlate); + } + } + + /** + * Retrieves the actual position of the right eye + * in image-plate + * coordinates and copies that value into the object provided. + * This value is a function of the windowEyepointPolicy, the tracking + * enable flag, and the manual right eye position. + * @param position the object that will receive the position + */ + public void getRightEyeInImagePlate(Point3d position) { + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + position.set(canvasViewCache.getRightEyeInImagePlate()); + } + } + else { + position.set(rightManualEyeInImagePlate); + } + } + + /** + * Retrieves the actual position of the center eye + * in image-plate + * coordinates and copies that value into the object provided. + * The center eye is the fictional eye half-way between the left and + * right eye. + * This value is a function of the windowEyepointPolicy, the tracking + * enable flag, and the manual right and left eye positions. + * @param position the object that will receive the position + * @see #setMonoscopicViewPolicy + */ + // XXXX: This might not make sense for field-sequential HMD. + public void getCenterEyeInImagePlate(Point3d position) { + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + position.set(canvasViewCache.getCenterEyeInImagePlate()); + } + } + else { + Point3d cenEye = new Point3d(); + cenEye.add(leftManualEyeInImagePlate, rightManualEyeInImagePlate); + cenEye.scale(0.5); + position.set(cenEye); + } + } + + /** + * Retrieves the current ImagePlate coordinates to Virtual World + * coordinates transform and places it into the specified object. + * @param t the Transform3D object that will receive the + * transform + */ + // TODO: Document -- This will return the transform of left plate. + public void getImagePlateToVworld(Transform3D t) { + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + t.set(canvasViewCache.getImagePlateToVworld()); + } + } + else { + t.setIdentity(); + } + } + + /** + * Computes the position of the specified AWT pixel value + * in image-plate + * coordinates and copies that value into the object provided. + * @param x the X coordinate of the pixel relative to the upper-left + * hand corner of the window. + * @param y the Y coordinate of the pixel relative to the upper-left + * hand corner of the window. + * @param imagePlatePoint the object that will receive the position in + * physical image plate coordinates (relative to the lower-left + * corner of the screen). + */ + // TODO: Document -- This transform the pixel location to the left image plate. + public void getPixelLocationInImagePlate(int x, int y, + Point3d imagePlatePoint) { + + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + imagePlatePoint.x = + canvasViewCache.getWindowXInImagePlate((double)x); + imagePlatePoint.y = + canvasViewCache.getWindowYInImagePlate((double)y); + imagePlatePoint.z = 0.0; + } + } else { + imagePlatePoint.set(0.0, 0.0, 0.0); + } + } + + + void getPixelLocationInImagePlate(double x, double y, double z, + Point3d imagePlatePoint) { + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + canvasViewCache.getPixelLocationInImagePlate( + x, y, z, imagePlatePoint); + } + } else { + imagePlatePoint.set(0.0, 0.0, 0.0); + } + } + + + /** + * Computes the position of the specified AWT pixel value + * in image-plate + * coordinates and copies that value into the object provided. + * @param pixelLocation the coordinates of the pixel relative to + * the upper-left hand corner of the window. + * @param imagePlatePoint the object that will receive the position in + * physical image plate coordinates (relative to the lower-left + * corner of the screen). + * + * @since Java 3D 1.2 + */ + // TODO: Document -- This transform the pixel location to the left image plate. + public void getPixelLocationInImagePlate(Point2d pixelLocation, + Point3d imagePlatePoint) { + + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + imagePlatePoint.x = + canvasViewCache.getWindowXInImagePlate(pixelLocation.x); + imagePlatePoint.y = + canvasViewCache.getWindowYInImagePlate(pixelLocation.y); + imagePlatePoint.z = 0.0; + } + } + else { + imagePlatePoint.set(0.0, 0.0, 0.0); + } + } + + + /** + * Projects the specified point from image plate coordinates + * into AWT pixel coordinates. The AWT pixel coordinates are + * copied into the object provided. + * @param imagePlatePoint the position in + * physical image plate coordinates (relative to the lower-left + * corner of the screen). + * @param pixelLocation the object that will receive the coordinates + * of the pixel relative to the upper-left hand corner of the window. + * + * @since Java 3D 1.2 + */ + // TODO: Document -- This transform the pixel location from the left image plate. + public void getPixelLocationFromImagePlate(Point3d imagePlatePoint, + Point2d pixelLocation) { + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + canvasViewCache.getPixelLocationFromImagePlate( + imagePlatePoint, pixelLocation); + } + } + else { + pixelLocation.set(0.0, 0.0); + } + } + + /** + * Copies the current Vworld projection transform for each eye + * into the specified Transform3D objects. This transform takes + * points in virtual world coordinates and projects them into + * clipping coordinates, which are in the range [-1,1] in + * X, Y, and Z after clipping and perspective + * division. + * In monoscopic mode, the same projection transform will be + * copied into both the right and left eye Transform3D objects. + * + * @param leftProjection the Transform3D object that will receive + * a copy of the current projection transform for the left eye. + * + * @param rightProjection the Transform3D object that will receive + * a copy of the current projection transform for the right eye. + * + * @since Java 3D 1.3 + */ + public void getVworldProjection(Transform3D leftProjection, + Transform3D rightProjection) { + if (canvasViewCache != null) { + ViewPlatformRetained viewPlatformRetained = + (ViewPlatformRetained)view.getViewPlatform().retained; + + synchronized(canvasViewCache) { + leftProjection.mul(canvasViewCache.getLeftProjection(), + canvasViewCache.getLeftVpcToEc()); + leftProjection.mul(viewPlatformRetained.getVworldToVpc()); + + // caluclate right eye if in stereo, otherwise + // this is the same as the left eye. + if (useStereo) { + rightProjection.mul(canvasViewCache.getRightProjection(), + canvasViewCache.getRightVpcToEc()); + rightProjection.mul(viewPlatformRetained.getVworldToVpc()); + } + else { + rightProjection.set(leftProjection); + } + } + } + else { + leftProjection.setIdentity(); + rightProjection.setIdentity(); + } + } + + /** + * Copies the inverse of the current Vworld projection transform + * for each eye into the specified Transform3D objects. This + * transform takes points in clipping coordinates, which are in + * the range [-1,1] in X, Y, and Z after + * clipping and perspective division, and transforms them into + * virtual world coordinates. + * In monoscopic mode, the same inverse projection transform will + * be copied into both the right and left eye Transform3D objects. + * + * @param leftInverseProjection the Transform3D object that will + * receive a copy of the current inverse projection transform for + * the left eye. + * @param rightInverseProjection the Transform3D object that will + * receive a copy of the current inverse projection transform for + * the right eye. + * + * @since Java 3D 1.3 + */ + public void getInverseVworldProjection(Transform3D leftInverseProjection, + Transform3D rightInverseProjection) { + if (canvasViewCache != null) { + ViewPlatformRetained viewPlatformRetained = + (ViewPlatformRetained)view.getViewPlatform().retained; + + synchronized(canvasViewCache) { + leftInverseProjection.set( + canvasViewCache.getLeftCcToVworld()); + + // caluclate right eye if in stereo, otherwise + // this is the same as the left eye. + if (useStereo) { + rightInverseProjection.set( + canvasViewCache.getRightCcToVworld()); + } + else { + rightInverseProjection.set(leftInverseProjection); + } + } + + } + else { + leftInverseProjection.setIdentity(); + rightInverseProjection.setIdentity(); + } + } + + + /** + * Retrieves the physical width of this canvas window in meters. + * @return the physical window width in meters. + */ + public double getPhysicalWidth() { + double width = 0.0; + + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + width = canvasViewCache.getPhysicalWindowWidth(); + } + } + + return width; + } + + /** + * Retrieves the physical height of this canvas window in meters. + * @return the physical window height in meters. + */ + public double getPhysicalHeight() { + double height = 0.0; + + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + height = canvasViewCache.getPhysicalWindowHeight(); + } + } + + return height; + } + + /** + * Retrieves the current Virtual World coordinates to ImagePlate + * coordinates transform and places it into the specified object. + * @param t the Transform3D object that will receive the + * transform + */ + // TODO: Document -- This will return the transform of left plate. + public void getVworldToImagePlate(Transform3D t) { + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + t.set(canvasViewCache.getVworldToImagePlate()); + } + } + else { + t.setIdentity(); + } + } + + void getLastVworldToImagePlate(Transform3D t) { + if (canvasViewCache != null) { + synchronized(canvasViewCache) { + t.set(canvasViewCache.getLastVworldToImagePlate()); + } + } + else { + t.setIdentity(); + } + } + + /** + * Sets view that points to this Canvas3D. + * @param view view object that points to this Canvas3D + */ + void setView(View view) { + pendingView = view; + + // We can't set View directly here in user thread since + // other threads may using canvas.view + // e.g. In Renderer, we use canvas3d.view.inCallBack + // before and after postSwap(), if view change in between + // than view.inCallBack may never reset to false. + VirtualUniverse.mc.postRequest(MasterControl.SET_VIEW, this); + evaluateActive(); + } + + void computeViewCache() { + synchronized(cvLock) { + if (view == null) { + canvasViewCache = null; + canvasViewCacheFrustum = null; + } else { + + canvasViewCache = new CanvasViewCache(this, + screen.screenViewCache, + view.viewCache); + // Issue 109 : construct a separate canvasViewCache for + // computing view frustum + canvasViewCacheFrustum = new CanvasViewCache(this, + screen.screenViewCache, + view.viewCache); + synchronized (dirtyMaskLock) { + cvDirtyMask[0] = VIEW_INFO_DIRTY; + cvDirtyMask[1] = VIEW_INFO_DIRTY; + } + } + } + } + + /** + * Gets view that points to this Canvas3D. + * @return view object that points to this Canvas3D + */ + public View getView() { + return pendingView; + } + + /** + * Returns a status flag indicating whether or not stereo + * is available. + * This is equivalent to: + *

    + * + * ((Boolean)queryProperties(). + * get("stereoAvailable")). + * booleanValue() + * + *
+ * + * @return a flag indicating whether stereo is available + */ + public boolean getStereoAvailable() { + return ((Boolean)queryProperties().get("stereoAvailable")). + booleanValue(); + } + + /** + * Turns stereo on or off. Note that this attribute is used + * only when stereo is available. Enabling stereo on a Canvas3D + * that does not support stereo has no effect. + * @param flag enables or disables the display of stereo + * + * @see #queryProperties + */ + public void setStereoEnable(boolean flag) { + stereoEnable = flag; + useStereo = stereoEnable && stereoAvailable; + synchronized(dirtyMaskLock) { + cvDirtyMask[0] |= STEREO_DIRTY; + cvDirtyMask[1] |= STEREO_DIRTY; + } + redraw(); + } + + /** + * Returns a status flag indicating whether or not stereo + * is enabled. + * @return a flag indicating whether stereo is enabled + */ + public boolean getStereoEnable() { + return this.stereoEnable; + } + + + /** + * Specifies how Java 3D generates monoscopic view. If set to + * View.LEFT_EYE_VIEW, the view generated corresponds to the view as + * seen from the left eye. If set to View.RIGHT_EYE_VIEW, the view + * generated corresponds to the view as seen from the right + * eye. If set to View.CYCLOPEAN_EYE_VIEW, the view generated + * corresponds to the view as seen from the 'center eye', the + * fictional eye half-way between the left and right eye. The + * default monoscopic view policy is View.CYCLOPEAN_EYE_VIEW. + *

+ * NOTE: for backward compatibility with Java 3D 1.1, if this + * attribute is set to its default value of + * View.CYCLOPEAN_EYE_VIEW, the monoscopic view policy in the + * View object will be used. An application should not use both + * the deprecated View method and this Canvas3D method at the same + * time. + * @param policy one of View.LEFT_EYE_VIEW, View.RIGHT_EYE_VIEW, or + * View.CYCLOPEAN_EYE_VIEW. + * + * @exception IllegalStateException if the specified + * policy is CYCLOPEAN_EYE_VIEW, the canvas is a stereo canvas, + * and the viewPolicy for the associated view is HMD_VIEW + * + * @since Java 3D 1.2 + */ + public void setMonoscopicViewPolicy(int policy) { + + + if((view !=null) && (view.viewPolicy == View.HMD_VIEW) && + (monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) && + (!useStereo)) { + throw new + IllegalStateException(J3dI18N.getString("View31")); + } + + monoscopicViewPolicy = policy; + synchronized(dirtyMaskLock) { + cvDirtyMask[0] |= MONOSCOPIC_VIEW_POLICY_DIRTY; + cvDirtyMask[1] |= MONOSCOPIC_VIEW_POLICY_DIRTY; + } + redraw(); + } + + + /** + * Returns policy on how Java 3D generates monoscopic view. + * @return policy one of View.LEFT_EYE_VIEW, View.RIGHT_EYE_VIEW or + * View.CYCLOPEAN_EYE_VIEW. + * + * @since Java 3D 1.2 + */ + public int getMonoscopicViewPolicy() { + return this.monoscopicViewPolicy; + } + + + /** + * Returns a status flag indicating whether or not double + * buffering is available. + * This is equivalent to: + *

    + * + * ((Boolean)queryProperties(). + * get("doubleBufferAvailable")). + * booleanValue() + * + *
+ * + * @return a flag indicating whether double buffering is available. + */ + public boolean getDoubleBufferAvailable() { + return ((Boolean)queryProperties().get("doubleBufferAvailable")). + booleanValue(); + } + + /** + * Turns double buffering on or off. If double buffering + * is off, all drawing is to the front buffer and no buffer swap + * is done between frames. It should be stressed that running + * Java 3D with double buffering disabled is not recommended. + * Enabling double buffering on a Canvas3D + * that does not support double buffering has no effect. + * + * @param flag enables or disables double buffering. + * + * @see #queryProperties + */ + public void setDoubleBufferEnable(boolean flag) { + doubleBufferEnable = flag; + useDoubleBuffer = doubleBufferEnable && doubleBufferAvailable; + if (Thread.currentThread() == screen.renderer) { + setRenderMode(ctx, FIELD_ALL, useDoubleBuffer); + } + redraw(); + } + + /** + * Returns a status flag indicating whether or not double + * buffering is enabled. + * @return a flag indicating if double buffering is enabled. + */ + public boolean getDoubleBufferEnable() { + return doubleBufferEnable; + } + + /** + * Returns a status flag indicating whether or not scene + * antialiasing is available. + * This is equivalent to: + *
    + * + * ((Boolean)queryProperties(). + * get("sceneAntialiasingAvailable")). + * booleanValue() + * + *
+ * + * @return a flag indicating whether scene antialiasing is available. + */ + public boolean getSceneAntialiasingAvailable() { + return ((Boolean)queryProperties().get("sceneAntialiasingAvailable")). + booleanValue(); + } + + + /** + * Returns a flag indicating whether or not the specified shading + * language is supported. A ShaderError will be generated if an + * unsupported shading language is used. + * + * @param shadingLanguage the shading language being queried, one of: + * Shader.SHADING_LANGUAGE_GLSL or + * Shader.SHADING_LANGUAGE_CG. + * + * @return true if the specified shading language is supported, + * false otherwise. + * + * @since Java 3D 1.4 + */ + public boolean isShadingLanguageSupported(int shadingLanguage) { + // Call queryProperties to ensure that the shading language flags are valid + queryProperties(); + + // Return flag for specified shading language + switch (shadingLanguage) { + case Shader.SHADING_LANGUAGE_GLSL: + return shadingLanguageGLSL; + case Shader.SHADING_LANGUAGE_CG: + return shadingLanguageCg; + } + + return false; + } + + + /** + * Returns a read-only Map object containing key-value pairs that define + * various properties for this Canvas3D. All of the keys are + * String objects. The values are key-specific, but most will be + * Boolean, Integer, Float, Double, or String objects. + * + *

+ * The currently defined keys are: + * + *

+ *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Key (String)Value Type
    shadingLanguageCgBoolean
    shadingLanguageGLSLBoolean
    doubleBufferAvailableBoolean
    stereoAvailableBoolean
    sceneAntialiasingAvailableBoolean
    sceneAntialiasingNumPassesInteger
    stencilSizeInteger
    texture3DAvailableBoolean
    textureColorTableSizeInteger
    textureLodRangeAvailableBoolean
    textureLodOffsetAvailableBoolean
    textureWidthMaxInteger
    textureHeightMaxInteger
    textureBoundaryWidthMaxInteger
    textureEnvCombineAvailableBoolean
    textureCombineDot3AvailableBoolean
    textureCombineSubtractAvailableBoolean
    textureCoordSetsMaxInteger
    textureUnitStateMaxInteger
    textureImageUnitsMaxInteger
    textureImageUnitsVertexMaxInteger
    textureImageUnitsCombinedMaxInteger
    textureCubeMapAvailableBoolean
    textureDetailAvailableBoolean
    textureSharpenAvailableBoolean
    textureFilter4AvailableBoolean
    textureAnisotropicFilterDegreeMaxFloat
    textureNonPowerOfTwoAvailableBoolean
    vertexAttrsMaxInteger
    compressedGeometry.majorVersionNumberInteger
    compressedGeometry.minorVersionNumberInteger
    compressedGeometry.minorMinorVersionNumberInteger
    native.versionString
    + *
+ * + *

+ * The descriptions of the values returned for each key are as follows: + * + *

+ *

    + *
  • + * shadingLanguageCg + *
      + * A Boolean indicating whether or not Cg shading Language + * is available for this Canvas3D. + *
    + *
  • + * + *
  • + * shadingLanguageGLSL + *
      + * A Boolean indicating whether or not GLSL shading Language + * is available for this Canvas3D. + *
    + *
  • + * + *
  • + * doubleBufferAvailable + *
      + * A Boolean indicating whether or not double buffering + * is available for this Canvas3D. This is equivalent to + * the getDoubleBufferAvailable method. If this flag is false, + * the Canvas3D will be rendered in single buffer mode; requests + * to enable double buffering will be ignored. + *
    + *
  • + * + *
  • + * stereoAvailable + *
      + * A Boolean indicating whether or not stereo + * is available for this Canvas3D. This is equivalent to + * the getStereoAvailable method. If this flag is false, + * the Canvas3D will be rendered in monoscopic mode; requests + * to enable stereo will be ignored. + *
    + *
  • + * + *
  • + * sceneAntialiasingAvailable + *
      + * A Boolean indicating whether or not scene antialiasing + * is available for this Canvas3D. This is equivalent to + * the getSceneAntialiasingAvailable method. If this flag is false, + * requests to enable scene antialiasing will be ignored. + *
    + *
  • + * + *
  • + * sceneAntialiasingNumPasses + *
      + * An Integer indicating the number of passes scene antialiasing + * requires to render a single frame for this Canvas3D. + * If this value is zero, scene antialiasing is not supported. + * If this value is one, multisampling antialiasing is used. + * Otherwise, the number indicates the number of rendering passes + * needed. + *
    + *
  • + * + *
  • + * stencilSize + *
      + * An Integer indicating the number of stencil bits that are available + * for this Canvas3D. + *
    + *
  • + * + *
  • + * texture3DAvailable + *
      + * A Boolean indicating whether or not 3D Texture mapping + * is available for this Canvas3D. If this flag is false, + * 3D texture mapping is either not supported by the underlying + * rendering layer or is otherwise unavailable for this + * particular Canvas3D. All use of 3D texture mapping will be + * ignored in this case. + *
    + *
  • + * + *
  • + * textureColorTableSize + *
      + * An Integer indicating the maximum size of the texture color + * table for this Canvas3D. If the size is 0, the texture + * color table is either not supported by the underlying rendering + * layer or is otherwise unavailable for this particular + * Canvas3D. An attempt to use a texture color table larger than + * textureColorTableSize will be ignored; no color lookup will be + * performed. + *
    + *
  • + * + *
  • + * textureLodRangeAvailable + *
      + * A Boolean indicating whether or not setting only a subset of mipmap + * levels and setting a range of texture LOD are available for this + * Canvas3D. + * If it indicates false, setting a subset of mipmap levels and + * setting a texture LOD range are not supported by the underlying + * rendering layer, and an attempt to set base level, or maximum level, + * or minimum LOD, or maximum LOD will be ignored. In this case, + * images for all mipmap levels must be defined for the texture to be + * valid. + *
    + *
  • + * + *
  • + * textureLodOffsetAvailable + *
      + * A Boolean indicating whether or not setting texture LOD offset is + * available for this Canvas3D. If it indicates false, setting + * texture LOD offset is not supported by the underlying rendering + * layer, and an attempt to set the texture LOD offset will be ignored. + *
    + *
  • + * + *
  • + * textureWidthMax + *
      + * An Integer indicating the maximum texture width supported by + * this Canvas3D. If the width of a texture exceeds the maximum texture + * width for a Canvas3D, then the texture will be effectively disabled + * for that Canvas3D. + *
    + *
  • + * + *
  • + * textureHeightMax + *
      + * An Integer indicating the maximum texture height supported by + * this Canvas3D. If the height of a texture exceeds the maximum texture + * height for a Canvas3D, then the texture will be effectively disabled + * for that Canvas3D. + *
    + *
  • + * + *
  • + * textureBoundaryWidthMax + *
      + * An Integer indicating the maximum texture boundary width + * supported by the underlying rendering layer for this Canvas3D. If + * the maximum supported texture boundary width is 0, then texture + * boundary is not supported by the underlying rendering layer. + * An attempt to specify a texture boundary width > the + * textureBoundaryWidthMax will effectively disable the texture. + *
    + *
  • + * + *
  • + * textureEnvCombineAvailable + *
      + * A Boolean indicating whether or not texture environment combine + * operation is supported for this Canvas3D. If it indicates false, + * then texture environment combine is not supported by the + * underlying rendering layer, and an attempt to specify COMBINE + * as the texture mode will be ignored. The texture mode in effect + * will be REPLACE. + *
    + *
  • + * + *
  • + * textureCombineDot3Available + *
      + * A Boolean indicating whether or not texture combine mode + * COMBINE_DOT3 is + * supported for this Canvas3D. If it indicates false, then + * texture combine mode COMBINE_DOT3 is not supported by + * the underlying rendering layer, and an attempt to specify + * COMBINE_DOT3 as the texture combine mode will be ignored. + * The texture combine mode in effect will be COMBINE_REPLACE. + *
    + *
  • + * + *
  • + * textureCombineSubtractAvailable + *
      + * A Boolean indicating whether or not texture combine mode + * COMBINE_SUBTRACT is + * supported for this Canvas3D. If it indicates false, then + * texture combine mode COMBINE_SUBTRACT is not supported by + * the underlying rendering layer, and an attempt to specify + * COMBINE_SUBTRACT as the texture combine mode will be ignored. + * The texture combine mode in effect will be COMBINE_REPLACE. + *
    + *
  • + * + *
  • + * textureCoordSetsMax + *
      + * An Integer indicating the maximum number of texture coordinate sets + * supported by the underlying rendering layer. + *
    + *
  • + * + *
  • + * textureUnitStateMax + *
      + * An Integer indicating the maximum number of fixed-function texture units + * supported by the underlying rendering layer. If the number of + * application-sepcified texture unit states exceeds the maximum number + * for a Canvas3D, and the fixed-function rendering pipeline is used, then + * the texture will be effectively disabled for that Canvas3D. + *
    + *
  • + * + *
  • + * textureImageUnitsMax + *
      + * An Integer indicating the maximum number of texture image units + * that can be accessed by the fragment shader when programmable shaders + * are used. + *
    + *
  • + * + *
  • + * textureImageUnitsVertexMax + *
      + * An Integer indicating the maximum number of texture image units + * that can be accessed by the vertex shader when programmable shaders + * are used. + *
    + *
  • + * + *
  • + * textureImageUnitsCombinedMax + *
      + * An Integer indicating the combined maximum number of texture image units + * that can be accessed by the vertex shader and the fragment shader when + * programmable shaders are used. + *
    + *
  • + * + *
  • + * textureCubeMapAvailable + *
      + * A Boolean indicating whether or not texture cube map is supported + * for this Canvas3D. If it indicates false, then texture cube map + * is not supported by the underlying rendering layer, and an attempt + * to specify NORMAL_MAP or REFLECTION_MAP as the texture generation + * mode will be ignored. The texture generation mode in effect will + * be SPHERE_MAP. + *
    + *
  • + * + *
  • + * textureDetailAvailable + *
      + * A Boolean indicating whether or not detail texture is supported + * for this Canvas3D. If it indicates false, then detail texture is + * not supported by the underlying rendering layer, and an attempt + * to specify LINEAR_DETAIL, LINEAR_DETAIL_ALPHA or + * LINEAR_DETAIL_RGB as the texture magnification filter mode will + * be ignored. The texture magnification filter mode in effect will + * be BASE_LEVEL_LINEAR. + * As of Java 3D 1.5, this property is always false. + *
    + *
  • + * + *
  • + * textureSharpenAvailable + *
      + * A Boolean indicating whether or not sharpen texture is supported + * for this Canvas3D. If it indicates false, then sharpen texture + * is not supported by the underlying rendering layer, and an attempt + * to specify LINEAR_SHARPEN, LINEAR_SHARPEN_ALPHA or + * LINEAR_SHARPEN_RGB as the texture magnification filter mode + * will be ignored. The texture magnification filter mode in effect + * will be BASE_LEVEL_LINEAR. + *
    + *
  • + * + *
  • + * textureFilter4Available + *
      + * A Boolean indicating whether or not filter4 is supported for this + * Canvas3D. If it indicates flase, then filter4 is not supported + * by the underlying rendering layer, and an attempt to specify + * FILTER_4 as the texture minification filter mode or texture + * magnification filter mode will be ignored. The texture filter mode + * in effect will be BASE_LEVEL_LINEAR. + *
    + *
  • + * + *
  • + * textureAnisotropicFilterDegreeMax + *
      + * A Float indicating the maximum degree of anisotropic filter + * available for this Canvas3D. If it indicates 1.0, setting + * anisotropic filter is not supported by the underlying rendering + * layer, and an attempt to set anisotropic filter degree will be ignored. + *
    + *
  • + + *
  • + * textureNonPowerOfTwoAvailable + *
      + * A Boolean indicating whether or not texture dimensions that are + * not powers of two are supported for + * for this Canvas3D. If it indicates false, then textures with + * non power of two sizes will be ignored. Set the property + * j3d.textureEnforcePowerOfTwo to revert to the pre-1.5 behavior + * of throwing exceptions for non power of two textures. + *
    + *
  • + * + *
  • + * vertexAttrsMax + *
      + * An Integer indicating the maximum number of vertex attributes + * supported by the underlying rendering layer. This is in addition to + * the vertex coordinate (position), color, normal, and so forth. + *
    + *
  • + * + *
  • + * compressedGeometry.majorVersionNumber
    + * compressedGeometry.minorVersionNumber
    + * compressedGeometry.minorMinorVersionNumber + *
      + * Integers indicating the major, minor, and minor-minor + * version numbers, respectively, of the version of compressed + * geometry supported by this version of Java 3D. + *
    + *
  • + * + *
  • + * native.version + *
      + * A String indicating the version number of the native graphics + * library. The format of this string is defined by the native + * library. + *
    + *
  • + *
+ * + * @return the properties of this Canavs3D + * + * @since Java 3D 1.2 + */ + public final Map queryProperties() { + if (queryProps == null) { + boolean createDummyCtx = false; + + synchronized (VirtualUniverse.mc.contextCreationLock) { + if (ctx == null) { + createDummyCtx = true; + } + } + + if (createDummyCtx) { + GraphicsConfigTemplate3D.setQueryProps(this); + } + + //create query Properties + createQueryProps(); + } + + if (fatalError) { + throw new IllegalStateException(J3dI18N.getString("Canvas3D29")); + } + + return queryProps; + } + + void createQueryContext() { + // create a dummy context to query for support of certain + // extensions, the context will destroy immediately + // inside the native code after setting the various + // fields in this object + createQueryContext(screen.display, drawable, + fbConfig, offScreen, 1, 1, + VirtualUniverse.mc.glslLibraryAvailable, + VirtualUniverse.mc.cgLibraryAvailable); + // compute the max available texture units + maxAvailableTextureUnits = Math.max(maxTextureUnits, maxTextureImageUnits); + } + + /** + * Creates the query properties for this Canvas. + */ + private void createQueryProps() { + // Create lists of keys and values + ArrayList keys = new ArrayList(); + ArrayList values = new ArrayList(); + int pass = 0; + + // properties not associated with graphics context + keys.add("doubleBufferAvailable"); + values.add(new Boolean(doubleBufferAvailable)); + + keys.add("stereoAvailable"); + values.add(new Boolean(stereoAvailable)); + + keys.add("sceneAntialiasingAvailable"); + values.add(new Boolean(sceneAntialiasingAvailable)); + + keys.add("sceneAntialiasingNumPasses"); + + if (sceneAntialiasingAvailable) { + pass = (sceneAntialiasingMultiSamplesAvailable ? + 1: Renderer.NUM_ACCUMULATION_SAMPLES); + } + values.add(new Integer(pass)); + + keys.add("stencilSize"); + // Return the actual stencil size if the user owns it, otherwise + // return 0 + if (userStencilAvailable) { + values.add(new Integer(actualStencilSize)); + } else { + values.add(new Integer(0)); + } + + keys.add("compressedGeometry.majorVersionNumber"); + values.add(new Integer(GeometryDecompressor.majorVersionNumber)); + keys.add("compressedGeometry.minorVersionNumber"); + values.add(new Integer(GeometryDecompressor.minorVersionNumber)); + keys.add("compressedGeometry.minorMinorVersionNumber"); + values.add(new Integer(GeometryDecompressor.minorMinorVersionNumber)); + + // Properties associated with graphics context + keys.add("texture3DAvailable"); + values.add(new Boolean((textureExtendedFeatures & TEXTURE_3D) != 0)); + + keys.add("textureColorTableSize"); + values.add(new Integer(textureColorTableSize)); + + keys.add("textureEnvCombineAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_COMBINE) != 0)); + + keys.add("textureCombineDot3Available"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_COMBINE_DOT3) != 0)); + + keys.add("textureCombineSubtractAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_COMBINE_SUBTRACT) != 0)); + + keys.add("textureCubeMapAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_CUBE_MAP) != 0)); + + keys.add("textureSharpenAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_SHARPEN) != 0)); + + keys.add("textureDetailAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_DETAIL) != 0)); + + keys.add("textureFilter4Available"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_FILTER4) != 0)); + + keys.add("textureAnisotropicFilterDegreeMax"); + values.add(new Float(anisotropicDegreeMax)); + + keys.add("textureWidthMax"); + values.add(new Integer(textureWidthMax)); + + keys.add("textureHeightMax"); + values.add(new Integer(textureHeightMax)); + + keys.add("texture3DWidthMax"); + values.add(new Integer(texture3DWidthMax)); + + keys.add("texture3DHeightMax"); + values.add(new Integer(texture3DHeightMax)); + + keys.add("texture3DDepthMax"); + values.add(new Integer(texture3DDepthMax)); + + keys.add("textureBoundaryWidthMax"); + values.add(new Integer(textureBoundaryWidthMax)); + + keys.add("textureLodRangeAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_LOD_RANGE) != 0)); + + keys.add("textureLodOffsetAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_LOD_OFFSET) != 0)); + + keys.add("textureNonPowerOfTwoAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_NON_POWER_OF_TWO) != 0)); + + keys.add("textureAutoMipMapGenerationAvailable"); + values.add(new Boolean( + (textureExtendedFeatures & TEXTURE_AUTO_MIPMAP_GENERATION) != 0)); + + keys.add("textureCoordSetsMax"); + values.add(new Integer(maxTexCoordSets)); + + keys.add("textureUnitStateMax"); + values.add(new Integer(maxTextureUnits)); + + keys.add("textureImageUnitsMax"); + values.add(new Integer(maxTextureImageUnits)); + + keys.add("textureImageUnitsVertexMax"); + values.add(new Integer(maxVertexTextureImageUnits)); + + keys.add("textureImageUnitsCombinedMax"); + values.add(new Integer(maxCombinedTextureImageUnits)); + + keys.add("vertexAttrsMax"); + values.add(new Integer(maxVertexAttrs)); + + keys.add("shadingLanguageGLSL"); + values.add(new Boolean(shadingLanguageGLSL)); + + keys.add("shadingLanguageCg"); + values.add(new Boolean(shadingLanguageCg)); + + keys.add("native.version"); + values.add(nativeGraphicsVersion); + + keys.add("native.vendor"); + values.add(nativeGraphicsVendor); + + keys.add("native.renderer"); + values.add(nativeGraphicsRenderer); + + // Now Create read-only properties object + queryProps = + new J3dQueryProps((String[]) keys.toArray(new String[0]), + values.toArray()); + } + + + /** + * Update the view cache associated with this canvas. + */ + void updateViewCache(boolean flag, CanvasViewCache cvc, + BoundingBox frustumBBox, boolean doInfinite) { + + assert cvc == null; + synchronized(cvLock) { + if (firstPaintCalled && (canvasViewCache != null)) { + assert canvasViewCacheFrustum != null; + // Issue 109 : choose the appropriate cvCache + if (frustumBBox != null) { + canvasViewCacheFrustum.snapshot(true); + canvasViewCacheFrustum.computeDerivedData(flag, null, + frustumBBox, doInfinite); + } else { + canvasViewCache.snapshot(false); + canvasViewCache.computeDerivedData(flag, null, + null, doInfinite); + } + } + } + } + + /** + * Set depthBufferWriteEnableOverride flag + */ + void setDepthBufferWriteEnableOverride(boolean flag) { + depthBufferWriteEnableOverride = flag; + } + + /** + * Set depthBufferEnableOverride flag + */ + void setDepthBufferEnableOverride(boolean flag) { + depthBufferEnableOverride = flag; + } + + // Static initializer for Canvas3D class + static { + VirtualUniverse.loadLibraries(); + } + + + void resetTexture(Context ctx, int texUnitIndex) { + // D3D also need to reset texture attributes + this.resetTextureNative(ctx, texUnitIndex); + + if (texUnitIndex < 0) { + texUnitIndex = 0; + } + texUnitState[texUnitIndex].mirror = null; + texUnitState[texUnitIndex].texture = null; + + if (VirtualUniverse.mc.isD3D()) { + texUnitState[texUnitIndex].texAttrs = null; + texUnitState[texUnitIndex].texGen = null; + } + } + + + // use by D3D only + void resetTextureBin() { + Object obj; + TextureRetained tex; + + // We don't use rdr.objectId for background texture in D3D + // so there is no need to handle rdr.objectId + if ((graphics2D != null) && + (graphics2D.objectId != -1)) { + VirtualUniverse.mc.freeTexture2DId(graphics2D.objectId); + // let J3DGraphics2DImpl to initialize texture again + graphics2D.objectId = -1; + } + + for (int id = textureIDResourceTable.size()-1; id >= 0; id--) { + obj = textureIDResourceTable.get(id); + if (obj != null) { + if (obj instanceof TextureRetained) { + tex = (TextureRetained) obj; + tex.resourceCreationMask &= ~canvasBit; + } + } + } + } + + + void d3dResize() { + assert VirtualUniverse.mc.isD3D(); + int status = resizeD3DCanvas(ctx); + + antialiasingSet = false; + + // We need to reevaluate everything since d3d may create + // a new ctx + if (status != NOCHANGE) { + resetRendering(status); + } + } + + void d3dToggle() { + assert VirtualUniverse.mc.isD3D(); + int status = toggleFullScreenMode(ctx); + + antialiasingSet = false; + if (status != NOCHANGE) { + resetRendering(status); + } + } + + // use by D3D only + void notifyD3DPeer(int cmd) { + assert VirtualUniverse.mc.isD3D(); + if (active) { + if (isRunning) { + if ((view != null) && + (view.active) && + // it is possible that view is set active by MC + // but renderer not yet set + (screen.renderer != null)) { + VirtualUniverse.mc.postRequest(MasterControl.STOP_RENDERER, this); + + while (isRunningStatus) { + MasterControl.threadYield(); + } + J3dMessage renderMessage = new J3dMessage(); + renderMessage.threads = J3dThread.RENDER_THREAD; + if (cmd == RESIZE) { + renderMessage.type = J3dMessage.RESIZE_CANVAS; + } else { + renderMessage.type = J3dMessage.TOGGLE_CANVAS; + } + renderMessage.universe = null; + renderMessage.view = null; + renderMessage.args[0] = this; + + screen.renderer.rendererStructure.addMessage(renderMessage); + VirtualUniverse.mc.postRequest(MasterControl.START_RENDERER, this); + VirtualUniverse.mc.sendRunMessage(view, + J3dThread.RENDER_THREAD); + } + } else { + // may be in immediate mode + reEvaluateCanvasCmd = cmd; + } + } + } + + // reset all attributes so that everything e.g. display list, + // texture will recreate again in the next frame + void resetRendering(int status) { + + if (status == RECREATEDDRAW) { + // D3D use MANAGE_POOL when createTexture, so there + // is no need to download texture again in case of RESETSURFACE + resetTextureBin(); + screen.renderer.needToResendTextureDown = true; + } + + reset(); + + synchronized (dirtyMaskLock) { + cvDirtyMask[0] |= VIEW_INFO_DIRTY; + cvDirtyMask[1] |= VIEW_INFO_DIRTY; + } + + } + + + void reset() { + int i; + currentAppear = new AppearanceRetained(); + currentMaterial = new MaterialRetained(); + viewFrustum = new CachedFrustum(); + canvasDirty = 0xffff; + lightBin = null; + environmentSet = null; + attributeBin = null; + shaderBin = null; + textureBin = null; + renderMolecule = null; + polygonAttributes = null; + lineAttributes = null; + pointAttributes = null; + material = null; + enableLighting = false; + transparency = null; + coloringAttributes = null; + shaderProgram = null; + texture = null; + texAttrs = null; + if (texUnitState != null) { + TextureUnitStateRetained tus; + for (i=0; i < texUnitState.length; i++) { + tus = texUnitState[i]; + if (tus != null) { + tus.texAttrs = null; + tus.texGen = null; + } + } + } + texCoordGeneration = null; + renderingAttrs = null; + appearance = null; + appHandle = null; + dirtyRenderMoleculeList.clear(); + displayListResourceFreeList.clear(); + + dirtyDlistPerRinfoList.clear(); + textureIdResourceFreeList.clear(); + + lightChanged = true; + modelMatrix = null; + modelClip = null; + fog = null; + texLinearMode = false; + sceneAmbient = new Color3f(); + + + for (i=0; i< frameCount.length;i++) { + frameCount[i] = -1; + } + + for (i=0; i < lights.length; i++) { + lights[i] = null; + } + + if (currentLights != null) { + for (i=0; i < currentLights.length; i++) { + currentLights[i] = null; + } + } + + enableMask = -1; + stateUpdateMask = 0; + depthBufferWriteEnableOverride = false; + depthBufferEnableOverride = false; + depthBufferWriteEnable = true; + vfPlanesValid = false; + lightChanged = false; + + for (i=0; i < curStateToUpdate.length; i++) { + curStateToUpdate[i] = null; + } + + // Issue 362 - need to reset display lists and ctxTimeStamp in this + // method, so that display lists will be recreated when canvas is + // removed from a view and then added back into a view with another + // canvas + needToRebuildDisplayList = true; + ctxTimeStamp = VirtualUniverse.mc.getContextTimeStamp(); + } + + + void resetImmediateRendering(int status) { + canvasDirty = 0xffff; + ra = null; + + setSceneAmbient(ctx, 0.0f, 0.0f, 0.0f); + disableFog(ctx); + resetRenderingAttributes(ctx, false, false); + + resetTexture(ctx, -1); + resetTexCoordGeneration(ctx); + resetTextureAttributes(ctx); + texUnitState[0].texAttrs = null; + texUnitState[0].texGen = null; + + resetPolygonAttributes(ctx); + resetLineAttributes(ctx); + resetPointAttributes(ctx); + resetTransparency(ctx, + RenderMolecule.SURFACE, + PolygonAttributes.POLYGON_FILL, + false, false); + resetColoringAttributes(ctx, + 1.0f, 1.0f, + 1.0f, 1.0f, false); + updateMaterial(ctx, 1.0f, 1.0f, 1.0f, 1.0f); + resetRendering(NOCHANGE); + makeCtxCurrent(); + synchronized (dirtyMaskLock) { + cvDirtyMask[0] |= VIEW_INFO_DIRTY; + cvDirtyMask[1] |= VIEW_INFO_DIRTY; + } + needToRebuildDisplayList = true; + + ctxTimeStamp = VirtualUniverse.mc.getContextTimeStamp(); + if (status == RECREATEDDRAW) { + screen.renderer.needToResendTextureDown = true; + } + } + + + // overide Canvas.getSize() + public Dimension getSize() { + if (!fullScreenMode) { + return super.getSize(); + } else { + return new Dimension(fullscreenWidth, fullscreenHeight); + } + } + + public Dimension getSize(Dimension rv) { + if (!fullScreenMode) { + return super.getSize(rv); + } else { + if (rv == null) { + return new Dimension(fullscreenWidth, fullscreenHeight); + } else { + rv.setSize(fullscreenWidth, fullscreenHeight); + return rv; + } + } + } + + public Point getLocationOnScreen() { + if (!fullScreenMode) { + try { + return super.getLocationOnScreen(); + } catch (IllegalComponentStateException e) {} + } + return new Point(); + } + + public int getX() { + if (!fullScreenMode) { + return super.getX(); + } else { + return 0; + } + } + + + public int getY() { + if (!fullScreenMode) { + return super.getY(); + } else { + return 0; + } + } + + public int getWidth() { + if (!fullScreenMode) { + return super.getWidth(); + } else { + return screen.screenSize.width; + } + } + + public int getHeight() { + if (!fullScreenMode) { + return super.getHeight(); + } else { + return screen.screenSize.height; + } + } + + public Point getLocation(Point rv) { + if (!fullScreenMode) { + return super.getLocation(rv); + } else { + if (rv != null) { + rv.setLocation(0, 0); + return rv; + } else { + return new Point(); + } + } + } + + public Point getLocation() { + if (!fullScreenMode) { + return super.getLocation(); + } else { + return new Point(); + } + } + + public Rectangle getBounds() { + if (!fullScreenMode) { + return super.getBounds(); + } else { + return new Rectangle(0, 0, + screen.screenSize.width, + screen.screenSize.height); + } + } + + public Rectangle getBounds(Rectangle rv) { + if (!fullScreenMode) { + return super.getBounds(rv); + } else { + if (rv != null) { + rv.setBounds(0, 0, + screen.screenSize.width, + screen.screenSize.height); + return rv; + } else { + return new Rectangle(0, 0, + screen.screenSize.width, + screen.screenSize.height); + } + } + } + + void setProjectionMatrix(Context ctx, Transform3D projTrans) { + this.projTrans = projTrans; + setProjectionMatrix(ctx, projTrans.mat); + } + + void setModelViewMatrix(Context ctx, double[] viewMatrix, Transform3D mTrans) { + setModelViewMatrix(ctx, viewMatrix, mTrans.mat); + if (!useStereo) { + this.modelMatrix = mTrans; + } else { + // TODO : This seems wrong to do only for the right eye. + // A possible approach is to invalidate the cache at begin of + // each eye. + if (rightStereoPass) { + // Only set cache in right stereo pass, otherwise + // if the left stereo pass set the cache value, + // setModelViewMatrix() in right stereo pass will not + // perform in RenderMolecules. + this.modelMatrix = mTrans; + } + } + } + + void setDepthBufferWriteEnable(boolean mode) { + depthBufferWriteEnable = mode; + setDepthBufferWriteEnable(ctx, mode); + } + + void setNumActiveTexUnit(int n) { + numActiveTexUnit = n; + } + + int getNumActiveTexUnit() { + return numActiveTexUnit; + } + + void setLastActiveTexUnit(int n) { + lastActiveTexUnit = n; + } + + int getLastActiveTexUnit() { + return lastActiveTexUnit; + } + + // Create the texture state array + void createTexUnitState() { + texUnitState = new TextureUnitStateRetained[maxAvailableTextureUnits]; + for (int t = 0; t < maxAvailableTextureUnits; t++) { + texUnitState[t] = new TextureUnitStateRetained(); + texUnitState[t].texture = null; + texUnitState[t].mirror = null; + } + } + + boolean supportGlobalAlpha() { + return ((extensionsSupported & SUN_GLOBAL_ALPHA) != 0); + } + + /** + * Enable separate specular color if it is not overriden by the + * property j3d.disableSeparateSpecular. + */ + void enableSeparateSpecularColor() { + boolean enable = !VirtualUniverse.mc.disableSeparateSpecularColor; + updateSeparateSpecularColorEnable(ctx, enable); + } + + final void beginScene() { + beginScene(ctx); + } + + final void endScene() { + endScene(ctx); + } + + + // Send a createOffScreenBuffer message to Renderer (via + // MasterControl) and wait for it to be done + private void sendCreateOffScreenBuffer() { + // Wait for the buffer to be created unless called from + // a Behavior or from a Rendering thread + if (!(Thread.currentThread() instanceof BehaviorScheduler) && + !(Thread.currentThread() instanceof Renderer)) { + + offScreenBufferPending = true; + } + + // Send message to Renderer thread to perform createOffScreenBuffer. + VirtualUniverse.mc.sendCreateOffScreenBuffer(this); + + // Wait for off-screen buffer to be created + while (offScreenBufferPending) { + // Issue 364: create master control thread if needed + VirtualUniverse.mc.createMasterControlThread(); + MasterControl.threadYield(); + } + } + + // Send a destroyOffScreenBuffer message to Renderer (via + // MasterControl) and wait for it to be done + private void sendDestroyCtxAndOffScreenBuffer() { + // Wait for the buffer to be destroyed unless called from + // a Behavior or from a Rendering thread + Thread currentThread = Thread.currentThread(); + if (!(currentThread instanceof BehaviorScheduler) && + !(currentThread instanceof Renderer)) { + + offScreenBufferPending = true; + } + + // Fix for Issue 18 and Issue 175 + // Send message to Renderer thread to perform remove Ctx and destroyOffScreenBuffer. + + VirtualUniverse.mc.sendDestroyCtxAndOffScreenBuffer(this); + + // Wait for ctx and off-screen buffer to be destroyed + while (offScreenBufferPending) { + // Issue 364: create master control thread if needed + VirtualUniverse.mc.createMasterControlThread(); + MasterControl.threadYield(); + } + } + + // Send a allocateCanvasId message to Renderer (via MasterControl) without + // waiting for it to be done + private void sendAllocateCanvasId() { + // Send message to Renderer thread to allocate a canvasId + VirtualUniverse.mc.sendAllocateCanvasId(this); + } + + // Send a freeCanvasId message to Renderer (via MasterControl) without + // waiting for it to be done + private void sendFreeCanvasId() { + // Send message to Renderer thread to free the canvasId + VirtualUniverse.mc.sendFreeCanvasId(this); + } + + private void removeCtx() { + + if ((screen != null) && + (screen.renderer != null) && + (ctx != null)) { + VirtualUniverse.mc.postRequest(MasterControl.FREE_CONTEXT, + new Object[]{this, + new Long(screen.display), + drawable, + ctx}); + // Fix for Issue 19 + // Wait for the context to be freed unless called from + // a Behavior or from a Rendering thread + Thread currentThread = Thread.currentThread(); + if (!(currentThread instanceof BehaviorScheduler) && + !(currentThread instanceof Renderer)) { + while (ctxTimeStamp != 0) { + MasterControl.threadYield(); + } + } + ctx = null; + } + } + + /** + * Serialization of Canvas3D objects is not supported. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + private void writeObject(java.io.ObjectOutputStream out) + throws java.io.IOException { + + throw new UnsupportedOperationException(J3dI18N.getString("Canvas3D20")); + } + + /** + * Serialization of Canvas3D objects is not supported. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + private void readObject(java.io.ObjectInputStream in) + throws java.io.IOException, ClassNotFoundException { + + throw new UnsupportedOperationException(J3dI18N.getString("Canvas3D20")); + } + + + // mark that the current bin specified by the bit is already updated + void setStateIsUpdated(int bit) { + stateUpdateMask &= ~(1 << bit); + } + + // mark that the bin specified by the bit needs to be updated + void setStateToUpdate(int bit, Object bin) { + stateUpdateMask |= 1 << bit; + curStateToUpdate[bit] = bin; + } + + // update LightBin, EnvironmentSet, AttributeBin & ShaderBin if neccessary + // according to the stateUpdateMask + + static int ENV_STATE_MASK = (1 << LIGHTBIN_BIT) | + (1 << ENVIRONMENTSET_BIT) | + (1 << ATTRIBUTEBIN_BIT) | + (1 << SHADERBIN_BIT); + + void updateEnvState() { + + if ((stateUpdateMask & ENV_STATE_MASK) == 0) + return; + + if ((stateUpdateMask & (1 << LIGHTBIN_BIT)) != 0) { + ((LightBin)curStateToUpdate[LIGHTBIN_BIT]).updateAttributes(this); + } + + if ((stateUpdateMask & (1 << ENVIRONMENTSET_BIT)) != 0) { + ((EnvironmentSet) + curStateToUpdate[ENVIRONMENTSET_BIT]).updateAttributes(this); + } + + if ((stateUpdateMask & (1 << ATTRIBUTEBIN_BIT)) != 0) { + ((AttributeBin) + curStateToUpdate[ATTRIBUTEBIN_BIT]).updateAttributes(this); + } + + if ((stateUpdateMask & (1 << SHADERBIN_BIT)) != 0) { + ((ShaderBin) + curStateToUpdate[SHADERBIN_BIT]).updateAttributes(this); + } + + + // reset the state update mask for those environment state bits + stateUpdateMask &= ~ENV_STATE_MASK; + } + + /** + * update state if neccessary according to the stateUpdatedMask + */ + void updateState( int dirtyBits) { + + + if (stateUpdateMask == 0) + return; + + updateEnvState(); + + if ((stateUpdateMask & (1 << TEXTUREBIN_BIT)) != 0) { + ((TextureBin) + curStateToUpdate[TEXTUREBIN_BIT]).updateAttributes(this); + } + + if ((stateUpdateMask & (1 << RENDERMOLECULE_BIT)) != 0) { + ((RenderMolecule) + curStateToUpdate[RENDERMOLECULE_BIT]).updateAttributes(this, + dirtyBits); + + } + + if ((stateUpdateMask & (1 << TRANSPARENCY_BIT)) != 0) { + ((RenderMolecule)curStateToUpdate[RENDERMOLECULE_BIT]).updateTransparencyAttributes(this); + stateUpdateMask &= ~(1 << TRANSPARENCY_BIT); + } + + // reset state update mask + stateUpdateMask = 0; + } + + + // This method updates this Texture2D for raster. + // Note : No multi-texture is not used. + void updateTextureForRaster(Texture2DRetained texture) { + + // Setup texture and texture attributes for texture unit 0. + Pipeline.getPipeline().updateTextureUnitState(ctx, 0, true); + setLastActiveTexUnit(0); + setNumActiveTexUnit(1); + + texture.updateNative(this); + resetTextureAttributes(ctx); + + for(int i=1; i < maxTextureUnits; i++) { + resetTexture(ctx, i); + } + + // set the active texture unit back to 0 + activeTextureUnit(ctx, 0); + + // Force the next textureBin to reload. + canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY | Canvas3D.TEXTUREATTRIBUTES_DIRTY; + } + + void restoreTextureBin() { + + // Need to check TextureBin's shaderBin for null + // TextureBin can get clear() if there isn't any RM under it. + if((textureBin != null) && (textureBin.shaderBin != null)) { + textureBin.updateAttributes(this); + } + } + + void textureFill(RasterRetained raster, Point2d winCoord, + float mapZ, float alpha) { + + int winWidth = canvasViewCache.getCanvasWidth(); + int winHeight = canvasViewCache.getCanvasHeight(); + + int rasterImageWidth = raster.image.width; + int rasterImageHeight = raster.image.height; + + float texMinU = 0, texMinV = 0, texMaxU = 0, texMaxV = 0; + float mapMinX = 0, mapMinY = 0, mapMaxX = 0, mapMaxY = 0; + + Point rasterSrcOffset = new Point(); + raster.getSrcOffset(rasterSrcOffset); + + Dimension rasterSize = new Dimension(); + raster.getSize(rasterSize); + +// System.err.println("rasterImageWidth " + rasterImageWidth + " rasterImageHeight " + rasterImageHeight); +// System.err.println("rasterSrcOffset " + rasterSrcOffset + " rasterSize " + rasterSize); + + int rasterMinX = rasterSrcOffset.x; + int rasterMaxX = rasterSrcOffset.x + rasterSize.width; + int rasterMinY = rasterSrcOffset.y; + int rasterMaxY = rasterSrcOffset.y + rasterSize.height; + + if ((rasterMinX >= rasterImageWidth) || (rasterMinY >= rasterImageHeight) || + (rasterMaxX <= 0) || (rasterMaxY <= 0)) { + return; + } + + if (rasterMinX < 0) { + rasterMinX = 0; + } + if (rasterMinY < 0) { + rasterMinY = 0; + } + + if (rasterMaxX > rasterImageWidth) { + rasterMaxX = rasterImageWidth; + } + + if (rasterMaxY > rasterImageHeight) { + rasterMaxY = rasterImageHeight; + } + + texMinU = (float) rasterMinX / (float) rasterImageWidth; + texMaxU = (float) rasterMaxX / (float) rasterImageWidth; + mapMinX = (float) winCoord.x / (float) winWidth; + mapMaxX = (float) (winCoord.x + (rasterMaxX - rasterMinX)) / (float) winWidth; + + if (raster.image.isYUp()) { + texMinV = (float) rasterMinY / (float) rasterImageHeight; + texMaxV = (float) rasterMaxY / (float) rasterImageHeight; + } else { + // System.err.println("In yUp is false case"); + texMinV = 1.0f - (float) rasterMaxY / (float) rasterImageHeight; + texMaxV = 1.0f - (float) rasterMinY / (float) rasterImageHeight; + } + + mapMinY = 1.0f - ((float) (winCoord.y + (rasterMaxY - rasterMinY)) / (float) winHeight); + mapMaxY = 1.0f - ((float) winCoord.y / (float) winHeight); + + textureFillRaster(ctx, texMinU, texMaxU, texMinV, texMaxV, + mapMinX, mapMaxX, mapMinY, mapMaxY, mapZ, alpha, raster.image.useBilinearFilter()); + + } + + void textureFill(BackgroundRetained bg, int winWidth, int winHeight) { + + final int maxX = bg.image.width; + final int maxY = bg.image.height; + +// System.err.println("maxX " + maxX + " maxY " + maxY); + + float xzoom = (float)winWidth / maxX; + float yzoom = (float)winHeight / maxY; + float zoom = 0; + float texMinU = 0, texMinV = 0, texMaxU = 0, texMaxV = 0, adjustV = 0; + float mapMinX = 0, mapMinY = 0, mapMaxX = 0, mapMaxY = 0; + float halfWidth = 0, halfHeight = 0; + + switch (bg.imageScaleMode) { + case Background.SCALE_NONE: + texMinU = 0.0f; + texMinV = 0.0f; + texMaxU = 1.0f; + texMaxV = 1.0f; + halfWidth = (float)winWidth/2.0f; + halfHeight = (float)winHeight/2.0f; + mapMinX = (float) ((0 - halfWidth)/halfWidth); + mapMinY = (float) ((0 - halfHeight)/halfHeight); + mapMaxX = (float) ((maxX - halfWidth)/halfWidth); + mapMaxY = (float) ((maxY - halfHeight)/halfHeight); + adjustV = ((float)winHeight - (float)maxY)/halfHeight; + mapMinY += adjustV; + mapMaxY += adjustV; + break; + case Background.SCALE_FIT_MIN: + zoom = Math.min(xzoom, yzoom); + texMinU = 0.0f; + texMinV = 0.0f; + texMaxU = 1.0f; + texMaxV = 1.0f; + mapMinX = -1.0f; + mapMaxY = 1.0f; + if (xzoom < yzoom) { + mapMaxX = 1.0f; + mapMinY = -1.0f + 2.0f * ( 1.0f - zoom * (float)maxY/(float) winHeight ); + } else { + mapMaxX = -1.0f + zoom * (float)maxX/winWidth * 2; + mapMinY = -1.0f; + } + break; + case Background.SCALE_FIT_MAX: + zoom = Math.max(xzoom, yzoom); + mapMinX = -1.0f; + mapMinY = -1.0f; + mapMaxX = 1.0f; + mapMaxY = 1.0f; + if (xzoom < yzoom) { + texMinU = 0.0f; + texMinV = 0.0f; + texMaxU = (float)winWidth/maxX/zoom; + texMaxV = 1.0f; + } else { + texMinU = 0.0f; + texMinV = 1.0f - (float)winHeight/maxY/zoom; + texMaxU = 1.0f; + texMaxV = 1.0f; + } + break; + case Background.SCALE_FIT_ALL: + texMinU = 0.0f; + texMinV = 0.0f; + texMaxU = 1.0f; + texMaxV = 1.0f; + mapMinX = -1.0f; + mapMinY = -1.0f; + mapMaxX = 1.0f; + mapMaxY = 1.0f; + break; + case Background.SCALE_REPEAT: + + texMinU = 0.0f; + texMinV = - yzoom; + texMaxU = xzoom; + texMaxV = 0.0f; + mapMinX = -1.0f; + mapMinY = -1.0f; + mapMaxX = 1.0f; + mapMaxY = 1.0f; + break; + case Background.SCALE_NONE_CENTER: + // TODO : Why is there a zoom ? + if(xzoom >= 1.0f){ + texMinU = 0.0f; + texMaxU = 1.0f; + mapMinX = -(float)maxX/winWidth; + mapMaxX = (float)maxX/winWidth; + } else { + texMinU = 0.5f - (float)winWidth/maxX/2; + texMaxU = 0.5f + (float)winWidth/maxX/2; + mapMinX = -1.0f; + mapMaxX = 1.0f; + } + if (yzoom >= 1.0f) { + texMinV = 0.0f; + texMaxV = 1.0f; + mapMinY = -(float)maxY/winHeight; + mapMaxY = (float)maxY/winHeight; + } else { + texMinV = 0.5f - (float)winHeight/maxY/2; + texMaxV = 0.5f + (float)winHeight/maxY/2; + mapMinY = -1.0f; + mapMaxY = 1.0f; + } + break; + } + +// System.err.println("Java 3D : mapMinX " + mapMinX + " mapMinY " + mapMinY + +// " mapMaxX " + mapMaxX + " mapMaxY " + mapMaxY); + textureFillBackground(ctx, texMinU, texMaxU, texMinV, texMaxV, + mapMinX, mapMaxX, mapMinY, mapMaxY, bg.image.useBilinearFilter()); + + } + + + void clear(BackgroundRetained bg, int winWidth, int winHeight) { + + // Issue 239 - clear stencil if requested and available + // Note that this is a partial solution, since we eventually want an API + // to control this. + boolean clearStencil = VirtualUniverse.mc.stencilClear && + userStencilAvailable; + + clear(ctx, bg.color.x, bg.color.y, bg.color.z, clearStencil); + + // TODO : This is a bug on not mirror bg. Will fix this as a bug after 1.5 beta. + // For now, as a workaround, we will check bg.image and bg.image.imageData not null. + if((bg.image != null) && (bg.image.imageData != null)) { + // setup Texture pipe. + updateTextureForRaster(bg.texture); + + textureFill(bg, winWidth, winHeight); + + // Restore texture pipe. + restoreTextureBin(); + } + } + + /** + * obj is either TextureRetained or DetailTextureImage + * if obj is DetailTextureImage then we just clear + * the resourceCreationMask of all the formats + * no matter it is create or not since we don't + * remember the format information for simplicity. + * We don't need to check duplicate value of id in the + * table since this procedure is invoke only when id + * of texture is -1 one time only. + * This is always call from Renderer thread. + */ + void addTextureResource(int id, Object obj) { + if (id <= 0) { + return; + } + + if (useSharedCtx) { + screen.renderer.addTextureResource(id, obj); + } else { + // This will replace the previous key if exists + if (textureIDResourceTable.size() <= id) { + for (int i=textureIDResourceTable.size(); + i < id; i++) { + textureIDResourceTable.add(null); + } + textureIDResourceTable.add(obj); + } else { + textureIDResourceTable.set(id, obj); + } + + } + } + + // handle free resource in the FreeList + void freeResourcesInFreeList(Context ctx) { + Iterator it; + ArrayList list; + int i, val; + GeometryArrayRetained geo; + + // free resource for those canvases that + // don't use shared ctx + if (displayListResourceFreeList.size() > 0) { + for (it = displayListResourceFreeList.iterator(); it.hasNext();) { + val = ((Integer) it.next()).intValue(); + if (val <= 0) { + continue; + } + freeDisplayList(ctx, val); + } + displayListResourceFreeList.clear(); + } + + if (textureIdResourceFreeList.size() > 0) { + for (it = textureIdResourceFreeList.iterator(); it.hasNext();) { + val = ((Integer) it.next()).intValue(); + if (val <= 0) { + continue; + } + if (val >= textureIDResourceTable.size()) { + System.err.println("Error in freeResourcesInFreeList : ResourceIDTableSize = " + + textureIDResourceTable.size() + + " val = " + val); + } else { + Object obj = textureIDResourceTable.get(val); + if (obj instanceof TextureRetained) { + TextureRetained tex = (TextureRetained) obj; + synchronized (tex.resourceLock) { + tex.resourceCreationMask &= ~canvasBit; + if (tex.resourceCreationMask == 0) { + tex.freeTextureId(val); + } + } + } + + textureIDResourceTable.set(val, null); + } + freeTexture(ctx, val); + } + textureIdResourceFreeList.clear(); + } + } + + void freeContextResources(Renderer rdr, boolean freeBackground, + Context ctx) { + + + Object obj; + TextureRetained tex; + + // Just return if we don't have a valid renderer or context + if (rdr == null || ctx == null) { + return; + } + + if (freeBackground) { + // Dispose of Graphics2D Texture + if (graphics2D != null) { + graphics2D.dispose(); + } + } + + for (int id = textureIDResourceTable.size()-1; id >= 0; id--) { + obj = textureIDResourceTable.get(id); + if (obj == null) { + continue; + } + + // Issue 403 : this assertion doesn't hold in some cases + // TODO KCR : determine why this is the case +// assert id == ((TextureRetained)obj).objectId; + + freeTexture(ctx, id); + if (obj instanceof TextureRetained) { + tex = (TextureRetained) obj; + synchronized (tex.resourceLock) { + tex.resourceCreationMask &= ~canvasBit; + if (tex.resourceCreationMask == 0) { + + tex.freeTextureId(id); + } + } + } + } + textureIDResourceTable.clear(); + + freeAllDisplayListResources(ctx); + } + + void freeAllDisplayListResources(Context ctx) { + if ((view != null) && (view.renderBin != null)) { + view.renderBin.freeAllDisplayListResources(this, ctx); + if (useSharedCtx) { + // We need to rebuild all other Canvas3D resource + // shared by this Canvas3D. Since we didn't + // remember resource in Renderer but RenderBin only. + if ((screen != null) && (screen.renderer != null)) { + screen.renderer.needToRebuildDisplayList = true; + } + } + } + + } + + + // ***************************************************************** + // Wrappers for native methods go below here + // ***************************************************************** + + // This is the native method for creating the underlying graphics context. + private Context createNewContext(long display, Drawable drawable, + long fbConfig, Context shareCtx, boolean isSharedCtx, + boolean offScreen, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + return Pipeline.getPipeline().createNewContext(this, display, drawable, + fbConfig, shareCtx, isSharedCtx, + offScreen, + glslLibraryAvailable, + cgLibraryAvailable); + } + + private void createQueryContext(long display, Drawable drawable, + long fbConfig, boolean offScreen, int width, int height, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + Pipeline.getPipeline().createQueryContext(this, display, drawable, + fbConfig, offScreen, width, height, + glslLibraryAvailable, + cgLibraryAvailable); + } + + // This is the native for creating offscreen buffer + Drawable createOffScreenBuffer(Context ctx, long display, long fbConfig, int width, int height) { + return Pipeline.getPipeline().createOffScreenBuffer(this, + ctx, display, fbConfig, width, height); + } + + void destroyOffScreenBuffer(Context ctx, long display, long fbConfig, Drawable drawable) { + assert drawable != null; + Pipeline.getPipeline().destroyOffScreenBuffer(this, ctx, display, fbConfig, drawable); + } + + // This is the native for reading the image from the offscreen buffer + private void readOffScreenBuffer(Context ctx, int format, int type, Object data, int width, int height) { + Pipeline.getPipeline().readOffScreenBuffer(this, ctx, format, type, data, width, height); + } + + // The native method for swapBuffers + int swapBuffers(Context ctx, long dpy, Drawable drawable) { + return Pipeline.getPipeline().swapBuffers(this, ctx, dpy, drawable); + } + + // notify D3D that Canvas is resize + private int resizeD3DCanvas(Context ctx) { + return Pipeline.getPipeline().resizeD3DCanvas(this, ctx); + } + + // notify D3D to toggle between FullScreen and window mode + private int toggleFullScreenMode(Context ctx) { + return Pipeline.getPipeline().toggleFullScreenMode(this, ctx); + } + + // ----------------------------------------------------------------------------- + + // native method for setting Material when no material is present + void updateMaterial(Context ctx, float r, float g, float b, float a) { + Pipeline.getPipeline().updateMaterialColor(ctx, r, g, b, a); + } + + static void destroyContext(long display, Drawable drawable, Context ctx) { + Pipeline.getPipeline().destroyContext(display, drawable, ctx); + } + + // This is the native method for doing accumulation. + void accum(Context ctx, float value) { + Pipeline.getPipeline().accum(ctx, value); + } + + // This is the native method for doing accumulation return. + void accumReturn(Context ctx) { + Pipeline.getPipeline().accumReturn(ctx); + } + + // This is the native method for clearing the accumulation buffer. + void clearAccum(Context ctx) { + Pipeline.getPipeline().clearAccum(ctx); + } + + // This is the native method for getting the number of lights the underlying + // native library can support. + int getNumCtxLights(Context ctx) { + return Pipeline.getPipeline().getNumCtxLights(ctx); + } + + // Native method for decal 1st child setup + boolean decal1stChildSetup(Context ctx) { + return Pipeline.getPipeline().decal1stChildSetup(ctx); + } + + // Native method for decal nth child setup + void decalNthChildSetup(Context ctx) { + Pipeline.getPipeline().decalNthChildSetup(ctx); + } + + // Native method for decal reset + void decalReset(Context ctx, boolean depthBufferEnable) { + Pipeline.getPipeline().decalReset(ctx, depthBufferEnable); + } + + // Native method for decal reset + void ctxUpdateEyeLightingEnable(Context ctx, boolean localEyeLightingEnable) { + Pipeline.getPipeline().ctxUpdateEyeLightingEnable(ctx, localEyeLightingEnable); + } + + // The following three methods are used in multi-pass case + + // native method for setting blend color + void setBlendColor(Context ctx, float red, float green, + float blue, float alpha) { + Pipeline.getPipeline().setBlendColor(ctx, red, green, + blue, alpha); + } + + // native method for setting blend func + void setBlendFunc(Context ctx, int src, int dst) { + Pipeline.getPipeline().setBlendFunc(ctx, src, dst); + } + + // native method for setting fog enable flag + void setFogEnableFlag(Context ctx, boolean enableFlag) { + Pipeline.getPipeline().setFogEnableFlag(ctx, enableFlag); + } + + // Setup the full scene antialising in D3D and ogl when GL_ARB_multisamle supported + void setFullSceneAntialiasing(Context ctx, boolean enable) { + Pipeline.getPipeline().setFullSceneAntialiasing(ctx, enable); + } + + void setGlobalAlpha(Context ctx, float alpha) { + Pipeline.getPipeline().setGlobalAlpha(ctx, alpha); + } + + // Native method to update separate specular color control + void updateSeparateSpecularColorEnable(Context ctx, boolean control) { + Pipeline.getPipeline().updateSeparateSpecularColorEnable(ctx, control); + } + + // Initialization for D3D when scene begin + private void beginScene(Context ctx) { + Pipeline.getPipeline().beginScene(ctx); + } + private void endScene(Context ctx) { + Pipeline.getPipeline().endScene(ctx); + } + + // True under Solaris, + // False under windows when display mode <= 8 bit + private boolean validGraphicsMode() { + return Pipeline.getPipeline().validGraphicsMode(); + } + + // native method for setting light enables + void setLightEnables(Context ctx, long enableMask, int maxLights) { + Pipeline.getPipeline().setLightEnables(ctx, enableMask, maxLights); + } + + // native method for setting scene ambient + void setSceneAmbient(Context ctx, float red, float green, float blue) { + Pipeline.getPipeline().setSceneAmbient(ctx, red, green, blue); + } + + // native method for disabling fog + void disableFog(Context ctx) { + Pipeline.getPipeline().disableFog(ctx); + } + + // native method for disabling modelClip + void disableModelClip(Context ctx) { + Pipeline.getPipeline().disableModelClip(ctx); + } + + // native method for setting default RenderingAttributes + void resetRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride) { + Pipeline.getPipeline().resetRenderingAttributes(ctx, + depthBufferWriteEnableOverride, + depthBufferEnableOverride); + } + + // native method for setting default texture + void resetTextureNative(Context ctx, int texUnitIndex) { + Pipeline.getPipeline().resetTextureNative(ctx, texUnitIndex); + } + + // native method for activating a particular texture unit + void activeTextureUnit(Context ctx, int texUnitIndex) { + Pipeline.getPipeline().activeTextureUnit(ctx, texUnitIndex); + } + + // native method for setting default TexCoordGeneration + void resetTexCoordGeneration(Context ctx) { + Pipeline.getPipeline().resetTexCoordGeneration(ctx); + } + + // native method for setting default TextureAttributes + void resetTextureAttributes(Context ctx) { + Pipeline.getPipeline().resetTextureAttributes(ctx); + } + + // native method for setting default PolygonAttributes + void resetPolygonAttributes(Context ctx) { + Pipeline.getPipeline().resetPolygonAttributes(ctx); + } + + // native method for setting default LineAttributes + void resetLineAttributes(Context ctx) { + Pipeline.getPipeline().resetLineAttributes(ctx); + } + + // native method for setting default PointAttributes + void resetPointAttributes(Context ctx) { + Pipeline.getPipeline().resetPointAttributes(ctx); + } + + // native method for setting default TransparencyAttributes + void resetTransparency(Context ctx, int geometryType, + int polygonMode, boolean lineAA, + boolean pointAA) { + Pipeline.getPipeline().resetTransparency(ctx, geometryType, + polygonMode, lineAA, + pointAA); + } + + // native method for setting default ColoringAttributes + void resetColoringAttributes(Context ctx, + float r, float g, + float b, float a, + boolean enableLight) { + Pipeline.getPipeline().resetColoringAttributes(ctx, + r, g, + b, a, + enableLight); + } + + /** + * This native method makes sure that the rendering for this canvas + * gets done now. + */ + void syncRender(Context ctx, boolean wait) { + Pipeline.getPipeline().syncRender(ctx, wait); + } + + // The native method that sets this ctx to be the current one + static boolean useCtx(Context ctx, long display, Drawable drawable) { + return Pipeline.getPipeline().useCtx(ctx, display, drawable); + } + + // Give the Pipeline a chance to release the context. The return + // value indicates whether the context was released. + private boolean releaseCtx(Context ctx, long dpy) { + return Pipeline.getPipeline().releaseCtx(ctx, dpy); + } + + void clear(Context ctx, float r, float g, float b, boolean clearStencil) { + Pipeline.getPipeline().clear(ctx, r, g, b, clearStencil); + } + + void textureFillBackground(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, boolean useBiliearFilter) { + Pipeline.getPipeline().textureFillBackground(ctx, texMinU, texMaxU, texMinV, texMaxV, + mapMinX, mapMaxX, mapMinY, mapMaxY, useBiliearFilter); + } + + void textureFillRaster(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, float mapZ, float alpha, boolean useBiliearFilter) { + Pipeline.getPipeline().textureFillRaster(ctx, texMinU, texMaxU, texMinV, texMaxV, + mapMinX, mapMaxX, mapMinY, mapMaxY, mapZ, alpha, useBiliearFilter); + } + + void executeRasterDepth(Context ctx, float posX, float posY, float posZ, + int srcOffsetX, int srcOffsetY, int rasterWidth, int rasterHeight, + int depthWidth, int depthHeight, int depthType, Object depthData) { + Pipeline.getPipeline().executeRasterDepth(ctx, posX, posY, posZ, + srcOffsetX, srcOffsetY, rasterWidth, rasterHeight, depthWidth, depthHeight, depthType, depthData); + } + + // The native method for setting the ModelView matrix. + void setModelViewMatrix(Context ctx, double[] viewMatrix, double[] modelMatrix) { + Pipeline.getPipeline().setModelViewMatrix(ctx, viewMatrix, modelMatrix); + } + + // The native method for setting the Projection matrix. + void setProjectionMatrix(Context ctx, double[] projMatrix) { + Pipeline.getPipeline().setProjectionMatrix(ctx, projMatrix); + } + + // The native method for setting the Viewport. + void setViewport(Context ctx, int x, int y, int width, int height) { + Pipeline.getPipeline().setViewport(ctx, x, y, width, height); + } + + // used for display Lists + void newDisplayList(Context ctx, int displayListId) { + Pipeline.getPipeline().newDisplayList(ctx, displayListId); + } + void endDisplayList(Context ctx) { + Pipeline.getPipeline().endDisplayList(ctx); + } + void callDisplayList(Context ctx, int id, boolean isNonUniformScale) { + Pipeline.getPipeline().callDisplayList(ctx, id, isNonUniformScale); + } + + static void freeDisplayList(Context ctx, int id) { + Pipeline.getPipeline().freeDisplayList(ctx, id); + } + static void freeTexture(Context ctx, int id) { + Pipeline.getPipeline().freeTexture(ctx, id); + } + + void texturemapping(Context ctx, + int px, int py, + int xmin, int ymin, int xmax, int ymax, + int texWidth, int texHeight, + int rasWidth, + int format, int objectId, + byte[] image, + int winWidth, int winHeight) { + Pipeline.getPipeline().texturemapping(ctx, + px, py, + xmin, ymin, xmax, ymax, + texWidth, texHeight, + rasWidth, + format, objectId, + image, + winWidth, winHeight); + } + + boolean initTexturemapping(Context ctx, int texWidth, + int texHeight, int objectId) { + return Pipeline.getPipeline().initTexturemapping(ctx, texWidth, + texHeight, objectId); + } + + + // Set internal render mode to one of FIELD_ALL, FIELD_LEFT or + // FIELD_RIGHT. Note that it is up to the caller to ensure that + // stereo is available before setting the mode to FIELD_LEFT or + // FIELD_RIGHT. The boolean isTRUE for double buffered mode, FALSE + // foe single buffering. + void setRenderMode(Context ctx, int mode, boolean doubleBuffer) { + Pipeline.getPipeline().setRenderMode(ctx, mode, doubleBuffer); + } + + // Set glDepthMask. + void setDepthBufferWriteEnable(Context ctx, boolean mode) { + Pipeline.getPipeline().setDepthBufferWriteEnable(ctx, mode); + } + + // Methods to get actual capabilities from Canvas3D + + boolean hasDoubleBuffer() { + return Pipeline.getPipeline().hasDoubleBuffer(this); + } + + boolean hasStereo() { + return Pipeline.getPipeline().hasStereo(this); + } + + int getStencilSize() { + return Pipeline.getPipeline().getStencilSize(this); + } + + boolean hasSceneAntialiasingMultisample() { + return Pipeline.getPipeline().hasSceneAntialiasingMultisample(this); + } + + boolean hasSceneAntialiasingAccum() { + return Pipeline.getPipeline().hasSceneAntialiasingAccum(this); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CanvasViewCache.java b/j3d-core/src/classes/share/javax/media/j3d/CanvasViewCache.java new file mode 100644 index 0000000..419dc63 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CanvasViewCache.java @@ -0,0 +1,2046 @@ +/* + * $RCSfile: CanvasViewCache.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.Point; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.IllegalComponentStateException; +import javax.vecmath.*; + +/** + * The CanvasViewCache class is used to cache all data, both API data + * and derived data, that is dependent on the Canvas3D or Screen3D. + * The final view and projection matrices are stored here. + */ + +class CanvasViewCache extends Object { + // Used for debugging only + private static Object debugLock = new Object(); + + // The canvas associated with this canvas view cache + private Canvas3D canvas; + + // Mask that indicates this CanvasViewCache view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + int cvcDirtyMask = 0; + + // The screen view cache associated with this canvas view cache + private ScreenViewCache screenViewCache; + + // The view cache associated with this canvas view cache + private ViewCache viewCache; + + // ************* + // API/INPUT DATA + // ************* + + // The position and size of the canvas (in pixels) + private int awtCanvasX; + private int awtCanvasY; + private int awtCanvasWidth; + private int awtCanvasHeight; + + // The current RenderBin used for rendering during the frame + // associated with this snapshot. + private RenderBin renderBin; + + // Flag indicating whether or not stereo will be used. Computed by + // Canvas3D as: useStereo = stereoEnable && stereoAvailable + private boolean useStereo; + + // Current monoscopic view policy from canvas + private int monoscopicViewPolicy; + + // The manual positions of the left and right eyes in image-plate + // coordinates. + // Note that these values are only used in non-head-tracked mode + // when the view's window eyepoint policy is one of RELATIVE_TO_SCREEN + // or RELATIVE_TO_WINDOW. + private Point3d leftManualEyeInImagePlate = new Point3d(); + private Point3d rightManualEyeInImagePlate = new Point3d(); + + // ************* + // DERIVED DATA + // ************* + + // The width and height of the screen in meters (from ScreenViewCache) + double physicalScreenWidth; + double physicalScreenHeight; + + // The width and height of the screen in pixels (from ScreenViewCache) + int screenWidth; + int screenHeight; + + // Meters per pixel in the X and Y dimension (from ScreenViewCache) + double metersPerPixelX; + double metersPerPixelY; + + // The position and size of the canvas (in pixels) + private int canvasX; + private int canvasY; + private int canvasWidth; + private int canvasHeight; + + // Either the Canvas' or the View's monoscopicViewPolicy + private int effectiveMonoscopicViewPolicy; + + // The current cached projection transforms. + private Transform3D leftProjection = new Transform3D(); + private Transform3D rightProjection = new Transform3D(); + private Transform3D infLeftProjection = new Transform3D(); + private Transform3D infRightProjection = new Transform3D(); + + // The current cached viewing transforms. + private Transform3D leftVpcToEc = new Transform3D(); + private Transform3D rightVpcToEc = new Transform3D(); + private Transform3D infLeftVpcToEc = new Transform3D(); + private Transform3D infRightVpcToEc = new Transform3D(); + + // The current cached inverse viewing transforms. + private Transform3D leftEcToVpc = new Transform3D(); + private Transform3D rightEcToVpc = new Transform3D(); + private Transform3D infLeftEcToVpc = new Transform3D(); + private Transform3D infRightEcToVpc = new Transform3D(); + + // Arrays of Vector4d objects that represent the plane equations for + // the 6 planes in the viewing frustum in ViewPlatform coordinates. + private Vector4d[] leftFrustumPlanes = new Vector4d[6]; + private Vector4d[] rightFrustumPlanes = new Vector4d[6]; + + // Arrays of Vector4d objects that represent the volume of viewing frustum + private Point4d leftFrustumPoints[] = new Point4d[8]; + private Point4d rightFrustumPoints[] = new Point4d[8]; + + // Calibration matrix from Screen object for HMD mode using + // non-field-sequential stereo + + private Transform3D headTrackerToLeftImagePlate = new Transform3D(); + private Transform3D headTrackerToRightImagePlate = new Transform3D(); + + // Head tracked version of eye in imageplate + private Point3d leftTrackedEyeInImagePlate = new Point3d(); + private Point3d rightTrackedEyeInImagePlate = new Point3d(); + + // Derived version of eye in image plate coordinates + private Point3d leftEyeInImagePlate = new Point3d(); + private Point3d rightEyeInImagePlate = new Point3d(); + private Point3d centerEyeInImagePlate = new Point3d(); + + // Derived version of nominalEyeOffsetFromNominalScreen + private double nominalEyeOffset; + + // Physical window position,size and center (in image plate coordinates) + private double physicalWindowXLeft; + private double physicalWindowYBottom; + private double physicalWindowXRight; + private double physicalWindowYTop; + private double physicalWindowWidth; + private double physicalWindowHeight; + private Point3d physicalWindowCenter = new Point3d(); + + // Screen scale value from viewCache or from screen size. + private double screenScale; + + // Window scale value that compensates for window size if + // the window resize policy is PHYSICAL_WORLD. + private double windowScale; + + // ViewPlatform scale that takes coordinates from view platform + // coordinates and scales them to physical coordinates + private double viewPlatformScale; + + // Various derived transforms + + private Transform3D leftCcToVworld = new Transform3D(); + private Transform3D rightCcToVworld = new Transform3D(); + + private Transform3D coexistenceToLeftPlate = new Transform3D(); + private Transform3D coexistenceToRightPlate = new Transform3D(); + + private Transform3D vpcToCoexistence = new Transform3D(); + + private Transform3D vpcToLeftPlate = new Transform3D(); + private Transform3D vpcToRightPlate = new Transform3D(); + private Transform3D leftPlateToVpc = new Transform3D(); + private Transform3D rightPlateToVpc = new Transform3D(); + private Transform3D vworldToLeftPlate = new Transform3D(); + private Transform3D lastVworldToLeftPlate = new Transform3D(); + private Transform3D vworldToRightPlate = new Transform3D(); + private Transform3D leftPlateToVworld = new Transform3D(); + private Transform3D rightPlateToVworld = new Transform3D(); + private Transform3D headToLeftImagePlate = new Transform3D(); + private Transform3D headToRightImagePlate = new Transform3D(); + + private Transform3D vworldToTrackerBase = new Transform3D(); + private Transform3D tempTrans = new Transform3D(); + private Transform3D headToVworld = new Transform3D(); + private Vector3d coexistenceCenter = new Vector3d(); + + // scale for transformimg clip and fog distances + private double vworldToCoexistenceScale; + private double infVworldToCoexistenceScale; + + // + // Temporary matrices and vectors, so we dont generate garbage + // + private Transform3D tMat1 = new Transform3D(); + private Transform3D tMat2 = new Transform3D(); + private Vector3d tVec1 = new Vector3d(); + private Vector3d tVec2 = new Vector3d(); + private Vector3d tVec3 = new Vector3d(); + private Point3d tPnt1 = new Point3d(); + private Point3d tPnt2 = new Point3d(); + + private Matrix4d tMatrix = new Matrix4d(); + + /** + * The view platform transforms. + */ + private Transform3D vworldToVpc = new Transform3D(); + private Transform3D vpcToVworld = new Transform3D(); + private Transform3D infVworldToVpc = new Transform3D(); + + // This flag is used to remember the last time doInfinite flag + // is true or not. + // If this cache is updated twice, the first time in RenderBin + // updateViewCache() and the second time in Renderer with + // geometryBackground. The first time will reset the vcDirtyMask + // to 0 so that geometry background will not get updated the + // second time doComputeDerivedData() is invoked when view change. + private boolean lastDoInfinite = false; + private boolean updateLastTime = false; + + void getCanvasPositionAndSize() { + if(J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2) { + System.err.println("Get canvas position and size"); + System.err.println("Before"); + System.err.println("Canvas pos = (" + awtCanvasX + ", " + + awtCanvasY + "), size = " + awtCanvasWidth + + "x" + awtCanvasHeight); + System.err.println("After"); + } + awtCanvasX = canvas.newPosition.x; + awtCanvasY = canvas.newPosition.y; + awtCanvasWidth = canvas.newSize.width; + awtCanvasHeight = canvas.newSize.height; + + // The following works around problem when awt creates 0-size + // window at startup + if ((awtCanvasWidth <= 0) || (awtCanvasHeight <= 0)) { + awtCanvasWidth = 1; + awtCanvasHeight = 1; + } + + if (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1) { + System.err.println("Canvas pos = (" + awtCanvasX + ", " + + awtCanvasY + "), size = " + awtCanvasWidth + + "x" + awtCanvasHeight); + } + } + + void computefrustumBBox(BoundingBox frustumBBox) { + int i; + + for(i = 0; i < leftFrustumPoints.length; i++) { + if(frustumBBox.lower.x > leftFrustumPoints[i].x) + frustumBBox.lower.x = leftFrustumPoints[i].x; + if(frustumBBox.lower.y > leftFrustumPoints[i].y) + frustumBBox.lower.y = leftFrustumPoints[i].y; + if(frustumBBox.lower.z > leftFrustumPoints[i].z) + frustumBBox.lower.z = leftFrustumPoints[i].z; + + if(frustumBBox.upper.x < leftFrustumPoints[i].x) + frustumBBox.upper.x = leftFrustumPoints[i].x; + if(frustumBBox.upper.y < leftFrustumPoints[i].y) + frustumBBox.upper.y = leftFrustumPoints[i].y; + if(frustumBBox.upper.z < leftFrustumPoints[i].z) + frustumBBox.upper.z = leftFrustumPoints[i].z; + } + + if(useStereo) { + + for(i = 0; i< rightFrustumPoints.length; i++) { + if(frustumBBox.lower.x > rightFrustumPoints[i].x) + frustumBBox.lower.x = rightFrustumPoints[i].x; + if(frustumBBox.lower.y > rightFrustumPoints[i].y) + frustumBBox.lower.y = rightFrustumPoints[i].y; + if(frustumBBox.lower.z > rightFrustumPoints[i].z) + frustumBBox.lower.z = rightFrustumPoints[i].z; + + if(frustumBBox.upper.x < rightFrustumPoints[i].x) + frustumBBox.upper.x = rightFrustumPoints[i].x; + if(frustumBBox.upper.y < rightFrustumPoints[i].y) + frustumBBox.upper.y = rightFrustumPoints[i].y; + if(frustumBBox.upper.z < rightFrustumPoints[i].z) + frustumBBox.upper.z = rightFrustumPoints[i].z; + } + + } + } + + + void copyComputedCanvasViewCache(CanvasViewCache cvc, boolean doInfinite) { + // For performance reason, only data needed by renderer are copied. + // useStereo, + // canvasWidth, + // canvasHeight, + // leftProjection, + // rightProjection, + // leftVpcToEc, + // rightVpcToEc, + // leftFrustumPlanes, + // rightFrustumPlanes, + // vpcToVworld, + // vworldToVpc. + + cvc.useStereo = useStereo; + cvc.canvasWidth = canvasWidth; + cvc.canvasHeight = canvasHeight; + cvc.leftProjection.set(leftProjection); + cvc.rightProjection.set(rightProjection); + cvc.leftVpcToEc.set(leftVpcToEc) ; + cvc.rightVpcToEc.set(rightVpcToEc) ; + + cvc.vpcToVworld = vpcToVworld; + cvc.vworldToVpc.set(vworldToVpc); + + if (doInfinite) { + cvc.infLeftProjection.set(infLeftProjection); + cvc.infRightProjection.set(infRightProjection); + cvc.infLeftVpcToEc.set(infLeftVpcToEc) ; + cvc.infRightVpcToEc.set(infRightVpcToEc) ; + cvc.infVworldToVpc.set(infVworldToVpc); + } + + for (int i = 0; i < leftFrustumPlanes.length; i++) { + cvc.leftFrustumPlanes[i].x = leftFrustumPlanes[i].x; + cvc.leftFrustumPlanes[i].y = leftFrustumPlanes[i].y; + cvc.leftFrustumPlanes[i].z = leftFrustumPlanes[i].z; + cvc.leftFrustumPlanes[i].w = leftFrustumPlanes[i].w; + + cvc.rightFrustumPlanes[i].x = rightFrustumPlanes[i].x; + cvc.rightFrustumPlanes[i].y = rightFrustumPlanes[i].y; + cvc.rightFrustumPlanes[i].z = rightFrustumPlanes[i].z; + cvc.rightFrustumPlanes[i].w = rightFrustumPlanes[i].w; + } + } + + + /** + * Take snapshot of all per-canvas API parameters and input values. + * NOTE: This is probably not needed, but we'll do it for symmetry + * with the ScreenViewCache and ViewCache objects. + */ + synchronized void snapshot(boolean computeFrustum) { + // Issue 109 : determine the the correct index to use -- either the + // Renderer or RenderBin + int dirtyIndex = computeFrustum ? + Canvas3D.RENDER_BIN_DIRTY_IDX : Canvas3D.RENDERER_DIRTY_IDX; + + synchronized (canvas.dirtyMaskLock) { + // Issue 109 : read/clear the dirty bits for the correct index + cvcDirtyMask = canvas.cvDirtyMask[dirtyIndex]; + canvas.cvDirtyMask[dirtyIndex] = 0; + } + + useStereo = canvas.useStereo; + monoscopicViewPolicy = canvas.monoscopicViewPolicy; + leftManualEyeInImagePlate.set(canvas.leftManualEyeInImagePlate); + rightManualEyeInImagePlate.set(canvas.rightManualEyeInImagePlate); + + if(( cvcDirtyMask & Canvas3D.MOVED_OR_RESIZED_DIRTY) != 0) { + getCanvasPositionAndSize(); + } + + renderBin = canvas.view.renderBin; + + } + + /** + * Compute derived data using the snapshot of the per-canvas, + * per-screen and per-view data. + */ + synchronized void computeDerivedData(boolean currentFlag, + CanvasViewCache cvc, BoundingBox frustumBBox, boolean doInfinite) { + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) { + synchronized(debugLock) { + System.err.println("------------------------------"); + doComputeDerivedData(currentFlag,cvc,frustumBBox,doInfinite); + } + } + else { + doComputeDerivedData(currentFlag,cvc,frustumBBox,doInfinite); + } + } + + /** + * Compute derived data using the snapshot of the per-canvas, + * per-screen and per-view data. Caller must synchronize before + * calling this method. + */ + private void doComputeDerivedData(boolean currentFlag, + CanvasViewCache cvc, BoundingBox frustumBBox, boolean doInfinite) { + + // Issue 109 : determine the the correct index to use -- either the + // Renderer or RenderBin + int dirtyIndex = (frustumBBox != null) ? + Canvas3D.RENDER_BIN_DIRTY_IDX : Canvas3D.RENDERER_DIRTY_IDX; + int scrvcDirtyMask; + + // Issue 109 : read/clear the dirty bits for the correct index + synchronized (screenViewCache) { + scrvcDirtyMask = screenViewCache.scrvcDirtyMask[dirtyIndex]; + // reset screen view dirty mask if canvas is offScreen. Note: + // there is only one canvas per offscreen, so it is ok to + // do the reset here. + if (canvas.offScreen) { + screenViewCache.scrvcDirtyMask[dirtyIndex] = 0; + } + } + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + if(cvcDirtyMask != 0) + System.err.println("cvcDirtyMask : " + cvcDirtyMask); + + if(scrvcDirtyMask != 0) + System.err.println("scrvcDirtyMask : "+ scrvcDirtyMask); + + if(viewCache.vcDirtyMask != 0) + System.err.println("vcDirtyMask : " + viewCache.vcDirtyMask); + } + + + // NOTE: This fix is only fixing the symptoms, but not the + // root of the bug. We shouldn't have to check for null here. + if(viewCache.vpRetained == null) { + System.err.println("CanvasViewCache : Error! viewCache.vpRetained is null"); + return; + } + + // This flag is use to force a computation when a ViewPlatformTransform + // is detected. No sync. needed. We're doing a read of t/f. + // XXXX: Peeking at the dirty flag is a hack. Need to revisit this. + boolean vprNotDirty = (viewCache.vpRetained.vprDirtyMask == 0); + + // Issue 131: If not manual, it has to be considered as an onscreen canvas. + if(!canvas.manualRendering && + (vprNotDirty) && + (cvcDirtyMask == 0) && + (scrvcDirtyMask == 0) && + (viewCache.vcDirtyMask == 0) && + !(updateLastTime && (doInfinite != lastDoInfinite))) { + if(frustumBBox != null) + computefrustumBBox(frustumBBox); + + // Copy the computed data into cvc. + if(cvc != null) { + copyComputedCanvasViewCache(cvc, doInfinite); + } + lastDoInfinite = doInfinite; + updateLastTime = false; + return; + } + + lastDoInfinite = doInfinite; + updateLastTime = true; + + if(currentFlag) { + vpcToVworld.set(viewCache.vpRetained.getCurrentLocalToVworld(null)); + } + else { + vpcToVworld.set(viewCache.vpRetained.getLastLocalToVworld(null)); + } + + // System.err.println("vpcToVworld is \n" + vpcToVworld); + + try { + vworldToVpc.invert(vpcToVworld); + } + catch (SingularMatrixException e) { + vworldToVpc.setIdentity(); + //System.err.println("SingularMatrixException encountered when doing vworldToVpc invert"); + } + if (doInfinite) { + vworldToVpc.getRotation(infVworldToVpc); + } + + // Compute global flags + if (monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) + effectiveMonoscopicViewPolicy = viewCache.monoscopicViewPolicy; + else + effectiveMonoscopicViewPolicy = monoscopicViewPolicy; + + // Recompute info about current canvas window + computeCanvasInfo(); + + // Compute coexistence center (in plate coordinates) + computeCoexistenceCenter(); + + // Get Eye position in image-plate coordinates + cacheEyePosition(); + + // Compute VPC to COE and COE to PLATE transforms + computeVpcToCoexistence(); + computeCoexistenceToPlate(); + + // Compute view and projection matrices + computeView(doInfinite); + + + computePlateToVworld(); + + if (!currentFlag) { + // save the result for use in RasterRetained computeWinCoord + lastVworldToLeftPlate.set(vworldToLeftPlate); + } + computeHeadToVworld(); + + if (frustumBBox != null) + computefrustumBBox(frustumBBox); + + // Issue 109: cvc should *always* be null + assert cvc == null; + if(cvc != null) + copyComputedCanvasViewCache(cvc, doInfinite); + + canvas.canvasDirty |= Canvas3D.VIEW_MATRIX_DIRTY; + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) { + // Print some data : + System.err.println("useStereo = " + useStereo); + System.err.println("leftProjection:\n" + leftProjection); + System.err.println("rightProjection:\n " + rightProjection); + System.err.println("leftVpcToEc:\n" + leftVpcToEc); + System.err.println("rightVpcToEc:\n" + rightVpcToEc); + System.err.println("vpcToVworld:\n" + vpcToVworld); + System.err.println("vworldToVpc:\n" + vworldToVpc); + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + int i; + for (i = 0; i < leftFrustumPlanes.length; i++) { + System.err.println("leftFrustumPlanes " + i + " is " + + leftFrustumPlanes[i]); + } + + for (i = 0; i < rightFrustumPlanes.length; i++) { + System.err.println("rightFrustumPlanes " + i + " is " + + rightFrustumPlanes[i]); + } + } + } + + } + + private void computeCanvasInfo() { + // Copy the screen width and height info into derived parameters + physicalScreenWidth = screenViewCache.physicalScreenWidth; + physicalScreenHeight = screenViewCache.physicalScreenHeight; + + screenWidth = screenViewCache.screenWidth; + screenHeight = screenViewCache.screenHeight; + + metersPerPixelX = screenViewCache.metersPerPixelX; + metersPerPixelY = screenViewCache.metersPerPixelY; + + // If a multi-screen virtual device (e.g. Xinerama) is being used, + // then awtCanvasX and awtCanvasY are relative to the origin of that + // virtual screen. Subtract the origin of the physical screen to + // compute the origin in physical (image plate) coordinates. + Rectangle screenBounds = canvas.graphicsConfiguration.getBounds(); + canvasX = awtCanvasX - screenBounds.x; + canvasY = awtCanvasY - screenBounds.y; + + // Use awtCanvasWidth and awtCanvasHeight as reported. + canvasWidth = awtCanvasWidth; + canvasHeight = awtCanvasHeight; + + // Convert the window system ``pixel'' coordinate location and size + // of the window into physical units (meters) and coordinate system. + + // Window width and Height in meters + physicalWindowWidth = canvasWidth * metersPerPixelX; + physicalWindowHeight = canvasHeight * metersPerPixelY; + + // Compute the 4 corners of the window in physical units + physicalWindowXLeft = metersPerPixelX * + (double) canvasX; + physicalWindowYBottom = metersPerPixelY * + (double)(screenHeight - canvasHeight - canvasY); + + physicalWindowXRight = physicalWindowXLeft + physicalWindowWidth; + physicalWindowYTop = physicalWindowYBottom + physicalWindowHeight; + + // Cache the physical location of the center of the window + physicalWindowCenter.x = + physicalWindowXLeft + physicalWindowWidth / 2.0; + physicalWindowCenter.y = + physicalWindowYBottom + physicalWindowHeight / 2.0; + physicalWindowCenter.z = 0.0; + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("Canvas pos = (" + awtCanvasX + ", " + + awtCanvasY + "), size = " + awtCanvasWidth + + "x" + awtCanvasHeight); + + System.err.println("Window LL corner (in plate coordinates): " + + "(" + physicalWindowXLeft + "," + physicalWindowYBottom + ")"); + + System.err.println("Window size (in plate coordinates): " + + "(" + physicalWindowWidth + "," + physicalWindowHeight + ")"); + + System.err.println("Window center (in plate coordinates): " + + physicalWindowCenter); + + System.err.println(); + } + + // Compute the view platform scale. This combines + // the screen scale and the window scale. + computeViewPlatformScale(); + + if (!viewCache.compatibilityModeEnable && + viewCache.viewPolicy == View.HMD_VIEW) { + if (!useStereo) { + switch(effectiveMonoscopicViewPolicy) { + case View.CYCLOPEAN_EYE_VIEW: + if(J3dDebug.devPhase) { + System.err.println("CanvasViewCache : Should never reach here.\n" + + "HMD_VIEW with CYCLOPEAN_EYE_VIEW is not allowed"); + } + break; + + case View.LEFT_EYE_VIEW: + headTrackerToLeftImagePlate.set(screenViewCache. + headTrackerToLeftImagePlate); + break; + + case View.RIGHT_EYE_VIEW: + headTrackerToLeftImagePlate.set(screenViewCache. + headTrackerToRightImagePlate); + break; + } + } + else { + headTrackerToLeftImagePlate.set(screenViewCache. + headTrackerToLeftImagePlate); + + headTrackerToRightImagePlate.set(screenViewCache. + headTrackerToRightImagePlate); + } + + } + } + + // Routine to compute the center of coexistence coordinates in + // imageplate coordinates. Also compute the scale from Vpc + private void computeViewPlatformScale() { + windowScale = screenScale = 1.0; + + if (!viewCache.compatibilityModeEnable) { + switch (viewCache.screenScalePolicy) { + case View.SCALE_SCREEN_SIZE: + screenScale = physicalScreenWidth / 2.0; + break; + case View.SCALE_EXPLICIT: + screenScale = viewCache.screenScale; + break; + } + + if (viewCache.windowResizePolicy == View.PHYSICAL_WORLD) { + windowScale = physicalWindowWidth / physicalScreenWidth; + } + } + + viewPlatformScale = windowScale * screenScale; + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("viewCache.windowResizePolicy = " + + viewCache.windowResizePolicy); + System.err.println("physicalWindowWidth = " + physicalWindowWidth); + System.err.println("physicalScreenWidth = " + physicalScreenWidth); + System.err.println("windowScale = " + windowScale); + System.err.println("screenScale = " + screenScale); + System.err.println("viewPlatformScale = " + viewPlatformScale); + } + } + + private void cacheEyePosFixedField() { + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) + System.err.println("cacheEyePosFixedField:"); + + // y is always the window center + rightEyeInImagePlate.y = + leftEyeInImagePlate.y = + physicalWindowCenter.y; + + if (!useStereo) { + switch(effectiveMonoscopicViewPolicy) { + case View.CYCLOPEAN_EYE_VIEW: + leftEyeInImagePlate.x = physicalWindowCenter.x; + break; + + case View.LEFT_EYE_VIEW: + leftEyeInImagePlate.x = + physicalWindowCenter.x + viewCache.leftEyePosInHead.x; + break; + + case View.RIGHT_EYE_VIEW: + leftEyeInImagePlate.x = + physicalWindowCenter.x + viewCache.rightEyePosInHead.x; + break; + } + + // Set right as well just in case + rightEyeInImagePlate.x = leftEyeInImagePlate.x; + } + else { + leftEyeInImagePlate.x = + physicalWindowCenter.x + viewCache.leftEyePosInHead.x; + + rightEyeInImagePlate.x = + physicalWindowCenter.x + viewCache.rightEyePosInHead.x; + } + + // + // Derive the z distance by constraining the field of view of the + // window width to be constant. + // + rightEyeInImagePlate.z = + leftEyeInImagePlate.z = + physicalWindowWidth / + (2.0 * Math.tan(viewCache.fieldOfView / 2.0)); + + // Denote that eyes-in-ImagePlate fields have changed so that + // these new values can be sent to the AudioDevice + if (this.viewCache.view.soundScheduler != null) + this.viewCache.view.soundScheduler.setListenerFlag( + SoundScheduler.EYE_POSITIONS_CHANGED); + } + + /** + * Case of view eye position contrainted to center of window, but + * with z distance from plate eye pos. + */ + private void cacheEyePosWindowRelative() { + + if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) + System.err.println("cacheEyePosWindowRelative:"); + + // y is always the window center + rightEyeInImagePlate.y = + leftEyeInImagePlate.y = + physicalWindowCenter.y; + + // z is always from the existing eye pos + rightEyeInImagePlate.z = + leftEyeInImagePlate.z = + leftManualEyeInImagePlate.z; + + if (!useStereo) { + + switch(effectiveMonoscopicViewPolicy) { + + case View.CYCLOPEAN_EYE_VIEW: + leftEyeInImagePlate.x = + physicalWindowCenter.x; + break; + + case View.LEFT_EYE_VIEW: + leftEyeInImagePlate.x = + physicalWindowCenter.x + + viewCache.leftEyePosInHead.x; + break; + + case View.RIGHT_EYE_VIEW: + leftEyeInImagePlate.x = + physicalWindowCenter.x + + viewCache.rightEyePosInHead.x; + break; + + } + + // Set right as well just in case + rightEyeInImagePlate.x = + leftEyeInImagePlate.x; + + } + else { + + leftEyeInImagePlate.x = + physicalWindowCenter.x + + viewCache.leftEyePosInHead.x; + + rightEyeInImagePlate.x = + physicalWindowCenter.x + + viewCache.rightEyePosInHead.x; + + // Right z gets its own value + rightEyeInImagePlate.z = + rightManualEyeInImagePlate.z; + } + + // Denote that eyes-in-ImagePlate fields have changed so that + // these new values can be sent to the AudioDevice + if (this.viewCache.view.soundScheduler != null) + this.viewCache.view.soundScheduler.setListenerFlag( + SoundScheduler.EYE_POSITIONS_CHANGED); + } + + /** + * Common routine used when head tracking and when using manual + * relative_to_screen eyepoint policy. + */ + private void cacheEyePosScreenRelative(Point3d leftEye, Point3d rightEye) { + if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) + System.err.println("cacheEyePosScreenRelative:"); + + if (!useStereo) { + switch(effectiveMonoscopicViewPolicy) { + + case View.CYCLOPEAN_EYE_VIEW: + leftEyeInImagePlate.x = (leftEye.x + rightEye.x) / 2.0; + leftEyeInImagePlate.y = (leftEye.y + rightEye.y) / 2.0; + leftEyeInImagePlate.z = (leftEye.z + rightEye.z) / 2.0; + break; + + case View.LEFT_EYE_VIEW: + leftEyeInImagePlate.set(leftEye); + break; + + case View.RIGHT_EYE_VIEW: + leftEyeInImagePlate.set(rightEye); + break; + + } + + // Set right as well just in case + rightEyeInImagePlate.set(leftEyeInImagePlate); + } + else { + leftEyeInImagePlate.set(leftEye); + rightEyeInImagePlate.set(rightEye); + } + + // Denote that eyes-in-ImagePlate fields have changed so that + // these new values can be sent to the AudioDevice + if (this.viewCache.view.soundScheduler != null) + this.viewCache.view.soundScheduler.setListenerFlag( + SoundScheduler.EYE_POSITIONS_CHANGED); + } + + private void cacheEyePosCoexistenceRelative(Point3d leftManualEyeInCoexistence, + Point3d rightManualEyeInCoexistence) { + + tPnt1.set(leftManualEyeInCoexistence); + viewCache.coexistenceToTrackerBase.transform(tPnt1); + screenViewCache.trackerBaseToImagePlate.transform(tPnt1); + tPnt1.add(coexistenceCenter); + + tPnt2.set(rightManualEyeInCoexistence); + viewCache.coexistenceToTrackerBase.transform(tPnt2); + screenViewCache.trackerBaseToImagePlate.transform(tPnt2); + tPnt2.add(coexistenceCenter); + + cacheEyePosScreenRelative(tPnt1, tPnt2); + + } + + /** + * Compute the head-tracked eye position for the right and + * left eyes. + */ + private void computeTrackedEyePosition() { + if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("computeTrackedEyePosition:"); + System.err.println("viewCache.headTrackerToTrackerBase:"); + System.err.println(viewCache.headTrackerToTrackerBase); + + System.err.println("viewCache.headToHeadTracker:"); + System.err.println(viewCache.headToHeadTracker); + } + + if (viewCache.viewPolicy != View.HMD_VIEW) { + if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("screenViewCache.trackerBaseToImagePlate:"); + System.err.println(screenViewCache.trackerBaseToImagePlate); + } + + headToLeftImagePlate.set(coexistenceCenter); + headToLeftImagePlate.mul(screenViewCache.trackerBaseToImagePlate); + headToLeftImagePlate.mul(viewCache.headTrackerToTrackerBase); + headToLeftImagePlate.mul(viewCache.headToHeadTracker); + + headToLeftImagePlate.transform(viewCache.leftEyePosInHead, + leftTrackedEyeInImagePlate); + + headToLeftImagePlate.transform(viewCache.rightEyePosInHead, + rightTrackedEyeInImagePlate); + } + else { + if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("headTrackerToLeftImagePlate:"); + System.err.println(headTrackerToLeftImagePlate); + } + + headToLeftImagePlate.mul(headTrackerToLeftImagePlate, + viewCache.headToHeadTracker); + + headToLeftImagePlate.transform(viewCache.leftEyePosInHead, + leftTrackedEyeInImagePlate); + + if(useStereo) { + headToRightImagePlate.mul(headTrackerToRightImagePlate, + viewCache.headToHeadTracker); + + headToRightImagePlate.transform(viewCache.rightEyePosInHead, + rightTrackedEyeInImagePlate); + } + else { // HMD_VIEW with no stereo. + headToLeftImagePlate.transform(viewCache.rightEyePosInHead, + rightTrackedEyeInImagePlate); + } + + } + + if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("headToLeftImagePlate:"); + System.err.println(headToLeftImagePlate); + System.err.println("headToRightImagePlate:"); + System.err.println(headToRightImagePlate); + + } + } + + /** + * Routine to cache the current eye position in image plate + * coordinates. + */ + private void cacheEyePosition() { + if (viewCache.compatibilityModeEnable) { + // XXXX: Compute compatibility mode eye position in ImagePlate??? + cacheEyePosScreenRelative(leftManualEyeInImagePlate, + rightManualEyeInImagePlate); + } + else if (viewCache.getDoHeadTracking()) { + computeTrackedEyePosition(); + cacheEyePosScreenRelative(leftTrackedEyeInImagePlate, + rightTrackedEyeInImagePlate); + } + else { + switch (viewCache.windowEyepointPolicy) { + + case View.RELATIVE_TO_FIELD_OF_VIEW: + cacheEyePosFixedField(); + break; + + case View.RELATIVE_TO_WINDOW: + cacheEyePosWindowRelative(); + break; + + case View.RELATIVE_TO_SCREEN: + cacheEyePosScreenRelative(leftManualEyeInImagePlate, + rightManualEyeInImagePlate); + break; + + case View.RELATIVE_TO_COEXISTENCE: + cacheEyePosCoexistenceRelative(viewCache.leftManualEyeInCoexistence, + viewCache.rightManualEyeInCoexistence); + break; + } + } + + // Compute center eye + centerEyeInImagePlate.add(leftEyeInImagePlate, rightEyeInImagePlate); + centerEyeInImagePlate.scale(0.5); + + // Compute derived value of nominalEyeOffsetFromNominalScreen + if (viewCache.windowEyepointPolicy == View.RELATIVE_TO_FIELD_OF_VIEW) + nominalEyeOffset = centerEyeInImagePlate.z; + else + nominalEyeOffset = viewCache.nominalEyeOffsetFromNominalScreen; + + if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) { + System.err.println("leftEyeInImagePlate = " + + leftEyeInImagePlate); + System.err.println("rightEyeInImagePlate = " + + rightEyeInImagePlate); + System.err.println("centerEyeInImagePlate = " + + centerEyeInImagePlate); + System.err.println("nominalEyeOffset = " + + nominalEyeOffset); + System.err.println(); + } + } + + private void computePlateToVworld() { + if (viewCache.compatibilityModeEnable) { + // XXXX: implement this correctly for compat mode + leftPlateToVworld.setIdentity(); + vworldToLeftPlate.setIdentity(); + } + else { + try { + leftPlateToVpc.invert(vpcToLeftPlate); + } + catch (SingularMatrixException e) { + leftPlateToVpc.setIdentity(); + /* + System.err.println("SingularMatrixException encountered when doing" + + " leftPlateToVpc invert"); + */ + } + + leftPlateToVworld.mul(vpcToVworld, leftPlateToVpc); + vworldToLeftPlate.mul(vpcToLeftPlate, vworldToVpc); + + if(useStereo) { + try { + rightPlateToVpc.invert(vpcToRightPlate); + } + catch (SingularMatrixException e) { + rightPlateToVpc.setIdentity(); + /* + System.err.println("SingularMatrixException encountered when doing" + + " rightPlateToVpc invert"); + */ + } + + rightPlateToVworld.mul(vpcToVworld, rightPlateToVpc); + vworldToRightPlate.mul(vpcToRightPlate, vworldToVpc); + + } + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("vpcToVworld:"); + System.err.println(vpcToVworld); + System.err.println("vpcToLeftPlate:"); + System.err.println(vpcToLeftPlate); + if(useStereo) { + System.err.println("vpcToRightPlate:"); + System.err.println(vpcToRightPlate); + + } + + } + } + + // Denote that eyes-in-ImagePlate fields have changed so that + // these new values can be sent to the AudioDevice + if (this.viewCache.view.soundScheduler != null) + this.viewCache.view.soundScheduler.setListenerFlag( + SoundScheduler.IMAGE_PLATE_TO_VWORLD_CHANGED); + } + + + private void computeHeadToVworld() { + // Concatenate headToLeftImagePlate with leftPlateToVworld + + if (viewCache.compatibilityModeEnable) { + // XXXX: implement this correctly for compat mode + headToVworld.setIdentity(); + } + else { + headToVworld.mul(leftPlateToVworld, headToLeftImagePlate); + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("leftPlateToVworld:"); + System.err.println(leftPlateToVworld); + System.err.println("headToLeftImagePlate:"); + System.err.println(headToLeftImagePlate); + System.err.println("...gives -> headToVworld:"); + System.err.println(headToVworld); + } + } + + // Denote that eyes-in-ImagePlate fields have changed so that + // these new values can be sent to the AudioDevice + if (this.viewCache.view.soundScheduler != null) + this.viewCache.view.soundScheduler.setListenerFlag( + SoundScheduler.HEAD_TO_VWORLD_CHANGED); + } + + private void computeVpcToCoexistence() { + // Create a transform with the view platform to coexistence scale + tMat1.set(viewPlatformScale); + + // XXXX: Is this really correct to ignore HMD? + + if (viewCache.viewPolicy != View.HMD_VIEW) { + switch (viewCache.coexistenceCenterInPworldPolicy) { + case View.NOMINAL_SCREEN : + switch (viewCache.viewAttachPolicy) { + case View.NOMINAL_SCREEN: + tMat2.setIdentity(); + break; + case View.NOMINAL_HEAD: + tVec1.set(0.0, 0.0, nominalEyeOffset); + tMat2.set(tVec1); + break; + case View.NOMINAL_FEET: + tVec1.set(0.0, -viewCache.nominalEyeHeightFromGround, + nominalEyeOffset); + tMat2.set(tVec1); + break; + } + + break; + case View.NOMINAL_HEAD : + switch (viewCache.viewAttachPolicy) { + case View.NOMINAL_SCREEN: + tVec1.set(0.0, 0.0, -nominalEyeOffset); + tMat2.set(tVec1); + break; + case View.NOMINAL_HEAD: + tMat2.setIdentity(); + break; + case View.NOMINAL_FEET: + tVec1.set(0.0, -viewCache.nominalEyeHeightFromGround, + 0.0); + tMat2.set(tVec1); + break; + } + break; + case View.NOMINAL_FEET: + switch (viewCache.viewAttachPolicy) { + case View.NOMINAL_SCREEN: + tVec1.set(0.0, + viewCache.nominalEyeHeightFromGround, -nominalEyeOffset); + tMat2.set(tVec1); + break; + case View.NOMINAL_HEAD: + tVec1.set(0.0, viewCache.nominalEyeHeightFromGround, + 0.0); + tMat2.set(tVec1); + + break; + case View.NOMINAL_FEET: + tMat2.setIdentity(); + break; + } + break; + } + + vpcToCoexistence.mul(tMat2, tMat1); + } + else { + vpcToCoexistence.set(tMat1); + } + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("vpcToCoexistence:"); + System.err.println(vpcToCoexistence); + } + } + + private void computeCoexistenceCenter() { + + if ((!viewCache.compatibilityModeEnable) && + (viewCache.viewPolicy != View.HMD_VIEW) && + (viewCache.coexistenceCenteringEnable) && + (viewCache.coexistenceCenterInPworldPolicy == View.NOMINAL_SCREEN)) { + + // Compute the coexistence center in image plate coordinates + + // Image plate cordinates have their orgin in the lower + // left hand corner of the CRT visiable raster. + // The nominal coexistence center is at the *center* of + // targeted area: either the window or screen, depending + // on policy. + if (viewCache.windowMovementPolicy == View.VIRTUAL_WORLD) { + coexistenceCenter.x = physicalScreenWidth / 2.0; + coexistenceCenter.y = physicalScreenHeight / 2.0; + coexistenceCenter.z = 0.0; + } + else { // windowMovementPolicy == PHYSICAL_WORLD + coexistenceCenter.x = physicalWindowCenter.x; + coexistenceCenter.y = physicalWindowCenter.y; + coexistenceCenter.z = 0.0; + } + } + else { + coexistenceCenter.set(0.0, 0.0, 0.0); + } + + if(J3dDebug.devPhase) { + if (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1) { + System.err.println("coexistenceCenter = " + coexistenceCenter); + } + } + } + + private void computeCoexistenceToPlate() { + if (viewCache.compatibilityModeEnable) { + // XXXX: implement this correctly + coexistenceToLeftPlate.setIdentity(); + return; + } + + if (viewCache.viewPolicy != View.HMD_VIEW) { + coexistenceToLeftPlate.set(coexistenceCenter); + coexistenceToLeftPlate.mul(screenViewCache.trackerBaseToImagePlate); + coexistenceToLeftPlate.mul(viewCache.coexistenceToTrackerBase); + + if(useStereo) { + coexistenceToRightPlate.set(coexistenceToLeftPlate); + } + } + else { + coexistenceToLeftPlate.mul(headTrackerToLeftImagePlate, + viewCache.trackerBaseToHeadTracker); + coexistenceToLeftPlate.mul(viewCache.coexistenceToTrackerBase); + + if(useStereo) { + coexistenceToRightPlate.mul(headTrackerToRightImagePlate, + viewCache.trackerBaseToHeadTracker); + coexistenceToRightPlate.mul(viewCache.coexistenceToTrackerBase); + } + } + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("coexistenceToLeftPlate:"); + System.err.println(coexistenceToLeftPlate); + if(useStereo) { + System.err.println("coexistenceToRightPlate:"); + System.err.println(coexistenceToRightPlate); + + } + } + } + + /** + * Computes the viewing matrices. + * + * computeView computes the following: + * + *
    + * left (& right) eye viewing matrices (only left is valid for mono view) + *
+ * + * This call works for both fixed screen and HMD displays. + */ + private void computeView(boolean doInfinite) { + int i,j; + int backClipPolicy; + double Fl, Fr, B, scale, backClipDistance; + + // compute scale used for transforming clip and fog distances + vworldToCoexistenceScale = vworldToVpc.getDistanceScale() + * vpcToCoexistence.getDistanceScale(); + if(doInfinite) { + infVworldToCoexistenceScale = infVworldToVpc.getDistanceScale() + * vpcToCoexistence.getDistanceScale(); + } + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("vworldToCoexistenceScale = " + + vworldToCoexistenceScale); + } + + // compute coexistenceToVworld transform -- dirty bit candidate!! + tempTrans.mul(viewCache.coexistenceToTrackerBase, vpcToCoexistence); + vworldToTrackerBase.mul(tempTrans, vworldToVpc); + + // If we are in compatibility mode, compute the view and + // projection matrices accordingly + if (viewCache.compatibilityModeEnable) { + leftProjection.set(viewCache.compatLeftProjection); + leftVpcToEc.set(viewCache.compatVpcToEc); + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) { + System.err.println("Left projection and view matrices"); + System.err.println("ecToCc (leftProjection) :"); + System.err.println(leftProjection); + System.err.println("vpcToEc:"); + System.err.println(leftVpcToEc); + } + + computeFrustumPlanes(leftProjection, leftVpcToEc, + leftFrustumPlanes, leftFrustumPoints, + leftCcToVworld); + + if(useStereo) { + rightProjection.set(viewCache.compatRightProjection); + rightVpcToEc.set(viewCache.compatVpcToEc); + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) { + System.err.println("Right projection and view matrices"); + System.err.println("ecToCc:"); + System.err.println("vpcToEc:"); + System.err.println(rightVpcToEc); + } + + computeFrustumPlanes(rightProjection, rightVpcToEc, + rightFrustumPlanes, rightFrustumPoints, + rightCcToVworld); + } + + return; + } + + // + // The clipping plane distances are set from the internal policy. + // + // Note that the plane distance follows the standard Z axis + // convention, e.g. negative numbers further away. + // Note that for policy from eye, the distance is negative in + // the direction of z in front of the eye. + // Note that for policy from screen, the distance is negative for + // locations behind the screen, and positive in front. + // + // The distance attributes are measured either in physical (plate) + // units, or vworld units. + // + + // Compute scale factor for front clip plane computation + if (viewCache.frontClipPolicy == View.VIRTUAL_EYE || + viewCache.frontClipPolicy == View.VIRTUAL_SCREEN) { + scale = vworldToCoexistenceScale; + } + else { + scale = windowScale; + } + + // Set left and right front clipping plane distances. + if(viewCache.frontClipPolicy == View.PHYSICAL_EYE || + viewCache.frontClipPolicy == View.VIRTUAL_EYE) { + Fl = leftEyeInImagePlate.z + + scale * -viewCache.frontClipDistance; + Fr = rightEyeInImagePlate.z + + scale * -viewCache.frontClipDistance; + } + else { + Fl = scale * -viewCache.frontClipDistance; + Fr = scale * -viewCache.frontClipDistance; + } + + // if there is an active clip node, use it and ignore the view's + // backclip + if ((renderBin != null) && (renderBin.backClipActive)) { + backClipPolicy = View.VIRTUAL_EYE; + backClipDistance = renderBin.backClipDistanceInVworld; + } else { + backClipPolicy = viewCache.backClipPolicy; + backClipDistance = viewCache.backClipDistance; + } + + // Compute scale factor for rear clip plane computation + if (backClipPolicy == View.VIRTUAL_EYE || + backClipPolicy == View.VIRTUAL_SCREEN) { + scale = vworldToCoexistenceScale; + } + else { + scale = windowScale; + } + + // Set left and right rear clipping plane distnaces. + if(backClipPolicy == View.PHYSICAL_EYE || + backClipPolicy == View.VIRTUAL_EYE) { + // Yes, left for both left and right rear. + B = leftEyeInImagePlate.z + + scale * -backClipDistance; + } + else { + B = scale * -backClipDistance; + } + + // XXXX: Can optimize for HMD case. + if (true /*viewCache.viewPolicy != View.HMD_VIEW*/) { + + // Call buildProjView to build the projection and view matrices. + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("Left projection and view matrices"); + System.err.println("Fl " + Fl + " B " + B); + System.err.println("leftEyeInImagePlate\n" + leftEyeInImagePlate); + System.err.println("Before : leftProjection\n" + leftProjection); + System.err.println("Before leftVpcToEc\n" + leftVpcToEc); + } + + buildProjView(leftEyeInImagePlate, coexistenceToLeftPlate, + vpcToLeftPlate, Fl, B, leftProjection, leftVpcToEc, false); + + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("After : leftProjection\n" + leftProjection); + System.err.println("After leftVpcToEc\n" + leftVpcToEc); + } + + computeFrustumPlanes(leftProjection, leftVpcToEc, + leftFrustumPlanes, leftFrustumPoints, + leftCcToVworld); + + if(useStereo) { + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) + System.err.println("Right projection and view matrices"); + + buildProjView(rightEyeInImagePlate, coexistenceToRightPlate, + vpcToRightPlate, Fr, B, rightProjection, + rightVpcToEc, false); + + computeFrustumPlanes(rightProjection, rightVpcToEc, + rightFrustumPlanes, rightFrustumPoints, + rightCcToVworld); + } + + // + // Now to compute the left (& right) eye (and infinite) + // viewing matrices. + if(doInfinite) { + // Call buildProjView separately for infinite view + buildProjView(leftEyeInImagePlate, coexistenceToLeftPlate, + vpcToLeftPlate, leftEyeInImagePlate.z - 0.05, + leftEyeInImagePlate.z - 1.5, + infLeftProjection, infLeftVpcToEc, true); + + if(useStereo) { + buildProjView(rightEyeInImagePlate, coexistenceToRightPlate, + vpcToRightPlate, rightEyeInImagePlate.z - 0.05, + rightEyeInImagePlate.z - 1.5, + infRightProjection, infRightVpcToEc, true); + + } + } + } + // XXXX: The following code has never been ported +// else { +// Point3d cen_eye; +// +// // HMD case. Just concatenate the approprate matrices together. +// // Additional work just for now +// +// compute_lr_plate_to_cc( &cen_eye, Fl, B, 0, &vb, 0); +// +// if(useStereo) { +// mat_mul_dpt(&right_eye_pos_in_head, +// head_to_right_plate, &cen_eye); +// compute_lr_plate_to_cc( &cen_eye, Fr, B, +// 1, &vb, 0); +// } +// +// // Make sure that coexistence_to_plate is current. +// // (It is usually constant for fixed plates, always varies for HMDs.) +// // For HMD case, computes finial matrices that will be used. +// // +// computeCoexistenceToPlate(); +// } + + } + + /** + * Debugging routine to analyze the projection matrix. + */ + private void analyzeProjection(Transform3D p, double xMax) { + if (viewCache.projectionPolicy == View.PARALLEL_PROJECTION) + System.err.println("PARALLEL_PROJECTION ="); + else + System.err.println("PERSPECTIVE_PROJECTION ="); + + System.err.println(p); + + double projectionPlaneZ = ((p.mat[0] * xMax + p.mat[3] - p.mat[15]) / + (p.mat[14] - p.mat[2])); + + System.err.println("projection plane at z = " + projectionPlaneZ); + } + + /** + * buildProjView creates a projection and viewing matrix. + * + * Inputs: + * ep : eye point, in plate coordinates + * coe2Plate : matrix from coexistence to image plate. + * F, B : front, back clipping planes, in plate coordinates + * doInfinite : flag to indicate ``at infinity'' view desired + * + * Output: + * vpc2Plate : matric from vpc to image plate. + * ecToCc : projection matrix from Eye Coordinates (EC) + * to Clipping Coordinates (CC) + * vpcToEc : view matrix from ViewPlatform Coordinates (VPC) + * to Eye Coordinates (EC) + */ + private void buildProjView(Point3d ep, + Transform3D coe2Plate, + Transform3D vpc2Plate, + double F, + double B, + Transform3D ecToCc, + Transform3D vpcToEc, + boolean doInfinite) { + + // Lx,Ly Hx,Hy will be adjusted window boundaries + double Lx, Hx, Ly, Hy; + Lx = physicalWindowXLeft; Hx = physicalWindowXRight; + Ly = physicalWindowYBottom; Hy = physicalWindowYTop; + + ecToCc.setIdentity(); + + + // XXXX: we have no concept of glass correction in the Java 3D API + // + // Correction in apparent 3D position of window due to glass/CRT + // and spherical/cylinderical curvarure of CRT. + // This boils down to producing modified values of Lx Ly Hx Hy + // and is different for hot spot vs. window center corrections. + // + /* XXXX: + double cx, cy; + if(viewPolicy != HMD_VIEW && enable_crt_glass_correction) { + if (correction_point == CORRECTION_POINT_WINDOW_CENTER) { + correct_crt( ep, Lx, Ly, &cx, &cy); Lx = cx; Ly = cy; + correct_crt( ep, Hx, Hy, &cx, &cy); Hx = cx; Hy = cy; + } + else { // must be hot spot correction + // Not real code yet, for now just do same as above. + correct_crt( ep, Lx, Ly, &cx, &cy); Lx = cx; Ly = cy; + correct_crt( ep, Hx, Hy, &cx, &cy); Hx = cx; Hy = cy; + } + } + */ + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("ep = " + ep); + System.err.println("Lx = " + Lx + ", Hx = " + Hx); + System.err.println("Ly = " + Ly + ", Hy = " + Hy); + System.err.println("F = " + F + ", B = " + B); + } + + // Compute the proper projection equation. Note that we + // do this in two steps: first we generate ImagePlateToCc, + // then we translate this by EcToPlate, resulting in a + // projection from EctoCc. + // + // A more efficient (and more accurate) approach would be to + // modify the equations below to directly project from EcToCc. + + if (viewCache.projectionPolicy == View.PARALLEL_PROJECTION) { + double inv_dx, inv_dy, inv_dz; + inv_dx = 1.0 / (Hx - Lx); + inv_dy = 1.0 / (Hy - Ly); + inv_dz = 1.0 / (F - B); + + ecToCc.mat[0] = 2.0 * inv_dx; + ecToCc.mat[3] = -(Hx + Lx) * inv_dx; + ecToCc.mat[5] = 2.0 * inv_dy; + ecToCc.mat[7] = -(Hy + Ly) * inv_dy; + ecToCc.mat[10] = 2.0 * inv_dz; + ecToCc.mat[11] = -(F + B) * inv_dz; + } + else { + double sxy, rzb, inv_dx, inv_dy; + + inv_dx = 1.0 / (Hx - Lx); + inv_dy = 1.0 / (Hy - Ly); + rzb = 1.0/(ep.z - B); + sxy = ep.z*rzb; + + ecToCc.mat[0] = sxy*2.0*inv_dx; + ecToCc.mat[5] = sxy*2.0*inv_dy; + + ecToCc.mat[2] = rzb*(Hx+Lx - 2.0*ep.x)*inv_dx; + ecToCc.mat[6] = rzb*(Hy+Ly - 2.0*ep.y)*inv_dy; + ecToCc.mat[10] = rzb*(B+F-2*ep.z)/(B-F); + ecToCc.mat[14] = -rzb; + + ecToCc.mat[3] = sxy*(-Hx-Lx)*inv_dx; + ecToCc.mat[7] = sxy*(-Hy-Ly)*inv_dy; + ecToCc.mat[11] = rzb*(B - ep.z - B*(B+F - 2*ep.z)/(B-F)); + ecToCc.mat[15] = sxy; + } + + // Since we set the matrix elements ourselves, we need to set the + // type field. A value of 0 means a non-affine matrix. + ecToCc.setOrthoDirtyBit(); + + // EC to ImagePlate matrix is a simple translation. + tVec1.set(ep.x, ep.y, ep.z); + tMat1.set(tVec1); + ecToCc.mul(tMat1); + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("ecToCc:"); + analyzeProjection(ecToCc, Hx); + } + + if(!doInfinite) { + // View matrix is: + // [plateToEc] [coexistence_to_plate] [vpc_to_coexistence] + // where vpc_to_coexistence includes the viewPlatformScale + + // First compute ViewPlatform to Plate + vpc2Plate.mul(coe2Plate, vpcToCoexistence); + + // ImagePlate to EC matrix is a simple translation. + tVec1.set(-ep.x, -ep.y, -ep.z); + tMat1.set(tVec1); + vpcToEc.mul(tMat1, vpc2Plate); + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + System.err.println("vpcToEc:"); + System.err.println(vpcToEc); + } + } + else { + // Final infinite composite is: + // [coexistence_to_eye] [vpc_to_coexistence (vom)] + // (does vworld_to_coe_scale_factor get used here??? ) + // + // The method is to relocate the coexistence org centered on + // the eye rather than the window center (via coexistence_to_eye). + // Computationaly simpler simplifed equation form may exist. + + // coexistence to eye is a simple translation. +/* + tVec1.set(ep.x, ep.y, ep.z); + tMat1.set(tVec1); + vpcToEc.mul(tMat1, vpcToCoexistence); + // First compute ViewPlatform to Plate + vpcToPlate.mul(coexistenceToPlatevpcToPlate, vpcToCoexistence); +*/ + + // ImagePlate to EC matrix is a simple translation. + tVec1.set(-ep.x, -ep.y, -ep.z); + tMat1.set(tVec1); + tMat1.mul(tMat1, vpc2Plate); + tMat1.getRotation(vpcToEc); // use only rotation component of transform + + } + + } + + /** + * Compute the plane equations for the frustum in ViewPlatform + * coordinates, plus its viewing frustum points. ccToVworld will + * be cached - used by Canavs3D.getInverseVworldProjection(). + */ + private void computeFrustumPlanes(Transform3D ecToCc, + Transform3D vpcToEc, + Vector4d [] frustumPlanes, + Point4d [] frustumPoints, + Transform3D ccToVworld) { + + // Compute the inverse of the Vworld to Cc transform. This + // gives us the Cc to Vworld transform. + tMat2.mul(ecToCc, vpcToEc); + ccToVworld.mul(tMat2, vworldToVpc); + // System.err.println("ccToVworld = " + ccToVworld); + try { + ccToVworld.invert(); + } + catch (SingularMatrixException e) { + ccToVworld.setIdentity(); + // System.err.println("SingularMatrixException encountered when doing invert in computeFrustumPlanes"); + } + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) { + Transform3D t = new Transform3D(); + t.mul(ecToCc, vpcToEc); + t.mul(vworldToVpc); + System.err.println("\nvworldToCc = " + t); + System.err.println("ccToVworld = " + ccToVworld); + t.mul(ccToVworld); + System.err.println("vworldToCc * ccToVworld = " + t); + } + + // Transform the 8 corners of the viewing frustum into Vpc + frustumPoints[0].set(-1.0, -1.0, 1.0, 1.0); // lower-left-front + frustumPoints[1].set(-1.0, 1.0, 1.0, 1.0); // upper-left-front + frustumPoints[2].set( 1.0, 1.0, 1.0, 1.0); // upper-right-front + frustumPoints[3].set( 1.0, -1.0, 1.0, 1.0); // lower-right-front + frustumPoints[4].set(-1.0, -1.0, -1.0, 1.0); // lower-left-back + frustumPoints[5].set(-1.0, 1.0, -1.0, 1.0); // upper-left-back + frustumPoints[6].set( 1.0, 1.0, -1.0, 1.0); // upper-right-back + frustumPoints[7].set( 1.0, -1.0, -1.0, 1.0); // lower-right-back + + ccToVworld.get(tMatrix); + int i; + for (i = 0; i < frustumPoints.length; i++) { + tMatrix.transform(frustumPoints[i]); + double w_inv = 1.0 / frustumPoints[i].w; + frustumPoints[i].x *= w_inv; + frustumPoints[i].y *= w_inv; + frustumPoints[i].z *= w_inv; + } + + // Now compute the 6 plane equations + // left + computePlaneEq(frustumPoints[0], frustumPoints[4], + frustumPoints[5], frustumPoints[1], + frustumPlanes[0]); + + // right + computePlaneEq(frustumPoints[3], frustumPoints[2], + frustumPoints[6], frustumPoints[7], + frustumPlanes[1]); + + // top + computePlaneEq(frustumPoints[1], frustumPoints[5], + frustumPoints[6], frustumPoints[2], + frustumPlanes[2]); + + // bottom + computePlaneEq(frustumPoints[0], frustumPoints[3], + frustumPoints[7], frustumPoints[4], + frustumPlanes[3]); + + // front + computePlaneEq(frustumPoints[0], frustumPoints[1], + frustumPoints[2], frustumPoints[3], + frustumPlanes[4]); + + // back + computePlaneEq(frustumPoints[4], frustumPoints[7], + frustumPoints[6], frustumPoints[5], + frustumPlanes[5]); + + //System.err.println("left plane = " + frustumPlanes[0]); + //System.err.println("right plane = " + frustumPlanes[1]); + //System.err.println("top plane = " + frustumPlanes[2]); + //System.err.println("bottom plane = " + frustumPlanes[3]); + //System.err.println("front plane = " + frustumPlanes[4]); + //System.err.println("back plane = " + frustumPlanes[5]); + } + + private void computePlaneEq(Point4d p1, Point4d p2, Point4d p3, Point4d p4, + Vector4d planeEq) { + tVec1.x = p3.x - p1.x; + tVec1.y = p3.y - p1.y; + tVec1.z = p3.z - p1.z; + + tVec2.x = p2.x - p1.x; + tVec2.y = p2.y - p1.y; + tVec2.z = p2.z - p1.z; + + tVec3.cross(tVec2, tVec1); + tVec3.normalize(); + planeEq.x = tVec3.x; + planeEq.y = tVec3.y; + planeEq.z = tVec3.z; + planeEq.w = -(planeEq.x * p1.x + planeEq.y * p1.y + planeEq.z * p1.z); + } + + // Get methods for returning derived data values. + // Eventually, these get functions will cause some of the parameters + // to be lazily evaluated. + // + // NOTE: in the case of Transform3D, and Tuple objects, a reference + // to the actual derived data is returned. In these cases, the caller + // must ensure that the returned data is not modified. + // + // NOTE: the snapshot and computeDerivedData methods are synchronized. + // Callers of the following methods that can run asynchronously with + // the renderer must call these methods and copy the data from within + // a synchronized block on the canvas view cache object. + + int getCanvasX() { + return canvasX; + } + + int getCanvasY() { + return canvasY; + } + + int getCanvasWidth() { + return canvasWidth; + } + + int getCanvasHeight() { + return canvasHeight; + } + + double getPhysicalWindowWidth() { + return physicalWindowWidth; + } + + double getPhysicalWindowHeight() { + return physicalWindowHeight; + } + + boolean getUseStereo() { + return useStereo; + } + + Transform3D getLeftProjection() { + return leftProjection; + } + + Transform3D getRightProjection() { + return rightProjection; + } + + Transform3D getLeftVpcToEc() { + return leftVpcToEc; + } + + Transform3D getRightVpcToEc() { + return rightVpcToEc; + } + + Transform3D getLeftEcToVpc() { + return leftEcToVpc; + } + + Transform3D getRightEcToVpc() { + return rightEcToVpc; + } + + Transform3D getInfLeftProjection() { + return infLeftProjection; + } + + Transform3D getInfRightProjection() { + return infLeftProjection; + } + + Transform3D getInfLeftVpcToEc() { + return infLeftVpcToEc; + } + + Transform3D getInfRightVpcToEc() { + return infRightVpcToEc; + } + + Transform3D getInfLeftEcToVpc() { + return infLeftEcToVpc; + } + + Transform3D getInfgRightEcToVpc() { + return infRightEcToVpc; + } + + Transform3D getInfVworldToVpc() { + return infVworldToVpc; + } + + Transform3D getLeftCcToVworld() { + return leftCcToVworld; + } + + Transform3D getRightCcToVworld() { + return rightCcToVworld; + } + + Transform3D getImagePlateToVworld() { + // XXXX: Document -- This will return the transform of left plate. + return leftPlateToVworld; + } + + + + Transform3D getLastVworldToImagePlate() { + // XXXX: Document -- This will return the transform of left plate. + return lastVworldToLeftPlate; + + } + + Transform3D getVworldToImagePlate() { + // XXXX: Document -- This will return the transform of left plate. + return vworldToLeftPlate; + } + + Transform3D getVworldToTrackerBase() { + return vworldToTrackerBase; + } + + double getVworldToCoexistenceScale() { + return vworldToCoexistenceScale; + } + + double getInfVworldToCoexistenceScale() { + return infVworldToCoexistenceScale; + } + + Point3d getLeftEyeInImagePlate() { + return leftEyeInImagePlate; + } + + Point3d getRightEyeInImagePlate() { + return rightEyeInImagePlate; + } + + Point3d getCenterEyeInImagePlate() { + return centerEyeInImagePlate; + } + + Transform3D getHeadToVworld() { + return headToVworld; + } + + Transform3D getVpcToVworld() { + return vpcToVworld; + } + + Transform3D getVworldToVpc() { + return vworldToVpc; + } + + + // Transform the specified X point in AWT window-relative coordinates + // to image plate coordinates + double getWindowXInImagePlate(double x) { + double xScreen = x + (double)canvasX; + return metersPerPixelX * xScreen; + } + + // Transform the specified Y point in AWT window-relative coordinates + // to image plate coordinates + double getWindowYInImagePlate(double y) { + double yScreen = y + (double)canvasY; + return metersPerPixelY * ((double)(screenHeight - 1) - yScreen); + } + + Vector4d[] getLeftFrustumPlanesInVworld() { + return leftFrustumPlanes; + } + + Vector4d[] getRightFrustumPlanesInVworld() { + return rightFrustumPlanes; + } + + + void getPixelLocationInImagePlate(double x, double y, double z, + Point3d imagePlatePoint) { + + double screenx = (x + canvasX)*metersPerPixelX; + double screeny = (screenHeight - 1 - canvasY - y)*metersPerPixelY; + + if ((viewCache.projectionPolicy == View.PERSPECTIVE_PROJECTION) && + (centerEyeInImagePlate.z != 0)) { + double zScale = 1.0 - z/centerEyeInImagePlate.z; + imagePlatePoint.x = (screenx - centerEyeInImagePlate.x)*zScale + + centerEyeInImagePlate.x; + imagePlatePoint.y = (screeny - centerEyeInImagePlate.y)*zScale + + centerEyeInImagePlate.y; + } else { + imagePlatePoint.x = screenx; + imagePlatePoint.y = screeny; + } + imagePlatePoint.z = z; + } + + /** + * Projects the specified point from image plate coordinates + * into AWT pixel coordinates. + */ + void getPixelLocationFromImagePlate(Point3d imagePlatePoint, + Point2d pixelLocation) { + + double screenX, screenY; + + if(viewCache.projectionPolicy == View.PERSPECTIVE_PROJECTION) { + // get the vector from centerEyeInImagePlate to imagePlatePoint + tVec1.sub(imagePlatePoint, centerEyeInImagePlate); + + // Scale this vector to make it end at the projection plane. + // Scale is ratio : + // eye->imagePlate Plane dist / eye->imagePlatePt dist + // eye dist to plane is eyePos.z (eye is in +z space) + // image->eye dist is -tVec1.z (image->eye is in -z dir) + //System.err.println("eye dist = " + (centerEyeInImagePlate.z)); + //System.err.println("image dist = " + (-tVec1.z)); + if (tVec1.z != 0) { + double zScale = centerEyeInImagePlate.z / (-tVec1.z); + screenX = centerEyeInImagePlate.x + tVec1.x * zScale; + screenY = centerEyeInImagePlate.y + tVec1.y * zScale; + + } else { + screenX = imagePlatePoint.x; + screenY = imagePlatePoint.y; + } + + } else { + screenX = imagePlatePoint.x; + screenY = imagePlatePoint.y; + } + + //System.err.println("screenX = " + screenX + " screenY = " + screenY); + // Note: screenPt is in image plate coords, at z=0 + + // Transform from image plate coords to screen coords + pixelLocation.x = (screenX / screenViewCache.metersPerPixelX) - canvasX; + pixelLocation.y = screenViewCache.screenHeight - 1 - + (screenY / screenViewCache.metersPerPixelY) - canvasY; + //System.err.println("pixelLocation = " + pixelLocation); + } + + /** + * Constructs and initializes a CanvasViewCache object. + * Note that the canvas, screen, screenCache, view, and + * viewCache parameters are all fixed at construction time + * and must be non-null. + */ + CanvasViewCache(Canvas3D canvas, + ScreenViewCache screenViewCache, + ViewCache viewCache) { + + this.canvas = canvas; + this.screenViewCache = screenViewCache; + this.viewCache = viewCache; + + // Set up the initial plane equations + int i; + for (i = 0; i < leftFrustumPlanes.length; i++) { + leftFrustumPlanes[i] = new Vector4d(); + rightFrustumPlanes[i] = new Vector4d(); + } + + for (i = 0; i < leftFrustumPoints.length; i++) { + leftFrustumPoints[i] = new Point4d(); + rightFrustumPoints[i] = new Point4d(); + } + + // canvas is null in Renderer copyOfCvCache + if (canvas != null) { + leftEyeInImagePlate.set(canvas.leftManualEyeInImagePlate); + rightEyeInImagePlate.set(canvas.rightManualEyeInImagePlate); + centerEyeInImagePlate.add(leftEyeInImagePlate, + rightEyeInImagePlate); + centerEyeInImagePlate.scale(0.5); + } + + if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) + System.err.println("Constructed a CanvasViewCache"); + } + + synchronized void setCanvas(Canvas3D c) { + canvas = c; + } + + synchronized void setScreenViewCache(ScreenViewCache svc) { + screenViewCache = svc; + } + + synchronized void setViewCache(ViewCache vc) { + viewCache = vc; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CanvasViewEventCatcher.java b/j3d-core/src/classes/share/javax/media/j3d/CanvasViewEventCatcher.java new file mode 100644 index 0000000..b821841 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CanvasViewEventCatcher.java @@ -0,0 +1,102 @@ +/* + * $RCSfile: CanvasViewEventCatcher.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; +import java.awt.*; +import java.awt.event.*; + +/** + * The CanvasViewEventCatcher class is used to track events on a Canvas3D that + * may cause view matries to change. + * + */ +class CanvasViewEventCatcher extends ComponentAdapter { + + // The canvas associated with this event catcher + private Canvas3D canvas; + private static final boolean DEBUG = false; + + CanvasViewEventCatcher(Canvas3D c) { + canvas = c; + } + + public void componentResized(ComponentEvent e) { + if (DEBUG) { + System.err.println("Component resized " + e); + } + + if(e.getComponent() == canvas ) { + if (DEBUG) { + System.err.println("It is canvas!"); + } + synchronized(canvas) { + synchronized (canvas.dirtyMaskLock) { + canvas.cvDirtyMask[0] |= Canvas3D.MOVED_OR_RESIZED_DIRTY; + canvas.cvDirtyMask[1] |= Canvas3D.MOVED_OR_RESIZED_DIRTY; + } + canvas.resizeGraphics2D = true; + } + + // see comment below + try { + canvas.newSize = canvas.getSize(); + canvas.newPosition = canvas.getLocationOnScreen(); + } catch (IllegalComponentStateException ex) {} + + } + } + + public void componentMoved(ComponentEvent e) { + if (DEBUG) { + System.err.println("Component moved " + e); + } + + synchronized(canvas) { + synchronized (canvas.dirtyMaskLock) { + canvas.cvDirtyMask[0] |= Canvas3D.MOVED_OR_RESIZED_DIRTY; + canvas.cvDirtyMask[1] |= Canvas3D.MOVED_OR_RESIZED_DIRTY; + } + } + // Can't sync. with canvas lock since canvas.getLocationOnScreen() + // required Component lock. The order is reverse of + // removeNotify() lock sequence which required Component lock + // first, then canvas lock in removeComponentListener() + + try { + canvas.newSize = canvas.getSize(); + canvas.newPosition = canvas.getLocationOnScreen(); + } catch (IllegalComponentStateException ex) {} + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CapabilityBits.java b/j3d-core/src/classes/share/javax/media/j3d/CapabilityBits.java new file mode 100644 index 0000000..8dbdb7e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CapabilityBits.java @@ -0,0 +1,546 @@ +/* + * $RCSfile: CapabilityBits.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * This CapabilityBits class provides a global namespace for all + * capability bits + */ +class CapabilityBits extends Object { + + // SceneGraphObject + + // Node extends SceneGraphObject + static final int NODE_ENABLE_COLLISION_REPORTING = 0; + static final int NODE_ENABLE_PICK_REPORTING = 1; + private static final int NODE_UNUSED_BIT = 2; + static final int NODE_ALLOW_BOUNDS_READ = 3; + static final int NODE_ALLOW_BOUNDS_WRITE = 4; + static final int NODE_ALLOW_PICKABLE_READ = 5; + static final int NODE_ALLOW_PICKABLE_WRITE = 6; + static final int NODE_ALLOW_COLLIDABLE_READ = 7; + static final int NODE_ALLOW_COLLIDABLE_WRITE = 8; + static final int NODE_ALLOW_AUTO_COMPUTE_BOUNDS_READ = 9; + static final int NODE_ALLOW_AUTO_COMPUTE_BOUNDS_WRITE = 10; + static final int NODE_ALLOW_LOCAL_TO_VWORLD_READ = 11; + + + // Group extends Node + static final int GROUP_ALLOW_CHILDREN_READ = 12; + static final int GROUP_ALLOW_CHILDREN_WRITE = 13; + static final int GROUP_ALLOW_CHILDREN_EXTEND = 14; + static final int GROUP_ALLOW_COLLISION_BOUNDS_READ = 15; + static final int GROUP_ALLOW_COLLISION_BOUNDS_WRITE = 16; + + // BranchGroup extends Group + static final int BRANCH_GROUP_ALLOW_DETACH = 17; + + // SharedGroup extends Group + static final int SHARED_GROUP_ALLOW_LINK_READ = 17; + + // TransformGroup extends Group + static final int TRANSFORM_GROUP_ALLOW_TRANSFORM_READ = 17; + static final int TRANSFORM_GROUP_ALLOW_TRANSFORM_WRITE = 18; + + // Switch extends Group + static final int SWITCH_ALLOW_SWITCH_READ = 17; + static final int SWITCH_ALLOW_SWITCH_WRITE = 18; + + // ViewSpecificGroup extends Group + static final int VIEW_SPECIFIC_GROUP_ALLOW_VIEW_READ = 17; + static final int VIEW_SPECIFIC_GROUP_ALLOW_VIEW_WRITE = 18; + + // OrderedGroup extends Group + static final int ORDERED_GROUP_ALLOW_CHILD_INDEX_ORDER_READ = 17; + static final int ORDERED_GROUP_ALLOW_CHILD_INDEX_ORDER_WRITE = 18; + + + // Leaf extends Node + + // Background extends Leaf + static final int BACKGROUND_ALLOW_APPLICATION_BOUNDS_READ = 12; + static final int BACKGROUND_ALLOW_APPLICATION_BOUNDS_WRITE = 13; + static final int BACKGROUND_ALLOW_IMAGE_READ = 14; + static final int BACKGROUND_ALLOW_IMAGE_WRITE = 15; + static final int BACKGROUND_ALLOW_COLOR_READ = 16; + static final int BACKGROUND_ALLOW_COLOR_WRITE = 17; + static final int BACKGROUND_ALLOW_GEOMETRY_READ = 18; + static final int BACKGROUND_ALLOW_GEOMETRY_WRITE = 19; + static final int BACKGROUND_ALLOW_IMAGE_SCALE_MODE_READ = 20; + static final int BACKGROUND_ALLOW_IMAGE_SCALE_MODE_WRITE = 21; + + // BoundingLeaf extends Leaf + static final int BOUNDING_LEAF_ALLOW_REGION_READ = 12; + static final int BOUNDING_LEAF_ALLOW_REGION_WRITE = 13; + + // Clip extends Leaf + static final int CLIP_ALLOW_APPLICATION_BOUNDS_READ = 12; + static final int CLIP_ALLOW_APPLICATION_BOUNDS_WRITE = 13; + static final int CLIP_ALLOW_BACK_DISTANCE_READ = 14; + static final int CLIP_ALLOW_BACK_DISTANCE_WRITE = 15; + + // Morph extends Leaf + static final int MORPH_ALLOW_GEOMETRY_ARRAY_READ = 12; + static final int MORPH_ALLOW_GEOMETRY_ARRAY_WRITE = 13; + static final int MORPH_ALLOW_APPEARANCE_READ = 14; + static final int MORPH_ALLOW_APPEARANCE_WRITE = 15; + static final int MORPH_ALLOW_WEIGHTS_READ = 16; + static final int MORPH_ALLOW_WEIGHTS_WRITE = 17; + static final int MORPH_ALLOW_COLLISION_BOUNDS_READ = 18; + static final int MORPH_ALLOW_COLLISION_BOUNDS_WRITE = 19; + static final int MORPH_ALLOW_APPEARANCE_OVERRIDE_READ = 20; + static final int MORPH_ALLOW_APPEARANCE_OVERRIDE_WRITE = 21; + + // Link extends Leaf + static final int LINK_ALLOW_SHARED_GROUP_READ = 12; + static final int LINK_ALLOW_SHARED_GROUP_WRITE = 13; + + // Shape3D extends Leaf + static final int SHAPE3D_ALLOW_GEOMETRY_READ = 12; + static final int SHAPE3D_ALLOW_GEOMETRY_WRITE = 13; + static final int SHAPE3D_ALLOW_APPEARANCE_READ = 14; + static final int SHAPE3D_ALLOW_APPEARANCE_WRITE = 15; + static final int SHAPE3D_ALLOW_COLLISION_BOUNDS_READ = 16; + static final int SHAPE3D_ALLOW_COLLISION_BOUNDS_WRITE = 17; + static final int SHAPE3D_ALLOW_APPEARANCE_OVERRIDE_READ = 18; + static final int SHAPE3D_ALLOW_APPEARANCE_OVERRIDE_WRITE = 19; + + // OrientedShape3D extends Shape3D + static final int ORIENTED_SHAPE3D_ALLOW_MODE_READ = 20; + static final int ORIENTED_SHAPE3D_ALLOW_MODE_WRITE = 21; + static final int ORIENTED_SHAPE3D_ALLOW_AXIS_READ = 22; + static final int ORIENTED_SHAPE3D_ALLOW_AXIS_WRITE = 23; + static final int ORIENTED_SHAPE3D_ALLOW_POINT_READ = 24; + static final int ORIENTED_SHAPE3D_ALLOW_POINT_WRITE = 25; + static final int ORIENTED_SHAPE3D_ALLOW_SCALE_READ = 26; + static final int ORIENTED_SHAPE3D_ALLOW_SCALE_WRITE = 27; + + // Soundscape extends Leaf + static final int SOUNDSCAPE_ALLOW_APPLICATION_BOUNDS_READ = 12; + static final int SOUNDSCAPE_ALLOW_APPLICATION_BOUNDS_WRITE = 13; + static final int SOUNDSCAPE_ALLOW_ATTRIBUTES_READ = 14; + static final int SOUNDSCAPE_ALLOW_ATTRIBUTES_WRITE = 15; + + // ViewPlatform extends Leaf + static final int VIEW_PLATFORM_ALLOW_POLICY_READ = 12; + static final int VIEW_PLATFORM_ALLOW_POLICY_WRITE = 13; + + // Fog extends Leaf + static final int FOG_ALLOW_INFLUENCING_BOUNDS_READ = 12; + static final int FOG_ALLOW_INFLUENCING_BOUNDS_WRITE = 13; + static final int FOG_ALLOW_COLOR_READ = 14; + static final int FOG_ALLOW_COLOR_WRITE = 15; + + // ExponentialFog extends Fog + static final int EXPONENTIAL_FOG_ALLOW_DENSITY_READ = 16; + static final int EXPONENTIAL_FOG_ALLOW_DENSITY_WRITE = 17; + + // LinearFog extends Fog + static final int LINEAR_FOG_ALLOW_DISTANCE_READ = 16; + static final int LINEAR_FOG_ALLOW_DISTANCE_WRITE = 17; + + // Additional Fog bits (must go after LinearFog bits) + static final int FOG_ALLOW_SCOPE_READ = 18; + static final int FOG_ALLOW_SCOPE_WRITE = 19; + + // Light extends Leaf + static final int LIGHT_ALLOW_STATE_READ = 12; + static final int LIGHT_ALLOW_STATE_WRITE = 13; + static final int LIGHT_ALLOW_COLOR_READ = 14; + static final int LIGHT_ALLOW_COLOR_WRITE = 15; + static final int LIGHT_ALLOW_INFLUENCING_BOUNDS_READ = 16; + static final int LIGHT_ALLOW_INFLUENCING_BOUNDS_WRITE = 17; + + // DirectionalLight extends Light + static final int DIRECTIONAL_LIGHT_ALLOW_DIRECTION_READ = 18; + static final int DIRECTIONAL_LIGHT_ALLOW_DIRECTION_WRITE = 19; + + // PointLight extends Light + static final int POINT_LIGHT_ALLOW_POSITION_READ = 18; + static final int POINT_LIGHT_ALLOW_POSITION_WRITE = 19; + static final int POINT_LIGHT_ALLOW_ATTENUATION_READ = 20; + static final int POINT_LIGHT_ALLOW_ATTENUATION_WRITE = 21; + + // SpotLight extends PointLight + static final int SPOT_LIGHT_ALLOW_SPREAD_ANGLE_WRITE = 22; + static final int SPOT_LIGHT_ALLOW_SPREAD_ANGLE_READ = 23; + static final int SPOT_LIGHT_ALLOW_CONCENTRATION_WRITE = 24; + static final int SPOT_LIGHT_ALLOW_CONCENTRATION_READ = 25; + static final int SPOT_LIGHT_ALLOW_DIRECTION_WRITE = 26; + static final int SPOT_LIGHT_ALLOW_DIRECTION_READ = 27; + + // Additional Light bits (must go after SpotLight bits) + static final int LIGHT_ALLOW_SCOPE_READ = 28; + static final int LIGHT_ALLOW_SCOPE_WRITE = 29; + + // Sound extends Leaf + static final int SOUND_ALLOW_SOUND_DATA_READ = 12; + static final int SOUND_ALLOW_SOUND_DATA_WRITE = 13; + static final int SOUND_ALLOW_INITIAL_GAIN_READ = 14; + static final int SOUND_ALLOW_INITIAL_GAIN_WRITE = 15; + static final int SOUND_ALLOW_LOOP_READ = 16; + static final int SOUND_ALLOW_LOOP_WRITE = 17; + static final int SOUND_ALLOW_RELEASE_READ = 18; + static final int SOUND_ALLOW_RELEASE_WRITE = 19; + static final int SOUND_ALLOW_CONT_PLAY_READ = 20; + static final int SOUND_ALLOW_CONT_PLAY_WRITE = 21; + static final int SOUND_ALLOW_ENABLE_READ = 22; + static final int SOUND_ALLOW_ENABLE_WRITE = 23; + static final int SOUND_ALLOW_SCHEDULING_BOUNDS_READ = 24; + static final int SOUND_ALLOW_SCHEDULING_BOUNDS_WRITE = 25; + static final int SOUND_ALLOW_PRIORITY_READ = 26; + static final int SOUND_ALLOW_PRIORITY_WRITE = 27; + static final int SOUND_ALLOW_DURATION_READ = 28; + static final int SOUND_ALLOW_IS_READY_READ = 29; + static final int SOUND_ALLOW_IS_PLAYING_READ = 30; + static final int SOUND_ALLOW_CHANNELS_USED_READ = 31; + static final int SOUND_ALLOW_MUTE_READ = 40; + static final int SOUND_ALLOW_MUTE_WRITE = 41; + static final int SOUND_ALLOW_PAUSE_READ = 42; + static final int SOUND_ALLOW_PAUSE_WRITE = 43; + static final int SOUND_ALLOW_RATE_SCALE_FACTOR_READ = 44; + static final int SOUND_ALLOW_RATE_SCALE_FACTOR_WRITE = 45; + + // PointSound extends Sound + static final int POINT_SOUND_ALLOW_POSITION_READ = 32; + static final int POINT_SOUND_ALLOW_POSITION_WRITE = 33; + static final int POINT_SOUND_ALLOW_DISTANCE_GAIN_READ = 34; + static final int POINT_SOUND_ALLOW_DISTANCE_GAIN_WRITE = 35; + + // ConeSound extends PointSound + static final int CONE_SOUND_ALLOW_DIRECTION_READ = 36; + static final int CONE_SOUND_ALLOW_DIRECTION_WRITE = 37; + static final int CONE_SOUND_ALLOW_ANGULAR_ATTENUATION_READ = 38; + static final int CONE_SOUND_ALLOW_ANGULAR_ATTENUATION_WRITE = 39; + + // ModelClip extends Leaf + static final int MODEL_CLIP_ALLOW_INFLUENCING_BOUNDS_READ = 12; + static final int MODEL_CLIP_ALLOW_INFLUENCING_BOUNDS_WRITE = 13; + static final int MODEL_CLIP_ALLOW_PLANE_READ = 14; + static final int MODEL_CLIP_ALLOW_PLANE_WRITE = 15; + static final int MODEL_CLIP_ALLOW_ENABLE_READ = 16; + static final int MODEL_CLIP_ALLOW_ENABLE_WRITE = 17; + static final int MODEL_CLIP_ALLOW_SCOPE_READ = 18; + static final int MODEL_CLIP_ALLOW_SCOPE_WRITE = 19; + + // AlternateAppearance extends Leaf + static final int ALTERNATE_APPEARANCE_ALLOW_INFLUENCING_BOUNDS_READ = 12; + static final int ALTERNATE_APPEARANCE_ALLOW_INFLUENCING_BOUNDS_WRITE = 13; + static final int ALTERNATE_APPEARANCE_ALLOW_APPEARANCE_READ = 14; + static final int ALTERNATE_APPEARANCE_ALLOW_APPEARANCE_WRITE = 15; + static final int ALTERNATE_APPEARANCE_ALLOW_SCOPE_READ = 16; + static final int ALTERNATE_APPEARANCE_ALLOW_SCOPE_WRITE = 17; + + // Additional Node bits (must go after all existing Node subclass bits) + static final int NODE_ALLOW_PARENT_READ = 46; + static final int NODE_ALLOW_LOCALE_READ = 47; + + + // NodeComponent extends SceneGraphObject + + // Appearance extends NodeComponent + static final int APPEARANCE_ALLOW_MATERIAL_READ = 0; + static final int APPEARANCE_ALLOW_MATERIAL_WRITE = 1; + static final int APPEARANCE_ALLOW_TEXTURE_READ = 2; + static final int APPEARANCE_ALLOW_TEXTURE_WRITE = 3; + static final int APPEARANCE_ALLOW_TEXGEN_READ = 4; + static final int APPEARANCE_ALLOW_TEXGEN_WRITE = 5; + static final int APPEARANCE_ALLOW_TEXTURE_ATTRIBUTES_READ = 6; + static final int APPEARANCE_ALLOW_TEXTURE_ATTRIBUTES_WRITE = 7; + static final int APPEARANCE_ALLOW_COLORING_ATTRIBUTES_READ = 8; + static final int APPEARANCE_ALLOW_COLORING_ATTRIBUTES_WRITE = 9; + static final int APPEARANCE_ALLOW_TRANSPARENCY_ATTRIBUTES_READ = 10; + static final int APPEARANCE_ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE = 11; + static final int APPEARANCE_ALLOW_RENDERING_ATTRIBUTES_READ = 12; + static final int APPEARANCE_ALLOW_RENDERING_ATTRIBUTES_WRITE = 13; + static final int APPEARANCE_ALLOW_POLYGON_ATTRIBUTES_READ = 14; + static final int APPEARANCE_ALLOW_POLYGON_ATTRIBUTES_WRITE = 15; + static final int APPEARANCE_ALLOW_LINE_ATTRIBUTES_READ = 16; + static final int APPEARANCE_ALLOW_LINE_ATTRIBUTES_WRITE = 17; + static final int APPEARANCE_ALLOW_POINT_ATTRIBUTES_READ = 18; + static final int APPEARANCE_ALLOW_POINT_ATTRIBUTES_WRITE = 19; + static final int APPEARANCE_ALLOW_TEXTURE_UNIT_STATE_READ = 20; + static final int APPEARANCE_ALLOW_TEXTURE_UNIT_STATE_WRITE = 21; + + // ShaderAppearance extends Appearance + static final int SHADER_APPEARANCE_ALLOW_SHADER_PROGRAM_READ = 22; + static final int SHADER_APPEARANCE_ALLOW_SHADER_PROGRAM_WRITE = 23; + static final int SHADER_APPEARANCE_ALLOW_SHADER_ATTRIBUTE_SET_READ = 24; + static final int SHADER_APPEARANCE_ALLOW_SHADER_ATTRIBUTE_SET_WRITE = 25; + + // AuralAttributes extends NodeComponent + static final int AURAL_ATTRIBUTES_ALLOW_ATTRIBUTE_GAIN_READ = 0; + static final int AURAL_ATTRIBUTES_ALLOW_ATTRIBUTE_GAIN_WRITE = 1; + static final int AURAL_ATTRIBUTES_ALLOW_ROLLOFF_READ = 2; + static final int AURAL_ATTRIBUTES_ALLOW_ROLLOFF_WRITE = 3; + static final int AURAL_ATTRIBUTES_ALLOW_REFLECTION_COEFFICIENT_READ = 4; + static final int AURAL_ATTRIBUTES_ALLOW_REFLECTION_COEFFICIENT_WRITE = 5; + static final int AURAL_ATTRIBUTES_ALLOW_REVERB_DELAY_READ = 6; + static final int AURAL_ATTRIBUTES_ALLOW_REVERB_DELAY_WRITE = 7; + static final int AURAL_ATTRIBUTES_ALLOW_REVERB_ORDER_READ = 8; + static final int AURAL_ATTRIBUTES_ALLOW_REVERB_ORDER_WRITE = 9; + static final int AURAL_ATTRIBUTES_ALLOW_DISTANCE_FILTER_READ = 10; + static final int AURAL_ATTRIBUTES_ALLOW_DISTANCE_FILTER_WRITE = 11; + static final int AURAL_ATTRIBUTES_ALLOW_FREQUENCY_SCALE_FACTOR_READ = 12; + static final int AURAL_ATTRIBUTES_ALLOW_FREQUENCY_SCALE_FACTOR_WRITE = 13; + static final int AURAL_ATTRIBUTES_ALLOW_VELOCITY_SCALE_FACTOR_READ = 14; + static final int AURAL_ATTRIBUTES_ALLOW_VELOCITY_SCALE_FACTOR_WRITE = 15; + static final int AURAL_ATTRIBUTES_ALLOW_REFLECTION_DELAY_READ = 16; + static final int AURAL_ATTRIBUTES_ALLOW_REFLECTION_DELAY_WRITE = 17; + static final int AURAL_ATTRIBUTES_ALLOW_REVERB_COEFFICIENT_READ = 18; + static final int AURAL_ATTRIBUTES_ALLOW_REVERB_COEFFICIENT_WRITE = 19; + static final int AURAL_ATTRIBUTES_ALLOW_DECAY_TIME_READ = 20; + static final int AURAL_ATTRIBUTES_ALLOW_DECAY_TIME_WRITE = 21; + static final int AURAL_ATTRIBUTES_ALLOW_DECAY_FILTER_READ = 22; + static final int AURAL_ATTRIBUTES_ALLOW_DECAY_FILTER_WRITE = 23; + static final int AURAL_ATTRIBUTES_ALLOW_DIFFUSION_READ = 24; + static final int AURAL_ATTRIBUTES_ALLOW_DIFFUSION_WRITE = 25; + static final int AURAL_ATTRIBUTES_ALLOW_DENSITY_READ = 26; + static final int AURAL_ATTRIBUTES_ALLOW_DENSITY_WRITE = 27; + + // ColoringAttributes extends NodeComponent + static final int COLORING_ATTRIBUTES_ALLOW_COLOR_READ = 0; + static final int COLORING_ATTRIBUTES_ALLOW_COLOR_WRITE = 1; + static final int COLORING_ATTRIBUTES_ALLOW_SHADE_MODEL_READ = 2; + static final int COLORING_ATTRIBUTES_ALLOW_SHADE_MODEL_WRITE = 3; + + // DepthComponent extends NodeComponent + static final int DEPTH_COMPONENT_ALLOW_SIZE_READ = 0; + static final int DEPTH_COMPONENT_ALLOW_DATA_READ = 1; + + // ImageComponent extends NodeComponent + static final int IMAGE_COMPONENT_ALLOW_SIZE_READ = 0; + static final int IMAGE_COMPONENT_ALLOW_FORMAT_READ = 1; + static final int IMAGE_COMPONENT_ALLOW_IMAGE_READ = 2; + static final int IMAGE_COMPONENT_ALLOW_IMAGE_WRITE = 3; + + // LineAttributes extends NodeComponent + static final int LINE_ATTRIBUTES_ALLOW_WIDTH_READ = 0; + static final int LINE_ATTRIBUTES_ALLOW_WIDTH_WRITE = 1; + static final int LINE_ATTRIBUTES_ALLOW_PATTERN_READ = 2; + static final int LINE_ATTRIBUTES_ALLOW_PATTERN_WRITE = 3; + static final int LINE_ATTRIBUTES_ALLOW_ANTIALIASING_READ = 4; + static final int LINE_ATTRIBUTES_ALLOW_ANTIALIASING_WRITE = 5; + + // Material extends NodeComponent + static final int MATERIAL_ALLOW_COMPONENT_READ = 0; + static final int MATERIAL_ALLOW_COMPONENT_WRITE = 1; + + // MediaContainer extends NodeComponent + static final int MEDIA_CONTAINER_ALLOW_CACHE_READ = 0; + static final int MEDIA_CONTAINER_ALLOW_CACHE_WRITE = 1; + static final int MEDIA_CONTAINER_ALLOW_URL_READ = 2; + static final int MEDIA_CONTAINER_ALLOW_URL_WRITE = 3; + + // PointAttributes extends NodeComponent + static final int POINT_ATTRIBUTES_ALLOW_SIZE_READ = 0; + static final int POINT_ATTRIBUTES_ALLOW_SIZE_WRITE = 1; + static final int POINT_ATTRIBUTES_ALLOW_ANTIALIASING_READ = 2; + static final int POINT_ATTRIBUTES_ALLOW_ANTIALIASING_WRITE = 3; + + // PolygonAttributes extends NodeComponent + static final int POLYGON_ATTRIBUTES_ALLOW_CULL_FACE_READ = 0; + static final int POLYGON_ATTRIBUTES_ALLOW_CULL_FACE_WRITE = 1; + static final int POLYGON_ATTRIBUTES_ALLOW_MODE_READ = 2; + static final int POLYGON_ATTRIBUTES_ALLOW_MODE_WRITE = 3; + static final int POLYGON_ATTRIBUTES_ALLOW_OFFSET_READ = 4; + static final int POLYGON_ATTRIBUTES_ALLOW_OFFSET_WRITE = 5; + static final int POLYGON_ATTRIBUTES_ALLOW_NORMAL_FLIP_READ = 6; + static final int POLYGON_ATTRIBUTES_ALLOW_NORMAL_FLIP_WRITE = 7; + + // RenderingAttributes extends NodeComponent + static final int RENDERING_ATTRIBUTES_ALLOW_ALPHA_TEST_VALUE_READ = 0; + static final int RENDERING_ATTRIBUTES_ALLOW_ALPHA_TEST_VALUE_WRITE = 1; + static final int RENDERING_ATTRIBUTES_ALLOW_ALPHA_TEST_FUNCTION_READ = 2; + static final int RENDERING_ATTRIBUTES_ALLOW_ALPHA_TEST_FUNCTION_WRITE = 3; + static final int RENDERING_ATTRIBUTES_ALLOW_DEPTH_ENABLE_READ = 4; + static final int RENDERING_ATTRIBUTES_ALLOW_VISIBLE_READ = 5; + static final int RENDERING_ATTRIBUTES_ALLOW_VISIBLE_WRITE = 6; + static final int RENDERING_ATTRIBUTES_ALLOW_RASTER_OP_READ = 7; + static final int RENDERING_ATTRIBUTES_ALLOW_RASTER_OP_WRITE = 8; + static final int + RENDERING_ATTRIBUTES_ALLOW_IGNORE_VERTEX_COLORS_READ = 9; + static final int + RENDERING_ATTRIBUTES_ALLOW_IGNORE_VERTEX_COLORS_WRITE = 10; + static final int RENDERING_ATTRIBUTES_ALLOW_DEPTH_ENABLE_WRITE = 11; + static final int RENDERING_ATTRIBUTES_ALLOW_DEPTH_TEST_FUNCTION_READ = 12; + static final int RENDERING_ATTRIBUTES_ALLOW_DEPTH_TEST_FUNCTION_WRITE = 13; + static final int RENDERING_ATTRIBUTES_ALLOW_STENCIL_ATTRIBUTES_READ = 14; + static final int RENDERING_ATTRIBUTES_ALLOW_STENCIL_ATTRIBUTES_WRITE = 15; + + // TexCoordGeneration extends NodeComponent + static final int TEX_COORD_GENERATION_ALLOW_ENABLE_READ = 0; + static final int TEX_COORD_GENERATION_ALLOW_ENABLE_WRITE = 1; + static final int TEX_COORD_GENERATION_ALLOW_FORMAT_READ = 2; + static final int TEX_COORD_GENERATION_ALLOW_MODE_READ = 3; + static final int TEX_COORD_GENERATION_ALLOW_PLANE_READ = 4; + static final int TEX_COORD_GENERATION_ALLOW_PLANE_WRITE = 5; + + // Texture extends NodeComponent + static final int TEXTURE_ALLOW_ENABLE_READ = 0; + static final int TEXTURE_ALLOW_ENABLE_WRITE = 1; + static final int TEXTURE_ALLOW_BOUNDARY_MODE_READ = 2; + static final int TEXTURE_ALLOW_FILTER_READ = 3; + static final int TEXTURE_ALLOW_IMAGE_READ = 4; + static final int TEXTURE_ALLOW_MIPMAP_MODE_READ = 5; + static final int TEXTURE_ALLOW_BOUNDARY_COLOR_READ = 6; + static final int TEXTURE_ALLOW_IMAGE_WRITE = 7; + static final int TEXTURE_ALLOW_SIZE_READ = 8; + static final int TEXTURE_ALLOW_FORMAT_READ = 9; + static final int TEXTURE_ALLOW_LOD_RANGE_READ = 10; + static final int TEXTURE_ALLOW_LOD_RANGE_WRITE = 11; + static final int TEXTURE_ALLOW_ANISOTROPIC_FILTER_READ = 12; + static final int TEXTURE_ALLOW_SHARPEN_TEXTURE_READ = 13; + static final int TEXTURE_ALLOW_FILTER4_READ = 14; + + // Texture2D extends Texture + static final int TEXTURE2D_ALLOW_DETAIL_TEXTURE_READ = 15; + + // TextureAttributes extends NodeComponent + static final int TEXTURE_ATTRIBUTES_ALLOW_MODE_READ = 0; + static final int TEXTURE_ATTRIBUTES_ALLOW_MODE_WRITE = 1; + static final int TEXTURE_ATTRIBUTES_ALLOW_BLEND_COLOR_READ = 2; + static final int TEXTURE_ATTRIBUTES_ALLOW_BLEND_COLOR_WRITE = 3; + static final int TEXTURE_ATTRIBUTES_ALLOW_TRANSFORM_READ = 4; + static final int TEXTURE_ATTRIBUTES_ALLOW_TRANSFORM_WRITE = 5; + static final int TEXTURE_ATTRIBUTES_ALLOW_COLOR_TABLE_READ = 6; + static final int TEXTURE_ATTRIBUTES_ALLOW_COLOR_TABLE_WRITE = 7; + static final int TEXTURE_ATTRIBUTES_ALLOW_COMBINE_READ = 8; + static final int TEXTURE_ATTRIBUTES_ALLOW_COMBINE_WRITE = 9; + + // TransparencyAttributes extends NodeComponent + static final int TRANSPARENCY_ATTRIBUTES_ALLOW_MODE_READ = 0; + static final int TRANSPARENCY_ATTRIBUTES_ALLOW_MODE_WRITE = 1; + static final int TRANSPARENCY_ATTRIBUTES_ALLOW_VALUE_READ = 2; + static final int TRANSPARENCY_ATTRIBUTES_ALLOW_VALUE_WRITE = 3; + static final int TRANSPARENCY_ATTRIBUTES_ALLOW_BLEND_FUNCTION_READ = 4; + static final int TRANSPARENCY_ATTRIBUTES_ALLOW_BLEND_FUNCTION_WRITE = 5; + + // TextureUnitState extends NodeComponent + static final int TEXTURE_UNIT_STATE_ALLOW_STATE_READ = 0; + static final int TEXTURE_UNIT_STATE_ALLOW_STATE_WRITE = 1; + + // ShaderProgram extends NodeComponent + static final int SHADER_PROGRAM_ALLOW_SHADERS_READ = 0; + static final int SHADER_PROGRAM_ALLOW_NAMES_READ = 1; + + // ShaderAttributeSet extends NodeComponent + static final int SHADER_ATTRIBUTE_SET_ALLOW_ATTRIBUTES_READ = 0; + static final int SHADER_ATTRIBUTE_SET_ALLOW_ATTRIBUTES_WRITE = 1; + + // ShaderAttribute extends NodeComponent + + // ShaderAttributeObject extends ShaderAttribute + static final int SHADER_ATTRIBUTE_OBJECT_ALLOW_VALUE_READ = 0; + static final int SHADER_ATTRIBUTE_OBJECT_ALLOW_VALUE_WRITE = 1; + + // Geometry extends NodeComponent + // NOTE: additional bits are below the subclasses + + // GeometryArray extends Geometry + static final int GEOMETRY_ARRAY_ALLOW_COORDINATE_READ = 0; + static final int GEOMETRY_ARRAY_ALLOW_COORDINATE_WRITE = 1; + static final int GEOMETRY_ARRAY_ALLOW_COLOR_READ = 2; + static final int GEOMETRY_ARRAY_ALLOW_COLOR_WRITE = 3; + static final int GEOMETRY_ARRAY_ALLOW_NORMAL_READ = 4; + static final int GEOMETRY_ARRAY_ALLOW_NORMAL_WRITE = 5; + static final int GEOMETRY_ARRAY_ALLOW_TEXCOORD_READ = 6; + static final int GEOMETRY_ARRAY_ALLOW_TEXCOORD_WRITE = 7; + static final int GEOMETRY_ARRAY_ALLOW_COUNT_READ = 8; + + // IndexedGeometryArray extends GeometryArray + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_COORDINATE_INDEX_READ = 9; + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_COORDINATE_INDEX_WRITE= 10; + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_COLOR_INDEX_READ = 11; + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_COLOR_INDEX_WRITE = 12; + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_NORMAL_INDEX_READ = 13; + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_NORMAL_INDEX_WRITE = 14; + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_TEXCOORD_INDEX_READ = 15; + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_TEXCOORD_INDEX_WRITE = 16; + + // Additional GeometryArray bits (must go after IndexedGeometryArray bits) + static final int GEOMETRY_ARRAY_ALLOW_FORMAT_READ = 17; + static final int J3D_1_2_GEOMETRY_ARRAY_ALLOW_REF_DATA_READ = 18; + static final int GEOMETRY_ARRAY_ALLOW_REF_DATA_WRITE = 19; + static final int GEOMETRY_ARRAY_ALLOW_COUNT_WRITE = 20; + static final int GEOMETRY_ARRAY_ALLOW_REF_DATA_READ = 21; + static final int GEOMETRY_ARRAY_ALLOW_VERTEX_ATTR_READ = 22; + static final int GEOMETRY_ARRAY_ALLOW_VERTEX_ATTR_WRITE = 23; + + // Additional GeometryArray bits (must go after IndexedGeometryArray bits) + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_VERTEX_ATTR_INDEX_READ = 24; + static final int INDEXED_GEOMETRY_ARRAY_ALLOW_VERTEX_ATTR_INDEX_WRITE = 25; + + // CompressedGeometry extends Geometry + static final int COMPRESSED_GEOMETRY_ALLOW_COUNT_READ = 0; + static final int COMPRESSED_GEOMETRY_ALLOW_HEADER_READ = 1; + static final int COMPRESSED_GEOMETRY_ALLOW_GEOMETRY_READ = 2; + static final int COMPRESSED_GEOMETRY_ALLOW_REF_DATA_READ = 3; + + // Raster extends Geometry + static final int RASTER_ALLOW_POSITION_READ = 0; + static final int RASTER_ALLOW_POSITION_WRITE = 1; + static final int RASTER_ALLOW_OFFSET_READ = 2; + static final int RASTER_ALLOW_OFFSET_WRITE = 3; + static final int RASTER_ALLOW_IMAGE_READ = 4; + static final int RASTER_ALLOW_IMAGE_WRITE = 5; + static final int RASTER_ALLOW_DEPTH_COMPONENT_READ = 6; + static final int RASTER_ALLOW_DEPTH_COMPONENT_WRITE = 7; + static final int RASTER_ALLOW_SIZE_READ = 8; + static final int RASTER_ALLOW_SIZE_WRITE = 9; + static final int RASTER_ALLOW_TYPE_READ = 10; + static final int RASTER_ALLOW_CLIP_MODE_READ = 11; + static final int RASTER_ALLOW_CLIP_MODE_WRITE = 12; + + // Text3D extends Geometry + static final int TEXT3D_ALLOW_FONT3D_READ = 0; + static final int TEXT3D_ALLOW_FONT3D_WRITE = 1; + static final int TEXT3D_ALLOW_STRING_READ = 2; + static final int TEXT3D_ALLOW_STRING_WRITE = 3; + static final int TEXT3D_ALLOW_POSITION_READ = 4; + static final int TEXT3D_ALLOW_POSITION_WRITE = 5; + static final int TEXT3D_ALLOW_ALIGNMENT_READ = 6; + static final int TEXT3D_ALLOW_ALIGNMENT_WRITE = 7; + static final int TEXT3D_ALLOW_PATH_READ = 8; + static final int TEXT3D_ALLOW_PATH_WRITE = 9; + static final int TEXT3D_ALLOW_CHARACTER_SPACING_READ = 10; + static final int TEXT3D_ALLOW_CHARACTER_SPACING_WRITE = 11; + static final int TEXT3D_ALLOW_BOUNDING_BOX_READ = 12; + + // Additional geometry bits (must go after GeometryArray bits) + // NOTE: ALLOW_INTERSECT was duplicated by the old value of + // ALLOW_REF_DATA_READ in Java 3D 1.2. + static final int GEOMETRY_ALLOW_INTERSECT = 18; + + // NOTE: any further additional Geometry bits must come after the + // last GeometryArray bit +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CapabilityNotSetException.java b/j3d-core/src/classes/share/javax/media/j3d/CapabilityNotSetException.java new file mode 100644 index 0000000..7b4cf74 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CapabilityNotSetException.java @@ -0,0 +1,56 @@ +/* + * $RCSfile: CapabilityNotSetException.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates an access to a live or + * compiled Scene Graph object without the required capability + * set. + */ +public class CapabilityNotSetException extends RestrictedAccessException { + +/** + * Create the exception object with default values. + */ + public CapabilityNotSetException(){ + } + +/** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public CapabilityNotSetException(String str){ + + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CgShaderProgram.java b/j3d-core/src/classes/share/javax/media/j3d/CgShaderProgram.java new file mode 100644 index 0000000..ebeda56 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CgShaderProgram.java @@ -0,0 +1,192 @@ +/* + * $RCSfile: CgShaderProgram.java,v $ + * + * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The CgShaderProgram object is a concrete implementation of a + * ShaderProgram node component for NVIDIA's Cg shader language. + * + * @see SourceCodeShader + * + * @since Java 3D 1.4 + */ + +public class CgShaderProgram extends ShaderProgram { + + /** + * Constructs a Cg shader program node component. + * + *
+ * TODO: ADD MORE DOCUMENTATION HERE. + */ + public CgShaderProgram() { + } + + // Implement abstract setVertexAttrNames method (inherit javadoc from parent class) + public void setVertexAttrNames(String[] vertexAttrNames) { + checkForLiveOrCompiled(); + + if (vertexAttrNames != null) { + for (int i = 0; i < vertexAttrNames.length; i++) { + if (vertexAttrNames[i] == null) { + throw new NullPointerException(); + } + } + } + + ((CgShaderProgramRetained)this.retained).setVertexAttrNames(vertexAttrNames); + } + + // Implement abstract getVertexAttrNames method (inherit javadoc from parent class) + public String[] getVertexAttrNames() { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_NAMES_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("CgShaderProgram0")); + } + } + + return ((CgShaderProgramRetained)this.retained).getVertexAttrNames(); + } + + // Implement abstract setShaderAttrNames method (inherit javadoc from parent class) + public void setShaderAttrNames(String[] shaderAttrNames) { + checkForLiveOrCompiled(); + + if (shaderAttrNames != null) { + for (int i = 0; i < shaderAttrNames.length; i++) { + if (shaderAttrNames[i] == null) { + throw new NullPointerException(); + } + } + } + + ((CgShaderProgramRetained)this.retained).setShaderAttrNames(shaderAttrNames); + } + + // Implement abstract getShaderAttrNames method (inherit javadoc from parent class) + public String[] getShaderAttrNames() { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_NAMES_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("CgShaderProgram0")); + } + } + + return ((CgShaderProgramRetained)this.retained).getShaderAttrNames(); + } + + /** + * Copies the specified array of shaders into this shader + * program. This method makes a shallow copy of the array. The + * array of shaders may be null or empty (0 length), but the + * elements of the array must be non-null. The shading language of + * each shader in the array must be + * SHADING_LANGUAGE_CG. Each shader in the array must + * be a SourceCodeShader. There must be no more than one vertex shader + * and one fragment shader in the array. + * + * @param shaders array of Shader objects to be copied into this + * ShaderProgram + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if the shading language of + * any shader in the shaders array is not + * SHADING_LANGUAGE_CG. + * + * @exception IllegalArgumentException if there are more than one + * vertex shader or more than one fragment shader in the shaders + * array. + * + * @exception ClassCastException if any shader in the shaders + * array is not a SourceCodeShader. + */ + public void setShaders(Shader[] shaders) { + checkForLiveOrCompiled(); + + if (shaders != null) { + // Check shaders for valid shading language, class type, etc. + for (int i = 0; i < shaders.length; i++) { + boolean hasVertexShader = false; + boolean hasFragmentShader = false; + + // Check shading language + if (shaders[i].getShadingLanguage() != Shader.SHADING_LANGUAGE_CG) { + throw new IllegalArgumentException(J3dI18N.getString("CgShaderProgram2")); + } + + // Check for more than one vertex shader or fragment shader + if (shaders[i].getShaderType() == Shader.SHADER_TYPE_VERTEX) { + if (hasVertexShader) { + throw new IllegalArgumentException(J3dI18N.getString("CgShaderProgram3")); + } + hasVertexShader = true; + } + else { // Shader.SHADER_TYPE_FRAGMENT + if (hasFragmentShader) { + throw new IllegalArgumentException(J3dI18N.getString("CgShaderProgram4")); + } + hasFragmentShader = true; + } + + // Try to cast shader to SourceCodeShader; it will throw + // ClassCastException if it isn't. + SourceCodeShader shad = (SourceCodeShader)shaders[i]; + } + } + + ((CgShaderProgramRetained)this.retained).setShaders(shaders); + } + + // Implement abstract getShaders method (inherit javadoc from parent class) + public Shader[] getShaders() { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_SHADERS_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("CgShaderProgram1")); + } + } + + return ((CgShaderProgramRetained)this.retained).getShaders(); + } + + /** + * Creates a retained mode CgShaderProgramRetained object that this + * CgShaderProgram component object will point to. + */ + void createRetained() { + this.retained = new CgShaderProgramRetained(); + this.retained.setSource(this); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CgShaderProgramRetained.java b/j3d-core/src/classes/share/javax/media/j3d/CgShaderProgramRetained.java new file mode 100644 index 0000000..8f7cd73 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CgShaderProgramRetained.java @@ -0,0 +1,404 @@ +/* + * $RCSfile: CgShaderProgramRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The CgShaderProgram object is a concrete implementation of a + * ShaderProgram node component for NVIDIA's Cg shader language. + */ + +class CgShaderProgramRetained extends ShaderProgramRetained { + + /** + * Constructs a Cg shader program node component. + */ + CgShaderProgramRetained() { + } + + synchronized void createMirrorObject() { + // System.err.println("CgShaderProgramRetained : createMirrorObject"); + // This method should only call by setLive(). + if (mirror == null) { + CgShaderProgramRetained mirrorCgSP = new CgShaderProgramRetained(); + mirror = mirrorCgSP; + } + initMirrorObject(); + } + + // ShaderAttributeValue methods + + ShaderError setUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + + return Pipeline.getPipeline().setCgUniform1i(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + + return Pipeline.getPipeline().setCgUniform1f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + + return Pipeline.getPipeline().setCgUniform2i(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setCgUniform2f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + + return Pipeline.getPipeline().setCgUniform3i(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setCgUniform3f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + + return Pipeline.getPipeline().setCgUniform4i(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setCgUniform4f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setCgUniformMatrix3f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setCgUniformMatrix4f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + // ShaderAttributeArray methods + + ShaderError setUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + + return Pipeline.getPipeline().setCgUniform1iArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setCgUniform1fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + + return Pipeline.getPipeline().setCgUniform2iArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setCgUniform2fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + + return Pipeline.getPipeline().setCgUniform3iArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setCgUniform3fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + + return Pipeline.getPipeline().setCgUniform4iArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setCgUniform4fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setCgUniformMatrix3fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setCgUniformMatrix4fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + + /** + * Method to return a flag indicating whether this + * ShaderProgram is supported on the specified Canvas. + */ + boolean isSupported(Canvas3D cv) { + return cv.shadingLanguageCg; + } + + /** + * Method to create the native shader. + */ + ShaderError createShader(Context ctx, ShaderRetained shader, ShaderId[] shaderIdArr) { + return Pipeline.getPipeline().createCgShader(ctx, shader.shaderType, shaderIdArr); + } + + /** + * Method to destroy the native shader. + */ + ShaderError destroyShader(Context ctx, ShaderId shaderId) { + return Pipeline.getPipeline().destroyCgShader(ctx, shaderId); + } + + /** + * Method to compile the native shader. + */ + ShaderError compileShader(Context ctx, ShaderId shaderId, String source) { + return Pipeline.getPipeline().compileCgShader(ctx, shaderId, source ); + } + + /** + * Method to create the native shader program. + */ + ShaderError createShaderProgram(Context ctx, ShaderProgramId[] shaderProgramIdArr) { + return Pipeline.getPipeline().createCgShaderProgram(ctx, shaderProgramIdArr); + } + + /** + * Method to destroy the native shader program. + */ + ShaderError destroyShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return Pipeline.getPipeline().destroyCgShaderProgram(ctx, shaderProgramId); + } + + /** + * Method to link the native shader program. + */ + ShaderError linkShaderProgram(Context ctx, ShaderProgramId shaderProgramId, ShaderId[] shaderIds) { + return Pipeline.getPipeline().linkCgShaderProgram(ctx, shaderProgramId, shaderIds); + } + + ShaderError bindVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, String attrName, int attrIndex) { + // This is a no-op for Cg + return null; + } + + void lookupVertexAttrNames(Context ctx, ShaderProgramId shaderProgramId, String[] attrNames, boolean[] errArr) { + Pipeline.getPipeline().lookupCgVertexAttrNames(ctx, shaderProgramId, attrNames.length, attrNames, errArr); + } + + void lookupShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + String[] attrNames, AttrNameInfo[] attrNameInfoArr) { + + int numAttrNames = attrNames.length; + + ShaderAttrLoc[] locArr = new ShaderAttrLoc[numAttrNames]; + int[] typeArr = new int[numAttrNames]; + int[] sizeArr = new int[numAttrNames]; // currently unused + boolean[] isArrayArr = new boolean[numAttrNames]; + + Pipeline.getPipeline().lookupCgShaderAttrNames(ctx, shaderProgramId, + numAttrNames, attrNames, locArr, typeArr, sizeArr, isArrayArr); + + for (int i = 0; i < numAttrNames; i++) { + attrNameInfoArr[i] = new AttrNameInfo(); + attrNameInfoArr[i].setLocation(locArr[i]); + attrNameInfoArr[i].setArray(isArrayArr[i]); + attrNameInfoArr[i].setType(typeArr[i]); + /* + System.err.println(attrNames[i] + + " : loc = " + locArr[i] + + ", type = " + typeArr[i] + + ", isArray = " + isArrayArr[i] + + ", size = " + sizeArr[i]); + */ + } + } + + /** + * Method to enable the native shader program. + */ + ShaderError enableShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return Pipeline.getPipeline().useCgShaderProgram(ctx, shaderProgramId); + } + + /** + * Method to disable the native shader program. + */ + ShaderError disableShaderProgram(Context ctx) { + return Pipeline.getPipeline().useCgShaderProgram(ctx, null); + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Clip.java b/j3d-core/src/classes/share/javax/media/j3d/Clip.java new file mode 100644 index 0000000..0d70595 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Clip.java @@ -0,0 +1,314 @@ +/* + * $RCSfile: Clip.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * The Clip leaf node defines the back, or far, clip distance in + * the virtual universe. + * The distance is specified in the local coordinate system of this node. + * This node also specifies an application + * region in which this clip node is active. + * A Clip node is active when its application region intersects + * the ViewPlatform's activation volume. If multiple Clip nodes + * are active, the Clip node that is "closest" to the eye will be + * used. + * If no clip node is in scope of the view platform + * associated with the current view, then the back clip distance is + * defined by the View object. + * The front clip distance is always defined by the + * View object. + * + * @see View + */ +public class Clip extends Leaf { + + /** + * Specifies that the Clip allows read access to its application + * bounds and bounding leaf at runtime. + */ + public static final int + ALLOW_APPLICATION_BOUNDS_READ = CapabilityBits.CLIP_ALLOW_APPLICATION_BOUNDS_READ; + + /** + * Specifies that the Clip allows write access to its application + * bounds and bounding leaf at runtime. + */ + public static final int + ALLOW_APPLICATION_BOUNDS_WRITE = CapabilityBits.CLIP_ALLOW_APPLICATION_BOUNDS_WRITE; + + /** + * Specifies that the Clip allows read access to its back distance + * at runtime. + */ + public static final int + ALLOW_BACK_DISTANCE_READ = CapabilityBits.CLIP_ALLOW_BACK_DISTANCE_READ; + + /** + * Specifies that the Clip allows write access to its back distance + * at runtime. + */ + public static final int + ALLOW_BACK_DISTANCE_WRITE = CapabilityBits.CLIP_ALLOW_BACK_DISTANCE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_APPLICATION_BOUNDS_READ, + ALLOW_BACK_DISTANCE_READ + }; + + /** + * Constructs a Clip node with default parameters. The default + * values are as follows: + *
    + * back clip distance : 100 meters + * application bounds : null
    + * application bounding leaf : null
    + *
+ */ + public Clip () { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a Clip node with the specified back clip distance. + */ + public Clip(double backDistance) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ClipRetained)this.retained).initBackDistance(backDistance); + } + + /** + * Sets the back clip distance to the specified value. + * There are several considerations that need to be taken into + * account when choosing values for the front and back clip + * distances. These are enumerated in the description of + * + * View.setFrontClipDistance. + * @param backDistance the new back clip distance in meters + * @see View#setFrontClipDistance + * @see View#setBackClipDistance + */ + public void setBackDistance(double backDistance) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_BACK_DISTANCE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Clip0")); + + if (isLive()) + ((ClipRetained)this.retained).setBackDistance(backDistance); + else + ((ClipRetained)this.retained).initBackDistance(backDistance); + } + + /** + * Retrieves the back clip distance. + * @return the current back clip distance, in meters + */ + public double getBackDistance() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_BACK_DISTANCE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Clip1")); + return ((ClipRetained)this.retained).getBackDistance(); + } + + /** + * Set the Clip's application region to the specified bounds. + * This is used when the application bounding leaf is set to null. + * @param region the bounds that contains the Clip's new application + * region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setApplicationBounds(Bounds region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Clip2")); + + if (isLive()) + ((ClipRetained)this.retained).setApplicationBounds(region); + else + ((ClipRetained)this.retained).initApplicationBounds(region); + } + + /** + * Retrieves the Clip node's application bounds. + * @return this Clip's application bounds information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getApplicationBounds() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Clip3")); + + return ((ClipRetained)this.retained).getApplicationBounds(); + } + + /** + * Set the Clip's application region to the specified bounding leaf. + * When set to a value other than null, this overrides the application + * bounds object. + * @param region the bounding leaf node used to specify the Clip + * node's new application region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setApplicationBoundingLeaf(BoundingLeaf region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Clip2")); + + if (isLive()) + ((ClipRetained)this.retained).setApplicationBoundingLeaf(region); + else + ((ClipRetained)this.retained).initApplicationBoundingLeaf(region); + } + + /** + * Retrieves the Clip node's application bounding leaf. + * @return this Clip's application bounding leaf information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BoundingLeaf getApplicationBoundingLeaf() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Clip3")); + + return ((ClipRetained)this.retained).getApplicationBoundingLeaf(); + } + + /** + * Creates the retained mode ClipRetained object that this + * Clip component object will point to. + */ + void createRetained() { + this.retained = new ClipRetained(); + this.retained.setSource(this); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Clip c = new Clip(); + c.duplicateNode(this, forceDuplicate); + return c; + } + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + ClipRetained rt = (ClipRetained) retained; + BoundingLeaf bl = rt.getApplicationBoundingLeaf(); + + // check for applicationBoundingLeaf + if (bl != null) { + Object o = referenceTable.getNewObjectReference(bl); + rt.initApplicationBoundingLeaf((BoundingLeaf) o); + } + } + + + /** + * Copies all Clip information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + ClipRetained attr = (ClipRetained) originalNode.retained; + ClipRetained rt = (ClipRetained) retained; + + rt.initBackDistance(attr.getBackDistance()); + rt.initApplicationBounds(attr.getApplicationBounds()); + + // correct value will set in updateNodeReferences + rt.initApplicationBoundingLeaf(attr.getApplicationBoundingLeaf()); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ClipRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ClipRetained.java new file mode 100644 index 0000000..85ca707 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ClipRetained.java @@ -0,0 +1,403 @@ +/* + * $RCSfile: ClipRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; + +/** + * The Clip leaf node defines the back, or far, clipping distance in + * the virtual universe. The front clipping plane is defined in the + * View object. If no clip node is in scope of the view platform + * associated with the current view, then the back clipping plane is + * also defined by the View. + * @see View + */ +class ClipRetained extends LeafRetained { + + static final int BOUNDS_CHANGED = 0x00001; + static final int BOUNDINGLEAF_CHANGED = 0x00002; + static final int BACKDISTANCE_CHANGED = 0x00004; + + /** + * Clip's back distance + */ + double backDistance = 100.0; + + /** + * back distance scaled to vworld + */ + double backDistanceInVworld; + + /** + * The Boundary object defining the application region. + */ + Bounds applicationRegion = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * The transformed value of the applicationRegion. + */ + Bounds transformedRegion = null; + + // This is true when this object is referenced in an immediate mode context + boolean inImmCtx = false; + + + // Target threads to be notified when light changes + // Note, the rendering env structure only get notified + // when there is a bounds related change + static final int targetThreads = J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_RENDERING_ENVIRONMENT; + + + // Is true, if the clip is viewScoped + boolean isViewScoped = false; + + /** + * Constructs a Clip node with a default color (black). + */ + ClipRetained () { + this.nodeType = NodeRetained.CLIP; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + /** + * initializes the clip's back distance to the specified value. + * @param backDistance the new back clipping distance + */ + final void initBackDistance(double backDistance) { + this.backDistance = backDistance; + } + + + /** + * Sets the clip's back distance to the specified value. + * @param backDistance the new back clipping distance + */ + final void setBackDistance(double backDistance) { + this.backDistance = backDistance; + sendMessage(BACKDISTANCE_CHANGED, new Double(backDistance), null); + } + + /** + * Retrieves the clip's back distance. + * @return the current back clipping distance + */ + final double getBackDistance() { + return backDistance; + } + + + /** + * Initializes the Clip's application region. + * @param region a region that contains the Backgound's new application bounds + */ + final void initApplicationBounds(Bounds region) { + if (region != null) { + applicationRegion = (Bounds) region.clone(); + } else { + applicationRegion = null; + } + } + + /** + * Set the Clip's application region. + * @param region a region that contains the Clip's new application bounds + */ + final void setApplicationBounds(Bounds region) { + initApplicationBounds(region); + // Don't send the message if there is a valid boundingleaf + if (boundingLeaf == null) { + sendMessage(BOUNDS_CHANGED, + (region != null ? region.clone(): null), null); + } + } + + /** + * Get the Backgound's application region. + * @return this Clip's application bounds information + */ + final Bounds getApplicationBounds() { + return (applicationRegion != null ? + (Bounds) applicationRegion.clone() : null); + } + + /** + * Initializes the Clip's application region + * to the specified Leaf node. + */ + void initApplicationBoundingLeaf(BoundingLeaf region) { + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + } else { + boundingLeaf = null; + } + } + + /** + * Set the Clip's application region to the specified Leaf node. + */ + void setApplicationBoundingLeaf(BoundingLeaf region) { + if (boundingLeaf != null) + boundingLeaf.mirrorBoundingLeaf.removeUser(this); + + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + boundingLeaf.mirrorBoundingLeaf.addUser(this); + } else { + boundingLeaf = null; + } + sendMessage(BOUNDINGLEAF_CHANGED, + (boundingLeaf != null ? + boundingLeaf.mirrorBoundingLeaf : null), + (applicationRegion != null ? applicationRegion.clone() : null)); + } + + /** + * Get the Clip's application region + */ + BoundingLeaf getApplicationBoundingLeaf() { + return (boundingLeaf != null ? + (BoundingLeaf)boundingLeaf.source : null); + } + + /** + * This sets the immedate mode context flag + */ + void setInImmCtx(boolean inCtx) { + inImmCtx = inCtx; + } + + /** + * This gets the immedate mode context flag + */ + boolean getInImmCtx() { + return inImmCtx; + } + + /** + * This setLive routine first calls the superclass's method, then + * it adds itself to the list of lights + */ + void setLive(SetLiveState s) { + if (inImmCtx) { + throw new IllegalSharingException(J3dI18N.getString("ClipRetained0")); + } + + super.doSetLive(s); + + if (inBackgroundGroup) { + throw new + IllegalSceneGraphException(J3dI18N.getString("ClipRetained1")); + } + + if (inSharedGroup) { + throw new + IllegalSharingException(J3dI18N.getString("ClipRetained2")); + } + + + initMirrorObject(); + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(this); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(this); + } + // process switch leaf + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(this, Targets.ENV_TARGETS); + } + switchState = (SwitchState)s.switchStates.get(0); + + // add this node to the transform target + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(this, Targets.ENV_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + + s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER; + + super.markAsLive(); + } + + /** + * This clearLive routine first calls the superclass's method, then + * it removes itself to the list of lights + */ + void clearLive(SetLiveState s) { + super.clearLive(s); + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(this); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(this); + } + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(this, Targets.ENV_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + + + s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER; + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(this, Targets.ENV_TARGETS); + } + } + + void initMirrorObject() { + Transform3D lastLocalToVworld = getLastLocalToVworld(); + + if (boundingLeaf != null) { + transformedRegion = (Bounds)boundingLeaf.mirrorBoundingLeaf.transformedRegion; + } + else { // Evaluate applicationRegion if not null + if (applicationRegion != null) { + transformedRegion = (Bounds)applicationRegion.clone(); + transformedRegion.transform(applicationRegion, lastLocalToVworld); + } + else { + transformedRegion = null; + } + + } + backDistanceInVworld = backDistance * + lastLocalToVworld.getDistanceScale(); + } + + + // The update Object function. + void updateImmediateMirrorObject(Object[] objs) { + int component = ((Integer)objs[1]).intValue(); + Transform3D trans; + Transform3D currentLocalToVworld = getCurrentLocalToVworld(); + + // Bounds message only sent when boundingleaf is null + if ((component & BOUNDS_CHANGED) != 0) { + if (objs[2] != null) { + transformedRegion = ((Bounds) objs[2]).copy(transformedRegion); + transformedRegion.transform(transformedRegion, + currentLocalToVworld); + } + else { + transformedRegion = null; + } + } + else if ((component & BOUNDINGLEAF_CHANGED) != 0) { + if (objs[2] != null) { + transformedRegion = ((BoundingLeafRetained)objs[2]).transformedRegion; + } + else { // Evaluate applicationRegion if not null + Bounds appRegion = (Bounds)objs[3]; + if (appRegion != null) { + transformedRegion = ((Bounds)appRegion).copy(transformedRegion); + transformedRegion.transform(appRegion, + currentLocalToVworld); + } + else { + transformedRegion = null; + } + + } + + } + else if ((component & BACKDISTANCE_CHANGED) != 0) { + backDistanceInVworld = ((Double)objs[2]).doubleValue() * + currentLocalToVworld.getDistanceScale(); + } + } + + /** Note: This routine will only be called on + * the mirror object - will update the object's + * cached region and transformed region + */ + + void updateBoundingLeaf() { + if (boundingLeaf != null && + boundingLeaf.mirrorBoundingLeaf.switchState.currentSwitchOn) { + transformedRegion = + boundingLeaf.mirrorBoundingLeaf.transformedRegion; + } else { // Evaluate applicationRegion if not null + if (applicationRegion != null) { + transformedRegion = applicationRegion.copy(transformedRegion); + transformedRegion.transform(applicationRegion, + getCurrentLocalToVworld()); + } else { + transformedRegion = null; + } + } + } + + void updateImmediateTransformChange() { + // If bounding leaf is null, tranform the bounds object + if (boundingLeaf == null) { + if (applicationRegion != null) { + transformedRegion = (Bounds)applicationRegion.clone(); + transformedRegion.transform(applicationRegion, + getCurrentLocalToVworld()); + } + } + } + + final void sendMessage(int attrMask, Object attr, Object attr2) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.type = J3dMessage.CLIP_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = attr2; + VirtualUniverse.mc.processMessage(createMessage); + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + if (applicationRegion != null) { + applicationRegion.transform(xform.transform); + } + } + void getMirrorObjects(ArrayList leafList, HashKey key) { + leafList.add(this); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ColorInterpolator.java b/j3d-core/src/classes/share/javax/media/j3d/ColorInterpolator.java new file mode 100644 index 0000000..03d0863 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ColorInterpolator.java @@ -0,0 +1,315 @@ +/* + * $RCSfile: ColorInterpolator.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; +import java.util.Enumeration; + +/** + * Color interpolation behavior. This class defines a behavior that + * modifies the ambient, emissive, diffuse, or specular color of its + * target material object by linearly interpolating between a pair of + * specified colors, using the value generated by the specified Alpha + * object. + * The behavior modifies the color specified by the + * Material's colorTarget attribute, one of: AMBIENT, EMISSIVE, + * DIFFUSE, SPECULAR, or AMBIENT_AND_DIFFUSE. + * The ALLOW_COMPONENT_READ bit must be set in the Material object in + * order for the Material's colorTarget to be read. + * If the Material object's ALLOW_COMPONENT_READ bit is not set, the + * diffuse component will be modified. + * + * @see Material + */ + +public class ColorInterpolator extends Interpolator { + + Material target; + Color3f startColor = new Color3f(); + Color3f endColor = new Color3f(); + Color3f newColor = new Color3f(); + + // We can't use a boolean flag since it is possible + // that after alpha change, this procedure only run + // once at alpha.finish(). So the best way is to + // detect alpha value change. + private float prevAlphaValue = Float.NaN; + private int prevColorTarget = -1; + private WakeupCriterion passiveWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0, true); + + // non-public, no parameter constructor used by cloneNode + ColorInterpolator() { + } + + /** + * Constructs a trivial color interpolator with a specified target, + * a starting color of black, and an ending color of white. + * @param alpha the alpha object for this interpolator + * @param target the material component object whose + * color is affected by this color interpolator + */ + public ColorInterpolator(Alpha alpha, + Material target) { + + super(alpha); + + this.target = target; + this.startColor.set(0.0f, 0.0f, 0.0f); + this.endColor.set(1.0f, 1.0f, 1.0f); + } + + /** + * Constructs a color interpolator with the specified target, + * starting color, and ending color. + * @param alpha the alpha object for this interpolator + * @param target the material component object whose + * color is affected by this color interpolator + * @param startColor the starting color + * @param endColor the ending color + */ + public ColorInterpolator(Alpha alpha, + Material target, + Color3f startColor, + Color3f endColor) { + + super(alpha); + + this.target = target; + this.startColor.set(startColor); + this.endColor.set(endColor); + } + + /** + * This method sets the startColor for this interpolator. + * @param color the new start color + */ + public void setStartColor(Color3f color) { + startColor.set(color); + prevAlphaValue = Float.NaN; + } + + /** + * This method retrieves this interpolator's startColor. + * @param color the vector that will receive the interpolator's start color + */ + public void getStartColor(Color3f color) { + color.set(startColor); + } + + /** + * This method sets the endColor for this interpolator. + * @param color the new end color + */ + public void setEndColor(Color3f color) { + endColor.set(color); + prevAlphaValue = Float.NaN; + } + + /** + * This method retrieves this interpolator's endColor. + * @param color the vector that will receive the interpolator's end color + */ + public void getEndColor(Color3f color) { + color.set(endColor); + } + + /** + * This method sets the target material component object for + * this interpolator. + * @param target the material component object whose + * color is affected by this color interpolator + */ + public void setTarget(Material target) { + this.target = target; + prevAlphaValue = Float.NaN; + } + + /** + * This method retrieves this interpolator's target material + * component object. + * @return the interpolator's target material component object + */ + public Material getTarget() { + return target; + } + + // The ColorInterpolator's initialize routine uses the default + // initialization routine. + + /** + * This method is invoked by the behavior scheduler every frame. + * It maps the alpha value that corresponds to the current time + * into a color value and updates the ambient, emissive, diffuse, + * or specular color (or both the ambient and diffuse color) of + * the specified target Material object with this new color value. + * + * @param criteria an enumeration of the criteria that caused the + * stimulus + */ + public void processStimulus(Enumeration criteria) { + + // Handle stimulus + WakeupCriterion criterion = passiveWakeupCriterion; + + if (alpha != null) { + float value = alpha.value(); + + int colorTarget = Material.DIFFUSE; + if (target.getCapability(Material.ALLOW_COMPONENT_READ)) + colorTarget = target.getColorTarget(); + + if (value != prevAlphaValue || colorTarget != prevColorTarget) { + newColor.x = (1.0f-value)*startColor.x + value*endColor.x; + newColor.y = (1.0f-value)*startColor.y + value*endColor.y; + newColor.z = (1.0f-value)*startColor.z + value*endColor.z; + + switch (colorTarget) { + case Material.AMBIENT: + target.setAmbientColor(newColor); + break; + case Material.AMBIENT_AND_DIFFUSE: + target.setAmbientColor(newColor); + // fall through + case Material.DIFFUSE: + target.setDiffuseColor(newColor); + break; + case Material.EMISSIVE: + target.setEmissiveColor(newColor); + break; + case Material.SPECULAR: + target.setSpecularColor(newColor); + break; + } + + prevAlphaValue = value; + prevColorTarget = colorTarget; + } + + if (!alpha.finished() && !alpha.isPaused()) { + criterion = defaultWakeupCriterion; + } + } + wakeupOn(criterion); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + ColorInterpolator ci = new ColorInterpolator(); + ci.duplicateNode(this, forceDuplicate); + return ci; + } + + + /** + * Copies all ColorInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + ColorInterpolator ci = (ColorInterpolator) originalNode; + + ci.getStartColor(startColor); + ci.getEndColor(endColor); + + // this reference will be updated in updateNodeReferences() + setTarget(ci.getTarget()); + } + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + super.updateNodeReferences(referenceTable); + + // check Material + NodeComponent nc = getTarget(); + + if (nc != null) { + setTarget((Material) referenceTable.getNewObjectReference(nc)); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ColoringAttributes.java b/j3d-core/src/classes/share/javax/media/j3d/ColoringAttributes.java new file mode 100644 index 0000000..769129f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ColoringAttributes.java @@ -0,0 +1,371 @@ +/* + * $RCSfile: ColoringAttributes.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; + +/** + * The ColoringAttributes object defines attributes used in + * color selection and shading model. + * + *

+ * Color + *

+ * The setColor methods set the current intrinsic red, green, and + * blue color values of this ColoringAttributes component object. + * This color is only used for unlit geometry. If lighting is enabled, + * the material colors are used in the lighting equation to produce + * the final color. When vertex colors are present in unlit + * geometry, those vertex colors are used in place of this + * ColoringAttributes color, unless the vertex colors are ignored. + *

+ * There are two variations on the setColor methods, one + * that takes a Color3f and one that takes three floats. No alpha + * value is allowed (it's automatically set to 1.0). The float values + * range between 0.0 and 1.0, with 1.0 being full intensity of the + * color. A color value of (1.0, 1.0, 1.0) is white. + *

+ * Shading Model + *

+ * The setShadeModel method sets the shade model for this + * ColoringAttributes component object. The shade model may be one of + * the following:

+ *

    + *
  • FASTEST - use the fastest available method for shading. This + * shading mode maps to whatever shading model the Java 3D implementor + * defines as the "fastest," which may be hardware-dependent.
  • + *

    + *

  • NICEST - use the nicest (highest quality) available method + * for shading. This shading mode maps to whatever shading model + * the Java 3D implementor defines as the "nicest," shading + * model, which may be hardware-dependent.
  • + *

    + *

  • SHADE_FLAT - use the flat shading model. This shading model + * does not interpolate color across the primitive. + * The primitive is drawn with a single color + * and the color of one vertex of the primitive is duplicated + * across all the vertices of the primitive.
  • + *

    + *

  • SHADE_GOURAUD - use the Gouraud (smooth) shading model. + * This shading model smoothly interpolates the color at each vertex + * across the primitive. + * The primitive is drawn with many different colors + * and the color at each vertex is treated individually. For lines, + * the colors along the line segment are interpolated between + * the vertex colors. This is the default shade model if no other + * is specified.
  • + *

+ * + * @see Appearance + */ +public class ColoringAttributes extends NodeComponent { + /** + * Specifies that this ColoringAttributes object allows + * reading its color component information. + */ + public static final int + ALLOW_COLOR_READ = CapabilityBits.COLORING_ATTRIBUTES_ALLOW_COLOR_READ; + + /** + * Specifies that this ColoringAttributes object allows + * writing its color component information. + */ + public static final int + ALLOW_COLOR_WRITE = CapabilityBits.COLORING_ATTRIBUTES_ALLOW_COLOR_WRITE; + + /** + * Specifies that this ColoringAttributes object allows + * reading its shade model component information. + */ + public static final int + ALLOW_SHADE_MODEL_READ = CapabilityBits.COLORING_ATTRIBUTES_ALLOW_SHADE_MODEL_READ; + + /** + * Specifies that this ColoringAttributes object allows + * writing its shade model component information. + */ + public static final int + ALLOW_SHADE_MODEL_WRITE = CapabilityBits.COLORING_ATTRIBUTES_ALLOW_SHADE_MODEL_WRITE; + + /** + * Use the fastest available method for shading. + */ + public static final int FASTEST = 0; + /** + * Use the nicest available method for shading. + */ + public static final int NICEST = 1; + + /** + * Do not interpolate color across the primitive. + */ + public static final int SHADE_FLAT = 2; + /** + * Smoothly interpolate the color at each vertex across the primitive. + */ + public static final int SHADE_GOURAUD = 3; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_COLOR_READ, + ALLOW_SHADE_MODEL_READ + }; + + /** + * Constructs a ColoringAttributes node with default parameters. + * The default values are as follows: + *
    + * color = white (1,1,1)
    + * shade model = SHADE_GOURAUD
    + *
+ */ + public ColoringAttributes() { + // Just use default attributes + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Construct ColoringAttributes object with specified values. + * @param color the intrisic color + * @param shadeModel the shade model used; one of FASTEST, NICEST, + * SHADE_FLAT, or SHADE_GOURAUD + */ + public ColoringAttributes(Color3f color, int shadeModel) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ColoringAttributesRetained)this.retained).initColor(color); + ((ColoringAttributesRetained)this.retained).initShadeModel(shadeModel); + + } + + /** + * Construct ColoringAttributes object with specified values. + * @param red red component of the intrisic color + * @param green green component of the intrisic color + * @param blue blue component of the intrisic color + * @param shadeModel the shade model used; one of FASTEST, NICEST, + * SHADE_FLAT, or SHADE_GOURAUD + */ + public ColoringAttributes(float red, float green, float blue, + int shadeModel) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ColoringAttributesRetained)this.retained).initColor(red, green,blue); + ((ColoringAttributesRetained)this.retained).initShadeModel(shadeModel); + } + + /** + * Sets the intrinsic color of this ColoringAttributes + * component object. This color is only used for unlit geometry; + * if lighting is enabled, then the material colors are used in the + * lighting equation to produce the final color. + * When vertex colors are present in unlit geometry, those + * vertex colors are used in place of this ColoringAttributes color + * unless the vertex colors are ignored. + * @param color the color that is used when lighting is disabled + * or when material is null + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @see Material + * @see RenderingAttributes#setIgnoreVertexColors + */ + public void setColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ColoringAttributes0")); + + if (isLive()) + ((ColoringAttributesRetained)this.retained).setColor(color); + else + ((ColoringAttributesRetained)this.retained).initColor(color); + + } + + /** + * Sets the intrinsic color of this ColoringAttributes + * component object. This color is only used for unlit geometry; + * if lighting is enabled, then the material colors are used in the + * lighting equation to produce the final color. + * When vertex colors are present in unlit geometry, those + * vertex colors are used in place of this ColoringAttributes color + * unless the vertex colors are ignored. + * @param r the red component of the color + * @param g the green component of the color + * @param b the blue component of the color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @see Material + * @see RenderingAttributes#setIgnoreVertexColors + */ + public void setColor(float r, float g, float b) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ColoringAttributes0")); + + if (isLive()) + ((ColoringAttributesRetained)this.retained).setColor(r, g, b); + else + ((ColoringAttributesRetained)this.retained).initColor(r, g, b); + } + + /** + * Gets the intrinsic color of this ColoringAttributes + * component object. + * @param color the vector that will receive color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ColoringAttributes2")); + + ((ColoringAttributesRetained)this.retained).getColor(color); + } + + /** + * Sets the shade mode for this ColoringAttributes component object. + * @param shadeModel the shade mode to be used; one of FASTEST, + * NICEST, SHADE_FLAT, or SHADE_GOURAUD + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setShadeModel(int shadeModel) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SHADE_MODEL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ColoringAttributes3")); + + if (isLive()) + ((ColoringAttributesRetained)this.retained).setShadeModel(shadeModel); + else + ((ColoringAttributesRetained)this.retained).initShadeModel(shadeModel); + } + + /** + * Gets the shade mode for this ColoringAttributes component object. + * @return shadeModel the shade mode + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getShadeModel() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SHADE_MODEL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ColoringAttributes4")); + + return ((ColoringAttributesRetained)this.retained).getShadeModel(); + } + + /** + * Creates a retained mode ColoringAttributesRetained object that this + * ColoringAttributes component object will point to. + */ + void createRetained() { + this.retained = new ColoringAttributesRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + + public NodeComponent cloneNodeComponent() { + ColoringAttributes ca = new ColoringAttributes(); + ca.duplicateNodeComponent(this); + return ca; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + + super.duplicateAttributes(originalNodeComponent, + forceDuplicate); + + ColoringAttributesRetained attr = + (ColoringAttributesRetained) originalNodeComponent.retained; + + ColoringAttributesRetained rt = (ColoringAttributesRetained) retained; + Color3f c = new Color3f(); + attr.getColor(c); + + rt.initColor(c); + rt.initShadeModel(attr.getShadeModel()); + } + + /** + * Returns a String representation of this ColoringAttributes object. + * If the scene graph is live only those values with their + * Capability read bit set will be displayed. + */ + public String toString() { + StringBuffer str = new StringBuffer(getNamePrefix()); + str.append("javax.media.j3d.ColoringAttributes: "); + String shadingModes[] = { "FASTEST", "NICEST", "SHADE_FLAT", + "SHADE_GOURAUD" }; + + try { + Color3f color=new Color3f(); + getColor( color ); + str.append( "Color="+color ); + } + catch (CapabilityNotSetException e) {str.append("Color=N/A");} + + try { + str.append( " ShadeModel="+shadingModes[getShadeModel()] ); + } + catch (CapabilityNotSetException ex) {str.append("ShadeModel=N/A");} + + return new String(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ColoringAttributesRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ColoringAttributesRetained.java new file mode 100644 index 0000000..5b496ae --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ColoringAttributesRetained.java @@ -0,0 +1,264 @@ +/* + * $RCSfile: ColoringAttributesRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; +import java.util.ArrayList; + +/** + * The ColoringAttributesRetained object defines attributes that apply to + * to coloring mapping. + */ +class ColoringAttributesRetained extends NodeComponentRetained { + // A list of pre-defined bits to indicate which component + // in this ColoringAttributes object changed. + static final int COLOR_CHANGED = 0x01; + static final int SHADE_MODEL_CHANGED = 0x02; + + // Intrinsic color used when lighting is disabled or when + // material is null + Color3f color = new Color3f(1.0f, 1.0f, 1.0f); + + // Shade model (flat, smooth) + int shadeModel = ColoringAttributes.SHADE_GOURAUD; + + /** + * Sets the intrinsic color of this ColoringAttributes + * component object. + * @param color the color that is used when lighting is disabled + * or when material is null + */ + final void initColor(Color3f color) { + this.color.set(color); + } + + /** + * Sets the intrinsic color of this ColoringAttributes + * component object and sends a message notifying + * the interested structures of the change. + * @param color the color that is used when lighting is disabled + * or when material is null + */ + final void setColor(Color3f color) { + initColor(color); + sendMessage(COLOR_CHANGED, new Color3f(color)); + } + + /** + * Sets the intrinsic color of this ColoringAttributes + * component object. This color is used when lighting is disabled + * or when material is null. + * @param r the red component of the color + * @param g the green component of the color + * @param b the blue component of the color + */ + final void initColor(float r, float g, float b) { + this.color.set(r, g, b); + } + + /** + * Sets the intrinsic color of this ColoringAttributes + * component object and sends a message notifying + * the interested structures of the change. + * This color is used when lighting is disabled + * or when material is null. + * @param r the red component of the color + * @param g the green component of the color + * @param b the blue component of the color + */ + final void setColor(float r, float g, float b) { + initColor(r, g, b); + sendMessage(COLOR_CHANGED, new Color3f(r, g, b)); + } + + /** + * Gets the intrinsic color of this ColoringAttributes + * component object. + * @param color the vector that will receive color + */ + final void getColor(Color3f color) { + color.set(this.color); + } + + /** + * Sets the shade mode for this ColoringAttributes component object. + * @param shadeModel the shade mode to be used; one of FASTEST, + * NICEST, SHADE_FLAT, or SHADE_GOURAUD + */ + final void initShadeModel(int shadeModel) { + this.shadeModel = shadeModel; + } + + /** + * Sets the shade mode for this ColoringAttributes component object + * and sends a message notifying + * the interested structures of the change. + * @param shadeModel the shade mode to be used; one of FASTEST, + * NICEST, SHADE_FLAT, or SHADE_GOURAUD + */ + final void setShadeModel(int shadeModel) { + initShadeModel(shadeModel); + sendMessage(SHADE_MODEL_CHANGED, new Integer(shadeModel)); + } + + /** + * Gets the shade mode for this ColoringAttributes component object. + * @return shadeModel the shade mode + */ + final int getShadeModel() { + return shadeModel; + } + + + /** + * Creates and initializes a mirror object, point the mirror object + * to the retained object if the object is not editable + */ + synchronized void createMirrorObject() { + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror = this; + } else { + ColoringAttributesRetained mirrorCa + = new ColoringAttributesRetained(); + mirrorCa.source = source; + mirrorCa.set(this); + mirror = mirrorCa; + } + } else { + ((ColoringAttributesRetained) mirror).set(this); + } + } + + void updateNative(Context ctx, + float dRed, float dGreen, float dBlue, + float alpha, boolean lEnable) { + Pipeline.getPipeline().updateColoringAttributes(ctx, + dRed, dBlue, dGreen, color.x, color.y, + color.z, alpha, + lEnable, shadeModel); + } + + /** + * Creates a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + ((ColoringAttributesRetained)mirror).set(this); + } + + /** Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + ColoringAttributesRetained mirrorCa = + (ColoringAttributesRetained) mirror; + + if ((component & COLOR_CHANGED) != 0) { + mirrorCa.color.set(((Color3f)value)); + } + else if ((component & SHADE_MODEL_CHANGED) != 0) { + mirrorCa.shadeModel = ((Integer)value).intValue(); + } + } + + boolean equivalent(ColoringAttributesRetained cr) { + return ((cr != null) && + color.equals(cr.color) && + (shadeModel == cr.shadeModel)); + } + + + // This functions clones the retained side only and is used + // internally + protected Object clone() { + ColoringAttributesRetained cr = + (ColoringAttributesRetained)super.clone(); + cr.color = new Color3f(color); + // shadeModel is copied in super.clone() + return cr; + } + + // This functions clones the retained side only and is used + // internally + protected void set(ColoringAttributesRetained cr) { + super.set(cr); + color.set(cr.color); + shadeModel = cr.shadeModel; + } + + final void sendMessage(int attrMask, Object attr) { + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.COLORINGATTRIBUTES_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i + * Compressed geometry may be passed to this CompressedGeometry object + * in one of two ways: by copying the data into this object using the + * existing constructor, or by passing a reference to the data. + *

+ *

    + *
  • + * By Copying: + * The existing CompressedGeometry constructor copies the buffer of + * compressed geometry data into this CompressedGeometry object. This + * is appropriate for many applications, and allows Java 3D to verify + * the data once and then not worry about it again. + *
  • + *
  • By Reference: + * A new constructor and set of methods in Java 3D version 1.2 allows + * compressed geometry data to be accessed by reference, directly from + * the user's array. To use this feature, you need to construct a + * CompressedGeometry object with the byReference flag + * set to true. In this mode, a reference to the input + * data is saved, but the data itself is not necessarily copied. Note + * that the compressed geometry header is still copied into this + * compressed geometry object. Data referenced by a + * CompressedGeometry object must not be modified after the + * CompressedGeometry object is constructed. + * Applications + * must exercise care not to violate this rule. If any referenced + * compressed geometry data is modified after construction, + * the results are undefined. + *
  • + *
+ * + * @deprecated As of Java 3D version 1.4. + */ +public class CompressedGeometry extends Geometry { + + CompressedGeometryHeader cgHeader ; + + /** + * Specifies that this CompressedGeometry object allows reading its + * byte count information. + */ + public static final int + ALLOW_COUNT_READ = CapabilityBits.COMPRESSED_GEOMETRY_ALLOW_COUNT_READ ; + + /** + * Specifies that this CompressedGeometry object allows reading its + * header information. + */ + public static final int + ALLOW_HEADER_READ = CapabilityBits.COMPRESSED_GEOMETRY_ALLOW_HEADER_READ ; + + /** + * Specifies that this CompressedGeometry object allows reading its + * geometry data component information. + */ + public static final int + ALLOW_GEOMETRY_READ = + CapabilityBits.COMPRESSED_GEOMETRY_ALLOW_GEOMETRY_READ ; + + /** + * Specifies that this CompressedGeometry allows reading the geometry + * data reference information for this object. This is only used in + * by-reference geometry mode. + * + * @since Java 3D 1.2 + */ + public static final int + ALLOW_REF_DATA_READ = + CapabilityBits.COMPRESSED_GEOMETRY_ALLOW_REF_DATA_READ; + + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_COUNT_READ, + ALLOW_HEADER_READ, + ALLOW_GEOMETRY_READ, + ALLOW_REF_DATA_READ + }; + + /** + * Package scoped default constructor for use by cloneNodeComponent. + */ + CompressedGeometry() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Creates a new CompressedGeometry NodeComponent by copying + * the specified compressed geometry data into this object. + * If the version number of compressed geometry, as specified by + * the CompressedGeometryHeader, is incompatible with the + * supported version of compressed geometry in the current version + * of Java 3D, then the compressed geometry object will not be + * rendered. + * + * @param hdr the compressed geometry header. This is copied + * into the CompressedGeometry NodeComponent. + * + * @param compressedGeometry the compressed geometry data. The + * geometry must conform to the format described in Appendix B of + * the Java 3D API Specification. + * + * @exception IllegalArgumentException if a problem is detected with the + * header + * + * @see CompressedGeometryHeader + * @see Canvas3D#queryProperties + */ + public CompressedGeometry(CompressedGeometryHeader hdr, + byte[] compressedGeometry) { + this(hdr, compressedGeometry, false) ; + } + + /** + * Creates a new CompressedGeometry NodeComponent. The + * specified compressed geometry data is either copied into this + * object or is accessed by reference. + * If the version number of compressed geometry, as specified by + * the CompressedGeometryHeader, is incompatible with the + * supported version of compressed geometry in the current version + * of Java 3D, the compressed geometry object will not be + * rendered. + * + * @param hdr the compressed geometry header. This is copied + * into the CompressedGeometry NodeComponent. + * + * @param compressedGeometry the compressed geometry data. The + * geometry must conform to the format described in Appendix B of + * the Java 3D API Specification. + * + * @param byReference a flag that indicates whether the data is copied + * into this compressed geometry object or is accessed by reference. + * + * @exception IllegalArgumentException if a problem is detected with the + * header + * + * @see CompressedGeometryHeader + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.2 + */ + public CompressedGeometry(CompressedGeometryHeader hdr, + byte[] compressedGeometry, + boolean byReference) { + + if ((hdr.size + hdr.start) > compressedGeometry.length) + throw new IllegalArgumentException + (J3dI18N.getString("CompressedGeometry0")) ; + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + // Create a separate copy of the given header. + cgHeader = new CompressedGeometryHeader() ; + hdr.copy(cgHeader) ; + + // Create the retained object. + ((CompressedGeometryRetained)this.retained).createCompressedGeometry + (cgHeader, compressedGeometry, byReference) ; + + // This constructor is designed to accept byte arrays that may contain + // possibly many large compressed geometry blocks interspersed with + // non-J3D-specific metadata. Only one of these blocks is used per + // CompressedGeometry object, so set the geometry offset to zero in + // the header if the data itself is copied. + if (!byReference) + cgHeader.start = 0 ; + } + + /** + * This constructor is not implemented. + * + * @exception UnsupportedOperationException this constructor is not + * implemented + * + * @since Java 3D 1.3 + */ + public CompressedGeometry(CompressedGeometryHeader hdr, + J3DBuffer compressedGeometry) { + throw new UnsupportedOperationException(J3dI18N.getString("CompressedGeometry9")) ; + } + + + /** + * Returns the size, in bytes, of the compressed geometry buffer. + * The size of the compressed geometry header is not included. + * + * @return the size, in bytes, of the compressed geometry buffer. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getByteCount() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException + (J3dI18N.getString("CompressedGeometry1")) ; + + return cgHeader.size ; + } + + /** + * Copies the compressed geometry header from the CompressedGeometry + * NodeComponent into the passed in parameter. + * + * @param hdr the CompressedGeometryHeader object into which to copy the + * CompressedGeometry NodeComponent's header; the offset field may differ + * from that which was originally specified if a copy of the original + * compressed geometry byte array was created. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see CompressedGeometryHeader + */ + public void getCompressedGeometryHeader(CompressedGeometryHeader hdr) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_HEADER_READ)) + throw new CapabilityNotSetException + (J3dI18N.getString("CompressedGeometry2")) ; + + cgHeader.copy(hdr) ; + } + + /** + * Retrieves the compressed geometry associated with the + * CompressedGeometry NodeComponent object. Copies the compressed + * geometry from the CompressedGeometry node into the given array. + * The array must be large enough to hold all of the bytes. + * The individual array elements must be allocated by the caller. + * + * @param compressedGeometry the array into which to copy the compressed + * geometry. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the data access mode for this + * object is by-reference. + * + * @exception ArrayIndexOutOfBoundsException if compressedGeometry byte + * array is not large enough to receive the compressed geometry + */ + public void getCompressedGeometry(byte[] compressedGeometry) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException + (J3dI18N.getString("CompressedGeometry3")) ; + + if (isByReference()) + throw new IllegalStateException + (J3dI18N.getString("CompressedGeometry7")) ; + + if (cgHeader.size > compressedGeometry.length) + throw new ArrayIndexOutOfBoundsException + (J3dI18N.getString("CompressedGeometry4")) ; + + ((CompressedGeometryRetained)this.retained).copy(compressedGeometry) ; + } + + /** + * Decompresses the compressed geometry. Returns an array of Shape nodes + * containing the decompressed geometry objects, or null if the version + * number of the compressed geometry is incompatible with the decompressor + * in the current version of Java 3D. + * + * @return an array of Shape nodes containing the + * geometry decompressed from this CompressedGeometry NodeComponent + * object, or null if its version is incompatible + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Shape3D[] decompress() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException + (J3dI18N.getString("CompressedGeometry5")) ; + + CompressedGeometryRetained cgr = + (CompressedGeometryRetained)this.retained ; + + GeometryDecompressorShape3D decompressor = + new GeometryDecompressorShape3D() ; + + // Decompress the geometry as TriangleStripArrays. A combination of + // TriangleStripArrays and TrianglesFanArrays is more compact but + // requires twice as many Shape3D objects, resulting in slower + // rendering performance. + // + // Using TriangleArray output is currently the fastest, given the + // strip sizes observed from various compressed geometry objects, but + // produces about twice as many vertices. TriangleStripArray produces + // the same number of Shape3D objects as TriangleArray using 1/2 + // to 2/3 of the vertices, with only a marginal performance penalty. + // + return decompressor.toTriangleStripArrays(cgr) ; + } + + + /** + * Retrieves the data access mode for this CompressedGeometry object. + * + * @return true if the data access mode for this + * CompressedGeometry object is by-reference; + * false if the data access mode is by-copying. + * + * @since Java 3D 1.2 + */ + public boolean isByReference() { + return ((CompressedGeometryRetained)this.retained).isByReference() ; + } + + + /** + * Gets the compressed geometry data reference. + * + * @return the current compressed geometry data reference. + * + * @exception IllegalStateException if the data access mode for this + * object is not by-reference. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public byte[] getCompressedGeometryRef() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ)) + throw new CapabilityNotSetException + (J3dI18N.getString("CompressedGeometry6")) ; + + if (!isByReference()) + throw new IllegalStateException + (J3dI18N.getString("CompressedGeometry8")) ; + + return ((CompressedGeometryRetained)this.retained).getReference() ; + } + + + /** + * Gets the compressed geometry data buffer reference, which is + * always null since NIO buffers are not supported for + * CompressedGeometry objects. + * + * @return null + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public J3DBuffer getCompressedGeometryBuffer() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ)) + throw new CapabilityNotSetException + (J3dI18N.getString("CompressedGeometry6")) ; + + return null; + } + + + /** + * Creates the retained mode CompressedGeometryRetained object that this + * CompressedGeometry object will point to. + */ + void createRetained() { + this.retained = new CompressedGeometryRetained() ; + this.retained.setSource(this) ; + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + CompressedGeometry cg = new CompressedGeometry() ; + + // Duplicate data specific to this class. + cg.cgHeader = new CompressedGeometryHeader() ; + cgHeader.copy(cg.cgHeader) ; + + // Duplicate the retained side. + CompressedGeometryRetained cgr = (CompressedGeometryRetained)retained ; + cgr.duplicate((CompressedGeometryRetained)cg.retained) ; + + // Duplicate superclass data and return. + cg.duplicateNodeComponent(this) ; + return cg ; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryHeader.java b/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryHeader.java new file mode 100644 index 0000000..fad8927 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryHeader.java @@ -0,0 +1,260 @@ +/* + * $RCSfile: CompressedGeometryHeader.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The CompressedGeometrHeader object is used in conjunction with + * the CompressedGeometry object. The CompressedGeometrHeader object + * contains information specific to the compressed geometry stored in + * CompressedGeometry NodeComponent object. This information + * is used to aid the decompression of the compressed geometry. + *

+ * All instance data is declared public and no get or set methods are + * provided. + * + * @see CompressedGeometry + * + * @deprecated As of Java 3D version 1.4. + */ +public class CompressedGeometryHeader extends Object { + + /** + * bufferType: compressed geometry is made up of individual points. + */ + public static final int POINT_BUFFER = 0 ; + + /** + * bufferType: compressed geometry is made up of line segments. + */ + public static final int LINE_BUFFER = 1 ; + + /** + * bufferType: compressed geometry is made up of triangles. + */ + public static final int TRIANGLE_BUFFER = 2 ; + + // Valid values for the bufferDataPresent field. + + /** + * bufferDataPresent: bit indicating that normal information is + * bundled with the vertices in the compressed geometry buffer. + */ + public static final int NORMAL_IN_BUFFER = 1 ; + + /** + * bufferDataPresent: bit indicating that RGB color information is + * bundled with the vertices in the compressed geometry buffer. + */ + public static final int COLOR_IN_BUFFER = 2 ; + + /** + * bufferDataPresent: bit indicating that alpha information is + * bundled with the vertices in the compressed geometry buffer. + */ + public static final int ALPHA_IN_BUFFER = 4 ; + + /** + * The major version number for the compressed geometry format that + * was used to compress the geometry. + * If the version number of compressed geometry is incompatible + * with the supported version of compressed geometry in the + * current version of Java 3D, the compressed geometry obejct will + * not be rendered. + * + * @see Canvas3D#queryProperties + */ + public int majorVersionNumber ; + + /** + * The minor version number for the compressed geometry format that + * was used to compress the geometry. + * If the version number of compressed geometry is incompatible + * with the supported version of compressed geometry in the + * current version of Java 3D, the compressed geometry obejct will + * not be rendered. + * + * @see Canvas3D#queryProperties + */ + public int minorVersionNumber ; + + /** + * The minor-minor version number for the compressed geometry format + * that was used to compress the geometry. + * If the version number of compressed geometry is incompatible + * with the supported version of compressed geometry in the + * current version of Java 3D, the compressed geometry obejct will + * not be rendered. + * + * @see Canvas3D#queryProperties + */ + public int minorMinorVersionNumber ; + + /** + * Describes the type of data in the compressed geometry buffer. + * Only one type may be present in any given compressed geometry + * buffer. + */ + public int bufferType ; + + /** + * Contains bits indicating what data is bundled with the vertices in the + * compressed geometry buffer. If this data is not present (e.g. color) + * then this info will be inherited from the Appearance node. + */ + public int bufferDataPresent ; + + /** + * Size of the compressed geometry in bytes. + */ + public int size ; + + /** + * Offset in bytes of the start of the compressed geometry from the + * beginning of the compressed geometry byte array passed to the + * CompressedGeometry constructor.

+ * + * If the CompressedGeometry is created with reference access semantics, + * then this allow external compressors or file readers to embed several + * blocks of compressed geometry in a single large byte array, possibly + * interspersed with metadata that is not specific to Java 3D, without + * having to copy each block to a separate byte array.

+ * + * If the CompressedGeometry is created with copy access semantics, then + * size bytes of compressed geometry data are copied from the + * offset indicated by start instead of copying the entire + * byte array. The getCompressedGeometry() method will return only the + * bytes used to construct the object, and the getCompressedGeometryHeader() + * method will return a header with the start field set to 0. + */ + public int start ; + + /** + * A point that defines the lower bound of the x, + * y, and z components for all positions in the + * compressed geometry buffer. If null, a lower bound of + * (-1,-1,-1) is assumed. Java 3D will use this information to + * construct a bounding box around compressed geometry objects + * that are used in nodes for which the auto compute bounds flag + * is true. The default value for this point is null. + * + * @since Java 3D 1.2 + */ + public Point3d lowerBound = null ; + + /** + * A point that defines the upper bound of the x, + * y, and z components for all positions in the + * compressed geometry buffer. If null, an upper bound of (1,1,1) + * is assumed. Java 3D will use this information to construct a + * bounding box around compressed geometry objects that are used + * in nodes for which the auto compute bounds flag is true. The + * default value for this point is null. + * + * @since Java 3D 1.2 + */ + public Point3d upperBound = null ; + + /** + * Creates a new CompressedGeometryHeader object used for the + * creation of a CompressedGeometry NodeComponent object. + * All instance data is declared public and no get or set methods are + * provided. All values are set to 0 by default and must be filled + * in by the application. + * + * @see CompressedGeometry + */ + public CompressedGeometryHeader() { + } + + /** + * Package-scoped method to copy current CompressedGeometryHeader object + * to the passed-in CompressedGeometryHeader object. + * + * @param hdr the CompressedGeometryHeader object into which to copy the + * current CompressedGeometryHeader. + */ + void copy(CompressedGeometryHeader hdr) { + hdr.majorVersionNumber = this.majorVersionNumber ; + hdr.minorVersionNumber = this.minorVersionNumber ; + hdr.minorMinorVersionNumber = this.minorMinorVersionNumber ; + hdr.bufferType = this.bufferType ; + hdr.bufferDataPresent = this.bufferDataPresent ; + hdr.size = this.size ; + hdr.start = this.start ; + hdr.lowerBound = this.lowerBound ; + hdr.upperBound = this.upperBound ; + } + + /** + * Returns a String describing the contents of the + * CompressedGeometryHeader object. + * + * @return a String describing contents of the compressed geometry header + */ + public String toString() { + String type = "UNKNOWN" ; + switch (bufferType) { + case POINT_BUFFER: type = "POINT_BUFFER" ; break ; + case LINE_BUFFER: type = "LINE_BUFFER" ; break ; + case TRIANGLE_BUFFER: type = "TRIANGLE_BUFFER" ; break ; + } + + String data = "" ; + if ((bufferDataPresent & NORMAL_IN_BUFFER) != 0) + data = data + "NORMALS " ; + if ((bufferDataPresent & COLOR_IN_BUFFER) != 0) + data = data + "COLORS " ; + if ((bufferDataPresent & ALPHA_IN_BUFFER) != 0) + data = data + "ALPHA " ; + + String lbound = "null" ; + if (lowerBound != null) + lbound = lowerBound.toString() ; + + String ubound = "null" ; + if (upperBound != null) + ubound = upperBound.toString() ; + + return + "majorVersionNumber: " + majorVersionNumber + " " + + "minorVersionNumber: " + minorVersionNumber + " " + + "minorMinorVersionNumber: " + minorMinorVersionNumber + "\n" + + "bufferType: " + type + " " + + "bufferDataPresent: " + data + "\n" + + "size: " + size + " " + + "start: " + start + "\n" + + "lower bound: " + lbound + "\n" + + "upper bound: " + ubound + " " ; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryRenderMethod.java b/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryRenderMethod.java new file mode 100644 index 0000000..352cd87 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryRenderMethod.java @@ -0,0 +1,119 @@ +/* + * $RCSfile: CompressedGeometryRenderMethod.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d ; + +/** + * The RenderMethod interface is used to create various ways to render + * different geometries. + */ + +class CompressedGeometryRenderMethod implements RenderMethod { + + /** + * The actual rendering code for this RenderMethod. + */ + public boolean render(RenderMolecule rm, Canvas3D cv, + RenderAtomListInfo ra, int dirtyBits) { + + CompressedGeometryRetained cgr ; + + if (rm.doInfinite) { + cv.updateState(dirtyBits); + while (ra != null) { + renderCompressedGeo(ra, rm, cv); + ra = ra.next; + } + return true; + } + + boolean isVisible = false; // True if any of the RAs is visible. + + while (ra != null) { + if (cv.ra == ra.renderAtom) { + if (cv.raIsVisible) { + cv.updateState(dirtyBits); + renderCompressedGeo(ra, rm, cv); + isVisible = true; + } + } + else { + if (!VirtualUniverse.mc.viewFrustumCulling || + ra.renderAtom.localeVwcBounds.intersect(cv.viewFrustum)) { + cv.updateState(dirtyBits); + cv.raIsVisible = true; + renderCompressedGeo(ra, rm, cv); + isVisible = true; + } + else { + cv.raIsVisible = false; + } + cv.ra = ra.renderAtom; + } + + ra = ra.next; + } + + return isVisible; + + } + + void renderCompressedGeo(RenderAtomListInfo ra, RenderMolecule rm, Canvas3D cv) { + + boolean useAlpha ; + CompressedGeometryRetained cgr ; + useAlpha = rm.useAlpha ; + + cgr = (CompressedGeometryRetained)ra.renderAtom.geometryAtom.geometryArray[ra.index]; + + /* force_decompression if lighting is disabled and + * ignoreVertexColors is TRUE, since there is no way for openGL + * to ignore vertexColors in this case, force decompression + */ + if (rm.textureBin.attributeBin.ignoreVertexColors && rm.enableLighting == false && cgr.mirrorGeometry == null) { + cgr.mirrorGeometry = cgr.getGeometry(true, cv) ; + } + else if (cgr.mirrorGeometry == null) { + // cgr.getGeometry() will decompress in software and return a + // GeometryRetained if hardware decompression isn't available, + // otherwise it just returns cgr. + cgr.mirrorGeometry = cgr.getGeometry(false, cv) ; + if (cgr.mirrorGeometry == null) + // decompressor error + return ; + } + + cgr.mirrorGeometry.execute(cv, ra.renderAtom, rm.isNonUniformScale, + (useAlpha && ra.geometry().noAlpha), rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin.ignoreVertexColors); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryRetained.java b/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryRetained.java new file mode 100644 index 0000000..080d248 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/CompressedGeometryRetained.java @@ -0,0 +1,466 @@ +/* + * $RCSfile: CompressedGeometryRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d ; +import javax.vecmath.* ; + +/** + * The compressed geometry object is used to store geometry in a + * compressed format. Using compressed geometry reduces the amount + * of memory needed by a Java 3D application and increases the speed + * objects can be sent over the network. Once geometry decompression + * hardware support becomes available, increased rendering performance + * will also result from the use of compressed geometry. + */ +class CompressedGeometryRetained extends GeometryRetained { + + // If not in by-reference mode, a 48-byte header as defined by the + // GL_SUNX_geometry_compression OpenGL extension is always concatenated to + // the beginning of the compressed geometry data and copied along with the + // it into a contiguous array. This allows hardware decompression using + // the obsolete experimental GL_SUNX_geometry_compression extension if + // that is all that is available. + // + // This is completely distinct and not to be confused with the cgHeader + // field on the non-retained side, although much of the data is + // essentially the same. + private static final int HEADER_LENGTH = 48 ; + + // These are the header locations examined. + private static final int HEADER_MAJOR_VERSION_OFFSET = 0 ; + private static final int HEADER_MINOR_VERSION_OFFSET = 1 ; + private static final int HEADER_MINOR_MINOR_VERSION_OFFSET = 2 ; + private static final int HEADER_BUFFER_TYPE_OFFSET = 3 ; + private static final int HEADER_BUFFER_DATA_OFFSET = 4 ; + + // The OpenGL compressed geometry extensions use bits instead of + // enumerations to represent the type of compressed geometry. + static final byte TYPE_POINT = 1 ; + static final byte TYPE_LINE = 2 ; + static final byte TYPE_TRIANGLE = 4 ; + + // Version number of this compressed geometry object. + int majorVersionNumber ; + int minorVersionNumber ; + int minorMinorVersionNumber ; + + // These fields are used by the native execute() method. + int packedVersion ; + int bufferType ; + int bufferContents ; + int renderFlags ; + int offset ; + int size ; + byte[] compressedGeometry ; + + // True if by-reference data access mode is in effect. + private boolean byReference = false ; + + // A reference to the original byte array with which this object was + // created. If hardware decompression is available but it doesn't support + // by-reference semantics, then an internal copy of the original byte array + // is made even when by-reference semantics have been requested. + private byte[] originalCompressedGeometry = null ; + + // True if the platform supports hardware decompression. + private static boolean hardwareDecompression = false ; + + // This field retains a reference to the GeometryRetained object used for + // geometry-based picking. It is normally the same reference as the + // mirror geometry used for rendering unless hardware decompression is + // supported. + private GeometryRetained pickGeometry = null ; + + /** + * Formerly native method that returns availability of a native by-reference + * rendering API for compressed geometry. + */ + private boolean decompressByRef(Context ctx) { + return false; + } + + /** + * Formerly native method that returns availability of hardware + * rendering (and acceleration) for compressed geometry of the + * given version. + */ + private boolean decompressHW(Context ctx, int majorVersion, int minorVersion) { + return false; + } + + /** + * Formerly native method that does HW compressed geometry rendering + */ + private void execute(Context ctx, int version, int bufferType, + int bufferContents, int renderFlags, + int offset, int size, byte[] geometry) { + + assert false : "This method should never be called!"; + } + + /** + * Method for calling native execute() method on behalf of the J3D renderer. + */ + void execute(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale, + boolean updateAlpha, float alpha, + int screen, boolean ignoreVertexColors) { + + // XXXX: alpha udpate + execute(cv.ctx, packedVersion, bufferType, bufferContents, + renderFlags, offset, size, compressedGeometry) ; + } + + /** + * The package-scoped constructor. + */ + CompressedGeometryRetained() { + this.geoType = GEO_TYPE_COMPRESSED ; + + // Compressed geometry is always bounded by [-1..1] on each axis, so + // set that as the initial bounding box. + geoBounds.setUpper( 1.0, 1.0, 1.0) ; + geoBounds.setLower(-1.0,-1.0,-1.0) ; + } + + /** + * Compressed geometry is immutable so this method does nothing. + */ + void computeBoundingBox() { + } + + /** + * Update this object. Compressed geometry is immutable so there's + * nothing to do. + */ + void update() { + isDirty = 0 ; + } + + /** + * Return true if the data access mode is by-reference. + */ + boolean isByReference() { + return this.byReference ; + } + + private void createByCopy(byte[] geometry) { + // Always copy a header along with the compressed geometry into a + // contiguous array in order to support hardware acceleration with the + // GL_SUNX_geometry_compression extension. The header is unnecessary + // if only the newer GL_SUN_geometry_compression API needs support. + compressedGeometry = new byte[HEADER_LENGTH + this.size] ; + + compressedGeometry[HEADER_MAJOR_VERSION_OFFSET] = + (byte)this.majorVersionNumber ; + + compressedGeometry[HEADER_MINOR_VERSION_OFFSET] = + (byte)this.minorVersionNumber ; + + compressedGeometry[HEADER_MINOR_MINOR_VERSION_OFFSET] = + (byte)this.minorMinorVersionNumber ; + + compressedGeometry[HEADER_BUFFER_TYPE_OFFSET] = + (byte)this.bufferType ; + + compressedGeometry[HEADER_BUFFER_DATA_OFFSET] = + (byte)this.bufferContents ; + + System.arraycopy(geometry, this.offset, + compressedGeometry, HEADER_LENGTH, this.size) ; + + this.offset = HEADER_LENGTH ; + } + + /** + * Creates the retained compressed geometry data. Data from the header is + * always copied; the compressed geometry is copied as well if the data + * access mode is not by-reference. + * + * @param hdr the compressed geometry header + * @param geometry the compressed geometry + * @param byReference if true then by-reference semantics requested + */ + void createCompressedGeometry(CompressedGeometryHeader hdr, + byte[] geometry, boolean byReference) { + + this.byReference = byReference ; + + if (hdr.lowerBound != null) + this.geoBounds.setLower(hdr.lowerBound) ; + + if (hdr.upperBound != null) + this.geoBounds.setUpper(hdr.upperBound) ; + + this.centroid.set(geoBounds.getCenter()); + recompCentroid = false; + this.majorVersionNumber = hdr.majorVersionNumber ; + this.minorVersionNumber = hdr.minorVersionNumber ; + this.minorMinorVersionNumber = hdr.minorMinorVersionNumber ; + + this.packedVersion = + (hdr.majorVersionNumber << 24) | + (hdr.minorVersionNumber << 16) | + (hdr.minorMinorVersionNumber << 8) ; + + switch(hdr.bufferType) { + case CompressedGeometryHeader.POINT_BUFFER: + this.bufferType = TYPE_POINT ; + break ; + case CompressedGeometryHeader.LINE_BUFFER: + this.bufferType = TYPE_LINE ; + break ; + case CompressedGeometryHeader.TRIANGLE_BUFFER: + this.bufferType = TYPE_TRIANGLE ; + break ; + } + + this.bufferContents = hdr.bufferDataPresent ; + this.renderFlags = 0 ; + + this.size = hdr.size ; + this.offset = hdr.start ; + + if (byReference) { + // Assume we can use the given reference, but maintain a second + // reference in case a copy is later needed. + this.compressedGeometry = geometry ; + this.originalCompressedGeometry = geometry ; + } else { + // Copy the original data into a format that can be used by both + // the software and native hardware decompressors. + createByCopy(geometry) ; + this.originalCompressedGeometry = null ; + } + } + + /** + * Decompress this object into a GeometryArrayRetained if hardware + * decompression is not available. Once decompressed the resulting + * geometry replaces the geometry reference in the associated RenderAtom + * as well as the mirror geometry reference in this object. + */ + GeometryRetained getGeometry(boolean forceDecompression, Canvas3D cv ) { + + if (forceDecompression) { + // forceDecompression is set to true if lighting is disabled and + // ignoreVertexColors is true, since there is no way for openGL to + // ignore vertexColors in this case. + GeometryDecompressorRetained gdr = + new GeometryDecompressorRetained() ; + + mirrorGeometry = gdr.decompress(this) ; + gdr.getBoundingBox(geoBounds) ; + pickGeometry = mirrorGeometry ; + } + else { + // Return this object if hardware decompression is available. + if (hardwareDecompression) + return (GeometryRetained)this ; + + // Check to see if hardware decompression is available. + if (decompressHW(cv.ctx, majorVersionNumber, minorVersionNumber)) { + hardwareDecompression = true ; + + // If hardware can't handle by-reference, punt to by-copy. + if (isByReference() && !decompressByRef(cv.ctx)) { + createByCopy(compressedGeometry) ; + } + + return (GeometryRetained)this ; + } + + // Decompress the data into a GeometryArrayRetained representation + // for the mirror geometry reference. + GeometryDecompressorRetained gdr = + new GeometryDecompressorRetained() ; + + mirrorGeometry = gdr.decompress(this) ; + gdr.getBoundingBox(geoBounds) ; + + // The mirror geometry contains a superset of the pick geometry + // data. Since hardware decompression isn't available, there's no + // need to retain separate pick geometry. + pickGeometry = mirrorGeometry ; + } + + return mirrorGeometry ; + } + + /** + * This method always decompresses the geometry and retains the result in + * order to support geometry-based picking and collision detection. The + * returned GeometryRetained object will contain only positions and + * connections. + */ + GeometryRetained getPickGeometry() { + // Return the pick geometry if available. + if (pickGeometry != null) + return pickGeometry ; + + // Decompress the data into a GeometryArrayRetained representation for + // the pick geometry reference. Retain it and its bounding box. + GeometryDecompressorRetained gdr = new GeometryDecompressorRetained() ; + gdr.setDecompressPositionsOnly(true) ; + + pickGeometry = gdr.decompress(this) ; + gdr.getBoundingBox(geoBounds) ; + return pickGeometry ; + } + + // + // The following intersect() methods are used to implement geometry-based + // picking and collision. + // + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + GeometryRetained geomR = getPickGeometry() ; + return (geomR != null ? + geomR.intersect(pickShape, pickInfo, flags, iPnt, geom, geomIndex) : false); + } + + boolean intersect(Bounds targetBound) { + GeometryRetained geom = getPickGeometry() ; + return (geom != null ? geom.intersect(targetBound) : false); + } + + boolean intersect(Transform3D thisToOtherVworld, GeometryRetained g) { + GeometryRetained geom = getPickGeometry() ; + return (geom != null ? + geom.intersect(thisToOtherVworld, g) : false); + } + + boolean intersect(Point3d[] pnts) { + GeometryRetained geom = getPickGeometry() ; + return (geom != null ? geom.intersect(pnts) : false); + } + + /** + * Return a vertex format mask that's compatible with GeometryArray + * objects. + */ + int getVertexFormat() { + int vertexFormat = GeometryArray.COORDINATES ; + + if ((this.bufferContents & + CompressedGeometryHeader.NORMAL_IN_BUFFER) != 0) + vertexFormat |= GeometryArray.NORMALS ; + + if ((this.bufferContents & + CompressedGeometryHeader.COLOR_IN_BUFFER) != 0) + vertexFormat |= GeometryArray.COLOR ; + + if ((this.bufferContents & + CompressedGeometryHeader.ALPHA_IN_BUFFER) != 0) + vertexFormat |= GeometryArray.WITH_ALPHA ; + + return vertexFormat ; + } + + /** + * Return a buffer type that's compatible with CompressedGeometryHeader. + */ + int getBufferType() { + switch(this.bufferType) { + case TYPE_POINT: + return CompressedGeometryHeader.POINT_BUFFER ; + case TYPE_LINE: + return CompressedGeometryHeader.LINE_BUFFER ; + default: + case TYPE_TRIANGLE: + return CompressedGeometryHeader.TRIANGLE_BUFFER ; + } + } + + /** + * Copies compressed geometry data into the given array of bytes. + * The internal header information is not copied. + * + * @param buff array of bytes into which to copy compressed geometry + */ + void copy(byte[] buff) { + System.arraycopy(compressedGeometry, offset, buff, 0, size) ; + } + + /** + * Returns a reference to the original compressed geometry byte array, + * which may have been copied even if by-reference semantics have been + * requested. It will be null if byCopy is in effect. + * + * @return reference to array of bytes containing the compressed geometry. + */ + byte[] getReference() { + return originalCompressedGeometry ; + } + + /** + * Copies all retained data for cloneNodeComponent() on the non-retained + * side. This is unlike GeometryArray subclasses which just call the + * public API constructors and then duplicateNodeComponent() to invoke the + * GeometryArray implementation of duplicateAttributes(), since the + * CompressedGeometry class directly subclasses Geometry and calling the + * public constructors would cause a lot of redundant data copying. + */ + void duplicate(CompressedGeometryRetained cgr) { + cgr.majorVersionNumber = this.majorVersionNumber ; + cgr.minorVersionNumber = this.minorVersionNumber ; + cgr.minorMinorVersionNumber = this.minorMinorVersionNumber ; + + cgr.packedVersion = this.packedVersion ; + cgr.bufferType = this.bufferType ; + cgr.bufferContents = this.bufferContents ; + cgr.renderFlags = this.renderFlags ; + + cgr.offset = this.offset ; + cgr.size= this.size ; + + cgr.geoBounds.setLower(this.geoBounds.lower) ; + cgr.geoBounds.setUpper(this.geoBounds.upper) ; + cgr.pickGeometry = this.pickGeometry ; + cgr.byReference = this.byReference ; + + if (this.byReference) { + // Copy references only. + cgr.compressedGeometry = this.compressedGeometry ; + cgr.originalCompressedGeometry = this.originalCompressedGeometry ; + } else { + // Copy entire byte array including 48-byte native OpenGL header. + cgr.compressedGeometry = new byte[this.compressedGeometry.length] ; + System.arraycopy(this.compressedGeometry, 0, + cgr.compressedGeometry, 0, + this.compressedGeometry.length) ; + cgr.originalCompressedGeometry = null ; + } + } + + int getClassType() { + return COMPRESS_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ConeSound.java b/j3d-core/src/classes/share/javax/media/j3d/ConeSound.java new file mode 100644 index 0000000..a5e1232 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ConeSound.java @@ -0,0 +1,962 @@ +/* + * $RCSfile: ConeSound.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.lang.Math; +import javax.vecmath.Point2f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + + +/** + * The ConeSound node object defines a PointSound node whose sound source is + * directed along a specific vector in space. A ConeSound source is attenuated + * by gain scale factors and filters based on the angle between the vector from + * the source to the listener, and the ConeSound's direction vector. This + * attenuation is either a single spherical distance gain attenuation (as for + * a general PointSound source) or dual front and back distance gain + * attenuations defining elliptical attenuation areas. The angular filter and the + * active AuralAttribute component filter define what filtering is applied to + * the sound source. (See AuralAtttribute class for more details on filtering.) + * This node has the same attributes as a PointSound node with the addition of a + * direction vector and an array of points each containing: angular distance (in + * radians), gain scale factor, and filter (which for now consists of a lowpass + * filter cutoff frequency). Similar to the definition of the back distance gain + * array for PointSounds, a piece-wise linear curve (defined in terms of + * radians from the axis) specifies the slope of these additional attenuation + * values. + *

+ * Distance Gain attuation + *

    + * A cone sound node can have one or two distance attenuation arrays. + * If none are set, no distance gain attenuation is performed (equivalent + * to using a distance gain of 1.0 for all distances). If only one distance + * attenuation array is set, sphere attenuation is assumed. If both a front + * and back distance attenuation are set, elliptical attenuation regions + * are defined. + *

    + * Use PointSound setDistanceGain() method to set the front distance + * attenuation array separate from the back distance attenuation array. + * A front distance attenuation array defines monotonically-increasing + * distances from the sound source origin along the position direction + * vector. A back distance attenuation array (if given) defines + * monotonically-increasing distances from the sound source origin along the + * negative direction vector. The two arrays must be of the same length. + * The backDistance[i] gain values must be less than or equal to + * the frontDistance[i] gain values. + *

    + * Gain scale factors are associated with distances from the listener to + * the sound source via an array of (distance, gain-scale-factor) pairs. + * The gain scale factor applied to the sound source is the linear + * interpolated gain value between the distance value range that includes + * the current distance from the listener to the sound source. + *

    + * The getDistanceGainLength method defined for PointSound returns the length + * of the all distance gain attenuation arrays, including the back distance + * gain arrays. Arrays passed into getDistanceGain methods should all + * be at least this size. + *

+ * Direction Methods + *

    + * This value is the sound source's direction vector. It is the axis from + * which angular distance is measured. + *

+ * Angular Attenuation + *

    + * Besides sound (linear) distance attenuation a ConeSound can optionally + * define angular gain and filter attenuation. + *

    + * This attenuation is defined + * as a triple of (angular distance, gain-scale-factor, filter). The + * distance is measured as the angle in radians between the ConeSound's + * direction vector and the vector from the sound source position to the + * listener. Both the gain scale factor and filter applied to the sound + * source is the linear interpolation of values between the distance value + * range that includes the angular distance from the sound source axis. + *

    + * If this is not set, no angular gain attenuation or filtering is performed + * (equivalent to using an angular gain scale factor of 1.0 and an angular + * filter of Sound.NO_FILTER for all distances). + *

    + * If angular distance from the listener-sound-position vector and a sound's + * direction vector is less than the first distance in the array, only the first + * gain scale factor and first filter are applied to the sound source. + * This creates a conical region around the listener within which the sound + * is uniformly attenuated by first gain and first filter in the array. + *

    + * If the distance from the listener-sound-position vector and the sound's + * direction vector is greater than the last distance in the array, the last gain + * scale factor and last filter are applied to the sound source. + *

    + * Distance elements in this array of points is a monotonically-increasing + * set of floating point numbers measured from 0 to p radians. Gain scale + * factors elements in this list of points can be any positive floating + * point numbers. While for most applications this list of gain scale + * factors will usually be monotonically-decreasing, they do not have to be. + * The filter (for now) is a single simple frequency cutoff value. + *

    + * The getAngularAttenuationArrayLength method returns the length of the angular + * attenuation arrays. Arrays passed into getAngularAttenuation methods + * should all be at least this size. + *

+ */ + +public class ConeSound extends PointSound { + // Constants + // + // These flags, when enabled using the setCapability method, allow an + // application to invoke methods that respectively read and write direction + // and angular attenuation array. These capability flags are enforced only + // when the node is part of a live or compiled scene graph. + + /** + * Specifies that this ConeSound allows access to its object's direction + * information. + */ + public static final int + ALLOW_DIRECTION_READ = CapabilityBits.CONE_SOUND_ALLOW_DIRECTION_READ; + + /** + * Specifies that this ConeSound allows writing to its object's direction + * information. + */ + public static final int + ALLOW_DIRECTION_WRITE = CapabilityBits.CONE_SOUND_ALLOW_DIRECTION_WRITE; + + /** + * Specifies that this ConeSound allows access to its object's cone params + * information. + */ + public static final int + ALLOW_ANGULAR_ATTENUATION_READ = CapabilityBits.CONE_SOUND_ALLOW_ANGULAR_ATTENUATION_READ; + + /** + * Specifies that this ConeSound allows writing to its object's cone params + * information. + */ + public static final int + ALLOW_ANGULAR_ATTENUATION_WRITE = CapabilityBits.CONE_SOUND_ALLOW_ANGULAR_ATTENUATION_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_DIRECTION_READ, + ALLOW_ANGULAR_ATTENUATION_READ + }; + + /** + * Constructs and initializes a new ConeSound node using default + * parameters. The following default values are used: + *
    + * Direction vector: (0.0, 0.0, 1.0)
    + * Angular attenuation: + * ((0.0, 1.0, Sound.NO_FILTER),(p/2, 0.0, Sound.NO_FILTER))
    + *
+ */ + public ConeSound() { + // Uses default values defined in ConeSoundRetained.java + super(); + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a ConeSound node object using only the provided parameter + * values for sound, overall initial gain, position, and direction. The + * remaining fields are set to the default values above. This form uses + * Point3f as input for its position and Vector3f for direction. + * @param soundData sound source data associated with this node + * @param initialGain amplitude scale factor applied to sound + * @param position 3D location of source + * @param direction 3D vector defining cone's axis + */ + public ConeSound(MediaContainer soundData, + float initialGain, + Point3f position, + Vector3f direction) { + + super(soundData, initialGain, position ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ConeSoundRetained)this.retained).setDirection(direction); + } + + /** + * Constructs a ConeSound node object using only the provided parameter + * values for sound, overall initial gain, position, and direction. The + * remaining fields are set to the default values above. This form uses + * individual float parameters for the elements of the position and + * direction vectors. + * @param soundData sound source data + * @param initialGain amplitude scale factor applied to sound + * @param posX x coordinate of location of source + * @param posY y coordinate of location of source + * @param posZ z coordinate of location of source + * @param dirX x coordinate cones' axii vector + * @param dirY y coordinate cones' axii vector + * @param dirZ z coordinate cones' axii vector + */ + public ConeSound(MediaContainer soundData, + float initialGain, + float posX, float posY, float posZ, + float dirX, float dirY, float dirZ) { + + super(soundData, initialGain, posX, posY, posZ ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ConeSoundRetained)this.retained).setDirection(dirX, dirY, dirZ); + } + + /** + * Constructs a ConeSound node object using all the provided PointSound + * parameter values. This form uses points or vectors as input for its + * position, direction, and front/back distance attenuation arrays. + *

+ * Unlike the single distance gain attenuation array for PointSounds which + * define spherical areas about the sound source between which gains are + * linearly interpolated, this directed ConeSound can have two distance gain + * attenuation arrays that define ellipsoidal attenuation areas. See the + * setDistanceGain PointSound method for details on how the separate distance + * and distanceGain arrays are interpreted. + *

+ * The ConeSound's direction vector and angular measurements are defined in + * the local coordinate system of the node. + * @param soundData sound source data associated with this node + * @param initialGain amplitude scale factor applied to sound + * @param loopCount number of times sound is looped + * @param release flag denoting playing sound to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param position 3D location of source + * @param frontDistanceAttenuation array of (distance,gain) pairs controlling + * attenuation values along the positive direction axis + * @param backDistanceAttenuation array of (distance,gain) pairs controlling + * attenuation values along the negative direction axis + * @param direction vector defining cones' axii + */ + public ConeSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + Point3f position, + Point2f[] frontDistanceAttenuation, + Point2f[] backDistanceAttenuation, + Vector3f direction) { + + super(soundData, initialGain, loopCount, release, continuous, enable, + region, priority, position, frontDistanceAttenuation ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ConeSoundRetained)this.retained).setBackDistanceGain( + backDistanceAttenuation); + ((ConeSoundRetained)this.retained).setDirection(direction); + } + + /** + * Constructs a ConeSound node object using the provided parameter values. + * This form uses individual float parameters for the elements of the + * position, direction, and two distance attenuation arrays. + * Unlike the single distance gain attenuation array for PointSounds, which + * define spherical areas about the sound source between which gains are + * linearly interpolated, this directed ConeSound can have two distance + * gain attenuation arrays that define ellipsoidal attenuation areas. + * See the setDistanceGain PointSound method for details on how the + * separate distance and distanceGain arrays are interpreted. + * The ConeSound's direction vector and angular measurements are defined + * in the local coordinate system of the node. + * @param soundData sound source data associated with this node + * @param initialGain amplitude scale factor applied to sound + * @param loopCount number of times sound is looped + * @param release flag denoting playing sound to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param posX x coordinate of location of source + * @param posY y coordinate of location of source + * @param posZ z coordinate of location of source + * @param frontDistance array of front distance values used for attenuation + * @param frontDistanceGain array of front gain scale factors used for attenuation + * @param backDistance array of back distance values used for attenuation + * @param backDistanceGain array of back gain scale factors used for attenuation + * @param dirX x coordinate cones' axii vector + * @param dirY y coordinate cones' axii vector + * @param dirZ z coordinate cones' axii vector + */ + public ConeSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + float posX, float posY, float posZ, + float[] frontDistance, + float[] frontDistanceGain, + float[] backDistance, + float[] backDistanceGain, + float dirX, float dirY, float dirZ ) { + super(soundData, initialGain, loopCount, release, continuous, enable, + region, priority, posX, posY, posZ, + frontDistance, frontDistanceGain ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ConeSoundRetained)this.retained).setDirection(dirX, dirY, dirZ); + ((ConeSoundRetained)this.retained).setBackDistanceGain( + backDistance, backDistanceGain ); + } + + /** + * Constructs a ConeSound node object using all the provided PointSound + * parameter values, which include a single spherical distance attenuation + * array, but includes an angular attenuation array. + * This form uses points and vectors as input for its position, direction, + * single spherical distanceAttenuation array, and angularAttenuation array. + * It also accepts arrays of points for the distance attenuation and angular + * values. Each Point2f in the distanceAttenuation array contains a distance + * and a gain scale factor. Each Point3f in the angularAttenuation array + * contains an angular distance, a gain scale factor, and a filtering value + * (which is currently defined as a simple cutoff frequency). + * @param soundData sound source data associated with this node + * @param initialGain amplitude scale factor applied to sound + * @param loopCount number of times sound is looped + * @param release flag denoting playing sound to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param position 3D location of source + * @param distanceAttenuation array of (distance,gain) pairs controlling + * attenuation values along the positive direction axis + * @param direction vector defining cones' axii + * @param angularAttenuation array of tuples defining angular gain/filtering + */ + public ConeSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + Point3f position, + Point2f[] distanceAttenuation, + Vector3f direction, + Point3f[] angularAttenuation ) { + + super(soundData, initialGain, loopCount, release, continuous, enable, + region, priority, position, distanceAttenuation ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ConeSoundRetained)this.retained).setDirection(direction); + ((ConeSoundRetained)this.retained).setAngularAttenuation( + angularAttenuation); + } + + /** + * Constructs a ConeSound node object using all the provided PointSound + * parameter values, which include a single spherical distance attenuation + * array, but includes an angular attenuation array. + * This form uses individual float parameters for elements of position, + * direction, distanceAttenuation array, and angularAttenuation array. + * It also accepts separate arrays for the distance and gain scale factors + * components of distance attenuation, and separate arrays for the angular + * distance, angular gain, and filtering components of angular attenuation. + * See the setDistanceGain ConeSound method for details on how the separate + * distance and distanceGain arrays are interpreted. See the + * setAngularAttenuation ConeSound method for details on how the separate + * angularDistance, angularGain, and filter arrays are interpreted. + * @param soundData sound source data associated with this node + * @param initialGain amplitude scale factor applied to sound + * @param loopCount number of times sound is looped + * @param release flag denoting playing sound to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param posX x coordinate of location of source + * @param posY y coordinate of location of source + * @param posZ z coordinate of location of source + * @param distance array of front distance values used for attenuation + * @param distanceGain array of front gain scale factors used for attenuation + * @param dirX x coordinate cones' axii vector + * @param dirY y coordinate cones' axii vector + * @param dirZ z coordinate cones' axii vector + * @param angle array of angle radians for angularAttenuation + * @param angularGain array of gain scale factors for angularAttenuation + * @param frequencyCutoff array of lowpass filter values in Hertz + */ + public ConeSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + float posX, float posY, float posZ, + float[] distance, + float[] distanceGain, + float dirX, float dirY, float dirZ, + float[] angle, + float[] angularGain, + float[] frequencyCutoff) { + super(soundData, initialGain, loopCount, release, continuous, enable, + region, priority, posX, posY, posZ, + distance, distanceGain ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ConeSoundRetained)this.retained).setDirection(dirX, dirY, dirZ); + ((ConeSoundRetained)this.retained).setAngularAttenuation(angle, + angularGain, frequencyCutoff); + } + + /** + * Constructs and initializes a new Cone Sound node explicitly setting all + * PointSound and ConeSound fields as arguments: the PointSound position, + * front and back distance attenuation Point2f array, and ConeSound + * direction vector and Point3f angular attenuation. + * @param soundData sound source data associated with this node + * @param initialGain amplitude scale factor applied to sound + * @param loopCount number of times sound is looped + * @param release flag denoting playing sound to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param position 3D location of source + * @param frontDistanceAttenuation array of (distance,gain) pairs controlling + * attenuation values along the positive direction axis + * @param backDistanceAttenuation array of (distance,gain) pairs controlling + * attenuation values along the negative direction axis + * @param direction vector defining cones' axii + * @param angularAttenuation array of tuples defining angular gain/filtering + */ + public ConeSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + Point3f position, + Point2f[] frontDistanceAttenuation, + Point2f[] backDistanceAttenuation, + Vector3f direction, + Point3f[] angularAttenuation ) { + + super(soundData, initialGain, loopCount, release, continuous, enable, + region, priority, position, frontDistanceAttenuation ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ConeSoundRetained)this.retained).setBackDistanceGain( + backDistanceAttenuation); + ((ConeSoundRetained)this.retained).setDirection(direction); + ((ConeSoundRetained)this.retained).setAngularAttenuation( + angularAttenuation); + } + + /** + * Constructs and initializes a new Cone Sound node explicitly setting all + * PointSound and ConeSound fields as arguments but all the vector and point + * arguments are broken into individual float array components. + * @param soundData sound source data associated with this node + * @param initialGain amplitude scale factor applied to sound + * @param loopCount number of times sound is looped + * @param release flag denoting playing sound to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param posX x coordinate of location of source + * @param posY y coordinate of location of source + * @param posZ z coordinate of location of source + * @param frontDistance array of front distance values used for attenuation + * @param frontDistanceGain array of front gain scale factors used for attenuation + * @param backDistance array of back distance values used for attenuation + * @param backDistanceGain array of back gain scale factors used for attenuation + * @param dirX x coordinate cones' axii vector + * @param dirY y coordinate cones' axii vector + * @param dirZ z coordinate cones' axii vector + * @param angle array of angle radians for angularAttenuation + * @param angularGain array of gain scale factors for angularAttenuation + * @param frequencyCutoff array of lowpass filter values in Hertz + */ + public ConeSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + float posX, float posY, float posZ, + float[] frontDistance, + float[] frontDistanceGain, + float[] backDistance, + float[] backDistanceGain, + float dirX, float dirY, float dirZ, + float[] angle, + float[] angularGain, + float[] frequencyCutoff) { + super(soundData, initialGain, loopCount, release, continuous, enable, + region, priority, posX, posY, posZ, + frontDistance, frontDistanceGain ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ConeSoundRetained)this.retained).setBackDistanceGain( + backDistance, backDistanceGain ); + ((ConeSoundRetained)this.retained).setDirection(dirX, dirY, dirZ); + ((ConeSoundRetained)this.retained).setAngularAttenuation(angle, + angularGain, frequencyCutoff); + } + + /** + * Creates the retained mode ConeSoundRetained object that this + * ConeSound object will point to. + */ + void createRetained() { + this.retained = new ConeSoundRetained(); + this.retained.setSource(this); + } + + // + // OVERLOADED Sound methods + // + /** + * Sets this sound's distance gain elliptical attenuation - + * where gain scale factor is applied to sound based on distance listener + * is from sound source. + * @param frontAttenuation defined by pairs of (distance,gain-scale-factor) + * @param backAttenuation defined by pairs of (distance,gain-scale-factor) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDistanceGain(Point2f[] frontAttenuation, + Point2f[] backAttenuation ) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound0")); + + ((ConeSoundRetained)this.retained).setDistanceGain(frontAttenuation, + backAttenuation); + } + + /** + * Sets this sound's distance gain attenuation as an array of Point2fs. + * @param frontDistance array of monotonically-increasing floats + * @param frontGain array of non-negative scale factors + * @param backDistance array of monotonically-increasing floats + * @param backGain array of non-negative scale factors + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDistanceGain(float[] frontDistance, float[] frontGain, + float[] backDistance, float[] backGain) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound0")); + + ((ConeSoundRetained)this.retained).setDistanceGain( + frontDistance, frontGain, backDistance, backGain); + } + + /** + * Sets this sound's back distance gain attenuation - where gain scale + * factor is applied to sound based on distance listener along the negative + * sound direction axis from sound source. + * @param attenuation defined by pairs of (distance,gain-scale-factor) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setBackDistanceGain(Point2f[] attenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound0")); + + ((ConeSoundRetained)this.retained).setBackDistanceGain(attenuation); + } + + /** + * Sets this sound's back distance gain attenuation as separate arrays. + * @param distance array of monotonically-increasing floats + * @param gain array of non-negative scale factors + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setBackDistanceGain(float[] distance, float[] gain) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound0")); + + ((ConeSoundRetained)this.retained).setBackDistanceGain(distance, gain); + } + + /** + * Gets this sound's elliptical distance attenuation. The + * attenuation values are copied into the specified arrays. + * The arrays must be large enough to hold all of the + * forward distances and backward distances attenuation values. + * The individual array elements must be allocated by the + * caller. The Point2f x,y values are defined as follows: + * x is the distance, y is the gain. + * @param frontAttenuation arrays containing forward distances + * attenuation pairs + * @param backAttenuation arrays containing backward distances + * attenuation pairs + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDistanceGain(Point2f[] frontAttenuation, + Point2f[] backAttenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound2")); + + ((ConeSoundRetained)this.retained).getDistanceGain( + frontAttenuation, backAttenuation); + } + + /** + * Gets this sound's elliptical distance gain attenuation values in + * separate arrays. The arrays must be large enough to hold all + * of the values. + * @param frontDistance array of float distances along the sound axis + * @param frontGain array of non-negative scale factors associated with + * front distances + * @param backDistance array of float negative distances along the sound + * axis + * @param backGain array of non-negative scale factors associated with + * back distances + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDistanceGain(float[] frontDistance, float[] frontGain, + float[] backDistance, float[] backGain) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound10")); + + ((ConeSoundRetained)this.retained).getDistanceGain( + frontDistance, frontGain, backDistance, backGain); + } + + /** + * Sets this sound's direction from the vector provided. + * @param direction the new direction + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDirection(Vector3f direction) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound3")); + + ((ConeSoundRetained)this.retained).setDirection(direction); + } + + /** + * Sets this sound's direction from the three values provided. + * @param x the new x direction + * @param y the new y direction + * @param z the new z direction + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDirection(float x, float y, float z) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound3")); + + ((ConeSoundRetained)this.retained).setDirection(x,y,z); + } + + /** + * Retrieves this sound's direction and places it in the + * vector provided. + * @param direction axis of cones; 'direction' of sound + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDirection(Vector3f direction) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound5")); + + ((ConeSoundRetained)this.retained).getDirection(direction); + } + + /** + * Sets this sound's angular gain attenuation (not including filter). + * In this form of setAngularAttenuation, only the angular distances + * and angular gain scale factors pairs are given. The filter values for + * these tuples are implicitly set to Sound.NO_FILTER. + * @param attenuation array containing angular distance and gain + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAngularAttenuation(Point2f[] attenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANGULAR_ATTENUATION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound6")); + + ((ConeSoundRetained)this.retained).setAngularAttenuation(attenuation); + } + + /** + * In the second form of setAngularAttenuation, an array of all three values + * is supplied. + * @param attenuation array containing angular distance, gain, and filter + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAngularAttenuation(Point3f[] attenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANGULAR_ATTENUATION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound6")); + + ((ConeSoundRetained)this.retained).setAngularAttenuation(attenuation); + } + + /** + * Sets angular attenuation including gain and filter using separate arrays. + * The third form of setAngularAttenuation accepts three separate arrays for + * these angular attenuation values. These arrays should be of the same + * length. If the angularGain or filtering array length is greater than + * angularDistance array length, the array elements beyond the length of + * the angularDistance array are ignored. If the angularGain or filtering + * array is shorter than the angularDistance array, the last value of the + * short array is repeated to fill an array of length equal to + * angularDistance array. + * @param distance array containing angular distance + * @param gain array containing angular gain attenuation + * @param filter array containing angular low-pass frequency cutoff values + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAngularAttenuation(float[] distance, float[] gain, + float[] filter) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANGULAR_ATTENUATION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound6")); + + ((ConeSoundRetained)this.retained).setAngularAttenuation(distance, + gain, filter); + } + + /** + * Retrieves angular attenuation array length. + * All arrays are forced to same size. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getAngularAttenuationLength() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANGULAR_ATTENUATION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound9")); + + return (((ConeSoundRetained)this.retained).getAngularAttenuationLength()); + } + + /** + * Copies the array of attenuation values from this sound, including + * gain and filter, into the specified array. The array must be + * large enough to hold all of the points. The individual array + * elements must be allocated by the caller. The Point3f x,y,z values + * are defined as follows: x is the angular distance, y is + * the angular gain attenuation, and z is the frequency + * cutoff. + * @param attenuation the array to receive the attenuation values + * applied to gain when listener is between cones + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getAngularAttenuation(Point3f[] attenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANGULAR_ATTENUATION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound9")); + + ((ConeSoundRetained)this.retained).getAngularAttenuation(attenuation); + } + + /** + * Copies the array of attenuation values from this sound, + * including gain and filter, into the separate arrays. + * The arrays must be large enough to hold all of the values. + * @param distance array containing angular distance + * @param gain array containing angular gain attenuation + * @param filter array containing angular low-pass frequency cutoff values + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getAngularAttenuation(float[] distance, float[] gain, + float[] filter) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANGULAR_ATTENUATION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ConeSound9")); + + ((ConeSoundRetained)this.retained).getAngularAttenuation(distance, + gain, filter); + } + + /** + * Creates a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + ConeSound c = new ConeSound(); + c.duplicateNode(this, forceDuplicate); + return c; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @exception ClassCastException if originalNode is not an instance of + * ConeSound + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + checkDuplicateNode(originalNode, forceDuplicate); + } + + + /** + * Copies all ConeSound information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + ConeSoundRetained orgRetained = (ConeSoundRetained)originalNode.retained; + ConeSoundRetained thisRetained = (ConeSoundRetained)this.retained; + + // front distance gain & attenuation is set in super + // set back distance gain only + int len = orgRetained.getDistanceGainLength(); + float distance[] = new float[len]; + float gain[] = new float[len]; + orgRetained.getDistanceGain(null, null,distance, gain); + thisRetained.setBackDistanceGain(distance, gain); + + Vector3f v = new Vector3f(); + orgRetained.getDirection(v); + thisRetained.setDirection(v); + + len = orgRetained.getAngularAttenuationLength(); + distance = gain = null; + float angle[] = new float[len]; + float angularGain[] = new float[len]; + float frequencyCutoff[] = new float[len]; + + orgRetained.getAngularAttenuation(angle, angularGain, + frequencyCutoff); + + thisRetained.setAngularAttenuation(angle, angularGain, frequencyCutoff); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ConeSoundRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ConeSoundRetained.java new file mode 100644 index 0000000..040a352 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ConeSoundRetained.java @@ -0,0 +1,660 @@ +/* + * $RCSfile: ConeSoundRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Vector3f; +import javax.vecmath.Vector3d; +import javax.vecmath.Point2f; +import javax.vecmath.Point3f; + + + +/** + * A ConeSoundRetained node defines a point sound source located at some + * location + * in space whose amplitude is constrained not only by maximum and minimum + * amplitude + * spheres but by two concentric cone volumes directed down an vector radiating + * from the sound's location. + */ + +class ConeSoundRetained extends PointSoundRetained { + /** + * The Cone Sound's direction vector. This is the cone axis. + */ + Vector3f direction = new Vector3f(0.0f, 0.0f, 1.0f); + + // The transformed direction of this sound + Vector3f xformDirection = new Vector3f(0.0f, 0.0f, 1.0f); + + // Sound's gain is attenuated for listener locations off-angle from + // the source source direction. + // This can be set of three numbers: + // angular distance in radians + // gain scale factor + // filtering (currently the only filtering supported is lowpass) + + // For now the only supported filterType will be LOW_PASS frequency cutoff. + // At some time full FIR filtering will be supported. + static final int NO_FILTERING = -1; + static final int LOW_PASS = 1; + + // Pairs of distances and gain scale factors that define piecewise linear + // gain BACK attenuation between each pair. + // These are used for defining elliptical attenuation regions. + float[] backAttenuationDistance = null; + float[] backAttenuationGain = null; + + float[] angularDistance = {0.0f, ((float)(Math.PI) * 0.5f)}; + float[] angularGain = {1.0f, 0.0f}; + int filterType = NO_FILTERING; + float[] frequencyCutoff = {Sound.NO_FILTER, Sound.NO_FILTER}; + + ConeSoundRetained() { + this.nodeType = NodeRetained.CONESOUND; + } + + // ********************* + // + // Distance Gain methods + // + // ********************* + + /** + * Sets this sound's distance gain elliptical attenuation - + * where gain scale factor is applied to sound based on distance listener + * is from sound source. + * @param frontAttenuation defined by pairs of (distance,gain-scale-factor) + * @param backAttenuation defined by pairs of (distance,gain-scale-factor) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + void setDistanceGain(Point2f[] frontAttenuation, + Point2f[] backAttenuation ) { + + this.setDistanceGain(frontAttenuation); + this.setBackDistanceGain(backAttenuation); + } + + /** + * Sets this sound's distance gain attenuation as an array of Point2fs. + * @param frontDistance array of monotonically-increasing floats + * @param frontGain array of non-negative scale factors + * @param backDistance array of monotonically-increasing floats + * @param backGain array of non-negative scale factors + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + void setDistanceGain(float[] frontDistance, float[] frontGain, + float[] backDistance, float[] backGain) { + this.setDistanceGain(frontDistance, frontGain); + this.setBackDistanceGain(backDistance, backGain); + } + + /** + * Sets this sound's back distance gain attenuation - where gain scale + * factor is applied to sound based on distance listener along the negative + * sound direction axis from sound source. + * @param attenuation defined by pairs of (distance,gain-scale-factor) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + void setBackDistanceGain(Point2f[] attenuation) + { + // if attenuation array null set both attenuation components to null + if (attenuation == null) { + this.backAttenuationDistance = null; + this.backAttenuationGain = null; + } + else { + int attenuationLength = attenuation.length; + if (attenuationLength == 0) { + this.backAttenuationDistance = null; + this.backAttenuationGain = null; + } + else { + this.backAttenuationDistance = new float[attenuationLength]; + this.backAttenuationGain = new float[attenuationLength]; + for (int i = 0; i < attenuationLength; i++) { + this.backAttenuationDistance[i] = attenuation[i].x; + this.backAttenuationGain[i] = attenuation[i].y; + } + } + } + dispatchAttribChange(BACK_DISTANCE_GAIN_DIRTY_BIT, attenuation); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Sets this sound's back distance gain attenuation as an array of Point2fs. + * @param distance array of monotonically-increasing floats + * @param gain array of non-negative scale factors + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + void setBackDistanceGain(float[] distance, float[] gain) + { + int distanceLength = 0; + // if distance or gain arrays are null then treat both as null + if (distance == null || gain == null) { + this.backAttenuationDistance = null; + this.backAttenuationGain = null; + } + else { + // now process the back attenuation values + int gainLength = gain.length; + distanceLength = distance.length; + if (distanceLength == 0 || gainLength == 0) { + this.backAttenuationDistance = null; + this.backAttenuationGain = null; + } + else { + this.backAttenuationDistance = new float[distanceLength]; + this.backAttenuationGain = new float[distanceLength]; + // Copy the distance array into nodes field + System.arraycopy(distance, 0, this.backAttenuationDistance, + 0, distanceLength); + // Copy the gain array an array of same length as the distance array + if (distanceLength <= gainLength) { + System.arraycopy(gain, 0, this.backAttenuationGain, + 0, distanceLength); + } + else { + System.arraycopy(gain, 0, this.backAttenuationGain, 0, gainLength); + // Extend gain array to length of distance array + // replicate last gain values. + for (int i=gainLength; i< distanceLength; i++) { + this.backAttenuationGain[i] = gain[gainLength - 1]; + } + } + } + } + + Point2f [] attenuation = new Point2f[distanceLength]; + for (int i=0; i distanceLength) + attenuationLength = distanceLength; + System.arraycopy(this.backAttenuationDistance, 0, distance, 0, attenuationLength); + attenuationLength = this.backAttenuationGain.length; + int gainLength = gain.length; + if (attenuationLength > gainLength) + attenuationLength = gainLength; + System.arraycopy(this.backAttenuationGain, 0, gain, 0, attenuationLength); + } + + + // ********************* + // + // Direction Methods + // + // ********************* + + /** + * Sets this sound's direction from the vector provided. + * @param direction the new direction + */ + void setDirection(Vector3f direction) { + if (staticTransform != null) { + staticTransform.transform.transform(direction, this.direction); + } else { + this.direction.set(direction); + } + dispatchAttribChange(DIRECTION_DIRTY_BIT, + (new Vector3f(this.direction))); + + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Sets this sound's direction from the three values provided. + * @param x the new x direction + * @param y the new y direction + * @param z the new z direction + */ + void setDirection(float x, float y, float z) { + direction.x = x; + direction.y = y; + direction.z = z; + if (staticTransform != null) { + staticTransform.transform.transform(direction); + } + dispatchAttribChange(DIRECTION_DIRTY_BIT, (new Vector3f(direction))); + + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + + /** + * Retrieves this sound's direction and places it in the + * vector provided. + * @return direction vector (axis of cones) + */ + void getDirection(Vector3f direction) + { + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + invTransform.transform(this.direction, direction); + } else { + direction.set(this.direction); + } + } + + void getXformDirection(Vector3f direction) + { + direction.set(this.xformDirection); + } + + + // *************************** + // + // Angular Attenuation + // + // *************************** + + /** + * Sets this sound's angular gain attenuation (not including filter) + * @param attenuation array containing angular distance and gain + */ + void setAngularAttenuation(Point2f[] attenuation) { + int attenuationLength = 0; + this.filterType = NO_FILTERING; + if (attenuation == null) { + this.angularDistance = null; + this.angularGain = null; + } + else { + attenuationLength = attenuation.length; + if (attenuationLength == 0) { + this.angularDistance = null; + this.angularGain = null; + } + else { + this.angularDistance = new float[attenuationLength]; + this.angularGain = new float[attenuationLength]; + for (int i = 0; i < attenuationLength; i++) { + this.angularDistance[i] = attenuation[i].x; + this.angularGain[i] = attenuation[i].y; + } + } // lengths not zero + } // arrays not null + Point3f [] attenuation3f = new Point3f[attenuationLength]; + for (int i=0; icloneTree call an updated reference was requested + * for a node that did not get cloned. This happens when a sub-graph is + * duplicated via cloneTree and has at least one Leaf node + * that contains a reference to a Node that has no corresponding node in + * the cloned sub-graph. This results in two Leaf nodes wanting to share + * access to the same Node. + *

+ * If dangling references are to be allowed during the cloneTree call, + * cloneTree should be called with the + * allowDanglingReferences parameter set to true. + * @see Node#cloneTree + */ +public class DanglingReferenceException extends RuntimeException { + + /** + * Create the exception object with default values. + */ + public DanglingReferenceException() { + } + + /** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public DanglingReferenceException(String str) { + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DecalGroup.java b/j3d-core/src/classes/share/javax/media/j3d/DecalGroup.java new file mode 100644 index 0000000..d5b4595 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DecalGroup.java @@ -0,0 +1,97 @@ +/* + * $RCSfile: DecalGroup.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * The DecalGroup node is an ordered group node used for defining decal + * geometry on top of other geometry. The DecalGroup node specifies that + * its children should be rendered in index order and that they generate + * coplanar objects. Examples of this include: painted decals or text on + * surfaces, a checkerboard layered on top of a table, etc. + *

+ * The first child, at index 0, defines the surface on top of which all + * other children are rendered. The geometry of this child must encompass + * all other children, otherwise incorrect rendering may result. The + * polygons contained within each of the children must be facing the same + * way. If the polygons defined by the first child are front facing, then + * all other surfaces should be front facing. In this case, the polygons + * are rendered in order. The renderer can use knowledge of the coplanar + * nature of the surfaces to avoid + * Z-buffer collisions. If the main surface is back facing then all other + * surfaces should be back facing, and need not be rendered (even if back + * face culling is disabled). + *

+ * Note that using the DecalGroup node does not guarantee that Z-buffer + * collisions are avoided. An implementation of Java 3D may fall back to + * treating DecalGroup node as an OrderedGroup node. + */ +public class DecalGroup extends OrderedGroup { + + /** + * Constructs and initializes a new DecalGroup node object. + */ + public DecalGroup() { + } + + + /** + * Creates the retained mode DecalGroupRetained object that this + * DecalGroup component object will point to. + */ + void createRetained() { + this.retained = new DecalGroupRetained(); + this.retained.setSource(this); + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + DecalGroup dg = new DecalGroup(); + dg.duplicateNode(this, forceDuplicate); + return dg; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DecalGroupRetained.java b/j3d-core/src/classes/share/javax/media/j3d/DecalGroupRetained.java new file mode 100644 index 0000000..c5cc2c4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DecalGroupRetained.java @@ -0,0 +1,39 @@ +/* + * $RCSfile: DecalGroupRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class DecalGroupRetained extends OrderedGroupRetained { + + DecalGroupRetained() { + this.nodeType = NodeRetained.DECALGROUP; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DefaultRenderMethod.java b/j3d-core/src/classes/share/javax/media/j3d/DefaultRenderMethod.java new file mode 100644 index 0000000..f631241 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DefaultRenderMethod.java @@ -0,0 +1,90 @@ +/* + * $RCSfile: DefaultRenderMethod.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The RenderMethod interface is used to create various ways to render + * different geometries. + */ + +class DefaultRenderMethod implements RenderMethod { + + boolean geometryIsLocked = false; + + /** + * The actual rendering code for this RenderMethod + */ + public boolean render(RenderMolecule rm, Canvas3D cv, + RenderAtomListInfo ra, int dirtyBits) { + + boolean isVisible = false; // True if any of the RAs is visible. + + while (ra != null) { + if (cv.ra == ra.renderAtom) { + if (cv.raIsVisible) { + cv.updateState(dirtyBits); + ra.geometry().execute(cv, ra.renderAtom, + rm.isNonUniformScale, + rm.useAlpha, rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin. + ignoreVertexColors); + isVisible = true; + } + } + else { + if (!VirtualUniverse.mc.viewFrustumCulling || + ra.renderAtom.localeVwcBounds.intersect(cv.viewFrustum)) { + cv.raIsVisible = true; + cv.updateState(dirtyBits); + ra.geometry().execute(cv, ra.renderAtom, rm.isNonUniformScale, + rm.useAlpha, rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin. + ignoreVertexColors); + isVisible = true; + } + else { + cv.raIsVisible = false; + } + cv.ra = ra.renderAtom; + } + ra = ra.next; + } + + return isVisible; + + } + + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DepthComponent.java b/j3d-core/src/classes/share/javax/media/j3d/DepthComponent.java new file mode 100644 index 0000000..df427af --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DepthComponent.java @@ -0,0 +1,94 @@ +/* + * $RCSfile: DepthComponent.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Abstract base class that defines a 2D array of depth (Z) values. + */ + +public abstract class DepthComponent extends NodeComponent { + /** + * Specifies that this DepthComponent object allows reading its + * size component information (width and height). + */ + public static final int + ALLOW_SIZE_READ = CapabilityBits.DEPTH_COMPONENT_ALLOW_SIZE_READ; + + /** + * Specifies that this DepthComponent object allows reading its + * depth data component information. + */ + public static final int + ALLOW_DATA_READ = CapabilityBits.DEPTH_COMPONENT_ALLOW_DATA_READ; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SIZE_READ, + ALLOW_DATA_READ + }; + + /** + * default constructor + */ + DepthComponent() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Retrieves the width of this depth component object. + * @return the width of the array of depth values + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getWidth() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SIZE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("DepthComponent0")); + return ((DepthComponentRetained)this.retained).getWidth(); + } + + /** + * Retrieves the height of this depth component object. + * @return the height of the array of depth values + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getHeight() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SIZE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("DepthComponent0")); + return ((DepthComponentRetained)this.retained).getHeight(); + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DepthComponentFloat.java b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentFloat.java new file mode 100644 index 0000000..e47101f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentFloat.java @@ -0,0 +1,136 @@ +/* + * $RCSfile: DepthComponentFloat.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:20 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A 2D array of depth (Z) values in floating point format in the range [0,1]. + * A value of 0.0 indicates the closest Z value to the user while a value of + * 1.0 indicates the farthest Z value. + */ + +public class DepthComponentFloat extends DepthComponent { + + /** + * Package scope defualt constructor used by cloneNodeComponent + */ + DepthComponentFloat() { + } + + /** + * Constructs a new floating-point depth (z-buffer) component object with + * the specified width and height. + * @param width the width of the array of depth values + * @param height the height of the array of depth values + */ + public DepthComponentFloat(int width, int height) { + ((DepthComponentFloatRetained)this.retained).initialize(width, height); + } + + /** + * Copies the specified depth data to this object. + * @param depthData array of floats containing the depth data + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + public void setDepthData(float[] depthData) { + checkForLiveOrCompiled(); + ((DepthComponentFloatRetained)this.retained).setDepthData(depthData); + } + + /** + * Copies the depth data from this object to the specified array. + * The array must be large enough to hold all of the floats. + * @param depthData array of floats that will receive a copy of + * the depth data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDepthData(float[] depthData) { + if (isLiveOrCompiled()) + if (!this.getCapability(DepthComponent.ALLOW_DATA_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("DepthComponentFloat0")); + ((DepthComponentFloatRetained)this.retained).getDepthData(depthData); + } + + /** + * Creates a retained mode DepthComponentFloatRetained object that this + * DepthComponentFloat component object will point to. + */ + void createRetained() { + this.retained = new DepthComponentFloatRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + DepthComponentFloatRetained rt = (DepthComponentFloatRetained) retained; + DepthComponentFloat d = new DepthComponentFloat(rt.width, + rt.height); + d.duplicateNodeComponent(this); + return d; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, + forceDuplicate); + // width, height is copied in cloneNode before + int len = getWidth()*getHeight(); + float f[] = new float[len]; + + ((DepthComponentFloatRetained) originalNodeComponent.retained).getDepthData(f); + ((DepthComponentFloatRetained) retained).setDepthData(f); + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DepthComponentFloatRetained.java b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentFloatRetained.java new file mode 100644 index 0000000..5afac54 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentFloatRetained.java @@ -0,0 +1,93 @@ +/* + * $RCSfile: DepthComponentFloatRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * A 2D array of depth (Z) values in floating point format in the range [0,1]. + * A value of 0.0 indicates the closest Z value to the user while a value of + * 1.0 indicates the farthest Z value. + */ + +class DepthComponentFloatRetained extends DepthComponentRetained { + float depthData[]; + + /** + * Constructs a new floating-point depth (z-buffer) component object with + * the specified width and height. + * @param width the width of the array of depth values + * @param height the height of the array of depth values + */ + void initialize(int width, int height) { + type = DEPTH_COMPONENT_TYPE_FLOAT; + depthData = new float[width * height]; + this.width = width; + this.height = height; + } + + /** + * Copies the specified depth data to this object. + * @param depthData array of floats containing the depth data + */ + void setDepthData(float[] depthData) { + int i; + for (i = 0; i < depthData.length; i++) + this.depthData[i] = depthData[i]; + } + + + /** + * Copies the depth data from this object to the specified array. + * @param depthData array of floats that will receive a copy of + * the depth data + */ + void getDepthData(float[] depthData) { + int i; + for (i = 0; i < this.depthData.length; i++) + depthData[i] = this.depthData[i]; + } + + /* + * retrieve depth data from input buffer + */ + final void retrieveDepth(float[] buf, int wRead, int hRead) { + int srcOffset, dstOffset, i; + + // Yup -> Ydown + for (srcOffset = (hRead - 1) * wRead, dstOffset = 0, + i = 0; i < hRead; i++, + srcOffset -= wRead, dstOffset += width) { + + System.arraycopy(buf, srcOffset, depthData, dstOffset, wRead); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DepthComponentInt.java b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentInt.java new file mode 100644 index 0000000..63c0338 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentInt.java @@ -0,0 +1,134 @@ +/* + * $RCSfile: DepthComponentInt.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A 2D array of depth (Z) values in integer format. Values are in the + * range [0,(2**N)-1], where N is the pixel depth of the Z buffer. + */ + +public class DepthComponentInt extends DepthComponent { + + /** + * Package scope default constructor + */ + DepthComponentInt() { + } + + /** + * Constructs a new integer depth (z-buffer) component object with the + * specified width and height. + * @param width the width of the array of depth values + * @param height the height of the array of depth values + */ + public DepthComponentInt(int width, int height) { + ((DepthComponentIntRetained)this.retained).initialize(width, height); + } + + /** + * Copies the specified depth data to this object. + * @param depthData array of ints containing the depth data + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + public void setDepthData(int[] depthData) { + checkForLiveOrCompiled(); + ((DepthComponentIntRetained)this.retained).setDepthData(depthData); + } + + /** + * Copies the depth data from this object to the specified array. + * The array must be large enough to hold all of the ints. + * @param depthData array of ints that will receive a copy of + * the depth data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDepthData(int[] depthData) { + if (isLiveOrCompiled()) + if (!this.getCapability(DepthComponent.ALLOW_DATA_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("DepthComponentInt0")); + ((DepthComponentIntRetained)this.retained).getDepthData(depthData); + } + + /** + * Creates a retained mode DepthComponentIntRetained object that this + * DepthComponentInt component object will point to. + */ + void createRetained() { + this.retained = new DepthComponentIntRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + DepthComponentIntRetained rt = (DepthComponentIntRetained) retained; + DepthComponentInt d = new DepthComponentInt(rt.width, + rt.height); + d.duplicateNodeComponent(this); + return d; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + // width, height is copied in cloneNode before + int len = getWidth()*getHeight(); + int d[] = new int[len]; + ((DepthComponentIntRetained) originalNodeComponent.retained).getDepthData(d); + ((DepthComponentIntRetained) retained).setDepthData(d); + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DepthComponentIntRetained.java b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentIntRetained.java new file mode 100644 index 0000000..1828e3d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentIntRetained.java @@ -0,0 +1,93 @@ +/* + * $RCSfile: DepthComponentIntRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * A 2D array of depth (Z) values in integer format. Values are in the + * range [0,(2**N)-1], where N is the pixel depth of the Z buffer. + */ + +class DepthComponentIntRetained extends DepthComponentRetained { + int depthData[]; + + /** + * Constructs a new integer depth (z-buffer) component object with the + * specified width and height. + * @param width the width of the array of depth values + * @param height the height of the array of depth values + */ + void initialize(int width, int height) { + type = DEPTH_COMPONENT_TYPE_INT; + depthData = new int[width * height]; + this.width = width; + this.height = height; + } + + /** + * Copies the specified depth data to this object. + * @param depthData array of ints containing the depth data + */ + void setDepthData(int[] depthData) { + int i; + for (i = 0; i < depthData.length; i++) + this.depthData[i] = depthData[i]; + } + + + /** + * Copies the depth data from this object to the specified array. + * @param depthData array of ints that will receive a copy of + * the depth data + */ + void getDepthData(int[] depthData) { + int i; + + for (i = 0; i < this.depthData.length; i++) + depthData[i] = this.depthData[i]; + } + + /** + * retrieve depth data from input buffer + */ + final void retrieveDepth(int[] buf, int wRead, int hRead) { + int srcOffset, dstOffset, i; + + // Yup -> Ydown + for (srcOffset = (hRead - 1) * wRead, dstOffset = 0, + i = 0; i < hRead; i++, + srcOffset -= wRead, dstOffset += width) { + + System.arraycopy(buf, srcOffset, depthData, dstOffset, wRead); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DepthComponentNative.java b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentNative.java new file mode 100644 index 0000000..714fb0e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentNative.java @@ -0,0 +1,126 @@ +/* + * $RCSfile: DepthComponentNative.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A 2D array of depth (Z) values stored in the most efficient format for a + * particular device. Values are not accessible by the user and may only be + * used to read the Z values and subsequently write them back. + */ + +public class DepthComponentNative extends DepthComponent { + /** + * Package scope defualt constructor for use by cloneNodeComponent + */ + DepthComponentNative() { + } + + /** + * Constructs a new native depth (z-buffer) component object with the + * specified width and height. + * @param width the width of the array of depth values + * @param height the height of the array of depth values + */ + public DepthComponentNative(int width, int height) { + ((DepthComponentNativeRetained)this.retained).initialize(width, height); + } + + /** + * Copies the depth data from this object to the specified array. + * @param depthData array of ints that will receive a copy of + * the depth data + */ + void getDepthData(int[] depthData) { + ((DepthComponentNativeRetained)this.retained).getDepthData(depthData); + } + + /** + * Creates a retained mode DepthComponentIntRetained object that this + * DepthComponentInt component object will point to. + */ + void createRetained() { + this.retained = new DepthComponentNativeRetained(); + this.retained.setSource(this); + } + + /** + * Creates a new DepthComponentNative object. Called from a Leaf node's + * duplicateNode method. + * + * @return a duplicate of the DepthComponentNative object. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + public NodeComponent cloneNodeComponent() { + DepthComponentNativeRetained rt = (DepthComponentNativeRetained) retained; + DepthComponentNative d = new DepthComponentNative(rt.width, + rt.height); + d.duplicateNodeComponent(this); + return d; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + int originalData[] = ((DepthComponentNativeRetained) + originalNodeComponent.retained).depthData; + + int currentData[] = ((DepthComponentNativeRetained) retained).depthData; + + if (originalData != null) { + for (int i=0; i < originalData.length; i++) + currentData[i] = originalData[i]; + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DepthComponentNativeRetained.java b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentNativeRetained.java new file mode 100644 index 0000000..4cbaec6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentNativeRetained.java @@ -0,0 +1,82 @@ +/* + * $RCSfile: DepthComponentNativeRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A 2D array of depth (Z) values stored in the most efficient format for a + * particular device. Values are not accessible by the user and may only be + * used to read the Z values and subsequently write them back. + */ + +class DepthComponentNativeRetained extends DepthComponentRetained { + // Change this to whatever native format is best... + int depthData[]; + + /** + * Constructs a new native depth (z-buffer) component object with the + * specified width and height. + * @param width the width of the array of depth values + * @param height the height of the array of depth values + */ + void initialize(int width, int height) { + type = DEPTH_COMPONENT_TYPE_NATIVE; + depthData = new int[width * height]; + this.width = width; + this.height = height; + } + + /** + * Copies the depth data from this object to the specified array. + * @param depthData array of ints that will receive a copy of + * the depth data + */ + void getDepthData(int[] depthData) { + int i; + for (i = 0; i < this.depthData.length; i++) + depthData[i] = this.depthData[i]; + } + + /** + * retrieve depth data from input buffer + */ + final void retrieveDepth(int[] buf, int wRead, int hRead) { + int srcOffset, dstOffset, i; + + // Yup -> Ydown + for (srcOffset = (hRead - 1) * wRead, dstOffset = 0, + i = 0; i < hRead; i++, + srcOffset -= wRead, dstOffset += width) { + + System.arraycopy(buf, srcOffset, depthData, dstOffset, wRead); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DepthComponentRetained.java b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentRetained.java new file mode 100644 index 0000000..1e9c008 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DepthComponentRetained.java @@ -0,0 +1,67 @@ +/* + * $RCSfile: DepthComponentRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Abstract base class that defines a 2D array of depth (Z) values. + */ + + +abstract class DepthComponentRetained extends NodeComponentRetained { + // depth component types + static final int DEPTH_COMPONENT_TYPE_INT = 1; + static final int DEPTH_COMPONENT_TYPE_FLOAT = 2; + static final int DEPTH_COMPONENT_TYPE_NATIVE = DEPTH_COMPONENT_TYPE_INT; + + + // Width and height of DepthComponent---set by subclasses + int width; + int height; + int type; + + /** + * Retrieves the width of this depth component object + * @return the width of the array of depth values + */ + int getWidth() { + return width; + } + + /** + * Retrieves the height of this depth component object + * @return the height of the array of depth values + */ + int getHeight() { + return height; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DirectionalLight.java b/j3d-core/src/classes/share/javax/media/j3d/DirectionalLight.java new file mode 100644 index 0000000..47def94 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DirectionalLight.java @@ -0,0 +1,222 @@ +/* + * $RCSfile: DirectionalLight.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; +import javax.vecmath.Vector3f; + +/** + * A DirectionalLight node defines an oriented light with an origin at + * infinity. It has the same attributes as a Light node, with the + * addition of a directional vector to specify the direction in which the + * light shines. A directional light has parallel light rays that travel + * in one direction along the specified vector. Directional light contributes + * to diffuse and specular reflections, which in turn depend on the + * orientation of an object's surface but not its position. A directional + * light does not contribute to ambient reflections. + */ + +public class DirectionalLight extends Light { + /** + * Specifies that the Node allows access to its object's direction + * information. + */ + public static final int + ALLOW_DIRECTION_READ = CapabilityBits.DIRECTIONAL_LIGHT_ALLOW_DIRECTION_READ; + + /** + * Specifies that the Node allows writing to its object's direction + * information. + */ + public static final int + ALLOW_DIRECTION_WRITE = CapabilityBits.DIRECTIONAL_LIGHT_ALLOW_DIRECTION_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_DIRECTION_READ + }; + + /** + * Constructs a DirectionalLight node with default parameters. + * The default values are as follows: + *

    + * direction : (0,0,-1)
    + *
+ */ + public DirectionalLight() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a directional light. + * @param color the color of the light source + * @param direction the direction vector pointing from the light + * to the object + */ + public DirectionalLight(Color3f color, Vector3f direction) { + super(color); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((DirectionalLightRetained)this.retained).initDirection(direction); + } + + /** + * Constructs and initializes a directional light. + * @param lightOn flag indicating whether this light is on or off + * @param color the color of the light source + * @param direction the direction vector pointing from the light + * to the object + */ + public DirectionalLight(boolean lightOn, Color3f color, Vector3f direction) { + super(lightOn, color); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((DirectionalLightRetained)this.retained).initDirection(direction); + } + + /** + * Creates the retained mode DirectionalLightRetained object that this + * DirectionalLight component object will point to. + */ + void createRetained() { + this.retained = new DirectionalLightRetained(); + this.retained.setSource(this); + } + + /** + * Set light direction. + * @param direction the new direction + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDirection(Vector3f direction) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_WRITE)) + throw new CapabilityNotSetException( + J3dI18N.getString("DirectionalLight0")); + + if (isLive()) + ((DirectionalLightRetained)this.retained).setDirection(direction); + else + ((DirectionalLightRetained)this.retained).initDirection(direction); + } + + /** + * Set light direction. + * @param x the new X direction + * @param y the new Y direction + * @param z the new Z direction + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDirection(float x, float y, float z) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_WRITE)) + throw new CapabilityNotSetException( + J3dI18N.getString("DirectionalLight1")); + + if (isLive()) + ((DirectionalLightRetained)this.retained).setDirection(x,y,z); + else + ((DirectionalLightRetained)this.retained).initDirection(x,y,z); + } + + /** + * Gets this Light's current direction and places it in the parameter specified. + * @param direction the vector that will receive this node's direction + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDirection(Vector3f direction) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_READ)) + throw new CapabilityNotSetException( + J3dI18N.getString("DirectionalLight2")); + + ((DirectionalLightRetained)this.retained).getDirection(direction); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + DirectionalLight d = new DirectionalLight(); + d.duplicateNode(this, forceDuplicate); + return d; + } + + + /** + * Copies all DirectionalLight information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + Vector3f v = new Vector3f(); + ((DirectionalLightRetained) originalNode.retained).getDirection(v); + ((DirectionalLightRetained) retained).initDirection(v); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DirectionalLightRetained.java b/j3d-core/src/classes/share/javax/media/j3d/DirectionalLightRetained.java new file mode 100644 index 0000000..57274b0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DirectionalLightRetained.java @@ -0,0 +1,220 @@ +/* + * $RCSfile: DirectionalLightRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * An infinite directional light source object. + */ + +class DirectionalLightRetained extends LightRetained +{ + static final int DIRECTION_CHANGED = LAST_DEFINED_BIT << 1; + + // The direction in which this light source is pointing. + Vector3f direction = new Vector3f(0.0f, 0.0f, -1.0f); + + // The transformed direction + Vector3f xformDirection = new Vector3f(0.0f, 0.0f, -1.0f); + + DirectionalLightRetained() { + this.nodeType = NodeRetained.DIRECTIONALLIGHT; + lightType = 2; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + /** + * Initializes this light's direction from the vector provided. + * @param direction the new direction + */ + void initDirection(Vector3f direction) { + this.direction.set(direction); + if (staticTransform != null) { + staticTransform.transform.transform( + this.direction, this.direction); + } + } + + /** + * Sets this light's direction from the vector provided. + * and sends a message + * @param direction the new direction + */ + void setDirection(Vector3f direction) { + initDirection(direction); + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.type = J3dMessage.LIGHT_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(DIRECTION_CHANGED); + if (inSharedGroup) + createMessage.args[2] = new Integer(numMirrorLights); + else + createMessage.args[2] = new Integer(1); + createMessage.args[3] = mirrorLights.clone(); + createMessage.args[4] = new Vector3f(direction); + VirtualUniverse.mc.processMessage(createMessage); + + } + + + /** + * Initializes this light's direction from the three values provided. + * @param x the new x direction + * @param y the new y direction + * @param z the new z direction + */ + void initDirection(float x, float y, float z) { + this.direction.x = x; + this.direction.y = y; + this.direction.z = z; + + if (staticTransform != null) { + staticTransform.transform.transform( + this.direction, this.direction); + } + } + + /** + * Sets this light's direction from the three values provided. + * @param x the new x direction + * @param y the new y direction + * @param z the new z direction + */ + void setDirection(float x, float y, float z) { + setDirection(new Vector3f(x, y, z)); + } + + + /** + * Retrieves this light's direction and places it in the + * vector provided. + * @param direction the variable to receive the direction vector + */ + void getDirection(Vector3f direction) { + direction.set(this.direction); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + invTransform.transform(direction, direction); + } + } + + + + void setLive(SetLiveState s) { + super.setLive(s); + J3dMessage createMessage = super.initMessage(8); + Object[] objs = (Object[])createMessage.args[4]; + objs[7] = new Vector3f(direction); + VirtualUniverse.mc.processMessage(createMessage); + + } + + /** + * This update function, and its native counterpart, + * updates a directional light. This includes its + * color and its transformed direction. + */ + // Note : if you add any more fields here , you need to update + // updateLight() in RenderingEnvironmentStructure + void updateMirrorObject(Object[] objs) { + int i; + int component = ((Integer)objs[1]).intValue(); + Transform3D trans; + int numLgts = ((Integer)objs[2]).intValue(); + + LightRetained[] mLgts = (LightRetained[]) objs[3]; + DirectionalLightRetained ml; + if ((component & DIRECTION_CHANGED) != 0) { + + for (i = 0; i < numLgts; i++) { + if (mLgts[i].nodeType == NodeRetained.DIRECTIONALLIGHT) { + ml = (DirectionalLightRetained) mLgts[i]; + ml.direction = (Vector3f)objs[4]; + ml.getLastLocalToVworld().transform(ml.direction, + ml.xformDirection); + ml.xformDirection.normalize(); + } + } + } + + if ((component & INIT_MIRROR) != 0) { + for (i = 0; i < numLgts; i++) { + if (mLgts[i].nodeType == NodeRetained.DIRECTIONALLIGHT) { + ml = (DirectionalLightRetained) mLgts[i]; + ml.direction = (Vector3f)((Object[])objs[4])[7]; + ml.getLastLocalToVworld().transform(ml.direction, + ml.xformDirection); + ml.xformDirection.normalize(); + } + } + } + // call the parent's mirror object update routine + super.updateMirrorObject(objs); + } + + + void update(Context ctx, int lightSlot, double scale) { + Pipeline.getPipeline().updateDirectionalLight(ctx, + lightSlot, color.x, color.y, color.z, + xformDirection.x, xformDirection.y, + xformDirection.z); + } + + // Clones only the retained side, internal use only + protected Object clone() { + DirectionalLightRetained dr = + (DirectionalLightRetained)super.clone(); + dr.direction = new Vector3f(direction); + dr.xformDirection = new Vector3f(0.0f, 0.0f, -1.0f); + return dr; + } + + + // Called on the mirror object + void updateTransformChange() { + super.updateTransformChange(); + + getLastLocalToVworld().transform(direction, xformDirection); + xformDirection.normalize(); + + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + xform.transform.transform(direction, direction); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DisplayListRenderMethod.java b/j3d-core/src/classes/share/javax/media/j3d/DisplayListRenderMethod.java new file mode 100644 index 0000000..6811067 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DisplayListRenderMethod.java @@ -0,0 +1,273 @@ +/* + * $RCSfile: DisplayListRenderMethod.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The RenderMethod interface is used to create various ways to render + * different geometries. + */ + +class DisplayListRenderMethod implements RenderMethod { + + /** + * display list buffer size + */ + final int bufferSize = 128; + + /** + * display list buffer + */ + int[] buffer = new int[bufferSize]; + + /** + * The actual rendering code for this RenderMethod + */ + public boolean render(RenderMolecule rm, Canvas3D cv, + RenderAtomListInfo ra, + int dirtyBits) { + + if (rm.doInfinite || + !VirtualUniverse.mc.viewFrustumCulling || + rm.vwcBounds.intersect(cv.viewFrustum)) { + cv.updateState(dirtyBits); + cv.callDisplayList(cv.ctx, rm.displayListId, + rm.isNonUniformScale); + return true; + } + return false; + } + + public boolean renderSeparateDlists(RenderMolecule rm, + Canvas3D cv, + RenderAtomListInfo r, int dirtyBits) { + + if (rm.doInfinite) { + cv.updateState(dirtyBits); + while (r != null) { + cv.callDisplayList(cv.ctx, + ((GeometryArrayRetained)r.geometry()).dlistId, + rm.isNonUniformScale); + r = r.next; + } + + return true; + } + + boolean isVisible = false; // True if any of the RAs is visible. + while (r != null) { + if (cv.ra == r.renderAtom) { + if (cv.raIsVisible) { + cv.updateState(dirtyBits); + cv.callDisplayList(cv.ctx, + ((GeometryArrayRetained)r.geometry()).dlistId, + rm.isNonUniformScale); + isVisible = true; + } + } + else { + if (r.renderAtom.localeVwcBounds.intersect(cv.viewFrustum)) { + cv.updateState(dirtyBits); + cv.raIsVisible = true; + cv.callDisplayList(cv.ctx, + ((GeometryArrayRetained)r.geometry()).dlistId, + rm.isNonUniformScale); + isVisible = true; + } + else { + cv.raIsVisible = false; + } + cv.ra = r.renderAtom; + } + r = r.next; + } + + return isVisible; + } + + + + public boolean renderSeparateDlistPerRinfo(RenderMolecule rm, + Canvas3D cv, + RenderAtomListInfo r, + int dirtyBits) { + + if (rm.doInfinite) { + cv.updateState(dirtyBits); + while (r != null) { + cv.callDisplayList(cv.ctx,r.renderAtom.dlistIds[r.index], + rm.isNonUniformScale); + r = r.next; + } + return true; + } + boolean isVisible = false; // True if any of the RAs is visible. + while (r != null) { + if (cv.ra == r.renderAtom) { + if (cv.raIsVisible) { + cv.updateState(dirtyBits); + cv.callDisplayList(cv.ctx, r.renderAtom.dlistIds[r.index], + rm.isNonUniformScale); + isVisible = true; + } + } + else { + if (r.renderAtom.localeVwcBounds.intersect(cv.viewFrustum)) { + cv.updateState(dirtyBits); + cv.raIsVisible = true; + cv.callDisplayList(cv.ctx, r.renderAtom.dlistIds[r.index], + rm.isNonUniformScale); + isVisible = true; + } + else { + cv.raIsVisible = false; + } + cv.ra = r.renderAtom; + } + r = r.next; + } + return isVisible; + + } + + + + + void buildDisplayList(RenderMolecule rm, Canvas3D cv) { + RenderAtomListInfo ra; + boolean useAlpha; + GeometryArrayRetained geo; + useAlpha = rm.useAlpha; + Transform3D staticTransform; + Transform3D staticNormalTransform; + + if ((rm.primaryRenderAtomList != null) && + (rm.texCoordSetMapLen <= cv.maxTexCoordSets)) { + + cv.newDisplayList(cv.ctx, rm.displayListId); + + ra = rm.primaryRenderAtomList; + + while (ra != null) { + geo = (GeometryArrayRetained)ra.geometry(); + if (ra.renderAtom.geometryAtom.source.staticTransform == null) { + staticTransform = null; + staticNormalTransform = null; + } else { + staticTransform = + ra.renderAtom.geometryAtom.source.staticTransform.transform; + if ((geo.vertexFormat & GeometryArray.NORMALS) != 0) { + staticNormalTransform = + ra.renderAtom.geometryAtom.source.staticTransform.getNormalTransform(); + } else { + staticNormalTransform = null; + } + } + geo.buildGA(cv, ra.renderAtom, false, + (useAlpha && + ((geo.vertexFormat & GeometryArray.COLOR) != 0)), + rm.alpha, + rm.textureBin.attributeBin.ignoreVertexColors, + staticTransform, + staticNormalTransform); + ra = ra.next; + } + cv.endDisplayList(cv.ctx); + } + } + + void buildIndividualDisplayList(RenderAtomListInfo ra, Canvas3D cv, + Context ctx) { + GeometryArrayRetained geo; + + geo = (GeometryArrayRetained)ra.geometry(); + if ((geo.texCoordSetMap != null) && + (geo.texCoordSetMap.length > cv.maxTexCoordSets)) { + return; + } + + // Note, the dlistId does not change when renderer is building + cv.newDisplayList(ctx, geo.dlistId); + + // No need to lock when it is indexed geometry since we have + // our own copy + // Note individual dlist is only created if alpha is not modifiable + // so, we don't need any renderMolecule specific information + geo.buildGA(cv, ra.renderAtom, false, + false, + 1.0f, + false, + null, null); + cv.endDisplayList(ctx); + } + + void buildDlistPerRinfo(RenderAtomListInfo ra, RenderMolecule rm, Canvas3D cv) { + boolean useAlpha; + GeometryArrayRetained geo; + useAlpha = rm.useAlpha; + Transform3D staticTransform; + Transform3D staticNormalTransform; + int id; + + geo = (GeometryArrayRetained)ra.geometry(); + if ((rm.primaryRenderAtomList != null) && + (rm.texCoordSetMapLen <= cv.maxTexCoordSets)) { + + id = ra.renderAtom.dlistIds[ra.index]; + cv.newDisplayList(cv.ctx, id); + geo = (GeometryArrayRetained)ra.geometry(); + if (ra.renderAtom.geometryAtom.source.staticTransform == null) { + staticTransform = null; + staticNormalTransform = null; + } else { + staticTransform = + ra.renderAtom.geometryAtom.source.staticTransform.transform; + if ((geo.vertexFormat & GeometryArray.NORMALS) != 0) { + staticNormalTransform = + ra.renderAtom.geometryAtom.source.staticTransform.getNormalTransform(); + } else { + staticNormalTransform = null; + } + } + + geo.buildGA(cv, ra.renderAtom, false, + (useAlpha && + ((geo.vertexFormat & GeometryArray.COLOR) != 0)), + rm.alpha, + rm.textureBin.attributeBin.ignoreVertexColors, + staticTransform, + staticNormalTransform); + cv.endDisplayList(cv.ctx); + } + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DistanceLOD.java b/j3d-core/src/classes/share/javax/media/j3d/DistanceLOD.java new file mode 100644 index 0000000..775d7b3 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DistanceLOD.java @@ -0,0 +1,310 @@ +/* + * $RCSfile: DistanceLOD.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Point3f; +import java.util.Enumeration; + +/** + * This class defines a distance-based LOD behavior node that operates on + * a Switch group node to select one of the children of that Switch node + * based on the distance of this LOD node from the viewer. + * An array of n monotonically increasing distance values is + * specified, such that distances[0] is associated with the highest level of + * detail and distances[n-1] is associated with the lowest level of + * detail. Based on the actual distance from the viewer to + * this DistanceLOD node, these n + * distance values [0, n-1] select from among n+1 + * levels of detail [0, n]. If d is the distance from + * the viewer to the LOD node, then the equation for determining + * which level of detail (child of the Switch node) is selected is: + *

+ *

    + * 0, if d <= distances[0] + *
    + * i, if distances[i-1] < d <= distances[i] + *
    + * n, if d > distances[n-1] + *
+ *

+ * Note that both the position and the array of distances are + * specified in the local coordinate system of this node. + */ +public class DistanceLOD extends LOD { + + private double distances[]; + private Point3f position = new Point3f(0.0f, 0.0f, 0.0f); + + // variables for processStimulus + private Point3f center = new Point3f(); + private Point3f viewPosition = new Point3f(); + + /** + * Constructs and initializes a DistanceLOD node with default values. + * Note that the default constructor creates a DistanceLOD object with + * a single distance value set to 0.0 and is, therefore, not useful. + */ + public DistanceLOD() { + distances = new double[1]; + distances[0] = 0.0; + } + + /** + * Constructs and initializes a DistanceLOD node with the specified + * array of distances and a default position of (0,0,0). + * @param distances an array of values representing LOD cutoff distances + */ + public DistanceLOD(float[] distances) { + this.distances = new double[distances.length]; + + for(int i=0;i distances[n-1] + + if( viewDistance <= distances[0] ) { + index = 0; + } else { + for (i=1; i < distances.length; i++) { + if ((viewDistance > distances[i-1]) && + (viewDistance <= distances[i])) { + index = i; + break; + } + } + } + + for(i=nSwitches-1; i>=0; i--) { + Switch sw = getSwitch(i); + // Optimize, this behavior is passive + // Note that we skip the capability check for getWhichChild() + if (((SwitchRetained) sw.retained).getWhichChild() != + index) { + sw.setWhichChild(index); + } + } + // Insert wakeup condition into queue + wakeupOn(wakeupFrame); + + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + DistanceLOD d = new DistanceLOD(); + d.duplicateNode(this, forceDuplicate); + return d; + } + + + /** + * Copies all DistanceLOD information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + DistanceLOD lod = (DistanceLOD) originalNode; + + int numD = lod.numDistances(); + + // No API available to set the size of this array after initialize + this.distances = new double[numD]; + + for (int i = 0; i < numD; i++) + setDistance(i, lod.getDistance(i)); + + Point3f p = new Point3f(); + lod.getPosition(p); + setPosition(p); + } + + void mergeTransform(TransformGroupRetained xform) { + xform.transform.transform(position, position); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Drawable.java b/j3d-core/src/classes/share/javax/media/j3d/Drawable.java new file mode 100644 index 0000000..bb531a9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Drawable.java @@ -0,0 +1,41 @@ +/* + * $RCSfile: Drawable.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Tagging interface for drawable (window) objects. The rendering pipelines + * will define concrete classes that implement this interface. All code that + * uses the tagged objects will be in the pipelines. + */ +interface Drawable { + // No methods or constants defined at this time +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DrawingSurfaceObject.java b/j3d-core/src/classes/share/javax/media/j3d/DrawingSurfaceObject.java new file mode 100644 index 0000000..f7063bc --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DrawingSurfaceObject.java @@ -0,0 +1,61 @@ +/* + * $RCSfile: DrawingSurfaceObject.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The DrawingSurfaceObject class is used to manage native drawing surface + */ + +abstract class DrawingSurfaceObject extends Object { + + Canvas3D canvas; + boolean gotDsiLock = false; + boolean onScreen; + + abstract boolean renderLock(); + abstract void unLock(); + abstract void getDrawingSurfaceObjectInfo(); + abstract void invalidate(); + + DrawingSurfaceObject(Canvas3D cv) { + canvas = cv; + onScreen = !cv.offScreen; + } + + synchronized boolean isLocked() { + return gotDsiLock; + } + + synchronized void contextValidated() { + canvas.validCtx = true; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/DrawingSurfaceObjectAWT.java b/j3d-core/src/classes/share/javax/media/j3d/DrawingSurfaceObjectAWT.java new file mode 100644 index 0000000..ccdb8b9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/DrawingSurfaceObjectAWT.java @@ -0,0 +1,170 @@ +/* + * $RCSfile: DrawingSurfaceObjectAWT.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.Point; + +/** + * The DrawingSurfaceObject class is used to manage native drawing surface + */ + +class DrawingSurfaceObjectAWT extends DrawingSurfaceObject { + + // drawing surface + private long nativeDS = 0; + private long dsi = 0; + + private boolean doLastUnlock = false; + private boolean xineramaDisabled = false; + + private long display = 0; + private int screenID = 0; + + private static long nativeAWT = 0; + + private native boolean lockAWT(long ds); + private native void unlockAWT(long ds); + private static native void lockGlobal(long awt); + private static native void unlockGlobal(long awt); + private native long getDrawingSurfaceAWT(Canvas3D cv, long awt); + private native long getDrawingSurfaceInfo(long ds); + private static native void freeResource(long awt, long ds, long dsi); + + // TODO: long window + private native int getDrawingSurfaceWindowIdAWT(Canvas3D cv, long ds, long dsi, + long display, int screenID, + boolean xineramaDisabled); + + DrawingSurfaceObjectAWT(Canvas3D cv, long awt, + long display, int screenID, + boolean xineramaDisabled) { + super(cv); + nativeAWT = awt; + + this.display = display; + this.screenID = screenID; + this.xineramaDisabled = xineramaDisabled; + } + + synchronized boolean renderLock() { + + if (onScreen) { + if (nativeDS == 0) { + return false; + } else { + if (lockAWT(nativeDS)) { + gotDsiLock = true; + return true; + } else { + return false; + } + } + } else { + gotDsiLock = true; + lockGlobal(nativeAWT); + } + return true; + } + + synchronized void unLock() { + + if (gotDsiLock) { + if (onScreen) { + if (nativeDS != 0) { + unlockAWT(nativeDS); + gotDsiLock = false; + if (doLastUnlock) { + nativeDS = 0; + dsi = 0; + doLastUnlock = false; + } + } + } else { + unlockGlobal(nativeAWT); + gotDsiLock = false; + } + } + } + + + synchronized void getDrawingSurfaceObjectInfo() { + // Free old DS and DSI + if (nativeDS != 0 && dsi != 0) { + freeResource(nativeAWT, nativeDS, dsi); + nativeDS = 0; + dsi = 0; + } + + // get native drawing surface - ds + nativeDS = getDrawingSurfaceAWT(canvas, nativeAWT); + + // get window id + if (nativeDS != 0) { + dsi = getDrawingSurfaceInfo(nativeDS); + if (dsi != 0) { + long nativeDrawable = getDrawingSurfaceWindowIdAWT + (canvas, nativeDS, dsi, display, screenID, + xineramaDisabled); + canvas.drawable = new NativeDrawable(nativeDrawable); + } + } + } + + + synchronized void invalidate() { + if (gotDsiLock && (nativeDS != 0)) { + // Should not call unlock in AWT thread + // Otherwise IllegalMonitorException will throw + // unlockAWT(nativeDS); + // We don't reset nativeDS & dsi to 0 here. + // This allow Renderer to continue unLock. + doLastUnlock = true; + } else { + nativeDS = 0; + dsi = 0; + } + } + + static void freeDrawingSurface(Object obj) { + long p[] = (long[]) obj; + freeResource(nativeAWT, p[0], p[1]); + } + + long getDSI() { + return dsi; + } + + long getDS() { + return nativeDS; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/EnvironmentSet.java b/j3d-core/src/classes/share/javax/media/j3d/EnvironmentSet.java new file mode 100644 index 0000000..1bcbc36 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/EnvironmentSet.java @@ -0,0 +1,557 @@ +/* + * $RCSfile: EnvironmentSet.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.*; + +/** + * The LightBin manages a collection of EnvironmentSet objects. + * The number of objects managed depends upon the number of Lights + * in each EnvironmentSet and the number of lights supported by + * the underlying rendering layer. + */ + +class EnvironmentSet extends Object implements ObjectUpdate{ + // A list of pre-defined bits to indicate which component + // of the rendermolecule changed + static final int LIGHTENABLE_CHANGED = 0x01; + static final int AMBIENT_CHANGED = 0x02; + static final int FOG_CHANGED = 0x04; + static final int MODELCLIP_CHANGED = 0x08; + + /** + * The ArrayList of Lights in this EnvironmentSet + */ + ArrayList lights = new ArrayList(); + + /** + * The position of the light in the lightbin that the + * lights in this environment set corresponds to + */ + int[] ltPos = null; + + + /** + * The arraylist of ambient lights in this env list + */ + ArrayList ambLights = new ArrayList(); + + /** + * The LightBin that this EnvironmentSet resides + */ + LightBin lightBin = null; + + /** + * The bitmask of light slots that need to be enabled for this + */ + long enableMask = 0; + + /** + * The cached scene ambient component for this EnvirionmentSet + */ + Color3f sceneAmbient = new Color3f(); + + /** + * The RenderBin for this EnvirionmentSet + */ + RenderBin renderBin = null; + + /** + * The fog for this EnvironmentSet + */ + FogRetained fog = null; + + + /** + * The model clip for this EnvironmentSet + */ + ModelClipRetained modelClip = null; + + /** + * enable mask for the model clip planes in this environment set + */ + int enableMCMask = 0; // enable mask used in modelClip.update() + int enableMCMaskCache = 0; // enable mask computed in renderBin that + // is copied into enableMCMask in updateObject + + /** + * The references to the next and previous LightBins in the + * list. + */ + EnvironmentSet next = null; + EnvironmentSet prev = null; + + /** + * List of attrributeBins to be added next Frame + */ + ArrayList addAttributeBins = new ArrayList(); + + + /** + * Canvas Dirty Mask for + */ + int canvasDirty = 0; + + /** + * cached value of enable mask + */ + long enableMaskCache = 0; + + /** + * + */ + boolean onUpdateList = false; + + /** + * The list of AttributeBins in this EnvironmentSet + */ + AttributeBin attributeBinList = null; + + EnvironmentSet(RenderAtom ra, LightRetained[] lightList, FogRetained fog, + ModelClipRetained modelClip, RenderBin rb) { + renderBin = rb; + reset(ra, lightList, fog, modelClip); + } + + private void reset(RenderAtom ra, LightRetained[] lightList, FogRetained fog, + ModelClipRetained modelClip) { + int i; + LightRetained light; + + prev = null; + next = null; + onUpdateList = false; + attributeBinList = null; + lights.clear(); + ambLights.clear(); + sceneAmbient.x = 0.0f; + sceneAmbient.y = 0.0f; + sceneAmbient.z = 0.0f; + if (lightList != null) { + for (i=0; i 1.0f) { + sceneAmbient.x = 1.0f; + } + if (sceneAmbient.y > 1.0f) { + sceneAmbient.y = 1.0f; + } + if (sceneAmbient.z > 1.0f) { + sceneAmbient.z = 1.0f; + } + } + + this.fog = fog; + + this.modelClip = modelClip; + enableMCMaskCache = 0; + if (modelClip != null) { + for (i = 0; i < 6; i++) { + if (modelClip.enables[i]) + enableMCMaskCache |= 1 << i; + } + enableMCMask = enableMCMaskCache; + } + + // Allocate the ltPos array + ltPos = new int[lights.size()]; + enableMask = 0; + + // Issue 466 : add the env set to the light, fog, and model clip + // lists only after the newly constructed env set is initialized + if (lightList != null) { + for (i=0; i 0) { + a = (AttributeBin)addAttributeBins.get(0); + if (attributeBinList == null) { + attributeBinList = a; + + } + else { + a.next = attributeBinList; + attributeBinList.prev = a; + attributeBinList = a; + } + for (i = 1; i < addAttributeBins.size() ; i++) { + a = (AttributeBin) addAttributeBins.get(i); + a.next = attributeBinList; + attributeBinList.prev = a; + attributeBinList = a; + } + } + + addAttributeBins.clear(); + + if (canvasDirty != 0) { + Canvas3D canvases[] = renderBin.view.getCanvases(); + + for (i = 0; i < canvases.length; i++) { + canvases[i].canvasDirty |= canvasDirty; + } + + if ((canvasDirty & Canvas3D.AMBIENTLIGHT_DIRTY) != 0) { + updateSceneAmbient(); + } + + if ((canvasDirty & Canvas3D.LIGHTENABLES_DIRTY) != 0) { + enableMask = enableMaskCache; + } + + if ((canvasDirty & Canvas3D.MODELCLIP_DIRTY) != 0) { + enableMCMask = enableMCMaskCache; + } + + canvasDirty = 0; + } + onUpdateList = false; + } + + /** + * Adds the given AttributeBin to this EnvironmentSet. + */ + void addAttributeBin(AttributeBin a, RenderBin rb) { + a.environmentSet = this; + addAttributeBins.add(a); + if (!onUpdateList) { + rb.objUpdateList.add(this); + onUpdateList = true; + } + } + + /** + * Removes the given AttributeBin from this EnvironmentSet. + */ + void removeAttributeBin(AttributeBin a) { + LightRetained light; + int i; + + a.environmentSet = null; + // If the attributeBin being remove is contained in addAttributeBins, then + // remove the attributeBin from the addList + if (addAttributeBins.contains(a)) { + addAttributeBins.remove(addAttributeBins.indexOf(a)); + } + else { + if (a.prev == null) { // At the head of the list + attributeBinList = a.next; + if (a.next != null) { + a.next.prev = null; + } + } else { // In the middle or at the end. + a.prev.next = a.next; + if (a.next != null) { + a.next.prev = a.prev; + } + } + } + a.prev = null; + a.next = null; + + if (a.definingRenderingAttributes != null && + (a.definingRenderingAttributes.changedFrequent != 0)) + a.definingRenderingAttributes = null; + a.onUpdateList &= ~AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST; + + if (attributeBinList == null && addAttributeBins.size() == 0) { + // Now remove this environment set from all the lights and fogs + // that use this + int sz = lights.size(); + for (i=0; i < sz; i++) { + ((LightRetained) lights.get(i)).environmentSets.remove(this); + } + sz = ambLights.size(); + for (i = 0; i < sz; i++) { + ((LightRetained) ambLights.get(i)).environmentSets.remove(this); + } + if (fog != null) { + fog.environmentSets.remove(this); + } + lightBin.removeEnvironmentSet(this); + } + } + + void updateSceneAmbient() + { + int i; + sceneAmbient.x = 0.0f; + sceneAmbient.y = 0.0f; + sceneAmbient.z = 0.0f; + for (i=0; i 1.0f) { + sceneAmbient.x = 1.0f; + } + if (sceneAmbient.y > 1.0f) { + sceneAmbient.y = 1.0f; + } + if (sceneAmbient.z > 1.0f) { + sceneAmbient.z = 1.0f; + } + } + + /** + * Renders this EnvironmentSet + */ + void render(Canvas3D cv) { + AttributeBin a; + + // include this EnvironmentSet to the to-be-updated list in Canvas + cv.setStateToUpdate(Canvas3D.ENVIRONMENTSET_BIT, this); + + a = attributeBinList; + while (a != null) { + a.render(cv); + a = a.next; + } + } + + + void updateAttributes(Canvas3D cv) { + LightRetained light; + int i, numLights; + float red, green, blue; + double scale; + boolean updateSceneAmbient = false, updateLightEnables = false; + boolean updateModelClip = false, updateFog = false; + // within frame + if (cv.environmentSet != this ) { + if (cv.enableMask != enableMask) { + updateLightEnables = true; + } + + if (cv.sceneAmbient.x != sceneAmbient.x || + cv.sceneAmbient.y != sceneAmbient.y || + cv.sceneAmbient.z != sceneAmbient.z ) { + updateSceneAmbient = true; + } + + if (cv.fog != fog) { + updateFog = true; + } + + if (cv.modelClip != modelClip) { + updateModelClip = true; + } + } + + // Check for dirtybit. + if ((cv.canvasDirty & (Canvas3D.LIGHTENABLES_DIRTY| + Canvas3D.AMBIENTLIGHT_DIRTY| + Canvas3D.FOG_DIRTY| + Canvas3D.MODELCLIP_DIRTY| + Canvas3D.VIEW_MATRIX_DIRTY)) != 0) { + + if ((cv.canvasDirty & Canvas3D.LIGHTENABLES_DIRTY) != 0) { + updateLightEnables = true; + } + + if ((cv.canvasDirty & Canvas3D.AMBIENTLIGHT_DIRTY) != 0) { + updateSceneAmbient = true; + } + + if ((cv.canvasDirty & Canvas3D.FOG_DIRTY) != 0) { + updateFog = true; + } + + if ((cv.canvasDirty & Canvas3D.MODELCLIP_DIRTY) != 0) { + updateModelClip = true; + } + + if ((cv.canvasDirty & Canvas3D.VIEW_MATRIX_DIRTY) != 0) { + updateFog = true; + updateModelClip = true; + } + } + + // do states update here. + if (updateLightEnables) { + cv.setLightEnables(cv.ctx, enableMask, renderBin.maxLights); + cv.enableMask = enableMask; + } + + if (updateSceneAmbient) { + cv.setSceneAmbient(cv.ctx, sceneAmbient.x, + sceneAmbient.y, sceneAmbient.z); + cv.sceneAmbient.set(sceneAmbient); + } + + if (updateFog) { + if (fog != null) { + scale = lightBin.geometryBackground == null? + cv.canvasViewCache.getVworldToCoexistenceScale(): + cv.canvasViewCache.getInfVworldToCoexistenceScale(); + fog.update(cv.ctx, scale); + } else { + cv.disableFog(cv.ctx); + } + cv.fog = fog; + } + + if (updateModelClip) { + if (modelClip != null) { + modelClip.update(cv, enableMCMask); + } else { + cv.disableModelClip(cv.ctx); + } + cv.modelClip = modelClip; + } + + cv.canvasDirty &= ~(Canvas3D.LIGHTENABLES_DIRTY| + Canvas3D.AMBIENTLIGHT_DIRTY | + Canvas3D.FOG_DIRTY | + Canvas3D.MODELCLIP_DIRTY | + Canvas3D.VIEW_MATRIX_DIRTY); + + cv.environmentSet = this; + + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/EventCatcher.java b/j3d-core/src/classes/share/javax/media/j3d/EventCatcher.java new file mode 100644 index 0000000..8ffe3df --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/EventCatcher.java @@ -0,0 +1,417 @@ +/* + * $RCSfile: EventCatcher.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.awt.*; +import java.awt.event.*; + + +/** + * The EventCatcher class is used to track events on a Canvas3D using the + * 1.1 event model. Most events are sent to the canvas for processing. + */ +class EventCatcher extends Object implements ComponentListener, FocusListener, + KeyListener, MouseListener, MouseMotionListener, MouseWheelListener, WindowListener { + + // The canvas associated with this event catcher + private Canvas3D canvas; + private static final boolean DEBUG = false; + private boolean stopped = false; + + /** + * flags for event listeners + */ + private boolean focusEvents = false; + private boolean keyEvents = false; + private boolean mouseEvents = false; + private boolean mouseMotionEvents = false; + private boolean mouseWheelEvents = false; + private boolean mouseListenerAdded = false; + + EventCatcher(Canvas3D c) { + canvas = c; + + if (VirtualUniverse.mc.isD3D()) { + enableKeyEvents(); + } + } + + void enableFocusEvents() { + if (!focusEvents) { + canvas.addFocusListener(this); + focusEvents = true; + } + } + + + void disableFocusEvents() { + if (focusEvents) { + canvas.removeFocusListener(this); + focusEvents = false; + } + } + + void enableKeyEvents() { + if (!keyEvents) { + canvas.addKeyListener(this); + keyEvents = true; + // listen for mouseEntered events for keyboard focusing + if (!mouseListenerAdded) { + canvas.addMouseListener(this); + mouseListenerAdded = true; + } + } + } + + void disableKeyEvents() { + if (keyEvents) { + canvas.removeKeyListener(this); + keyEvents = false; + // listen for mouseEntered events for keyboard focusing + if (!mouseEvents) { + if (mouseListenerAdded) { + canvas.removeMouseListener(this); + mouseListenerAdded = false; + } + } + } + } + + + + void enableMouseEvents() { + if (!mouseEvents) { + mouseEvents = true; + if (!mouseListenerAdded) { + canvas.addMouseListener(this); + mouseListenerAdded = true; + } + } + } + + void disableMouseEvents() { + if (mouseEvents) { + mouseEvents = false; + if (!keyEvents) { + if (mouseListenerAdded) { + canvas.removeMouseListener(this); + mouseListenerAdded = false; + } + } + } + } + + void enableMouseMotionEvents() { + if (!mouseMotionEvents) { + canvas.addMouseMotionListener(this); + mouseMotionEvents = true; + } + } + + + void disableMouseMotionEvents() { + if (mouseMotionEvents) { + canvas.removeMouseMotionListener(this); + mouseMotionEvents = false; + } + } + + void enableMouseWheelEvents() { + if (!mouseWheelEvents) { + canvas.addMouseWheelListener(this); + mouseWheelEvents = true; + } + } + + + void disableMouseWheelEvents() { + if (mouseWheelEvents) { + canvas.removeMouseWheelListener(this); + mouseWheelEvents = false; + } + } + + + public void componentResized(ComponentEvent e) { + if (e.getSource() == canvas) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + if (VirtualUniverse.mc.isD3D()) { + canvas.notifyD3DPeer(Canvas3D.RESIZE); + } + canvas.evaluateVisiblilty(); + canvas.redraw(); + } + } + + public void componentMoved(ComponentEvent e) { + if (e.getSource() == canvas) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + + // Issue 458 - the following is not needed for a move +// if (VirtualUniverse.mc.isD3D()) { +// canvas.notifyD3DPeer(Canvas3D.RESIZE); +// } +// canvas.evaluateVisiblilty(true); + } + } + + public void componentHidden(ComponentEvent e) { + if (DEBUG) { + System.err.println(e); + } + if (e.getSource() == canvas) { + canvas.sendEventToBehaviorScheduler(e); + } + canvas.evaluateVisiblilty(); + } + + public void componentShown(ComponentEvent e) { + if (DEBUG) { + System.err.println(e); + } + if (e.getSource() == canvas) { + canvas.sendEventToBehaviorScheduler(e); + } + canvas.evaluateVisiblilty(); + } + + public void focusGained(FocusEvent e) { + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + public void focusLost(FocusEvent e) { + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + public void keyTyped(KeyEvent e) { + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + public void keyPressed(KeyEvent e) { + canvas.sendEventToBehaviorScheduler(e); + + if (VirtualUniverse.mc.isD3D() && + e.isAltDown() && + (e.getKeyCode() == KeyEvent.VK_ENTER)) { + canvas.notifyD3DPeer(Canvas3D.TOGGLEFULLSCREEN); + } + + if (DEBUG) { + System.err.println(e); + } + } + + public void keyReleased(KeyEvent e) { + canvas.sendEventToBehaviorScheduler(e); + if (stopped) { + stopped = false; + } else { + stopped = true; + } + if (DEBUG) { + System.err.println(e); + } + } + + public void mouseClicked(MouseEvent e) { +// if (keyEvents && +// (VirtualUniverse.mc.getRenderingAPI() != +// MasterControl.RENDER_OPENGL_SOLARIS)) { +// // bug 4362074 +// canvas.requestFocus(); +// } + + if (mouseEvents) { + canvas.sendEventToBehaviorScheduler(e); + } + if (DEBUG) { + System.err.println(e); + } + } + + public void mouseEntered(MouseEvent e) { +// if (keyEvents && +// (VirtualUniverse.mc.getRenderingAPI() == +// MasterControl.RENDER_OPENGL_SOLARIS)) { +// // bug 4362074 +// canvas.requestFocus(); +// } + if (mouseEvents) { + canvas.sendEventToBehaviorScheduler(e); + } + if (DEBUG) { + System.err.println(e); + } + } + + public void mouseExited(MouseEvent e) { + if (mouseEvents) + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + public void mousePressed(MouseEvent e) { + if (mouseEvents) + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + public void mouseReleased(MouseEvent e) { + if (mouseEvents) + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + public void mouseDragged(MouseEvent e) { + // Note : We don't have to test for mouseMotionEvent here because + // this routine will never be called unless mouseMotionEvent is enabled. + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + public void mouseMoved(MouseEvent e) { + // Note : We don't have to test for mouseMotionEvent here because + // this routine will never be called unless mouseMotionEvent is enabled. + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + public void mouseWheelMoved(MouseWheelEvent e) { + // Note : We don't have to test for mouseWheelEvent here because + // this routine will never be called unless mouseWheelEvent is enabled. + canvas.sendEventToBehaviorScheduler(e); + if (DEBUG) { + System.err.println(e); + } + } + + /* + * WindowListener methods + */ + public void windowClosed(WindowEvent e) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + // Issue 458 - Don't set canvas visible to false + } + + public void windowClosing(WindowEvent e) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + // Issue 458 - Don't set canvas.visible to false + } + + public void windowActivated(WindowEvent e) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + } + + public void windowDeactivated(WindowEvent e) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + } + + public void windowDeiconified(WindowEvent e) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + if (canvas.view != null) { + canvas.view.sendEventToSoundScheduler(e); + } + canvas.evaluateVisiblilty(); + } + + public void windowIconified(WindowEvent e) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + if (canvas.view != null) { + canvas.view.sendEventToSoundScheduler(e); + } + canvas.evaluateVisiblilty(); + } + + public void windowOpened(WindowEvent e) { + if (DEBUG) { + System.err.println(e); + } + canvas.sendEventToBehaviorScheduler(e); + canvas.evaluateVisiblilty(); + } + + void reset() { + focusEvents = false; + keyEvents = false; + mouseEvents = false; + mouseMotionEvents = false; + mouseWheelEvents = false; + mouseListenerAdded = false; + stopped = false; + } + +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/ExceptionStrings.properties b/j3d-core/src/classes/share/javax/media/j3d/ExceptionStrings.properties new file mode 100644 index 0000000..05ee875 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ExceptionStrings.properties @@ -0,0 +1,1003 @@ +Alpha0=Alpha: time <= 0 +Appearance0=Appearance: no capability to set material +Appearance1=Appearance: no capability to get material +Appearance2=Appearance: no capability to set texture +Appearance3=Appearance: no capability to get texture +Appearance4=Appearance: no capability to set textureAttributes +Appearance5=Appearance: no capability to get textureAttributes +Appearance6=Appearance: no capability to set coloringAttributes +Appearance7=Appearance: no capability to get coloringAttributes +Appearance8=Appearance: no capability to set transparencyAttributes +Appearance9=Appearance: no capability to get transparencyAttributes +Appearance10=Appearance: no capability to set renderingAttributes +Appearance11=Appearance: no capability to get renderingAttributes +Appearance12=Appearance: no capability to set polygonAttributes +Appearance13=Appearance: no capability to get polygonAttributes +Appearance14=Appearance: no capability to set lineAttributes +Appearance15=Appearance: no capability to get lineAttributes +Appearance16=Appearance: no capability to set pointAttributes +Appearance17=Appearance: no capability to get pointAttributes +Appearance18=Appearance: no capability to set TexCoordGeneraion +Appearance19=Appearance: no capability to get TexGen +Appearance20=Appearance: no capability to set TextureUnitState +Appearance21=Appearance: no capability to get TextureUnitState +BoundingSphere0=BoundingSphere( Bounds ) unrecognized bounds object +BoundingSphere2=set( Bounds) unrecognized bounds type +BoundingSphere3=BoundingSphere.combine( Bounds) unrecognized bounds type +BoundingSphere4=BoundingSphere.combine( Bounds[]) unrecognized bounds type +BoundingSphere5=transform( Bounds, trans) unrecognized bounds type +BoundingSphere6=sphere.intersect(Bounds ) bounds type not recognized= +BoundingSphere7=sphere.intersect(Bounds[]) bounds type not recognized= +BoundingSphere8=BoundingSphere.intersect(Bounds, newBoundingSphere) bounds type not recognized= +BoundingSphere9=BoundingSphere.intersect(Bounds[], newBoundingSphere) bounds type not recognized= +BoundingSphere10=sphere.closestIntersection(Bounds[]) unrecognized bounds type +Background0=Background: no capability to set color +Background2=Background: no capability to get color +Background3=Background: no capability to set image +Background4=Background: no capability to get image +Background5=Background: no capability to set background geometry +Background6=Background: no capability to get background geometry +Background7=Background: no capability to set application bounds +Background8=Background: no capability to get application bounds +Background9=Background: no capability to set image scale mode +Background10=Background: no capability to get image scale mode +Background11=Background: illegal image scale mode +Background12=Background: Live Background with an ImageComponent2D that is being used by a Canvas3D as an off-screen buffer. +Background13=Background: In Immediate mode context with an ImageComponent2D that is being used by a Canvas3D as an off-screen buffer. +AlternateAppearance0=AlternateAppearance: no capability to write appearance +AlternateAppearance2=AlternateAppearance: no capability to read appearance +AlternateAppearance3=AlternateAppearance: no capability to write influencing bounds +AlternateAppearance4=AlternateAppearance: no capability to read influencing bounds +AlternateAppearance7=AlternateAppearance: no capability to write scope +AlternateAppearance8=AlternateAppearance: no capability to read scope +AlternateAppearance9=AlternateAppearance: no capability to insert scope +AlternateAppearance10=AlternateAppearance: no capability to remove scope +AlternateAppearance11=AlternateAppearance: no capability to read scopes +AlternateAppearance12=AlternateAppearance: no capability to append scope +AlternateAppearanceRetained13=AlternateAppearance: Immediate mode alternate appearance may not be in scene graph +AlternateAppearanceRetained14=AlternateAppearance: Immediate mode appearance may not be in scene graph +AlternateAppearanceRetained15=AlternateAppearance: illegal node under SharedGroup Branch +AlternateAppearanceRetained16=AlternateAppearance: illegal node under Background geometry Branch +AudioDeviceEnumerator0=No more audio devices +AuralAttributes0=AuralAttributes: no capability to set attribute gain +AuralAttributes1=AuralAttributes: no capability to get attribute gain +AuralAttributes2=AuralAttributes: no capability to set rolloff +AuralAttributes3=AuralAttributes: no capability to get rolloff +AuralAttributes4=AuralAttributes: no capability to set reflection coefficient +AuralAttributes5=AuralAttributes: no capability to set reverberation delay +AuralAttributes7=AuralAttributes: no capability to get reverberation delay +AuralAttributes8=AuralAttributes: no capability to set reverberation order +AuralAttributes9=AuralAttributes: no capability to get reverberation order +AuralAttributes10=AuralAttributes: no capability to set distance filter +AuralAttributes12=AuralAttributes: no capability to get distance filter +AuralAttributes15=AuralAttributes: no capability to set Doppler scale factor +AuralAttributes17=AuralAttributes: no capability to get Doppler scale factor +AuralAttributes19=AuralAttributes: no capability to set Doppler velocity +AuralAttributes20=AuralAttributes: no capability to get Doppler velocity +AuralAttributes21=AuralAttributes: no capability to get reflection coefficient +AuralAttributes22=AuralAttributes: no capability to set reflection delay +AuralAttributes23=AuralAttributes: no capability to get reflection delay +AuralAttributes24=AuralAttributes: no capability to set reverberation coefficient +AuralAttributes25=AuralAttributes: no capability to get reverberation coefficient +AuralAttributes26=AuralAttributes: no capability to set reverberation bounds +AuralAttributes27=AuralAttributes: no capability to get reverberation bounds +AuralAttributes28=AuralAttributes: no capability to set decay time +AuralAttributes29=AuralAttributes: no capability to get decay time +AuralAttributes30=AuralAttributes: no capability to set decay filter +AuralAttributes31=AuralAttributes: no capability to get decay filter +AuralAttributes32=AuralAttributes: no capability to set diffusion +AuralAttributes33=AuralAttributes: no capability to get diffusion +AuralAttributes34=AuralAttributes: no capability to set density +AuralAttributes35=AuralAttributes: no capability to get density +Behavior0=wakeupOn must be called from initialize or processStimulus +Behavior1=illegal schedulingInterval value +BehaviorRetained0=Behavior: illegal node under Background geometry Branch +BehaviorRetained1=Behavior: illegal node under SharedGroup Branch +BehaviorRetained2=Behavior: wakeupCondition criteria cannot be null +ConeSound0=ConeSound: no capability to set distance attenuation +ConeSound2=ConeSound: no capability to get distance attenuation +ConeSound3=ConeSound: no capability to set direction +ConeSound5=ConeSound: no capability to get direction +ConeSound6=ConeSound: no capability to set cone attenuation +ConeSound9=ConeSound: no capability to get cone attenuation +ConeSound10=ConeSound: no capability to get max distance attenuation +BoundingBox0=BoundingBox( Bounds) unrecognized bounds type +BoundingBox1=BoundingBox( Bounds[]) unrecognized bounds type +BoundingBox3=BoundingBox.combine( Bounds) unrecognized bounds type +BoundingBox4=BoundingBox.combine( Bounds[]) unrecognized bounds type +BoundingBox5=transform( Bounds, trans) unrecognized bounds type +BoundingBox6=intersect(Bounds[]) unrecognized bounds type +BoundingBox7=BoundingBox.intersect(Bounds, newBoundingBox) unrecognized bounds type +BoundingBox9=box.closestIntersection(Bounds[]) unrecognized bounds type +BoundingLeaf0=BoundingLeaf: no capability to write bounding region +BoundingLeaf1=BoundingLeaf: no capability to read bounding region +BoundingLeafRetained0=BoundingLeaf: illegal node under Background geometry Branch +BoundingLeafRetained1=BoundingLeaf: illegal node under SharedGroup Branch +BackgroundRetained0=Background: Background geometry BranchGroup cannot be referenced by multiple Background node +BackgroundRetained1=Background: Immediate mode background may not be in scene graph +BackgroundRetained3=Background: Background geometry BranchGroup is not at the root of a branch graph +BackgroundRetained4=Background: Background geometry BranchGroup cannot be attached to a locale +BackgroundRetained5=Background: illegal node under Background geometry Branch +BackgroundRetained6=Background: illegal node under SharedGroup Branch +Canvas3D0=Canvas3D: Cannot swap buffers when the renderer is running +Canvas3D1=Canvas3D: Not in off-screen mode +Canvas3D2=Canvas3D: Off-screening rendering is in progress +Canvas3D3=Canvas3D: The specified ImageComponent2D is used by more than on Canvas3D +Canvas3D7=WARNING: Canvas3D constructed with null GraphicsConfiguration; +Canvas3D8=Canvas3D: The width of the associated Screen3D's size is <= 0 +Canvas3D9=Canvas3D: The height of the associated Screen3D's size is <= 0 +Canvas3D10=Canvas3D: Off-screen buffer is null +Canvas3D11=Canvas3D: Java3D renderer is stopped +Canvas3D12=Canvas3D: The physical width of the associated Screen3D is <= 0 +Canvas3D13=Canvas3D: The physical height of the associated Screen3D is <= 0 +Canvas3D14=Canvas3D: Illegal operation in off-screen mode +Canvas3D15=Canvas3D: For offscreen rendering, byReference image should be an instance of BufferedImage +Canvas3D16=Canvas3D: Offscreen rendering has to be a 3-component or 4-component format. +Canvas3D17=Canvas3D: GraphicsConfiguration is not compatible with Canvas3D +Canvas3D18=will attempt to use a default GraphicsConfiguration +Canvas3D19=Canvas3D: null GraphicsConfiguration +Canvas3D20=Canvas3D does not support serialization +Canvas3D23=Unable to get FBConfig from GraphicsConfiguration +Canvas3D24=Canvas3D: Can't force render of offscreen buffer because it is an automatic one. +Canvas3D25=Canvas3D: AutoOffscreenCanvas3D must be used as off-screen Canvas3D. +Canvas3D26=Canvas3D: ImageComponent2D is already part of a live scene graph. +Canvas3D27=Canvas3D: ImageComponent2D is already being used by an immediate mode context. +Canvas3D28=Canvas3D: ImageComponent2D is already being used by by another Canvas3D as an off-screen buffer. +Canvas3D29=Canvas3D: Non-recoverable graphics configuration error +Canvas3D30=Canvas3D: Non-recoverable off-screen rendering error +Canvas3D31=Canvas3D: Can't wait for off-screen rendering in a canvas callback +BoundingPolytope0=BoundingPolytope( Bounds) unrecognized bounds object +BoundingPolytope1=BoundingPolytope( Bounds) unrecognized bounds type +BoundingPolytope2=set( Bounds) unrecognized bounds type +BoundingPolytope3=combine( Bounds) unrecognized bounds type +BoundingPolytope4=BoundingPolytope.combine( Bounds ) unrecognized bounds type +BoundingPolytope5=BoundingPolytope.transform( Bounds, transform ) unrecognized bounds type +BoundingPolytope6=intersect(Bounds[]) unrecognized bounds type +BoundingPolytope7=BoundingPolytope.intersect(Bounds[]) unrecognized bounds type +BoundingPolytope8=intersect(Bounds, BoundingPolytope) bounds type not recognized= +BoundingPolytope10=sphere.closestIntersection(Bounds[]) unrecognized bounds object +BoundingPolytope11=Must specify at least 4 planes +BranchGroup0=Cannot compile a live BranchGroup +BranchGroup1=BranchGroup: no capability to detach +BranchGroup2=Group: no capability to write children +BranchGroup3=Picking can only work if BranchGroup is alive +BranchGroup4=BranchGroup: Mode has to be either PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY +BranchGroup5=BranchGroup: Mode can't be PickInfo.PICK_GEOMETRY if PickShape is PickPoint +BranchGroup6=BranchGroup: CLOSEST_GEOM_INFO and ALL_GEOM_INFO can't be set together. +BranchGroup7=BranchGroup: Mode can't be PICK_BOUNDS if geometry information is needed +BranchGroup8=BranchGroup: PickShape can't be PickBounds if geometry information is needed +BranchGroup9=BranchGroup: Cannot call picking under a SharedGroup node +CachedFrustum0=Frustum must have aleast 6 planes +CachedFrustum1=Frustum must have 6 planes +Clip0=Clip: no capability to set back distance +Clip1=Clip: no capability to get back distance +Clip2=Clip: no capability to set application bounds +Clip3=Clip: no capability to get application bounds +ColoringAttributes0=ColoringAttributes: no capability to set color +ColoringAttributes2=ColoringAttributes: no capability to get Color +ColoringAttributes3=ColoringAttributes: no capability to set shademodel +ColoringAttributes4=ColoringAttributes: no capability to get shademodel +CompressedGeometry0=CompressedGeometry: start+size exceeds geometry length +CompressedGeometry1=CompressedGeometry: no capability to get byte count +CompressedGeometry2=CompressedGeometry: no capability to get geometry header +CompressedGeometry3=CompressedGeometry: no capability to get geometry +CompressedGeometry4=CompressedGeometry: target buffer is too small +CompressedGeometry5=CompressedGeometry: no capability to get geometry +CompressedGeometry6=CompressedGeometry: no capability to get data reference +CompressedGeometry7=CompressedGeometry: cannot directly access data in byReference mode +CompressedGeometry8=CompressedGeometry: must be in byReference mode to use this method +CompressedGeometry9=CompressedGeometry: NIO buffer support is not implemented +ClipRetained0=Clip: Immediate mode clip may not be in scene graph +ClipRetained1=Clip: illegal node under Background geometry Branch +ClipRetained2=Clip: illegal node under SharedGroup Branch +DepthComponentInt0=DepthComponentInt: no capability to get data +DepthComponent0=DepthComponent: no capability to get size +ImageComponentRetained0=ImageComponent: illegal width value +ImageComponentRetained1=ImageComponent: illegal height value +ImageComponentRetained2=ImageComponent: illegal depth value +ImageComponentRetained3=ImageComponent: illegal format value +ExponentialFog0=ExponentialFog: no capability to write density +ExponentialFog1=ExponentialFog: no capability to read density +Fog0=Fog: no capability to write color +Fog2=Fog: no capability to read color +Fog3=Fog: no capability to write influencing bounds +Fog4=Fog: no capability to read influencing bounds +Fog7=Fog: no capability to write fog's scope +Fog8=Fog: no capability to read fog's scope +Fog9=Fog: no capability to insert scope +Fog10=Fog: no capability to remove scope +Fog11=Fog: no capability to read scopes +Fog12=Fog: no capability to append scope +DirectionalLight0=Light: no capability to set light's state +DirectionalLight1=Light: no capability to set light's direction +DirectionalLight2=Light: no capability to read light's direction +FogRetained0=Fog: Immediate mode fog may not be in scene graph +FogRetained1=Fog: illegal node under SharedGroup Branch +DepthComponentFloat0=DepthComponentFloat: no capability to get data +FontExtrusion0=FontExtrusion:invalid shape- non-monotonic +FontExtrusion1=FontExtrusion: invalid shape- shape must start or end at x = 0.0f +FontExtrusion2=FontExtrusion:method not implemented +FontExtrusion3=FontExtrusion:invalid shape- multiple contours +Group0=Group: no capability to set bounds +Group1=Group: no capability to read user bounds +Group2=SharedGroup must be referenced through a link node +Group3=Group: only BranchGroup nodes may be set +Group4=Group: no capability to detach BranchGroup +Group6=Group: only a BranchGroup node may be inserted +Group7=Group: only a BranchGroup node may be removed +Group9=Group: no capability to read children +Group12=Group: only a BranchGroup node may be added +Group13=Group: no capability to set children +Group14=Group: no capability to insert children +Group15=Group: no capability to remove children +Group16=Group: no capability to append children +GeneralizedStrip0=GeneralizedStrip: strip ended incompletely +GeometryArray0=GeometryArray: vertexFormat must include COORDINATES +GeometryArray1=GeometryArray: no capability to get vertex count +GeometryArray2=GeometryArray: no capability to get vertex format +GeometryArray3=GeometryArray: no capability to set coordinate +GeometryArray7=GeometryArray: no capability to set coordinates +GeometryArray15=GeometryArray: no capability to set color +GeometryArray21=GeometryArray: no capability to set colors +GeometryArray33=GeometryArray: no capability to set normal +GeometryArray35=GeometryArray: no capability to set normals +GeometryArray39=GeometryArray: no capability to set texture coordinate +GeometryArray42=GeometryArray: no capability to set texture coordinates +GeometryArray48=GeometryArray: no capability to read coordinate +GeometryArray52=GeometryArray: no capability to read coordinates +GeometryArray56=GeometryArray: no capability to read color +GeometryArray62=GeometryArray: no capability to read colors +GeometryArray68=GeometryArray: no capability to read normal +GeometryArray70=GeometryArray: no capability to read normals +GeometryArray72=GeometryArray: no capability to read texture coordinate +GeometryArray75=GeometryArray: no capability to read texture coordinates +GeometryArray76=GeometryArray: has no colors +GeometryArray77=GeometryArray: has no normals +GeometryArray78=GeometryArray: has no normals +GeometryArray79=GeometryArray: has no texture coordinates +GeometryArray80=GeometryArray: INTERLEAVED flag set without setting BY_REFERENCE flag +GeometryArray81=GeometryArray: no capability to update geometry data +GeometryArray82=GeometryArray: cannot directly access data in BY_REFERENCE mode +GeometryArray83=GeometryArray: must be in BY_REFERENCE mode to use this method +GeometryArray84=GeometryArray: cannot access individual array references in INTERLEAVED mode +GeometryArray85=GeometryArray: must be in INTERLEAVED mode to use this method +GeometryArray86=GeometryArray: no capability to write data reference +GeometryArray87=GeometryArray: no capability to read data reference +GeometryArray88=GeometryArray: no capability to set valid vertex count +GeometryArray89=GeometryArray: no capability to get valid vertex count +GeometryArray90=GeometryArray: no capability to set initial index +GeometryArray91=GeometryArray: no capability to get initial index +GeometryArray92=GeometryArray: must be in COLOR_3 mode to use this method +GeometryArray93=GeometryArray: must be in COLOR_4 mode to use this method +GeometryArray94=GeometryArray: must be in TEXTURE_COORDINATE_2 mode to use this method +GeometryArray95=GeometryArray: must be in TEXTURE_COORDINATE_3 mode to use this method +GeometryArray96=GeometryArray: vertex count < 0 +GeometryArray97=GeometryArray: initial index < 0 +GeometryArray98=GeometryArray: array reference is already non-null +GeometryArray99=GeometryArray: vertex array length is incorrect +GeometryArray100=GeometryArray: initial vertex index + valid vertex count > vertex count +GeometryArray101=GeometryArray: initial color index + valid vertex count > vertex count +GeometryArray102=GeometryArray: initial normal index + valid vertex count > vertex count +GeometryArray103=GeometryArray: initial tex coord index + valid vertex count > vertex count +GeometryArray104=GeometryArray: initial coord index + valid vertex count > vertex count +GeometryArray105=GeometryArray: must not be in BY_REFERENCE mode to use this method +GeometryArray106=GeometryArray: texCoord set mapping is not specified +GeometryArray107=GeometryArray: must specify at least one set of texture coordinates +GeometryArray108=GeometryArray: invalid texCoord set mapping +GeometryArray109=GeometryArray: must be in TEXTURE_COORDINATE_4 mode to use this method +GeometryArray110=GeometryArray: validVertexCount should be greater than or equal to zero +GeometryArray111=GeometryArray: normal array length is incorrect +GeometryArray112=GeometryArray: color array length is incorrect +GeometryArray113=GeometryArray: texture coord array length is incorrect +GeometryArray114=GeometryArray: interleaved array length is incorrect +GeometryArray115=GeometryArray: NIO buffer is null +GeometryArray116=GeometryArray: Illegal NIO buffer type +GeometryArray117=GeometryArray: USE_NIO_BUFFER flag set without setting BY_REFERENCE flag +GeometryArray118=GeometryArray: must be in USE_NIO_BUFFER mode to use this method +GeometryArray119=GeometryArray: must not be in USE_NIO_BUFFER mode to use this method +GeometryArray120=GeometryArray: must be direct nio buffer +GeometryArray121=GeometryArray: None of the TEXTURE_COORDINATE bits are set in vertexFormat +GeometryArray122=GeometryArray: NORMALS bit is not set in vertexFormat +GeometryArray123=GeometryArray: None of the COLOR bits are set in vertexFormat +GeometryArray124=GeometryArray: texCoordSetCount < 0 +GeometryArray125=GeometryArray: vertexAttrCount < 0 +GeometryArray126=GeometryArray: no capability to set vertex attributes +GeometryArray127=GeometryArray: no capability to read vertex attributes +GeometryArray128=GeometryArray: VERTEX_ATTRIBUTES flag must not be set in INTERLEAVED mode +GeometryArray129=GeometryArray: vertex attr array length is incorrect +GeometryArray130=GeometryArray: initial vertex attr index + valid vertex count > vertex count +GeometryArray131=GeometryArray: vertexAttrCount > 0, but VERTEX_ATTRIBUTES flag is not set +GeometryArray132=GeometryArray: vertexAttrCount != vertexAttrSizes.length +GeometryArray133=GeometryArray: vertexAttrSize value out of range +GeometryArray134=GeometryArray: vertexAttrSize invalid for this method +GeometryArray135=GeometryArray: USE_COORD_INDEX_ONLY bit cannot be set for non-indexed geometry +GeometryArray136=GeometryArray: BY_REFERENCE_INDICES bit can be set only for indexed geometry +GeometryArray137=GeometryArray: BY_REFERENCE_INDICES bit can be set only if BY_REFERENCE bit is also set +GeometryArray138=GeometryArray: BY_REFERENCE_INDICES bit can be set only if USE_COORD_INDEX_ONLY bit is also set +GeometryDecompressor0=GeometryDecompressor: start+length > data array size +GeometryDecompressor1=GeometryDecompressor: bad delta normal in compressed buffer +GeometryDecompressorRetained0=GeometryDecompressorRetained: bad buffer data type +GeometryDecompressorRetained1=GeometryDecompressorRetained: unexpected vertexFormat/SetState in compressed buffer +GeometryDecompressorRetained2=GeometryDecompressorRetained: unexpected color in compressed buffer +GeometryDecompressorRetained3=GeometryDecompressorRetained: unexpected normal in compressed buffer +GeometryDecompressorRetained4=GeometryDecompressorRetained: bad buffer data type +GeometryDecompressorShape3D0=GeometryDecompressorShape3D: bad triangle output type +GeometryDecompressorShape3D1=GeometryDecompressorShape3D: bad buffer data type +GroupRetained0=Group.setChild: child already has a parent +GroupRetained1=Group.insertChild: child already has a parent +GroupRetained2=Group.addChild: child already has a parent +GeometryRetained1=Geometry - intersect : Sorry! This method is not supported at present +Light0=Light: no capability to set light's state +Light1=Light: no capability to read light's state +Light2=Light: no capability to write light's color +Light3=Light: no capability to read light's color +Light4=Light: no capability to write light's scope +Light5=Light: no capability to read light's scope +Light6=Light: no capability to insert scope +Light7=Light: no capability to remove scope +Light8=Light: no capability to read scopes +Light9=Light: no capability to append scope +Light11=Light: no capability to write influencing bounds +Light12=Light: no capability to read influencing bounds +GeometryStripArrayRetained0=Illegal stripVertexCounts +GeometryStripArray0=GeometryStripArray: no capability to get number of strips +GeometryStripArray1=GeometryStripArray: no capability to get strip vertex counts +GeometryStripArray2=GeometryStripArray: no capability to set strip vertex counts +GeometryStripArray3=GeometryStripArray: initial vertex index + valid vertex count > vertex count +GeometryStripArray4=GeometryStripArray: initial color index + valid vertex count > vertex count +GeometryStripArray5=GeometryStripArray: initial normal index + valid vertex count > vertex count +GeometryStripArray6=GeometryStripArray: initial tex coord index + valid vertex count > vertex count +GeometryStripArray7=GeometryStripArray: initial coord index + valid vertex count > vertex count +GeometryStripArray8=GeometryStripArray: initial vertex attr index + valid vertex count > vertex count +GraphicsContext3D11=Background: Scene Graph background may not be in immediate mode +GraphicsContext3D12=Fog: Scene Graph fog may not be in immediate mode +GraphicsContext3D13=GraphicsContext3D: Light object is null +GraphicsContext3D14=Light: Scene Graph light may not be in immediate mode +GraphicsContext3D17=GraphicsContext3D: setSound object is null +GraphicsContext3D21=readRaster: Scene Graph Raster may not be in immediate mode +GraphicsContext3D22=Background: Background geometry can not be used in immediate mode context +GraphicsContext3D23=Sound: Scene Graph sound may not be in immediate mode +GraphicsContext3D25=ModelClip: Scene Graph ModelClip may not be in immediate mode +GraphicsContext3D26=Shape3D: Scene Graph Shape3D may not be in immediate mode +GraphicsContext3D27=ImageComponent2D size is smaller than read Raster size +GraphicsContext3D28=DepthComponent size is smaller than read Raster size +GraphicsContext3D29=GraphicsContext3D: For readRaster, byReference image should be an instance of BufferedImage +GraphicsContext3D30=GraphicsContext3D: Appearance has an ImageComponent2D used by an OffScreen Canvas3D. +GraphicsContext3D31=GraphicsContext3D: Background's ImageComponent2D is already being used as an OffScreen Canvas3D. +GraphicsContext3D32=GraphicsContext3D: Raster's ImageComponent2D is already being used as an OffScreen Canvas3D. +GraphicsContext3D33=GraphicsContext3D: Raster's ImageComponent2D is not of ImageClass.BUFFERED_IMAGE. +GraphicsContext3D34=GraphicsContext3D: Raster's ImageComponent2D is in by-reference mode and its RenderedImage is null. +GraphicsContext3D35=GraphicsContext3D: Raster's ImageComponent2D format is not a 3-component format or a 4-component format. +GraphicsContext3D36=GraphicsContext3D: Raster and Raster's ImageComponent2D are part of a live scene graph. +GraphicsContext3D37=GraphicsContext3D: Raster's ImageComponent2D is being used by an immediate mode context, or by a Canvas3D as an off-screen buffer. +ImageComponent0=ImageComponent: no capability to get width +ImageComponent1=ImageComponent: no capability to get height +ImageComponent2=ImageComponent: no capability to get format +ImageComponent3=ImageComponent: This image is being used by a Canvas3D as an off-screen buffer. +ImageComponent4=ImageComponent: The image class of this object is ImageClass.NIO_IMAGE_BUFFER. +ImageComponent5=ImageComponent: Mismatch in the number of components between format and image buffer. +ImageComponent2D0=ImageComponent2D: no capability to get image +ImageComponent2D1=ImageComponent2D: no capability to set image +ImageComponent2D2=ImageComponent2D: must be in BY_REFERENCE mode to use this method +ImageComponent2D3=ImageComponent2D: illegal dimension +ImageComponent2D4=ImageComponent2D: must be in BY_COPY mode to use this method +ImageComponent2D5=ImageComponent2D: image is not an instanceof of BufferedImage +ImageComponent2D6=ImageComponent2D: type mismatch between sub-image and existing image. +ImageComponent2D7=ImageComponent2D: Nio buffer image must be byReference is true. +ImageComponent2D8=ImageComponent2D: Nio buffer image must be yUp is true. +ImageComponent2D9=ImageComponent2D: The image class is not ImageClass.NIO_IMAGE_BUFFER. +ImageComponent3D0=ImageComponent3D: no capability to get depth +ImageComponent3D1=ImageComponent3D - incompatible depth +ImageComponent3D2=ImageComponent3D - incompatible width +ImageComponent3D3=ImageComponent3D: no capability to get image +ImageComponent3D4=ImageComponent3D - incompatible height +ImageComponent3D5=ImageComponent3D: no capability to set image +ImageComponent3D6=ImageComponent3D: must be in BY_REFERENCE mode to use this method +ImageComponent3D7=ImageComponent3D: illegal dimension +ImageComponent3D8=ImageComponent3D: must be in BY_COPY mode to use this method +ImageComponent3D9=ImageComponent3D: image is not an instanceof of BufferedImage +ImageComponent2DRetained0=ImageComponent2D - incompatible width +ImageComponent2DRetained1=ImageComponent2D - incompatible height +ImageComponent2DRetained2=Raster does not support FORMAT_CHANNEL8 +ImageComponent3DRetained0=ImageComponent3D: image is not an instanceof of BufferedImage +Locale0=Locale.addBranchGraph: Branch Group already has a parent +Locale1=Locale: no capability to detach BranchGroup +Locale3=Locale.replaceBranchGraph: Branch Group already has a parent +Locale4=Locale has been removed from its VirtualUniverse +Locale5=Locale: Mode has to be either PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY +Locale6=Locale: Mode can't be PickInfo.PICK_GEOMETRY if PickShape is PickPoint +Locale7=Locale: CLOSEST_GEOM_INFO and ALL_GEOM_INFO can't be set together. +Locale8=Locale: Mode can't be PICK_BOUNDS if geometry information is needed +Locale9=Locale: PickShape can't be PickBounds if geometry information is needed +IndexedLineStripArray0=IndexedLineStripArray: illegal vertexCount +IndexedLineStripArray1=IndexedLineStripArray: illegal indexCount +IndexedGeometryArray0=IndexedGeometryArray: no capability to get index count +IndexedGeometryArray1=IndexedGeometryArray: no capability to set coordinate index +IndexedGeometryArray3=IndexedGeometryArray: no capability to set color index +IndexedGeometryArray5=IndexedGeometryArray: no capability to set normal index +IndexedGeometryArray7=IndexedGeometryArray: no capability to set texture coordinate index +IndexedGeometryArray9=IndexedGeometryArray: no capability to get coordinate index +IndexedGeometryArray11=IndexedGeometryArray: no capability to get color index +IndexedGeometryArray13=IndexedGeometryArray: no capability to get normal index +IndexedGeometryArray15=IndexedGeometryArray: no capability to get texture coordinate index +IndexedGeometryArray16=IndexedGeometryArray: no capability to set valid index count +IndexedGeometryArray17=IndexedGeometryArray: no capability to get valid index count +IndexedGeometryArray18=IndexedGeometryArray: no capability to set initial index index +IndexedGeometryArray19=IndexedGeometryArray: no capability to get initial index index +IndexedGeometryArray20=IndexedGeometryArray: initial index < 0 +IndexedGeometryArray21=IndexedGeometryArray: valid index < 0 +IndexedGeometryArray22=IndexedGeometryArray: initial index Index +valid index count > index count +IndexedGeometryArray23=IndexedGeometryArray: index coord value greater than the array length +IndexedGeometryArray24=IndexedGeometryArray: index color value greater than the array length +IndexedGeometryArray25=IndexedGeometryArray: index texcoord value greater than the array length +IndexedGeometryArray26=IndexedGeometryArray: index normal value greater than the array length +IndexedGeometryArray27=IndexedGeometryArray: index value less than zero +IndexedGeometryArray28=IndexedGeometryArray: no capability to set vertex attribute index +IndexedGeometryArray29=IndexedGeometryArray: no capability to get vertex attribute index +IndexedGeometryArray30=IndexedGeometryArray: index vertexAttr value greater than the array length +IndexedGeometryArray31=IndexedGeometryArray: cannot access indices directly in BY_REFERENCE_INDICES mode +IndexedGeometryArray32=IndexedGeometryArray: can access indices by reference only in BY_REFERENCE_INDICES mode +IndexedGeometryArray33=IndexedGeometryArray: coordIndices array length < initial index index + valid index count +IndexedLineArray0=IndexedLineArray: illegal vertexCount +IndexedLineArray1=IndexedLineArray: illegal indexCount +IndexedGeometryStripArray0=IndexedGeometryStripArray: no capability to get number of strips +IndexedGeometryStripArray1=IndexedGeometryStripArray: no capability to get strip index counts +IndexedGeometryStripArray2=IndexedGeometryStripArray: no capability to set strip index counts +LineAttributes0=LineAttributes: illegal line pattern +LineAttributes1=LineAttributes: no capability to set line width +LineAttributes2=LineAttributes: no capability to get line width +LineAttributes3=LineAttributes: no capability to set line pattern +LineAttributes4=setLinePattern: illegal line pattern +LineAttributes5=LineAttributes: no capability to get line pattern +LineAttributes6=LineAttributes: no capability to set line antialiasing +LineAttributes7=LineAttributes: no capability to get line antialiasing +LineAttributes8=LineAttributes: no capability to set line pattern mask +LineAttributes9=LineAttributes: no capability to get line pattern mask +LineAttributes10=LineAttributes: no capability to set line pattern scale factor +LineAttributes11=LineAttributes: no capability to get line pattern scale factor +LineArray0=LineArray: illegal vertexCount +IndexedGeometryStripArrayRetained0=Illegal stripIndexCounts +IndexedLineArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +IndexedLineStripArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +IndexedLineStripArrayRetained1=IndexedLineStripArray: stripVertexCounts element less than 2 +IndexedPointArray0=IndexedPointArray: illegal vertexCount +IndexedPointArray1=IndexedPointArray: illegal indexCount +IndexedPointArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +IndexedQuadArray0=IndexedQuadArray: illegal vertexCount +IndexedQuadArray1=IndexedQuadArray: illegal indexCount +IndexedQuadArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +IndexedTriangleArray0=IndexedTriangleArray: illegal vertexCount +IndexedTriangleArray1=IndexedTriangleArray: illegal indexCount +IndexedTriangleArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +IndexedTriangleFanArray0=IndexedTriangleFanArray: illegal vertexCount +IndexedTriangleFanArray1=IndexedTriangleFanArray: illegal indexCount +IndexedTriangleFanArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +IndexedTriangleFanArrayRetained1=IndexedTriangleFanArray: stripVertexCounts element less than 3 +IndexedTriangleStripArray0=IndexedTriangleStripArray: illegal vertexCount +IndexedTriangleStripArray1=IndexedTriangleStripArray: illegal indexCount +IndexedTriangleStripArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +IndexedTriangleStripArrayRetained1=IndexedTriangleStripArray: stripVertexCounts element less than 3 +LightRetained0=Light: Immediate mode light may not be in scene graph +LineStripArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +LineStripArrayRetained1=stripVertexCounts element less than 2 +LineArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +LineStripArray0=LineStripArray: illegal vertexCount +Link0=Link: no capability to set SharedGroup +Link1=Link: no capability to get SharedGroup +LinkRetained0=Link: illegal node under Background geometry Branch +LinkRetained1=Link: Scene Graph are not directed acyclic graphs +LinearFog0=LinearFog: no capability to write distance +LinearFog1=LinearFog: no capability to read distance +PointArray0=PointArray: illegal vertexCount +Material0=Material: no capability to set component +Material2=Material: no capability to get component +Material3=Material: no capability to set color target +Material4=Material: no capability to get color target +Material15=Material: no capability to set lighting +Material16=Material: no capability to get lighting +Morph0=Group: no capability to set bounds +Morph1=Group: no capability to read user bounds +Morph2=Morph: no capability to set geometryArrays +Morph3=Morph: no capability to get geometryArrays +Morph4=Morph: no capability to set appearance +Morph5=Morph: no capability to get appearance +Morph6=Morph: no capability to allow intersect +Morph8=Morph: no capability to set morph weight vector +Morph9=Morph: no capability to get morph weight vector +Morph10=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +Morph11=Morph: no capability to set appearance override enable +Morph12=Morph: no capability to get appearance override enable +MediaContainer0=MediaContainer: setURL - bad URL +MediaContainer1=MediaContainer: no capability to set cached flag +MediaContainer2=MediaContainer: no capability to get cached flag +MediaContainer3=MediaContainer: no capability to set URL +MediaContainer4=MediaContainer: no capability to get URL +MediaContainer5=MediaContainer: only one type of sound data may be simultaneously set non-null +MorphRetained0=Morph: Incorrect number of GeometryArrays +MorphRetained1=Morph: All GeometryArrays must have same vertexFormat, same vertexCount and same texCoordSetCount +MorphRetained2=Morph: All GeometryArrays must be of same type +MorphRetained5=Invalid SceneGraphPath encountered : localToVworld is null. +MorphRetained7=Morph: number of weights not same as number of GeometryArrays +MorphRetained8=Morph: sum of all weights is NOT 1.0 +MorphRetained9=Morph: vertex attributes are not supported +NioImageBuffer0=NioImageBuffer: image width is not positive +NioImageBuffer1=NioImageBuffer: image height is not positive +NioImageBuffer2=NioImageBuffer: unsupported image type +NioImageBuffer3=NioImageBuffer: NIO buffer limit is incorrect +NioImageBuffer4=NioImageBuffer: NIO buffer type does not match image type +NioImageBuffer5=NioImageBuffer: NIO buffer does not match native byte order of underlying platform +Node0=Node: no capability to read parent +Node1=Node: no capability to set bounds +Node2=Node: no capability to read user bounds +Node3=Node: no capability to read Pickable +Node4=Node: no capability to set Collidable +Node5=Node: no capability to set user auto compute bounds +Node6=Node: no capability to read user auto compute bounds +Node7=Node: local to vworld transform is undefined for a node that is compiled but not live +Node8=Node: no capability to read local to vworld transform +Node9=Node: Invalid geometric bounds +Node11=cloneTree: should be overridden in child +Node12=cloneNode must be defined in subclass +Node13=Node: Cannot clone a live or compiled scenegraph +Node14=Node: no capability to set Pickable +Node15=Node: Cannot compile, clone or getBounds on a scene graph that contains a cycle. +Node16=Node: no capability to read Collidable +Node17=Node: no capability to read locale +PickInfo0=PickInfo: PICK_GEOMETRY mode - no capability to ALLOW_GEOMETRY_READ +PickInfo1=PickInfo: PICK_GEOMETRY mode - no capability to ALLOW_INTERSECT +PickInfo2=PickInfo: PICK_GEOMETRY mode - no capability to ALLOW_COORDINATE_READ +PickInfo3=PickInfo: PICK_GEOMETRY mode - no capability to ALLOW_COUNT_READ +PickInfo4=PickInfo: PICK_GEOMETRY mode - no capability to ALLOW_FORMAT_READ +PickInfo5=PickInfo: PICK_GEOMETRY mode - no capability to ALLOW_COORDINATE_INDEX_READ +PickInfo6=PickInfo: PICK_GEOMETRY mode - no capability to ALLOW_GEOMETRY_ARRAY_READ +Picking0=Cannot call picking under a SharedGroup node +Picking2=Picking: Node has no parent and locale. This is illegal! +NodeComponent0=NodeComponent:cloneNodeComponent must be defined in subclass +NodeComponent1=Cannot duplicate a Compiled NodeComponent object +NodeComponent2=Live NodeComponent with an ImageComponent2D that is being used by a Canvas3D as an off-screen buffer. +NodeComponent3=In Immediate mode context with an ImageComponent2D that is being used by a Canvas3D as an off-screen buffer. +NodeRetained0=Not supported in a Shared Graph +NodeRetained1=Only supported in a Shared Graph +NodeRetained2=invalid scene graph path +NodeRetained3=No node object may exist in more than one virtual universe +NodeRetained4=SharedGroup has no parent. This is illegal! +NodeRetained5=Node has no parent and locale. This is illegal! +OrderedGroup0=OrderedGroup: childIndexOrder.length != number of children +OrderedGroup1=OrderedGroup: childIndexOrder[i] must be >= 0, for i in [0, numChildren-1] +OrderedGroup2=OrderedGroup: childIndexOrder[i] must be < numChildren, for i in [0, numChildren-1] +OrderedGroup3=OrderedGroup: childIndexOrder[i] must not equal to childIndexOrder[j], for i,j in [0,numChildren-1] and i != j +OrderedGroup4=OrderedGroup: no capability to write child index order +OrderedGroup5=OrderedGroup: no capability to read child index order +OrderedGroup6=OrderedGroup: insertChild illegal when childIndexOrder != null +OrientedShape3D0=OrientedShape3D: no capability to set alignment mode +OrientedShape3D1=OrientedShape3D: no capability to get alignment mode +OrientedShape3D2=OrientedShape3D: no capability to set alignment axis +OrientedShape3D3=OrientedShape3D: no capability to get alignment axis +OrientedShape3D4=OrientedShape3D: no capability to set rotation point +OrientedShape3D5=OrientedShape3D: no capability to get rotation point +OrientedShape3D6=OrientedShape3D: no capability to set constant scale enable +OrientedShape3D7=OrientedShape3D: no capability to get constant scale enable +OrientedShape3D8=OrientedShape3D: no capability to set scale +OrientedShape3D9=OrientedShape3D: no capability to get scale +PathInterpolator0=PathInterpolator: first knot is not 0.0 +PathInterpolator1=PathInterpolator: last knot is not 1.0 +PathInterpolator2=PathInterpolator: invalid knot value +PhysicalBody0=non-rigid transform +PointLight0=PointLight: no capability to set light's state +PointLight1=PointLight: no capability to set light's position +PointLight2=PointLight: no capability to read light's position +PointLight3=PointLight: no capability to set light's attenuation +PointLight5=PointLight: no capability to read light's attenuation +PointSound0=PointSound: no capability to set position +PointSound2=PointSound: no capability to get position +PointSound3=PointSound: no capability to set distance attenuation +PointSound4=PointSound: no capability to get max distance attenuation +RotPosPathInterpolator0=RotPosPathInterpolator: length of knots, positions, and quats must be equal +PhysicalEnvironment0=addInputDevice: InputDevice.getProcessingMode must return one of BLOCKING, NON_BLOCKING, or DEMAND_DRIVEN +PhysicalEnvironment1=non-rigid transform +PhysicalEnvironment2=Illegal policy value +Raster0=Raster: no capability to set position +Raster1=Raster: no capability to get position +Raster2=Raster: no capability to get type +Raster3=Raster: no capability to set image +Raster4=Raster: no capability to get image +Raster5=Raster: no capability to set depth component +Raster6=Raster: no capability to get depth component +Raster7=Raster: no capability to set offset +Raster8=Raster: no capability to get offset +Raster9=Raster: no capability to set size +Raster10=Raster: no capability to set clip mode +Raster11=Raster: no capability to get clip mode +Raster12=Raster: Live Raster with an ImageComponent2D that is being used by a Canvas3D as an off-screen buffer. +PointArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +PointAttributes0=PointAttributes: no capability to set point size +PointAttributes1=PointAttributes: no capability to get point size +PointAttributes2=PointAttributes: no capability to set point antialiasing +PointAttributes3=PointAttributes: no capability to get point antialiasing +PolygonAttributes0=PolygonAttributes: illegal polygon mode +PolygonAttributes2=PolygonAttributes: no capability to set polygon cull face +PolygonAttributes3=setCullFace: illegal cull face +PolygonAttributes4=PolygonAttributes: no capability to get polygon cull face +PolygonAttributes5=PolygonAttributes: no capability to set back face normal flip flag +PolygonAttributes6=PolygonAttributes: no capability to get back face normal flip flag +PolygonAttributes7=PolygonAttributes: no capability to set polygon mode +PolygonAttributes8=setPolygonMode: illegal polygon mode +PolygonAttributes9=PolygonAttributes: no capability to get polygon mode +PolygonAttributes10=PolygonAttributes: no capability to set polygon offset +PolygonAttributes11=PolygonAttributes: no capability to get polygon offset +PolygonAttributes12=PolygonAttributes: illegal cull face +QuadArray0=QuadArray: illegal vertexCount +QuadArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +PositionPathInterpolator0=PositionPathInterpolator: length of knots and positions must be equal +Renderer0=Renderer: Unexpected RuntimeException caught during buffer swap +Renderer1=Renderer: Error initializing GraphicsConfiguration properties +Renderer2=Renderer: Error creating Canvas3D graphics context for queryProperties() +Renderer3=Renderer: Error in GraphicsConfigTemplate3D.getBestConfiguration() +Renderer4=Renderer: Error in GraphicsConfigTemplate3D.isConfigSupported() +Renderer5=Renderer: Error creating Canvas3D off-screen buffer +Renderer6=Renderer: Error creating immediate mode Canvas3D graphics context +Renderer7=Renderer: Error creating Canvas3D graphics context +Renderer8=Renderer: Unexpected RuntimeException caught during rendering +RenderingAttributes0=RenderingAttributes: no capability to set depth buffer mode +RenderingAttributes1=RenderingAttributes: no capability to get depth buffer mode +RenderingAttributes2=RenderingAttributes: no capability to set depth buffer write mode +RenderingAttributes3=RenderingAttributes: no capability to get depth buffer write mode +RenderingAttributes4=RenderingAttributes: no capability to set alpha test value +RenderingAttributes5=RenderingAttributes: no capability to get alpha test value +RenderingAttributes6=RenderingAttributes: no capability to set alpha test function +RenderingAttributes7=RenderingAttributes: no capability to get alpha test function +RenderingAttributes8=RenderingAttributes: no capability to set visibility +RenderingAttributes9=RenderingAttributes: no capability to get visibility +RenderingAttributes10=RenderingAttributes: no capability to set raster op +RenderingAttributes11=RenderingAttributes: no capability to get raster op +RenderingAttributes12=RenderingAttributes: no capability to set ignore vertex colors flag +RenderingAttributes13=RenderingAttributes: no capability to get ignore vertex colors flag +RenderingAttributes14=RenderingAttributes: no capability to set depth test function +RenderingAttributes15=RenderingAttributes: no capability to get depth test function +RenderingAttributes16=RenderingAttributes: no capability to set stencil attributes +RenderingAttributes17=RenderingAttributes: no capability to get stencil attributes +TriangleStripArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +TriangleStripArrayRetained1=stripVertexCounts element less than 3 +RotationPathInterpolator0=RotationPathInterpolator: length of knots and quats must be of the same length +RotPosScalePathInterpolator0=RotPosScalePathInterpolator: length of knots and positions must be of the same length +RotPosScalePathInterpolator1=PositionPathInterpolator: length of knots and quats must be equal +RotPosScalePathInterpolator2=PositionPathInterpolator: length of knots and scales must be equal +SceneGraphObject0=Cannot modify capability bits on a live or compiled object +SceneGraphObject1=Cannot modify capability isFrequent bits on a compiled object +SceneGraphObject2=Object is either live or compiled +SceneGraphObjectRetained0=CloneNotSupportedException +SceneGraphPath0=SceneGraphPath : Node array pointer is null. +SceneGraphPath1=SceneGraphPath : Node array bounds exceeded. +SceneGraphPath2=Invalid SceneGraphPath: a Locale is not specified. +SceneGraphPath3=Invalid SceneGraphPath: A member is not live. +SceneGraphPath5=Invalid SceneGraphPath: A Link node has been excluded. +SceneGraphPath9=Invalid SceneGraphPath: Locale and path are not associated. +SceneGraphPath10=Invalid SceneGraphPath: a Node is not specified. +SceneGraphPath11=Invalid SceneGraphPath: Not all nodes are on the same path or there is an ordering problem. +Screen3D0=Screen3D: non-rigid transform +Screen3D1=Screen3D: Cannot set screen size, screen is not in off-screen mode +Sensor0=Sensor.setPredictor: Must use PREDICT_NONE or PREDICT_NEXT_FRAME_TIME +Sensor1=Sensor.setPredictionPolicy: Illegal policy +Sensor2=getRead(read, deltaT) must have value >= 0 for deltaT +Sensor3=Sensor.lastRead(transform,kth); kth can't be bigger than the sensor read count +Sensor4=Sensor.lastTime(k); k can't be bigger than the sensor read count +Sensor5=Sensor.lastButtons(k, values); k can't be bigger than the sensor read count +Sensor6=Sensor.lastButtons(k); k can't be bigger than the sensor read count +SensorRead0=SensorRead: Array of button values is not long enough +SensorRead1=SensorRead: Trying to set button values when this SensorRead object has no buttons +Shape3D0=Group: no capability to set bounds +Shape3D1=Group: no capability to read user bounds +Shape3D2=Shape3D: no capability to set geometry +Shape3D3=Shape3D: no capability to get geometry +Shape3D4=Shape3D: no capability to set appearance +Shape3D5=Shape3D: no capability to get appearance +Shape3D6=Shape3D: no capability to allow intersect +Shape3D7=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +Shape3D8=Shape3D: no capability to set appearance override enable +Shape3D9=Shape3D: no capability to get appearance override enable +Sound0=Sound: no capability to set sound data +Sound1=Sound: no capability to get sound data +Sound2=Sound: no capability to set initial gain +Sound3=Sound: no capability to get initial gain +Sound4=Sound: no capability to set loop +Sound5=Sound: no capability to get loop +Sound6=Sound: no capability to set release flag +Sound7=Sound: no capability to get release flag +Sound8=Sound: no capability to set continuous play flag +Sound9=Sound: no capability to get continuous play flag +Sound10=Sound: no capability set sound state +Sound11=Sound: no capability to set scheduling bounds +Sound12=Sound: no capability to get scheduling bounds +Sound15=Sound: no capability set sound priority +Sound16=Sound: no capability to get sound on priority +Sound17=Sound: no capability to get duration +Sound18=Sound: no capability to get playing state +Sound20=Sound: no capability to get to get channels used for sound +Sound21=Sound: no capability to get sound on flag +Sound22=Sound: no capability to get ready state +Sound23=Sound: no capability to set mute flag +Sound24=Sound: no capability to get mute flag +Sound25=Sound: no capability to set pause flag +Sound26=Sound: no capability to get pause flag +Sound27=Sound: no capability to set rate scale factor +Sound28=Sound: no capability to get rate scale factor +SoundRetained1=Sound source data could not be loaded +SoundRetained2=Sound: Immediate mode sound may not be in scene graph +SoundRetained3=Sound: illegal node under Background geometry Branch +Switch0=Switch: no capability to set children +Switch1=Switch: no capability to read switch index +Switch2=Switch: no capability to set childMask +Switch3=Switch: no capability to read switch childMask +Switch4=Switch: no capability to read children +Text3D0=Text3D: no capability to get Font3D +Text3D1=Text3D: no capability to set Font3D +Text3D2=Text3D: no capability to get string +Text3D3=Text3D: no capability to set string +Text3D4=Text3D: no capability to get position +Text3D5=Text3D: no capability to set position +Text3D6=Text3D: no capability to get allignment +Text3D7=Text3D: no capability to set allignment +Text3D8=Text3D: no capability to get path +Text3D9=Text3D: no capability to set path +Text3D10=Text3D: no capability to get bounding box +Text3D11=Text3D: no capability to get character spacing +Text3D12=Text3D: no capability to set character spacing +Shape3DRetained3=Invalid SceneGraphPath encountered : localToVworld is null. +Shape3DRetained5=Shape3D: the new geometry component is not of the same equivalence class as the existing geometry components. +SharedGroup0=Cannot compile a live SharedGroup +SharedGroup1=SharedGroup: No capability to get Links +Soundscape0=Soundscape: no capability to set application bounds +Soundscape1=Soundscape: no capability to get application bounds +Soundscape4=Soundscape: no capability to set aural attributes +Soundscape5=Soundscape: no capability to get an attribute set +SoundscapeRetained0=Soundscape: illegal node under Background geometry Branch +SoundscapeRetained1=Soundscape: illegal node under SharedGroup Branch +SpotLight0=SpotLight: no capability to set light's spreadAngle +SpotLight1=SpotLight: no capability to read light's spreadAngle +SpotLight2=Light: no capability to set light's concentration +SpotLight3=SpotLight: no capability to read light's concentration +SpotLight4=SpotLight: no capability to set light's direction +SpotLight6=SpotLight: no capability to read light's direction +SharedGroupRetained0=SharedGroup: Illegal leaf nodes +Text3DRetained0=execute() called on Text3D +Text3DRetained1=Text3D - intersect : Sorry! Geometry type not supported. +TexCoordGeneration0=TexCoordGeneration: no capability to set enable +TexCoordGeneration1=TexCoordGeneration: no capability to get enable +TexCoordGeneration2=TexCoordGeneration: no capability to get format +TexCoordGeneration3=TexCoordGeneration: no capability to get mode +TexCoordGeneration4=TexCoordGeneration: no capability to get plane +TexCoordGeneration5=TexCoordGeneration: illegal texture generation mode +TexCoordGeneration6=TexCoordGeneration: no capability to set plane +Texture0=Texture: Illegal mipmapMode value +Texture1=Texture: Illegal format value +Texture2=Texture: width NOT power of 2 +Texture3=Texture: height NOT power of 2 +Texture4=Texture: no capability to get boundry mode +Texture6=Texture: no capability to get filter +Texture8=Texture: cannot use ImageComponent3D in Texture2D +Texture9=Texture: no capability to get image +Texture10=Texture: no capability to get mipmap mode +Texture11=Texture: no capability to set enable +Texture12=Texture: no capability to get enable +Texture13=Texture: no capability to get boundry color +Texture14=Texture: cannot use ImageComponent2D in Texture3D +Texture15=Texture: no capability to set image +Texture16=Texture: no capability to get width +Texture17=Texture: no capability to get height +Texture18=Texture: no capability to get number of mipmap levels +Texture19=Texture: no capability to get format +Texture20=Texture: number of images != number of mipmap levels +Texture21=Texture: no capability to get sharpen texture information +Texture22=Texture: the length of lod does not match the length of pts +Texture23=Texture: no capability to get texture filter4 information +Texture24=Texture: the length of weights < 4 +Texture25=Texture: Illegal anisotropic filter mode value +Texture26=Texture: no capability to get anisotropic filter information +Texture27=Texture: Illegal anisotropic filter degree +Texture28=Texture: Illegal minification filter +Texture29=Texture: Illegal magnification filter +Texture30=Texture: illegal boundary width +Texture31=Texture: illegal boundary mode value +Texture32=Texture: no capability to set base level +Texture33=Texture: no capability to set maximum level +Texture34=Texture: no capability to get base level +Texture35=Texture: no capability to get maximum level +Texture36=Texture: baseLevel < 0 or baseLevel > maximum Level +Texture37=Texture: maximumLevel < baseLevel or maximum Level > 2 powerof(max(width,height)) +Texture38=Texture: no capability to set minimum lod +Texture39=Texture: no capability to set maximum lod +Texture40=Texture: no capability to get minimum lod +Texture41=Texture: no capability to get maximum lod +Texture42=Texture: minimumLOD > maximumLOD +Texture43=Texture: maximumLOD < minimumLOD +Texture44=Texture: no capability to set lod offset +Texture45=Texture: no capability to get lod offset +Texture46=Texture: illegal width < 1 +Texture47=Texture: illegal height < 1 +Texture48=Texture: maximumLevel must be zero if mipmapMode is BASE_LEVEL +Texture2D0=Texture: no capability to get detail texture information +Texture2D1=Texture: Illegal detail texture mode value +Texture2D2=Texture: Illegal detail texture level +Texture2D3=Texture: the length of lod does not match the length of pts +Texture3D0=Texture: no capability to get boundry mode +Texture3D1=Texture: depth NOT power of 2 +Texture3D2=Texture: no capability to get depth +TextureAttributes0=TextureAttributes: no capability to set TextureMode +TextureAttributes1=TextureAttributes: no capability to get TextureMode +TextureAttributes2=TextureAttributes: no capability to set TexEnv cplor +TextureAttributes3=TextureAttributes: no capability to set TexEnv color +TextureAttributes4=TextureAttributes: no capability to get TexEnv color +TextureAttributes5=TextureAttributes: no capability to set texture coord transform +TextureAttributes6=TextureAttributes: no capability to get texture coord transform +TextureAttributes7=TextureAttributes: no capability to set perspective correction mode +TextureAttributes8=TextureAttributes: no capability to get perspective correction mode +TextureAttributes9=TextureAttributes: illegal perspective correction mode +TextureAttributes10=TextureAttributes: illegal texture mode +TextureAttributes11=TextureAttributes: no capability to set texture color table +TextureAttributes12=TextureAttributes: no capability to get texture color table +TextureAttributes13=TextureAttributes: table.length is not 3 or 4 +TextureAttributes14=TextureAttributes: component array length NOT power of 2 +TextureAttributes15=TextureAttributes: component array do not have same length +TextureAttributes16=TextureAttributes: no capability to set CombineRgbMode +TextureAttributes17=TextureAttributes: no capability to get CombineRgbMode +TextureAttributes18=TextureAttributes: no capability to set CombineAlphaMode +TextureAttributes19=TextureAttributes: no capability to get CombineAlphaMode +TextureAttributes20=TextureAttributes: illegal combine mode +TextureAttributes21=TextureAttributes: no capability to set CombineRgbSource +TextureAttributes22=TextureAttributes: no capability to get CombineRgbSource +TextureAttributes23=TextureAttributes: no capability to set CombineAlphaSource +TextureAttributes24=TextureAttributes: no capability to get CombineAlphaSource +TextureAttributes25=TextureAttributes: index out of range +TextureAttributes26=TextureAttributes: illegal combine source +TextureAttributes27=TextureAttributes: no capability to set CombineRgbFunction +TextureAttributes28=TextureAttributes: no capability to get CombineRgbFunction +TextureAttributes29=TextureAttributes: no capability to set CombineAlphaFunction +TextureAttributes30=TextureAttributes: no capability to get CombineAlphaFunction +TextureAttributes31=TextureAttributes: illegal combine function +TextureAttributes32=TextureAttributes: no capability to set CombineRgbScale +TextureAttributes33=TextureAttributes: no capability to get CombineRgbScale +TextureAttributes34=TextureAttributes: no capability to set CombineAlphaScale +TextureAttributes35=TextureAttributes: no capability to get CombineAlphaScale +TextureAttributes36=TextureAttributes: value other than 1, 2, or 4 +TextureCubeMap1=TextureCubeMap: no capability set images +TextureCubeMap2=TextureCubeMap: no capability get images +TextureCubeMap3=TextureCubeMap: cannot use ImageComponent3D in TextureCubeMap +TextureCubeMap4=TextureCubeMap: illegal cube map face +TextureRetained0=cannot set image in default texture +TextureRetained1=Texture:illegal image size +TextureRetained3=Texture: mipmap image not set at level +TextureUnitState0=TextureUnitState: no capability to set Texture +TextureUnitState1=TextureUnitState: no capability to get Texture +TextureUnitState2=TextureUnitState: no capability to set TextureAttributes +TextureUnitState3=TextureUnitState: no capability to get TextureAttributes +TextureUnitState4=TextureUnitState: no capability to set TexCoordGeneration +TextureUnitState5=TextureUnitState: no capability to get TexCoordGeneration +Transform3D0=Transform3D add +Transform3D1=cannot invert matrix +Transform3D4=Logic error: imax < 0 +TransformGroup0=TransformGroup: non-affine transform +TransformGroup1=Group: no capability to set transform +TransformGroup2=Group: no capability to get transform +TransparencyAttributes0=Transparency: no capability to set transparency mode +TransparencyAttributes1=Transparency: no capability to get transparency mode +TransparencyAttributes2=Transparency: no capability to set component +TransparencyAttributes3=Transparency: no capability to get component +TransparencyAttributes4=Transparency: no capability to set blend function +TransparencyAttributes5=Transparency: no capability to get blend function +TransparencyAttributes6=Transparency: illegal transparency mode +TransparencyAttributes7=Transparency: illegal source blend function +TransparencyAttributes8=Transparency: illegal destination blend function +Traverser0=Cycle found in SharedGroup +TriangleArray0=TriangleArray: illegal vertexCount +TriangleArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +TriangleFanArray0=TriangleFanArray: illegal vertexCount +View0=setViewPolicy: invalid value +View1=setProjectionPolicy: invalid value +View2=Cannot set projection when compatibility mode is disabled +View4=Cannot get projection when compatibility mode is disabled +View6=Cannot set VpcToEc when compatibility mode is disabled +View7=non-affine viewing transform +View8=Cannot get VpcToEc when compatibility mode is disabled +View9=Cannot get transform when userHeadToVworldEnable is disabled +View10=Sharing canvas with multiple views +View13=PhysicalBody is null +View14=PhysicalEnvironment is null +View15=View.stopBehaviorScheduler: can't call stopBehaviorScheduler() in a canvas callback. +View16=View.stopBehaviorScheduler: can't call stopBehaviorScheduler() in a behavior method. +View17=View.startBehaviorScheduler: can't call startBehaviorScheduler() in a canvas callback. +View18=View.startBehaviorScheduler: can't call startBehaviorScheduler() in a behavior method. +View19=View.stopView: can't call stopView() in a canvas callback. +View20=View.stopView: can't call stopView() in a behavior method. +View21=View.startView: can't call startView() in a canvas callback. +View22=View.startView: can't call startView() in a behavior method. +View23=Can't add an input device when the PhysicalEnvironment object is null +View24=Can't enumerate input devices when the PhysicalEnvironment object is null +View25=Can't add an audio device when the PhysicalEnvironment object is null +View26=Can't enumerate audio devices when the PhysicalEnvironment object is null +View27=Minimum time cannot be less than 0 +View28=View.renderOnce: can't call renderOnce() in a canvas callback. +View29=View.renderOnce: can't call renderOnce() in a behavior method. +View30=View.renderOnce: can't call renderOnce() when view is currently running. +View31=HMD mode not supported in CYCLOPEAN_EYE_VIEW mode. +TriangleStripArray0=TriangleStripArray: illegal vertexCount. +TriangleFanArrayRetained0=PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance. +TriangleFanArrayRetained1=stripVertexCounts element less than 3 +ViewPlatform0=ViewPlatform: no capability to write policy +ViewPlatform1=Illegal policy value +ViewPlatform2=ViewPlatform: no capability to read policy +ViewSpecificGroup1=ViewSpecificGroup: no capability to write view +ViewSpecificGroup2=ViewSpecificGroup: no capability to read view +ViewSpecificGroup3=ViewSpecificGroup: illegal node under Background geometry Branch +WakeupOnCollisionEntry0=For collision, only Group, Shape3D, Morph, or BoundingLeaf nodes are permitted. +WakeupOnCollisionEntry1=WakeupOnCollisionEntry: cannot use object in a background geometry branch to arm a collision +WakeupOnCollisionEntry4=WakeupOnCollisionEntry: Illegal value for speed hint +WakeupOnCollisionEntry5=WakeupOnCollisionEntry: Can only call getTriggeringPath from within a Behavior's processStimulus method +WakeupOnCollisionEntry6=WakeupOnCollisionEntry: Can only call getTriggeringBounds from within a Behavior's processStimulus method +WakeupOnCollisionEntry7=WakeupOnCollisionEntry: SceneGraphPath is not unique or Object is under a SharedGroup node +WakeupOnSensorEntry0=WakeupOnSensorEntry: Can only call from within a Behavior's processStimulus method +WakeupOnSensorExit0=WakeupOnSensorExit: Can only call from within a Behavior's processStimulus method +WakeupOnViewPlatformEntry0=WakeupOnViewPlatformEntry: Can only call from within a Behavior's processStimulus method +WakeupOnViewPlatformExit0=WakeupOnViewPlatformExit: Can only call from within a Behavior's processStimulus method +ViewPlatformRetained0=non-congruent transform above ViewPlatform +ViewPlatformRetained1=ViewPlatform: illegal node under Background geometry Branch +ViewPlatformRetained2=ViewPlatform: illegal node under SharedGroup Branch +ViewPlatformRetained3=ViewPlatform: illegal node under ViewSpecificGroup Branch +VirtualUniverse0=Locale not attached to this VirtualUniverse +WakeupOnCollisionExit0=For collision, only Group, Shape3D, Morph, or BoundingLeaf nodes are permitted. +WakeupOnCollisionExit1=WakeupOnCollisionEntry: cannot use object in a background geometry branch to arm a collision +WakeupOnCollisionExit3=WakeupOnCollisionEntry: cannot use object in a background geometry branch to arm a collision +WakeupOnCollisionExit4=WakeupOnCollisionExit: Illegal value for speed hint +WakeupOnCollisionExit5=WakeupOnCollisionExit: Can only call getTriggeringPath from within a Behavior's processStimulus method +WakeupOnCollisionExit6=WakeupOnCollisionExit: Can only call getTriggeringBounds from within a Behavior's processStimulus method +WakeupOnCollisionExit7=WakeupOnCollisionExit: SceneGraphPath is not unique or Object is under a SharedGroup node +WakeupOnElapsedFrames0=WakeupOnElapsedFrames(int) requires an argument >= 0 +WakeupOnCollisionMovement0=For collision, only Group, Shape3D, Morph, or BoundingLeaf nodes are permitted. +WakeupOnCollisionMovement1=WakeupOnCollisionEntry: cannot use object in a background geometry branch to arm a collision +WakeupOnCollisionMovement4=WakeupOnCollisionMovement: Illegal value for speed hint +WakeupOnCollisionMovement5=WakeupOnCollisionMovement: Can only call getTriggeringPath from within a Behavior's processStimulus method +WakeupOnCollisionMovement6=WakeupOnCollisionMovement: Can only call getTriggeringBounds from within a Behavior's processStimulus method +WakeupOnCollisionMovement7=WakeupOnCollisionMovement: SceneGraphPath is not unique or Object is under a SharedGroup node +WakeupOnCollisionMovement8=WakeupOnCollisionEntry: cannot use object in a background geometry branch to arm a collision +WakeupCriteriaEnumerator0=No more criterion +WakeupOnElapsedTime0=WakeupOnElapsedTime(int) requires an argument > 0L +ModelClip0=ModelClip: no capability to write influencing bounds +ModelClip1=ModelClip: no capability to read influencing bounds +ModelClip2=ModelClip: no capability to write plane +ModelClip3=ModelClip: no capability to read plane +ModelClip4=ModelClip: no capability to write enable +ModelClip5=ModelClip: no capability to read enable +ModelClip6=ModelClip: illegal plane num value +ModelClip7=ModelClip: no capability to write scope +ModelClip8=ModelClip: no capability to read scope +ModelClip9=ModelClip: no capability to insert scope +ModelClip10=ModelClip: no capability to remove scope +ModelClip11=ModelClip: no capability to read scopes +ModelClip12=ModelClip: no capability to append scope +ModelClip13=ModelClip: no capability to write influencing bounding leaf +ModelClip14=ModelClip: no capability to read influencing bounding leaf +ModelClipRetained1=ModelClip: illegal node under SharedGroup Branch +MasterControl0=OpenGL is not MT safe +MasterControl2=NOTE: simulated multi-texture will not work for programmable shaders +MasterControl3=and will be removed entirely in the next release of Java 3D +J3DBuffer0=Native access to NIO buffer not supported +J3DBuffer1=NIO buffer must be a direct buffer +J3DBuffer2=NIO buffer must match native byte order of underlying platform +J3DGraphics2D0=Cannot use Graphics2D object after dispose() is called +GLSLShaderProgram0=GLSLShaderProgram: no capability to read names +GLSLShaderProgram1=GLSLShaderProgram: no capability to read shaders +GLSLShaderProgram2=GLSLShaderProgram: Shader has incompatible shading language +CgShaderProgram0=CgShaderProgram: no capability to read names +CgShaderProgram1=CgShaderProgram: no capability to read shaders +CgShaderProgram2=CgShaderProgram: Shader has incompatible shading language +CgShaderProgram3=CgShaderProgram: must not specify more than one vertex shader +CgShaderProgram4=CgShaderProgram: must not specify more than one fragment shader +ShaderAppearance0=ShaderAppearance: no capability to set shader program +ShaderAppearance1=ShaderAppearance: no capability to get shader program +ShaderAppearance2=ShaderAppearance: no capability to set shader attribute set +ShaderAppearance3=ShaderAppearance: no capability to get shader attribute set +ShaderAttributeBinding0=ShaderAttributeBinding is not supported +ShaderProgramRetained0=Shading language not supported +ShaderAttributeObject0=ShaderAttributeObject: no capability to get value +ShaderAttributeObject1=ShaderAttributeObject: no capability to set value +ShaderAttributeSet0=ShaderAttributeSet: no capability to get attribute +ShaderAttributeSet1=ShaderAttributeSet: no capability to set attribute diff --git a/j3d-core/src/classes/share/javax/media/j3d/ExponentialFog.java b/j3d-core/src/classes/share/javax/media/j3d/ExponentialFog.java new file mode 100644 index 0000000..a6106af --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ExponentialFog.java @@ -0,0 +1,230 @@ +/* + * $RCSfile: ExponentialFog.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; + +/** + * The ExponentialFog leaf node extends the Fog leaf node by adding a + * fog density that is used as the exponent of the fog equation. The + * density is defined in the local coordinate system of the node, but + * the actual fog equation will ideally take place in eye coordinates. + *

+ * The fog blending factor, f, is computed as follows: + *

    + * f = e-(density * z)

    + * where + *

      z is the distance from the viewpoint.
      + * density is the density of the fog.

+ * + * In addition to specifying the fog density, ExponentialFog lets you + * specify the fog color, which is represented by R, G, and B + * color values, where a color of (0,0,0) represents black. + */ +public class ExponentialFog extends Fog { + /** + * Specifies that this ExponentialFog node allows read access to its + * density information. + */ + public static final int + ALLOW_DENSITY_READ = CapabilityBits.EXPONENTIAL_FOG_ALLOW_DENSITY_READ; + + /** + * Specifies that this ExponentialFog node allows write access to its + * density information. + */ + public static final int + ALLOW_DENSITY_WRITE = CapabilityBits.EXPONENTIAL_FOG_ALLOW_DENSITY_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_DENSITY_READ + }; + + /** + * Constructs an ExponentialFog node with default parameters. + * The default values are as follows: + *
    + * density : 1.0
    + *
+ */ + public ExponentialFog() { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs an ExponentialFog node with the specified fog color. + * @param color the fog color + */ + public ExponentialFog(Color3f color) { + super(color); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs an ExponentialFog node with the specified fog color + * and density. + * @param color the fog color + * @param density the density of the fog + */ + public ExponentialFog(Color3f color, float density) { + super(color); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ExponentialFogRetained)this.retained).initDensity(density); + } + + /** + * Constructs an ExponentialFog node with the specified fog color. + * @param r the red component of the fog color + * @param g the green component of the fog color + * @param b the blue component of the fog color + */ + public ExponentialFog(float r, float g, float b) { + super(r, g, b); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs an ExponentialFog node with the specified fog color + * and density. + * @param r the red component of the fog color + * @param g the green component of the fog color + * @param b the blue component of the fog color + * @param density the density of the fog + */ + public ExponentialFog(float r, float g, float b, float density) { + super(r, g, b); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ExponentialFogRetained)this.retained).initDensity(density); + } + + /** + * Sets fog density. + * @param density the new density of this fog + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDensity(float density) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DENSITY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ExponentialFog0")); + + if (isLive()) + ((ExponentialFogRetained)this.retained).setDensity(density); + else + ((ExponentialFogRetained)this.retained).initDensity(density); + } + + /** + * Gets fog density. + * @return the density of this fog + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getDensity() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DENSITY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ExponentialFog1")); + + return ((ExponentialFogRetained)this.retained).getDensity(); + } + + /** + * Creates the retained mode ExponentialFogRetained object that this + * ExponentialFog node will point to. + */ + void createRetained() { + this.retained = new ExponentialFogRetained(); + this.retained.setSource(this); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + ExponentialFog ef = new ExponentialFog(); + ef.duplicateNode(this, forceDuplicate); + return ef; + } + + + /** + * Copies all ExponentialFog information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + ((ExponentialFogRetained) retained).initDensity( + ((ExponentialFogRetained) originalNode.retained).getDensity()); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ExponentialFogRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ExponentialFogRetained.java new file mode 100644 index 0000000..6d8d29c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ExponentialFogRetained.java @@ -0,0 +1,183 @@ +/* + * $RCSfile: ExponentialFogRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; +import java.util.ArrayList; + +/** + * The ExponentialFog leaf node defines distance parameters for + * exponential fog. + */ +class ExponentialFogRetained extends FogRetained { + // Fog density + private float density = 1.0f; + + // Issue 144: density in Eye Coordinates (EC) + private float densityInEc; + + // dirty bits for ExponentialFog + static final int DENSITY_CHANGED = FogRetained.LAST_DEFINED_BIT << 1; + + + ExponentialFogRetained() { + this.nodeType = NodeRetained.EXPONENTIALFOG; + } + + /** + * initializes fog density + */ + void initDensity(float density){ + this.density = density; + } + + /** + * Sets fog density and send a message + */ + void setDensity(float density){ + this.density = density; + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.type = J3dMessage.FOG_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(DENSITY_CHANGED); + createMessage.args[2] = new Float(density); + VirtualUniverse.mc.processMessage(createMessage); + } + + /** + * Gets fog density + */ + float getDensity(){ + return this.density; + } + + + void setLive(SetLiveState s) { + super.setLive(s); + GroupRetained group; + + // Initialize the mirror object, this needs to be done, when + // renderBin is not accessing any of the fields + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.universe = universe; + createMessage.type = J3dMessage.FOG_CHANGED; + createMessage.args[0] = this; + // a snapshot of all attributes that needs to be initialized + // in the mirror object + createMessage.args[1]= new Integer(INIT_MIRROR); + ArrayList addScopeList = new ArrayList(); + for (int i = 0; i < scopes.size(); i++) { + group = (GroupRetained)scopes.get(i); + tempKey.reset(); + group.addAllNodesForScopedFog(mirrorFog, addScopeList, tempKey); + } + Object[] scopeInfo = new Object[2]; + scopeInfo[0] = ((scopes.size() > 0) ? Boolean.TRUE:Boolean.FALSE); + scopeInfo[1] = addScopeList; + createMessage.args[2] = scopeInfo; + Color3f clr = new Color3f(color); + createMessage.args[3] = clr; + + Object[] obj = new Object[5]; + obj[0] = boundingLeaf; + obj[1] = (regionOfInfluence != null?regionOfInfluence.clone():null); + obj[2] = (inBackgroundGroup? Boolean.TRUE:Boolean.FALSE); + obj[3] = geometryBackground; + obj[4] = new Float(density); + + createMessage.args[4] = obj; + VirtualUniverse.mc.processMessage(createMessage); + + } + + + /** + * This method and its native counterpart update the native context + * fog values. + */ + void update(Context ctx, double scale) { + // Issue 144: recompute the density in EC, and send it to native code + validateDistancesInEc(scale); + Pipeline.getPipeline().updateExponentialFog(ctx, color.x, color.y, color.z, densityInEc); + } + + + + // The update Object function. + // Note : if you add any more fields here , you need to update + // updateFog() in RenderingEnvironmentStructure + void updateMirrorObject(Object[] objs) { + + int component = ((Integer)objs[1]).intValue(); + + + if ((component & DENSITY_CHANGED) != 0) + ((ExponentialFogRetained)mirrorFog).density = ((Float)objs[2]).floatValue(); + + if ((component & INIT_MIRROR) != 0) { + ((ExponentialFogRetained)mirrorFog).density = ((Float)((Object[])objs[4])[4]).floatValue(); + + } + // Issue 144: store the local to vworld scale used to transform the density + ((ExponentialFogRetained)mirrorFog).setLocalToVworldScale(getLastLocalToVworld().getDistanceScale()); + + super.updateMirrorObject(objs); + } + + + // Clone the retained side only, internal use only + protected Object clone() { + ExponentialFogRetained efr = + (ExponentialFogRetained)super.clone(); + + efr.initDensity(getDensity()); + + return efr; + } + + // Issue 144: method to recompute the density in EC by multiplying the specified + // density by the inverse of the local to EC scale + /** + * Scale distances from local to eye coordinate. + */ + protected void validateDistancesInEc(double vworldToCoexistenceScale) { + // vworldToCoexistenceScale can be used here since + // CoexistenceToEc has a unit scale + double localToEcScale = getLocalToVworldScale() * vworldToCoexistenceScale; + + densityInEc = (float)(density / localToEcScale); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Fog.java b/j3d-core/src/classes/share/javax/media/j3d/Fog.java new file mode 100644 index 0000000..3b49425 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Fog.java @@ -0,0 +1,570 @@ +/* + * $RCSfile: Fog.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Enumeration; +import javax.vecmath.Color3f; + +/** + * The Fog leaf node defines a set of fog parameters common to all + * types of fog. These parameters include the fog color and a region + * of influence in which this Fog node is active. + * A Fog node also contains a list of Group nodes that specifies the + * hierarchical scope of this Fog. If the scope list is empty, then + * the Fog node has universe scope: all nodes within the region of + * influence are affected by this Fog node. If the scope list is + * non-empty, then only those Leaf nodes under the Group nodes in the + * scope list are affected by this Fog node (subject to the + * influencing bounds). + *

+ * If the regions of influence of multiple Fog nodes overlap, the + * Java 3D system will choose a single set of fog parameters for those + * objects that lie in the intersection. This is done in an + * implementation-dependent manner, but in general, the Fog node that + * is "closest" to the object is chosen. + */ + +public abstract class Fog extends Leaf { + /** + * Specifies that this Fog node allows read access to its + * influencing bounds and bounds leaf information. + */ + public static final int + ALLOW_INFLUENCING_BOUNDS_READ = CapabilityBits.FOG_ALLOW_INFLUENCING_BOUNDS_READ; + + /** + * Specifies that this Fog node allows write access to its + * influencing bounds and bounds leaf information. + */ + public static final int + ALLOW_INFLUENCING_BOUNDS_WRITE = CapabilityBits.FOG_ALLOW_INFLUENCING_BOUNDS_WRITE; + + /** + * Specifies that this Fog node allows read access to its color + * information. + */ + public static final int + ALLOW_COLOR_READ = CapabilityBits.FOG_ALLOW_COLOR_READ; + + /** + * Specifies that this Fog node allows write access to its color + * information. + */ + public static final int + ALLOW_COLOR_WRITE = CapabilityBits.FOG_ALLOW_COLOR_WRITE; + + /** + * Specifies that this Fog node allows read access to its scope + * information at runtime. + */ + public static final int + ALLOW_SCOPE_READ = CapabilityBits.FOG_ALLOW_SCOPE_READ; + + /** + * Specifies that this Fog node allows write access to its scope + * information at runtime. + */ + public static final int + ALLOW_SCOPE_WRITE = CapabilityBits.FOG_ALLOW_SCOPE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_INFLUENCING_BOUNDS_READ, + ALLOW_COLOR_READ, + ALLOW_SCOPE_READ + }; + + /** + * Constructs a Fog node with default parameters. The default + * values are as follows: + *

    + * color : black (0,0,0)
    + * scope : empty (universe scope)
    + * influencing bounds : null
    + * influencing bounding leaf : null
    + *
+ */ + public Fog() { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a Fog node with the specified fog color. + * @param color the fog color + */ + public Fog(Color3f color) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((FogRetained)this.retained).initColor(color); + } + + /** + * Constructs a Fog node with the specified fog color. + * @param r the red component of the fog color + * @param g the green component of the fog color + * @param b the blue component of the fog color + */ + public Fog(float r, float g, float b) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((FogRetained)this.retained).initColor(r, g, b); + } + + /** + * Sets the fog color to the specified color. + * @param color the new fog color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setColor(Color3f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog0")); + + if (isLive()) + ((FogRetained)this.retained).setColor(color); + else + ((FogRetained)this.retained).initColor(color); + } + + /** + * Sets the fog color to the specified color. + * @param r the red component of the fog color + * @param g the green component of the fog color + * @param b the blue component of the fog color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setColor(float r, float g, float b) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog0")); + + if (isLive()) + ((FogRetained)this.retained).setColor(r, g, b); + else + ((FogRetained)this.retained).initColor(r, g, b); + } + + /** + * Retrieves the fog color. + * @param color the vector that will receive the current fog color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getColor(Color3f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog2")); + + ((FogRetained)this.retained).getColor(color); + } + + /** + * Sets the Fog's influencing region to the specified bounds. + * This is used when the influencing bounding leaf is set to null. + * @param region the bounds that contains the Fog's new influencing region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInfluencingBounds(Bounds region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog3")); + + if (isLive()) + ((FogRetained)this.retained).setInfluencingBounds(region); + else + ((FogRetained)this.retained).initInfluencingBounds(region); + + } + + /** + * Retrieves the Fog node's influencing bounds. + * @return this Fog's influencing bounds information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getInfluencingBounds() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog4")); + + return ((FogRetained)this.retained).getInfluencingBounds(); + } + + /** + * Sets the Fog's influencing region to the specified bounding leaf. + * When set to a value other than null, this overrides the influencing + * bounds object. + * @param region the bounding leaf node used to specify the Fog + * node's new influencing region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInfluencingBoundingLeaf(BoundingLeaf region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog3")); + + if (isLive()) + ((FogRetained)this.retained).setInfluencingBoundingLeaf(region); + else + ((FogRetained)this.retained).initInfluencingBoundingLeaf(region); + } + + /** + * Retrieves the Fog node's influencing bounding leaf. + * @return this Fog's influencing bounding leaf information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BoundingLeaf getInfluencingBoundingLeaf() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog4")); + + return ((FogRetained)this.retained).getInfluencingBoundingLeaf(); + } + + + /** + * Replaces the node at the specified index in this Fog node's + * list of scopes with the specified Group node. + * By default, Fog nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be stored at the specified index. + * @param index the index of the Group node to be replaced. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void setScope(Group scope, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog7")); + + + if (isLive()) + ((FogRetained)this.retained).setScope(scope, index); + else + ((FogRetained)this.retained).initScope(scope, index); + } + + + /** + * Retrieves the Group node at the specified index from this Fog node's + * list of scopes. + * @param index the index of the Group node to be returned. + * @return the Group node at the specified index. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Group getScope(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog8")); + + return ((FogRetained)this.retained).getScope(index); + } + + + /** + * Inserts the specified Group node into this Fog node's + * list of scopes at the specified index. + * By default, Fog nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be inserted at the specified index. + * @param index the index at which the Group node is inserted. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void insertScope(Group scope, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog9")); + + if (isLive()) + ((FogRetained)this.retained).insertScope(scope, index); + else + ((FogRetained)this.retained).initInsertScope(scope, index); + } + + + /** + * Removes the node at the specified index from this Fog node's + * list of scopes. If this operation causes the list of scopes to + * become empty, then this Fog will have universe scope: all nodes + * within the region of influence will be affected by this Fog node. + * @param index the index of the Group node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the group node at the + * specified index is part of a compiled scene graph + */ + public void removeScope(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog10")); + + if (isLive()) + ((FogRetained)this.retained).removeScope(index); + else + ((FogRetained)this.retained).initRemoveScope(index); + } + + + /** + * Returns an enumeration of this Fog node's list of scopes. + * @return an Enumeration object containing all nodes in this Fog node's + * list of scopes. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Enumeration getAllScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog11")); + + return (Enumeration) ((FogRetained)this.retained).getAllScopes(); + } + + + /** + * Appends the specified Group node to this Fog node's list of scopes. + * By default, Fog nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be appended. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void addScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog12")); + + if (isLive()) + ((FogRetained)this.retained).addScope(scope); + else + ((FogRetained)this.retained).initAddScope(scope); + } + + + /** + * Returns the number of nodes in this Fog node's list of scopes. + * If this number is 0, then the list of scopes is empty and this + * Fog node has universe scope: all nodes within the region of + * influence are affected by this Fog node. + * @return the number of nodes in this Fog node's list of scopes. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int numScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog11")); + + return ((FogRetained)this.retained).numScopes(); + } + + + /** + * Retrieves the index of the specified Group node in this + * Fog node's list of scopes. + * + * @param scope the Group node to be looked up. + * @return the index of the specified Group node; + * returns -1 if the object is not in the list. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int indexOfScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog8")); + return ((FogRetained)this.retained).indexOfScope(scope); + } + + + /** + * Removes the specified Group node from this Fog + * node's list of scopes. If the specified object is not in the + * list, the list is not modified. If this operation causes the + * list of scopes to become empty, then this Fog + * will have universe scope: all nodes within the region of + * influence will be affected by this Fog node. + * + * @param scope the Group node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog10")); + + if (isLive()) + ((FogRetained)this.retained).removeScope(scope); + else + ((FogRetained)this.retained).initRemoveScope(scope); + } + + + /** + * Removes all Group nodes from this Fog node's + * list of scopes. The Fog node will then have + * universe scope: all nodes within the region of influence will + * be affected by this Fog node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if any group node in this + * node's list of scopes is part of a compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeAllScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Fog10")); + + if (isLive()) + ((FogRetained)this.retained).removeAllScopes(); + else + ((FogRetained)this.retained).initRemoveAllScopes(); + } + + + /** + * Copies all Fog information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + FogRetained attr = (FogRetained) originalNode.retained; + FogRetained rt = (FogRetained) retained; + + Color3f c = new Color3f(); + attr.getColor(c); + rt.initColor(c); + rt.initInfluencingBounds(attr.getInfluencingBounds()); + + Enumeration elm = attr.getAllScopes(); + while (elm.hasMoreElements()) { + // this reference will set correctly in updateNodeReferences() callback + rt.initAddScope((Group) elm.nextElement()); + } + + // this reference will set correctly in updateNodeReferences() callback + rt.initInfluencingBoundingLeaf(attr.getInfluencingBoundingLeaf()); + } + + /** + * Callback used to allow a node to check if any nodes referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any node references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding Node in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * node is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + + FogRetained rt = (FogRetained) retained; + BoundingLeaf bl = rt.getInfluencingBoundingLeaf(); + + if (bl != null) { + Object o = referenceTable.getNewObjectReference(bl); + rt.initInfluencingBoundingLeaf((BoundingLeaf) o); + } + + + int num = rt.numScopes(); + for (int i=0; i < num; i++) { + rt.initScope((Group) referenceTable. + getNewObjectReference(rt.getScope(i)), i); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/FogRetained.java b/j3d-core/src/classes/share/javax/media/j3d/FogRetained.java new file mode 100644 index 0000000..7bde7fa --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/FogRetained.java @@ -0,0 +1,827 @@ +/* + * $RCSfile: FogRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.Enumeration; +import java.util.Vector; +import java.util.ArrayList; + +/** + * The Fog leaf node defines Fog parameters. + * It also specifies an region of influence in which this fog node + * is active. + */ +abstract class FogRetained extends LeafRetained{ + + // Statics used when something in the fog changes + static final int COLOR_CHANGED = 0x0001; + static final int SCOPE_CHANGED = 0x0002; + static final int BOUNDS_CHANGED = 0x0004; + static final int BOUNDINGLEAF_CHANGED = 0x0008; + static final int INIT_MIRROR = 0x0010; + static final int CLEAR_MIRROR = 0x0020; + static final int LAST_DEFINED_BIT = 0x0020; + + // Fog color. + Color3f color = new Color3f(0.0f, 0.0f, 0.0f); + + /** + * The Boundary object defining the lights's region of influence. + */ + Bounds regionOfInfluence = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * Vector of GroupRetained nodes that scopes this fog. + */ + Vector scopes = new Vector(); + + // An int that is set when this fog is changed + int isDirty = 0xffff; + + // This is true when this fog is referenced in an immediate mode context + boolean inImmCtx = false; + + /** + * The transformed value of the applicationRegion. + */ + Bounds region = null; + + // A reference to the scene graph fog + FogRetained sgFog = null; + + // The mirror copy of this fog + FogRetained mirrorFog = null; + + // Target threads to be notified when light changes + static final int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_RENDER; + + // Boolean to indicate if this object is scoped (only used for mirror objects + boolean isScoped = false; + + // The object that contains the dynamic HashKey - a string type object + // Used in scoping + HashKey tempKey = new HashKey(250); + + /** + * The EnvironmentSets which reference this fog. + * Note that multiple RenderBin update thread may access + * this shared environmentSets simultaneously. + * So we use UnorderList when sync. all the operations. + */ + UnorderList environmentSets = new UnorderList(1, EnvironmentSet.class); + + // Is true, if the mirror fog is viewScoped + boolean isViewScoped = false; + + // Scale value extracted from localToVworld transform + private double localToVworldScale = 1.0; + + FogRetained() { + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + /** + * Initialize the fog color to the specified color. + */ + void initColor(Color3f color) { + this.color.set(color); + } + /** + * Sets the fog color to the specified color and send message + */ + void setColor(Color3f color) { + this.color.set(color); + sendMessage(COLOR_CHANGED, new Color3f(color)); + } + + /** + * Sets the fog color to the specified color. + */ + void initColor(float r, float g, float b) { + this.color.x = r; + this.color.y = g; + this.color.z = b; + } + /** + * Sets the fog color to the specified color and send message + */ + void setColor(float r, float g, float b) { + initColor(r, g, b); + sendMessage(COLOR_CHANGED, new Color3f(r, g, b)); + } + + /** + * Retrieves the fog color. + */ + void getColor(Color3f color) { + color.set(this.color); + } + + /** + * Set the Fog's region of influence. + */ + void initInfluencingBounds(Bounds region) { + if (region != null) { + this.regionOfInfluence = (Bounds) region.clone(); + } else { + this.regionOfInfluence = null; + } + if (staticTransform != null) { + this.regionOfInfluence.transform(staticTransform.transform); + } + } + + /** + * Set the Fog's region of influence and send message + */ + void setInfluencingBounds(Bounds region) { + initInfluencingBounds(region); + sendMessage(BOUNDS_CHANGED, + (region != null ? region.clone() : null)); + } + + /** + * Get the Fog's region of Influence. + */ + Bounds getInfluencingBounds() { + Bounds b = null; + if (regionOfInfluence != null) { + b = (Bounds)regionOfInfluence.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + } + return b; + } + + /** + * Set the Fog's region of influence to the specified Leaf node. + */ + void initInfluencingBoundingLeaf(BoundingLeaf region) { + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + } else { + boundingLeaf = null; + } + } + + /** + * Set the Fog's region of influence to the specified Leaf node. + */ + void setInfluencingBoundingLeaf(BoundingLeaf region) { + if (boundingLeaf != null) + boundingLeaf.mirrorBoundingLeaf.removeUser(mirrorFog); + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + boundingLeaf.mirrorBoundingLeaf.addUser(mirrorFog); + } else { + boundingLeaf = null; + } + sendMessage(BOUNDINGLEAF_CHANGED, + (boundingLeaf != null ? + boundingLeaf.mirrorBoundingLeaf : null)); + } + + + /** + * Get the Fog's region of influence. + */ + BoundingLeaf getInfluencingBoundingLeaf() { + return (boundingLeaf != null ? + (BoundingLeaf)boundingLeaf.source : null); + } + + /** + * Replaces the specified scope with the scope provided. + * @param scope the new scope + * @param index which scope to replace + */ + void initScope(Group scope, int index) { + scopes.setElementAt((GroupRetained)(scope.retained), index); + + } + + /** + * Replaces the specified scope with the scope provided. + * @param scope the new scope + * @param index which scope to replace + */ + void setScope(Group scope, int index) { + + ArrayList addScopeList = new ArrayList(); + ArrayList removeScopeList = new ArrayList(); + GroupRetained group; + Object[] scopeInfo = new Object[3]; + + + group = (GroupRetained) scopes.get(index); + tempKey.reset(); + group.removeAllNodesForScopedFog(mirrorFog, removeScopeList, tempKey); + + group = (GroupRetained)scope.retained; + initScope(scope, index); + tempKey.reset(); + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + group.addAllNodesForScopedFog(mirrorFog,addScopeList, tempKey); + + scopeInfo[0] = addScopeList; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE:Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + /** + * Inserts the specified scope at specified index.before the + * fog is live + * @param scope the new scope + * @param index position to insert new scope at + */ + void initInsertScope(Node scope, int index) { + GroupRetained group = (GroupRetained)scope.retained; + group.setFogScope(); + scopes.insertElementAt((GroupRetained)(scope.retained), index); + } + + /** + * Inserts the specified scope at specified index and sends + * a message + * @param scope the new scope + * @param index position to insert new scope at + */ + void insertScope(Node scope, int index) { + Object[] scopeInfo = new Object[3]; + ArrayList addScopeList = new ArrayList(); + + initInsertScope(scope, index); + GroupRetained group = (GroupRetained)scope.retained; + tempKey.reset(); + group.addAllNodesForScopedFog(mirrorFog,addScopeList, tempKey); + scopeInfo[0] = addScopeList; + scopeInfo[1] = null; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + + void initRemoveScope(int index) { + GroupRetained group = (GroupRetained)scopes.elementAt(index); + scopes.removeElementAt(index); + group.removeFogScope(); + + } + + void removeScope(int index) { + + Object[] scopeInfo = new Object[3]; + ArrayList removeScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scopes.elementAt(index); + + tempKey.reset(); + group.removeAllNodesForScopedFog(mirrorFog, removeScopeList, tempKey); + + initRemoveScope(index); + scopeInfo[0] = null; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + + /** + * Returns the scope specified by the index. + * @param index which scope to return + * @return the scoperen at location index + */ + Group getScope(int index) { + return (Group)(((GroupRetained)(scopes.elementAt(index))).source); + } + + /** + * Returns an enumeration object of the scoperen. + * @return an enumeration object of the scoperen + */ + Enumeration getAllScopes() { + Enumeration elm = scopes.elements(); + Vector v = new Vector(scopes.size()); + while (elm.hasMoreElements()) { + v.add( ((GroupRetained) elm.nextElement()).source); + } + return v.elements(); + } + + /** + * Appends the specified scope to this node's list of scopes before + * the fog is alive + * @param scope the scope to add to this node's list of scopes + */ + void initAddScope(Group scope) { + GroupRetained group = (GroupRetained)scope.retained; + scopes.addElement((GroupRetained)(scope.retained)); + group.setFogScope(); + } + + /** + * Appends the specified scope to this node's list of scopes. + * @param scope the scope to add to this node's list of scopes + */ + void addScope(Group scope) { + + Object[] scopeInfo = new Object[3]; + ArrayList addScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scope.retained; + + initAddScope(scope); + tempKey.reset(); + group.addAllNodesForScopedFog(mirrorFog,addScopeList, tempKey); + scopeInfo[0] = addScopeList; + scopeInfo[1] = null; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + /** + * Returns a count of this nodes' scopes. + * @return the number of scopes descendant from this node + */ + int numScopes() { + return scopes.size(); + } + + /** + * Returns the index of the specified scope within this nodes' list of scopes + * @param scope whose index is desired + * @return index of specified scope + */ + int indexOfScope(Group scope) { + if(scope != null) + return scopes.indexOf((GroupRetained)scope.retained); + else + return scopes.indexOf(null); + } + + /** + * Removes the specified scope from this nodes' list of scopes + * @param scope to be removed. If the scope is not found, + * the method returns silently + */ + void removeScope(Group scope) { + int i = indexOfScope(scope); + if(i >= 0) + removeScope(i); + } + + void initRemoveScope(Group scope) { + int i = indexOfScope(scope); + if(i >= 0) + initRemoveScope(i); + } + + /** + * Removes all the scopes from this node's list of scopes. + * The node should revert to universal + * scope after this method returns + */ + void removeAllScopes() { + Object[] scopeInfo = new Object[3]; + ArrayList removeScopeList = new ArrayList(); + GroupRetained group; + int n = scopes.size(); + + tempKey.reset(); + for(int index = n-1; index >= 0; index--) { + group = (GroupRetained)scopes.elementAt(index); + group.removeAllNodesForScopedFog(mirrorFog, removeScopeList, tempKey); + initRemoveScope(index); + } + scopeInfo[0] = null; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = Boolean.FALSE; + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + /** + * Removes all scopes from this node + */ + void initRemoveAllScopes() { + int n = scopes.size(); + for(int index = n-1; index >= 0; index--) + initRemoveScope(index); + } + + /** + * This sets the immedate mode context flag + */ + void setInImmCtx(boolean inCtx) { + inImmCtx = inCtx; + } + + /** + * This gets the immedate mode context flag + */ + boolean getInImmCtx() { + return (inImmCtx); + } + + boolean isScoped() { + return (scopes != null); + } + + /** + * This abstract method is used to update the current native + * context fog values. + */ + abstract void update(Context ctx, double scale); + + + void updateImmediateMirrorObject(Object[] objs) { + GroupRetained group; + Vector currentScopes; + int i, nscopes; + Transform3D trans; + + int component = ((Integer)objs[1]).intValue(); + if ((component & BOUNDS_CHANGED) != 0) { + mirrorFog.regionOfInfluence = (Bounds) objs[2]; + if (mirrorFog.boundingLeaf == null) { + if (objs[2] != null) { + mirrorFog.region = ((Bounds)mirrorFog.regionOfInfluence).copy(mirrorFog.region); + mirrorFog.region.transform( + mirrorFog.regionOfInfluence, + getCurrentLocalToVworld()); + } + else { + mirrorFog.region = null; + } + } + } + else if ((component & BOUNDINGLEAF_CHANGED) != 0) { + mirrorFog.boundingLeaf = (BoundingLeafRetained)objs[2]; + if (objs[2] != null) { + mirrorFog.region = (Bounds)mirrorFog.boundingLeaf.transformedRegion; + } + else { + if (mirrorFog.regionOfInfluence != null) { + mirrorFog.region = ((Bounds)mirrorFog.regionOfInfluence).copy(mirrorFog.region); + mirrorFog.region.transform( + mirrorFog.regionOfInfluence, + getCurrentLocalToVworld()); + } + else { + mirrorFog.region = null; + } + + } + } + else if ((component & SCOPE_CHANGED) != 0) { + Object[] scopeList = (Object[])objs[2]; + ArrayList addList = (ArrayList)scopeList[0]; + ArrayList removeList = (ArrayList)scopeList[1]; + boolean isScoped = ((Boolean)scopeList[2]).booleanValue(); + + if (addList != null) { + mirrorFog.isScoped = isScoped; + for (i = 0; i < addList.size(); i++) { + Shape3DRetained obj = ((GeometryAtom)addList.get(i)).source; + obj.addFog(mirrorFog); + } + } + + if (removeList != null) { + mirrorFog.isScoped = isScoped; + for (i = 0; i < removeList.size(); i++) { + Shape3DRetained obj = ((GeometryAtom)removeList.get(i)).source; + obj.removeFog(mirrorFog); + } + } + } + + + } + + /** + * The update Object function. + */ + void updateMirrorObject(Object[] objs) { + + int component = ((Integer)objs[1]).intValue(); + if ((component & COLOR_CHANGED) != 0) { + mirrorFog.color.set((Color3f)objs[2]); + } + if ((component & INIT_MIRROR) != 0) { + mirrorFog.color.set((Color3f)objs[3]); + } + } + + + /** + * Note: This routine will only be called on + * the mirror object - will update the object's + * cached region and transformed region + */ + void updateBoundingLeaf() { + if (boundingLeaf != null && boundingLeaf.switchState.currentSwitchOn) { + region = boundingLeaf.transformedRegion; + } else { + if (regionOfInfluence != null) { + region = regionOfInfluence.copy(region); + region.transform(regionOfInfluence, + getCurrentLocalToVworld()); + } else { + region = null; + } + } + } + + /** + * This setLive routine just calls the superclass's method (after + * checking for use by an immediate context). It is up to the + * subclasses of fog to add themselves to the list of fogs + */ + void setLive(SetLiveState s) { + GroupRetained group; + Vector currentScopes; + int i, nscopes; + TransformGroupRetained[] tlist; + + if (inImmCtx) { + throw new IllegalSharingException(J3dI18N.getString("FogRetained0")); + } + super.doSetLive(s); + + if (inSharedGroup) { + throw new + IllegalSharingException(J3dI18N.getString("FogRetained1")); + } + + + // Create the mirror object + // Initialization of the mirror object during the INSERT_NODE + // message (in updateMirrorObject) + if (mirrorFog == null) { + // mirrorFog = (FogRetained)this.clone(true); + mirrorFog = (FogRetained)this.clone(); + // Assign the bounding leaf of this mirror object as null + // it will later be assigned to be the mirror of the lights + // bounding leaf object + mirrorFog.boundingLeaf = null; + mirrorFog.sgFog = this; + } + // initMirrorObject(); + // If bounding leaf is not null, add the mirror object as a user + // so that any changes to the bounding leaf will be received + if (boundingLeaf != null) { + boundingLeaf.mirrorBoundingLeaf.addUser(mirrorFog); + } + + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(mirrorFog); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(mirrorFog); + } + + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(mirrorFog, Targets.ENV_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + + + + // process switch leaf + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(mirrorFog, Targets.ENV_TARGETS); + } + mirrorFog.switchState = (SwitchState)s.switchStates.get(0); + + s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER; + + + + super.markAsLive(); + + + } + // This is called on the parent object + void initMirrorObject(Object[] args) { + Shape3DRetained shape; + Object[] scopeInfo = (Object[]) args[2]; + Boolean scoped = (Boolean)scopeInfo[0]; + ArrayList shapeList = (ArrayList)scopeInfo[1]; + BoundingLeafRetained bl=(BoundingLeafRetained)((Object[])args[4])[0]; + Bounds bnds = (Bounds)((Object[])args[4])[1]; + + mirrorFog.inBackgroundGroup = ((Boolean)((Object[])args[4])[2]).booleanValue(); + mirrorFog.geometryBackground = (BackgroundRetained)((Object[])args[4])[3]; + for (int i = 0; i < shapeList.size(); i++) { + shape = ((GeometryAtom)shapeList.get(i)).source; + shape.addFog(mirrorFog); + } + mirrorFog.isScoped = scoped.booleanValue(); + + if (bl != null) { + mirrorFog.boundingLeaf = bl.mirrorBoundingLeaf; + mirrorFog.region = boundingLeaf.transformedRegion; + } else { + mirrorFog.boundingLeaf = null; + mirrorFog.region = null; + } + + if (bnds != null) { + mirrorFog.regionOfInfluence = bnds; + if (mirrorFog.region == null) { + mirrorFog.region = (Bounds)regionOfInfluence.clone(); + mirrorFog.region.transform(regionOfInfluence, getLastLocalToVworld()); + } + } + else { + mirrorFog.regionOfInfluence = null; + } + + } + + // This is called on the parent object + void clearMirrorObject(Object[] args) { + Shape3DRetained shape; + ArrayList shapeList = (ArrayList)args[2]; + ArrayList removeScopeList = new ArrayList(); + + for (int i = 0; i < shapeList.size(); i++) { + shape = ((GeometryAtom)shapeList.get(i)).source; + shape.removeFog(mirrorFog); + } + mirrorFog.isScoped = false; + + + + } + + + + /** + * This clearLive routine first calls the superclass's method, then + * it removes itself to the list of fogs + */ + void clearLive(SetLiveState s) { + int i, j; + GroupRetained group; + + super.clearLive(s); + + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(mirrorFog, Targets.ENV_TARGETS); + } + s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER; + + // Remove this mirror light as users of the bounding leaf + if (mirrorFog.boundingLeaf != null) + mirrorFog.boundingLeaf.removeUser(mirrorFog); + + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(mirrorFog); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(mirrorFog); + } + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(mirrorFog, Targets.ENV_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + + + if (scopes.size() > 0) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.universe = universe; + createMessage.type = J3dMessage.FOG_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(CLEAR_MIRROR); + ArrayList removeScopeList = new ArrayList(); + for (i = 0; i < scopes.size(); i++) { + group = (GroupRetained)scopes.get(i); + tempKey.reset(); + group.removeAllNodesForScopedFog(mirrorFog, removeScopeList, tempKey); + } + createMessage.args[2] = removeScopeList; + VirtualUniverse.mc.processMessage(createMessage); + } + } + + // Clone the retained side only, internal use only + protected Object clone() { + FogRetained fr = (FogRetained)super.clone(); + + fr.color = new Color3f(color); + Bounds b = getInfluencingBounds(); + if (b != null) { + fr.initInfluencingBounds(b); + } + + fr.scopes = new Vector(); + fr.isDirty = 0xffff; + fr.inImmCtx = false; + fr.region = null; + fr.sgFog = null; + fr.mirrorFog = null; + fr.environmentSets = new UnorderList(1, EnvironmentSet.class); + return fr; + } + + void updateTransformChange() { + super.updateTransformChange(); + setLocalToVworldScale(sgFog.getLastLocalToVworld().getDistanceScale()); + } + + // Called on mirror object + void updateImmediateTransformChange() { + // If bounding leaf is null, tranform the bounds object + if (boundingLeaf == null) { + if (regionOfInfluence != null) { + region = regionOfInfluence.copy(region); + region.transform(regionOfInfluence, + sgFog.getCurrentLocalToVworld()); + } + + } + } + + final void sendMessage(int attrMask, Object attr) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.universe = universe; + createMessage.type = J3dMessage.FOG_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + VirtualUniverse.mc.processMessage(createMessage); + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + if (regionOfInfluence != null) { + regionOfInfluence.transform(xform.transform); + } + } + void getMirrorObjects(ArrayList leafList, HashKey key) { + leafList.add(mirrorFog); + } + + /** + * Scale distances from local to eye coordinate + */ + protected void validateDistancesInEc(double vworldToCoexistenceScale) { + assert false : "subclasses should override this method"; + } + + double getLocalToVworldScale() { + return localToVworldScale; + } + + void setLocalToVworldScale(double localToVworldScale) { + this.localToVworldScale = localToVworldScale; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Font3D.java b/j3d-core/src/classes/share/javax/media/j3d/Font3D.java new file mode 100644 index 0000000..100eae5 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Font3D.java @@ -0,0 +1,1167 @@ +/* + * $RCSfile: Font3D.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import com.sun.j3d.utils.geometry.*; +import com.sun.j3d.internal.FastVector; +import java.awt.Font; +import java.awt.font.*; +import java.awt.geom.Rectangle2D; +import java.awt.geom.AffineTransform; +import javax.vecmath.*; +import java.awt.Shape; +import java.awt.geom.PathIterator; +import java.util.*; + +/** + * The Font3D object is used to store extruded 2D glyphs. These + * 3D glyphs can then be used to construct Text3D NodeComponent + * objects. + *

+ * A 3D Font consists of a Java 2D font, a tesellation tolerance, + * and an extrusion path. The extrusion + * path creates depth by describing how the edge of a glyph varies + * in the Z axis. + *

+ * The construction of a Text3D object requires a Font3D object. + * The Font3D object describes the style of the text, such as its + * depth. The text also needs other classes, such as java.awt.Font and + * FontExtrusion. The Font object describes the font name (Helvetica, + * Courier, etc.), the font style (bold, Italic, etc.), and point + * size. The FontExtrusion object extends Font3D by describing + * the extrusion path for the Font3D object (how the edge of the + * font glyph varies in the Z axis). + *

+ * To ensure correct rendering, the 2D Font object should be created + * with the default AffineTransform. The point size of the 2D font will + * be used as a rough measure of how fine a tesselation to use when + * creating the Font3D object: the larger the point size, in + * general, the finer the tesselation. + *

+ * Custom 3D fonts as well as methods to store 3D fonts + * to disk will be addressed in a future release. + * + * @see java.awt.Font + * @see FontExtrusion + * @see Text3D + */ +public class Font3D extends NodeComponent { + + Font font; + double tessellationTolerance; + FontExtrusion fontExtrusion; + FontRenderContext frc; + // Used by triangulateGlyphs method to split contour data into islands. + final static float EPS = 0.000001f; + + // Map glyph code to GeometryArrayRetained + Hashtable geomHash = new Hashtable(20); + + /** + * Constructs a Font3D object from the specified Font and + * FontExtrusion objects, using the default value for the + * tessellation tolerance. The default value is as follows: + * + *

    + * tessellation tolerance : 0.01
    + *
+ *

+ * The FontExtrusion object contains the extrusion path to use on + * the 2D Font glyphs. To ensure correct rendering the font must + * be created with the default AffineTransform. Passing null for + * the FontExtrusion parameter results in no extrusion being done. + * + * @param font the Java 2D font used to create the 3D font object + * @param extrudePath the extrusion path used to describe how + * the edge of the font varies along the Z axis + */ + public Font3D(Font font, FontExtrusion extrudePath) { + this(font, 0.01, extrudePath); + } + + /** + * Constructs a Font3D object from the specified Font and + * FontExtrusion objects, using the specified tessellation + * tolerance. + * The FontExtrusion object contains the extrusion path to use on + * the 2D Font glyphs. To ensure correct rendering, the font must + * be created with the default AffineTransform. Passing null for + * the FontExtrusion parameter results in no extrusion being done. + * + * @param font the Java 2D font used to create the 3D font object. + * @param tessellationTolerance the tessellation tolerance value + * used in tessellating the glyphs of the 2D Font. + * This corresponds to the flatness parameter in + * the java.awt.Shape.getPathIterator method. + * @param extrudePath the extrusion path used to describe how + * the edge of the font varies along the Z axis. + * + * @since Java 3D 1.2 + */ + public Font3D(Font font, + double tessellationTolerance, + FontExtrusion extrudePath) { + + this.font = font; + this.tessellationTolerance = tessellationTolerance; + this.fontExtrusion = extrudePath; + this.frc = new FontRenderContext(new AffineTransform(), + true, true); + } + + /** + * Returns the Java 2D Font used to create this Font3D object. + * @return Font object used by this Font3D + */ + public Font getFont() { + return this.font; + } + + + /** + * Returns the tessellation tolerance with which this Font3D was + * created. + * @return the tessellation tolerance used by this Font3D + * + * @since Java 3D 1.2 + */ + public double getTessellationTolerance() { + return tessellationTolerance; + } + + + /** + * Copies the FontExtrusion object used to create this Font3D object + * into the specified parameter. + * + * @param extrudePath object that will receive the + * FontExtrusion information for this Font3D object + */ + public void getFontExtrusion(FontExtrusion extrudePath) { + extrudePath = this.fontExtrusion; + } + + /** + * Returns the 3D bounding box of the specified glyph code. + * + * @param glyphCode the glyphCode from the original 2D Font + * @param bounds the 3D glyph's bounds + */ + public void getBoundingBox(int glyphCode, BoundingBox bounds){ + int[] gCodes = {glyphCode}; + GlyphVector gVec = font.createGlyphVector(frc, gCodes); + Rectangle2D.Float bounds2d = (Rectangle2D.Float) + (((GlyphMetrics)(gVec.getGlyphMetrics(0))).getBounds2D()); + + Point3d lower = new Point3d(bounds2d.x, bounds2d.y, 0.0); + Point3d upper; + if (fontExtrusion != null) { + upper = new Point3d(bounds2d.x + bounds2d.width, + bounds2d.y + bounds2d.height, + fontExtrusion.length); + } else { + upper = new Point3d(bounds2d.x + bounds2d.width, + bounds2d.y + bounds2d.height, + 0.0); + } + bounds.setLower(lower); + bounds.setUpper(upper); + } + + // BY MIK OF CLASSX + /** + * Returns a GeometryArray of a glyph in this Font3D. + * + * @param c character from which to generate a tessellated glyph. + * + * @return a GeometryArray + * + * @since Java 3D 1.4 + */ + public GeometryArray getGlyphGeometry(char c) { + char code[] = { c }; + GlyphVector gv = font.createGlyphVector(frc, code); + + // triangulate the glyph + GeometryArrayRetained glyph_gar = triangulateGlyphs(gv, code[0]); + + // Assume that triangulateGlyphs returns a triangle array with only coords & normals + // (and without by-ref, interleaved, etc.) + assert glyph_gar instanceof TriangleArrayRetained : + "Font3D: GeometryArray is not an instance of TrangleArray"; + assert glyph_gar.getVertexFormat() == (GeometryArray.COORDINATES | GeometryArray.NORMALS) : + "Font3D: Illegal GeometryArray format -- only coordinates and normals expected"; + + // create a correctly sized TriangleArray + TriangleArray ga = new TriangleArray(glyph_gar.getVertexCount(),glyph_gar.getVertexFormat()); + + // temp storage for coords, normals + float tmp[] = new float[3]; + + int vertexCount = ga.getVertexCount(); + for(int i=0; i 0) { + if (setMaxY) { + // Get Previous point + beginIdx = start; + endIdx = numPoints-1; + } + contours.addElement(num); + num = 0; + numContours++; + } + } else if (flag == PathIterator.SEG_MOVETO){ + vertex.x = tmpCoords[0]; + vertex.y = tmpCoords[1]; + lastX = vertex.x; + lastY = vertex.y; + + if ((lastX == firstPntx) && (lastY == firstPnty)) { + pIt.next(); + continue; + } + setMaxY = false; + coords.add(vertex); + firstPntx = lastX; + firstPnty = lastY; + if (num> 0){ + contours.addElement(num); + num = 0; + numContours++; + } + num++; + numPoints++; + // skip checking of first point, + // since the last point will repeat this. + start = numPoints ; + } else if (flag == PathIterator.SEG_LINETO){ + vertex.x = tmpCoords[0]; + vertex.y = tmpCoords[1]; + //Check here for duplicate points. Code + //later in this function can not handle + //duplicate points. + + if ((vertex.x == lastX) && (vertex.y == lastY)) { + pIt.next(); + continue; + } + if (vertex.y > maxY) { + maxY = vertex.y; + maxYIndex = numPoints; + setMaxY = true; + } + lastX = vertex.x; + lastY = vertex.y; + coords.add(vertex); + num++; + numPoints++; + } + pIt.next(); + } + + // No data(e.g space, control characters) + // Two point can't form a valid contour + if (numPoints == 0){ + return null; + } + + + + // Determine font winding order use for side triangles + Point3f p1 = new Point3f(), p2 = new Point3f(), p3 = new Point3f(); + boolean flip_side_orient = true; + Point3f vertices[] = (Point3f []) coords.toArray(false); + + if (endIdx - beginIdx > 0) { + // must be true unless it is a single line + // define as "MoveTo p1 LineTo p2 Close" which is + // not a valid font definition. + + if (maxYIndex == beginIdx) { + p1.set(vertices[endIdx]); + } else { + p1.set(vertices[maxYIndex-1]); + } + p2.set(vertices[maxYIndex]); + if (maxYIndex == endIdx) { + p3.set(vertices[beginIdx]); + } else { + p3.set(vertices[maxYIndex+1]); + } + + if (p3.x != p2.x) { + if (p1.x != p2.x) { + // Use the one with smallest slope + if (Math.abs((p2.y - p1.y)/(p2.x - p1.x)) > + Math.abs((p3.y - p2.y)/(p3.x - p2.x))) { + flip_side_orient = (p3.x > p2.x); + } else { + flip_side_orient = (p2.x > p1.x); + } + } else { + flip_side_orient = (p3.x > p2.x); + } + } else { + // p1.x != p2.x, otherwise all three + // point form a straight vertical line with + // the middle point the highest. This is not a + // valid font definition. + flip_side_orient = (p2.x > p1.x); + } + } + + // Build a Tree of Islands + int startIdx = 0; + IslandsNode islandsTree = new IslandsNode(-1, -1); + int contourCounts[] = contours.getData(); + + + for (i= 0;i < contours.getSize(); i++) { + endIdx = startIdx + contourCounts[i]; + islandsTree.insert(new IslandsNode(startIdx, endIdx), vertices); + startIdx = endIdx; + } + + coords = null; // Free memory + contours = null; + contourCounts = null; + + // Compute islandCounts[][] and outVerts[][] + UnorderList islandsList = new UnorderList(10, IslandsNode.class); + islandsTree.collectOddLevelNode(islandsList, 0); + IslandsNode nodes[] = (IslandsNode []) islandsList.toArray(false); + int islandCounts[][] = new int[islandsList.arraySize()][]; + Point3f outVerts[][] = new Point3f[islandCounts.length][]; + int nchild, sum; + IslandsNode node; + + for (i=0; i < islandCounts.length; i++) { + node = nodes[i]; + nchild = node.numChild(); + islandCounts[i] = new int[nchild + 1]; + islandCounts[i][0] = node.numVertices(); + sum = 0; + sum += islandCounts[i][0]; + for (j=0; j < nchild; j++) { + islandCounts[i][j+1] = node.getChild(j).numVertices(); + sum += islandCounts[i][j+1]; + } + outVerts[i] = new Point3f[sum]; + startIdx = 0; + for (k=node.startIdx; k < node.endIdx; k++) { + outVerts[i][startIdx++] = vertices[k]; + } + + for (j=0; j < nchild; j++) { + endIdx = node.getChild(j).endIdx; + for (k=node.getChild(j).startIdx; k < endIdx; k++) { + outVerts[i][startIdx++] = vertices[k]; + } + } + } + + + + islandsTree = null; // Free memory + islandsList = null; + vertices = null; + + contourCounts = new int[1]; + int currCoordIndex = 0, vertOffset = 0; + ArrayList triangData = new ArrayList(); + + Point3f q1 = new Point3f(), q2 = new Point3f(), q3 = new Point3f(); + Vector3f n1 = new Vector3f(), n2 = new Vector3f(); + numPoints = 0; + //Now loop thru each island, calling triangulator once per island. + //Combine triangle data for all islands together in one object. + for (i=0;i < islandCounts.length;i++) { + contourCounts[0] = islandCounts[i].length; + numPoints += outVerts[i].length; + gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY); + gi.setCoordinates(outVerts[i]); + gi.setStripCounts(islandCounts[i]); + gi.setContourCounts(contourCounts); + ng.generateNormals(gi); + + GeometryArray ga = gi.getGeometryArray(false, false, false); + vertOffset += ga.getVertexCount(); + + triangData.add(ga); + } + // Multiply by 2 since we create 2 faces of the font + // Second term is for side-faces along depth of the font + if (fontExtrusion == null) + vertCnt = vertOffset; + else{ + if (fontExtrusion.shape == null) + vertCnt = vertOffset * 2 + numPoints *6; + else{ + vertCnt = vertOffset * 2 + numPoints * 6 * + (fontExtrusion.pnts.length -1); + } + } + + // XXXX: Should use IndexedTriangleArray to avoid + // duplication of vertices. To create triangles for + // side faces, every vertex is duplicated currently. + TriangleArray triAry = new TriangleArray(vertCnt, + GeometryArray.COORDINATES | + GeometryArray.NORMALS); + + boolean flip_orient[] = new boolean[islandCounts.length]; + boolean findOrient; + // last known non-degenerate normal + Vector3f goodNormal = new Vector3f(); + + + for (j=0;j < islandCounts.length;j++) { + GeometryArray ga = (GeometryArray)triangData.get(j); + vertOffset = ga.getVertexCount(); + + findOrient = false; + + //Create the triangle array + for (i= 0; i < vertOffset; i+= 3, currCoordIndex += 3){ + //Get 3 points. Since triangle is known to be flat, normal + // must be same for all 3 points. + ga.getCoordinate(i, p1); + ga.getNormal(i, n1); + ga.getCoordinate(i+1, p2); + ga.getCoordinate(i+2, p3); + + if (!findOrient) { + //Check here if triangles are wound incorrectly and need + //to be flipped. + if (!getNormal(p1,p2, p3, n2)) { + continue; + } + + if (n2.z >= EPS) { + flip_orient[j] = false; + } else if (n2.z <= -EPS) { + flip_orient[j] = true; + } else { + continue; + } + findOrient = true; + } + if (flip_orient[j]){ + //New Triangulator preserves contour orientation. If contour + //input is wound incorrectly, swap 2nd and 3rd points to + //sure all triangles are wound correctly for j3d. + q1.x = p2.x; q1.y = p2.y; q1.z = p2.z; + p2.x = p3.x; p2.y = p3.y; p2.z = p3.z; + p3.x = q1.x; p3.y = q1.y; p3.z = q1.z; + n1.x = -n1.x; n1.y = -n1.y; n1.z = -n1.z; + } + + + if (fontExtrusion != null) { + n2.x = -n1.x;n2.y = -n1.y;n2.z = -n1.z; + + triAry.setCoordinate(currCoordIndex, p1); + triAry.setNormal(currCoordIndex, n2); + triAry.setCoordinate(currCoordIndex+1, p3); + triAry.setNormal(currCoordIndex+1, n2); + triAry.setCoordinate(currCoordIndex+2, p2); + triAry.setNormal(currCoordIndex+2, n2); + + q1.x = p1.x; q1.y = p1.y; q1.z = p1.z + fontExtrusion.length; + q2.x = p2.x; q2.y = p2.y; q2.z = p2.z + fontExtrusion.length; + q3.x = p3.x; q3.y = p3.y; q3.z = p3.z + fontExtrusion.length; + + triAry.setCoordinate(currCoordIndex+vertOffset, q1); + triAry.setNormal(currCoordIndex+vertOffset, n1); + triAry.setCoordinate(currCoordIndex+1+vertOffset, q2); + triAry.setNormal(currCoordIndex+1+vertOffset, n1); + triAry.setCoordinate(currCoordIndex+2+vertOffset, q3); + triAry.setNormal(currCoordIndex+2+vertOffset, n1); + } else { + triAry.setCoordinate(currCoordIndex, p1); + triAry.setNormal(currCoordIndex, n1); + triAry.setCoordinate(currCoordIndex+1, p2); + triAry.setNormal(currCoordIndex+1, n1); + triAry.setCoordinate(currCoordIndex+2, p3); + triAry.setNormal(currCoordIndex+2, n1); + } + + } + if (fontExtrusion != null) { + currCoordIndex += vertOffset; + } + } + + //Now add side triangles in both cases. + + // Since we duplicated triangles with different Z, make sure + // currCoordIndex points to correct location. + if (fontExtrusion != null){ + if (fontExtrusion.shape == null){ + boolean smooth; + // we'll put a crease if the angle between the normals is + // greater than 44 degrees + float threshold = (float) Math.cos(44.0*Math.PI/180.0); + float cosine; + // need the previous normals to check for smoothing + Vector3f pn1 = null, pn2 = null; + // need the next normals to check for smoothing + Vector3f n3 = new Vector3f(), n4 = new Vector3f(); + // store the normals for each point because they are + // the same for both triangles + Vector3f p1Normal = new Vector3f(); + Vector3f p2Normal = new Vector3f(); + Vector3f p3Normal = new Vector3f(); + Vector3f q1Normal = new Vector3f(); + Vector3f q2Normal = new Vector3f(); + Vector3f q3Normal = new Vector3f(); + + for (i=0;i < islandCounts.length;i++){ + for (j=0, k=0, num =0;j < islandCounts[i].length;j++){ + num += islandCounts[i][j]; + p1.x = outVerts[i][num - 1].x; + p1.y = outVerts[i][num - 1].y; + p1.z = 0.0f; + q1.x = p1.x; q1.y = p1.y; q1.z = p1.z+fontExtrusion.length; + p2.z = 0.0f; + q2.z = p2.z+fontExtrusion.length; + for (int m=0; m < num;m++) { + p2.x = outVerts[i][m].x; + p2.y = outVerts[i][m].y; + q2.x = p2.x; + q2.y = p2.y; + if (getNormal(p1, q1, p2, n1)) { + + if (!flip_side_orient) { + n1.negate(); + } + goodNormal.set(n1); + break; + } + } + + for (;k < num;k++){ + p2.x = outVerts[i][k].x;p2.y = outVerts[i][k].y;p2.z = 0.0f; + q2.x = p2.x; q2.y = p2.y; q2.z = p2.z+fontExtrusion.length; + + if (!getNormal(p1, q1, p2, n1)) { + n1.set(goodNormal); + } else { + if (!flip_side_orient) { + n1.negate(); + } + goodNormal.set(n1); + } + + if (!getNormal(p2, q1, q2, n2)) { + n2.set(goodNormal); + } else { + if (!flip_side_orient) { + n2.negate(); + } + goodNormal.set(n2); + } + // if there is a previous normal, see if we need to smooth + // this normal or make a crease + + if (pn1 != null) { + cosine = n1.dot(pn2); + smooth = cosine > threshold; + if (smooth) { + p1Normal.x = (pn1.x + pn2.x + n1.x); + p1Normal.y = (pn1.y + pn2.y + n1.y); + p1Normal.z = (pn1.z + pn2.z + n1.z); + normalize(p1Normal); + + q1Normal.x = (pn2.x + n1.x + n2.x); + q1Normal.y = (pn2.y + n1.y + n2.y); + q1Normal.z = (pn2.z + n1.z + n2.z); + normalize(q1Normal); + } // if smooth + else { + p1Normal.x = n1.x; p1Normal.y = n1.y; p1Normal.z = n1.z; + q1Normal.x = n1.x+n2.x; + q1Normal.y = n1.y+n2.y; + q1Normal.z = n1.z+ n2.z; + normalize(q1Normal); + } // else + } // if pn1 != null + else { + pn1 = new Vector3f(); + pn2 = new Vector3f(); + p1Normal.x = n1.x; + p1Normal.y = n1.y; + p1Normal.z = n1.z; + + q1Normal.x = (n1.x + n2.x); + q1Normal.y = (n1.y + n2.y); + q1Normal.z = (n1.z + n2.z); + normalize(q1Normal); + } // else + + // if there is a next, check if we should smooth normal + + if (k+1 < num) { + p3.x = outVerts[i][k+1].x; p3.y = outVerts[i][k+1].y; + p3.z = 0.0f; + q3.x = p3.x; q3.y = p3.y; q3.z = p3.z + fontExtrusion.length; + + if (!getNormal(p2, q2, p3, n3)) { + n3.set(goodNormal); + } else { + if (!flip_side_orient) { + n3.negate(); + } + goodNormal.set(n3); + } + + if (!getNormal(p3, q2, q3, n4)) { + n4.set(goodNormal); + } else { + if (!flip_side_orient) { + n4.negate(); + } + goodNormal.set(n4); + } + + cosine = n2.dot(n3); + smooth = cosine > threshold; + + if (smooth) { + p2Normal.x = (n1.x + n2.x + n3.x); + p2Normal.y = (n1.y + n2.y + n3.y); + p2Normal.z = (n1.z + n2.z + n3.z); + normalize(p2Normal); + + q2Normal.x = (n2.x + n3.x + n4.x); + q2Normal.y = (n2.y + n3.y + n4.y); + q2Normal.z = (n2.z + n3.z + n4.z); + normalize(q2Normal); + } else { // if smooth + p2Normal.x = n1.x + n2.x; + p2Normal.y = n1.y + n2.y; + p2Normal.z = n1.z + n2.z; + normalize(p2Normal); + q2Normal.x = n2.x; q2Normal.y = n2.y; q2Normal.z = n2.z; + } // else + } else { // if k+1 < num + p2Normal.x = (n1.x + n2.x); + p2Normal.y = (n1.y + n2.y); + p2Normal.z = (n1.z + n2.z); + normalize(p2Normal); + + q2Normal.x = n2.x; + q2Normal.y = n2.y; + q2Normal.z = n2.z; + } // else + + // add pts for the 2 tris + // p1, q1, p2 and p2, q1, q2 + + if (flip_side_orient) { + triAry.setCoordinate(currCoordIndex, p1); + triAry.setNormal(currCoordIndex, p1Normal); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, q1); + triAry.setNormal(currCoordIndex, q1Normal); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, p2); + triAry.setNormal(currCoordIndex, p2Normal); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, p2); + triAry.setNormal(currCoordIndex, p2Normal); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, q1); + triAry.setNormal(currCoordIndex, q1Normal); + currCoordIndex++; + } else { + triAry.setCoordinate(currCoordIndex, q1); + triAry.setNormal(currCoordIndex, q1Normal); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, p1); + triAry.setNormal(currCoordIndex, p1Normal); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, p2); + triAry.setNormal(currCoordIndex, p2Normal); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, q1); + triAry.setNormal(currCoordIndex, q1Normal); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, p2); + triAry.setNormal(currCoordIndex, p2Normal); + currCoordIndex++; + } + triAry.setCoordinate(currCoordIndex, q2); + triAry.setNormal(currCoordIndex, q2Normal); + currCoordIndex++; + pn1.x = n1.x; pn1.y = n1.y; pn1.z = n1.z; + pn2.x = n2.x; pn2.y = n2.y; pn2.z = n2.z; + p1.x = p2.x; p1.y = p2.y; p1.z = p2.z; + q1.x = q2.x; q1.y = q2.y; q1.z = q2.z; + + }// for k + + // set the previous normals to null when we are done + pn1 = null; + pn2 = null; + }// for j + }//for i + } else { // if shape + int m, offset=0; + Point3f P2 = new Point3f(), Q2 = new Point3f(), P1=new Point3f(); + Vector3f nn = new Vector3f(), nn1= new Vector3f(), + nn2= new Vector3f(), nn3= new Vector3f(); + Vector3f nna = new Vector3f(), nnb=new Vector3f(); + float length; + boolean validNormal = false; + + // fontExtrusion.shape is specified, and is NOT straight line + for (i=0;i < islandCounts.length;i++){ + for (j=0, k= 0, offset = num =0;j < islandCounts[i].length;j++){ + num += islandCounts[i][j]; + + p1.x = outVerts[i][num - 1].x; + p1.y = outVerts[i][num - 1].y; + p1.z = 0.0f; + q1.x = p1.x; q1.y = p1.y; q1.z = p1.z+fontExtrusion.length; + p3.z = 0.0f; + for (m=num-2; m >= 0; m--) { + p3.x = outVerts[i][m].x; + p3.y = outVerts[i][m].y; + + if (getNormal(p3, q1, p1, nn1)) { + if (!flip_side_orient) { + nn1.negate(); + } + goodNormal.set(nn1); + break; + } + } + for (;k < num;k++){ + p2.x = outVerts[i][k].x;p2.y = outVerts[i][k].y;p2.z = 0.0f; + q2.x = p2.x; q2.y = p2.y; q2.z = p2.z+fontExtrusion.length; + getNormal(p1, q1, p2, nn2); + + p3.x = outVerts[i][(k+1)==num ? offset:(k+1)].x; + p3.y = outVerts[i][(k+1)==num ? offset:(k+1)].y; + p3.z = 0.0f; + if (!getNormal(p3,p2,q2, nn3)) { + nn3.set(goodNormal); + } else { + if (!flip_side_orient) { + nn3.negate(); + } + goodNormal.set(nn3); + } + + // Calculate normals at the point by averaging normals + // of two faces on each side of the point. + nna.x = (nn1.x+nn2.x); + nna.y = (nn1.y+nn2.y); + nna.z = (nn1.z+nn2.z); + normalize(nna); + + nnb.x = (nn3.x+nn2.x); + nnb.y = (nn3.y+nn2.y); + nnb.z = (nn3.z+nn2.z); + normalize(nnb); + + P1.x = p1.x;P1.y = p1.y;P1.z = p1.z; + P2.x = p2.x;P2.y = p2.y; P2.z = p2.z; + Q2.x = q2.x;Q2.y = q2.y; Q2.z = q2.z; + for (m=1;m < fontExtrusion.pnts.length;m++){ + q1.z = q2.z = fontExtrusion.pnts[m].x; + q1.x = P1.x + nna.x * fontExtrusion.pnts[m].y; + q1.y = P1.y + nna.y * fontExtrusion.pnts[m].y; + q2.x = P2.x + nnb.x * fontExtrusion.pnts[m].y; + q2.y = P2.y + nnb.y * fontExtrusion.pnts[m].y; + + if (!getNormal(p1, q1, p2, n1)) { + n1.set(goodNormal); + } else { + if (!flip_side_orient) { + n1.negate(); + } + goodNormal.set(n1); + } + + if (flip_side_orient) { + triAry.setCoordinate(currCoordIndex, p1); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, q1); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + } else { + triAry.setCoordinate(currCoordIndex, q1); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, p1); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + } + triAry.setCoordinate(currCoordIndex, p2); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + + if (!getNormal(p2, q1, q2, n1)) { + n1.set(goodNormal); + } else { + if (!flip_side_orient) { + n1.negate(); + } + goodNormal.set(n1); + } + + if (flip_side_orient) { + triAry.setCoordinate(currCoordIndex, p2); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, q1); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + } else { + triAry.setCoordinate(currCoordIndex, q1); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + + triAry.setCoordinate(currCoordIndex, p2); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + } + triAry.setCoordinate(currCoordIndex, q2); + triAry.setNormal(currCoordIndex, n1); + currCoordIndex++; + + p1.x = q1.x;p1.y = q1.y;p1.z = q1.z; + p2.x = q2.x;p2.y = q2.y;p2.z = q2.z; + }// for m + p1.x = P2.x; p1.y = P2.y; p1.z = P2.z; + q1.x = Q2.x; q1.y = Q2.y; q1.z = Q2.z; + nn1.x = nn2.x;nn1.y = nn2.y;nn1.z = nn2.z; + }// for k + offset = num; + }// for j + }//for i + }// if shape + }// if fontExtrusion + geo = (GeometryArrayRetained) triAry.retained; + geomHash.put(ch, geo); + } + + return geo; + } + + + static boolean getNormal(Point3f p1, Point3f p2, Point3f p3, Vector3f normal) { + Vector3f v1 = new Vector3f(); + Vector3f v2 = new Vector3f(); + + // Must compute normal + v1.sub(p2, p1); + v2.sub(p2, p3); + normal.cross(v1, v2); + normal.negate(); + + float length = normal.length(); + + if (length > 0) { + length = 1 / length; + normal.x *= length; + normal.y *= length; + normal.z *= length; + return true; + } + return false; + } + + + // check if 2 contours are inside/outside/intersect one another + // INPUT: + // vertCnt1, vertCnt2 - number of vertices in 2 contours + // begin1, begin2 - starting indices into vertices for 2 contours + // vertices - actual vertex data + // OUTPUT: + // status == 1 - intersecting contours + // 2 - first contour inside the second + // 3 - second contour inside the first + // 0 - disjoint contours(2 islands) + + static int check2Contours(int begin1, int end1, int begin2, int end2, + Point3f[] vertices) { + int i, j; + boolean inside2, inside1; + + inside2 = pointInPolygon2D(vertices[begin1].x, vertices[begin1].y, + begin2, end2, vertices); + + for (i=begin1+1; i < end1;i++) { + if (pointInPolygon2D(vertices[i].x, vertices[i].y, + begin2, end2, vertices) != inside2) { + return 1; //intersecting contours + } + } + + // Since we are using point in polygon test and not + // line in polygon test. There are cases we miss the interesting + // if we are not checking the reverse for all points. This happen + // when two points form a line pass through a polygon but the two + // points are outside of it. + + inside1 = pointInPolygon2D(vertices[begin2].x, vertices[begin2].y, + begin1, end1, vertices); + + for (i=begin2+1; i < end2;i++) { + if (pointInPolygon2D(vertices[i].x, vertices[i].y, + begin1, end1, vertices) != inside1) { + return 1; //intersecting contours + } + } + + if (!inside2) { + if (!inside1) { + return 0; // disjoint countours + } + // inside2 = false and inside1 = true + return 3; // second contour inside first + } + + // must be inside2 = true and inside1 = false + // Note that it is not possible inside2 = inside1 = true + // unless two contour overlap to each others. + // + return 2; // first contour inside second + } + + // Test if 2D point (x,y) lies inside polygon represented by verts. + // z-value of polygon vertices is ignored. Sent only to avoid data-copy. + // Uses ray-shooting algorithm to compute intersections along +X axis. + // This algorithm works for all polygons(concave, self-intersecting) and + // is best solution here due to large number of polygon vertices. + // Point is INSIDE if number of intersections is odd, OUTSIDE if number + // of intersections is even. + static boolean pointInPolygon2D(float x, float y, int begIdx, int endIdx, + Point3f[] verts){ + + int i, num_intersections = 0; + float xi; + + for (i=begIdx;i < endIdx-1;i++) { + if ((verts[i].y >= y && verts[i+1].y >= y) || + (verts[i].y < y && verts[i+1].y < y)) + continue; + + xi = verts[i].x + (verts[i].x - verts[i+1].x)*(y - verts[i].y)/ + (verts[i].y - verts[i+1].y); + + if (x < xi) num_intersections++; + } + + // Check for segment from last vertex to first vertex. + + if (!((verts[i].y >= y && verts[begIdx].y >= y) || + (verts[i].y < y && verts[begIdx].y < y))) { + xi = verts[i].x + (verts[i].x - verts[begIdx].x)*(y - verts[i].y)/ + (verts[i].y - verts[begIdx].y); + + if (x < xi) num_intersections++; + } + + return ((num_intersections % 2) != 0); + } + + + static final boolean normalize(Vector3f v) { + float len = v.length(); + + if (len > 0) { + len = 1.0f/len; + v.x *= len; + v.y *= len; + v.z *= len; + return true; + } + return false; + } + + + // A Tree of islands form based on contour, each parent's contour + // enclosed all the child. We built this since Triangular fail to + // handle the case of multiple concentrated contours. i.e. if + // 4 contours A > B > C > D. Triangular will fail recongized + // two island, one form by A & B and the other by C & D. + // Using this tree we can separate out every 2 levels and pass + // in to triangular to workaround its limitation. + static private class IslandsNode { + + private ArrayList islandsList = null; + int startIdx, endIdx; + + IslandsNode(int startIdx, int endIdx) { + this.startIdx = startIdx; + this.endIdx = endIdx; + islandsList = null; + } + + void addChild(IslandsNode node) { + + if (islandsList == null) { + islandsList = new ArrayList(5); + } + islandsList.add(node); + } + + void removeChild(IslandsNode node) { + islandsList.remove(islandsList.indexOf(node)); + } + + IslandsNode getChild(int idx) { + return (IslandsNode) islandsList.get(idx); + } + + int numChild() { + return (islandsList == null ? 0 : islandsList.size()); + } + + int numVertices() { + return endIdx - startIdx; + } + + void insert(IslandsNode newNode, Point3f[] vertices) { + boolean createNewLevel = false; + + if (islandsList != null) { + IslandsNode childNode; + int status; + + for (int i=numChild()-1; i>=0; i--) { + childNode = getChild(i); + status = check2Contours(newNode.startIdx, newNode.endIdx, + childNode.startIdx, childNode.endIdx, + vertices); + switch (status) { + case 2: // newNode inside childNode, go down recursively + childNode.insert(newNode, vertices); + return; + case 3:// childNode inside newNode, + // continue to search other childNode also + // inside this one and group them together. + newNode.addChild(childNode); + createNewLevel = true; + break; + default: // intersecting or disjoint + + } + } + } + + if (createNewLevel) { + // Remove child in newNode from this + for (int i=newNode.numChild()-1; i>=0; i--) { + removeChild(newNode.getChild(i)); + } + // Add the newNode to parent + } + addChild(newNode); + } + + // Return a list of node with odd number of level + void collectOddLevelNode(UnorderList list, int level) { + if ((level % 2) == 1) { + list.add(this); + } + if (islandsList != null) { + level++; + for (int i=numChild()-1; i>=0; i--) { + getChild(i).collectOddLevelNode(list, level); + } + } + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/FontExtrusion.java b/j3d-core/src/classes/share/javax/media/j3d/FontExtrusion.java new file mode 100644 index 0000000..672a5ba --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/FontExtrusion.java @@ -0,0 +1,260 @@ +/* + * $RCSfile: FontExtrusion.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import javax.vecmath.*; +import java.lang.Math; +import java.awt.Shape; +import java.awt.geom.PathIterator; +import java.util.ArrayList; + + /** + * The FontExtrusion object is used to describe the extrusion path + * for a Font3D object. The extrusion path is used in conjunction + * with a Font2D object. The extrusion path defines the edge contour + * of 3D text. This contour is perpendicular to the face of the text. + * The extrusion has it's origin at the edge of the glyph with 1.0 being + * the height of the tallest glyph. Contour must be monotonic in x. + *

+ * The shape of the extrusion path is, by default, a straight line + * from 0.0 to 0.2 (known as a straight bevel). The shape may be + * modified via the extrusionShape parameter, a Shape object that + * describes the 3D contour of a Font3D object. + *

+ * User is responsible for data sanity and must make sure that + * extrusionShape does not cause intersection of adjacent glyphs + * or within single glyph. Else undefined output may be generated. + * + * @see java.awt.Font + * @see Font3D + */ +public class FontExtrusion extends Object { + + // Default FontExtrusion is a straight line of length .2 + float length = 0.2f; + Shape shape; + Point2f [] pnts; + + double tessellationTolerance = 0.01; + + /** + * Constructs a FontExtrusion object with default parameters. The + * default parameters are as follows: + * + *

    + * extrusion shape : null
    + * tessellation tolerance : 0.01
    + *
+ * + * A null extrusion shape specifies that a straight line from 0.0 + * to 0.2 (straight bevel) is used. + * + * @see Font3D + */ + public FontExtrusion() { + shape = null; + } + + /** + * Constructs a FontExtrusion object with the specified shape, using + * the default tessellation tolerance. The + * specified shape is used to construct the edge + * contour of a Font3D object. Each shape begins with an implicit + * point at 0.0. Contour must be monotonic in x. + * + * @param extrusionShape the shape object to use to generate the + * extrusion path. + * A null shape specifies that a straight line from 0.0 to 0.2 + * (straight bevel) is used. + * + * @exception IllegalArgumentException if multiple contours in + * extrusionShape, or contour is not monotonic or least x-value + * of a contour point is not 0.0f + * + * @see Font3D + */ + public FontExtrusion(Shape extrusionShape) { + setExtrusionShape(extrusionShape); + } + + + /** + * Constructs a FontExtrusion object with the specified shape, using + * the specified tessellation tolerance. The + * specified shape is used to construct the edge + * contour of a Font3D object. Each shape begins with an implicit + * point at 0.0. Contour must be monotonic in x. + * + * @param extrusionShape the shape object to use to generate the + * extrusion path. + * A null shape specifies that a straight line from 0.0 to 0.2 + * (straight bevel) is used. + * @param tessellationTolerance the tessellation tolerance value + * used in tessellating the extrusion shape. + * This corresponds to the flatness parameter in + * the java.awt.Shape.getPathIterator method. + * + * @exception IllegalArgumentException if multiple contours in + * extrusionShape, or contour is not monotonic or least x-value + * of a contour point is not 0.0f + * + * @see Font3D + * + * @since Java 3D 1.2 + */ + public FontExtrusion(Shape extrusionShape, + double tessellationTolerance) { + + this.tessellationTolerance = tessellationTolerance; + setExtrusionShape(extrusionShape); + } + + + /** + * Sets the FontExtrusion's shape parameter. This + * parameter is used to construct the 3D contour of a Font3D object. + * + * @param extrusionShape the shape object to use to generate the + * extrusion path. + * A null shape specifies that a straight line from 0.0 to 0.2 + * (straight bevel) is used. + * + * @exception IllegalArgumentException if multiple contours in + * extrusionShape, or contour is not monotonic or least x-value + * of a contour point is not 0.0f + * + * @see Font3D + * @see java.awt.Shape + */ + public void setExtrusionShape(Shape extrusionShape) { + shape = extrusionShape; + if (shape == null) return; + + PathIterator pIt = shape.getPathIterator(null, tessellationTolerance); + ArrayList coords = new ArrayList(); + float tmpCoords[] = new float[6], prevX = 0.0f; + int flag, n = 0, inc = -1; + + // Extrusion shape is restricted to be single contour, monotonous + // increasing, non-self-intersecting curve. Throw exception otherwise + while (!pIt.isDone()) { + Point2f vertex = new Point2f(); + flag = pIt.currentSegment(tmpCoords); + if (flag == PathIterator.SEG_LINETO){ + vertex.x = tmpCoords[0]; + vertex.y = tmpCoords[1]; + if (inc == -1){ + if (prevX < vertex.x) inc = 0; + else if (prevX > vertex.x) inc = 1; + } + //Flag 'inc' indicates if curve is monotonic increasing or + // monotonic decreasing. It is set to -1 initially and remains + // -1 if consecutive x values are same. Once 'inc' is set to + // 1 or 0, exception is thrown is curve changes direction. + if (((inc == 0) && (prevX > vertex.x)) || + ((inc == 1) && (prevX < vertex.x))) + throw new IllegalArgumentException(J3dI18N.getString("FontExtrusion0")); + + prevX = vertex.x; + n++; + coords.add(vertex); + }else if (flag == PathIterator.SEG_MOVETO){ + if (n != 0) + throw new IllegalArgumentException(J3dI18N.getString("FontExtrusion3")); + + vertex.x = tmpCoords[0]; + vertex.y = tmpCoords[1]; + prevX = vertex.x; + n++; + coords.add(vertex); + } + pIt.next(); + } + + //if (inc == 1){ + //Point2f vertex = new Point2f(0.0f, 0.0f); + //coords.add(vertex); + //} + int i, num = coords.size(); + pnts = new Point2f[num]; + //System.err.println("num "+num+" inc "+inc); + if (inc == 0){ + for (i=0;i < num;i++){ + pnts[i] = (Point2f)coords.get(i); + //System.err.println("i "+i+" x "+ pnts[i].x+" y "+pnts[i].y); + } + } + else { + for (i=0;i < num;i++) { + pnts[i] = (Point2f)coords.get(num - i -1); + //System.err.println("i "+i+" x "+ pnts[i].x+" y "+pnts[i].y); + } + } + + //Force last y to be zero until Text3D face scaling is implemented + pnts[num-1].y = 0.0f; + if (pnts[0].x != 0.0f) + throw new IllegalArgumentException(J3dI18N.getString("FontExtrusion1")); + + //Compute straight line distance between first and last points. + float dx = (pnts[0].x - pnts[num-1].x); + float dy = (pnts[0].y - pnts[num-1].y); + length = (float)Math.sqrt(dx*dx + dy*dy); + } + + + /** + * Gets the FontExtrusion's shape parameter. This + * parameter is used to construct the 3D contour of a Font3D object. + * + * @return extrusionShape the shape object used to generate the + * extrusion path + * + * @see Font3D + * @see java.awt.Shape + */ + public Shape getExtrusionShape() { + return shape; + } + + + /** + * Returns the tessellation tolerance with which this FontExtrusion was + * created. + * @return the tessellation tolerance used by this FontExtrusion + * + * @since Java 3D 1.2 + */ + public double getTessellationTolerance() { + return tessellationTolerance; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/FreeListManager.java b/j3d-core/src/classes/share/javax/media/j3d/FreeListManager.java new file mode 100644 index 0000000..aa40a8e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/FreeListManager.java @@ -0,0 +1,94 @@ +/* + * $RCSfile: FreeListManager.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +class FreeListManager { + + private static final boolean DEBUG = false; + + // constants that represent the freelists managed by the Manager + static final int DISPLAYLIST = 0; + static final int TEXTURE2D = 1; + static final int TEXTURE3D = 2; + + private static int maxFreeListNum = 2; + + // what list we are going to shrink next + private static int currlist = 0; + + static MemoryFreeList[] freelist = null; + + static void createFreeLists() { + maxFreeListNum = 2; + freelist = new MemoryFreeList[maxFreeListNum+1]; + freelist[DISPLAYLIST] = new IntegerFreeList(); + freelist[TEXTURE2D] = new IntegerFreeList(); + freelist[TEXTURE3D] = new IntegerFreeList(); + + } + + // see if the current list can be shrunk + static void manageLists() { +// System.err.println("manageLists"); + if (freelist[currlist] != null) { + freelist[currlist].shrink(); + } + + currlist++; + if (currlist > maxFreeListNum) currlist = 0; + } + + // return the freelist specified by the list param + static MemoryFreeList getFreeList(int list) { + if (list < 0 || list > maxFreeListNum) { + if (DEBUG) System.err.println("illegal list"); + return null; + } + else { + return freelist[list]; + } + } + + static Object getObject(int listId) { + return freelist[listId].getObject(); + } + + static void freeObject(int listId, Object obj) { + freelist[listId].add(obj); + } + + static void clearList(int listId) { + freelist[listId].clear(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GLSLShaderProgram.java b/j3d-core/src/classes/share/javax/media/j3d/GLSLShaderProgram.java new file mode 100644 index 0000000..b29813c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GLSLShaderProgram.java @@ -0,0 +1,177 @@ +/* + * $RCSfile: GLSLShaderProgram.java,v $ + * + * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The GLSLShaderProgram object is a concrete implementation of a + * ShaderProgram node component for the OpenGL GLSL shading language. + * + * @see SourceCodeShader + * + * @since Java 3D 1.4 + */ + +public class GLSLShaderProgram extends ShaderProgram { + + /** + * Constructs a GLSL shader program node component. + * + *
+ * TODO: ADD MORE DOCUMENTATION HERE. + */ + public GLSLShaderProgram() { + } + + // Implement abstract setVertexAttrNames method (inherit javadoc from parent class) + public void setVertexAttrNames(String[] vertexAttrNames) { + checkForLiveOrCompiled(); + + if (vertexAttrNames != null) { + for (int i = 0; i < vertexAttrNames.length; i++) { + if (vertexAttrNames[i] == null) { + throw new NullPointerException(); + } + } + } + + ((GLSLShaderProgramRetained)this.retained).setVertexAttrNames(vertexAttrNames); + } + + // Implement abstract getVertexAttrNames method (inherit javadoc from parent class) + public String[] getVertexAttrNames() { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_NAMES_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GLSLShaderProgram0")); + } + } + + return ((GLSLShaderProgramRetained)this.retained).getVertexAttrNames(); + + } + + // Implement abstract setShaderAttrNames method (inherit javadoc from parent class) + public void setShaderAttrNames(String[] shaderAttrNames) { + checkForLiveOrCompiled(); + + if (shaderAttrNames != null) { + for (int i = 0; i < shaderAttrNames.length; i++) { + if (shaderAttrNames[i] == null) { + throw new NullPointerException(); + } + } + } + + ((GLSLShaderProgramRetained)this.retained).setShaderAttrNames(shaderAttrNames); + } + + // Implement abstract getShaderAttrNames method (inherit javadoc from parent class) + public String[] getShaderAttrNames() { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_NAMES_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GLSLShaderProgram0")); + } + } + + return ((GLSLShaderProgramRetained)this.retained).getShaderAttrNames(); + + } + + /** + * Copies the specified array of shaders into this shader + * program. This method makes a shallow copy of the array. The + * array of shaders may be null or empty (0 length), but the + * elements of the array must be non-null. The shading language of + * each shader in the array must be + * SHADING_LANGUAGE_GLSL. Each shader in the array must + * be a SourceCodeShader. + * + * @param shaders array of Shader objects to be copied into this + * ShaderProgram + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if the shading language of + * any shader in the shaders array is not + * SHADING_LANGUAGE_GLSL. + * + * @exception ClassCastException if any shader in the shaders + * array is not a SourceCodeShader. + * + * @exception NullPointerException if any element in the + * shaders array is null. + */ + public void setShaders(Shader[] shaders) { + checkForLiveOrCompiled(); + + if(shaders != null) { + // Check shaders for valid shading language and class type + for (int i = 0; i < shaders.length; i++) { + if (shaders[i].getShadingLanguage() != Shader.SHADING_LANGUAGE_GLSL) { + throw new IllegalArgumentException(J3dI18N.getString("GLSLShaderProgram2")); + } + + // Try to cast shader to SourceCodeShader; it will throw + // ClassCastException if it isn't. + SourceCodeShader shad = (SourceCodeShader)shaders[i]; + } + + } + + ((GLSLShaderProgramRetained)this.retained).setShaders(shaders); + } + + // Implement abstract getShaders method (inherit javadoc from parent class) + public Shader[] getShaders() { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_SHADERS_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GLSLShaderProgram1")); + } + } + + return ((GLSLShaderProgramRetained)this.retained).getShaders(); + } + + /** + * Creates a retained mode GLSLShaderProgramRetained object that this + * GLSLShaderProgram component object will point to. + */ + void createRetained() { + this.retained = new GLSLShaderProgramRetained(); + this.retained.setSource(this); + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GLSLShaderProgramRetained.java b/j3d-core/src/classes/share/javax/media/j3d/GLSLShaderProgramRetained.java new file mode 100644 index 0000000..830171d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GLSLShaderProgramRetained.java @@ -0,0 +1,401 @@ +/* + * $RCSfile: GLSLShaderProgramRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The GLSLShaderProgram object is a concrete implementation of a + * ShaderProgram node component for the OpenGL GLSL shading language. + */ + +class GLSLShaderProgramRetained extends ShaderProgramRetained { + + /** + * Constructs a GLSL shader program node component. + */ + GLSLShaderProgramRetained() { + } + + synchronized void createMirrorObject() { + // System.err.println("GLSLShaderProgramRetained : createMirrorObject"); + // This method should only call by setLive(). + if (mirror == null) { + GLSLShaderProgramRetained mirrorGLSLSP = new GLSLShaderProgramRetained(); + mirror = mirrorGLSLSP; + mirror.source = source; + } + initMirrorObject(); + } + + // ShaderAttributeValue methods + + ShaderError setUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + + return Pipeline.getPipeline().setGLSLUniform1i(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + + return Pipeline.getPipeline().setGLSLUniform1f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + + return Pipeline.getPipeline().setGLSLUniform2i(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniform2f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + + return Pipeline.getPipeline().setGLSLUniform3i(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniform3f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + + return Pipeline.getPipeline().setGLSLUniform4i(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniform4f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniformMatrix3f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + ShaderError setUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniformMatrix4f(ctx, + shaderProgramId, + uniformLocation, + value); + } + + // ShaderAttributeArray methods + + ShaderError setUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + + return Pipeline.getPipeline().setGLSLUniform1iArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniform1fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + + return Pipeline.getPipeline().setGLSLUniform2iArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniform2fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + + return Pipeline.getPipeline().setGLSLUniform3iArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniform3fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + + return Pipeline.getPipeline().setGLSLUniform4iArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniform4fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniformMatrix3fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + ShaderError setUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + + return Pipeline.getPipeline().setGLSLUniformMatrix4fArray(ctx, + shaderProgramId, + uniformLocation, + numElements, + value); + } + + /** + * Method to return a flag indicating whether this + * ShaderProgram is supported on the specified Canvas. + */ + boolean isSupported(Canvas3D cv) { + return cv.shadingLanguageGLSL; + } + + /** + * Method to create the native shader. + */ + ShaderError createShader(Context ctx, ShaderRetained shader, ShaderId[] shaderIdArr) { + return Pipeline.getPipeline().createGLSLShader(ctx, shader.shaderType, shaderIdArr); + } + + /** + * Method to destroy the native shader. + */ + ShaderError destroyShader(Context ctx, ShaderId shaderId) { + return Pipeline.getPipeline().destroyGLSLShader(ctx, shaderId); + } + + /** + * Method to compile the native shader. + */ + ShaderError compileShader(Context ctx, ShaderId shaderId, String source) { + return Pipeline.getPipeline().compileGLSLShader(ctx, shaderId, source ); + } + + /** + * Method to create the native shader program. + */ + ShaderError createShaderProgram(Context ctx, ShaderProgramId[] shaderProgramIdArr) { + return Pipeline.getPipeline().createGLSLShaderProgram(ctx, shaderProgramIdArr); + } + + /** + * Method to destroy the native shader program. + */ + ShaderError destroyShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return Pipeline.getPipeline().destroyGLSLShaderProgram(ctx, shaderProgramId); + } + + /** + * Method to link the native shader program. + */ + ShaderError linkShaderProgram(Context ctx, ShaderProgramId shaderProgramId, ShaderId[] shaderIds) { + return Pipeline.getPipeline().linkGLSLShaderProgram(ctx, shaderProgramId, shaderIds); + } + + ShaderError bindVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, String attrName, int attrIndex) { + return Pipeline.getPipeline().bindGLSLVertexAttrName(ctx, shaderProgramId, attrName, attrIndex); + } + + void lookupVertexAttrNames(Context ctx, ShaderProgramId shaderProgramId, String[] attrNames, boolean[] errArr) { + // This method is a no-op for GLSL + } + + void lookupShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + String[] attrNames, AttrNameInfo[] attrNameInfoArr) { + + int numAttrNames = attrNames.length; + + ShaderAttrLoc[] locArr = new ShaderAttrLoc[numAttrNames]; + int[] typeArr = new int[numAttrNames]; + int[] sizeArr = new int[numAttrNames]; // currently unused + boolean[] isArrayArr = new boolean[numAttrNames]; + + Pipeline.getPipeline().lookupGLSLShaderAttrNames(ctx, shaderProgramId, + numAttrNames, attrNames, locArr, typeArr, sizeArr, isArrayArr); + + for (int i = 0; i < numAttrNames; i++) { + attrNameInfoArr[i] = new AttrNameInfo(); + attrNameInfoArr[i].setLocation(locArr[i]); + attrNameInfoArr[i].setArray(isArrayArr[i]); + attrNameInfoArr[i].setType(typeArr[i]); +// System.err.println(attrNames[i] + +// " : loc = " + locArr[i] + +// ", type = " + typeArr[i] + +// ", isArray = " + isArrayArr[i] + +// ", size = " + sizeArr[i]); + } + } + + /** + * Method to enable the native shader program. + */ + ShaderError enableShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return Pipeline.getPipeline().useGLSLShaderProgram(ctx, shaderProgramId); + } + + /** + * Method to disable the native shader program. + */ + ShaderError disableShaderProgram(Context ctx) { + return Pipeline.getPipeline().useGLSLShaderProgram(ctx, null); + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeneralizedStrip.java b/j3d-core/src/classes/share/javax/media/j3d/GeneralizedStrip.java new file mode 100644 index 0000000..5c41992 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeneralizedStrip.java @@ -0,0 +1,894 @@ +/* + * $RCSfile: GeneralizedStrip.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.* ; + + +/** + * This class provides static methods to support topological + * transformations on generalized strips. This is used by the + * GeometryDecompressor. These methods only need to look at the + * vertex replacement flags to determine how the vertices in the strip + * are connected. The connections are rearranged in different ways to + * transform generalized strips to GeometryArray representations. + * + * @see GeneralizedStripFlags + * @see GeneralizedVertexList + * @see GeometryDecompressor + */ +class GeneralizedStrip { + private static final boolean debug = false ; + + // Private convenience copies of various constants. + private static final int CW = + GeneralizedStripFlags.FRONTFACE_CW ; + private static final int CCW = + GeneralizedStripFlags.FRONTFACE_CCW ; + private static final int RESTART_CW = + GeneralizedStripFlags.RESTART_CW ; + private static final int RESTART_CCW = + GeneralizedStripFlags.RESTART_CCW ; + private static final int REPLACE_MIDDLE = + GeneralizedStripFlags.REPLACE_MIDDLE ; + private static final int REPLACE_OLDEST = + GeneralizedStripFlags.REPLACE_OLDEST ; + + /** + * The IntList is like an ArrayList, but avoids the Integer + * object wrapper and accessor overhead for simple lists of ints. + */ + static class IntList { + /** + * The array of ints. + */ + int ints[] ; + + /** + * The number of ints in this instance. + */ + int count ; + + /** + * Construct a new empty IntList of the given initial size. + * @param initialSize initial size of the backing array + */ + IntList(int initialSize) { + ints = new int[initialSize] ; + count = 0 ; + } + + /** + * Constructs an IntList with the given contents. + * @param ints the array of ints to use as the contents + */ + IntList(int ints[]) { + this.ints = ints ; + this.count = ints.length ; + } + + /** + * Add a new int to the end of this list. + * @param i the int to be appended to this list + */ + void add(int i) { + if (count == ints.length) { + int newints[] = new int[2*count] ; + System.arraycopy(ints, 0, newints, 0, count) ; + ints = newints ; + if (debug) + System.err.println + ("GeneralizedStrip.IntList: reallocated " + + (2*count) + " ints") ; + } + ints[count++] = i ; + } + + /** + * Trim the backing array to the current count and return the + * resulting backing array. + */ + int[] trim() { + if (count != ints.length) { + int newints[] = new int[count] ; + System.arraycopy(ints, 0, newints, 0, count) ; + ints = newints ; + } + return ints ; + } + + /** + * Fill the list with consecutive integers starting from 0. + */ + void fillAscending() { + for (int i = 0 ; i < ints.length ; i++) + ints[i] = i ; + + count = ints.length ; + } + + public String toString() { + String s = new String("[") ; + for (int i = 0 ; i < count-1 ; i++) + s = s + Integer.toString(ints[i]) + ", " ; + return s + Integer.toString(ints[count-1]) + "]" ; + } + } + + /** + * The StripArray class is used as the output of some conversion methods + * in the GeneralizedStrip class. + */ + static class StripArray { + /** + * A list of indices into the vertices of the original generalized + * strip. It specifies the order in which vertices in the original + * strip should be followed to build GeometryArray objects. + */ + IntList vertices ; + + /** + * A list of strip counts. + */ + IntList stripCounts ; + + /** + * Creates a StripArray with the specified vertices and stripCounts. + * @param vertices IntList containing vertex indicies. + * @param stripCounts IntList containing strip lengths. + */ + StripArray(IntList vertices, IntList stripCounts) { + this.vertices = vertices ; + this.stripCounts = stripCounts ; + } + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning a 2-element array of + * StripArray objects. The first StripArray will contain triangle strips + * and the second will contain triangle fans. + * + * @param vertices an object implementing GeneralizedStripFlags + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @return a 2-element array containing strips in 0 and fans in 1 + */ + static StripArray[] toStripsAndFans(GeneralizedStripFlags vertices, + int frontFace) { + + int size = vertices.getFlagCount() ; + + // Initialize IntLists to worst-case sizes. + IntList stripVerts = new IntList(size*3) ; + IntList fanVerts = new IntList(size*3) ; + IntList stripCounts = new IntList(size) ; + IntList fanCounts = new IntList(size) ; + + toStripsAndFans(vertices, frontFace, + stripVerts, stripCounts, fanVerts, fanCounts) ; + + // Construct the StripArray output. + StripArray sa[] = new StripArray[2] ; + + if (stripCounts.count > 0) + sa[0] = new StripArray(stripVerts, stripCounts) ; + + if (fanCounts.count > 0) + sa[1] = new StripArray(fanVerts, fanCounts) ; + + return sa ; + } + + private static void toStripsAndFans(GeneralizedStripFlags vertices, + int frontFace, + IntList stripVerts, + IntList stripCounts, + IntList fanVerts, + IntList fanCounts) { + int newFlag, curFlag, winding ; + int v, size, stripStart, stripLength ; + boolean transition = false ; + + stripStart = 0 ; + stripLength = 3 ; + curFlag = vertices.getFlag(0) ; + winding = (curFlag == RESTART_CW ? CW : CCW) ; + size = vertices.getFlagCount() ; + + // Vertex replace flags for the first 3 vertices are irrelevant since + // they can only define a single triangle. The first meaningful + // replace flag starts at the 4th vertex. + v = 3 ; + if (v < size) + curFlag = vertices.getFlag(v) ; + + while (v < size) { + newFlag = vertices.getFlag(v) ; + + if ((newFlag == curFlag) && + (newFlag != RESTART_CW) && (newFlag != RESTART_CCW)) { + // The last flag was the same as this one, and it wasn't a + // restart: proceed to the next vertex. + stripLength++ ; + v++ ; + + } else { + // Either this vertex flag changed from the last one, or + // the flag explicitly specifies a restart: process the + // last strip and start up a new one. + if (curFlag == REPLACE_MIDDLE) + addFan(fanVerts, fanCounts, stripStart, stripLength, + frontFace, winding, transition) ; + else + addStrip(stripVerts, stripCounts, stripStart, stripLength, + frontFace, winding) ; + + // Restart: skip to the 4th vertex of the new strip. + if ((newFlag == RESTART_CW) || (newFlag == RESTART_CCW)) { + winding = (newFlag == RESTART_CW ? CW : CCW) ; + stripStart = v ; + stripLength = 3 ; + v += 3 ; + transition = false ; + if (v < size) + curFlag = vertices.getFlag(v) ; + } + // Strip/fan transition: decrement start of strip. + else { + if (newFlag == REPLACE_OLDEST) { + // Flip winding order when transitioning from fans + // to strips. + winding = (winding == CW ? CCW : CW) ; + stripStart = v-2 ; + stripLength = 3 ; + } else { + // Flip winding order when transitioning from + // strips to fans only if the preceding strip has + // an even number of vertices. + if ((stripLength & 0x01) == 0) + winding = (winding == CW ? CCW : CW) ; + stripStart = v-3 ; + stripLength = 4 ; + } + v++ ; + transition = true ; + curFlag = newFlag ; + } + } + } + + // Finish off the last strip or fan. + // If v > size then the strip is degenerate. + if (v == size) + if (curFlag == REPLACE_MIDDLE) + addFan(fanVerts, fanCounts, stripStart, stripLength, + frontFace, winding, transition) ; + else + addStrip(stripVerts, stripCounts, stripStart, stripLength, + frontFace, winding) ; + else + throw new IllegalArgumentException + (J3dI18N.getString("GeneralizedStrip0")) ; + + if (debug) { + System.err.println("GeneralizedStrip.toStripsAndFans") ; + if (v > size) + System.err.println(" ended with a degenerate triangle:" + + " number of vertices: " + (v-size)) ; + + System.err.println("\n number of strips: " + stripCounts.count) ; + if (stripCounts.count > 0) { + System.err.println(" number of vertices: " + stripVerts.count) ; + System.err.println(" vertices/strip: " + + (float)stripVerts.count/stripCounts.count) ; + System.err.println(" strip counts: " + stripCounts.toString()) ; + // System.err.println(" indices: " + stripVerts.toString()) ; + } + + System.err.println("\n number of fans: " + fanCounts.count) ; + if (fanCounts.count > 0) { + System.err.println(" number of vertices: " + fanVerts.count) ; + System.err.println(" vertices/strip: " + + (float)fanVerts.count/fanCounts.count) ; + System.err.println(" fan counts: " + fanCounts.toString()) ; + // System.err.println(" indices: " + fanVerts.toString()) ; + } + System.err.println("\n total vertices: " + + (stripVerts.count + fanVerts.count) + + "\n original number of vertices: " + size + + "\n") ; + } + } + + // + // Java 3D specifies that the vertices of front-facing polygons + // have counter-clockwise (CCW) winding order when projected to + // the view surface. Polygons with clockwise (CW) vertex winding + // will be culled as back-facing by default. + // + // Generalized triangle strips can flip the orientation of their + // triangles with the RESTART_CW and RESTART_CCW vertex flags. + // Strips flagged with an orientation opposite to what has been + // specified as front-facing must have their windings reversed in + // order to have the correct face orientation when represented as + // GeometryArray objects. + // + private static void addStrip(IntList stripVerts, + IntList stripCounts, + int start, int length, + int frontFace, int winding) { + int vindex = start ; + + if (winding == frontFace) { + // Maintain original order. + stripCounts.add(length) ; + while (vindex < start + length) { + stripVerts.add(vindex++) ; + } + } else if ((length & 0x1) == 1) { + // Reverse winding order if number of vertices is odd. + stripCounts.add(length) ; + vindex += length-1 ; + while (vindex >= start) { + stripVerts.add(vindex--) ; + } + } else if (length == 4) { + // Swap middle vertices. + stripCounts.add(4) ; + stripVerts.add(vindex) ; + stripVerts.add(vindex+2) ; + stripVerts.add(vindex+1) ; + stripVerts.add(vindex+3) ; + } else { + // Make the 1st triangle a singleton with reverse winding. + stripCounts.add(3) ; + stripVerts.add(vindex) ; + stripVerts.add(vindex+2) ; + stripVerts.add(vindex+1) ; + if (length > 3) { + // Copy the rest of the vertices in original order. + vindex++ ; + stripCounts.add(length-1) ; + while (vindex < start + length) { + stripVerts.add(vindex++) ; + } + } + } + } + + private static void addFan(IntList fanVerts, + IntList fanCounts, + int start, int length, + int frontFace, int winding, + boolean transition) { + int vindex = start ; + fanVerts.add(vindex++) ; + + if (winding == frontFace) { + if (transition) { + // Skip 1st triangle if this is the result of a transition. + fanCounts.add(length-1) ; + vindex++ ; + } else { + fanCounts.add(length) ; + fanVerts.add(vindex++) ; + } + while (vindex < start + length) { + fanVerts.add(vindex++) ; + } + } else { + // Reverse winding order. + vindex += length-2 ; + while (vindex > start+1) { + fanVerts.add(vindex--) ; + } + if (transition) { + // Skip 1st triangle if this is the result of a transition. + fanCounts.add(length-1) ; + } else { + fanCounts.add(length) ; + fanVerts.add(vindex) ; + } + } + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning a StripArray containing + * exclusively strips. + * + * @param vertices an object implementing GeneralizedStripFlags + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @return a StripArray containing the converted strips + */ + static StripArray toTriangleStrips(GeneralizedStripFlags vertices, + int frontFace) { + + int size = vertices.getFlagCount() ; + + // initialize lists to worst-case sizes. + IntList stripVerts = new IntList(size*3) ; + IntList fanVerts = new IntList(size*3) ; + IntList stripCounts = new IntList(size) ; + IntList fanCounts = new IntList(size) ; + + toStripsAndFans(vertices, frontFace, + stripVerts, stripCounts, fanVerts, fanCounts) ; + + if (fanCounts.count == 0) + if (stripCounts.count > 0) + return new StripArray(stripVerts, stripCounts) ; + else + return null ; + + // convert each fan to one or more strips + int i, v = 0 ; + for (i = 0 ; i < fanCounts.count ; i++) { + fanToStrips(v, fanCounts.ints[i], fanVerts.ints, + stripVerts, stripCounts, false) ; + v += fanCounts.ints[i] ; + } + + // create the StripArray output + StripArray sa = new StripArray(stripVerts, stripCounts) ; + + if (debug) { + System.err.println("GeneralizedStrip.toTriangleStrips" + + "\n number of strips: " + + sa.stripCounts.count) ; + if (sa.stripCounts.count > 0) { + System.err.println(" number of vertices: " + + sa.vertices.count + + "\n vertices/strip: " + + ((float)sa.vertices.count / + (float)sa.stripCounts.count)) ; + System.err.print(" strip counts: [") ; + for (i = 0 ; i < sa.stripCounts.count-1 ; i++) + System.err.print(sa.stripCounts.ints[i] + ", ") ; + System.err.println(sa.stripCounts.ints[i] + "]") ; + } + System.err.println() ; + } + return sa ; + } + + private static void fanToStrips(int v, int length, int fans[], + IntList stripVerts, + IntList stripCounts, + boolean convexPlanar) { + if (convexPlanar) { + // Construct a strip by criss-crossing across the interior. + stripCounts.add(length) ; + stripVerts.add(fans[v]) ; + + int j = v + 1 ; + int k = v + (length - 1) ; + while (j <= k) { + stripVerts.add(fans[j++]) ; + if (j > k) break ; + stripVerts.add(fans[k--]) ; + } + } else { + // Traverse non-convex or non-planar fan, biting off 3-triangle + // strips or less. First 5 vertices produce 1 strip of 3 + // triangles, and every 4 vertices after that produce another + // strip of 3 triangles. Each remaining strip adds 2 vertices. + int fanStart = v ; + v++ ; + while (v+4 <= fanStart + length) { + stripVerts.add(fans[v]) ; + stripVerts.add(fans[v+1]) ; + stripVerts.add(fans[fanStart]) ; + stripVerts.add(fans[v+2]) ; + stripVerts.add(fans[v+3]) ; + stripCounts.add(5) ; + v += 3 ; + } + + // Finish off the fan. + if (v+1 < fanStart + length) { + stripVerts.add(fans[v]) ; + stripVerts.add(fans[v+1]) ; + stripVerts.add(fans[fanStart]) ; + v++ ; + + if (v+1 < fanStart + length) { + stripVerts.add(fans[v+1]) ; + stripCounts.add(4) ; + } + else + stripCounts.add(3) ; + } + } + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning an array of vertex + * references representing the original generalized strip as individual + * triangles. Each sequence of three consecutive vertex references in the + * output defines a single triangle. + * + * @param vertices an object implementing GeneralizedStripFlags + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @return an array of indices into the original vertex array + */ + static int[] toTriangles(GeneralizedStripFlags vertices, int frontFace) { + + int vertexCount = 0 ; + StripArray sa[] = toStripsAndFans(vertices, frontFace) ; + + if (sa[0] != null) + vertexCount = 3 * getTriangleCount(sa[0].stripCounts) ; + if (sa[1] != null) + vertexCount += 3 * getTriangleCount(sa[1].stripCounts) ; + + if (debug) + System.err.println("GeneralizedStrip.toTriangles\n" + + " number of triangles: " + vertexCount/3 + "\n" + + " number of vertices: " + vertexCount + "\n") ; + int t = 0 ; + int triangles[] = new int[vertexCount] ; + + if (sa[0] != null) + t = stripsToTriangles(t, triangles, + 0, sa[0].vertices.ints, + 0, sa[0].stripCounts.ints, + sa[0].stripCounts.count) ; + if (sa[1] != null) + t = fansToTriangles(t, triangles, + 0, sa[1].vertices.ints, + 0, sa[1].stripCounts.ints, + sa[1].stripCounts.count) ; + return triangles ; + } + + private static int stripsToTriangles(int tstart, int tbuff[], + int vstart, int vertices[], + int stripStart, int stripCounts[], + int stripCount) { + int t = tstart ; + int v = vstart ; + for (int i = 0 ; i < stripCount ; i++) { + for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) { + if ((j & 0x01) == 0) { + // even-numbered triangles + tbuff[t*3 +0] = vertices[v+0] ; + tbuff[t*3 +1] = vertices[v+1] ; + tbuff[t*3 +2] = vertices[v+2] ; + } else { + // odd-numbered triangles + tbuff[t*3 +0] = vertices[v+1] ; + tbuff[t*3 +1] = vertices[v+0] ; + tbuff[t*3 +2] = vertices[v+2] ; + } + t++ ; v++ ; + } + v += 2 ; + } + return t ; + } + + private static int fansToTriangles(int tstart, int tbuff[], + int vstart, int vertices[], + int stripStart, int stripCounts[], + int stripCount) { + int t = tstart ; + int v = vstart ; + for (int i = 0 ; i < stripCount ; i++) { + for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) { + tbuff[t*3 +0] = vertices[v] ; + tbuff[t*3 +1] = vertices[v+j+1] ; + tbuff[t*3 +2] = vertices[v+j+2] ; + t++ ; + } + v += stripCounts[i+stripStart] ; + } + return t ; + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning a 2-element array of + * StripArray objects. The first StripArray will contain triangle strips + * and the second will contain individual triangles in the vertices + * field. Short strips will be converted to individual triangles. + * + * @param vertices an object implementing GeneralizedStripFlags + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @param shortStripSize strips this size or less will be converted to + * individual triangles if there are more than maxShortStrips of them + * @param maxShortStrips maximum number of short strips allowed before + * creating individual triangles + * @return a 2-element array containing strips in 0 and triangles in 1 + */ + static StripArray[] toStripsAndTriangles(GeneralizedStripFlags vertices, + int frontFace, int shortStripSize, + int maxShortStrips) { + int longStripCount = 0 ; + int longStripVertexCount = 0 ; + int shortStripCount = 0 ; + int triangleCount = 0 ; + + StripArray sa[] = new StripArray[2] ; + StripArray ts = toTriangleStrips(vertices, frontFace) ; + + for (int i = 0 ; i < ts.stripCounts.count ; i++) + if (ts.stripCounts.ints[i] <= shortStripSize) { + shortStripCount++ ; + triangleCount += ts.stripCounts.ints[i] - 2 ; + } else { + longStripCount++ ; + longStripVertexCount += ts.stripCounts.ints[i] ; + } + + if (debug) + System.err.print("GeneralizedStrip.toStripsAndTriangles\n" + + " short strip size: " + shortStripSize + + " short strips tolerated: " + maxShortStrips + + " number of short strips: " + shortStripCount + + "\n\n") ; + + if (shortStripCount <= maxShortStrips) { + sa[0] = ts ; + sa[1] = null ; + } else { + int si = 0 ; int newStripVerts[] = new int[longStripVertexCount] ; + int ci = 0 ; int newStripCounts[] = new int[longStripCount] ; + int ti = 0 ; int triangles[] = new int[3*triangleCount] ; + int vi = 0 ; + + for (int i = 0 ; i < ts.stripCounts.count ; i++) { + if (ts.stripCounts.ints[i] <= shortStripSize) { + ti = stripsToTriangles(ti, triangles, + vi, ts.vertices.ints, + i, ts.stripCounts.ints, 1) ; + vi += ts.stripCounts.ints[i] ; + } else { + newStripCounts[ci++] = ts.stripCounts.ints[i] ; + for (int j = 0 ; j < ts.stripCounts.ints[i] ; j++) + newStripVerts[si++] = ts.vertices.ints[vi++] ; + } + } + + if (longStripCount > 0) + sa[0] = new StripArray(new IntList(newStripVerts), + new IntList(newStripCounts)) ; + else + sa[0] = null ; + + sa[1] = new StripArray(new IntList(triangles), null) ; + + if (debug) { + System.err.println(" triangles separated: " + triangleCount) ; + if (longStripCount > 0) { + System.err.println + (" new vertices/strip: " + + ((float)longStripVertexCount/(float)longStripCount)) ; + + System.err.print(" long strip counts: [") ; + for (int i = 0 ; i < longStripCount-1 ; i++) + System.err.print(newStripCounts[i++] + ", ") ; + + System.err.println + (newStripCounts[longStripCount-1] + "]\n") ; + } + } + } + return sa ; + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning a StripArray. + * + * RESTART_CW and RESTART_CCW are treated as equivalent, as are + * REPLACE_MIDDLE and REPLACE_OLDEST. + * + * @param vertices an object implementing GeneralizedStripFlags + * @return a StripArray representing an array of line strips + */ + static StripArray toLineStrips(GeneralizedStripFlags vertices) { + int v, size, stripStart, stripLength, flag ; + + stripStart = 0 ; + stripLength = 2 ; + size = vertices.getFlagCount() ; + + // Initialize IntLists to worst-case sizes. + IntList stripVerts = new IntList(size*2) ; + IntList stripCounts = new IntList(size) ; + + // Vertex replace flags for the first two vertices are irrelevant. + v = 2 ; + while (v < size) { + flag = vertices.getFlag(v) ; + + if ((flag != RESTART_CW) && (flag != RESTART_CCW)) { + // proceed to the next vertex. + stripLength++ ; + v++ ; + + } else { + // Record the last strip. + stripCounts.add(stripLength) ; + for (int i = stripStart ; i < stripStart+stripLength ; i++) + stripVerts.add(i) ; + + // Start a new strip and skip to its 3rd vertex. + stripStart = v ; + stripLength = 2 ; + v += 2 ; + } + } + + // Finish off the last strip. + // If v > size then the strip is degenerate. + if (v == size) { + stripCounts.add(stripLength) ; + for (int i = stripStart ; i < stripStart+stripLength ; i++) + stripVerts.add(i) ; + } else + throw new IllegalArgumentException + (J3dI18N.getString("GeneralizedStrip0")) ; + + if (debug) { + System.err.println("GeneralizedStrip.toLineStrips\n") ; + if (v > size) + System.err.println(" ended with a degenerate line") ; + + System.err.println(" number of strips: " + stripCounts.count) ; + if (stripCounts.count > 0) { + System.err.println(" number of vertices: " + stripVerts.count) ; + System.err.println(" vertices/strip: " + + (float)stripVerts.count/stripCounts.count) ; + System.err.println(" strip counts: " + stripCounts.toString()) ; + // System.err.println(" indices: " + stripVerts.toString()) ; + } + System.err.println() ; + } + + if (stripCounts.count > 0) + return new StripArray(stripVerts, stripCounts) ; + else + return null ; + } + + /** + * Counts the number of lines defined by arrays of line strips. + * + * @param stripCounts array of strip counts, as used by the + * GeometryStripArray object + * @return number of lines in the strips + */ + static int getLineCount(int stripCounts[]) { + int count = 0 ; + for (int i = 0 ; i < stripCounts.length ; i++) + count += (stripCounts[i] - 1) ; + return count ; + } + + /** + * Counts the number of triangles defined by arrays of + * triangle strips or fans. + * + * @param stripCounts array of strip counts, as used by the + * GeometryStripArray object + * @return number of triangles in the strips or fans + */ + static int getTriangleCount(int stripCounts[]) { + int count = 0 ; + for (int i = 0 ; i < stripCounts.length ; i++) + count += (stripCounts[i] - 2) ; + return count ; + } + + /** + * Counts the number of triangles defined by arrays of + * triangle strips or fans. + * + * @param stripCounts IntList of strip counts + * @return number of triangles in the strips or fans + */ + static int getTriangleCount(IntList stripCounts) { + int count = 0 ; + for (int i = 0 ; i < stripCounts.count ; i++) + count += (stripCounts.ints[i] - 2) ; + return count ; + } + + /** + * Breaks up triangle strips into separate triangles. + * + * @param stripCounts array of strip counts, as used by the + * GeometryStripArray object + * @return array of ints which index into the original vertex array; each + * set of three consecutive vertex indices defines a single triangle + */ + static int[] stripsToTriangles(int stripCounts[]) { + int triangleCount = getTriangleCount(stripCounts) ; + int tbuff[] = new int[3*triangleCount] ; + IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ; + + vertices.fillAscending() ; + stripsToTriangles(0, tbuff, + 0, vertices.ints, + 0, stripCounts, + stripCounts.length) ; + return tbuff ; + } + + /** + * Breaks up triangle fans into separate triangles. + * + * @param stripCounts array of strip counts, as used by the + * GeometryStripArray object + * @return array of ints which index into the original vertex array; each + * set of three consecutive vertex indices defines a single triangle + */ + static int[] fansToTriangles(int stripCounts[]) { + int triangleCount = getTriangleCount(stripCounts) ; + int tbuff[] = new int[3*triangleCount] ; + IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ; + + vertices.fillAscending() ; + fansToTriangles(0, tbuff, + 0, vertices.ints, + 0, stripCounts, + stripCounts.length) ; + return tbuff ; + } + + /** + * Takes a fan and converts it to one or more strips. + * + * @param v index into the fans array of the first vertex in the fan + * @param length number of vertices in the fan + * @param fans array of vertex indices representing one or more fans + * @param convexPlanar if true indicates that the fan is convex and + * planar; such fans will always be converted into a single strip + * @return a StripArray containing the converted strips + */ + static StripArray fanToStrips(int v, int length, int fans[], + boolean convexPlanar) { + + // Initialize IntLists to worst-case sizes. + IntList stripVerts = new IntList(length*3) ; + IntList stripCounts = new IntList(length) ; + + fanToStrips(v, length, fans, stripVerts, stripCounts, convexPlanar) ; + return new StripArray(stripVerts, stripCounts) ; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeneralizedStripFlags.java b/j3d-core/src/classes/share/javax/media/j3d/GeneralizedStripFlags.java new file mode 100644 index 0000000..9d37808 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeneralizedStripFlags.java @@ -0,0 +1,92 @@ +/* + * $RCSfile: GeneralizedStripFlags.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A class which implements GeneralizedStripFlags provides the means to access + * the vertex replace code flags associated with each vertex of a generalized + * strip. This allows a flexible representation of generalized strips for + * various classes and makes it possible to provide a common subset of static + * methods which operate only on their topology. + * + * @see GeneralizedStrip + * @see GeneralizedVertexList + */ +interface GeneralizedStripFlags { + + /** + * This flag indicates that a vertex starts a new strip with clockwise + * winding. + */ + static final int RESTART_CW = 0 ; + + /** + * This flag indicates that a vertex starts a new strip with + * counter-clockwise winding. + */ + static final int RESTART_CCW = 1 ; + + /** + * This flag indicates that the next triangle in the strip is defined by + * replacing the middle vertex of the previous triangle in the strip. + */ + static final int REPLACE_MIDDLE = 2 ; + + /** + * This flag indicates that the next triangle in the strip is defined by + * replacing the oldest vertex of the previous triangle in the strip. + */ + static final int REPLACE_OLDEST = 3 ; + + /** + * This constant is used to indicate that triangles with clockwise vertex + * winding are front facing. + */ + static final int FRONTFACE_CW = 0 ; + + /** + * This constant is used to indicate that triangles with counter-clockwise + * vertex winding are front facing. + */ + static final int FRONTFACE_CCW = 1 ; + + /** + * Return the number of flags. This should be the same as the number of + * vertices in the generalized strip. + */ + int getFlagCount() ; + + /** + * Return the flag associated with the vertex at the specified index. + */ + int getFlag(int index) ; +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeneralizedVertexList.java b/j3d-core/src/classes/share/javax/media/j3d/GeneralizedVertexList.java new file mode 100644 index 0000000..d146189 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeneralizedVertexList.java @@ -0,0 +1,406 @@ +/* + * $RCSfile: GeneralizedVertexList.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import javax.vecmath.* ; +import java.util.* ; + +/** + * The GeneralizedVertexList class is a variable-size list used to + * collect the vertices for a generalized strip of points, lines, or + * triangles. This is used by the GeometryDecompressor. This class + * implements the GeneralizedStripFlags interface and provides methods + * for copying instance vertex data into various fixed-size + * GeometryArray representations. + * + * @see GeneralizedStrip + * @see GeometryDecompressor + */ +class GeneralizedVertexList implements GeneralizedStripFlags { + + // The ArrayList containing the vertices. + private ArrayList vertices ; + + // Booleans for individual vertex components. + private boolean hasColor3 = false ; + private boolean hasColor4 = false ; + private boolean hasNormals = false ; + + // Indicates the vertex winding of front-facing triangles in this strip. + private int frontFace ; + + /** + * Count of number of strips generated after conversion to GeometryArray. + */ + int stripCount ; + + /** + * Count of number of vertices generated after conversion to GeometryArray. + */ + int vertexCount ; + + /** + * Count of number of triangles generated after conversion to GeometryArray. + */ + int triangleCount ; + + /** + * Bits describing the data bundled with each vertex. This is specified + * using the GeometryArray mask components. + */ + int vertexFormat ; + + /** + * Creates a new GeneralizedVertexList for the specified vertex format. + * @param vertexFormat a mask indicating which components are + * present in each vertex, as used by GeometryArray. + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @param initSize initial number of elements + * @see GeometryArray + */ + GeneralizedVertexList(int vertexFormat, int frontFace, int initSize) { + this.frontFace = frontFace ; + setVertexFormat(vertexFormat) ; + + if (initSize == 0) + vertices = new ArrayList() ; + else + vertices = new ArrayList(initSize) ; + + stripCount = 0 ; + vertexCount = 0 ; + triangleCount = 0 ; + } + + /** + * Creates a new GeneralizedVertexList for the specified vertex format. + * @param vertexFormat a mask indicating which components are + * present in each vertex, as used by GeometryArray. + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @see GeometryArray + */ + GeneralizedVertexList(int vertexFormat, int frontFace) { + this(vertexFormat, frontFace, 0) ; + } + + /** + * Sets the vertex format for this vertex list. + * @param vertexFormat a mask indicating which components are + * present in each vertex, as used by GeometryArray. + */ + void setVertexFormat(int vertexFormat) { + this.vertexFormat = vertexFormat ; + + if ((vertexFormat & GeometryArray.NORMALS) != 0) + hasNormals = true ; + + if ((vertexFormat & GeometryArray.COLOR) != 0) + if ((vertexFormat & GeometryArray.WITH_ALPHA) != 0) + hasColor4 = true ; + else + hasColor3 = true ; + } + + /** + * A class with fields corresponding to all the data that can be bundled + * with the vertices of generalized strips. + */ + class Vertex { + int flag ; + Point3f coord ; + Color3f color3 ; + Color4f color4 ; + Vector3f normal ; + + Vertex(Point3f p, Vector3f n, Color4f c, int flag) { + this.flag = flag ; + coord = new Point3f(p) ; + + if (hasNormals) + normal = new Vector3f(n) ; + + if (hasColor3) + color3 = new Color3f(c.x, c.y, c.z) ; + + else if (hasColor4) + color4 = new Color4f(c) ; + } + } + + /** + * Copy vertex data to a new Vertex object and add it to this list. + */ + void addVertex(Point3f pos, Vector3f norm, Color4f color, int flag) { + vertices.add(new Vertex(pos, norm, color, flag)) ; + } + + /** + * Return the number of vertices in this list. + */ + int size() { + return vertices.size() ; + } + + // GeneralizedStripFlags interface implementation + public int getFlagCount() { + return vertices.size() ; + } + + // GeneralizedStripFlags interface implementation + public int getFlag(int index) { + return ((Vertex)vertices.get(index)).flag ; + } + + // Copy vertices in the given order to a fixed-length GeometryArray. + // Using the array versions of the GeometryArray set() methods results in + // a significant performance improvement despite needing to create + // fixed-length arrays to hold the vertex elements. + private void copyVertexData(GeometryArray ga, + GeneralizedStrip.IntList indices) { + Vertex v ; + Point3f p3f[] = new Point3f[indices.count] ; + + if (hasNormals) { + Vector3f v3f[] = new Vector3f[indices.count] ; + if (hasColor3) { + Color3f c3f[] = new Color3f[indices.count] ; + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + v3f[i] = v.normal ; + c3f[i] = v.color3 ; + } + ga.setColors(0, c3f) ; + + } else if (hasColor4) { + Color4f c4f[] = new Color4f[indices.count] ; + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + v3f[i] = v.normal ; + c4f[i] = v.color4 ; + } + ga.setColors(0, c4f) ; + + } else { + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + v3f[i] = v.normal ; + } + } + ga.setNormals(0, v3f) ; + + } else { + if (hasColor3) { + Color3f c3f[] = new Color3f[indices.count] ; + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + c3f[i] = v.color3 ; + } + ga.setColors(0, c3f) ; + + } else if (hasColor4) { + Color4f c4f[] = new Color4f[indices.count] ; + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + c4f[i] = v.color4 ; + } + ga.setColors(0, c4f) ; + + } else { + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + } + } + } + ga.setCoordinates(0, p3f) ; + } + + /** + * Output a PointArray. + */ + PointArray toPointArray() { + int size = vertices.size() ; + + if (size > 0) { + PointArray pa = new PointArray(size, vertexFormat) ; + GeneralizedStrip.IntList il = new GeneralizedStrip.IntList(size) ; + + il.fillAscending() ; + copyVertexData(pa, il) ; + + vertexCount += size ; + return pa ; + } + else + return null ; + } + + /** + * Output a TriangleArray. + */ + TriangleArray toTriangleArray() { + int vertices[] = GeneralizedStrip.toTriangles(this, frontFace) ; + + if (vertices != null) { + TriangleArray ta ; + GeneralizedStrip.IntList il ; + + ta = new TriangleArray(vertices.length, vertexFormat) ; + il = new GeneralizedStrip.IntList(vertices) ; + copyVertexData(ta, il) ; + + vertexCount += vertices.length ; + triangleCount += vertices.length/3 ; + return ta ; + } else + return null ; + } + + /** + * Output a LineStripArray. + */ + LineStripArray toLineStripArray() { + GeneralizedStrip.StripArray stripArray = + GeneralizedStrip.toLineStrips(this) ; + + if (stripArray != null) { + LineStripArray lsa ; + lsa = new LineStripArray(stripArray.vertices.count, + vertexFormat, + stripArray.stripCounts.trim()) ; + + copyVertexData(lsa, stripArray.vertices) ; + + vertexCount += stripArray.vertices.count ; + stripCount += stripArray.stripCounts.count ; + return lsa ; + } else + return null ; + } + + /** + * Output a TriangleStripArray. + */ + TriangleStripArray toTriangleStripArray() { + GeneralizedStrip.StripArray stripArray = + GeneralizedStrip.toTriangleStrips(this, frontFace) ; + + if (stripArray != null) { + TriangleStripArray tsa ; + tsa = new TriangleStripArray(stripArray.vertices.count, + vertexFormat, + stripArray.stripCounts.trim()) ; + + copyVertexData(tsa, stripArray.vertices) ; + + vertexCount += stripArray.vertices.count ; + stripCount += stripArray.stripCounts.count ; + return tsa ; + } else + return null ; + } + + /** + * Output triangle strip and triangle fan arrays. + * @return a 2-element array of GeometryStripArray; element 0 if non-null + * will contain a TriangleStripArray, and element 1 if non-null will + * contain a TriangleFanArray. + */ + GeometryStripArray[] toStripAndFanArrays() { + GeneralizedStrip.StripArray stripArray[] = + GeneralizedStrip.toStripsAndFans(this, frontFace) ; + + GeometryStripArray gsa[] = new GeometryStripArray[2] ; + + if (stripArray[0] != null) { + gsa[0] = new TriangleStripArray(stripArray[0].vertices.count, + vertexFormat, + stripArray[0].stripCounts.trim()) ; + + copyVertexData(gsa[0], stripArray[0].vertices) ; + + vertexCount += stripArray[0].vertices.count ; + stripCount += stripArray[0].stripCounts.count ; + } + + if (stripArray[1] != null) { + gsa[1] = new TriangleFanArray(stripArray[1].vertices.count, + vertexFormat, + stripArray[1].stripCounts.trim()) ; + + copyVertexData(gsa[1], stripArray[1].vertices) ; + + vertexCount += stripArray[1].vertices.count ; + stripCount += stripArray[1].stripCounts.count ; + } + return gsa ; + } + + /** + * Output triangle strip and and triangle arrays. + * @return a 2-element array of GeometryArray; element 0 if non-null + * will contain a TriangleStripArray, and element 1 if non-null will + * contain a TriangleArray. + */ + GeometryArray[] toStripAndTriangleArrays() { + GeneralizedStrip.StripArray stripArray[] = + GeneralizedStrip.toStripsAndTriangles(this, frontFace, 4, 12) ; + + GeometryArray ga[] = new GeometryArray[2] ; + + if (stripArray[0] != null) { + ga[0] = new TriangleStripArray(stripArray[0].vertices.count, + vertexFormat, + stripArray[0].stripCounts.trim()) ; + + copyVertexData(ga[0], stripArray[0].vertices) ; + + vertexCount += stripArray[0].vertices.count ; + stripCount += stripArray[0].stripCounts.count ; + } + + if (stripArray[1] != null) { + ga[1] = new TriangleArray(stripArray[1].vertices.count, + vertexFormat) ; + + copyVertexData(ga[1], stripArray[1].vertices) ; + triangleCount += stripArray[1].vertices.count/3 ; + } + return ga ; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Geometry.java b/j3d-core/src/classes/share/javax/media/j3d/Geometry.java new file mode 100644 index 0000000..fd160cc --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Geometry.java @@ -0,0 +1,72 @@ +/* + * $RCSfile: Geometry.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Geometry is an abstract class that specifies the geometry + * component information required by a Shape3D node. Geometry objects + * describe both the geometry and topology of the Shape3D nodes that + * reference them. Geometry objects consist of four generic geometric + * types:

+ *

  • Compressed Geometry
  • + *
  • GeometryArray
  • + *
  • Raster
  • + *
  • Text3D
  • + *

+ * Each of these geometric types defines a visible object or set of + * objects. A Geometry object is used as a component object of a Shape3D + * leaf node. + * + */ + +public abstract class Geometry extends NodeComponent { + + /** + * Specifies that this Geometry allows intersect operation. This + * capability bit is set (true) by default for all Geometry objects. + */ + public static final int + ALLOW_INTERSECT = CapabilityBits.GEOMETRY_ALLOW_INTERSECT; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_INTERSECT + }; + + /** + * Constructs a new Geometry object. + */ + public Geometry() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryArray.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryArray.java new file mode 100644 index 0000000..bd29d67 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryArray.java @@ -0,0 +1,7460 @@ +/* + * $RCSfile: GeometryArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:21 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + + +/** + * The GeometryArray object contains separate arrays of positional + * coordinates, colors, normals, texture coordinates, and vertex + * attributes that + * describe point, line, or polygon geometry. This class is extended + * to create the various primitive types (such as lines, + * triangle strips, etc.). + * Vertex data may be passed to this geometry array in one of two + * ways: by copying the data into the array using the existing + * methods, or by passing a reference to the data. + *

+ *

    + *
  • + * By Copying: + * The existing methods for setting positional coordinates, colors, + * normals, texture coordinates, and vertex attributes + * (such as setCoordinate, + * setColors, etc.) copy the data into this + * GeometryArray. This is appropriate for many applications and + * offers an application much flexibility in organizing its data. + * This is the default mode. + *
  • + *
  • By Reference: + * A new set of methods in Java 3D version 1.2 allows data to be + * accessed by reference, directly from the user's arrays. To use + * this feature, set the BY_REFERENCE bit in the + * vertexFormat field of the constructor for this + * GeometryArray. In this mode, the various set methods for + * coordinates, normals, colors, texture coordinates, and vertex attributes + * are not used. + * Instead, new methods are used to set a reference to user-supplied + * coordinate, color, normal, texture coordinate, and vertex attribute + * arrays (such as + * setCoordRefFloat, setColorRefFloat, + * etc.). Data in any array that is referenced by a live or compiled + * GeometryArray object may only be modified via the + * updateData method (subject to the + * ALLOW_REF_DATA_WRITE capability bit). Applications + * must exercise care not to violate this rule. If any referenced + * geometry data is modified outside of the updateData + * method, the results are undefined. + *
  • + *
+ *

+ * All colors used in the geometry array object must be in the range [0.0,1.0]. + * Values outside this range will cause undefined results. + * All normals used in the geometry array object must be unit length + * vectors. That is their geometric length must be 1.0. Normals that + * are not unit length vectors will cause undefined results. + *

+ * Note that the term coordinate, as used in the method names + * and method descriptions, actually refers to a set of x, + * y, and z coordinates representing the position of a + * single vertex. The term coordinates (plural) is used to + * indicate sets of x, y, and z coordinates for + * multiple vertices. This is somewhat at odds with the mathematical + * definition of a coordinate, but is used as a convenient shorthand. + * Similarly, the term texture coordinate is used to indicate a + * set of texture coordinates for a single vertex, while the term + * texture coordinates (plural) is used to indicate sets of + * texture coordinates for multiple vertices. + */ + +public abstract class GeometryArray extends Geometry { + + /** + * Specifies that this GeometryArray allows reading the array of + * coordinates. + */ + public static final int + ALLOW_COORDINATE_READ = CapabilityBits.GEOMETRY_ARRAY_ALLOW_COORDINATE_READ; + + /** + * Specifies that this GeometryArray allows writing the array of + * coordinates. + */ + public static final int + ALLOW_COORDINATE_WRITE = CapabilityBits.GEOMETRY_ARRAY_ALLOW_COORDINATE_WRITE; + + /** + * Specifies that this GeometryArray allows reading the array of + * colors. + */ + public static final int + ALLOW_COLOR_READ = CapabilityBits.GEOMETRY_ARRAY_ALLOW_COLOR_READ; + + /** + * Specifies that this GeometryArray allows writing the array of + * colors. + */ + public static final int + ALLOW_COLOR_WRITE = CapabilityBits.GEOMETRY_ARRAY_ALLOW_COLOR_WRITE; + + /** + * Specifies that this GeometryArray allows reading the array of + * normals. + */ + public static final int + ALLOW_NORMAL_READ = CapabilityBits.GEOMETRY_ARRAY_ALLOW_NORMAL_READ; + + /** + * Specifies that this GeometryArray allows writing the array of + * normals. + */ + public static final int + ALLOW_NORMAL_WRITE = CapabilityBits.GEOMETRY_ARRAY_ALLOW_NORMAL_WRITE; + + /** + * Specifies that this GeometryArray allows reading the array of + * texture coordinates. + */ + public static final int + ALLOW_TEXCOORD_READ = CapabilityBits.GEOMETRY_ARRAY_ALLOW_TEXCOORD_READ; + + /** + * Specifies that this GeometryArray allows writing the array of + * texture coordinates. + */ + public static final int + ALLOW_TEXCOORD_WRITE = CapabilityBits.GEOMETRY_ARRAY_ALLOW_TEXCOORD_WRITE; + + /** + * Specifies that this GeometryArray allows reading the array of + * vertex attributes. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_VERTEX_ATTR_READ = CapabilityBits.GEOMETRY_ARRAY_ALLOW_VERTEX_ATTR_READ; + + /** + * Specifies that this GeometryArray allows writing the array of + * vertex attributes. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_VERTEX_ATTR_WRITE = CapabilityBits.GEOMETRY_ARRAY_ALLOW_VERTEX_ATTR_WRITE; + + /** + * Specifies that this GeometryArray allows reading the count or + * initial index information for this object. + */ + public static final int + ALLOW_COUNT_READ = CapabilityBits.GEOMETRY_ARRAY_ALLOW_COUNT_READ; + + /** + * Specifies that this GeometryArray allows writing the count or + * initial index information for this object. + * + * @since Java 3D 1.2 + */ + public static final int + ALLOW_COUNT_WRITE = CapabilityBits.GEOMETRY_ARRAY_ALLOW_COUNT_WRITE; + + /** + * Specifies that this GeometryArray allows reading the vertex format + * information for this object. + */ + public static final int + ALLOW_FORMAT_READ = CapabilityBits.GEOMETRY_ARRAY_ALLOW_FORMAT_READ; + + /** + * Specifies that this GeometryArray allows reading the geometry + * data reference information for this object. This is only used in + * by-reference geometry mode. + * + * @since Java 3D 1.2 + */ + public static final int + ALLOW_REF_DATA_READ = CapabilityBits.GEOMETRY_ARRAY_ALLOW_REF_DATA_READ; + + private static final int J3D_1_2_ALLOW_REF_DATA_READ = + CapabilityBits.J3D_1_2_GEOMETRY_ARRAY_ALLOW_REF_DATA_READ; + + /** + * Specifies that this GeometryArray allows writing the geometry + * data reference information for this object. It also enables + * writing the referenced data itself, via the GeometryUpdater + * interface. This is only used in by-reference geometry mode. + * + * @since Java 3D 1.2 + */ + public static final int + ALLOW_REF_DATA_WRITE = CapabilityBits.GEOMETRY_ARRAY_ALLOW_REF_DATA_WRITE; + + /** + * Specifies that this GeometryArray contains an array of coordinates. + * This bit must be set. + */ + public static final int COORDINATES = 0x01; + + /** + * Specifies that this GeometryArray contains an array of normals. + */ + public static final int NORMALS = 0x02; + + /** + * Specifies that this GeometryArray contains an array of colors. + */ + static final int COLOR = 0x04; + + /** + * Specifies that this GeometryArray's colors contain alpha. + */ + static final int WITH_ALPHA = 0x08; + + /** + * Specifies that this GeometryArray contains an array of colors without alpha. + */ + public static final int COLOR_3 = COLOR; + + /** + * Specifies that this GeometryArray contains an array of colors with alpha. + * This takes precedence over COLOR_3. + */ + public static final int COLOR_4 = COLOR | WITH_ALPHA; + + /** + * Specifies that this GeometryArray contains one or more arrays of + * 2D texture coordinates. + */ + public static final int TEXTURE_COORDINATE_2 = 0x20; + + /** + * Specifies that this GeometryArray contains one or more arrays of + * 3D texture coordinates. + * This takes precedence over TEXTURE_COORDINATE_2. + */ + public static final int TEXTURE_COORDINATE_3 = 0x40; + + + /** + * Specifies that this GeometryArray contains one or more arrays of + * 4D texture coordinates. + * This takes precedence over TEXTURE_COORDINATE_2 and TEXTURE_COORDINATE_3. + * + * @since Java 3D 1.3 + */ + public static final int TEXTURE_COORDINATE_4 = 0x400; + + + static final int TEXTURE_COORDINATE = TEXTURE_COORDINATE_2 | + TEXTURE_COORDINATE_3 | + TEXTURE_COORDINATE_4; + + /** + * Specifies that the position, color, normal, and texture coordinate + * data for this GeometryArray are accessed by reference. + * + * @since Java 3D 1.2 + */ + public static final int BY_REFERENCE = 0x80; + + + /** + * Specifies that the position, color, normal, and texture + * coordinate data for this GeometryArray are accessed via a single + * interleaved, floating-point array reference. All of the data + * values for each vertex are stored in consecutive memory + * locations. This flag is only valid in conjunction with the + * BY_REFERENCE flag. + * + * @since Java 3D 1.2 + */ + public static final int INTERLEAVED = 0x100; + + /** + * Specifies that geometry by-reference data for this + * GeometryArray, whether interleaved or non-interleaved, is + * accessed via J3DBuffer objects that wrap NIO Buffer objects, + * rather than float, double, byte, or TupleXX arrays. This flag + * is only valid in conjunction with the BY_REFERENCE + * flag. + * + * @see J3DBuffer + * @see #setCoordRefBuffer(J3DBuffer) + * @see #setColorRefBuffer(J3DBuffer) + * @see #setNormalRefBuffer(J3DBuffer) + * @see #setTexCoordRefBuffer(int,J3DBuffer) + * @see #setVertexAttrRefBuffer(int,J3DBuffer) + * @see #setInterleavedVertexBuffer(J3DBuffer) + * + * @since Java 3D 1.3 + */ + public static final int USE_NIO_BUFFER = 0x800; + + /** + * Specifies that only the coordinate indices are used for indexed + * geometry arrays. In this mode, the values from the coordinate + * index array are used as a single set of index values to access + * the vertex data for all five vertex components (coord, color, + * normal, texCoord, and vertexAttr). The color, normal, texCoord, + * and vertexAttr index arrays are neither allocated nor used. Any + * attempt to access the color, normal, texCoord, + * or vertexAttr index arrays will result in a NullPointerException. + * This flag is only valid for indexed geometry arrays + * (subclasses of IndexedGeometryArray). + * + * @since Java 3D 1.3 + */ + public static final int USE_COORD_INDEX_ONLY = 0x200; + + /** + * Specifies that this GeometryArray contains one or more arrays of + * vertex attributes. These attributes are used in programmable + * shading. + * + * @since Java 3D 1.4 + */ + public static final int VERTEX_ATTRIBUTES = 0x1000; + + //NVaidya + /** + * Specifies that the indices in this GeometryArray + * are accessed by reference. This flag is only valid for + * indexed geometry arrays (subclasses of IndexedGeometryArray) and only + * when used in conjunction with the BY_REFERENCE and + * USE_COORD_INDEX_ONLY flags. + * + * @since Java 3D 1.5 + */ + public static final int BY_REFERENCE_INDICES = 0x2000; + + // Used to keep track of the last bit (for adding new bits only) + private static final int LAST_FORMAT_BIT = 0x2000; + + // Scratch arrays for converting Point[234]f to TexCoord[234]f + private TexCoord2f [] texCoord2fArray = null; + private TexCoord3f [] texCoord3fArray = null; + private TexCoord4f [] texCoord4fArray = null; + private TexCoord2f texCoord2fScratch = null; + private TexCoord3f texCoord3fScratch = null; + + private static final int[] defTexCoordMap = { 0 }; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_COLOR_READ, + ALLOW_COORDINATE_READ, + ALLOW_COUNT_READ, + ALLOW_FORMAT_READ, + ALLOW_NORMAL_READ, + ALLOW_REF_DATA_READ, + ALLOW_TEXCOORD_READ, + ALLOW_VERTEX_ATTR_READ + }; + + + // non-public, no parameter constructor + GeometryArray() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + //NVaidya + /** + * Constructs an empty GeometryArray object with the specified + * number of vertices and vertex format. Defaults are used + * for all other parameters. The default values are as follows: + *

    + * texCoordSetCount : 1
    + * texCoordSetMap : { 0 }
    + * vertexAttrCount : 0
    + * vertexAttrSizes : null
    + * validVertexCount : vertexCount
    + * initialVertexIndex : 0
    + * initialCoordIndex : 0
    + * initialColorIndex : 0
    + * initialNormalIndex : 0
    + * initialTexCoordIndex : 0
    + * initialVertexAttrIndex : 0
    + * all data array values : 0.0
    + * all data array references : null
    + *
+ * + * @param vertexCount the number of vertex elements in this GeometryArray + * @param vertexFormat a mask indicating which components are + * present in each vertex. This is specified as one or more + * individual flags that are bitwise "OR"ed together to describe + * the per-vertex data. + * The flags include: COORDINATES, to signal the inclusion of + * vertex positions--always present; NORMALS, to signal + * the inclusion of per vertex normals; one of COLOR_3 or + * COLOR_4, to signal the inclusion of per vertex + * colors (without or with alpha information); one of + * TEXTURE_COORDINATE_2, TEXTURE_COORDINATE_3 + * or TEXTURE_COORDINATE_4, + * to signal the + * inclusion of per-vertex texture coordinates (2D, 3D or 4D); + * BY_REFERENCE, to indicate that the data is passed + * by reference + * rather than by copying; INTERLEAVED, to indicate + * that the referenced + * data is interleaved in a single array; + * USE_NIO_BUFFER, to indicate that the referenced data + * is accessed via a J3DBuffer object that wraps an NIO buffer; + * USE_COORD_INDEX_ONLY, + * to indicate that only the coordinate indices are used for indexed + * geometry arrays; + * BY_REFERENCE_INDICES, to indicate + * that the indices are accessed by reference in indexed + * geometry arrays.

+ * + * @exception IllegalArgumentException if vertexCount < 0 + * + * @exception IllegalArgumentException if vertexFormat does not + * include COORDINATES + * + * @exception IllegalArgumentException if the USE_COORD_INDEX_ONLY + * bit or the BY_REFERENCE_INDICES bit is set for + * non-indexed geometry arrays (that is, GeometryArray objects + * that are not a subclass of IndexedGeometryArray) + * + * @exception IllegalArgumentException if the INTERLEAVED + * bit is set without the BY_REFERENCE bit being set + * + * @exception IllegalArgumentException if the USE_NIO_BUFFER + * bit is set without the BY_REFERENCE bit being set + * + * @exception IllegalArgumentException if the INTERLEAVED + * bit and the VERTEX_ATTRIBUTES bit are both set + * + * @exception IllegalArgumentException if the + * BY_REFERENCE_INDICES + * bit is set without the BY_REFERENCE and + * USE_COORD_INDEX_ONLY bits being set + */ + public GeometryArray(int vertexCount, int vertexFormat) { + this(vertexCount, vertexFormat, + ((vertexFormat & TEXTURE_COORDINATE) != 0 ? 1 : 0), + ((vertexFormat & TEXTURE_COORDINATE) != 0 ? defTexCoordMap : null)); + } + + + //NVaidya + /** + * Constructs an empty GeometryArray object with the specified + * number of vertices, vertex format, number of texture coordinate + * sets, and texture coordinate mapping array. Defaults are used + * for all other parameters. + * + * @param vertexCount the number of vertex elements in this + * GeometryArray

+ * + * @param vertexFormat a mask indicating which components are + * present in each vertex. This is specified as one or more + * individual flags that are bitwise "OR"ed together to describe + * the per-vertex data. + * The flags include: COORDINATES, to signal the inclusion of + * vertex positions--always present; NORMALS, to signal + * the inclusion of per vertex normals; one of COLOR_3 or + * COLOR_4, to signal the inclusion of per vertex + * colors (without or with alpha information); one of + * TEXTURE_COORDINATE_2 or TEXTURE_COORDINATE_3 + * or TEXTURE_COORDINATE_4, + * to signal the + * inclusion of per-vertex texture coordinates (2D , 3D or 4D); + * BY_REFERENCE, to indicate that the data is passed + * by reference + * rather than by copying; INTERLEAVED, to indicate + * that the referenced + * data is interleaved in a single array; + * USE_NIO_BUFFER, to indicate that the referenced data + * is accessed via a J3DBuffer object that wraps an NIO buffer; + * USE_COORD_INDEX_ONLY, + * to indicate that only the coordinate indices are used for indexed + * geometry arrays; + * BY_REFERENCE_INDICES, to indicate + * that the indices are accessed by reference in indexed + * geometry arrays.

+ * + * @param texCoordSetCount the number of texture coordinate sets + * in this GeometryArray object. If vertexFormat + * does not include one of TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3, the + * texCoordSetCount parameter is not used.

+ * + * + * @param texCoordSetMap an array that maps texture coordinate + * sets to texture units. The array is indexed by texture unit + * number for each texture unit in the associated Appearance + * object. The values in the array specify the texture coordinate + * set within this GeometryArray object that maps to the + * corresponding texture + * unit. All elements within the array must be less than + * texCoordSetCount. A negative value specifies that + * no texture coordinate set maps to the texture unit + * corresponding to the index. If there are more texture units in + * any associated Appearance object than elements in the mapping + * array, the extra elements are assumed to be -1. The same + * texture coordinate set may be used for more than one texture + * unit. Each texture unit in every associated Appearance must + * have a valid source of texture coordinates: either a + * non-negative texture coordinate set must be specified in the + * mapping array or texture coordinate generation must be enabled. + * Texture coordinate generation will take precedence for those + * texture units for which a texture coordinate set is specified + * and texture coordinate generation is enabled. If + * vertexFormat does not include one of + * TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3 or + * TEXTURE_COORDINATE_4, the + * texCoordSetMap array is not used. The following example + * illustrates the use of the texCoordSetMap array. + * + *

+ *

+ *

+ * + * @exception IllegalArgumentException if vertexCount < 0 + * + * @exception IllegalArgumentException if vertexFormat does not + * include COORDINATES + * + * @exception IllegalArgumentException if the USE_COORD_INDEX_ONLY + * bit or the BY_REFERENCE_INDICES bit is set for + * non-indexed geometry arrays (that is, GeometryArray objects + * that are not a subclass of IndexedGeometryArray) + * + * @exception IllegalArgumentException if the INTERLEAVED + * bit is set without the BY_REFERENCE bit being set + * + * @exception IllegalArgumentException if the USE_NIO_BUFFER + * bit is set without the BY_REFERENCE bit being set + * + * @exception IllegalArgumentException if the INTERLEAVED + * bit and the VERTEX_ATTRIBUTES bit are both set + * + * @exception IllegalArgumentException if the + * BY_REFERENCE_INDICES + * bit is set without the BY_REFERENCE and + * USE_COORD_INDEX_ONLY bits being set + * + * @exception IllegalArgumentException if + * texCoordSetCount < 0 + * + * @exception IllegalArgumentException if any element in + * texCoordSetMap[] >= texCoordSetCount. + * + * @since Java 3D 1.2 + */ + public GeometryArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap) { + this(vertexCount, vertexFormat, texCoordSetCount, texCoordSetMap, 0, null); + } + + + //NVaidya + /** + * Constructs an empty GeometryArray object with the specified + * number of vertices, vertex format, number of texture coordinate + * sets, texture coordinate mapping array, vertex attribute count, + * and vertex attribute sizes array. + * + * @param vertexCount the number of vertex elements in this + * GeometryArray

+ * + * @param vertexFormat a mask indicating which components are + * present in each vertex. This is specified as one or more + * individual flags that are bitwise "OR"ed together to describe + * the per-vertex data. + * The flags include: COORDINATES, to signal the inclusion of + * vertex positions--always present; NORMALS, to signal + * the inclusion of per vertex normals; one of COLOR_3 or + * COLOR_4, to signal the inclusion of per vertex + * colors (without or with alpha information); one of + * TEXTURE_COORDINATE_2 or TEXTURE_COORDINATE_3 + * or TEXTURE_COORDINATE_4, + * to signal the + * inclusion of per-vertex texture coordinates (2D , 3D or 4D); + * VERTEX_ATTRIBUTES, to signal + * the inclusion of one or more arrays of vertex attributes; + * BY_REFERENCE, to indicate that the data is passed + * by reference + * rather than by copying; INTERLEAVED, to indicate + * that the referenced + * data is interleaved in a single array; + * USE_NIO_BUFFER, to indicate that the referenced data + * is accessed via a J3DBuffer object that wraps an NIO buffer; + * USE_COORD_INDEX_ONLY, + * to indicate that only the coordinate indices are used for indexed + * geometry arrays; + * BY_REFERENCE_INDICES, to indicate + * that the indices are accessed by reference in indexed + * geometry arrays.

+ * + * @param texCoordSetCount the number of texture coordinate sets + * in this GeometryArray object. If vertexFormat + * does not include one of TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3, the + * texCoordSetCount parameter is not used.

+ * + * + * @param texCoordSetMap an array that maps texture coordinate + * sets to texture units. The array is indexed by texture unit + * number for each texture unit in the associated Appearance + * object. The values in the array specify the texture coordinate + * set within this GeometryArray object that maps to the + * corresponding texture + * unit. All elements within the array must be less than + * texCoordSetCount. A negative value specifies that + * no texture coordinate set maps to the texture unit + * corresponding to the index. If there are more texture units in + * any associated Appearance object than elements in the mapping + * array, the extra elements are assumed to be -1. The same + * texture coordinate set may be used for more than one texture + * unit. Each texture unit in every associated Appearance must + * have a valid source of texture coordinates: either a + * non-negative texture coordinate set must be specified in the + * mapping array or texture coordinate generation must be enabled. + * Texture coordinate generation will take precedence for those + * texture units for which a texture coordinate set is specified + * and texture coordinate generation is enabled. If + * vertexFormat does not include one of + * TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3 or + * TEXTURE_COORDINATE_4, the + * texCoordSetMap array is not used. The following example + * illustrates the use of the texCoordSetMap array. + * + *

+ *

+ *

+ * + * @param vertexAttrCount the number of vertex attributes + * in this GeometryArray object. If vertexFormat + * does not include VERTEX_ATTRIBUTES, the + * vertexAttrCount parameter must be 0.

+ * + * @param vertexAttrSizes is an array that specifes the size of + * each vertex attribute. Each element in the array specifies the + * number of components in the attribute, from 1 to 4. The length + * of the array must be equal to vertexAttrCount.

+ * + * @exception IllegalArgumentException if vertexCount < 0 + * + * @exception IllegalArgumentException if vertexFormat does not + * include COORDINATES + * + * @exception IllegalArgumentException if the USE_COORD_INDEX_ONLY + * bit or the BY_REFERENCE_INDICES bit is set for + * non-indexed geometry arrays (that is, GeometryArray objects + * that are not a subclass of IndexedGeometryArray) + * + * @exception IllegalArgumentException if the INTERLEAVED + * bit is set without the BY_REFERENCE bit being set + * + * @exception IllegalArgumentException if the USE_NIO_BUFFER + * bit is set without the BY_REFERENCE bit being set + * + * @exception IllegalArgumentException if the INTERLEAVED + * bit and the VERTEX_ATTRIBUTES bit are both set + * + * @exception IllegalArgumentException if the + * BY_REFERENCE_INDICES + * bit is set without the BY_REFERENCE and + * USE_COORD_INDEX_ONLY bits being set + * + * @exception IllegalArgumentException if + * texCoordSetCount < 0 + * + * @exception IllegalArgumentException if any element in + * texCoordSetMap[] >= texCoordSetCount. + * + * @exception IllegalArgumentException if + * vertexAttrCount > 0 and the + * VERTEX_ATTRIBUTES bit is not set + * + * @exception IllegalArgumentException if + * vertexAttrCount < 0 + * + * @exception IllegalArgumentException if + * vertexAttrSizes.length != vertexAttrCount + * + * @exception IllegalArgumentException if any element in + * vertexAttrSizes[] is < 1 or + * > 4. + * + * @since Java 3D 1.4 + */ + public GeometryArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) { + + if (vertexCount < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray96")); + + if (texCoordSetCount < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray124")); + + if (vertexAttrCount < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray125")); + + if ((vertexFormat & COORDINATES) == 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray0")); + + if ((vertexFormat & INTERLEAVED) != 0 && + (vertexFormat & BY_REFERENCE) == 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray80")); + + if ((vertexFormat & INTERLEAVED) != 0 && + (vertexFormat & VERTEX_ATTRIBUTES) != 0) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray128")); + } + + if ((vertexFormat & USE_COORD_INDEX_ONLY) != 0 && + !(this instanceof IndexedGeometryArray)) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray135")); + } + + //NVaidya + if ((vertexFormat & BY_REFERENCE_INDICES) != 0) { + if (!(this instanceof IndexedGeometryArray)) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray136")); + if ((vertexFormat & BY_REFERENCE) == 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray137")); + if ((vertexFormat & USE_COORD_INDEX_ONLY) == 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray138")); + } + + if ((vertexFormat & USE_NIO_BUFFER) != 0 && + (vertexFormat & BY_REFERENCE) == 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray117")); + + if ((vertexFormat & TEXTURE_COORDINATE) != 0) { + if (texCoordSetMap == null) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray106")); + + if (texCoordSetCount == 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray107")); + + for (int i = 0; i < texCoordSetMap.length; i++) { + if (texCoordSetMap[i] >= texCoordSetCount) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray108")); + } + + if ((vertexFormat & TEXTURE_COORDINATE_2) != 0) { + texCoord2fArray = new TexCoord2f[1]; + texCoord2fScratch = new TexCoord2f(); + } + else if ((vertexFormat & TEXTURE_COORDINATE_3) != 0) { + texCoord3fArray = new TexCoord3f[1]; + texCoord3fScratch = new TexCoord3f(); + } + else if ((vertexFormat & TEXTURE_COORDINATE_4) != 0) { + texCoord4fArray = new TexCoord4f[1]; + } + } + + if ((vertexFormat & VERTEX_ATTRIBUTES) != 0) { + if (vertexAttrCount > 0) { + if (vertexAttrCount != vertexAttrSizes.length) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray132")); + } + + for (int i = 0; i < vertexAttrSizes.length; i++) { + if (vertexAttrSizes[i] < 1 || vertexAttrSizes[i] > 4) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray133")); + } + } + } else { + if (vertexAttrSizes != null && vertexAttrSizes.length != 0) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray132")); + } + } + } else { + if (vertexAttrCount > 0) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray131")); + } + } + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((GeometryArrayRetained)this.retained).createGeometryArrayData( + vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + + } + + + //------------------------------------------------------------------ + // Common methods + //------------------------------------------------------------------ + + /** + * Retrieves the number of vertices in this GeometryArray + * @return number of vertices in this GeometryArray + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + */ + public int getVertexCount() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray1")); + + return ((GeometryArrayRetained)this.retained).getVertexCount(); + } + + /** + * Retrieves the vertexFormat of this GeometryArray + * @return format of vertices in this GeometryArray + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + */ + public int getVertexFormat() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_FORMAT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray2")); + + return ((GeometryArrayRetained)this.retained).getVertexFormat(); + } + + + /** + * Retrieves the number of texture coordinate sets in this + * GeometryArray object. + * + * @return the number of texture coordinate sets + * in this GeometryArray object + * + * @since Java 3D 1.2 + */ + public int getTexCoordSetCount() { + return ((GeometryArrayRetained)this.retained).getTexCoordSetCount(); + } + + + /** + * Retrieves the length of the texture coordinate set mapping + * array of this GeometryArray object. + * + * @return the length of the texture coordinate set mapping + * array of this GeometryArray object + * + * @since Java 3D 1.2 + */ + public int getTexCoordSetMapLength() { + return ((GeometryArrayRetained)this.retained).getTexCoordSetMapLength(); + } + + + /** + * Retrieves the texture coordinate set mapping + * array from this GeometryArray object. + * + * @param texCoordSetMap an array that will receive a copy of the + * texture coordinate set mapping array. The array must be large + * enough to hold all entries of the texture coordinate set + * mapping array. + * + * @since Java 3D 1.2 + */ + public void getTexCoordSetMap(int[] texCoordSetMap) { + ((GeometryArrayRetained)this.retained).getTexCoordSetMap(texCoordSetMap); + } + + + /** + * Retrieves the number of vertex attributes in this GeometryArray + * object. + * + * @return the number of vertex attributes in this GeometryArray + * object + * + * @since Java 3D 1.4 + */ + public int getVertexAttrCount() { + return ((GeometryArrayRetained)this.retained).getVertexAttrCount(); + } + + + /** + * Retrieves the vertex attribute sizes array from this + * GeometryArray object. + * + * @param vertexAttrSizes an array that will receive a copy of + * the vertex attribute sizes array. The array must hold at least + * vertexAttrCount elements. + * + * @since Java 3D 1.4 + */ + public void getVertexAttrSizes(int[] vertexAttrSizes) { + ((GeometryArrayRetained)this.retained).getVertexAttrSizes(vertexAttrSizes); + } + + + /** + * Updates geometry array data that is accessed by reference. + * This method calls the updateData method of the specified + * GeometryUpdater object to synchronize updates to vertex + * data that is referenced by this GeometryArray object. + * Applications that wish to modify such data must perform all + * updates via this method. + *

+ * This method may also be used to atomically set multiple + * references (for example, to coordinate and color arrays) + * or to atomically + * change multiple data values through the geometry data copying + * methods. + * + * @param updater object whose updateData callback method will be + * called to update the data referenced by this GeometryArray. + * @exception CapabilityNotSetException if the appropriate capability + * is not set, the vertex data mode is BY_REFERENCE, and this + * object is part of a live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public void updateData(GeometryUpdater updater) { + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0 && + isLiveOrCompiled() && + !this.getCapability(ALLOW_REF_DATA_WRITE)) { + + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray81")); + } + + ((GeometryArrayRetained)this.retained).updateData(updater); + } + + + /** + * Sets the valid vertex count for this GeometryArray object. + * This count specifies the number of vertices actually used in + * rendering or other operations such as picking and collision. + * This attribute is initialized to vertexCount. + * + * @param validVertexCount the new valid vertex count. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + *

+ * @exception IllegalArgumentException if any of the following are + * true: + *

    + * validVertexCount < 0,
    + * initialVertexIndex + validVertexCount > vertexCount,
    + * initialCoordIndex + validVertexCount > vertexCount,
    + * initialColorIndex + validVertexCount > vertexCount,
    + * initialNormalIndex + validVertexCount > vertexCount,
    + * initialTexCoordIndex + validVertexCount > vertexCount,
    + * initialVertexAttrIndex + validVertexCount > vertexCount + *
+ *

+ * @exception ArrayIndexOutOfBoundsException if the geometry data format + * is BY_REFERENCE and any the following + * are true for non-null array references: + *

    + * CoordRef.length < num_words * + * (initialCoordIndex + validVertexCount),
    + * ColorRef.length < num_words * + * (initialColorIndex + validVertexCount),
    + * NormalRef.length < num_words * + * (initialNormalIndex + validVertexCount),
    + * TexCoordRef.length < num_words * + * (initialTexCoordIndex + validVertexCount),
    + * VertexAttrRef.length < num_words * + * (initialVertexAttrIndex + validVertexCount),
    + * InterleavedVertices.length < words_per_vertex * + * (initialVertexIndex + validVertexCount)
    + *
+ * where num_words depends on which variant of + * setArrayRef is used, and + * words_per_vertex depends on which vertex formats are enabled + * for interleaved arrays. + * + * @since Java 3D 1.2 + */ + public void setValidVertexCount(int validVertexCount) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray88")); + + if (validVertexCount < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray96")); + + ((GeometryArrayRetained)this.retained).setValidVertexCount(validVertexCount); + // NOTE: the checks for initial*Index + validVertexCount > + // vertexCount need to be done in the retained method + } + + + /** + * Gets the valid vertex count for this GeometryArray object. + * For geometry strip primitives (subclasses of GeometryStripArray), + * the valid vertex count is defined to be the sum of the + * stripVertexCounts array. + * @return the current valid vertex count + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getValidVertexCount() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray89")); + + return ((GeometryArrayRetained)this.retained).getValidVertexCount(); + } + + + /** + * Copies all node information from originalNodeComponent + * into the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + // vertexFormat and vertexCount are copied in subclass when constructor + // public GeometryArray(int vertexCount, int vertexFormat) is used + // in cloneNodeComponent() + GeometryArrayRetained src = (GeometryArrayRetained) originalNodeComponent.retained; + GeometryArrayRetained dst = (GeometryArrayRetained) retained; + int format = src.getVertexFormat(); + if ((format & BY_REFERENCE) == 0) { + System.arraycopy(src.vertexData, 0, dst.vertexData, 0, + src.vertexData.length); + dst.setInitialVertexIndex(src.getInitialVertexIndex()); + + } else { + dst.setInitialCoordIndex(src.getInitialCoordIndex()); + dst.setInitialColorIndex(src.getInitialColorIndex()); + dst.setInitialNormalIndex(src.getInitialNormalIndex()); + int setCount = src.getTexCoordSetCount(); + int vAttrCount = src.getVertexAttrCount(); + for (int i=0; i < setCount; i++) { + dst.setInitialTexCoordIndex(i, src.getInitialTexCoordIndex(i)); + } + if ((format & INTERLEAVED) == 0) { + if ((format & USE_NIO_BUFFER) == 0) { + // Java arrays + dst.setCoordRefFloat(src.getCoordRefFloat()); + dst.setCoordRefDouble(src.getCoordRefDouble()); + dst.setCoordRef3f(src.getCoordRef3f()); + dst.setCoordRef3d(src.getCoordRef3d()); + dst.setColorRefFloat(src.getColorRefFloat()); + dst.setColorRefByte(src.getColorRefByte()); + if ((format & WITH_ALPHA) == 0) { + dst.setColorRef3f(src.getColorRef3f()); + dst.setColorRef3b(src.getColorRef3b()); + } else { + dst.setColorRef4f(src.getColorRef4f()); + dst.setColorRef4b(src.getColorRef4b()); + } + dst.setNormalRefFloat(src.getNormalRefFloat()); + dst.setNormalRef3f(src.getNormalRef3f()); + + switch (src.getVertexAttrType()) { + case GeometryArrayRetained.AF: + for (int i=0; i < vAttrCount; i++) { + dst.setVertexAttrRefFloat(i, src.getVertexAttrRefFloat(i)); + } + break; + } + + switch (src.getTexCoordType()) { + case GeometryArrayRetained.TF: + for (int i=0; i < setCount; i++) { + dst.setTexCoordRefFloat(i, src.getTexCoordRefFloat(i)); + } + break; + case GeometryArrayRetained.T2F: + for (int i=0; i < setCount; i++) { + dst.setTexCoordRef2f(i, src.getTexCoordRef2f(i)); + } + break; + case GeometryArrayRetained.T3F: + for (int i=0; i < setCount; i++) { + dst.setTexCoordRef3f(i, src.getTexCoordRef3f(i)); + } + break; + } + } else { + // NIO buffer + dst.setCoordRefBuffer(src.getCoordRefBuffer()); + dst.setColorRefBuffer(src.getColorRefBuffer()); + dst.setNormalRefBuffer(src.getNormalRefBuffer()); + + switch (src.getVertexAttrType()) { + case GeometryArrayRetained.AF: + for (int i=0; i < vAttrCount; i++) { + dst.setVertexAttrRefBuffer(i, src.getVertexAttrRefBuffer(i)); + } + break; + } + + switch (src.getTexCoordType()) { + case GeometryArrayRetained.TF: + for (int i=0; i < setCount; i++) { + dst.setTexCoordRefBuffer(i, src.getTexCoordRefBuffer(i)); + } + break; + } + } + } else { + dst.setInterleavedVertices(src.getInterleavedVertices()); + } + } + } + + + //------------------------------------------------------------------ + // By-copying methods + //------------------------------------------------------------------ + + /** + * Sets the initial vertex index for this GeometryArray object. + * This index specifies the first vertex within this geometry + * array that is actually used in rendering or other operations + * such as picking and collision. This attribute is initialized + * to 0. + * This attribute is only used when the data mode for this + * geometry array object is not BY_REFERENCE + * or when the data mode is INTERLEAVED. + * + * @param initialVertexIndex the new initial vertex index. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalArgumentException if either of the following are + * true: + *
    + * initialVertexIndex < 0 or
    + * initialVertexIndex + validVertexCount > vertexCount
    + *
+ * + * @exception ArrayIndexOutOfBoundsException if the geometry data format + * is INTERLEAVED, the InterleavedVertices array is + * non-null, and: + *
    + * InterleavedVertices.length < num_words * + * (initialVertexIndex + validVertexCount)
    + *
+ * where num_words depends on which vertex formats are enabled. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE and is not + * INTERLEAVED. + * + * @since Java 3D 1.2 + */ + public void setInitialVertexIndex(int initialVertexIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray90")); + + if (initialVertexIndex < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray97")); + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0 && (format & INTERLEAVED) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray105")); + + ((GeometryArrayRetained)this.retained).setInitialVertexIndex(initialVertexIndex); + // NOTE: the check for initialVertexIndex + validVertexCount > + // vertexCount is done in the retained method + } + + + /** + * Gets the initial vertex index for this GeometryArray object. + * This attribute is only used when the data mode for this + * geometry array object is not BY_REFERENCE + * or when the data mode is INTERLEAVED. + * @return the current initial vertex index for this GeometryArray object. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getInitialVertexIndex() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray91")); + + return ((GeometryArrayRetained)this.retained).getInitialVertexIndex(); + } + + + /** + * Sets the coordinate associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param coordinate source array of 3 values containing the new coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinate(int index, float coordinate[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray3")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinate(index, coordinate); + } + + /** + * Sets the coordinate associated with the vertex at + * the specified index. + * @param index destination vertex index in this geometry array + * @param coordinate source array of 3 values containing the new coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinate(int index, double coordinate[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray3")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinate(index, coordinate); + } + + /** + * Sets the coordinate associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param coordinate a point containing the new coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinate(int index, Point3f coordinate) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray3")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinate(index, coordinate); + } + + /** + * Sets the coordinate associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param coordinate a point containing the new coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinate(int index, Point3d coordinate) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray3")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinate(index, coordinate); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param coordinates source array of 3*n values containing n new coordinates + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinates(int index, float coordinates[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray7")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinates(index, coordinates); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param coordinates source array of 3*n values containing n new coordinates + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinates(int index, double coordinates[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray7")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinates(index, coordinates); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param coordinates source array of points containing new coordinates + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinates(int index, Point3f coordinates[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray7")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinates(index, coordinates); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param coordinates source array of points containing new coordinates + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinates(int index, Point3d coordinates[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray7")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinates(index, coordinates); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object using coordinate data starting + * from vertex index start for length vertices. + * @param index starting destination vertex index in this geometry array + * @param coordinates source array of 3*n values containing n new coordinates + * @param start starting source vertex index in coordinates array. + * @param length number of vertices to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinates(int index, float coordinates[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray7")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinates(index, coordinates, + start, length); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object using coordinate data starting + * from vertex index start for length vertices. + * @param index starting destination vertex index in this geometry array + * @param coordinates source array of 3*n values containing n new coordinates + * @param start starting source vertex index in coordinates array. + * @param length number of vertices to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinates(int index, double coordinates[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray7")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinates(index, coordinates, + start, length); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object using coordinate data starting + * from vertex index start for length vertices. + * @param index starting destination vertex index in this geometry array + * @param coordinates source array of points containing new coordinates + * @param start starting source vertex index in coordinates array. + * @param length number of vertices to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinates(int index, Point3f coordinates[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray7")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinates(index, coordinates, + start, length); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object using coordinate data starting + * from vertex index start for length vertices. + * @param index starting destination vertex index in this geometry array + * @param coordinates source array of points containing new coordinates + * @param start starting source vertex index in coordinates array. + * @param length number of vertices to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setCoordinates(int index, Point3d coordinates[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray7")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).setCoordinates(index, coordinates, + start, length); + } + + /** + * Sets the color associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param color source array of 3 or 4 values containing the new color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setColor(int index, float color[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray15")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).setColor(index, color); + } + + /** + * Sets the color associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param color source array of 3 or 4 values containing the new color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setColor(int index, byte color[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray15")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).setColor(index, color); + } + + /** + * Sets the color associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param color a Color3f containing the new color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in the vertex + * format + */ + public void setColor(int index, Color3f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray15")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).setColor(index, color); + } + + /** + * Sets the color associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param color a Color4f containing the new color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in the vertex + * format + */ + public void setColor(int index, Color4f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray15")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).setColor(index, color); + } + + /** + * Sets the color associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param color a Color3b containing the new color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in the vertex + * format + */ + public void setColor(int index, Color3b color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray15")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).setColor(index, color); + } + + /** + * Sets the color associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param color a Color4b containing the new color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in the vertex + * format + */ + public void setColor(int index, Color4b color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray15")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).setColor(index, color); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param colors source array of 3*n or 4*n values containing n new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setColors(int index, float colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param colors source array of 3*n or 4*n values containing n new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setColors(int index, byte colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param colors source array of Color3f objects containing new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in vertex format + */ + public void setColors(int index, Color3f colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param colors source array of Color4f objects containing new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in vertex format + */ + public void setColors(int index, Color4f colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param colors source array of Color3b objects containing new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in vertex format + */ + public void setColors(int index, Color3b colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param colors source array of Color4b objects containing new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in vertex format + */ + public void setColors(int index, Color4b colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index starting destination vertex index in this geometry array + * @param colors source array of 3*n or 4*n values containing n new colors + * @param start starting source vertex index in colors array. + * @param length number of colors to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setColors(int index, float colors[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors, start, + length); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index starting destination vertex index in this geometry array + * @param colors source array of 3*n or 4*n values containing n new colors + * @param start starting source vertex index in colors array. + * @param length number of colors to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setColors(int index, byte colors[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors, start, + length); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index starting destination vertex index in this geometry array + * @param colors source array of Color3f objects containing new colors + * @param start starting source vertex index in colors array. + * @param length number of colors to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in vertex format + */ + public void setColors(int index, Color3f colors[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors, start, + length); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index starting destination vertex index in this geometry array + * @param colors source array of Color4f objects containing new colors + * @param start starting source vertex index in colors array. + * @param length number of colors to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in vertex format + */ + public void setColors(int index, Color4f colors[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors, start, + length); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index starting destination vertex index in this geometry array + * @param colors source array of Color3b objects containing new colors + * @param start starting source vertex index in colors array. + * @param length number of colors to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in vertex format + */ + public void setColors(int index, Color3b colors[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors, start, + length); + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index starting destination vertex index in this geometry array + * @param colors source array of Color4b objects containing new colors + * @param start starting source vertex index in colors array. + * @param length number of colors to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if COLOR bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in vertex format + */ + public void setColors(int index, Color4b colors[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray21")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).setColors(index, colors, start, + length); + } + + /** + * Sets the normal associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param normal source array of 3 values containing the new normal + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if NORMALS bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setNormal(int index, float normal[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray33")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).setNormal(index, normal); + } + + /** + * Sets the normal associated with the vertex at + * the specified index for this object. + * @param index destination vertex index in this geometry array + * @param normal the vector containing the new normal + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if NORMALS bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setNormal(int index, Vector3f normal) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray33")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).setNormal(index, normal); + } + + /** + * Sets the normals associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param normals source array of 3*n values containing n new normals + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if NORMALS bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setNormals(int index, float normals[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray35")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).setNormals(index, normals); + } + + /** + * Sets the normals associated with the vertices starting at + * the specified index for this object. The entire source array is + * copied to this geometry array. + * @param index starting destination vertex index in this geometry array + * @param normals source array of vectors containing new normals + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if NORMALS bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setNormals(int index, Vector3f normals[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray35")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).setNormals(index, normals); + } + + /** + * Sets the normals associated with the vertices starting at + * the specified index for this object using data in normals + * starting at index start and ending at index start+length. + * @param index starting destination vertex index in this geometry array + * @param normals source array of 3*n values containing n new normals + * @param start starting source vertex index in normals array. + * @param length number of normals to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if NORMALS bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setNormals(int index, float normals[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray35")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).setNormals(index, normals, start, length); + } + + /** + * Sets the normals associated with the vertices starting at + * the specified index for this object using data in normals + * starting at index start and ending at index start+length. + * @param index starting destination vertex index in this geometry array + * @param normals source array of vectors containing new normals + * @param start starting source vertex index in normals array. + * @param length number of normals to be copied. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception ArrayIndexOutOfBoundsException if NORMALS bit NOT set in + * constructor vertexFormat or array index for element is out of bounds. + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void setNormals(int index, Vector3f normals[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray35")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).setNormals(index, normals, start, length); + } + + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinate(int texCoordSet, ...) + */ + public void setTextureCoordinate(int index, float texCoord[]) { + setTextureCoordinate(0, index, texCoord); + } + + /** + * Sets the texture coordinate associated with the vertex at the + * specified index in the specified texture coordinate set for + * this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index destination vertex index in this geometry array + * @param texCoord source array of 2, 3 or 4 values containing the new + * texture coordinate + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinate(int texCoordSet, + int index, float texCoord[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray39")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoord, 0, 1); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinate(int texCoordSet, TexCoord2f texCoord) + */ + public void setTextureCoordinate(int index, Point2f texCoord) { + texCoord2fScratch.set(texCoord); + setTextureCoordinate(0, index, texCoord2fScratch); + } + + /** + * Sets the texture coordinate associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index destination vertex index in this geometry array + * @param texCoord the TexCoord2f containing the new texture coordinate + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_3 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinate(int texCoordSet, + int index, TexCoord2f texCoord) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray39")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_3 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray94")); + + texCoord2fArray[0] = texCoord; + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoord2fArray, 0, 1); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinate(int texCoordSet, TexCoord3f texCoord) + */ + public void setTextureCoordinate(int index, Point3f texCoord) { + texCoord3fScratch.set(texCoord); + setTextureCoordinate(0, index, texCoord3fScratch); + } + + /** + * Sets the texture coordinate associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index destination vertex index in this geometry array + * @param texCoord the TexCoord3f containing the new texture coordinate + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinate(int texCoordSet, + int index, TexCoord3f texCoord) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray39")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray95")); + + texCoord3fArray[0] = texCoord; + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoord3fArray, 0, 1); + } + + /** + * Sets the texture coordinate associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index destination vertex index in this geometry array + * @param texCoord the TexCoord4f containing the new texture coordinate + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3 is specified in vertex format + * + * @since Java 3D 1.3 + */ + public void setTextureCoordinate(int texCoordSet, + int index, TexCoord4f texCoord) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray39")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_3)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray109")); + + texCoord4fArray[0] = texCoord; + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoord4fArray, 0, 1); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinates(int texCoordSet, ...) + */ + public void setTextureCoordinates(int index, float texCoords[]) { + setTextureCoordinates(0, index, texCoords); + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index in the specified texture coordinate set + * for this object. The entire source array is + * copied to this geometry array. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting destination vertex index in this geometry array + * @param texCoords source array of 2*n, 3*n or 4*n values containing n new + * texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinates(int texCoordSet, + int index, float texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & GeometryArray.TEXTURE_COORDINATE_2) != 0) + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, 0, texCoords.length / 2); + else if ((format & GeometryArray.TEXTURE_COORDINATE_3) != 0) + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, 0, texCoords.length / 3); + else + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, 0, texCoords.length / 4); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinates(int texCoordSet, TexCoord2f texCoords[]) + */ + public void setTextureCoordinates(int index, Point2f texCoords[]) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + 0, index, texCoords, 0, texCoords.length); + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index in the specified texture coordinate set + * for this object. The entire source array is + * copied to this geometry array. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting destination vertex index in this geometry array + * @param texCoords source array of TexCoord2f objects containing new + * texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_3 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinates(int texCoordSet, + int index, TexCoord2f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_3 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray94")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, 0, texCoords.length); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinates(int texCoordSet, TexCoord3f texCoords[]) + */ + public void setTextureCoordinates(int index, Point3f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + 0, index, texCoords, 0, texCoords.length); + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index in the specified texture coordinate set + * for this object. The entire source array is + * copied to this geometry array. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting destination vertex index in this geometry array + * @param texCoords source array of TexCoord3f objects containing new + * texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinates(int texCoordSet, + int index, TexCoord3f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray95")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, 0, texCoords.length); + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index in the specified texture coordinate set + * for this object. The entire source array is + * copied to this geometry array. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting destination vertex index in this geometry array + * @param texCoords source array of TexCoord4f objects containing new + * texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3 is specified in vertex format + * + * @since Java 3D 1.3 + */ + public void setTextureCoordinates(int texCoordSet, + int index, TexCoord4f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_3)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray109")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, 0, texCoords.length); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinates(int texCoordSet, ...) + */ + public void setTextureCoordinates(int index, float texCoords[], + int start, int length) { + setTextureCoordinates(0, index, texCoords, start, length); + } + + /** + * Sets the texture coordinates associated with the vertices + * starting at the specified index in the specified texture + * coordinate set for this object using data in + * texCoords starting at index start and + * ending at index start+length. + * + * @param index starting destination vertex index in this geometry array + * @param texCoords source array of 2*n , 3*n or 4*n values containing + * n new texture coordinates + * @param start starting source vertex index in texCoords + * array. + * @param length number of texture Coordinates to be copied. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinates(int texCoordSet, + int index, float texCoords[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, start, length); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinates(int texCoordSet, TexCoord2f texCoords[], ...) + */ + public void setTextureCoordinates(int index, Point2f texCoords[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + 0, index, texCoords, start, length); + } + + /** + * Sets the texture coordinates associated with the vertices + * starting at the specified index in the specified texture + * coordinate set for this object using data in + * texCoords starting at index start and + * ending at index start+length. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting destination vertex index in this geometry array + * @param texCoords source array of TexCoord2f objects containing new + * texture coordinates + * @param start starting source vertex index in texCoords + * array. + * @param length number of texture Coordinates to be copied. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_3 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinates(int texCoordSet, + int index, TexCoord2f texCoords[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_3 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray94")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, start, length); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinates(int texCoordSet, TexCoord3f texCoords[], ...) + */ + public void setTextureCoordinates(int index, Point3f texCoords[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + 0, index, texCoords, start, length); + } + + /** + * Sets the texture coordinates associated with the vertices + * starting at the specified index in the specified texture + * coordinate set for this object. starting at index + * start and ending at index start+length. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting destination vertex index in this geometry array + * @param texCoords source array of TexCoord3f objects containing new + * texture coordinates + * @param start starting source vertex index in texCoords + * array. + * @param length number of texture Coordinates to be copied. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinates(int texCoordSet, + int index, TexCoord3f texCoords[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray95")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, start, length); + } + + /** + * Sets the texture coordinates associated with the vertices + * starting at the specified index in the specified texture + * coordinate set for this object. starting at index + * start and ending at index start+length. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting destination vertex index in this geometry array + * @param texCoords source array of TexCoord4f objects containing new + * texture coordinates + * @param start starting source vertex index in texCoords + * array. + * @param length number of texture Coordinates to be copied. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3 is specified in vertex format + * + * @since Java 3D 1.3 + */ + public void setTextureCoordinates(int texCoordSet, + int index, TexCoord4f texCoords[], + int start, int length) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray42")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_3)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray109")); + + ((GeometryArrayRetained)this.retained).setTextureCoordinates( + texCoordSet, index, texCoords, start, length); + } + + + /** + * Sets the vertex attribute associated with the vertex at the + * specified index in the specified vertex attribute number for + * this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index destination vertex index in this geometry array + * @param vertexAttr source array of 1, 2, 3 or 4 values containing + * the new vertex attribute + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range, or if the vertexAttr array is + * too small. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.4 + */ + public void setVertexAttr(int vertexAttrNum, int index, + float[] vertexAttr) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttr, 0, 1); + } + + /** + * Sets the vertex attribute associated with the vertex at the + * specified index in the specified vertex attribute number for + * this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index destination vertex index in this geometry array + * @param vertexAttr the Point2f containing the new vertex attribute + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 2. + * + * @since Java 3D 1.4 + */ + public void setVertexAttr(int vertexAttrNum, int index, + Point2f vertexAttr) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 2) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttr( + vertexAttrNum, index, vertexAttr); + } + + /** + * Sets the vertex attribute associated with the vertex at the + * specified index in the specified vertex attribute number for + * this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index destination vertex index in this geometry array + * @param vertexAttr the Point3f containing the new vertex attribute + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 3. + * + * @since Java 3D 1.4 + */ + public void setVertexAttr(int vertexAttrNum, int index, + Point3f vertexAttr) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 3) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttr( + vertexAttrNum, index, vertexAttr); + } + + /** + * Sets the vertex attribute associated with the vertex at the + * specified index in the specified vertex attribute number for + * this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index destination vertex index in this geometry array + * @param vertexAttr the Point4f containing the new vertex attribute + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 4. + * + * @since Java 3D 1.4 + */ + public void setVertexAttr(int vertexAttrNum, int index, + Point4f vertexAttr) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 4) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttr( + vertexAttrNum, index, vertexAttr); + } + + /** + * Sets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. The entire source array is copied to this + * geometry array. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of 1*n, 2*n, 3*n, or 4*n values + * containing n new vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range, or if the vertexAttr array is + * too large. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrs(int vertexAttrNum, int index, + float[] vertexAttrs) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttrs, 0, vertexAttrs.length / size); + } + + /** + * Sets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. The entire source array is copied to this + * geometry array. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point2f objects containing new + * vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range, or if the vertexAttr array is + * too large. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 2. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrs(int vertexAttrNum, int index, + Point2f[] vertexAttrs) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 2) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttrs, 0, vertexAttrs.length); + } + + /** + * Sets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. The entire source array is copied to this + * geometry array. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point3f objects containing new + * vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range, or if the vertexAttr array is + * too large. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 3. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrs(int vertexAttrNum, int index, + Point3f[] vertexAttrs) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 3) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttrs, 0, vertexAttrs.length); + } + + /** + * Sets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. The entire source array is copied to this + * geometry array. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point4f objects containing new + * vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range, or if the vertexAttr array is + * too large. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 4. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrs(int vertexAttrNum, int index, + Point4f[] vertexAttrs) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 4) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttrs, 0, vertexAttrs.length); + } + + /** + * Sets the vertex attributes associated with the vertices + * starting at the specified index in the specified vertex + * attribute number for this object using data in + * vertexAttrs starting at index start and + * ending at index start+length. + * + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of 1*n, 2*n, 3*n, or 4*n values + * containing n new vertex attributes + * @param start starting source vertex index in vertexAttrs + * array. + * @param length number of vertex attributes to be copied. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if any of index, + * (index+length), or vertexAttrNum are out of range, or if + * vertexAttrs is too small. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrs(int vertexAttrNum, int index, + float[] vertexAttrs, + int start, int length) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttrs, start, length); + } + + /** + * Sets the vertex attributes associated with the vertices + * starting at the specified index in the specified vertex + * attribute number for this object using data in + * vertexAttrs starting at index start and + * ending at index start+length. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point2f objects containing new + * vertex attributes + * @param start starting source vertex index in vertexAttrs + * array. + * @param length number of vertex attributes to be copied. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if any of index, + * (index+length), or vertexAttrNum are out of range, or if + * vertexAttrs is too small. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 2. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrs(int vertexAttrNum, int index, + Point2f[] vertexAttrs, + int start, int length) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 2) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttrs, start, length); + } + + /** + * Sets the vertex attributes associated with the vertices + * starting at the specified index in the specified vertex + * attribute number for this object using data in + * vertexAttrs starting at index start and + * ending at index start+length. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point3f objects containing new + * vertex attributes + * @param start starting source vertex index in vertexAttrs + * array. + * @param length number of vertex attributes to be copied. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if any of index, + * (index+length), or vertexAttrNum are out of range, or if + * vertexAttrs is too small. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 3. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrs(int vertexAttrNum, int index, + Point3f[] vertexAttrs, + int start, int length) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 3) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttrs, start, length); + } + + /** + * Sets the vertex attributes associated with the vertices + * starting at the specified index in the specified vertex + * attribute number for this object using data in + * vertexAttrs starting at index start and + * ending at index start+length. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point4f objects containing new + * vertex attributes + * @param start starting source vertex index in vertexAttrs + * array. + * @param length number of vertex attributes to be copied. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if any of index, + * (index+length), or vertexAttrNum are out of range, or if + * vertexAttrs is too small. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 4. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrs(int vertexAttrNum, int index, + Point4f[] vertexAttrs, + int start, int length) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray126")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 4) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrs( + vertexAttrNum, index, vertexAttrs, start, length); + } + + + /** + * Gets the coordinate associated with the vertex at + * the specified index for this object using data in texCoords + * @param index source vertex index in this geometry array + * @param coordinate destination array of 3 values that will receive the coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getCoordinate(int index, float coordinate[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray48")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).getCoordinate(index, coordinate); + } + + /** + * Gets the coordinate associated with the vertex at + * the specified index for this object. + * @param index source vertex index in this geometry array + * @param coordinate destination array of 3 values that will receive the coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getCoordinate(int index, double coordinate[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray48")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).getCoordinate(index, coordinate); + } + + /** + * Gets the coordinate associated with the vertex at + * the specified index for this object. + * @param index source vertex index in this geometry array + * @param coordinate a vector that will receive the coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getCoordinate(int index, Point3f coordinate) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray48")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).getCoordinate(index, coordinate); + } + + /** + * Gets the coordinate associated with the vertex at + * the specified index for this object. + * @param index source vertex index in this geometry array + * @param coordinate a vector that will receive the coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getCoordinate(int index, Point3d coordinate) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray48")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).getCoordinate(index, coordinate); + } + + /** + * Gets the coordinates associated with the vertices starting at + * the specified index for this object. The length of the destination + * array determines the number of vertices copied. + * A maximum of vertexCount-index coordinates + * are copied. If the destination array is larger than is needed + * to hold the coordinates, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the coordinates, only as + * many coordinates as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param coordinates destination array of 3*n values that will receive new coordinates + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getCoordinates(int index, float coordinates[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray52")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).getCoordinates(index, coordinates); + } + + /** + * Gets the coordinates associated with the vertices starting at + * the specified index for this object. The length of the destination + * array determines the number of vertices copied. + * A maximum of vertexCount-index coordinates + * are copied. If the destination array is larger than is needed + * to hold the coordinates, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the coordinates, only as + * many coordinates as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param coordinates destination array of 3*n values that will receive new coordinates + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getCoordinates(int index, double coordinates[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray52")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).getCoordinates(index, coordinates); + } + + /** + * Gets the coordinates associated with the vertices starting at + * the specified index for this object. The length of the destination + * array determines the number of vertices copied. + * A maximum of vertexCount-index coordinates + * are copied. If the destination array is larger than is needed + * to hold the coordinates, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the coordinates, only as + * many coordinates as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param coordinates destination array of points that will receive new coordinates + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getCoordinates(int index, Point3f coordinates[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray52")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).getCoordinates(index, coordinates); + } + + /** + * Gets the coordinates associated with the vertices starting at + * the specified index for this object. The length of the destination + * array determines the number of vertices copied. + * A maximum of vertexCount-index coordinates + * are copied. If the destination array is larger than is needed + * to hold the coordinates, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the coordinates, only as + * many coordinates as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param coordinates destination array of points that will receive new coordinates + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getCoordinates(int index, Point3d coordinates[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray52")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + ((GeometryArrayRetained)this.retained).getCoordinates(index, coordinates); + } + + /** + * Gets the color associated with the vertex at + * the specified index for this object. The color is copied into the + * specified array. The array must be large enough to hold all + * of the colors. + * @param index source vertex index in this geometry array + * @param color destination array of 3 or 4 values that will receive the color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getColor(int index, float color[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray56")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).getColor(index, color); + } + + /** + * Gets the color associated with the vertex at + * the specified index for this object. The color is copied into the + * specified array. The array must be large enough to hold all of + * the colors. + * @param index source vertex index in this geometry array + * @param color destination array of 3 or 4 values that will receive the color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getColor(int index, byte color[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray56")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).getColor(index, color); + } + + /** + * Gets the color associated with the vertex at + * the specified index for this object. + * @param index source vertex index in this geometry array + * @param color a vector that will receive the color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in the vertex + * format + */ + public void getColor(int index, Color3f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray56")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).getColor(index, color); + } + + /** + * Gets the color associated with the vertex at + * the specified index for this object. + * @param index source vertex index in this geometry array + * @param color a vector that will receive the color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in the vertex + * format + */ + public void getColor(int index, Color4f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray56")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).getColor(index, color); + } + + /** + * Gets the color associated with the vertex at + * the specified index for this object. + * @param index source vertex index in this geometry array + * @param color a vector that will receive the color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in the vertex + * format + */ + public void getColor(int index, Color3b color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray56")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).getColor(index, color); + } + + /** + * Gets the color associated with the vertex at + * the specified index for this object. + * @param index source vertex index in this geometry array + * @param color a vector that will receive the color + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in the vertex + * format + */ + public void getColor(int index, Color4b color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray56")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).getColor(index, color); + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index for this object. The color is copied into the + * specified array. The length of the destination + * array determines the number of colors copied. + * A maximum of vertexCount-index colors + * are copied. If the destination array is larger than is needed + * to hold the colors, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the colors, only as + * many colors as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param colors destination array of 3*n or 4*n values that will + * receive n new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getColors(int index, float colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray62")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).getColors(index, colors); + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index for this object. The color is copied into the + * specified array. The length of the destination + * array determines the number of colors copied. + * A maximum of vertexCount-index colors + * are copied. If the destination array is larger than is needed + * to hold the colors, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the colors, only as + * many colors as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param colors destination array of 3*n or 4*n values that will + * receive new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getColors(int index, byte colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray62")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + ((GeometryArrayRetained)this.retained).getColors(index, colors); + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index for this object. The color is copied into the + * specified array. The length of the destination + * array determines the number of colors copied. + * A maximum of vertexCount-index colors + * are copied. If the destination array is larger than is needed + * to hold the colors, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the colors, only as + * many colors as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param colors destination array of Color3f objects that will receive new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in the vertex + * format + */ + public void getColors(int index, Color3f colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray62")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).getColors(index, colors); + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index for this object. The color is copied into the + * specified array. The length of the destination + * array determines the number of colors copied. + * A maximum of vertexCount-index colors + * are copied. If the destination array is larger than is needed + * to hold the colors, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the colors, only as + * many colors as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param colors destination array of Color4f objects that will receive new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in the vertex + * format + */ + public void getColors(int index, Color4f colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray62")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).getColors(index, colors); + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index for this object. The color is copied into the + * specified array. The length of the destination + * array determines the number of colors copied. + * A maximum of vertexCount-index colors + * are copied. If the destination array is larger than is needed + * to hold the colors, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the colors, only as + * many colors as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param colors destination array of Color3b objects that will receive new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_4 is specified in the vertex + * format + */ + public void getColors(int index, Color3b colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray62")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).getColors(index, colors); + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index for this object. The color is copied into the + * specified array. The length of the destination + * array determines the number of colors copied. + * A maximum of vertexCount-index colors + * are copied. If the destination array is larger than is needed + * to hold the colors, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the colors, only as + * many colors as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param colors destination array of Color4b objects that will receive new colors + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * @exception IllegalStateException if COLOR_3 is specified in the vertex + * format + */ + public void getColors(int index, Color4b colors[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray62")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & COLOR ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray76")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).getColors(index, colors); + } + + /** + * Gets the normal associated with the vertex at + * the specified index for this object. The normal is copied into + * the specified array. + * @param index source vertex index in this geometry array + * @param normal destination array of 3 values that will receive the normal + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getNormal(int index, float normal[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray68")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).getNormal(index, normal); + } + + /** + * Gets the normal associated with the vertex at + * the specified index for this object. + * @param index source vertex index in this geometry array + * @param normal the vector that will receive the normal + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getNormal(int index, Vector3f normal) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray68")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).getNormal(index, normal); + } + + /** + * Gets the normals associated with the vertices starting at + * the specified index for this object. The length of the destination + * array determines the number of normals copied. + * A maximum of vertexCount-index normals + * are copied. If the destination array is larger than is needed + * to hold the normals, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the normals, only as + * many normals as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param normals destination array of 3*n values that will receive the normal + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getNormals(int index, float normals[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray70")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).getNormals(index, normals); + } + + /** + * Gets the normals associated with the vertices starting at + * the specified index for this object. The length of the destination + * array determines the number of normals copied. + * A maximum of vertexCount-index normals + * are copied. If the destination array is larger than is needed + * to hold the normals, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the normals, only as + * many normals as the array will hold are copied. + * + * @param index starting source vertex index in this geometry array + * @param normals destination array of vectors that will receive the normals + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + */ + public void getNormals(int index, Vector3f normals[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray70")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & NORMALS ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray77")); + + ((GeometryArrayRetained)this.retained).getNormals(index, normals); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getTextureCoordinate(int texCoordSet, ...) + */ + public void getTextureCoordinate(int index, float texCoord[]) { + getTextureCoordinate(0, index, texCoord); + } + + /** + * Gets the texture coordinate associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index source vertex index in this geometry array + * @param texCoord array of 2, 3 or 4 values that will receive the + * texture coordinate + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.2 + */ + public void getTextureCoordinate(int texCoordSet, + int index, float texCoord[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray72")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + ((GeometryArrayRetained)this.retained).getTextureCoordinate( + texCoordSet, index, texCoord); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getTextureCoordinate(int texCoordSet, TexCoord2f texCoord) + */ + public void getTextureCoordinate(int index, Point2f texCoord) { + getTextureCoordinate(0, index, texCoord2fArray[0]); + texCoord.set(texCoord2fArray[0]); + } + + /** + * Gets the texture coordinate associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index source vertex index in this geometry array + * @param texCoord the vector that will receive the texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_3 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void getTextureCoordinate(int texCoordSet, + int index, TexCoord2f texCoord) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray72")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_3 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray94")); + + ((GeometryArrayRetained)this.retained).getTextureCoordinate( + texCoordSet, index, texCoord); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getTextureCoordinate(int texCoordSet, TexCoord3f texCoord) + */ + public void getTextureCoordinate(int index, Point3f texCoord) { + getTextureCoordinate(0, index, texCoord3fArray[0]); + texCoord.set(texCoord3fArray[0]); + } + + /** + * Gets the texture coordinate associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index source vertex index in this geometry array + * @param texCoord the vector that will receive the texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void getTextureCoordinate(int texCoordSet, + int index, TexCoord3f texCoord) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray72")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray95")); + ((GeometryArrayRetained)this.retained).getTextureCoordinate( + texCoordSet, index, texCoord); + } + + /** + * Gets the texture coordinate associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index source vertex index in this geometry array + * @param texCoord the vector that will receive the texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3 is specified in vertex format + * + * @since Java 3D 1.3 + */ + public void getTextureCoordinate(int texCoordSet, + int index, TexCoord4f texCoord) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray72")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_3)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray109")); + ((GeometryArrayRetained)this.retained).getTextureCoordinate( + texCoordSet, index, texCoord); + } + + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getTextureCoordinates(int texCoordSet, ...) + */ + public void getTextureCoordinates(int index, float texCoords[]) { + getTextureCoordinates(0, index, texCoords); + } + + /** + * Gets the texture coordinates associated with the vertices starting at + * the specified index in the specified texture coordinate set + * for this object. The length of the destination + * array determines the number of texture coordinates copied. + * A maximum of vertexCount-index texture coordinates + * are copied. If the destination array is larger than is needed + * to hold the texture coordinates, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the texture coordinates, only as + * many texture coordinates as the array will hold are copied. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting source vertex index in this geometry array + * @param texCoords destination array of 2*n , 3*n or 4*n values that + * will receive n new texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.2 + */ + public void getTextureCoordinates(int texCoordSet, + int index, float texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray75")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + ((GeometryArrayRetained)this.retained).getTextureCoordinates( + texCoordSet, index, texCoords); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getTextureCoordinates(int texCoordSet, TexCoord2f texCoords[]) + */ + public void getTextureCoordinates(int index, Point2f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray75")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + ((GeometryArrayRetained)this.retained).getTextureCoordinates( + 0, index, texCoords); + } + + /** + * Gets the texture coordinates associated with the vertices starting at + * the specified index in the specified texture coordinate set + * for this object. The length of the destination + * array determines the number of texture coordinates copied. + * A maximum of vertexCount-index texture coordinates + * are copied. If the destination array is larger than is needed + * to hold the texture coordinates, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the texture coordinates, only as + * many texture coordinates as the array will hold are copied. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting source vertex index in this geometry array + * @param texCoords destination array of TexCoord2f objects that will + * receive the texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_3 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void getTextureCoordinates(int texCoordSet, + int index, TexCoord2f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray75")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_3 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray94")); + ((GeometryArrayRetained)this.retained).getTextureCoordinates( + texCoordSet, index, texCoords); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getTextureCoordinates(int texCoordSet, TexCoord3f texCoords[]) + */ + public void getTextureCoordinates(int index, Point3f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray75")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + ((GeometryArrayRetained)this.retained).getTextureCoordinates( + 0, index, texCoords); + } + + /** + * Gets the texture coordinates associated with the vertices starting at + * the specified index in the specified texture coordinate set + * for this object. The length of the destination + * array determines the number of texture coordinates copied. + * A maximum of vertexCount-index texture coordinates + * are copied. If the destination array is larger than is needed + * to hold the texture coordinates, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the texture coordinates, only as + * many texture coordinates as the array will hold are copied. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting source vertex index in this geometry array + * @param texCoords destination array of TexCoord3f objects that will + * receive the texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_4 is specified in vertex format + * + * @since Java 3D 1.2 + */ + public void getTextureCoordinates(int texCoordSet, + int index, TexCoord3f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray75")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray95")); + ((GeometryArrayRetained)this.retained).getTextureCoordinates( + texCoordSet, index, texCoords); + } + + + /** + * Gets the texture coordinates associated with the vertices starting at + * the specified index in the specified texture coordinate set + * for this object. The length of the destination + * array determines the number of texture coordinates copied. + * A maximum of vertexCount-index texture coordinates + * are copied. If the destination array is larger than is needed + * to hold the texture coordinates, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the texture coordinates, only as + * many texture coordinates as the array will hold are copied. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index starting source vertex index in this geometry array + * @param texCoords destination array of TexCoord4f objects that will + * receive the texture coordinates + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if TEXTURE_COORDINATE_2 or + * TEXTURE_COORDINATE_3 is specified in vertex format + * + * @since Java 3D 1.3 + */ + public void getTextureCoordinates(int texCoordSet, + int index, TexCoord4f texCoords[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray75")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((format & TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + if (((((GeometryArrayRetained)this.retained).vertexFormat) & + (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_3)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray109")); + + ((GeometryArrayRetained)this.retained).getTextureCoordinates( + texCoordSet, index, texCoords); + } + + /** + * Gets the vertex attribute associated with the vertex at + * the specified index in the specified vertex attribute number + * for this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index source vertex index in this geometry array + * @param vertexAttr array of 1, 2, 3 or 4 values that will receive the + * vertex attribute + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range, or if the vertexAttr array is + * too small. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.4 + */ + public void getVertexAttr(int vertexAttrNum, int index, + float[] vertexAttr) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray127")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + ((GeometryArrayRetained)this.retained).getVertexAttr( + vertexAttrNum, index, vertexAttr); + } + + /** + * Gets the vertex attribute associated with the vertex at + * the specified index in the specified vertex attribute number + * for this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index source vertex index in this geometry array + * @param vertexAttr the vector that will receive the vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 2. + * + * @since Java 3D 1.4 + */ + public void getVertexAttr(int vertexAttrNum, int index, + Point2f vertexAttr) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray127")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 2) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).getVertexAttr( + vertexAttrNum, index, vertexAttr); + } + + /** + * Gets the vertex attribute associated with the vertex at + * the specified index in the specified vertex attribute number + * for this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index source vertex index in this geometry array + * @param vertexAttr the vector that will receive the vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 3. + * + * @since Java 3D 1.4 + */ + public void getVertexAttr(int vertexAttrNum, int index, + Point3f vertexAttr) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray127")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 3) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).getVertexAttr( + vertexAttrNum, index, vertexAttr); + } + + /** + * Gets the vertex attribute associated with the vertex at + * the specified index in the specified vertex attribute number + * for this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index source vertex index in this geometry array + * @param vertexAttr the vector that will receive the vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 4. + * + * @since Java 3D 1.4 + */ + public void getVertexAttr(int vertexAttrNum, int index, + Point4f vertexAttr) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray127")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 4) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).getVertexAttr( + vertexAttrNum, index, vertexAttr); + } + + /** + * Gets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. The length of the destination + * array determines the number of vertex attributes copied. + * A maximum of vertexCount-index vertex attributes + * are copied. If the destination array is larger than is needed + * to hold the vertex attributes, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the vertex attributes, only as + * many vertex attributes as the array will hold are copied. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting source vertex index in this geometry array + * @param vertexAttrs destination array of 1*n, 2*n, 3*n, or 4*n values + * that will receive n new vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @since Java 3D 1.4 + */ + public void getVertexAttrs(int vertexAttrNum, int index, + float[] vertexAttrs) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray127")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + ((GeometryArrayRetained)this.retained).getVertexAttrs( + vertexAttrNum, index, vertexAttrs); + } + + /** + * Gets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. The length of the destination + * array determines the number of vertex attributes copied. + * A maximum of vertexCount-index vertex attributes + * are copied. If the destination array is larger than is needed + * to hold the vertex attributes, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the vertex attributes, only as + * many vertex attributes as the array will hold are copied. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting source vertex index in this geometry array + * @param vertexAttrs destination array of Point2f objects that will + * receive the vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 2. + * + * @since Java 3D 1.4 + */ + public void getVertexAttrs(int vertexAttrNum, int index, + Point2f[] vertexAttrs) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray127")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 2) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).getVertexAttrs( + vertexAttrNum, index, vertexAttrs); + } + + /** + * Gets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. The length of the destination + * array determines the number of vertex attributes copied. + * A maximum of vertexCount-index vertex attributes + * are copied. If the destination array is larger than is needed + * to hold the vertex attributes, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the vertex attributes, only as + * many vertex attributes as the array will hold are copied. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting source vertex index in this geometry array + * @param vertexAttrs destination array of Point3f objects that will + * receive the vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 3. + * + * @since Java 3D 1.4 + */ + public void getVertexAttrs(int vertexAttrNum, int index, + Point3f[] vertexAttrs) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray127")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 3) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).getVertexAttrs( + vertexAttrNum, index, vertexAttrs); + } + + /** + * Gets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. The length of the destination + * array determines the number of vertex attributes copied. + * A maximum of vertexCount-index vertex attributes + * are copied. If the destination array is larger than is needed + * to hold the vertex attributes, the excess locations in the + * array are not modified. If the destination array is smaller + * than is needed to hold the vertex attributes, only as + * many vertex attributes as the array will hold are copied. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting source vertex index in this geometry array + * @param vertexAttrs destination array of Point4f objects that will + * receive the vertex attributes + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE. + * + * @exception IllegalStateException if the size of the specified + * vertex attribute number is not 4. + * + * @since Java 3D 1.4 + */ + public void getVertexAttrs(int vertexAttrNum, int index, + Point4f[] vertexAttrs) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_VERTEX_ATTR_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray127")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + } + + int size = ((GeometryArrayRetained)this.retained).vertexAttrSizes[vertexAttrNum]; + if (size != 4) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray134")); + } + + ((GeometryArrayRetained)this.retained).getVertexAttrs( + vertexAttrNum, index, vertexAttrs); + } + + + //------------------------------------------------------------------ + // By-reference methods + //------------------------------------------------------------------ + + /** + * Sets the initial coordinate index for this GeometryArray object. + * This index specifies the first coordinate within the array of + * coordinates referenced by this geometry + * array that is actually used in rendering or other operations + * such as picking and collision. This attribute is initialized + * to 0. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * + * @param initialCoordIndex the new initial coordinate index. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + *

+ * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE or if the data mode + * is INTERLEAVED. + *

+ * @exception IllegalArgumentException if either of the following are + * true: + *

    + * initialCoordIndex < 0 or
    + * initialCoordIndex + validVertexCount > vertexCount
    + *
+ *

+ * @exception ArrayIndexOutOfBoundsException if + * the CoordRef array is non-null and: + *

    + * CoordRef.length < num_words * + * (initialCoordIndex + validVertexCount)
    + *
+ * where num_words depends on which variant of + * setCoordRef is used. + * + * @since Java 3D 1.2 + */ + public void setInitialCoordIndex(int initialCoordIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray90")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if (initialCoordIndex < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray97")); + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setInitialCoordIndex(initialCoordIndex); + // NOTE: the check for initialCoordIndex + validVertexCount > + // vertexCount needs to be done in the retained method + } + + + /** + * Gets the initial coordinate index for this GeometryArray object. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * @return the current initial coordinate index for this + * GeometryArray object. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getInitialCoordIndex() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray91")); + + return ((GeometryArrayRetained)this.retained).getInitialCoordIndex(); + } + + + /** + * Sets the initial color index for this GeometryArray object. + * This index specifies the first color within the array of + * colors referenced by this geometry + * array that is actually used in rendering or other operations + * such as picking and collision. This attribute is initialized + * to 0. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * + * @param initialColorIndex the new initial color index. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + *

+ * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE or if the data mode + * is INTERLEAVED. + *

+ * @exception IllegalArgumentException if either of the following are + * true: + *

    + * initialColorIndex < 0 or
    + * initialColorIndex + validVertexCount > vertexCount
    + *
+ *

+ * @exception ArrayIndexOutOfBoundsException if + * the ColorRef array is non-null and: + *

    + * ColorRef.length < num_words * + * (initialColorIndex + validVertexCount)
    + *
+ * where num_words depends on which variant of + * setColorRef is used. + * + * @since Java 3D 1.2 + */ + public void setInitialColorIndex(int initialColorIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray90")); + + if (initialColorIndex < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray97")); + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setInitialColorIndex(initialColorIndex); + // NOTE: the check for initialColorIndex + validVertexCount > + // vertexCount needs to be done in the retained method + } + + + /** + * Gets the initial color index for this GeometryArray object. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * @return the current initial color index for this + * GeometryArray object. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getInitialColorIndex() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray91")); + + return ((GeometryArrayRetained)this.retained).getInitialColorIndex(); + } + + + /** + * Sets the initial normal index for this GeometryArray object. + * This index specifies the first normal within the array of + * normals referenced by this geometry + * array that is actually used in rendering or other operations + * such as picking and collision. This attribute is initialized + * to 0. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * + * @param initialNormalIndex the new initial normal index. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + *

+ * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE or if the data mode + * is INTERLEAVED. + *

+ * @exception IllegalArgumentException if either of the following are + * true: + *

    + * initialNormalIndex < 0 or
    + * initialNormalIndex + validVertexCount > vertexCount
    + *
+ *

+ * @exception ArrayIndexOutOfBoundsException if normals + * the NormalRef array is non-null and: + *

    + * NormalRef.length < num_words * + * (initialNormalIndex + validVertexCount)
    + *
+ * where num_words depends on which variant of + * setNormalRef is used. + * + * @since Java 3D 1.2 + */ + public void setInitialNormalIndex(int initialNormalIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray90")); + + if (initialNormalIndex < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray97")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setInitialNormalIndex(initialNormalIndex); + // NOTE: the check for initialNormalIndex + validVertexCount > + // vertexCount needs to be done in the retained method + } + + + /** + * Gets the initial normal index for this GeometryArray object. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * @return the current initial normal index for this + * GeometryArray object. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getInitialNormalIndex() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray91")); + + return ((GeometryArrayRetained)this.retained).getInitialNormalIndex(); + } + + + /** + * Sets the initial texture coordinate index for the specified + * texture coordinate set for this GeometryArray object. This + * index specifies the first texture coordinate within the array + * of texture coordinates referenced by this geometry array that + * is actually used in rendering or other operations such as + * picking and collision. This attribute is initialized to 0. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param initialTexCoordIndex the new initial texture coordinate index. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + *

+ * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE or if the data mode + * is INTERLEAVED. + *

+ * @exception IllegalArgumentException if either of the following are + * true: + *

    + * initialTexCoordIndex < 0 or
    + * initialTexCoordIndex + validVertexCount > vertexCount
    + *
+ *

+ * @exception ArrayIndexOutOfBoundsException if + * the TexCoordRef array is non-null and: + *

    + * TexCoordRef.length < num_words * + * (initialTexCoordIndex + validVertexCount)
    + *
+ * where num_words depends on which variant of + * setTexCoordRef is used. + *

+ * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if texCoordSet is out of range. + * + * @since Java 3D 1.2 + */ + public void setInitialTexCoordIndex(int texCoordSet, + int initialTexCoordIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray90")); + + if (initialTexCoordIndex < 0) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray97")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setInitialTexCoordIndex( + texCoordSet, initialTexCoordIndex); + + // NOTE: the check for initialTexCoordIndex + validVertexCount > + // vertexCount needs to be done in the retained method + } + + + /** + * Gets the initial texture coordinate index for the specified + * texture coordinate set for this GeometryArray object. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * + * @param texCoordSet texture coordinate set in this geometry array + * + * @return the current initial texture coordinate index for the specified + * texture coordinate set + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if texCoordSet is out of range. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getInitialTexCoordIndex(int texCoordSet) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray91")); + + return ((GeometryArrayRetained)this.retained).getInitialTexCoordIndex( + texCoordSet); + } + + + /** + * Sets the initial vertex attribute index for the specified + * vertex attribute number for this GeometryArray object. This + * index specifies the first vertex attribute within the array + * of vertex attributes referenced by this geometry array that + * is actually used in rendering or other operations such as + * picking and collision. This attribute is initialized to 0. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param initialVertexAttrIndex the new initial vertex attribute index. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + *

+ * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE or if the data mode + * is INTERLEAVED. + *

+ * @exception IllegalArgumentException if either of the following are + * true: + *

    + * initialVertexAttrIndex < 0 or
    + * initialVertexAttrIndex + validVertexCount > vertexCount
    + *
+ *

+ * @exception ArrayIndexOutOfBoundsException if + * the VertexAttrRef array is non-null and: + *

    + * VertexAttrRef.length < num_words * + * (initialVertexAttrIndex + validVertexCount)
    + *
+ * where num_words is the size of the specified + * vertexAttrNum (1, 2, 3, or 4). + *

+ * @exception ArrayIndexOutOfBoundsException if vertexAttrNum is + * out of range. + * + * @since Java 3D 1.4 + */ + public void setInitialVertexAttrIndex(int vertexAttrNum, + int initialVertexAttrIndex) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COUNT_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray90")); + } + } + + if (initialVertexAttrIndex < 0) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray97")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + } + + if ((format & INTERLEAVED) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + } + + ((GeometryArrayRetained)this.retained).setInitialVertexAttrIndex( + vertexAttrNum, initialVertexAttrIndex); + + // NOTE: the check for initialVertexAttrIndex + validVertexCount > + // vertexCount needs to be done in the retained method + } + + + /** + * Gets the initial vertex attribute index for the specified + * vertex attribute number for this GeometryArray object. + * This attribute is only used when the data mode for this + * geometry array object is BY_REFERENCE + * and is not INTERLEAVED. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * + * @return the current initial vertex attribute index for the specified + * vertex attribute number + * + * @exception ArrayIndexOutOfBoundsException if vertexAttrNum is + * out of range. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public int getInitialVertexAttrIndex(int vertexAttrNum) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COUNT_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray91")); + } + } + + return ((GeometryArrayRetained)this.retained).getInitialVertexAttrIndex( + vertexAttrNum); + } + + + /** + * Sets the coordinate buffer reference to the specified + * buffer object. The buffer contains either a java.nio.FloatBuffer + * or java.nio.DoubleBuffer object containing single or double + * precision floating-point x, y, + * and z values for each vertex (for a total of 3*n + * values, where n is the number of vertices). + * If the coordinate buffer + * reference is null, the entire geometry array object is + * treated as if it were null--any Shape3D or Morph node that uses + * this geometry array will not be drawn. + * + * @param coords a J3DBuffer object to which a reference will be set. + * The buffer contains an NIO buffer of 3*n float or + * double values. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception IllegalArgumentException if the java.nio.Buffer + * contained in the specified J3DBuffer is not a + * java.nio.FloatBuffer or a java.nio.DoubleBuffer object. + * + * @exception ArrayIndexOutOfBoundsException if + * coords.getBuffer().limit() < + * 3 * (initialCoordIndex + validVertexCount). + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the coordinate index array is greater than or equal to the + * number of vertices defined by the coords object, + * coords.getBuffer().limit() / 3. + * + * @since Java 3D 1.3 + */ + public void setCoordRefBuffer(J3DBuffer coords) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setCoordRefBuffer(coords); + } + + + /** + * Gets the coordinate array buffer reference. + * @return the current coordinate array buffer reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @since Java 3D 1.3 + */ + public J3DBuffer getCoordRefBuffer() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getCoordRefBuffer(); + } + + + /** + * Sets the float coordinate array reference to the specified + * array. The array contains floating-point x, y, + * and z values for each vertex (for a total of 3*n + * values, where n is the number of vertices). Only one of + * coordRefFloat, coordRefDouble, + * coordRef3f, or coordRef3d may be + * non-null (or they may all be null). An attempt to set more + * than one of these attributes to a non-null reference will + * result in an exception being thrown. If all coordinate array + * references are null, the entire geometry array object is + * treated as if it were null--any Shape3D or Morph node that uses + * this geometry array will not be drawn. + * + * @param coords an array of 3*n values to which a + * reference will be set. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * @exception IllegalArgumentException if the specified array is + * non-null and any other coordinate reference is also non-null. + * @exception ArrayIndexOutOfBoundsException if + * coords.length < 3 * (initialCoordIndex + validVertexCount). + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the coordinate index array is greater than or equal to the + * number of vertices defined by the coords array, + * coords.length / 3. + * + * @since Java 3D 1.2 + */ + public void setCoordRefFloat(float[] coords) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setCoordRefFloat(coords); + + } + + + /** + * Gets the float coordinate array reference. + * @return the current float coordinate array reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * + * @since Java 3D 1.2 + */ + public float[] getCoordRefFloat() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getCoordRefFloat(); + } + + + /** + * Sets the double coordinate array reference to the specified + * array. The array contains double-precision + * floating-point x, y, + * and z values for each vertex (for a total of 3*n + * values, where n is the number of vertices). Only one of + * coordRefFloat, coordRefDouble, + * coordRef3f, or coordRef3d may be + * non-null (or they may all be null). An attempt to set more + * than one of these attributes to a non-null reference will + * result in an exception being thrown. If all coordinate array + * references are null, the entire geometry array object is + * treated as if it were null--any Shape3D or Morph node that uses + * this geometry array will not be drawn. + * + * @param coords an array of 3*n values to which a + * reference will be set. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * @exception IllegalArgumentException if the specified array is + * non-null and any other coordinate reference is also non-null. + * @exception ArrayIndexOutOfBoundsException if + * coords.length < 3 * (initialCoordIndex + validVertexCount). + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the coordinate index array is greater than or equal to the + * number of vertices defined by the coords array, + * coords.length / 3. + * + * @since Java 3D 1.2 + */ + public void setCoordRefDouble(double[] coords) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setCoordRefDouble(coords); + + } + + + /** + * Gets the double coordinate array reference. + * @return the current double coordinate array reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * + * @since Java 3D 1.2 + */ + public double[] getCoordRefDouble() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getCoordRefDouble(); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Point3f arrays + * + * @since Java 3D 1.2 + */ + public void setCoordRef3f(Point3f[] coords) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setCoordRef3f(coords); + + + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Point3f arrays + * + * @since Java 3D 1.2 + */ + public Point3f[] getCoordRef3f() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getCoordRef3f(); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Point3d arrays + * + * @since Java 3D 1.2 + */ + public void setCoordRef3d(Point3d[] coords) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setCoordRef3d(coords); + + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Point3d arrays + * + * @since Java 3D 1.2 + */ + public Point3d[] getCoordRef3d() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getCoordRef3d(); + } + + + /** + * Sets the color buffer reference to the specified + * buffer object. The buffer contains either a java.nio.FloatBuffer + * or java.nio.ByteBuffer object containing floating-point + * or byte red, green, + * blue, and, optionally, alpha values for each + * vertex (for a total of 3*n or 4*n values, where + * n is the number of vertices). + * If the color buffer reference is null and colors are enabled + * (that is, the vertexFormat includes either COLOR_3 or + * COLOR_4), the entire geometry array object is + * treated as if it were null--any Shape3D or Morph node that uses + * this geometry array will not be drawn. + * + * @param colors a J3DBuffer object to which a reference will be set. + * The buffer contains an NIO buffer of 3*n or 4*n + * float or byte values. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception IllegalArgumentException if the java.nio.Buffer + * contained in the specified J3DBuffer is not a + * java.nio.FloatBuffer or a java.nio.ByteBuffer object. + * + * @exception ArrayIndexOutOfBoundsException if none of the + * COLOR bits are set in the + * vertexFormat, or if + * colors.getBuffer().limit() < num_words * + * (initialColorIndex + validVertexCount), + * where num_words is 3 or 4 depending on the vertex color format. + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the color index array is greater than or equal to the + * number of vertices defined by the colors object, + * colors.getBuffer().limit() / num_words. + * + * @since Java 3D 1.3 + */ + public void setColorRefBuffer(J3DBuffer colors) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setColorRefBuffer(colors); + + } + + + /** + * Gets the color array buffer reference. + * @return the current color array buffer reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @since Java 3D 1.3 + */ + public J3DBuffer getColorRefBuffer() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getColorRefBuffer(); + } + + + /** + * Sets the float color array reference to the specified array. + * The array contains floating-point red, green, + * blue, and, optionally, alpha values for each + * vertex (for a total of 3*n or 4*n values, where + * n is the number of vertices). Only one of + * colorRefFloat, colorRefByte, + * colorRef3f, colorRef4f, + * colorRef3b, or colorRef4b may be + * non-null (or they may all be null). An attempt to set more + * than one of these attributes to a non-null reference will + * result in an exception being thrown. If all color array + * references are null and colors are enabled (that is, the + * vertexFormat includes either COLOR_3 or + * COLOR_4), the entire geometry array object is + * treated as if it were null--any Shape3D or Morph node that uses + * this geometry array will not be drawn. + * + * @param colors an array of 3*n or 4*n values to which a + * reference will be set. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * @exception IllegalArgumentException if the specified array is + * non-null and any other color reference is also non-null. + * + * @exception ArrayIndexOutOfBoundsException if none of the + * COLOR bits are set in the + * vertexFormat, or if + * colors.length < num_words * + * (initialColorIndex + validVertexCount), + * where num_words is 3 or 4 depending on the vertex color format. + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the color index array is greater than or equal to the + * number of vertices defined by the colors array, + * colors.length / num_words. + * + * @since Java 3D 1.2 + */ + public void setColorRefFloat(float[] colors) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setColorRefFloat(colors); + + } + + + /** + * Gets the float color array reference. + * @return the current float color array reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * + * @since Java 3D 1.2 + */ + public float[] getColorRefFloat() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getColorRefFloat(); + } + + + /** + * Sets the byte color array reference to the specified array. + * The array contains red, green, + * blue, and, optionally, alpha values for each + * vertex (for a total of 3*n or 4*n values, where + * n is the number of vertices). Only one of + * colorRefFloat, colorRefByte, + * colorRef3f, colorRef4f, + * colorRef3b, or colorRef4b may be + * non-null (or they may all be null). An attempt to set more + * than one of these attributes to a non-null reference will + * result in an exception being thrown. If all color array + * references are null and colors are enabled (that is, the + * vertexFormat includes either COLOR_3 or + * COLOR_4), the entire geometry array object is + * treated as if it were null--any Shape3D or Morph node that uses + * this geometry array will not be drawn. + * + * @param colors an array of 3*n or 4*n values to which a + * reference will be set. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * @exception IllegalArgumentException if the specified array is + * non-null and any other color reference is also non-null. + * + * @exception ArrayIndexOutOfBoundsException if none of the + * COLOR bits are set in the + * vertexFormat, or if + * colors.length < num_words * + * (initialColorIndex + validVertexCount), + * where num_words is 3 or 4 depending on the vertex color format. + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the color index array is greater than or equal to the + * number of vertices defined by the colors array, + * colors.length / num_words. + * + * @since Java 3D 1.2 + */ + public void setColorRefByte(byte[] colors) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setColorRefByte(colors); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * Gets the byte color array reference. + * @return the current byte color array reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * + * @since Java 3D 1.2 + */ + public byte[] getColorRefByte() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getColorRefByte(); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Color3f arrays + * + * @since Java 3D 1.2 + */ + public void setColorRef3f(Color3f[] colors) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).setColorRef3f(colors); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Color3f arrays + * + * @since Java 3D 1.2 + */ + public Color3f[] getColorRef3f() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getColorRef3f(); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Color4f arrays + * + * @since Java 3D 1.2 + */ + public void setColorRef4f(Color4f[] colors) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).setColorRef4f(colors); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Color4f arrays + * + * @since Java 3D 1.2 + */ + public Color4f[] getColorRef4f() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getColorRef4f(); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Color3b arrays + * + * @since Java 3D 1.2 + */ + public void setColorRef3b(Color3b[] colors) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + if ((format & WITH_ALPHA) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + + ((GeometryArrayRetained)this.retained).setColorRef3b(colors); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Color3b arrays + * + * @since Java 3D 1.2 + */ + public Color3b[] getColorRef3b() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getColorRef3b(); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Color4b arrays + * + * @since Java 3D 1.2 + */ + public void setColorRef4b(Color4b[] colors) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + if ((format & WITH_ALPHA) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + + ((GeometryArrayRetained)this.retained).setColorRef4b(colors); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Color4b arrays + * + * @since Java 3D 1.2 + */ + public Color4b[] getColorRef4b() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getColorRef4b(); + } + + + /** + * Sets the normal buffer reference to the specified + * buffer object. The buffer contains a java.nio.FloatBuffer + * object containing nx, ny, + * and nz values for each vertex (for a total of 3*n + * values, where n is the number of vertices). + * If the normal buffer reference is null and normals are enabled + * (that is, the vertexFormat includes NORMAL), the + * entire geometry array object is treated as if it were null--any + * Shape3D or Morph node that uses this geometry array will not be + * drawn. + * + * @param normals a J3DBuffer object to which a reference will be set. + * The buffer contains an NIO buffer of 3*n float values. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception IllegalArgumentException if the java.nio.Buffer + * contained in the specified J3DBuffer is not a + * java.nio.FloatBuffer object. + * + * @exception ArrayIndexOutOfBoundsException if + * NORMALS bit is not set in the + * vertexFormat, or if + * normals.getBuffer().limit() < + * 3 * (initialNormalIndex + validVertexCount). + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the normal index array is greater than or equal to the + * number of vertices defined by the normals object, + * normals.getBuffer().limit() / 3. + * + * @since Java 3D 1.3 + */ + public void setNormalRefBuffer(J3DBuffer normals) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setNormalRefBuffer(normals); + } + + + /** + * Gets the normal array buffer reference. + * @return the current normal array buffer reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @since Java 3D 1.3 + */ + public J3DBuffer getNormalRefBuffer() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getNormalRefBuffer(); + } + + + /** + * Sets the float normal array reference to the specified + * array. The array contains floating-point nx, ny, + * and nz values for each vertex (for a total of 3*n + * values, where n is the number of vertices). Only one of + * normalRefFloat or normalRef3f may be + * non-null (or they may all be null). An attempt to set more + * than one of these attributes to a non-null reference will + * result in an exception being thrown. If all normal array + * references are null and normals are enabled (that is, the + * vertexFormat includes + * NORMAL), the entire geometry array object is + * treated as if it were null--any Shape3D or Morph node that uses + * this geometry array will not be drawn. + * + * @param normals an array of 3*n values to which a + * reference will be set. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * @exception IllegalArgumentException if the specified array is + * non-null and any other normal reference is also non-null. + * @exception ArrayIndexOutOfBoundsException if + * NORMALS bit is not set in the + * vertexFormat, or if + * normals.length < 3 * (initialNormalIndex + validVertexCount). + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the normal index array is greater than or equal to the + * number of vertices defined by the normals array, + * normals.length / 3. + * + * @since Java 3D 1.2 + */ + public void setNormalRefFloat(float[] normals) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setNormalRefFloat(normals); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * Gets the float normal array reference. + * @return the current float normal array reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * + * @since Java 3D 1.2 + */ + public float[] getNormalRefFloat() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getNormalRefFloat(); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Vector3f arrays + * + * @since Java 3D 1.2 + */ + public void setNormalRef3f(Vector3f[] normals) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setNormalRef3f(normals); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for Vector3f arrays + * + * @since Java 3D 1.2 + */ + public Vector3f[] getNormalRef3f() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getNormalRef3f(); + } + + + /** + * Sets the texture coordinate buffer reference for the specified + * texture coordinate set to the + * specified buffer object. The buffer contains a java.nio.FloatBuffer + * object containing s, + * t, and, optionally, r and q values for each + * vertex (for + * a total of 2*n , 3*n or 4*n values, + * where n is + * the number of vertices). + * If the texCoord buffer reference is null and texture + * coordinates are enabled (that is, the vertexFormat includes + * TEXTURE_COORDINATE_2, + * TEXTURE_COORDINATE_3, or + * TEXTURE_COORDINATE_4), the entire geometry + * array object is treated as if it were null--any Shape3D or + * Morph node that uses this geometry array will not be drawn. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param texCoords a J3DBuffer object to which a reference will be set. + * The buffer contains an NIO buffer of 2*n, 3*n or + * 4*n float values. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception IllegalArgumentException if the java.nio.Buffer + * contained in the specified J3DBuffer is not a + * java.nio.FloatBuffer object. + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat, or if texCoordSet is out of range, + * or if + * texCoords.getBuffer().limit() < num_words + * * (initialTexCoordIndex + validVertexCount), + * where num_words is 2, 3, or 4 depending on the vertex + * texture coordinate format. + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the texture coordinate index array is greater than or equal to the + * number of vertices defined by the texCoords object, + * texCoords.getBuffer().limit() / num_words. + * + * @since Java 3D 1.3 + */ + public void setTexCoordRefBuffer(int texCoordSet, J3DBuffer texCoords) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setTexCoordRefBuffer( + texCoordSet, texCoords); + + } + + + /** + * Gets the texture coordinate array buffer reference for the specified + * texture coordinate set. + * + * @param texCoordSet texture coordinate set in this geometry array + * + * @return the current texture coordinate array buffer reference + * for the specified texture coordinate set + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or texCoordSet is out of range. + * + * @since Java 3D 1.3 + */ + public J3DBuffer getTexCoordRefBuffer(int texCoordSet) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getTexCoordRefBuffer(texCoordSet); + } + + + /** + * Sets the float texture coordinate array reference for the specified + * texture coordinate set to the + * specified array. The array contains floating-point s, + * t, and, optionally, r and q values for each + * vertex (for + * a total of 2*n , 3*n or 4*n values, + * where n is + * the number of vertices). Only one of + * texCoordRefFloat, texCoordRef2f, or + * texCoordRef3f may be non-null (or they may all be + * null). An attempt to set more than one of these attributes to + * a non-null reference will result in an exception being thrown. + * If all texCoord array references are null and texture + * coordinates are enabled (that is, the vertexFormat includes + * TEXTURE_COORDINATE_2, + * TEXTURE_COORDINATE_3, or + * TEXTURE_COORDINATE_4), the entire geometry + * array object is treated as if it were null--any Shape3D or + * Morph node that uses this geometry array will not be drawn. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param texCoords an array of 2*n, 3*n or + * 4*n values to + * which a reference will be set. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * @exception IllegalArgumentException if the specified array is + * non-null and any other texCoord reference is also non-null. + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat, or if texCoordSet is out of range, + * or if + * texCoords.length < num_words * + * (initialTexCoordIndex + validVertexCount), + * where num_words is 2, 3, or 4 depending on the vertex + * texture coordinate format. + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the texture coordinate index array is greater than or equal to the + * number of vertices defined by the texCoords array, + * texCoords.length / num_words. + * + * @since Java 3D 1.2 + */ + public void setTexCoordRefFloat(int texCoordSet, float[] texCoords) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + ((GeometryArrayRetained)this.retained).setTexCoordRefFloat( + texCoordSet, texCoords); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * Gets the float texture coordinate array reference for the specified + * texture coordinate set. + * + * @param texCoordSet texture coordinate set in this geometry array + * + * @return the current float texture coordinate array reference + * for the specified texture coordinate set + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception ArrayIndexOutOfBoundsException if none of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or texCoordSet is out of range. + * + * @since Java 3D 1.2 + */ + public float[] getTexCoordRefFloat(int texCoordSet) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getTexCoordRefFloat( + texCoordSet); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for TexCoord2f arrays + * + * @since Java 3D 1.2 + */ + public void setTexCoordRef2f(int texCoordSet, TexCoord2f[] texCoords) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + if ((format & (TEXTURE_COORDINATE_3 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray94")); + + ((GeometryArrayRetained)this.retained).setTexCoordRef2f( + texCoordSet, texCoords); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for TexCoord2f arrays + * + * @since Java 3D 1.2 + */ + public TexCoord2f[] getTexCoordRef2f(int texCoordSet) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getTexCoordRef2f( + texCoordSet); + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for TexCoord3f arrays + * + * @since Java 3D 1.2 + */ + public void setTexCoordRef3f(int texCoordSet, TexCoord3f[] texCoords) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + if ((format & (TEXTURE_COORDINATE_2 | TEXTURE_COORDINATE_4)) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray95")); + + ((GeometryArrayRetained)this.retained).setTexCoordRef3f( + texCoordSet, texCoords); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * @deprecated As of Java 3D version 1.3, use geometry by-copy + * for TexCoord3f arrays + * + * @since Java 3D 1.2 + */ + public TexCoord3f[] getTexCoordRef3f(int texCoordSet) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + if ((format & INTERLEAVED) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + + return ((GeometryArrayRetained)this.retained).getTexCoordRef3f( + texCoordSet); + } + + + /** + * Sets the vertex attribute buffer reference for the specified + * vertex attribute number to the specified buffer object. The + * buffer contains a java.nio.FloatBuffer object containing 1, 2, + * 3, or 4 values for each vertex (for a total of 1*n, + * 2*n, 3*n, or 4*n values, where n is + * the number of vertices). + * If the vertexAttr buffer reference is null and vertex + * attributes are enabled (that is, the vertexFormat includes + * VERTEX_ATTRIBUTES), the entire geometry array + * object is treated as if it were null--any Shape3D node that + * uses this geometry array will not be drawn. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * + * @param vertexAttrs a J3DBuffer object to which a reference will + * be set. The buffer contains an NIO buffer of 1*n, + * 2*n, 3*n, or 4*n float values. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception IllegalArgumentException if the java.nio.Buffer + * contained in the specified J3DBuffer is not a + * java.nio.FloatBuffer object. + * + * @exception ArrayIndexOutOfBoundsException if vertexAttrNum is out of + * range, or if + * vertexAttrs.getBuffer().limit() < num_words + * * (initialVertexAttrIndex + validVertexCount), + * where num_words is the size of the specified + * vertexAttrNum (1, 2, 3, or 4). + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the vertex attribute index array is greater than or equal to the + * number of vertices defined by the vertexAttrs object, + * vertexAttrs.getBuffer().limit() / num_words. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrRefBuffer(int vertexAttrNum, J3DBuffer vertexAttrs) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + + if ((format & USE_NIO_BUFFER) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + } + + if ((format & INTERLEAVED) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrRefBuffer( + vertexAttrNum, vertexAttrs); + } + + + /** + * Gets the vertex attribute array buffer reference for the specified + * vertex attribute number. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * + * @return the current vertex attribute array buffer reference + * for the specified vertex attribute number + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is not USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception ArrayIndexOutOfBoundsException if vertexAttrNum is out + * of range. + * + * @since Java 3D 1.4 + */ + public J3DBuffer getVertexAttrRefBuffer(int vertexAttrNum) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + + if ((format & USE_NIO_BUFFER) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + } + + if ((format & INTERLEAVED) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + } + + return ((GeometryArrayRetained)this.retained).getVertexAttrRefBuffer(vertexAttrNum); + } + + + /* + * XXXX: add the following to the javadoc if we ever add double-precision + * methods for vertex attribtues. + * + *----------------------------------------------------------------- + * Only one of vertexAttrRefFloat, or + * vertexAttrRefDouble may be non-null (or they may + * all be null). An attempt to set more than one of these + * attributes to a non-null reference will result in an exception + * being thrown. + * + * If all vertexAttr array references are null and vertex + * ... + * @exception IllegalArgumentException if the specified array is + * non-null and any other vertexAttr reference is also non-null. + * ... + *----------------------------------------------------------------- + */ + + /** + * Sets the float vertex attribute array reference for the + * specified vertex attribute number to the specified array. The + * array contains 1, 2, 3, or 4 floating-point values for each + * vertex (for a total of 1*n, 2*n, 3*n, or + * 4*n values, where n is the number of vertices). + * + * If the vertexAttr array reference is null and vertex + * attributes are enabled (that is, the vertexFormat includes + * VERTEX_ATTRIBUTES), the entire geometry array + * object is treated as if it were null--any Shape3D node that + * uses this geometry array will not be drawn. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * + * @param vertexAttrs an array of 1*n, 2*n, + * 3*n, or 4*n values to which a reference will be + * set. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception ArrayIndexOutOfBoundsException if vertexAttrNum is + * out of range, or if + * vertexAttrs.length < num_words * + * (initialVertexAttrIndex + validVertexCount), + * where num_words is the size of the specified + * vertexAttrNum (1, 2, 3, or 4). + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the vertex attribute index array is greater than or equal to the + * number of vertices defined by the vertexAttrs array, + * vertexAttrs.length / num_words. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrRefFloat(int vertexAttrNum, float[] vertexAttrs) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + } + + if ((format & USE_NIO_BUFFER) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + } + + if ((format & INTERLEAVED) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + } + + ((GeometryArrayRetained)this.retained).setVertexAttrRefFloat( + vertexAttrNum, vertexAttrs); + + // NOTE: the checks for multiple non-null references, and the + // array length check need to be done in the retained method + } + + + /** + * Gets the float vertex attribute array reference for the specified + * vertex attribute number. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * + * @return the current float vertex attribute array reference + * for the specified vertex attribute number + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE, + * is USE_NIO_BUFFER, or is INTERLEAVED. + * + * @exception ArrayIndexOutOfBoundsException if vertexAttrNum is + * out of range. + * + * @since Java 3D 1.4 + */ + public float[] getVertexAttrRefFloat(int vertexAttrNum) { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray83")); + } + + if ((format & USE_NIO_BUFFER) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + } + + if ((format & INTERLEAVED) != 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray84")); + } + + return ((GeometryArrayRetained)this.retained).getVertexAttrRefFloat( + vertexAttrNum); + } + + + /** + * Sets the interleaved vertex array reference to the specified + * array. The vertex components must be stored in a predetermined + * order in the array. The order is: texture coordinates, colors, + * normals, and positional coordinates. + * Vertex attributes are not supported in interleaved mode. + * In the case of texture + * coordinates, the values for each texture coordinate set + * are stored in order from 0 through texCoordSetCount-1. Only those + * components that are enabled appear in the vertex. The number + * of words per vertex depends on which vertex components are + * enabled. Texture coordinates, if enabled, use 2 words per + * texture coordinate set per vertex for + * TEXTURE_COORDINATE_2, 3 words per texture + * coordinate set per vertex for + * TEXTURE_COORDINATE_3 or 4 words per texture + * coordinate set per vertex for + * TEXTURE_COORDINATE_4. Colors, if enabled, use 3 + * words per vertex for COLOR_3 or 4 words per vertex + * for COLOR_4. Normals, if enabled, use 3 words per + * vertex. Positional coordinates, which are always enabled, use + * 3 words per vertex. For example, the format of interleaved + * data for a GeometryArray object whose vertexFormat includes + * COORDINATES, COLOR_3, and + * NORMALS would be: red, green, + * blue, Nx, Ny, Nz, x, + * y, z. All components of a vertex are stored in + * adjacent memory locations. The first component of vertex 0 is + * stored beginning at index 0 in the array. The first component + * of vertex 1 is stored beginning at index + * words_per_vertex in the array. The total number of + * words needed to store n vertices is + * words_per_vertex*n. + * + * @param vertexData an array of vertex values to which a + * reference will be set. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not INTERLEAVED + * or is USE_NIO_BUFFER. + * + * @exception ArrayIndexOutOfBoundsException if + * vertexData.length < words_per_vertex * + * (initialVertexIndex + validVertexCount), + * where words_per_vertex depends on which formats are enabled. + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the index array associated with any of the enabled vertex + * components (coord, color, normal, texcoord) is greater than or + * equal to the number of vertices defined by the vertexData + * array, + * vertexData.length / words_per_vertex. + * + * @since Java 3D 1.2 + */ + public void setInterleavedVertices(float[] vertexData) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & INTERLEAVED) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray85")); + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + ((GeometryArrayRetained)this.retained).setInterleavedVertices(vertexData); + + // NOTE: the array length check needs to be done in the retained method + } + + + /** + * Gets the interleaved vertices array reference. + * @return the current interleaved vertices array reference. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data mode for this geometry + * array object is not INTERLEAVED + * or is USE_NIO_BUFFER. + * + * @since Java 3D 1.2 + */ + public float[] getInterleavedVertices() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & INTERLEAVED) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray85")); + + + if ((format & USE_NIO_BUFFER) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray119")); + + return ((GeometryArrayRetained)this.retained).getInterleavedVertices(); + } + + /** + * Sets the interleaved vertex buffer reference to the specified + * buffer object. The buffer must contain a java.nio.FloatBuffer object. + * The vertex components must be stored in a predetermined + * order in the buffer. The order is: texture coordinates, colors, + * normals, and positional coordinates. + * Vertex attributes are not supported in interleaved mode. + * In the case of texture + * coordinates, the values for each texture coordinate set + * are stored in order from 0 through texCoordSetCount-1. Only those + * components that are enabled appear in the vertex. The number + * of words per vertex depends on which vertex components are + * enabled. Texture coordinates, if enabled, use 2 words per + * texture coordinate set per vertex for + * TEXTURE_COORDINATE_2, 3 words per texture + * coordinate set per vertex for + * TEXTURE_COORDINATE_3 or 4 words per texture + * coordinate set per vertex for + * TEXTURE_COORDINATE_4. Colors, if enabled, use 3 + * words per vertex for COLOR_3 or 4 words per vertex + * for COLOR_4. Normals, if enabled, use 3 words per + * vertex. Positional coordinates, which are always enabled, use + * 3 words per vertex. For example, the format of interleaved + * data for a GeometryArray object whose vertexFormat includes + * COORDINATES, COLOR_3, and + * NORMALS would be: red, green, + * blue, Nx, Ny, Nz, x, + * y, z. All components of a vertex are stored in + * adjacent memory locations. The first component of vertex 0 is + * stored beginning at index 0 in the buffer. The first component + * of vertex 1 is stored beginning at index + * words_per_vertex in the buffer. The total number of + * words needed to store n vertices is + * words_per_vertex*n. + * + * @param vertexData a J3DBuffer object to which a reference will be set. + * The buffer contains an NIO float buffer of + * words_per_vertex*n values. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not INTERLEAVED + * or is not USE_NIO_BUFFER. + * + * @exception IllegalArgumentException if the java.nio.Buffer + * contained in the specified J3DBuffer is not a + * java.nio.FloatBuffer object. + * + * @exception ArrayIndexOutOfBoundsException if + * vertexData.getBuffer().limit() < words_per_vertex * + * (initialVertexIndex + validVertexCount), + * where words_per_vertex depends on which formats are enabled. + * + * @exception ArrayIndexOutOfBoundsException if this GeometryArray + * object is a subclass of IndexedGeometryArray, and any element + * in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the index array associated with any of the enabled vertex + * components (coord, color, normal, texcoord) is greater than or + * equal to the number of vertices defined by the vertexData + * object, + * vertexData.getBuffer().limit() / words_per_vertex. + * + * @since Java 3D 1.3 + */ + public void setInterleavedVertexBuffer(J3DBuffer vertexData) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & INTERLEAVED) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray85")); + + + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + ((GeometryArrayRetained)this.retained).setInterleavedVertexBuffer(vertexData); + + } + + + /** + * Gets the interleaved vertex array buffer reference. + * @return the current interleaved vertex array buffer reference. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not INTERLEAVED + * or is not USE_NIO_BUFFER. + * + * @since Java 3D 1.3 + */ + public J3DBuffer getInterleavedVertexBuffer() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ) && + !this.getCapability(J3D_1_2_ALLOW_REF_DATA_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + } + + int format = ((GeometryArrayRetained)this.retained).vertexFormat; + if ((format & INTERLEAVED) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray85")); + + if ((format & USE_NIO_BUFFER) == 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray118")); + + return ((GeometryArrayRetained)this.retained).getInterleavedVertexBuffer(); + + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryArrayRetained.java new file mode 100644 index 0000000..20f99de --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryArrayRetained.java @@ -0,0 +1,11299 @@ +/* + * $RCSfile: GeometryArrayRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.12 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import com.sun.j3d.internal.Distance; +import javax.vecmath.*; +import java.lang.Math; +import java.util.ArrayList; +import java.util.Set; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Vector; +import java.util.Enumeration; +import com.sun.j3d.internal.ByteBufferWrapper; +import com.sun.j3d.internal.BufferWrapper; +import com.sun.j3d.internal.FloatBufferWrapper; +import com.sun.j3d.internal.DoubleBufferWrapper; + + +/** + * The GeometryArray object contains arrays of positional coordinates, + * colors, normals and/or texture coordinates that describe + * point, line, or surface geometry. It is extended to create + * the various primitive types (e.g., lines, triangle_strips, etc.) + */ + +abstract class GeometryArrayRetained extends GeometryRetained{ + + // XXXX: Memory footprint reduction. Should have separate object to + // to contain specific data such as a ByRef object for + // all ByRef related data. So that incases where no + // ByRef is needed, the ByRef object reference is + // set to null. Hence saving memory! + // Need object such as Texture, D3d and ByRef ... + // + + + // Contains a bitset indicating which components are present + int vertexFormat; + + // Whether this geometry was ever rendered as transparent + int c4fAllocated = 0; + + // Total Number of vertices + int vertexCount; + + // number of vertices used in rendering + int validVertexCount; + + // The vertex data in packed format + float vertexData[]; + + // vertex data in packed format for each screen in multi-screen situation + // if alpha values of each vertex are to be updated + private float mvertexData[][]; + + // + // The following offset/stride values are internally computed + // from the format + // + + // Stride (in words) from one vertex to the next + int stride; + + // Stride (in words) from one texture coordinate to the next + int texCoordStride; + + // Offset (in words) within each vertex of the coordinate position + int coordinateOffset; + + // Offset (in words) within each vertex of the normal + int normalOffset; + + // Offset (in words) within each vertex of the color + int colorOffset; + + // Offset (in words) within each vertex of the texture coordinate + int textureOffset; + + // Offset (in words) within each vertex of each vertex attribute + int[] vertexAttrOffsets; + + // Stride (size) of all vertex attributes + int vertexAttrStride; + + // alpha value for transparency and texture blending + private float[] lastAlpha = new float[1]; + float lastScreenAlpha = -1; + + int colorChanged = 0; + + // byte to float scale factor + static final float ByteToFloatScale = 1.0f/255.0f; + + // float to byte scale factor + static final float FloatToByteScale = 255.0f; + + // Set flag indicating that we are in the updater. This flag + // can be used by the various setRef methods to inhibit any + // update messages + boolean inUpdater = false; + + // Array List used for messages + ArrayList gaList = new ArrayList(1); + + + // Target threads to be notified when morph changes + static final int targetThreads = (J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_GEOMETRY); + + // used for byReference geometry + float[] floatRefCoords = null; + double[] doubleRefCoords = null; + Point3d[] p3dRefCoords = null; + Point3f[] p3fRefCoords = null; + + // Used for NIO buffer geometry + J3DBuffer coordRefBuffer = null; + FloatBufferWrapper floatBufferRefCoords = null; + DoubleBufferWrapper doubleBufferRefCoords = null; + + // Initial index to use for rendering + int initialCoordIndex = 0; + int initialColorIndex = 0; + int initialNormalIndex = 0; + int[] initialTexCoordIndex = null; + int[] initialVertexAttrIndex = null; + int initialVertexIndex = 0; + + + // used for byReference colors + float[] floatRefColors = null; + byte[] byteRefColors = null; + Color3f[] c3fRefColors = null; + Color4f[] c4fRefColors = null; + Color3b[] c3bRefColors = null; + Color4b[] c4bRefColors = null; + + // Used for NIO buffer colors + J3DBuffer colorRefBuffer = null; + FloatBufferWrapper floatBufferRefColors = null; + ByteBufferWrapper byteBufferRefColors = null; + + // flag to indicate if the "by reference" component is already set + int vertexType = 0; + static final int PF = 0x1; + static final int PD = 0x2; + static final int P3F = 0x4; + static final int P3D = 0x8; + static final int VERTEX_DEFINED = PF | PD | P3F | P3D; + + static final int CF = 0x10; + static final int CUB = 0x20; + static final int C3F = 0x40; + static final int C4F = 0x80; + static final int C3UB = 0x100; + static final int C4UB = 0x200; + static final int COLOR_DEFINED = CF | CUB | C3F | C4F| C3UB | C4UB; + + static final int NF = 0x400; + static final int N3F = 0x800; + static final int NORMAL_DEFINED = NF | N3F; + + static final int TF = 0x1000; + static final int T2F = 0x2000; + static final int T3F = 0x4000; + static final int TEXCOORD_DEFINED = TF | T2F | T3F; + + static final int AF = 0x8000; + static final int VATTR_DEFINED = AF; + + // Flag word indicating the type of by-ref texCoord. We will copy this to + // the vertexType field only when the references for all texture coordinate + // sets are set to non-null values. + private int texCoordType = 0; + + // Flag word indicating the type of by-ref vertex attr. We will copy this to + // the vertexType field only when the references for all vertex attrs + // are set to non-null values. + private int vertexAttrType = 0; + + // flag for execute geometry array when by reference + static final int COORD_FLOAT = 0x01; + static final int COORD_DOUBLE = 0x02; + static final int COLOR_FLOAT = 0x04; + static final int COLOR_BYTE = 0x08; + static final int NORMAL_FLOAT = 0x10; + static final int TEXCOORD_FLOAT = 0x20; + static final int VATTR_FLOAT = 0x40; + + + // used by "by reference" normals + float[] floatRefNormals = null; + Vector3f[] v3fRefNormals = null; + + // Used for NIO buffer normals + J3DBuffer normalRefBuffer = null; + FloatBufferWrapper floatBufferRefNormals = null; + + // used for "by reference" vertex attrs + float[][] floatRefVertexAttrs = null; + + // Used for NIO buffer vertex attrs + J3DBuffer[] vertexAttrsRefBuffer = null; + FloatBufferWrapper[] floatBufferRefVertexAttrs = null; + Object[] nioFloatBufferRefVertexAttrs = null; + + // used by "by reference" tex coords + Object[] refTexCoords = null; + TexCoord2f[] t2fRefTexCoords = null; + TexCoord3f[] t3fRefTexCoords = null; + + // Used for NIO buffer tex coords + Object[] refTexCoordsBuffer = null; + //FloatBufferWrapper[] floatBufferRefTexCoords = null; + + + // used by interleaved array + float[] interLeavedVertexData = null; + + // used by interleaved NIO buffer + J3DBuffer interleavedVertexBuffer = null; + FloatBufferWrapper interleavedFloatBufferImpl = null; + + // pointers used, when transparency is turned on + // or when its an object such as C3F, P3F etc .. + float[] mirrorFloatRefCoords = null; + double[] mirrorDoubleRefCoords = null; + float[] mirrorFloatRefNormals = null; + float[][] mirrorFloatRefVertexAttrs = null; + float[] mirrorFloatRefTexCoords = null; + Object[] mirrorRefTexCoords = null; + + float[][] mirrorFloatRefColors = new float[1][]; + byte[][] mirrorUnsignedByteRefColors= new byte[1][]; + float[][] mirrorInterleavedColorPointer = null; + + // boolean to determine if a mirror was allocated + int mirrorVertexAllocated = 0; + int mirrorColorAllocated = 0; + boolean mirrorNormalAllocated = false; + + // Some dirty bits for GeometryArrays + static final int COORDINATE_CHANGED = 0x01; + static final int NORMAL_CHANGED = 0x02; + static final int COLOR_CHANGED = 0x04; + static final int TEXTURE_CHANGED = 0x08; + static final int BOUNDS_CHANGED = 0x10; + static final int INDEX_CHANGED = 0x20; + static final int STRIPCOUNT_CHANGED = 0x40; + static final int VATTR_CHANGED = 0x80; + static final int VERTEX_CHANGED = COORDINATE_CHANGED | + NORMAL_CHANGED | + COLOR_CHANGED | + TEXTURE_CHANGED | + VATTR_CHANGED; + + static final int defaultTexCoordSetMap[] = {0}; + int texCoordSetCount = 0; + int [] texCoordSetMap = null; + + // this array contains offset to the texCoord data for each + // texture unit. -1 means no corresponding texCoord data offset + int [] texCoordSetMapOffset = null; + + // Vertex attribute information + int vertexAttrCount = 0; + int[] vertexAttrSizes = null; + + + // This point to a list of VertexBuffers in a Vector structure + // Each element correspond to a D3D context that create this VB. + // Note that this GeometryArray can be used by multiple ctx. + long pVertexBuffers = 0; + int dirtyFlag; + + // each bit corresponds to a unique renderer if shared context + // or a unique canvas otherwise + int resourceCreationMask = 0x0; + + // Fix for Issue 5 + // + // Replace the per-canvas reference count with a per-RenderBin set + // of users. The per-RenderBin set of users of this display list + // is defined as a HashMap where: + // + // key = the RenderBin + // value = a set of RenderAtomListInfo objects using this + // geometry array for display list purposes + private HashMap dlistUsers = null; + + // timestamp used to create display list. This is either + // one per renderer for useSharedCtx, or one per Canvas for non-shared + // ctx + private long[] timeStampPerDlist = new long[2]; + + // Unique display list Id, if this geometry is shared + int dlistId = -1; + Integer dlistObj = null; + + // A list of pre-defined bits to indicate which component + // in this Texture object changed. + // static final int DLIST_CREATE_CHANGED = 0x01; + static final int INIT_MIRROR_GEOMETRY = 0x02; + + + // A list of Universes that this Geometry is referenced in Morph from + ArrayList morphUniverseList = null; + + // A list of ArrayLists which contain all the MorphRetained objects + // refering to this geometry. Each list corresponds to the universe + // above. + ArrayList morphUserLists = null; + + // The following variables are only used in compile mode + + // Offset of a geometry array into the merged array + int[] geoOffset; + + // vertexcount of a geometry array in a merge array + int[] compileVcount; + + boolean isCompiled = false; + + boolean isShared = false; + + IndexedGeometryArrayRetained cloneSourceArray = null; + + static final double EPS = 1.0e-13; + + void freeD3DArray(boolean deleteVB) { + assert VirtualUniverse.mc.isD3D(); + Pipeline.getPipeline().freeD3DArray(this, deleteVB); + } + + GeometryArrayRetained() { + dirtyFlag = INDEX_CHANGED|VERTEX_CHANGED; + lastAlpha[0] = 1.0f; + } + + + void setLive(boolean inBackgroundGroup, int refCount) { + dirtyFlag = VERTEX_CHANGED|INDEX_CHANGED; + isEditable = !isWriteStatic(); + super.doSetLive(inBackgroundGroup, refCount); + super.markAsLive(); + // Send message to RenderingAttribute structure to obtain a dlistId + // System.err.println("Geometry - "+this+"refCount = "+this.refCount); + if (this.refCount > 1) { + // Send to rendering attribute structure, + /* + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.GEOMETRYARRAY_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(DLIST_CREATE_CHANGED); + VirtualUniverse.mc.processMessage(createMessage); + */ + isShared = true; + } // Clone geometry only for the first setLive + else { + // If geometry is indexed and use_index_coord is false, unindexify + // otherwise, set mirrorGeometry to null (from previous clearLive) + if (this instanceof IndexedGeometryArrayRetained) { + // Send to rendering attribute structure, + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.GEOMETRY_CHANGED; + createMessage.universe = null; + createMessage.args[0] = null; + createMessage.args[1]= this; + createMessage.args[2]= new Integer(INIT_MIRROR_GEOMETRY); + VirtualUniverse.mc.processMessage(createMessage); + } + } + + } + + void clearLive(int refCount) { + super.clearLive(refCount); + + if (this.refCount <= 0) { + if (pVertexBuffers != 0) { + J3dMessage renderMessage = new J3dMessage(); + renderMessage.threads = J3dThread.RENDER_THREAD; + renderMessage.type = J3dMessage.RENDER_IMMEDIATE; + renderMessage.universe = null; + renderMessage.view = null; + renderMessage.args[0] = null; + renderMessage.args[1] = this; + // Any one renderer is fine since VB store the ctx + // where it is created. + Enumeration e = Screen3D.deviceRendererMap.elements(); + Renderer rdr = (Renderer) e.nextElement(); + rdr.rendererStructure.addMessage(renderMessage); + VirtualUniverse.mc.setWorkForRequestRenderer(); + } + isShared = false; + } + } + + void computeBoundingBox() { + + // System.err.println("computeBoundingBox ...."); + + if (boundsDirty && VirtualUniverse.mc.cacheAutoComputedBounds) { + for(ArrayList users : userLists) { + for(Shape3DRetained shape : users) + shape.dirtyBoundsCache(); + } + } + + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + // by copy + computeBoundingBox(initialVertexIndex, vertexData); + + } else if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { // USE_NIO_BUFFER + //System.err.println("vertexFormat & GeometryArray.USE_NIO_BUFFER"); + if((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + computeBoundingBox(initialCoordIndex, interleavedFloatBufferImpl); + } else if((vertexType & PF) != 0) { + computeBoundingBox(floatBufferRefCoords); + } else if((vertexType & PD) != 0) { + computeBoundingBox(doubleBufferRefCoords); + } + + } else if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + //System.err.println("vertexFormat & GeometryArray.INTERLEAVED"); + computeBoundingBox(initialCoordIndex, interLeavedVertexData); + } else if ((vertexType & PF) != 0) { + //System.err.println("vertexType & PF"); + computeBoundingBox(floatRefCoords); + } else if ((vertexType & P3F) != 0) { + //System.err.println("vertexType & P3F"); + computeBoundingBox(p3fRefCoords); + } else if ((vertexType & P3D) != 0) { + //System.err.println("vertexType & P3D"); + computeBoundingBox(p3dRefCoords); + } else if ((vertexType & PD) != 0) { + //System.err.println("vertexType & PD"); + computeBoundingBox(doubleRefCoords); + } + + } + + + // NullGeometry is true only for byRef case + void processCoordsChanged(boolean nullGeo) { + + /* + System.err.println("processCoordsChanged : nullGeo " + nullGeo); + System.err.println("Before :processCoordsChanged : geoBounds "); + System.err.println(geoBounds); + */ + if (nullGeo) { + synchronized(geoBounds) { + geoBounds.setLower(-1.0, -1.0, -1.0); + geoBounds.setUpper(1.0, 1.0, 1.0); + boundsDirty = false; + } + synchronized(centroid) { + recompCentroid = false; + this.centroid.set(geoBounds.getCenter()); + } + + } + else { + // re-compute centroid if used + synchronized(centroid) { + recompCentroid = true; + } + + synchronized(geoBounds) { + boundsDirty = true; + computeBoundingBox(); + } + + /* + System.err.println("After :processCoordsChanged : geoBounds "); + System.err.println(geoBounds); + */ + } + } + + + void computeBoundingBox(int vIndex, float[] vdata) { + int i, offset; + double xmin, xmax, ymin, ymax, zmin, zmax; + + + //System.err.println("Before : computeBoundingBox : geoBounds "); + // System.err.println(geoBounds); + + synchronized(geoBounds) { + + // If autobounds compute is false then return + // It is possible that user call getBounds() before + // this Geometry add to live scene graph. + if ((computeGeoBounds == 0) && (refCount > 0)) { + return; + } + if (!boundsDirty) + return; + + // Initial offset + offset = vIndex * stride+coordinateOffset; + // Compute the bounding box + xmin = xmax = vdata[offset]; + ymin = ymax = vdata[offset+1]; + zmin = zmax = vdata[offset+2]; + offset += stride; + for (i=1; i xmax) + xmax = vdata[offset]; + if (vdata[offset] < xmin) + xmin = vdata[offset]; + + if (vdata[offset+1] > ymax) + ymax = vdata[offset+1]; + if (vdata[offset+1] < ymin) + ymin = vdata[offset+1]; + + if (vdata[offset+2] > zmax) + zmax = vdata[offset+2]; + if (vdata[offset+2] < zmin) + zmin = vdata[offset+2]; + + offset += stride; + } + + geoBounds.setUpper(xmax, ymax, zmax); + geoBounds.setLower(xmin, ymin, zmin); + boundsDirty = false; + } + /* + System.err.println("After : computeBoundingBox : geoBounds "); + System.err.println(geoBounds); + */ + } + + // Compute boundingbox for interleaved nio buffer + void computeBoundingBox(int vIndex, FloatBufferWrapper vdata) { + int i, offset; + double xmin, xmax, ymin, ymax, zmin, zmax; + + + synchronized(geoBounds) { + // If autobounds compute is false then return + if ((computeGeoBounds == 0) && (refCount > 0)) { + return; + } + + if (!boundsDirty) + return; + + // Initial offset + offset = vIndex * stride+coordinateOffset; + // Compute the bounding box + xmin = xmax = vdata.get(offset); + ymin = ymax = vdata.get(offset+1); + zmin = zmax = vdata.get(offset+2); + offset += stride; + for (i=1; i xmax) + xmax = vdata.get(offset); + if (vdata.get(offset) < xmin) + xmin = vdata.get(offset); + + if (vdata.get(offset+1) > ymax) + ymax = vdata.get(offset+1); + if (vdata.get(offset+1) < ymin) + ymin = vdata.get(offset+1); + + if (vdata.get(offset+2) > zmax) + zmax = vdata.get(offset+2); + if (vdata.get(offset+2) < zmin) + zmin = vdata.get(offset+2); + + offset += stride; + } + + geoBounds.setUpper(xmax, ymax, zmax); + geoBounds.setLower(xmin, ymin, zmin); + boundsDirty = false; + } + } + + + // compute bounding box for coord with noi buffer + void computeBoundingBox( DoubleBufferWrapper buffer) { + int i, j, k, sIndex; + double xmin, xmax, ymin, ymax, zmin, zmax; + + synchronized(geoBounds) { + // If autobounds compute is false then return + if ((computeGeoBounds == 0) && (refCount > 0)) { + return; + } + + if (!boundsDirty) + return; + + sIndex = initialCoordIndex; + int maxIndex = 3*validVertexCount; + + // Compute the bounding box + xmin = xmax = buffer.get(sIndex++); + ymin = ymax = buffer.get(sIndex++); + zmin = zmax = buffer.get(sIndex++); + + for (i=sIndex; i xmax) + xmax = buffer.get(i); + if (buffer.get(i) < xmin) + xmin = buffer.get(i); + + if (buffer.get(j) > ymax) + ymax = buffer.get(j); + if (buffer.get(j) < ymin) + ymin = buffer.get(j); + + if (buffer.get(k) > zmax) + zmax = buffer.get(k); + if (buffer.get(k) < zmin) + zmin = buffer.get(k); + + } + geoBounds.setUpper(xmax, ymax, zmax); + geoBounds.setLower(xmin, ymin, zmin); + boundsDirty = false; + } + } + + // compute bounding box for coord with noi buffer + void computeBoundingBox( FloatBufferWrapper buffer) { + int i, j, k, sIndex; + double xmin, xmax, ymin, ymax, zmin, zmax; + + + synchronized(geoBounds) { + // If autobounds compute is false then return + if ((computeGeoBounds == 0) && (refCount > 0)) { + return; + } + + if (!boundsDirty) + return; + + + sIndex = initialCoordIndex; + int maxIndex = 3*validVertexCount; + + // Compute the bounding box + xmin = xmax = buffer.get(sIndex++); + ymin = ymax = buffer.get(sIndex++); + zmin = zmax = buffer.get(sIndex++); + + for (i=sIndex; i xmax) + xmax = buffer.get(i); + if (buffer.get(i) < xmin) + xmin = buffer.get(i); + + if (buffer.get(j) > ymax) + ymax = buffer.get(j); + if (buffer.get(j) < ymin) + ymin = buffer.get(j); + + if (buffer.get(k) > zmax) + zmax = buffer.get(k); + if (buffer.get(k) < zmin) + zmin = buffer.get(k); + + } + geoBounds.setUpper(xmax, ymax, zmax); + geoBounds.setLower(xmin, ymin, zmin); + boundsDirty = false; + } + } + + void computeBoundingBox(float[] coords) { + // System.err.println("GeometryArrayRetained : computeBoundingBox(float[] coords)"); + int i, j, k, sIndex; + double xmin, xmax, ymin, ymax, zmin, zmax; + + synchronized(geoBounds) { + // If autobounds compute is false then return + if ((computeGeoBounds == 0) && (refCount > 0)) { + return; + } + + if (!boundsDirty) + return; + + sIndex = initialCoordIndex; + int maxIndex = 3*validVertexCount; + + // Compute the bounding box + xmin = xmax = coords[sIndex++]; + ymin = ymax = coords[sIndex++]; + zmin = zmax = coords[sIndex++]; + + for (i=sIndex; i xmax) + xmax = coords[i]; + if (coords[i] < xmin) + xmin = coords[i]; + + if (coords[j] > ymax) + ymax = coords[j]; + if (coords[j] < ymin) + ymin = coords[j]; + + if (coords[k] > zmax) + zmax = coords[k]; + if (coords[k] < zmin) + zmin = coords[k]; + + } + geoBounds.setUpper(xmax, ymax, zmax); + // System.err.println("max(" + xmax + ", " + ymax + ", " + zmax + ")"); + geoBounds.setLower(xmin, ymin, zmin); + // System.err.println("min(" + xmin + ", " + ymin + ", " + zmin + ")"); + + boundsDirty = false; + } + + } + + void computeBoundingBox(double[] coords) { + int i, j, k, sIndex; + double xmin, xmax, ymin, ymax, zmin, zmax; + + synchronized(geoBounds) { + // If autobounds compute is false then return + if ((computeGeoBounds == 0) && (refCount > 0)) { + return; + } + + if (!boundsDirty) + return; + + + sIndex = initialCoordIndex; + int maxIndex = 3*validVertexCount; + + // Compute the bounding box + xmin = xmax = coords[sIndex++]; + ymin = ymax = coords[sIndex++]; + zmin = zmax = coords[sIndex++]; + + for (i=sIndex; i xmax) + xmax = coords[i]; + if (coords[i] < xmin) + xmin = coords[i]; + + if (coords[j] > ymax) + ymax = coords[j]; + if (coords[j] < ymin) + ymin = coords[j]; + + if (coords[k] > zmax) + zmax = coords[k]; + if (coords[k] < zmin) + zmin = coords[k]; + + } + geoBounds.setUpper(xmax, ymax, zmax); + geoBounds.setLower(xmin, ymin, zmin); + boundsDirty = false; + } + + } + + void computeBoundingBox(Point3f[] coords) { + + double xmin, xmax, ymin, ymax, zmin, zmax; + Point3f p; + + synchronized(geoBounds) { + // If autobounds compute is false then return + if ((computeGeoBounds == 0) && (refCount > 0)) { + return; + } + + if (!boundsDirty) + return; + + + + // Compute the bounding box + xmin = xmax = coords[initialCoordIndex].x; + ymin = ymax = coords[initialCoordIndex].y; + zmin = zmax = coords[initialCoordIndex].z; + + for (int i=initialCoordIndex+1; i xmax) xmax = p.x; + if (p.x < xmin) xmin = p.x; + + if (p.y > ymax) ymax = p.y; + if (p.y < ymin) ymin = p.y; + + if (p.z > zmax) zmax = p.z; + if (p.z < zmin) zmin = p.z; + + } + geoBounds.setUpper(xmax, ymax, zmax); + geoBounds.setLower(xmin, ymin, zmin); + boundsDirty = false; + } + + } + + void computeBoundingBox(Point3d[] coords) { + + double xmin, xmax, ymin, ymax, zmin, zmax; + Point3d p; + + synchronized(geoBounds) { + // If autobounds compute is false then return + if ((computeGeoBounds == 0) && (refCount > 0)) { + return; + } + + if (!boundsDirty) + return; + + + // Compute the bounding box + xmin = xmax = coords[initialCoordIndex].x; + ymin = ymax = coords[initialCoordIndex].y; + zmin = zmax = coords[initialCoordIndex].z; + + for (int i=initialCoordIndex+1; i xmax) xmax = p.x; + if (p.x < xmin) xmin = p.x; + + if (p.y > ymax) ymax = p.y; + if (p.y < ymin) ymin = p.y; + + if (p.z > zmax) zmax = p.z; + if (p.z < zmin) zmin = p.z; + + } + geoBounds.setUpper(xmax, ymax, zmax); + geoBounds.setLower(xmin, ymin, zmin); + boundsDirty = false; + } + + } + + + synchronized void update() { + } + + void setupMirrorVertexPointer(int vType) { + int i, index; + + switch (vType) { + case PF: + if (floatRefCoords == null) { + if ((vertexType & VERTEX_DEFINED) == PF) { + vertexType &= ~PF; + mirrorFloatRefCoords = null; + mirrorVertexAllocated &= ~PF; + } + } + else { + vertexType |= PF; + mirrorFloatRefCoords = floatRefCoords; + mirrorVertexAllocated &= ~PF; + } + + break; + case PD: + if (doubleRefCoords == null) { + if ((vertexType & VERTEX_DEFINED) == PD) { + mirrorDoubleRefCoords = null; + mirrorVertexAllocated &= ~PD; + vertexType &= ~PD; + } + vertexType &= ~PD; + } + else { + vertexType |= PD; + mirrorDoubleRefCoords = doubleRefCoords; + mirrorVertexAllocated &= ~PD; + } + + break; + case P3F: + if (p3fRefCoords == null) { + vertexType &= ~P3F; + // Don't set the mirrorFloatRefCoords to null, + // may be able to re-use + // mirrorFloatRefCoords = null; + } + else { + vertexType |= P3F; + + if ((mirrorVertexAllocated & PF) == 0) { + mirrorFloatRefCoords = new float[vertexCount * 3]; + mirrorVertexAllocated |= PF; + } + + index = initialCoordIndex * 3; + for ( i=initialCoordIndex; i= 0.0; + /* + System.err.println("updateAlphaInFloatRefColors ** : lastAlpha[screen] " + + lastAlpha[screen]); + + System.err.println("((colorChanged & (1<= 0.0; + /* + System.err.println("updateAlphaInByteRefColors ## : lastAlpha[screen] " + + lastAlpha[screen]); + + System.err.println("((colorChanged & (1< 0) { + for (int i = oldSize; i < screen+1; i++) { + cfData[i] = new float[stride * vertexCount]; + System.arraycopy(cfData[0], 0, cfData[i], 0, + stride * vertexCount); + lastAlpha[i] = lastAlpha[0]; + } + } + + mvertexData = cfData; + + // Issue 113 - since we copied the data from screen 0, we don't need + // to do any further special processing. + } + + assert lastAlpha[screen] >= 0.0; + + if ((colorChanged & (1<= 0.0; + + if ((colorChanged & (1<= 0 implies one pass for one texture unit state + + void execute(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale, + boolean updateAlpha, float alpha, + int screen, + boolean ignoreVertexColors) { + + int cdirty; + boolean useAlpha = false; + Object[] retVal; + + // Check for by-copy case + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + float[] vdata; + + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + // update the alpha values + retVal = updateAlphaInVertexData(cv, screen, alpha); + useAlpha = (retVal[0] == Boolean.TRUE); + vdata = (float[])retVal[1]; + + // D3D only + if (alpha != lastScreenAlpha) { + // handle multiple screen case + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + vdata = vertexData; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + // geomLock is get in MasterControl when + // RenderBin render the geometry. So it is safe + // just to set the dirty flag here + dirtyFlag = 0; + } + + Pipeline.getPipeline().execute(cv.ctx, + this, geoType, isNonUniformScale, + useAlpha, + ignoreVertexColors, + initialVertexIndex, + validVertexCount, + ((vertexFormat & GeometryArray.COLOR) != 0)?(vertexFormat|GeometryArray.COLOR_4):vertexFormat, + texCoordSetCount, texCoordSetMap, + (texCoordSetMap == null) ? 0 : texCoordSetMap.length, + texCoordSetMapOffset, + cv.numActiveTexUnit, + vertexAttrCount, vertexAttrSizes, + vdata, null, + cdirty); + } + + //By reference with java array + else if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { + // interleaved data + if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + if(interLeavedVertexData == null) + return; + + float[] cdata = null; + + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + // update the alpha values + retVal = updateAlphaInInterLeavedData(cv, screen, alpha); + useAlpha = (retVal[0] == Boolean.TRUE); + cdata = (float[])retVal[1]; + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + dirtyFlag = 0; + } + + Pipeline.getPipeline().execute(cv.ctx, + this, geoType, isNonUniformScale, + useAlpha, + ignoreVertexColors, + initialVertexIndex, + validVertexCount, + vertexFormat, + texCoordSetCount, texCoordSetMap, + (texCoordSetMap == null) ? 0 : texCoordSetMap.length, + texCoordSetMapOffset, + cv.numActiveTexUnit, + vertexAttrCount, vertexAttrSizes, + interLeavedVertexData, cdata, + cdirty); + + } // end of interleaved case + + // non interleaved data + else { + + // Check if a vertexformat is set, but the array is null + // if yes, don't draw anything + if ((vertexType == 0) || + ((vertexType & VERTEX_DEFINED) == 0) || + (((vertexFormat & GeometryArray.COLOR) != 0) && + (vertexType & COLOR_DEFINED) == 0) || + (((vertexFormat & GeometryArray.NORMALS) != 0) && + (vertexType & NORMAL_DEFINED) == 0) || + (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) && + (vertexType & VATTR_DEFINED) == 0) || + (((vertexFormat& GeometryArray.TEXTURE_COORDINATE) != 0) && + (vertexType & TEXCOORD_DEFINED) == 0)) { + return; + } else { + byte[] cbdata = null; + float[] cfdata = null; + + if ((vertexType & (CF | C3F | C4F )) != 0) { + + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + cfdata = updateAlphaInFloatRefColors(cv, screen, alpha); + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + cfdata = mirrorFloatRefColors[0]; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + + } + dirtyFlag = 0; + } + } // end of color in float format + else if ((vertexType & (CUB| C3UB | C4UB)) != 0) { + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + cbdata = updateAlphaInByteRefColors(cv, screen, alpha); + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + cbdata = mirrorUnsignedByteRefColors[0]; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + dirtyFlag = 0; + } + } // end of color in byte format + else { + cdirty = dirtyFlag; + } + // setup vdefined to passed to native code + int vdefined = 0; + if((vertexType & (PF | P3F)) != 0) + vdefined |= COORD_FLOAT; + if((vertexType & (PD | P3D)) != 0) + vdefined |= COORD_DOUBLE; + if((vertexType & (CF | C3F | C4F)) != 0) + vdefined |= COLOR_FLOAT; + if((vertexType & (CUB| C3UB | C4UB)) != 0) + vdefined |= COLOR_BYTE; + if((vertexType & NORMAL_DEFINED) != 0) + vdefined |= NORMAL_FLOAT; + if((vertexType & VATTR_DEFINED) != 0) + vdefined |= VATTR_FLOAT; + if((vertexType & TEXCOORD_DEFINED) != 0) + vdefined |= TEXCOORD_FLOAT; + + Pipeline.getPipeline().executeVA(cv.ctx, + this, geoType, isNonUniformScale, + ignoreVertexColors, + validVertexCount, + (vertexFormat | c4fAllocated), + vdefined, + initialCoordIndex, + mirrorFloatRefCoords, mirrorDoubleRefCoords, + initialColorIndex, cfdata, cbdata, + initialNormalIndex, mirrorFloatRefNormals, + vertexAttrCount, vertexAttrSizes, + initialVertexAttrIndex, mirrorFloatRefVertexAttrs, + ((texCoordSetMap == null) ? 0:texCoordSetMap.length), + texCoordSetMap, + cv.numActiveTexUnit, + initialTexCoordIndex,texCoordStride, + mirrorRefTexCoords, cdirty); + }// end of all vertex data being set + }// end of non interleaved case + }// end of by reference with java array + + //By reference with nio buffer + else { + // interleaved data + if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + + if ( interleavedFloatBufferImpl == null) + return; + + float[] cdata = null; + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + // update the alpha values + // XXXX: to handle alpha case + retVal = updateAlphaInInterLeavedData(cv, screen, alpha); + useAlpha = (retVal[0] == Boolean.TRUE); + cdata = (float[])retVal[1]; + + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + // XXXX: to handle alpha case + cdata = null; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + dirtyFlag = 0; + } + + Pipeline.getPipeline().executeInterleavedBuffer(cv.ctx, + this, geoType, isNonUniformScale, + useAlpha, + ignoreVertexColors, + initialVertexIndex, + validVertexCount, + vertexFormat, + texCoordSetCount, texCoordSetMap, + (texCoordSetMap == null) ? 0 : texCoordSetMap.length, + texCoordSetMapOffset, + cv.numActiveTexUnit, + interleavedFloatBufferImpl.getBufferAsObject(), cdata, + cdirty); + + } // end of interleaved case + + // non interleaved data + else { + + // Check if a vertexformat is set, but the array is null + // if yes, don't draw anything + if ((vertexType == 0) || + ((vertexType & VERTEX_DEFINED) == 0) || + (((vertexFormat & GeometryArray.COLOR) != 0) && + (vertexType & COLOR_DEFINED) == 0) || + (((vertexFormat & GeometryArray.NORMALS) != 0) && + (vertexType & NORMAL_DEFINED) == 0) || + (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) && + (vertexType & VATTR_DEFINED) == 0) || + (((vertexFormat& GeometryArray.TEXTURE_COORDINATE) != 0) && + (vertexType & TEXCOORD_DEFINED) == 0)) { + return; + } else { + byte[] cbdata = null; + float[] cfdata = null; + + if ((vertexType & CF ) != 0) { + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + cfdata = updateAlphaInFloatRefColors(cv, + screen, alpha); + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + // XXXX: handle transparency case + //cfdata = null; + cfdata = mirrorFloatRefColors[0]; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + + } + dirtyFlag = 0; + } + } // end of color in float format + else if ((vertexType & CUB) != 0) { + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + cbdata = updateAlphaInByteRefColors( + cv, screen, alpha); + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + // XXXX: handle transparency case + //cbdata = null; + cbdata = mirrorUnsignedByteRefColors[0]; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + dirtyFlag = 0; + } + } // end of color in byte format + else { + cdirty = dirtyFlag; + } + + Object vcoord = null, cdataBuffer=null, normal=null; + + int vdefined = 0; + if((vertexType & PF) != 0) { + vdefined |= COORD_FLOAT; + vcoord = floatBufferRefCoords.getBufferAsObject(); + } else if((vertexType & PD ) != 0) { + vdefined |= COORD_DOUBLE; + vcoord = doubleBufferRefCoords.getBufferAsObject(); + } + + if((vertexType & CF ) != 0) { + vdefined |= COLOR_FLOAT; + cdataBuffer = floatBufferRefColors.getBufferAsObject(); + } else if((vertexType & CUB) != 0) { + vdefined |= COLOR_BYTE; + cdataBuffer = byteBufferRefColors.getBufferAsObject(); + } + + if((vertexType & NORMAL_DEFINED) != 0) { + vdefined |= NORMAL_FLOAT; + normal = floatBufferRefNormals.getBufferAsObject(); + } + + if ((vertexType & VATTR_DEFINED) != 0) { + vdefined |= VATTR_FLOAT; + } + + if((vertexType & TEXCOORD_DEFINED) != 0) + vdefined |= TEXCOORD_FLOAT; + + Pipeline.getPipeline().executeVABuffer(cv.ctx, + this, geoType, isNonUniformScale, + ignoreVertexColors, + validVertexCount, + (vertexFormat | c4fAllocated), + vdefined, + initialCoordIndex, + vcoord, + initialColorIndex, + cdataBuffer, + cfdata, cbdata, + initialNormalIndex, + normal, + vertexAttrCount, vertexAttrSizes, + initialVertexAttrIndex, + nioFloatBufferRefVertexAttrs, + ((texCoordSetMap == null) ? 0:texCoordSetMap.length), + texCoordSetMap, + cv.numActiveTexUnit, + initialTexCoordIndex,texCoordStride, + refTexCoords, cdirty); + }// end of all vertex data being set + }// end of non interleaved case + }// end of by reference with nio-buffer case + } + + void buildGA(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale, + boolean updateAlpha, float alpha, boolean ignoreVertexColors, + Transform3D xform, Transform3D nxform) { + + float[] vdata = null; + + // NIO buffers are no longer supported in display lists + assert (vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0; + + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + vdata = vertexData; + } + else if ((vertexFormat & GeometryArray.INTERLEAVED) != 0 && + ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0)) { + vdata = interLeavedVertexData; + } + if (vdata != null) { + /* + System.err.println("calling native buildGA()"); + System.err.println("geoType = "+geoType+" initialVertexIndex = "+initialVertexIndex+" validVertexCount = "+validVertexCount+" vertexFormat = "+vertexFormat+" vertexData = "+vertexData); + */ + Pipeline.getPipeline().buildGA(cv.ctx, + this, geoType, isNonUniformScale, + updateAlpha, alpha, ignoreVertexColors, + initialVertexIndex, + validVertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + (texCoordSetMap == null) ? 0 : texCoordSetMap.length, + texCoordSetMapOffset, + vertexAttrCount, vertexAttrSizes, + (xform == null) ? null : xform.mat, + (nxform == null) ? null : nxform.mat, + vdata); + } + else { + // Check if a vertexformat is set, but the array is null + // if yes, don't draw anything + if ((vertexType == 0) || + ((vertexType & VERTEX_DEFINED) == 0) || + (((vertexFormat & GeometryArray.COLOR) != 0) && + (vertexType & COLOR_DEFINED) == 0) || + (((vertexFormat & GeometryArray.NORMALS) != 0) && + (vertexType & NORMAL_DEFINED) == 0) || + (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) && + (vertexType & VATTR_DEFINED) == 0) || + (((vertexFormat& GeometryArray.TEXTURE_COORDINATE) != 0) && + (vertexType & TEXCOORD_DEFINED) == 0)) { + + return; + } + + // Either non-interleaved, by-ref or nio buffer + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { + // Java array case + // setup vdefined to passed to native code + int vdefined = 0; + if((vertexType & (PF | P3F)) != 0) + vdefined |= COORD_FLOAT; + if((vertexType & (PD | P3D)) != 0) + vdefined |= COORD_DOUBLE; + if((vertexType & (CF | C3F | C4F)) != 0) + vdefined |= COLOR_FLOAT; + if((vertexType & (CUB| C3UB | C4UB)) != 0) + vdefined |= COLOR_BYTE; + if((vertexType & NORMAL_DEFINED) != 0) + vdefined |= NORMAL_FLOAT; + if((vertexType & VATTR_DEFINED) != 0) + vdefined |= VATTR_FLOAT; + if((vertexType & TEXCOORD_DEFINED) != 0) + vdefined |= TEXCOORD_FLOAT; + + Pipeline.getPipeline().buildGAForByRef(cv.ctx, + this, geoType, isNonUniformScale, + updateAlpha, alpha, + ignoreVertexColors, + validVertexCount, + vertexFormat, + vdefined, + initialCoordIndex, + mirrorFloatRefCoords, mirrorDoubleRefCoords, + initialColorIndex, mirrorFloatRefColors[0], mirrorUnsignedByteRefColors[0], + initialNormalIndex, mirrorFloatRefNormals, + vertexAttrCount, vertexAttrSizes, + initialVertexAttrIndex, mirrorFloatRefVertexAttrs, + ((texCoordSetMap == null) ? 0:texCoordSetMap.length), + texCoordSetMap, + initialTexCoordIndex,texCoordStride, + mirrorRefTexCoords, + (xform == null) ? null : xform.mat, + (nxform == null) ? null : nxform.mat); + } + /* + // NOTE: NIO buffers are no longer supported in display lists. + // This was never enabled by default anyway (only when the + // optimizeForSpace property was set to false), so it wasn't + // well-tested. If future support is desired, we will need to + // add vertex attributes to buildGAForBuffer. There are no plans + // to ever do this. + else { + // NIO Buffer case + Object vcoord = null, cdataBuffer=null, normal=null; + + int vdefined = 0; + if((vertexType & PF) != 0) { + vdefined |= COORD_FLOAT; + vcoord = floatBufferRefCoords.getBufferAsObject(); + } else if((vertexType & PD ) != 0) { + vdefined |= COORD_DOUBLE; + vcoord = doubleBufferRefCoords.getBufferAsObject(); + } + + if((vertexType & CF ) != 0) { + vdefined |= COLOR_FLOAT; + cdataBuffer = floatBufferRefColors.getBufferAsObject(); + } else if((vertexType & CUB) != 0) { + vdefined |= COLOR_BYTE; + cdataBuffer = byteBufferRefColors.getBufferAsObject(); + } + + if((vertexType & NORMAL_DEFINED) != 0) { + vdefined |= NORMAL_FLOAT; + normal = floatBufferRefNormals.getBufferAsObject(); + } + + if((vertexType & TEXCOORD_DEFINED) != 0) + vdefined |= TEXCOORD_FLOAT; + // NOTE : need to add vertex attrs + Pipeline.getPipeline().buildGAForBuffer(cv.ctx, + this, geoType, isNonUniformScale, + updateAlpha, alpha, + ignoreVertexColors, + validVertexCount, + vertexFormat, + vdefined, + initialCoordIndex, + vcoord, + initialColorIndex,cdataBuffer, + initialNormalIndex, normal, + ((texCoordSetMap == null) ? 0:texCoordSetMap.length), + texCoordSetMap, + initialTexCoordIndex,texCoordStride, + refTexCoords, + (xform == null) ? null : xform.mat, + (nxform == null) ? null : nxform.mat); + } + */ + + } + + } + + void unIndexify(IndexedGeometryArrayRetained src) { + if ((src.vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { + unIndexifyJavaArray(src); + } + else { + unIndexifyNIOBuffer(src); + } + } + + private void unIndexifyJavaArray(IndexedGeometryArrayRetained src) { +// System.err.println("unIndexifyJavaArray"); + + int vOffset = 0, srcOffset, tOffset = 0; + int index, colorStride = 0; + float[] vdata = null; + int i; + int start, end; + start = src.initialIndexIndex; + end = src.initialIndexIndex + src.validIndexCount; + // If its either "normal" data or interleaved data then .. + if (((src.vertexFormat & GeometryArray.BY_REFERENCE) == 0) || + ((src.vertexFormat & GeometryArray.INTERLEAVED) != 0)) { + + if ((src.vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + vdata = src.vertexData; + if ((src.vertexFormat & GeometryArray.COLOR) != 0) + colorStride = 4; + } + else if ((src.vertexFormat & GeometryArray.INTERLEAVED) != 0) { + vdata = src.interLeavedVertexData; + if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + colorStride = 4; + else if ((src.vertexFormat & GeometryArray.COLOR) != 0) + colorStride = 3; + } + + // System.err.println("===> start = "+start+" end = "+end); + for (index= start; index < end; index++) { + if ((vertexFormat & GeometryArray.NORMALS) != 0){ + System.arraycopy(vdata, + src.indexNormal[index]*src.stride + src.normalOffset, + vertexData, vOffset + normalOffset, 3); + } + if (colorStride == 4){ + // System.err.println("===> copying color3"); + System.arraycopy(vdata, + src.indexColor[index]*src.stride + src.colorOffset, + vertexData, vOffset + colorOffset, colorStride); + } else if (colorStride == 3) { + // System.err.println("===> copying color4"); + System.arraycopy(vdata, + src.indexColor[index]*src.stride + src.colorOffset, + vertexData, vOffset + colorOffset, colorStride); + vertexData[vOffset + colorOffset + 3] = 1.0f; + } + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + int tcOffset = vOffset + textureOffset; + int interleavedOffset = 0; + + for (i = 0; i < texCoordSetCount; + i++, tcOffset += texCoordStride) { + + if ((src.vertexFormat & GeometryArray.INTERLEAVED) != 0) { + interleavedOffset = i * texCoordStride; + } + + System.arraycopy(vdata, + (src.indexTexCoord[i][index])*src.stride + src.textureOffset + interleavedOffset, + vertexData, tcOffset, texCoordStride); + } + } + + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + // vertex attributes can't be interleaved + assert (src.vertexFormat & GeometryArray.INTERLEAVED) == 0; + + for (i = 0; i < vertexAttrCount; i++) { + int vaOffset = vOffset + vertexAttrOffsets[i]; + + System.arraycopy(vdata, + (src.indexVertexAttr[i][index])*src.stride + src.vertexAttrOffsets[i], + vertexData, vaOffset, vertexAttrSizes[i]); + } + } + + if ((vertexFormat & GeometryArray.COORDINATES) != 0){ + // System.err.println("===> copying coords"); + System.arraycopy(vdata, + src.indexCoord[index]*src.stride + + src.coordinateOffset, + vertexData, + vOffset + coordinateOffset, 3); + } + vOffset += stride; + } + + } else { + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + vOffset = normalOffset; + switch ((src.vertexType & NORMAL_DEFINED)) { + case NF: + for (index=start; index < end; index++) { + System.arraycopy(src.floatRefNormals, + src.indexNormal[index]*3, + vertexData, + vOffset, 3); + vOffset += stride; + } + break; + case N3F: + for (index=start; index < end; index++) { + srcOffset = src.indexNormal[index]; + vertexData[vOffset] = src.v3fRefNormals[srcOffset].x; + vertexData[vOffset+1] = src.v3fRefNormals[srcOffset].y; + vertexData[vOffset+2] = src.v3fRefNormals[srcOffset].z; + vOffset += stride; + } + break; + default: + break; + } + } + + if ((vertexFormat & GeometryArray.COLOR) != 0) { + vOffset = colorOffset; + int multiplier = 3; + if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + multiplier = 4; + + switch ((src.vertexType & COLOR_DEFINED)) { + case CF: + for (index=start; index < end; index++) { + if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) { + System.arraycopy(src.floatRefColors, + src.indexColor[index]*multiplier, + vertexData, + vOffset, 4); + } + else { + System.arraycopy(src.floatRefColors, + src.indexColor[index]*multiplier, + vertexData, + vOffset, 3); + vertexData[vOffset+3] = 1.0f; + } + vOffset += stride; + } + break; + case CUB: + for (index=start; index < end; index++) { + srcOffset = src.indexColor[index] * multiplier; + vertexData[vOffset] = (src.byteRefColors[srcOffset] & 0xff) * ByteToFloatScale; + vertexData[vOffset+1] = (src.byteRefColors[srcOffset+1] & 0xff) * ByteToFloatScale; + vertexData[vOffset+2] = (src.byteRefColors[srcOffset+2] & 0xff) * ByteToFloatScale; + if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) { + vertexData[vOffset+3] = (src.byteRefColors[srcOffset+3] & 0xff) * ByteToFloatScale; + } + else { + vertexData[vOffset+3] = 1.0f; + } + vOffset += stride; + } + break; + case C3F: + for (index=start; index < end; index++) { + srcOffset = src.indexColor[index]; + vertexData[vOffset] = src.c3fRefColors[srcOffset].x; + vertexData[vOffset+1] = src.c3fRefColors[srcOffset].y; + vertexData[vOffset+2] = src.c3fRefColors[srcOffset].z; + vertexData[vOffset+3] = 1.0f; + vOffset += stride; + } + break; + case C4F: + for (index=start; index < end; index++) { + srcOffset = src.indexColor[index]; + vertexData[vOffset] = src.c4fRefColors[srcOffset].x; + vertexData[vOffset+1] = src.c4fRefColors[srcOffset].y; + vertexData[vOffset+2] = src.c4fRefColors[srcOffset].z; + vertexData[vOffset+3] = src.c4fRefColors[srcOffset].w; + vOffset += stride; + } + break; + case C3UB: + for (index=start; index < end; index++) { + srcOffset = src.indexColor[index]; + vertexData[vOffset] = (src.c3bRefColors[srcOffset].x & 0xff) * ByteToFloatScale; + vertexData[vOffset+1] = (src.c3bRefColors[srcOffset].y & 0xff) * ByteToFloatScale; + vertexData[vOffset+2] = (src.c3bRefColors[srcOffset].z & 0xff) * ByteToFloatScale; + vertexData[vOffset+3] = 1.0f; + vOffset += stride; + } + break; + case C4UB: + for (index=start; index < end; index++) { + srcOffset = src.indexColor[index]; + vertexData[vOffset] = (src.c4bRefColors[srcOffset].x & 0xff) * ByteToFloatScale; + vertexData[vOffset+1] = (src.c4bRefColors[srcOffset].y & 0xff) * ByteToFloatScale; + vertexData[vOffset+2] = (src.c4bRefColors[srcOffset].z & 0xff) * ByteToFloatScale; + vertexData[vOffset+3] = (src.c4bRefColors[srcOffset].w & 0xff) * ByteToFloatScale; + vOffset += stride; + } + break; + default: + break; + } + } + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + vOffset = textureOffset; + switch ((src.vertexType & TEXCOORD_DEFINED)) { + case TF: + for (index=start; index < end; index++) { + for (i = 0, tOffset = vOffset; + i < texCoordSetCount; i++) { + System.arraycopy(src.refTexCoords[i], + src.indexTexCoord[i][index]*texCoordStride, + vertexData, tOffset, texCoordStride); + tOffset += texCoordStride; + } + vOffset += stride; + } + break; + case T2F: + for (index=start; index < end; index++) { + for (i = 0, tOffset = vOffset; + i < texCoordSetCount; i++) { + srcOffset = src.indexTexCoord[i][index]; + vertexData[tOffset] = + ((TexCoord2f[])src.refTexCoords[i])[srcOffset].x; + vertexData[tOffset+1] = + ((TexCoord2f[])src.refTexCoords[i])[srcOffset].y; + tOffset += texCoordStride; + } + vOffset += stride; + } + break; + case T3F: + for (index=start; index < end; index++) { + for (i = 0, tOffset = vOffset; + i < texCoordSetCount; i++) { + srcOffset = src.indexTexCoord[i][index]; + vertexData[tOffset] = + ((TexCoord3f[])src.refTexCoords[i])[srcOffset].x; + vertexData[tOffset+1] = + ((TexCoord3f[])src.refTexCoords[i])[srcOffset].y; + vertexData[tOffset+2] = + ((TexCoord3f[])src.refTexCoords[i])[srcOffset].z; + tOffset += texCoordStride; + } + vOffset += stride; + } + break; + default: + break; + } + } + + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + vOffset = 0; + switch (src.vertexType & VATTR_DEFINED) { + case AF: + for (index=start; index < end; index++) { + for (i = 0; i < vertexAttrCount; i++) { + int vaOffset = vOffset + vertexAttrOffsets[i]; + System.arraycopy(src.floatRefVertexAttrs[i], + src.indexVertexAttr[i][index]*vertexAttrSizes[i], + vertexData, vaOffset, vertexAttrSizes[i]); + } + vOffset += stride; + } + break; + } + } + + if ((vertexFormat & GeometryArray.COORDINATES) != 0) { + vOffset = coordinateOffset; + switch ((src.vertexType & VERTEX_DEFINED)) { + case PF: + for (index=start; index < end; index++) { + System.arraycopy(src.floatRefCoords, + src.indexCoord[index]*3, + vertexData, + vOffset, 3); + vOffset += stride; + } + break; + case PD: + for (index=start; index < end; index++) { + srcOffset = src.indexCoord[index] * 3; + vertexData[vOffset] = (float)src.doubleRefCoords[srcOffset]; + vertexData[vOffset+1] = (float)src.doubleRefCoords[srcOffset+1]; + vertexData[vOffset+2] = (float)src.doubleRefCoords[srcOffset+2]; + vOffset += stride; + } + break; + case P3F: + for (index=start; index < end; index++) { + srcOffset = src.indexCoord[index]; + vertexData[vOffset] = src.p3fRefCoords[srcOffset].x; + vertexData[vOffset+1] = src.p3fRefCoords[srcOffset].y; + vertexData[vOffset+2] = src.p3fRefCoords[srcOffset].z; + vOffset += stride; + } + break; + case P3D: + for (index=start; index < end; index++) { + srcOffset = src.indexCoord[index]; + vertexData[vOffset] = (float)src.p3dRefCoords[srcOffset].x; + vertexData[vOffset+1] = (float)src.p3dRefCoords[srcOffset].y; + vertexData[vOffset+2] = (float)src.p3dRefCoords[srcOffset].z; + vOffset += stride; + } + break; + default: + break; + } + } + + } + } + + + private void unIndexifyNIOBuffer(IndexedGeometryArrayRetained src) { +// System.err.println("unIndexifyNIOBuffer"); + + int vOffset = 0, srcOffset, tOffset = 0; + int index, colorStride = 0; + float[] vdata = null; + int i; + int start, end; + start = src.initialIndexIndex; + end = src.initialIndexIndex + src.validIndexCount; + // If its interleaved data then .. + if ((src.vertexFormat & GeometryArray.INTERLEAVED) != 0) { + if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + colorStride = 4; + else if ((src.vertexFormat & GeometryArray.COLOR) != 0) + colorStride = 3; + + // System.err.println("===> start = "+start+" end = "+end); + for (index= start; index < end; index++) { + if ((vertexFormat & GeometryArray.NORMALS) != 0){ + src.interleavedFloatBufferImpl.position(src.indexNormal[index]*src.stride + src.normalOffset); + src.interleavedFloatBufferImpl.get(vertexData, vOffset + normalOffset, 3); + } + + if (colorStride == 4){ + src.interleavedFloatBufferImpl.position(src.indexColor[index]*src.stride + src.colorOffset); + src.interleavedFloatBufferImpl.get(vertexData, vOffset + colorOffset, colorStride); + } else if (colorStride == 3) { + src.interleavedFloatBufferImpl.position(src.indexColor[index]*src.stride + src.colorOffset); + src.interleavedFloatBufferImpl.get(vertexData, vOffset + colorOffset, colorStride); + vertexData[vOffset + colorOffset + 3] = 1.0f; + } + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + int tcOffset = vOffset + textureOffset; + for (i = 0; i < texCoordSetCount; + i++, tcOffset += texCoordStride) { + + src.interleavedFloatBufferImpl.position((src.indexTexCoord[i][index])*src.stride + + src.textureOffset); + src.interleavedFloatBufferImpl.get(vertexData, tcOffset, texCoordStride); + } + } + if ((vertexFormat & GeometryArray.COORDINATES) != 0){ + src.interleavedFloatBufferImpl.position(src.indexCoord[index]*src.stride + src.coordinateOffset ); + src.interleavedFloatBufferImpl.get(vertexData, vOffset + coordinateOffset, 3); + } + vOffset += stride; + } + + } else { + if ((vertexFormat & GeometryArray.NORMALS) != 0){ + vOffset = normalOffset; + if ((src.vertexType & NORMAL_DEFINED) != 0) { + for (index=start; index < end; index++) { + src.floatBufferRefNormals.position(src.indexNormal[index]*3); + src.floatBufferRefNormals.get(vertexData, vOffset, 3); + vOffset += stride; + } + } + } + + if ((vertexFormat & GeometryArray.COLOR) != 0){ + vOffset = colorOffset; + int multiplier = 3; + if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + multiplier = 4; + + switch ((src.vertexType & COLOR_DEFINED)) { + case CF: + for (index=start; index < end; index++) { + if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) { + src.floatBufferRefColors.position(src.indexColor[index]*multiplier); + src.floatBufferRefColors.get(vertexData, vOffset, 4); + } + else { + src.floatBufferRefColors.position(src.indexColor[index]*multiplier); + src.floatBufferRefColors.get(vertexData, vOffset, 3); + vertexData[vOffset+3] = 1.0f; + } + vOffset += stride; + } + break; + case CUB: + for (index=start; index < end; index++) { + srcOffset = src.indexColor[index] * multiplier; + vertexData[vOffset] = (src.byteBufferRefColors.get(srcOffset) & 0xff) * ByteToFloatScale; + vertexData[vOffset+1] = (src.byteBufferRefColors.get(srcOffset+1) & 0xff) * ByteToFloatScale; + vertexData[vOffset+2] = (src.byteBufferRefColors.get(srcOffset+2) & 0xff) * ByteToFloatScale; + + if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) { + vertexData[vOffset+3] = (src.byteBufferRefColors.get(srcOffset+3) & 0xff) * ByteToFloatScale; + } + else { + vertexData[vOffset+3] = 1.0f; + } + vOffset += stride; + } + break; + default: + break; + } + } + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + vOffset = textureOffset; + FloatBufferWrapper texBuffer; + if ((src.vertexType & TEXCOORD_DEFINED) != 0) { + for (index=start; index < end; index++) { + for (i = 0, tOffset = vOffset; + i < texCoordSetCount; i++) { + texBuffer = (FloatBufferWrapper)(((J3DBuffer) (src.refTexCoordsBuffer[i])).getBufferImpl()); + texBuffer.position(src.indexTexCoord[i][index]*texCoordStride); + texBuffer.get(vertexData, tOffset, texCoordStride); + tOffset += texCoordStride; + } + vOffset += stride; + } + } + } + + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + vOffset = 0; + if ((src.vertexType & VATTR_DEFINED) == AF) { + for (index=start; index < end; index++) { + for (i = 0; i < vertexAttrCount; i++) { + int vaOffset = vOffset + vertexAttrOffsets[i]; + FloatBufferWrapper vaBuffer = src.floatBufferRefVertexAttrs[i]; + vaBuffer.position(src.indexVertexAttr[i][index]*vertexAttrSizes[i]); + vaBuffer.get(vertexData, vaOffset, vertexAttrSizes[i]); + } + vOffset += stride; + } + } + } + + if ((vertexFormat & GeometryArray.COORDINATES) != 0){ + vOffset = coordinateOffset; + switch ((src.vertexType & VERTEX_DEFINED)) { + case PF: + for (index=start; index < end; index++) { + src.floatBufferRefCoords.position(src.indexCoord[index]*3); + src.floatBufferRefCoords.get(vertexData, vOffset, 3); + vOffset += stride; + } + break; + case PD: + for (index=start; index < end; index++) { + srcOffset = src.indexCoord[index] * 3; + vertexData[vOffset] = (float)src.doubleBufferRefCoords.get(srcOffset); + vertexData[vOffset+1] = (float)src.doubleBufferRefCoords.get(srcOffset+1); + vertexData[vOffset+2] = (float)src.doubleBufferRefCoords.get(srcOffset+2); + vOffset += stride; + } + break; + default: + break; + } + } + + } + } + + + /** + * Returns the vertex stride in numbers of floats as a function + * of the vertexFormat. + * @return the stride in floats for this vertex array + */ + int stride() + { + int stride = 0; + + if((this.vertexFormat & GeometryArray.COORDINATES) != 0) stride += 3; + if((this.vertexFormat & GeometryArray.NORMALS) != 0) stride += 3; + + if ((this.vertexFormat & GeometryArray.COLOR) != 0) { + if ((this.vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + // By copy + stride += 4; + } else { + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) == 0) { + stride += 3; + } + else { + stride += 4; + } + } + } + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + + if ((this.vertexFormat & + GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texCoordStride = 2; + } else if ((this.vertexFormat & + GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texCoordStride = 3; + } else if ((this.vertexFormat & + GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texCoordStride = 4; + } + + stride += texCoordStride * texCoordSetCount; + } + + if ((this.vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + stride += vertexAttrStride; + } + + //System.err.println("stride() = " + stride); + return stride; + } + + int[] texCoordSetMapOffset() + { + if (texCoordSetMap == null) + return null; + + texCoordSetMapOffset = new int[texCoordSetMap.length]; + for (int i = 0; i < texCoordSetMap.length; i++) { + if (texCoordSetMap[i] == -1) { + texCoordSetMapOffset[i] = -1; + } else { + texCoordSetMapOffset[i] = texCoordSetMap[i] * texCoordStride; + } + } + return texCoordSetMapOffset; + } + + /** + * Returns the stride of the set of vertex attributes. This is the + * sum of the sizes of each vertex attribute. + * @return the stride of the vertex attribute data + */ + int vertexAttrStride() { + int sum = 0; + for (int i = 0; i < vertexAttrCount; i++) { + sum += vertexAttrSizes[i]; + } + return sum; + } + + /** + * Returns the offset in number of floats from the start of a vertex to + * each per-vertex vertex attribute. + * @return array of offsets in floats vertex start to the vertex attribute data + */ + int[] vertexAttrOffsets() { + int[] offsets; + + // Create array of offsets to the start of each vertex attribute. + // The offset of the first attribute is always 0. If no vertex attributes exist, + // then we will allocate an array of length 1 to avoid some checking elsewhere. + if (vertexAttrCount > 0) { + offsets = new int[vertexAttrCount]; + } + else { + offsets = new int[1]; + } + offsets[0] = 0; + for (int i = 1; i < vertexAttrCount; i++) { + offsets[i] = offsets[i-1] + vertexAttrSizes[i-1]; + } + + return offsets; + } + + /** + * Returns the offset in number of floats from the start of a vertex to + * the per-vertex texture coordinate data. + * texture coordinate data always follows vertex attribute data + * @return the offset in floats vertex start to the tetxure data + */ + int textureOffset() + { + int offset = vertexAttrOffsets[0]; + + if ((this.vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + offset += vertexAttrStride; + } + + return offset; + } + + /** + * Returns the offset in number of floats from the start of a vertex to + * the per-vertex color data. + * color data always follows texture data + * @param vertexFormat the vertex format for this array + * @return the offset in floats vertex start to the color data + */ + int colorOffset() + { + int offset = textureOffset; + + if((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) + offset += 2 * texCoordSetCount; + else if((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) + offset += 3 * texCoordSetCount; + else if((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) + offset += 4 * texCoordSetCount; + + return offset; + } + + /** + * Returns the offset in number of floats from the start of a vertex to + * the per-vertex normal data. + * normal data always follows color data + * @return the offset in floats from the start of a vertex to the normal + */ + int normalOffset() + { + int offset = colorOffset; + + if ((this.vertexFormat & GeometryArray.COLOR) != 0) { + if ((this.vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + offset += 4; + } else { + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) == 0) { + offset += 3; + } + else { + offset += 4; + } + } + } + return offset; + } + + /** + * Returns the offset in number of floats from the start of a vertex to + * the per vertex coordinate data. + * @return the offset in floats vertex start to the coordinate data + */ + int coordinateOffset() + { + int offset = normalOffset; + + if ((this.vertexFormat & GeometryArray.NORMALS) != 0) offset += 3; + return offset; + } + + /** + * Returns number of vertices in the GeometryArray + * @return vertexCount number of vertices in the GeometryArray + */ + int getVertexCount(){ + return vertexCount; + } + + /** + * Returns vertexFormat in the GeometryArray + * @return vertexFormat format of vertices in the GeometryArray + */ + int getVertexFormat(){ + return vertexFormat; + } + + /** + * Retrieves the number of vertex attributes in this GeometryArray + * object. + * + * @return the number of vertex attributes in this GeometryArray + * object + */ + int getVertexAttrCount() { + return vertexAttrCount; + } + + + /** + * Retrieves the vertex attribute sizes array from this + * GeometryArray object. + * + * @param vertexAttrSizes an array that will receive a copy of + * the vertex attribute sizes array. The array must hold at least + * vertexAttrCount elements. + */ + void getVertexAttrSizes(int[] vertexAttrSizes) { + for (int i = 0; i < vertexAttrCount; i++) { + vertexAttrSizes[i] = this.vertexAttrSizes[i]; + } + } + + + + void sendDataChangedMessage(boolean coordinatesChanged) { + J3dMessage[] m; + int i, j, k, index, numShapeMessages, numMorphMessages; + ArrayList shapeList; + Shape3DRetained s; + ArrayList morphList; + MorphRetained morph; + + synchronized(liveStateLock) { + if (source != null && source.isLive()) { + // System.err.println("In GeometryArrayRetained - "); + + // Send a message to renderBin to rebuild the display list or + // process the vertex array accordingly + // XXXX: Should I send one per universe, isn't display list + // shared by all context/universes? + int threads = J3dThread.UPDATE_RENDER; + // If the geometry type is Indexed then we need to clone the geometry + // We also need to update the cachedChangedFrequent flag + threads |= J3dThread.UPDATE_RENDERING_ATTRIBUTES; + + synchronized (universeList) { + numShapeMessages = universeList.size(); + m = new J3dMessage[numShapeMessages]; + + k = 0; + + for (i = 0; i < numShapeMessages; i++, k++) { + gaList.clear(); + + shapeList = (ArrayList)userLists.get(i); + for (j=0; j 0) { + synchronized (morphUniverseList) { + for (i = 0; i < numMorphMessages; i++, k++) { + morphList = (ArrayList)morphUserLists.get(i); + for (j=0; jstart for length vertices. + * @param index the vertex index + * @param coordinates an array of vectors containing new coordinates + * @param start starting vertex index of data in coordinates . + * @param length number of vertices to be copied. + */ + void setCoordinates(int index, float coordinates[], int start, int length) { + int offset = this.stride * index + coordinateOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + for (i= start * 3, j= offset; i < (start+length) * 3; + i+=3, j+= this.stride) { + this.vertexData[j] = coordinates[i]; + this.vertexData[j+1]= coordinates[i+1]; + this.vertexData[j+2]= coordinates[i+2]; + } + if(isLive) { + geomLock.unLock(); + } + if (inUpdater ||source == null ) { + return; + } + if (!isLive) { + boundsDirty = true; + return; + } + + // Compute geo's bounds + processCoordsChanged(false); + + sendDataChangedMessage(true); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object using coordinate data starting + * from vertex index start for length vertices. + * @param index the vertex index + * @param coordinates an array of 3*n values containing n new coordinates + * @param start starting vertex index of data in coordinates . + * @param length number of vertices to be copied. + */ + void setCoordinates(int index, double coordinates[], int start, int length) { + int offset = this.stride * index + coordinateOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + + for (i= start*3, j= offset; i < (start+length)*3; + i+=3, j+= this.stride) { + this.vertexData[j] = (float)coordinates[i]; + this.vertexData[j+1]= (float)coordinates[i+1]; + this.vertexData[j+2]= (float)coordinates[i+2]; + } + + if(isLive) { + geomLock.unLock(); + } + if (inUpdater || (source == null)) { + return; + } + if (!isLive) { + boundsDirty = true; + return; + } + + + // Compute geo's bounds + processCoordsChanged(false); + + sendDataChangedMessage(true); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object using coordinate data starting + * from vertex index start for length vertices. + * @param index the vertex index + * @param coordinates an array of vectors containing new coordinates + * @param start starting vertex index of data in coordinates . + * @param length number of vertices to be copied. + */ + void setCoordinates(int index, Point3f coordinates[], int start, + int length) { + int offset = this.stride * index + coordinateOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + + for (i=start, j= offset;i < start + length; i++, j+= this.stride) { + this.vertexData[j] = coordinates[i].x; + this.vertexData[j+1]= coordinates[i].y; + this.vertexData[j+2]= coordinates[i].z; + } + + if(isLive) { + geomLock.unLock(); + } + + if (inUpdater || (source == null)) { + return; + } + if (!isLive) { + boundsDirty = true; + return; + } + + + // Compute geo's bounds + processCoordsChanged(false); + + sendDataChangedMessage(true); + } + + /** + * Sets the coordinates associated with the vertices starting at + * the specified index for this object using coordinate data starting + * from vertex index start for length vertices. + * @param index the vertex index + * @param coordinates an array of vectors containing new coordinates + * @param start starting vertex index of data in coordinates . + * @param length number of vertices to be copied. + */ + void setCoordinates(int index, Point3d coordinates[], int start, + int length) { + int offset = this.stride * index + coordinateOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + + for (i=start, j= offset;i < start + length; i++, j+= this.stride) { + this.vertexData[j] = (float)coordinates[i].x; + this.vertexData[j+1]= (float)coordinates[i].y; + this.vertexData[j+2]= (float)coordinates[i].z; + } + + if(isLive) { + geomLock.unLock(); + } + if (inUpdater || (source == null)) { + return; + } + if (!isLive) { + boundsDirty = true; + return; + } + + // Compute geo's bounds + processCoordsChanged(false); + + sendDataChangedMessage(true); + } + + /** + * Sets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color an array of 3 or 4 values containing the new color + */ + void setColor(int index, float color[]) { + int offset = this.stride*index + colorOffset; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + this.vertexData[offset] = color[0]; + this.vertexData[offset+1] = color[1]; + this.vertexData[offset+2] = color[2]; + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + this.vertexData[offset+3] = color[3]*lastAlpha[0]; + else + this.vertexData[offset+3] = lastAlpha[0]; + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color an array of 3 or 4 values containing the new color + */ + void setColor(int index, byte color[]) { + int offset = this.stride*index + colorOffset; + + boolean isLive = source!=null && source.isLive(); + if(isLive) { + geomLock.getLock(); + } + + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + this.vertexData[offset] = (color[0] & 0xff) * ByteToFloatScale; + this.vertexData[offset+1] = (color[1] & 0xff) * ByteToFloatScale; + this.vertexData[offset+2] = (color[2] & 0xff) * ByteToFloatScale; + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + this.vertexData[offset+3] = ((color[3] & 0xff)* ByteToFloatScale)*lastAlpha[0]; + else + this.vertexData[offset+3] = lastAlpha[0]; + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color a vector containing the new color + */ + void setColor(int index, Color3f color) { + int offset = this.stride*index + colorOffset; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + this.vertexData[offset] = color.x; + this.vertexData[offset+1] = color.y; + this.vertexData[offset+2] = color.z; + this.vertexData[offset+3] = lastAlpha[0]; + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + + } + + /** + * Sets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color a vector containing the new color + */ + void setColor(int index, Color4f color) { + int offset = this.stride*index + colorOffset; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + this.vertexData[offset] = color.x; + this.vertexData[offset+1] = color.y; + this.vertexData[offset+2] = color.z; + this.vertexData[offset+3] = color.w*lastAlpha[0]; + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color a vector containing the new color + */ + void setColor(int index, Color3b color) { + int offset = this.stride*index + colorOffset; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + this.vertexData[offset] = (color.x & 0xff) * ByteToFloatScale; + this.vertexData[offset+1] = (color.y & 0xff) * ByteToFloatScale; + this.vertexData[offset+2] = (color.z & 0xff) * ByteToFloatScale; + this.vertexData[offset+3] = lastAlpha[0]; + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color a vector containing the new color + */ + void setColor(int index, Color4b color) { + int offset = this.stride*index + colorOffset; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + this.vertexData[offset] = (color.x * 0xff) * ByteToFloatScale; + this.vertexData[offset+1] = (color.y * 0xff) * ByteToFloatScale; + this.vertexData[offset+2] = (color.z * 0xff) * ByteToFloatScale; + this.vertexData[offset+3] = ((color.w & 0xff) * ByteToFloatScale)*lastAlpha[0]; + + if(isLive){ + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values containing n new colors + */ + void setColors(int index, float colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + { + for (i=0, j= offset;i < num; i+= 4, j+= this.stride) + { + this.vertexData[j] = colors[i]; + this.vertexData[j+1] = colors[i+1]; + this.vertexData[j+2] = colors[i+2]; + this.vertexData[j+3] = colors[i+3]*lastAlpha[0]; + } + } + else + { + for (i=0, j= offset;i < num; i+= 3, j+= this.stride) + { + this.vertexData[j] = colors[i]; + this.vertexData[j+1] = colors[i+1]; + this.vertexData[j+2] = colors[i+2]; + this.vertexData[j+3] = lastAlpha[0]; + } + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values containing n new colors + */ + void setColors(int index, byte colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + { + for (i=0, j= offset;i < num; i+= 4, j+= this.stride) + { + this.vertexData[j] = (colors[i] & 0xff) * ByteToFloatScale; + this.vertexData[j+1] = (colors[i+1] & 0xff) * ByteToFloatScale; + this.vertexData[j+2] = (colors[i+2] & 0xff) * ByteToFloatScale; + this.vertexData[j+3] = ((colors[i+3] & 0xff) * ByteToFloatScale)*lastAlpha[0]; + } + } + else + { + for (i=0, j= offset;i < num; i+= 3, j+= this.stride) + { + this.vertexData[j] = (colors[i] & 0xff) * ByteToFloatScale; + this.vertexData[j+1] = (colors[i+1] & 0xff) * ByteToFloatScale; + this.vertexData[j+2] = (colors[i+2] & 0xff) * ByteToFloatScale; + this.vertexData[j+3] = lastAlpha[0]; + } + } + + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of vectors containing new colors + */ + void setColors(int index, Color3f colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + for (i=0, j= offset;i < num; i++, j+= this.stride) + { + this.vertexData[j] = colors[i].x; + this.vertexData[j+1] = colors[i].y; + this.vertexData[j+2] = colors[i].z; + this.vertexData[j+3] = lastAlpha[0]; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of vectors containing new colors + */ + void setColors(int index, Color4f colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + for (i=0, j= offset;i < num; i++, j+= this.stride) + { + this.vertexData[j] = colors[i].x; + this.vertexData[j+1] = colors[i].y; + this.vertexData[j+2] = colors[i].z; + this.vertexData[j+3] = colors[i].w*lastAlpha[0]; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of vectors containing new colors + */ + void setColors(int index, Color3b colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + for (i=0, j= offset;i < num; i++, j+= this.stride) + { + this.vertexData[j] = (colors[i].x & 0xff) * ByteToFloatScale; + this.vertexData[j+1] = (colors[i].y & 0xff) * ByteToFloatScale; + this.vertexData[j+2] = (colors[i].z & 0xff) * ByteToFloatScale; + this.vertexData[j+3] = lastAlpha[0]; + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + + /** + * Sets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of vectors containing new colors + */ + void setColors(int index, Color4b colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + for (i=0, j= offset;i < num; i++, j+= this.stride) + { + this.vertexData[j] = (colors[i].x & 0xff) * ByteToFloatScale; + this.vertexData[j+1] = (colors[i].y & 0xff) * ByteToFloatScale; + this.vertexData[j+2] = (colors[i].z & 0xff) * ByteToFloatScale; + this.vertexData[j+3] = ((colors[i].w & 0xff) * ByteToFloatScale)*lastAlpha[0]; + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values containing n new colors + * @param start starting color index of data in colors. + * @param length number of colors to be copied. + */ + void setColors(int index, float colors[], int start, int length) { + int offset = this.stride*index + colorOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) { + for (i = start * 4, j = offset; i < (start + length) * 4; + i += 4, j += this.stride) { + this.vertexData[j] = colors[i]; + this.vertexData[j+1] = colors[i+1]; + this.vertexData[j+2] = colors[i+2]; + this.vertexData[j+3] = colors[i+3]*lastAlpha[0]; + } + } else { + for (i = start * 3, j = offset; i < (start + length) * 3; + i += 3, j += this.stride) { + this.vertexData[j] = colors[i]; + this.vertexData[j+1] = colors[i+1]; + this.vertexData[j+2] = colors[i+2]; + this.vertexData[j+3] = lastAlpha[0]; + } + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values containing n new colors + * @param start starting color index of data in colors. + * @param length number of colors to be copied. + */ + void setColors(int index, byte colors[], int start, int length) { + int offset = this.stride*index + colorOffset; + int i, j; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) { + for (i = start * 4, j = offset; i < (start + length) * 4; + i += 4, j += this.stride) { + this.vertexData[j] = (colors[i] & 0xff) * ByteToFloatScale; + this.vertexData[j+1] = (colors[i+1] & 0xff) * ByteToFloatScale; + this.vertexData[j+2] = (colors[i+2] & 0xff) * ByteToFloatScale; + this.vertexData[j+3] = ((colors[i+3] & 0xff) * ByteToFloatScale)*lastAlpha[0]; + } + } else { + for (i = start * 3, j = offset; i < (start + length) * 3; + i += 3, j += this.stride) { + this.vertexData[j] = (colors[i] & 0xff) * ByteToFloatScale; + this.vertexData[j+1] = (colors[i+1] & 0xff) * ByteToFloatScale; + this.vertexData[j+2] = (colors[i+2] & 0xff) * ByteToFloatScale; + this.vertexData[j+3] = lastAlpha[0]; + } + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values containing n new colors + * @param start starting color index of data in colors. + * @param length number of colors to be copied. + */ + void setColors(int index, Color3f colors[], int start, int length) { + int offset = this.stride*index + colorOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = colors[i].x; + this.vertexData[j+1] = colors[i].y; + this.vertexData[j+2] = colors[i].z; + this.vertexData[j+3] = lastAlpha[0]; + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values containing n new colors + * @param start starting color index of data in colors. + * @param length number of colors to be copied. + */ + void setColors(int index, Color4f colors[], int start, int length) { + int offset = this.stride*index + colorOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = colors[i].x; + this.vertexData[j+1] = colors[i].y; + this.vertexData[j+2] = colors[i].z; + this.vertexData[j+3] = colors[i].w*lastAlpha[0]; + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values containing n new colors + * @param start starting color index of data in colors. + * @param length number of colors to be copied. + */ + void setColors(int index, Color3b colors[], int start, int length) { + int offset = this.stride*index + colorOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = (colors[i].x & 0xff) * ByteToFloatScale; + this.vertexData[j+1] = (colors[i].y & 0xff) * ByteToFloatScale; + this.vertexData[j+2] = (colors[i].z & 0xff) * ByteToFloatScale; + this.vertexData[j+3] = lastAlpha[0]; + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the colors associated with the vertices starting at + * the specified index for this object using data in colors + * starting at index start for length colors. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values containing n new colors + * @param start starting color index of data in colors. + * @param length number of colors to be copied. + */ + void setColors(int index, Color4b colors[], int start, int length) { + int offset = this.stride*index + colorOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = (colors[i].x & 0xff) * ByteToFloatScale; + this.vertexData[j+1] = (colors[i].y & 0xff) * ByteToFloatScale; + this.vertexData[j+2] = (colors[i].z & 0xff) * ByteToFloatScale; + this.vertexData[j+3] = ((colors[i].w & 0xff) * ByteToFloatScale)*lastAlpha[0]; + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the normal associated with the vertex at + * the specified index. + * @param index the vertex index + * @param normal the new normal + */ + void setNormal(int index, float normal[]) { + int offset = this.stride*index + normalOffset; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + this.vertexData[offset] = normal[0]; + this.vertexData[offset+1] = normal[1]; + this.vertexData[offset+2] = normal[2]; + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the normal associated with the vertex at + * the specified index. + * @param index the vertex index + * @param normal the vector containing the new normal + */ + void setNormal(int index, Vector3f normal) { + int offset = this.stride*index + normalOffset; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + this.vertexData[offset] = normal.x; + this.vertexData[offset+1] = normal.y; + this.vertexData[offset+2] = normal.z; + + if(isLive){ + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the normals associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param normals the new normals + */ + void setNormals(int index, float normals[]) { + int offset = this.stride*index + normalOffset; + int i, j, num = normals.length; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + for (i=0, j= offset;i < num;i += 3, j+= this.stride) + { + this.vertexData[j] = normals[i]; + this.vertexData[j+1] = normals[i+1]; + this.vertexData[j+2] = normals[i+2]; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the normals associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param normals the vector containing the new normals + */ + void setNormals(int index, Vector3f normals[]) { + int offset = this.stride*index + normalOffset; + int i, j, num = normals.length; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + for (i=0, j= offset;i < num;i++, j+= this.stride) + { + this.vertexData[j] = normals[i].x; + this.vertexData[j+1] = normals[i].y; + this.vertexData[j+2] = normals[i].z; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the normals associated with the vertices starting at + * the specified index for this object using data in normals + * starting at index start and ending at index start+length. + * @param index the vertex index + * @param normals the new normals + * @param start starting normal index of data in colors . + * @param length number of normals to be copied. + */ + void setNormals(int index, float normals[], int start, int length) { + int offset = this.stride*index + normalOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + for (i = start * 3, j = offset; i < (start + length) * 3; + i+=3, j += this.stride) { + this.vertexData[j] = normals[i]; + this.vertexData[j+1] = normals[i+1]; + this.vertexData[j+2] = normals[i+2]; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the normals associated with the vertices starting at + * the specified index for this object using data in normals + * starting at index start and ending at index start+length. + * @param index the vertex index + * @param normals the new normals + * @param start starting normal index of data in colors . + * @param length number of normals to be copied. + */ + void setNormals(int index, Vector3f normals[], int start, int length) { + int offset = this.stride*index + normalOffset; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = normals[i].x; + this.vertexData[j+1] = normals[i].y; + this.vertexData[j+2] = normals[i].z; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index for this object using data in texCoords + * starting at index start and ending at index start+length. + * @param index the vertex index + * @param texCoords the new texture coordinates + * @param start starting texture coordinate index of data in texCoords . + * @param length number of texture Coordinates to be copied. + */ + void setTextureCoordinates(int texCoordSet, int index, float texCoords[], + int start, int length) { + + if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j, k; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + for (i = start * 4, j = offset, k = 0; k < length; + j += this.stride, k++) { + this.vertexData[j] = texCoords[i++]; + this.vertexData[j+1] = texCoords[i++]; + this.vertexData[j+2] = texCoords[i++]; + this.vertexData[j+3] = texCoords[i++]; + } + } else if ((this.vertexFormat & + GeometryArray.TEXTURE_COORDINATE_3) != 0) { + for (i = start * 3, j = offset, k = 0; k < length; + j += this.stride, k++) { + this.vertexData[j] = texCoords[i++]; + this.vertexData[j+1] = texCoords[i++]; + this.vertexData[j+2] = texCoords[i++]; + } + } else { + for (i = start * 2, j = offset, k = 0; k < length; + j += this.stride, k++) { + this.vertexData[j] = texCoords[i++]; + this.vertexData[j+1] = texCoords[i++]; + } + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index for this object using data in texCoords + * starting at index start and ending at index start+length. + * @param index the vertex index + * @param texCoords the new texture coordinates + * @param start starting texture coordinate index of data in texCoords . + * @param length number of texture Coordinates to be copied. + */ + void setTextureCoordinates(int texCoordSet, int index, Point2f texCoords[], + int start, int length) { + + if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = texCoords[i].x; + this.vertexData[j+1] = texCoords[i].y; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index for this object using data in texCoords + * starting at index start and ending at index start+length. + * @param index the vertex index + * @param texCoords the new texture coordinates + * @param start starting texture coordinate index of data in texCoords . + * @param length number of texture Coordinates to be copied. + */ + void setTextureCoordinates(int texCoordSet, int index, Point3f texCoords[], + int start, int length) { + + if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = texCoords[i].x; + this.vertexData[j+1] = texCoords[i].y; + this.vertexData[j+2] = texCoords[i].z; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index for this object using data in texCoords + * starting at index start and ending at index start+length. + * @param index the vertex index + * @param texCoords the new texture coordinates + * @param start starting texture coordinate index of data in texCoords . + * @param length number of texture Coordinates to be copied. + */ + void setTextureCoordinates(int texCoordSet, int index, TexCoord2f texCoords[], + int start, int length) { + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = texCoords[i].x; + this.vertexData[j+1] = texCoords[i].y; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index for this object using data in texCoords + * starting at index start and ending at index start+length. + * @param index the vertex index + * @param texCoords the new texture coordinates + * @param start starting texture coordinate index of data in texCoords . + * @param length number of texture Coordinates to be copied. + */ + void setTextureCoordinates(int texCoordSet, int index, + TexCoord3f texCoords[], + int start, int length) { + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + + if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = texCoords[i].x; + this.vertexData[j+1] = texCoords[i].y; + this.vertexData[j+2] = texCoords[i].z; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + /** + * Sets the texture coordinates associated with the vertices starting at + * the specified index for this object using data in texCoords + * starting at index start and ending at index start+length. + * @param index the vertex index + * @param texCoords the new texture coordinates + * @param start starting texture coordinate index of data in texCoords . + * @param length number of texture Coordinates to be copied. + */ + void setTextureCoordinates(int texCoordSet, int index, + TexCoord4f texCoords[], + int start, int length) { + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + + if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0) + throw new IllegalStateException(J3dI18N.getString("GeometryArray82")); + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79")); + + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j; + + for (i = start, j = offset; i < start+length; i++, j += this.stride) { + this.vertexData[j] = texCoords[i].x; + this.vertexData[j+1] = texCoords[i].y; + this.vertexData[j+2] = texCoords[i].z; + this.vertexData[j+3] = texCoords[i].w; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + + /** + * Sets the vertex attribute associated with the vertex at the + * specified index in the specified vertex attribute number for + * this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index destination vertex index in this geometry array + * @param vertexAttr the Point2f containing the new vertex attribute + */ + void setVertexAttr(int vertexAttrNum, int index, + Point2f vertexAttr) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + + this.vertexData[offset] = vertexAttr.x; + this.vertexData[offset+1] = vertexAttr.y; + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + /** + * Sets the vertex attribute associated with the vertex at the + * specified index in the specified vertex attribute number for + * this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index destination vertex index in this geometry array + * @param vertexAttr the Point3f containing the new vertex attribute + */ + void setVertexAttr(int vertexAttrNum, int index, + Point3f vertexAttr) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + + this.vertexData[offset] = vertexAttr.x; + this.vertexData[offset+1] = vertexAttr.y; + this.vertexData[offset+2] = vertexAttr.z; + + if (isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + /** + * Sets the vertex attribute associated with the vertex at the + * specified index in the specified vertex attribute number for + * this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index destination vertex index in this geometry array + * @param vertexAttr the Point4f containing the new vertex attribute + */ + void setVertexAttr(int vertexAttrNum, int index, + Point4f vertexAttr) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + + this.vertexData[offset] = vertexAttr.x; + this.vertexData[offset+1] = vertexAttr.y; + this.vertexData[offset+2] = vertexAttr.z; + this.vertexData[offset+3] = vertexAttr.w; + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + /** + * Sets the vertex attributes associated with the vertices + * starting at the specified index in the specified vertex + * attribute number for this object using data in + * vertexAttrs starting at index start and + * ending at index start+length. + * + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of 1*n, 2*n, 3*n, or 4*n values + * containing n new vertex attributes + * @param start starting source vertex index in vertexAttrs + * array. + * @param length number of vertex attributes to be copied. + */ + void setVertexAttrs(int vertexAttrNum, int index, + float[] vertexAttrs, + int start, int length) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int size = vertexAttrSizes[vertexAttrNum]; + int i, j, k; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + + for (i = start * size, j = offset, k = 0; k < length; i += size, j += this.stride, k++) { + for (int ii = 0; ii < size; ii++) { + this.vertexData[j+ii] = vertexAttrs[i+ii]; + } + } + + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + /** + * Sets the vertex attributes associated with the vertices + * starting at the specified index in the specified vertex + * attribute number for this object using data in + * vertexAttrs starting at index start and + * ending at index start+length. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point2f objects containing new + * vertex attributes + * @param start starting source vertex index in vertexAttrs + * array. + * @param length number of vertex attributes to be copied. + */ + void setVertexAttrs(int vertexAttrNum, int index, + Point2f[] vertexAttrs, + int start, int length) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int i, j, k; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + + for (i = start, j = offset, k = 0; k < length; i++, j += this.stride, k++) { + this.vertexData[j] = vertexAttrs[i].x; + this.vertexData[j+1] = vertexAttrs[i].y; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + /** + * Sets the vertex attributes associated with the vertices + * starting at the specified index in the specified vertex + * attribute number for this object using data in + * vertexAttrs starting at index start and + * ending at index start+length. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point3f objects containing new + * vertex attributes + * @param start starting source vertex index in vertexAttrs + * array. + * @param length number of vertex attributes to be copied. + */ + void setVertexAttrs(int vertexAttrNum, int index, + Point3f[] vertexAttrs, + int start, int length) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int i, j, k; + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + + for (i = start, j = offset, k = 0; k < length; i++, j += this.stride, k++) { + this.vertexData[j] = vertexAttrs[i].x; + this.vertexData[j+1] = vertexAttrs[i].y; + this.vertexData[j+2] = vertexAttrs[i].z; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + /** + * Sets the vertex attributes associated with the vertices + * starting at the specified index in the specified vertex + * attribute number for this object using data in + * vertexAttrs starting at index start and + * ending at index start+length. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index starting destination vertex index in this geometry array + * @param vertexAttrs source array of Point4f objects containing new + * vertex attributes + * @param start starting source vertex index in vertexAttrs + * array. + * @param length number of vertex attributes to be copied. + */ + void setVertexAttrs(int vertexAttrNum, int index, + Point4f[] vertexAttrs, + int start, int length) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int i, j, k; + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + + for (i = start, j = offset, k = 0; k < length; i++, j += this.stride, k++) { + this.vertexData[j] = vertexAttrs[i].x; + this.vertexData[j+1] = vertexAttrs[i].y; + this.vertexData[j+2] = vertexAttrs[i].z; + this.vertexData[j+3] = vertexAttrs[i].w; + } + if(isLive) { + geomLock.unLock(); + sendDataChangedMessage(false); + } + } + + + /** + * Gets the coordinate associated with the vertex at + * the specified index. + * @param index the vertex index + * @param coordinate an array of 3 values that will receive the new coordinate + */ + void getCoordinate(int index, float coordinate[]) { + int offset = this.stride*index + coordinateOffset; + + coordinate[0]= this.vertexData[offset]; + coordinate[1]= this.vertexData[offset+1]; + coordinate[2]= this.vertexData[offset+2]; + } + + /** + * Gets the coordinate associated with the vertex at + * the specified index. + * @param index the vertex index + * @param coordinate an array of 3 values that will receive the new coordinate + */ + void getCoordinate(int index, double coordinate[]) { + int offset = this.stride*index + coordinateOffset; + + coordinate[0]= (double)this.vertexData[offset]; + coordinate[1]= (double)this.vertexData[offset+1]; + coordinate[2]= (double)this.vertexData[offset+2]; + } + + /** + * Gets the coordinate associated with the vertex at + * the specified index. + * @param index the vertex index + * @param coordinate a vector that will receive the new coordinate + */ + void getCoordinate(int index, Point3f coordinate) { + int offset = this.stride*index + coordinateOffset; + + coordinate.x = this.vertexData[offset]; + coordinate.y = this.vertexData[offset+1]; + coordinate.z = this.vertexData[offset+2]; + } + + /** + * Gets the coordinate associated with the vertex at + * the specified index. + * @param index the vertex index + * @param coordinate a vector that will receive the new coordinate + */ + void getCoordinate(int index, Point3d coordinate) { + int offset = this.stride*index + coordinateOffset; + + coordinate.x = (double)this.vertexData[offset]; + coordinate.y = (double)this.vertexData[offset+1]; + coordinate.z = (double)this.vertexData[offset+2]; + } + + /** + * Gets the coordinates associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param coordinates an array of 3*n values that will receive new coordinates + */ + void getCoordinates(int index, float coordinates[]) { + int offset = this.stride*index + coordinateOffset; + int i, j, num = coordinates.length; + + for (i=0,j= offset;i < num;i +=3, j += this.stride) + { + coordinates[i] = this.vertexData[j]; + coordinates[i+1]= this.vertexData[j+1]; + coordinates[i+2]= this.vertexData[j+2]; + } + } + + + /** + * Gets the coordinates associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param coordinates an array of 3*n values that will receive new coordinates + */ + void getCoordinates(int index, double coordinates[]) { + int offset = this.stride*index + coordinateOffset; + int i, j, num = coordinates.length; + + for (i=0,j= offset;i < num;i +=3, j += this.stride) + { + coordinates[i] = (double)this.vertexData[j]; + coordinates[i+1]= (double)this.vertexData[j+1]; + coordinates[i+2]= (double)this.vertexData[j+2]; + } + } + + /** + * Gets the coordinates associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param coordinates an array of vectors that will receive new coordinates + */ + void getCoordinates(int index, Point3f coordinates[]) { + int offset = this.stride*index + coordinateOffset; + int i, j, num = coordinates.length; + + for (i=0,j= offset;i < num;i++, j += this.stride) + { + coordinates[i].x = this.vertexData[j]; + coordinates[i].y = this.vertexData[j+1]; + coordinates[i].z = this.vertexData[j+2]; + } + } + + /** + * Gets the coordinates associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param coordinates an array of vectors that will receive new coordinates + */ + void getCoordinates(int index, Point3d coordinates[]) { + int offset = this.stride*index + coordinateOffset; + int i, j, num = coordinates.length; + + for (i=0,j= offset;i < num;i++, j += this.stride) + { + coordinates[i].x = (double)this.vertexData[j]; + coordinates[i].y = (double)this.vertexData[j+1]; + coordinates[i].z = (double)this.vertexData[j+2]; + } + } + + /** + * Gets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color an array of 3 or 4 values that will receive the new color + */ + void getColor(int index, float color[]) { + int offset = this.stride*index + colorOffset; + + color[0]= this.vertexData[offset]; + color[1]= this.vertexData[offset+1]; + color[2]= this.vertexData[offset+2]; + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + color[3]= this.vertexData[offset+3]/lastAlpha[0]; + } + + /** + * Gets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color an array of 3 or 4 values that will receive the new color + */ + void getColor(int index, byte color[]) { + int offset = this.stride*index + colorOffset; + + color[0]= (byte)(this.vertexData[offset] * FloatToByteScale); + color[1]= (byte)(this.vertexData[offset+1] * FloatToByteScale); + color[2]= (byte)(this.vertexData[offset+2] * FloatToByteScale); + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + color[3]= (byte)((this.vertexData[offset+3]/lastAlpha[0]) * FloatToByteScale); + } + + /** + * Gets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color a vector that will receive the new color + */ + void getColor(int index, Color3f color) { + int offset = this.stride*index + colorOffset; + + color.x = this.vertexData[offset]; + color.y = this.vertexData[offset+1]; + color.z = this.vertexData[offset+2]; + } + + /** + * Gets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color a vector that will receive the new color + */ + void getColor(int index, Color4f color) { + int offset = this.stride*index + colorOffset; + + color.x = this.vertexData[offset]; + color.y = this.vertexData[offset+1]; + color.z = this.vertexData[offset+2]; + color.w= this.vertexData[offset+3]/lastAlpha[0]; + } + + /** + * Gets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color a vector that will receive the new color + */ + void getColor(int index, Color3b color) { + int offset = this.stride*index + colorOffset; + + color.x = (byte)(this.vertexData[offset] * FloatToByteScale); + color.y = (byte)(this.vertexData[offset+1] * FloatToByteScale); + color.z = (byte)(this.vertexData[offset+2] * FloatToByteScale); + } + + /** + * Gets the color associated with the vertex at + * the specified index. + * @param index the vertex index + * @param color a vector that will receive the new color + */ + void getColor(int index, Color4b color) { + int offset = this.stride*index + colorOffset; + + color.x = (byte)(this.vertexData[offset] * FloatToByteScale); + color.y = (byte)(this.vertexData[offset+1] * FloatToByteScale); + color.z = (byte)(this.vertexData[offset+2] * FloatToByteScale); + color.w = (byte)((this.vertexData[offset+3]/lastAlpha[0]) * FloatToByteScale); + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values that will receive n new colors + */ + void getColors(int index, float colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + float val = 1.0f/lastAlpha[0]; + + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + { + for (i=0, j= offset;i < num; i+= 4, j+= this.stride) + { + colors[i] = this.vertexData[j]; + colors[i+1]= this.vertexData[j+1]; + colors[i+2]= this.vertexData[j+2]; + colors[i+3]= this.vertexData[j+3] * val; + } + } + else + { + for (i=0, j= offset;i < num; i+= 3, j+= this.stride) + { + colors[i] = this.vertexData[j]; + colors[i+1]= this.vertexData[j+1]; + colors[i+2]= this.vertexData[j+2]; + } + } + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of 3*n or 4*n values that will receive new colors + */ + void getColors(int index, byte colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + float val = 1.0f/lastAlpha[0]; + + + if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + { + for (i=0, j= offset;i < num; i+= 4, j+= this.stride) + { + colors[i] = (byte)(this.vertexData[j] * FloatToByteScale); + colors[i+1]= (byte)(this.vertexData[j+1] * FloatToByteScale); + colors[i+2]= (byte)(this.vertexData[j+2] * FloatToByteScale); + colors[i+3]= (byte)((this.vertexData[j+3] * val) * FloatToByteScale); + } + } + else + { + for (i=0, j= offset;i < num; i+= 3, j+= this.stride) + { + colors[i] = (byte)(this.vertexData[j] * FloatToByteScale); + colors[i+1]= (byte)(this.vertexData[j+1] * FloatToByteScale); + colors[i+2]= (byte)(this.vertexData[j+2] * FloatToByteScale); + } + } + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of vectors that will receive new colors + */ + void getColors(int index, Color3f colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + + for (i=0, j= offset;i < num; i++, j+= this.stride) + { + colors[i].x = this.vertexData[j]; + colors[i].y = this.vertexData[j+1]; + colors[i].z = this.vertexData[j+2]; + } + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of vectors that will receive new colors + */ + void getColors(int index, Color4f colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + float val = 1.0f/lastAlpha[0]; + + for (i=0, j= offset;i < num; i++, j+= this.stride) + { + colors[i].x = this.vertexData[j]; + colors[i].y = this.vertexData[j+1]; + colors[i].z = this.vertexData[j+2]; + colors[i].w = this.vertexData[j+3] * val; + } + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of vectors that will receive new colors + */ + void getColors(int index, Color3b colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + + for (i=0, j= offset;i < num; i++, j+= this.stride) + { + colors[i].x = (byte)(this.vertexData[j] * FloatToByteScale); + colors[i].y = (byte)(this.vertexData[j+1] * FloatToByteScale); + colors[i].z = (byte)(this.vertexData[j+2] * FloatToByteScale); + } + } + + /** + * Gets the colors associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param colors an array of vectors that will receive new colors + */ + void getColors(int index, Color4b colors[]) { + int offset = this.stride*index + colorOffset; + int i, j, num = colors.length; + float val = 1.0f/lastAlpha[0]; + + for (i=0, j= offset;i < num; i++, j+= this.stride) + { + colors[i].x = (byte)(this.vertexData[j] * FloatToByteScale); + colors[i].y = (byte)(this.vertexData[j+1] * FloatToByteScale); + colors[i].z = (byte)(this.vertexData[j+2] * FloatToByteScale); + colors[i].w = (byte)(this.vertexData[j+3] * val * FloatToByteScale); + } + } + + /** + * Gets the normal associated with the vertex at + * the specified index. + * @param index the vertex index + * @param normal array that will receive the new normal + */ + void getNormal(int index, float normal[]) { + int offset = this.stride*index + normalOffset; + + normal[0]= this.vertexData[offset]; + normal[1]= this.vertexData[offset+1]; + normal[2]= this.vertexData[offset+2]; + } + + /** + * Gets the normal associated with the vertex at + * the specified index. + * @param index the vertex index + * @param normal the vector that will receive the new normal + */ + void getNormal(int index, Vector3f normal) { + int offset = this.stride*index + normalOffset; + + normal.x= this.vertexData[offset]; + normal.y= this.vertexData[offset+1]; + normal.z= this.vertexData[offset+2]; + } + + /** + * Gets the normals associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param normals array that will receive the new normals + */ + void getNormals(int index, float normals[]) { + int offset = this.stride*index + normalOffset; + int i, j, num = normals.length; + + for (i=0, j= offset;i < num;i+=3, j+= this.stride) + { + normals[i] = this.vertexData[j]; + normals[i+1]= this.vertexData[j+1]; + normals[i+2]= this.vertexData[j+2]; + } + } + + /** + * Gets the normals associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param normals the vector that will receive the new normals + */ + void getNormals(int index, Vector3f normals[]) { + int offset = this.stride*index + normalOffset; + int i, j, num = normals.length; + + for (i=0, j= offset;i < num;i++, j+= this.stride) + { + normals[i].x= this.vertexData[j]; + normals[i].y= this.vertexData[j+1]; + normals[i].z= this.vertexData[j+2]; + } + } + + /** + * Gets the texture co-ordinate associated with the vertex at + * the specified index. + * @param index the vertex index + * @param texCoord array that will receive the new texture co-ordinate + */ + void getTextureCoordinate(int texCoordSet, int index, float texCoord[]) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + + texCoord[0]= this.vertexData[offset]; + texCoord[1]= this.vertexData[offset+1]; + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texCoord[2]= this.vertexData[offset+2]; + + } else if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) + != 0) { + texCoord[2]= this.vertexData[offset+2]; + texCoord[3]= this.vertexData[offset+3]; + } + } + + /** + * Gets the texture co-ordinate associated with the vertex at + * the specified index. + * @param index the vertex index + * @param texCoord the vector that will receive the new texture co-ordinates + */ + void getTextureCoordinate(int texCoordSet, int index, TexCoord2f texCoord) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + + texCoord.x= this.vertexData[offset]; + texCoord.y= this.vertexData[offset+1]; + } + + /** + * Gets the texture co-ordinate associated with the vertex at + * the specified index. + * @param index the vertex index + * @param texCoord the vector that will receive the new texture co-ordinates + */ + void getTextureCoordinate(int texCoordSet, int index, TexCoord3f texCoord) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + + texCoord.x= this.vertexData[offset]; + texCoord.y= this.vertexData[offset+1]; + texCoord.z= this.vertexData[offset+2]; + } + + /** + * Gets the texture co-ordinate associated with the vertex at + * the specified index. + * @param index the vertex index + * @param texCoord the vector that will receive the new texture co-ordinates + */ + void getTextureCoordinate(int texCoordSet, int index, TexCoord4f texCoord) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + + texCoord.x= this.vertexData[offset]; + texCoord.y= this.vertexData[offset+1]; + texCoord.z= this.vertexData[offset+2]; + texCoord.w= this.vertexData[offset+3]; + } + + /** + * Gets the texture co-ordinates associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param texCoords array that will receive the new texture co-ordinates + */ + void getTextureCoordinates(int texCoordSet, int index, float texCoords[]) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j, num = texCoords.length; + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + for (i=0, j= offset;i < num;i+=4, j+= this.stride) + { + texCoords[i]= this.vertexData[j]; + texCoords[i+1]= this.vertexData[j+1]; + texCoords[i+2]= this.vertexData[j+2]; + texCoords[i+3]= this.vertexData[j+3]; + } + } else if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) + != 0) { + for (i=0, j= offset;i < num;i+=3, j+= this.stride) + { + texCoords[i]= this.vertexData[j]; + texCoords[i+1]= this.vertexData[j+1]; + texCoords[i+2]= this.vertexData[j+2]; + } + } else { + for (i=0, j= offset;i < num;i+=2, j+= this.stride) + { + texCoords[i]= this.vertexData[j]; + texCoords[i+1]= this.vertexData[j+1]; + } + } + } + + /** + * Gets the texture co-ordinates associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param texCoords the vector that will receive the new texture co-ordinates + */ + void getTextureCoordinates(int texCoordSet, int index, + TexCoord2f texCoords[]) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j, num = texCoords.length; + + for (i=0, j= offset;i < num;i++, j+= this.stride) + { + texCoords[i].x= this.vertexData[j]; + texCoords[i].y= this.vertexData[j+1]; + } + } + + /** + * Gets the texture co-ordinates associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param texCoords the vector that will receive the new texture co-ordinates + */ + void getTextureCoordinates(int texCoordSet, int index, TexCoord3f texCoords[]) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j, num = texCoords.length; + + for (i=0, j= offset;i < num;i++, j+= this.stride) + { + texCoords[i].x= this.vertexData[j]; + texCoords[i].y= this.vertexData[j+1]; + texCoords[i].z= this.vertexData[j+2]; + } + } + + /** + * Gets the texture co-ordinates associated with the vertices starting at + * the specified index. + * @param index the vertex index + * @param texCoords the vector that will receive the new texture co-ordinates + */ + void getTextureCoordinates(int texCoordSet, int index, TexCoord4f texCoords[]) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j, num = texCoords.length; + + for (i=0, j= offset;i < num;i++, j+= this.stride) + { + texCoords[i].x= this.vertexData[j]; + texCoords[i].y= this.vertexData[j+1]; + texCoords[i].z= this.vertexData[j+2]; + texCoords[i].w= this.vertexData[j+3]; + } + } + + void getTextureCoordinates(int texCoordSet, int index, + Point2f texCoords[]) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j, num = texCoords.length; + + for (i=0, j= offset;i < num;i++, j+= this.stride) + { + texCoords[i].x= this.vertexData[j]; + texCoords[i].y= this.vertexData[j+1]; + } + } + + void getTextureCoordinates(int texCoordSet, int index, Point3f texCoords[]) { + int offset = this.stride*index + textureOffset + + texCoordSet * texCoordStride; + int i, j, num = texCoords.length; + + for (i=0, j= offset;i < num;i++, j+= this.stride) + { + texCoords[i].x= this.vertexData[j]; + texCoords[i].y= this.vertexData[j+1]; + texCoords[i].z= this.vertexData[j+2]; + } + } + + + /** + * Gets the vertex attribute associated with the vertex at + * the specified index in the specified vertex attribute number + * for this object. + */ + public void getVertexAttr(int vertexAttrNum, int index, + float[] vertexAttr) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int size = vertexAttrSizes[vertexAttrNum]; + + for (int i = 0; i < size; i++) { + vertexAttr[i] = this.vertexData[offset+i]; + + } + + } + + /** + * Gets the vertex attribute associated with the vertex at + * the specified index in the specified vertex attribute number + * for this object. + */ + public void getVertexAttr(int vertexAttrNum, int index, + Point2f vertexAttr) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + + vertexAttr.x = this.vertexData[offset]; + vertexAttr.y = this.vertexData[offset+1]; + + } + + /** + * Gets the vertex attribute associated with the vertex at + * the specified index in the specified vertex attribute number + * for this object. + */ + public void getVertexAttr(int vertexAttrNum, int index, + Point3f vertexAttr) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + + vertexAttr.x = this.vertexData[offset]; + vertexAttr.y = this.vertexData[offset+1]; + vertexAttr.z = this.vertexData[offset+2]; + + } + + /** + * Gets the vertex attribute associated with the vertex at + * the specified index in the specified vertex attribute number + * for this object. + */ + public void getVertexAttr(int vertexAttrNum, int index, + Point4f vertexAttr) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + + vertexAttr.x = this.vertexData[offset]; + vertexAttr.y = this.vertexData[offset+1]; + vertexAttr.z = this.vertexData[offset+2]; + vertexAttr.w = this.vertexData[offset+3]; + + } + + /** + * Gets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. + */ + public void getVertexAttrs(int vertexAttrNum, int index, + float[] vertexAttrs) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int size = vertexAttrSizes[vertexAttrNum]; + int i, j, k; + + for (i = 0, j = offset; + ((i < vertexAttrs.length) && (j < this.vertexData.length)) ; + i += size, j += this.stride) { + for (k = 0; k < size; k++) { + vertexAttrs[i+k] = this.vertexData[j+k]; + } + } + + } + + /** + * Gets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. + */ + public void getVertexAttrs(int vertexAttrNum, int index, + Point2f[] vertexAttrs) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int i, j; + + for (i = 0, j = offset; + ((i < vertexAttrs.length) && (j < this.vertexData.length)) ; + i++, j += this.stride) { + vertexAttrs[i].x = this.vertexData[j]; + vertexAttrs[i].y = this.vertexData[j+1]; + } + + } + + /** + * Gets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. + */ + public void getVertexAttrs(int vertexAttrNum, int index, + Point3f[] vertexAttrs) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int i, j; + + for (i = 0, j = offset; + ((i < vertexAttrs.length) && (j < this.vertexData.length)) ; + i++, j += this.stride) { + vertexAttrs[i].x = this.vertexData[j]; + vertexAttrs[i].y = this.vertexData[j+1]; + vertexAttrs[i].z = this.vertexData[j+2]; + } + + } + + /** + * Gets the vertex attributes associated with the vertices starting at + * the specified index in the specified vertex attribute number + * for this object. + */ + public void getVertexAttrs(int vertexAttrNum, int index, + Point4f[] vertexAttrs) { + + int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum]; + int i, j; + + for (i = 0, j = offset; + ((i < vertexAttrs.length) && (j < this.vertexData.length)) ; + i++, j += this.stride) { + vertexAttrs[i].x = this.vertexData[j]; + vertexAttrs[i].y = this.vertexData[j+1]; + vertexAttrs[i].z = this.vertexData[j+2]; + vertexAttrs[i].w = this.vertexData[j+3]; + } + + } + + + /** + * Updates geometry array data. + */ + void updateData(GeometryUpdater updater) { + boolean nullGeo = false; + + // Add yourself to obtain the geometry lock + // and Thread.currentThread().sleep until you get the lock + geomLock.getLock(); + + inUpdater = true; + updater.updateData((Geometry)source); + inUpdater = false; + if ((vertexFormat & GeometryArray.BY_REFERENCE) != 0) { + if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + // XXXX: handle the nio buffer + if (!(this instanceof IndexedGeometryArrayRetained) || + (vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if (((vertexFormat & GeometryArray.INTERLEAVED) != 0)) { + setupMirrorInterleavedColorPointer(false); + nullGeo = (interleavedFloatBufferImpl == null); + } + else { + setupMirrorColorPointer((vertexType & COLOR_DEFINED), false); + nullGeo = ((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0); + } + } + } + else { + if (!(this instanceof IndexedGeometryArrayRetained) || + (vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if (((vertexFormat & GeometryArray.INTERLEAVED) != 0)) { + setupMirrorInterleavedColorPointer(false); + nullGeo = (interLeavedVertexData == null); + } + else { + setupMirrorVertexPointer(vertexType & VERTEX_DEFINED); + setupMirrorColorPointer((vertexType & COLOR_DEFINED), false); + setupMirrorNormalPointer(vertexType & NORMAL_DEFINED); + setupMirrorTexCoordPointer(texCoordType); + setupMirrorVertexAttrPointer(vertexAttrType); + nullGeo = ((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0); + } + } + } + + //NVaidya + // User may or may not have changed indices in updater callback. + // We need to presume that the user may indeed have and, thus, will + // need to recompute maxCoordIndex unconditionally while + // geomLock is still locked. + if ((vertexFormat & GeometryArray.BY_REFERENCE_INDICES) != 0) { + assert (this instanceof IndexedGeometryArrayRetained); + + if (((IndexedGeometryArrayRetained)this).getCoordIndicesRef() == null) { + nullGeo = true; + } + ((IndexedGeometryArrayRetained)this).doPostUpdaterUpdate(); + } + } + + dirtyFlag |= VERTEX_CHANGED; + colorChanged = 0xffff; + geomLock.unLock(); + + if (source != null && source.isLive()) { + processCoordsChanged(nullGeo); + sendDataChangedMessage(true); + } + } + + boolean intersectBoundingBox( Point3d coordinates[], + BoundingBox box, + double dist[], + Point3d iPnt) { + int i, j; + int out[] = new int[6]; + + //Do trivial vertex test. + for(i=0; i<6; i++) + out[i] = 0; + for(i=0; i= box.lower.x) && (coordinates[i].x <= box.upper.x) && + (coordinates[i].y >= box.lower.y) && (coordinates[i].y <= box.upper.y) && + (coordinates[i].z >= box.lower.z) && (coordinates[i].z <= box.upper.z)) + // We're done! It's inside the boundingbox. + return true; + else { + if(coordinates[i].x < box.lower.x) + out[0]++; // left + if(coordinates[i].y < box.lower.y) + out[1]++; // bottom + if(coordinates[i].z < box.lower.z) + out[2]++; // back + if(coordinates[i].x > box.upper.x) + out[3]++; // right + if(coordinates[i].y > box.upper.y) + out[4]++; // top + if(coordinates[i].z > box.upper.z) + out[5]++; // front + } + + } + + if((out[0] == coordinates.length) || (out[1] == coordinates.length) || + (out[2] == coordinates.length) || (out[3] == coordinates.length) || + (out[4] == coordinates.length) || (out[5] == coordinates.length)) + // we're done. primitive is outside of boundingbox. + return false; + + // Setup bounding planes. + Point3d pCoor[] = new Point3d[4]; + for(i=0; i<4; i++) + pCoor[i] = new Point3d(); + + // left plane. + pCoor[0].set(box.lower.x, box.lower.y, box.lower.z); + pCoor[1].set(box.lower.x, box.lower.y, box.upper.z); + pCoor[2].set(box.lower.x, box.upper.y, box.upper.z); + pCoor[3].set(box.lower.x, box.upper.y, box.lower.z); + + + if (intersectPolygon(pCoor, coordinates)) { + if (dist != null) { + computeMinDistance(pCoor, box.getCenter(), + null, + dist, iPnt); + } + return true; + } + + // right plane. + pCoor[0].set(box.upper.x, box.lower.y, box.lower.z); + pCoor[1].set(box.upper.x, box.upper.y, box.lower.z); + pCoor[2].set(box.upper.x, box.upper.y, box.upper.z); + pCoor[3].set(box.upper.x, box.lower.y, box.upper.z); + if (intersectPolygon(pCoor, coordinates)) { + if (dist != null) { + computeMinDistance(pCoor, box.getCenter(), + null, + dist, iPnt); + } + return true; + } + + // bottom plane. + pCoor[0].set(box.upper.x, box.lower.y, box.upper.z); + pCoor[1].set(box.lower.x, box.lower.y, box.upper.z); + pCoor[2].set(box.lower.x, box.lower.y, box.lower.z); + pCoor[3].set(box.upper.x, box.lower.y, box.lower.z); + if (intersectPolygon(pCoor, coordinates)) { + if (dist != null) { + computeMinDistance(pCoor, box.getCenter(), + null, + dist, iPnt); + } + return true; + } + // top plane. + pCoor[0].set(box.upper.x, box.upper.y, box.upper.z); + pCoor[1].set(box.upper.x, box.upper.y, box.lower.z); + pCoor[2].set(box.lower.x, box.upper.y, box.lower.z); + pCoor[3].set(box.lower.x, box.upper.y, box.upper.z); + if (intersectPolygon(pCoor, coordinates)) { + if (dist != null) { + computeMinDistance(pCoor, box.getCenter(), + null, + dist, iPnt); + } + return true; + } + + // front plane. + pCoor[0].set(box.upper.x, box.upper.y, box.upper.z); + pCoor[1].set(box.lower.x, box.upper.y, box.upper.z); + pCoor[2].set(box.lower.x, box.lower.y, box.upper.z); + pCoor[3].set(box.upper.x, box.lower.y, box.upper.z); + if (intersectPolygon(pCoor, coordinates)) { + if (dist != null) { + computeMinDistance(pCoor, box.getCenter(), + null, + dist, iPnt); + } + return true; + } + + // back plane. + pCoor[0].set(box.upper.x, box.upper.y, box.lower.z); + pCoor[1].set(box.upper.x, box.lower.y, box.lower.z); + pCoor[2].set(box.lower.x, box.lower.y, box.lower.z); + pCoor[3].set(box.lower.x, box.upper.y, box.lower.z); + if (intersectPolygon(pCoor, coordinates)) { + if (dist != null) { + computeMinDistance(pCoor, box.getCenter(), + null, + dist, iPnt); + } + return true; + } + return false; + } + + + boolean intersectBoundingSphere(Point3d coordinates[], + BoundingSphere sphere, + double dist[], + Point3d iPnt) + { + int i, j; + Vector3d tempV3D = new Vector3d(); + boolean esFlag; + + //Do trivial vertex test. + + for (i=0; i 0.0) + break; + } + + for(j=i; j 0.0) + break; + } + + if(j == (coordinates.length-1)) { + // System.err.println("(1) Degenerate polygon."); + return false; // Degenerate polygon. + } + + /* + for(i=0; i sphere.radius) { + return false; + } + + tq = pNrmDotPa / nLenSq; + + q.x = sphere.center.x + tq * pNrm.x; + q.y = sphere.center.y + tq * pNrm.y; + q.z = sphere.center.z + tq * pNrm.z; + + // PolyPnt2D Test. + if (pointIntersectPolygon2D( pNrm, coordinates, q)) { + if (dist != null) { + computeMinDistance(coordinates, + sphere.getCenter(), + pNrm, + dist, iPnt); + } + return true; + } + return false; + + } + + + boolean intersectBoundingPolytope(Point3d coordinates[], + BoundingPolytope polytope, + double dist[], + Point3d iPnt) + { + boolean debug = false; + + Point4d tP4d = new Point4d(); + + // this is a multiplier to the halfplane distance coefficients + double distanceSign = -1.0; + + if(coordinates.length == 2) { + // we'll handle line separately. + if (polytope.intersect( coordinates[0], + coordinates[1], tP4d)) { + if (dist != null) { + iPnt.x = tP4d.x; + iPnt.y = tP4d.y; + iPnt.z = tP4d.z; + Point3d pc = polytope.getCenter(); + double x = iPnt.x - pc.x; + double y = iPnt.y - pc.y; + double z = iPnt.z - pc.z; + dist[0] = Math.sqrt(x*x + y*y + z*z); + } + return true; + } + return false; + } + + // It is a triangle or a quad. + + // first test to see if any of the coordinates are all inside of the + // intersection polytope's half planes + // essentially do a matrix multiply of the constraintMatrix K*3 with + // the input coordinates 3*1 = K*1 vector + + if (debug) { + System.err.println("The value of the input vertices are: "); + for(int i=0; i < coordinates.length; i++) { + System.err.println("The " +i+ " th vertex is: " + coordinates[i]); + } + + System.err.println("The value of the input bounding Polytope's planes ="); + for(int i=0; i < polytope.planes.length; i++) { + System.err.println("The " +i+ " th plane is: " + polytope.planes[i]); + } + + } + + // the direction for the intersection cost function + double centers[] = new double[4]; + centers[0] = 0.8; centers[1] = 0.9; centers[2] = 1.1; centers[3] = 1.2; + + boolean intersection = true; + boolean PreTest = false; + + if(PreTest) { + // for each coordinate, test it with each half plane + for( int i=0; i < coordinates.length; i++) { + for (int j=0; j < polytope.planes.length; j++) { + if ( ( polytope.planes[j].x * coordinates[i].x + + polytope.planes[j].y * coordinates[i].y + + polytope.planes[j].z*coordinates[i].z) <= + (distanceSign)*polytope.planes[j].w){ + // the point satisfies this particular hyperplane + intersection = true; + } else { + // the point fails this hyper plane try with a new hyper plane + intersection = false; + break; + } + } + if(intersection) { + // a point was found to be completely inside the bounding hull + if (dist != null) { + computeMinDistance(coordinates, + polytope.getCenter(), + null, + dist, iPnt); + } + return true; + } + } + } // end of pretest + + // at this point all points are outside of the bounding hull + // build the problem tableau for the linear program + + int numberCols = polytope.planes.length + 2 + coordinates.length + 1; + int numberRows = 1 + coordinates.length; + + double problemTableau[][] = new double[numberRows][numberCols]; + + // compute -Mtrans = -A*P + + for( int i = 0; i < polytope.planes.length; i++) { + for( int j=0; j < coordinates.length; j++) { + problemTableau[j][i] = (-1.0)* (polytope.planes[i].x*coordinates[j].x+ + polytope.planes[i].y*coordinates[j].y+ + polytope.planes[i].z*coordinates[j].z); + } + } + + // add the other rows + for(int i = 0; i < coordinates.length; i++) { + problemTableau[i][polytope.planes.length] = -1.0; + problemTableau[i][polytope.planes.length + 1] = 1.0; + + for(int j=0; j < coordinates.length; j++) { + if ( i==j ) { + problemTableau[i][j + polytope.planes.length + 2] = 1.0; + } else { + problemTableau[i][j + polytope.planes.length + 2] = 0.0; + } + + // place the last column elements the Ci's + problemTableau[i][numberCols - 1] = centers[i]; + } + } + + // place the final rows value + for(int j = 0; j < polytope.planes.length; j++) { + problemTableau[numberRows - 1][j] = + (distanceSign)*polytope.planes[j].w; + } + problemTableau[numberRows - 1][polytope.planes.length] = 1.0; + problemTableau[numberRows - 1][polytope.planes.length+1] = -1.0; + for(int j = 0; j < coordinates.length; j++) { + problemTableau[numberRows - 1][polytope.planes.length+2+j] = 0.0; + } + + if(debug) { + System.err.println("The value of the problem tableau is: " ); + for(int i=0; i < problemTableau.length; i++) { + for(int j=0; j < problemTableau[0].length; j++) { + System.err.print(problemTableau[i][j] + " "); + } + System.err.println(); + } + } + + double distance = generalStandardSimplexSolver(problemTableau, + Float.NEGATIVE_INFINITY); + if(debug) { + System.err.println("The value returned by the general standard simplex = " + + distance); + } + if (distance == Float.POSITIVE_INFINITY) { + return false; + } + if (dist != null) { + computeMinDistance(coordinates, + polytope.getCenter(), + null, + dist, iPnt); + } + return true; + + } + + + // optimized version using arrays of doubles, but using the standard simplex + // method to solve the LP tableau. This version has not been optimized to + // work with a particular size input tableau and is much slower than some + // of the other variants...supposedly + double generalStandardSimplexSolver(double problemTableau[][], + double stopingValue) { + boolean debug = false; + int numRow = problemTableau.length; + int numCol = problemTableau[0].length; + boolean optimal = false; + int i, pivotRowIndex, pivotColIndex; + double maxElement, element, endElement, ratio, prevRatio; + int count = 0; + double multiplier; + + if(debug) { + System.err.println("The number of rows is : " + numRow); + System.err.println("The number of columns is : " + numCol); + } + + // until the optimal solution is found continue to do + // iterations of the simplex method + while(!optimal) { + + if(debug) { + System.err.println("input problem tableau is:"); + for(int k=0; k < numRow; k++) { + for(int j=0; j < numCol; j++) { + System.err.println("kth, jth value is:" +k+" "+j+" : " + + problemTableau[k][j]); + } + } + } + + // test to see if the current solution is optimal + // check all bottom row elements except the right most one and + // if all positive or zero its optimal + for(i = 0, maxElement = 0, pivotColIndex = -1; i < numCol - 1; i++) { + // a bottom row element + element = problemTableau[numRow - 1][i]; + if( element < maxElement) { + maxElement = element; + pivotColIndex = i; + } + } + + // if there is no negative non-zero element then we + // have found an optimal solution (the last row of the tableau) + if(pivotColIndex == -1) { + // found an optimal solution + //System.err.println("Found an optimal solution"); + optimal = true; + } + + //System.err.println("The value of maxElement is:" + maxElement); + + if(!optimal) { + // Case when the solution is not optimal but not known to be + // either unbounded or infeasable + + // from the above we have found the maximum negative element in + // bottom row, we have also found the column for this value + // the pivotColIndex represents this + + // initialize the values for the algorithm, -1 for pivotRowIndex + // indicates no solution + + prevRatio = Float.POSITIVE_INFINITY; + ratio = 0.0; + pivotRowIndex = -1; + + // note if all of the elements in the pivot column are zero or + // negative the problem is unbounded. + for(i = 0; i < numRow - 1; i++) { + element = problemTableau[i][pivotColIndex]; // r value + endElement = problemTableau[i][numCol-1]; // s value + + // pivot according to the rule that we want to choose the row + // with smallest s/r ratio see third case + // currently we ignore valuse of r==0 (case 1) and cases where the + // ratio is negative, i.e. either r or s are negative (case 2) + if(element == 0) { + if(debug) { + System.err.println("Division by zero has occurred"); + System.err.println("Within the linear program solver"); + System.err.println("Ignoring the zero as a potential pivot"); + } + } else if ( (element < 0.0) || (endElement < 0.0) ){ + if(debug) { + System.err.println("Ignoring cases where element is negative"); + System.err.println("The value of element is: " + element); + System.err.println("The value of end Element is: " + endElement); + } + } else { + ratio = endElement/element; // should be s/r + if(debug) { + System.err.println("The value of element is: " + element); + System.err.println("The value of endElement is: " + endElement); + System.err.println("The value of ratio is: " + ratio); + System.err.println("The value of prevRatio is: " + prevRatio); + System.err.println("Value of ratio <= prevRatio is :" + + (ratio <= prevRatio)); + } + if(ratio <= prevRatio) { + if(debug) { + System.err.println("updating prevRatio with ratio"); + } + prevRatio = ratio; + pivotRowIndex = i; + } + } + } + + // if the pivotRowIndex is still -1 then we know the pivotColumn + // has no viable pivot points and the solution is unbounded or + // infeasable (all pivot elements were either zero or negative or + // the right most value was negative (the later shouldn't happen?) + if(pivotRowIndex == -1) { + if(debug) { + System.err.println("UNABLE TO FIND SOLUTION"); + System.err.println("The system is infeasable or unbounded"); + } + return(Float.POSITIVE_INFINITY); + } + + // we now have the pivot row and col all that remains is + // to divide through by this value and subtract the appropriate + // multiple of the pivot row from all other rows to obtain + // a tableau which has a column of all zeros and one 1 in the + // intersection of pivot row and col + + // divide through by the pivot value + double pivotValue = problemTableau[pivotRowIndex][pivotColIndex]; + + if(debug) { + System.err.println("The value of row index is: " + pivotRowIndex); + System.err.println("The value of col index is: " + pivotColIndex); + System.err.println("The value of pivotValue is: " + pivotValue); + } + // divide through by s on the pivot row to obtain a 1 in pivot col + for(i = 0; i < numCol; i++) { + problemTableau[pivotRowIndex][i] = + problemTableau[pivotRowIndex][i] / pivotValue; + } + + // subtract appropriate multiple of pivot row from all other rows + // to zero out all rows except the final row and the pivot row + for(i = 0; i < numRow; i++) { + if(i != pivotRowIndex) { + multiplier = problemTableau[i][pivotColIndex]; + for(int j=0; j < numCol; j++) { + problemTableau[i][j] = problemTableau[i][j] - + multiplier * problemTableau[pivotRowIndex][j]; + } + } + } + } + // case when the element is optimal + } + return(problemTableau[numRow - 1][numCol - 1]); + } + + + + boolean edgeIntersectSphere(BoundingSphere sphere, Point3d start, + Point3d end) + { + double abLenSq, acLenSq, apLenSq, abDotAp, radiusSq; + Vector3d ab = new Vector3d(); + Vector3d ap = new Vector3d(); + + ab.x = end.x - start.x; + ab.y = end.y - start.y; + ab.z = end.z - start.z; + + ap.x = sphere.center.x - start.x; + ap.y = sphere.center.y - start.y; + ap.z = sphere.center.z - start.z; + + abDotAp = ab.dot(ap); + + if(abDotAp < 0.0) { + return false; // line segment points away from sphere. + } + + abLenSq = ab.lengthSquared(); + acLenSq = abDotAp * abDotAp / abLenSq; + + if(acLenSq < abLenSq) { + return false; // C doesn't lies between end points of edge. + } + + radiusSq = sphere.radius * sphere.radius; + apLenSq = ap.lengthSquared(); + + if((apLenSq - acLenSq) <= radiusSq) { + return true; + } + + return false; + + } + + + double det2D(Point2d a, Point2d b, Point2d p) + { + return (((p).x - (a).x) * ((a).y - (b).y) + + ((a).y - (p).y) * ((a).x - (b).x)); + } + + // Assume coord is CCW. + boolean pointIntersectPolygon2D(Vector3d normal, Point3d[] coord, + Point3d point) + { + + double absNrmX, absNrmY, absNrmZ; + Point2d coord2D[] = new Point2d[coord.length]; + Point2d pnt = new Point2d(); + + int i, j, axis; + + // Project 3d points onto 2d plane. + // Note : Area of polygon is not preserve in this projection, but + // it doesn't matter here. + + // Find the axis of projection. + absNrmX = Math.abs(normal.x); + absNrmY = Math.abs(normal.y); + absNrmZ = Math.abs(normal.z); + + if(absNrmX > absNrmY) + axis = 0; + else + axis = 1; + + if(axis == 0) { + if(absNrmX < absNrmZ) + axis = 2; + } + else if(axis == 1) { + if(absNrmY < absNrmZ) + axis = 2; + } + + // System.err.println("Normal " + normal + " axis " + axis ); + + for(i=0; i0.0) + ; + else + return false; + else + if(det2D(coord2D[j], coord2D[0], pnt)>0.0) + ; + else + return false; + } + + return true; + + } + + + boolean edgeIntersectPlane(Vector3d normal, Point3d pnt, Point3d start, + Point3d end, Point3d iPnt) + { + + Vector3d tempV3d = new Vector3d(); + Vector3d direction = new Vector3d(); + double pD, pNrmDotrDir, tr; + + // Compute plane D. + tempV3d.set((Tuple3d) pnt); + pD = normal.dot(tempV3d); + + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + pNrmDotrDir = normal.dot(direction); + + // edge is parallel to plane. + if(pNrmDotrDir== 0.0) { + // System.err.println("Edge is parallel to plane."); + return false; + } + + tempV3d.set((Tuple3d) start); + + tr = (pD - normal.dot(tempV3d))/ pNrmDotrDir; + + // Edge intersects the plane behind the edge's start. + // or exceed the edge's length. + if((tr < 0.0 ) || (tr > 1.0 )) { + // System.err.println("Edge intersects the plane behind the start or exceed end."); + return false; + } + + iPnt.x = start.x + tr * direction.x; + iPnt.y = start.y + tr * direction.y; + iPnt.z = start.z + tr * direction.z; + + return true; + + } + + // Assume coord is CCW. + boolean edgeIntersectPolygon2D(Vector3d normal, Point3d[] coord, + Point3d[] seg) + { + + double absNrmX, absNrmY, absNrmZ; + Point2d coord2D[] = new Point2d[coord.length]; + Point2d seg2D[] = new Point2d[2]; + + int i, j, axis; + + // Project 3d points onto 2d plane. + // Note : Area of polygon is not preserve in this projection, but + // it doesn't matter here. + + // Find the axis of projection. + absNrmX = Math.abs(normal.x); + absNrmY = Math.abs(normal.y); + absNrmZ = Math.abs(normal.z); + + if(absNrmX > absNrmY) + axis = 0; + else + axis = 1; + + if(axis == 0) { + if(absNrmX < absNrmZ) + axis = 2; + } + else if(axis == 1) { + if(absNrmY < absNrmZ) + axis = 2; + } + + // System.err.println("Normal " + normal + " axis " + axis ); + + for(i=0; i nAbsY) { + if(nAbsX > nAbsZ) { + i0 = 1; // nAbsX is greatest. + i1 = 2; + } + else { + i0 = 0; // nAbsZ is greatest. + i1 = 1; + } + } else { // nAbsX <= nAbsY + if(nAbsZ > nAbsY) { + i0 = 0; // nAbsZ is greatest. + i1 = 1; + } + else { + i0 = 0; // nAbsY is greatest. + i1 = 2; + } + } + return pointInTri(v0, u0, u1, u2, i0, i1); + } + + boolean pointInTri(Point3d v0, Point3d u0, Point3d u1, Point3d u2, + int i0, int i1) { + + double a, b, c, d0, d1, d2; + // is T1 completely inside T2 ? + // check if v0 is inside tri(u0,u1,u2) + + a = getCompValue(u1, u0, i1); + b = -(getCompValue(u1, u0, i0)); + c = -a * getCompValue(u0, i0) - b * getCompValue(u0, i1); + d0 = a * getCompValue(v0, i0) + b * getCompValue(v0, i1) + c; + + a = getCompValue(u2, u1, i1); + b = -(getCompValue(u2, u1, i0)); + c = -a * getCompValue(u1, i0) - b * getCompValue(u1, i1); + d1 = a * getCompValue(v0, i0) + b * getCompValue(v0, i1) + c; + + a = getCompValue(u0, u2, i1); + b = -(getCompValue(u0, u2, i0)); + c = -a * getCompValue(u2, i0) - b * getCompValue(u2, i1); + d2 = a * getCompValue(v0, i0) + b * getCompValue(v0, i1) + c; + + if(d0*d1>0.0) { + if(d0*d2>0.0) { + return true; + } + } + return false; + } + + + // this edge to edge test is based on Franlin Antonio's gem: + // "Faster line segment intersection", in Graphics Gems III, pp 199-202 + boolean edgeAgainstEdge(Point3d v0, Point3d u0, Point3d u1, double aX, double aY, + int i0, int i1) { + double bX, bY, cX, cY, e, d, f; + + bX = getCompValue(u0, u1,i0); + bY = getCompValue(u0, u1, i1); + cX = getCompValue(v0, u0, i0); + cY = getCompValue(v0, u0, i1); + + f = aY * bX - aX * bY; + d = bY * cX - bX * cY; + if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f)) { + e = aX * cY - aY * cX; + if(f>0) { + if(e>=0 && e<=f) + return true; + } + else { + if(e<=0 && e>=f) + return true; + } + } + + return false; + } + + + boolean edgeAgainstTriEdges(Point3d v0, Point3d v1, Point3d u0, + Point3d u1, Point3d u2, int i0, int i1) { + double aX, aY; + + // aX = v1[i0] - v0[i0]; + // aY = v1[i1] - v0[i1]; + aX = getCompValue(v1, v0, i0); + aY = getCompValue(v1, v0, i1); + + // test edge u0, u1 against v0, v1 + if(edgeAgainstEdge(v0, u0, u1, aX, aY, i0, i1)) + return true; + // test edge u1, u2 against v0, v1 + if(edgeAgainstEdge(v0, u1, u2, aX, aY, i0, i1)) + return true; + // test edge u2, u0 against v0, v1 + if(edgeAgainstEdge(v0, u2, u0, aX, aY, i0, i1)) + return true; + + return false; + + } + + boolean coplanarTriTri(Vector3d normal, Point3d v0, Point3d v1, Point3d v2, + Point3d u0, Point3d u1, Point3d u2) { + + double nAbsX, nAbsY, nAbsZ; + int i0, i1; + + // first project onto an axis-aligned plane, that maximizes the area + // of the triangles, compute indices i0, i1. + nAbsX = Math.abs(normal.x); + nAbsY = Math.abs(normal.y); + nAbsZ = Math.abs(normal.z); + + if(nAbsX > nAbsY) { + if(nAbsX > nAbsZ) { + i0 = 1; // nAbsX is greatest. + i1 = 2; + } + else { + i0 = 0; // nAbsZ is greatest. + i1 = 1; + } + } + else { // nAbsX <= nAbsY + if(nAbsZ > nAbsY) { + i0 = 0; // nAbsZ is greatest. + i1 = 1; + } + else { + i0 = 0; // nAbsY is greatest. + i1 = 2; + } + } + + // test all edges of triangle 1 against the edges of triangle 2 + if(edgeAgainstTriEdges(v0, v1, u0, u1, u2, i0, i1)) + return true; + + if(edgeAgainstTriEdges(v1, v2, u0, u1, u2, i0, i1)) + return true; + + if(edgeAgainstTriEdges(v2, v0, u0, u1, u2, i0, i1)) + return true; + + // finally, test if tri1 is totally contained in tri2 or vice versa. + if(pointInTri(v0, u0, u1, u2, i0, i1)) + return true; + + if(pointInTri(u0, v0, v1, v2, i0, i1)) + return true; + + return false; + } + + + + + + boolean intersectTriPnt(Point3d v0, Point3d v1, Point3d v2, Point3d u) { + + Vector3d e1 = new Vector3d(); + Vector3d e2 = new Vector3d(); + Vector3d n1 = new Vector3d(); + Vector3d tempV3d = new Vector3d(); + + double d1, du; + + // compute plane equation of triange(coord1) + e1.x = v1.x - v0.x; + e1.y = v1.y - v0.y; + e1.z = v1.z - v0.z; + + e2.x = v2.x - v0.x; + e2.y = v2.y - v0.y; + e2.z = v2.z - v0.z; + + n1.cross(e1,e2); + + if(n1.length() == 0.0) { + // System.err.println("(1) Degenerate triangle."); + return false; // Degenerate triangle. + } + + tempV3d.set((Tuple3d) v0); + d1 = - n1.dot(tempV3d); // plane equation 1: n1.x + d1 = 0 + + // put u to compute signed distance to the plane. + tempV3d.set((Tuple3d) u); + du = n1.dot(tempV3d) + d1; + + // coplanarity robustness check + if(Math.abs(du) nAbsY) { + if(nAbsX > nAbsZ) { + i0 = 1; // nAbsX is greatest. + i1 = 2; + } + else { + i0 = 0; // nAbsZ is greatest. + i1 = 1; + } + } + else { // nAbsX <= nAbsY + if(nAbsZ > nAbsY) { + i0 = 0; // nAbsZ is greatest. + i1 = 1; + } + else { + i0 = 0; // nAbsY is greatest. + i1 = 2; + } + } + + + // finally, test if u is totally contained in tri. + if(pointInTri(u, v0, v1, v2, i0, i1)) { + return true; + } + + return false; + } + + + /** + * Return flag indicating whether two triangles intersect. This + * uses Tomas Moller's code for fast triangle-triangle + * intersection from his "Real-Time Rendering" book. + * + * The code is now divisionless. It tests for separating by planes + * parallel to either triangle. If neither separate the + * triangles, then two cases are considered. First case is if the + * normals to the triangles are parallel. In that case, the + * triangles are coplanar and a sequence of tests are made to see + * if edges of each triangle intersect the other triangle. If the + * normals are not parallel, then the two triangles can intersect + * only on the line of intersection of the two planes. The + * intervals of intersection of the triangles with the line of + * intersection of the two planes are computed and tested for + * overlap. + */ + boolean intersectTriTri(Point3d v0, Point3d v1, Point3d v2, + Point3d u0, Point3d u1, Point3d u2) { + + // System.err.println("In intersectTriTri ..."); + Vector3d e1 = new Vector3d(); + Vector3d e2 = new Vector3d(); + Vector3d n1 = new Vector3d(); + Vector3d n2 = new Vector3d(); + Vector3d tempV3d = new Vector3d(); + + double d1, d2; + double du0, du1, du2, dv0, dv1, dv2; + double du0du1, du0du2, dv0dv1, dv0dv2; + int index; + double vp0=0.0, vp1=0.0, vp2=0.0; + double up0=0.0, up1=0.0, up2=0.0; + double bb, cc, max; + + // compute plane equation of triange(coord1) + e1.x = v1.x - v0.x; + e1.y = v1.y - v0.y; + e1.z = v1.z - v0.z; + + e2.x = v2.x - v0.x; + e2.y = v2.y - v0.y; + e2.z = v2.z - v0.z; + + n1.cross(e1,e2); + + if(n1.length() == 0.0) { + // System.err.println("(1) Degenerate triangle."); + return false; // Degenerate triangle. + } + + tempV3d.set((Tuple3d) v0); + d1 = - n1.dot(tempV3d); // plane equation 1: n1.x + d1 = 0 + + // put u0, u1, and u2 into plane equation 1 + // to compute signed distance to the plane. + tempV3d.set((Tuple3d) u0); + du0 = n1.dot(tempV3d) + d1; + tempV3d.set((Tuple3d) u1); + du1 = n1.dot(tempV3d) + d1; + tempV3d.set((Tuple3d) u2); + du2 = n1.dot(tempV3d) + d1; + + // coplanarity robustness check + if(Math.abs(du0)0.0 && du0du2>0.0) { + // System.err.println("In intersectTriTri : du0du1>0.0 && du0du2>0.0"); + return false; + } + + // compute plane of triangle(coord2) + e1.x = u1.x - u0.x; + e1.y = u1.y - u0.y; + e1.z = u1.z - u0.z; + + e2.x = u2.x - u0.x; + e2.y = u2.y - u0.y; + e2.z = u2.z - u0.z; + + n2.cross(e1,e2); + + if(n2.length() == 0.0) { + // System.err.println("(2) Degenerate triangle."); + return false; // Degenerate triangle. + } + + tempV3d.set((Tuple3d) u0); + d2 = - n2.dot(tempV3d); // plane equation 2: n2.x + d2 = 0 + + // put v0, v1, and v2 into plane equation 2 + // to compute signed distance to the plane. + tempV3d.set((Tuple3d) v0); + dv0 = n2.dot(tempV3d) + d2; + tempV3d.set((Tuple3d) v1); + dv1 = n2.dot(tempV3d) + d2; + tempV3d.set((Tuple3d) v2); + dv2 = n2.dot(tempV3d) + d2; + + // coplanarity robustness check + if(Math.abs(dv0)0.0 && dv0dv2>0.0) { + // System.err.println("In intersectTriTri : dv0dv1>0.0 && dv0dv2>0.0"); + return false; + } + // compute direction of intersection line. + tempV3d.cross(n1, n2); + + // compute and index to the largest component of tempV3d. + max = Math.abs(tempV3d.x); + index = 0; + bb = Math.abs(tempV3d.y); + cc = Math.abs(tempV3d.z); + if(bb>max) { + max=bb; + index=1; + } + if(cc>max) { + max=cc; + index=2; + } + + // this is the simplified projection onto L. + + switch (index) { + case 0: + vp0 = v0.x; + vp1 = v1.x; + vp2 = v2.x; + + up0 = u0.x; + up1 = u1.x; + up2 = u2.x; + break; + case 1: + vp0 = v0.y; + vp1 = v1.y; + vp2 = v2.y; + + up0 = u0.y; + up1 = u1.y; + up2 = u2.y; + break; + case 2: + vp0 = v0.z; + vp1 = v1.z; + vp2 = v2.z; + + up0 = u0.z; + up1 = u1.z; + up2 = u2.z; + break; + } + + // compute intereval for triangle 1. + double a=0.0, b=0.0, c=0.0, x0=0.0, x1=0.0; + if(dv0dv1>0.0) { + // here we know that dv0dv2 <= 0.0 that is dv0 and dv1 are on the same side, + // dv2 on the other side or on the plane. + a = vp2; b = (vp0 - vp2) * dv2; c = (vp1 - vp2) * dv2; + x0 = dv2 - dv0; x1 = dv2 - dv1; + } + else if(dv0dv2>0.0) { + // here we know that dv0dv1<=0.0 + a = vp1; b = (vp0 - vp1) * dv1; c = (vp2 - vp1) * dv1; + x0 = dv1 - dv0; x1 = dv1 - dv2; + } + else if((dv1*dv2>0.0) || (dv0 != 0.0)) { + // here we know that dv0vd1<=0.0 or that dv0!=0.0 + a = vp0; b = (vp1 - vp0) * dv0; c = (vp2 - vp0) * dv0; + x0 = dv0 - dv1; x1 = dv0 - dv2; + } + else if(dv1 != 0.0) { + a = vp1; b = (vp0 - vp1) * dv1; c = (vp2 - vp1) * dv1; + x0 = dv1 - dv0; x1 = dv1 - dv2; + } + else if(dv2 != 0.0) { + a = vp2; b = (vp0 - vp2) * dv2; c = (vp1 - vp2) * dv2; + x0 = dv2 - dv0; x1 = dv2 - dv1; + } + else { + // triangles are coplanar + boolean toreturn = coplanarTriTri(n1, v0, v1, v2, u0, u1, u2); + return toreturn; + } + + + // compute intereval for triangle 2. + double d=0.0, e=0.0, f=0.0, y0=0.0, y1=0.0; + if(du0du1>0.0) { + // here we know that du0du2 <= 0.0 that is du0 and du1 are on the same side, + // du2 on the other side or on the plane. + d = up2; e = (up0 - up2) * du2; f = (up1 - up2) * du2; + y0 = du2 - du0; y1 = du2 - du1; + } + else if(du0du2>0.0) { + // here we know that du0du1<=0.0 + d = up1; e = (up0 - up1) * du1; f = (up2 - up1) * du1; + y0 = du1 - du0; y1 = du1 - du2; + } + else if((du1*du2>0.0) || (du0 != 0.0)) { + // here we know that du0du1<=0.0 or that D0!=0.0 + d = up0; e = (up1 - up0) * du0; f = (up2 - up0) * du0; + y0 = du0 - du1; y1 = du0 - du2; + } + else if(du1 != 0.0) { + d = up1; e = (up0 - up1) * du1; f = (up2 - up1) * du1; + y0 = du1 - du0; y1 = du1 - du2; + } + else if(du2 != 0.0) { + d = up2; e = (up0 - up2) * du2; f = (up1 - up2) * du2; + y0 = du2 - du0; y1 = du2 - du1; + } + else { + // triangles are coplanar + // System.err.println("In intersectTriTri : coplanarTriTri test 2"); + boolean toreturn = coplanarTriTri(n2, v0, v1, v2, u0, u1, u2); + return toreturn; + } + + double xx, yy, xxyy, tmp, isect1S, isect1E, isect2S, isect2E; + xx = x0 * x1; + yy = y0 * y1; + xxyy = xx * yy; + + tmp = a * xxyy; + isect1S = tmp + b * x1 * yy; + isect1E = tmp + c * x0 * yy; + + tmp = d * xxyy; + isect2S = tmp + e * y1 * xx; + isect2E = tmp + f * y0 * xx; + + // sort so that isect1S <= isect1E + if(isect1S > isect1E) { + tmp = isect1S; + isect1S = isect1E; + isect1E = tmp; + } + + // sort so that isect2S <= isect2E + if(isect2S > isect2E) { + tmp = isect2S; + isect2S = isect2E; + isect2E = tmp; + } + + if(isect1E 0.0) + break; + } + + for(j=i; j 0.0) + break; + } + + if(j == (coord1.length-1)) { + // System.err.println("(1) Degenerate polygon."); + return false; // Degenerate polygon. + } + + /* + for(i=0; i1) { + break; + } + } + } + + if (j==0) { + return false; + } + + if (coord2.length < 3) { + boolean toreturn = pointIntersectPolygon2D(pNrm, coord1, seg[0]); + return toreturn; + } else { + boolean toreturn = edgeIntersectPolygon2D(pNrm, coord1, seg); + return toreturn; + } + } + + + /** + * Return true if triangle or quad intersects with ray and the + * distance is stored in dist[0] and the intersect point in iPnt + * (if iPnt is not null). + */ + boolean intersectRay(Point3d coordinates[], PickRay ray, double dist[], + Point3d iPnt) { + + return intersectRayOrSegment(coordinates, ray.direction, ray.origin, + dist, iPnt, false); + + } + + /** + * Return true if triangle or quad intersects with segment and + * the distance is stored in dist[0]. + */ + boolean intersectSegment( Point3d coordinates[], Point3d start, Point3d end, + double dist[], Point3d iPnt ) { + boolean result; + Vector3d direction = new Vector3d(); + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + result = intersectRayOrSegment(coordinates, direction, start, dist, iPnt, true); + return result; + } + + + + /** + * Return true if triangle or quad intersects with ray and the distance is + * stored in pr. + */ + boolean intersectRayOrSegment(Point3d coordinates[], + Vector3d direction, Point3d origin, + double dist[], Point3d iPnt, boolean isSegment) { + Vector3d vec0, vec1, pNrm, tempV3d; + vec0 = new Vector3d(); + vec1 = new Vector3d(); + pNrm = new Vector3d(); + + double absNrmX, absNrmY, absNrmZ, pD = 0.0; + double pNrmDotrDir = 0.0; + + boolean isIntersect = false; + int i, j, k=0, l = 0; + + // Compute plane normal. + for (i=0; i 0.0) { + break; + } + } + + + for (j=l; j 0.0) { + break; + } + } + + pNrm.cross(vec0,vec1); + + if ((vec1.length() == 0) || (pNrm.length() == 0)) { + // degenerate to line if vec0.length() == 0 + // or vec0.length > 0 and vec0 parallel to vec1 + k = (l == 0 ? coordinates.length-1: l-1); + isIntersect = intersectLineAndRay(coordinates[l], + coordinates[k], + origin, + direction, + dist, + iPnt); + + // put the Vectors on the freelist + return isIntersect; + } + + // It is possible that Quad is degenerate to Triangle + // at this point + + pNrmDotrDir = pNrm.dot(direction); + + // Ray is parallel to plane. + if (pNrmDotrDir == 0.0) { + // Ray is parallel to plane + // Check line/triangle intersection on plane. + for (i=0; i < coordinates.length ;i++) { + if (i != coordinates.length-1) { + k = i+1; + } else { + k = 0; + } + if (intersectLineAndRay(coordinates[i], + coordinates[k], + origin, + direction, + dist, + iPnt)) { + isIntersect = true; + break; + } + } + return isIntersect; + } + + // Plane equation: (p - p0)*pNrm = 0 or p*pNrm = pD; + tempV3d = new Vector3d(); + tempV3d.set((Tuple3d) coordinates[0]); + pD = pNrm.dot(tempV3d); + tempV3d.set((Tuple3d) origin); + + // Substitute Ray equation: + // p = origin + pi.distance*direction + // into the above Plane equation + + dist[0] = (pD - pNrm.dot(tempV3d))/ pNrmDotrDir; + + // Ray intersects the plane behind the ray's origin. + if ((dist[0] < -EPS ) || + (isSegment && (dist[0] > 1.0+EPS))) { + // Ray intersects the plane behind the ray's origin + // or intersect point not fall in Segment + return false; + } + + // Now, one thing for sure the ray intersect the plane. + // Find the intersection point. + if (iPnt == null) { + iPnt = new Point3d(); + } + iPnt.x = origin.x + direction.x * dist[0]; + iPnt.y = origin.y + direction.y * dist[0]; + iPnt.z = origin.z + direction.z * dist[0]; + + // Project 3d points onto 2d plane + // Find the axis so that area of projection is maximize. + absNrmX = Math.abs(pNrm.x); + absNrmY = Math.abs(pNrm.y); + absNrmZ = Math.abs(pNrm.z); + + // All sign of (y - y0) (x1 - x0) - (x - x0) (y1 - y0) + // must agree. + double sign, t, lastSign = 0; + Point3d p0 = coordinates[coordinates.length-1]; + Point3d p1 = coordinates[0]; + + isIntersect = true; + + if (absNrmX > absNrmY) { + if (absNrmX < absNrmZ) { + for (i=0; i < coordinates.length; i++) { + p0 = coordinates[i]; + p1 = (i != coordinates.length-1 ? coordinates[i+1]: coordinates[0]); + sign = (iPnt.y - p0.y)*(p1.x - p0.x) - + (iPnt.x - p0.x)*(p1.y - p0.y); + if (isNonZero(sign)) { + if (sign*lastSign < 0) { + isIntersect = false; + break; + } + lastSign = sign; + } else { // point on line, check inside interval + t = p1.y - p0.y; + if (isNonZero(t)) { + t = (iPnt.y - p0.y)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + t = p1.x - p0.x; + if (isNonZero(t)) { + t = (iPnt.x - p0.x)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + // Ignore degenerate line=>point happen when Quad => Triangle. + // Note that by next round sign*lastSign = 0 so it will + // not pass the interest test. This should only happen once in the + // loop because we already check for degenerate geometry before. + } + } + } + } + } else { + for (i=0; i -EPS) && (t < 1+EPS)); + break; + + } else { + t = p1.z - p0.z; + if (isNonZero(t)) { + t = (iPnt.z - p0.z)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + //degenerate line=>point + } + } + } + } + } + } else { + if (absNrmY < absNrmZ) { + for (i=0; i -EPS) && (t < 1+EPS)); + break; + } else { + t = p1.x - p0.x; + if (isNonZero(t)) { + t = (iPnt.x - p0.x)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + //degenerate line=>point + } + } + } + } + } else { + for (i=0; i -EPS) && (t < 1+EPS)); + break; + } else { + t = p1.z - p0.z; + if (isNonZero(t)) { + t = (iPnt.z - p0.z)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + //degenerate line=>point + } + } + } + } + } + } + + if (isIntersect) { + dist[0] *= direction.length(); + } + return isIntersect; + } + + + + static final boolean isNonZero(double v) { + return ((v > EPS) || (v < -EPS)); + + } + + /** + * Return true if point is on the inside of halfspace test. The + * halfspace is partition by the plane of triangle or quad. + */ + boolean inside( Point3d coordinates[], PickPoint point, int ccw ) { + + Vector3d vec0 = new Vector3d(); // Edge vector from point 0 to point 1; + Vector3d vec1 = new Vector3d(); // Edge vector from point 0 to point 2 or 3; + Vector3d pNrm = new Vector3d(); + double absNrmX, absNrmY, absNrmZ, pD = 0.0; + Vector3d tempV3d = new Vector3d(); + double pNrmDotrDir = 0.0; + + double tempD; + + int i, j; + + // Compute plane normal. + for(i=0; i 0.0) + break; + } + + for(j=i; j 0.0) + break; + } + + if(j == (coordinates.length-1)) { + // System.err.println("(1) Degenerate polygon."); + return false; // Degenerate polygon. + } + + /* + System.err.println("Ray orgin : " + ray.origin + " dir " + ray.direction); + System.err.println("Triangle/Quad :"); + for(i=0; i (temp + EPS))) + return false; + } + + if(flag < 2) { + temp = ori.z + dist[0] * dir.z; + if((pnt.z < (temp - EPS)) || (pnt.z > (temp + EPS))) + return false; + } + + return true; + + } + + boolean intersectLineAndRay(Point3d start, Point3d end, + Point3d ori, Vector3d dir, double dist[], + Point3d iPnt) { + + double m00, m01, m10, m11; + double mInv00, mInv01, mInv10, mInv11; + double dmt, t, s, tmp1, tmp2; + Vector3d lDir; + + // System.err.println("GeometryArrayRetained : intersectLineAndRay"); + // System.err.println("start " + start + " end " + end ); + // System.err.println("ori " + ori + " dir " + dir); + + lDir = new Vector3d(); + lDir.x = (end.x - start.x); + lDir.y = (end.y - start.y); + lDir.z = (end.z - start.z); + + m00 = lDir.x; + m01 = -dir.x; + m10 = lDir.y; + m11 = -dir.y; + + // Get the determinant. + dmt = (m00 * m11) - (m10 * m01); + + if (dmt==0.0) { // No solution, check degenerate line + boolean isIntersect = false; + if ((lDir.x == 0) && (lDir.y == 0) && (lDir.z == 0)) { + isIntersect = intersectPntAndRay(start, ori, dir, dist); + if (isIntersect && (iPnt != null)) { + iPnt.set(start); + } + } + return isIntersect; + } + // Find the inverse. + tmp1 = 1/dmt; + + mInv00 = tmp1 * m11; + mInv01 = tmp1 * (-m01); + mInv10 = tmp1 * (-m10); + mInv11 = tmp1 * m00; + + tmp1 = ori.x - start.x; + tmp2 = ori.y - start.y; + + t = mInv00 * tmp1 + mInv01 * tmp2; + s = mInv10 * tmp1 + mInv11 * tmp2; + + if(s<0.0) { // Before the origin of ray. + // System.err.println("Before the origin of ray " + s); + return false; + } + if((t<0)||(t>1.0)) {// Before or after the end points of line. + // System.err.println("Before or after the end points of line. " + t); + return false; + } + + tmp1 = ori.z + s * dir.z; + tmp2 = start.z + t * lDir.z; + + if((tmp1 < (tmp2 - EPS)) || (tmp1 > (tmp2 + EPS))) { + // System.err.println("No intersection : tmp1 " + tmp1 + " tmp2 " + tmp2); + return false; + } + + dist[0] = s; + + if (iPnt != null) { + // compute point of intersection. + iPnt.x = ori.x + dir.x * dist[0]; + iPnt.y = ori.y + dir.y * dist[0]; + iPnt.z = ori.z + dir.z * dist[0]; + } + + // System.err.println("Intersected : tmp1 " + tmp1 + " tmp2 " + tmp2); + return true; + } + + /** + Return true if triangle or quad intersects with cylinder. The + distance is stored in dist. + */ + boolean intersectCylinder(Point3d coordinates[], PickCylinder cyl, + double dist[], Point3d iPnt) { + + Point3d origin = new Point3d(); + Point3d end = new Point3d(); + Vector3d direction = new Vector3d(); + Point3d iPnt1 = new Point3d(); + Vector3d originToIpnt = new Vector3d(); + + if (iPnt == null) { + iPnt = new Point3d(); + } + + // Get cylinder information + cyl.getOrigin (origin); + cyl.getDirection (direction); + double radius = cyl.getRadius (); + + if (cyl instanceof PickCylinderSegment) { + ((PickCylinderSegment)cyl).getEnd (end); + } + + // If the ray intersects, we're good (do not do this if we only have + // a segment + if (coordinates.length > 2) { + if (cyl instanceof PickCylinderRay) { + if (intersectRay(coordinates, + new PickRay(origin, direction), + dist, iPnt)) { + return true; + } + } + else { + if (intersectSegment(coordinates, origin, end, dist, iPnt)) { + return true; + } + } + } + + // Ray doesn't intersect, check distance to edges + double sqDistToEdge; + int j; + for (int i=0; i 2) { + if (cone instanceof PickConeRay) { + if (intersectRay(coordinates, + new PickRay (origin, direction), + dist, iPnt)) { + return true; + } + } + else { + if (intersectSegment(coordinates, origin, end, dist, iPnt)) { + return true; + } + } + } + + // Ray doesn't intersect, check distance to edges + double sqDistToEdge; + int j = 0; + for (int i=0; i= coords.getBufferImpl().limit()) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } else if (coords.getBufferImpl().limit() < (3*(initialCoordIndex+validVertexCount))) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + } + + // lock the geometry and start to do real work + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + coordRefBuffer = coords; + if(coords == null) { + floatBufferRefCoords = null; + doubleBufferRefCoords = null; + // XXXX: if not mix java array with nio buffer + // vertexType can be used as vertexTypeBuffer + vertexType &= ~PD; + vertexType &= ~PF; + }else { + switch (coords.getBufferType()) { + case J3DBuffer.TYPE_FLOAT: + floatBufferRefCoords = + (FloatBufferWrapper)coords.getBufferImpl(); + doubleBufferRefCoords = null; + vertexType |= PF; + vertexType &= ~PD; + break; + case J3DBuffer.TYPE_DOUBLE: + floatBufferRefCoords = null; + doubleBufferRefCoords = + (DoubleBufferWrapper)coords.getBufferImpl(); + vertexType |= PD; + vertexType &= ~PF; + break; + default: + break; + } + } + + // need not call setupMirrorVertexPointer() since + // we are not going to set mirror in NIO buffer case + // XXXX: if we need to mix java array with buffer, + // we may need to consider setupMirrorVertexPointer() + + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && source != null) { + if (isLive) { + processCoordsChanged((coords == null)); + sendDataChangedMessage(true); + } else { + boundsDirty = true; + } + } + + } + + + J3DBuffer getCoordRefBuffer() { + return coordRefBuffer; + } + + + void setCoordRefFloat(float[] coords) { + + // If non-null coordinate and vertType is either defined + // to be something other than PF, then issue an error + if (coords != null) { + if ((vertexType & VERTEX_DEFINED) != 0 && + (vertexType & VERTEX_DEFINED) != PF) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (3 * idx.maxCoordIndex >= coords.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } else if (coords.length < 3 * (initialCoordIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + + floatRefCoords = coords; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (coords == null) + vertexType &= ~PF; + else + vertexType |= PF; + } + else { + setupMirrorVertexPointer(PF); + } + + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && source != null) { + if (isLive) { + processCoordsChanged(coords == null); + sendDataChangedMessage(true); + } else { + boundsDirty = true; + } + } + } + + + float[] getCoordRefFloat() { + return floatRefCoords; + } + + + void setCoordRefDouble(double[] coords) { + + if (coords != null) { + if ((vertexType & VERTEX_DEFINED) != 0 && + (vertexType & VERTEX_DEFINED) != PD) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + if (3 * idx.maxCoordIndex >= coords.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } else if (coords.length < 3 * (initialCoordIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + doubleRefCoords = coords; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (coords == null) + vertexType &= ~PD; + else + vertexType |= PD; + } + else { + setupMirrorVertexPointer(PD); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && source != null) { + if (isLive) { + processCoordsChanged(coords == null); + sendDataChangedMessage(true); + } else { + boundsDirty = true; + } + } + } + + double[] getCoordRefDouble() { + return doubleRefCoords; + } + + void setCoordRef3f(Point3f[] coords) { + + if (coords != null) { + if ((vertexType & VERTEX_DEFINED) != 0 && + (vertexType & VERTEX_DEFINED) != P3F) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (idx.maxCoordIndex >= coords.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } else if (coords.length < (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + p3fRefCoords = coords; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (coords == null) + vertexType &= ~P3F; + else + vertexType |= P3F; + } + else { + setupMirrorVertexPointer(P3F); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && source != null) { + if (isLive) { + processCoordsChanged(coords == null); + sendDataChangedMessage(true); + } else { + boundsDirty = true; + } + } + } + + Point3f[] getCoordRef3f() { + return p3fRefCoords; + + } + + void setCoordRef3d(Point3d[] coords) { + + if (coords != null) { + if ((vertexType & VERTEX_DEFINED) != 0 && + (vertexType & VERTEX_DEFINED) != P3D) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (idx.maxCoordIndex >= coords.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } else if (coords.length < (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + p3dRefCoords = coords; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (coords == null) + vertexType &= ~P3D; + else + vertexType |= P3D; + } else { + setupMirrorVertexPointer(P3D); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && source != null) { + if (isLive) { + processCoordsChanged(coords == null); + sendDataChangedMessage(true); + } else { + boundsDirty = true; + } + } + } + + Point3d[] getCoordRef3d() { + return p3dRefCoords; + } + + void setColorRefFloat(float[] colors) { + + if (colors != null) { + if ((vertexType & COLOR_DEFINED) != 0 && + (vertexType & COLOR_DEFINED) != CF) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if ((vertexFormat & GeometryArray.COLOR) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray123")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (getColorStride() * idx.maxColorIndex >= colors.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } else if (colors.length < getColorStride() * (initialColorIndex+ validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + floatRefColors = colors; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (colors == null) + vertexType &= ~CF; + else + vertexType |= CF; + } + else { + setupMirrorColorPointer(CF, false); + } + + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + + } + + float[] getColorRefFloat() { + return floatRefColors; + } + + + // set the color with nio buffer + void setColorRefBuffer(J3DBuffer colors) { + if (colors != null) { + switch(colors.getBufferType()) { + case J3DBuffer.TYPE_FLOAT: + assert ((FloatBufferWrapper)colors.getBufferImpl()).isDirect(); + break; + case J3DBuffer.TYPE_BYTE: + assert ((ByteBufferWrapper)colors.getBufferImpl()).isDirect(); + break; + case J3DBuffer.TYPE_NULL: + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray115")); + + default: + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116")); + } + + if ((vertexFormat & GeometryArray.COLOR) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray123")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (getColorStride() * idx.maxColorIndex >= colors.getBufferImpl().limit()) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } else if (colors.getBufferImpl().limit() < + getColorStride() * (initialColorIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + colorRefBuffer = colors; + if(colors == null) { + floatBufferRefColors = null; + byteBufferRefColors = null; + } else { + switch (colors.getBufferType()) { + case J3DBuffer.TYPE_FLOAT: + floatBufferRefColors = (FloatBufferWrapper)colors.getBufferImpl(); + byteBufferRefColors = null; + break; + + case J3DBuffer.TYPE_BYTE: + byteBufferRefColors = (ByteBufferWrapper)colors.getBufferImpl(); + floatBufferRefColors = null; + break; + default: + break; + } + } + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if(colors == null) { + vertexType &= ~CF; + vertexType &= ~CUB; + } else { + switch (colors.getBufferType()) { + case J3DBuffer.TYPE_FLOAT: + vertexType |= CF; + vertexType &= ~CUB; + break; + + case J3DBuffer.TYPE_BYTE: + vertexType |= CUB; + vertexType &= ~CF; + break; + default: + break; + } + } + } + else { + setupMirrorColorPointer(CF|CUB, false); + } + + if(isLive) { + geomLock.unLock(); + } + + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + // return the color data in nio buffer format + J3DBuffer getColorRefBuffer() { + return colorRefBuffer; + } + + void setColorRefByte(byte[] colors) { + + if (colors != null) { + if ((vertexType & COLOR_DEFINED) != 0 && + (vertexType & COLOR_DEFINED) != CUB) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if ((vertexFormat & GeometryArray.COLOR) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray123")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (getColorStride() * idx.maxColorIndex >= colors.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } else if (colors.length < getColorStride() * (initialColorIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + byteRefColors = colors; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (colors == null) + vertexType &= ~CUB; + else + vertexType |= CUB; + } + else { + setupMirrorColorPointer(CUB, false); + } + if(isLive){ + geomLock.unLock(); + } + + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + + } + + byte[] getColorRefByte() { + return byteRefColors; + } + + void setColorRef3f(Color3f[] colors) { + + if (colors != null) { + if ((vertexType & COLOR_DEFINED) != 0 && + (vertexType & COLOR_DEFINED) != C3F) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if ((vertexFormat & GeometryArray.COLOR_3) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + if (idx.maxColorIndex >= colors.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } else if (colors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + c3fRefColors = colors; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (colors == null) + vertexType &= ~C3F; + else + vertexType |= C3F; + } + else { + setupMirrorColorPointer(C3F, false); + } + + if(isLive) { + geomLock.unLock(); + } + + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + + } + + Color3f[] getColorRef3f() { + return c3fRefColors; + } + + + void setColorRef4f(Color4f[] colors) { + + if (colors != null) { + if ((vertexType & COLOR_DEFINED) != 0 && + (vertexType & COLOR_DEFINED) != C4F) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + if ((vertexFormat & GeometryArray.COLOR_4) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + if (idx.maxColorIndex >= colors.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } else if (colors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + c4fRefColors = colors; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (colors == null) + vertexType &= ~C4F; + else + vertexType |= C4F; + } + else { + setupMirrorColorPointer(C4F, false); + } + if(isLive) { + geomLock.unLock(); + } + + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + Color4f[] getColorRef4f() { + return c4fRefColors; + } + + + void setColorRef3b(Color3b[] colors) { + + if (colors != null) { + + if ((vertexType & COLOR_DEFINED) != 0 && + (vertexType & COLOR_DEFINED) != C3UB) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if ((vertexFormat & GeometryArray.COLOR_3) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray92")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (idx.maxColorIndex >= colors.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } else if (colors.length < (initialColorIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + c3bRefColors = colors; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (colors == null) + vertexType &= ~C3UB; + else + vertexType |= C3UB; + } + else { + setupMirrorColorPointer(C3UB, false); + } + + if(isLive) { + geomLock.unLock(); + } + + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + + Color3b[] getColorRef3b() { + return c3bRefColors; + } + + void setColorRef4b(Color4b[] colors) { + + if (colors != null) { + if ((vertexType & COLOR_DEFINED) != 0 && + (vertexType & COLOR_DEFINED) != C4UB) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if ((vertexFormat & GeometryArray.COLOR_4) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray93")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained) this; + + if (idx.maxColorIndex >= colors.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } else if (colors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + c4bRefColors = colors; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (colors == null) + vertexType &= ~C4UB; + else + vertexType |= C4UB; + } + else { + setupMirrorColorPointer(C4UB, false); + } + + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + + Color4b[] getColorRef4b() { + return c4bRefColors; + } + + void setNormalRefFloat(float[] normals) { + + if (normals != null) { + if ((vertexType & NORMAL_DEFINED) != 0 && + (vertexType & NORMAL_DEFINED) != NF) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if ((vertexFormat & GeometryArray.NORMALS) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray122")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (idx.maxNormalIndex*3 >= normals.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + } else if (normals.length < 3 * (initialNormalIndex + validVertexCount )) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + floatRefNormals = normals; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (normals == null) + vertexType &= ~NF; + else + vertexType |= NF; + } + else { + setupMirrorNormalPointer(NF); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + + } + + float[] getNormalRefFloat() { + return floatRefNormals; + } + + // setup the normal with nio buffer + void setNormalRefBuffer(J3DBuffer normals) { + + FloatBufferWrapper bufferImpl = null; + + if (normals != null) { + if(normals.getBufferType() != J3DBuffer.TYPE_FLOAT) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116")); + + bufferImpl = (FloatBufferWrapper)normals.getBufferImpl(); + + assert bufferImpl.isDirect(); + + if ((vertexFormat & GeometryArray.NORMALS) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray122")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + if (idx.maxNormalIndex * 3 >= + ((FloatBufferWrapper)normals.getBufferImpl()).limit()) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + } else if (bufferImpl.limit() < 3 * (initialNormalIndex + validVertexCount )) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + normalRefBuffer = normals; + + if (normals == null) { + vertexType &= ~NF; + floatBufferRefNormals = null; + } + else { + vertexType |= NF; + floatBufferRefNormals = bufferImpl; + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + J3DBuffer getNormalRefBuffer() { + return normalRefBuffer; + } + + void setNormalRef3f(Vector3f[] normals) { + + if (normals != null) { + if ((vertexType & NORMAL_DEFINED) != 0 && + (vertexType & NORMAL_DEFINED) != N3F) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98")); + } + + if ((vertexFormat & GeometryArray.NORMALS) == 0) { + throw new IllegalStateException(J3dI18N.getString("GeometryArray122")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + if (idx.maxNormalIndex >= normals.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + } else if (normals.length < (initialNormalIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + v3fRefNormals = normals; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + if (normals == null) + vertexType &= ~N3F; + else + vertexType |= N3F; + } + else { + setupMirrorNormalPointer(N3F); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + Vector3f[] getNormalRef3f() { + return v3fRefNormals; + } + + final int getColorStride() { + return ((vertexFormat & GeometryArray.WITH_ALPHA) != 0 ? 4 : 3); + } + + final int getTexStride() { + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + return 2; + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + return 3; + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + return 4; + } + + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray121")); + } + + void setTexCoordRefFloat(int texCoordSet, float[] texCoords) { + + if (texCoordType != 0 && texCoordType != TF) { + if (texCoords != null) { + throw new IllegalArgumentException( + J3dI18N.getString("GeometryArray98")); + } + return; + } + + if (texCoords != null) { + + int ts = getTexStride(); + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (idx.maxTexCoordIndices[texCoordSet]*ts >= texCoords.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + } else if (texCoords.length < ts*(initialTexCoordIndex[texCoordSet]+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray113")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + refTexCoords[texCoordSet] = texCoords; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + texCoordType = TF; + validateTexCoordPointerType(); + } + else { + setupMirrorTexCoordPointer(texCoordSet, TF); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + + float[] getTexCoordRefFloat(int texCoordSet) { + return ((float[])refTexCoords[texCoordSet]); + } + + // set the tex coord with nio buffer + void setTexCoordRefBuffer(int texCoordSet, J3DBuffer texCoords) { + + FloatBufferWrapper bufferImpl = null; + + if (texCoords != null) { + if(texCoords.getBufferType() != J3DBuffer.TYPE_FLOAT) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116")); + + bufferImpl = (FloatBufferWrapper)texCoords.getBufferImpl(); + int bufferSize = bufferImpl.limit(); + + assert bufferImpl.isDirect(); + + int ts = getTexStride(); + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + if (idx.maxTexCoordIndices[texCoordSet] * ts >= bufferSize) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + } else if (bufferSize < ts*(initialTexCoordIndex[texCoordSet] + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray113")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + // refTexCoordsBuffer contains J3DBuffer object for tex coord + refTexCoordsBuffer[texCoordSet] = texCoords; + if (texCoords == null) { + refTexCoords[texCoordSet] = null; + } + else { + // refTexCoords contains NIOBuffer object for tex coord + refTexCoords[texCoordSet] = bufferImpl.getBufferAsObject(); + } + texCoordType = TF; + validateTexCoordPointerType(); + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + J3DBuffer getTexCoordRefBuffer(int texCoordSet) { + return (J3DBuffer)(refTexCoordsBuffer[texCoordSet]); + } + + void setTexCoordRef2f(int texCoordSet, TexCoord2f[] texCoords) { + + if (texCoordType != 0 && texCoordType != T2F) { + if (texCoords != null) { + throw new IllegalArgumentException( + J3dI18N.getString("GeometryArray98")); + } + return; + } + + if (texCoords != null) { + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) == 0) { + throw new IllegalStateException( + J3dI18N.getString("GeometryArray94")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (idx.maxTexCoordIndices[texCoordSet] >= texCoords.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + } else if (texCoords.length < (initialTexCoordIndex[texCoordSet] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray113")); + } + + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + refTexCoords[texCoordSet] = texCoords; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + texCoordType = T2F; + validateTexCoordPointerType(); + } + else { + setupMirrorTexCoordPointer(texCoordSet, T2F); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + + TexCoord2f[] getTexCoordRef2f(int texCoordSet) { + if (refTexCoords != null && refTexCoords[texCoordSet] != null && + refTexCoords[texCoordSet] instanceof TexCoord2f[]) { + return ((TexCoord2f[])refTexCoords[texCoordSet]); + } else { + return null; + } + } + + + void setTexCoordRef3f(int texCoordSet, TexCoord3f[] texCoords) { + + if (texCoordType != 0 && texCoordType != T3F) { + if (texCoords != null) { + throw new IllegalArgumentException( + J3dI18N.getString("GeometryArray98")); + } + return; + } + + if (texCoords != null) { + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) == 0) { + throw new IllegalStateException( + J3dI18N.getString("GeometryArray95")); + } + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (idx.maxTexCoordIndices[texCoordSet] >= texCoords.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + + } else if (texCoords.length < (initialTexCoordIndex[texCoordSet] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray113")); + } + + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + refTexCoords[texCoordSet] = texCoords; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + texCoordType = T3F; + validateTexCoordPointerType(); + } + else { + setupMirrorTexCoordPointer(texCoordSet, T3F); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + + TexCoord3f[] getTexCoordRef3f(int texCoordSet) { + if (refTexCoords != null && refTexCoords[texCoordSet] != null && + refTexCoords[texCoordSet] instanceof TexCoord3f[]) { + return ((TexCoord3f[])refTexCoords[texCoordSet]); + } else { + return null; + } + } + + + /** + * Sets the float vertex attribute array reference for the + * specified vertex attribute number to the specified array. + */ + void setVertexAttrRefFloat(int vertexAttrNum, float[] vertexAttrs) { + + // XXXX: Add the following test if we ever add double-precision types + /* + if (vertexAttrType != 0 && vertexAttrType != AF) { + if (vertexAttrs != null) { + // XXXX: new exception string + throw new IllegalArgumentException( + J3dI18N.getString("GeometryArray98-XXX")); + } + return; + } + */ + + if (vertexAttrs != null) { + int sz = vertexAttrSizes[vertexAttrNum]; + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (sz*idx.maxVertexAttrIndices[vertexAttrNum] >= vertexAttrs.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray30")); + } + + } else if (vertexAttrs.length < sz*(initialVertexAttrIndex[vertexAttrNum] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray129")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + floatRefVertexAttrs[vertexAttrNum] = vertexAttrs; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + vertexAttrType = AF; + validateVertexAttrPointerType(); + } + else { + setupMirrorVertexAttrPointer(vertexAttrNum, AF); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Gets the float vertex attribute array reference for the specified + * vertex attribute number. + */ + float[] getVertexAttrRefFloat(int vertexAttrNum) { + return floatRefVertexAttrs[vertexAttrNum]; + } + + + /** + * Sets the vertex attribute buffer reference for the specified + * vertex attribute number to the specified buffer object. + */ + void setVertexAttrRefBuffer(int vertexAttrNum, J3DBuffer vertexAttrs) { + + FloatBufferWrapper bufferImpl = null; + + if (vertexAttrs != null) { + if(vertexAttrs.getBufferType() != J3DBuffer.TYPE_FLOAT) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116")); + + bufferImpl = (FloatBufferWrapper)vertexAttrs.getBufferImpl(); + int bufferSize = bufferImpl.limit(); + + assert bufferImpl.isDirect(); + + int sz = vertexAttrSizes[vertexAttrNum]; + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (idx.maxVertexAttrIndices[vertexAttrNum] * sz >= bufferSize) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray30")); + } + } else if (bufferSize < sz*(initialVertexAttrIndex[vertexAttrNum] + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray129")); + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + vertexAttrsRefBuffer[vertexAttrNum] = vertexAttrs; + if (vertexAttrs == null) { + floatBufferRefVertexAttrs[vertexAttrNum] = null; + nioFloatBufferRefVertexAttrs[vertexAttrNum] = null; + } + else { + floatBufferRefVertexAttrs[vertexAttrNum] = bufferImpl; + nioFloatBufferRefVertexAttrs[vertexAttrNum] = + bufferImpl.getBufferAsObject(); + } + vertexAttrType = AF; + validateVertexAttrPointerType(); + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + + } + + /** + * Gets the vertex attribute array buffer reference for the specified + * vertex attribute number. + */ + J3DBuffer getVertexAttrRefBuffer(int vertexAttrNum) { + return vertexAttrsRefBuffer[vertexAttrNum]; + } + + + void setInterleavedVertices(float[] vertexData) { + if (vertexData != null) { + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (stride * idx.maxCoordIndex >= vertexData.length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + if (stride * idx.maxTexCoordIndices[i] >= vertexData.length) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("IndexedGeometryArray25")); + } + } + } + + if (((this.vertexFormat & GeometryArray.COLOR) != 0) && + (stride * idx.maxColorIndex >= vertexData.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + + if (((this.vertexFormat & GeometryArray.NORMALS) != 0) && + (stride * idx.maxNormalIndex >= vertexData.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + } else { + if (vertexData.length < (stride * (initialVertexIndex+validVertexCount))) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114")); + } + } + + // If the geometry has been rendered transparent, then make a copy + // of the color pointer with 4f + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VERTEX_CHANGED; + colorChanged = 0xffff; + interLeavedVertexData = vertexData; + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + setupMirrorInterleavedColorPointer(false); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + processCoordsChanged(vertexData == null); + sendDataChangedMessage(true); + } + } + + // set the interleaved vertex with NIO buffer + void setInterleavedVertexBuffer(J3DBuffer vertexData) { + + FloatBufferWrapper bufferImpl = null; + + if (vertexData != null ){ + + if (vertexData.getBufferType() != J3DBuffer.TYPE_FLOAT) + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116")); + + bufferImpl = (FloatBufferWrapper)vertexData.getBufferImpl(); + + assert bufferImpl.isDirect(); + + int bufferSize = bufferImpl.limit(); + + if (this instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this; + + if (stride * idx.maxCoordIndex >= bufferSize) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + + if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + if (stride * idx.maxTexCoordIndices[i] >= bufferSize) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("IndexedGeometryArray25")); + } + } + } + + if (((this.vertexFormat & GeometryArray.COLOR) != 0) && + (stride * idx.maxColorIndex >= bufferSize)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + + if (((this.vertexFormat & GeometryArray.NORMALS) != 0) && + (stride * idx.maxNormalIndex >= bufferSize)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } else { + if (bufferSize < (stride * (initialVertexIndex+validVertexCount))) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114")); + } + } + // If the geometry has been rendered transparent, then make a copy + // of the color pointer with 4f + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VERTEX_CHANGED; + colorChanged = 0xffff; + interleavedVertexBuffer = vertexData; + + if(vertexData == null) + interleavedFloatBufferImpl = null; + else + interleavedFloatBufferImpl = bufferImpl; + + if (inUpdater || (this instanceof IndexedGeometryArrayRetained && + ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) { + setupMirrorInterleavedColorPointer(false); + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + processCoordsChanged(vertexData == null); + sendDataChangedMessage(true); + } + } + + float[] getInterleavedVertices() { + return interLeavedVertexData; + } + + J3DBuffer getInterleavedVertexBuffer() { + return interleavedVertexBuffer; + } + + void setValidVertexCount(int validVertexCount) { + + boolean nullGeo = false; + if (validVertexCount < 0) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray110")); + } + + if ((initialVertexIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray100")); + } + + if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + // Interleaved, by-ref + + // use nio buffer for interleaved data + if(( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 && interleavedFloatBufferImpl != null){ + if(interleavedFloatBufferImpl.limit() < stride * (initialVertexIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114")); + } + } + //use java array for interleaved data + else if( interLeavedVertexData != null) { + if(interLeavedVertexData.length < stride * (initialVertexIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114")); + } + } + else { + nullGeo = true; + } + } else if ((vertexFormat & GeometryArray.BY_REFERENCE) != 0) { + // Non-interleaved, by-ref + + if ((initialCoordIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray104")); + } + if ((initialColorIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray101")); + } + if ((initialNormalIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray102")); + } + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + if ((initialTexCoordIndex[i] + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString( + "GeometryArray103")); + } + } + } + + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + if ((initialVertexAttrIndex[i] + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString( + "GeometryArray130")); + } + } + } + + if ((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0) { + nullGeo = true; + } + + if (( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + // by reference with nio buffer + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case PF: + if(floatBufferRefCoords.limit() < 3 * (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + case PD: + if(doubleBufferRefCoords.limit() < 3 * (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + } + + switch ((vertexType & COLOR_DEFINED)) { + case CF: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + if (floatBufferRefColors.limit() < 3 * (initialColorIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + if (floatBufferRefColors.limit() < 4 * (initialColorIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + break; + case CUB: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + if (byteBufferRefColors.limit() < 3 * (initialColorIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + if (byteBufferRefColors.limit() < 4 * (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + break; + } + switch ((vertexType & GeometryArrayRetained.TEXCOORD_DEFINED)) { + case TF: + FloatBufferWrapper texBuffer; + for (int i = 0; i < texCoordSetCount; i++) { + texBuffer = (FloatBufferWrapper)(((J3DBuffer)refTexCoordsBuffer[i]).getBufferImpl()); + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + if (texBuffer.limit() < 2 * (initialTexCoordIndex[i] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + if (texBuffer.limit() < 3 * (initialTexCoordIndex[i] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + if (texBuffer.limit() < 4 * (initialTexCoordIndex[i] + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } + } + break; + } + switch ((vertexType & GeometryArrayRetained.NORMAL_DEFINED)) { + case NF: + if (floatBufferRefNormals.limit() < 3 * (initialNormalIndex + validVertexCount )) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + break; + } + switch ((vertexType & GeometryArrayRetained.VATTR_DEFINED)) { + case AF: + for (int i = 0; i < vertexAttrCount; i++) { + int sz = vertexAttrSizes[i]; + if (floatBufferRefVertexAttrs[i].limit() < + (sz * (initialVertexAttrIndex[i] + validVertexCount)) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray129")); + } + } + break; + } + } + // By reference with java array + else { + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case PF: + if (floatRefCoords.length < 3 * (initialCoordIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + case PD: + if (doubleRefCoords.length < 3 * (initialCoordIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + case P3F: + if (p3fRefCoords.length < (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + case P3D: + if (p3dRefCoords.length < (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + } + switch ((vertexType & COLOR_DEFINED)) { + case CF: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + if (floatRefColors.length < 3 * (initialColorIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + if (floatRefColors.length < 4 * (initialColorIndex+ validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + break; + case CUB: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + if (byteRefColors.length < 3 * (initialColorIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + if (byteRefColors.length < 4 * (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + break; + case C3F: + if (c3fRefColors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + break; + case C4F: + if (c4fRefColors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + break; + case C3UB: + if (c3bRefColors.length < (initialColorIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + break; + case C4UB: + if (c4bRefColors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + break; + } + switch ((vertexType & GeometryArrayRetained.TEXCOORD_DEFINED)) { + case TF: + for (int i = 0; i < texCoordSetCount; i++) { + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + if (((float[])refTexCoords[i]).length < 2 * (initialTexCoordIndex[i] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + if (((float[])refTexCoords[i]).length < 3 * (initialTexCoordIndex[i] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + if (((float[])refTexCoords[i]).length < 4 * (initialTexCoordIndex[i] + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } + } + } + break; + case T2F: + for (int i = 0; i < texCoordSetCount; i++) { + if (((TexCoord2f[])refTexCoords[i]).length < (initialTexCoordIndex[i] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } + break; + case T3F: + for (int i = 0; i < texCoordSetCount; i++) { + if (((TexCoord3f[])refTexCoords[i]).length < (initialTexCoordIndex[i] + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } + break; + } + switch ((vertexType & GeometryArrayRetained.NORMAL_DEFINED)) { + case NF: + if (floatRefNormals.length < 3 * (initialNormalIndex + validVertexCount )) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + break; + case N3F: + if (v3fRefNormals.length < (initialNormalIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + } + switch ((vertexType & GeometryArrayRetained.VATTR_DEFINED)) { + case AF: + for (int i = 0; i < vertexAttrCount; i++) { + int sz = vertexAttrSizes[i]; + if (floatRefVertexAttrs[i].length < + (sz * (initialVertexAttrIndex[i] + validVertexCount)) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray129")); + } + } + break; + } + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VERTEX_CHANGED; + this.validVertexCount = validVertexCount; + + if(isLive){ + geomLock.unLock(); + } + + if (!inUpdater && isLive) { + processCoordsChanged(nullGeo); + sendDataChangedMessage(true); + } + } + + + int getValidVertexCount() { + return validVertexCount; + } + + //Used for interleaved data (array or nio buffer) + void setInitialVertexIndex(int initialVertexIndex) { + boolean nullGeo = false; + + if ((initialVertexIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray100")); + } + + if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 && interleavedFloatBufferImpl != null) { + if(interleavedFloatBufferImpl.limit() < stride * (initialVertexIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114")); + } + } + // interleaved data using java array + else if(interLeavedVertexData != null) { + if (interLeavedVertexData.length < stride * (initialVertexIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114")); + } + } + else { + nullGeo = (vertexFormat & GeometryArray.INTERLEAVED) != 0; // Only for byRef + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VERTEX_CHANGED; + this.initialVertexIndex = initialVertexIndex; + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + processCoordsChanged(nullGeo); + sendDataChangedMessage(true); + } + } + + int getInitialVertexIndex() { + return initialVertexIndex; + } + + void setInitialCoordIndex(int initialCoordIndex) { + if ((initialCoordIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray104")); + } + // use NIO buffer + if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0){ + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case PF: + if(floatBufferRefCoords.limit() < (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + case PD: + if(doubleBufferRefCoords.limit() < (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + } + } else { + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case PF: + if (floatRefCoords.length < 3 * (initialCoordIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + case PD: + if (doubleRefCoords.length < 3 * (initialCoordIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + case P3F: + if (p3fRefCoords.length < (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + case P3D: + if (p3dRefCoords.length < (initialCoordIndex+validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99")); + } + break; + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COORDINATE_CHANGED; + this.initialCoordIndex = initialCoordIndex; + dirtyFlag |= COORDINATE_CHANGED; + if(isLive) { + geomLock.unLock(); + } + // Send a message, since bounds changed + if (!inUpdater && isLive) { + processCoordsChanged((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0); + sendDataChangedMessage(true); + } + } + + int getInitialCoordIndex() { + return initialCoordIndex; + } + + void setInitialColorIndex(int initialColorIndex) { + if ((initialColorIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray101")); + } + // NIO BUFFER CASE + if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0){ + switch ((vertexType & COLOR_DEFINED)) { + case CF: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + if (floatBufferRefColors.limit() < 3 * (initialColorIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + if (floatBufferRefColors.limit() < 4 * (initialColorIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + break; + + case CUB: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + if (byteBufferRefColors.limit() < 3 * (initialColorIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + if (byteBufferRefColors.limit() < 4 * (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + break; + } + } + // Java ARRAY CASE + else { + switch ((vertexType & COLOR_DEFINED)) { + case CF: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + if (floatRefColors.length < 3 * (initialColorIndex+validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + if (floatRefColors.length < 4 * (initialColorIndex+ validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + break; + case CUB: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + if (byteRefColors.length < 3 * (initialColorIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + if (byteRefColors.length < 4 * (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + } + break; + case C3F: + if (c3fRefColors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + break; + case C4F: + if (c4fRefColors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + break; + case C3UB: + if (c3bRefColors.length < (initialColorIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + break; + case C4UB: + if (c4bRefColors.length < (initialColorIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112")); + } + break; + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= COLOR_CHANGED; + colorChanged = 0xffff; + this.initialColorIndex = initialColorIndex; + if(isLive) { + geomLock.unLock(); + } + // There is no need to send message for by reference, since we + // use VA + + } + + int getInitialColorIndex() { + return initialColorIndex; + } + + void setInitialNormalIndex(int initialNormalIndex) { + if ((initialNormalIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray102")); + } + if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0){ + if((vertexType & NORMAL_DEFINED) == NF){ + if (floatBufferRefNormals.limit() < 3 * (initialNormalIndex + validVertexCount )) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + } + } else { + switch((vertexType & NORMAL_DEFINED)){ + case NF: + if (floatRefNormals.length < 3 * (initialNormalIndex + validVertexCount )) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + break; + case N3F: + if (v3fRefNormals.length < (initialNormalIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111")); + } + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= NORMAL_CHANGED; + this.initialNormalIndex = initialNormalIndex; + if(isLive) { + geomLock.unLock(); + } + // There is no need to send message for by reference, since we + // use VA + } + + int getInitialNormalIndex() { + return initialNormalIndex; + } + + /** + * Sets the initial vertex attribute index for the specified + * vertex attribute number for this GeometryArray object. + */ + void setInitialVertexAttrIndex(int vertexAttrNum, + int initialVertexAttrIndex) { + + if ((initialVertexAttrIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray130")); + } + + int sz = vertexAttrSizes[vertexAttrNum]; + int minLength = sz * (initialVertexAttrIndex + validVertexCount); + if ((vertexType & VATTR_DEFINED) == AF) { + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + if (floatBufferRefVertexAttrs[vertexAttrNum].limit() < minLength) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray129")); + } + } else { + if (floatRefVertexAttrs[vertexAttrNum].length < minLength ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray129")); + } + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= VATTR_CHANGED; + this.initialVertexAttrIndex[vertexAttrNum] = initialVertexAttrIndex; + if(isLive) { + geomLock.unLock(); + } + // There is no need to send message for by reference, since we + // use VA + } + + + /** + * Gets the initial vertex attribute index for the specified + * vertex attribute number for this GeometryArray object. + */ + int getInitialVertexAttrIndex(int vertexAttrNum) { + return initialVertexAttrIndex[vertexAttrNum]; + } + + void setInitialTexCoordIndex(int texCoordSet, int initialTexCoordIndex) { + if ((initialTexCoordIndex + validVertexCount) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryArray103")); + } + + if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0){ + if((vertexType & TEXCOORD_DEFINED) == TF) { + FloatBufferWrapper texBuffer = (FloatBufferWrapper)(((J3DBuffer) refTexCoordsBuffer[texCoordSet]).getBufferImpl()); + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + if (texBuffer.limit() < 2 * (initialTexCoordIndex+ validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + if (texBuffer.limit() < 3 * (initialTexCoordIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + if (texBuffer.limit() < 4 * (initialTexCoordIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } + } + } else { + switch ((vertexType & TEXCOORD_DEFINED)) { + case TF: + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + if (((float[])refTexCoords[texCoordSet]).length < 2 * (initialTexCoordIndex+ validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + if (((float[])refTexCoords[texCoordSet]).length < 3 * (initialTexCoordIndex + validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + if (((float[])refTexCoords[texCoordSet]).length < 4 * (initialTexCoordIndex + validVertexCount)) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + } + break; + case T2F: + if (((TexCoord2f[])refTexCoords[texCoordSet]).length < (initialTexCoordIndex+ validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + break; + case T3F: + if (((TexCoord3f[])refTexCoords[texCoordSet]).length < (initialTexCoordIndex+ validVertexCount) ) { + throw new ArrayIndexOutOfBoundsException( + J3dI18N.getString("GeometryArray113")); + } + break; + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= TEXTURE_CHANGED; + this.initialTexCoordIndex[texCoordSet] = initialTexCoordIndex; + if(isLive) { + geomLock.unLock(); + } + // There is no need to send message for by reference, since we + // use VA + } + + int getInitialTexCoordIndex(int texCoordSet) { + return initialTexCoordIndex[texCoordSet]; + } + + + int getTexCoordSetCount() { + return this.texCoordSetCount; + } + + int getTexCoordSetMapLength() { + if (this.texCoordSetMap != null) + return this.texCoordSetMap.length; + else + return 0; + } + + void getTexCoordSetMap(int [] texCoordSetMap) { + + if (this.texCoordSetMap!=null) { + for (int i = 0; i < this.texCoordSetMap.length; i++) { + texCoordSetMap[i] = this.texCoordSetMap[i]; + } + } + } + + void freeDlistId() { + if (dlistId != -1) { + VirtualUniverse.mc.freeDisplayListId(dlistObj); + dlistId = -1; + } + } + + void assignDlistId() { + if (dlistId == -1) { + dlistObj = VirtualUniverse.mc.getDisplayListId(); + dlistId = dlistObj.intValue(); + } + } + + // Add the specified render atom as a user of this geometry array + // (for the specified render bin) + void addDlistUser(RenderBin renderBin, RenderAtomListInfo ra) { + if (dlistUsers == null) { + dlistUsers = new HashMap(2, 1.0f); + } + + Set raSet = (Set)dlistUsers.get(renderBin); + if (raSet == null) { + raSet = new HashSet(); + dlistUsers.put(renderBin, raSet); + } + raSet.add(ra); + } + + // Remove the specified render atom from the set of users of this + // geometry array (for the specified render bin) + void removeDlistUser(RenderBin renderBin, RenderAtomListInfo ra) { + if (dlistUsers == null) { + // Nothing to do + return; + } + + Set raSet = (Set)dlistUsers.get(renderBin); + if (raSet == null) { + // Nothing to do + return; + } + raSet.remove(ra); + } + + // Returns true if the set of render atoms using this geometry + // array in the specified render bin is empty. + boolean isDlistUserSetEmpty(RenderBin renderBin) { + if (dlistUsers == null) { + return true; + } + + Set raSet = (Set)dlistUsers.get(renderBin); + if (raSet == null) { + return true; + } + return raSet.isEmpty(); + } + + // This method is used for debugging only + int numDlistUsers(RenderBin renderBin) { + if (isDlistUserSetEmpty(renderBin)) { + return 0; + } + Set raSet = (Set)dlistUsers.get(renderBin); + return raSet.size(); + } + + void setDlistTimeStamp(int rdrBit, long timeStamp) { + int index = getIndex(rdrBit); + if (index >= timeStampPerDlist.length) { + long[] newList = new long[index * 2]; + for (int i = 0; i < timeStampPerDlist.length; i++) { + newList[i] = timeStampPerDlist[i]; + } + timeStampPerDlist = newList; + } + timeStampPerDlist[index] = timeStamp; + } + + long getDlistTimeStamp(int rdrBit) { + int index = getIndex(rdrBit); + // If index is greater than what currently exists, increase + // the array and return zero + if (index >= timeStampPerDlist.length) { + setDlistTimeStamp(rdrBit, 0); + } + return timeStampPerDlist[index]; + } + + int getIndex(int bit) { + int num = 0; + + while (bit > 0) { + num++; + bit >>= 1; + } + return num; + } + + + boolean isWriteStatic() { + + if (source.getCapability(GeometryArray.ALLOW_COORDINATE_WRITE ) || + source.getCapability(GeometryArray.ALLOW_COLOR_WRITE) || + source.getCapability(GeometryArray.ALLOW_NORMAL_WRITE) || + source.getCapability(GeometryArray.ALLOW_TEXCOORD_WRITE) || + source.getCapability(GeometryArray.ALLOW_VERTEX_ATTR_WRITE) || + source.getCapability(GeometryArray.ALLOW_COUNT_WRITE) || + source.getCapability(GeometryArray.ALLOW_REF_DATA_WRITE)) + return false; + + return true; + } + + /** + * The functions below are only used in compile mode + */ + void setCompiled(ArrayList curList) { + int i; + int num = curList.size(); + int offset = 0; + geoOffset = new int[num]; + compileVcount = new int[num]; + int vcount = 0, vformat = 0; + vcount = 0; + isCompiled = true; + + if (num > 0) + source = ((SceneGraphObjectRetained)curList.get(0)).source; + for (i = 0; i < num; i++) { + // Build the back mapping + GeometryArrayRetained geo = (GeometryArrayRetained)curList.get(i); + ((GeometryArray)geo.source).retained = this; + compileVcount[i] = geo.getValidVertexCount(); + vcount += geo.getValidVertexCount(); + geoOffset[i] = offset; + offset += geo.stride() * compileVcount[i]; + vformat = geo.getVertexFormat(); + } + createGeometryArrayData(vcount, vformat); + + // Assign the initial and valid fields + validVertexCount = vcount; + initialVertexIndex = 0; + + mergeGeometryArrays(curList); + + } + + /* + // Ununsed + int getVertexCount(int index) { + return compileVcount[index]; + } + + + int getValidVertexCount(int index) { + return compileVcount[index]; + } + + + int getInitialVertexIndex(int index) { + return 0; + } + */ + + void mergeGeometryArrays(ArrayList list) { + float[] curVertexData; + int length, srcOffset; + int curOffset = 0; + // We only merge if the texCoordSetCount is 1 and there are no + // vertex attrs + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + texCoordSetCount = 1; + texCoordSetMap = new int[1]; + texCoordSetMap[0] = 1; + } + for (int i = 0; i < list.size(); i++) { + GeometryArrayRetained geo = (GeometryArrayRetained)list.get(i); + // Take into account the validVertexCount and initialVertexIndex + curVertexData = geo.vertexData; + length = geo.validVertexCount * stride; + srcOffset = geo.initialVertexIndex * stride; + System.arraycopy(curVertexData, srcOffset, this.vertexData, curOffset, + length); + curOffset += length; + + // assign geoBounds + geoBounds.combine(geo.geoBounds); + + } + this.centroid.set(geoBounds.getCenter()); + } + + boolean isMergeable() { + + // For now, turn off by ref geometry + if ((vertexFormat & GeometryArray.BY_REFERENCE) != 0) + return false; + + if (!isStatic()) + return false; + + // If there is more than one set of texture coordinate set defined + // then don't merge geometry (we avoid dealing with texCoordSetMap + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0 && + (texCoordSetCount > 1 || + texCoordSetMap != null && texCoordSetMap.length > 1)) { + return false; + } + + // We will avoid merging geometry if there are any vertex attributes. + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + return false; + } + + // If intersect is allowed turn off merging + if (source.getCapability(Geometry.ALLOW_INTERSECT)) + return false; + + return true; + } + + void compile(CompileState compState) { + super.compile(compState); + + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + compState.needNormalsTransform = true; + } + } + + void mergeTransform(TransformGroupRetained xform) { + if (geoBounds != null) { + geoBounds.transform(xform.transform); + } + } + + // This adds a MorphRetained to the list of users of this geometry + void addMorphUser(MorphRetained m) { + int index; + ArrayList morphList; + + if(morphUniverseList == null) { + morphUniverseList = new ArrayList(1); + morphUserLists = new ArrayList(1); + } + synchronized (morphUniverseList) { + if (morphUniverseList.contains(m.universe)) { + index = morphUniverseList.indexOf(m.universe); + morphList = (ArrayList)morphUserLists.get(index); + morphList.add(m); + } else { + morphUniverseList.add(m.universe); + morphList = new ArrayList(5); + morphList.add(m); + morphUserLists.add(morphList); + } + } + } + + // This adds a MorphRetained to the list of users of this geometry + void removeMorphUser(MorphRetained m) { + int index; + ArrayList morphList; + + if(morphUniverseList == null) + return; + + synchronized (morphUniverseList) { + index = morphUniverseList.indexOf(m.universe); + morphList = (ArrayList)morphUserLists.get(index); + morphList.remove(morphList.indexOf(m)); + if (morphList.size() == 0) { + morphUserLists.remove(index); + morphUniverseList.remove(index); + } + } + } + // Initialize mirror object when geometry is first setLived + void initMirrorGeometry() { + geomLock.getLock(); + if (this instanceof IndexedGeometryArrayRetained) { + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) { + mirrorGeometry = + ((IndexedGeometryArrayRetained)this).cloneNonIndexedGeometry(); + } + else { + mirrorGeometry = null; + } + } + geomLock.unLock(); + + } + + // Update Mirror Object in response to change in geometry + void updateMirrorGeometry() { + geomLock.getLock(); + if (this instanceof IndexedGeometryArrayRetained) { + if (mirrorGeometry != null) { + mirrorGeometry = + ((IndexedGeometryArrayRetained)this).cloneNonIndexedGeometry(); + } + } + geomLock.unLock(); + + } + + + // Used by the picking intersect routines + void getVertexData(int i, Point3d pnts) { + int offset; + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + offset = stride * i + coordinateOffset; + pnts.x = this.vertexData[offset]; + pnts.y = this.vertexData[offset+1]; + pnts.z = this.vertexData[offset+2]; + return; + } + + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0 ) { + if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + offset = stride * i + coordinateOffset; + pnts.x = this.interLeavedVertexData[offset]; + pnts.y = this.interLeavedVertexData[offset+1]; + pnts.z = this.interLeavedVertexData[offset+2]; + } + else { + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case GeometryArrayRetained.PF: + offset = i*3; + pnts.x = this.floatRefCoords[offset]; + pnts.y = this.floatRefCoords[offset+1]; + pnts.z = this.floatRefCoords[offset+2]; + break; + case GeometryArrayRetained.PD: + offset = i*3; + pnts.x = this.doubleRefCoords[offset]; + pnts.y = this.doubleRefCoords[offset+1]; + pnts.z = this.doubleRefCoords[offset+2]; + break; + case GeometryArrayRetained.P3F: + pnts.x = this.p3fRefCoords[i].x; + pnts.y = this.p3fRefCoords[i].y; + pnts.z = this.p3fRefCoords[i].z; + break; + case GeometryArrayRetained.P3D: + pnts.x = this.p3dRefCoords[i].x; + pnts.y = this.p3dRefCoords[i].y; + pnts.z = this.p3dRefCoords[i].z; + break; + } + } + }// end of non nio buffer + else { // NIO BUFFER + if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + offset = stride * i + coordinateOffset; + pnts.x = this.interleavedFloatBufferImpl.get(offset); + pnts.y = this.interleavedFloatBufferImpl.get(offset+1); + pnts.z = this.interleavedFloatBufferImpl.get(offset+2); + } + else { + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case GeometryArrayRetained.PF: + offset = i*3; + pnts.x = this.floatBufferRefCoords.get(offset); + pnts.y = this.floatBufferRefCoords.get(offset+1); + pnts.z = this.floatBufferRefCoords.get(offset+2); + break; + case GeometryArrayRetained.PD: + offset = i*3; + pnts.x = this.doubleBufferRefCoords.get(offset); + pnts.y = this.doubleBufferRefCoords.get(offset+1); + pnts.z = this.doubleBufferRefCoords.get(offset+2); + break; + } + } + } // end of nio buffer + } + + void getCrossValue(Point3d p1, Point3d p2, Vector3d value) { + value.x += p1.y*p2.z - p1.z*p2.y; + value.y += p2.x*p1.z - p2.z*p1.x; + value.z += p1.x*p2.y - p1.y*p2.x; + } + + + boolean intersect(Transform3D thisLocalToVworld, + Transform3D otherLocalToVworld, GeometryRetained geom) { + + Transform3D t3d = new Transform3D(); + boolean isIntersect = false; + + if (geom instanceof GeometryArrayRetained ) { + GeometryArrayRetained geomArray = (GeometryArrayRetained) geom; + + if (geomArray.validVertexCount >= validVertexCount) { + t3d.invert(otherLocalToVworld); + t3d.mul(thisLocalToVworld); + isIntersect = intersect(t3d, geom); + } else { + t3d.invert(thisLocalToVworld); + t3d.mul(otherLocalToVworld); + isIntersect = geomArray.intersect(t3d, this); + } + } else { + t3d.invert(thisLocalToVworld); + t3d.mul(otherLocalToVworld); + isIntersect = geom.intersect(t3d, this); + } + return isIntersect; + } + + int getNumCoordCount() { + int count = 0; + if ((vertexFormat & GeometryArray.COORDINATES) != 0){ + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0){ + count = vertexCount; + return count; + } + + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){ + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case PF: + count = floatRefCoords.length/3; + break; + case PD: + count = doubleRefCoords.length/3; + break; + case P3F: + count = p3fRefCoords.length; + break; + case P3D: + count = p3dRefCoords.length; + break; + } + } + else { + count = interLeavedVertexData.length/stride; + } + } + else { // nio buffer + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){ + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case PF: + count = floatBufferRefCoords.limit()/3; // XXXX: limit or capacity? + break; + case PD: + count = doubleBufferRefCoords.limit()/3; + break; + } + } + else { + count = interleavedFloatBufferImpl.limit()/stride; + } + } + } + return count; + } + + int getNumColorCount() { + int count = 0; + if ((vertexFormat & GeometryArray.COLOR) != 0){ + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0){ + count = vertexCount; + return count; + } + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){ + switch ((vertexType & GeometryArrayRetained.COLOR_DEFINED)) { + case CF: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + count = floatRefColors.length/3; + } + else if ((vertexFormat & GeometryArray.COLOR_4)== GeometryArray.COLOR_4){ + count = floatRefColors.length/4; + } + break; + case CUB: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + count = byteRefColors.length/3; + } + else if ((vertexFormat & GeometryArray.COLOR_4)== GeometryArray.COLOR_4){ + count = byteRefColors.length/4; + } + break; + case C3F: + count = c3fRefColors.length; + break; + case C4F: + count = c4fRefColors.length; + break; + case C3UB: + count = c3bRefColors.length; + break; + case C4UB: + count = c4bRefColors.length; + break; + } + } + else { + count = interLeavedVertexData.length/stride; + } + } // end of non nio buffer + else { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){ + switch ((vertexType & GeometryArrayRetained.COLOR_DEFINED)) { + case CF: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + count = floatBufferRefColors.limit()/3; + } + else if ((vertexFormat & GeometryArray.COLOR_4)== GeometryArray.COLOR_4){ + count = floatBufferRefColors.limit()/4; + } + break; + case CUB: + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + count = byteBufferRefColors.limit()/3; + } + else if ((vertexFormat & GeometryArray.COLOR_4)== GeometryArray.COLOR_4){ + count = byteBufferRefColors.limit()/4; + } + break; + } + } + else { + count = interleavedFloatBufferImpl.limit()/stride; + } + } // end of nio buffer + } + return count; + } + + int getNumNormalCount() { + int count = 0; + if ((vertexFormat & GeometryArray.NORMALS) != 0){ + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0){ + count = vertexCount; + return count; + } + + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){ + switch ((vertexType & NORMAL_DEFINED)) { + case NF: + count = floatRefNormals.length/3; + break; + case N3F: + count = v3fRefNormals.length; + break; + } + } + else { + count = interLeavedVertexData.length/stride; + } + } // end of non nio buffer + else { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){ + if ((vertexType & NORMAL_DEFINED) == NF ) { + count = floatBufferRefNormals.limit()/3; + } + } + else { + count = interleavedFloatBufferImpl.limit()/stride; + } + } + } + return count; + } + + int getNumTexCoordCount(int i) { + int count = 0; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0){ + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0){ + count = vertexCount; + return count; + } + + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){ + switch ((vertexType & TEXCOORD_DEFINED)) { + case TF: + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + count = ((float[])refTexCoords[i]).length/2; + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + count = ((float[])refTexCoords[i]).length/3; + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + count = ((float[])refTexCoords[i]).length/4; + } + + break; + case T2F: + count = ((TexCoord2f[])refTexCoords[i]).length; + break; + case T3F: + count = ((TexCoord3f[])refTexCoords[i]).length; + } + } + else { + count = interLeavedVertexData.length/stride; + } + } + else { // nio buffer + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){ + if ((vertexType & TEXCOORD_DEFINED) == TF) { + FloatBufferWrapper texBuffer = (FloatBufferWrapper)(((J3DBuffer) refTexCoordsBuffer[i]).getBufferImpl()); + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + count = texBuffer.limit()/2; + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + count = texBuffer.limit()/3; + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + count = texBuffer.limit()/4; + } + } + } + else { + count = interleavedFloatBufferImpl.limit()/stride; + } + } + } + return count; + } + + // NOTE: we don't need a getNumVertexAttrCount method, since getNum*Count + // is only called by Morph, which doesn't support vertex attrs + + + // Found the min distance from center to the point/line/tri/quad + // form by dist[] + void computeMinDistance(Point3d coordinates[], Point3d center, + Vector3d normal, + double dist[], Point3d iPnt) { + double x, y, z; + int i, j; + + if (coordinates.length == 1) { + // a point + iPnt.x = coordinates[0].x; + iPnt.y = coordinates[0].y; + iPnt.z = coordinates[0].z; + x = iPnt.x - center.x; + y = iPnt.y - center.y; + z = iPnt.z - center.z; + dist[0] = Math.sqrt(x*x + y*y + z*z); + return; + } + + + if (coordinates.length == 2) { + // a line + dist[0] = Math.sqrt(Distance.pointToSegment(center, + coordinates[0], + coordinates[1], + iPnt, null)); + return; + } + + double normalLen = 0; + + if (normal == null) { + Vector3d vec0 = new Vector3d(); + Vector3d vec1 = new Vector3d(); + normal = new Vector3d(); + // compute plane normal for coordinates. + for (i=0; i 0.0) + break; + } + + for (j=i; j 0.0) + break; + } + + if (j == (coordinates.length-1)) { + // Degenerate polygon, check with edge only + normal = null; + } else { + normal.cross(vec0,vec1); + } + } + + if (normal != null) { + normalLen = normal.length(); + if ( normalLen == 0.0) { + // Degenerate polygon, check with edge only + normal = null; + } + } + + + if (coordinates.length == 3) { + // a triangle + if (normal != null) { + double d = -(normal.x*coordinates[0].x + + normal.y*coordinates[0].y + + normal.z*coordinates[0].z); + dist[0] = (normal.x*center.x + normal.y*center.y + + normal.z*center.z + + d)/normalLen; + iPnt.x = center.x - dist[0]*normal.x/normalLen; + iPnt.y = center.y - dist[0]*normal.y/normalLen; + iPnt.z = center.z - dist[0]*normal.z/normalLen; + + if (pointInTri(iPnt, coordinates[0], coordinates[1], + coordinates[2], normal)) { + return; + } + } + + // checking point to line distance + double minDist; + Point3d minPnt = new Point3d(); + + dist[0] = Distance.pointToSegment(center, coordinates[0], + coordinates[1], iPnt, null); + minDist = Distance.pointToSegment(center, coordinates[1], + coordinates[2], minPnt, null); + if (minDist < dist[0]) { + dist[0] = minDist; + iPnt.x = minPnt.x; + iPnt.y = minPnt.y; + iPnt.z = minPnt.z; + } + minDist = Distance.pointToSegment(center, coordinates[2], + coordinates[0], minPnt, null); + if (minDist < dist[0]) { + dist[0] = minDist; + iPnt.x = minPnt.x; + iPnt.y = minPnt.y; + iPnt.z = minPnt.z; + } + dist[0] = Math.sqrt(dist[0]); + return; + } + + // a quad + if (normal != null) { + double d = -(normal.x*coordinates[0].x + + normal.y*coordinates[0].y + + normal.z*coordinates[0].z); + dist[0] = (normal.x*center.x + normal.y*center.y + + normal.z*center.z + + d)/normalLen; + iPnt.x = center.x - dist[0]*normal.x/normalLen; + iPnt.y = center.y - dist[0]*normal.y/normalLen; + iPnt.z = center.z - dist[0]*normal.z/normalLen; + + if (pointInTri(iPnt, coordinates[0], coordinates[1], + coordinates[2], normal) || + pointInTri(iPnt, coordinates[1], coordinates[2], + coordinates[3], normal)) { + return; + } + } + + // checking point to line distance + double minDist; + Point3d minPnt = new Point3d(); + + dist[0] = Distance.pointToSegment(center, coordinates[0], + coordinates[1], iPnt, null); + minDist = Distance.pointToSegment(center, coordinates[1], + coordinates[2], minPnt, null); + if (minDist < dist[0]) { + dist[0] = minDist; + iPnt.x = minPnt.x; + iPnt.y = minPnt.y; + iPnt.z = minPnt.z; + } + minDist = Distance.pointToSegment(center, coordinates[2], + coordinates[3], minPnt, null); + if (minDist < dist[0]) { + dist[0] = minDist; + iPnt.x = minPnt.x; + iPnt.y = minPnt.y; + iPnt.z = minPnt.z; + } + + minDist = Distance.pointToSegment(center, coordinates[3], + coordinates[0], minPnt, null); + if (minDist < dist[0]) { + dist[0] = minDist; + iPnt.x = minPnt.x; + iPnt.y = minPnt.y; + iPnt.z = minPnt.z; + } + + dist[0] = Math.sqrt(dist[0]); + } + + void handleFrequencyChange(int bit) { + int mask = 0; + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + if ((bit == GeometryArray.ALLOW_COORDINATE_WRITE) || + (((vertexFormat & GeometryArray.COLOR) != 0) && + bit == GeometryArray.ALLOW_COLOR_WRITE)|| + (((vertexFormat & GeometryArray.NORMALS) != 0) && + bit == GeometryArray.ALLOW_NORMAL_WRITE) || + (((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) && + bit == GeometryArray.ALLOW_TEXCOORD_WRITE) || + (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) && + bit == GeometryArray.ALLOW_VERTEX_ATTR_WRITE) || + (bit == GeometryArray.ALLOW_COUNT_WRITE)) { + mask = 1; + } + } + else { + if (bit == GeometryArray.ALLOW_REF_DATA_WRITE) + mask = 1; + } + if (mask != 0) { + setFrequencyChangeMask(bit, mask); + } + } + + int getTexCoordType() { + return texCoordType; + } + + int getVertexAttrType() { + return vertexAttrType; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryAtom.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryAtom.java new file mode 100644 index 0000000..e21450f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryAtom.java @@ -0,0 +1,311 @@ +/* + * $RCSfile: GeometryAtom.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; +import javax.vecmath.*; + +/** + * A GeometryAtom is the smallest object representing Geometry. + */ + +class GeometryAtom extends Object implements BHLeafInterface, NnuId { + + /** + * Array of geometry components of this geometry atom + */ + // The first index of geometryArr should always be 0, unless geometryArr contains + // multiple Text3Ds. + GeometryRetained[] geometryArray = null; + + /** + * Array of transforms used only for Text3d. + */ + Transform3D[] lastLocalTransformArray = null; + + + /** + * The locale that this geometry atom is attatched to. This is only non-null + * if this instance is directly linked into a locale. + */ + Locale locale = null; + + /** + * The mirror Shape3DRetained for this GeometryAtom. + */ + Shape3DRetained source = null; + + /** + * The BHLeafNode for this GeometryAtom. + */ + BHLeafNode bhLeafNode = null; + + // true if alpha channel is editable + boolean alphaEditable; + + // true if this ga is visible. Default is true. + boolean visible = true; + + /** + * This is the original geometry type from which this atom came + */ + int geoType = -1; + + /** + * The list of RenderAtoms for this GeometryAtom + */ + RenderAtom[] renderAtoms = new RenderAtom[0]; + + // Id use for quick search. + int nnuId; + + Point3d[] centroid = null; + boolean centroidIsDirty = true; + Object lockObj = new Object(); + + + GeometryAtom() { + // Get a not necessary unique Id. + nnuId = NnuIdManager.getId(); + } + + public int getId() { + return nnuId; + } + + public int equal(NnuId obj) { + int keyId = obj.getId(); + if(nnuId < keyId) { + return -1; + } + else if(nnuId > keyId) { + return 1; + } + else { // Found it! + return 0; + } + } + + public BoundingBox computeBoundingHull() { + /* + System.err.println("Bounds is " + source.vwcBounds); + for(int i=0; i= renderAtoms.length) { + + // If creating a new RenderAtom, but this ga is not scoped + // to this view, then just return .. + if (source.viewList != null && + !source.viewList.contains(view)) + return null; + RenderAtom[] newList = new RenderAtom[index+1]; + for (int i = 0; i < renderAtoms.length; i++) { + newList[i] = renderAtoms[i]; + } + ra = new RenderAtom(); + newList[index] = ra; + newList[index].geometryAtom = this; + + // Allocate space based on number of geometry in the list + ra.rListInfo = new RenderAtomListInfo[geometryArray.length]; + if (geoType != GeometryRetained.GEO_TYPE_TEXT3D) { + for (int j = 0; j < ra.rListInfo.length; j++) { + ra.rListInfo[j] = new RenderAtomListInfo(); + ra.rListInfo[j].renderAtom = ra; + ra.rListInfo[j].index = j; + } + } + else { + for (int j = 0; j < ra.rListInfo.length; j++) { + ra.rListInfo[j] = new RenderAtomListInfo(); + ra.rListInfo[j].renderAtom = ra; + ra.rListInfo[j].index = j; + ra.rListInfo[j].localToVworld = new Transform3D(); + } + } + + // Note this must be the last line in synchronized. + // Otherwise the lock is changed to newList and + // another thread can come in modified. This cause + // NullPointerException in + // renderAtoms[index].geometryAtom = this; + // which I encounter. + renderAtoms = newList; + } else { + if (renderAtoms[index] == null) { + // If creating a new RenderAtom, but this ga is not scoped + // to this view, then just return .. + if (source.viewList != null && + !source.viewList.contains(view)) + return null; + + ra = new RenderAtom(); + renderAtoms[index] = ra; + renderAtoms[index].geometryAtom = this; + // Allocate space based on number of geometry in the list + ra.rListInfo = new RenderAtomListInfo[geometryArray.length]; + if (geoType != GeometryRetained.GEO_TYPE_TEXT3D) { + for (int j = 0; j < ra.rListInfo.length; j++) { + ra.rListInfo[j] = new RenderAtomListInfo(); + ra.rListInfo[j].renderAtom = ra; + ra.rListInfo[j].index = j; + } + } + else { + for (int j = 0; j < ra.rListInfo.length; j++) { + ra.rListInfo[j] = new RenderAtomListInfo(); + ra.rListInfo[j].renderAtom = ra; + ra.rListInfo[j].index = j; + ra.rListInfo[j].localToVworld = new Transform3D(); + } + } + } + } + } + + return (renderAtoms[index]); + } + // If the renderAtom is transparent, then make sure that the + // value is up-to-date + + void updateCentroid() { + // New for 1.3.2 + // If the sortShape3DBounds flag is set, the bounds of the + // Shape3D node will be used in place of the computed + // GeometryArray bounds for transparency sorting for those + // Shape3D nodes whose boundsAutoCompute attribute is set to + // false. + if (VirtualUniverse.mc.sortShape3DBounds && + !source.boundsAutoCompute) { + + synchronized(lockObj) { + if (centroid == null) { + centroid = new Point3d[geometryArray.length]; + for (int j = 0; j < centroid.length; j++) { + centroid[j] = new Point3d(source.localBounds.getCenter()); + source.getCurrentLocalToVworld(0).transform(centroid[j]); + } + } + else { + for (int j = 0; j < centroid.length; j++) { + centroid[j].set(source.localBounds.getCenter()); + source.getCurrentLocalToVworld(0).transform(centroid[j]); + } + } + } + + return; + } + // End of new for 1.3.2 + + synchronized(lockObj) { + for (int j = 0; j < geometryArray.length; j++) { + if (geometryArray[j] == null) + continue; + synchronized(geometryArray[j].centroid) { + if (geometryArray[j].recompCentroid) { + geometryArray[j].computeCentroid(); + geometryArray[j].recompCentroid = false; + } + } + } + if (centroidIsDirty) { + if (centroid == null) { + centroid = new Point3d[geometryArray.length]; + for (int j = 0; j < centroid.length; j++) { + if (geometryArray[j] == null) + continue; + centroid[j] = new Point3d(geometryArray[j].centroid); + source.getCurrentLocalToVworld(0).transform(centroid[j]); + } + } + else { + for (int j = 0; j < centroid.length; j++) { + if (geometryArray[j] == null) + continue; + centroid[j].set(geometryArray[j].centroid); + source.getCurrentLocalToVworld(0).transform(centroid[j]); + } + } + centroidIsDirty = false; + } + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressor.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressor.java new file mode 100644 index 0000000..a999dbd --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressor.java @@ -0,0 +1,1219 @@ +/* + * $RCSfile: GeometryDecompressor.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import javax.vecmath.* ; + +/** + * This abstract class provides the base methods needed to create a geometry + * decompressor. Subclasses must implement a backend to handle the output, + * consisting of a generalized triangle strip, line strip, or point array, + * along with possible global color and normal changes. + */ +abstract class GeometryDecompressor { + private static final boolean debug = false ; + private static final boolean benchmark = false ; + + /** + * Compressed geometry format version supported. + */ + static final int majorVersionNumber = 1 ; + static final int minorVersionNumber = 0 ; + static final int minorMinorVersionNumber = 2 ; + + /** + * This method is called when a SetState command is encountered in the + * decompression stream. + * + * @param bundlingNorm true indicates normals are bundled with vertices + * @param bundlingColor true indicates colors are bundled with vertices + * @param doingAlpha true indicates alpha values are bundled with vertices + */ + abstract void outputVertexFormat(boolean bundlingNorm, + boolean bundlingColor, + boolean doingAlpha) ; + + /** + * This method captures the vertex output of the decompressor. The normal + * or color references may be null if the corresponding data is not + * bundled with the vertices in the compressed geometry buffer. Alpha + * values may be included in the color. + * + * @param position The coordinates of the vertex. + * @param normal The normal bundled with the vertex. May be null. + * @param color The color bundled with the vertex. May be null. + * Alpha may be present. + * @param vertexReplaceCode Specifies the generalized strip flag + * that is bundled with each vertex. + * @see GeneralizedStripFlags + * @see CompressedGeometryHeader + */ + abstract void outputVertex(Point3f position, Vector3f normal, + Color4f color, int vertexReplaceCode) ; + + /** + * This method captures the global color output of the decompressor. It + * is only invoked if colors are not bundled with the vertex data. The + * global color applies to all succeeding vertices until the next time the + * method is invoked. + * + * @param color The current global color. + */ + abstract void outputColor(Color4f color) ; + + /** + * This method captures the global normal output of the decompressor. It + * is only invoked if normals are not bundled with the vertex data. The + * global normal applies to all succeeding vertices until the next time the + * method is invoked. + * + * @param normal The current global normal. + */ + abstract void outputNormal(Vector3f normal) ; + + // Geometry compression opcodes. + private static final int GC_VERTEX = 0x40 ; + private static final int GC_SET_NORM = 0xC0 ; + private static final int GC_SET_COLOR = 0x80 ; + private static final int GC_MESH_B_R = 0x20 ; + private static final int GC_SET_STATE = 0x18 ; + private static final int GC_SET_TABLE = 0x10 ; + private static final int GC_PASS_THROUGH = 0x08 ; + private static final int GC_EOS = 0x00 ; + private static final int GC_V_NO_OP = 0x01 ; + private static final int GC_SKIP_8 = 0x07 ; + + // Three 64-entry decompression tables are used: gctables[0] for + // positions, gctables[1] for colors, and gctables[2] for normals. + private HuffmanTableEntry gctables[][] ; + + /** + * Decompression table entry. + */ + static class HuffmanTableEntry { + int tagLength, dataLength ; + int rightShift, absolute ; + + public String toString() { + return + " tag length: " + tagLength + + " data length: " + dataLength + + " shift: " + rightShift + + " abs/rel: " + absolute ; + } + } + + // A 16-entry mesh buffer is used. + private MeshBufferEntry meshBuffer[] ; + private int meshIndex = 15 ; + private int meshState ; + + // meshState values. These are needed to determine if colors and/or + // normals should come from meshBuffer or from SetColor or SetNormal. + private static final int USE_MESH_NORMAL = 0x1 ; + private static final int USE_MESH_COLOR = 0x2 ; + + /** + * Mesh buffer entry containing position, normal, and color. + */ + static class MeshBufferEntry { + short x, y, z ; + short octant, sextant, u, v ; + short r, g, b, a ; + } + + // Geometry compression state variables. + private short curX, curY, curZ ; + private short curR, curG, curB, curA ; + private int curSex, curOct, curU, curV ; + + // Current vertex data. + private Point3f curPos ; + private Vector3f curNorm ; + private Color4f curColor ; + private int repCode ; + + // Flags indicating what data is bundled with the vertex. + private boolean bundlingNorm ; + private boolean bundlingColor ; + private boolean doingAlpha ; + + // Internal decompression buffering variables. + private int currentHeader = 0 ; + private int nextHeader = 0 ; + private int bitBuffer = 0 ; + private int bitBufferCount = 32 ; + + // Used for benchmarking if so configured. + private long startTime ; + private int vertexCount ; + + // Bit-field masks: BMASK[i] = (1< 64) continue ; + + psi = NORMAL_MAX_Y_ANG * (i / 64.0) ; + th = Math.asin(Math.tan(NORMAL_MAX_Y_ANG * ((64-j)/64.0))) ; + + qnx = Math.cos(th) * Math.cos(psi) ; + qny = Math.sin(psi) ; + qnz = Math.sin(th) * Math.cos(psi) ; + + // Convert the floating point normal to s1.14 bit notation, + // then back again. + qnx = qnx*16384.0 ; inx = (int)qnx ; + qnx = (double)inx ; qnx = qnx/16384.0 ; + + qny = qny*16384.0 ; iny = (int)qny ; + qny = (double)iny ; qny = qny/16384.0 ; + + qnz = qnz*16384.0 ; inz = (int)qnz ; + qnz = (double)inz ; qnz = qnz/16384.0 ; + + gcNormals[i][j][0] = qnx ; + gcNormals[i][j][1] = qny ; + gcNormals[i][j][2] = qnz ; + } + } + + if (printNormalTable) { + System.err.println("struct {") ; + System.err.println(" double nx, ny, nz ;") ; + System.err.println("} gcNormals[65][65] = {"); + for (i = 0 ; i <= 64 ; i++) { + System.err.println("{") ; + for (j = 0 ; j <= 64 ; j++) { + if (j+i > 64) continue ; + System.err.println("{ " + gcNormals[i][j][0] + + ", " + gcNormals[i][j][1] + + ", " + gcNormals[i][j][2] + " }") ; + } + System.err.println("},") ; + } + System.err.println("}") ; + } + } + + // + // The constructor. + // + GeometryDecompressor() { + curPos = new Point3f() ; + curNorm = new Vector3f() ; + curColor = new Color4f() ; + gctables = new HuffmanTableEntry[3][64] ; + + for (int i = 0 ; i < 64 ; i++) { + gctables[0][i] = new HuffmanTableEntry() ; + gctables[1][i] = new HuffmanTableEntry() ; + gctables[2][i] = new HuffmanTableEntry() ; + } + + meshBuffer = new MeshBufferEntry[16] ; + for (int i = 0 ; i < 16 ; i++) + meshBuffer[i] = new MeshBufferEntry() ; + } + + /** + * Check version numbers and return true if compatible. + */ + boolean checkVersion(int majorVersionNumber, int minorVersionNumber) { + return ((majorVersionNumber < this.majorVersionNumber) || + ((majorVersionNumber == this.majorVersionNumber) && + (minorVersionNumber <= this.minorVersionNumber))) ; + } + + /** + * Decompress data and invoke abstract output methods. + * + * @param start byte offset to start of compressed geometry in data array + * @param length size of compressed geometry in bytes + * @param data array containing compressed geometry buffer of the + * specified length at the given offset from the start of the array + * @exception ArrayIndexOutOfBoundsException if start+length > data size + */ + void decompress(int start, int length, byte data[]) { + if (debug) + System.err.println("GeometryDecompressor.decompress\n" + + " start: " + start + + " length: " + length + + " data array size: " + data.length) ; + if (benchmark) + benchmarkStart(length) ; + + if (start+length > data.length) + throw new ArrayIndexOutOfBoundsException + (J3dI18N.getString("GeometryDecompressor0")) ; + + // Set reference to compressed data and skip to start of data. + gcData = data ; + gcIndex = start ; + + // Initialize state. + bitBufferCount = 0 ; + meshState = 0 ; + bundlingNorm = false ; + bundlingColor = false ; + doingAlpha = false ; + repCode = 0 ; + + // Headers are interleaved for hardware implementations, so the + // first is always a nullop. + nextHeader = GC_V_NO_OP ; + + // Enter decompression loop. + while (gcIndex < start+length) + processDecompression() ; + + // Finish out any bits left in bitBuffer. + while (bitBufferCount > 0) + processDecompression() ; + + if (benchmark) + benchmarkPrint(length) ; + } + + // + // Return the next bitCount bits of compressed data. + // + private int getBits(int bitCount, String d) { + int bits ; + + if (debug) + System.err.print(" getBits(" + bitCount + ") " + d + ", " + + bitBufferCount + " available at gcIndex " + + gcIndex) ; + + if (bitCount == 0) { + if (debug) System.err.println(": got 0x0") ; + return 0 ; + } + + if (bitBufferCount == 0) { + bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) | + ((gcData[gcIndex++] & 0xff) << 16) | + ((gcData[gcIndex++] & 0xff) << 8) | + ((gcData[gcIndex++] & 0xff))) ; + + bitBufferCount = 32 ; + } + + if (bitBufferCount >= bitCount) { + bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ; + bitBuffer = bitBuffer << bitCount ; + bitBufferCount -= bitCount ; + } else { + bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ; + bits = bits >>> (bitCount - bitBufferCount) ; + bits = bits << (bitCount - bitBufferCount) ; + + bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) | + ((gcData[gcIndex++] & 0xff) << 16) | + ((gcData[gcIndex++] & 0xff) << 8) | + ((gcData[gcIndex++] & 0xff))) ; + + bits = bits | + ((bitBuffer >>> (32 - (bitCount - bitBufferCount))) & + BMASK[bitCount - bitBufferCount]) ; + + bitBuffer = bitBuffer << (bitCount - bitBufferCount) ; + bitBufferCount = 32 - (bitCount - bitBufferCount) ; + } + + if (debug) + System.err.println(": got 0x" + Integer.toHexString(bits)) ; + + return bits ; + } + + // + // Shuffle interleaved headers and opcodes. + // + private void processDecompression() { + int mbp ; + currentHeader = nextHeader ; + + if ((currentHeader & 0xC0) == GC_VERTEX) { + // Process a vertex. + if (!bundlingNorm && !bundlingColor) { + // get next opcode, process current position opcode + nextHeader = getBits(8, "header") ; + mbp = processDecompressionOpcode(0) ; + + } else if (bundlingNorm && !bundlingColor) { + // get normal header, process current position opcode + nextHeader = getBits(6, "normal") ; + mbp = processDecompressionOpcode(0) ; + currentHeader = nextHeader | GC_SET_NORM ; + + // get next opcode, process current normal opcode + nextHeader = getBits(8, "header") ; + processDecompressionOpcode(mbp) ; + + } else if (!bundlingNorm && bundlingColor) { + // get color header, process current position opcode + nextHeader = getBits(6, "color") ; + mbp = processDecompressionOpcode(0) ; + currentHeader = nextHeader | GC_SET_COLOR ; + + // get next opcode, process current color opcode + nextHeader = getBits(8, "header") ; + processDecompressionOpcode(mbp) ; + + } else { + // get normal header, process current position opcode + nextHeader = getBits(6, "normal") ; + mbp = processDecompressionOpcode(0) ; + currentHeader = nextHeader | GC_SET_NORM ; + + // get color header, process current normal opcode + nextHeader = getBits(6, "color") ; + processDecompressionOpcode(mbp) ; + currentHeader = nextHeader | GC_SET_COLOR ; + + // get next opcode, process current color opcode + nextHeader = getBits(8, "header") ; + processDecompressionOpcode(mbp) ; + } + + // Send out the complete vertex. + outputVertex(curPos, curNorm, curColor, repCode) ; + if (benchmark) vertexCount++ ; + + // meshState bits get turned off in the setColor and setNormal + // routines in order to keep track of what data a mesh buffer + // reference should use. + meshState |= USE_MESH_NORMAL ; + meshState |= USE_MESH_COLOR ; + + } else { + // Non-vertex case: get next opcode, then process current opcode. + nextHeader = getBits(8, "header") ; + processDecompressionOpcode(0) ; + } + } + + // + // Decode the opcode in currentHeader, and dispatch to the appropriate + // processing method. + // + private int processDecompressionOpcode(int mbp) { + if ((currentHeader & 0xC0) == GC_SET_NORM) + processSetNormal(mbp) ; + else if ((currentHeader & 0xC0) == GC_SET_COLOR) + processSetColor(mbp) ; + else if ((currentHeader & 0xC0) == GC_VERTEX) + // Return the state of the mesh buffer push bit + // when processing a vertex. + return processVertex() ; + else if ((currentHeader & 0xE0) == GC_MESH_B_R) { + processMeshBR() ; + + // Send out the complete vertex. + outputVertex(curPos, curNorm, curColor, repCode) ; + if (benchmark) vertexCount++ ; + + // meshState bits get turned off in the setColor and setNormal + // routines in order to keep track of what data a mesh buffer + // reference should use. + meshState |= USE_MESH_NORMAL ; + meshState |= USE_MESH_COLOR ; + } + else if ((currentHeader & 0xF8) == GC_SET_STATE) + processSetState() ; + else if ((currentHeader & 0xF8) == GC_SET_TABLE) + processSetTable() ; + else if ((currentHeader & 0xFF) == GC_EOS) + processEos() ; + else if ((currentHeader & 0xFF) == GC_V_NO_OP) + processVNoop() ; + else if ((currentHeader & 0xFF) == GC_PASS_THROUGH) + processPassThrough() ; + else if ((currentHeader & 0xFF) == GC_SKIP_8) + processSkip8() ; + + return 0 ; + } + + // + // Process a set state opcode. + // + private void processSetState() { + int ii ; + if (debug) + System.err.println("GeometryDecompressor.processSetState") ; + + ii = getBits(3, "bundling") ; + + bundlingNorm = ((currentHeader & 0x1) != 0) ; + bundlingColor = (((ii >>> 2) & 0x1) != 0) ; + doingAlpha = (((ii >>> 1) & 0x1) != 0) ; + + if (debug) + System.err.println(" bundling normal: " + bundlingNorm + + " bundling color: " + bundlingColor + + " alpha present: " + doingAlpha) ; + + // Call the abstract output implementation. + outputVertexFormat(bundlingNorm, bundlingColor, doingAlpha) ; + } + + // + // Process a set decompression table opcode. + // + // Extract the parameters of the table set command, + // and set the approprate table entries. + // + private void processSetTable() { + HuffmanTableEntry gct[] ; + int i, adr, tagLength, dataLength, rightShift, absolute ; + int ii, index ; + + if (debug) + System.err.println("GeometryDecompressor.processSetTable") ; + + // Get reference to approprate 64 entry table. + index = (currentHeader & 0x6) >>> 1 ; + gct = gctables[index] ; + + // Get the remaining bits of the set table command. + ii = getBits(15, "set table") ; + + // Extract the individual fields from the two bit strings. + adr = ((currentHeader & 0x1) << 6) | ((ii >>> 9) & 0x3F) ; + + // Get data length. For positions and colors, 0 really means 16, as 0 + // lengths are meaningless for them. Normal components are allowed to + // have lengths of 0. + dataLength = (ii >>> 5) & 0x0F ; + if (dataLength == 0 && index != 2) + dataLength = 16 ; + + rightShift = ii & 0x0F ; + absolute = (ii >>> 4) & 0x1 ; + + // + // Decode the tag length from the address field by finding the + // first set 1 from the left in the bitfield. + // + for (tagLength = 6 ; tagLength > 0 ; tagLength--) { + if ((adr >> tagLength) != 0) break ; + } + + // Shift the address bits up into place, and off the leading 1. + adr = (adr << (6 - tagLength)) & 0x3F ; + + if (debug) + System.err.println(" table " + ((currentHeader & 0x6) >>> 1) + + " address " + adr + + " tag length " + tagLength + + " data length " + dataLength + + " shift " + rightShift + + " absolute " + absolute) ; + + // Fill in the table fields with the specified values. + for (i = 0 ; i < (1 << (6 - tagLength)) ; i++) { + gct[adr+i].tagLength = tagLength ; + gct[adr+i].dataLength = dataLength ; + gct[adr+i].rightShift = rightShift ; + gct[adr+i].absolute = absolute ; + } + } + + + // + // Process a vertex opcode. Any bundled normal and/or color will be + // processed by separate methods. Return the mesh buffer push indicator. + // + private int processVertex() { + HuffmanTableEntry gct ; + float fX, fY, fZ ; + short dx, dy, dz ; + int mbp, x, y, z, dataLen ; + int ii ; + + // If the next command is a mesh buffer reference + // then use colors and normals from the mesh buffer. + meshState = 0 ; + + // Get a reference to the approprate tag table entry. + gct = gctables[0][currentHeader & 0x3F] ; + + if (debug) System.err.println("GeometryDecompressor.processVertex\n" + + gct.toString()) ; + + // Get the true length of the data. + dataLen = gct.dataLength - gct.rightShift ; + + // Read in the replace code and mesh buffer push bits, + // if they're not in the current header. + if (6 - (3 * dataLen) - gct.tagLength > 0) { + int numBits = 6 - (3 * dataLen) - gct.tagLength ; + int jj ; + + jj = currentHeader & BMASK[numBits] ; + ii = getBits(3 - numBits, "repcode/mbp") ; + ii |= (jj << (3 - numBits)) ; + } + else + ii = getBits(3, "repcode/mbp") ; + + repCode = ii >>> 1 ; + mbp = ii & 0x1 ; + + // Read in x, y, and z components. + x = currentHeader & BMASK[6-gct.tagLength] ; + + if (gct.tagLength + dataLen == 6) { + y = getBits(dataLen, "y") ; + z = getBits(dataLen, "z") ; + } else if (gct.tagLength + dataLen < 6) { + x = x >> (6 - gct.tagLength - dataLen) ; + + y = currentHeader & BMASK[6 - gct.tagLength - dataLen] ; + if (gct.tagLength + 2*dataLen == 6) { + z = getBits(dataLen, "z") ; + } else if (gct.tagLength + 2*dataLen < 6) { + y = y >> (6 - gct.tagLength - 2*dataLen) ; + + z = currentHeader & BMASK[6 - gct.tagLength - 2*dataLen] ; + if (gct.tagLength + 3*dataLen < 6) { + z = z >> (6 - gct.tagLength - 3*dataLen) ; + } else if (gct.tagLength + 3*dataLen > 6) { + ii = getBits(dataLen - (6 - gct.tagLength - 2*dataLen), + "z") ; + z = (z << (dataLen - (6 - gct.tagLength - 2*dataLen))) + | ii ; + } + } else { + ii = getBits(dataLen - (6 - gct.tagLength - dataLen), "y") ; + y = (y << (dataLen - (6 - gct.tagLength - dataLen))) | ii ; + z = getBits(dataLen, "z") ; + } + } else { + ii = getBits(dataLen - (6 - gct.tagLength), "x") ; + x = (x << (dataLen - (6 - gct.tagLength))) | ii ; + y = getBits(dataLen, "y") ; + z = getBits(dataLen, "z") ; + } + + // Sign extend delta x y z components. + x = x << (32 - dataLen) ; x = x >> (32 - dataLen) ; + y = y << (32 - dataLen) ; y = y >> (32 - dataLen) ; + z = z << (32 - dataLen) ; z = z >> (32 - dataLen) ; + + // Normalize values. + dx = (short)(x << gct.rightShift) ; + dy = (short)(y << gct.rightShift) ; + dz = (short)(z << gct.rightShift) ; + + // Update current position, first adding deltas if in relative mode. + if (gct.absolute != 0) { + curX = dx ; curY = dy ; curZ = dz ; + if (debug) System.err.println(" absolute position: " + + curX + " " + curY + " " + curZ) ; + } else { + curX += dx ; curY += dy ; curZ += dz ; + if (debug) System.err.println(" delta position: " + + dx + " " + dy + " " + dz) ; + } + + // Do optional mesh buffer push. + if (mbp != 0) { + // Increment to next position (meshIndex is initialized to 15). + meshIndex = (meshIndex + 1) & 0xF ; + meshBuffer[meshIndex].x = curX ; + meshBuffer[meshIndex].y = curY ; + meshBuffer[meshIndex].z = curZ ; + if (debug) + System.err.println(" pushed position into mesh buffer at " + + meshIndex) ; + } + + // Convert point back to [-1..1] floating point. + fX = curX ; fX /= 32768.0 ; + fY = curY ; fY /= 32768.0 ; + fZ = curZ ; fZ /= 32768.0 ; + if (debug) + System.err.println(" result position " + fX + " " + fY + " " + fZ) ; + + curPos.set(fX, fY, fZ) ; + return mbp ; + } + + + // + // Process a set current normal opcode. + // + private void processSetNormal(int mbp) { + HuffmanTableEntry gct ; + int index, du, dv, n, dataLength ; + int ii ; + + // if next command is a mesh buffer reference, use this normal + meshState &= ~USE_MESH_NORMAL ; + + // use table 2 for normals + gct = gctables[2][currentHeader & 0x3F] ; + + if (debug) + System.err.println("GeometryDecompressor.processSetNormal\n" + + gct.toString()) ; + + // subtract up-shift amount to get true data (u, v) length + dataLength = gct.dataLength - gct.rightShift ; + + if (gct.absolute != 0) { + // + // Absolute normal case. Extract index from 6-bit tag. + // + index = currentHeader & BMASK[6-gct.tagLength] ; + + if (gct.tagLength != 0) { + // read in the rest of the 6-bit sex/oct pair (index) + ii = getBits(6 - (6 - gct.tagLength), "sex/oct") ; + index = (index << (6 - (6 - gct.tagLength))) | ii ; + } + + // read in u and v data + curU = getBits(dataLength, "u") ; + curV = getBits(dataLength, "v") ; + + // normalize u, v, sextant, and octant + curU = curU << gct.rightShift ; + curV = curV << gct.rightShift ; + + curSex = (index >> 3) & 0x7 ; + curOct = index & 0x7 ; + + if (debug) { + if (curSex < 6) + System.err.println(" absolute normal: sex " + curSex + + " oct " + curOct + + " u " + curU + " v " + curV) ; + else + System.err.println(" special normal: sex " + curSex + + " oct " + curOct) ; + } + } else { + // + // Relative normal case. Extract du from 6-bit tag. + // + du = currentHeader & BMASK[6-gct.tagLength] ; + + if (gct.tagLength + dataLength < 6) { + // normalize du, get dv + du = du >> (6 - gct.tagLength - dataLength) ; + dv = currentHeader & BMASK[6 - gct.tagLength - dataLength] ; + + if (gct.tagLength + 2*dataLength < 6) { + // normalize dv + dv = dv >> (6 - gct.tagLength - 2*dataLength) ; + } else if (gct.tagLength + 2*dataLength > 6) { + // read in rest of dv and normalize it + ii = getBits(dataLength - + (6 - gct.tagLength - dataLength), "dv") ; + dv = (dv << (dataLength - + (6 - gct.tagLength - dataLength))) | ii ; + } + } else if (gct.tagLength + dataLength > 6) { + // read in rest of du and normalize it + ii = getBits(dataLength - (6 - gct.tagLength), "du") ; + du = (du << (dataLength - (6 - gct.tagLength))) | ii ; + // read in dv + dv = getBits(dataLength, "dv") ; + } else { + // read in dv + dv = getBits(dataLength, "dv") ; + } + + // Sign extend delta uv components. + du = du << (32 - dataLength) ; du = du >> (32 - dataLength) ; + dv = dv << (32 - dataLength) ; dv = dv >> (32 - dataLength) ; + + // normalize values + du = du << gct.rightShift ; + dv = dv << gct.rightShift ; + + // un-delta + curU += du ; + curV += dv ; + + if (debug) + System.err.println(" delta normal: du " + du + " dv " + dv) ; + + // + // Check for normal wrap. + // + if (! ((curU >= 0) && (curV >= 0) && (curU + curV <= 64))) + if ((curU < 0) && (curV >= 0)) { + // wrap on u, same octant, different sextant + curU = -curU ; + switch (curSex) { + case 0: curSex = 4 ; break ; + case 1: curSex = 5 ; break ; + case 2: curSex = 3 ; break ; + case 3: curSex = 2 ; break ; + case 4: curSex = 0 ; break ; + case 5: curSex = 1 ; break ; + } + } else if ((curU >= 0) && (curV < 0)) { + // wrap on v, same sextant, different octant + curV = -curV ; + switch (curSex) { + case 1: case 5: + curOct = curOct ^ 4 ; // invert x axis + break ; + case 0: case 4: + curOct = curOct ^ 2 ; // invert y axis + break ; + case 2: case 3: + curOct = curOct ^ 1 ; // invert z axis + break ; + } + } else if (curU + curV > 64) { + // wrap on uv, same octant, different sextant + curU = 64 - curU ; + curV = 64 - curV ; + switch (curSex) { + case 0: curSex = 2 ; break ; + case 1: curSex = 3 ; break ; + case 2: curSex = 0 ; break ; + case 3: curSex = 1 ; break ; + case 4: curSex = 5 ; break ; + case 5: curSex = 4 ; break ; + } + } else { + throw new IllegalArgumentException + (J3dI18N.getString("GeometryDecompressor1")) ; + } + } + + // do optional mesh buffer push + if (mbp != 0) { + if (debug) + System.err.println(" pushing normal into mesh buffer at " + + meshIndex) ; + + meshBuffer[meshIndex].sextant = (short)curSex ; + meshBuffer[meshIndex].octant = (short)curOct ; + meshBuffer[meshIndex].u = (short)curU ; + meshBuffer[meshIndex].v = (short)curV ; + } + + // convert normal back to [-1..1] floating point + indexNormal(curSex, curOct, curU, curV, curNorm) ; + + // a set normal opcode when normals aren't bundled with the vertices + // is a global normal change. + if (! bundlingNorm) outputNormal(curNorm) ; + } + + + // + // Get the floating point normal from its sextant, octant, u, and v. + // + private void indexNormal(int sex, int oct, int u, int v, Vector3f n) { + float nx, ny, nz, t ; + + if (debug) System.err.println(" sextant " + sex + " octant " + oct + + " u " + u + " v " + v) ; + if (sex > 5) { + // special normals + switch (oct & 0x1) { + case 0: // six coordinate axes + switch (((sex & 0x1) << 1) | ((oct & 0x4) >> 2)) { + case 0: nx = 1.0f ; ny = nz = 0.0f ; break ; + case 1: ny = 1.0f ; nx = nz = 0.0f ; break ; + default: + case 2: nz = 1.0f ; nx = ny = 0.0f ; break ; + } + sex = 0 ; oct = (oct & 0x2) >> 1 ; + oct = (oct << 2) | (oct << 1) | oct ; + break ; + case 1: // eight mid + default: + oct = ((sex & 0x1) << 2) | (oct >> 1) ; + sex = 0 ; + nx = ny = nz = (float)(1.0/Math.sqrt(3.0)) ; + break ; + } + if ((oct & 0x1) != 0) nz = -nz ; + if ((oct & 0x2) != 0) ny = -ny ; + if ((oct & 0x4) != 0) nx = -nx ; + + } else { + // regular normals + nx = (float)gcNormals[v][u][0] ; + ny = (float)gcNormals[v][u][1] ; + nz = (float)gcNormals[v][u][2] ; + + // reverse the swap + if ((sex & 0x4) != 0) { t = nx ; nx = nz ; nz = t ; } + if ((sex & 0x2) != 0) { t = ny ; ny = nz ; nz = t ; } + if ((sex & 0x1) != 0) { t = nx ; nx = ny ; ny = t ; } + + // reverse the sign flip + if ((oct & 0x1) != 0) nz = -nz ; + if ((oct & 0x2) != 0) ny = -ny ; + if ((oct & 0x4) != 0) nx = -nx ; + } + + // return resulting normal + n.set(nx, ny, nz) ; + if (debug) + System.err.println(" result normal: " + nx + " " + ny + " " + nz) ; + } + + + // + // Process a set current color command. + // + private void processSetColor(int mbp) { + HuffmanTableEntry gct ; + short dr, dg, db, da ; + float fR, fG, fB, fA ; + int r, g, b, a, index, dataLength ; + int ii ; + + // If the next command is a mesh buffer reference, use this color. + meshState &= ~USE_MESH_COLOR ; + + // Get the huffman table entry. + gct = gctables[1][currentHeader & 0x3F] ; + + if (debug) + System.err.println("GeometryDecompressor.processSetColor\n" + + gct.toString()) ; + + // Get the true length of the data. + dataLength = gct.dataLength - gct.rightShift ; + + // Read in red, green, blue, and possibly alpha. + r = currentHeader & BMASK[6 - gct.tagLength] ; + a = 0 ; + + if (gct.tagLength + dataLength == 6) { + g = getBits(dataLength, "g") ; + b = getBits(dataLength, "b") ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + else if (gct.tagLength + dataLength < 6) { + r = r >> (6 - gct.tagLength - dataLength) ; + + g = currentHeader & BMASK[6-gct.tagLength-dataLength] ; + if (gct.tagLength + 2*dataLength == 6) { + b = getBits(dataLength, "b") ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + else if (gct.tagLength + 2*dataLength < 6) { + g = g >> (6 - gct.tagLength - 2*dataLength) ; + + b = currentHeader & BMASK[6-gct.tagLength-2*dataLength] ; + if (gct.tagLength + 3*dataLength == 6) { + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + else if (gct.tagLength + 3*dataLength < 6) { + b = b >> (6 - gct.tagLength - 3*dataLength) ; + + if (doingAlpha) { + a = currentHeader & + BMASK[6 - gct.tagLength - 4*dataLength] ; + if (gct.tagLength + 4 * dataLength < 6) { + a = a >> (6 - gct.tagLength - 3*dataLength) ; + } + else if (gct.tagLength + 4 * dataLength > 6) { + ii = getBits(dataLength - + (6-gct.tagLength - 3*dataLength), "a") ; + a = (a << (dataLength - + (6-gct.tagLength - 3*dataLength))) | ii ; + } + } + } else { + ii = getBits(dataLength - + (6 - gct.tagLength - 2*dataLength), "b") ; + b = (b << (dataLength - + (6 - gct.tagLength - 2*dataLength))) | ii ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + } else { + ii = getBits(dataLength - (6 - gct.tagLength - dataLength), + "g") ; + g = (g << (dataLength - + (6 - gct.tagLength - dataLength))) | ii ; + b = getBits(dataLength, "b") ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + } else { + ii = getBits(dataLength - (6 - gct.tagLength), "r") ; + r = (r << (dataLength - (6 - gct.tagLength))) | ii ; + g = getBits(dataLength, "g") ; + b = getBits(dataLength, "b") ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + + // Sign extend delta x y z components. + r <<= (32 - dataLength) ; r >>= (32 - dataLength) ; + g <<= (32 - dataLength) ; g >>= (32 - dataLength) ; + b <<= (32 - dataLength) ; b >>= (32 - dataLength) ; + a <<= (32 - dataLength) ; a >>= (32 - dataLength) ; + + // Normalize values. + dr = (short)(r << gct.rightShift) ; + dg = (short)(g << gct.rightShift) ; + db = (short)(b << gct.rightShift) ; + da = (short)(a << gct.rightShift) ; + + // Update current position, first adding deltas if in relative mode. + if (gct.absolute != 0) { + curR = dr ; curG = dg ; curB = db ; + if (doingAlpha) curA = da ; + if (debug) System.err.println(" absolute color: r " + curR + + " g " + curG + " b " + curB + + " a " + curA) ; + } else { + curR += dr ; curG += dg ; curB += db ; + if (doingAlpha) curA += da ; + if (debug) System.err.println(" delta color: dr " + dr + + " dg " + dg + " db " + db + + " da " + da) ; + } + + // Do optional mesh buffer push. + if (mbp != 0) { + if (debug) + System.err.println(" pushing color into mesh buffer at " + + meshIndex) ; + + meshBuffer[meshIndex].r = curR ; + meshBuffer[meshIndex].g = curG ; + meshBuffer[meshIndex].b = curB ; + meshBuffer[meshIndex].a = curA ; + } + + // Convert point back to [-1..1] floating point. + fR = curR ; fR /= 32768.0 ; + fG = curG ; fG /= 32768.0 ; + fB = curB ; fB /= 32768.0 ; + fA = curA ; fA /= 32768.0 ; + + curColor.set(fR, fG, fB, fA) ; + if (debug) System.err.println(" result color: " + fR + + " " + fG + " " + fB + " " + fA) ; + + // A set color opcode when colors aren't bundled with the vertices + // is a global color change. + if (! bundlingColor) outputColor(curColor) ; + } + + + // + // Process a mesh buffer reference command. + // + private void processMeshBR() { + MeshBufferEntry entry ; + int index, normal ; + int ii ; + + if (debug) + System.err.println("GeometryDecompressor.processMeshBR") ; + + ii = getBits(1, "mbr") ; + + index = (currentHeader >>> 1) & 0xF ; + repCode = ((currentHeader & 0x1) << 1) | ii ; + + // Adjust index to proper place in fifo. + index = (meshIndex - index) & 0xf ; + if (debug) + System.err.println(" using index " + index) ; + + // Get reference to mesh buffer entry. + entry = meshBuffer[index] ; + curX = entry.x ; + curY = entry.y ; + curZ = entry.z ; + + // Convert point back to [-1..1] floating point. + curPos.set(((float)curX)/32768.0f, + ((float)curY)/32768.0f, + ((float)curZ)/32768.0f) ; + + if (debug) System.err.println(" retrieved position " + curPos.x + + " " + curPos.y + " " + curPos.z + + " replace code " + repCode) ; + + // Get mesh buffer normal if previous opcode was not a setNormal. + if (bundlingNorm && ((meshState & USE_MESH_NORMAL) != 0)) { + curSex = entry.sextant ; + curOct = entry.octant ; + curU = entry.u ; + curV = entry.v ; + + // Convert normal back to -1.0 - 1.0 floating point from index. + normal = (curSex<<15) | (curOct<<12) | (curU<<6) | curV ; + + if (debug) System.err.println(" retrieving normal") ; + indexNormal(curSex, curOct, curU, curV, curNorm) ; + } + + // Get mesh buffer color if previous opcode was not a setColor. + if (bundlingColor && ((meshState & USE_MESH_COLOR) != 0)) { + curR = entry.r ; + curG = entry.g ; + curB = entry.b ; + + // Convert point back to -1.0 - 1.0 floating point. + curColor.x = curR ; curColor.x /= 32768.0 ; + curColor.y = curG ; curColor.y /= 32768.0 ; + curColor.z = curB ; curColor.z /= 32768.0 ; + + if (doingAlpha) { + curA = entry.a ; + curColor.w = curA ; curColor.w /= 32768.0 ; + } + if (debug) + System.err.println(" retrieved color " + curColor.x + + " " + curColor.y + " " + curColor.z + + " " + curColor.w) ; + } + + // Reset meshState. + meshState = 0 ; + } + + + // Process a end-of-stream opcode. + private void processEos() { + if (debug) System.err.println("GeometryDecompressor.processEos") ; + } + + // Process a variable length no-op opcode. + private void processVNoop() { + int ii, ct ; + if (debug) System.err.println("GeometryDecompressor.processVNoop") ; + + ct = getBits(5, "noop count") ; + ii = getBits(ct, "noop bits") ; + } + + // Process a pass-through opcode. + private void processPassThrough() { + int ignore ; + if (debug) + System.err.println("GeometryDecompressor.processPassThrough") ; + + ignore = getBits(24, "passthrough") ; + ignore = getBits(32, "passthrough") ; + } + + // Process a skip-8 opcode. + private void processSkip8() { + int skip ; + if (debug) System.err.println("GeometryDecompressor.processSkip8") ; + + skip = getBits(8, "skip8") ; + } + + private void benchmarkStart(int length) { + vertexCount = 0 ; + System.err.println(" GeometryDecompressor: decompressing " + + length + " bytes...") ; + startTime = J3dClock.currentTimeMillis() ; + } + + private void benchmarkPrint(int length) { + float t = (J3dClock.currentTimeMillis() - startTime) / 1000.0f ; + System.err.println + (" done in " + t + " sec." + "\n" + + " decompressed " + vertexCount + " vertices at " + + (vertexCount/t) + " vertices/sec\n") ; + + System.err.print(" vertex data present: coords") ; + int floatVertexSize = 12 ; + if (bundlingNorm) { + System.err.print(" normals") ; + floatVertexSize += 12 ; + } + if (bundlingColor) { + System.err.println(" colors") ; + floatVertexSize += 12 ; + } + if (doingAlpha) { + System.err.println(" alpha") ; + floatVertexSize += 4 ; + } + System.err.println() ; + + System.err.println + (" bytes of data in generalized strip output: " + + (vertexCount * floatVertexSize) + "\n" + + " compression ratio: " + + (length / (float)(vertexCount * floatVertexSize)) + "\n") ; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressorRetained.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressorRetained.java new file mode 100644 index 0000000..5304a03 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressorRetained.java @@ -0,0 +1,403 @@ +/* + * $RCSfile: GeometryDecompressorRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import javax.vecmath.* ; +import java.util.* ; + +/** + * This class implements a retained geometry backend for the abstract + * GeometryDecompressor. + */ +class GeometryDecompressorRetained extends GeometryDecompressor { + private static final boolean debug = false ; + private static final boolean benchmark = false ; + private static final boolean statistics = false ; + private static final boolean printInfo = debug || benchmark || statistics ; + + // Type of connections in the compressed data: + // TYPE_POINT (1), TYPE_LINE (2), or TYPE_TRIANGLE (4). + private int bufferDataType ; + + // Data bundled with each vertex: bitwise combination of + // NORMAL_IN_BUFFER (1), COLOR_IN_BUFFER (2), ALPHA_IN_BUFFER (4). + private int dataPresent ; + + // Size of the compressed geometry in bytes. + private int size ; + + // Decompressor output state variables. + private Color4f curColor ; + private Vector3f curNormal ; + + // List for accumulating the output of the decompressor and converting to + // GeometryArray representations. + private GeneralizedVertexList vlist ; + + // Geometric bounds. + private Point3d lbounds = new Point3d() ; + private Point3d ubounds = new Point3d() ; + + // Decompression output constraints. The decompressor will still process + // all data contained in the compressed buffer, but will only retain data + // for output subject to these booleans. + private boolean boundsOnly = false ; + private boolean positionsOnly = false ; + + // A very rough gauge used to initialize the size of vlist, based on + // normal-per-vertex data collected from the HelloUniverse.cg file + // (seagull, '57 Chevy, dinosaur). + // + // XXXX: get fudge values for other vertex combinations + private static final float bytesPerVertexFudge = 5.3f ; + + // Used for benchmarking if so configured. + private long startTime ; + private long endTime ; + + // Private convenience copies of various constants. + private static final int TYPE_POINT = + CompressedGeometryRetained.TYPE_POINT ; + private static final int TYPE_LINE = + CompressedGeometryRetained.TYPE_LINE ; + private static final int TYPE_TRIANGLE = + CompressedGeometryRetained.TYPE_TRIANGLE ; + private static final int FRONTFACE_CCW = + GeneralizedStripFlags.FRONTFACE_CCW ; + + /** + * If the given argument is true, sets the decompressor to output only the + * bounding box of the decompressed geometry. + * @param boundsOnly set to true if the decompressor should output only the + * geometric bounding box. + */ + void setDecompressBoundsOnly(boolean boundsOnly) { + this.boundsOnly = boundsOnly ; + if (boundsOnly) this.positionsOnly = false ; + } + + /** + * If the given argument is true, sets the decompressor to output only the + * decompressed positions, their connections, and the bounding box. + * @param positionsOnly set to true if the decompressor should output only + * position, connection, and bounding box data. + */ + void setDecompressPositionsOnly(boolean positionsOnly) { + this.positionsOnly = positionsOnly ; + if (positionsOnly) this.boundsOnly = false ; + } + + /** + * Decompress the geometry data in a CompressedGeometryRetained. The + * GeometryArray output is intended to be cached as retained data for + * efficient rendering. Global color and normal changes output by the + * decompressor are stored as redundant per-vertex data so that a single + * GeometryArray can be used. + * + * Since only one GeometryArray is created, if the bundling attributes + * change while building the vertex list then the decompression is + * aborted. There should be only one SetState bundling attribute command + * per CompressedGeometry. + * + * @param cgr CompressedGeometryRetained containing compressed geometry + * @return GeometryArrayRetained containing the results of the + * decompression, or null if only the bounds are computed. + */ + GeometryRetained decompress(CompressedGeometryRetained cgr) { + + if (! checkVersion(cgr.majorVersionNumber, cgr.minorVersionNumber)) { + return null ; + } + + vlist = null ; + curColor = null ; + curNormal = null ; + lbounds.set( 1.0, 1.0, 1.0) ; + ubounds.set(-1.0,-1.0,-1.0) ; + + // Get the descriptors for the compressed data. + bufferDataType = cgr.bufferType ; + dataPresent = cgr.bufferContents ; + if (printInfo) beginPrint() ; + + // Call the superclass decompress() method which calls the output + // methods of this subclass. The results are stored in vlist. + size = cgr.size ; + super.decompress(cgr.offset, size, cgr.compressedGeometry) ; + + if (boundsOnly) { + if (printInfo) endPrint() ; + return null ; + } + + // Convert the output to a GeometryRetained. + GeometryArray ga ; + switch(bufferDataType) { + case TYPE_TRIANGLE: + ga = vlist.toTriangleStripArray() ; + break ; + case TYPE_LINE: + ga = vlist.toLineStripArray() ; + break ; + case TYPE_POINT: + ga = vlist.toPointArray() ; + break ; + default: + throw new IllegalArgumentException + (J3dI18N.getString("GeometryDecompressorRetained0")) ; + } + + // Release the reference to the non-retained data. + ga.retained.setSource(null) ; + + if (printInfo) endPrint() ; + return (GeometryRetained)ga.retained ; + } + + /** + * Get the bounds of the decompressed geometry. + * @param bb BoundingBox to receive bounds + */ + void getBoundingBox(BoundingBox bb) { + bb.setLower(lbounds) ; + bb.setUpper(ubounds) ; + } + + /** + * Initialize the vertex output list based on the vertex format provided + * by the SetState decompression command. + */ + void outputVertexFormat(boolean bundlingNorm, boolean bundlingColor, + boolean doingAlpha) { + + if (boundsOnly) return ; + + if (vlist != null) + throw new IllegalStateException + (J3dI18N.getString("GeometryDecompressorRetained1")) ; + + int vertexFormat = GeometryArray.COORDINATES ; + + if (! positionsOnly) { + if (bundlingNorm) vertexFormat |= GeometryArray.NORMALS ; + if (bundlingColor) vertexFormat |= GeometryArray.COLOR ; + if (doingAlpha) vertexFormat |= GeometryArray.WITH_ALPHA ; + } + + vlist = new GeneralizedVertexList(vertexFormat, FRONTFACE_CCW, + (int)(size/bytesPerVertexFudge)) ; + } + + /** + * Process a decompressed vertex. + */ + void outputVertex(Point3f position, Vector3f normal, + Color4f color, int vertexReplaceCode) { + + if (position.x < lbounds.x) lbounds.x = position.x ; + if (position.y < lbounds.y) lbounds.y = position.y ; + if (position.z < lbounds.z) lbounds.z = position.z ; + + if (position.x > ubounds.x) ubounds.x = position.x ; + if (position.y > ubounds.y) ubounds.y = position.y ; + if (position.z > ubounds.z) ubounds.z = position.z ; + + if (boundsOnly) return ; + if (curColor != null) color = curColor ; + if (curNormal != null) normal = curNormal ; + + vlist.addVertex(position, normal, color, vertexReplaceCode) ; + + if (debug) { + System.err.println("outputVertex: flag " + vertexReplaceCode) ; + System.err.println(" position " + position.toString()) ; + if (normal != null) + System.err.println(" normal " + normal.toString()) ; + if (color != null) + System.err.println(" color " + color.toString()) ; + } + } + + /** + * Any global colors output by the decompressor are stored as per-vertex + * color in the retained data used internally by the renderer. This is + * done for performance and simplicity reasons, at the expense of + * replicating colors. + * + * The next method sets the current color that will be copied to each + * succeeding vertex. The outputColor() method is never called if + * colors are bundled with each vertex in the compressed buffer. + */ + void outputColor(Color4f color) { + if (boundsOnly || positionsOnly) return ; + if (debug) System.err.println("outputColor: " + color.toString()) ; + + if ((vlist.vertexFormat & GeometryArray.COLOR) == 0) { + if (vlist.size() > 0) + throw new IllegalStateException + (J3dI18N.getString("GeometryDecompressorRetained2")) ; + + vlist.setVertexFormat(vlist.vertexFormat | GeometryArray.COLOR) ; + } + + if (curColor == null) curColor = new Color4f() ; + curColor.set(color) ; + } + + /** + * Set the current normal that will be copied to each succeeding vertex + * output by the decompressor. The per-vertex copy is always needed since + * in Java 3D a normal is always associated with a vertex. This is never + * called if normals are bundled with each vertex in the compressed + * buffer. + */ + void outputNormal(Vector3f normal) { + if (boundsOnly || positionsOnly) return ; + if (debug) System.err.println("outputNormal: " + normal.toString()) ; + + if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0) { + if (vlist.size() > 0) + throw new IllegalStateException + (J3dI18N.getString("GeometryDecompressorRetained3")) ; + + vlist.setVertexFormat(vlist.vertexFormat | GeometryArray.NORMALS) ; + } + + if (curNormal == null) curNormal = new Vector3f() ; + curNormal.set(normal) ; + } + + private void beginPrint() { + System.err.println("\nGeometryDecompressorRetained") ; + + switch(bufferDataType) { + case TYPE_TRIANGLE: + System.err.println(" buffer TYPE_TRIANGLE") ; + break ; + case TYPE_LINE: + System.err.println(" buffer TYPE_LINE") ; + break ; + case TYPE_POINT: + System.err.println(" buffer TYPE_POINT") ; + break ; + default: + throw new IllegalArgumentException + (J3dI18N.getString("GeometryDecompressorRetained4")) ; + } + + System.err.print(" buffer data present: coords") ; + + if ((dataPresent & CompressedGeometryHeader.NORMAL_IN_BUFFER) != 0) + System.err.print(" normals") ; + if ((dataPresent & CompressedGeometryHeader.COLOR_IN_BUFFER) != 0) + System.err.print(" colors") ; + if ((dataPresent & CompressedGeometryHeader.ALPHA_IN_BUFFER) != 0) + System.err.print(" alpha") ; + + System.err.println() ; + if (boundsOnly) System.err.println(" computing bounds only") ; + if (positionsOnly) System.err.println(" computing positions only") ; + + startTime = J3dClock.currentTimeMillis() ; + } + + private void endPrint() { + endTime = J3dClock.currentTimeMillis() ; + + if (benchmark || statistics) + printBench() ; + + if (statistics) + printStats() ; + } + + private void printBench() { + float t = (endTime - startTime) / 1000.0f ; + + if (boundsOnly) { + System.err.println(" decompression took " + t + " sec.\n") ; + return ; + } + + System.err.println + (" decompression + strip conversion took " + t + " sec.") ; + + switch(bufferDataType) { + case TYPE_POINT: + System.err.println + (" decompressed " + (vlist.size()) + + " points at " + (vlist.size()/t) + + " points/sec.\n") ; + break ; + case TYPE_LINE: + System.err.println + (" decompressed " + (vlist.vertexCount - vlist.stripCount) + + " lines at " + ((vlist.vertexCount - vlist.stripCount)/t) + + " lines/sec.\n") ; + break ; + case TYPE_TRIANGLE: + System.err.println + (" decompressed " + + (vlist.vertexCount - 2*vlist.stripCount) + + " triangles at " + + ((vlist.vertexCount - 2*vlist.stripCount)/t) + + " triangles/sec.\n") ; + break ; + } + } + + private void printStats() { + System.err.println(" bounding box:\n lower " + lbounds.toString() + + "\n upper " + ubounds.toString()) ; + + if (boundsOnly) return ; + + System.err.print + (" number of vertices in GeometryArray output: " + + vlist.vertexCount + "\n" + + " GeometryArray vertex data present: coords") ; + + if ((vlist.vertexFormat & GeometryArray.NORMALS) != 0) + System.err.print(" normals") ; + + if ((vlist.vertexFormat & GeometryArray.COLOR) != 0) + System.err.print(" colors") ; + + if ((vlist.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + System.err.print(" alpha") ; + + System.err.println("\n number of strips: " + vlist.stripCount) ; + if (vlist.stripCount > 0) + System.err.println + (" vertices/strip: " + + ((float)vlist.vertexCount / (float)vlist.stripCount)) ; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressorShape3D.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressorShape3D.java new file mode 100644 index 0000000..e07cf8e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryDecompressorShape3D.java @@ -0,0 +1,485 @@ +/* + * $RCSfile: GeometryDecompressorShape3D.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import javax.vecmath.* ; +import java.util.* ; + +/** + * This class implements a Shape3D backend for the abstract + * GeometryDecompressor. + */ +class GeometryDecompressorShape3D extends GeometryDecompressor { + private static final boolean debug = false ; + private static final boolean benchmark = false ; + private static final boolean statistics = false ; + private static final boolean printInfo = debug || benchmark || statistics ; + + // Type of connections in the compressed data: + // TYPE_POINT (1), TYPE_LINE (2), or TYPE_TRIANGLE (4). + private int bufferDataType ; + + // Data bundled with each vertex: bitwise combination of + // NORMAL_IN_BUFFER (1), COLOR_IN_BUFFER (2), ALPHA_IN_BUFFER (4). + private int dataPresent ; + + // List for accumulating the output of the decompressor and converting to + // GeometryArray representations. + private GeneralizedVertexList vlist ; + + // Accumulates Shape3D objects constructed from decompressor output. + private ArrayList shapes ; + + // Decompressor output state variables. + private Color4f curColor ; + private Vector3f curNormal ; + + // Variables for gathering statistics. + private int origVertexCount ; + private int stripCount ; + private int vertexCount ; + private int triangleCount ; + private long startTime ; + private long endTime ; + + // Triangle array type to construct. + private int triOutputType ; + + // Types of triangle output available. + private static final int TRI_SET = 0 ; + private static final int TRI_STRIP_SET = 1 ; + private static final int TRI_STRIP_AND_FAN_SET = 2 ; + private static final int TRI_STRIP_AND_TRI_SET = 3 ; + + // Private convenience copies of various constants. + private static final int TYPE_POINT = + CompressedGeometryRetained.TYPE_POINT ; + private static final int TYPE_LINE = + CompressedGeometryRetained.TYPE_LINE ; + private static final int TYPE_TRIANGLE = + CompressedGeometryRetained.TYPE_TRIANGLE ; + private static final int FRONTFACE_CCW = + GeneralizedStripFlags.FRONTFACE_CCW ; + + /** + * Decompress the given compressed geometry. + * @param cgr CompressedGeometryRetained object with compressed geometry + * @return an array of Shape3D with TriangleArray geometry if compressed + * data contains triangles; otherwise, Shape3D array containing PointArray + * or LineStripArray geometry + * @see CompressedGeometry + * @see GeometryDecompressor + */ + Shape3D[] toTriangleArrays(CompressedGeometryRetained cgr) { + return decompress(cgr, TRI_SET) ; + } + + + /** + * Decompress the given compressed geometry. + * @param cgr CompressedGeometryRetained object with compressed geometry + * @return an array of Shape3D with TriangleStripArray geometry if + * compressed data contains triangles; otherwise, Shape3D array containing + * PointArray or LineStripArray geometry + * @see CompressedGeometry + * @see GeometryDecompressor + */ + Shape3D[] toTriangleStripArrays(CompressedGeometryRetained cgr) { + return decompress(cgr, TRI_STRIP_SET) ; + } + + + /** + * Decompress the given compressed geometry. + * @param cgr CompressedGeometryRetained object with compressed geometry + * @return an array of Shape3D with TriangleStripArray and + * TriangleFanArray geometry if compressed data contains triangles; + * otherwise, Shape3D array containing PointArray or LineStripArray + * geometry + * @see CompressedGeometry + * @see GeometryDecompressor + */ + Shape3D[] toStripAndFanArrays(CompressedGeometryRetained cgr) { + return decompress(cgr, TRI_STRIP_AND_FAN_SET) ; + } + + + /** + * Decompress the given compressed geometry. + * @param cgr CompressedGeometryRetained object with compressed geometry + * @return an array of Shape3D with TriangleStripArray and + * TriangleArray geometry if compressed data contains triangles; + * otherwise, Shape3D array containing PointArray or LineStripArray + * geometry + * @see CompressedGeometry + * @see GeometryDecompressor + */ + Shape3D[] toStripAndTriangleArrays(CompressedGeometryRetained cgr) { + return decompress(cgr, TRI_STRIP_AND_TRI_SET) ; + } + + /** + * Decompress the data contained in a CompressedGeometryRetained and + * return an array of Shape3D objects using the specified triangle output + * type. The triangle output type is ignored if the compressed data + * contains points or lines. + */ + private Shape3D[] decompress(CompressedGeometryRetained cgr, + int triOutputType) { + + if (! checkVersion(cgr.majorVersionNumber, cgr.minorVersionNumber)) { + return null ; + } + + vlist = null ; + curColor = null ; + curNormal = null ; + + // Get descriptors for compressed data. + bufferDataType = cgr.bufferType ; + dataPresent = cgr.bufferContents ; + if (printInfo) beginPrint() ; + + // Initialize the decompressor backend. + this.triOutputType = triOutputType ; + shapes = new ArrayList() ; + + // Call the superclass decompress() method which calls the output + // methods of this subclass. The results are stored in vlist. + super.decompress(cgr.offset, cgr.size, cgr.compressedGeometry) ; + + // Convert the decompressor output to Shape3D objects. + addShape3D() ; + if (printInfo) endPrint() ; + + // Return the fixed-length output array. + Shape3D shapeArray[] = new Shape3D[shapes.size()] ; + return (Shape3D[])shapes.toArray(shapeArray) ; + } + + /** + * Initialize the vertex output list based on the vertex format provided + * by the SetState decompression command. + */ + void outputVertexFormat(boolean bundlingNorm, boolean bundlingColor, + boolean doingAlpha) { + + if (vlist != null) + // Construct shapes using the current vertex format. + addShape3D() ; + + int vertexFormat = GeometryArray.COORDINATES ; + + if (bundlingNorm) vertexFormat |= GeometryArray.NORMALS ; + if (bundlingColor) vertexFormat |= GeometryArray.COLOR ; + if (doingAlpha) vertexFormat |= GeometryArray.WITH_ALPHA ; + + vlist = new GeneralizedVertexList(vertexFormat, FRONTFACE_CCW) ; + } + + /** + * Add a new decompressed vertex to the current list. + */ + void outputVertex(Point3f position, Vector3f normal, + Color4f color, int vertexReplaceCode) { + + if (curNormal != null) normal = curNormal ; + vlist.addVertex(position, normal, color, vertexReplaceCode) ; + + if (debug) { + System.err.println(" outputVertex: flag " + vertexReplaceCode) ; + System.err.println(" position " + position.toString()) ; + if (normal != null) + System.err.println(" normal " + normal.toString()) ; + if (color != null) + System.err.println(" color " + color.toString()) ; + } + } + + /** + * Create a Shape3D using the current color for both the ambient and + * diffuse material colors, then start a new vertex list for the new + * color. The outputColor() method is never called if colors are bundled + * with each vertex in the compressed buffer. + */ + void outputColor(Color4f color) { + if (debug) System.err.println(" outputColor: " + color.toString()) ; + + if (vlist.size() > 0) { + // Construct Shape3D using the current color. + addShape3D() ; + + // Start a new vertex list for the new color. + vlist = new GeneralizedVertexList(vlist.vertexFormat, + FRONTFACE_CCW) ; + } + if (curColor == null) curColor = new Color4f() ; + curColor.set(color) ; + } + + /** + * Set the current normal that will be copied to each succeeding vertex + * output by the decompressor. The per-vertex copy is needed since in + * Java 3D a normal is always associated with a vertex. This method is + * never called if normals are bundled with each vertex in the compressed + * buffer. + */ + void outputNormal(Vector3f normal) { + if (debug) System.err.println(" outputNormal: " + normal.toString()) ; + + if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0) { + if (vlist.size() > 0) + // Construct Shape3D using the current vertex format. + addShape3D() ; + + // Start a new vertex list with the new format. + vlist = new GeneralizedVertexList + (vlist.vertexFormat|GeometryArray.NORMALS, FRONTFACE_CCW) ; + } + if (curNormal == null) curNormal = new Vector3f() ; + curNormal.set(normal) ; + } + + /** + * Create a Shape3D object of the desired type from the current vertex + * list. Apply the current color, if non-null, as a Material attribute. + */ + private void addShape3D() { + Material m = new Material() ; + + if (curColor != null) { + if ((vlist.vertexFormat & GeometryArray.WITH_ALPHA) == 0) { + m.setAmbientColor(curColor.x, curColor.y, curColor.z) ; + m.setDiffuseColor(curColor.x, curColor.y, curColor.z) ; + } + else { + m.setAmbientColor(curColor.x, curColor.y, curColor.z) ; + m.setDiffuseColor(curColor.x, curColor.y, curColor.z, + curColor.w) ; + } + } + + if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0) + m.setLightingEnable(false) ; + else + m.setLightingEnable(true) ; + + Appearance a = new Appearance() ; + a.setMaterial(m) ; + + switch(bufferDataType) { + case TYPE_TRIANGLE: + switch(triOutputType) { + case TRI_SET: + TriangleArray ta = vlist.toTriangleArray() ; + if (ta != null) + shapes.add(new Shape3D(ta, a)) ; + break ; + case TRI_STRIP_SET: + TriangleStripArray tsa = vlist.toTriangleStripArray() ; + if (tsa != null) + shapes.add(new Shape3D(tsa, a)) ; + break ; + case TRI_STRIP_AND_FAN_SET: + GeometryStripArray gsa[] = vlist.toStripAndFanArrays() ; + if (gsa[0] != null) + shapes.add(new Shape3D(gsa[0], a)) ; + if (gsa[1] != null) + shapes.add(new Shape3D(gsa[1], a)) ; + break ; + case TRI_STRIP_AND_TRI_SET: + GeometryArray ga[] = vlist.toStripAndTriangleArrays() ; + if (ga[0] != null) + shapes.add(new Shape3D(ga[0], a)) ; + if (ga[1] != null) + shapes.add(new Shape3D(ga[1], a)) ; + break ; + default: + throw new IllegalArgumentException + (J3dI18N.getString("GeometryDecompressorShape3D0")) ; + } + break ; + + case TYPE_LINE: + LineStripArray lsa = vlist.toLineStripArray() ; + if (lsa != null) + shapes.add(new Shape3D(lsa, a)) ; + break ; + + case TYPE_POINT: + PointArray pa = vlist.toPointArray() ; + if (pa != null) + shapes.add(new Shape3D(pa, a)) ; + break ; + + default: + throw new IllegalArgumentException + (J3dI18N.getString("GeometryDecompressorShape3D1")) ; + } + + if (benchmark || statistics) { + origVertexCount += vlist.size() ; + vertexCount += vlist.vertexCount ; + stripCount += vlist.stripCount ; + triangleCount += vlist.triangleCount ; + } + } + + private void beginPrint() { + System.err.println("\nGeometryDecompressorShape3D") ; + + switch(bufferDataType) { + case TYPE_TRIANGLE: + System.err.println(" buffer TYPE_TRIANGLE") ; + break ; + case TYPE_LINE: + System.err.println(" buffer TYPE_LINE") ; + break ; + case TYPE_POINT: + System.err.println(" buffer TYPE_POINT") ; + break ; + default: + throw new IllegalArgumentException + (J3dI18N.getString("GeometryDecompressorShape3D1")) ; + } + + System.err.print(" buffer data present: coords") ; + + if ((dataPresent & CompressedGeometryHeader.NORMAL_IN_BUFFER) != 0) + System.err.print(" normals") ; + if ((dataPresent & CompressedGeometryHeader.COLOR_IN_BUFFER) != 0) + System.err.print(" colors") ; + if ((dataPresent & CompressedGeometryHeader.ALPHA_IN_BUFFER) != 0) + System.err.print(" alpha") ; + + System.err.println() ; + + stripCount = 0 ; + vertexCount = 0 ; + triangleCount = 0 ; + origVertexCount = 0 ; + + startTime = J3dClock.currentTimeMillis() ; + } + + private void endPrint() { + endTime = J3dClock.currentTimeMillis() ; + + if (benchmark || statistics) + printBench() ; + + if (statistics) + printStats() ; + } + + private void printBench() { + float t = (endTime - startTime) / 1000.0f ; + System.err.println + (" decompression + strip conversion took " + t + " sec.") ; + + switch(bufferDataType) { + case TYPE_POINT: + System.err.println + (" points decompressed: " + vertexCount + "\n" + + " net decompression rate: " + (vertexCount/t) + + " points/sec.\n") ; + break ; + case TYPE_LINE: + System.err.println + (" lines decompressed: " + (vertexCount - stripCount) + "\n" + + " net decompression rate: " + ((vertexCount - stripCount)/t) + + " lines/sec.\n") ; + break ; + case TYPE_TRIANGLE: + System.err.println + (" triangles decompressed: " + + (vertexCount - 2*stripCount) + "\n" + + " net decompression rate: " + + ((vertexCount - 2*stripCount)/t) + " triangles/sec.\n") ; + break ; + } + } + + private void printStats() { + switch(triOutputType) { + case TRI_SET: + System.err.println(" using individual triangle output") ; + break ; + case TRI_STRIP_SET: + System.err.println(" using strip output") ; + break ; + case TRI_STRIP_AND_FAN_SET: + System.err.println(" using strips and fans for output") ; + break ; + case TRI_STRIP_AND_TRI_SET: + System.err.println(" using strips and triangles for output") ; + break ; + } + + System.err.print + (" number of Shape3D objects: " + shapes.size() + + "\n number of Shape3D decompressed vertices: ") ; + + if (triOutputType == TRI_SET || bufferDataType == TYPE_POINT) { + System.err.println(vertexCount) ; + } + else if (triOutputType == TRI_STRIP_AND_TRI_SET) { + System.err.println((vertexCount + triangleCount*3) + + "\n number of strips: " + stripCount + + "\n number of individual triangles: " + + triangleCount) ; + if (stripCount > 0) + System.err.println + (" vertices/strip: " + (float)vertexCount/stripCount + + "\n triangles represented in strips: " + + (vertexCount - 2*stripCount)) ; + } + else { + System.err.println(vertexCount + + "\n number of strips: " + stripCount) ; + if (stripCount > 0) + System.err.println + (" vertices/strip: " + (float)vertexCount/stripCount) ; + } + + System.err.print(" vertex data present in last Shape3D: coords") ; + if ((vlist.vertexFormat & GeometryArray.NORMALS) != 0) + System.err.print(" normals") ; + + if ((vlist.vertexFormat & GeometryArray.COLOR) != 0) { + System.err.print(" colors") ; + if ((vlist.vertexFormat & GeometryArray.WITH_ALPHA) != 0) + System.err.print(" alpha") ; + } + System.err.println() ; + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryLock.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryLock.java new file mode 100644 index 0000000..c091dcf --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryLock.java @@ -0,0 +1,91 @@ +/* + * $RCSfile: GeometryLock.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; + +class GeometryLock { + + // Current thread holding the lock + Thread threadId = null; + + // Whether the lock is currently owned + boolean lockOwned = false; + + // Count > 1 , if there is nested lock by the same thread + int count = 0; + + // Number of outstanding threads waiting for the lock + int waiting = 0; + + + synchronized void getLock() { + Thread curThread = Thread.currentThread(); + // If the thread already has the lock, incr + // a count and return + if (threadId == curThread) { + count++; + return; + } + // Otherwise, wait until the lock is released + while (lockOwned) { + try { + waiting++; + wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + waiting--; + } + count++; + // Acquire the lock + lockOwned = true; + threadId = curThread; + } + + synchronized void unLock() { + Thread curThread = Thread.currentThread(); + if (threadId == curThread) { + // If the lock count > 0, then return + if (--count > 0) { + return; + } + lockOwned = false; + threadId = null; + if (waiting > 0) { + notify(); + } + } + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryRetained.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryRetained.java new file mode 100644 index 0000000..1852091 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryRetained.java @@ -0,0 +1,396 @@ +/* + * $RCSfile: GeometryRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; + +abstract class GeometryRetained extends NodeComponentRetained { + + static final int GEO_TYPE_NONE = -1; + + static final int GEO_TYPE_QUAD_SET = 1; + static final int GEO_TYPE_TRI_SET = 2; + static final int GEO_TYPE_POINT_SET = 3; + static final int GEO_TYPE_LINE_SET = 4; + static final int GEO_TYPE_TRI_STRIP_SET = 5; + static final int GEO_TYPE_TRI_FAN_SET = 6; + static final int GEO_TYPE_LINE_STRIP_SET = 7; + + static final int GEO_TYPE_INDEXED_QUAD_SET = 8; + static final int GEO_TYPE_INDEXED_TRI_SET = 9; + static final int GEO_TYPE_INDEXED_POINT_SET = 10; + static final int GEO_TYPE_INDEXED_LINE_SET = 11; + static final int GEO_TYPE_INDEXED_TRI_STRIP_SET = 12; + static final int GEO_TYPE_INDEXED_TRI_FAN_SET = 13; + static final int GEO_TYPE_INDEXED_LINE_STRIP_SET = 14; + + static final int GEO_TYPE_RASTER = 15; + static final int GEO_TYPE_TEXT3D = 16; + static final int GEO_TYPE_COMPRESSED = 17; + + static final int GEO_TYPE_TOTAL = 17; + static final int GEO_TYPE_GEOMETRYARRAY = 14; + + BoundingBox geoBounds = new BoundingBox(); + + // Indicates whether bounds need to be computed. + // Checked when a user does addUser/removeUser and count goes from 0 to one + // but geometry has not changed and there is no need to recompute + boolean boundsDirty = true; // Changed while holding the geoBounds lock + + int computeGeoBounds = 0; // Changed while holding the geoBounds lock + + // The "type" of this object + int geoType = GEO_TYPE_NONE; + + // The id used by the native code when building this object + int nativeId = -1; + + // A mask that indicates that something has changed in this object + int isDirty = 0xffff; + + + // Geometry Lock (used only by GeometryArrayRetained and RasterRetained) + GeometryLock geomLock = new GeometryLock(); + + // Lock used for synchronization of live state + Object liveStateLock = new Object(); + + abstract void update(); + + // A reference to the mirror copy of the geometry + GeometryRetained mirrorGeometry = null; + + // indicates whether the geometry in editable + boolean isEditable = true; + + // A list of Universes that this Geometry is referenced from + ArrayList universeList = new ArrayList(); + + // A list of ArrayLists which contain all the Shape3DRetained objects + // refering to this geometry. Each list corresponds to the universe + // above. + ArrayList> userLists = new ArrayList(); + + // true if color not specified with alpha channel + boolean noAlpha = false; + static final double EPSILON = 1.0e-6; + + Point3d centroid = new Point3d(); + boolean recompCentroid = true; + // The cached value is evaluated by renderBin and used in determining + // whether to put it in display list or not + int cachedChangedFrequent = 0; + + static final int POINT_TYPE = 1; + static final int LINE_TYPE = 2; + static final int TRIANGLE_TYPE = 3; + static final int QUAD_TYPE = 4; + static final int RASTER_TYPE = 5; + static final int TEXT3D_TYPE = 6; + static final int COMPRESS_TYPE = 7; + + + boolean isEquivalenceClass( GeometryRetained geometry ) { + int t1 = getClassType(); + int t2 = geometry.getClassType(); + + if (t1 == QUAD_TYPE) { + t1 = TRIANGLE_TYPE; + } + if (t2 == QUAD_TYPE) { + t2 = TRIANGLE_TYPE; + } + return (t1 == t2); + } + + void incrComputeGeoBounds() { + synchronized(geoBounds) { + computeGeoBounds++; + // When it goes from zero to one, compute it .. + if (computeGeoBounds == 1 && source.isLive()) { + computeBoundingBox(); + } + } + } + + void decrComputeGeoBounds() { + synchronized(geoBounds) { + computeGeoBounds--; + } + } + + + // This adds a Shape3DRetained to the list of users of this geometry + void addUser(Shape3DRetained s) { + int index; + ArrayList shapeList; + + if (s.sourceNode.boundsAutoCompute) { + incrComputeGeoBounds(); + } + + // If static, no need to maintain a userlist + if (this instanceof GeometryArrayRetained) { + if (((GeometryArrayRetained)this).isWriteStatic()) { + return; + } + } + synchronized (universeList) { + if (universeList.contains(s.universe)) { + index = universeList.indexOf(s.universe); + shapeList = (ArrayList)userLists.get(index); + shapeList.add(s); + } else { + universeList.add(s.universe); + shapeList = new ArrayList(); + shapeList.add(s); + userLists.add(shapeList); + } + } + + } + + // This adds a Shape3DRetained to the list of users of this geometry + void removeUser(Shape3DRetained s) { + int index; + ArrayList shapeList; + + if (s.sourceNode.boundsAutoCompute) { + decrComputeGeoBounds(); + } + + if (this instanceof GeometryArrayRetained) { + if (((GeometryArrayRetained)this).isWriteStatic()) { + return; + } + } + + synchronized (universeList) { + index = universeList.indexOf(s.universe); + shapeList = (ArrayList)userLists.get(index); + shapeList.remove(shapeList.indexOf(s)); + if (shapeList.size() == 0) { + userLists.remove(index); + universeList.remove(index); + } + } + + } + + public void updateObject() { + this.update(); + } + + + abstract void computeBoundingBox(); + + void setLive(boolean inBackgroundGroup, int refCount) { + doSetLive(inBackgroundGroup,refCount); + super.markAsLive(); + } + + /** + * This setLive routine calls the superclass's method when reference + * count is 1 + */ + void doSetLive(boolean inBackgroundGroup, int refCount) { + super.doSetLive(inBackgroundGroup, refCount); + this.update(); + this.computeBoundingBox(); + } + + abstract void execute(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale, + boolean updateAlpha, float alpha, + int screen, boolean ignoreVertexColors); + + /** + * This method should return an int indicating the format of the vertices, + * if any, stored in the geometry. Instances that can return a valid value + * should override this method, otherwise it will be assumed that no + * valid vertex components exist. + * @return format of vertices in the GeometryRetained as specified by + * GeometryArray, if appropriate to this instance. + */ + int getVertexFormat() { + return 0 ; + } + + // Issue 199 -- Chien + abstract boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex); + + // Old stuff -- Chien + //abstract boolean intersect(PickShape pickShape, PickInfo.IntersectionInfo iInfo, int flags, Point3d iPnt); + + abstract boolean intersect(Bounds targetBound); + abstract boolean intersect(Point3d[] pnts); + abstract boolean intersect(Transform3D thisToOtherVworld, GeometryRetained geom); + + void storeInterestData(PickInfo pickInfo, int flags, GeometryRetained geom, int geomIndex, + int[] vtxIndexArr, Point3d iPnt, double dist) { + + PickInfo.IntersectionInfo iInfo = null; + + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + PickInfo.IntersectionInfo iInfoArr[] = pickInfo.getIntersectionInfos(); + if((iInfoArr == null) || (iInfoArr.length == 0)) { + iInfo = pickInfo.createIntersectionInfo(); + pickInfo.insertIntersectionInfo(iInfo); + } + else { + assert(iInfoArr.length == 1); + iInfo = iInfoArr[0]; + } + } + else if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + iInfo = pickInfo.createIntersectionInfo(); + pickInfo.insertIntersectionInfo(iInfo); + } + else { + assert(false); + } + // This only set the reference to geometry.source. + iInfo.setGeometry((Geometry) geom.source); + // The rest are by copy. + iInfo.setGeometryIndex(geomIndex); + iInfo.setDistance(dist); + iInfo.setIntersectionPoint(iPnt); + iInfo.setVertexIndices(vtxIndexArr); + } + + boolean intersect(Transform3D thisLocalToVworld, + Transform3D otherLocalToVworld, GeometryRetained geom) { + Transform3D t3d = new Transform3D(); + t3d.invert(otherLocalToVworld); + t3d.mul(thisLocalToVworld); + return intersect(t3d, geom); + } + + + boolean intersect(Transform3D thisLocalToVworld, Bounds targetBound) { + Bounds transBound = (Bounds) targetBound.clone(); + + Transform3D t3d = new Transform3D(); + t3d.invert(thisLocalToVworld); + transBound.transform(t3d); + return intersect(transBound); + } + + + // Return a flag indicating whether or not this Geometry object can be in + // a display list. + // + // XXXX: Note that for IndexedGeometryArray objects, the original + // vertex format is used in making this determination, even when it has + // been unindexified. This should be fixed by using the vertex format of + // the mirror geometry if there is one. + boolean canBeInDisplayList(boolean alphaEditable) { + // Check global flag to see whether we can build display lists + if (!VirtualUniverse.mc.isDisplayList) { + return false; + } + + // Can't build display lists if geometry is frequently writable + // + // Issue 181 : to fix performance regression from 1.3.2, we will allow + // editable geometry if the optimizeForSpace property is set false and + // the cachedChangedFrequent flag is set; note this will basically + // restore the 1.3.2 behavior, which isn't completely correct. + // Eventually, we should fix the bug that is causing the + // cachedChangedFrequent bit to be wrong; we can then remove the + // erroneous dependency on optimizeForSpace. + if (this.isEditable) { + if (cachedChangedFrequent != 0) { + return false; + } + + // TODO: remove the following when cachedChangedFrequent is fixed + // to correctly reflect the state + if (!VirtualUniverse.mc.buildDisplayListIfPossible) { + return false; + } + } + + if (this instanceof GeometryArrayRetained) { + int vFormat = ((GeometryArrayRetained)this).vertexFormat; + + // If geometry has vertex attributes, check whether + // vertex attributes are allowed in display lists + if (((vFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) && + !VirtualUniverse.mc.vertexAttrsInDisplayList) { + return false; + } + + // Can't build display lists if alpha is editable and + // geometry array has colors + if (alphaEditable && ((vFormat & GeometryArray.COLOR) != 0)) { + return false; + } + + // Only build DL for by-ref geometry when system property is set. + // Exclude NIO buffers and use-coord-index-only + if ((vFormat & GeometryArray.BY_REFERENCE) != 0) { + if (!VirtualUniverse.mc.buildDisplayListIfPossible) { + return false; + } + + // XXXX: we could change this to allow display lists for + // non-interleaved NIO buffers, but we would first need to + // update the now-obsolete buildGAForBuffer method to handle + // vertex attrs + if ((vFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + return false; + } + + if ((vFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + return false; + } + } + + return true; + } else { + // Can't build display lists for other kind of geometry + // NOTE: This method is not called for any type of Geometry + // other than GeometryArray, so we shouldn't even get here. + return false; + } + } + + void computeCentroid() { + this.centroid.set(geoBounds.getCenter()); + } + + abstract int getClassType(); + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryStripArray.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryStripArray.java new file mode 100644 index 0000000..68c65e1 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryStripArray.java @@ -0,0 +1,272 @@ +/* + * $RCSfile: GeometryStripArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The GeometryStripArray object is an abstract class that is extended for + * a set of GeometryArray strip primitives. These include LINE_STRIP, + * TRIANGLE_STRIP, and TRIANGLE_FAN. In addition to specifying the array + * of vertex elements, which is inherited from GeometryArray, the + * GeometryStripArray class specifies the number of strips and an + * array of per-strip vertex counts that specify where the separate strips + * appear in the vertex array. + */ + +public abstract class GeometryStripArray extends GeometryArray { + + // non-public, no parameter constructor + GeometryStripArray() {} + + /** + * Constructs an empty GeometryStripArray object with the specified + * number of vertices, vertex format, and + * array of per-strip vertex counts. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param stripVertexCounts array that specifies + * the count of the number of vertices for each separate strip. + * The length of this array is the number of separate strips. + * The sum of the elements in this array defines the total number + * of valid vertices that are rendered (validVertexCount). + * + * @exception IllegalArgumentException if + * validVertexCount > vertexCount + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public GeometryStripArray(int vertexCount, + int vertexFormat, + int[] stripVertexCounts) { + + super(vertexCount, vertexFormat); + ((GeometryStripArrayRetained)this.retained).setStripVertexCounts(stripVertexCounts); + } + + /** + * Constructs an empty GeometryStripArray object with the specified + * number of vertices, vertex format, number of texture coordinate + * sets, texture coordinate mapping array, and + * array of per-strip vertex counts. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param stripVertexCounts array that specifies + * the count of the number of vertices for each separate strip. + * The length of this array is the number of separate strips. + * The sum of the elements in this array defines the total number + * of valid vertices that are rendered (validVertexCount). + * + * @exception IllegalArgumentException if + * validVertexCount > vertexCount + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public GeometryStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int[] stripVertexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap); + ((GeometryStripArrayRetained)this.retained).setStripVertexCounts(stripVertexCounts); + } + + /** + * Constructs an empty GeometryStripArray object with the + * specified number of vertices, vertex format, number of texture + * coordinate sets, texture coordinate mapping array, vertex + * attribute count, vertex attribute sizes array, and array of + * per-strip vertex counts. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param stripVertexCounts array that specifies + * the count of the number of vertices for each separate strip. + * The length of this array is the number of separate strips. + * The sum of the elements in this array defines the total number + * of valid vertices that are rendered (validVertexCount). + * + * @exception IllegalArgumentException if + * validVertexCount > vertexCount + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public GeometryStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int[] stripVertexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + + ((GeometryStripArrayRetained)this.retained).setStripVertexCounts(stripVertexCounts); + } + + /** + * Get number of strips in the GeometryStripArray. + * @return numStrips number of strips + */ + public int getNumStrips() { + if (isLiveOrCompiled()) + if(!this.getCapability(GeometryArray.ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryStripArray0")); + + return ((GeometryStripArrayRetained)this.retained).getNumStrips(); + } + + /** + * Sets the array of strip vertex counts. The length of this + * array is the number of separate strips. The elements in this + * array specify the number of vertices for each separate strip. + * The sum of the elements in this array defines the total number + * of valid vertices that are rendered (validVertexCount). + * + * @param stripVertexCounts array that specifies + * the count of the number of vertices for each separate strip. + * + * @exception IllegalArgumentException if any of the following are + * true: + *

    + * initialVertexIndex + validVertexCount > vertexCount,
    + * initialCoordIndex + validVertexCount > vertexCount,
    + * initialColorIndex + validVertexCount > vertexCount,
    + * initialNormalIndex + validVertexCount > vertexCount,
    + * initialTexCoordIndex + validVertexCount > vertexCount + *
+ *

+ * + * @exception ArrayIndexOutOfBoundsException if the geometry data format + * is BY_REFERENCE and any the following + * are true for non-null array references: + *

    + * CoordRef.length < num_words * + * (initialCoordIndex + validVertexCount)
    + * ColorRef.length < num_words * + * (initialColorIndex + validVertexCount)
    + * NormalRef.length < num_words * + * (initialNormalIndex + validVertexCount)
    + * TexCoordRef.length < num_words * + * (initialTexCoordIndex + validVertexCount)
    + *
+ * where num_words depends on which variant of + * setArrayRef is used. + * + * @since Java 3D 1.3 + */ + public void setStripVertexCounts(int[] stripVertexCounts) { + if (isLiveOrCompiled()) + if(!this.getCapability(GeometryArray.ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryStripArray2")); + + ((GeometryStripArrayRetained)this.retained).setStripVertexCounts(stripVertexCounts); + + } + + /** + * Get a list of vertexCounts for each strip. The list is copied + * into the specified array. The array must be large enough to hold + * all of the ints. + * @param stripVertexCounts an array that will receive vertexCounts + */ + public void getStripVertexCounts(int[] stripVertexCounts) { + if (isLiveOrCompiled()) + if(!this.getCapability(GeometryArray.ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryStripArray1")); + + ((GeometryStripArrayRetained)this.retained).getStripVertexCounts(stripVertexCounts); + } + + /** + * This method is not supported for geometry strip arrays. + * The sum of the elements in the strip vertex counts array + * defines the valid vertex count. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setValidVertexCount(int validVertexCount) { + throw new UnsupportedOperationException(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GeometryStripArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/GeometryStripArrayRetained.java new file mode 100644 index 0000000..d16ade6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GeometryStripArrayRetained.java @@ -0,0 +1,835 @@ +/* + * $RCSfile: GeometryStripArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; +import java.util.Vector; +import com.sun.j3d.internal.ByteBufferWrapper; +import com.sun.j3d.internal.BufferWrapper; +import com.sun.j3d.internal.FloatBufferWrapper; +import com.sun.j3d.internal.DoubleBufferWrapper; + + +/** + * The GeometryStripArray object is an abstract class that is extended for + * a set of GeometryArray strip primitives. These include LINE_STRIP, + * TRIANGLE_STRIP, and TRIANGLE_FAN. + */ + +abstract class GeometryStripArrayRetained extends GeometryArrayRetained { + + // Array of per-strip vertex counts + int stripVertexCounts[]; + + // Array of per-strip starting index + int stripStartVertexIndices[]; // start of vertices for both by-copy + // and by-ref + int stripStartOffsetIndices[]; // Used in byRef non_interleaved + + // Following variables are only used in the compile mode + // isCompiled = true + int[] compileNumStrips; + int[] compileStripCountOffset; + + + /** + * Set stripVertexCount data into local array + */ + void setStripVertexCounts(int stripVertexCounts[]) { + boolean nullGeo = false; + + int i, num = stripVertexCounts.length, total = 0; + for (i=0; i < num; i++) { + total += stripVertexCounts[i]; + if (this instanceof LineStripArrayRetained) { + if (stripVertexCounts[i] < 2) { + throw new IllegalArgumentException(J3dI18N.getString("LineStripArrayRetained1")); + } + } + else if (this instanceof TriangleStripArrayRetained) { + if (stripVertexCounts[i] < 3) { + throw new IllegalArgumentException(J3dI18N.getString("TriangleStripArrayRetained1")); + } + } + else if (this instanceof TriangleFanArrayRetained) { + if (stripVertexCounts[i] < 3) { + throw new IllegalArgumentException(J3dI18N.getString("TriangleFanArrayRetained1")); + } + } + } + + if ((initialVertexIndex + total) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryStripArray3")); + } + if ((initialCoordIndex + total) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryStripArray7")); + } + if ((initialColorIndex + total) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryStripArray4")); + } + if ((initialNormalIndex + total) > vertexCount) { + throw new IllegalArgumentException(J3dI18N.getString("GeometryStripArray5")); + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if ((vertexFormat & (GeometryArray.BY_REFERENCE|vertexFormat &GeometryArray.INTERLEAVED)) == GeometryArray.BY_REFERENCE) { + for (i = 0; i < texCoordSetCount; i++) { + if ((initialTexCoordIndex[i] + total) > vertexCount) { + throw new IllegalArgumentException( + J3dI18N.getString("GeometryStripArray6")); + } + } + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + if ((vertexFormat & (GeometryArray.BY_REFERENCE|vertexFormat &GeometryArray.INTERLEAVED)) == GeometryArray.BY_REFERENCE) { + for (i = 0; i < vertexAttrCount; i++) { + if ((initialVertexAttrIndex[i] + total) > vertexCount) { + throw new IllegalArgumentException( + J3dI18N.getString("GeometryStripArray8")); + } + } + } + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= STRIPCOUNT_CHANGED; + validVertexCount = total; + this.stripVertexCounts = new int[num]; + stripStartVertexIndices = new int[num]; + stripStartOffsetIndices = new int[num]; + stripStartOffsetIndices[0] = 0; + if ((vertexFormat & (GeometryArray.BY_REFERENCE|vertexFormat &GeometryArray.INTERLEAVED)) == GeometryArray.BY_REFERENCE) { + stripStartVertexIndices[0] = initialCoordIndex; + nullGeo = ((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0); + } + else { + stripStartVertexIndices[0] = initialVertexIndex; + if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + if (( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + nullGeo = (interLeavedVertexData == null); + } + else { + nullGeo = (interleavedFloatBufferImpl == null); + } + } + } + + for (i=0; i 0) { + reEvaluateWakeupCollisionGAs = false; + for (int i=0; i < nMsg; i++) { + lock.writeLock(); + m = messages[i]; + switch (m.type) { + case J3dMessage.TRANSFORM_CHANGED: + transformMsg = true; + break; + case J3dMessage.SWITCH_CHANGED: + processSwitchChanged(m); + // may need to process dirty switched-on transform + if (universe.transformStructure.getLazyUpdate()) { + transformMsg = true; + } + break; + case J3dMessage.INSERT_NODES: + insertNodes((Object[])m.args[0]); + reEvaluateWakeupCollisionGAs = true; + break; + case J3dMessage.REMOVE_NODES: + removeNodes(m); + reEvaluateWakeupCollisionGAs = true; + break; + case J3dMessage.SHAPE3D_CHANGED: { + int comp = ((Integer)m.args[1]).intValue(); + if (comp == Shape3DRetained.GEOMETRY_CHANGED) { + m.args[0] = m.args[2]; + removeNodes(m); + insertNodes((Object[])m.args[3]); + reEvaluateWakeupCollisionGAs = true; + } + else if (comp == Shape3DRetained.APPEARANCE_CHANGED) { + processVisibleChanged(m.args[2], + ((GeometryAtom[]) m.args[3])); + } + break; + } + case J3dMessage.TEXT3D_DATA_CHANGED: + removeNodes(m); + insertNodes((Object[])m.args[1]); + break; + case J3dMessage.TEXT3D_TRANSFORM_CHANGED: + processBoundsChanged((Object []) m.args[0], false); + break; + case J3dMessage.MORPH_CHANGED: { + int comp = ((Integer)m.args[1]).intValue(); + if (comp == MorphRetained.GEOMETRY_CHANGED) { + processBoundsChanged((Object []) m.args[3], false); + } + else if (comp == MorphRetained.APPEARANCE_CHANGED) { + processVisibleChanged(m.args[2], + ((GeometryAtom[]) m.args[3])); + } + break; + } + case J3dMessage.REGION_BOUND_CHANGED: + case J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED: + // Only set this flag, when bounds might be empty. + processBoundsChanged((Object [])m.args[0], false); + break; + case J3dMessage.GEOMETRY_CHANGED: + // System.err.println("J3dMessage.GEOMETRY_CHANGED"); + processBoundsChanged((Object []) m.args[0], false); + break; + case J3dMessage.RENDERINGATTRIBUTES_CHANGED: + processVisibleChanged(m.args[2], + ((GeometryAtom[]) m.args[3])); + break; + } + + lock.writeUnlock(); + m.decRefcount(); + } + + if (transformMsg) { + targets = universe.transformStructure.getTargetList(); + lock.writeLock(); + + processTransformChanged(targets); + + lock.writeUnlock(); + + transformMsg = false; + targets = null; + } + + Arrays.fill(messages, 0, nMsg, null); + } + + processCollisionDetection(); + } + + + private int getBHTreeIndex(Locale locale) { + int i; + + for (i=0; i< bhTreeCount; i++) { + if (bhTreeArr[i].locale == locale) + return i; + } + // Can't find will return -1 so that other + // program know this + return -1; + } + + private int getOrAddBHTreeIndex(Locale locale) { + int i; + + for (i=0; i< bhTreeCount; i++) { + if (bhTreeArr[i].locale == locale) + return i; + } + + if (bhTreeCount >= bhTreeMax) { + // allocate a bigger array here.... + if (J3dDebug.devPhase) + J3dDebug.doDebug(J3dDebug.geometryStructure, J3dDebug.LEVEL_2, + "Expanding bhTreeArr array ...\n"); + bhTreeMax += bhTreeBlockSize; + BHTree[] oldBhTreeArr = bhTreeArr; + + bhTreeArr = new BHTree[bhTreeMax]; + System.arraycopy(oldBhTreeArr, 0, bhTreeArr, 0, oldBhTreeArr.length); + } + + bhTreeArr[bhTreeCount] = new BHTree(locale); + bhTreeCount++; + return i; + } + + private void clearBhNodeArr() { + // Issue 353: set all elements to null so we don't leak + // NOTE: we really should change this to be an ArrayList, but that + // would be a less localized change. Consider for 1.6.0. + for (int i = 0; i < bhNodeCount; i++) { + bhNodeArr[i] = null; + } + + bhNodeCount = 0; + } + + private void addToBhNodeArr(BHNode bhNode) { + + // Add to bhNodeArr. + if (bhNodeCount >= bhNodeMax) { + bhNodeMax += bhNodeBlockSize; + BHNode[] oldbhNodeArr = bhNodeArr; + + bhNodeArr = new BHNode[bhNodeMax]; + System.arraycopy(oldbhNodeArr, 0, bhNodeArr, 0, oldbhNodeArr.length); + } + + bhNodeArr[bhNodeCount] = bhNode; + bhNodeCount++; + } + + private void processVisibleChanged(Object valueObj, GeometryAtom[] gaArr) { + boolean visible = true; // Default is true. + int i, treeIndex; + + if ((gaArr == null) || (gaArr.length < 1)) + return; + + treeIndex = getBHTreeIndex(gaArr[0].locale); + + visible = ((Boolean)valueObj).booleanValue(); + + for ( i=gaArr.length-1; i>=0; i--) { + gaArr[i].visible = visible; + } + + } + + private void insertNodes(Object[] nodes) { + Object node; + GeometryAtom geomAtom; + BHTree currTree = null; + + clearBhNodeArr(); + + // System.err.println("GS : nodes.length is " + nodes.length); + + for (int i=0; i=0; j--) { + wentry = wentryArr[j]; + if (wentry.behav == behav) { + collideEntryList.remove(wentry); + } + } + WakeupOnCollisionExit wexit; + WakeupOnCollisionExit wexitArr[] = + (WakeupOnCollisionExit []) collideExitList.toArray(); + for (int j=collideExitList.arraySize()-1; j>=0; j--) { + wexit = wexitArr[j]; + if (wexit.behav == behav) { + collideExitList.remove(wexit); + } + } + } + } + } + + if (bhNodeCount < 1) { + return; + } + + if (currTree == null) { + index = getBHTreeIndex(((BHLeafNode)bhNodeArr[0]).getLocale()); + if (index<0) { + // Issue 353: must clear array after we are done with it + clearBhNodeArr(); + + return; + } + currTree = bhTreeArr[index]; + } + currTree.delete(bhNodeArr, bhNodeCount); + + // Issue 353: must clear array after we are done with it + clearBhNodeArr(); + + // It is safe to do it here since only GeometryStructure + // thread invoke wakeupOnCollisionEntry/Exit .toArray() + + wakeupOnCollisionEntry.clearMirror(); + wakeupOnCollisionMovement.clearMirror(); + wakeupOnCollisionExit.clearMirror(); + + synchronized (collideListLock) { + collideEntryList.clearMirror(); + collideExitList.clearMirror(); + } + } + + + private void processBoundsChanged(Object[] nodes, boolean transformChanged) { + + int index; + Object node; + + clearBhNodeArr(); + + for (int i = 0; i < nodes.length; i++) { + node = nodes[i]; + if (node instanceof GeometryAtom) { + synchronized (node) { + + GeometryAtom geomAtom = (GeometryAtom) node; + if (geomAtom.bhLeafNode != null) { + addToBhNodeArr(geomAtom.bhLeafNode); + } + } + } else if (node instanceof GroupRetained) { + + GroupRetained group = (GroupRetained) node; + if (group.nodeType != NodeRetained.SWITCH) { + synchronized (node) { + if (group.bhLeafNode != null) { + addToBhNodeArr(group.bhLeafNode); + } + } + } + } + } + + if (bhNodeCount < 1) { + return; + } + + index = getBHTreeIndex(((BHLeafNode)bhNodeArr[0]).getLocale()); + + if (index >= 0) { + bhTreeArr[index].boundsChanged(bhNodeArr, bhNodeCount); + } + + // Issue 353: must clear array after we are done with it + clearBhNodeArr(); + + } + + private void processTransformChanged(UpdateTargets targets) { + + int i, j, index; + Object[] nodes, nodesArr; + UnorderList arrList; + int size; + + clearBhNodeArr(); + + arrList = targets.targetList[Targets.GEO_TARGETS]; + + if (arrList != null) { + size = arrList.size(); + nodesArr = arrList.toArray(false); + + for (j = 0; j < size; j++) { + nodes = (Object[])nodesArr[j]; + for (i = 0; i < nodes.length; i++) { + GeometryAtom geomAtom = (GeometryAtom) nodes[i]; + synchronized (geomAtom) { + if (geomAtom.bhLeafNode != null) { + addToBhNodeArr(geomAtom.bhLeafNode); + } + } + } + } + } + + + arrList = targets.targetList[Targets.GRP_TARGETS]; + if (arrList != null) { + size = arrList.size(); + nodesArr = arrList.toArray(false); + for ( j = 0; j < size; j++) { + nodes = (Object[])nodesArr[j]; + for ( i = 0; i < nodes.length; i++) { + GroupRetained group = (GroupRetained) nodes[i]; + if (group.nodeType != NodeRetained.SWITCH) { + synchronized (group) { + if (group.bhLeafNode != null) { + addToBhNodeArr(group.bhLeafNode); + } + } + } + } + } + } + + if (bhNodeCount < 1) { + return; + } + + index = getBHTreeIndex(((BHLeafNode)bhNodeArr[0]).getLocale()); + + if (index >= 0) { + bhTreeArr[index].boundsChanged(bhNodeArr, bhNodeCount); + + } + + // Issue 353: must clear array after we are done with it + clearBhNodeArr(); + + } + + // This method is called by RenderBin to get a array of possibly visible + // sub-trees. + // bhTrees mustn't be null. + // Return true if bhTree's root in encompass by frustumBBox. + + boolean getVisibleBHTrees(RenderBin rBin, + BoundingBox frustumBBox, + Locale locale, long referenceTime, + boolean stateChanged, + int visibilityPolicy) { + + int i, j; + boolean unviInFB = true; + + // System.err.println("GeometryStructure : view's locale is " + locale); + lock.readLock(); + + // Issue 353: create a new array list each time rather than passing it + // in. This will not generate too much garbage, since we only call + // this once per frame and it is very short-lived. + ArrayList bhTrees = new ArrayList(); + if (bhTreeCount == 1) { + // For debugging only. + if (J3dDebug.devPhase) { + if (J3dDebug.doDebug(J3dDebug.geometryStructure, J3dDebug.LEVEL_2)) { + System.err.println("GeometryStructure : In simple case"); + System.err.println("GeometryStructure : view's locale is " + + locale); + System.err.println("GeometryStructure : bhTreeArr[0].locale is " + + bhTreeArr[0].locale); + } + } + // One locale case - Lets make the simple case fast. + synchronized(visLock) { + unviInFB = bhTreeArr[0].getVisibleBHTrees(rBin, bhTrees, frustumBBox, + referenceTime, + stateChanged, + visibilityPolicy, true); + } + } + else { + // Multiple locale case. + + // For debugging only. + if (J3dDebug.devPhase) + J3dDebug.doDebug(J3dDebug.geometryStructure, J3dDebug.LEVEL_2, + "GeometryStructure : bhTreeCount is " + + universe.geometryStructure.bhTreeCount + + " view's locale is " + locale + "\n"); + + BoundingBox localeFrustumBBox = new BoundingBox(); + + synchronized(visLock) { + + for (j=0; j=0; i--) { + wentry = collideEntryArr[i]; + if ((wentry.behav == w.behav) && + (wentry.geometryAtoms == w.geometryAtoms)) { + collideEntryList.remove(i); + needTrigger = false; + break; + } + } + } + + // add to wakeup list + wakeupOnCollisionEntry.add(w); + w.updateCollisionBounds(false); + // check for collision and triggered event + BHLeafInterface target = collide(w.behav.locale, + w.accuracyMode, + w.geometryAtoms, + w.vwcBounds, + w.boundingLeaf, + w.armingNode, + null); + + if (target != null) { + collideEntryList.add(w); + w.setTarget(target); + } + + if ((target != null) && (needTrigger)) { + w.setTriggered(); + } + } + + + void addWakeupOnCollision(WakeupOnCollisionExit w) { + + // Cleanup, since collideExitList did not remove + // its condition in removeWakeupOnCollision + boolean needTrigger = true; + + synchronized (collideListLock) { + WakeupOnCollisionExit collideExitArr[] = + (WakeupOnCollisionExit []) collideExitList.toArray(); + WakeupOnCollisionExit wexit; + for (int i=collideExitList.arraySize()-1; i>=0; i--) { + wexit = collideExitArr[i]; + if ((wexit.behav == w.behav) && + (wexit.geometryAtoms == w.geometryAtoms)) { + collideExitList.remove(i); + needTrigger = false; + break; + } + } + } + + // add condition + wakeupOnCollisionExit.add(w); + w.updateCollisionBounds(false); + BHLeafInterface target = collide(w.behav.locale, + w.accuracyMode, + w.geometryAtoms, + w.vwcBounds, + w.boundingLeaf, + w.armingNode, + null); + + if (target != null) { + // store the target that cause this condition to collide + // this is used when this condition is triggered. + w.setTarget(target); + collideExitList.add(w); + } + + if (!needTrigger) { + return; + } + // see if the matching wakeupOnCollisionEntry + // condition exists + + synchronized (collideListLock) { + WakeupOnCollisionEntry collideEntryArr[] = + (WakeupOnCollisionEntry []) collideEntryList.toArray(); + WakeupOnCollisionEntry wentry; + + for (int i=collideEntryList.arraySize()-1; i>=0; i--) { + wentry = collideEntryArr[i]; + if ((wentry.behav == w.behav) && + (wentry.geometryAtoms == w.geometryAtoms)) { + // Should not call collideEntryList.remove(i); + // Otherwise wakeupOn for Entry case may call several + // time at when initialize if collide + if (target == null) { + w.setTriggered(); + } + break; + } + } + } + } + + void addWakeupOnCollision(WakeupOnCollisionMovement w) { + wakeupOnCollisionMovement.add(w); + w.updateCollisionBounds(false); + BHLeafInterface target = collide(w.behav.locale, + w.accuracyMode, + w.geometryAtoms, + w.vwcBounds, + w.boundingLeaf, + w.armingNode, + w); + if (target != null) { + w.setTarget(target); + collideMovementList.add(w); + } + } + + void removeWakeupOnCollision(WakeupOnCollisionEntry wentry) { + wakeupOnCollisionEntry.remove(wentry); + // No need to remove collideEntry, it is used next time + // when WakeupOnExitCollision is added to determine + // whether to trigger it. + } + + void removeWakeupOnCollision(WakeupOnCollisionExit wexit) { + wakeupOnCollisionExit.remove(wexit); + // No need to remove collideExit, it is used next time + // when WakeupOnExitCollision is added to determine + // whether to trigger it. + } + + + void removeWakeupOnCollision(WakeupOnCollisionMovement wmovement) { + wakeupOnCollisionMovement.remove(wmovement); + collideMovementList.remove(wmovement); // remove if exists + } + + /** + * This method test all wakeupOnCollision list and trigger the + * condition if collision occurs. + */ + void processCollisionDetection() { + int i, idx; + BHLeafInterface target; + + // handle WakeupOnCollisionEntry + WakeupOnCollisionEntry wentry; + WakeupOnCollisionEntry wentryArr[] = (WakeupOnCollisionEntry []) + wakeupOnCollisionEntry.toArray(); + + for (i = wakeupOnCollisionEntry.arraySize()-1; i >=0; i--) { + wentry = wentryArr[i]; + wentry.updateCollisionBounds(reEvaluateWakeupCollisionGAs); + target = collide(wentry.behav.locale, + wentry.accuracyMode, + wentry.geometryAtoms, + wentry.vwcBounds, + wentry.boundingLeaf, + wentry.armingNode, + null); + idx = collideEntryList.indexOf(wentry); + + if (target != null) { + if (idx < 0) { + collideEntryList.add(wentry); + wentry.setTarget(target); + wentry.setTriggered(); + } + } else { + if (idx >= 0) { + collideEntryList.remove(idx); + } + } + } + + // handle WakeupOnCollisionMovement + + WakeupOnCollisionMovement wmove; + WakeupOnCollisionMovement wmoveArr[] = (WakeupOnCollisionMovement []) + wakeupOnCollisionMovement.toArray(); + + for (i = wakeupOnCollisionMovement.arraySize()-1; i >=0; i--) { + wmove = wmoveArr[i]; + wmove.updateCollisionBounds(reEvaluateWakeupCollisionGAs); + target = collide(wmove.behav.locale, + wmove.accuracyMode, + wmove.geometryAtoms, + wmove.vwcBounds, + wmove.boundingLeaf, + wmove.armingNode, + wmove); + idx = collideMovementList.indexOf(wmove); + if (target != null) { + if (idx < 0) { + collideMovementList.add(wmove); + wmove.setTarget(target); + } else { + if (!wmove.duplicateEvent) { + wmove.setTriggered(); + } + } + } else { + if (idx >= 0) { + collideMovementList.remove(idx); + wmove.lastSrcBounds = null; + wmove.lastDstBounds = null; + } + } + } + + + // Finally, handle WakeupOnCollisionExit + + WakeupOnCollisionExit wexit; + WakeupOnCollisionExit wexitArr[] = (WakeupOnCollisionExit []) + wakeupOnCollisionExit.toArray(); + + for (i = wakeupOnCollisionExit.arraySize()-1; i >=0; i--) { + wexit = wexitArr[i]; + wexit.updateCollisionBounds(reEvaluateWakeupCollisionGAs); + target = collide(wexit.behav.locale, + wexit.accuracyMode, + wexit.geometryAtoms, + wexit.vwcBounds, + wexit.boundingLeaf, + wexit.armingNode, + null); + idx = collideExitList.indexOf(wexit); + if (target != null) { + if (idx < 0) { + collideExitList.add(wexit); + wexit.setTarget(target); + } + } else { + if (idx >= 0) { + collideExitList.remove(idx); + wexit.setTriggered(); + } + } + } + + } + + + /** + * Check for duplicate WakeupOnCollisionMovement event. + * We don't want to continue deliver event even though the + * two colliding object did not move but this Geometry update + * thread continue to run due to transform change in others + * shape not in collision. + */ + void checkDuplicateEvent(WakeupOnCollisionMovement wmove, + Bounds bound, + BHLeafInterface hitNode) { + Bounds hitBound; + + if ((wmove.lastSrcBounds != null) && + wmove.lastSrcBounds.equals(bound)) { + if (hitNode instanceof GeometryAtom) { + hitBound = ((GeometryAtom) hitNode).source.vwcBounds; + } else { + hitBound = ((GroupRetained) hitNode).collisionVwcBounds; + } + if ((wmove.lastDstBounds != null) && + wmove.lastDstBounds.equals(hitBound)) { + wmove.duplicateEvent = true; + } else { + wmove.duplicateEvent = false; + wmove.lastDstBounds = (Bounds) hitBound.clone(); + } + } else { + wmove.duplicateEvent = false; + wmove.lastSrcBounds = (Bounds) bound.clone(); + } + } + + + /** + * check if either the geomAtoms[] or + * bound or boundingLeaf collide with BHTree. + * Only one of geomAtoms, bound, boundingLeaf is non-null. + * If accurancyMode is USE_GEOMETRY, object geometry is used, + * otherwise object bounding box is used for collision + * detection. + * In case of GROUP & BOUND, the armingNode is used + * to tell whether the colliding Group is itself or not. + * Also in case GROUP, geomAtoms is non-null if USE_GEOMETRY. + * If cond != null, it must be instanceof WakeupOnCollisionMovement + */ + BHLeafInterface collide(Locale locale, + int accurancyMode, + UnorderList geomAtoms, + Bounds bound, + BoundingLeafRetained boundingLeaf, + NodeRetained armingNode, + WakeupCriterion cond) { + + lock.readLock(); + int idx = getBHTreeIndex(locale); + + if (idx < 0) { + lock.readUnlock(); + return null; + } + BHLeafInterface hitNode; + + if (geomAtoms != null) { + synchronized (bhTreeArr[idx]) { + if ((bound != null) && + (armingNode instanceof GroupRetained)) { + // Check Bound intersect first before process + // to individual Shape3D geometryAtoms + hitNode = bhTreeArr[idx].selectAny(bound, + accurancyMode, + (GroupRetained) + armingNode); + if (hitNode == null) { + lock.readUnlock(); + return null; + } + GeometryAtom galist[] = (GeometryAtom []) + geomAtoms.toArray(false); + + hitNode = bhTreeArr[idx].selectAny(galist, + geomAtoms.arraySize(), + accurancyMode); + + if (hitNode != null) { + lock.readUnlock(); + if (cond != null) { + checkDuplicateEvent((WakeupOnCollisionMovement) cond, + bound, hitNode); + } + return hitNode; + } + } else { + GeometryAtom ga = (GeometryAtom) geomAtoms.get(0); + hitNode = bhTreeArr[idx].selectAny(ga, accurancyMode); + + if (hitNode != null) { + lock.readUnlock(); + if (cond != null) { + checkDuplicateEvent((WakeupOnCollisionMovement) cond, + ga.source.vwcBounds, + hitNode); + } + return hitNode; + } + } + } + } else { + if (bound == null) { + if (boundingLeaf == null) { + lock.readUnlock(); + return null; + } + bound = boundingLeaf.transformedRegion; + } + if (bound == null) { + lock.readUnlock(); + return null; + } + if (armingNode instanceof GroupRetained) { + synchronized (bhTreeArr[idx]) { + hitNode = bhTreeArr[idx].selectAny(bound, + accurancyMode, + (GroupRetained) + armingNode); + lock.readUnlock(); + if ((hitNode != null) && (cond != null)) { + checkDuplicateEvent((WakeupOnCollisionMovement) cond, + bound, hitNode); + } + return hitNode; + } + } else { + synchronized (bhTreeArr[idx]) { + hitNode = bhTreeArr[idx].selectAny(bound, accurancyMode, + armingNode); + lock.readUnlock(); + if ((hitNode != null) && (cond != null)) { + checkDuplicateEvent((WakeupOnCollisionMovement) cond, + bound, hitNode); + } + return hitNode; + } + } + } + lock.readUnlock(); + return null; + } + + + /** + * This prevents wakeupCondition sent out message and set + * conditionMet to true but the + * BehaviorStructure/BehaviorScheduler is not fast enough to + * process the message and reset conditionMet to false + * when view deactivate/unregister. + */ + void resetConditionMet() { + BehaviorStructure.resetConditionMet(wakeupOnCollisionEntry); + BehaviorStructure.resetConditionMet(wakeupOnCollisionExit); + BehaviorStructure.resetConditionMet(wakeupOnCollisionMovement); + } + + /** + * This processes a switch change. + */ + private void processSwitchChanged(J3dMessage m) { + + int i; + UnorderList arrList; + int size, treeIndex; + Object[] nodes; + LeafRetained leaf; + +/* is now a NOOP + + UpdateTargets targets = (UpdateTargets)m.args[0]; + + arrList = targets.targetList[Targets.GEO_TARGETS]; + + if (arrList != null) { + size = arrList.size(); + nodes = arrList.toArray(false); + + treeIndex = getBHTreeIndex(((LeafRetained)nodes[0]).locale); + + for (i=0; iupdateData method of the + * GeometryArray object to be modified. + * + * @since Java 3D 1.2 + */ + +public interface GeometryUpdater { + /** + * Updates geometry data that is accessed by reference. + * This method is called by the updateData method of a + * GeometryArray object to effect + * safe updates to vertex data that + * is referenced by that object. Applications that wish to modify + * such data must implement this method and perform all updates + * within it. + *
+ * NOTE: Applications should not call this method directly. + * + * @param geometry the Geometry object being updated. + * @see GeometryArray#updateData + */ + public void updateData(Geometry geometry); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GraphStructureChangeListener.java b/j3d-core/src/classes/share/javax/media/j3d/GraphStructureChangeListener.java new file mode 100755 index 0000000..fc64a85 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GraphStructureChangeListener.java @@ -0,0 +1,73 @@ +/* + * $RCSfile: GraphStructureChangeListener.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Listener interface for monitoring structural changes to live scene + * graphs. BranchGroup additions, removals and moves are reported. + * + * @see VirtualUniverse#addGraphStructureChangeListener + * + * @since Java 3D 1.4 + */ +public interface GraphStructureChangeListener { + /** + * Invoked when a branch group is added. + * Called just before the child is added to the parent. + * Parent can be either a BranchGroup or a Locale. + * + * @param parent the parent of the child being added + * @param child the child being added + */ + public void branchGroupAdded(Object parent, BranchGroup child); + + /** + * Invoked when a branch group is removed. + * Called just after the child has been removed from the parent. + * Parent can be either a BranchGroup or a Locale. + * + * @param parent the parent of the child being added + * @param child the child being added + */ + public void branchGroupRemoved(Object parent, BranchGroup child); + + /** + * Invoked when a branch group is moved. + * Called after a child has been moved to it's new parent. This call differs + * from the other methods in that the child is live when this method is called. + * + * @param oldParent the original parent of the child being moved + * @param newParent the new parent of the child being moved + * @param child the child being moved + */ + public void branchGroupMoved(Object oldParent, Object newParent, BranchGroup child); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GraphicsConfigInfo.java b/j3d-core/src/classes/share/javax/media/j3d/GraphicsConfigInfo.java new file mode 100644 index 0000000..be086d0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GraphicsConfigInfo.java @@ -0,0 +1,63 @@ +/* + * $RCSfile: GraphicsConfigInfo.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Container for the GraphicsTemplate3D and other private data about a selected + * GraphicsConfiguration. An instance of this class is created along with an + * instance of GrahpicsConfiguration, whenever getBestConfiguration is called. + */ +class GraphicsConfigInfo { + private GraphicsConfigTemplate3D graphicsConfigTemplate3D = null; + private Object privateData = null; + + GraphicsConfigInfo(GraphicsConfigTemplate3D graphicsConfigTemplate3D) { + setGraphicsConfigTemplate3D(graphicsConfigTemplate3D); + } + + GraphicsConfigTemplate3D getGraphicsConfigTemplate3D() { + return graphicsConfigTemplate3D; + } + + void setGraphicsConfigTemplate3D(GraphicsConfigTemplate3D graphicsConfigTemplate3D) { + this.graphicsConfigTemplate3D = graphicsConfigTemplate3D; + } + + Object getPrivateData() { + return privateData; + } + + void setPrivateData(Object privateData) { + this.privateData = privateData; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GraphicsConfigTemplate3D.java b/j3d-core/src/classes/share/javax/media/j3d/GraphicsConfigTemplate3D.java new file mode 100644 index 0000000..46e3ea4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GraphicsConfigTemplate3D.java @@ -0,0 +1,448 @@ +/* + * $RCSfile: GraphicsConfigTemplate3D.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsDevice; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsConfigTemplate; + +/** + * This class is used to obtain a valid GraphicsConfiguration that can be used by Java 3D. + * A user instantiates one of these objects and then sets all + * non-default attributes as desired. The getBestConfiguration() + * method in the GraphicsDevice class is then called with this + * GraphicsConfigTemplate and the "best" GraphicsConfiguration is returned. The "best" + * GraphicsConfiguration means that this GraphicsConfiguration is supported and it + * meets or exceeds what was requested in the GraphicsConfigTemplate. + * Null is returned if no such "best" GraphicsConfiguration is found. + * + * @see GraphicsConfigTemplate + * @see GraphicsDevice + * @see GraphicsConfiguration + */ +public class GraphicsConfigTemplate3D extends GraphicsConfigTemplate { + + int depthSize; + int doubleBuffer; + int blueSize; + int greenSize; + int redSize; + int sceneAntialiasing; + int stereo; + int stencilSize; + + // Temporary variables use for passing argument to/from Request Renderer + Object testCfg; + + static Object globalLock = new Object(); + static Object monitorLock = new Object(); + static volatile boolean threadWaiting = false; + + /** + * Constructs a GraphicsConfigTemplate3D object with default parameters. + * The default values are as follows: + *
    + * depthSize : 16
    + * doubleBuffer : REQUIRED
    + * sceneAntialiasing : UNNECESSARY
    + * stereo : UNNECESSARY
    + * redSize : 2
    + * greenSize : 2
    + * blueSize : 2
    + * stencilSize : 0
    + *
+ */ + public GraphicsConfigTemplate3D() { + doubleBuffer = REQUIRED; + stereo = UNNECESSARY; + depthSize = 16; + stencilSize = 0; + redSize = greenSize = blueSize = 2; + sceneAntialiasing = UNNECESSARY; + } + + /** + * Sets the double buffering requirement. It should be + * GraphicsConfigTemplate.REQUIRED, GraphicsConfigTemplate.PREFERRED, + * or GraphicsConfigTemplate.UNNECESSARY. + * If an invalid value is passed in, it is ignored. + * If the value of double buffering is + * GraphicsConfigTemplate.REQUIRED, and no GraphicsConfiguration is found + * that meets this requirement, null will be returned in getBestConfiguration(). + * @param value the value to set this field to + */ + public void setDoubleBuffer(int value) { + if (value < REQUIRED && value > UNNECESSARY) + return; + + doubleBuffer = value; + } + + /** + * Retrieves the double buffering value. + * @return the current value of the doubleBuffer attribute + */ + public int getDoubleBuffer() { + return doubleBuffer; + } + + /** + * Sets the stereo requirement. It should be + * GraphicsConfigTemplate.REQUIRED, GraphicsConfigTemplate.PREFERRED, + * or GraphicsConfigTemplate.UNNECESSARY. If an invalid value + * is passed in, it is ignored. If the value of stereo requirement is + * GraphicsConfigTemplate.REQUIRED, and no GraphicsConfiguration is found + * that meets this requirement, null will be returned in getBestConfiguration(). + * @param value the value to set this field to + */ + public void setStereo(int value) { + if (value < REQUIRED && value > UNNECESSARY) + return; + + stereo = value; + } + + /** + * Retrieves the stereo value. + * @return the current value of the stereo attribute. + */ + public int getStereo() { + return stereo; + } + + /** + * Sets the scene antialiasing requirement. It should be + * GraphicsConfigTemplate.REQUIRED, GraphicsConfigTemplate.PREFERRED, + * or GraphicsConfigTemplate.UNNECESSARY. If an invalid value + * is passed in, it is ignored. If the value of scene antialiasing is + * GraphicsConfigTemplate.REQUIRED, and no GraphicsConfiguration is found + * that meets this requirement, null will be returned in getBestConfiguration(). + * @param value the value to set this field to + */ + public void setSceneAntialiasing(int value) { + if (value < REQUIRED && value > UNNECESSARY) + return; + + sceneAntialiasing = value; + } + + /** + * Retrieves the scene antialiasing value. + * @return the current value of the scene antialiasing attribute. + */ + public int getSceneAntialiasing() { + return sceneAntialiasing; + } + + /** + * Sets the depth buffer size requirement. This is the minimum requirement. + * If no GraphicsConfiguration is found that meets or + * exceeds this minimum requirement, null will be returned in + * getBestConfiguration(). + * @param value the value to set this field to + */ + public void setDepthSize(int value) { + if (value < 0) + return; + + depthSize = value; + } + + /** + * Retrieves the size of the depth buffer. + * @return the current value of the depthSize attribute + */ + public int getDepthSize() { + return depthSize; + } + + /** + * Sets the stencil buffer size requirement. + * This is the minimum requirement. + * If no GraphicsConfiguration is found that meets or + * exceeds this minimum requirement, null will be returned in + * getBestConfiguration(). + * + * @param value the value to set this field to + * + * @since Java 3D 1.4 + */ + public void setStencilSize(int value) { + if (value < 0) + return; + + stencilSize = value; + } + + /** + * Retrieves the size of the stencil buffer. + * + * @return the current value of the stencilSize attribute + * + * @since Java 3D 1.4 + */ + public int getStencilSize() { + return stencilSize; + } + + /** + * Sets the number of red bits required. This is the minimum requirement. + * If no GraphicsConfiguration is found that meets or + * exceeds this minimum requirement, null will be returned in + * getBestConfiguration(). + * @param value the value to set this field to + */ + public void setRedSize(int value) { + if (value < 0) + return; + + redSize = value; + } + + /** + * Retrieves the number of red bits requested by this template. + * @return the current value of the redSize attribute. + */ + public int getRedSize() { + return redSize; + } + + + /** + * Sets the number of green bits required. This is the minimum requirement. + * If no GraphicsConfiguration is found that meets or + * exceeds this minimum requirement, null will be returned in + * getBestConfiguration(). + * @param value the value to set this field to + */ + public void setGreenSize(int value) { + if (value < 0) + return; + + greenSize = value; + } + + /** + * Retrieves the number of green bits requested by this template. + * @return the current value of the greenSize attribute. + */ + public int getGreenSize() { + return greenSize; + } + + /** + * Sets the number of blue bits required. This is the minimum requirement. + * If no GraphicsConfiguration is found that meets or + * exceeds this minimum requirement, null will be returned in + * getBestConfiguration(). + * @param value the value to set this field to + */ + public void setBlueSize(int value) { + if (value < 0) + return; + + blueSize = value; + } + + /** + * Retrieves the number of blue bits requested by this template. + * @return the current value of the blueSize attribute. + */ + public int getBlueSize() { + return blueSize; + } + + /** + * Implement the abstract function of getBestConfiguration() in GraphicsConfigTemplate. + * Usually this function is not directly called by the user. It is + * implicitly called by getBestConfiguration() in GraphicsDevice. + * The method getBestConfiguration() in GraphicsDevice will return whatever this function returns. + * This function will return the "best" GraphicsConfiguration. The "best" GraphicsConfiguration + * means that this GraphicsConfiguration is supported and it meets or exceeds what was requested in the + * GraphicsConfigTemplate. If no such "best" GraphicsConfiguration is found, null is returned. + * @param gc the array of GraphicsConfigurations to choose from + * + * @return the best GraphicsConfiguration + * + * @see GraphicsDevice + */ + public GraphicsConfiguration + getBestConfiguration(GraphicsConfiguration[] gc) { + if ((gc == null) || (gc.length == 0) || (gc[0] == null)) { + return null; + } + + synchronized (globalLock) { + testCfg = gc; + + // It is possible that the followign postRequest will + // cause request renderer run immediately before + // runMonitor(WAIT). So we need to set + // threadWaiting to true. + threadWaiting = true; + + // Prevent deadlock if invoke from Behavior callback since + // this thread has to wait Renderer thread to finish but + // MC can only handle postRequest and put it in Renderer + // queue when free. + if (Thread.currentThread() instanceof BehaviorScheduler) { + VirtualUniverse.mc.sendRenderMessage(gc[0], this, + MasterControl.GETBESTCONFIG); + } else { + VirtualUniverse.mc.postRequest(MasterControl.GETBESTCONFIG, this); + } + runMonitor(J3dThread.WAIT); + return (GraphicsConfiguration) testCfg; + } + } + + /** + * Returns a boolean indicating whether or not the given + * GraphicsConfiguration can be used to create a drawing + * surface that can be rendered to. + * + * @param gc the GraphicsConfiguration object to test + * + * @return true if this GraphicsConfiguration object + * can be used to create surfaces that can be rendered to, + * false if the GraphicsConfiguration can not be used + * to create a drawing surface usable by this API. + */ + public boolean isGraphicsConfigSupported(GraphicsConfiguration gc) { + if (gc == null) { + return false; + } + + synchronized (globalLock) { + testCfg = gc; + threadWaiting = true; + if (Thread.currentThread() instanceof BehaviorScheduler) { + VirtualUniverse.mc.sendRenderMessage(gc, this, MasterControl.ISCONFIGSUPPORT); + } else { + VirtualUniverse.mc.postRequest(MasterControl.ISCONFIGSUPPORT, this); + } + runMonitor(J3dThread.WAIT); + return ((Boolean) testCfg).booleanValue(); + } + } + + /** + * Set the stereo/doubleBuffer/sceneAntialiasingAccum + * and hasSceneAntialiasingMultiSamples flags in Canvas3D + */ + static void getGraphicsConfigFeatures(Canvas3D c) { + synchronized (globalLock) { + threadWaiting = true; + if (Thread.currentThread() instanceof BehaviorScheduler) { + VirtualUniverse.mc.sendRenderMessage(c.graphicsConfiguration, c, + MasterControl.SET_GRAPHICSCONFIG_FEATURES); + } else { + VirtualUniverse.mc.postRequest(MasterControl.SET_GRAPHICSCONFIG_FEATURES, c); + } + runMonitor(J3dThread.WAIT); + } + } + + + + /** + * Set the queryProperties() map in Canvas3D + */ + static void setQueryProps(Canvas3D c) { + synchronized (globalLock) { + threadWaiting = true; + if (Thread.currentThread() instanceof BehaviorScheduler) { + VirtualUniverse.mc.sendRenderMessage(c.graphicsConfiguration, c, + MasterControl.SET_QUERYPROPERTIES); + } else { + VirtualUniverse.mc.postRequest(MasterControl.SET_QUERYPROPERTIES, c); + } + runMonitor(J3dThread.WAIT); + } + } + + + static void runMonitor(int action) { + // user thread will locked the globalLock when Renderer + // thread invoke this function so we can't use + // the same lock. + synchronized (monitorLock) { + switch (action) { + case J3dThread.WAIT: + // Issue 279 - loop until ready + while (threadWaiting) { + try { + monitorLock.wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + } + break; + case J3dThread.NOTIFY: + monitorLock.notify(); + threadWaiting = false; + break; + } + } + } + + + // Return a string representing the value, one of: + // REQUIRED, PREFERRED, or UNNECESSARY + private static final String enumStr(int val) { + switch (val) { + case REQUIRED: + return "REQUIRED"; + case PREFERRED: + return "PREFERRED"; + case UNNECESSARY: + return "UNNECESSARY"; + } + + return "UNDEFINED"; + } + + /** + * Returns a string representation of this object. + * @return a string representation of this object. + */ + public String toString() { + return + "redSize : " + redSize + ", " + + "greenSize : " + greenSize + ", " + + "blueSize : " + blueSize + ", " + + "depthSize : " + depthSize + ", " + + "doubleBuffer : " + enumStr(doubleBuffer) + ", " + + "sceneAntialiasing : " + enumStr(sceneAntialiasing) + ", " + + "stereo : " + enumStr(stereo); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GraphicsContext3D.java b/j3d-core/src/classes/share/javax/media/j3d/GraphicsContext3D.java new file mode 100644 index 0000000..91d175c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GraphicsContext3D.java @@ -0,0 +1,3080 @@ +/* + * $RCSfile: GraphicsContext3D.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.15 $ + * $Date: 2008/02/28 20:17:22 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.Point; +import java.awt.image.BufferedImage; +import javax.vecmath.*; +import java.util.Vector; +import java.util.Enumeration; +import java.awt.Dimension; + +/** + * A GraphicsContext3D object is used for immediate mode rendering into + * a 3D canvas. It is created by, and associated with, a specific + * Canvas3D object. A GraphicsContext3D defines methods to set 3D graphics + * state and draw 3D geometric primitives. There are no public + * constructors of GraphicsContext3D. An application obtains a 3D graphics + * context object from the Canvas3D object that the application wishes + * to render into by using the getGraphicsContext3D method. A new graphics + * context is created if one does not already exist. A new GraphicsContext3D + * initializes its state variables to the following defaults: + *
    + *
  • Background object: null
  • + *
  • Fog object: null
  • + *
  • ModelClip object: null
  • + *
  • Appearance object: null
  • + *
  • List of Light objects: empty
  • + *
  • high-res coordinate: (0, 0, 0)
  • + *
  • modelTransform: identity
  • + *
  • AuralAttributes object: null
  • + *
  • List of Sound objects: empty
  • + *
  • buffer override: false
  • + *
  • front buffer rendering: false
  • + *
  • stereo mode: STEREO_BOTH
  • + *
+ * + *

+ * Note that the drawing methods in this class are not necessarily + * executed immediately. They may be buffered up for future + * execution. Applications must call the + * flush(boolean) + * method to ensure that the rendering actually happens. The flush + * method is implicitly called in the following cases: + * + *

    + *
  • The readRaster method calls + * flush(true)
  • + *
  • The Canvas3D.swap method calls + * flush(true)
  • + *
  • The Java 3D renderer calls flush(true) prior to + * swapping the buffer for a double buffered on-screen Canvas3D
  • + *
  • The Java 3D renderer calls flush(true) prior to + * copying into the off-screen buffer of an off-screen Canvas3D
  • + *
  • The Java 3D renderer calls flush(false) after + * calling the preRender, renderField, postRender, and postSwap + * Canvas3D callback methods.
  • + *
+ * + *

+ * A single-buffered, pure-immediate mode application must explicitly + * call flush to ensure that the graphics will be rendered to the + * Canvas3D. + * + * @see Canvas3D#getGraphicsContext3D + */ +public class GraphicsContext3D extends Object { + /** + * Specifies that rendering is done to the left eye. + * @see #setStereoMode + * @since Java 3D 1.2 + */ + public static final int STEREO_LEFT = 0; + + /** + * Specifies that rendering is done to the right eye. + * @see #setStereoMode + * @since Java 3D 1.2 + */ + public static final int STEREO_RIGHT = 1; + + /** + * Specifies that rendering is done to both eyes. This is the + * default. + * @see #setStereoMode + * @since Java 3D 1.2 + */ + public static final int STEREO_BOTH = 2; + + + /** + * Canvas3D in which this GraphicsContext3D will render. + */ + Canvas3D canvas3d = null; + +// +// Graphics state +// +// current user specified graphics state + private Background uBackground = null; + private Fog uFog = null; + private Appearance uAppearance = null; + private Vector uLights = new Vector(); + private HiResCoord uHiRes = new HiResCoord(); + private Vector uSounds = new Vector(); + private AuralAttributes uAuralAttributes = null; + private boolean uBufferOverride = false; + private boolean uFrontBufferRendering = false; + private int uStereoMode = STEREO_BOTH; + private ModelClip uModelClip = null; + +// Current rendering graphics state + // Current background + Background background = null; + + // Background to use if background is null; + BackgroundRetained black = new BackgroundRetained(); + + // Current fog + Fog fog = null; + + // Current modelClip + ModelClip modelClip = null; + + // Current appearance object + Appearance appearance = null; + + // default appearance retained object + AppearanceRetained defaultAppearanceRetained = new AppearanceRetained(); + + // The vector of lights + Vector lights = new Vector(); + + // Current High resolution coordinate + HiResCoord hiRes = new HiResCoord(); + + // Current modeling transform + Transform3D modelTransform = new Transform3D(); + Transform3D identityTransform = new Transform3D(); + + Transform3D modelClipTransform = null; + Transform3D normalTransform = null; + boolean normalTransformNeedToUpdate = true; + + // The vector of sounds + Vector sounds = new Vector(); + + // Current AuralAttributes state parameters + AuralAttributes auralAttributes = null; + + // The render object associated with this context + LightSet ls = null; + + // The current list of lights + LightRetained[] lightlist = null; + + // Ambient lights + Color3f sceneAmbient = new Color3f(0.0f, 0.0f, 0.0f); + + // The current number of lights, may be less than lightlist.length + int numLights = 0; + + // Current composite transform: hi-res + modelTransform + Transform3D compTransform = new Transform3D(); + + // Draw transform: hi-res + modelTransform + view + Transform3D drawTransform = new Transform3D(); + + // The view transform (VPC to EC). + // NOTE that this is *read-only* + Transform3D vpcToEc; + + // A boolean that indicates the lights have changed + boolean lightsChanged = false; + + // A boolean that indicates the sounds have changed + // XXXX: the soundsChanged flag are set like lights methods set + // lightsChanged? but where is this supposed to be check??? + // lightsChanged tested in 'draw'; but Sound are not processed + // in draw. + boolean soundsChanged = false; + + // Buffer override flag; enables frontBufferRendering and stereoMode + // attributes. + boolean bufferOverride = false; + + // Forces rendering to the front buffer (if bufferOverride is true) + boolean frontBufferRendering = false; + + // Stereo mode for this buffer (if bufferOverride is true) + int stereoMode = STEREO_BOTH; + + // Read Buffer for reading raster of color image + byte[] byteBuffer = new byte[1]; + + // Read Buffer for reading floating depth image + float[] floatBuffer = new float[1]; + + // Read Buffer for reading integer depth image + int[] intBuffer = new int[1]; + + /** + * The cached ColoringAttributes color value. It is + * 1.0, 1.0, 1.0 if there is no ColoringAttributes. + */ + float red = 1.0f; + float green = 1.0f; + float blue = 1.0f; + + + /** + * Cached diffuse color value + */ + float dRed = 1.0f; + float dGreen = 1.0f; + float dBlue = 1.0f; + + /** + * The cached TransparencyAttributes transparency value. It is + * 0.0 if there is no TransparencyAttributes. + */ + float alpha = 0.0f; + + /** + * The cached visible flag for geometry. + */ + boolean visible = true; + + /** + * Cached values for polygonMode, line antialiasing, and point antialiasing + */ + int polygonMode = PolygonAttributes.POLYGON_FILL; + boolean lineAA = false; + boolean pointAA = false; + + + /** + /** + * A boolean indicating whether or not lighting should be on. + */ + boolean enableLighting = false; + + private Appearance defaultAppearance = null; + + private boolean geometryIsLocked = false; + + private boolean ignoreVertexColors = false; + + static final int CLEAR = 0; + static final int DRAW = 1; + static final int SWAP = 2; + static final int READ_RASTER = 3; + static final int SET_APPEARANCE = 4; + static final int SET_BACKGROUND = 5; + static final int SET_FOG = 6; + static final int SET_LIGHT = 7; + static final int INSERT_LIGHT = 8; + static final int REMOVE_LIGHT = 9; + static final int ADD_LIGHT = 10; + static final int SET_HI_RES = 11; + static final int SET_MODEL_TRANSFORM = 12; + static final int MULTIPLY_MODEL_TRANSFORM = 13; + static final int SET_SOUND = 14; + static final int INSERT_SOUND = 15; + static final int REMOVE_SOUND = 16; + static final int ADD_SOUND = 17; + static final int SET_AURAL_ATTRIBUTES = 18; + static final int SET_BUFFER_OVERRIDE = 19; + static final int SET_FRONT_BUFFER_RENDERING = 20; + static final int SET_STEREO_MODE = 21; + static final int FLUSH = 22; + static final int FLUSH2D = 23; + static final int DRAWANDFLUSH2D = 24; + static final int SET_MODELCLIP = 25; + static final int DISPOSE2D = 26; + static final int NCOMMANDS = 27; // needs to be incremented + // when a new command is to be + // added to the list + + private static Integer[] commands = new Integer[NCOMMANDS]; + private static Integer[] stereoModes = { + new Integer(STEREO_LEFT), + new Integer(STEREO_RIGHT), + new Integer(STEREO_BOTH) + }; + + // dirty bits + private static final int BUFFER_MODE = 0x1; + private int dirtyMask = 0; + + // multi-texture + private int numActiveTexUnit = 0; + private int lastActiveTexUnitIndex = 0; + + // for read raster + private volatile boolean readRasterReady = false; + + // for runMonitor + private boolean gcReady = false; + private int waiting = 0; + + + /** + * Constructs and creates a GraphicsContext3D object with default + * values. Users do not call this directly, rather they get a + * graphics context from a Canvas3D. + */ + GraphicsContext3D(Canvas3D canvas3d) { + this.canvas3d = canvas3d; + } + + /** + * Gets the Canvas3D that created this GraphicsContext3D. + * @return the Canvas3D that created this GraphicsContext3D + */ + public Canvas3D getCanvas3D() { + return this.canvas3d; + } + +// +// Methods to set/get graphics state +// + + /** + * Sets the current Appearance object to the specified + * Appearance component object. + * The graphics context stores a reference to the specified + * Appearance object. This means that the application may modify + * individual appearance attributes by using the appropriate + * methods on the Appearance object. + * If the Appearance object is null, default values will be used + * for all appearance attributes - it is as if an + * Appearance node were created using the default constructor. + * + * @param appearance the new Appearance object + * + * @exception IllegalSharingException if the specified appearance refers + * to an ImageComponent2D that is being used by a Canvas3D as + * an off-screen buffer. + */ + public void setAppearance(Appearance appearance) { + + if(appearance == null) { + if(defaultAppearance == null) { + defaultAppearance = new Appearance(); + } + appearance = defaultAppearance; + } else { + // Check whether any ImageComponent2D referred to by + // the new appearance is being used as an off-screen buffer and throw + // IllegalSharingException if it is. + TextureRetained texRetained; + ImageComponent[] images; + AppearanceRetained appRetained = (AppearanceRetained)appearance.retained; + if(appRetained.texture != null) { + assert (appRetained.texUnitState == null); + texRetained = appRetained.texture; + images = texRetained.getImages(); + if(images != null) { + for(int i=0; ifrontBufferRendering and stereoMode + * attributes. + * + * @param bufferOverride the new buffer override flag + * + * @see #setFrontBufferRendering + * @see #setStereoMode + * + * @since Java 3D 1.2 + */ + public void setBufferOverride(boolean bufferOverride) { + uBufferOverride = bufferOverride; + if ((canvas3d.view == null) || + (canvas3d.view.universe == null) || + (!canvas3d.view.active) || + (Thread.currentThread() == canvas3d.screen.renderer)) { + doSetBufferOverride(bufferOverride); + } else if (Thread.currentThread() == + canvas3d.view.universe.behaviorScheduler) { + sendRenderMessage(false, GraphicsContext3D.SET_BUFFER_OVERRIDE, + new Boolean(bufferOverride), null); + } else { + sendRenderMessage(true, GraphicsContext3D.SET_BUFFER_OVERRIDE, + new Boolean(bufferOverride), null); + } + } + + void doSetBufferOverride(boolean bufferOverride) { + if (bufferOverride != this.bufferOverride) { + this.bufferOverride = bufferOverride; + dirtyMask |= BUFFER_MODE; + } + } + + + /** + * Returns the current buffer override flag. + * @return true if buffer override is enabled; otherwise, + * false is returned + * + * @since Java 3D 1.2 + */ + public boolean getBufferOverride() { + return uBufferOverride; + } + + + /** + * Sets a flag that enables or disables immediate mode rendering + * into the front buffer of a double buffered Canvas3D. + * This attribute is only used when the + * bufferOverride flag is enabled. + *

+ * Note that this attribute has no effect if double buffering + * is disabled or is not available on the Canvas3D. + * + * @param frontBufferRendering the new front buffer rendering flag + * + * @see #setBufferOverride + * + * @since Java 3D 1.2 + */ + public void setFrontBufferRendering(boolean frontBufferRendering) { + uFrontBufferRendering = frontBufferRendering; + if ((canvas3d.view == null) || + (canvas3d.view.universe == null) || + (!canvas3d.view.active) || + (Thread.currentThread() == canvas3d.screen.renderer)) { + doSetFrontBufferRendering(frontBufferRendering); + } else if (Thread.currentThread() == + canvas3d.view.universe.behaviorScheduler) { + sendRenderMessage(false, GraphicsContext3D.SET_FRONT_BUFFER_RENDERING, + new Boolean(frontBufferRendering), null); + } else { + sendRenderMessage(true, GraphicsContext3D.SET_FRONT_BUFFER_RENDERING, + new Boolean(frontBufferRendering), null); + } + } + + void doSetFrontBufferRendering(boolean frontBufferRendering) { + if (frontBufferRendering != this.frontBufferRendering) { + this.frontBufferRendering = frontBufferRendering; + dirtyMask |= BUFFER_MODE; + } + } + + + /** + * Returns the current front buffer rendering flag. + * @return true if front buffer rendering is enabled; otherwise, + * false is returned + * + * @since Java 3D 1.2 + */ + public boolean getFrontBufferRendering() { + return uFrontBufferRendering; + } + + + /** + * Sets the stereo mode for immediate mode rendering. The + * parameter specifies which stereo buffer or buffers is rendered + * into. This attribute is only used when the + * bufferOverride flag is enabled. + *

    + *
  • + * STEREO_LEFT specifies that rendering is done into + * the left eye. + *
  • + *
  • + * STEREO_RIGHT specifies that rendering is done into + * the right eye. + *
  • + *
  • + * STEREO_BOTH specifies that rendering is done into + * both eyes. This is the default. + *
  • + *
+ * + *

+ * Note that this attribute has no effect if stereo is disabled or + * is not available on the Canvas3D. + * + * @param stereoMode the new stereo mode + * + * @see #setBufferOverride + * + * @since Java 3D 1.2 + */ + public void setStereoMode(int stereoMode) { + uStereoMode = stereoMode; + if ((canvas3d.view == null) || + (canvas3d.view.universe == null) || + (!canvas3d.view.active) || + (Thread.currentThread() == canvas3d.screen.renderer)) { + doSetStereoMode(stereoMode); + } else if (Thread.currentThread() == + canvas3d.view.universe.behaviorScheduler) { + sendRenderMessage(false, GraphicsContext3D.SET_STEREO_MODE, + stereoModes[stereoMode], null); + } else { + sendRenderMessage(true, GraphicsContext3D.SET_STEREO_MODE, + stereoModes[stereoMode], null); + } + } + + void doSetStereoMode(int stereoMode) { + if (stereoMode != this.stereoMode) { + this.stereoMode = stereoMode; + dirtyMask |= BUFFER_MODE; + } + } + + + /** + * Returns the current stereo mode. + * @return the stereo mode, one of STEREO_LEFT, + * STEREO_RIGHT, or STEREO_BOTH. + * + * @since Java 3D 1.2 + */ + public int getStereoMode() { + return uStereoMode; + } + + +// +// Methods to draw graphics objects +// + + /** + * Clear the Canvas3D to the color or image specified by the + * current background node. + */ + public void clear() { + if ((canvas3d.view == null) || (canvas3d.view.universe == null) || + (!canvas3d.view.active)) { + return; + } else if (Thread.currentThread() == canvas3d.screen.renderer) { + doClear(); + } else if (Thread.currentThread() == + canvas3d.view.universe.behaviorScheduler) { + sendRenderMessage(false, GraphicsContext3D.CLEAR, null, null); + } else { + sendRenderMessage(true, GraphicsContext3D.CLEAR, null, null); + } + } + + void doClear() { + + if (!canvas3d.firstPaintCalled) + return; + + RenderBin rb = canvas3d.view.renderBin; + BackgroundRetained back = null; + + + if (this.background != null) + back = (BackgroundRetained)this.background.retained; + else + back = this.black; + + // XXXX: This should ideally be done by the renderer (or by the + // canvas itself) when the canvas is first added to a view. + /* + if ((canvas3d.screen.renderer != null) && + (canvas3d.screen.renderer.renderBin == null)) + canvas3d.screen.renderer.renderBin = rb; + */ + // If we are in pure immediate mode, update the view cache + if (!canvas3d.isRunning) + updateViewCache(rb); + + // We need to catch NullPointerException when the dsi + // gets yanked from us during a remove. + + try { + // Issue 78 - need to get the drawingSurface info every + // frame; this is necessary since the HDC (window ID) + // on Windows can become invalidated without our + // being notified! + if (!canvas3d.offScreen) { + canvas3d.drawingSurfaceObject.getDrawingSurfaceObjectInfo(); + } + + if (canvas3d.drawingSurfaceObject.renderLock()) { + // XXXX : Fix texture + /* + if (canvas3d.useSharedCtx) { + if (canvas3d.screen.renderer.sharedCtx == 0) { + synchronized (VirtualUniverse.mc.contextCreationLock) { + canvas3d.screen.renderer.sharedCtx = canvas3d.createNewContext( + canvas3d.screen.display, + canvas3d.window, 0, true, + canvas3d.offScreen); + canvas3d.screen.renderer.sharedCtxTimeStamp = + VirtualUniverse.mc.getContextTimeStamp(); + canvas3d.screen.renderer.needToRebuildDisplayList = true; + } + } + } + */ + + if (canvas3d.ctx == null) { + synchronized (VirtualUniverse.mc.contextCreationLock) { + canvas3d.ctx = canvas3d.createNewContext(null, false); + if (canvas3d.ctx == null) { + canvas3d.drawingSurfaceObject.unLock(); + return; + } + + canvas3d.ctxTimeStamp = + VirtualUniverse.mc.getContextTimeStamp(); + canvas3d.screen.renderer.listOfCtxs.add(canvas3d.ctx); + canvas3d.screen.renderer.listOfCanvases.add(canvas3d); + + canvas3d.beginScene(); + + if (canvas3d.graphics2D != null) { + canvas3d.graphics2D.init(); + } + + // enable separate specular color + canvas3d.enableSeparateSpecularColor(); + } + + // create the cache texture state in canvas + // for state download checking purpose + if (canvas3d.texUnitState == null) { + canvas3d.createTexUnitState(); + } + + canvas3d.drawingSurfaceObject.contextValidated(); + canvas3d.screen.renderer.currentCtx = canvas3d.ctx; + canvas3d.screen.renderer.currentDrawable = canvas3d.drawable; + initializeState(); + canvas3d.ctxChanged = true; + canvas3d.canvasDirty = 0xffff; + // Update Appearance + updateState(rb, RenderMolecule.SURFACE); + + canvas3d.currentLights = new + LightRetained[canvas3d.getNumCtxLights(canvas3d.ctx)]; + + for (int j=0; jflush(true) prior to reading the + * frame buffer. + * + * @param raster the Raster object used to read the + * contents of the frame buffer + * + * @exception IllegalArgumentException if the image class of the specified + * Raster's ImageComponent2D is not ImageClass.BUFFERED_IMAGE. + * + * @exception IllegalArgumentException if the specified Raster's + * ImageComponent2D is in by-reference mode and its + * RenderedImage is null. + * + * @exception IllegalArgumentException if the the Raster's + * ImageComponent2D format + * is not a 3-component format (e.g., FORMAT_RGB) + * or a 4-component format (e.g., FORMAT_RGBA). + * + * @exception IllegalSharingException if the Raster object is + * part of a live scene graph, or if the Raster's ImageComponent2D is + * part of a live scene graph. + * + * @exception IllegalSharingException if the Raster's ImageComponent2D is + * being used by an immediate mode context, or by a Canvas3D as + * an off-screen buffer. + * + * @see #flush + * @see ImageComponent + * @see DepthComponent + */ + public void readRaster(Raster raster) { + if ((raster != null) && raster.isLive()) { + ImageComponent2D image = raster.getImage(); + if (image != null){ + ImageComponent2DRetained imageRetained = (ImageComponent2DRetained)image.retained; + if (image.getImageClass() != ImageComponent.ImageClass.BUFFERED_IMAGE) { + throw new IllegalArgumentException(J3dI18N.getString("GraphicsContext3D33")); + } + if (image.isByReference() && (image.getImage() == null)) { + throw new IllegalArgumentException(J3dI18N.getString("GraphicsContext3D34")); + } + if (imageRetained.getNumberOfComponents() < 3) { + throw new IllegalArgumentException(J3dI18N.getString("GraphicsContext3D35")); + } + if (image.isLive()) { + throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D36")); + } + if (imageRetained.getInImmCtx() || imageRetained.getUsedByOffScreen()) { + throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D37")); + } + } + } + if ((canvas3d.view == null) || (canvas3d.view.universe == null) || + (!canvas3d.view.active)) { + return; + } else if (Thread.currentThread() == canvas3d.screen.renderer) { + doReadRaster(raster); + } else if (Thread.currentThread() == + canvas3d.view.universe.behaviorScheduler) { + readRasterReady = false; + sendRenderMessage(false, GraphicsContext3D.READ_RASTER, raster, null); + while (!readRasterReady) { + MasterControl.threadYield(); + } + } else { + // call from user thread + readRasterReady = false; + sendRenderMessage(true, GraphicsContext3D.READ_RASTER, raster, null); + while (!readRasterReady) { + MasterControl.threadYield(); + } + } + } + + void doReadRaster(Raster raster) { + if (!canvas3d.firstPaintCalled) { + readRasterReady = true; + return; + } + + RasterRetained ras = (RasterRetained)raster.retained; + Dimension canvasSize = canvas3d.getSize(); + Dimension rasterSize = new Dimension(); + ImageComponent2DRetained image = ras.image; + + int format = 0; // Not use in case of DepthComponent read + + if (canvas3d.ctx == null) { + // Force an initial clear if one has not yet been done + doClear(); + } + + if (J3dDebug.devPhase && J3dDebug.debug) { + J3dDebug.doAssert(canvas3d.ctx != null, "canvas3d.ctx != null"); + } + + ras.getSize(rasterSize); + // allocate read buffer space + if ( (ras.type & Raster.RASTER_COLOR) != 0) { + if ((rasterSize.width > ras.image.width) || + (rasterSize.height > ras.image.height)) { + throw new RuntimeException(J3dI18N.getString("GraphicsContext3D27")); + } + } + + if ( (ras.type & Raster.RASTER_DEPTH) != 0) { + int size = ras.depthComponent.height * ras.depthComponent.width; + if (ras.depthComponent.type + == DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT) { + if (floatBuffer.length < size) + floatBuffer = new float[size]; + } else { // type INT or NATIVE + if (intBuffer.length < size) + intBuffer = new int[size]; + } + if ((rasterSize.width > ras.depthComponent.width) || + (rasterSize.height > ras.depthComponent.height)) { + throw new RuntimeException(J3dI18N.getString("GraphicsContext3D28")); + } + } + + if ( (ras.type & Raster.RASTER_COLOR) != 0) { + + // If by reference, check if a copy needs to be made + // and also evaluate the storedFormat .. + if (image.isByReference()) { + image.geomLock.getLock(); + image.evaluateExtensions(canvas3d); + image.geomLock.unLock(); + } else { + // If image has a null buffer ( BufferedImage) + if (image.imageData == null) { + image.createBlankImageData(); + } + // Check for possible format conversion in imageData + else { + // Format convert imageData if format is unsupported. + image.evaluateExtensions(canvas3d); + } + } + } + + // We need to catch NullPointerException when the dsi + // gets yanked from us during a remove. + try { + if (canvas3d.drawingSurfaceObject.renderLock()) { + // Make the context current and read the raster information + canvas3d.makeCtxCurrent(); + canvas3d.syncRender(canvas3d.ctx, true); + Point rasterSrcOffset = new Point(); + ras.getDstOffset(rasterSrcOffset); + + DepthComponentRetained depthComp = ras.depthComponent; + int depthType = 0; + if(depthComp != null) { + depthType = depthComp.type; + } + Pipeline.getPipeline().readRaster(canvas3d.ctx, + ras.type, rasterSrcOffset.x, rasterSrcOffset.y, + rasterSize.width, rasterSize.height, canvasSize.height, + image.getImageDataTypeIntValue(), + image.getImageFormatTypeIntValue(false), + image.imageData.get(), + depthType, depthComp); + + canvas3d.drawingSurfaceObject.unLock(); + } + } catch (NullPointerException ne) { + canvas3d.drawingSurfaceObject.unLock(); + throw ne; + } + + if ( (ras.type & Raster.RASTER_DEPTH) != 0) { + if (ras.depthComponent.type == + DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT) + ((DepthComponentFloatRetained)ras.depthComponent).retrieveDepth( + floatBuffer, rasterSize.width, rasterSize.height); + else if (ras.depthComponent.type == + DepthComponentRetained.DEPTH_COMPONENT_TYPE_INT) + ((DepthComponentIntRetained)ras.depthComponent).retrieveDepth( + intBuffer, rasterSize.width, rasterSize.height); + else if (ras.depthComponent.type == + DepthComponentRetained.DEPTH_COMPONENT_TYPE_NATIVE) + ((DepthComponentNativeRetained)ras.depthComponent).retrieveDepth( + intBuffer, rasterSize.width, rasterSize.height); + } + readRasterReady = true; + } + + /** + * Flushes all previously executed rendering operations to the + * drawing buffer for this 3D graphics context. + * + * @param wait flag indicating whether or not to wait for the + * rendering to be complete before returning from this call. + * + * @since Java 3D 1.2 + */ + public void flush(boolean wait) { + if ((canvas3d.view == null) || + (canvas3d.view.universe == null) || + (!canvas3d.view.active) || + (Thread.currentThread() == canvas3d.screen.renderer)) { + doFlush(wait); + } else { + Boolean waitArg = (wait ? Boolean.TRUE : Boolean.FALSE); + + if (Thread.currentThread() == + canvas3d.view.universe.behaviorScheduler) { + sendRenderMessage(false, GraphicsContext3D.FLUSH, waitArg, + null); + } else { + sendRenderMessage(true, GraphicsContext3D.FLUSH, waitArg, + null); + } + // Issue 131: AutomaticOffscreen canvases must be treated as onscreen ones. + if (wait && canvas3d.active && canvas3d.isRunningStatus && + !canvas3d.manualRendering ) { + // No need to wait if renderer thread is not schedule + runMonitor(J3dThread.WAIT); + } + } + } + + void doFlush(boolean wait) { + try { + if (canvas3d.drawingSurfaceObject.renderLock()) { + canvas3d.syncRender(canvas3d.ctx, wait); + canvas3d.drawingSurfaceObject.unLock(); + if (wait) { + runMonitor(J3dThread.NOTIFY); + } + } + } catch (NullPointerException ne) { + canvas3d.drawingSurfaceObject.unLock(); + throw ne; + } + } + + void updateLightAndFog() { + int enableMask = 0; + int i; + sceneAmbient.x = 0.0f; + sceneAmbient.y = 0.0f; + sceneAmbient.z = 0.0f; + + int n = 0; + int nLight = lights.size();; + for (i = 0; i < nLight;i++) { + LightRetained lt = (LightRetained)((Light)lights.get(i)).retained; + if (lt instanceof AmbientLightRetained) { + sceneAmbient.x += lt.color.x; + sceneAmbient.y += lt.color.y; + sceneAmbient.z += lt.color.z; + continue; + } + + lt.update(canvas3d.ctx, n, + canvas3d.canvasViewCache.getVworldToCoexistenceScale()); + if (lt.lightOn) + enableMask |= (1 << n); + n++; + } + if (sceneAmbient.x > 1.0f) { + sceneAmbient.x = 1.0f; + } + if (sceneAmbient.y > 1.0f) { + sceneAmbient.y = 1.0f; + } + if (sceneAmbient.z > 1.0f) { + sceneAmbient.z = 1.0f; + } + + canvas3d.setSceneAmbient(canvas3d.ctx, sceneAmbient.x, + sceneAmbient.y, sceneAmbient.z); + + canvas3d.canvasDirty |= Canvas3D.AMBIENTLIGHT_DIRTY; + canvas3d.sceneAmbient.set(sceneAmbient); + + if (canvas3d.enableMask != enableMask) { + canvas3d.canvasDirty |= Canvas3D.LIGHTENABLES_DIRTY; + // XXXX: 32 => renderBin.maxLights + canvas3d.setLightEnables(canvas3d.ctx, enableMask, 32); + canvas3d.enableMask = enableMask; + } + + // Force LightBin.updateAttributes and EnvironmentSet.updateAttributes + // to use the within frame case. + canvas3d.lightBin = null; + canvas3d.environmentSet = null; + + if (fog != null) { + if (fog.retained != canvas3d.fog) { + ((FogRetained)fog.retained).update(canvas3d.ctx, + canvas3d.canvasViewCache.getVworldToCoexistenceScale()); + canvas3d.fog = (FogRetained) fog.retained; + canvas3d.canvasDirty |= Canvas3D.FOG_DIRTY; + } + } else { // Turn off fog + if (canvas3d.fog != null) { + canvas3d.setFogEnableFlag(canvas3d.ctx, false); + canvas3d.fog = null; + canvas3d.canvasDirty |= Canvas3D.FOG_DIRTY; + } + } + } + + void updateModelClip(Transform3D vworldToVpc) { + if (modelClip != null) { + int enableMask = 0; + for (int i = 0; i < 6; i++) { + if (((ModelClipRetained)modelClip.retained).enables[i]) + enableMask |= 1 << i; + } + // planes are already transformed to eye coordinates + // in immediate mode + if (enableMask != 0) { + this.drawTransform.mul(vworldToVpc, this.modelClipTransform); + canvas3d.setModelViewMatrix(canvas3d.ctx, vpcToEc.mat, + this.drawTransform); + } + ((ModelClipRetained)modelClip.retained).update( + canvas3d.ctx, enableMask, + this.drawTransform); + canvas3d.canvasDirty |= Canvas3D.MODELCLIP_DIRTY; + canvas3d.modelClip = (ModelClipRetained) modelClip.retained; + } else { + if (canvas3d.modelClip != null) { + canvas3d.disableModelClip(canvas3d.ctx); + canvas3d.modelClip = null; + canvas3d.canvasDirty |= Canvas3D.MODELCLIP_DIRTY; + } + } + + // Force EnvironmentSet.updateAttributes to use the within frame case. + canvas3d.environmentSet = null; + + } + + + + boolean updateState(RenderBin rb, int geometryType) { + + boolean useAlpha = false; + numActiveTexUnit = 0; + lastActiveTexUnitIndex = 0; + + // Update Appearance + if (appearance != null) { + AppearanceRetained app = (AppearanceRetained) appearance.retained; + + // If the material is not null then check if the one in the canvas + // is equivalent to the one being sent down. If Yes, do nothing + // Otherwise, cache the sent down material and mark the canvas + // dirty flag so that the compiled/compiled-retained rendering + // catches the change + // if material != null, we will need to load the material + // parameter again, because the apps could have changed + // the material parameter + + if (app.material != null) { + app.material.updateNative(canvas3d.ctx, + red,green,blue, + alpha,enableLighting); + canvas3d.material = app.material; + canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY; + } else { + if (canvas3d.material != null) { + canvas3d.updateMaterial(canvas3d.ctx, + red, green, blue, alpha); + canvas3d.material = null; + canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY; + } + } + + // Set flag indicating whether we are using shaders + boolean useShaders = false; + if (app instanceof ShaderAppearanceRetained) { + ShaderProgramRetained spR = ((ShaderAppearanceRetained)app).shaderProgram; + if ( spR != null) { + spR.updateNative(canvas3d, true); + + ShaderAttributeSetRetained sasR = + ((ShaderAppearanceRetained)app).shaderAttributeSet; + + if (sasR != null) { + sasR.updateNative(canvas3d, spR); + } + + canvas3d.shaderProgram = spR; + useShaders = true; + } + } + else if (canvas3d.shaderProgram != null) { + canvas3d.shaderProgram.updateNative(canvas3d, false); + canvas3d.shaderProgram = null; + useShaders = false; + } + + // Set the number of available texture units; this depends on + // whether or not shaders are being used. + int availableTextureUnits = + useShaders ? canvas3d.maxTextureImageUnits : canvas3d.maxTextureUnits; + + int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit(); + + // Get the number of active texture units. + // Note that this total number now includes disabled units. + if (app.texUnitState != null) { + TextureUnitStateRetained tus; + + for (int i = 0; i < app.texUnitState.length; i++) { + tus = app.texUnitState[i]; + if (tus != null && tus.isTextureEnabled()) { + lastActiveTexUnitIndex = i; + numActiveTexUnit = i + 1; + if (tus.texAttrs != null) { + useAlpha = useAlpha || + (tus.texAttrs.textureMode == + TextureAttributes.BLEND); + } + } + } + + if (numActiveTexUnit <= availableTextureUnits) { + // Normal, single-pass rendering case + + // update all active texture unit states + for (int i = 0; i < app.texUnitState.length; i++) { + if (i >= availableTextureUnits) { + // This can happen if there are disabled units at + // the end of the array + break; + } + + if ((app.texUnitState[i] != null) && + app.texUnitState[i].isTextureEnabled()) { + app.texUnitState[i].updateNative(i, canvas3d, + false, false); + } else { + canvas3d.resetTexture(canvas3d.ctx, i); + } + } + + // reset the remaining texture units + for (int i = app.texUnitState.length; i < prevNumActiveTexUnit; i++) { + canvas3d.resetTexture(canvas3d.ctx, i); + } + + // set the number active texture unit in Canvas3D + canvas3d.setNumActiveTexUnit(numActiveTexUnit); + + } else { + // Exceeded limit, disable all the texture units + for (int i = 0; i < prevNumActiveTexUnit; i++) { + canvas3d.resetTexture(canvas3d.ctx, i); + } + canvas3d.setNumActiveTexUnit(0); + } + + // set the active texture unit back to 0 + canvas3d.activeTextureUnit(canvas3d.ctx, 0); + } else { + // if texUnitState is null, let's disable + // all texture units first + if (canvas3d.multiTexAccelerated) { + if (canvas3d.texUnitState != null) { + for (int i = 0; i < prevNumActiveTexUnit; i++) { + TextureUnitStateRetained tur = canvas3d.texUnitState[i]; + if ((tur != null) && (tur.texture != null)) { + canvas3d.resetTexture(canvas3d.ctx, i); + canvas3d.texUnitState[i].texture = null; + } + } + } + + // set the active texture unit back to 0 + canvas3d.activeTextureUnit(canvas3d.ctx, 0); + } + + if ((canvas3d.texUnitState != null) && + (canvas3d.texUnitState[0] != null) && + (canvas3d.texUnitState[0].texture != app.texture)) { + + // If the image is by reference, check if the image + // should be processed + if (app.texture != null) { + app.texture.updateNative(canvas3d); + canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + numActiveTexUnit = 1; + lastActiveTexUnitIndex = 0; + } + else { + numActiveTexUnit = 0; + canvas3d.resetTexture(canvas3d.ctx, -1); + canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + } + + canvas3d.texUnitState[0].texture = app.texture; + } + + // set the number active texture unit in Canvas3D + canvas3d.setNumActiveTexUnit(numActiveTexUnit); + + if (app.texCoordGeneration != null) { + app.texCoordGeneration.updateNative(canvas3d); + canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + if ((canvas3d.texUnitState != null) && + (canvas3d.texUnitState[0] != null)) { + canvas3d.texUnitState[0].texGen = app.texCoordGeneration; + } + } + else { + // If the canvas does not alreadt have a null texCoordGeneration + // load the default + if ((canvas3d.texUnitState != null) && + (canvas3d.texUnitState[0] != null) && + (canvas3d.texUnitState[0].texGen != null)) { + canvas3d.resetTexCoordGeneration(canvas3d.ctx); + canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + canvas3d.texUnitState[0].texGen = app.texCoordGeneration; + } + } + + + if (app.textureAttributes != null) { + if ((canvas3d.texUnitState != null) && + (canvas3d.texUnitState[0] != null)) { + + if (canvas3d.texUnitState[0].texture != null) { + app.textureAttributes.updateNative(canvas3d, false, + canvas3d.texUnitState[0].texture.format); + } else { + app.textureAttributes.updateNative(canvas3d, false, + Texture.RGBA); + } + canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + canvas3d.texUnitState[0].texAttrs = + app.textureAttributes; + } + } + else { + // If the canvas does not already have a null texAttribute + // load the default if necessary + if ((canvas3d.texUnitState != null) && + (canvas3d.texUnitState[0] != null) && + (canvas3d.texUnitState[0].texAttrs != null)) { + canvas3d.resetTextureAttributes(canvas3d.ctx); + canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + canvas3d.texUnitState[0].texAttrs = null; + } + } + } + + if (app.coloringAttributes != null) { + app.coloringAttributes.updateNative(canvas3d.ctx, + dRed, dBlue, + dGreen, + alpha, enableLighting); + canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY; + canvas3d.coloringAttributes = app.coloringAttributes; + } + else { + if (canvas3d.coloringAttributes != null) { + canvas3d.resetColoringAttributes(canvas3d.ctx, + red, green, blue, alpha, + enableLighting); + canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY; + canvas3d.coloringAttributes = null; + } + } + + + if (app.transparencyAttributes != null) { + app.transparencyAttributes.updateNative(canvas3d.ctx, + alpha, geometryType, + polygonMode, + lineAA, pointAA); + canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY; + canvas3d.transparency = app.transparencyAttributes; + + useAlpha = useAlpha || ((app.transparencyAttributes.transparencyMode != + TransparencyAttributes.NONE) + && + (VirtualUniverse.mc.isD3D() + || + (!VirtualUniverse.mc.isD3D() && + (app.transparencyAttributes. transparencyMode != + TransparencyAttributes.SCREEN_DOOR)))); + } else { + canvas3d.resetTransparency(canvas3d.ctx, geometryType, + polygonMode, lineAA, pointAA); + canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY; + canvas3d.transparency = null; + } + + + if (app.renderingAttributes != null) { + ignoreVertexColors =app.renderingAttributes.ignoreVertexColors; + app.renderingAttributes.updateNative(canvas3d, + canvas3d.depthBufferWriteEnableOverride, + canvas3d.depthBufferEnableOverride); + canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + canvas3d.renderingAttrs = app.renderingAttributes; + + useAlpha = useAlpha || + (app.renderingAttributes.alphaTestFunction + != RenderingAttributes.ALWAYS); + } else { + // If the canvas does not alreadt have a null renderingAttrs + // load the default + ignoreVertexColors = false; + if (canvas3d.renderingAttrs != null) { + canvas3d.resetRenderingAttributes(canvas3d.ctx, + canvas3d.depthBufferWriteEnableOverride, + canvas3d.depthBufferEnableOverride); + canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + canvas3d.renderingAttrs = null; + } + } + + + if (app.polygonAttributes != null) { + app.polygonAttributes.updateNative(canvas3d.ctx); + canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY; + canvas3d.polygonAttributes = app.polygonAttributes; + } else { + // If the canvas does not alreadt have a null polygonAttr + // load the default + if (canvas3d.polygonAttributes != null) { + canvas3d.resetPolygonAttributes(canvas3d.ctx); + canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY; + canvas3d.polygonAttributes = null; + } + } + + + + if (app.lineAttributes != null) { + app.lineAttributes.updateNative(canvas3d.ctx); + canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY; + canvas3d.lineAttributes = app.lineAttributes; + } else { + // If the canvas does not already have a null lineAttr + // load the default + if (canvas3d.lineAttributes != null) { + canvas3d.resetLineAttributes(canvas3d.ctx); + canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY; + canvas3d.lineAttributes = null; + } + } + + + + if (app.pointAttributes != null) { + app.pointAttributes.updateNative(canvas3d.ctx); + canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY; + canvas3d.pointAttributes = app.pointAttributes; + } else { + // If the canvas does not already have a null pointAttr + // load the default + if (canvas3d.pointAttributes != null) { + canvas3d.resetPointAttributes(canvas3d.ctx); + canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY; + canvas3d.pointAttributes = null; + } + } + + canvas3d.appearance = app; + + } else { + if (canvas3d.appearance != null) { + resetAppearance(); + canvas3d.appearance = null; + } + } + + + return (useAlpha ); + } + + void initializeState() { + + canvas3d.setSceneAmbient(canvas3d.ctx, 0.0f, 0.0f, 0.0f); + canvas3d.disableFog(canvas3d.ctx); + canvas3d.resetRenderingAttributes(canvas3d.ctx,false, false); + + if(canvas3d.shaderProgram != null) { + canvas3d.shaderProgram.updateNative(canvas3d, false); + canvas3d.shaderProgram = null; + } + + // reset the previously enabled texture units + + int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit(); + + if (prevNumActiveTexUnit > 0) { + for (int i = 0; i < prevNumActiveTexUnit; i++) { + if (canvas3d.texUnitState[i].texture != null) { + canvas3d.resetTexture(canvas3d.ctx, i); + canvas3d.texUnitState[i].texture = null; + } + if (canvas3d.texUnitState[i].texAttrs != null) { + canvas3d.resetTextureAttributes(canvas3d.ctx); + canvas3d.texUnitState[i].texAttrs = null; + } + if (canvas3d.texUnitState[i].texGen != null) { + canvas3d.resetTexCoordGeneration(canvas3d.ctx); + canvas3d.texUnitState[i].texGen = null; + } + canvas3d.texUnitState[i].mirror = null; + } + canvas3d.setNumActiveTexUnit(0); + } + + canvas3d.resetPolygonAttributes(canvas3d.ctx); + canvas3d.resetLineAttributes(canvas3d.ctx); + canvas3d.resetPointAttributes(canvas3d.ctx); + canvas3d.resetTransparency(canvas3d.ctx, RenderMolecule.SURFACE, + PolygonAttributes.POLYGON_FILL, + false, false); + canvas3d.resetColoringAttributes(canvas3d.ctx,1.0f, 1.0f, 1.0f, 1.0f, false); + canvas3d.updateMaterial(canvas3d.ctx, 1.0f, 1.0f, 1.0f, 1.0f); + } + + + void resetAppearance() { + //System.err.println("GC3D.resetAppearance ...."); + + if (canvas3d.material != null) { + canvas3d.updateMaterial(canvas3d.ctx, + red, green, blue, alpha); + canvas3d.material = null; + canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY; + } + + if(canvas3d.shaderProgram != null) { + canvas3d.shaderProgram.updateNative(canvas3d, false); + canvas3d.shaderProgram = null; + // ShaderBin doesn't use dirty bit. + } + + // reset the previously enabled texture units + int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit(); + + if (prevNumActiveTexUnit > 0) { + for (int i = 0; i < prevNumActiveTexUnit; i++) { + if (canvas3d.texUnitState[i].texture != null) { + canvas3d.resetTexture(canvas3d.ctx, i); + canvas3d.texUnitState[i].texture = null; + } + if (canvas3d.texUnitState[i].texAttrs != null) { + canvas3d.resetTextureAttributes(canvas3d.ctx); + canvas3d.texUnitState[i].texAttrs = null; + } + if (canvas3d.texUnitState[i].texGen != null) { + canvas3d.resetTexCoordGeneration(canvas3d.ctx); + canvas3d.texUnitState[i].texGen = null; + } + canvas3d.texUnitState[i].mirror = null; + } + canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + canvas3d.setNumActiveTexUnit(0); + } + + if (canvas3d.coloringAttributes != null) { + canvas3d.resetColoringAttributes(canvas3d.ctx, + red, green, blue, alpha, enableLighting); + canvas3d.coloringAttributes = null; + canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY; + } + + if (canvas3d.transparency != null) { + canvas3d.resetTransparency(canvas3d.ctx, RenderMolecule.SURFACE, + PolygonAttributes.POLYGON_FILL, lineAA, pointAA); + canvas3d.transparency = null; + canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY; + } + + if (canvas3d.renderingAttrs != null) { + ignoreVertexColors = false; + canvas3d.resetRenderingAttributes(canvas3d.ctx, + canvas3d.depthBufferWriteEnableOverride, + canvas3d.depthBufferEnableOverride); + canvas3d.renderingAttrs = null; + canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY; + } + + if (canvas3d.polygonAttributes != null) { + canvas3d.resetPolygonAttributes(canvas3d.ctx); + canvas3d.polygonAttributes = null; + canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY; + } + + if (canvas3d.lineAttributes != null) { + canvas3d.resetLineAttributes(canvas3d.ctx); + canvas3d.lineAttributes = null; + canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY; + } + + if (canvas3d.pointAttributes != null) { + canvas3d.resetPointAttributes(canvas3d.ctx); + canvas3d.pointAttributes = null; + canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY; + } + } + + void sendRenderMessage(boolean renderRun, int command, + Object arg1, Object arg2) { + + // send a message to the request renderer + + J3dMessage renderMessage = new J3dMessage(); + renderMessage.threads = J3dThread.RENDER_THREAD; + renderMessage.type = J3dMessage.RENDER_IMMEDIATE; + renderMessage.universe = null; + renderMessage.view = null; + renderMessage.args[0] = canvas3d; + renderMessage.args[1] = getImmCommand(command); + renderMessage.args[2] = arg1; + renderMessage.args[3] = arg2; + + while (!canvas3d.view.inRenderThreadData) { + // wait until the renderer thread data in added in + // MC:RenderThreadData array ready to receive message + MasterControl.threadYield(); + } + + canvas3d.screen.renderer.rendererStructure.addMessage(renderMessage); + + if (renderRun) { + // notify mc that there is work to do + VirtualUniverse.mc.sendRunMessage(canvas3d.view, J3dThread.RENDER_THREAD); + } else { + // notify mc that there is work for the request renderer + VirtualUniverse.mc.setWorkForRequestRenderer(); + } + } + + void sendSoundMessage(int command, Object arg1, Object arg2) { + if ((canvas3d.view == null) || + (canvas3d.view.universe == null) ) { + return; + } + // send a message to the request sound scheduling + J3dMessage soundMessage = new J3dMessage(); + soundMessage.threads = J3dThread.SOUND_SCHEDULER; + soundMessage.type = J3dMessage.RENDER_IMMEDIATE; + soundMessage.universe = canvas3d.view.universe; + soundMessage.view = canvas3d.view; + soundMessage.args[0] = getImmCommand(command); + soundMessage.args[1] = arg1; + soundMessage.args[2] = arg2; + // notify mc that there is work to do + VirtualUniverse.mc.processMessage(soundMessage); + } + + static Integer getImmCommand(int command) { + if (commands[command] == null) { + commands[command] = new Integer(command); + } + return commands[command]; + } + + synchronized void runMonitor(int action) { + if (action == J3dThread.WAIT) { + while (!gcReady) { + waiting++; + try { + wait(); + } catch (InterruptedException e){} + waiting--; + } + gcReady = false; + } else { + gcReady = true; + if (waiting > 0) { + notify(); + } + } + } + +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/Group.java b/j3d-core/src/classes/share/javax/media/j3d/Group.java new file mode 100644 index 0000000..50f92f9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Group.java @@ -0,0 +1,560 @@ +/* + * $RCSfile: Group.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.BitSet; +import java.util.Vector; +import java.util.Hashtable; +import java.util.Enumeration; + +/** + * The Group node object is a general-purpose grouping node. Group + * nodes have exactly one parent and an arbitrary number of children + * that are rendered in an unspecified order (or in parallel). Null + * children are allowed; no operation is performed on a null child + * node. Operations on Group node objects include adding, removing, + * and enumerating the children of the Group node. The subclasses of + * Group node add additional semantics. + */ + +public class Group extends Node { + /** + * Specifies that this Group node allows reading its children. + */ + public static final int + ALLOW_CHILDREN_READ = CapabilityBits.GROUP_ALLOW_CHILDREN_READ; + + /** + * Specifies that this Group node allows writing its children. + */ + public static final int + ALLOW_CHILDREN_WRITE = CapabilityBits.GROUP_ALLOW_CHILDREN_WRITE; + + /** + * Specifies that this Group node allows adding new children. + */ + public static final int + ALLOW_CHILDREN_EXTEND = CapabilityBits.GROUP_ALLOW_CHILDREN_EXTEND; + + /** + * Specifies that this Group node allows reading its collision Bounds + */ + public static final int + ALLOW_COLLISION_BOUNDS_READ = + CapabilityBits.GROUP_ALLOW_COLLISION_BOUNDS_READ; + + /** + * Specifies that this Group node allows writing its collision Bounds + */ + public static final int + ALLOW_COLLISION_BOUNDS_WRITE = + CapabilityBits.GROUP_ALLOW_COLLISION_BOUNDS_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_CHILDREN_READ, + ALLOW_COLLISION_BOUNDS_READ + }; + + + /** + * Creates the retained mode GroupRetained object that this + * Group component object will point to. + */ + void createRetained() { + retained = new GroupRetained(); + retained.setSource(this); + } + + + /** + * Sets the collision bounds of a node. + * @param bounds the collision bounding object for a node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setCollisionBounds(Bounds bounds) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLLISION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Group0")); + + ((GroupRetained)this.retained).setCollisionBounds(bounds); + } + + /** + * Returns the collision bounding object of this node. + * @return the node's collision bounding object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getCollisionBounds() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLLISION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Group1")); + + return ((GroupRetained)this.retained).getCollisionBounds(); + } + + /** + * Replaces the child node at the specified index in this + * group node's list of children with the specified child. + * @param child the new child + * @param index which child to replace. The index must + * be a value + * greater than or equal to 0 and less than numChildren(). + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live or compiled scene graph and the child node being set is not + * a BranchGroup node + * @exception MultipleParentException if child has already + * been added as a child of another group node + * @exception IndexOutOfBoundsException if index is invalid + */ + public void setChild(Node child, int index) { + if (child instanceof SharedGroup) { + throw new IllegalArgumentException(J3dI18N.getString("Group2")); + } + + if (isLiveOrCompiled()) { + Node oldchild = + (Node) ((GroupRetained)this.retained).getChild(index); + if (! (child instanceof BranchGroup)) + throw new RestrictedAccessException(J3dI18N.getString("Group3")); + + if (!getCapability(ALLOW_CHILDREN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Group13")); + + if ((oldchild != null) && + (! ((BranchGroup)oldchild).getCapability(BranchGroup.ALLOW_DETACH))) { + throw new CapabilityNotSetException(J3dI18N.getString("Group4")); + } + } + + ((GroupRetained)retained).setChild(child, index); + } + + /** + * Inserts the specified child node in this group node's list of + * children at the specified index. + * @param child the new child + * @param index at which location to insert. The index + * must be a value + * greater than or equal to 0 and less than or equal to + * numChildren(). + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live + * or compiled scene graph and the child node being inserted is not + * a BranchGroup node + * @exception MultipleParentException if child has already + * been added as a child of another group node. + * @exception IndexOutOfBoundsException if index is invalid. + */ + public void insertChild(Node child, int index) { + if (child instanceof SharedGroup) { + throw new IllegalArgumentException(J3dI18N.getString("Group2")); + } + + if (isLiveOrCompiled()) { + if (! (child instanceof BranchGroup)) + throw new RestrictedAccessException(J3dI18N.getString("Group6")); + + if (!this.getCapability(ALLOW_CHILDREN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Group14")); + } + + ((GroupRetained)this.retained).insertChild(child, index); + } + + /** + * Removes the child node at the specified index from this group node's + * list of children. + * @param index which child to remove. The index + * must be a value + * greater than or equal to 0 and less than numChildren(). + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live or compiled scene graph and the child node being removed is not + * a BranchGroup node + * @exception IndexOutOfBoundsException if index is invalid. + */ + public void removeChild(int index) { + if (isLiveOrCompiled()) { + Node child = ((GroupRetained)this.retained).getChild(index); + if (!(child instanceof BranchGroup)) { + throw new RestrictedAccessException(J3dI18N.getString("Group7")); + } + + if (!this.getCapability(ALLOW_CHILDREN_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("Group15")); + } + + if (!((BranchGroup)child).getCapability(BranchGroup.ALLOW_DETACH)) { + throw new CapabilityNotSetException(J3dI18N.getString("Group4")); + } + } + + ((GroupRetained)this.retained).removeChild(index); + } + + /** + * Retrieves the child node at the specified index in + * this group node's list of children. + * @param index which child to return. + * @return the children at location index. The index + * must be a value + * greater than or equal to 0 and less than numChildren(). + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * @exception IndexOutOfBoundsException if index is invalid. + */ + public Node getChild(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHILDREN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Group9")); + + return (Node) ((GroupRetained)this.retained).getChild(index); + } + + /** + * Returns an Enumeration object of this group node's list of children. + * @return an Enumeration object of all the children + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + */ + public Enumeration getAllChildren() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHILDREN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Group9")); + + return (Enumeration)((GroupRetained)this.retained).getAllChildren(); + } + + /** + * Appends the specified child node to this group node's list of children. + * @param child the child to add to this node's list of children + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part + * of live + * or compiled scene graph and the child node being added is not + * a BranchGroup node + * @exception MultipleParentException if child has already + * been added as a child of another group node. + */ + public void addChild(Node child) { + if (child instanceof SharedGroup) { + throw new IllegalArgumentException(J3dI18N.getString("Group2")); + } + + if (isLiveOrCompiled()) { + if (! (child instanceof BranchGroup)) + throw new RestrictedAccessException(J3dI18N.getString("Group12")); + + if(!this.getCapability(ALLOW_CHILDREN_EXTEND)) + throw new CapabilityNotSetException(J3dI18N.getString("Group16")); + } + + ((GroupRetained)this.retained).addChild(child); + } + + /** + * Moves the specified branch group node from its existing location to + * the end of this group node's list of children. + * @param branchGroup the branch group node to move to this node's list + * of children + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + */ + public void moveTo(BranchGroup branchGroup) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_CHILDREN_EXTEND)) + throw new CapabilityNotSetException(J3dI18N.getString("Group16")); + + if (! branchGroup.getCapability(BranchGroup.ALLOW_DETACH)) { + throw new CapabilityNotSetException(J3dI18N.getString("Group4")); + } + } + + ((GroupRetained)this.retained).moveTo(branchGroup); + } + + /** + * Returns a count of this group node's children. + * @return the number of children descendant from this node. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + */ + public int numChildren() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHILDREN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Group9")); + + return ((GroupRetained)this.retained).numChildren(); + } + + + /** + * Retrieves the index of the specified child node in + * this group node's list of children. + * + * @param child the child node to be looked up. + * @return the index of the specified child node; + * returns -1 if the object is not in the list. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int indexOfChild(Node child) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHILDREN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Group9")); + + return ((GroupRetained)this.retained).indexOfChild(child); + } + + + /** + * Removes the specified child node from this group node's + * list of children. + * If the specified object is not in the list, the list is not modified. + * + * @param child the child node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live or compiled scene graph and the child node being removed is not + * a BranchGroup node + * + * @since Java 3D 1.3 + */ + public void removeChild(Node child) { + + if (isLiveOrCompiled()) { + if (!(child instanceof BranchGroup)) { + throw new RestrictedAccessException(J3dI18N.getString("Group7")); + } + + if (!this.getCapability(ALLOW_CHILDREN_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("Group15")); + } + + if (!((BranchGroup)child).getCapability(BranchGroup.ALLOW_DETACH)) { + throw new CapabilityNotSetException(J3dI18N.getString("Group4")); + } + } + + ((GroupRetained)retained).removeChild(child); + } + + + /** + * Removes all children from this Group node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live or compiled scene graph and any of the children being removed are + * not BranchGroup nodes + * + * @since Java 3D 1.3 + */ + public void removeAllChildren() { + + if (isLiveOrCompiled()) { + GroupRetained groupR = (GroupRetained)this.retained; + for (int index = groupR.numChildren() - 1; index >= 0; index--) { + Node child = groupR.getChild(index); + if (! (child instanceof BranchGroup)) + throw new RestrictedAccessException(J3dI18N.getString("Group7")); + + if (!this.getCapability(ALLOW_CHILDREN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Group15")); + + if (!((BranchGroup)child).getCapability(BranchGroup.ALLOW_DETACH)) { + throw new CapabilityNotSetException(J3dI18N.getString("Group4")); + } + } + } + + ((GroupRetained)retained).removeAllChildren(); + } + + + /** + * Causes this Group node to be reported as the collision target when + * collision is being used and this node or any of its children is in + * a collision. The default value is false. For collision with + * USE_GEOMETRY set, the collision traverser will check the geometry + * of all the Group node's leaf descendants; for collision with + * USE_BOUNDS set, the collision traverser will only check the bounds + * at this Group node. In both cases, if there is a collision, this + * Group node will be reported as the colliding object in the + * SceneGraphPath. This reporting is done regardless of whether + * ENABLE_COLLISION_REPORTING + * is set for this group node (setting alternate collision target to + * true implies collision reporting). + * @param target Indicates whether this Group node can be the target + * of a collision. + * @see WakeupOnCollisionEntry + * @see WakeupOnCollisionMovement + * @see WakeupOnCollisionExit + */ + public void setAlternateCollisionTarget(boolean target) { + ((GroupRetained)this.retained).setAlternateCollisionTarget(target); + } + + /** + * Returns the collision target state. + * @return Indicates whether this Group node can be the target of a + * collision. + */ + public boolean getAlternateCollisionTarget() { + return ((GroupRetained)this.retained).getAlternateCollisionTarget(); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to cloneNode and + * then cloneTree is called for each child node. For + * Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * duplicateOnCloneTree flag found in every Leaf Node's + * component data class and by the forceDuplicate paramter. + * + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree + * flag to be ignored. When false, the value of each + * node's + * duplicateOnCloneTree determines whether data is + * duplicated or copied. + * + * + * @return a reference to the cloned scene graph. + * + * @see NodeComponent#setDuplicateOnCloneTree + */ + Node cloneTree(boolean forceDuplicate, Hashtable nodeHashtable) { + Group g = (Group) super.cloneTree(forceDuplicate, nodeHashtable); + GroupRetained rt = (GroupRetained) retained; + + int nChildren = rt.numChildren(); + // call cloneTree on all child nodes + for (int i = 0; i < nChildren; i++) { + Node n = rt.getChild(i); + Node clonedN = n.cloneTree(forceDuplicate, nodeHashtable); + // add the cloned child to the cloned group node + ((GroupRetained) g.retained).addChild(clonedN); + + } + return g; + } + + + + /** + * Copies all Node information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + GroupRetained attr = (GroupRetained) originalNode.retained; + GroupRetained rt = (GroupRetained) retained; + + rt.setCollisionBounds(attr.getCollisionBounds()); + rt.setAlternateCollisionTarget(attr.getAlternateCollisionTarget()); + // throw away any child create before, since some node such as + // Sphere has already created its own branch + // Without doing this, we may end up with two branches with exactly + // the same content when cloneTree() is invoked. + rt.children.clear(); + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Group g = new Group(); + g.duplicateNode(this, forceDuplicate); + return g; + } + + + /** + * Constructs a Group node with default parameters. The default + * values are as follows: + *

    + * collision bounds : null
    + * alternate collision target : false
    + *
+ */ + public Group() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/GroupRetained.java b/j3d-core/src/classes/share/javax/media/j3d/GroupRetained.java new file mode 100644 index 0000000..b1bfb2d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/GroupRetained.java @@ -0,0 +1,3225 @@ +/* + * $RCSfile: GroupRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.16 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; +import java.util.Enumeration; +import java.util.ArrayList; + +/** + * Group node. + */ + +class GroupRetained extends NodeRetained implements BHLeafInterface { + /** + * The Group Node's children vector. + */ + ArrayList children = new ArrayList(1); + + /** + * The Group node's collision bounds in local coordinates. + */ + Bounds collisionBound = null; + + // The locale that this node is decended from + Locale locale = null; + + // The list of lights that are scoped to this node + // One such arraylist per path. If not in sharedGroup + // then only index 0 is valid + ArrayList lights = null; + + // The list of fogs that are scoped to this node + // One such arraylist per path. If not in sharedGroup + // then only index 0 is valid + ArrayList fogs = null; + + // The list of model clips that are scoped to this node + // One such arraylist per path. If not in sharedGroup + // then only index 0 is valid + ArrayList modelClips = null; + + + // The list of alternateappearance that are scoped to this node + // One such arraylist per path. If not in sharedGroup + // then only index 0 is valid + ArrayList altAppearances = null; + + + // indicates whether this Group node can be the target of a collision + boolean collisionTarget = false; + + // per child switchLinks + ArrayList childrenSwitchLinks = null; + + // the immediate childIndex of a parentSwitchLink + int parentSwitchLinkChildIndex = -1; + + // per shared path ordered path data + ArrayList orderedPaths = null; + + /** + * If collisionBound is set, this is equal to the + * transformed collisionBounds, otherwise it is equal + * to the transformed localBounds. + * This variable is set to null unless collisionTarget = true. + * This bound is only used by mirror Group. + */ + BoundingBox collisionVwcBounds; + + /** + * Mirror group of this node, it is only used when + * collisionTarget = true. Otherwise it is set to null. + * If not in shared group, + * only entry 0 is used. + * + */ + ArrayList mirrorGroup; + + /** + * key of mirror GroupRetained. + */ + HashKey key; + + /** + * sourceNode of this mirror Group + */ + GroupRetained sourceNode; + + /** + * The BHLeafNode for this GeometryAtom. + */ + BHLeafNode bhLeafNode = null; + + // + // The following variables are used during compile + // + + // true if this is the root of the scenegraph tree + boolean isRoot = false; + + boolean allocatedLights = false; + + boolean allocatedFogs = false; + + boolean allocatedMclips = false; + + boolean allocatedAltApps = false; + + // > 0 if this group is being used in scoping + int scopingRefCount = 0; + + + ArrayList compiledChildrenList = null; + + boolean isInClearLive = false; + + // List of viewes scoped to this Group, for all subclasses + // of group, except ViewSpecificGroup its a pointer to closest + // ViewSpecificGroup parent + // viewList for this node, if inSharedGroup is + // false then only viewList(0) is valid + // For VSGs, this list is an intersection of + // higher level VSGs + ArrayList viewLists = null; + + // True if this Node is descendent of ViewSpecificGroup; + boolean inViewSpecificGroup = false; + + GroupRetained() { + this.nodeType = NodeRetained.GROUP; + // issue 544 + if (VirtualUniverse.mc.useBoxForGroupBounds) { + localBounds = new BoundingBox((Bounds) null); + } else { + localBounds = new BoundingSphere(); + ((BoundingSphere) localBounds).setRadius(-1.0); + } + } + + /** + * Sets the collision bounds of a node. + * @param bounds the bounding object for the node + */ + void setCollisionBounds(Bounds bounds) { + if (bounds == null) { + this.collisionBound = null; + } else { + this.collisionBound = (Bounds)bounds.clone(); + } + + if (source.isLive()) { + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.COLLISION_BOUND_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM | + J3dThread.UPDATE_GEOMETRY; + message.universe = universe; + message.args[0] = this; + VirtualUniverse.mc.processMessage(message); + } + + } + + + /** + * Gets the collision bounds of a node. + * @return the node's bounding object + */ + Bounds getCollisionBounds() { + return (collisionBound == null ? null : (Bounds)collisionBound.clone()); + } + + /** + * Replaces the specified child with the child provided. + * @param child the new child + * @param index which child to replace + */ + void setChild(Node child, int index) { + + checkValidChild(child, "GroupRetained0"); + if (this.source.isLive()) { + universe.resetWaitMCFlag(); + synchronized (universe.sceneGraphLock) { + doSetChild(child, index); + universe.setLiveState.clear(); + } + universe.waitForMC(); + + } else { + doSetChild(child, index); + if (universe != null) { + synchronized (universe.sceneGraphLock) { + universe.setLiveState.clear(); + } + } + } + dirtyBoundsCache(); + } + + // The method that does the work once the lock is acquired. + void doSetChild(Node child, int index) { + NodeRetained oldchildr; + J3dMessage[] messages = null; + int numMessages = 0; + int attachStartIndex = 0; + + + // since we want to make sure the replacement of the child + // including removal of the oldChild and insertion of the newChild + // all happen in the same frame, we'll send all the necessary + // messages to masterControl for processing in one call. + // So let's first find out how many messages will be sent + + oldchildr = (NodeRetained) children.get(index); + + if (this.source.isLive()) { + if (oldchildr != null) { + numMessages+=3; // REMOVE_NODES, ORDERED_GROUP_REMOVED + // VIEWSPECIFICGROUP_CLEAR + attachStartIndex = 3; + } + + if (child != null) { + numMessages+=4; // INSERT_NODES,BEHAVIOR_ACTIVATE,ORDERED_GROUP_INSERTED, + // VIEWSPECIFICGROUP_INIT + } + + messages = new J3dMessage[numMessages]; + for (int i = 0; i < numMessages; i++) { + messages[i] = new J3dMessage(); + } + } + + if(oldchildr != null) { + oldchildr.setParent(null); + checkClearLive(oldchildr, messages, 0, index, null); + if (this.source.isLive()) { + universe.notifyStructureChangeListeners(false, this.source, (BranchGroup)oldchildr.source); + } + } + removeChildrenData(index); + + if(child == null) { + children.set(index, null); + if (messages != null) { + VirtualUniverse.mc.processMessage(messages); + } + return; + } + + if (this.source.isLive()) { + universe.notifyStructureChangeListeners(true, this.source, (BranchGroup)child); + } + NodeRetained childr = (NodeRetained) child.retained; + childr.setParent(this); + children.set(index, childr); + + + insertChildrenData(index); + checkSetLive(childr, index, messages, attachStartIndex, null); + if (this.source.isLive()) { + ((BranchGroupRetained)childr).isNew = true; + } + + if (messages != null) { + VirtualUniverse.mc.processMessage(messages); + } + } + + /** + * Inserts the specified child at specified index. + * @param child the new child + * @param index position to insert new child at + */ + void insertChild(Node child, int index) { + + checkValidChild(child, "GroupRetained1"); + if (this.source.isLive()) { + universe.resetWaitMCFlag(); + synchronized (universe.sceneGraphLock) { + universe.notifyStructureChangeListeners(true, this.source, (BranchGroup)child); + doInsertChild(child, index); + universe.setLiveState.clear(); + } + universe.waitForMC(); + } else { + doInsertChild(child, index); + if (universe != null) { + synchronized (universe.sceneGraphLock) { + universe.setLiveState.clear(); + } + } + } + dirtyBoundsCache(); + } + + // The method that does the work once the lock is acquired. + void doInsertChild(Node child, int index) { + int i; + NodeRetained childi; + + insertChildrenData(index); + for (i=index; i= 0) + removeChild(i); + } + + void removeAllChildren() { + int n = children.size(); + for(int i = n-1; i >= 0; i--) { + removeChild(i); + } + } + + + // The method that does the work once the lock is acquired. + void doRemoveChild(int index, J3dMessage messages[], int messageIndex) { + NodeRetained oldchildr, child; + int i; + + oldchildr = (NodeRetained) children.get(index); + + int size = children.size(); + for (i=index; i 0) { + int count = 0; + for (int i=0; i < numMessages; i++) { + if (messages[i].type != J3dMessage.INVALID_TYPE) { + count++; + } + } + if (count == numMessages) { + // in most cases + VirtualUniverse.mc.processMessage(messages); + } else { + J3dMessage ms[] = null; + + if (count > 0) { + ms = new J3dMessage[count]; + } + + int k=0; + for (int i=0; i < numMessages; i++) { + if (messages[i].type != J3dMessage.INVALID_TYPE) { + ms[k++] = messages[i]; + } + } + if (ms != null) { + VirtualUniverse.mc.processMessage(ms); + } + } + } + } + + + /** + * Returns a count of this nodes' children. + * @return the number of children descendant from this node + */ + int numChildren() { + return children.size(); + } + + // Remove a light from the list of lights + void removeLight(int numLgt, LightRetained[] removelight, HashKey key) { + ArrayList l; + int index; + if (inSharedGroup) { + int hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + l = (ArrayList)lights.get(hkIndex); + if (l != null) { + for (int i = 0; i < numLgt; i++) { + index = l.indexOf(removelight[i]); + l.remove(index); + } + } + } + else { + l = (ArrayList)lights.get(0); + for (int i = 0; i < numLgt; i++) { + index = l.indexOf(removelight[i]); + l.remove(index); + } + } + + /* + // XXXX: lights may remove twice or more during clearLive(), + // one from itself and one call from every LightRetained + // reference this. So there is case that this procedure get + // called when light already removed. + if (i >= 0) + lights.remove(i); + */ + } + + + void addAllNodesForScopedLight(int numLgts, + LightRetained[] ml, + ArrayList list, + HashKey k) { + if (inSharedGroup) { + for (int i = 0; i < localToVworldKeys.length; i++) { + k.set(localToVworldKeys[i]); + processAllNodesForScopedLight(numLgts, ml, list, k); + } + } + else { + processAllNodesForScopedLight(numLgts, ml, list, k); + } + } + + void processAllNodesForScopedLight(int numLgts, LightRetained[] ml, ArrayList list, HashKey k) { + if (allocatedLights) { + addLight(ml, numLgts, k); + } + if (this.source.isLive() || this.isInSetLive()) { + for (int i = children.size()-1; i >=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) { + if (child instanceof GroupRetained && (child.source.isLive() || child.isInSetLive())) + ((GroupRetained)child).processAllNodesForScopedLight(numLgts, ml, list, k); + else if (child instanceof LinkRetained && (child.source.isLive()|| child.isInSetLive())) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + ((GroupRetained)(ln.sharedGroup)). + processAllNodesForScopedLight(numLgts, ml, list, k.append("+"). + append(ln.nodeId)); + k.count = lastCount; + } else if (child instanceof Shape3DRetained && child.source.isLive()) { + ((Shape3DRetained)child).getMirrorObjects(list, k); + } else if (child instanceof MorphRetained && child.source.isLive()) { + ((MorphRetained)child).getMirrorObjects(list, k); + } + } + } + } + } + + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + void removeAllNodesForScopedLight(int numLgts, LightRetained[] ml, ArrayList list, HashKey k) { + if (inSharedGroup) { + for (int i = 0; i < localToVworldKeys.length; i++) { + k.set(localToVworldKeys[i]); + processRemoveAllNodesForScopedLight(numLgts, ml, list, k); + } + } + else { + processRemoveAllNodesForScopedLight(numLgts, ml, list, k); + } + } + + void processRemoveAllNodesForScopedLight(int numLgts, LightRetained[] ml, ArrayList list, HashKey k) { + if (allocatedLights) { + removeLight(numLgts,ml, k); + } + // If the source is live, then notify the children + if (this.source.isLive() && !isInClearLive) { + for (int i = children.size()-1; i >=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) { + if (child instanceof GroupRetained &&(child.source.isLive() && + ! ((GroupRetained)child).isInClearLive)) + ((GroupRetained)child).processRemoveAllNodesForScopedLight(numLgts, ml,list, k); + else if (child instanceof LinkRetained && child.source.isLive()) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + ((GroupRetained)(ln.sharedGroup)). + processRemoveAllNodesForScopedLight(numLgts, ml, list, k.append("+"). + append(ln.nodeId)); + k.count = lastCount; + } else if (child instanceof Shape3DRetained && child.source.isLive() ) { + ((Shape3DRetained)child).getMirrorObjects(list, k); + } else if (child instanceof MorphRetained && child.source.isLive()) { + ((MorphRetained)child).getMirrorObjects(list, k); + } + } + } + } + } + + + void addAllNodesForScopedFog(FogRetained mfog, ArrayList list, HashKey k) { + if (inSharedGroup) { + for (int i = 0; i < localToVworldKeys.length; i++) { + k.set(localToVworldKeys[i]); + processAddNodesForScopedFog(mfog, list, k); + } + } + else { + processAddNodesForScopedFog(mfog, list, k); + } + } + + void processAddNodesForScopedFog(FogRetained mfog, ArrayList list, HashKey k) { + // If this group has it own scoping list then add .. + if (allocatedFogs) + addFog(mfog, k); + // If the source is live, then notify the children + if (this.source.isLive() || this.isInSetLive()) { + for (int i = children.size()-1; i >=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) { + if (child instanceof GroupRetained && (child.source.isLive()|| child.isInSetLive())) + ((GroupRetained)child).processAddNodesForScopedFog(mfog, list, k); + else if (child instanceof LinkRetained && (child.source.isLive()||child.isInSetLive() )) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + ((GroupRetained)(ln.sharedGroup)). + processAddNodesForScopedFog(mfog, list, k.append("+"). + append(ln.nodeId)); + k.count = lastCount; + } else if (child instanceof Shape3DRetained && child.source.isLive()) { + ((Shape3DRetained)child).getMirrorObjects(list, k); + } else if (child instanceof MorphRetained && child.source.isLive()) { + ((MorphRetained)child).getMirrorObjects(list, k); + } + } + } + } + } + + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + void removeAllNodesForScopedFog(FogRetained mfog, ArrayList list, HashKey k) { + if (inSharedGroup) { + for (int i = 0; i < localToVworldKeys.length; i++) { + k.set(localToVworldKeys[i]); + processRemoveAllNodesForScopedFog(mfog, list, k); + } + } + else { + processRemoveAllNodesForScopedFog(mfog, list, k); + } + } + void processRemoveAllNodesForScopedFog(FogRetained mfog, ArrayList list, HashKey k) { + // If the source is live, then notify the children + if (allocatedFogs) + removeFog(mfog, k); + if (this.source.isLive() && !isInClearLive) { + for (int i = children.size()-1; i >=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) { + if (child instanceof GroupRetained &&(child.source.isLive() && + ! ((GroupRetained)child).isInClearLive)) + ((GroupRetained)child).processRemoveAllNodesForScopedFog(mfog, list, k); + else if (child instanceof LinkRetained && child.source.isLive()) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + ((GroupRetained)(ln.sharedGroup)). + processRemoveAllNodesForScopedFog(mfog, list, k.append("+"). + append(ln.nodeId)); + k.count = lastCount; + } else if (child instanceof Shape3DRetained && child.source.isLive() ) { + ((Shape3DRetained)child).getMirrorObjects(list, k); + } else if (child instanceof MorphRetained && child.source.isLive()) { + ((MorphRetained)child).getMirrorObjects(list, k); + } + } + } + } + } + + void addAllNodesForScopedModelClip(ModelClipRetained mModelClip, ArrayList list, HashKey k) { + if (inSharedGroup) { + for (int i = 0; i < localToVworldKeys.length; i++) { + k.set(localToVworldKeys[i]); + processAddNodesForScopedModelClip(mModelClip, list, k); + } + } + else { + processAddNodesForScopedModelClip(mModelClip, list, k); + } + } + + void processAddNodesForScopedModelClip(ModelClipRetained mModelClip, + ArrayList list, + HashKey k) { + if (allocatedMclips) + addModelClip(mModelClip, k); + // If the source is live, then notify the children + if (this.source.isLive() || this.isInSetLive()) { + for (int i = children.size()-1; i >=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) { + if (child instanceof GroupRetained && (child.source.isLive()||child.isInSetLive() )) + ((GroupRetained)child).processAddNodesForScopedModelClip( + mModelClip, list, k); + else if (child instanceof LinkRetained && (child.source.isLive()||child.isInSetLive() )) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + ((GroupRetained)(ln.sharedGroup)). + processAddNodesForScopedModelClip(mModelClip, list, + k.append("+").append(ln.nodeId)); + k.count = lastCount; + } else if (child instanceof Shape3DRetained && child.source.isLive()) { + ((Shape3DRetained)child).getMirrorObjects(list, k); + } else if (child instanceof MorphRetained && child.source.isLive()) { + ((MorphRetained)child).getMirrorObjects(list, k); + } + } + } + } + } + void removeAllNodesForScopedModelClip(ModelClipRetained mModelClip, ArrayList list, HashKey k) { + if (inSharedGroup) { + for (int i = 0; i < localToVworldKeys.length; i++) { + k.set(localToVworldKeys[i]); + processRemoveAllNodesForScopedModelClip(mModelClip, list, k); + } + } + else { + processRemoveAllNodesForScopedModelClip(mModelClip, list, k); + } + + } + + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + void processRemoveAllNodesForScopedModelClip(ModelClipRetained mModelClip, ArrayList list, HashKey k) { + // If the source is live, then notify the children + if (allocatedMclips) + removeModelClip(mModelClip, k); + if (this.source.isLive() && !isInClearLive) { + for (int i = children.size()-1; i >=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) { + if (child instanceof GroupRetained &&(child.source.isLive() && + ! ((GroupRetained)child).isInClearLive)) + ((GroupRetained)child).processRemoveAllNodesForScopedModelClip(mModelClip, list, k); + else if (child instanceof LinkRetained && child.source.isLive()) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + ((GroupRetained)(ln.sharedGroup)). + processRemoveAllNodesForScopedModelClip(mModelClip, list, k.append("+"). + append(ln.nodeId)); + k.count = lastCount; + } else if (child instanceof Shape3DRetained && child.source.isLive() ) { + ((Shape3DRetained)child).getMirrorObjects(list, k); + } else if (child instanceof MorphRetained && child.source.isLive()) { + ((MorphRetained)child).getMirrorObjects(list, k); + } + } + } + } + } + + void addAllNodesForScopedAltApp(AlternateAppearanceRetained mAltApp, ArrayList list, HashKey k) { + if (inSharedGroup) { + for (int i = 0; i < localToVworldKeys.length; i++) { + k.set(localToVworldKeys[i]); + processAddNodesForScopedAltApp(mAltApp, list, k); + } + } + else { + processAddNodesForScopedAltApp(mAltApp, list, k); + } + } + + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + void processAddNodesForScopedAltApp(AlternateAppearanceRetained mAltApp, ArrayList list, HashKey k) { + // If the source is live, then notify the children + if (allocatedAltApps) + addAltApp(mAltApp, k); + if (this.source.isLive() || this.isInSetLive()) { + for (int i = children.size()-1; i >=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) { + if (child instanceof GroupRetained && (child.source.isLive() || child.isInSetLive())) + ((GroupRetained)child).processAddNodesForScopedAltApp(mAltApp, list, k); + else if (child instanceof LinkRetained && child.source.isLive()) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + ((GroupRetained)(ln.sharedGroup)). + processAddNodesForScopedAltApp(mAltApp, list, k.append("+"). + append(ln.nodeId)); + k.count = lastCount; + } else if (child instanceof Shape3DRetained && child.source.isLive() ) { + ((Shape3DRetained)child).getMirrorObjects(list, k); + } else if (child instanceof MorphRetained && child.source.isLive()) { + ((MorphRetained)child).getMirrorObjects(list, k); + } + } + } + } + } + + void removeAllNodesForScopedAltApp(AlternateAppearanceRetained mAltApp, ArrayList list, HashKey k) { + if (inSharedGroup) { + for (int i = 0; i < localToVworldKeys.length; i++) { + k.set(localToVworldKeys[i]); + processRemoveNodesForScopedAltApp(mAltApp, list, k); + } + } + else { + processAddNodesForScopedAltApp(mAltApp, list, k); + } + } + + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + void processRemoveNodesForScopedAltApp(AlternateAppearanceRetained mAltApp, ArrayList list, HashKey k) { + // If the source is live, then notify the children + if (allocatedAltApps) + removeAltApp(mAltApp, k); + if (this.source.isLive() && !isInClearLive) { + for (int i = children.size()-1; i >=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) { + if (child instanceof GroupRetained &&(child.source.isLive() && + ! ((GroupRetained)child).isInClearLive)) + ((GroupRetained)child).processRemoveNodesForScopedAltApp(mAltApp, list, k); + else if (child instanceof LinkRetained && child.source.isLive()) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + ((GroupRetained)(ln.sharedGroup)). + processRemoveNodesForScopedAltApp(mAltApp, list, k.append("+"). + append(ln.nodeId)); + k.count = lastCount; + } else if (child instanceof Shape3DRetained && child.source.isLive() ) { + ((Shape3DRetained)child).getMirrorObjects(list, k); + } else if (child instanceof MorphRetained && child.source.isLive()) { + ((MorphRetained)child).getMirrorObjects(list, k); + } + } + } + } + } + + synchronized void setLightScope() { + // Make group's own copy + ArrayList newLights; + if (!allocatedLights) { + allocatedLights = true; + if (lights != null) { + newLights = new ArrayList(lights.size()); + int size = lights.size(); + for (int i = 0; i < size; i++) { + ArrayList l = (ArrayList)lights.get(i); + if (l != null) { + newLights.add(l.clone()); + } + else { + newLights.add(null); + } + } + } + else { + if (inSharedGroup) { + newLights = new ArrayList(); + for (int i = 0; i < localToVworldKeys.length; i++) { + newLights.add(new ArrayList()); + } + } + else { + newLights = new ArrayList(); + newLights.add(new ArrayList()); + } + } + lights = newLights; + + } + scopingRefCount++; + } + synchronized void removeLightScope() { + scopingRefCount--; + } + + + synchronized void setFogScope() { + // Make group's own copy + ArrayList newFogs; + if (!allocatedFogs) { + allocatedFogs = true; + if (fogs != null) { + newFogs = new ArrayList(fogs.size()); + int size = fogs.size(); + for (int i = 0; i < size; i++) { + ArrayList l = (ArrayList)fogs.get(i); + if (l != null) { + newFogs.add(l.clone()); + } + else { + newFogs.add(null); + } + } + } + else { + if (inSharedGroup) { + newFogs = new ArrayList(); + for (int i = 0; i < localToVworldKeys.length; i++) { + newFogs.add(new ArrayList()); + } + } + else { + newFogs = new ArrayList(); + newFogs.add(new ArrayList()); + } + } + fogs = newFogs; + + } + scopingRefCount++; + } + synchronized void removeFogScope() { + scopingRefCount--; + } + + + synchronized void setMclipScope() { + // Make group's own copy + ArrayList newMclips; + if (!allocatedMclips) { + allocatedMclips = true; + if (modelClips != null) { + newMclips = new ArrayList(modelClips.size()); + int size = modelClips.size(); + for (int i = 0; i < size; i++) { + ArrayList l = (ArrayList)modelClips.get(i); + if (l != null) { + newMclips.add(l.clone()); + } + else { + newMclips.add(null); + } + } + } + else { + if (inSharedGroup) { + newMclips =new ArrayList(); + for (int i = 0; i < localToVworldKeys.length; i++) { + newMclips.add(new ArrayList()); + } + } + else { + newMclips = new ArrayList(); + newMclips.add(new ArrayList()); + } + } + modelClips = newMclips; + + } + scopingRefCount++; + } + synchronized void removeMclipScope() { + scopingRefCount--; + } + + + synchronized void setAltAppScope() { + // Make group's own copy + ArrayList newAltApps; + if (!allocatedAltApps) { + allocatedAltApps = true; + if (altAppearances != null) { + newAltApps = new ArrayList(altAppearances.size()); + int size = altAppearances.size(); + for (int i = 0; i < size; i++) { + ArrayList l = (ArrayList)altAppearances.get(i); + if (l != null) { + newAltApps.add(l.clone()); + } + else { + newAltApps.add(null); + } + } + } + else { + if (inSharedGroup) { + newAltApps = new ArrayList(); + for (int i = 0; i < localToVworldKeys.length; i++) { + newAltApps.add(new ArrayList()); + } + } + else { + newAltApps = new ArrayList(); + newAltApps.add(new ArrayList()); + } + } + altAppearances = newAltApps; + + } + scopingRefCount++; + } + + synchronized void removeAltAppScope() { + scopingRefCount--; + } + + + synchronized boolean usedInScoping() { + return (scopingRefCount > 0); + } + + // Add a light to the list of lights + void addLight(LightRetained[] addlight, int numLgts, HashKey key) { + ArrayList l; + if (inSharedGroup) { + int hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + l = (ArrayList)lights.get(hkIndex); + if (l != null) { + for (int i = 0; i < numLgts; i++) { + l.add(addlight[i]); + } + } + } + else { + l = (ArrayList)lights.get(0); + for (int i = 0; i < numLgts; i++) { + l.add(addlight[i]); + } + } + + } + // Add a fog to the list of fogs + void addFog(FogRetained fog, HashKey key) { + ArrayList l; + if (inSharedGroup) { + int hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + l = (ArrayList)fogs.get(hkIndex); + if (l != null) { + l.add(fog); + } + } + else { + l = (ArrayList)fogs.get(0); + l.add(fog); + } + + } + + // Add a ModelClip to the list of ModelClip + void addModelClip(ModelClipRetained modelClip, HashKey key) { + ArrayList l; + if (inSharedGroup) { + int hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + l = (ArrayList)modelClips.get(hkIndex); + if (l != null) { + l.add(modelClip); + } + } + else { + l = (ArrayList)modelClips.get(0); + l.add(modelClip); + } + + } + // Add a alt appearance to the list of alt appearance + void addAltApp(AlternateAppearanceRetained altApp, HashKey key) { + ArrayList l; + if (inSharedGroup) { + int hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + l = (ArrayList)altAppearances.get(hkIndex); + if (l != null) { + l.add(altApp); + } + } + else { + l = (ArrayList)altAppearances.get(0); + l.add(altApp); + } + + } + + + // Remove a fog from the list of fogs + void removeFog(FogRetained fog, HashKey key) { + ArrayList l; + int index; + if (inSharedGroup) { + int hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + l = (ArrayList)fogs.get(hkIndex); + if (l != null) { + index = l.indexOf(fog); + l.remove(index); + } + } + else { + l = (ArrayList)fogs.get(0); + index = l.indexOf(fog); + l.remove(index); + } + + } + + + // Remove a ModelClip from the list of ModelClip + void removeModelClip(ModelClipRetained modelClip, HashKey key) { + ArrayList l; + int index; + if (inSharedGroup) { + int hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + l = (ArrayList)modelClips.get(hkIndex); + if (l != null) { + index = l.indexOf(modelClip); + l.remove(index); + } + } + else { + l = (ArrayList)modelClips.get(0); + index = l.indexOf(modelClip); + l.remove(index); + } + } + + + + // Remove a fog from the list of alt appearance + void removeAltApp(AlternateAppearanceRetained altApp, HashKey key) { + ArrayList l; + int index; + if (inSharedGroup) { + int hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + l = (ArrayList)altAppearances.get(hkIndex); + if (l != null) { + index = l.indexOf(altApp); + l.remove(index); + } + } + else { + l = (ArrayList)altAppearances.get(0); + index = l.indexOf(altApp); + l.remove(index); + } + + } + + + void updatePickable(HashKey keys[], boolean pick[]) { + int numChildLessOne = children.size() - 1; + super.updatePickable(keys, pick); + int i=0; + NodeRetained child; + + // Fix for issue 540 + if (numChildLessOne < 0) { + return; + } + // End fix for issue 540 + + for (i = 0; i < numChildLessOne; i++) { + child = (NodeRetained)children.get(i); + if(child != null) + child.updatePickable(keys, (boolean []) pick.clone()); + } + // No need to clone for the last value + + child = (NodeRetained)children.get(i); + if(child != null) + child.updatePickable(keys, pick); + + } + + + void updateCollidable(HashKey keys[], boolean collide[]) { + int numChildLessOne = children.size() - 1; + super.updateCollidable(keys, collide); + int i=0; + NodeRetained child; + + // Fix for issue 540 + if (numChildLessOne < 0) { + return; + } + // End fix for issue 540 + + for (i = 0; i < numChildLessOne; i++) { + child = (NodeRetained)children.get(i); + if(child != null) + child.updateCollidable(keys, (boolean []) collide.clone()); + } + // No need to clone for the last value + child = (NodeRetained)children.get(i); + if(child != null) + child.updateCollidable(keys, collide); + } + + void setAlternateCollisionTarget(boolean target) { + if (collisionTarget == target) + return; + + collisionTarget = target; + + if (source.isLive()) { + // Notify parent TransformGroup to add itself + // Since we want to update collisionVwcBounds when + // transform change in TransformStructure. + TransformGroupRetained tg; + J3dMessage message = new J3dMessage(); + message.threads = J3dThread.UPDATE_GEOMETRY; + message.universe = universe; + // send message to GeometryStructure to add/remove this + // group node in BHTree as AlternateCollisionTarget + + int numPath; + CachedTargets newCtArr[] = null; + + if (target) { + createMirrorGroup(); + + TargetsInterface ti = getClosestTargetsInterface( + TargetsInterface.TRANSFORM_TARGETS); + if (ti != null) { + + // update targets + CachedTargets ct; + Targets targets = new Targets(); + numPath = mirrorGroup.size(); + newCtArr = new CachedTargets[numPath]; + for (int i=0; i 0) { + numMessages++; + } + else { + sendOGMessage = false; + } + if(s.changedViewGroup != null) { + numMessages++; + } + else { + sendVSGMessage = false; + } + + messages = new J3dMessage[numMessages]; + messageIndex = 0; + for(int mIndex=0; mIndex < numMessages; mIndex++) { + messages[mIndex] = new J3dMessage(); + } + sendMessages = true; + } + + if(sendOGMessage) { + createMessage = messages[messageIndex++]; + createMessage.threads = J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.type = J3dMessage.ORDERED_GROUP_INSERTED; + createMessage.universe = universe; + createMessage.args[0] = s.ogList.toArray(); + createMessage.args[1] = s.ogChildIdList.toArray(); + createMessage.args[2] = s.ogOrderedIdList.toArray(); + createMessage.args[3] = s.ogCIOList.toArray(); + createMessage.args[4] = s.ogCIOTableList.toArray(); + } + + + if(sendVSGMessage) { + createMessage = messages[messageIndex++]; + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.type = J3dMessage.VIEWSPECIFICGROUP_INIT; + createMessage.universe = universe; + createMessage.args[0] = s.changedViewGroup; + createMessage.args[1] = s.changedViewList; + createMessage.args[2] = s.keyList; + } + + createMessage = messages[messageIndex++]; + createMessage.threads = s.notifyThreads; + createMessage.type = J3dMessage.INSERT_NODES; + createMessage.universe = universe; + createMessage.args[0] = s.nodeList.toArray(); + if (newCtArr != null) { + createMessage.args[1] = transformInterface; + createMessage.args[2] = newCtArr; + } else { + createMessage.args[1] = null; + createMessage.args[2] = null; + } + + if (s.viewScopedNodeList != null) { + createMessage.args[3] = s.viewScopedNodeList; + createMessage.args[4] = s.scopedNodesViewList; + } + + // execute user behavior's initialize methods + int sz = s.behaviorNodes.size(); + + for (int i=0; i < sz; i++) { + BehaviorRetained b; + b = (BehaviorRetained)s.behaviorNodes.get(i); + b.executeInitialize(); + } + + s.behaviorNodes.clear(); + + createMessage = messages[messageIndex++]; + + createMessage.threads = J3dThread.UPDATE_BEHAVIOR; + createMessage.type = J3dMessage.BEHAVIOR_ACTIVATE; + createMessage.universe = universe; + + if (sendMessages == true) { + VirtualUniverse.mc.processMessage(messages); + } + + if (nodeType == NodeRetained.SWITCH) { + // force reEvaluation of switch children + SwitchRetained sw = (SwitchRetained)this; + sw.setWhichChild(sw.whichChild, true); + } + + //Reset SetLiveState to free up memory. + s.reset(null); + } + } + + + + void checkClearLive(NodeRetained child, + J3dMessage messages[], int messageIndex, + int childIndex, NodeRetained linkNode) { + checkClearLive(child, localToVworldKeys, inSharedGroup, + messages, messageIndex, childIndex, linkNode); + } + + + + /** + * This checks if clearLive needs to be called. If it does, it gets the + * needed info and calls it. + */ + void checkClearLive(NodeRetained child, HashKey keys[], + boolean isShared, + J3dMessage messages[], int messageIndex, + int childIndex, NodeRetained linkNode) { + + SceneGraphObject me = this.source; + J3dMessage destroyMessage; + boolean sendMessages = false; + boolean sendOGMessage = true; + boolean sendVSGMessage = true; + + int i, j; + TransformGroupRetained tg; + + if (me.isLive()) { + SetLiveState s = universe.setLiveState; + + s.reset(locale); + s.refCount = refCount; + s.inSharedGroup = isShared; + s.inBackgroundGroup = inBackgroundGroup; + s.inViewSpecificGroup = inViewSpecificGroup; + s.keys = keys; + s.fogs = fogs; + s.lights = lights; + s.altAppearances = altAppearances; + s.modelClips = modelClips; + + // Issue 312: Allocate data structures if we are in a ViewSpecificGroup + if (s.inViewSpecificGroup && + (s.changedViewGroup == null)) { + s.changedViewGroup = new ArrayList(); + s.changedViewList = new ArrayList(); + s.keyList = new int[10]; + s.viewScopedNodeList = new ArrayList(); + s.scopedNodesViewList = new ArrayList(); + } + + if (this instanceof OrderedGroupRetained && linkNode == null) { + // set this regardless of refCount + s.ogList.add(this); + s.ogChildIdList.add(new Integer(childIndex)); + s.ogCIOList.add(this); + int[] newArr = null; + OrderedGroupRetained og = (OrderedGroupRetained)this; + if(og.userChildIndexOrder != null) { + newArr = new int[og.userChildIndexOrder.length]; + System.arraycopy(og.userChildIndexOrder, 0, newArr, + 0, og.userChildIndexOrder.length); + } + s.ogCIOTableList.add(newArr); + + } + + // Issue 312: always initialize s.viewLists + s.viewLists = viewLists; + + TargetsInterface transformInterface, switchInterface; + transformInterface = initTransformStates(s, false); + switchInterface = initSwitchStates(s, this, child, linkNode, false); + + child.clearLive(s); + + CachedTargets[] newCtArr = null; + newCtArr = updateTransformStates(s, transformInterface, false); + updateSwitchStates(s, switchInterface, false); + + // We're sending multiple messages in the call, inorder to + // have all these messages to be process as an atomic operation. + // We need to create an array of messages to MasterControl, this + // will ensure that all these messages will get the same time stamp. + + // If it is called from "moveTo", messages is not null. + if (messages == null) { + int numMessages = 1; + if(s.ogList.size() > 0) { + numMessages++; + } + else { + sendOGMessage = false; + } + + if(s.changedViewGroup != null) { + numMessages++; + } + else { + sendVSGMessage = false; + } + + messages = new J3dMessage[numMessages]; + messageIndex = 0; + for(int mIndex=0; mIndex < numMessages; mIndex++) { + messages[mIndex] = new J3dMessage(); + } + sendMessages = true; + } + + if(sendOGMessage) { + destroyMessage = messages[messageIndex++]; + destroyMessage.threads = J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_RENDERING_ENVIRONMENT; + destroyMessage.type = J3dMessage.ORDERED_GROUP_REMOVED; + destroyMessage.universe = universe; + destroyMessage.args[0] = s.ogList.toArray(); + destroyMessage.args[1] = s.ogChildIdList.toArray(); + destroyMessage.args[3] = s.ogCIOList.toArray(); + destroyMessage.args[4] = s.ogCIOTableList.toArray(); + } + + // Issue 312: We need to send the REMOVE_NODES message to the + // RenderingEnvironmentStructure before we send VIEWSPECIFICGROUP_CLEAR, + // since the latter clears the list of views that is referred to by + // scopedNodesViewList and used by removeNodes. + destroyMessage = messages[messageIndex++]; + destroyMessage.threads = s.notifyThreads; + destroyMessage.type = J3dMessage.REMOVE_NODES; + destroyMessage.universe = universe; + destroyMessage.args[0] = s.nodeList.toArray(); + + if (newCtArr != null) { + destroyMessage.args[1] = transformInterface; + destroyMessage.args[2] = newCtArr; + } else { + destroyMessage.args[1] = null; + destroyMessage.args[2] = null; + } + if (s.viewScopedNodeList != null) { + destroyMessage.args[3] = s.viewScopedNodeList; + destroyMessage.args[4] = s.scopedNodesViewList; + } + + if(sendVSGMessage) { + destroyMessage = messages[messageIndex++]; + destroyMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + destroyMessage.type = J3dMessage.VIEWSPECIFICGROUP_CLEAR; + destroyMessage.universe = universe; + destroyMessage.args[0] = s.changedViewGroup; + destroyMessage.args[1] = s.keyList; + } + + if (sendMessages == true) { + VirtualUniverse.mc.processMessage(messages); + } + + s.reset(null); // for GC + } + } + + TargetsInterface initTransformStates(SetLiveState s, boolean isSetLive) { + + int numPaths = (inSharedGroup)? s.keys.length : 1; + TargetsInterface ti = getClosestTargetsInterface( + TargetsInterface.TRANSFORM_TARGETS); + + + if (isSetLive) { + s.currentTransforms = localToVworld; + s.currentTransformsIndex = localToVworldIndex; + s.localToVworldKeys = localToVworldKeys; + s.localToVworld = s.currentTransforms; + s.localToVworldIndex = s.currentTransformsIndex; + + s.parentTransformLink = parentTransformLink; + if (parentTransformLink != null) { + if (parentTransformLink instanceof TransformGroupRetained) { + TransformGroupRetained tg; + tg = (TransformGroupRetained) parentTransformLink; + s.childTransformLinks = tg.childTransformLinks; + } else { + SharedGroupRetained sg; + sg = (SharedGroupRetained) parentTransformLink; + s.childTransformLinks = sg.childTransformLinks; + } + } + } + + int transformLevels[] = new int[numPaths]; + findTransformLevels(transformLevels); + s.transformLevels = transformLevels; + + if (ti != null) { + Targets[] newTargets = new Targets[numPaths]; + for(int i=0; i= 0) { + newTargets[i] = new Targets(); + } else { + newTargets[i] = null; + } + } + s.transformTargets = newTargets; + + // XXXX: optimization for targetThreads computation, require + // cleanup in GroupRetained.doSetLive() + //s.transformTargetThreads = 0; + } + + return ti; + } + + CachedTargets[] updateTransformStates(SetLiveState s, + TargetsInterface ti, boolean isSetLive) { + CachedTargets[] newCtArr = null; + + if (ti != null) { + if (isSetLive) { + CachedTargets ct; + int newTargetThreads = 0; + int hkIndex; + + newCtArr = new CachedTargets[localToVworld.length]; + + // update targets + if (! inSharedGroup) { + if (s.transformTargets[0] != null) { + ct = ti.getCachedTargets( + TargetsInterface.TRANSFORM_TARGETS, 0, -1); + if (ct != null) { + newCtArr[0] = s.transformTargets[0].snapShotAdd(ct); + } + } else { + newCtArr[0] = null; + } + } else { + for (int i=0; i= 0) { + newTargets[i] = new Targets(); + } else { + newTargets[i] = null; + } + } + s.switchTargets = newTargets; + } + + if (isSetLive) { + // set switch states + if (nodeType == NodeRetained.SWITCH) { + i = parentSwitchLinkChildIndex; + s.childSwitchLinks = (ArrayList)childrenSwitchLinks.get(i); + s.parentSwitchLink = this; + + } else { + if (nodeType == NodeRetained.SHAREDGROUP) { + i = parentSwitchLinkChildIndex; + s.childSwitchLinks = (ArrayList)childrenSwitchLinks.get(i); + s.parentSwitchLink = this; + + } else { + s.parentSwitchLink = parentSwitchLink; + if (parentSwitchLink != null) { + i = parentSwitchLinkChildIndex; + s.childSwitchLinks = (ArrayList) + parentSwitchLink.childrenSwitchLinks.get(i); + } + } + } + if (ti != null) { + s.switchStates = ti.getTargetsData( + TargetsInterface.SWITCH_TARGETS, + parentSwitchLinkChildIndex); + } else { + s.switchStates = new ArrayList(1); + s.switchStates.add(new SwitchState(false)); + } + } + return ti; + } + + void updateSwitchStates(SetLiveState s, TargetsInterface ti, + boolean isSetLive) { + + // update switch leaves's compositeSwitchMask for ancestors + // and update switch leaves' switchOn flag if at top level switch + + if (ti != null) { + if (isSetLive) { + CachedTargets[] newCtArr = null; + CachedTargets ct; + + newCtArr = new CachedTargets[localToVworld.length]; + + // update targets + if (! inSharedGroup) { + + if (s.switchTargets[0] != null) { + ct = ti.getCachedTargets( + TargetsInterface.SWITCH_TARGETS, 0, + parentSwitchLinkChildIndex); + if (ct != null) { + newCtArr[0] = s.switchTargets[0].snapShotAdd(ct); + } else { + newCtArr[0] = s.switchTargets[0].snapShotInit(); + } + } else { + newCtArr[0] = null; + } + } else { + for (int i=0; i=0; i--) { + child = (NodeRetained)children.get(i); + if(child != null) + child.updateLocalToVworld(); + } + } + + void setNodeData(SetLiveState s) { + super.setNodeData(s); + orderedPaths = s.orderedPaths; + } + + void removeNodeData(SetLiveState s) { + + if((!inSharedGroup) || (s.keys.length == localToVworld.length)) { + orderedPaths = null; + } + else { + // Set it back to its parent localToVworld data. This is b/c the + // parent has changed it localToVworld data arrays. + orderedPaths = s.orderedPaths; + } + super.removeNodeData(s); + } + + + + void setLive(SetLiveState s) { + doSetLive(s); + super.markAsLive(); + } + + // Note that SwitchRetained, OrderedGroupRetained and SharedGroupRetained + // override this method + void childDoSetLive(NodeRetained child, int childIndex, SetLiveState s) { + if(child!=null) + child.setLive(s); + } + + // Note that BranchRetained, OrderedGroupRetained and SharedGroupRetained + // TransformGroupRetained override this method + void childCheckSetLive(NodeRetained child, int childIndex, + SetLiveState s, NodeRetained linkNode) { + child.setLive(s); + } + + /** + * This version of setLive calls setLive on all of its chidren. + */ + void doSetLive(SetLiveState s) { + int i, nchildren; + NodeRetained child; + super.doSetLive(s); + locale = s.locale; + + inViewSpecificGroup = s.inViewSpecificGroup; + nchildren = children.size(); + ArrayList savedScopedLights = s.lights; + ArrayList savedScopedFogs = s.fogs; + ArrayList savedScopedAltApps = s.altAppearances; + ArrayList savedScopedMclips = s.modelClips; + + boolean oldpickableArray[] = (boolean []) s.pickable.clone(); + boolean oldcollidableArray[] = (boolean []) s.collidable.clone(); + boolean workingpickableArray[] = new boolean[oldpickableArray.length]; + boolean workingcollidableArray[] = new boolean[oldcollidableArray.length]; + ArrayList oldBranchGroupPaths = s.branchGroupPaths; + setScopingInfo(s); + + + if (!(this instanceof ViewSpecificGroupRetained)) { + viewLists = s.viewLists; + } + + for (i=0; i=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + if(child != null) + child.computeCombineBounds(bounds); + } + } else { + // Should this be lock too ? ( MT safe ? ) + synchronized(localBounds) { + bounds.combine(localBounds); + } + } + } else { + // Issue 514 : NPE in Wonderland : triggered in cached bounds computation + if (validCachedBounds && boundsAutoCompute) { + bounds.combine(cachedBounds); + return; + } + + if (boundsAutoCompute) { + // issue 544 + if (VirtualUniverse.mc.useBoxForGroupBounds) { + cachedBounds = new BoundingBox((Bounds) null); + } else { + cachedBounds = new BoundingSphere(); + ((BoundingSphere) cachedBounds).setRadius(-1); + } + for (int i = children.size() - 1; i >= 0; i--) { + NodeRetained child = (NodeRetained) children.get(i); + if (child != null) { + child.computeCombineBounds(cachedBounds); + } + } + bounds.combine(cachedBounds); + } else { + // Should this be lock too ? ( MT safe ? ) + synchronized(localBounds) { + bounds.combine(localBounds); + } + } + } + + } + + + /** + * Gets the bounding object of a node. + * @return the node's bounding object + */ + Bounds getBounds() { + + if ( boundsAutoCompute) { + // Issue 514 : NPE in Wonderland : triggered in cached bounds computation + if (validCachedBounds) { + return (Bounds) cachedBounds.clone(); + } + // issue 544 + Bounds boundingObject = null; + if (VirtualUniverse.mc.useBoxForGroupBounds) { + boundingObject = new BoundingBox((Bounds) null); + } else { + boundingObject = new BoundingSphere(); + ((BoundingSphere) boundingObject).setRadius(-1.0); + } + for (int i = children.size() - 1; i >= 0; i--) { + NodeRetained child = (NodeRetained) children.get(i); + if (child != null) { + child.computeCombineBounds((Bounds) boundingObject); + } + } + + return (Bounds) boundingObject; + } + return super.getBounds(); + } + + /** + * Gets the bounding object of a node. + * @return the node's bounding object + */ + Bounds getEffectiveBounds() { + if ( boundsAutoCompute) { + return getBounds(); + } + return super.getEffectiveBounds(); + } + + // returns true if children cannot be read/written and none of the + // children can read their parent (i.e., "this") group node + boolean isStaticChildren() { + if (source.getCapability(Group.ALLOW_CHILDREN_READ) || + source.getCapability(Group.ALLOW_CHILDREN_WRITE)) { + return false; + } + + for (int i = children.size() - 1; i >= 0; i--) { + SceneGraphObjectRetained nodeR = + (SceneGraphObjectRetained) children.get(i); + if (nodeR != null && nodeR.source.getCapability(Node.ALLOW_PARENT_READ)) { + return false; + } + } + + return true; + } + + + boolean isStatic() { + return (super.isStatic() && isStaticChildren()); + } + + /** + * This compiles() a group + */ + void setCompiled() { + super.setCompiled(); + for (int i=children.size()-1; i>=0; i--) { + SceneGraphObjectRetained node = + (SceneGraphObjectRetained) children.get(i); + if (node != null) + node.setCompiled(); + } + } + + void traverse(boolean sameLevel, int level) { + SceneGraphObjectRetained node; + + if (!sameLevel) { + super.traverse(true, level); + + if (source.getCapability(Group.ALLOW_CHILDREN_READ)) { + System.err.print(" (r)"); + } else if (isStatic()) { + System.err.print(" (s)"); + } else if (source.getCapability(Group.ALLOW_CHILDREN_WRITE)) { + System.err.print(" (w)"); + } + } + + level++; + for (int i = 0; i < children.size(); i++) { + node = (SceneGraphObjectRetained) children.get(i); + if (node != null) { + node.traverse(false, level); + } + } + } + + void compile(CompileState compState) { + + SceneGraphObjectRetained node; + + super.compile(compState); + + mergeFlag = SceneGraphObjectRetained.MERGE; + + if (!isStatic()) { + compState.keepTG = true; + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + } + + if (isRoot || this.usedInScoping() || + (parent instanceof SwitchRetained)) { + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + } + + compiledChildrenList = new ArrayList(5); + + for (int i = 0; i < children.size(); i++) { + node = (SceneGraphObjectRetained) children.get(i); + if (node != null) { + node.compile(compState); + } + } + + if (J3dDebug.devPhase && J3dDebug.debug) { + compState.numGroups++; + } + } + + void merge(CompileState compState) { + + GroupRetained saveParentGroup = null; + SceneGraphObjectRetained node; + + if (mergeFlag != SceneGraphObjectRetained.MERGE_DONE) { + if (mergeFlag == SceneGraphObjectRetained.DONT_MERGE) { + + // don't merge/eliminate this node + super.merge(compState); + + saveParentGroup = compState.parentGroup; + compState.parentGroup = this; + } + + for (int i = 0; i < children.size(); i++) { + node = (SceneGraphObjectRetained) children.get(i); + if (node != null) { + node.merge(compState); + } + } + + if (compState.parentGroup == this) { + this.children = compiledChildrenList; + compState.doShapeMerge(); + compiledChildrenList = null; + compState.parentGroup = saveParentGroup; + } else { + // this group node can be eliminated + this.children.clear(); + + if (J3dDebug.devPhase && J3dDebug.debug) { + compState.numMergedGroups++; + } + } + + mergeFlag = SceneGraphObjectRetained.MERGE_DONE; + + } else { + if (compState.parentGroup != null) { + compState.parentGroup.compiledChildrenList.add(this); + parent = compState.parentGroup; + } + } + } + + /** + * This version of clearLive calls clearLive on all of its chidren. + */ + void clearLive(SetLiveState s) { + int i, k, hkIndex, nchildren; + NodeRetained child; + int parentScopedLtSize = 0; + int parentScopedFogSize = 0; + int parentScopedMcSize = 0; + int parentScopedAltAppSize = 0; + int groupScopedLtSize = 0; + int groupScopedFogSize = 0; + int groupScopedMcSize = 0; + int groupScopedAltAppSize = 0; + int size; + + isInClearLive = true; + + // Save this for later use in this method. Temporary. to be removed when OG cleanup. + HashKey[] savedLocalToVworldKeys = localToVworldKeys; + + super.clearLive(s); + + + nchildren = this.children.size(); + + if (!(this instanceof ViewSpecificGroupRetained)) { + viewLists = s.viewLists; + } + + ArrayList savedParentLights = s.lights; + if (allocatedLights) { + s.lights = lights; + } + + ArrayList savedParentFogs = s.fogs; + if (allocatedFogs) { + s.fogs = fogs; + } + + ArrayList savedParentMclips = s.modelClips; + if (allocatedMclips) { + s.modelClips = modelClips; + } + + + ArrayList savedParentAltApps = s.altAppearances; + if (allocatedAltApps) { + s.altAppearances = altAppearances; + } + + + for (i=nchildren-1; i >=0 ; i--) { + child = (NodeRetained)children.get(i); + if (this instanceof OrderedGroupRetained) { + OrderedGroupRetained og = (OrderedGroupRetained)this; + + // adjust refCount, which has been decremented + //in super.clearLive + if ((refCount+1) == s.refCount) { + //only need to do it once if in shared group. Add + //all the children to the list of OG_REMOVED message + s.ogList.add(this); + s.ogChildIdList.add(new Integer(i)); + } + s.orderedPaths = (ArrayList)og.childrenOrderedPaths.get(i); + } + + if (child != null) { + child.clearLive(s); + } + } + // Has its own copy + // XXXX: Handle the case of + // was non-zero, gone to zero? + if (savedParentLights != null) { + if (allocatedLights) { + if (inSharedGroup) { + + for (i=0; i < s.keys.length; i++) { + hkIndex = s.keys[i].equals(localToVworldKeys, 0, + localToVworldKeys.length); + ArrayList l = (ArrayList)savedParentLights.get(hkIndex); + ArrayList gl = (ArrayList)lights.get(hkIndex); + if (l != null) { + size = l.size(); + for (k = 0; k < size; k++) { + gl.remove(l.get(k)); + } + } + + } + } + else { + ArrayList l = (ArrayList)savedParentLights.get(0); + ArrayList gl = (ArrayList)lights.get(0); + size = l.size(); + for (int m = 0; m < size; m++) { + gl.remove(l.get(m)); + } + } + } + } + + if (savedParentFogs != null) { + if (allocatedFogs) { + if (inSharedGroup) { + for (i=0; i < s.keys.length; i++) { + hkIndex = s.keys[i].equals(localToVworldKeys, 0, + localToVworldKeys.length); + ArrayList l = (ArrayList)savedParentFogs.get(hkIndex); + ArrayList gl = (ArrayList)fogs.get(hkIndex); + if (l != null) { + size = l.size(); + for (k = 0; k < size; k++) { + gl.remove(l.get(k)); + } + } + + } + } + else { + ArrayList l = (ArrayList)savedParentFogs.get(0); + size = l.size(); + for (int m = 0; m < size; m++) { + fogs.remove(l.get(m)); + } + } + } + } + + if (savedParentMclips != null) { + if (allocatedMclips) { + if (inSharedGroup) { + for (i=0; i < s.keys.length; i++) { + hkIndex = s.keys[i].equals(localToVworldKeys, 0, + localToVworldKeys.length); + ArrayList l = (ArrayList)savedParentMclips.get(hkIndex); + ArrayList gl = (ArrayList)modelClips.get(hkIndex); + if (l != null) { + size = l.size(); + for (k = 0; k < size; k++) { + gl.remove(l.get(k)); + } + } + + } + } + else { + ArrayList l = (ArrayList)savedParentMclips.get(0); + size = l.size(); + for (int m = 0; m < size; m++) { + modelClips.remove(l.get(m)); + } + } + } + } + + if (savedParentAltApps != null) { + if (allocatedAltApps) { + if (inSharedGroup) { + for (i=0; i < s.keys.length; i++) { + hkIndex = s.keys[i].equals(localToVworldKeys, 0, + localToVworldKeys.length); + ArrayList l = (ArrayList)savedParentAltApps.get(hkIndex); + ArrayList gl = (ArrayList)altAppearances.get(hkIndex); + if (l != null) { + size = l.size(); + for (k = 0; k < size; k++) { + gl.remove(l.get(k)); + } + } + + } + } + else { + ArrayList l = (ArrayList)savedParentAltApps.get(0); + size = l.size(); + for (int m = 0; m < size; m++) { + altAppearances.remove(l.get(m)); + } + } + } + } + + if (collisionTarget) { + GroupRetained g; + if (inSharedGroup) { + for (i=s.keys.length-1; i >=0; i--) { + HashKey hkey = s.keys[i]; + for (int j = mirrorGroup.size()-1; j >=0 ; j--) { + g = (GroupRetained) mirrorGroup.get(j); + if (g.key.equals(hkey)) { + s.nodeList.add(mirrorGroup.remove(j)); + if (s.transformTargets != null && + s.transformTargets[j] != null) { + s.transformTargets[j].addNode(g, Targets.GRP_TARGETS); + } + break; + } + + } + } + } else { + g = (GroupRetained)mirrorGroup.get(0); + if (s.transformTargets != null && + s.transformTargets[0] != null) { + s.transformTargets[0].addNode(g, Targets.GRP_TARGETS); + } + s.nodeList.add(mirrorGroup.remove(0)); + } + } + s.lights = savedParentLights; + s.modelClips = savedParentMclips; + s.fogs = savedParentFogs; + s.altAppearances = savedParentAltApps; + isInClearLive = false; + } + + // This is only used by alternateCollisionTarget + public BoundingBox computeBoundingHull() { + return collisionVwcBounds; + } + + // If isSwitchOn cached here, we don't need to traverse up the tree + public boolean isEnable() { + return isNodeSwitchOn(this.sourceNode, key); + } + + // If isSwitchOn cached here, we don't need to traverse up the tree + // This method does nothing with vis. + public boolean isEnable(int vis) { + return isNodeSwitchOn(this.sourceNode, key); + } + + // Can't use getLocale, it is used by BranchGroupRetained + public Locale getLocale2() { + return locale; + } + + /** + * Return true of nodeR is not under a switch group or + * nodeR is enable under a switch group. + */ + static boolean isNodeSwitchOn(NodeRetained node, HashKey key) { + NodeRetained prevNode = null; + if (key != null) { + key = new HashKey(key); + } + + synchronized (node.universe.sceneGraphLock) { + do { + if ((node instanceof SwitchRetained) && + (prevNode != null) && + !validSwitchChild((SwitchRetained) node, prevNode)) { + return false; + } + prevNode = node; + if (node instanceof SharedGroupRetained) { + // retrieve the last node ID + String nodeId = key.getLastNodeId(); + Vector parents = ((SharedGroupRetained) node).parents; + // find the matching link + for(int i=parents.size()-1; i >=0; i--) { + NodeRetained link = (NodeRetained) parents.get(i); + if (link.nodeId.equals(nodeId)) { + node = link; + break; + } + } + if (node == prevNode) { + // Fail to found a matching link, this is + // probably cause by BHTree not yet updated + // because message not yet arrive + // when collision so it return current node as target. + return false; + } + } else { + node = node.parent; + } + } while (node != null); + // reach locale + } + return true; + } + + + + /** + * Determinte if nodeR is a valid child to render for + * Switch Node swR. + */ + static boolean validSwitchChild(SwitchRetained sw, + NodeRetained node) { + + int whichChild = sw.whichChild; + + if (whichChild == Switch.CHILD_NONE) { + return false; + } + + if (whichChild == Switch.CHILD_ALL) { + return true; + } + + ArrayList children = sw.children; + + if (whichChild >= 0) { // most common case + return (children.get(whichChild) == node); + } + + // Switch.CHILD_MASK + for (int i=children.size()-1; i >=0; i--) { + if (sw.childMask.get(i) && + (children.get(i) == node)) { + return true; + } + } + return false; + } + + + /** + * Create mirror group when this Group AlternateCollisionTarget + * is set to true while live. + */ + void createMirrorGroup() { + GroupRetained g; + + mirrorGroup = new ArrayList(); + + Bounds bound = (collisionBound != null ? + collisionBound : getEffectiveBounds()); + + if (inSharedGroup) { + for (int i=0; i < localToVworldKeys.length; i++) { + g = new GroupRetained(); + g.key = localToVworldKeys[i]; + g.localToVworld = new Transform3D[1][]; + g.localToVworldIndex = new int[1][]; + g.localToVworld[0] = localToVworld[i]; + g.localToVworldIndex[0] = localToVworldIndex[i]; + g.collisionVwcBounds = new BoundingBox(); + g.collisionVwcBounds.transform(bound, g.getCurrentLocalToVworld()); + g.sourceNode = this; + g.locale = locale; // need by getVisibleGeometryAtom() + mirrorGroup.add(g); + } + } else { + g = new GroupRetained(); + g.localToVworld = new Transform3D[1][]; + g.localToVworldIndex = new int[1][]; + g.localToVworld[0] = localToVworld[0]; + g.localToVworldIndex[0] = localToVworldIndex[0]; + g.collisionVwcBounds = new BoundingBox(); + g.collisionVwcBounds.transform(bound, g.getCurrentLocalToVworld()); + g.sourceNode = this; + g.locale = locale; // need by getVisibleGeometryAtom() + mirrorGroup.add(g); + } + } + + void setBoundsAutoCompute(boolean autoCompute) { + if (autoCompute != boundsAutoCompute) { + super.setBoundsAutoCompute(autoCompute); + if (!autoCompute) { + localBounds = getEffectiveBounds(); + } + if (source.isLive() && collisionBound == null && autoCompute + && mirrorGroup != null) { + + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.COLLISION_BOUND_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM | + J3dThread.UPDATE_GEOMETRY; + message.universe = universe; + message.args[0] = this; + VirtualUniverse.mc.processMessage(message); + } + } + } + + void setBounds(Bounds bounds) { + super.setBounds(bounds); + if (source.isLive() && !boundsAutoCompute && + collisionBound == null && mirrorGroup != null) { + + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.COLLISION_BOUND_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM | + J3dThread.UPDATE_GEOMETRY; + message.universe = universe; + message.args[0] = this; + VirtualUniverse.mc.processMessage(message); + } + } + + + int[] processViewSpecificInfo(int mode, HashKey k, View v, ArrayList vsgList, int[] keyList, + ArrayList leafList) { + int nchildren = children.size(); + if (source.isLive()) { + for (int i = 0; i < nchildren; i++) { + NodeRetained child = (NodeRetained) children.get(i); + if (child instanceof LeafRetained) { + if (child instanceof LinkRetained) { + int lastCount = k.count; + LinkRetained ln = (LinkRetained) child; + if (k.count == 0) { + k.append(locale.nodeId); + } + keyList = ((GroupRetained)(ln.sharedGroup)). + processViewSpecificInfo(mode, k.append("+").append(ln.nodeId), v, vsgList, + keyList, leafList); + k.count = lastCount; + } + else { + ((LeafRetained)child).getMirrorObjects(leafList, k); + } + } else { + keyList = child.processViewSpecificInfo(mode, k, v, vsgList, keyList, leafList); + } + } + } + return keyList; + } + + void findSwitchInfo(SetLiveState s, NodeRetained parentNode, + NodeRetained childNode, NodeRetained linkNode) { + + NodeRetained child; + NodeRetained parent; + + parentSwitchLinkChildIndex = -1; + + // traverse up scene graph to find switch parent information + if (!inSharedGroup) { + child = (linkNode == null)? childNode: linkNode; + parent = parentNode; + while (parent != null) { + if (parent instanceof SwitchRetained) { + s.switchLevels[0]++; + if (s.closestSwitchParents[0] == null) { + s.closestSwitchParents[0] = (SwitchRetained)parent; + s.closestSwitchIndices[0] = + ((SwitchRetained)parent).switchIndexCount++; + } + if (parentSwitchLinkChildIndex == -1) { + parentSwitchLinkChildIndex = + ((GroupRetained)parent).children.indexOf(child); + } + } else if (parent instanceof SharedGroupRetained) { + if (parentSwitchLinkChildIndex == -1) { + parentSwitchLinkChildIndex = + ((GroupRetained)parent).children.indexOf(child); + } + } + child = parent; + parent = child.parent; + } + } else { + HashKey key; + int i,j; + + s.switchLevels = new int[localToVworldKeys.length]; + s.closestSwitchParents = + new SwitchRetained[localToVworldKeys.length]; + s.closestSwitchIndices = new int[localToVworldKeys.length]; + for (i=0; i=0; i--) { + NodeRetained child = (NodeRetained)children.get(i); + child.searchGeometryAtoms(list); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/HashKey.java b/j3d-core/src/classes/share/javax/media/j3d/HashKey.java new file mode 100644 index 0000000..8a86d5f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/HashKey.java @@ -0,0 +1,259 @@ +/* + * $RCSfile: HashKey.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class HashKey extends Object { + + /** + * The value is used for character storage. + */ + char value[]; + + /** + * The count is the number of characters in the buffer. + */ + int count = 0; + + HashKey() { + this(16); + } + + HashKey(int length) { + value = new char[length]; + } + + HashKey(HashKey hashkey) { + this.set(hashkey); + } + + HashKey(String str) { + this(str.length() + 16); + append(str); + } + + void set(HashKey hashkey) { + int i; + + if (this.count < hashkey.count) { + this.value = new char[hashkey.count]; + } + + for (i=0; i maxCapacity) { + int newCapacity = (maxCapacity + 1) * 2; + if (minimumCapacity > newCapacity) { + newCapacity = minimumCapacity; + } + + char newValue[] = new char[newCapacity]; + System.arraycopy(value, 0, newValue, 0, count); + value = newValue; + } + } + + HashKey append(String str) { + int len = 0; + + if (str == null) + return this; + + len = str.length(); + ensureCapacity(count + len); + str.getChars(0, len, value, count); + count += len; + return this; + } + + public int hashCode() { + int h = 0; + int off = 0; + char val[] = value; + int len = count; + + if (len < 16) { + for (int i = len ; i > 0; i--) { + h = (h * 37) + val[off++]; + } + } else { + // only sample some characters + int skip = len / 8; + for (int i = len ; i > 0; i -= skip, off += skip) { + h = (h * 39) + val[off]; + } + } + return h; + } + + public boolean equals(Object anObject) { + if ((anObject != null) && (anObject instanceof HashKey)) { + HashKey anotherHashKey = (HashKey)anObject; + int n = count; + if (n == anotherHashKey.count) { + char v1[] = value; + char v2[] = anotherHashKey.value;; + int i = 0; + int j = 0; + while (n-- != 0) { + if (v1[i++] != v2[j++]) { + return false; + } + } + return true; + } + } + return false; + } + + + /* For internal use only. */ + private int equals(HashKey hk) { + int index = 0; + + while((index < count) && (index < hk.count)) { + if(value[index] < hk.value[index]) + return -1; + else if(value[index] > hk.value[index]) + return 1; + index++; + } + + if(count == hk.count) + // Found it! + return 0; + else if(count < hk.count) + return -1; + else + return 1; + + } + + + /* For package use only. */ + int equals(HashKey localToVworldKeys[], int start, int end) { + int mid; + + mid = start +((end - start)/ 2); + if(localToVworldKeys[mid] != null) { + int test = equals(localToVworldKeys[mid]); + + if((test < 0) && (start != mid)) + return equals(localToVworldKeys, start, mid); + else if((test > 0) && (start != mid)) + return equals(localToVworldKeys, mid, end); + else if(test == 0) + return mid; + else + return -1; + } + // A null haskey encountered. + return -2; + } + + /* For package use only. */ + boolean equals(HashKey localToVworldKeys[], int[] index, + int start, int end) { + + int mid; + + mid = start +((end - start)/ 2); + if(localToVworldKeys[mid] != null) { + int test = equals(localToVworldKeys[mid]); + + if(start != mid) { + if(test < 0) { + return equals(localToVworldKeys, index, start, mid); + } + else if(test > 0) { + return equals(localToVworldKeys, index, mid, end); + } + } + else { // (start == mid) + if(test < 0) { + index[0] = mid; + return false; + } + else if(test > 0) { + index[0] = mid+1; + return false; + } + } + + // (test == 0) + index[0] = mid; + return true; + + } + // A null haskey encountered. + // But we still want to return the index where we encounter it. + index[0] = mid; + return false; + } + + public String toString() { + return new String(value, 0, count); + } + + String getLastNodeId() { + int i, j, temp; + + for(i=(count-1); i>0; i--) + if(value[i] == '+') + break; + + if(i>0) { + value[i++] = '\0'; + temp = count-i; + char v1[] = new char[temp]; + for(j=0; j + * The HiResCoord defines a point using a set of three + * high-resolution coordinates, each of which consists of three + * two's-complement fixed-point numbers. + * Each high-resolution number consists of 256 total bits with a + * binary point at bit 128, or between the integers at index +* 3 and 4. A high-resolution coordinate of 1.0 is defined to be exactly + * 1 meter. This coordinate system is sufficient to describe a + * universe in excess of several billion light years across, yet + * still define objects smaller than a proton. + *

+ * Java 3D uses integer arrays of length + * eight to define or extract a single 256-bit coordinate value. + * Java 3D interprets the integer at index 0 as the 32 + * most-significant bits and the integer at index 7 as the 32 + * least-significant bits. + */ + +public class HiResCoord { + /** + * The eight-element array containing the high resolution coordinate's + * x value. + */ + int x[]; + + /** + * The eight-element array containing the high resolution coordinate's + * y value. + */ + int y[]; + + /** + * The eight-element array containing the high resolution coordinate's + * z value. + */ + int z[]; + +private double scales[] = { + 79228162514264337593543950336.0, // 2^96 + 18446744073709551616.0, // 2^64 + 4294967296.0, // 2^32 + 1.0, // 2^0 + 2.3283064365386962890625e-10, // 2^-32 + 5.421010862427522170037264004349708557128906250000000000000000e-20, // 2^-64 + 1.26217744835361888865876570445245796747713029617443680763244628906250e-29, // 2^-96 + 2.938735877055718769921841343055614194546663891930218803771879265696043148636817932128906250e-39 }; + + + + /** + * Constructs and initializes a new HiResCoord using the values + * provided in the argument. + * The HiResCoord represents 768 bits of floating point 3-Space. + * @param X an eight element array specifying the x position + * @param Y an eight element array specifying the y position + * @param Z an eight element array specifying the z position + */ + public HiResCoord(int[] X, int[] Y, int[] Z) { + int i; + + this.x = new int[8]; + this.y = new int[8]; + this.z = new int[8]; + + for(i=0;i<8;i++) { + this.x[i] = X[i]; + this.y[i] = Y[i]; + this.z[i] = Z[i]; + } + + } + + /** + * Constructs and initializes a new HiResCoord using the values + * provided in the argument. + * The HiResCoord represents 768 bits of floating point 3-Space. + * @param hc the HiResCoord to copy + */ + public HiResCoord(HiResCoord hc) { + this.x = new int[8]; + this.y = new int[8]; + this.z = new int[8]; + + this.x[0] = hc.x[0]; + this.y[0] = hc.y[0]; + this.z[0] = hc.z[0]; + + this.x[1] = hc.x[1]; + this.y[1] = hc.y[1]; + this.z[1] = hc.z[1]; + + this.x[2] = hc.x[2]; + this.y[2] = hc.y[2]; + this.z[2] = hc.z[2]; + + this.x[3] = hc.x[3]; + this.y[3] = hc.y[3]; + this.z[3] = hc.z[3]; + + this.x[4] = hc.x[4]; + this.y[4] = hc.y[4]; + this.z[4] = hc.z[4]; + + this.x[5] = hc.x[5]; + this.y[5] = hc.y[5]; + this.z[5] = hc.z[5]; + + this.x[6] = hc.x[6]; + this.y[6] = hc.y[6]; + this.z[6] = hc.z[6]; + + this.x[7] = hc.x[7]; + this.y[7] = hc.y[7]; + this.z[7] = hc.z[7]; + } + + /** + * Constructs and initializes a new HiResCoord located at (0, 0, 0). + * The HiResCoord represents 768 bits of floating point 3-Space. + */ + public HiResCoord() { + this.x = new int[8]; + this.y = new int[8]; + this.z = new int[8]; + } + + /** + * Sets this HiResCoord to the location specified by the + * parameters provided. + * @param X an eight-element array specifying the x position + * @param Y an eight-element array specifying the y position + * @param Z an eight-element array specifying the z position + */ + public void setHiResCoord(int[] X, int[] Y, int[] Z) { + int i; + + for(i=0;i<8;i++) { + this.x[i] = X[i]; + this.y[i] = Y[i]; + this.z[i] = Z[i]; + } + + } + + /** + * Sets this HiResCoord to the location specified by the + * hires provided. + * @param hires the hires coordinate to copy + */ + public void setHiResCoord(HiResCoord hires) { + this.x[0] = hires.x[0]; + this.y[0] = hires.y[0]; + this.z[0] = hires.z[0]; + + this.x[1] = hires.x[1]; + this.y[1] = hires.y[1]; + this.z[1] = hires.z[1]; + + this.x[2] = hires.x[2]; + this.y[2] = hires.y[2]; + this.z[2] = hires.z[2]; + + this.x[3] = hires.x[3]; + this.y[3] = hires.y[3]; + this.z[3] = hires.z[3]; + + this.x[4] = hires.x[4]; + this.y[4] = hires.y[4]; + this.z[4] = hires.z[4]; + + this.x[5] = hires.x[5]; + this.y[5] = hires.y[5]; + this.z[5] = hires.z[5]; + + this.x[6] = hires.x[6]; + this.y[6] = hires.y[6]; + this.z[6] = hires.z[6]; + + this.x[7] = hires.x[7]; + this.y[7] = hires.y[7]; + this.z[7] = hires.z[7]; + } + + + /** + * Sets this HiResCoord's X value to that specified by the argument. + * @param X an eight-element array specifying the x position + */ + public void setHiResCoordX(int[] X) { + this.x[0] = X[0]; + this.x[1] = X[1]; + this.x[2] = X[2]; + this.x[3] = X[3]; + this.x[4] = X[4]; + this.x[5] = X[5]; + this.x[6] = X[6]; + this.x[7] = X[7]; + } + + /** + * Sets this HiResCoord's Y value to that specified by the argument. + * @param Y an eight-element array specifying the y position + */ + public void setHiResCoordY(int[] Y) { + this.y[0] = Y[0]; + this.y[1] = Y[1]; + this.y[2] = Y[2]; + this.y[3] = Y[3]; + this.y[4] = Y[4]; + this.y[5] = Y[5]; + this.y[6] = Y[6]; + this.y[7] = Y[7]; + } + + /** + * Sets this HiResCoord's Z value to that specified by the argument. + * @param Z an eight-element array specifying the z position + */ + public void setHiResCoordZ(int[] Z) { + this.z[0] = Z[0]; + this.z[1] = Z[1]; + this.z[2] = Z[2]; + this.z[3] = Z[3]; + this.z[4] = Z[4]; + this.z[5] = Z[5]; + this.z[6] = Z[6]; + this.z[7] = Z[7]; + } + + /** + * Retrieves this HiResCoord's location and saves the coordinates + * in the specified arrays. The arrays must be large enough + * to hold all of the ints. + * @param X an eight element array that will receive the x position + * @param Y an eight element array that will receive the y position + * @param Z an eight element array that will receive the z position + */ + public void getHiResCoord(int[] X, int[] Y, int[] Z) { + X[0] = this.x[0]; + X[1] = this.x[1]; + X[2] = this.x[2]; + X[3] = this.x[3]; + X[4] = this.x[4]; + X[5] = this.x[5]; + X[6] = this.x[6]; + X[7] = this.x[7]; + + Y[0] = this.y[0]; + Y[1] = this.y[1]; + Y[2] = this.y[2]; + Y[3] = this.y[3]; + Y[4] = this.y[4]; + Y[5] = this.y[5]; + Y[6] = this.y[6]; + Y[7] = this.y[7]; + + Z[0] = this.z[0]; + Z[1] = this.z[1]; + Z[2] = this.z[2]; + Z[3] = this.z[3]; + Z[4] = this.z[4]; + Z[5] = this.z[5]; + Z[6] = this.z[6]; + Z[7] = this.z[7]; + } + + /** + * Retrieves this HiResCoord's location and places it into the hires + * argument. + * @param hc the hires coordinate that will receive this node's location + */ + public void getHiResCoord(HiResCoord hc) { + hc.x[0] = this.x[0]; + hc.x[1] = this.x[1]; + hc.x[2] = this.x[2]; + hc.x[3] = this.x[3]; + hc.x[4] = this.x[4]; + hc.x[5] = this.x[5]; + hc.x[6] = this.x[6]; + hc.x[7] = this.x[7]; + + hc.y[0] = this.y[0]; + hc.y[1] = this.y[1]; + hc.y[2] = this.y[2]; + hc.y[3] = this.y[3]; + hc.y[4] = this.y[4]; + hc.y[5] = this.y[5]; + hc.y[6] = this.y[6]; + hc.y[7] = this.y[7]; + + hc.z[0] = this.z[0]; + hc.z[1] = this.z[1]; + hc.z[2] = this.z[2]; + hc.z[3] = this.z[3]; + hc.z[4] = this.z[4]; + hc.z[5] = this.z[5]; + hc.z[6] = this.z[6]; + hc.z[7] = this.z[7]; + } + + /** + * Retrieves this HiResCoord's X value and stores it in the specified + * array. The array must be large enough to hold all of the ints. + * @param X an eight-element array that will receive the x position + */ + public void getHiResCoordX(int[] X) { + X[0] = this.x[0]; + X[1] = this.x[1]; + X[2] = this.x[2]; + X[3] = this.x[3]; + X[4] = this.x[4]; + X[5] = this.x[5]; + X[6] = this.x[6]; + X[7] = this.x[7]; + } + + /** + * Retrieves this HiResCoord's Y value and stores it in the specified + * array. The array must be large enough to hold all of the ints. + * @param Y an eight-element array that will receive the y position + */ + public void getHiResCoordY(int[] Y) { + Y[0] = this.y[0]; + Y[1] = this.y[1]; + Y[2] = this.y[2]; + Y[3] = this.y[3]; + Y[4] = this.y[4]; + Y[5] = this.y[5]; + Y[6] = this.y[6]; + Y[7] = this.y[7]; + } + + /** + * Retrieves this HiResCoord's Z value and stores it in the specified + * array. The array must be large enough to hold all of the ints. + * @param Z an eight-element array that will receive the z position + */ + public void getHiResCoordZ(int[] Z) { + Z[0] = this.z[0]; + Z[1] = this.z[1]; + Z[2] = this.z[2]; + Z[3] = this.z[3]; + Z[4] = this.z[4]; + Z[5] = this.z[5]; + Z[6] = this.z[6]; + Z[7] = this.z[7]; + } + + /** + * Compares the specified HiResCoord to this HiResCoord. + * @param h1 the second HiResCoord + * @return true if equal, false if not equal + */ + public boolean equals(HiResCoord h1) { + try { + return ((this.x[0] == h1.x[0]) + && (this.x[1] == h1.x[1]) + && (this.x[2] == h1.x[2]) + && (this.x[3] == h1.x[3]) + && (this.x[4] == h1.x[4]) + && (this.x[5] == h1.x[5]) + && (this.x[6] == h1.x[6]) + && (this.x[7] == h1.x[7]) + && (this.y[0] == h1.y[0]) + && (this.y[1] == h1.y[1]) + && (this.y[2] == h1.y[2]) + && (this.y[3] == h1.y[3]) + && (this.y[4] == h1.y[4]) + && (this.y[5] == h1.y[5]) + && (this.y[6] == h1.y[6]) + && (this.y[7] == h1.y[7]) + && (this.z[0] == h1.z[0]) + && (this.z[1] == h1.z[1]) + && (this.z[2] == h1.z[2]) + && (this.z[3] == h1.z[3]) + && (this.z[4] == h1.z[4]) + && (this.z[5] == h1.z[5]) + && (this.z[6] == h1.z[6]) + && (this.z[7] == h1.z[7])); + } + catch (NullPointerException e2) {return false;} + + } + + /** + * Returns true if the Object o1 is of type HiResCoord and all of the + * data members of o1 are equal to the corresponding data members in + * this HiResCoord. + * @param o1 the second HiResCoord + * @return true if equal, false if not equal + */ + public boolean equals(Object o1) { + try { + HiResCoord h1 = (HiResCoord)o1; + return ((this.x[0] == h1.x[0]) + && (this.x[1] == h1.x[1]) + && (this.x[2] == h1.x[2]) + && (this.x[3] == h1.x[3]) + && (this.x[4] == h1.x[4]) + && (this.x[5] == h1.x[5]) + && (this.x[6] == h1.x[6]) + && (this.x[7] == h1.x[7]) + && (this.y[0] == h1.y[0]) + && (this.y[1] == h1.y[1]) + && (this.y[2] == h1.y[2]) + && (this.y[3] == h1.y[3]) + && (this.y[4] == h1.y[4]) + && (this.y[5] == h1.y[5]) + && (this.y[6] == h1.y[6]) + && (this.y[7] == h1.y[7]) + && (this.z[0] == h1.z[0]) + && (this.z[1] == h1.z[1]) + && (this.z[2] == h1.z[2]) + && (this.z[3] == h1.z[3]) + && (this.z[4] == h1.z[4]) + && (this.z[5] == h1.z[5]) + && (this.z[6] == h1.z[6]) + && (this.z[7] == h1.z[7])); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + + + } + /** + * Adds two HiResCoords placing the results into this HiResCoord. + * @param h1 the first HiResCoord + * @param h2 the second HiResCoord + */ + public void add(HiResCoord h1, HiResCoord h2) { + // needs to handle carry bits + // move to long, add, add in carry bit + + hiResAdd( this, h1, h2 ); + + } + + /** + * Subtracts two HiResCoords placing the results into this HiResCoord. + * @param h1 the first HiResCoord + * @param h2 the second HiResCoord + */ + public void sub(HiResCoord h1, HiResCoord h2) { + HiResCoord tmpHc = new HiResCoord(); + + // negate via two's complement then add + // + hiResNegate( tmpHc, h2); + hiResAdd( this, h1, tmpHc); + + } + + /** + * Negates the specified HiResCoords and places the + * results into this HiResCoord. + * @param h1 the source HiResCoord + */ + public void negate(HiResCoord h1) { + + hiResNegate( this, h1); + + } + + /** + * Negates this HiResCoord + */ + public void negate() { + + hiResNegate( this, this ); + + } + + /** + * Scales the specified HiResCoords by the specified value and + * places the results into this HiResCoord. + * @param scale the amount to scale the specified HiResCoord + * @param h1 the source HiResCoord + */ + public void scale(int scale, HiResCoord h1) { + hiResScale( h1.x, this.x, scale); + hiResScale( h1.y, this.y, scale); + hiResScale( h1.z, this.z, scale); + } + + /** + * Scales this HiResCoord by the specified value. + * @param scale the amount to scale the specified HiResCoord + */ + public void scale(int scale) { + hiResScale( this.x, this.x, scale); + hiResScale( this.y, this.y, scale); + hiResScale( this.z, this.z, scale); + return; + } + + /** + * Subtracts the specified HiResCoord from this HiResCoord + * placing the difference vector into the specified + * double-precision vector. + * @param h1 the HiResCoord to be subtracted from this + * @param v the vector that will receive the result + */ + public void difference(HiResCoord h1, Vector3d v) { + // negate coord via two compliment, add, convert result to double + // by scaling each bit set appropriately + + hiResDiff( this, h1, v); + return; + } + + /** + * The floating point distance between the specified + * HiResCoord and this HiResCoord. + * @param h1 the second HiResCoord + */ + public double distance(HiResCoord h1) { + Vector3d diff = new Vector3d(); + + hiResDiff( this, h1, diff); + + return( Math.sqrt( diff.x*diff.x + diff.y*diff.y + diff.z*diff.z)); + } + + private void hiResNegate( HiResCoord ho, HiResCoord hi) { + + negateCoord( ho.x, hi.x); + negateCoord( ho.y, hi.y); + negateCoord( ho.z, hi.z); + + return; + } + + private void negateCoord( int cout[], int cin[] ) { + int i; + + for(i=0;i<8;i++) { + cout[i] = ~cin[i]; // take compliment of each + } + + for(i=7;i>=0;i--) { // add one + if( cout[i] == 0xffffffff) { + cout[i] = 0; + } else { + cout[i] += 1; + break; + } + } + return; + } + + private void hiResAdd(HiResCoord ho, HiResCoord h1, HiResCoord h2 ){ + int i; + long tmp1, tmp2,carry; + long signMask = Integer.MAX_VALUE; + long signBit = 1; + signBit = signBit << 31; + long carryMask = 0x7fffffff; + carryMask = carryMask <<1; + carryMask += 1; + + + carry = 0; + for(i=7;i>0;i--) { + tmp1 = 0; + tmp1 = signMask & h1.x[i]; // mask off sign bit so will not get put in msb + if( h1.x[i] < 0 ) tmp1 |= signBit; // add sign bit back + + tmp2 = 0; + tmp2 = signMask & h2.x[i]; // mask off sign bit so will not get put in msb + if( h2.x[i] < 0 ) tmp2 |= signBit; // add sign bit back + + tmp2 = tmp2+tmp1 + carry; + carry = tmp2 >> 32; // get carry bits for next operation + ho.x[i] = (int)(tmp2 & carryMask); // mask off high bits + } + ho.x[0] = h1.x[0] + h2.x[0] + (int)carry; + + + carry = 0; + for(i=7;i>0;i--) { + tmp1 = 0; + tmp1 = signMask & h1.y[i]; // mask off sign bit so will not get put in msb + if( h1.y[i] < 0 ) tmp1 |= signBit; // add sign bit back + + tmp2 = 0; + tmp2 = signMask & h2.y[i]; // mask off sign bit so will not get put in msb + if( h2.y[i] < 0 ) tmp2 |= signBit; // add sign bit back + + tmp2 = tmp2+tmp1 + carry; + carry = tmp2 >> 32; // get carry bits for next operation + ho.y[i] = (int)(tmp2 & carryMask); // mask off high bits + } + ho.y[0] = h1.y[0] + h2.y[0] + (int)carry; + + carry = 0; + for(i=7;i>0;i--) { + tmp1 = 0; + tmp1 = signMask & h1.z[i]; // mask off sign bit so will not get put in msb + if( h1.z[i] < 0 ) tmp1 |= signBit; // add sign bit back + + tmp2 = 0; + tmp2 = signMask & h2.z[i]; // mask off sign bit so will not get put in msb + if( h2.z[i] < 0 ) tmp2 |= signBit; // add sign bit back + + tmp2 = tmp2+tmp1 + carry; + carry = tmp2 >> 32; // get carry bits for next operation + ho.z[i] = (int)(tmp2 & carryMask); // mask off high bits + } + ho.z[0] = h1.z[0] + h2.z[0] + (int)carry; + return; + } + + private void hiResScale( int tin[], int tout[], double scale) { + int i; + long tmp,carry; + int signMask = Integer.MAX_VALUE; + long carryMask = 0x7fffffff; + carryMask = carryMask <<1; + carryMask += 1; + long signBit = 1; + signBit = signBit << 31; + + carry = 0; + for(i=7;i>0;i--) { + tmp = 0; + tmp = (long)(signMask & tin[i]); // mask off sign bit + if( tin[i] < 0 ) tmp |= signBit; // add sign bit back + tmp = (long)(tmp*scale + carry); + carry = tmp >> 32; // get carry bits for next operation + tout[i] = (int)(tmp & carryMask); // mask off high bits + } + tout[0] = (int)(tin[0]*scale + carry); + return; + } + private void hiResDiff( HiResCoord h1, HiResCoord h2, Vector3d diff) { + int i; + HiResCoord diffHi = new HiResCoord(); + long value; + int coordSpace[] = new int[8]; + int[] tempCoord; + int signMask = Integer.MAX_VALUE; + long signBit = 1; + signBit = signBit << 31; + + // negate via two's complement then add + // + hiResNegate( diffHi, h2); + hiResAdd( diffHi, h1, diffHi); + + + if( diffHi.x[0] < 0 ) { + tempCoord = coordSpace; + negateCoord( tempCoord, diffHi.x ); + } else { + tempCoord = diffHi.x; + } + diff.x = 0; + for(i=7;i>0;i--) { + value = (long)(tempCoord[i] & signMask); + if( tempCoord[i] < 0) value |= signBit; + diff.x += (double)(scales[i]*value); + } + diff.x += scales[0]*tempCoord[0]; + if( diffHi.x[0] < 0 )diff.x = -diff.x; + + if( diffHi.y[0] < 0 ) { + tempCoord = coordSpace; + negateCoord( tempCoord, diffHi.y ); + } else { + tempCoord = diffHi.y; + } + diff.y = 0; + for(i=7;i>0;i--) { + value = (long)(tempCoord[i] & signMask); + if( tempCoord[i] < 0) value |= signBit; + diff.y += scales[i]*value; + } + diff.y += scales[0]*tempCoord[0]; + if( diffHi.y[0] < 0 )diff.y = -diff.y; + + if( diffHi.z[0] < 0 ) { + tempCoord = coordSpace; + negateCoord( tempCoord, diffHi.z ); + } else { + tempCoord = diffHi.z; + } + diff.z = 0; + for(i=7;i>0;i--) { + value = (long)(tempCoord[i] & signMask); + if( tempCoord[i] < 0) value |= signBit; + diff.z += scales[i]*value; + } + diff.z += scales[0]*tempCoord[0]; + if( diffHi.z[0] < 0 )diff.z = -diff.z; + return; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IllegalRenderingStateException.java b/j3d-core/src/classes/share/javax/media/j3d/IllegalRenderingStateException.java new file mode 100644 index 0000000..a874796 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IllegalRenderingStateException.java @@ -0,0 +1,54 @@ +/* + * $RCSfile: IllegalRenderingStateException.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates an illegal state for rendering. This is typically some sort of + * resource or graphics device error encountered during rendering. + */ +public class IllegalRenderingStateException extends IllegalStateException { + + /** + * Create the exception object with default values. + */ + public IllegalRenderingStateException(){ + } + + /** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public IllegalRenderingStateException(String str){ + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IllegalSceneGraphException.java b/j3d-core/src/classes/share/javax/media/j3d/IllegalSceneGraphException.java new file mode 100644 index 0000000..a295d58 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IllegalSceneGraphException.java @@ -0,0 +1,59 @@ +/* + * $RCSfile: IllegalSceneGraphException.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates an illegal Java 3D scene graph. + * For example, the following is illegal: + *

    + *
  • A ViewPlatform node under a ViewSpecificGroup
  • + *
+ * + * @since Java 3D 1.3 + */ + +public class IllegalSceneGraphException extends RuntimeException { + + /** + * Create the exception object with default values. + */ + public IllegalSceneGraphException() { + } + + /** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public IllegalSceneGraphException(String str) { + super(str); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IllegalSharingException.java b/j3d-core/src/classes/share/javax/media/j3d/IllegalSharingException.java new file mode 100644 index 0000000..29fe941 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IllegalSharingException.java @@ -0,0 +1,79 @@ +/* + * $RCSfile: IllegalSharingException.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates an illegal attempt to share a scene graph object. For example, + * the following are illegal: + *
    + *
  • referencing a shared subgraph in more than one virtual universe
  • + *
  • using the same node both in the scene graph and in an + * immediate mode graphics context
  • + *
  • including any of the following unsupported types of leaf node within a shared subgraph:
  • + *
      + *
    • AlternateAppearance
    • + *
    • Background
    • + *
    • Behavior
    • + *
    • BoundingLeaf
    • + *
    • Clip
    • + *
    • Fog
    • + *
    • ModelClip
    • + *
    • Soundscape
    • + *
    • ViewPlatform
    • + *
    + *
  • referencing a BranchGroup node in more than one of the following + * ways:
  • + *
      + *
    • attaching it to a (single) Locale
    • + *
    • adding it as a child of a Group Node within the scene graph
    • + *
    • referencing it from a (single) Background Leaf Node as + * background geometry
    • + *
    + *
+ */ +public class IllegalSharingException extends IllegalSceneGraphException { + + /** + * Create the exception object with default values. + */ + public IllegalSharingException() { + } + + /** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public IllegalSharingException(String str) { + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ImageComponent.java b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent.java new file mode 100644 index 0000000..eacc8c5 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent.java @@ -0,0 +1,439 @@ +/* + * $RCSfile: ImageComponent.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Abstract class that is used to define 2D or 3D ImageComponent + * classes used in a Java 3D scene graph. This is used for texture + * images, background images and raster components of Shape3D nodes. + * + *

+ * Image data may be passed to this ImageComponent object in + * one of two ways: by copying the image data into this object or by + * accessing the image data by reference. + * + *

+ *

    + *
  • + * By Copying: + * By default, the set and get image methods copy the image + * data into or out of this ImageComponent object. This is + * appropriate for many applications, since the application may reuse + * the RenderedImage object after copying it to the ImageComponent. + *
  • + *
  • By Reference: + * A new feature in Java 3D version 1.2 allows image data to + * be accessed by reference, directly from the RenderedImage object. + * To use this feature, you need to construct an ImageComponent object + * with the byReference flag set to true. + * In this mode, a reference to the input data is saved, but the data + * itself is not necessarily copied (although it may be, depending on + * the value of the yUp flag, the format of the + * ImageComponent, and the format of the RenderedImage). Image data + * referenced by an ImageComponent object can only be modified via + * the updateData method. + * Applications must exercise care not to violate this rule. If any + * referenced RenderedImage is modified outside the updateData method + * after it has been passed + * to an ImageComponent object, the results are undefined. + * Another restriction in by-reference mode is that if the specified + * RenderedImage is not an instance of BufferedImage, then + * this ImageComponent cannot be used for readRaster or + * off-screen rendering operations, since these operations modify + * the ImageComponent data. + *
  • + *
+ * + *

+ * An image component object also specifies whether the orientation of + * its image data is "y-up" or "y-down" (the default). Y-up mode + * causes images to be interpreted as having their origin at the lower + * left (rather than the default upper left) of a texture or raster + * image with successive scan lines moving up. This is more + * consistent with texture mapping data onto a surface, and maps + * directly into the the way textures are used in OpenGL and other 3D + * APIs. Setting the yUp flag to true in conjunction + * with setting the byReference flag to true makes it + * possible for Java 3D to avoid copying the texture map in some + * cases. + * + *

+ * Note that all color fields are treated as unsigned values, even though + * Java does not directly support unsigned variables. This means, for + * example, that an ImageComponent using a format of FORMAT_RGB5 can + * represent red, green, and blue values between 0 and 31, while an + * ImageComponent using a format of FORMAT_RGB8 can represent color + * values between 0 and 255. Even when byte values are used to create a + * RenderedImage with 8-bit color components, the resulting colors + * (bytes) are interpreted as if they were unsigned. + * Values greater than 127 can be assigned to a byte variable using a + * type cast. For example: + *

    byteVariable = (byte) intValue; // intValue can be > 127
+ * If intValue is greater than 127, then byteVariable will be negative. The + * correct value will be extracted when it is used (by masking off the upper + * bits). + */ + +public abstract class ImageComponent extends NodeComponent { + // + // Pixel format values + // + + /** + * Specifies that each pixel contains 3 8-bit channels: one each + * for red, green, blue. Same as FORMAT_RGB8. + */ + public static final int FORMAT_RGB = 1; + + /** + * Specifies that each pixel contains 4 8-bit channels: one each + * for red, green, blue, alpha. Same as FORMAT_RGBA8. + */ + public static final int FORMAT_RGBA = 2; + + /** + * Specifies that each pixel contains 3 8-bit channels: one each + * for red, green, blue. Same as FORMAT_RGB. + */ + public static final int FORMAT_RGB8 = FORMAT_RGB; + + /** + * Specifies that each pixel contains 4 8-bit channels: one each + * for red, green, blue, alpha. Same as FORMAT_RGBA. + */ + public static final int FORMAT_RGBA8 = FORMAT_RGBA; + + /** + * Specifies that each pixel contains 3 5-bit channels: one each + * for red, green, blue. + */ + public static final int FORMAT_RGB5 = 3; + + /** + * Specifies that each pixel contains 3 5-bit channels: one each + * for red, green, blue and 1 1-bit channel for alpha. + */ + public static final int FORMAT_RGB5_A1 = 4; + + /** + * Specifies that each pixel contains 3 4-bit channels: one each + * for red, green, blue. + */ + public static final int FORMAT_RGB4 = 5; + + /** + * Specifies that each pixel contains 4 4-bit channels: one each + * for red, green, blue, alpha. + */ + public static final int FORMAT_RGBA4 = 6; + + /** + * Specifies that each pixel contains 2 4-bit channels: one each + * for luminance and alpha. + */ + public static final int FORMAT_LUM4_ALPHA4 = 7; + + /** + * Specifies that each pixel contains 2 8-bit channels: one each + * for luminance and alpha. + */ + public static final int FORMAT_LUM8_ALPHA8 = 8; + + /** + * Specifies that each pixel contains 2 3-bit channels: one each + * for red, green, and 1 2-bit channel for blue. + */ + public static final int FORMAT_R3_G3_B2 = 9; + + /** + * Specifies that each pixel contains 1 8-bit channel: it can be + * used for only luminance or only alpha or only intensity. + */ + public static final int FORMAT_CHANNEL8 = 10; + + // Internal variable for checking validity of formats + // Change this if any more formats are added or removed + static final int FORMAT_TOTAL = 10; + + + /** + * Used to specify the class of the image being wrapped. + * + * @since Java 3D 1.5 + */ + public enum ImageClass { + /** + * Indicates that this ImageComponent object wraps a BufferedImage + * object. This is the default state. Note that the image class will + * be BUFFERED_IMAGE following a call to set(RenderedImage image) + * if we are in by-copy mode, or if the image is an instance of + * BufferedImage. + */ + BUFFERED_IMAGE, + + /** + * Indicates that this ImageComponent object wraps a RenderedImage + * object that is not a BufferedImage. Note that the image class + * of an ImageComponent following a call to set(RenderedImage image) + * will be RENDERED_IMAGE, if and only if the image is not an instance + * of BufferedImage and the ImageComponent is in by-reference mode. + */ + RENDERED_IMAGE, + + /** + * Indicates that this ImageComponent object wraps an NioImageBuffer + * object. Note that an ImageComponent in this state must not be used + * as the off-screen buffer of a Canvas3D nor as the target of a + * readRaster operation. + */ + NIO_IMAGE_BUFFER, + } + + + /** + * Specifies that this ImageComponent object allows reading its + * size component information (width, height, and depth). + */ + public static final int + ALLOW_SIZE_READ = CapabilityBits.IMAGE_COMPONENT_ALLOW_SIZE_READ; + + /** + * Specifies that this ImageComponent object allows reading its + * format component information. + */ + public static final int + ALLOW_FORMAT_READ = CapabilityBits.IMAGE_COMPONENT_ALLOW_FORMAT_READ; + + /** + * Specifies that this ImageComponent object allows reading its + * image component information. + */ + public static final int + ALLOW_IMAGE_READ = CapabilityBits.IMAGE_COMPONENT_ALLOW_IMAGE_READ; + + /** + * Specifies that this ImageComponent object allows writing its + * image component information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_IMAGE_WRITE = CapabilityBits.IMAGE_COMPONENT_ALLOW_IMAGE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SIZE_READ, + ALLOW_IMAGE_READ, + ALLOW_FORMAT_READ + }; + + /** + * Not a public constructor, for internal use + */ + ImageComponent() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs an image component object using the specified format, width, + * and height. Default values are used for all other parameters. The + * default values are as follows: + *
    + * byReference : false
    + * yUp : false
    + *
+ * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA etc. + * @param width the number of columns of pixels in this image component + * object + * @param height the number of rows of pixels in this image component + * object + * @exception IllegalArgumentException if format is invalid, or if + * width or height are not positive. + */ + public ImageComponent(int format, int width, int height) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ImageComponentRetained)this.retained).processParams(format, width, height, 1); + } + + /** + * Constructs an image component object using the specified format, width, + * height, byReference flag, and yUp flag. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA etc. + * @param width the number of columns of pixels in this image component + * object + * @param height the number of rows of pixels in this image component + * object + * @param byReference a flag that indicates whether the data is copied + * into this image component object or is accessed by reference. + * @param yUp a flag that indicates the y-orientation of this image + * component. If yUp is set to true, the origin of the image is + * the lower left; otherwise, the origin of the image is the upper + * left. + * @exception IllegalArgumentException if format is invalid, or if + * width or height are not positive. + * + * @since Java 3D 1.2 + */ + public ImageComponent(int format, + int width, + int height, + boolean byReference, + boolean yUp) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ImageComponentRetained)this.retained).setYUp(yUp); + ((ImageComponentRetained)this.retained).setByReference(byReference); + ((ImageComponentRetained)this.retained).processParams(format, width, height, 1); + } + + /** + * Retrieves the width of this image component object. + * @return the width of this image component object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getWidth() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SIZE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent0")); + return ((ImageComponentRetained)this.retained).getWidth(); + } + + /** + * Retrieves the height of this image component object. + * @return the height of this image component object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getHeight() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SIZE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent1")); + return ((ImageComponentRetained)this.retained).getHeight(); + } + + /** + * Retrieves the format of this image component object. + * @return the format of this image component object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getFormat() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_FORMAT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2")); + return ((ImageComponentRetained)this.retained).getFormat(); + } + + + /** + * Retrieves the data access mode for this ImageComponent object. + * + * @return true if the data access mode for this + * ImageComponent object is by-reference; + * false if the data access mode is by-copying. + * + * @since Java 3D 1.2 + */ + public boolean isByReference() { + return ((ImageComponentRetained)this.retained).isByReference(); + } + + + /** + * Sets the y-orientation of this ImageComponent object to + * y-up or y-down. + * + * @param yUp a flag that indicates the y-orientation of this image + * component. If yUp is set to true, the origin of the image is + * the lower left; otherwise, the origin of the image is the upper + * left. + * + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @exception IllegalStateException if the image class of this object + * is ImageClass.NIO_IMAGE_BUFFER. + * + * @deprecated as of Java 3D 1.5, the yUp flag should only be set at object + * construction time. + * + * @since Java 3D 1.2 + */ + public void setYUp(boolean yUp) { + checkForLiveOrCompiled(); + + // check for illegal image class + if (((ImageComponentRetained)this.retained).getImageClass() == ImageClass.NIO_IMAGE_BUFFER) { + throw new IllegalStateException("ImageComponent4"); + } + + ((ImageComponentRetained)this.retained).setYUp(yUp); + } + + + /** + * Retrieves the y-orientation for this ImageComponent object. + * + * @return true if the y-orientation of this + * ImageComponent object is y-up; false if the + * y-orientation of this ImageComponent object is y-down. + * + * @since Java 3D 1.2 + */ + public boolean isYUp() { + return ((ImageComponentRetained)this.retained).isYUp(); + } + + + /** + * Retrieves the image class of this ImageComponent object. + * + * @return the image class of this ImageComponent, + * one of: ImageClass.BUFFERED_IMAGE, + * ImageClass.RENDERED_IMAGE, or ImageClass.NIO_IMAGE_BUFFER. + * + * @since Java 3D 1.5 + */ + public ImageClass getImageClass() { + return ((ImageComponentRetained)this.retained).getImageClass(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ImageComponent2D.java b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent2D.java new file mode 100644 index 0000000..1203baa --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent2D.java @@ -0,0 +1,745 @@ +/* + * $RCSfile: ImageComponent2D.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; +import java.util.logging.Level; + +/** + * This class defines a 2D image component. This is used for texture + * images, background images and raster components of Shape3D nodes. + * Prior to Java 3D 1.2, only BufferedImage objects could be used as the + * input to an ImageComponent2D object. As of Java 3D 1.2, an + * ImageComponent2D accepts any RenderedImage object (BufferedImage is + * an implementation of the RenderedImage interface). The methods + * that set/get a BufferedImage object are left in for compatibility. + * The new methods that set/get a RenderedImage are a superset of the + * old methods. In particular, the two set methods in the following + * example are equivalent: + * + *

+ *

    + * + * BufferedImage bi;
    + * RenderedImage ri = bi;
    + * ImageComponent2D ic;
    + *

    + * // Set the image to the specified BufferedImage
    + * ic.set(bi);
    + *

    + * // Set the image to the specified RenderedImage
    + * ic.set(ri);
    + *
    + *

+ * + *

+ * As of Java 3D 1.5, an ImageComponent2D accepts an NioImageBuffer object + * as an alternative to a RenderedImage. + */ + +public class ImageComponent2D extends ImageComponent { + + // non-public, no parameter constructor + ImageComponent2D() {} + + /** + * Constructs a 2D image component object using the specified + * format, width, and height. Default values are used for + * all other parameters. The default values are as follows: + *

    + * image : null
    + * imageClass : ImageClass.BUFFERED_IMAGE
    + *
+ * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA, etc. + * @param width the number of columns of pixels in this image component + * object + * @param height the number of rows of pixels in this image component + * object + * @exception IllegalArgumentException if format is invalid, or if + * width or height are not positive. + */ + public ImageComponent2D(int format, + int width, + int height) { + + if (MasterControl.isDevLoggable(Level.FINER)) { + MasterControl.getDevLogger().finer("ImageComponent - using default of byCopy"); + } + ((ImageComponent2DRetained)this.retained).processParams(format, width, height, 1); + } + + /** + * Constructs a 2D image component object using the specified format + * and BufferedImage. A copy of the BufferedImage is made. + * The image class is set to ImageClass.BUFFERED_IMAGE. + * Default values are used for all other parameters. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA, etc. + * @param image the BufferedImage used to create this 2D image component. + * @exception IllegalArgumentException if format is invalid, or if + * the width or height of the image are not positive. + */ + public ImageComponent2D(int format, BufferedImage image) { + + if (MasterControl.isDevLoggable(Level.FINER)) { + MasterControl.getDevLogger().finer("ImageComponent - using default of byCopy"); + } + ((ImageComponent2DRetained)this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); + ((ImageComponent2DRetained)this.retained).set(image); + } + + /** + * Constructs a 2D image component object using the specified format + * and RenderedImage. A copy of the RenderedImage is made. + * The image class is set to ImageClass.BUFFERED_IMAGE. + * Default values are used for all other parameters. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA, etc. + * @param image the RenderedImage used to create this 2D image component + * @exception IllegalArgumentException if format is invalid, or if + * the width or height of the image are not positive. + * + * @since Java 3D 1.2 + */ + public ImageComponent2D(int format, RenderedImage image) { + + + if (MasterControl.isDevLoggable(Level.FINER)) { + MasterControl.getDevLogger().finer("ImageComponent - using default of byCopy"); + } + ((ImageComponent2DRetained)this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); + ((ImageComponent2DRetained)this.retained).set(image); + } + + /** + * Constructs a 2D image component object using the specified + * format, width, height, byReference flag, and yUp flag. + * Default values are used for all other parameters. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA, etc. + * @param width the number of columns of pixels in this image component + * object + * @param height the number of rows of pixels in this image component + * object + * @param byReference a flag that indicates whether the data is copied + * into this image component object or is accessed by reference. + * @param yUp a flag that indicates the y-orientation of this image + * component. If yUp is set to true, the origin of the image is + * the lower left; otherwise, the origin of the image is the upper + * left. + * @exception IllegalArgumentException if format is invalid, or if + * width or height are not positive. + * + * @since Java 3D 1.2 + */ + public ImageComponent2D(int format, + int width, + int height, + boolean byReference, + boolean yUp) { + + if (MasterControl.isDevLoggable(Level.INFO)) { + if (byReference && !yUp) { + MasterControl.getDevLogger().info("ImageComponent - yUp should " + + "be set when using byReference, " + + "otherwise an extra copy of the image will be created"); + } + } + + ((ImageComponentRetained)this.retained).setByReference(byReference); + ((ImageComponentRetained)this.retained).setYUp(yUp); + ((ImageComponent2DRetained)this.retained).processParams(format, width, height, 1); + } + + /** + * Constructs a 2D image component object using the specified format, + * BufferedImage, byReference flag, and yUp flag. + * The image class is set to ImageClass.BUFFERED_IMAGE. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA, etc. + * @param image the BufferedImage used to create this 2D image component + * @param byReference a flag that indicates whether the data is copied + * into this image component object or is accessed by reference + * @param yUp a flag that indicates the y-orientation of this image + * component. If yUp is set to true, the origin of the image is + * the lower left; otherwise, the origin of the image is the upper + * left. + * @exception IllegalArgumentException if format is invalid, or if + * the width or height of the image are not positive. + * + * @since Java 3D 1.2 + */ + public ImageComponent2D(int format, + BufferedImage image, + boolean byReference, + boolean yUp) { + + if (MasterControl.isDevLoggable(Level.INFO)) { + if (byReference && !yUp) { + MasterControl.getDevLogger().info("ImageComponent - yUp should " + + "be set when using byReference, " + + "otherwise an extra copy of the image will be created"); + } + } + + ((ImageComponentRetained)this.retained).setByReference(byReference); + ((ImageComponentRetained)this.retained).setYUp(yUp); + ((ImageComponent2DRetained)this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); + ((ImageComponent2DRetained)this.retained).set(image); + } + + /** + * Constructs a 2D image component object using the specified format, + * RenderedImage, byReference flag, and yUp flag. + * The image class is set to ImageClass.RENDERED_IMAGE if the byReferece + * flag is true and the specified RenderedImage is not an instance + * of BufferedImage. In all other cases, the image class is set to + * ImageClass.BUFFERED_IMAGE. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA, etc. + * @param image the RenderedImage used to create this 2D image component + * @param byReference a flag that indicates whether the data is copied + * into this image component object or is accessed by reference. + * @param yUp a flag that indicates the y-orientation of this image + * component. If yUp is set to true, the origin of the image is + * the lower left; otherwise, the origin of the image is the upper + * left. + * @exception IllegalArgumentException if format is invalid, or if + * the width or height of the image are not positive. + * + * @since Java 3D 1.2 + */ + public ImageComponent2D(int format, + RenderedImage image, + boolean byReference, + boolean yUp) { + + if (MasterControl.isDevLoggable(Level.INFO)) { + if (byReference && !yUp) + MasterControl.getDevLogger().info("ImageComponent - yUp should " + + "be set when using byReference, " + + "otherwise an extra copy of the image will be created"); + } + ((ImageComponentRetained)this.retained).setByReference(byReference); + ((ImageComponentRetained)this.retained).setYUp(yUp); + ((ImageComponent2DRetained)this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); + ((ImageComponent2DRetained)this.retained).set(image); + } + + /** + * Constructs a 2D image component object using the specified format, + * NioImageBuffer, byReference flag, and yUp flag. + * The image class is set to ImageClass.NIO_IMAGE_BUFFER. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA, etc. + * @param image the NioImageBuffer used to create this 2D image component + * @param byReference a flag that indicates whether the data is copied + * into this image component object or is accessed by reference. + * @param yUp a flag that indicates the y-orientation of this image + * component. If yUp is set to true, the origin of the image is + * the lower left; otherwise, the origin of the image is the upper + * left. + * + * @exception IllegalArgumentException if format is invalid, or if + * the width or height of the image are not positive. + * + * @exception IllegalArgumentException if the byReference flag is false. + * + * @exception IllegalArgumentException if the yUp flag is false. + * + * @exception IllegalArgumentException if the number of components in format + * does not match the number of components in image. + * + * @since Java 3D 1.5 + */ + public ImageComponent2D(int format, + NioImageBuffer image, + boolean byReference, + boolean yUp) { + + ((ImageComponentRetained)this.retained).setByReference(byReference); + ((ImageComponentRetained)this.retained).setYUp(yUp); + ((ImageComponent2DRetained)this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); + ((ImageComponent2DRetained)this.retained).set(image); + } + + /** + * Sets this image component to the specified BufferedImage + * object. + * If the data access mode is not by-reference, then the + * BufferedImage data is copied into this object. If + * the data access mode is by-reference, then a reference to the + * BufferedImage is saved, but the data is not necessarily + * copied. + *

+ * The image class is set to ImageClass.BUFFERED_IMAGE. + * + * @param image BufferedImage object containing the image. + * Its size must be the same as the current size of this + * ImageComponent2D object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if the width and height of the + * specified image is not equal to the width and height of this + * ImageComponent object. + */ + public void set(BufferedImage image) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_WRITE)) + throw new CapabilityNotSetException( + J3dI18N.getString("ImageComponent2D1")); + } + + ((ImageComponent2DRetained)this.retained).set(image); + } + + /** + * Sets this image component to the specified RenderedImage + * object. If the data access mode is not by-reference, the + * RenderedImage data is copied into this object. If + * the data access mode is by-reference, a reference to the + * RenderedImage is saved, but the data is not necessarily + * copied. + *

+ * The image class is set to ImageClass.RENDERED_IMAGE if the the + * data access mode is by-reference and the specified + * RenderedImage is not an instance of BufferedImage. In all + * other cases, the image class is set to ImageClass.BUFFERED_IMAGE. + * + * @param image RenderedImage object containing the image. + * Its size must be the same as the current size of this + * ImageComponent2D object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if the width and height of the + * specified image is not equal to the width and height of this + * ImageComponent object. + * + * @since Java 3D 1.2 + */ + public void set(RenderedImage image) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_WRITE)) + throw new CapabilityNotSetException( + J3dI18N.getString("ImageComponent2D1")); + } + + ((ImageComponent2DRetained)this.retained).set(image); + } + + /** + * Sets this image component to the specified NioImageBuffer + * object. If the data access mode is not by-reference, the + * NioImageBuffer data is copied into this object. If + * the data access mode is by-reference, a reference to the + * NioImageBuffer is saved, but the data is not necessarily + * copied. + *

+ * The image class is set to ImageClass.NIO_IMAGE_BUFFER. + * + * @param image NioImageBuffer object containing the image. + * Its size must be the same as the current size of this + * ImageComponent2D object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if this ImageComponent object + * is not yUp. + * + * @exception IllegalArgumentException if the width and height of the + * specified image is not equal to the width and height of this + * ImageComponent object. + * + * @exception IllegalArgumentException if the number of components in format + * does not match the number of components in image. + * + * @since Java 3D 1.5 + */ + public void set(NioImageBuffer image) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("ImageComponent2D1")); + } + } + + ((ImageComponent2DRetained)this.retained).set(image); + } + + /** + * Retrieves the image from this ImageComponent2D object. If the + * data access mode is not by-reference, a copy of the image + * is made. If the data access mode is by-reference, the + * reference is returned. + * + * @return either a new BufferedImage object created from the data + * in this image component, or the BufferedImage object referenced + * by this image component. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the image class is not + * ImageClass.BUFFERED_IMAGE. + */ + public BufferedImage getImage() { + if (isLiveOrCompiled()) { + if(!this.getCapability(ImageComponent.ALLOW_IMAGE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D0")); + } + + RenderedImage img = ((ImageComponent2DRetained)this.retained).getImage(); + + if ((img != null) && !(img instanceof BufferedImage)) { + throw new IllegalStateException(J3dI18N.getString("ImageComponent2D5")); + } + return (BufferedImage) img; + + } + + /** + * Retrieves the image from this ImageComponent2D object. If the + * data access mode is not by-reference, a copy of the image + * is made. If the data access mode is by-reference, the + * reference is returned. + * + * @return either a new RenderedImage object created from the data + * in this image component, or the RenderedImage object referenced + * by this image component. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the image class is not one of: + * ImageClass.BUFFERED_IMAGE or ImageClass.RENDERED_IMAGE. + * + * @since Java 3D 1.2 + */ + public RenderedImage getRenderedImage() { + + if (isLiveOrCompiled()) + if(!this.getCapability(ImageComponent.ALLOW_IMAGE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D0")); + return ((ImageComponent2DRetained)this.retained).getImage(); + } + + /** + * Retrieves the image from this ImageComponent2D object. If the + * data access mode is not by-reference, a copy of the image + * is made. If the data access mode is by-reference, the + * reference is returned. + * + * @return either a new NioImageBuffer object created from the data + * in this image component, or the NioImageBuffer object referenced + * by this image component. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the image class is not + * ImageClass.NIO_IMAGE_BUFFER. + * + * @since Java 3D 1.5 + */ + public NioImageBuffer getNioImage() { + + if (isLiveOrCompiled()) { + if (!this.getCapability(ImageComponent.ALLOW_IMAGE_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D0")); + } + } + return ((ImageComponent2DRetained)this.retained).getNioImage(); + + } + + + /** + * Modifies a contiguous subregion of the image component. + * Block of data of dimension (width * height) + * starting at the offset (srcX, srcY) of the specified + * RenderedImage object will be copied into the image component + * starting at the offset (dstX, dstY) of the ImageComponent2D object. + * The specified RenderedImage object must be of the same format as + * the current RenderedImage object in this image component. + * This method can only be used if the data access mode is + * by-copy. If it is by-reference, see updateData(). + * + * @param image RenderedImage object containing the subimage. + * @param width width of the subregion. + * @param height height of the subregion. + * @param srcX starting X offset of the subregion in the + * specified image. + * @param srcY starting Y offset of the subregion in the + * specified image. + * @param dstX starting X offset of the subregion in the image + * component of this object. + * @param dstY starting Y offset of the subregion in the image + * component of this object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the data access mode is + * BY_REFERENCE. + * + * @exception IllegalArgumentException if width or + * height of + * the subregion exceeds the dimension of the image of this object. + * + * @exception IllegalArgumentException if dstX < 0, or + * (dstX + width) > width of this object, or + * dstY < 0, or + * (dstY + height) > height of this object. + * + * @exception IllegalArgumentException if srcX < 0, or + * (srcX + width) > width of the RenderedImage + * object containing the subimage, or + * srcY < 0, or + * (srcY + height) > height of the + * RenderedImage object containing the subimage. + * + * @exception IllegalArgumentException if the specified RenderedImage + * is not compatible with the existing RenderedImage. + * + * @exception IllegalStateException if the image class is not one of: + * ImageClass.BUFFERED_IMAGE or ImageClass.RENDERED_IMAGE. + * + * @since Java 3D 1.3 + */ + public void setSubImage(RenderedImage image, int width, int height, + int srcX, int srcY, int dstX, int dstY) { + if (isLiveOrCompiled() && + !this.getCapability(ALLOW_IMAGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("ImageComponent2D1")); + } + + if (((ImageComponent2DRetained)this.retained).isByReference()) { + throw new IllegalStateException( + J3dI18N.getString("ImageComponent2D4")); + } + + int w = ((ImageComponent2DRetained)this.retained).getWidth(); + int h = ((ImageComponent2DRetained)this.retained).getHeight(); + + // Fix to issue 492 + if ((srcX < 0) || (srcY < 0) || + ((srcX + width) > image.getWidth()) || ((srcY + height) > image.getHeight()) || + (dstX < 0) || (dstY < 0) || + ((dstX + width) > w) || ((dstY + height) > h)) { + throw new IllegalArgumentException( + J3dI18N.getString("ImageComponent2D3")); + } + + ((ImageComponent2DRetained)this.retained).setSubImage( + image, width, height, srcX, srcY, dstX, dstY); + } + + /** + * Updates image data that is accessed by reference. + * This method calls the updateData method of the specified + * ImageComponent2D.Updater object to synchronize updates to the + * image data that is referenced by this ImageComponent2D object. + * Applications that wish to modify such data must perform all + * updates via this method. + *

+ * The data to be modified has to be within the boundary of the + * subregion + * specified by the offset (x, y) and the dimension (width*height). + * It is illegal to modify data outside this boundary. + * If any referenced data is modified outisde the updateData + * method, or any data outside the specified boundary is modified, + * the results are undefined. + *

+ * @param updater object whose updateData callback method will be + * called to update the data referenced by this ImageComponent2D object. + * @param x starting X offset of the subregion. + * @param y starting Y offset of the subregion. + * @param width width of the subregion. + * @param height height of the subregion. + * + * @exception CapabilityNotSetException if the appropriate capability + * is not set, and this object is part of a live or compiled scene graph + * @exception IllegalStateException if the data access mode is + * BY_COPY. + * @exception IllegalArgumentException if width or + * height of + * the subregion exceeds the dimension of the image of this object. + * @exception IllegalArgumentException if x < 0, or + * (x + width) > width of this object, or + * y < 0, or + * (y + height) > height of this object. + * + * @since Java 3D 1.3 + */ + public void updateData(Updater updater, + int x, int y, + int width, int height) { + + if (isLiveOrCompiled() && + !this.getCapability(ALLOW_IMAGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("ImageComponent2D1")); + } + + if (!((ImageComponent2DRetained)this.retained).isByReference()) { + throw new IllegalStateException( + J3dI18N.getString("ImageComponent2D2")); + } + + int w = ((ImageComponent2DRetained)this.retained).getWidth(); + int h = ((ImageComponent2DRetained)this.retained).getHeight(); + + if ((x < 0) || (y < 0) || ((x + width) > w) || ((y + height) > h)) { + throw new IllegalArgumentException( + J3dI18N.getString("ImageComponent2D3")); + } + + ((ImageComponent2DRetained)this.retained).updateData( + updater, x, y, width, height); + } + + /** + * Creates a retained mode ImageComponent2DRetained object that this + * ImageComponent2D component object will point to. + */ + void createRetained() { + this.retained = new ImageComponent2DRetained(); + this.retained.setSource(this); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + ImageComponent2DRetained rt = (ImageComponent2DRetained) retained; + + ImageComponent2D img = new ImageComponent2D(rt.getFormat(), + rt.width, + rt.height, + rt.byReference, + rt.yUp); + img.duplicateNodeComponent(this); + return img; + } + + + /** + * Copies all node information from originalNodeComponent + * into the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + ImageComponent.ImageClass imageClass = + ((ImageComponentRetained)originalNodeComponent.retained).getImageClass(); + if(imageClass == ImageComponent.ImageClass.NIO_IMAGE_BUFFER) { + NioImageBuffer nioImg = ((ImageComponent2DRetained) + originalNodeComponent.retained).getNioImage(); + + if(nioImg != null) { + ((ImageComponent2DRetained) retained).set(nioImg); + } + } else { + RenderedImage img = ((ImageComponent2DRetained) + originalNodeComponent.retained).getImage(); + + if (img != null) { + ((ImageComponent2DRetained) retained).set(img); + } + } + } + + /** + * The ImageComponent2D.Updater interface is used in updating image data + * that is accessed by reference from a live or compiled ImageComponent + * object. Applications that wish to modify such data must define a + * class that implements this interface. An instance of that class is + * then passed to the updateData method of the + * ImageComponent object to be modified. + * + * @since Java 3D 1.3 + */ + public static interface Updater { + /** + * Updates image data that is accessed by reference. + * This method is called by the updateData method of an + * ImageComponent object to effect + * safe updates to image data that + * is referenced by that object. Applications that wish to modify + * such data must implement this method and perform all updates + * within it. + *
+ * NOTE: Applications should not call this method directly. + * + * @param imageComponent the ImageComponent object being updated. + * @param x starting X offset of the subregion. + * @param y starting Y offset of the subregion. + * @param width width of the subregion. + * @param height height of the subregion. + * + * @see ImageComponent2D#updateData + */ + public void updateData(ImageComponent2D imageComponent, + int x, int y, + int width, int height); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ImageComponent2DRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent2DRetained.java new file mode 100644 index 0000000..fad9dba --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent2DRetained.java @@ -0,0 +1,341 @@ +/* + * $RCSfile: ImageComponent2DRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.image.*; +import java.awt.color.ColorSpace; + +/** + * This class defines a 2D image component. + * This is used for texture images, background images and raster components + * of Shape3D nodes. + */ + +class ImageComponent2DRetained extends ImageComponentRetained { + + ImageComponent2DRetained() { + } + + /** + * This method handles NioImageBuffer + * Refers or copies the specified NioImageBuffer to this 2D image component object. + * @param image NioImageBuffer object containing the image. + * The format and size must be the same as the current format in this + * ImageComponent2D object. + */ + void set(NioImageBuffer image) { + + int width = image.getWidth(); + int height = image.getHeight(); + + if (!byReference) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent2D7")); + } + if (!yUp) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent2D8")); + } + + if (width != this.width) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent2DRetained0")); + } + if (height != this.height) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent2DRetained1")); + } + + geomLock.getLock(); + + setImageClass(image); + + // This is a byRef image. + setRefImage(image,0); + + // Reset this flag to true, incase it was set to false due to + // the previous image type. + abgrSupported = true; + + imageTypeIsSupported = isImageTypeSupported(image); + + if (imageTypeIsSupported) { + + /* Use reference when ( format is OK, Yup is true, and byRef is true). */ + // Create image data object with the byRef image. */ + imageData = createNioImageBufferDataObject(image); + + } else { + // Handle abgrSupported is false case. + imageData = createNioImageBufferDataObject(null); + copyUnsupportedNioImageToImageData(image, 0, 0, 0, 0, width, height, imageData); + + } + + geomLock.unLock(); + + if (source.isLive()) { + // send a IMAGE_CHANGED message in order to + // notify all the users of the change + sendMessage(IMAGE_CHANGED, null); + } + } + + /** + * This method handles both BufferedImage and RenderedImage + * Copies the specified RenderedImage to this 2D image component object. + * @param image RenderedImage object containing the image. + * The format and size must be the same as the current format in this + * ImageComponent2D object. + */ + void set(RenderedImage image) { + + int width = image.getWidth(); + int height = image.getHeight(); + + if (width != this.width) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent2DRetained0")); + } + if (height != this.height) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent2DRetained1")); + } + + setImageClass(image); + + geomLock.getLock(); + + if (byReference) { + setRefImage(image,0); + } + + // Reset this flag to true, incase it was set to false due to + // the previous image type. + abgrSupported = true; + + imageTypeIsSupported = isImageTypeSupported(image); + + if (imageTypeIsSupported) { + + if (byReference && yUp) { + /* Use reference when ( format is OK, Yup is true, and byRef is true). */ + // System.err.println("ImageComponent2DRetained.set() : (imageTypeSupported && byReference && yUp) --- (1)"); + if (image instanceof BufferedImage) { + // Create image data object with the byRef image. */ + imageData = createRenderedImageDataObject(image); + } + else { + // System.err.println("byRef and not BufferedImage !!!"); + imageData = null; + } + + } else { + // Either not byRef or not yUp or not both + // System.err.println("ImageComponent2DRetained.set() : (imageTypeSupported && ((!byReference && yUp) || (imageTypeSupported && !yUp)) --- (2)"); + + // Create image data object with buffer for image. */ + imageData = createRenderedImageDataObject(null); + copySupportedImageToImageData(image, 0, imageData); + } + + } else { + // image type is unsupported, need to create a supported local copy. + // TODO : borrow code from JAI to convert to right format. + // System.err.println("ImageComponent2DRetained.set() : (imageTypeSupported == false) --- (4)"); + /* Will use the code segment in copy() method */ + + // Create image data object with buffer for image. */ + imageData = createRenderedImageDataObject(null); + copyUnsupportedImageToImageData(image, 0, imageData); + + } + + geomLock.unLock(); + + if (source.isLive()) { + // send a IMAGE_CHANGED message in order to + // notify all the users of the change + sendMessage(IMAGE_CHANGED, null); + } + } + + void setSubImage(RenderedImage image, int width, int height, + int srcX, int srcY, int dstX, int dstY) { + + if (!isSubImageTypeEqual(image)) { + throw new IllegalStateException( + J3dI18N.getString("ImageComponent2D6")); + } + + // Can't be byReference + assert (!byReference); + assert (imageData != null); + + geomLock.getLock(); + + if (imageTypeIsSupported) { + // Either not byRef or not yUp or not both + // System.err.println("ImageComponent2DRetained.setSubImage() : (imageTypeSupported ) --- (1)"); + if (image instanceof BufferedImage) { + copyImageLineByLine((BufferedImage)image, srcX, srcY, dstX, dstY, 0, width, height, imageData); + } + else { + copySupportedImageToImageData(image, srcX, srcY, dstX, dstY, 0, width, height, imageData); + } + } else { + // image type is unsupported, need to create a supported local copy. + // TODO : Should look into borrow code from JAI to convert to right format. + // System.err.println("ImageComponent2DRetained.setSubImage() : (imageTypeSupported == false) --- (2)"); + if (image instanceof BufferedImage) { + copyUnsupportedImageToImageData((BufferedImage)image, srcX, srcY, dstX, dstY, 0, width, height, imageData); + } + else { + copyUnsupportedImageToImageData(image, srcX, srcY, dstX, dstY, 0, width, height, imageData); + } + } + geomLock.unLock(); + + if (source.isLive()) { + + // send a SUBIMAGE_CHANGED message in order to + // notify all the users of the change + + ImageComponentUpdateInfo info; + + info = new ImageComponentUpdateInfo(); + info.x = dstX; + info.y = dstY; + info.z = 0; + info.width = width; + info.height = height; + + sendMessage(SUBIMAGE_CHANGED, info); + } + } + + /** + * Retrieves a copy of the image in this ImageComponent2D object. + * @return a new RenderedImage object created from the image in this + * ImageComponent2D object + */ + RenderedImage getImage() { + + if (isByReference()) { + return (RenderedImage) getRefImage(0); + } + + if(imageData != null) { + return imageData.createBufferedImage(0); + } + + return null; + } + + /** + * Retrieves the reference of the nio image in this ImageComponent2D object. + */ + NioImageBuffer getNioImage() { + + if (getImageClass() != ImageComponent.ImageClass.NIO_IMAGE_BUFFER) { + throw new IllegalStateException(J3dI18N.getString("ImageComponent2D9")); + } + + assert (byReference == true); + + return (NioImageBuffer) getRefImage(0); + } + + /** + * Update data. + * x and y specifies the x & y offset of the image data in + * ImageComponent. It assumes that the origin is (0, 0). + */ + void updateData(ImageComponent2D.Updater updater, + int x, int y, int width, int height) { + + geomLock.getLock(); + // call the user supplied updateData method to update the data + updater.updateData((ImageComponent2D)source, x, y, width, height); + + Object refImage = getRefImage(0); + assert (refImage != null); + assert (imageData != null); + + // Check is data copied internally. + if(!imageData.isDataByRef()) { + // update the internal copy of the image data if a copy has been + // made + if (imageTypeIsSupported) { + assert !(refImage instanceof NioImageBuffer); + + if (refImage instanceof BufferedImage) { + copyImageLineByLine((BufferedImage)refImage, x, y, x, y, 0, width, height, imageData); + } else { + RenderedImage ri = (RenderedImage)refImage; + copySupportedImageToImageData(ri, (x + ri.getMinX()), (y + ri.getMinY()), x, y, 0, width, height, imageData); + } + } else { + // image type is unsupported, need to create a supported local copy. + // TODO : Should look into borrow code from JAI to convert to right format. + if (refImage instanceof BufferedImage) { + copyUnsupportedImageToImageData((BufferedImage)refImage, x, y, x, y, 0, width, height, imageData); + } else if (refImage instanceof RenderedImage) { + RenderedImage ri = (RenderedImage)refImage; + copyUnsupportedImageToImageData(ri, (x + ri.getMinX()), (y + ri.getMinY()), x, y, 0, width, height, imageData); + } else if (refImage instanceof NioImageBuffer) { + copyUnsupportedNioImageToImageData((NioImageBuffer)refImage, x, y, x, y, width, height, imageData); + } else { + assert false; + } + } + } + geomLock.unLock(); + + + if (source.isLive()) { + + // send a SUBIMAGE_CHANGED message in order to + // notify all the users of the change + + ImageComponentUpdateInfo info; + + info = new ImageComponentUpdateInfo(); + info.x = x; + info.y = y; + info.z = 0; + info.width = width; + info.height = height; + + sendMessage(SUBIMAGE_CHANGED, info); + } + } + + void clearLive(int refCount) { + super.clearLive(refCount); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ImageComponent3D.java b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent3D.java new file mode 100644 index 0000000..78f73b2 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent3D.java @@ -0,0 +1,981 @@ +/* + * $RCSfile: ImageComponent3D.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; + +/** + * This class defines a 3D image component. This is used for texture + * images. + * Prior to Java 3D 1.2, only BufferedImage objects could be used as + * the input to an ImageComponent3D object. As of Java 3D 1.2, an + * ImageComponent3D accepts an array of arbitrary RenderedImage + * objects (BufferedImage is an implementation of the RenderedImage + * interface). The methods that set/get a BufferedImage object are + * left in for compatibility. The new methods that set/get a + * RenderedImage are a superset of the old methods. In particular, + * the two set methods in the following example are equivalent: + * + *

+ *

    + * + * BufferedImage bi;
    + * RenderedImage ri = bi;
    + * ImageComponent3D ic;
    + *

    + * // Set image 0 to the specified BufferedImage
    + * ic.set(0, bi);
    + *

    + * // Set image 0 to the specified RenderedImage
    + * ic.set(0, ri);
    + *
    + *

+ * + */ +public class ImageComponent3D extends ImageComponent { + + // non-public, no parameter constructor + ImageComponent3D() {} + + /** + * Constructs a 3D image component object using the specified + * format, width, height, and depth. Default values are used for + * all other parameters. The default values are as follows: + *
    + * array of images : null
    + * imageClass : ImageClass.BUFFERED_IMAGE
    + *
+ * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA, etc. + * @param width the number of columns of pixels in this image component + * object + * @param height the number of rows of pixels in this image component + * object + * @param depth the number of 2D slices in this image component object + * @exception IllegalArgumentException if format is invalid, or if + * any of width, height, or depth are not positive. + */ + public ImageComponent3D(int format, + int width, + int height, + int depth) { + + ((ImageComponent3DRetained)this.retained).processParams(format, width, height, depth); + } + + /** + * Constructs a 3D image component object using the specified format, + * and the BufferedImage array. + * The image class is set to ImageClass.BUFFERED_IMAGE. + * Default values are used for all other parameters. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA etc. + * @param images an array of BufferedImage objects. The + * first image in the array determines the width and height of this + * ImageComponent3D. + * + * @exception IllegalArgumentException if format is invalid, or if + * the width or height of the first image are not positive. + */ + public ImageComponent3D(int format, BufferedImage[] images) { + ((ImageComponent3DRetained)this.retained).processParams(format, + images[0].getWidth(null), images[0].getHeight(null), images.length); + for (int i=0; inot an + * instance of BufferedImage. In all other cases, the image class is set to + * ImageClass.BUFFERED_IMAGE. + * + * @param format the image component format, one of: FORMAT_RGB, + * FORMAT_RGBA etc. + * @param images an array of RenderedImage objects. The + * first image in the array determines the width and height of this + * ImageComponent3D. + * @param byReference a flag that indicates whether the data is copied + * into this image component object or is accessed by reference. + * @param yUp a flag that indicates the y-orientation of this image + * component. If yUp is set to true, the origin of the image is + * the lower left; otherwise, the origin of the image is the upper + * left. + * @exception IllegalArgumentException if format is invalid, or if + * the width or height of the first image are not positive. + * + * @since Java 3D 1.2 + */ + public ImageComponent3D(int format, + RenderedImage[] images, + boolean byReference, + boolean yUp) { + + ((ImageComponentRetained)this.retained).setByReference(byReference); + ((ImageComponentRetained)this.retained).setYUp(yUp); + ((ImageComponent3DRetained)this.retained).processParams(format, + images[0].getWidth(), images[0].getHeight(), images.length); + for (int i=0; i + * The image class is set to ImageClass.BUFFERED_IMAGE. + * + * @param images array of BufferedImage objects containing the image. + * The size (width and height) of each image must be the same as the + * size of the image component, and the length of the images array + * must equal the depth of the image component. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if the length of the images array is + * not equal to the depth of this ImageComponent object. + * + * @exception IllegalArgumentException if the width and height of each + * image in the images array is not equal to the width and height of this + * ImageComponent object. + */ + public void set(BufferedImage[] images) { + checkForLiveOrCompiled(); + int depth = ((ImageComponent3DRetained)this.retained).getDepth(); + + if (depth != images.length) + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent3D1")); + for (int i=0; i + * The image class is set to ImageClass.RENDERED_IMAGE if the data access + * mode is by-reference and any of the specified RenderedImages + * is not an instance of BufferedImage. In all other cases, + * the image class is set to ImageClass.BUFFERED_IMAGE. + * + * @param images array of RenderedImage objects containing the image. + * The size (width and height) of each image must be the same as the + * size of the image component, and the length of the images array + * must equal the depth of the image component. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if the length of the images array is + * not equal to the depth of this ImageComponent object. + * + * @exception IllegalArgumentException if the width and height of each + * image in the images array is not equal to the width and height of this + * ImageComponent object. + * + * @since Java 3D 1.2 + */ + public void set(RenderedImage[] images) { + + checkForLiveOrCompiled(); + int depth = ((ImageComponent3DRetained)this.retained).getDepth(); + + if (depth != images.length) + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent3D1")); + for (int i=0; i + * The image class is set to ImageClass.NIO_IMAGE_BUFFER. + * + * @param images array of NioImageBuffer objects containing the image. + * The size (width and height) of each image must be the same as the + * size of the image component, and the length of the images array + * must equal the depth of the image component. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if this ImageComponent object + * is not yUp. + * + * @exception IllegalArgumentException if the length of the images array is + * not equal to the depth of this ImageComponent object. + * + * @exception IllegalArgumentException if the width and height of each + * image in the images array is not equal to the width and height of this + * ImageComponent object. + * + * @exception UnsupportedOperationException this method is not supported + * for Java 3D 1.5. + * + * @since Java 3D 1.5 + */ + public void set(NioImageBuffer[] images) { + + throw new UnsupportedOperationException(); + /* + checkForLiveOrCompiled(); + int depth = ((ImageComponent3DRetained)this.retained).getDepth(); + + if (depth != images.length) + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent3D1")); + for (int i=0; iBY_REFERENCE. + * + * @exception IllegalArgumentException if width or + * height of + * the subregion exceeds the dimension of the image in this object. + * + * @exception IllegalArgumentException if dstX < 0, or + * (dstX + width) > width of this object, or + * dstY < 0, or + * (dstY + height) > height of this object. + * + * @exception IllegalArgumentException if srcX < 0, or + * (srcX + width) > width of the RenderedImage + * object containing the subimage, or + * srcY < 0, or + * (srcY + height) > height of the + * RenderedImage object containing the subimage. + * + * @exception IllegalArgumentException if the specified RenderedImage + * is not compatible with the existing RenderedImage. + * + * @exception IllegalStateException if the image class is not one of: + * ImageClass.BUFFERED_IMAGE or ImageClass.RENDERED_IMAGE. + * + * @since Java 3D 1.3 + */ + public void setSubImage(int index, RenderedImage image, + int width, int height, + int srcX, int srcY, int dstX, int dstY) { + if (isLiveOrCompiled() && + !this.getCapability(ALLOW_IMAGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("ImageComponent3D5")); + } + + if (((ImageComponent3DRetained)this.retained).isByReference()) { + throw new IllegalStateException( + J3dI18N.getString("ImageComponent3D8")); + } + + int w = ((ImageComponent3DRetained)this.retained).getWidth(); + int h = ((ImageComponent3DRetained)this.retained).getHeight(); + + if ((srcX < 0) || (srcY < 0) || + ((srcX + width) > w) || ((srcY + height) > h) || + (dstX < 0) || (dstY < 0) || + ((dstX + width) > w) || ((dstY + height) > h)) { + throw new IllegalArgumentException( + J3dI18N.getString("ImageComponent3D7")); + } + + ((ImageComponent3DRetained)this.retained).setSubImage( + index, image, width, height, srcX, srcY, dstX, dstY); + } + + /** + * Updates a particular slice of image data that is accessed by reference. + * This method calls the updateData method of the specified + * ImageComponent3D.Updater object to synchronize updates to the + * image data that is referenced by this ImageComponent3D object. + * Applications that wish to modify such data must perform all + * updates via this method. + *

+ * The data to be modified has to be within the boundary of the + * subregion + * specified by the offset (x, y) and the dimension (width*height). + * It is illegal to modify data outside this boundary. If any + * referenced data is modified outside the updateData method, or + * any data outside the specified boundary is modified, the + * results are undefined. + *

+ * @param updater object whose updateData callback method will be + * called to update the data referenced by this ImageComponent3D object. + * @param index index of the image to be modified. + * The index must be less than the depth of this ImageComponent3D object. + * @param x starting X offset of the subregion. + * @param y starting Y offset of the subregion. + * @param width width of the subregion. + * @param height height of the subregion. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalStateException if the data access mode is + * BY_COPY. + * @exception IllegalArgumentException if width or + * height of + * the subregion exceeds the dimension of the image in this object. + * @exception IllegalArgumentException if x < 0, or + * (x + width) > width of this object, or + * y < 0, or + * (y + height) > height of this object. + * @exception ArrayIndexOutOfBoundsException if index > the + * depth of this object. + * + * @since Java 3D 1.3 + */ + public void updateData(Updater updater, int index, + int x, int y, + int width, int height) { + if (isLiveOrCompiled() && + !this.getCapability(ALLOW_IMAGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("ImageComponent3D5")); + } + + if (!((ImageComponent3DRetained)this.retained).isByReference()) { + throw new IllegalStateException( + J3dI18N.getString("ImageComponent3D6")); + } + + int w = ((ImageComponent3DRetained)this.retained).getWidth(); + int h = ((ImageComponent3DRetained)this.retained).getHeight(); + + if ((x < 0) || (y < 0) || ((x + width) > w) || ((y + height) > h)) { + throw new IllegalArgumentException( + J3dI18N.getString("ImageComponent3D7")); + } + + ((ImageComponent3DRetained)this.retained).updateData( + updater, index, x, y, width, height); + } + + + /** + * Creates a retained mode ImageComponent3DRetained object that this + * ImageComponent3D component object will point to. + */ + void createRetained() { + this.retained = new ImageComponent3DRetained(); + this.retained.setSource(this); + } + + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + ImageComponent3DRetained rt = (ImageComponent3DRetained) retained; + + ImageComponent3D img = new ImageComponent3D(rt.getFormat(), + rt.width, + rt.height, + rt.depth); + + // XXXX : replace by this to duplicate other attributes + /* + ImageComponent3D img = new ImageComponent3D(rt.format, + rt.width, + rt.height, + rt.depth, + rt.byReference, + rt.yUp); + */ + img.duplicateNodeComponent(this); + return img; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + // TODO : Handle NioImageBuffer if its supported. + RenderedImage imgs[] = ((ImageComponent3DRetained) + originalNodeComponent.retained).getImage(); + + if (imgs != null) { + ImageComponent3DRetained rt = (ImageComponent3DRetained) retained; + + for (int i=rt.depth-1; i>=0; i--) { + if (imgs[i] != null) { + rt.set(i, imgs[i]); + } + } + } + } + + /** + * The ImageComponent3D.Updater interface is used in updating image data + * that is accessed by reference from a live or compiled ImageComponent + * object. Applications that wish to modify such data must define a + * class that implements this interface. An instance of that class is + * then passed to the updateData method of the + * ImageComponent object to be modified. + * + * @since Java 3D 1.3 + */ + public static interface Updater { + /** + * Updates image data that is accessed by reference. + * This method is called by the updateData method of an + * ImageComponent object to effect + * safe updates to image data that + * is referenced by that object. Applications that wish to modify + * such data must implement this method and perform all updates + * within it. + *
+ * NOTE: Applications should not call this method directly. + * + * @param imageComponent the ImageComponent object being updated. + * @param index index of the image to be modified. + * @param x starting X offset of the subregion. + * @param y starting Y offset of the subregion. + * @param width width of the subregion. + * @param height height of the subregion. + * + * @see ImageComponent3D#updateData + */ + public void updateData(ImageComponent3D imageComponent, + int index, + int x, int y, + int width, int height); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ImageComponent3DRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent3DRetained.java new file mode 100644 index 0000000..057bd66 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ImageComponent3DRetained.java @@ -0,0 +1,384 @@ +/* + * $RCSfile: ImageComponent3DRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:23 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.image.*; + +/** + * This class defines a 3D array of pixels. + * This is used for texture images. + */ + +class ImageComponent3DRetained extends ImageComponentRetained { + + void setDepth(int depth) { + this.depth = depth; + } + + /** + * Retrieves the depth of this 3D image component object. + * @return the format of this 3D image component object + */ + int getDepth() { + return depth; + } + + /** + * Copies the specified BufferedImage to this 3D image component + * object at the specified index. + * @param index the image index + * @param images BufferedImage object containing the image. + * The format and size must be the same as the current format in this + * ImageComponent3D object. The index must not exceed the depth of this + * ImageComponent3D object. + */ + void set(int index, BufferedImage image) { + + geomLock.getLock(); + + if(byReference) { + // Fix to issue 488. + setRefImage(image, index); + } + + if(imageData == null) { + // Only do this once, on the first image + // Reset this flag to true, incase it was set to false due to + // the previous image type. + abgrSupported = true; + imageTypeIsSupported = isImageTypeSupported(image); + imageData = createRenderedImageDataObject(null); + } + else { + if(getImageType() != evaluateImageType(image)) { + // TODO need to throw illegal state exception + } + } + + if (imageTypeIsSupported) { + copySupportedImageToImageData(image, index, imageData); + } else { + // image type is unsupported, need to create a supported local copy. + // TODO : borrow code from JAI to convert to right format. + copyUnsupportedImageToImageData(image, index, imageData); + + } + + geomLock.unLock(); + + if (source.isLive()) { + // send a IMAGE_CHANGED message in order to + // notify all the users of the change + sendMessage(IMAGE_CHANGED, null); + } + } + + /** + * Copies the specified BufferedImage to this 3D image component + * object at the specified index. + * @param index the image index + * @param images BufferedImage object containing the image. + * The format and size must be the same as the current format in this + * ImageComponent3D object. The index must not exceed the depth of this + * ImageComponent3D object. + * + void set(int index, NioImageBuffer nioImage) { + + int width = nioImage.getWidth(); + int height = nioImage.getHeight(); + + if (!byReference) { + throw new IllegalArgumentException(J3dI18N.getString("Need_New_Message_XXXXXImageComponent2D7")); + } + if (!yUp) { + throw new IllegalArgumentException(J3dI18N.getString("Need_New_Message_XXXXXImageComponent2D8")); + } + + if (width != this.width) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent3D2")); + } + if (height != this.height) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent3D4")); + } + + geomLock.getLock(); + + setImageClass(nioImage); + + // This is a byRef image. + setRefImage(nioImage,0); + + if(imageData == null) { + // Only do this once, on the first image + // Reset this flag to true, incase it was set to false due to + // the previous image type. + abgrSupported = true; + + imageTypeIsSupported = isImageTypeSupported(nioImage); + + + // TODO : Need to handle null .... + imageData = createNioImageBufferDataObject(null); + } + else { + + //if(getImageType() != evaluateImageType(image)) { + // TODO need to throw illegal state exception + //} + + } + + if (imageTypeIsSupported) { + // TODO : Need to handle this ..... case .... + // copySupportedImageToImageData(image, index, imageData); + } else { + // System.err.println("Image format is unsupported -- illogical case"); + throw new AssertionError(); + } + + geomLock.unLock(); + + if (source.isLive()) { + // send a IMAGE_CHANGED message in order to + // notify all the users of the change + sendMessage(IMAGE_CHANGED, null); + } + } + */ + + void set(int index, RenderedImage image) { + + int width = image.getWidth(); + int height = image.getHeight(); + + if (width != this.width) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent3D2")); + } + if (height != this.height) { + throw new IllegalArgumentException(J3dI18N.getString("ImageComponent3D4")); + } + + if (image instanceof BufferedImage) { + set(index, ((BufferedImage)image)); + } + else { + // Create a buffered image from renderImage + ColorModel cm = image.getColorModel(); + WritableRaster wRaster = image.copyData(null); + BufferedImage bi = new BufferedImage(cm, + wRaster, + cm.isAlphaPremultiplied() + ,null); + set(index, bi); + } + } + + /** + * Retrieves a copy of the images in this ImageComponent3D object. + * @return a new array of new BufferedImage objects created from the + * images in this ImageComponent3D object + */ + RenderedImage[] getRenderedImage() { + int i; + RenderedImage bi[] = new RenderedImage[depth]; + + if (!byReference) { + for (i=0; i copyWidth) { + curw = copyWidth; + } + + if (curh > copyHeight) { + curh = copyHeight; + } + + // save the to-be-copied width of the left most tile + int startw = curw; + + // temporary variable for dimension of the to-be-copied region + int tmpw = copyWidth; + int tmph = copyHeight; + + // offset of the first pixel of the tile to be copied; offset is + // relative to the upper left corner of the title + int x = srcX - startXTile; + int y = srcY - startYTile; + + // determine the number of tiles in each direction that the + // image spans + numXTiles = (copyWidth + x) / tilew; + numYTiles = (copyHeight + y) / tileh; + + if (((float)(copyWidth + x ) % (float)tilew) > 0) { + numXTiles += 1; + } + + if (((float)(copyHeight + y ) % (float)tileh) > 0) { + numYTiles += 1; + } + + int offset; + int w, h, i, j, m, n; + int dstBegin; + Object pixel = null; + java.awt.image.Raster ras; + int lineUnits; // nbytes per line in dst image buffer + int sign; // -1 for going down + int dstLineUnits; // sign * lineUnits + int tileStart; // destination buffer offset + // at the next left most tile + + byte[] dstByteBuffer = null; + int[] dstIntBuffer = null; + + switch(data.getType()) { + case TYPE_BYTE_ARRAY: + dstByteBuffer = data.getAsByteArray(); + break; + case TYPE_INT_ARRAY: + dstIntBuffer = data.getAsIntArray(); + break; + default: + assert false; + } + + int dataWidth = data.dataWidth; + int dataHeight = data.dataHeight; + + lineUnits = dataWidth * unitsPerPixel; + if (yUp) { + // destination buffer offset + tileStart = (depthIndex * dataWidth * dataHeight + dstY * dataWidth + dstX) * unitsPerPixel; + sign = 1; + dstLineUnits = lineUnits; + } else { + // destination buffer offset + tileStart = (depthIndex * dataWidth * dataHeight + (dataHeight - dstY - 1) * dataWidth + dstX) * unitsPerPixel; + sign = -1; + dstLineUnits = -lineUnits; + } + +/* + System.err.println("tileStart= " + tileStart + " dstLineUnits= " + dstLineUnits); + System.err.println("startw= " + startw); + */ + + // allocate memory for a pixel + ras = ri.getTile(minTileX,minTileY); + pixel = getDataElementBuffer(ras); + + int srcOffset, dstOffset; + int tileLineUnits = tilew * unitsPerPixel; + int copyUnits; + + for (n = minTileY; n < minTileY+numYTiles; n++) { + + dstBegin = tileStart; // destination buffer offset + tmpw = copyWidth; // reset the width to be copied + curw = startw; // reset the width to be copied of + // the left most tile + x = srcX - startXTile; // reset the starting x offset of + // the left most tile + + for (m = minTileX; m < minTileX+numXTiles; m++) { + + // retrieve the raster for the next tile + ras = ri.getTile(m,n); + + srcOffset = (y * tilew + x) * unitsPerPixel; + dstOffset = dstBegin; + + copyUnits = curw * unitsPerPixel; + + //System.err.println("curh = "+curh+" curw = "+curw); + //System.err.println("x = "+x+" y = "+y); + + switch(data.getType()) { + case TYPE_BYTE_ARRAY: + byte[] srcByteBuffer = ((DataBufferByte)ras.getDataBuffer()).getData(); + for (h = 0; h < curh; h++) { + System.arraycopy(srcByteBuffer, srcOffset, dstByteBuffer, dstOffset, + copyUnits); + srcOffset += tileLineUnits; + dstOffset += dstLineUnits; + } + break; + case TYPE_INT_ARRAY: + int[] srcIntBuffer = ((DataBufferInt)ras.getDataBuffer()).getData(); + for (h = 0; h < curh; h++) { + System.arraycopy(srcIntBuffer, srcOffset, dstIntBuffer, dstOffset, + copyUnits); + srcOffset += tileLineUnits; + dstOffset += dstLineUnits; + } + break; + default: + assert false; + } + + // advance the destination buffer offset + dstBegin += curw * unitsPerPixel; + + // move to the next tile in x direction + x = 0; + + // determine the width of copy region of the next tile + + tmpw -= curw; + if (tmpw < tilew) { + curw = tmpw; + } else { + curw = tilew; + } + } + + // we are done copying an array of tiles in the x direction + // advance the tileStart offset + tileStart += dataWidth * unitsPerPixel * curh * sign; + + // move to the next set of tiles in y direction + y = 0; + + // determine the height of copy region for the next set + // of tiles + tmph -= curh; + if (tmph < tileh) { + curh = tmph; + } else { + curh = tileh; + } + } + + if((imageData == data) && (imageDataPowerOfTwo != null)) { + updateImageDataPowerOfTwo(depthIndex); + } + } + + // Quick line by line copy + void copyImageLineByLine(BufferedImage bi, int srcX, int srcY, + int dstX, int dstY, int depthIndex, int copyWidth, int copyHeight, ImageData data) { + + assert (data != null); + + int h; + int rowBegin, // src begin row index + srcBegin, // src begin offset + dstBegin; // dst begin offset + + int dataWidth = data.dataWidth; + int dataHeight = data.dataHeight; + int dstUnitsPerRow = dataWidth * unitsPerPixel; // bytes per row in dst image + rowBegin = srcY; + + if (yUp) { + dstBegin = (depthIndex * dataWidth * dataHeight + dstY * dataWidth + dstX) * unitsPerPixel; + } else { + dstBegin = (depthIndex * dataWidth * dataHeight + (dataHeight - dstY - 1) * dataWidth + dstX) * unitsPerPixel; + dstUnitsPerRow = - 1 * dstUnitsPerRow; + } + + int copyUnits = copyWidth * unitsPerPixel; + int srcWidth = bi.getWidth(); + int srcUnitsPerRow = srcWidth * unitsPerPixel; + srcBegin = (rowBegin * srcWidth + srcX) * unitsPerPixel; + + switch(data.getType()) { + case TYPE_BYTE_ARRAY: + byte[] srcByteBuffer = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData(); + byte[] dstByteBuffer = data.getAsByteArray(); + for (h = 0; h < copyHeight; h++) { + System.arraycopy(srcByteBuffer, srcBegin, dstByteBuffer, dstBegin, copyUnits); + dstBegin += dstUnitsPerRow; + srcBegin += srcUnitsPerRow; + } + break; + + case TYPE_INT_ARRAY: + int[] srcIntBuffer = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + int[] dstIntBuffer = data.getAsIntArray(); + for (h = 0; h < copyHeight; h++) { + System.arraycopy(srcIntBuffer, srcBegin, dstIntBuffer, dstBegin, copyUnits); + dstBegin += dstUnitsPerRow; + srcBegin += srcUnitsPerRow; + } + break; + default: + assert false; + } + + if((imageData == data) && (imageDataPowerOfTwo != null)) { + updateImageDataPowerOfTwo(depthIndex); + } + } + + // Quick block copy for yUp image + void copyImageByBlock(BufferedImage bi, int depthIndex, ImageData data) { + + assert ((data != null) && yUp); + + int dataWidth = data.dataWidth; + int dataHeight = data.dataHeight; + + int dstBegin; // dst begin offset + dstBegin = depthIndex * dataWidth * dataHeight * unitsPerPixel; + + switch(imageData.getType()) { + case TYPE_BYTE_ARRAY: + byte[] srcByteBuffer = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData(); + byte[] dstByteBuffer = data.getAsByteArray(); + System.arraycopy(srcByteBuffer, 0, dstByteBuffer, dstBegin, (dataWidth * dataHeight * unitsPerPixel)); + break; + case TYPE_INT_ARRAY: + int[] srcIntBuffer = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + int[] dstIntBuffer = data.getAsIntArray(); + System.arraycopy(srcIntBuffer, 0, dstIntBuffer, dstBegin, (dataWidth * dataHeight * unitsPerPixel)); + break; + default: + assert false; + } + + if((imageData == data) && (imageDataPowerOfTwo != null)) { + updateImageDataPowerOfTwo(depthIndex); + } + + } + + /** + * copy complete region of a RenderedImage to ImageComponent's imageData object. + */ + void copySupportedImageToImageData(RenderedImage ri, int depthIndex, ImageData data) { + + if (ri instanceof BufferedImage) { + if(yUp) { + /* Use quick block copy when ( format is OK, Yup is true, and byRef is false). */ + // System.err.println("ImageComponentRetained.copySupportedImageToImageData() : (imageTypeSupported && !byReference && yUp) --- (2 BI)"); + copyImageByBlock((BufferedImage)ri, depthIndex, data); + } else { + /* Use quick inverse line by line copy when (format is OK and Yup is false). */ + // System.err.println("ImageComponentRetained.copySupportedImageToImageData() : (imageTypeSupported && !yUp) --- (3 BI)"); + copyImageLineByLine((BufferedImage)ri, 0, 0, 0, 0, depthIndex, data.dataWidth, data.dataHeight, data); + } + } else { + // System.err.println("ImageComponentRetained.copySupportedImageToImageData() : (imageTypeSupported && !byReference ) --- (2 RI)"); + copySupportedImageToImageData(ri, ri.getMinX(), ri.getMinY(), 0, 0, depthIndex, data.dataWidth, data.dataHeight, data); + + /* + * An alternative approach. + * + // Create a buffered image from renderImage + ColorModel cm = ri.getColorModel(); + WritableRaster wRaster = ri.copyData(null); + BufferedImage bi = new BufferedImage(cm, + wRaster, + cm.isAlphaPremultiplied() + ,null); + + copySupportedImageToImageData((BufferedImage)ri, 0, 0, 0, 0, depthIndex, data.dataWidth, data.dataHeight, data); + + * + * + */ + } + } + + /* + * copy the complete unsupported NioImageBuffer into a supported BYTE_BUFFER format + */ + void copyUnsupportedNioImageToImageData(NioImageBuffer nioImage, int srcX, int srcY, + int dstX, int dstY, int copyWidth, int copyHeight, ImageData iData) { + + if (MasterControl.isDevLoggable(Level.INFO)) { + MasterControl.getDevLogger().info("ImageComponent - Copying Unsupported NioImage, use a different image type"); + } + + assert (iData.getType() == ImageDataType.TYPE_BYTE_BUFFER); + assert (getImageFormatType() == ImageFormatType.TYPE_BYTE_RGBA); + + int length = copyWidth * copyHeight; + ByteBuffer srcBuffer = (ByteBuffer) nioImage.getDataBuffer(); + srcBuffer.rewind(); + ByteBuffer dstBuffer = iData.getAsByteBuffer(); + dstBuffer.rewind(); + + // Do copy and swap. + for(int i = 0; i < length; i +=4) { + dstBuffer.put(i, srcBuffer.get(i+3)); + dstBuffer.put(i+1, srcBuffer.get(i+2)); + dstBuffer.put(i+2, srcBuffer.get(i+1)); + dstBuffer.put(i+3, srcBuffer.get(i)); + } + } + + /* + * copy the complete unsupported image into a supported BYTE_ARRAY format + */ + void copyUnsupportedImageToImageData(RenderedImage ri, int depthIndex, ImageData data) { + + assert (data.getType() == ImageDataType.TYPE_BYTE_ARRAY); + + if (MasterControl.isDevLoggable(Level.INFO)) { + MasterControl.getDevLogger().info("ImageComponent - Copying Unsupported Image, use a different image type"); + } + + if (ri instanceof BufferedImage) { + copyUnsupportedImageToImageData((BufferedImage)ri, 0, 0, 0, 0, + depthIndex, data.dataWidth, data.dataHeight, data); + } else { + copyUnsupportedImageToImageData(ri, ri.getMinX(), ri.getMinY(), + 0, 0, depthIndex, data.dataWidth, data.dataHeight, data); + } + } + + void copyUnsupportedImageToImageData(BufferedImage bi, int srcX, int srcY, + int dstX, int dstY, int depthIndex, int copyWidth, int copyHeight, ImageData data) { + + int w, h, i, j; + int rowBegin, // src begin row index + srcBegin, // src begin offset + dstBegin, // dst begin offset + rowInc, // row increment + // -1 --- ydown + // 1 --- yup + row; + + rowBegin = srcY; + rowInc = 1; + + assert (data != null); + + int dataWidth = data.dataWidth; + int dataHeight = data.dataHeight; + int dstBytesPerRow = dataWidth * unitsPerPixel; // bytes per row in dst image + + if (yUp) { + dstBegin = (depthIndex * dataWidth * dataHeight + dstY * dataWidth + dstX) * unitsPerPixel; + } else { + dstBegin = (depthIndex * dataWidth * dataHeight + (dataHeight - dstY - 1) * dataWidth + dstX) * unitsPerPixel; + dstBytesPerRow = - 1 * dstBytesPerRow; + } + + WritableRaster ras = bi.getRaster(); + ColorModel cm = bi.getColorModel(); + Object pixel = getDataElementBuffer(ras); + + byte[] dstBuffer = data.getAsByteArray(); + + switch(numberOfComponents) { + case 4: { + for (row = rowBegin, h = 0; + h < copyHeight; h++, row += rowInc) { + j = dstBegin; + for (w = srcX; w < (copyWidth + srcX); w++) { + ras.getDataElements(w, row, pixel); + dstBuffer[j++] = (byte)cm.getRed(pixel); + dstBuffer[j++] = (byte)cm.getGreen(pixel); + dstBuffer[j++] = (byte)cm.getBlue(pixel); + dstBuffer[j++] = (byte)cm.getAlpha(pixel); + } + dstBegin += dstBytesPerRow; + } + } + break; + + case 3: { + for (row = rowBegin, h = 0; + h < copyHeight; h++, row += rowInc) { + j = dstBegin; + for (w = srcX; w < (copyWidth + srcX); w++) { + ras.getDataElements(w, row, pixel); + dstBuffer[j++] = (byte)cm.getRed(pixel); + dstBuffer[j++] = (byte)cm.getGreen(pixel); + dstBuffer[j++] = (byte)cm.getBlue(pixel); + } + dstBegin += dstBytesPerRow; + } + } + break; + + case 2: { + for (row = rowBegin, h = 0; + h < copyHeight; h++, row += rowInc) { + j = dstBegin; + for (w = srcX; w < (copyWidth + srcX); w++) { + ras.getDataElements(w, row, pixel); + dstBuffer[j++] = (byte)cm.getRed(pixel); + dstBuffer[j++] = (byte)cm.getAlpha(pixel); + } + dstBegin += dstBytesPerRow; + } + } + break; + + case 1: { + for (row = rowBegin, h = 0; + h < copyHeight; h++, row += rowInc) { + j = dstBegin; + for (w = srcX; w < (copyWidth + srcX); w++) { + ras.getDataElements(w, row, pixel); + dstBuffer[j++] = (byte)cm.getRed(pixel); + } + dstBegin += dstBytesPerRow; + } + } + break; + default: + assert false; + } + + if((imageData == data) && (imageDataPowerOfTwo != null)) { + updateImageDataPowerOfTwo(depthIndex); + } + } + + void copyUnsupportedImageToImageData(RenderedImage ri, int srcX, int srcY, + int dstX, int dstY, int depthIndex, int copyWidth, int copyHeight, ImageData data) { + + int w, h, i, j, m, n; + int dstBegin; + Object pixel = null; + java.awt.image.Raster ras; + // dst image buffer + int sign; // -1 for going down + int dstLineBytes; // sign * lineBytes + int tileStart; // destination buffer offset + // at the next left most tile + + int offset; + + ColorModel cm = ri.getColorModel(); + + int xoff = ri.getTileGridXOffset(); // tile origin x offset + int yoff = ri.getTileGridYOffset(); // tile origin y offset + int minTileX = ri.getMinTileX(); // min tile x index + int minTileY = ri.getMinTileY(); // min tile y index + tilew = ri.getTileWidth(); // tile width in pixels + tileh = ri.getTileHeight(); // tile height in pixels + + // determine the first tile of the image + + float mt; + + mt = (float)(srcX - xoff) / (float)tilew; + if (mt < 0) { + minTileX = (int)(mt - 1); + } else { + minTileX = (int)mt; + } + + mt = (float)(srcY - yoff) / (float)tileh; + if (mt < 0) { + minTileY = (int)(mt - 1); + } else { + minTileY = (int)mt; + } + + // determine the pixel offset of the upper-left corner of the + // first tile + int startXTile = minTileX * tilew + xoff; + int startYTile = minTileY * tileh + yoff; + + + // image dimension in the first tile + int curw = (startXTile + tilew - srcX); + int curh = (startYTile + tileh - srcY); + + // check if the to-be-copied region is less than the tile image + // if so, update the to-be-copied dimension of this tile + if (curw > copyWidth) { + curw = copyWidth; + } + + if (curh > copyHeight) { + curh = copyHeight; + } + + // save the to-be-copied width of the left most tile + int startw = curw; + + + // temporary variable for dimension of the to-be-copied region + int tmpw = copyWidth; + int tmph = copyHeight; + + + // offset of the first pixel of the tile to be copied; offset is + // relative to the upper left corner of the title + int x = srcX - startXTile; + int y = srcY - startYTile; + + + // determine the number of tiles in each direction that the + // image spans + + numXTiles = (copyWidth + x) / tilew; + numYTiles = (copyHeight + y) / tileh; + + if (((float)(copyWidth + x ) % (float)tilew) > 0) { + numXTiles += 1; + } + + if (((float)(copyHeight + y ) % (float)tileh) > 0) { + numYTiles += 1; + } + + assert (data != null); + int dataWidth = data.dataWidth; + int dataHeight = data.dataHeight; + int lineBytes = dataWidth * unitsPerPixel; // nbytes per line in + + if (yUp) { + // destination buffer offset + tileStart = (depthIndex * dataWidth * dataHeight + dstY * dataWidth + dstX) * unitsPerPixel; + sign = 1; + dstLineBytes = lineBytes; + } else { + // destination buffer offset + tileStart = (depthIndex * dataWidth * dataHeight + (dataHeight - dstY - 1) * dataWidth + dstX) * unitsPerPixel; + sign = -1; + dstLineBytes = -lineBytes; + } + +/* + System.err.println("tileStart= " + tileStart + " dstLineBytes= " + dstLineBytes); + System.err.println("startw= " + startw); + */ + + // allocate memory for a pixel + ras = ri.getTile(minTileX,minTileY); + pixel = getDataElementBuffer(ras); + byte[] dstBuffer = imageData.getAsByteArray(); + + switch(numberOfComponents) { + case 4: { + // System.err.println("Case 1: byReference = "+byReference); + for (n = minTileY; n < minTileY+numYTiles; n++) { + + dstBegin = tileStart; // destination buffer offset + tmpw = copyWidth; // reset the width to be copied + curw = startw; // reset the width to be copied of + // the left most tile + x = srcX - startXTile; // reset the starting x offset of + // the left most tile + + for (m = minTileX; m < minTileX+numXTiles; m++) { + + // retrieve the raster for the next tile + ras = ri.getTile(m,n); + + j = dstBegin; + offset = 0; + + //System.err.println("curh = "+curh+" curw = "+curw); + //System.err.println("x = "+x+" y = "+y); + + for (h = y; h < (y + curh); h++) { + // System.err.println("j = "+j); + for (w = x; w < (x + curw); w++) { + ras.getDataElements(w, h, pixel); + dstBuffer[j++] = (byte)cm.getRed(pixel); + dstBuffer[j++] = (byte)cm.getGreen(pixel); + dstBuffer[j++] = (byte)cm.getBlue(pixel); + dstBuffer[j++] = (byte)cm.getAlpha(pixel); + } + offset += dstLineBytes; + j = dstBegin + offset; + } + + // advance the destination buffer offset + dstBegin += curw * unitsPerPixel; + + // move to the next tile in x direction + x = 0; + + // determine the width of copy region of the next tile + + tmpw -= curw; + if (tmpw < tilew) { + curw = tmpw; + } else { + curw = tilew; + } + } + + // we are done copying an array of tiles in the x direction + // advance the tileStart offset + + tileStart += dataWidth * unitsPerPixel * curh * sign; + + // move to the next set of tiles in y direction + y = 0; + + // determine the height of copy region for the next set + // of tiles + tmph -= curh; + if (tmph < tileh) { + curh = tmph; + } else { + curh = tileh; + } + } + } + break; + case 3: { + for (n = minTileY; n < minTileY+numYTiles; n++) { + + dstBegin = tileStart; // destination buffer offset + tmpw = copyWidth; // reset the width to be copied + curw = startw; // reset the width to be copied of + // the left most tile + x = srcX - startXTile; // reset the starting x offset of + // the left most tile + + for (m = minTileX; m < minTileX+numXTiles; m++) { + + // retrieve the raster for the next tile + ras = ri.getTile(m,n); + + j = dstBegin; + offset = 0; + + //System.err.println("curh = "+curh+" curw = "+curw); + //System.err.println("x = "+x+" y = "+y); + + for (h = y; h < (y + curh); h++) { + // System.err.println("j = "+j); + for (w = x; w < (x + curw); w++) { + ras.getDataElements(w, h, pixel); + dstBuffer[j++] = (byte)cm.getRed(pixel); + dstBuffer[j++] = (byte)cm.getGreen(pixel); + dstBuffer[j++] = (byte)cm.getBlue(pixel); + } + offset += dstLineBytes; + j = dstBegin + offset; + } + + // advance the destination buffer offset + dstBegin += curw * unitsPerPixel; + + // move to the next tile in x direction + x = 0; + + // determine the width of copy region of the next tile + + tmpw -= curw; + if (tmpw < tilew) { + curw = tmpw; + } else { + curw = tilew; + } + } + + // we are done copying an array of tiles in the x direction + // advance the tileStart offset + + tileStart += dataWidth * unitsPerPixel * curh * sign; + + // move to the next set of tiles in y direction + y = 0; + + // determine the height of copy region for the next set + // of tiles + tmph -= curh; + if (tmph < tileh) { + curh = tmph; + } else { + curh = tileh; + } + } + } + break; + case 2: { + for (n = minTileY; n < minTileY+numYTiles; n++) { + + dstBegin = tileStart; // destination buffer offset + tmpw = copyWidth; // reset the width to be copied + curw = startw; // reset the width to be copied of + // the left most tile + x = srcX - startXTile; // reset the starting x offset of + // the left most tile + + for (m = minTileX; m < minTileX+numXTiles; m++) { + + // retrieve the raster for the next tile + ras = ri.getTile(m,n); + + j = dstBegin; + offset = 0; + + //System.err.println("curh = "+curh+" curw = "+curw); + //System.err.println("x = "+x+" y = "+y); + + for (h = y; h < (y + curh); h++) { + // System.err.println("j = "+j); + for (w = x; w < (x + curw); w++) { + ras.getDataElements(w, h, pixel); + dstBuffer[j++] = (byte)cm.getRed(pixel); + dstBuffer[j++] = (byte)cm.getAlpha(pixel); + } + offset += dstLineBytes; + j = dstBegin + offset; + } + + // advance the destination buffer offset + dstBegin += curw * unitsPerPixel; + + // move to the next tile in x direction + x = 0; + + // determine the width of copy region of the next tile + + tmpw -= curw; + if (tmpw < tilew) { + curw = tmpw; + } else { + curw = tilew; + } + } + + + // we are done copying an array of tiles in the x direction + // advance the tileStart offset + + tileStart += dataWidth * unitsPerPixel * curh * sign; + + + // move to the next set of tiles in y direction + y = 0; + + // determine the height of copy region for the next set + // of tiles + tmph -= curh; + if (tmph < tileh) { + curh = tmph; + } else { + curh = tileh; + } + } + } + break; + case 1: { + for (n = minTileY; n < minTileY+numYTiles; n++) { + + dstBegin = tileStart; // destination buffer offset + tmpw = copyWidth; // reset the width to be copied + curw = startw; // reset the width to be copied of + // the left most tile + x = srcX - startXTile; // reset the starting x offset of + // the left most tile + + for (m = minTileX; m < minTileX+numXTiles; m++) { + + // retrieve the raster for the next tile + ras = ri.getTile(m,n); + + j = dstBegin; + offset = 0; + + //System.err.println("curh = "+curh+" curw = "+curw); + //System.err.println("x = "+x+" y = "+y); + + for (h = y; h < (y + curh); h++) { + // System.err.println("j = "+j); + for (w = x; w < (x + curw); w++) { + ras.getDataElements(w, h, pixel); + dstBuffer[j++] = (byte)cm.getRed(pixel); + } + offset += dstLineBytes; + j = dstBegin + offset; + } + + // advance the destination buffer offset + dstBegin += curw * unitsPerPixel; + + // move to the next tile in x direction + x = 0; + + // determine the width of copy region of the next tile + + tmpw -= curw; + if (tmpw < tilew) { + curw = tmpw; + } else { + curw = tilew; + } + } + + // we are done copying an array of tiles in the x direction + // advance the tileStart offset + tileStart += dataWidth * unitsPerPixel * curh * sign; + + // move to the next set of tiles in y direction + y = 0; + + // determine the height of copy region for the next set + // of tiles + tmph -= curh; + if (tmph < tileh) { + curh = tmph; + } else { + curh = tileh; + } + } + } + break; + + default: + assert false; + } + + if((imageData == data) && (imageDataPowerOfTwo != null)) { + updateImageDataPowerOfTwo(depthIndex); + } + } + + + void evaluateExtensions(Canvas3D canvas) { + // Issue 366: need to synchronize since it could be called concurrently + // from multiple renderers (and maybe the renderer(s) and renderbin) + synchronized (evaluateExtLock) { + // For performance reason the ordering of the following 2 statements is intentional. + // So that we only need to do format conversion for imageData only + evaluateExtABGR(canvas.extensionsSupported); + evaluateExtNonPowerOfTwo(canvas.textureExtendedFeatures); + } + + } + + + void evaluateExtABGR(int ext) { + + + // If abgrSupported is false, a copy has been created so + // we don't have to check again. + if(!abgrSupported) { + return; + } + + if(getImageFormatType() != ImageFormatType.TYPE_BYTE_ABGR) { + return; + } + + if((ext & Canvas3D.EXT_ABGR) != 0) { + return; + } + + // ABGR is unsupported, set flag to false. + abgrSupported = false; + convertImageDataFromABGRToRGBA(); + + } + + private int getClosestPowerOf2(int value) { + + if (value < 1) + return value; + + int powerValue = 1; + for (;;) { + powerValue *= 2; + if (value < powerValue) { + // Found max bound of power, determine which is closest + int minBound = powerValue/2; + if ((powerValue - value) > + (value - minBound)) + return minBound; + else + return powerValue; + } + } + } + + private int getCeilPowerOf2(int value) { + + if (value < 1) + return value; + + int powerValue = 1; + for (;;) { + powerValue *= 2; + if (value <= powerValue) { + // Found max bound of power + return powerValue; + } + } + } + + void evaluateExtNonPowerOfTwo(int ext) { + // Only need to enforce for Raster or Background. + if(!enforceNonPowerOfTwoSupport) { + return; + } + + // If npotSupported is false, a copy power of two image has been created + // so we don't have to check again. + if(!npotSupported) { + return; + } + + if (imageData == null && !isByReference()) { + return; + } + + if((ext & Canvas3D.TEXTURE_NON_POWER_OF_TWO) != 0) { + return; + } + + // NPOT is unsupported, set flag to false. + npotSupported = false; + + int npotWidth; + int npotHeight; + // Always scale up if image size is smaller 512*512. + if((width * height) < IMAGE_SIZE_512X512) { + npotWidth = getCeilPowerOf2(width); + npotHeight = getCeilPowerOf2(height); + } else { + npotWidth = getClosestPowerOf2(width); + npotHeight = getClosestPowerOf2(height); + } + + // System.err.println("width " + width + " height " + height + " npotWidth " + npotWidth + " npotHeight " + npotHeight); + + float xScale = (float)npotWidth/(float)width; + float yScale = (float)npotHeight/(float)height; + + // scale if scales aren't 1.0 + if (!(xScale == 1.0f && yScale == 1.0f)) { + + if (imageData == null) { + // This is a byRef, support format and is a RenderedImage case. + // See ImageComponent2DRetained.set(RenderedImage image) + RenderedImage ri = (RenderedImage) getRefImage(0); + + assert !(ri instanceof BufferedImage); + + // Create a buffered image from renderImage + ColorModel cm = ri.getColorModel(); + WritableRaster wRaster = ri.copyData(null); + ri = new BufferedImage(cm, + wRaster, + cm.isAlphaPremultiplied() + ,null); + + + // Create image data object with buffer for image. */ + imageData = createRenderedImageDataObject(null); + copySupportedImageToImageData(ri, 0, imageData); + + } + + assert imageData != null; + + // Create a supported BufferedImage type. + BufferedImage bi = imageData.createBufferedImage(0); + + int imageType = bi.getType(); + BufferedImage scaledImg = new BufferedImage(npotWidth, npotHeight, imageType); + + AffineTransform at = AffineTransform.getScaleInstance(xScale, + yScale); + + powerOfTwoATOp = new AffineTransformOp(at, + AffineTransformOp.TYPE_BILINEAR); + + powerOfTwoATOp.filter(bi, scaledImg); + + // System.err.println("bi " + bi.getColorModel()); + // System.err.println("scaledImg " + scaledImg.getColorModel()); + + imageDataPowerOfTwo = createRenderedImageDataObject(null, npotWidth, npotHeight); + // Since bi is created from imageData, it's imageType is supported. + copySupportedImageToImageData(scaledImg, 0, imageDataPowerOfTwo); + + } else { + imageDataPowerOfTwo = null; + } + } + + void convertImageDataFromABGRToRGBA() { + + // Unsupported format on HW, switch to slow copy. + imageFormatType = ImageFormatType.TYPE_BYTE_RGBA; + imageTypeIsSupported = false; + + // Only need to convert imageData + imageData.convertFromABGRToRGBA(); + + } + + /** + * Copy supported ImageType from ImageData to the user defined bufferedImage + */ + void copyToRefImage(int depth) { + int h; + int rowBegin, // src begin row index + srcBegin, // src begin offset + dstBegin; // dst begin offset + + // refImage has to be a BufferedImage for off screen and read raster + assert refImage[depth] != null; + assert (refImage[depth] instanceof BufferedImage); + + BufferedImage bi = (BufferedImage)refImage[depth]; + int dstUnitsPerRow = width * unitsPerPixel; // bytes per row in dst image + rowBegin = 0; + + if (yUp) { + dstBegin = (depth * width * height) * unitsPerPixel; + } else { + dstBegin = (depth * width * height + (height - 1) * width ) * unitsPerPixel; + dstUnitsPerRow = - 1 * dstUnitsPerRow; + } + + int scanline = width * unitsPerPixel; + srcBegin = (rowBegin * width ) * unitsPerPixel; + + switch(imageData.getType()) { + case TYPE_BYTE_ARRAY: + byte[] dstByteBuffer = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData(); + byte[] srcByteBuffer = imageData.getAsByteArray(); + for (h = 0; h < height; h++) { + System.arraycopy(srcByteBuffer, srcBegin, dstByteBuffer, dstBegin, scanline); + dstBegin += dstUnitsPerRow; + srcBegin += scanline; + } + break; + + case TYPE_INT_ARRAY: + int[] dstIntBuffer = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + int[] srcIntBuffer = imageData.getAsIntArray(); + for (h = 0; h < height; h++) { + System.arraycopy(srcIntBuffer, srcBegin, dstIntBuffer, dstBegin, scanline); + dstBegin += dstUnitsPerRow; + srcBegin += scanline; + } + break; + default: + assert false; + } + + } + + /** + * Copy image to the user defined bufferedImage ( 3 or 4 components only ) + */ + void copyToRefImageWithFormatConversion(int depth) { + int w, h, i, j; + int dstBegin, dstInc, dstIndex, dstIndexInc; + // refImage has to be a BufferedImage for off screen and read raster + assert refImage[depth] != null; + assert (refImage[depth] instanceof BufferedImage); + + BufferedImage bi = (BufferedImage)refImage[depth]; + int biType = bi.getType(); + byte[] buf = imageData.getAsByteArray(); + + // convert from Ydown to Yup for texture + if (!yUp) { + dstInc = -1 * width; + dstBegin = (height - 1) * width; + dstIndex = height -1; + dstIndexInc = -1; + } else { + dstInc = width; + dstBegin = 0; + dstIndex = 0; + dstIndexInc = 1; + } + + switch (biType) { + case BufferedImage.TYPE_INT_ARGB: + int[] intData = + ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + // Multiply by 4 to get the byte incr and start point + j = 0; + switch (imageFormatType) { + case TYPE_BYTE_RGBA: + for(h = 0; h < height; h++, dstBegin += dstInc) { + i = dstBegin; + for (w = 0; w < width; w++, j+=4, i++) { + intData[i] = (((buf[j+3] &0xff) << 24) | // a + ((buf[j] &0xff) << 16) | // r + ((buf[j+1] &0xff) << 8) | // g + (buf[j+2] & 0xff)); // b + } + } + break; + case TYPE_BYTE_RGB: + for(h = 0; h < height; h++, dstBegin += dstInc) { + i = dstBegin; + for (w = 0; w < width; w++, j+=3, i++) { + intData[i] = (0xff000000 | // a + ((buf[j] &0xff) << 16) | // r + ((buf[j+1] &0xff) << 8) | // g + (buf[j+2] & 0xff)); // b + } + } + break; + default: + assert false; + } + break; + + case BufferedImage.TYPE_INT_RGB: + intData = + ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + // Multiply by 4 to get the byte incr and start point + j = 0; + for(h = 0; h < height; h++, dstBegin += dstInc) { + i = dstBegin; + for (w = 0; w < width; w++, j+=4, i++) { + intData[i] = (0xff000000 | // a + ((buf[j] &0xff) << 16) | // r + ((buf[j+1] &0xff) << 8) | // g + (buf[j+2] & 0xff)); // b + } + } + break; + + case BufferedImage.TYPE_4BYTE_ABGR: + byte[] byteData = + ((DataBufferByte)bi.getRaster().getDataBuffer()).getData(); + // Multiply by 4 to get the byte incr and start point + j = 0; + + //Issue 381: dstBegin contains pixel count, but we are looping over byte count. In case of YDown, it contains a count that is decremented and if we do not multiply, we have an AIOOB thrown at 25% of the copy. + dstBegin <<= 2; + + switch (imageFormatType) { + case TYPE_BYTE_RGBA: + for(h = 0; h < height; h++, dstBegin += (dstInc << 2)) { + i = dstBegin; + for (w = 0; w < width; w++, j+=4) { + byteData[i++] = buf[j+3]; // a + byteData[i++] = buf[j+2]; // b + byteData[i++] = buf[j+1];// g + byteData[i++] = buf[j]; // r + } + } + break; + case TYPE_BYTE_RGB: + for(h = 0; h < height; h++, dstBegin += (dstInc << 2)) { + i = dstBegin; + for (w = 0; w < width; w++, j+=3) { + byteData[i++] = (byte) 0xff; // a + byteData[i++] = buf[j+2]; // b + byteData[i++] = buf[j+1];// g + byteData[i++] = buf[j]; // r + } + } + break; + default: + assert false; + } + break; + + case BufferedImage.TYPE_INT_BGR: + intData = + ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + // Multiply by 4 to get the byte incr and start point + j = 0; + + for(h = 0; h < height; h++, dstBegin += dstInc) { + i = dstBegin; + for (w = 0; w < width; w++, j+=4, i++) { + intData[i] = (0xff000000 | // a + ((buf[j] &0xff) ) | // r + ((buf[j+1] &0xff) << 8) | // g + (buf[j+2] & 0xff)<< 16); // b + } + } + break; + default: + assert false; + } + + } + + // Add a user to the userList + synchronized void addUser(NodeComponentRetained node) { + userList.add(node); + } + + // Add a user to the userList + synchronized void removeUser(NodeComponentRetained node) { + int i = userList.indexOf(node); + if (i >= 0) { + userList.remove(i); + } + } + + /* + * + * @exception IllegalSharingException if this image is + * being used by a Canvas3D as an off-screen buffer. + */ + void setLive(boolean inBackgroundGroup, int refCount) { + // Do illegalSharing check. + if(getUsedByOffScreen()) { + throw new IllegalSharingException(J3dI18N.getString("ImageComponent3")); + } + super.setLive(inBackgroundGroup, refCount); + } + + /** + * ImageComponent object doesn't really have mirror object. + * But it's using the updateMirrorObject interface to propagate + * the changes to the users + */ + synchronized void updateMirrorObject(int component, Object value) { + + //System.err.println("ImageComponent.updateMirrorObject"); + + Object user; + + if (((component & IMAGE_CHANGED) != 0) || + ((component & SUBIMAGE_CHANGED) != 0)) { + synchronized(userList) { + for (int i = userList.size()-1; i >=0; i--) { + user = userList.get(i); + if (user != null) { + if (user instanceof TextureRetained) { + ((TextureRetained)user).notifyImageComponentImageChanged(this, (ImageComponentUpdateInfo)value); + } else if (user instanceof RasterRetained) { + ((RasterRetained)user).notifyImageComponentImageChanged(this, (ImageComponentUpdateInfo)value); + } else if (user instanceof BackgroundRetained) { + ((BackgroundRetained)user).notifyImageComponentImageChanged(this, (ImageComponentUpdateInfo)value); + } + } + } + } + } + } + + final void sendMessage(int attrMask, Object attr) { + + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES | + J3dThread.UPDATE_RENDER; + createMessage.type = J3dMessage.IMAGE_COMPONENT_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + } + + void handleFrequencyChange(int bit) { + if (bit == ImageComponent.ALLOW_IMAGE_WRITE) { + setFrequencyChangeMask(ImageComponent.ALLOW_IMAGE_WRITE, 0x1); + } + } + + static Object getDataElementBuffer(java.awt.image.Raster ras) { + int nc = ras.getNumDataElements(); + + switch (ras.getTransferType()) { + case DataBuffer.TYPE_INT: + return new int[nc]; + case DataBuffer.TYPE_BYTE: + return new byte[nc]; + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_SHORT: + return new short[nc]; + case DataBuffer.TYPE_FLOAT: + return new float[nc]; + case DataBuffer.TYPE_DOUBLE: + return new double[nc]; + } + // Should not happen + return null; + } + + /** + * Wrapper class for image data. + * Currently supports byte array and int array. + * Will eventually support NIO ByteBuffer and IntBuffer. + */ + class ImageData { + + private Object data = null; + private ImageDataType imageDataType = ImageDataType.TYPE_NULL; + private int length = 0; + private boolean dataIsByRef = false; + private int dataWidth, dataHeight; + + /** + * Constructs a new ImageData buffer of the specified type with the + * specified length. + */ + ImageData(ImageDataType imageDataType, int length, int dataWidth, int dataHeight) { + this.imageDataType = imageDataType; + this.length = length; + this.dataWidth = dataWidth; + this.dataHeight = dataHeight; + this.dataIsByRef = false; + + switch (imageDataType) { + case TYPE_BYTE_ARRAY: + data = new byte[length]; + break; + case TYPE_INT_ARRAY: + data = new int[length]; + break; + case TYPE_BYTE_BUFFER: + ByteOrder order = ByteOrder.nativeOrder(); + data = ByteBuffer.allocateDirect(length).order(order); + break; + case TYPE_INT_BUFFER: + default: + throw new AssertionError(); + } + } + + /** + * Constructs a new ImageData buffer of the specified type with the + * specified length and the specified byRefImage as data. + */ + ImageData(ImageDataType imageDataType, int length, int dataWidth, int dataHeight, + Object byRefImage) { + BufferedImage bi; + NioImageBuffer nio; + + this.imageDataType = imageDataType; + this.length = length; + this.dataWidth = dataWidth; + this.dataHeight = dataHeight; + this.dataIsByRef = true; + + switch (imageDataType) { + case TYPE_BYTE_ARRAY: + bi = (BufferedImage) byRefImage; + data = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData(); + break; + case TYPE_INT_ARRAY: + bi = (BufferedImage) byRefImage; + data = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + break; + case TYPE_BYTE_BUFFER: + case TYPE_INT_BUFFER: + nio = (NioImageBuffer) byRefImage; + data = nio.getDataBuffer(); + break; + default: + throw new AssertionError(); + } + } + + /** + * Constructs a new ImageData buffer from the specified + * object. This object stores a reference to the input image data. + */ + ImageData(Object data, boolean isByRef) { + this.data = data; + dataIsByRef = isByRef; + dataWidth = ((ImageData) data).dataWidth; + dataHeight = ((ImageData) data).dataHeight; + + if (data == null) { + imageDataType = ImageDataType.TYPE_NULL; + length = 0; + } else if (data instanceof byte[]) { + imageDataType = ImageDataType.TYPE_BYTE_ARRAY; + length = ((byte[]) data).length; + } else if (data instanceof int[]) { + imageDataType = ImageDataType.TYPE_INT_ARRAY; + length = ((int[]) data).length; + } else if (data instanceof ByteBuffer) { + imageDataType = ImageDataType.TYPE_BYTE_BUFFER; + length = ((ByteBuffer) data).limit(); + } else if (data instanceof IntBuffer) { + imageDataType = ImageDataType.TYPE_INT_BUFFER; + length = ((IntBuffer) data).limit(); + } else { + assert false; + } + } + + /** + * Returns the type of this DataBuffer. + */ + ImageDataType getType() { + return imageDataType; + } + + /** + * Returns the number of elements in this DataBuffer. + */ + int length() { + return length; + } + + /** + * Returns the width of this DataBuffer. + */ + int getWidth() { + return dataWidth; + } + + /** + * Returns the height of this DataBuffer. + */ + int getHeight() { + return dataHeight; + } + + /** + * Returns this DataBuffer as an Object. + */ + Object get() { + return data; + } + + /** + * Returns is this data is byRef. No internal data is made. + */ + boolean isDataByRef() { + return dataIsByRef; + } + + + /** + * Returns this DataBuffer as a byte array. + */ + byte[] getAsByteArray() { + return (byte[]) data; + } + + /** + * Returns this DataBuffer as an int array. + */ + int[] getAsIntArray() { + return (int[]) data; + } + + /** + * Returns this DataBuffer as an nio ByteBuffer. + */ + ByteBuffer getAsByteBuffer() { + return (ByteBuffer) data; + } + + /** + * Returns this DataBuffer as an nio IntBuffer. + */ + IntBuffer getAsIntBuffer() { + return (IntBuffer) data; + } + + // Handle TYPE_BYTE_LA only + void copyByLineAndExpand(BufferedImage bi, int depthIndex) { + int h; + int srcBegin, // src begin offset + dstBegin; // dst begin offset + + assert (imageData.getType() == ImageDataType.TYPE_BYTE_ARRAY); + assert (imageFormatType == ImageFormatType.TYPE_BYTE_LA); + + int unitsPerRow = width * unitsPerPixel; // bytes per row + int scanline = unitsPerRow; + if (yUp) { + srcBegin = (depthIndex * width * height) * unitsPerPixel; + } else { + srcBegin = (depthIndex * width * height + (height - 1) * width) * unitsPerPixel; + unitsPerRow = - 1 * unitsPerRow; + } + + dstBegin = 0; + // ABGR is 4 bytes per pixel + int dstUnitsPerRow = width * 4; + + byte[] dstByteBuffer = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData(); + byte[] srcByteBuffer = imageData.getAsByteArray(); + for (h = 0; h < height; h++) { + for( int v = 0, w = 0; w < scanline; w += unitsPerPixel, v += 4) { + dstByteBuffer[dstBegin+v] = srcByteBuffer[srcBegin+w+1]; // Alpha + dstByteBuffer[dstBegin+v+1] = 0; + dstByteBuffer[dstBegin+v+2] = 0; + dstByteBuffer[dstBegin+v+3] = srcByteBuffer[srcBegin+w]; // Red + } + + dstBegin += dstUnitsPerRow; + srcBegin += unitsPerRow; + } + + } + + // Quick line by line copy + void copyByLine(BufferedImage bi, int depthIndex, boolean swapNeeded) { + + int h; + int srcBegin, // src begin offset + dstBegin; // dst begin offset + + int unitsPerRow = width * unitsPerPixel; // bytes per row + int copyUnits = unitsPerRow; + if (yUp) { + srcBegin = (depthIndex * width * height) * unitsPerPixel; + } else { + srcBegin = (depthIndex * width * height + (height - 1) * width) * unitsPerPixel; + unitsPerRow = - 1 * unitsPerRow; + } + + dstBegin = 0; + + switch(imageData.getType()) { + case TYPE_BYTE_ARRAY: + byte[] dstByteBuffer = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData(); + byte[] srcByteBuffer = imageData.getAsByteArray(); + for (h = 0; h < height; h++) { + if(!swapNeeded) { + System.arraycopy(srcByteBuffer, srcBegin, + dstByteBuffer, dstBegin, copyUnits); + } else { + if(imageFormatType == ImageFormatType.TYPE_BYTE_RGB) { + assert (unitsPerPixel == 3); + for(int w = 0; w < copyUnits; w += unitsPerPixel) { + dstByteBuffer[dstBegin+w] = srcByteBuffer[srcBegin+w+2]; + dstByteBuffer[dstBegin+w+1] = srcByteBuffer[srcBegin+w+1]; + dstByteBuffer[dstBegin+w+2] = srcByteBuffer[srcBegin+w]; + } + } else if(imageFormatType == ImageFormatType.TYPE_BYTE_RGBA) { + assert (unitsPerPixel == 4); + for(int w = 0; w < copyUnits; w += unitsPerPixel) { + dstByteBuffer[dstBegin+w] = srcByteBuffer[srcBegin+w+3]; + dstByteBuffer[dstBegin+w+1] = srcByteBuffer[srcBegin+w+2]; + dstByteBuffer[dstBegin+w+2] = srcByteBuffer[srcBegin+w+1]; + dstByteBuffer[dstBegin+w+3] = srcByteBuffer[srcBegin+w]; + } + } else { + assert false; + } + } + dstBegin += copyUnits; + srcBegin += unitsPerRow; + } + break; + + // INT case doesn't required to handle swapNeeded + case TYPE_INT_ARRAY: + assert (!swapNeeded); + int[] dstIntBuffer = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + int[] srcIntBuffer = imageData.getAsIntArray(); + for (h = 0; h < height; h++) { + System.arraycopy(srcIntBuffer, srcBegin, dstIntBuffer, dstBegin, copyUnits); + dstBegin += copyUnits; + srcBegin += unitsPerRow; + } + break; + default: + assert false; + } + } + + void copyByBlock(BufferedImage bi, int depthIndex) { + // src begin offset + int srcBegin = depthIndex * width * height * unitsPerPixel; + + switch(imageData.getType()) { + case TYPE_BYTE_ARRAY: + byte[] dstByteBuffer = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData(); + byte[] srcByteBuffer = imageData.getAsByteArray(); + System.arraycopy(srcByteBuffer, srcBegin, dstByteBuffer, 0, (height * width * unitsPerPixel)); + break; + case TYPE_INT_ARRAY: + int[] dstIntBuffer = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + int[] srcIntBuffer = imageData.getAsIntArray(); + System.arraycopy(srcIntBuffer, srcBegin, dstIntBuffer, 0, (height * width * unitsPerPixel)); + break; + default: + assert false; + } + } + + // Need to check for imageData is null. if it is null return null. + BufferedImage createBufferedImage(int depthIndex) { + if(data != null) { + int bufferType = BufferedImage.TYPE_CUSTOM; + boolean swapNeeded = false; + + switch(imageFormatType) { + case TYPE_BYTE_BGR: + bufferType = BufferedImage.TYPE_3BYTE_BGR; + break; + case TYPE_BYTE_RGB: + bufferType = BufferedImage.TYPE_3BYTE_BGR; + swapNeeded = true; + break; + case TYPE_BYTE_ABGR: + bufferType = BufferedImage.TYPE_4BYTE_ABGR; + break; + case TYPE_BYTE_RGBA: + bufferType = BufferedImage.TYPE_4BYTE_ABGR; + swapNeeded = true; + break; + // This is a special case. Need to handle separately. + case TYPE_BYTE_LA: + bufferType = BufferedImage.TYPE_4BYTE_ABGR; + break; + case TYPE_BYTE_GRAY: + bufferType = BufferedImage.TYPE_BYTE_GRAY; + break; + case TYPE_INT_BGR: + bufferType = BufferedImage.TYPE_INT_BGR; + break; + case TYPE_INT_RGB: + bufferType = BufferedImage.TYPE_INT_RGB; + break; + case TYPE_INT_ARGB: + bufferType = BufferedImage.TYPE_INT_ARGB; + break; + // Unsupported case, so shouldn't be here. + case TYPE_USHORT_GRAY: + bufferType = BufferedImage.TYPE_USHORT_GRAY; + default: + assert false; + + } + + BufferedImage bi = new BufferedImage(width, height, bufferType); + if((!swapNeeded) && (imageFormatType != ImageFormatType.TYPE_BYTE_LA)) { + if(yUp) { + copyByBlock(bi, depthIndex); + } else { + copyByLine(bi, depthIndex, false); + } + } else if(swapNeeded) { + copyByLine(bi, depthIndex, swapNeeded); + } else if(imageFormatType == ImageFormatType.TYPE_BYTE_LA) { + copyByLineAndExpand(bi, depthIndex); + } else { + assert false; + } + + return bi; + + } + return null; + } + + void convertFromABGRToRGBA() { + int i; + + if(imageDataType == ImageComponentRetained.ImageDataType.TYPE_BYTE_ARRAY) { + // Note : Highly inefficient for depth > 0 case. + // This method doesn't take into account of depth, it is assuming that + // depth == 0, which is true for ImageComponent2D. + byte[] srcBuffer, dstBuffer; + srcBuffer = getAsByteArray(); + + if(dataIsByRef) { + dstBuffer = new byte[length]; + // Do copy and swap. + for(i = 0; i < length; i +=4) { + dstBuffer[i] = srcBuffer[i+3]; + dstBuffer[i+1] = srcBuffer[i+2]; + dstBuffer[i+2] = srcBuffer[i+1]; + dstBuffer[i+3] = srcBuffer[i]; + } + data = dstBuffer; + dataIsByRef = false; + + } else { + byte a, b; + // Do swap in place. + for(i = 0; i < length; i +=4) { + a = srcBuffer[i]; + b = srcBuffer[i+1]; + srcBuffer[i] = srcBuffer[i+3]; + srcBuffer[i+1] = srcBuffer[i+2]; + srcBuffer[i+2] = b; + srcBuffer[i+3] = a; + } + } + } + else if(imageDataType == ImageComponentRetained.ImageDataType.TYPE_BYTE_BUFFER) { + + assert dataIsByRef; + ByteBuffer srcBuffer, dstBuffer; + + srcBuffer = getAsByteBuffer(); + srcBuffer.rewind(); + + ByteOrder order = ByteOrder.nativeOrder(); + dstBuffer = ByteBuffer.allocateDirect(length).order(order); + dstBuffer.rewind(); + + // Do copy and swap. + for(i = 0; i < length; i +=4) { + dstBuffer.put(i, srcBuffer.get(i+3)); + dstBuffer.put(i+1, srcBuffer.get(i+2)); + dstBuffer.put(i+2, srcBuffer.get(i+1)); + dstBuffer.put(i+3, srcBuffer.get(i)); + } + + dataIsByRef = false; + + } + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ImageComponentUpdateInfo.java b/j3d-core/src/classes/share/javax/media/j3d/ImageComponentUpdateInfo.java new file mode 100644 index 0000000..be48742 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ImageComponentUpdateInfo.java @@ -0,0 +1,49 @@ +/* + * $RCSfile: ImageComponentUpdateInfo.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Image Component update information for the users + */ +class ImageComponentUpdateInfo extends Object { + + int x = 0; + int y = 0; + int z = 0; + int width = 0; + int height = 0; + int updateMask = 0; // which resources need to be updated + // canvas or renderer + boolean entireImage = false;// true if the entire image needs to be updated + // then none of the dimension info is to be + // applied. +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryArray.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryArray.java new file mode 100644 index 0000000..0a71320 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryArray.java @@ -0,0 +1,1276 @@ +/* + * $RCSfile: IndexedGeometryArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The IndexedGeometryArray object contains separate integer arrays + * that index into the arrays of positional coordinates, colors, + * normals, texture coordinates, and vertex attributes. + * These index arrays specify how + * vertices are connected to form geometry primitives. This class is + * extended to create the various indexed primitive types (e.g., + * lines, triangle strips, etc.). + */ + +public abstract class IndexedGeometryArray extends GeometryArray { + + // non-public, no parameter constructor + IndexedGeometryArray() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Specifies that this IndexedGeometryArray allows reading the array of + * coordinate indices. + */ + public static final int + ALLOW_COORDINATE_INDEX_READ = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_COORDINATE_INDEX_READ; + + /** + * Specifies that this IndexedGeometryArray allows writing the array of + * coordinate indices. + */ + public static final int + ALLOW_COORDINATE_INDEX_WRITE = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_COORDINATE_INDEX_WRITE; + + /** + * Specifies that this IndexedGeometryArray allows reading the array of + * color indices. + */ + public static final int + ALLOW_COLOR_INDEX_READ = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_COLOR_INDEX_READ; + + /** + * Specifies that this IndexedGeometryArray allows writing the array of + * color indices. + */ + public static final int + ALLOW_COLOR_INDEX_WRITE = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_COLOR_INDEX_WRITE; + + /** + * Specifies that this IndexedGeometryArray allows reading the array of + * normal indices. + */ + public static final int + ALLOW_NORMAL_INDEX_READ = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_NORMAL_INDEX_READ; + + /** + * Specifies that this IndexedGeometryArray allows writing the array of + * normal indices. + */ + public static final int + ALLOW_NORMAL_INDEX_WRITE = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_NORMAL_INDEX_WRITE; + + /** + * Specifies that this IndexedGeometryArray allows reading the array of + * texture coordinate indices. + */ + public static final int + ALLOW_TEXCOORD_INDEX_READ = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_TEXCOORD_INDEX_READ; + + /** + * Specifies that this IndexedGeometryArray allows writing the array of + * texture coordinate indices. + */ + public static final int + ALLOW_TEXCOORD_INDEX_WRITE = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_TEXCOORD_INDEX_WRITE; + + /** + * Specifies that this IndexedGeometryArray allows reading the array of + * vertex attribute indices. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_VERTEX_ATTR_INDEX_READ = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_VERTEX_ATTR_INDEX_READ; + + /** + * Specifies that this IndexedGeometryArray allows writing the array of + * vertex attribute indices. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_VERTEX_ATTR_INDEX_WRITE = CapabilityBits.INDEXED_GEOMETRY_ARRAY_ALLOW_VERTEX_ATTR_INDEX_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_COLOR_INDEX_READ, + ALLOW_COORDINATE_INDEX_READ, + ALLOW_NORMAL_INDEX_READ, + ALLOW_TEXCOORD_INDEX_READ, + ALLOW_VERTEX_ATTR_INDEX_READ + }; + + /** + * Constructs an empty IndexedGeometryArray object with the specified + * number of vertices, vertex format, and number of indices. + * Defaults are used for all other parameters. The default values + * are as follows: + * + *

    + * validIndexCount : indexCount
    + * initialIndexIndex : 0
    + * all index array values : 0
    + *
+ * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param indexCount the number of indices in this object. This + * count is the maximum number of vertices that will be rendered. + * + * @exception IllegalArgumentException if indexCount < 0 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public IndexedGeometryArray(int vertexCount, + int vertexFormat, + int indexCount) { + super(vertexCount, vertexFormat); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((IndexedGeometryArrayRetained)this.retained).createIndexedGeometryArrayData(indexCount); + } + + /** + * Constructs an empty IndexedGeometryArray object with the specified + * number of vertices, vertex format, number of texture coordinate + * sets, texture coordinate mapping array, and number of indices. + * Defaults are used for all other parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount the number of indices in this object. This + * count is the maximum number of vertices that will be rendered. + * + * @exception IllegalArgumentException if indexCount < 0 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedGeometryArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount) { + this(vertexCount, vertexFormat, texCoordSetCount, texCoordSetMap, 0, null, indexCount); + } + + /** + * Constructs an empty IndexedGeometryArray object with the + * specified number of vertices, vertex format, number of texture + * coordinate sets, texture coordinate mapping array, vertex + * attribute count, vertex attribute sizes array, and number of + * indices. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount the number of indices in this object. This + * count is the maximum number of vertices that will be rendered. + * + * @exception IllegalArgumentException if indexCount < 0 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedGeometryArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((IndexedGeometryArrayRetained)this.retained).createIndexedGeometryArrayData(indexCount); + } + + /** + * Gets number of indices for this IndexedGeometryArray. + * @return indexCount the number of indices + */ + public int getIndexCount(){ + if (isLiveOrCompiled()) + if(!this.getCapability(GeometryArray.ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray0")); + + return ((IndexedGeometryArrayRetained)this.retained).getIndexCount(); + } + + /** + * Sets the valid index count for this IndexedGeometryArray object. + * This count specifies the number of indexed vertices actually used + * in rendering or other operations such as picking and collision. + * This attribute is initialized to indexCount. + * + * @param validIndexCount the new valid index count. + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @exception IllegalArgumentException if either of the following is true: + *
    + * validIndexCount < 0, or
    + * initialIndexIndex + validIndexCount > indexCount
    + *
+ * + * @exception ArrayIndexOutOfBoundsException if any element in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the index array associated with any of the enabled vertex + * components (coord, color, normal, texcoord) is out of range. + * An element is out of range if it is less than 0 or is greater + * than or equal to the number of vertices actually defined for + * the particular component's array. + * + * @exception ArrayIndexOutOfBoundsException if the data mode for this geometry + * array object is BY_REFERENCE_INDICES and + * coordIndices.length < (initialIndexIndex + validIndexCount). + * + * @since Java 3D 1.3 + */ + public void setValidIndexCount(int validIndexCount) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray16")); + + ((IndexedGeometryArrayRetained)this.retained).setValidIndexCount(validIndexCount); + } + + /** + * Gets the valid index count for this IndexedGeometryArray + * object. For geometry strip primitives (subclasses of + * IndexedGeometryStripArray), the valid index count is defined + * to be the sum of the stripIndexCounts array. + * + * @return the current valid index count + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getValidIndexCount() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray17")); + + return ((IndexedGeometryArrayRetained)this.retained).getValidIndexCount(); + } + + /** + * Sets the initial index index for this IndexedGeometryArray object. + * This index specifies the first index within this indexed geometry + * array that is actually used in rendering or other operations + * such as picking and collision. This attribute is initialized + * to 0. + * + * @param initialIndexIndex the new initial index index. + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * @exception IllegalArgumentException if either of the following is true: + *
    + * initialIndexIndex < 0, or
    + * initialIndexIndex + validIndexCount > indexCount
    + *
+ * + * @exception ArrayIndexOutOfBoundsException if any element in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * in the index array associated with any of the enabled vertex + * components (coord, color, normal, texcoord) is out of range. + * An element is out of range if it is less than 0 or is greater + * than or equal to the number of vertices actually defined for + * the particular component's array. + * + * @exception ArrayIndexOutOfBoundsException if the data mode for this geometry + * array object is BY_REFERENCE_INDICES and + * coordIndices.length < (initialIndexIndex + validIndexCount). + * + * @since Java 3D 1.3 + */ + public void setInitialIndexIndex(int initialIndexIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray18")); + + if (initialIndexIndex < 0) + throw new IllegalArgumentException(J3dI18N.getString("IndexedGeometryArray20")); + + + ((IndexedGeometryArrayRetained)this.retained).setInitialIndexIndex(initialIndexIndex); + } + + /** + * Gets the initial index index for this IndexedGeometryArray object. + * @return the current initial index index + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this object is part of a live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getInitialIndexIndex() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray19")); + + return ((IndexedGeometryArrayRetained)this.retained).getInitialIndexIndex(); + + } + + /** + * This method is not supported for indexed geometry arrays. + * Indexed primitives use an array of indices to determine how + * to access the vertex array. + * The initialIndexIndex attribute can be used to set the starting + * index within the index arrays. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setInitialVertexIndex(int initialVertexIndex) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported for indexed geometry arrays. + * Indexed primitives use an array of indices to determine how + * to access the vertex array. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setInitialCoordIndex(int initialCoordIndex) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported for indexed geometry arrays. + * Indexed primitives use an array of indices to determine how + * to access the vertex array. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setInitialColorIndex(int initialColorIndex) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported for indexed geometry arrays. + * Indexed primitives use an array of indices to determine how + * to access the vertex array. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setInitialNormalIndex(int initialNormalIndex) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported for indexed geometry arrays. + * Indexed primitives use an array of indices to determine how + * to access the vertex array. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setInitialTexCoordIndex(int texCoordSet, + int initialTexCoordIndex) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported for indexed geometry arrays. + * Indexed primitives use an array of indices to determine how + * to access the vertex array. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.4 + */ + public void setInitialVertexAttrIndex(int vertexAttrNum, + int initialVertexAttrIndex) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported for indexed geometry arrays. + * Indexed primitives use an array of indices to determine how + * to access the vertex array. + * The validIndexCount attribute can be used to set the number of + * valid indexed vertices rendered. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setValidVertexCount(int validVertexCount) { + throw new UnsupportedOperationException(); + } + + + //NVaidya + /** + * Sets the coordinate index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @param coordinateIndex the new coordinate index + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if index is less than 0 + * or is greater than or equal to indexCount + * + * @exception ArrayIndexOutOfBoundsException if index is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * and the specified coordinateIndex is out of range. The + * coordinateIndex is out of range if it is less than 0 or is + * greater than or equal to the number of vertices actually + * defined for the coordinate array. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE_INDICES. + */ + public void setCoordinateIndex(int index, int coordinateIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_INDEX_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray1")); + + //NVaidya + int format = ((IndexedGeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE_INDICES) != 0) + throw new IllegalStateException(J3dI18N.getString("IndexedGeometryArray31")); + + ((IndexedGeometryArrayRetained)this.retained).setCoordinateIndex(index, coordinateIndex); + } + + + //NVaidya + /** + * Sets the coordinate indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param coordinateIndices an array of coordinate indices + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if index is less than 0 + * or is greater than or equal to indexCount + * + * @exception ArrayIndexOutOfBoundsException if any element of the + * coordinateIndices array whose destination position is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * is out of range. An element is out of range if it is less than 0 + * or is greater than or equal to the number of vertices actually + * defined for the coordinate array. + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE_INDICES. + */ + public void setCoordinateIndices(int index, int coordinateIndices[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_INDEX_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray1")); + + //NVaidya + int format = ((IndexedGeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE_INDICES) != 0) + throw new IllegalStateException(J3dI18N.getString("IndexedGeometryArray31")); + + ((IndexedGeometryArrayRetained)this.retained).setCoordinateIndices(index, coordinateIndices); + } + + //NVaidya + /** + * Sets the coordinate indices array reference to the specified array. + * If the coordinate indices array reference is null, the entire + * geometry array object is treated as if it were null--any + * Shape3D or Morph node that uses this geometry array will not be drawn. + * + * @param coordIndices an array of indices to which a reference + * will be set. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE_INDICES. + * + * @exception ArrayIndexOutOfBoundsException if any element of the + * coordIndices array whose destination position is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * is out of range. An element is out of range if it is less than 0 + * or is greater than or equal to the number of vertices actually + * defined for the coordinate array. + * + * @exception ArrayIndexOutOfBoundsException if + * coordIndices.length < (initialIndexIndex + validIndexCount). + * + * @since Java 3D 1.5 + */ + public void setCoordIndicesRef(int coordIndices[]) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray86")); + + //NVaidya + int format = ((IndexedGeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE_INDICES) == 0) + throw new IllegalStateException(J3dI18N.getString("IndexedGeometryArray32")); + + ((IndexedGeometryArrayRetained)this.retained).setCoordIndicesRef(coordIndices); + } + + /** + * Sets the color index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @param colorIndex the new color index + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if index is less than 0 + * or is greater than or equal to indexCount + * + * @exception ArrayIndexOutOfBoundsException if index is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * and the specified colorIndex is out of range. The + * colorIndex is out of range if it is less than 0 or is + * greater than or equal to the number of vertices actually + * defined for the color array. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + */ + public void setColorIndex(int index, int colorIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_INDEX_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray3")); + + ((IndexedGeometryArrayRetained)this.retained).setColorIndex(index, colorIndex); + } + + /** + * Sets the color indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param colorIndices an array of color indices + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if index is less than 0 + * or is greater than or equal to indexCount + * + * @exception ArrayIndexOutOfBoundsException if any element of the + * colorIndices array whose destination position is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * is out of range. An element is out of range if it is less than 0 + * or is greater than or equal to the number of vertices actually + * defined for the color array. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + */ + public void setColorIndices(int index, int colorIndices[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_INDEX_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray3")); + + ((IndexedGeometryArrayRetained)this.retained).setColorIndices(index, colorIndices); + } + + /** + * Sets the normal index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @param normalIndex the new normal index + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if index is less than 0 + * or is greater than or equal to indexCount + * + * @exception ArrayIndexOutOfBoundsException if index is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * and the specified normalIndex is out of range. The + * normalIndex is out of range if it is less than 0 or is + * greater than or equal to the number of vertices actually + * defined for the normal array. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + */ + public void setNormalIndex(int index, int normalIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_INDEX_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray5")); + + ((IndexedGeometryArrayRetained)this.retained).setNormalIndex(index, normalIndex); + } + + /** + * Sets the normal indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param normalIndices an array of normal indices + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if index is less than 0 + * or is greater than or equal to indexCount + * + * @exception ArrayIndexOutOfBoundsException if any element of the + * normalIndices array whose destination position is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * is out of range. An element is out of range if it is less than 0 + * or is greater than or equal to the number of vertices actually + * defined for the normal array. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + */ + public void setNormalIndices(int index, int normalIndices[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_INDEX_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray5")); + + ((IndexedGeometryArrayRetained)this.retained).setNormalIndices(index, normalIndices); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinateIndex(int texCoordSet, ...) + */ + public void setTextureCoordinateIndex(int index, int texCoordIndex) { + setTextureCoordinateIndex(0, index, texCoordIndex); + } + + /** + * Sets the texture coordinate index associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index the vertex index + * @param texCoordIndex the new texture coordinate index + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if neither of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception ArrayIndexOutOfBoundsException if index is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * and the specified texCoordIndex is out of range. The + * texCoordIndex is out of range if it is less than 0 or is + * greater than or equal to the number of vertices actually + * defined for the texture coordinate array. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinateIndex(int texCoordSet, + int index, + int texCoordIndex) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_INDEX_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray7")); + + ((IndexedGeometryArrayRetained)this.retained).setTextureCoordinateIndex(texCoordSet, index, texCoordIndex); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setTextureCoordinateIndices(int texCoordSet, ...) + */ + public void setTextureCoordinateIndices(int index, int texCoordIndices[]) { + setTextureCoordinateIndices(0, index, texCoordIndices); + } + + /** + * Sets the texture coordinate indices associated with the vertices + * starting at the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index the vertex index + * @param texCoordIndices an array of texture coordinate indices + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if neither of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception ArrayIndexOutOfBoundsException if any element of the + * texCoordIndices array whose destination position is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * is out of range. An element is out of range if it is less than 0 + * or is greater than or equal to the number of vertices actually + * defined for the texture coordinate array. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + * + * @since Java 3D 1.2 + */ + public void setTextureCoordinateIndices(int texCoordSet, + int index, + int texCoordIndices[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TEXCOORD_INDEX_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray7")); + + ((IndexedGeometryArrayRetained)this.retained).setTextureCoordinateIndices(texCoordSet, index, texCoordIndices); + } + + /** + * Sets the vertex attribute index associated with the vertex at + * the specified index for the specified vertex attribute number + * for this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index the vertex index + * @param vertexAttrIndex the new vertex attribute index + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception ArrayIndexOutOfBoundsException if index is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * and the specified vertexAttrIndex is out of range. The + * vertexAttrIndex is out of range if it is less than 0 or is + * greater than or equal to the number of vertices actually + * defined for the vertex attribute array. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrIndex(int vertexAttrNum, + int index, + int vertexAttrIndex) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_VERTEX_ATTR_INDEX_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray28")); + } + } + + ((IndexedGeometryArrayRetained)this.retained).setVertexAttrIndex(vertexAttrNum, index, vertexAttrIndex); + } + + /** + * Sets the vertex attribute indices associated with the vertices + * starting at the specified index for the specified vertex attribute number + * for this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index the vertex index + * @param vertexAttrIndices an array of vertex attribute indices + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception ArrayIndexOutOfBoundsException if any element of the + * vertexAttrIndices array whose destination position is in the range + * [initialIndexIndex, initialIndexIndex+validIndexCount-1] + * is out of range. An element is out of range if it is less than 0 + * or is greater than or equal to the number of vertices actually + * defined for the vertex attribute array. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + * + * @since Java 3D 1.4 + */ + public void setVertexAttrIndices(int vertexAttrNum, + int index, + int[] vertexAttrIndices) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_VERTEX_ATTR_INDEX_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray28")); + } + } + + ((IndexedGeometryArrayRetained)this.retained).setVertexAttrIndices(vertexAttrNum, index, vertexAttrIndices); + } + + //NVaidya + /** + * Retrieves the coordinate index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @return the coordinate index + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE_INDICES. + */ + public int getCoordinateIndex(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray9")); + + //NVaidya + int format = ((IndexedGeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE_INDICES) != 0) + throw new IllegalStateException(J3dI18N.getString("IndexedGeometryArray31")); + + return ((IndexedGeometryArrayRetained)this.retained).getCoordinateIndex(index); + } + + //NVaidya + /** + * Retrieves the coordinate indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param coordinateIndices array that will receive the coordinate indices + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is BY_REFERENCE_INDICES. + */ + public void getCoordinateIndices(int index, int coordinateIndices[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray9")); + + //NVaidya + int format = ((IndexedGeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE_INDICES) != 0) + throw new IllegalStateException(J3dI18N.getString("IndexedGeometryArray31")); + + ((IndexedGeometryArrayRetained)this.retained).getCoordinateIndices(index, coordinateIndices); + } + + //NVaidya + /** + * Returns a reference to the coordinate indices associated with + * the vertices + * @return the coordinate indices array + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalStateException if the data mode for this geometry + * array object is not BY_REFERENCE_INDICES. + * + * @since Java 3D 1.5 + */ + public int[] getCoordIndicesRef() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_REF_DATA_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("GeometryArray87")); + + int format = ((IndexedGeometryArrayRetained)this.retained).vertexFormat; + if ((format & BY_REFERENCE_INDICES) == 0) + throw new IllegalStateException(J3dI18N.getString("IndexedGeometryArray32")); + + return ((IndexedGeometryArrayRetained)this.retained).getCoordIndicesRef(); + } + + /** + * Retrieves the color index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @return the color index + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + */ + public int getColorIndex(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray11")); + + return ((IndexedGeometryArrayRetained)this.retained).getColorIndex(index); + } + + /** + * Retrieves the color indices associated with the vertices starting at + * the specified index for this object. The color indicies are + * copied into the specified array. The array must be large enough + * to hold all of the indices. + * @param index the vertex index + * @param colorIndices array that will receive the color indices + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + */ + public void getColorIndices(int index, int colorIndices[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray11")); + + ((IndexedGeometryArrayRetained)this.retained).getColorIndices(index, colorIndices); + } + + /** + * Retrieves the normal index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @return the normal index + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + */ + public int getNormalIndex(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray13")); + + return ((IndexedGeometryArrayRetained)this.retained).getNormalIndex(index); + } + + /** + * Retrieves the normal indices associated with the vertices starting at + * the specified index for this object. The normal indicies are + * copied into the specified array. The array must be large enough + * to hold all of the normal indicies. + * + * @param index the vertex index + * @param normalIndices array that will receive the normal indices + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + */ + public void getNormalIndices(int index, int normalIndices[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray13")); + + ((IndexedGeometryArrayRetained)this.retained).getNormalIndices(index, normalIndices); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getTextureCoordinateIndex(int texCoordSet, ...) + */ + public int getTextureCoordinateIndex(int index) { + return (getTextureCoordinateIndex(0, index)); + } + + /** + * Retrieves the texture coordinate index associated with the vertex at + * the specified index in the specified texture coordinate set + * for this object. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index the vertex index + * + * @return the texture coordinate index + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if neither of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + * + * @since Java 3D 1.2 + */ + public int getTextureCoordinateIndex(int texCoordSet, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray15")); + + return ((IndexedGeometryArrayRetained)this.retained).getTextureCoordinateIndex(texCoordSet, index); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getTextureCoordinateIndices(int texCoordSet, ...) + */ + public void getTextureCoordinateIndices(int index, int texCoordIndices[]) { + getTextureCoordinateIndices(0, index, texCoordIndices); + } + + + /** + * Retrieves the texture coordinate indices associated with the vertices + * starting at the specified index in the specified texture coordinate set + * for this object. The texture + * coordinate indices are copied into the specified array. The array + * must be large enough to hold all of the indices. + * + * @param texCoordSet texture coordinate set in this geometry array + * @param index the vertex index + * @param texCoordIndices array that will receive the texture coordinate + * indices + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if neither of the + * TEXTURE_COORDINATE bits are set in the + * vertexFormat or if the index or + * texCoordSet is out of range. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + * + * @since Java 3D 1.2 + */ + public void getTextureCoordinateIndices(int texCoordSet, + int index, + int texCoordIndices[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COORDINATE_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray15")); + + ((IndexedGeometryArrayRetained)this.retained).getTextureCoordinateIndices(texCoordSet, index, texCoordIndices); + } + + /** + * Retrieves the vertex attribute index associated with the vertex at + * the specified index for the specified vertex attribute number + * for this object. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index the vertex index + * + * @return the vertex attribute index + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + * + * @since Java 3D 1.4 + */ + public int getVertexAttrIndex(int vertexAttrNum, + int index) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_VERTEX_ATTR_INDEX_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray29")); + } + } + + return ((IndexedGeometryArrayRetained)this.retained).getVertexAttrIndex(vertexAttrNum, index); + } + + /** + * Retrieves the vertex attribute indices associated with the vertices + * starting at the specified index for the specified vertex attribute number + * for this object. The vertex attribute indices + * are copied into the specified array. The array + * must be large enough to hold all of the indices. + * + * @param vertexAttrNum vertex attribute number in this geometry array + * @param index the vertex index + * @param vertexAttrIndices array that will receive the vertex attribute indices + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception ArrayIndexOutOfBoundsException if the index or + * vertexAttrNum is out of range. + * + * @exception NullPointerException if the USE_COORD_INDEX_ONLY + * bit is set in vertexFormat. + * + * @since Java 3D 1.4 + */ + public void getVertexAttrIndices(int vertexAttrNum, + int index, + int[] vertexAttrIndices) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_VERTEX_ATTR_INDEX_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryArray29")); + } + } + + ((IndexedGeometryArrayRetained)this.retained).getVertexAttrIndices(vertexAttrNum, index, vertexAttrIndices); + } + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + // vertexFormat, vertexCount and indexCount are copied in + // subclass when constructor + // public IndexedGeometryArray(int vertexCount, int vertexFormat, + // int indexCount) + // is used in cloneNodeComponent() + IndexedGeometryArrayRetained ga = + (IndexedGeometryArrayRetained) originalNodeComponent.retained; + IndexedGeometryArrayRetained rt = + (IndexedGeometryArrayRetained) retained; + + int vformat = ga.getVertexFormat(); + int buffer[] = new int[ga.getIndexCount()]; + + if ((vformat & COORDINATES) != 0) { + ga.getCoordinateIndices(0, buffer); + rt.setCoordinateIndices(0, buffer); + } + + if ((vformat & USE_COORD_INDEX_ONLY) == 0) { + if ((vformat & NORMALS) != 0) { + ga.getNormalIndices(0, buffer); + rt.setNormalIndices(0, buffer); + } + + if ((vformat & COLOR) != 0) { + ga.getColorIndices(0, buffer); + rt.setColorIndices(0, buffer); + } + + if ((vformat & VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < ga.vertexAttrCount; i++) { + ga.getVertexAttrIndices(i, 0, buffer); + rt.setVertexAttrIndices(i, 0, buffer); + } + } + + if ((vformat & TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < ga.texCoordSetCount; i++) { + ga.getTextureCoordinateIndices(i, 0, buffer); + rt.setTextureCoordinateIndices(i, 0, buffer); + } + } + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryArrayRetained.java new file mode 100644 index 0000000..7eeab6e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryArrayRetained.java @@ -0,0 +1,1928 @@ +/* + * $RCSfile: IndexedGeometryArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.12 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; +import com.sun.j3d.internal.FloatBufferWrapper; + +/** + * The IndexedGeometryArray object contains arrays of positional coordinates, + * colors, normals and/or texture coordinates that describe + * point, line, or surface geometry. It is extended to create + * the various primitive types (e.g., lines, triangle_strips, etc.) + */ + +abstract class IndexedGeometryArrayRetained extends GeometryArrayRetained { + + // arrays to save indices for coord, color, normal, texcoord, vertexAttr + int[] indexCoord; + int[] indexColor; + int[] indexNormal; + int[][] indexTexCoord; + int[][] indexVertexAttr; + + int indexCount = 0; + + int initialIndexIndex = 0; + int validIndexCount = 0; + + // Following variables are only used in compile mode + int[] compileIndexCount; + int[] compileIndexOffset; + + int maxCoordIndex = 0; + int maxColorIndex = 0; + int maxNormalIndex = 0; + int[] maxTexCoordIndices = null; + int[] maxVertexAttrIndices = null; + + void createIndexedGeometryArrayData(int indexCount) { + this.indexCount = indexCount; + this.validIndexCount = indexCount; + + // Only allocate color, normal, texCoord, and vertexAttr + // index arrays if USE_COORD_INDEX_ONLY is not set + boolean notUCIO = (this.vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0; + + //NVaidya + // Only allocate indexCoord if BY_REFERENCE_INDICES not set + if(((this.vertexFormat & GeometryArray.COORDINATES) != 0) && + ((this.vertexFormat & GeometryArray.BY_REFERENCE_INDICES) == 0)) + this.indexCoord = new int[indexCount]; + + if(((this.vertexFormat & GeometryArray.NORMALS) != 0) && notUCIO) + this.indexNormal = new int[indexCount]; + + if(((this.vertexFormat & GeometryArray.COLOR) != 0) && notUCIO) + this.indexColor = new int[indexCount]; + + if((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + this.indexTexCoord = new int[this.texCoordSetCount][]; + if(notUCIO) { + for (int i = 0; i < this.texCoordSetCount; i++) { + this.indexTexCoord[i] = new int[indexCount]; + } + } + maxTexCoordIndices = new int[texCoordSetCount]; + } + + if ((this.vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + this.indexVertexAttr = new int[this.vertexAttrCount][]; + if (notUCIO) { + for (int i = 0; i < this.vertexAttrCount; i++) { + this.indexVertexAttr[i] = new int[indexCount]; + } + } + this.maxVertexAttrIndices = new int[this.vertexAttrCount]; + } + } + + + GeometryArrayRetained cloneNonIndexedGeometry() { + GeometryArrayRetained obj = null; + + switch (this.geoType) { + case GEO_TYPE_INDEXED_LINE_SET: + obj = new LineArrayRetained(); + break; + case GEO_TYPE_INDEXED_POINT_SET: + obj = new PointArrayRetained(); + break; + case GEO_TYPE_INDEXED_QUAD_SET: + obj = new QuadArrayRetained(); + break; + case GEO_TYPE_INDEXED_TRI_SET: + obj = new TriangleArrayRetained(); + break; + default: + assert false; // Should never get here + } + + obj.createGeometryArrayData(validIndexCount, + (vertexFormat & ~(GeometryArray.BY_REFERENCE|GeometryArray.INTERLEAVED|GeometryArray.USE_NIO_BUFFER)), + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + obj.cloneSourceArray = this; + obj.unIndexify(this); + obj.source=source; + + return obj; + } + + + /** + * Gets current number of indices + * @return indexCount + */ + int getIndexCount(){ + return indexCount; + } + + void doErrorCheck(int newMax) { + doCoordCheck(newMax); + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if ((vertexFormat & GeometryArray.COLOR) != 0) { + doColorCheck(newMax); + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + doTexCoordCheck(newMax, i); + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + doVertexAttrCheck(newMax, i); + } + } + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + doNormalCheck(newMax); + } + } + } + + void doCoordCheck(int newMax) { + // Check to make sure that the array length defined by the user is ateast maxCoordIndex long + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + if (newMax >= vertexCount) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } + else { + if(( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0) { + switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case PF: + if(floatBufferRefCoords != null && 3 * newMax >= floatBufferRefCoords.limit() ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + break; + case PD: + if(doubleBufferRefCoords != null && 3 * newMax >= doubleBufferRefCoords.limit() ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + break; + } + } + else { + if(interleavedFloatBufferImpl != null && stride * newMax >= interleavedFloatBufferImpl.limit() ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } + } else { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0) { + switch ((vertexType & VERTEX_DEFINED)) { + case PF: + if (floatRefCoords != null && (3 * newMax >= floatRefCoords.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + break; + case PD: + if (doubleRefCoords != null && (3 * newMax >= doubleRefCoords.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + + break; + case P3F: + if (p3fRefCoords != null && (newMax >= p3fRefCoords.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + break; + case P3D: + if (p3dRefCoords != null && (newMax >= p3dRefCoords.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + break; + default: + break; + } + } + else { + if (interLeavedVertexData != null && (stride * newMax >= interLeavedVertexData.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23")); + } + } + } + } + + } + + void doColorCheck(int newMax) { + // If the new Value is greater than the old value, make sure there is array length + // to support the change + // Check to make sure that the array length defined by the user is ateast maxCoordIndex long + if ((vertexFormat & GeometryArray.COLOR) == 0) + return; + + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + if (newMax >= vertexCount) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } + else { + int multiplier = getColorStride(); + + if(( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0) { + switch ((vertexType & COLOR_DEFINED)) { + case CF: + if (floatBufferRefColors != null && multiplier * newMax >= floatBufferRefColors.limit()) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + break; + case CUB: + if (byteBufferRefColors != null && multiplier * newMax >= byteBufferRefColors.limit()) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + break; + } + } + else { + if(interleavedFloatBufferImpl != null && + stride * newMax >= interleavedFloatBufferImpl.limit()) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } + } else { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0) { + switch ((vertexType & COLOR_DEFINED)) { + case CF: + if (floatRefColors != null && (multiplier * newMax >= floatRefColors.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + break; + case CUB: + if (byteRefColors != null && (multiplier * newMax >= byteRefColors.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + + break; + case C3F: + if (c3fRefColors != null && (newMax >= c3fRefColors.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + break; + case C4F: + if (c4fRefColors != null && (newMax >= c4fRefColors.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + break; + case C3UB: + if (c3bRefColors != null && (newMax >= c3bRefColors.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + break; + case C4UB: + if (c4bRefColors != null && (newMax >= c4bRefColors.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + break; + default: + break; + } + } else { + if (interLeavedVertexData != null && (stride * newMax >= interLeavedVertexData.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24")); + } + } + } + } + + } + + + void doNormalCheck(int newMax) { + if ((vertexFormat & GeometryArray.NORMALS) == 0) + return; + + // Check to make sure that the array length defined by the user is ateast maxCoordIndex long + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + if (newMax >= vertexCount) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + } + else { + if(( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0) { + switch ((vertexType & GeometryArrayRetained.NORMAL_DEFINED)) { + case NF: + if(floatBufferRefNormals != null && 3 * newMax >= floatBufferRefNormals.limit() ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + break; + } + } + else { + if(interleavedFloatBufferImpl != null && stride * newMax >= interleavedFloatBufferImpl.limit() ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + } + } else { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0) { + switch ((vertexType & NORMAL_DEFINED)) { + case NF: + if (floatRefNormals != null && (3 * newMax >= floatRefNormals.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + break; + case N3F: + if (v3fRefNormals != null && (newMax >= v3fRefNormals.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + + break; + default: + break; + } + } + else { + if (interLeavedVertexData != null && (stride * newMax >= interLeavedVertexData.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26")); + } + } + } + } + + } + + + + void doTexCoordCheck(int newMax, int texCoordSet) { + + // Check to make sure that the array length defined by the user is ateast maxCoordIndex long + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) == 0) + return; + + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + if (newMax >= vertexCount) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + } + else { + int multiplier = getTexStride(); + + if(( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0) { + switch ((vertexType & GeometryArrayRetained.TEXCOORD_DEFINED)) { + case TF: + FloatBufferWrapper texBuffer; + texBuffer = (FloatBufferWrapper)(((J3DBuffer) refTexCoordsBuffer[texCoordSet]).getBufferImpl()); + if(refTexCoords[texCoordSet] != null && multiplier * newMax >= texBuffer.limit()) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + break; + } + } + else { + if(interleavedFloatBufferImpl != null && stride * newMax >= interleavedFloatBufferImpl.limit() ) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + } + } else { + + if ((vertexFormat & GeometryArray.INTERLEAVED) == 0) { + switch ((vertexType & TEXCOORD_DEFINED)) { + case TF: + if (refTexCoords[texCoordSet] != null && (multiplier * newMax >= ((float[])refTexCoords[texCoordSet]).length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + break; + case T2F: + if (refTexCoords[texCoordSet] != null && (newMax >= ((TexCoord2f[])refTexCoords[texCoordSet]).length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + + break; + case T3F: + if (refTexCoords[texCoordSet] != null && (newMax >= ((TexCoord3f[])refTexCoords[texCoordSet]).length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + break; + default: + break; + } + } + else { + if (interLeavedVertexData != null && (stride * newMax >= interLeavedVertexData.length)) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25")); + } + } + } + } + + } + + void doVertexAttrCheck(int newMax, int vertexAttrNum) { + + // Check to make sure that the array length defined by the user is ateast maxVertexAttrIndex long + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) == 0) { + return; + } + + // Vertex attributes must not be interleaved + assert (vertexFormat & GeometryArray.INTERLEAVED) == 0; + + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + if (newMax >= vertexCount) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray30")); + } + } else { + int multiplier = vertexAttrSizes[vertexAttrNum]; + + if(( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + switch (vertexType & VATTR_DEFINED) { + case AF: + if(multiplier * newMax >= floatBufferRefVertexAttrs[vertexAttrNum].limit()) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray30")); + } + break; + } + } else { + switch (vertexType & VATTR_DEFINED) { + case AF: + if (multiplier * newMax >= floatRefVertexAttrs[vertexAttrNum].length) { + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray30")); + } + break; + } + } + } + } + + + /** + * Sets the coordinate index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @param coordinateIndex the new coordinate index + */ + final void setCoordinateIndex(int index, int coordinateIndex) { + int newMax; + newMax = doIndexCheck(index, maxCoordIndex, indexCoord, coordinateIndex); + if (newMax > maxCoordIndex) { + doErrorCheck(newMax); + } + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if ((vertexFormat & GeometryArray.COLOR) != 0) { + maxColorIndex = newMax; + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = newMax; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = newMax; + } + } + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + maxNormalIndex = newMax; + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= INDEX_CHANGED; + this.indexCoord[index] = coordinateIndex; + maxCoordIndex = newMax; + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(true); + } + } + + int doIndexCheck(int index, int maxIndex, int[] indices, int dataValue) { + int newMax = maxIndex; + if (index < initialIndexIndex) + return newMax; + + if (index >= (initialIndexIndex+validIndexCount)) + return newMax; + + if (dataValue < 0) { + // Throw an exception, since index is negative + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray27")); + + } + + if (newMax == indices[index]) { + if (dataValue >= newMax) { + newMax = dataValue; + } + // Go thru the entire list and look for the max + else { + for (int i = 0; i < indices.length; i++) { + if (indices[i] > newMax) { + newMax = indices[i]; + } + } + } + } + else if (dataValue > newMax) { + newMax = dataValue; + } + return newMax; + } + + int doIndicesCheck(int index, int maxIndex, int[] indices, int[] newIndices) { + int newMax = maxIndex; + boolean computeNewMax = false; + int i, j, num = newIndices.length; + boolean maxReset = false; + for (j = 0; j < num; j++) { + if ((index+j) < initialIndexIndex) + continue; + + if ((index+j) >= (initialIndexIndex+validIndexCount)) + continue; + if (newIndices[j] < 0) { + // Throw an exception, since index is negative + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray27")); + + } + if (indices[index+j] == maxIndex) { + if (newIndices[j] >= newMax) { + newMax = newIndices[j]; + computeNewMax = false; + maxReset = true; + } + // Go thru the entire list and look for the max + // If in the new list there is no value that is >= + // to the old maximum + else if (!maxReset){ + computeNewMax = true; + } + } + else if (newIndices[j] >= newMax) { + newMax = newIndices[j]; + computeNewMax = false; + maxReset = true; + } + } + if (computeNewMax) { + for (i = 0; i < indices.length; i++) { + if (indices[i] > newMax) { + newMax = indices[i]; + } + } + } + return newMax; + } + + + /** + * Sets the coordinate indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param coordinateIndices an array of coordinate indices + */ + final void setCoordinateIndices(int index, int coordinateIndices[]) { + int newMax; + int i, j, num = coordinateIndices.length; + newMax = doIndicesCheck(index, maxCoordIndex, indexCoord, coordinateIndices); + if (newMax > maxCoordIndex) { + doErrorCheck(newMax); + } + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if ((vertexFormat & GeometryArray.COLOR) != 0) { + maxColorIndex = newMax; + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = newMax; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = newMax; + } + } + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + maxNormalIndex = newMax; + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= INDEX_CHANGED; + maxCoordIndex = newMax; + for (i=0, j = index; i < num;i++, j++) { + this.indexCoord[j] = coordinateIndices[i]; + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(true); + } + } + + //NVaidya + /** + * Sets the coordinate indices by reference to the specified array + * @param coordinateIndices an array of coordinate indices + */ + final void setCoordIndicesRef(int coordinateIndices[]) { + int newMax = 0; + + if (coordinateIndices != null) { + if (coordinateIndices.length < initialIndexIndex + validIndexCount) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedGeometryArray33")); + } + + // + // option 1: could fake the args to "re-use" doIndicesCheck() + //NVaidya + // newMax = doIndicesCheck(0, maxCoordIndex, coordinateIndices, coordinateIndices); + // if (newMax > maxCoordIndex) { + // doErrorCheck(newMax); + // } + // + // option 2: same logic as in setInitialIndexIndex: Better, I Think ? + // computeMaxIndex() doesn't check for index < 0 while doIndicesCheck() does. + // So, a new method computeMaxIndexWithCheck + //NVaidya + newMax = computeMaxIndexWithCheck(initialIndexIndex, validIndexCount, coordinateIndices); + if (newMax > maxCoordIndex) { + doErrorCheck(newMax); + } + } + + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if ((vertexFormat & GeometryArray.COLOR) != 0) { + maxColorIndex = newMax; + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = newMax; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = newMax; + } + } + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + maxNormalIndex = newMax; + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= INDEX_CHANGED; + maxCoordIndex = newMax; + this.indexCoord = coordinateIndices; + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(true); + } + } + + //NVaidya + /** + * trigger from GeometryArrayRetained#updateData() + * to recompute maxCoordIndex and perform index integrity checks + */ + final void doPostUpdaterUpdate() { + // user may have called setCoordIndicesRef and/or + // changed contents of indexCoord array. Thus, need to + // recompute maxCoordIndex unconditionally (and redundantly + // if user had only invoked setCoordIndicesRef but not also + // changed contents). geomLock is currently locked. + + // Option 1: + // simply call setCoordIndicesRef(indexCoord); but this seems to cause + // deadlock or freeze - probably because the !inUpdater branch sends + // out too many sendDataChangedMessage(true) - occurs if updateData + // method is called rapidly. + // setCoordIndicesRef(indexCoord); + + // Option 2: + // use only necessary code from setCoordIndicesRef + // System.err.println("IndexedGeometryArrayretained#doUpdaterUpdate"); + int newMax = 0; + + if (indexCoord != null) { + newMax = computeMaxIndexWithCheck(initialIndexIndex, validIndexCount, indexCoord); + if (newMax > maxCoordIndex) { + doErrorCheck(newMax); + } + } + + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if ((vertexFormat & GeometryArray.COLOR) != 0) { + maxColorIndex = newMax; + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = newMax; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = newMax; + } + } + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + maxNormalIndex = newMax; + } + } + + dirtyFlag |= INDEX_CHANGED; + maxCoordIndex = newMax; + } + + /** + * Sets the color index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @param colorIndex the new color index + */ + final void setColorIndex(int index, int colorIndex) { + int newMax = maxColorIndex; + + newMax = doIndexCheck(index, maxColorIndex, indexColor, colorIndex); + if (newMax > maxColorIndex) { + doColorCheck(newMax); + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + // No need to set INDEX_CHANGED since IndexBuffer + // is used only when USE_COORD_INDEX_ONLY specified. + // In this case only coordinate index array is + // considered. + this.indexColor[index] = colorIndex; + maxColorIndex = newMax; + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Sets the color indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param colorIndices an array of color indices + */ + final void setColorIndices(int index, int colorIndices[]) { + int i, j, num = colorIndices.length; + int newMax; + + newMax = doIndicesCheck(index, maxColorIndex, indexColor, colorIndices); + if (newMax > maxColorIndex) { + doColorCheck(newMax); + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + maxColorIndex = newMax; + for (i=0, j = index; i < num;i++, j++) { + this.indexColor[j] = colorIndices[i]; + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Sets the normal index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @param normalIndex the new normal index + */ + final void setNormalIndex(int index, int normalIndex) { + int newMax; + + newMax = doIndexCheck(index, maxNormalIndex, indexNormal, normalIndex); + if (newMax > maxNormalIndex) { + doNormalCheck(newMax); + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + maxNormalIndex = newMax; + this.indexNormal[index] = normalIndex; + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Sets the normal indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param normalIndices an array of normal indices + */ + final void setNormalIndices(int index, int normalIndices[]) { + int i, j, num = normalIndices.length; + int newMax; + + newMax = doIndicesCheck(index, maxNormalIndex, indexNormal, normalIndices); + if (newMax > maxNormalIndex) { + doNormalCheck(newMax); + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + for (i=0, j = index; i < num;i++, j++) { + this.indexNormal[j] = normalIndices[i]; + } + maxNormalIndex = newMax; + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Sets the texture coordinate index associated with the vertex at + * the specified index for this object. + * @param texCoordSet the texture coordinate set + * @param index the vertex index + * @param texCoordIndex the new texture coordinate index + */ + final void setTextureCoordinateIndex(int texCoordSet, int index, int texCoordIndex) { + int newMax; + int [] indices = this.indexTexCoord[texCoordSet]; + + newMax = doIndexCheck(index, maxTexCoordIndices[texCoordSet],indices, texCoordIndex); + if (newMax > maxTexCoordIndices[texCoordSet]) { + doTexCoordCheck(newMax, texCoordSet); + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + maxTexCoordIndices[texCoordSet] = newMax; + indices[index] = texCoordIndex; + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Sets the texture coordinate indices associated with the vertices + * starting at the specified index for this object. + * @param texCoordSet the texture coordinate set + * @param index the vertex index + * @param texCoordIndices an array of texture coordinate indices + */ + final void setTextureCoordinateIndices(int texCoordSet, int index, int texCoordIndices[]) { + int i, j, num = texCoordIndices.length; + int [] indices = this.indexTexCoord[texCoordSet]; + + int newMax; + + newMax = doIndicesCheck(index, maxTexCoordIndices[texCoordSet], indices, texCoordIndices); + if (newMax > maxTexCoordIndices[texCoordSet]) { + doTexCoordCheck(newMax, texCoordSet); + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + maxTexCoordIndices[texCoordSet] = newMax; + for (i=0, j = index; i < num;i++, j++) { + indices[j] = texCoordIndices[i]; + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Sets the vertex attribute index associated with the vertex at + * the specified index for the specified vertex attribute number + * for this object. + */ + void setVertexAttrIndex(int vertexAttrNum, + int index, + int vertexAttrIndex) { + + int newMax; + int [] indices = this.indexVertexAttr[vertexAttrNum]; + + newMax = doIndexCheck(index, maxVertexAttrIndices[vertexAttrNum],indices, vertexAttrIndex); + if (newMax > maxVertexAttrIndices[vertexAttrNum]) { + doVertexAttrCheck(newMax, vertexAttrNum); + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + maxVertexAttrIndices[vertexAttrNum] = newMax; + indices[index] = vertexAttrIndex; + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Sets the vertex attribute indices associated with the vertices + * starting at the specified index for the specified vertex attribute number + * for this object. + */ + void setVertexAttrIndices(int vertexAttrNum, + int index, + int[] vertexAttrIndices) { + + int i, j, num = vertexAttrIndices.length; + int [] indices = this.indexVertexAttr[vertexAttrNum]; + + int newMax; + + newMax = doIndicesCheck(index, maxVertexAttrIndices[vertexAttrNum], indices, vertexAttrIndices); + if (newMax > maxVertexAttrIndices[vertexAttrNum]) { + doVertexAttrCheck(newMax, vertexAttrNum); + } + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + maxVertexAttrIndices[vertexAttrNum] = newMax; + for (i=0, j = index; i < num;i++, j++) { + indices[j] = vertexAttrIndices[i]; + } + if(isLive) { + geomLock.unLock(); + } + if (!inUpdater && isLive) { + sendDataChangedMessage(false); + } + } + + /** + * Retrieves the coordinate index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @return the coordinate index + */ + final int getCoordinateIndex(int index) { + return this.indexCoord[index]; + } + + /** + * Retrieves the coordinate indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param coordinateIndices array that will receive the coordinate indices + */ + final void getCoordinateIndices(int index, int coordinateIndices[]) { + int i, j, num = coordinateIndices.length; + + for (i=0, j = index;i < num;i++, j++) { + coordinateIndices[i] = this.indexCoord[j]; + } + } + + //NVaidya + /** + * Returns a reference to the coordinate indices associated + * with the vertices + */ + final int[] getCoordIndicesRef() { + return this.indexCoord; + } + + /** + * Retrieves the color index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @return the color index + */ + final int getColorIndex(int index) { + return this.indexColor[index]; + } + + /** + * Retrieves the color indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param colorIndices array that will receive the color indices + */ + final void getColorIndices(int index, int colorIndices[]) { + int i, j, num = colorIndices.length; + + for (i=0, j = index;i < num;i++, j++) { + colorIndices[i] = this.indexColor[j]; + } + } + + /** + * Retrieves the normal index associated with the vertex at + * the specified index for this object. + * @param index the vertex index + * @return the normal index + */ + final int getNormalIndex(int index) { + return this.indexNormal[index]; + } + + /** + * Retrieves the normal indices associated with the vertices starting at + * the specified index for this object. + * @param index the vertex index + * @param normalIndices array that will receive the normal indices + */ + final void getNormalIndices(int index, int normalIndices[]) { + int i, j, num = normalIndices.length; + + for (i=0, j = index;i < num;i++, j++) { + normalIndices[i] = this.indexNormal[j]; + } + } + + /** + * Retrieves the texture coordinate index associated with the vertex at + * the specified index for this object. + * @param texCoordSet the texture coordinate set + * @param index the vertex index + * @return the texture coordinate index + */ + final int getTextureCoordinateIndex(int texCoordSet, int index) { + int [] indices = this.indexTexCoord[texCoordSet]; + + return indices[index]; + } + + /** + * Retrieves the texture coordinate indices associated with the vertices + * starting at the specified index for this object. + * @param texCoordSet the texture coordinate set + * @param index the vertex index + * @param texCoordIndices array that will receive the texture coordinate indices + */ + final void getTextureCoordinateIndices(int texCoordSet, int index, int texCoordIndices[]) { + int i, j, num = texCoordIndices.length; + int [] indices = this.indexTexCoord[texCoordSet]; + + for (i=0, j = index;i < num;i++, j++) { + texCoordIndices[i] = indices[j]; + } + } + + /** + * Retrieves the vertex attribute index associated with the vertex at + * the specified index for the specified vertex attribute number + * for this object. + */ + int getVertexAttrIndex(int vertexAttrNum, + int index) { + + int [] indices = this.indexVertexAttr[vertexAttrNum]; + + return indices[index]; + } + + /** + * Retrieves the vertex attribute indices associated with the vertices + * starting at the specified index for the specified vertex attribute number + * for this object. + */ + void getVertexAttrIndices(int vertexAttrNum, + int index, + int[] vertexAttrIndices) { + + int i, j, num = vertexAttrIndices.length; + int [] indices = this.indexVertexAttr[vertexAttrNum]; + + for (i=0, j = index;i < num;i++, j++) { + vertexAttrIndices[i] = indices[j]; + } + } + + + void execute(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale, + boolean updateAlpha, float alpha, + int screen, boolean ignoreVertexColors) { + + int cdirty; + boolean useAlpha = false; + Object[] retVal; + if (mirrorGeometry != null) { + mirrorGeometry.execute(cv, ra, isNonUniformScale, updateAlpha, alpha, + screen, ignoreVertexColors); + return; + } + + // Check if index array is null; if yes, don't draw anything + if (indexCoord == null) { + return; + } + + //By reference with java array + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + float[] vdata; + // System.err.println("by-copy"); + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + // update the alpha values + retVal = updateAlphaInVertexData(cv, screen, alpha); + useAlpha = (retVal[0] == Boolean.TRUE); + vdata = (float[])retVal[1]; + + // D3D only + if (alpha != lastScreenAlpha) { + // handle multiple screen case + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + vdata = vertexData; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + // geomLock is get in MasterControl when + // RenderBin render the geometry. So it is safe + // just to set the dirty flag here + dirtyFlag = 0; + } + + Pipeline.getPipeline().executeIndexedGeometry(cv.ctx, + this, geoType, isNonUniformScale, + useAlpha, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + // Vertex Count is maxCoordIndex + 1 + maxCoordIndex + 1, + ((vertexFormat & GeometryArray.COLOR) != 0)?(vertexFormat|GeometryArray.COLOR_4):vertexFormat, + vertexAttrCount, vertexAttrSizes, + texCoordSetCount, texCoordSetMap, + (texCoordSetMap == null) ? 0 : texCoordSetMap.length, + texCoordSetMapOffset, + cv.numActiveTexUnit, + vdata, null, + cdirty, indexCoord); + + + } // end of non by reference + else if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + if(interLeavedVertexData == null) + return; + + float[] cdata = null; + + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + // update the alpha values + retVal = updateAlphaInInterLeavedData(cv, screen, alpha); + useAlpha = (retVal[0] == Boolean.TRUE); + cdata = (float[])retVal[1]; + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + dirtyFlag = 0; + } + + Pipeline.getPipeline().executeIndexedGeometry(cv.ctx, + this, geoType, isNonUniformScale, + useAlpha, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + maxCoordIndex + 1, + vertexFormat, + vertexAttrCount, vertexAttrSizes, + texCoordSetCount, texCoordSetMap, + (texCoordSetMap == null) ? 0 : texCoordSetMap.length, + texCoordSetMapOffset, + cv.numActiveTexUnit, + interLeavedVertexData, cdata, + cdirty, indexCoord); + } //end of interleaved + else { + // Check if a vertexformat is set, but the array is null + // if yes, don't draw anything + if ((vertexType == 0) || + ((vertexType & VERTEX_DEFINED) == 0) || + (((vertexFormat & GeometryArray.COLOR) != 0) && + (vertexType & COLOR_DEFINED) == 0) || + (((vertexFormat & GeometryArray.NORMALS) != 0) && + (vertexType & NORMAL_DEFINED) == 0) || + (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) && + (vertexType & VATTR_DEFINED) == 0) || + (((vertexFormat& GeometryArray.TEXTURE_COORDINATE) != 0) && + (vertexType & TEXCOORD_DEFINED) == 0)) { + return; + } else { + byte[] cbdata = null; + float[] cfdata = null; + + if ((vertexType & (CF | C3F | C4F )) != 0) { + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + cfdata = updateAlphaInFloatRefColors(cv, + screen, alpha); + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + cfdata = mirrorFloatRefColors[0]; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + + } + dirtyFlag = 0; + } + } else if ((vertexType & (CUB| C3UB | C4UB)) != 0) { + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + cbdata = updateAlphaInByteRefColors( + cv, screen, alpha); + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + cbdata = mirrorUnsignedByteRefColors[0]; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + dirtyFlag = 0; + } + } else { + cdirty = dirtyFlag; + } + + int vdefined = 0; + if((vertexType & (PF | P3F)) != 0) + vdefined |= COORD_FLOAT; + if((vertexType & (PD | P3D)) != 0) + vdefined |= COORD_DOUBLE; + if((vertexType & (CF | C3F | C4F)) != 0) + vdefined |= COLOR_FLOAT; + if((vertexType & (CUB| C3UB | C4UB)) != 0) + vdefined |= COLOR_BYTE; + if((vertexType & NORMAL_DEFINED) != 0) + vdefined |= NORMAL_FLOAT; + if((vertexType & VATTR_DEFINED) != 0) + vdefined |= VATTR_FLOAT; + if((vertexType & TEXCOORD_DEFINED) != 0) + vdefined |= TEXCOORD_FLOAT; + + Pipeline.getPipeline().executeIndexedGeometryVA(cv.ctx, + this, geoType, isNonUniformScale, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + maxCoordIndex + 1, + (vertexFormat | c4fAllocated), + vdefined, + mirrorFloatRefCoords, mirrorDoubleRefCoords, + cfdata, cbdata, + mirrorFloatRefNormals, + vertexAttrCount, vertexAttrSizes, + mirrorFloatRefVertexAttrs, + ((texCoordSetMap == null) ? 0:texCoordSetMap.length), + texCoordSetMap, + cv.numActiveTexUnit, + texCoordStride, + mirrorRefTexCoords, cdirty, indexCoord); + } + } // end of non interleaved and by reference + }//end of non io buffer + + else { + if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + if( interleavedFloatBufferImpl == null) + return; + + float[] cdata = null; + + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + // update the alpha values + retVal = updateAlphaInInterLeavedData(cv, screen, alpha); + useAlpha = (retVal[0] == Boolean.TRUE); + cdata = (float[])retVal[1]; + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + dirtyFlag = 0; + } + + Pipeline.getPipeline().executeIndexedGeometryBuffer(cv.ctx, + this, geoType, isNonUniformScale, + useAlpha, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + maxCoordIndex + 1, + vertexFormat, + texCoordSetCount, texCoordSetMap, + (texCoordSetMap == null) ? 0 : texCoordSetMap.length, + texCoordSetMapOffset, + cv.numActiveTexUnit, + interleavedFloatBufferImpl.getBufferAsObject(), cdata, + cdirty, indexCoord); + } //end of interleaved + else { + // Check if a vertexformat is set, but the array is null + // if yes, don't draw anything + if ((vertexType == 0) || + ((vertexType & VERTEX_DEFINED) == 0) || + (((vertexFormat & GeometryArray.COLOR) != 0) && + (vertexType & COLOR_DEFINED) == 0) || + (((vertexFormat & GeometryArray.NORMALS) != 0) && + (vertexType & NORMAL_DEFINED) == 0) || + (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) && + (vertexType & VATTR_DEFINED) == 0) || + (((vertexFormat& GeometryArray.TEXTURE_COORDINATE) != 0) && + (vertexType & TEXCOORD_DEFINED) == 0)) { + return; + } else { + byte[] cbdata = null; + float[] cfdata = null; + + if ((vertexType & CF ) != 0) { + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + cfdata = updateAlphaInFloatRefColors(cv, + screen, alpha); + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + // XXXX: handle transparency case + //cfdata = null; + cfdata = mirrorFloatRefColors[0]; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + + } + dirtyFlag = 0; + } + } else if ((vertexType & CUB ) != 0) { + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + cbdata = updateAlphaInByteRefColors( + cv, screen, alpha); + if (alpha != lastScreenAlpha) { + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + // XXXX: handle transparency case + // cbdata = null; + cbdata = mirrorUnsignedByteRefColors[0]; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + dirtyFlag = 0; + } + } else { + cdirty = dirtyFlag; + } + + Object vcoord = null, cdataBuffer=null, normal=null; + + int vdefined = 0; + if((vertexType & PF) != 0) { + vdefined |= COORD_FLOAT; + vcoord = floatBufferRefCoords.getBufferAsObject(); + } else if((vertexType & PD ) != 0) { + vdefined |= COORD_DOUBLE; + vcoord = doubleBufferRefCoords.getBufferAsObject(); + } + if((vertexType & CF ) != 0) { + vdefined |= COLOR_FLOAT; + cdataBuffer = floatBufferRefColors.getBufferAsObject(); + } else if((vertexType & CUB) != 0) { + vdefined |= COLOR_BYTE; + cdataBuffer = byteBufferRefColors.getBufferAsObject(); + } + + if((vertexType & NORMAL_DEFINED) != 0) { + vdefined |= NORMAL_FLOAT; + normal = floatBufferRefNormals.getBufferAsObject(); + } + + if ((vertexType & VATTR_DEFINED) != 0) { + vdefined |= VATTR_FLOAT; + } + + if ((vertexType & TEXCOORD_DEFINED) != 0) { + vdefined |= TEXCOORD_FLOAT; + } + + Pipeline.getPipeline().executeIndexedGeometryVABuffer(cv.ctx, + this, geoType, isNonUniformScale, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + maxCoordIndex + 1, + (vertexFormat | c4fAllocated), + vdefined, + vcoord, + cdataBuffer, + cfdata, cbdata, + normal, + vertexAttrCount, vertexAttrSizes, + nioFloatBufferRefVertexAttrs, + ((texCoordSetMap == null) ? 0:texCoordSetMap.length), + texCoordSetMap, + cv.numActiveTexUnit, + texCoordStride, + refTexCoords, cdirty, indexCoord); + + } + } // end of non interleaved and by reference + } // end of nio buffer + } + + void buildGA(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale, + boolean updateAlpha, float alpha, boolean ignoreVertexColors, + Transform3D xform, Transform3D nxform) { + int cdirty; + boolean useAlpha = false; + Object[] retVal; + if (mirrorGeometry != null) { + ((GeometryArrayRetained)mirrorGeometry).buildGA(cv, ra, isNonUniformScale, updateAlpha, alpha, + ignoreVertexColors, xform, nxform); + } + else { + + if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) { + float[] vdata; + // System.err.println("by-copy"); + synchronized (this) { + cdirty = dirtyFlag; + if (updateAlpha && !ignoreVertexColors) { + // update the alpha values + retVal = updateAlphaInVertexData(cv, cv.screen.screen, alpha); + useAlpha = (retVal[0] == Boolean.TRUE); + vdata = (float[])retVal[1]; + + // D3D only + if (alpha != lastScreenAlpha) { + // handle multiple screen case + lastScreenAlpha = alpha; + cdirty |= COLOR_CHANGED; + } + } else { + vdata = vertexData; + // if transparency switch between on/off + if (lastScreenAlpha != -1) { + lastScreenAlpha = -1; + cdirty |= COLOR_CHANGED; + } + } + // geomLock is get in MasterControl when + // RenderBin render the geometry. So it is safe + // just to set the dirty flag here + dirtyFlag = 0; + } + + Pipeline.getPipeline().buildIndexedGeometry(cv.ctx, + this, geoType, isNonUniformScale, + updateAlpha, alpha, ignoreVertexColors, + initialIndexIndex, + validIndexCount, + maxCoordIndex + 1, + vertexFormat, + vertexAttrCount, vertexAttrSizes, + texCoordSetCount, texCoordSetMap, + (texCoordSetMap == null) ? 0 : texCoordSetMap.length, + texCoordSetMapOffset, + (xform == null) ? null : xform.mat, + (nxform == null) ? null : nxform.mat, + vdata, indexCoord); + } + // XXXX: Note that there is no "else" clause here, and no + // buildIndexedGeometryForByRef() method. + // We would need to create one if we ever wanted to support by-ref + // indexed geometry in display lists. Better yet, we could fix + // canBeInDisplayList so that unindexified by-ref geometry could + // go into a display list. + } + } + + void mergeGeometryArrays(ArrayList list) { + int numMerge = list.size(); + int[] texCoord = null; + indexCount = 0; + for (int i=0; i < numMerge; i++) { + IndexedGeometryArrayRetained geo= (IndexedGeometryArrayRetained)list.get(i); + indexCount += geo.validIndexCount; + } + validIndexCount = indexCount; + initialIndexIndex = 0; + compileIndexCount = new int[numMerge]; + compileIndexOffset = new int[numMerge]; + indexCoord = new int[indexCount]; + boolean notUCIO = (vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0; + if (notUCIO) { + if ((vertexFormat & GeometryArray.COLOR) != 0) + indexColor = new int[indexCount]; + if ((vertexFormat & GeometryArray.NORMALS) != 0) + indexNormal = new int[indexCount]; + // We only merge if the texCoordSetCount is 1 and there are no + // vertex attrs + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + indexTexCoord = new int[1][]; + indexTexCoord[0] = new int[indexCount]; + texCoord = indexTexCoord[0]; + } + } + int curDataOffset = 0; + int curIndexOffset = 0; + for (int i = 0; i < numMerge; i++) { + IndexedGeometryArrayRetained geo= (IndexedGeometryArrayRetained)list.get(i); + int curIndexCount = geo.validIndexCount; + compileIndexCount[i] = curIndexCount; + // Copy all the indices + for (int j = 0; j < curIndexCount; j++) { + indexCoord[j+curIndexOffset] = geo.indexCoord[j+geo.initialIndexIndex]+curDataOffset; + if (notUCIO) { + if ((vertexFormat & GeometryArray.COLOR) != 0) + indexColor[j+curIndexOffset] = geo.indexColor[j+geo.initialIndexIndex]+curDataOffset; + if ((vertexFormat & GeometryArray.NORMALS) != 0) + indexNormal[j+curIndexOffset] = geo.indexNormal[j+geo.initialIndexIndex]+curDataOffset; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) + texCoord[j+curIndexOffset] = geo.indexTexCoord[0][j+geo.initialIndexIndex]+curDataOffset; + } + } + maxCoordIndex = geo.maxCoordIndex +curDataOffset; + compileIndexOffset[i] = curIndexOffset; + curDataOffset += geo.vertexCount; + curIndexOffset += curIndexCount; + } + // reset the max Values + + // call the super to merge the vertex data + super.mergeGeometryArrays(list); + } + + + boolean isWriteStatic() { + + if (!super.isWriteStatic() || + source.getCapability(IndexedGeometryArray.ALLOW_COORDINATE_INDEX_WRITE ) || + source.getCapability(IndexedGeometryArray.ALLOW_COLOR_INDEX_WRITE) || + source.getCapability(IndexedGeometryArray.ALLOW_NORMAL_INDEX_WRITE) || + source.getCapability(IndexedGeometryArray.ALLOW_VERTEX_ATTR_INDEX_WRITE) || + source.getCapability(IndexedGeometryArray.ALLOW_TEXCOORD_INDEX_WRITE)) { + return false; + } + + return true; + } + + /** + * Gets current number of indices + * @return indexCount + */ + int getIndexCount(int id){ + return compileIndexCount[id]; + } + + int computeMaxIndex(int initial, int count, int[] indices) { + int maxIndex = 0; + if (indices != null) { + for (int i = initial; i < (initial+count); i++) { + if (indices[i] > maxIndex) { + maxIndex = indices[i]; + } + } + } + return maxIndex; + + } + + //NVaidya + // same as computeMaxIndex method but checks for index < 0 + int computeMaxIndexWithCheck(int initial, int count, int[] indices) { + int maxIndex = 0; + for (int i = initial; i < (initial+count); i++) { + // Throw an exception, since index is negative + if (indices[i] < 0) + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray27")); + if (indices[i] > maxIndex) { + maxIndex = indices[i]; + } + } + return maxIndex; + + } + + void setValidIndexCount(int validIndexCount) { + if (validIndexCount < 0) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedGeometryArray21")); + } + if ((initialIndexIndex + validIndexCount) > indexCount) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedGeometryArray22")); + } + if ((vertexFormat & GeometryArray.BY_REFERENCE_INDICES) != 0) { + if (indexCoord != null && indexCoord.length < initialIndexIndex + validIndexCount) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedGeometryArray33")); + } + } + int newCoordMax =0; + int newColorIndex=0; + int newNormalIndex=0; + int[] newTexCoordIndex = null; + int[] newVertexAttrIndex = null; + + newCoordMax = computeMaxIndex(initialIndexIndex, validIndexCount,indexCoord ); + doErrorCheck(newCoordMax); + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) { + if ((vertexFormat & GeometryArray.COLOR) != 0) { + newColorIndex = computeMaxIndex(initialIndexIndex, validIndexCount, indexColor); + doColorCheck(newColorIndex); + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + newTexCoordIndex = new int[texCoordSetCount]; + for (int i = 0; i < texCoordSetCount; i++) { + newTexCoordIndex[i] = computeMaxIndex(initialIndexIndex,validIndexCount, + indexTexCoord[i]); + doTexCoordCheck(newTexCoordIndex[i], i); + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + newVertexAttrIndex = new int[vertexAttrCount]; + for (int i = 0; i < vertexAttrCount; i++) { + newVertexAttrIndex[i] = computeMaxIndex(initialIndexIndex, + validIndexCount, + indexVertexAttr[i]); + doVertexAttrCheck(newVertexAttrIndex[i], i); + } + } + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + newNormalIndex = computeMaxIndex(initialIndexIndex, validIndexCount, indexNormal); + doNormalCheck(newNormalIndex); + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + this.validIndexCount = validIndexCount; + maxCoordIndex = newCoordMax; + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) { + maxColorIndex = newColorIndex; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = newTexCoordIndex[i]; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = newVertexAttrIndex[i]; + } + } + maxNormalIndex = newNormalIndex; + } + else { + maxColorIndex = maxCoordIndex; + maxNormalIndex = maxCoordIndex; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = maxCoordIndex; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = maxCoordIndex; + } + } + } + if(isLive) { + geomLock.unLock(); + } + // bbox is computed for the entries list. + // so, send as false + if (!inUpdater && isLive) { + sendDataChangedMessage(true); + } + + } + + void setInitialIndexIndex(int initialIndexIndex) { + if ((initialIndexIndex + validIndexCount) > indexCount) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedGeometryArray22")); + } + if ((vertexFormat & GeometryArray.BY_REFERENCE_INDICES) != 0) { + if (indexCoord != null && indexCoord.length < initialIndexIndex + validIndexCount) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedGeometryArray33")); + } + } + + int newCoordMax =0; + int newColorIndex=0; + int newNormalIndex=0; + int[] newTexCoordIndex = null; + int[] newVertexAttrIndex = null; + + newCoordMax = computeMaxIndex(initialIndexIndex, validIndexCount, indexCoord); + doErrorCheck(newCoordMax); + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) { + if ((vertexFormat & GeometryArray.COLOR) != 0) { + newColorIndex = computeMaxIndex(initialIndexIndex, validIndexCount, indexColor); + doColorCheck(newColorIndex); + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + newTexCoordIndex = new int[texCoordSetCount]; + for (int i = 0; i < texCoordSetCount; i++) { + newTexCoordIndex[i] = computeMaxIndex(initialIndexIndex,validIndexCount, + indexTexCoord[i]); + doTexCoordCheck(newTexCoordIndex[i], i); + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + newVertexAttrIndex = new int[vertexAttrCount]; + for (int i = 0; i < vertexAttrCount; i++) { + newVertexAttrIndex[i] = computeMaxIndex(initialIndexIndex, + validIndexCount, + indexVertexAttr[i]); + doVertexAttrCheck(newVertexAttrIndex[i], i); + } + } + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + newNormalIndex = computeMaxIndex(initialIndexIndex, validIndexCount, indexNormal); + doNormalCheck(newNormalIndex); + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + dirtyFlag |= INDEX_CHANGED; + this.initialIndexIndex = initialIndexIndex; + maxCoordIndex = newCoordMax; + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) { + maxColorIndex = newColorIndex; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = newTexCoordIndex[i]; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = newVertexAttrIndex[i]; + } + } + maxNormalIndex = newNormalIndex; + } + else { + maxColorIndex = maxCoordIndex; + maxNormalIndex = maxCoordIndex; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (int i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = maxCoordIndex; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = maxCoordIndex; + } + } + } + if(isLive) { + geomLock.unLock(); + } + // bbox is computed for the entries list. + // so, send as false + if (!inUpdater && isLive) { + sendDataChangedMessage(true); + } + } + + int getInitialIndexIndex() { + return initialIndexIndex; + } + + int getValidIndexCount() { + return validIndexCount; + } + + void handleFrequencyChange(int bit) { + if ((bit == IndexedGeometryArray.ALLOW_COORDINATE_INDEX_WRITE) || + (((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) && + ((vertexFormat & GeometryArray.COLOR) != 0) && + bit == IndexedGeometryArray.ALLOW_COLOR_INDEX_WRITE) || + (((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) && + ((vertexFormat & GeometryArray.NORMALS) != 0) && + bit == IndexedGeometryArray.ALLOW_NORMAL_INDEX_WRITE) || + (((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0)&& + ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0)&& + bit == IndexedGeometryArray.ALLOW_VERTEX_ATTR_INDEX_WRITE) || + (((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0)&& + ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0)&& + bit == IndexedGeometryArray.ALLOW_TEXCOORD_INDEX_WRITE)) { + + setFrequencyChangeMask(bit, 0x1); + } + else { + super.handleFrequencyChange(bit); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryStripArray.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryStripArray.java new file mode 100644 index 0000000..a87ed00 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryStripArray.java @@ -0,0 +1,265 @@ +/* + * $RCSfile: IndexedGeometryStripArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The IndexedGeometryStripArray object is an abstract class that is extended for + * a set of IndexedGeometryArray strip primitives. These include LINE_STRIP, + * TRIANGLE_STRIP, and TRIANGLE_FAN. + */ + +public abstract class IndexedGeometryStripArray extends IndexedGeometryArray { + + // non-public, no parameter constructor + IndexedGeometryStripArray() {} + + /** + * Constructs an empty IndexedGeometryStripArray object with the specified + * number of vertices, vertex format, number of indices, and + * array of per-strip index counts. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int)} + * for a description of this parameter. + * + * @param stripIndexCounts array that specifies + * the count of the number of indices for each separate strip. + * The length of this array is the number of separate strips. + * The sum of the elements in this array defines the total number + * of valid indexed vertices that are rendered (validIndexCount). + * + * @exception IllegalArgumentException if + * validIndexCount > indexCount + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public IndexedGeometryStripArray(int vertexCount, + int vertexFormat, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, indexCount); + ((IndexedGeometryStripArrayRetained)this.retained). + setStripIndexCounts(stripIndexCounts); + } + + /** + * Constructs an empty IndexedGeometryStripArray object with the specified + * number of vertices, vertex format, number of texture coordinate + * sets, texture coordinate mapping array, number of indices, and + * array of per-strip index counts. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int)} + * for a description of this parameter. + * + * @param stripIndexCounts array that specifies + * the count of the number of indices for each separate strip. + * The length of this array is the number of separate strips. + * The sum of the elements in this array defines the total number + * of valid indexed vertices that are rendered (validIndexCount). + * + * @exception IllegalArgumentException if + * validIndexCount > indexCount + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedGeometryStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + indexCount); + ((IndexedGeometryStripArrayRetained)this.retained). + setStripIndexCounts(stripIndexCounts); + } + + /** + * Constructs an empty IndexedGeometryStripArray object with the + * specified number of vertices, vertex format, number of texture + * coordinate sets, texture coordinate mapping array, vertex + * attribute count, vertex attribute sizes array, number of + * indices, and array of per-strip index counts. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int,int[],int)} + * for a description of this parameter. + * + * @param stripIndexCounts array that specifies + * the count of the number of indices for each separate strip. + * The length of this array is the number of separate strips. + * The sum of the elements in this array defines the total number + * of valid indexed vertices that are rendered (validIndexCount). + * + * @exception IllegalArgumentException if + * validIndexCount > indexCount + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedGeometryStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + indexCount); + + ((IndexedGeometryStripArrayRetained)this.retained). + setStripIndexCounts(stripIndexCounts); + } + + /** + * Get number of strips in the GeometryStripArray + * @return numStrips number of strips + */ + public int getNumStrips(){ + if (isLiveOrCompiled()) + if(!this.getCapability(GeometryArray.ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryStripArray0")); + + return ((IndexedGeometryStripArrayRetained)this.retained).getNumStrips(); + } + + /** + * Sets the array of strip index counts. The length of this + * array is the number of separate strips. The elements in this + * array specify the number of indices for each separate strip. + * The sum of the elements in this array defines the total number + * of valid indexed vertices that are rendered (validIndexCount). + * + * @param stripIndexCounts array that specifies + * the count of the number of indices for each separate strip. + * + * @exception IllegalArgumentException if + * initialIndexIndex + validIndexCount > indexCount + * + * @since Java 3D 1.3 + */ + public void setStripIndexCounts(int[] stripIndexCounts) { + if (isLiveOrCompiled()) + if(!this.getCapability(GeometryArray.ALLOW_COUNT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryStripArray2")); + + ((IndexedGeometryStripArrayRetained)this.retained).setStripIndexCounts(stripIndexCounts); + + } + + /** + * Gets a list of indexCounts for each strip. The list is + * copied into the specified array. The array must be + * large enough to hold all of the ints. + * @param stripIndexCounts an array that will receive indexCounts + */ + public void getStripIndexCounts(int[] stripIndexCounts) { + if (isLiveOrCompiled()) + if(!this.getCapability(GeometryArray.ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("IndexedGeometryStripArray1")); + + ((IndexedGeometryStripArrayRetained)this.retained). + getStripIndexCounts(stripIndexCounts); + } + + /** + * This method is not supported for indexed geometry strip arrays. + * The sum of the elements in the strip index counts array defines + * the valid index count. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setValidIndexCount(int validIndexCount) { + throw new UnsupportedOperationException(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryStripArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryStripArrayRetained.java new file mode 100644 index 0000000..5538cdb --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedGeometryStripArrayRetained.java @@ -0,0 +1,251 @@ +/* + * $RCSfile: IndexedGeometryStripArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.ArrayList; + +/** + * The IndexedGeometryStripArray object is an abstract class that is extended for + * a set of IndexedGeometryArray strip primitives. These include LINE_STRIP, + * TRIANGLE_STRIP, and TRIANGLE_FAN. + */ + +abstract class IndexedGeometryStripArrayRetained extends IndexedGeometryArrayRetained { + + // Array of per-strip vertex counts + int stripIndexCounts[]; + + // Following variables are only used in compile mode + int[] compileStripICOffset; + int[] compileIndexLength; + + /** + * Set stripIndexCount data into local array + */ + void setStripIndexCounts(int stripIndexCounts[]) { + int i, num = stripIndexCounts.length, total = 0; + + for (i=0; i < num; i++) { + total += stripIndexCounts[i]; + if (this instanceof IndexedLineStripArrayRetained) { + if (stripIndexCounts[i] < 2) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArrayRetained1")); + } + } + else if (this instanceof IndexedTriangleStripArrayRetained) { + if (stripIndexCounts[i] < 3) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleStripArrayRetained1")); + } + } + else if (this instanceof IndexedTriangleFanArrayRetained) { + if (stripIndexCounts[i] < 3) { + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleFanArrayRetained1")); + } + } + } + + // Sum of all stripIndexCounts MUST be same as indexCount + if ((initialIndexIndex + total) > indexCount) + throw new IllegalArgumentException(J3dI18N.getString("IndexedGeometryStripArrayRetained0")); + int newCoordMax =0; + int newColorIndex=0; + int newNormalIndex=0; + int[] newTexCoordIndex = null; + int[] newVertexAttrIndex = null; + + newCoordMax = computeMaxIndex(initialIndexIndex, total, indexCoord); + doErrorCheck(newCoordMax); + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) { + if ((vertexFormat & GeometryArray.COLOR) != 0) { + newColorIndex = computeMaxIndex(initialIndexIndex, total, indexColor); + doColorCheck(newColorIndex); + } + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + newTexCoordIndex = new int[texCoordSetCount]; + for (i = 0; i < texCoordSetCount; i++) { + newTexCoordIndex[i] = computeMaxIndex(initialIndexIndex,total, + indexTexCoord[i]); + doTexCoordCheck(newTexCoordIndex[i], i); + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + newVertexAttrIndex = new int[vertexAttrCount]; + for (i = 0; i < vertexAttrCount; i++) { + newVertexAttrIndex[i] = computeMaxIndex(initialIndexIndex, + total, + indexVertexAttr[i]); + doTexCoordCheck(newVertexAttrIndex[i], i); + } + } + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + newNormalIndex = computeMaxIndex(initialIndexIndex, total, indexNormal); + doNormalCheck(newNormalIndex); + } + } + + boolean isLive = source!=null && source.isLive(); + if(isLive){ + geomLock.getLock(); + } + validIndexCount = total; + this.stripIndexCounts = new int[num]; + for (i=0;i < num;i++) + { + this.stripIndexCounts[i] = stripIndexCounts[i]; + } + maxCoordIndex = newCoordMax; + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) { + maxColorIndex = newColorIndex; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = newTexCoordIndex[i]; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = newVertexAttrIndex[i]; + } + } + maxNormalIndex = newNormalIndex; + } + else { + maxColorIndex = maxCoordIndex; + maxNormalIndex = maxCoordIndex; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (i = 0; i < texCoordSetCount; i++) { + maxTexCoordIndices[i] = maxCoordIndex; + } + } + if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (i = 0; i < vertexAttrCount; i++) { + maxVertexAttrIndices[i] = maxCoordIndex; + } + } + } + if(isLive) { + geomLock.unLock(); + } + // bbox is computed for the entries list. + // so, send as false + if (!inUpdater && isLive) { + sendDataChangedMessage(true); + } + + } + + @Override + GeometryArrayRetained cloneNonIndexedGeometry() { + GeometryStripArrayRetained obj = null; + + switch (this.geoType) { + case GEO_TYPE_INDEXED_LINE_STRIP_SET: + obj = new LineStripArrayRetained(); + break; + case GEO_TYPE_INDEXED_TRI_FAN_SET: + obj = new TriangleFanArrayRetained(); + break; + case GEO_TYPE_INDEXED_TRI_STRIP_SET: + obj = new TriangleStripArrayRetained(); + break; + } + obj.createGeometryArrayData(validIndexCount, + (vertexFormat & ~(GeometryArray.BY_REFERENCE|GeometryArray.INTERLEAVED|GeometryArray.USE_NIO_BUFFER)), + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + obj.unIndexify(this); + obj.setStripVertexCounts(stripIndexCounts); + obj.cloneSourceArray = this; + obj.source = source; + + return obj; + } + + + /** + * Get number of strips in the GeometryStripArray + * @return numStrips number of strips + */ + int getNumStrips(){ + return stripIndexCounts.length; + } + + /** + * Get a list of vertexCounts for each strip + * @param stripIndexCounts an array that will receive vertexCounts + */ + void getStripIndexCounts(int stripIndexCounts[]){ + for (int i=stripIndexCounts.length-1;i >= 0; i--) { + stripIndexCounts[i] = this.stripIndexCounts[i]; + } + } + + void mergeGeometryArrays(ArrayList list) { + int numMerge = list.size(); + int numCount = 0; + int i, j; + + for (i = 0; i < numMerge; i++) { + IndexedGeometryStripArrayRetained geo = (IndexedGeometryStripArrayRetained) list.get(i); + numCount += geo.stripIndexCounts.length; + } + + stripIndexCounts = new int[numCount]; + compileIndexLength = new int[numCount]; + compileStripICOffset = new int[numMerge]; + int curICOffset = 0; + for (i = 0; i < numMerge; i++) { + IndexedGeometryStripArrayRetained geo = (IndexedGeometryStripArrayRetained) list.get(i); + compileStripICOffset[i] = curICOffset; + compileIndexLength[i] = geo.stripIndexCounts.length; + System.arraycopy(geo.stripIndexCounts, 0, stripIndexCounts, + curICOffset, geo.stripIndexCounts.length); + curICOffset += geo.stripIndexCounts.length; + } + super.mergeGeometryArrays(list); + + } + int getNumStrips(int id){ + return compileIndexLength[id]; + } + + /** + * Get a list of vertexCounts for each strip + * @param stripIndexCounts an array that will receive vertexCounts + */ + void getStripIndexCounts(int id, int stripIndexCounts[]){ + int count = compileIndexLength[id]; + int coffset = compileStripICOffset[id]; + for (int i=0;i < count; i++) { + stripIndexCounts[i] = this.stripIndexCounts[coffset+1]; + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedLineArray.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedLineArray.java new file mode 100644 index 0000000..842908e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedLineArray.java @@ -0,0 +1,222 @@ +/* + * $RCSfile: IndexedLineArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The IndexedLineArray object draws the array of vertices as individual + * line segments. Each pair of vertices defines a line to be drawn. + */ + +public class IndexedLineArray extends IndexedGeometryArray { + /** + * Package scoped default constructor. + */ + IndexedLineArray() { + } + + /** + * Constructs an empty IndexedLineArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 2, or indexCount is not + * a multiple of 2 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public IndexedLineArray(int vertexCount, int vertexFormat, int indexCount) { + super(vertexCount,vertexFormat, indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineArray0")); + + if (indexCount < 2 || ((indexCount%2) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineArray1")); + } + + /** + * Constructs an empty IndexedLineArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 2, or indexCount is not + * a multiple of 2 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedLineArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineArray0")); + + if (indexCount < 2 || ((indexCount%2) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineArray1")); + } + + /** + * Constructs an empty IndexedLineArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int,int[],int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 2, or indexCount is not + * a multiple of 2 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedLineArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineArray0")); + + if (indexCount < 2 || ((indexCount%2) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineArray1")); + } + + /** + * Creates the retained mode IndexedLineArrayRetained object that this + * IndexedLineArray object will point to. + */ + void createRetained() { + this.retained = new IndexedLineArrayRetained(); + this.retained.setSource(this); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + IndexedLineArrayRetained rt = (IndexedLineArrayRetained) retained; + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + IndexedLineArray l = new IndexedLineArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + rt.getIndexCount()); + l.duplicateNodeComponent(this); + return l; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedLineArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedLineArrayRetained.java new file mode 100644 index 0000000..d2c7c35 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedLineArrayRetained.java @@ -0,0 +1,431 @@ +/* + * $RCSfile: IndexedLineArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The IndexedLineArray object draws the array of vertices as individual + * line segments. Each pair of vertices defines a line to be drawn. + */ + +class IndexedLineArrayRetained extends IndexedGeometryArrayRetained { + + IndexedLineArrayRetained() { + this.geoType = GEO_TYPE_INDEXED_LINE_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[2]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + //NVaidya + // Bug 447: While loops below now traverse over all + // elements in the valid index range from initialIndexIndex + // to initialIndexInex + validIndexCount - 1 + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + int[] vtxIndexArr = new int[2]; + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < loopStopIndex) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[k]); + } + if (intersectLineAndRay(pnts[0], pnts[1], pickRay.origin, + pickRay.direction, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + Vector3d dir = + new Vector3d(pickSegment.end.x - pickSegment.start.x, + pickSegment.end.y - pickSegment.start.y, + pickSegment.end.z - pickSegment.start.z); + + while (i < loopStopIndex) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[k]); + } + if (intersectLineAndRay(pnts[0], pnts[1], + pickSegment.start, + dir, sdist, iPnt) && + (sdist[0] <= 1.0)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < loopStopIndex) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[k]); + } + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < loopStopIndex) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[k]); + } + if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < loopStopIndex) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[k]); + } + if (intersectBoundingPolytope(pnts, bpolytope, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < loopStopIndex) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[k]); + } + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < loopStopIndex) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[k]); + } + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineArrayRetained0")); + default: + throw new RuntimeException("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + + } + + boolean intersect(Point3d[] pnts) { + Point3d[] points = new Point3d[2]; + Vector3d dir; + double dist[] = new double[1]; + //NVaidya + // Bug 447: correction for loop indices + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + points[0] = new Point3d(); + points[1] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle/Quad , common case first + case 4: + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + if (intersectSegment(pnts, points[0], points[1], dist, + null)) { + return true; + } + } + break; + case 2: // Line + dir = new Vector3d(); + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + dir.x = points[1].x - points[0].x; + dir.y = points[1].y - points[0].y; + dir.z = points[1].z - points[0].z; + if (intersectLineAndRay(pnts[0], pnts[1], points[0], + dir, dist, null) && + (dist[0] <= 1.0)) { + return true; + } + } + break; + case 1: // Point + dir = new Vector3d(); + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + dir.x = points[1].x - points[0].x; + dir.y = points[1].y - points[0].y; + dir.z = points[1].z - points[0].z; + if (intersectPntAndRay(pnts[0], points[0], dir, dist) && + (dist[0] <= 1.0)) { + return true; + } + } + break; + } + return false; + } + + + boolean intersect(Transform3D thisToOtherVworld, + GeometryRetained geom) { + + Point3d[] pnts = new Point3d[2]; + //NVaidya + // Bug 447: correction for loop indices + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], pnts[0]); + getVertexData(indexCoord[i++], pnts[1]); + thisToOtherVworld.transform(pnts[0]); + thisToOtherVworld.transform(pnts[1]); + if (geom.intersect(pnts)) { + return true; + } + } + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + Point3d[] pnts = new Point3d[2]; + //NVaidya + // Bug 447: correction for loop indices + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while(i < loopStopIndex) { + getVertexData(indexCoord[i++], pnts[0]); + getVertexData(indexCoord[i++], pnts[1]); + if (intersectBoundingBox(pnts, box, null, null)) { + return true; + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + + while(i < loopStopIndex) { + getVertexData(indexCoord[i++], pnts[0]); + getVertexData(indexCoord[i++], pnts[1]); + if (intersectBoundingSphere(pnts, bsphere, null, null)) { + return true; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + + while(i < loopStopIndex) { + getVertexData(indexCoord[i++], pnts[0]); + getVertexData(indexCoord[i++], pnts[1]); + if (intersectBoundingPolytope(pnts, bpolytope, null, null)) { + return true; + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + return false; + } + + int getClassType() { + return LINE_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedLineStripArray.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedLineStripArray.java new file mode 100644 index 0000000..6afcc2f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedLineStripArray.java @@ -0,0 +1,250 @@ +/* + * $RCSfile: IndexedLineStripArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The IndexedLineStripArray object draws an array of vertices as a set of + * connected line strips. An array of per-strip index counts specifies + * where the separate strips appear in the indexed vertex array. + * For every strip in the set, each vertex, beginning with + * the second vertex in the array, defines a line segment to be drawn + * from the previous vertex to the current vertex. + */ + +public class IndexedLineStripArray extends IndexedGeometryStripArray { + + /** + * Package scoped default constructor. + */ + IndexedLineStripArray() { + } + + /** + * Constructs an empty IndexedLineStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int)} + * for a description of this parameter. + * + * @param stripIndexCounts + * see {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 2, + * or any element in the stripIndexCounts array is less than 2 + * ;
+ * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[])} + * for more exceptions that can be thrown + */ + public IndexedLineStripArray(int vertexCount, + int vertexFormat, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArray0")); + + if (indexCount < 2 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArray1")); + } + + /** + * Constructs an empty IndexedLineStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int)} + * for a description of this parameter. + * + * @param stripIndexCounts + * see {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 2, + * or any element in the stripIndexCounts array is less than 2 + * ;
+ * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedLineStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArray0")); + + if (indexCount < 2 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArray1")); + } + + /** + * Constructs an empty IndexedLineStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int,int[],int)} + * for a description of this parameter. + * + * @param stripIndexCounts + * see {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 2, + * or any element in the stripIndexCounts array is less than 2 + * ;
+ * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedLineStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArray0")); + + if (indexCount < 2 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArray1")); + } + + /** + * Creates the retained mode IndexedLineStripArrayRetained object that this + * IndexedLineStripArray object will point to. + */ + void createRetained() { + this.retained = new IndexedLineStripArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + IndexedLineStripArrayRetained rt = + (IndexedLineStripArrayRetained) retained; + int stripIndexCounts[] = new int[rt.getNumStrips()]; + rt.getStripIndexCounts(stripIndexCounts); + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + IndexedLineStripArray l = new IndexedLineStripArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + rt.getIndexCount(), + stripIndexCounts); + l.duplicateNodeComponent(this); + return l; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedLineStripArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedLineStripArrayRetained.java new file mode 100644 index 0000000..bf3a270 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedLineStripArrayRetained.java @@ -0,0 +1,494 @@ +/* + * $RCSfile: IndexedLineStripArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import javax.vecmath.*; +import java.lang.Math; + +/** + * The IndexedLineStripArray object draws an array of vertices as a set of + * connected line strips. An array of per-strip vertex counts specifies + * where the separate strips appear in the vertex array. + * For every strip in the set, each vertex, beginning with + * the second vertex in the array, defines a line segment to be drawn + * from the previous vertex to the current vertex. + */ + +class IndexedLineStripArrayRetained extends IndexedGeometryStripArrayRetained { + + IndexedLineStripArrayRetained() { + geoType = GEO_TYPE_INDEXED_LINE_STRIP_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[2]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int scount, j, i = 0; + int count = 0; + int[] vtxIndexArr = new int[2]; + + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < stripIndexCounts.length) { + vtxIndexArr[0] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + vtxIndexArr[1] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[1]); + if (intersectLineAndRay(pnts[0], pnts[1], pickRay.origin, + pickRay.direction, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + Vector3d dir = + new Vector3d(pickSegment.end.x - pickSegment.start.x, + pickSegment.end.y - pickSegment.start.y, + pickSegment.end.z - pickSegment.start.z); + + while (i < stripIndexCounts.length) { + vtxIndexArr[0] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + vtxIndexArr[1] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[1]); + if (intersectLineAndRay(pnts[0], pnts[1], + pickSegment.start, + dir, sdist, iPnt) && + (sdist[0] <= 1.0)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + vtxIndexArr[0] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + vtxIndexArr[1] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[1]); + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + vtxIndexArr[0] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + vtxIndexArr[1] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[1]); + if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + vtxIndexArr[0] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + vtxIndexArr[1] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[1]); + if (intersectBoundingPolytope(pnts, bpolytope, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < stripIndexCounts.length) { + vtxIndexArr[0] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + vtxIndexArr[1] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[1]); + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < stripIndexCounts.length) { + vtxIndexArr[0] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + vtxIndexArr[1] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[1]); + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + // intersect pnts[] with every triangle in this object + boolean intersect(Point3d[] pnts) { + int i = 0; + int j, count=0; + int scount; + Point3d[] points = new Point3d[2]; + double dist[] = new double[1]; + Vector3d dir; + + points[0] = new Point3d(); + points[1] = new Point3d(); + + switch (pnts.length) { + case 3: + case 4: // Triangle, Quad + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + getVertexData(indexCoord[count++], points[1]); + if (intersectSegment(pnts, points[0], points[1], + dist, null)) { + return true; + } + points[0].set(points[1]); + } + } + break; + case 2: // line + dir = new Vector3d(); + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + getVertexData(indexCoord[count++], points[1]); + dir.x = points[1].x - points[0].x; + dir.y = points[1].y - points[0].y; + dir.z = points[1].z - points[0].z; + if (intersectLineAndRay(pnts[0], pnts[1], + points[0], dir, dist, null) + && (dist[0] <= 1.0)) { + return true; + } + points[0].set(points[1]); + } + } + break; + case 1: // point + dir = new Vector3d(); + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + getVertexData(indexCoord[count++], points[1]); + dir.x = points[1].x - points[0].x; + dir.y = points[1].y - points[0].y; + dir.z = points[1].z - points[0].z; + if (intersectPntAndRay(pnts[0], points[0], dir, + dist) && + (dist[0] <= 1.0)) { + return true; + } + points[0].set(points[1]); + } + } + break; + } + + return false; + } + + boolean intersect(Transform3D thisToOtherVworld, + GeometryRetained geom) { + int i = 0; + int j, count=0; + Point3d[] pnts = new Point3d[2]; + int scount; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + thisToOtherVworld.transform(pnts[0]); + scount = stripIndexCounts[i++]; + + for (j = 1; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[1]); + thisToOtherVworld.transform(pnts[1]); + if (geom.intersect( pnts)) { + return true; + } + pnts[0].set(pnts[1]); + } + } + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + int i = 0; + int j, count=0; + Point3d[] pnts = new Point3d[2]; + int scount; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[1]); + if (intersectBoundingBox(pnts, box, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + } + + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[1]); + if (intersectBoundingSphere(pnts, bsphere, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + scount = stripIndexCounts[i++]; + for (j=1; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[1]); + if (intersectBoundingPolytope(pnts, bpolytope, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + return false; + } + + int getClassType() { + return LINE_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedObject.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedObject.java new file mode 100644 index 0000000..1ae97db --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedObject.java @@ -0,0 +1,73 @@ +/* + * $RCSfile: IndexedObject.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class used for IndexedUnorderedList + */ + +abstract class IndexedObject extends Object { + + /** + * A 2D array listIdx[3][len] is used. + * The entry listIdx[0][], listIdx[0][1] is used for each VirtualUniverse. + * The entry listIdx[2][0] is used for index to which one to use. + * + * This is used to handle the case the Node Object move from + * one VirtualUniverse A to another VirtualUniverse B. + * It is possible that another Structures in B may get the add + * message first before the Structures in A get the remove + * message to clear the entry. This cause MT problem. So a + * 2D array is used to resolve it. + */ + int[][] listIdx; + + abstract VirtualUniverse getVirtualUniverse(); + + synchronized int getIdxUsed(VirtualUniverse u) { + int idx = listIdx[2][0]; + if (u == getVirtualUniverse()) { + return idx; + } + return (idx == 0 ? 1 : 0); + } + + void incIdxUsed() { + if (listIdx[2][0] == 0) { + listIdx[2][0] = 1; + } else { + listIdx[2][0] = 0; + } + } +} + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedPointArray.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedPointArray.java new file mode 100644 index 0000000..eaba2ef --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedPointArray.java @@ -0,0 +1,221 @@ +/* + * $RCSfile: IndexedPointArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The IndexedPointArray object draws the array of vertices as + * individual points. + */ + +public class IndexedPointArray extends IndexedGeometryArray { + + /** + * Package scoped default constructor. + */ + IndexedPointArray() { + } + + /** + * Constructs an empty IndexedPointArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1 + * or indexCount is less than 1 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public IndexedPointArray(int vertexCount, int vertexFormat, int indexCount) { + super(vertexCount,vertexFormat, indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedPointArray0")); + + if (indexCount < 1 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedPointArray1")); + } + + /** + * Constructs an empty IndexedPointArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1 + * or indexCount is less than 1 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedPointArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedPointArray0")); + + if (indexCount < 1 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedPointArray1")); + } + + /** + * Constructs an empty IndexedPointArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int,int[],int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1 + * or indexCount is less than 1 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedPointArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedPointArray0")); + + if (indexCount < 1 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedPointArray1")); + } + + /** + * Creates the retained mode IndexedPointArrayRetained object that this + * IndexedPointArray object will point to. + */ + void createRetained() { + this.retained = new IndexedPointArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + IndexedPointArrayRetained rt = (IndexedPointArrayRetained) retained; + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + IndexedPointArray p = new IndexedPointArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + rt.getIndexCount()); + p.duplicateNodeComponent(this); + return p; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedPointArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedPointArrayRetained.java new file mode 100644 index 0000000..e88e4c8 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedPointArrayRetained.java @@ -0,0 +1,309 @@ +/* + * $RCSfile: IndexedPointArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The IndexedPointArray object draws the array of vertices as individual points. + */ + +class IndexedPointArrayRetained extends IndexedGeometryArrayRetained { + + IndexedPointArrayRetained() { + this.geoType = GEO_TYPE_INDEXED_POINT_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + Point3d pnt = new Point3d(); + int[] vtxIndexArr = new int[1]; + + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < validVertexCount) { + vtxIndexArr[0] = indexCoord[i]; + getVertexData(indexCoord[i++], pnt); + if (intersectPntAndRay(pnt, pickRay.origin, + pickRay.direction, sdist)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + Vector3d dir = + new Vector3d(pickSegment.end.x - pickSegment.start.x, + pickSegment.end.y - pickSegment.start.y, + pickSegment.end.z - pickSegment.start.z); + + while (i < validVertexCount) { + vtxIndexArr[0] = indexCoord[i]; + getVertexData(indexCoord[i++], pnt); + if (intersectPntAndRay(pnt, pickSegment.start, + dir, sdist) && + (sdist[0] <= 1.0)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGBOX: + case PickShape.PICKBOUNDINGSPHERE: + case PickShape.PICKBOUNDINGPOLYTOPE: + Bounds bounds = ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + vtxIndexArr[0] = indexCoord[i]; + getVertexData(indexCoord[i++], pnt); + if (bounds.intersect(pnt)) { + if (flags == 0) { + return true; + } + sdist[0] = pickShape.distance(pnt); + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < validVertexCount) { + vtxIndexArr[0] = indexCoord[i]; + getVertexData(indexCoord[i++], pnt); + if (intersectCylinder(pnt, pickCylinder, sdist)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < validVertexCount) { + vtxIndexArr[0] = indexCoord[i]; + getVertexData(indexCoord[i++], pnt); + if (intersectCone(pnt, pickCone, sdist)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("IndexedPointArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + boolean intersect(Point3d[] pnts) { + Point3d point = new Point3d(); + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + switch (pnts.length) { + case 3: // Triangle + while (i < validVertexCount) { + getVertexData(indexCoord[i++], point); + if (intersectTriPnt(pnts[0], pnts[1], pnts[2], point)) { + return true; + } + } + break; + case 4: // Quad + while (i < validVertexCount) { + getVertexData(indexCoord[i++], point); + if (intersectTriPnt(pnts[0], pnts[1], pnts[2], point) || + intersectTriPnt(pnts[0], pnts[2], pnts[3], point)) { + return true; + } + } + break; + case 2: // Line + double dist[] = new double[1]; + Vector3d dir = new Vector3d(); + + while (i < validVertexCount) { + getVertexData(indexCoord[i++], point); + dir.x = pnts[1].x - pnts[0].x; + dir.y = pnts[1].y - pnts[0].y; + dir.z = pnts[1].z - pnts[0].z; + if (intersectPntAndRay(point, pnts[0], dir, dist) && + (dist[0] <= 1.0)) { + return true; + } + } + break; + case 1: // Point + while (i < validVertexCount) { + getVertexData(indexCoord[i++], point); + if ((pnts[0].x == point.x) && + (pnts[0].y == point.y) && + (pnts[0].z == point.z)) { + return true; + } + } + break; + } + return false; + } + + boolean intersect(Transform3D thisToOtherVworld, + GeometryRetained geom) { + Point3d[] pnt = new Point3d[1]; + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + pnt[0] = new Point3d(); + + while (i < validVertexCount) { + getVertexData(indexCoord[i++], pnt[0]); + thisToOtherVworld.transform(pnt[0]); + if (geom.intersect(pnt)) { + return true; + } + } + return false; + + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + Point3d pnt = new Point3d(); + + while (i < validVertexCount) { + getVertexData(indexCoord[i++], pnt); + if (targetBound.intersect(pnt)) { + return true; + } + } + return false; + } + + int getClassType() { + return POINT_TYPE; + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedQuadArray.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedQuadArray.java new file mode 100644 index 0000000..3849ac7 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedQuadArray.java @@ -0,0 +1,225 @@ +/* + * $RCSfile: IndexedQuadArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The IndexedQuadArray object draws the array of vertices as individual + * quadrilaterals. Each group + * of four vertices defines a quadrilateral to be drawn. + */ + +public class IndexedQuadArray extends IndexedGeometryArray { + + /** + * Package scoped default constructor. + */ + IndexedQuadArray() { + } + + /** + * Constructs an empty IndexedQuadArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 4, or indexCount is not + * a multiple of 4 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public IndexedQuadArray(int vertexCount, int vertexFormat, int indexCount) { + super(vertexCount,vertexFormat, indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedQuadArray0")); + + if (indexCount < 4 || ((indexCount%4) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedQuadArray1")); + } + + /** + * Constructs an empty IndexedQuadArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 4, or indexCount is not + * a multiple of 4 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedQuadArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedQuadArray0")); + + if (indexCount < 4 || ((indexCount%4) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedQuadArray1")); + } + + /** + * Constructs an empty IndexedQuadArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int,int[],int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 4, or indexCount is not + * a multiple of 4 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedQuadArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedQuadArray0")); + + if (indexCount < 4 || ((indexCount%4) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedQuadArray1")); + } + + /** + * Creates the retained mode IndexedQuadArrayRetained object that this + * IndexedQuadArray object will point to. + */ + void createRetained() { + this.retained = new IndexedQuadArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + IndexedQuadArrayRetained rt = (IndexedQuadArrayRetained) retained; + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + IndexedQuadArray q = new IndexedQuadArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + rt.getIndexCount()); + q.duplicateNodeComponent(this); + return q; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedQuadArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedQuadArrayRetained.java new file mode 100644 index 0000000..0368835 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedQuadArrayRetained.java @@ -0,0 +1,460 @@ +/* + * $RCSfile: IndexedQuadArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The IndexedQuadArray object draws the array of vertices as individual + * quadrilaterals. Each group + * of four vertices defines a quadrilateral to be drawn. + */ + +class IndexedQuadArrayRetained extends IndexedGeometryArrayRetained { + + IndexedQuadArrayRetained() { + this.geoType = GEO_TYPE_INDEXED_QUAD_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[4]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int[] vtxIndexArr = new int[4]; + + //NVaidya + // Bug 447: While loops below now traverse over all + // elements in the valid index range from initialIndexIndex + // to initialIndexInex + validIndexCount - 1 + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + pnts[3] = new Point3d(); + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < loopStopIndex) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectRay(pnts, pickRay, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + + while (i < loopStopIndex) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectSegment(pnts, pickSegment.start, + pickSegment.end, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + while (i < loopStopIndex) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + while (i < loopStopIndex) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + while (i < loopStopIndex) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectBoundingPolytope(pnts, bpolytope, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + while (i < loopStopIndex) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + while (i < loopStopIndex) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("IndexedQuadArrayRetained0")); + default: + throw new RuntimeException("PickShape not supported for intersection "); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + + } + + // intersect pnts[] with every quad in this object + boolean intersect(Point3d[] pnts) { + Point3d[] points = new Point3d[4]; + double dist[] = new double[1]; + //NVaidya + // Bug 447: correction for loop indices + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + points[3] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + getVertexData(indexCoord[i++], points[2]); + getVertexData(indexCoord[i++], points[3]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[2], points[3], + pnts[0], pnts[1], pnts[2])) { + return true; + } + } + break; + case 4: // Quad + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + getVertexData(indexCoord[i++], points[2]); + getVertexData(indexCoord[i++], points[3]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[2], pnts[3]) || + intersectTriTri(points[0], points[2], points[3], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[2], points[3], + pnts[0], pnts[2], pnts[3])) { + return true; + } + } + break; + case 2: // Line + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + getVertexData(indexCoord[i++], points[2]); + getVertexData(indexCoord[i++], points[3]); + if (intersectSegment(points, pnts[0], pnts[1], dist, + null)) { + return true; + } + } + break; + case 1: // Point + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + getVertexData(indexCoord[i++], points[2]); + getVertexData(indexCoord[i++], points[3]); + if (intersectTriPnt(points[0], points[1], points[2], + pnts[0]) || + intersectTriPnt(points[0], points[2], points[3], + pnts[0])) { + return true; + } + } + break; + } + return false; + } + + + boolean intersect(Transform3D thisToOtherVworld, + GeometryRetained geom) { + + Point3d[] points = new Point3d[4]; + //NVaidya + // Bug 447: correction for loop indices + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + points[3] = new Point3d(); + + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + getVertexData(indexCoord[i++], points[2]); + getVertexData(indexCoord[i++], points[3]); + thisToOtherVworld.transform(points[0]); + thisToOtherVworld.transform(points[1]); + thisToOtherVworld.transform(points[2]); + thisToOtherVworld.transform(points[3]); + if (geom.intersect(points)) { + return true; + } + } // for each quad + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + Point3d[] points = new Point3d[4]; + //NVaidya + // Bug 447: correction for loop indices + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + points[3] = new Point3d(); + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + getVertexData(indexCoord[i++], points[2]); + getVertexData(indexCoord[i++], points[3]); + if (intersectBoundingBox(points, box, null, null)) { + return true; + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + getVertexData(indexCoord[i++], points[2]); + getVertexData(indexCoord[i++], points[3]); + if (intersectBoundingSphere(points, bsphere, null, + null)) { + return true; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + while (i < loopStopIndex) { + getVertexData(indexCoord[i++], points[0]); + getVertexData(indexCoord[i++], points[1]); + getVertexData(indexCoord[i++], points[2]); + getVertexData(indexCoord[i++], points[3]); + if (intersectBoundingPolytope(points, bpolytope, null, null)) { + return true; + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + return false; + } + + + int getClassType() { + return QUAD_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleArray.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleArray.java new file mode 100644 index 0000000..ee2dc69 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleArray.java @@ -0,0 +1,225 @@ +/* + * $RCSfile: IndexedTriangleArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The IndexedTriangleArray object draws the array of vertices as individual + * triangles. Each group + * of three vertices defines a triangle to be drawn. + */ + +public class IndexedTriangleArray extends IndexedGeometryArray { + + /** + * Package scoped default constructor. + */ + IndexedTriangleArray() { + } + + /** + * Constructs an empty IndexedTriangleArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 3, or indexCount is not + * a multiple of 3 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public IndexedTriangleArray(int vertexCount, int vertexFormat, int indexCount) { + super(vertexCount,vertexFormat, indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleArray0")); + + if (indexCount < 3 || ((indexCount%3) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleArray1")); + } + + /** + * Constructs an empty IndexedTriangleArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 3, or indexCount is not + * a multiple of 3 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedTriangleArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleArray0")); + + if (indexCount < 3 || ((indexCount%3) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleArray1")); + } + + /** + * Constructs an empty IndexedTriangleArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int,int[],int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 3, or indexCount is not + * a multiple of 3 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedTriangleArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + indexCount); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleArray0")); + + if (indexCount < 3 || ((indexCount%3) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleArray1")); + } + + /** + * Creates the retained mode IndexedTriangleArrayRetained object that this + * IndexedTriangleArray object will point to. + */ + void createRetained() { + this.retained = new IndexedTriangleArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + IndexedTriangleArrayRetained rt = (IndexedTriangleArrayRetained) retained; + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + IndexedTriangleArray t = new IndexedTriangleArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + rt.getIndexCount()); + t.duplicateNodeComponent(this); + return t; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleArrayRetained.java new file mode 100644 index 0000000..dca0208 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleArrayRetained.java @@ -0,0 +1,440 @@ +/* + * $RCSfile: IndexedTriangleArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:24 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The IndexedTriangleArray object draws the array of vertices as individual + * triangles. Each group + * of three vertices defines a triangle to be drawn. + */ + +class IndexedTriangleArrayRetained extends IndexedGeometryArrayRetained { + + IndexedTriangleArrayRetained() { + this.geoType = GEO_TYPE_INDEXED_TRI_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[3]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int[] vtxIndexArr = new int[3]; + + //NVaidya + // Bug 447: While loops below now traverse over all + // elements in the valid index range from initialIndexIndex + // to initialIndexInex + validIndexCount - 1 + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < loopStopIndex) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectRay(pnts, pickRay, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + while (i < loopStopIndex) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectSegment(pnts, pickSegment.start, + pickSegment.end, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < loopStopIndex) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < loopStopIndex) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < loopStopIndex) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectBoundingPolytope(pnts, bpolytope, + sdist,iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + while (i < loopStopIndex) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectCylinder(pnts, pickCylinder, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < loopStopIndex) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = indexCoord[i]; + getVertexData(indexCoord[i++], pnts[j]); + } + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + // intersect pnts[] with every triangle in this object + boolean intersect(Point3d[] pnts) { + Point3d[] points = new Point3d[3]; + double dist[] = new double[1]; + //NVaidya + // Bug 447: correction for loop indices + int i = initialIndexIndex; + int loopStopIndex = initialIndexIndex + validIndexCount; + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle + while (i + * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[])} + * for more exceptions that can be thrown + */ + public IndexedTriangleFanArray(int vertexCount, + int vertexFormat, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleFanArray0")); + + if (indexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleFanArray1")); + } + + /** + * Constructs an empty IndexedTriangleFanArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int)} + * for a description of this parameter. + * + * @param stripIndexCounts + * see {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 3, + * or any element in the stripIndexCounts array is less than 3 + * ;
+ * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedTriangleFanArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleFanArray0")); + + if (indexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleFanArray1")); + } + + /** + * Constructs an empty IndexedTriangleFanArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int,int[],int)} + * for a description of this parameter. + * + * @param stripIndexCounts + * see {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 3, + * or any element in the stripIndexCounts array is less than 3 + * ;
+ * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedTriangleFanArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleFanArray0")); + + if (indexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleFanArray1")); + } + + /** + * Creates the retained mode IndexedTriangleFanArrayRetained object that this + * IndexedTriangleFanArray object will point to. + */ + void createRetained() { + this.retained = new IndexedTriangleFanArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + IndexedTriangleFanArrayRetained rt = + (IndexedTriangleFanArrayRetained) retained; + int stripIndexCounts[] = new int[rt.getNumStrips()]; + rt.getStripIndexCounts(stripIndexCounts); + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + IndexedTriangleFanArray t = new IndexedTriangleFanArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + rt.getIndexCount(), + stripIndexCounts); + t.duplicateNodeComponent(this); + return t; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleFanArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleFanArrayRetained.java new file mode 100644 index 0000000..89bdb07 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleFanArrayRetained.java @@ -0,0 +1,513 @@ +/* + * $RCSfile: IndexedTriangleFanArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The IndexedTriangleFanArray object draws an array of vertices as a set of + * connected triangle fans. An array of per-strip + * vertex counts specifies where the separate strips (fans) appear + * in the vertex array. For every strip in the set, + * each vertex, beginning with the third vertex in the array, + * defines a triangle to be drawn using the current vertex, + * the previous vertex and the first vertex. This can be thought of + * as a collection of convex polygons. + */ + +class IndexedTriangleFanArrayRetained extends IndexedGeometryStripArrayRetained { + + IndexedTriangleFanArrayRetained(){ + geoType = GEO_TYPE_INDEXED_TRI_FAN_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[3]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int i = 0; + int j, scount, count = 0; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + int[] vtxIndexArr = new int[3]; + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectRay(pnts, pickRay, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectSegment(pnts, pickSegment.start, + pickSegment.end, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingSphere(pnts, bsphere, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingPolytope(pnts, bpolytope, + sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleFanArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + // intersect pnts[] with every triangle in this object + boolean intersect(Point3d[] pnts) { + int j, end; + Point3d[] points = new Point3d[3]; + double dist[] = new double[1]; + int i = 0, scount, count = 0; + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + getVertexData(indexCoord[count++], points[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], points[2]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2])) { + return true; + } + points[1].set(points[2]); + } + } + break; + case 4: // Quad + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + getVertexData(indexCoord[count++], points[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], points[2]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[2], pnts[3])) { + return true; + } + points[1].set(points[2]); + } + } + break; + case 2: // Line + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + getVertexData(indexCoord[count++], points[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], points[2]); + if (intersectSegment(points, pnts[0], pnts[1], + dist, null)) { + return true; + } + points[1].set(points[2]); + } + } + break; + case 1: // Point + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + getVertexData(indexCoord[count++], points[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], points[2]); + if (intersectTriPnt(points[0], points[1], points[2], + pnts[0])) { + return true; + } + points[1].set(points[2]); + } + } + break; + } + return false; + } + + boolean intersect(Transform3D thisToOtherVworld, GeometryRetained geom) { + int i = 0, j, scount, count = 0; + Point3d[] pnts = new Point3d[3]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + getVertexData(indexCoord[count++], pnts[1]); + thisToOtherVworld.transform(pnts[0]); + thisToOtherVworld.transform(pnts[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[2]); + thisToOtherVworld.transform(pnts[2]); + if (geom.intersect(pnts)) { + return true; + } + pnts[1].set(pnts[2]); + } + } + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + int i = 0; + int j, scount, count = 0; + Point3d[] pnts = new Point3d[3]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + getVertexData(indexCoord[count++], pnts[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingBox(pnts, box, null, null)) { + return true; + } + pnts[1].set(pnts[2]); + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + getVertexData(indexCoord[count++], pnts[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingSphere(pnts, bsphere, null, null)) { + return true; + } + pnts[1].set(pnts[2]); + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + getVertexData(indexCoord[count++], pnts[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingPolytope(pnts, bpolytope, null, null)) { + return true; + } + pnts[1].set(pnts[2]); + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + return false; + } + + int getClassType() { + return TRIANGLE_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleStripArray.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleStripArray.java new file mode 100644 index 0000000..6d959d4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleStripArray.java @@ -0,0 +1,251 @@ +/* + * $RCSfile: IndexedTriangleStripArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The IndexedTriangleStripArray object draws an array of vertices as a set of + * connected triangle strips. An array of per-strip index counts specifies + * where the separate strips appear in the indexed vertex array. + * For every strip in the set, + * each vertex, beginning with the third vertex in the array, + * defines a triangle to be drawn using the current vertex and + * the two previous vertices. + */ + +public class IndexedTriangleStripArray extends IndexedGeometryStripArray { + + /** + * Package scoped default constructor + */ + IndexedTriangleStripArray() { + } + + /** + * Constructs an empty IndexedTriangleStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int)} + * for a description of this parameter. + * + * @param stripIndexCounts + * see {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 3, + * or any element in the stripIndexCounts array is less than 3 + * ;
+ * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[])} + * for more exceptions that can be thrown + */ + public IndexedTriangleStripArray(int vertexCount, + int vertexFormat, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleStripArray0")); + + if (indexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleStripArray1")); + } + + /** + * Constructs an empty IndexedTriangleStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int)} + * for a description of this parameter. + * + * @param stripIndexCounts + * see {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 3, + * or any element in the stripIndexCounts array is less than 3 + * ;
+ * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public IndexedTriangleStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleStripArray0")); + + if (indexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleStripArray1")); + } + + /** + * Constructs an empty IndexedTriangleStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param indexCount + * see {@link IndexedGeometryArray#IndexedGeometryArray(int,int,int,int[],int,int[],int)} + * for a description of this parameter. + * + * @param stripIndexCounts + * see {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1, + * or indexCount is less than 3, + * or any element in the stripIndexCounts array is less than 3 + * ;
+ * See {@link IndexedGeometryStripArray#IndexedGeometryStripArray(int,int,int,int[],int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public IndexedTriangleStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int indexCount, + int[] stripIndexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + indexCount, stripIndexCounts); + + if (vertexCount < 1) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleStripArray0")); + + if (indexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleStripArray1")); + } + + /** + * Creates the retained mode IndexedTriangleStripArrayRetained object that this + * IndexedTriangleStripArray object will point to. + */ + void createRetained() { + this.retained = new IndexedTriangleStripArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + IndexedTriangleStripArrayRetained rt = + (IndexedTriangleStripArrayRetained) retained; + int stripIndexCounts[] = new int[rt.getNumStrips()]; + rt.getStripIndexCounts(stripIndexCounts); + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + IndexedTriangleStripArray t = new IndexedTriangleStripArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + rt.getIndexCount(), + stripIndexCounts); + t.duplicateNodeComponent(this); + return t; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleStripArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleStripArrayRetained.java new file mode 100644 index 0000000..8558065 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedTriangleStripArrayRetained.java @@ -0,0 +1,534 @@ +/* + * $RCSfile: IndexedTriangleStripArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The IndexedTriangleStripArray object draws an array of vertices as a set of + * connected triangle strips. An array of per-strip vertex counts specifies + * where the separate strips appear in the vertex array. + * For every strip in the set, + * each vertex, beginning with the third vertex in the array, + * defines a triangle to be drawn using the current vertex and + * the two previous vertices. + */ + +class IndexedTriangleStripArrayRetained extends IndexedGeometryStripArrayRetained { + + IndexedTriangleStripArrayRetained(){ + geoType = GEO_TYPE_INDEXED_TRI_STRIP_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[3]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int i = 0; + int j, scount, count = 0; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + int[] vtxIndexArr = new int[3]; + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectRay(pnts, pickRay, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectSegment(pnts, pickSegment.start, + pickSegment.end, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingSphere(pnts, bsphere, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingPolytope(pnts, bpolytope, + sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < stripIndexCounts.length) { + for(int k=0; k<2; k++) { + vtxIndexArr[k] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[k]); + } + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + vtxIndexArr[2] = indexCoord[count]; + getVertexData(indexCoord[count++], pnts[2]); + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleStripArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + // intersect pnts[] with every triangle in this object + boolean intersect(Point3d[] pnts) { + int j, end; + Point3d[] points = new Point3d[3]; + double dist[] = new double[1]; + int i = 0, scount, count = 0; + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + getVertexData(indexCoord[count++], points[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], points[2]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2])) { + return true; + } + points[0].set(points[1]); + points[1].set(points[2]); + } + } + break; + case 4: // Quad + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + getVertexData(indexCoord[count++], points[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], points[2]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[2], pnts[3])) { + return true; + } + points[0].set(points[1]); + points[1].set(points[2]); + } + } + break; + case 2: // Line + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + getVertexData(indexCoord[count++], points[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], points[2]); + if (intersectSegment(points, pnts[0], pnts[1], + dist, null)) { + return true; + } + points[0].set(points[1]); + points[1].set(points[2]); + } + } + break; + case 1: // Point + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], points[0]); + getVertexData(indexCoord[count++], points[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], points[2]); + if (intersectTriPnt(points[0], points[1], points[2], + pnts[0])) { + return true; + } + points[0].set(points[1]); + points[1].set(points[2]); + } + } + break; + } + return false; + } + + boolean intersect(Transform3D thisToOtherVworld, GeometryRetained geom) { + int i = 0, j, scount, count = 0; + Point3d[] pnts = new Point3d[3]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + getVertexData(indexCoord[count++], pnts[1]); + thisToOtherVworld.transform(pnts[0]); + thisToOtherVworld.transform(pnts[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[2]); + thisToOtherVworld.transform(pnts[2]); + if (geom.intersect(pnts)) { + return true; + } + pnts[0].set(pnts[1]); + pnts[1].set(pnts[2]); + } + } + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + int i = 0; + int j, scount, count = 0; + Point3d[] pnts = new Point3d[3]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + getVertexData(indexCoord[count++], pnts[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingBox(pnts, box, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + pnts[1].set(pnts[2]); + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + getVertexData(indexCoord[count++], pnts[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingSphere(pnts, bsphere, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + pnts[1].set(pnts[2]); + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + + while (i < stripIndexCounts.length) { + getVertexData(indexCoord[count++], pnts[0]); + getVertexData(indexCoord[count++], pnts[1]); + scount = stripIndexCounts[i++]; + for (j=2; j < scount; j++) { + getVertexData(indexCoord[count++], pnts[2]); + if (intersectBoundingPolytope(pnts, bpolytope, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + pnts[1].set(pnts[2]); + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + return false; + } + + int getClassType() { + return TRIANGLE_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IndexedUnorderSet.java b/j3d-core/src/classes/share/javax/media/j3d/IndexedUnorderSet.java new file mode 100644 index 0000000..e3a45c0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IndexedUnorderSet.java @@ -0,0 +1,617 @@ +/* + * $RCSfile: IndexedUnorderSet.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A strongly type indexed unorder set. + * All operations remove(IndexedObject, ListType), add(IndexedObject, ListType), + * contains(IndexedObject, ListType) etc. take O(1) time. + * The class is designed to optimize speed. So many reductance + * procedures call and range check as found in ArrayList are + * removed. + * + *

+ * Use the following code to iterate through an array. + * + *

+ *  IndexedUnorderSet  IUset =
+ *      new IndexedUnorderSet(YourClass.class, listType);
+ *  // add element here
+ *
+ *  YourClass[] arr = (YourClass []) IUset.toArray();
+ *  int size = IUset.arraySize();
+ *  for (int i=0; i < size; i++) {
+ *      YourClass obj = arr[i];
+ *      ....
+ *  }
+ * 
+ * + *

+ * Note: + *

    + * 1) The array return is a copied of internal array.
    + * 2) Don't use arr.length , use IUset.arraySize();
    + * 3) IndexedObject contains an array of listIndex, the number of + * array elements depends on the number of different types of + * IndexedUnorderSet that use it.
    + * 4) No need to do casting for individual element as in ArrayList.
    + * 5) IndexedUnorderSet is thread safe.
    + * 6) Object implement this interface MUST initialize the index to -1.
    + *
+ * + *

+ * Limitation: + *

    + * 1) Order of IndexedObject in list is not important
    + * 2) Can't modify the clone() copy.
    + * 3) IndexedObject can't be null
    + *
+ */ + +class IndexedUnorderSet implements Cloneable, java.io.Serializable { + + // XXXX: set to false when release + final static boolean debug = false; + + /** + * The array buffer into which the elements of the ArrayList are stored. + * The capacity of the ArrayList is the length of this array buffer. + * + * It is non-private to enable compiler do inlining for get(), + * set(), remove() when -O flag turn on. + */ + transient IndexedObject elementData[]; + + /** + * Clone copy of elementData return by toArray(true); + */ + transient Object cloneData[]; + // size of the above clone objec. + transient int cloneSize; + + transient boolean isDirty = true; + + /** + * Component Type of individual array element entry + */ + Class componentType; + + /** + * The size of the ArrayList (the number of elements it contains). + * + * We make it non-private to enable compiler do inlining for + * getSize() when -O flag turn on. + */ + int size; + + int listType; + + // Current VirtualUniverse using this structure + VirtualUniverse univ; + + /** + * Constructs an empty list with the specified initial capacity. + * and the class data Type + * + * @param initialCapacity the initial capacity of the list. + * @param componentType class type of element in the list. + */ + IndexedUnorderSet(int initialCapacity, Class componentType, + int listType, VirtualUniverse univ) { + this.componentType = componentType; + this.elementData = (IndexedObject[])java.lang.reflect.Array.newInstance( + componentType, initialCapacity); + this.listType = listType; + this.univ = univ; + } + + /** + * Constructs an empty list. + * @param componentType class type of element in the list. + */ + IndexedUnorderSet(Class componentType, int listType, + VirtualUniverse univ) { + this(10, componentType, listType, univ); + } + + + /** + * Constructs an empty list with the specified initial capacity. + * + * @param initialCapacity the initial capacity of the list. + */ + IndexedUnorderSet(int initialCapacity, int listType, + VirtualUniverse univ) { + this(initialCapacity, IndexedObject.class, listType, univ); + } + + /** + * Constructs an empty list. + * @param listType default to Object. + */ + IndexedUnorderSet(int listType, VirtualUniverse univ) { + this(10, IndexedObject.class, listType, univ); + } + + /** + * Initialize all indexes to -1 + */ + final static void init(IndexedObject obj, int len) { + obj.listIdx = new int[3][]; + + obj.listIdx[0] = new int[len]; + obj.listIdx[1] = new int[len]; + obj.listIdx[2] = new int[1]; + + for (int i=0; i < len; i++) { + obj.listIdx[0][i] = -1; + obj.listIdx[1][i] = -1; + } + + // Just want to set both RenderMolecule idx + // and BehaviorRetained idx to 0 by default + // It is OK without the following lines + if (obj instanceof SceneGraphObjectRetained) { + // setlive() will change this back to 0 + obj.listIdx[2][0] = 1; + } else { + obj.listIdx[2][0] = 0; + } + } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list. + */ + final int size() { + return size; + } + + + /** + * Returns the size of entry use in toArray() number of elements + * in this list. + * + * @return the number of elements in this list. + */ + final int arraySize() { + return cloneSize; + } + + /** + * Tests if this list has no elements. + * + * @return true if this list has no elements; + * false otherwise. + */ + final boolean isEmpty() { + return size == 0; + } + + /** + * Returns true if this list contains the specified element. + * + * @param o element whose presence in this List is to be tested. + */ + synchronized final boolean contains(IndexedObject o) { + return (o.listIdx[o.getIdxUsed(univ)][listType] >= 0); + } + + + /** + * Searches for the last occurence of the given argument, testing + * for equality using the equals method. + * + * @param o an object. + * @return the index of the first occurrence of the argument in this + * list; returns -1 if the object is not found. + * @see Object#equals(Object) + */ + synchronized final int indexOf(IndexedObject o) { + return o.listIdx[o.getIdxUsed(univ)][listType]; + } + + /** + * Returns a shallow copy of this ArrayList instance. (The + * elements themselves are not copied.) + * + * @return a clone of this ArrayList instance. + */ + synchronized protected final Object clone() { + try { + IndexedUnorderSet v = (IndexedUnorderSet)super.clone(); + v.elementData = (IndexedObject[])java.lang.reflect.Array.newInstance( + componentType, size); + System.arraycopy(elementData, 0, v.elementData, 0, size); + isDirty = true; // can't use the old cloneData reference + return v; + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + + + /** + * Returns an array containing all of the elements in this list. + * The size of the array may longer than the actual size. Use + * arraySize() to retrieve the size. + * The array return is a copied of internal array. if copy + * is true. + * + * @return an array containing all of the elements in this list + */ + synchronized final Object[] toArray(boolean copy) { + if (copy) { + if (isDirty) { + if ((cloneData == null) || cloneData.length < size) { + cloneData = (Object[])java.lang.reflect.Array.newInstance( + componentType, size); + } + System.arraycopy(elementData, 0, cloneData, 0, size); + cloneSize = size; + isDirty = false; + } + return cloneData; + } else { + cloneSize = size; + return elementData; + } + + } + + /** + * Returns an array containing all of the elements in this list. + * The size of the array may longer than the actual size. Use + * arraySize() to retrieve the size. + * The array return is a copied of internal array. So another + * thread can continue add/delete the current list. However, + * it should be noticed that two call to toArray() may return + * the same copy. + * + * @return an array containing all of the elements in this list + */ + synchronized final Object[] toArray() { + return toArray(true); + } + + + /** + * Returns an array containing elements starting from startElement + * all of the elements in this list. A new array of exact size + * is always allocated. + * + * @param startElement starting element to copy + * + * @return an array containing elements starting from + * startElement, null if element not found. + * + */ + synchronized final Object[] toArray(IndexedObject startElement) { + int idx = indexOf(startElement); + if (idx < 0) { + return (Object[])java.lang.reflect.Array.newInstance(componentType, 0); + } + + int s = size - idx; + Object data[] = (Object[])java.lang.reflect.Array.newInstance(componentType, s); + System.arraycopy(elementData, idx, data, 0, s); + return data; + } + + /** + * Trims the capacity of this ArrayList instance to be the + * list's current size. An application can use this operation to minimize + * the storage of an ArrayList instance. + */ + synchronized final void trimToSize() { + if (elementData.length > size) { + Object oldData[] = elementData; + elementData = (IndexedObject[])java.lang.reflect.Array.newInstance( + componentType, + size); + System.arraycopy(oldData, 0, elementData, 0, size); + } + } + + + // Positional Access Operations + + /** + * Returns the element at the specified position in this list. + * + * @param index index of element to return. + * @return the element at the specified position in this list. + * @throws IndexOutOfBoundsException if index is out of range (index + * < 0 || index >= size()). + */ + synchronized final Object get(int index) { + return elementData[index]; + } + + /** + * Replaces the element at the specified position in this list with + * the specified element. + * + * @param index index of element to replace. + * @param o element to be stored at the specified position. + * @return the element previously at the specified position. + * @throws IndexOutOfBoundsException if index out of range + * (index < 0 || index >= size()). + */ + synchronized final void set(int index, IndexedObject o) { + IndexedObject oldElm = elementData[index]; + if (oldElm != null) { + oldElm.listIdx[oldElm.getIdxUsed(univ)][listType] = -1; + } + elementData[index] = o; + + int univIdx = o.getIdxUsed(univ); + + if (debug) { + if (o.listIdx[univIdx][listType] != -1) { + System.err.println("Illegal use of UnorderIndexedList idx in set " + + o.listIdx[univIdx][listType]); + Thread.dumpStack(); + } + } + + o.listIdx[univIdx][listType] = index; + isDirty = true; + } + + /** + * Appends the specified element to the end of this list. + * It is the user responsible to ensure that the element add is of + * the same type as array componentType. + * + * @param o element to be appended to this list. + */ + synchronized final void add(IndexedObject o) { + + if (elementData.length == size) { + IndexedObject oldData[] = elementData; + elementData = (IndexedObject[])java.lang.reflect.Array.newInstance( + componentType, + (size << 1)); + System.arraycopy(oldData, 0, elementData, 0, size); + + } + + int univIdx = o.getIdxUsed(univ); + + if (debug) { + int idx = o.listIdx[univIdx][listType]; + if (idx >= 0) { + if (elementData[idx] != o) { + System.err.println("Illegal use of UnorderIndexedList idx in add " + idx); + Thread.dumpStack(); + } + } + } + + int idx = size++; + elementData[idx] = o; + o.listIdx[univIdx][listType] = idx; + isDirty = true; + } + + + /** + * Removes the element at the specified position in this list. + * Replace the removed element by the last one. + * + * @param index the index of the element to removed. + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index >= size()). + */ + synchronized final void remove(int index) { + IndexedObject elm = elementData[index]; + + int univIdx = elm.getIdxUsed(univ); + + if (debug) { + if (elm.listIdx[univIdx][listType] != index) { + System.err.println("Inconsistent idx in remove, expect " + index + " actual " + elm.listIdx[univIdx][listType]); + Thread.dumpStack(); + } + } + + elm.listIdx[univIdx][listType] = -1; + size--; + if (index != size) { + elm = elementData[size]; + elm.listIdx[univIdx][listType] = index; + elementData[index] = elm; + } + elementData[size] = null; + isDirty = true; + /* + if ((cloneData != null) && (index < cloneData.length)) { + cloneData[index] = null; // for gc + } + */ + } + + + /** + * Removes the element at the last position in this list. + * @return The element remove + * @throws IndexOutOfBoundsException if array is empty + */ + synchronized final Object removeLastElement() { + IndexedObject elm = elementData[--size]; + elementData[size] = null; + elm.listIdx[elm.getIdxUsed(univ)][listType] = -1; + isDirty = true; + /* + if ((cloneData != null) && (size < cloneData.length)) { + cloneData[size] = null; // for gc + } + */ + return elm; + } + + + /** + * Removes the specified element in this list. + * Replace the removed element by the last one. + * + * @param o the element to removed. + * @return true if object remove + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index >= size()). + */ + synchronized final boolean remove(IndexedObject o) { + int univIdx = o.getIdxUsed(univ); + int idx = o.listIdx[univIdx][listType]; + + if (idx >= 0) { + if (debug) { + if (o != elementData[idx]) { + System.err.println(this + " Illegal use of UnorderIndexedList in remove expect " + o + " actual " + elementData[idx] + " idx = " + idx); + Thread.dumpStack(); + } + } + // Object in the container + size--; + if (idx != size) { + IndexedObject elm = elementData[size]; + elementData[idx] = elm; + elm.listIdx[elm.getIdxUsed(univ)][listType] = idx; + } + elementData[size] = null; + o.listIdx[univIdx][listType] = -1; + isDirty = true; + return true; + } + return false; + } + + + /** + * Removes all of the elements from this list. The list will + * be empty after this call returns. + */ + synchronized final void clear() { + IndexedObject o; + for (int i = size-1; i >= 0; i--) { + o = elementData[i]; + o.listIdx[o.getIdxUsed(univ)][listType] = -1; + elementData[i] = null; // Let gc do its work + } + size = 0; + isDirty = true; + } + + synchronized final void clearMirror() { + + if (cloneData != null) { + for (int i = cloneData.length-1; i >= 0; i--) { + // don't set index to -1 since the original + // copy is using this. + cloneData[i] = null; // Let gc do its work + } + } + cloneSize = 0; + isDirty = true; + } + + final Class getComponentType() { + return componentType; + } + + /* + synchronized public String toString() { + StringBuffer sb = new StringBuffer("Size = " + size + "\n["); + int len = size-1; + Object obj; + + for (int i=0; i < size; i++) { + obj = elementData[i]; + if (obj != null) { + sb.append(elementData[i].toString()); + } else { + sb.append("NULL"); + } + if (i != len) { + sb.append(", "); + } + } + sb.append("]\n"); + return sb.toString(); + } + */ + + + /** + * Save the state of the ArrayList instance to a stream (that + * is, serialize it). + * + * @serialData The length of the array backing the ArrayList + * instance is emitted (int), followed by all of its elements + * (each an Object) in the proper order. + */ + private synchronized void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException{ + // Write out element count, and any hidden stuff + s.defaultWriteObject(); + + // Write out array length + s.writeInt(elementData.length); + + // Write out all elements in the proper order. + for (int i=0; iArrayList instance from a stream (that is, + * deserialize it). + */ + private synchronized void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in array length and allocate array + int arrayLength = s.readInt(); + elementData = (IndexedObject[])java.lang.reflect.Array.newInstance( + componentType, arrayLength); + + // Read in all elements in the proper order. + for (int i=0; i + * NOTE: this method should not be called after the input + * device has been added to a PhysicalEnvironment. The + * processingMode must remain constant while a device is attached + * to a PhysicalEnvironment. + * + * @param mode One of BLOCKING, NON_BLOCKING, or DEMAND_DRIVEN + */ + public abstract void setProcessingMode(int mode); + + + /** + * This method gets the number of sensors associated with the device. + * @return the device's sensor count. + */ + public int getSensorCount(); + + /** + * Gets the specified Sensor associated with the device. Each InputDevice + * implementation is responsible for creating and managing its own set of + * sensors. The sensor indices begin at zero and end at number of + * sensors minus one. Each sensor should have had + * Sensor.setDevice(InputDevice) set properly before addInputDevice + * is called. + * @param sensorIndex the sensor to retrieve + * @return Returns the specified sensor. + */ + public Sensor getSensor(int sensorIndex); + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/InputDeviceBlockingThread.java b/j3d-core/src/classes/share/javax/media/j3d/InputDeviceBlockingThread.java new file mode 100644 index 0000000..ad866b8 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/InputDeviceBlockingThread.java @@ -0,0 +1,124 @@ +/* + * $RCSfile: InputDeviceBlockingThread.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class InputDeviceBlockingThread extends Thread { + + // action flag for runMonitor + private static final int WAIT = 0; + private static final int NOTIFY = 1; + private static final int STOP = 2; + + // blocking device that this thread manages + private InputDevice device; + private volatile boolean running = true; + private volatile boolean stop = false; + private boolean waiting = false; + private boolean ready = false; + private static int numInstances = 0; + private int instanceNum = -1; + + InputDeviceBlockingThread(ThreadGroup threadGroup, InputDevice device) { + super(threadGroup, ""); + setName("J3D-InputDeviceBlockingThread-" + getInstanceNum()); + this.device = device; + } + + private synchronized int newInstanceNum() { + return (++numInstances); + } + + private int getInstanceNum() { + if (instanceNum == -1) + instanceNum = newInstanceNum(); + return instanceNum; + } + + + public void run() { + // Since this thread is blocking, this thread should not be + // taking an inordinate amount of CPU time. Note that the + // yield() call should not be necessary (and may be ineffective), + // but we can't call MasterControl.threadYield() because it will + // sleep for at least a millisecond. + while (running) { + while (!stop) { + device.pollAndProcessInput(); + Thread.yield(); + } + runMonitor(WAIT); + } + } + + void sleep() { + stop = true; + } + + void restart() { + stop = false; + runMonitor(NOTIFY); + } + + void finish() { + stop = true; + runMonitor(STOP); + } + + synchronized void runMonitor(int action) { + + switch (action) { + case WAIT: + // Issue 279 - loop until ready + while (running && !ready) { + waiting = true; + try { + wait(); + } catch (InterruptedException e) {} + waiting = false; + } + ready = false; + break; + case NOTIFY: + ready = true; + if (waiting) { + notify(); + } + break; + case STOP: + running = false; + if (waiting) { + notify(); + } + break; + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/InputDeviceScheduler.java b/j3d-core/src/classes/share/javax/media/j3d/InputDeviceScheduler.java new file mode 100644 index 0000000..ae9c4ab --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/InputDeviceScheduler.java @@ -0,0 +1,223 @@ +/* + * $RCSfile: InputDeviceScheduler.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * This thread manages all input device scheduling. It monitors and caches + * all device additions and removals. It spawns new threads for blocking + * devices, manages all non-blocking drivers itself, and tags the sensors + * of demand_driven devices. This implementation assume that + * processMode of InputDevice will not change after addInputDevice(). + * + */ + +class InputDeviceScheduler extends J3dThread { + + // list of devices that have been added with the phys env interface + ArrayList nonBlockingDevices = new ArrayList(1); + + // This condition holds blockingDevices.size() == threads.size() + ArrayList blockingDevices = new ArrayList(1); + ArrayList threads = new ArrayList(1); + + // This is used by MasterControl to keep track activeViewRef + PhysicalEnvironment physicalEnv; + + // store all inputDevices + Vector devices = new Vector(1); + + J3dThreadData threadData = new J3dThreadData(); + boolean active = false; + + // The time to sleep before next processAndProcess() is invoked + // for non-blocking input device + static int samplingTime = 5; + + // Some variables used to name threads correctly + private static int numInstances = 0; + private int instanceNum = -1; + + private synchronized int newInstanceNum() { + return (++numInstances); + } + + int getInstanceNum() { + if (instanceNum == -1) + instanceNum = newInstanceNum(); + return instanceNum; + } + + InputDeviceScheduler(ThreadGroup threadGroup, + PhysicalEnvironment physicalEnv) { + super(threadGroup); + setName("J3D-InputDeviceScheduler-" + getInstanceNum()); + threadData.threadType = J3dThread.INPUT_DEVICE_SCHEDULER; + threadData.thread = this; + this.physicalEnv = physicalEnv; + + synchronized (physicalEnv.devices) { + Enumeration elm = physicalEnv.devices.elements(); + while (elm.hasMoreElements()) { + addInputDevice((InputDevice) elm.nextElement()); + } + physicalEnv.inputsched = this; + } + + } + + + void addInputDevice(InputDevice device) { + + switch(device.getProcessingMode()) { + case InputDevice.BLOCKING: + InputDeviceBlockingThread thread = + VirtualUniverse.mc.getInputDeviceBlockingThread(device); + thread.start(); + synchronized (blockingDevices) { + threads.add(thread); + blockingDevices.add(device); + } + break; + case InputDevice.NON_BLOCKING: + synchronized (nonBlockingDevices) { + nonBlockingDevices.add(device); + if (active && (nonBlockingDevices.size() == 1)) { + VirtualUniverse.mc.addInputDeviceScheduler(this); + } + } + break; + default: // InputDevice.DEMAND_DRIVEN: + // tag the sensors + for (int i=device.getSensorCount()-1; i>=0; i--) { + device.getSensor(i).demand_driven = true; + } + break; + } + + } + + + void removeInputDevice(InputDevice device) { + + switch(device.getProcessingMode()) { + case InputDevice.BLOCKING: + // tell the thread to clean up and permanently block + synchronized (blockingDevices) { + int idx = blockingDevices.indexOf(device); + InputDeviceBlockingThread thread = + (InputDeviceBlockingThread) threads.remove(idx); + thread.finish(); + blockingDevices.remove(idx); + } + break; + case InputDevice.NON_BLOCKING: + // remove references that are in this thread + synchronized (nonBlockingDevices) { + nonBlockingDevices.remove(nonBlockingDevices.indexOf(device)); + if (active && (nonBlockingDevices.size() == 0)) { + VirtualUniverse.mc.removeInputDeviceScheduler(this); + } + } + break; + default: // InputDevice.DEMAND_DRIVEN: + // untag the sensors + for (int i=device.getSensorCount()-1; i>=0; i--) { + device.getSensor(i).demand_driven = false; + } + } + } + + // Add this thread to MC (Callback from MC thread) + void activate() { + if (!active) { + active = true; + + synchronized (nonBlockingDevices) { + if (nonBlockingDevices.size() > 0) { + VirtualUniverse.mc.addInputDeviceScheduler(this); + } + } + // run all spawn threads + synchronized (blockingDevices) { + for (int i=threads.size()-1; i >=0; i--) { + ((InputDeviceBlockingThread)threads.get(i)).restart(); + } + } + } + } + + // Remove this thread from MC (Callback from MC thread) + void deactivate() { + if (active) { + synchronized (nonBlockingDevices) { + if (nonBlockingDevices.size() > 0) { + VirtualUniverse.mc.removeInputDeviceScheduler(this); + } + } + + // stop all spawn threads + synchronized (blockingDevices) { + for (int i=threads.size()-1; i >=0; i--) { + ((InputDeviceBlockingThread)threads.get(i)).sleep(); + } + } + active = false; + } + } + + J3dThreadData getThreadData() { + return threadData; + } + + void doWork(long referenceTime) { + synchronized (nonBlockingDevices) { + for (int i = nonBlockingDevices.size()-1; i >=0; i--) { + ((InputDevice)nonBlockingDevices.get(i)).pollAndProcessInput(); + } + } + } + + void shutdown() { + // stop all spawn threads + for (int i=threads.size()-1; i >=0; i--) { + ((InputDeviceBlockingThread)threads.get(i)).finish(); + } + // for gc + threads.clear(); + blockingDevices.clear(); + nonBlockingDevices.clear(); + devices.clear(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/IntegerFreeList.java b/j3d-core/src/classes/share/javax/media/j3d/IntegerFreeList.java new file mode 100644 index 0000000..1cbd67d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/IntegerFreeList.java @@ -0,0 +1,59 @@ +/* + * $RCSfile: IntegerFreeList.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class IntegerFreeList extends MemoryFreeList { + + int count = 0; + + // default the initial count to 1 + IntegerFreeList() { + super("java.lang.Integer"); + } + + // sets up an initial count and an initial capacity for the freelist + IntegerFreeList(int initialCount, int initCapacity) { + super("java.lang.Integer", initCapacity); + count = initialCount; + } + + synchronized Object getObject() { + if (size > 0) return super.removeLastElement(); + else return new Integer(++count); + } + + public synchronized void clear() { + super.clear(); + count = 0; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Interpolator.java b/j3d-core/src/classes/share/javax/media/j3d/Interpolator.java new file mode 100644 index 0000000..07e7d52 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Interpolator.java @@ -0,0 +1,145 @@ +/* + * $RCSfile: Interpolator.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +import java.util.Vector; + +/** + * Interpolator is an abstract class that extends Behavior to provide + * common methods used by various interpolation subclasses. These + * include methods to convert a time value into an alpha value (A + * value in the range 0 to 1) and a method to initialize the behavior. + * Subclasses provide the methods that convert alpha values into + * values within that subclass' output range. + */ + +public abstract class Interpolator extends Behavior { + + // This interpolator's alpha generator + Alpha alpha; + + + /** + * Default WakeupCondition for all interpolators. The + * wakeupOn method of Behavior, which takes a WakeupCondition as + * the method parameter, will need to be called at the end + * of the processStimulus method of any class that subclasses + * Interpolator; this can be done with the following method call: + * wakeupOn(defaultWakeupCriterion). + */ + protected WakeupCriterion defaultWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0); + + + /** + * Constructs an Interpolator node with a null alpha value. + */ + public Interpolator() { + } + + + /** + * Constructs an Interpolator node with the specified alpha value. + * @param alpha the alpha object used by this interpolator. + * If it is null, then this interpolator will not run. + */ + public Interpolator(Alpha alpha){ + this.alpha = alpha; + } + + + /** + * Retrieves this interpolator's alpha object. + * @return this interpolator's alpha object + */ + public Alpha getAlpha() { + return this.alpha; + } + + + /** + * Set this interpolator's alpha to the specified alpha object. + * @param alpha the new alpha object. If set to null, + * then this interpolator will stop running. + */ + public void setAlpha(Alpha alpha) { + this.alpha = alpha; + VirtualUniverse.mc.sendRunMessage(J3dThread.RENDER_THREAD); + } + + + /** + * This is the default Interpolator behavior initialization routine. + * It schedules the behavior to awaken at the next frame. + */ + public void initialize() { + // Reset alpha + //alpha.setStartTime(J3dClock.currentTimeMillis()); + + // Insert wakeup condition into queue + wakeupOn(defaultWakeupCriterion); + } + + + /** + * Copies all Interpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + Interpolator it = (Interpolator) originalNode; + + Alpha a = it.getAlpha(); + if (a != null) { + setAlpha(a.cloneAlpha()); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3DBuffer.java b/j3d-core/src/classes/share/javax/media/j3d/J3DBuffer.java new file mode 100644 index 0000000..0169ae3 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3DBuffer.java @@ -0,0 +1,247 @@ +/* + * $RCSfile: J3DBuffer.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import com.sun.j3d.internal.ByteBufferWrapper; +import com.sun.j3d.internal.BufferWrapper; +import com.sun.j3d.internal.FloatBufferWrapper; +import com.sun.j3d.internal.DoubleBufferWrapper; +import com.sun.j3d.internal.ByteOrderWrapper; + +/** + * Java 3D wrapper class for java.nio.Buffer objects. + * When used to wrap a non-null NIO buffer object, this class will + * create a read-only view of the wrapped NIO buffer, and will call + * rewind on the read-only view, so that elements 0 + * through buffer.limit()-1 will be available internally. + * + * @see GeometryArray#setCoordRefBuffer(J3DBuffer) + * @see GeometryArray#setColorRefBuffer(J3DBuffer) + * @see GeometryArray#setNormalRefBuffer(J3DBuffer) + * @see GeometryArray#setTexCoordRefBuffer(int,J3DBuffer) + * @see GeometryArray#setVertexAttrRefBuffer(int,J3DBuffer) + * @see GeometryArray#setInterleavedVertexBuffer(J3DBuffer) + * @see CompressedGeometry#CompressedGeometry(CompressedGeometryHeader,J3DBuffer) + * + * @since Java 3D 1.3 + */ + +public class J3DBuffer { + static final int TYPE_NULL = 0; + static final int TYPE_UNKNOWN = 1; + static final int TYPE_BYTE = 2; + static final int TYPE_CHAR = 3; + static final int TYPE_SHORT = 4; + static final int TYPE_INT = 5; + static final int TYPE_LONG = 6; + static final int TYPE_FLOAT = 7; + static final int TYPE_DOUBLE = 8; + + static boolean unsupportedOperation = false; + + private java.nio.Buffer originalBuffer = null; + private BufferWrapper bufferImpl = null; + private int bufferType = TYPE_NULL; + + /** + * Constructs a J3DBuffer object and initializes it with + * a null NIO buffer object. The NIO buffer object + * must be set to a non-null value before using this J3DBuffer + * object in a Java 3D node component. + * + * @exception UnsupportedOperationException if the JVM does not + * support native access to direct NIO buffers + */ + public J3DBuffer() { + this(null); + } + + + /** + * Constructs a J3DBuffer object and initializes it with + * the specified NIO buffer object. + * + * @param buffer the NIO buffer wrapped by this J3DBuffer + * + * @exception UnsupportedOperationException if the JVM does not + * support native access to direct NIO buffers + * + * @exception IllegalArgumentException if the specified buffer is + * not a direct buffer, or if the byte order of the specified + * buffer does not match the native byte order of the underlying + * platform. + */ + public J3DBuffer(java.nio.Buffer buffer) { + if (unsupportedOperation) + throw new UnsupportedOperationException(J3dI18N.getString("J3DBuffer0")); + + setBuffer(buffer); + } + + + /** + * Sets the NIO buffer object in this J3DBuffer to + * the specified object. + * + * @param buffer the NIO buffer wrapped by this J3DBuffer + * + * @exception IllegalArgumentException if the specified buffer is + * not a direct buffer, or if the byte order of the specified + * buffer does not match the native byte order of the underlying + * platform. + */ + public void setBuffer(java.nio.Buffer buffer) { + int bType = TYPE_NULL; + boolean direct = false; + java.nio.ByteOrder order = java.nio.ByteOrder.BIG_ENDIAN; + + if (buffer == null) { + bType = TYPE_NULL; + } + else if (buffer instanceof java.nio.ByteBuffer) { + bType = TYPE_BYTE; + direct = ((java.nio.ByteBuffer)buffer).isDirect(); + order = ((java.nio.ByteBuffer)buffer).order(); + } + else if (buffer instanceof java.nio.CharBuffer) { + bType = TYPE_CHAR; + direct = ((java.nio.CharBuffer)buffer).isDirect(); + order = ((java.nio.CharBuffer)buffer).order(); + } + else if (buffer instanceof java.nio.ShortBuffer) { + bType = TYPE_SHORT; + direct = ((java.nio.ShortBuffer)buffer).isDirect(); + order = ((java.nio.ShortBuffer)buffer).order(); + } + else if (buffer instanceof java.nio.IntBuffer) { + bType = TYPE_INT; + direct = ((java.nio.IntBuffer)buffer).isDirect(); + order = ((java.nio.IntBuffer)buffer).order(); + } + else if (buffer instanceof java.nio.LongBuffer) { + bType = TYPE_LONG; + direct = ((java.nio.LongBuffer)buffer).isDirect(); + order = ((java.nio.LongBuffer)buffer).order(); + } + else if (buffer instanceof java.nio.FloatBuffer) { + bType = TYPE_FLOAT; + direct = ((java.nio.FloatBuffer)buffer).isDirect(); + order = ((java.nio.FloatBuffer)buffer).order(); + } + else if (buffer instanceof java.nio.DoubleBuffer) { + bType = TYPE_DOUBLE; + direct = ((java.nio.DoubleBuffer)buffer).isDirect(); + order = ((java.nio.DoubleBuffer)buffer).order(); + } + else { + bType = TYPE_UNKNOWN; + } + + // Verify that the buffer is direct and has the correct byte order + if (buffer != null) { + if (!direct) { + throw new IllegalArgumentException(J3dI18N.getString("J3DBuffer1")); + } + + if (order != java.nio.ByteOrder.nativeOrder()) { + throw new IllegalArgumentException(J3dI18N.getString("J3DBuffer2")); + } + } + + bufferType = bType; + originalBuffer = buffer; + + // Make a read-only view of the buffer if the type is one + // of the internally supported types: byte, float, or double + switch (bufferType) { + case TYPE_BYTE: + java.nio.ByteBuffer byteBuffer = + ((java.nio.ByteBuffer)buffer).asReadOnlyBuffer(); + byteBuffer.rewind(); + bufferImpl = new ByteBufferWrapper(byteBuffer); + break; + case TYPE_FLOAT: + java.nio.FloatBuffer floatBuffer = + ((java.nio.FloatBuffer)buffer).asReadOnlyBuffer(); + floatBuffer.rewind(); + bufferImpl = new FloatBufferWrapper(floatBuffer); + break; + case TYPE_DOUBLE: + java.nio.DoubleBuffer doubleBuffer = + ((java.nio.DoubleBuffer)buffer).asReadOnlyBuffer(); + doubleBuffer.rewind(); + bufferImpl = new DoubleBufferWrapper(doubleBuffer); + break; + default: + bufferImpl = null; + } + } + + + /** + * Retrieves the NIO buffer object from this J3DBuffer. + * + * @return the current NIO buffer wrapped by this J3DBuffer + */ + public java.nio.Buffer getBuffer() { + return originalBuffer; + } + + + int getBufferType() { + return bufferType; + } + + + BufferWrapper getBufferImpl() { + return bufferImpl; + } + + private static boolean checkNativeBufferAccess(java.nio.Buffer buffer) { + if (buffer == null /*|| !Pipeline.getPipeline().checkNativeBufferAccess(buffer)*/) { + return false; + } + else { + return true; + } + } + + static { + // Allocate a direct byte buffer and verify that we can + // access the data pointer from native code + java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocateDirect(8); + + if (!checkNativeBufferAccess(buffer)) { + unsupportedOperation = true; + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3DGraphics2D.java b/j3d-core/src/classes/share/javax/media/j3d/J3DGraphics2D.java new file mode 100644 index 0000000..c42e696 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3DGraphics2D.java @@ -0,0 +1,190 @@ +/* + * $RCSfile: J3DGraphics2D.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; + + +/** + * The J3DGraphics2D class extends Graphics2D to provide 2D rendering + * into a Canvas3D. It is an abstract base class that is further + * extended by a non-public Java 3D implementation class. This class + * allows Java 2D rendering to be mixed with Java 3D rendering in the + * same Canvas3D, subject to the same restrictions as imposed for 3D + * immediate-mode rendering: In mixed-mode rendering, all Java 2D + * requests must be done from one of the Canvas3D callback methods; in + * pure-immediate mode, the Java 3D renderer must be stopped for the + * Canvas3D being rendered into. + * + *

+ * An application obtains a J3D 2D graphics context object from the + * Canvas3D object that the application wishes to render into by using + * the getGraphics2D method. A new J3DGraphics2D object is created if + * one does not already exist. + * + *

+ * Note that the drawing methods in this class, including those + * inherited from Graphics2D, are not necessarily executed + * immediately. They may be buffered up for future execution. + * Applications must call the flush(boolean) method to ensure + * that the rendering actually happens. The flush method is implicitly + * called in the following cases: + * + *

    + *
  • The Canvas3D.swap method calls + * flush(true)
  • + *
  • The Java 3D renderer calls flush(true) prior to + * swapping the buffer for a double buffered on-screen Canvas3D
  • + *
  • The Java 3D renderer calls flush(true) prior to + * copying into the off-screen buffer of an off-screen Canvas3D
  • + *
  • The Java 3D renderer calls flush(false) after + * calling the preRender, renderField, postRender, and postSwap + * Canvas3D callback methods.
  • + *
+ * + *

+ * A single-buffered, pure-immediate mode application must explicitly + * call flush to ensure that the graphics will be rendered to the + * Canvas3D. + * + * @see Canvas3D#getGraphics2D + * + * @since Java 3D 1.2 + */ + +public abstract class J3DGraphics2D extends Graphics2D { + + // Package scope contructor + J3DGraphics2D() { + } + + /** + * This method is not supported. The only way to obtain a + * J3DGraphics2D is from the associated Canvas3D. + * + * @exception UnsupportedOperationException this method is not supported + * + * @see Canvas3D#getGraphics2D + */ + public final Graphics create() { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported. The only way to obtain a + * J3DGraphics2D is from the associated Canvas3D. + * + * @exception UnsupportedOperationException this method is not supported + * + * @see Canvas3D#getGraphics2D + */ + public final Graphics create(int x, int y, int width, int height) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported. Clearing a Canvas3D is done implicitly + * via a Background node in the scene graph or explicitly via the clear + * method in a 3D graphics context. + * + * @exception UnsupportedOperationException this method is not supported + * + * @see Background + * @see GraphicsContext3D#setBackground + * @see GraphicsContext3D#clear + */ + public final void setBackground(Color color) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported. Clearing a Canvas3D is done implicitly + * via a Background node in the scene graph or explicitly via the clear + * method in a 3D graphics context. + * + * @exception UnsupportedOperationException this method is not supported + * + * @see Background + * @see GraphicsContext3D#getBackground + * @see GraphicsContext3D#clear + */ + public final Color getBackground() { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported. Clearing a Canvas3D is done implicitly + * via a Background node in the scene graph or explicitly via the clear + * method in a 3D graphics context. + * + * @exception UnsupportedOperationException this method is not supported + * + * @see Background + * @see GraphicsContext3D#setBackground + * @see GraphicsContext3D#clear + */ + public final void clearRect(int x, int y, int width, int height) { + throw new UnsupportedOperationException(); + } + + + /** + * Flushes all previously executed rendering operations to the + * drawing buffer for this 2D graphics object. + * + * @param wait flag indicating whether or not to wait for the + * rendering to be complete before returning from this call. + */ + public abstract void flush(boolean wait); + + /** + * Draws the specified image and flushes the buffer. This is + * functionally equivalent to calling drawImage(...) + * followed by flush(false), but can avoid the cost + * of making an extra copy of the image in some cases. Anything + * previously drawn to this J3DGraphics2D will be flushed before + * the image is drawn. + * + * @param img The image to draw + * @param x The x location to draw at + * @param y The y location to draw at + * @param observer The ImageObserver + * + * @since Java 3D 1.3 + */ + public abstract void drawAndFlushImage(BufferedImage img, int x, int y, + ImageObserver observer); + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3DGraphics2DImpl.java b/j3d-core/src/classes/share/javax/media/j3d/J3DGraphics2DImpl.java new file mode 100644 index 0000000..4ad2605 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3DGraphics2DImpl.java @@ -0,0 +1,1117 @@ +/* + * $RCSfile: J3DGraphics2DImpl.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/05/15 19:11:56 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.io.*; +import java.util.*; +import java.awt.*; +import java.awt.event.*; +import java.text.AttributedCharacterIterator; +import java.awt.RenderingHints.Key; +import java.awt.geom.*; +import java.awt.image.*; +import java.awt.image.renderable.RenderableImage; +import java.awt.font.*; + +/** + * Implementation class for J3DGraphics2D + */ + +final class J3DGraphics2DImpl extends J3DGraphics2D { + private boolean hasBeenDisposed = false; + private Graphics2D offScreenGraphics2D; + private BufferedImage g3dImage = null; + private byte[] data = null; + private boolean isFlushed = true; + private Canvas3D canvas3d; + private int width, height; + private int texWidth, texHeight; + private int xmin, ymin, xmax, ymax; + private Object extentLock = new Object(); + private boolean abgr; + private boolean initTexMap = false; + private boolean strokeSet=false; + private Point2D.Float ptSrc = new Point2D.Float(); + private Point2D.Float ptDst1 = new Point2D.Float(); + private Point2D.Float ptDst2 = new Point2D.Float(); + private Color xOrModeColor = null; + private volatile boolean initCtx = false; + private volatile boolean threadWaiting = false; + static final Color blackTransparent = new Color(0,0,0,0); + int objectId = -1; + + // Package scope contructor + J3DGraphics2DImpl(Canvas3D c) { + canvas3d = c; + + synchronized (VirtualUniverse.mc.contextCreationLock) { + if (c.ctx == null) { + // create a dummy bufferImage + width = 1; + height = 1; + g3dImage = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + offScreenGraphics2D = g3dImage.createGraphics(); + } else { + init(); + } + } + + } + + // This is invoke from Renderer callback when the first + // time createContext() finish which set + // canvas3d.extensionSupported correctly. + void init() { + // if ABGR extension is supported, we want to use + // TYPE_4BYTE_ABGR to make a fast copy + if (!initCtx) { + abgr = ((canvas3d.extensionsSupported & Canvas3D.EXT_ABGR) != 0); + + width = canvas3d.getWidth(); + height = canvas3d.getHeight(); + initTexMap = false; + + if (width <= 0) { + width = 1; + } + if (height <= 0) { + height = 1; + } + + synchronized (extentLock) { + xmax = width; + ymax = height; + xmin = 0; + ymin = 0; + } + g3dImage = new BufferedImage(width, height, + (abgr ? BufferedImage.TYPE_4BYTE_ABGR: + BufferedImage.TYPE_INT_ARGB)); + offScreenGraphics2D = g3dImage.createGraphics(); + clearOffScreen(); + if (!abgr) { + data = new byte[width*height*4]; + } + + // should be the last flag to set + initCtx = true; + } + } + + /** + * Flushes all previously executed rendering operations to the + * drawing buffer for this 2D graphics object. + * + * @param wait flag indicating whether or not to wait for the + * rendering to be complete before returning from this call. + */ + public void flush(boolean waiting) { + + if (hasBeenDisposed) { + throw new IllegalStateException(J3dI18N.getString("J3DGraphics2D0")); + } + + if (!isFlushed) { + // Composite g3dImage into Canvas3D + if (Thread.currentThread() == canvas3d.screen.renderer) { + if (!initCtx) { + return; + } + doFlush(); + } else { + if (!initCtx) { + if (waiting && + (canvas3d.pendingView != null) && + canvas3d.pendingView.activeStatus) { + // wait until Renderer init() this context + + while (!initCtx) { + MasterControl.threadYield(); + } + } else { + return; + } + } + // Behavior Scheduler or other threads + // XXXX: may not be legal for behaviorScheduler + // May cause deadlock if it is in behaviorScheduler + // and we wait for Renderer to finish + boolean renderRun = (Thread.currentThread() != + canvas3d.view.universe.behaviorScheduler); + // This must put before sendRenderMessage() + threadWaiting = true; + sendRenderMessage(renderRun, GraphicsContext3D.FLUSH2D, null, + null, null); + if (waiting) { + // It is possible that thread got notify BEFORE + // the following runMonitor invoke. + runMonitor(J3dThread.WAIT); + } + } + isFlushed = true; + + } + } + + // copy the data into a byte buffer that will be passed to opengl + void doFlush() { + assert !hasBeenDisposed; + + // clip to offscreen buffer size + if (canvas3d.ctx == null) { + canvas3d.getGraphicsContext3D().doClear(); + } + + synchronized (extentLock) { + if (xmin < 0) { + xmin = 0; + } + if (xmax > width) { + xmax = width; + } + if (ymin < 0) { + ymin = 0; + } + if (ymax > height) { + ymax = height; + } + + if ((xmax - xmin > 0) && + (ymax - ymin > 0)) { + if (abgr) { + data = ((DataBufferByte)g3dImage.getRaster().getDataBuffer()).getData(); + } else { + copyImage(g3dImage, data, width, height, xmin, ymin, xmax, ymax); + } + copyDataToCanvas(0, 0, xmin, ymin, xmax, ymax, width, height); + } else { + + runMonitor(J3dThread.NOTIFY); + } + // this define an empty region + xmax = 0; + ymax = 0; + xmin = width; + ymin = height; + } + + } + + + // borrowed from ImageComponentRetained since ImageComponent2D + // seems to do stuff we don't need to + final void copyImage(BufferedImage bi, byte[] image, + int width, int height, + int x1, int y1, int x2, int y2) { + + assert !hasBeenDisposed; + + int biType = bi.getType(); + int w, h, i, j; + int row, rowBegin, rowInc, dstBegin; + + dstBegin = 0; + rowInc = 1; + rowBegin = 0; + + // convert format to RGBA for underlying OGL use + if ((biType == BufferedImage.TYPE_INT_ARGB) || + (biType == BufferedImage.TYPE_INT_RGB)) { + // optimized cases + rowBegin = y1; + + int colBegin = x1; + + int[] intData = + ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); + int rowOffset = rowInc * width; + int intPixel; + + rowBegin = rowBegin*width + colBegin; + dstBegin = rowBegin*4; + + if (biType == BufferedImage.TYPE_INT_ARGB) { + for (h = y1; h < y2; h++) { + i = rowBegin; + j = dstBegin; + for (w = x1; w < x2; w++, i++) { + intPixel = intData[i]; + image[j++] = (byte)((intPixel >> 16) & 0xff); + image[j++] = (byte)((intPixel >> 8) & 0xff); + image[j++] = (byte)(intPixel & 0xff); + image[j++] = (byte)((intPixel >> 24) & 0xff); + } + rowBegin += rowOffset; + dstBegin += (rowOffset*4); + } + } else { + for (h = y1; h < y2; h++) { + i = rowBegin; + j = dstBegin; + for (w = x1; w < x2; w++, i++) { + intPixel = intData[i]; + image[j++] = (byte)((intPixel >> 16) & 0xff); + image[j++] = (byte)((intPixel >> 8) & 0xff); + image[j++] = (byte)(intPixel & 0xff); + image[j++] = (byte)255; + } + rowBegin += rowOffset; + dstBegin += (rowOffset*4); + } + } + } else { + // non-optimized cases + WritableRaster ras = bi.getRaster(); + ColorModel cm = bi.getColorModel(); + Object pixel = ImageComponentRetained.getDataElementBuffer(ras); + + j = (y1*width + x1)*4; + for (h = y1; h < y2; h++) { + i = j; + for (w = x1; w < x2; w++) { + ras.getDataElements(w, h, pixel); + image[j++] = (byte)cm.getRed(pixel); + image[j++] = (byte)cm.getGreen(pixel); + image[j++] = (byte)cm.getBlue(pixel); + image[j++] = (byte)cm.getAlpha(pixel); + + } + j = i+ width*4; + } + } + } + + void sendRenderMessage(boolean renderRun, int command, + Object arg1, Object arg2, Object arg3) { + // send a message to the request renderer + J3dMessage renderMessage = new J3dMessage(); + renderMessage.threads = J3dThread.RENDER_THREAD; + renderMessage.type = J3dMessage.RENDER_IMMEDIATE; + renderMessage.universe = null; + renderMessage.view = null; + renderMessage.args[0] = canvas3d; + renderMessage.args[1] = new Integer(command); + renderMessage.args[2] = arg1; + renderMessage.args[3] = arg2; + renderMessage.args[4] = arg3; + + while (!canvas3d.view.inRenderThreadData) { + // wait until the renderer thread data in added in + // MC:RenderThreadData array ready to receive message + MasterControl.threadYield(); + } + + canvas3d.screen.renderer.rendererStructure.addMessage(renderMessage); + + if (renderRun) { + // notify mc that there is work to do + VirtualUniverse.mc.sendRunMessage(canvas3d.view, J3dThread.RENDER_THREAD); + } else { + // notify mc that there is work for the request renderer + VirtualUniverse.mc.setWorkForRequestRenderer(); + } + } + + final void validate() { + validate(0, 0, width, height); + } + + void validate(float x1, float y1, float x2, float y2, + AffineTransform xform) { + float t; + + if (xform == null) { + validate(x1, y1, x2, y2); + } else { + ptSrc.x = x1; + ptSrc.y = y1; + xform.transform(ptSrc, ptDst1); + ptSrc.x = x2; + ptSrc.y = y2; + xform.transform(ptSrc, ptDst2); + + if (ptDst1.x > ptDst2.x) { + t = ptDst1.x; + ptDst1.x = ptDst2.x; + ptDst2.x = t; + } + if (ptDst1.y > ptDst2.y) { + t = ptDst1.y; + ptDst1.y = ptDst2.y; + ptDst2.y = t; + } + // take care of numerical error by adding 1 + validate(ptDst1.x-1, ptDst1.y-1, ptDst2.x+1, ptDst2.y+1); + } + } + + void validate(float x1, float y1, float x2, float y2) { + boolean doResize = false; + isFlushed = false; + + synchronized(canvas3d) { + if (initCtx && canvas3d.resizeGraphics2D) { + doResize = true; + canvas3d.resizeGraphics2D = false; + } + } + if (doResize) { + synchronized (VirtualUniverse.mc.contextCreationLock) { + Graphics2D oldOffScreenGraphics2D = offScreenGraphics2D; + initCtx = false; + init(); + copyGraphics2D(oldOffScreenGraphics2D); + } + } else { + AffineTransform tr = getTransform(); + ptSrc.x = x1; + ptSrc.y = y1; + tr.transform(ptSrc, ptDst1); + ptSrc.x = x2; + ptSrc.y = y2; + tr.transform(ptSrc, ptDst2); + + synchronized (extentLock) { + if (ptDst1.x < xmin) { + xmin = (int) ptDst1.x; + } + if (ptDst1.y < ymin) { + ymin = (int) ptDst1.y; + } + if (ptDst2.x > xmax) { + xmax = (int) ptDst2.x; + } + if (ptDst2.y > ymax) { + ymax = (int) ptDst2.y; + } + } + } + } + + void copyGraphics2D(Graphics2D oldg) { + // restore the original setting of Graphics2D when resizing the windows + setColor(oldg.getColor()); + setFont(oldg.getFont()); + setClip(oldg.getClip()); + setComposite(oldg.getComposite()); + setTransform(oldg.getTransform()); + setPaint(oldg.getPaint()); + setStroke(oldg.getStroke()); + if (xOrModeColor != null) { + setXORMode(xOrModeColor); + } + + } + + // Implementation of Graphics2D methods + public final void clip(Shape s) { + offScreenGraphics2D.clip(s); + } + + public FontMetrics getFontMetrics() { + return offScreenGraphics2D.getFontMetrics(); + } + + public Rectangle getClipBounds(Rectangle r) { + return offScreenGraphics2D.getClipBounds(r); + } + + public Rectangle getClipRect() { + return offScreenGraphics2D.getClipRect(); + } + + public String toString() { + return offScreenGraphics2D.toString(); + + } + + public final AffineTransform getTransform() { + return offScreenGraphics2D.getTransform(); + } + + public final Color getColor() { + return offScreenGraphics2D.getColor(); + } + + public final Composite getComposite() { + return offScreenGraphics2D.getComposite(); + } + + public final Font getFont() { + return offScreenGraphics2D.getFont(); + } + + public final FontMetrics getFontMetrics(Font f) { + return offScreenGraphics2D.getFontMetrics(f); + } + + public final FontRenderContext getFontRenderContext() { + return offScreenGraphics2D.getFontRenderContext(); + } + + public final GraphicsConfiguration getDeviceConfiguration() { + return offScreenGraphics2D.getDeviceConfiguration(); + } + + public final Object getRenderingHint(Key hintKey) { + return offScreenGraphics2D.getRenderingHint(hintKey); + } + + public final Paint getPaint() { + return offScreenGraphics2D.getPaint(); + } + + public final Rectangle getClipBounds() { + return offScreenGraphics2D.getClipBounds(); + } + + public final RenderingHints getRenderingHints() { + return offScreenGraphics2D.getRenderingHints(); + } + + public final Shape getClip() { + return offScreenGraphics2D.getClip(); + } + + public final Stroke getStroke() { + return offScreenGraphics2D.getStroke(); + } + + public final boolean drawImage(Image img, AffineTransform xform, + ImageObserver obs) { + + validate(0, 0, img.getWidth(obs), img.getHeight(obs), xform); + return offScreenGraphics2D.drawImage(img, xform, obs); + } + + public final void drawImage(BufferedImage img, BufferedImageOp op, + int x, int y) { + if (op != null) { + img = op.filter(img, null); + } + validate(x, y, x+img.getWidth(), y+img.getHeight()); + offScreenGraphics2D.drawImage(img, null, x, y); + } + + public final boolean drawImage(Image img, + int x, int y, + ImageObserver observer) { + + validate(x, y, + x + img.getWidth(observer), + y + img.getWidth(observer)); + return offScreenGraphics2D.drawImage(img, x, y, observer); + } + + public final boolean drawImage(Image img, int x, int y, + int width, int height, + ImageObserver observer) { + validate(x, y, x+width, y+height); + return offScreenGraphics2D.drawImage(img, x, y, width, height, + observer); + } + + public final boolean drawImage(Image img, int x, int y, + int width, int height, + Color bgcolor, + ImageObserver observer) { + validate(x, y, x+width, y+height); + return offScreenGraphics2D.drawImage(img, x, y, width, height, bgcolor, + observer); + } + + public final void drawImage(BufferedImage img, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) { + validate(dx1, dy1, dx2, dy2); + offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, + sx2, sy2, observer); + } + + public final boolean drawImage(Image img, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) { + validate(dx1, dy1, dx2, dy2); + return offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, + sx2, sy2, observer); + } + + public final boolean drawImage(Image img, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, + ImageObserver observer) { + validate(dx1, dy1, dx2, dy2); + return offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, + sx2, sy2, bgcolor, observer); + } + + public final boolean drawImage(Image img, int x, int y, + Color bgcolor, + ImageObserver observer) { + validate(x, y, x+img.getWidth(observer), y+img.getHeight(observer)); + return offScreenGraphics2D.drawImage(img, x, y, bgcolor, observer); + } + + public final boolean hit(Rectangle rect, Shape s, boolean onStroke) { + return offScreenGraphics2D.hit(rect, s, onStroke); + } + + public final void addRenderingHints(Map hints) { + offScreenGraphics2D.addRenderingHints(hints); + } + + public final void clipRect(int x, int y, int width, int height) { + offScreenGraphics2D.clipRect(x, y, width, height); + } + + public final void copyArea(int x, int y, int width, int height, + int dx, int dy) { + validate(x+dx, y+dy, x+dx+width, y+dy+height); + offScreenGraphics2D.copyArea(x, y, width, height, dx, dy); + } + + public final void draw(Shape s) { + Rectangle rect = s.getBounds(); + validate(rect.x, rect.y, + rect.x + rect.width, + rect.y + rect.height); + offScreenGraphics2D.draw(s); + } + + public final void drawArc(int x, int y, int width, int height, + int startAngle, int arcAngle) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawArc(x, y, width, height, startAngle, arcAngle); + } + + public final void drawGlyphVector(GlyphVector g, float x, float y) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawGlyphVector(g, x, y); + } + + public final void drawLine(int x1, int y1, int x2, int y2) { + int minx, miny, maxx, maxy; + if (!strokeSet) { + if (x1 > x2) { + minx = x2; + maxx = x1; + } else { + minx = x1; + maxx = x2; + } + if (y1 > y2) { + miny = y2; + maxy = y1; + } else { + miny = y1; + maxy = y2; + } + validate(minx, miny, maxx, maxy); + } else { + // XXXX: call validate with bounding box of primitive + // XXXX: Need to consider Stroke width + validate(); + } + offScreenGraphics2D.drawLine(x1, y1, x2, y2); + } + + public final void drawOval(int x, int y, int width, int height) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawOval(x, y, width, height); + } + + public final void drawPolygon(int xPoints[], int yPoints[], + int nPoints) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawPolygon(xPoints, yPoints, nPoints); + } + + public final void drawPolyline(int xPoints[], int yPoints[], + int nPoints) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawPolyline(xPoints, yPoints, nPoints); + } + + public final void drawRenderableImage(RenderableImage img, + AffineTransform xform) { + + validate(0, 0, img.getWidth(), img.getHeight(), xform); + offScreenGraphics2D.drawRenderableImage(img, xform); + } + + public final void drawRenderedImage(RenderedImage img, + AffineTransform xform) { + validate(0, 0, img.getWidth(), img.getHeight(), xform); + offScreenGraphics2D.drawRenderedImage(img, xform); + } + + public final void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawRoundRect(x, y, width, height, arcWidth, + arcHeight); + } + + public final void drawString(AttributedCharacterIterator iterator, + int x, int y) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawString(iterator, x, y); + } + + public final void drawString(AttributedCharacterIterator iterator, + float x, float y) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawString(iterator, x, y); + } + + public final void drawString(String s, float x, float y) { + TextLayout layout = new TextLayout(s, getFont(), + getFontRenderContext()); + Rectangle2D bounds = layout.getBounds(); + float x1 = (float) bounds.getX(); + float y1 = (float) bounds.getY(); + validate(x1+x, y1+y, + x1 + x + (float) bounds.getWidth(), + y1 + y + (float) bounds.getHeight()); + offScreenGraphics2D.drawString(s, x, y); + + } + + public final void drawString(String s, int x, int y) { + drawString(s, (float) x, (float) y); + } + + public final void fill(Shape s) { + Rectangle rect = s.getBounds(); + validate(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); + offScreenGraphics2D.fill(s); + } + + public final void fillArc(int x, int y, int width, int height, + int startAngle, int arcAngle) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.fillArc(x, y, width, height, startAngle, arcAngle); + } + + public final void fillOval(int x, int y, int width, int height) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.fillOval(x, y, width, height); + } + + public final void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.fillRoundRect(x, y, width, height, arcWidth, + arcHeight); + } + + public final void rotate(double theta) { + offScreenGraphics2D.rotate(theta); + } + + public final void rotate(double theta, double x, double y) { + offScreenGraphics2D.rotate(theta, x, y); + } + + public final void scale(double sx, double sy) { + offScreenGraphics2D.scale(sx, sy); + } + + public final void setClip(Shape clip) { + offScreenGraphics2D.setClip(clip); + } + + + public final void setClip(int x, int y, int width, int height) { + offScreenGraphics2D.setClip(x, y, width, height); + } + + public final void setColor(Color c) { + offScreenGraphics2D.setColor(c); + } + + public final void setComposite(Composite comp) { + offScreenGraphics2D.setComposite(comp); + } + + public final void setFont(Font font) { + offScreenGraphics2D.setFont(font); + } + + public final void setPaint( Paint paint ) { + offScreenGraphics2D.setPaint(paint); + } + + public final void setPaintMode() { + xOrModeColor = null; + offScreenGraphics2D.setPaintMode(); + } + + public final void setRenderingHint(Key hintKey, Object hintValue) { + offScreenGraphics2D.setRenderingHint(hintKey, hintValue); + } + + public final void setRenderingHints(Map hints) { + offScreenGraphics2D.setRenderingHints(hints); + } + + public final void setStroke(Stroke s) { + strokeSet = (s != null); + offScreenGraphics2D.setStroke(s); + } + + public final void setTransform(AffineTransform Tx) { + offScreenGraphics2D.setTransform(Tx); + } + + public final void setXORMode(Color c1) { + xOrModeColor = c1; + offScreenGraphics2D.setXORMode(c1); + } + + public final void shear(double shx, double shy) { + offScreenGraphics2D.shear(shx, shy); + } + + public final void transform(AffineTransform Tx) { + offScreenGraphics2D.transform(Tx); + } + + public final void translate(double tx, double ty) { + offScreenGraphics2D.translate(tx, ty); + } + + public final void translate(int x, int y) { + offScreenGraphics2D.translate(x, y); + } + public boolean hitClip(int x, int y, int width, int height) { + return offScreenGraphics2D.hitClip(x, y, width, height); + } + + public void draw3DRect(int x, int y, int width, int height, + boolean raised) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.draw3DRect(x, y, width, height, raised); + } + + public void drawBytes(byte data[], int offset, int length, int x, int y) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawBytes(data, offset, length, x, y); + } + + public void drawChars(char data[], int offset, int length, int x, int y) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawChars(data, offset, length, x, y); + } + + public void drawPolygon(Polygon p) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.drawPolygon(p); + } + + public void drawRect(int x, int y, int width, int height) { + // XXXX: call validate with bounding box of primitive + // XXXX: need to consider Stroke width + validate(); + offScreenGraphics2D.drawRect(x, y, width, height); + } + + public void fill3DRect(int x, int y, int width, int height, + boolean raised) { + // XXXX: call validate with bounding box of primitive + // XXXX: need to consider Stroke width + validate(); + offScreenGraphics2D.fill3DRect(x, y, width, height, raised); + } + + public void fillPolygon(Polygon p) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.fillPolygon(p); + } + + public final void fillPolygon(int xPoints[], int yPoints[], + int nPoints) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.fillPolygon(xPoints, yPoints, nPoints); + } + + public final void fillRect(int x, int y, int width, int height) { + // XXXX: call validate with bounding box of primitive + validate(); + offScreenGraphics2D.fillRect(x, y, width, height); + } + + // Issue 121 - release all resources, mark as disposed + public void dispose() { + + // Issue 583 - do nothing if graphics has already been disposed + if (hasBeenDisposed) { + return; + } + + if (Thread.currentThread() == canvas3d.screen.renderer) { + doDispose(); + } else { + // Behavior Scheduler or other threads + // XXXX: may not be legal for behaviorScheduler + // May cause deadlock if it is in behaviorScheduler + // and we wait for Renderer to finish + boolean renderRun = (Thread.currentThread() != + canvas3d.view.universe.behaviorScheduler); + sendRenderMessage(renderRun, GraphicsContext3D.DISPOSE2D, + null, null, null); + } + + + } + + public void doDispose() { + + if (hasBeenDisposed) { + return; + } + + if (objectId != -1) { + canvas3d.freeTexture(canvas3d.ctx, objectId); + VirtualUniverse.mc.freeTexture2DId(objectId); + objectId = -1; + } + + // Dispose of the underlying Graphics2D + offScreenGraphics2D.dispose(); + + // Mark as disposed + hasBeenDisposed = true; + // Issue 583 - set graphics2D field to null so it will get recreated + canvas3d.graphics2D = null; + } + + public void drawAndFlushImage(BufferedImage img, int x, int y, + ImageObserver observer) { + + if (hasBeenDisposed) { + throw new IllegalStateException(J3dI18N.getString("J3DGraphics2D0")); + } + + if (!(initCtx && abgr && + (img.getType() == BufferedImage.TYPE_4BYTE_ABGR))) { + drawImage(img, x, y, observer); + flush(false); + return; + } + + if (Thread.currentThread() == canvas3d.screen.renderer) { + doDrawAndFlushImage(img, x, y, observer); + } else { + // Behavior Scheduler or other threads + // XXXX: may not be legal for behaviorScheduler + // May cause deadlock if it is in behaviorScheduler + // and we wait for Renderer to finish + boolean renderRun = (Thread.currentThread() != + canvas3d.view.universe.behaviorScheduler); + sendRenderMessage(renderRun, GraphicsContext3D.DRAWANDFLUSH2D, + img, new Point(x, y), observer); + } + } + + void doDrawAndFlushImage(BufferedImage img, int x, int y, + ImageObserver observer) { + + assert !hasBeenDisposed; + + int imgWidth = img.getWidth(observer); + int imgHeight = img.getHeight(observer); + int px, py, x1, y1, x2, y2; + + if (canvas3d.ctx == null) { + canvas3d.getGraphicsContext3D().doClear(); + } + + // format needs to be 4BYTE_ABGR and abgr needs to be supported + // also must be in canvas callback + data = ((DataBufferByte)img.getRaster().getDataBuffer()).getData(); + + // Transform the affine transform, + // note we do not handle scale/rotate etc. + AffineTransform tr = getTransform(); + ptSrc.x = x; + ptSrc.y = y; + tr.transform(ptSrc, ptDst1); + px = (int) ptDst1.x; + py = (int) ptDst1.y; + + // clip to offscreen buffer size + + if (px + imgWidth > width) { + x2 = width - px; + } else { + x2 = imgWidth; + } + + if (px < 0) { + x1 = -px; + px = 0; + } else { + x1 = 0; + } + + if (py + imgHeight > height) { + y2 = height - py; + } else { + y2 = imgHeight; + } + + if (py < 0) { + y1 = -py; + py = 0; + } else { + y1 = 0; + } + + if ((y2 - y1 > 0) && (x2 - x1 > 0)) { + copyDataToCanvas(px, py, x1,y1, x2, y2,imgWidth, imgHeight); + } + + } + + + void copyDataToCanvas(int px, int py, int x1, int y1, + int x2, int y2, int w, int h) { + try { + if (!canvas3d.drawingSurfaceObject.renderLock()) { + return; + } + + if (!initTexMap) { + if (objectId == -1) { + objectId = VirtualUniverse.mc.getTexture2DId(); + } + texWidth = getGreaterPowerOf2(w); + texHeight = getGreaterPowerOf2(h); + + // Canvas got resize, need to init texture map again + // in Renderer thread + if (!canvas3d.initTexturemapping(canvas3d.ctx, + texWidth, texHeight, + objectId)) { + // Fail to get the texture surface, most likely + // there is not enough texture memory + initTexMap = false; + VirtualUniverse.mc.freeTexture2DId(objectId); + objectId = -1; + // TODO : Need to find a better way to report no resource problem --- Chien. + System.err.println("J3DGraphics2DImpl.copyDataToCanvas() : Fail to get texture resources ..."); + + } else { + initTexMap = true; + } + } + if (initTexMap) { + canvas3d.texturemapping(canvas3d.ctx, px, py, + x1, y1, x2, y2, + texWidth, texHeight, w, + (abgr ? ImageComponentRetained.TYPE_BYTE_ABGR: + ImageComponentRetained.TYPE_BYTE_RGBA), + objectId, data, width, height); + } + + canvas3d.drawingSurfaceObject.unLock(); + } catch (NullPointerException ne) { + canvas3d.drawingSurfaceObject.unLock(); + throw ne; + } + + clearOffScreen(); + runMonitor(J3dThread.NOTIFY); + } + + void clearOffScreen() { + Composite comp = offScreenGraphics2D.getComposite(); + Color c = offScreenGraphics2D.getColor(); + offScreenGraphics2D.setComposite(AlphaComposite.Src); + offScreenGraphics2D.setColor(blackTransparent); + offScreenGraphics2D.fillRect(xmin, ymin, (xmax-xmin), (ymax-ymin)); + offScreenGraphics2D.setComposite(comp); + offScreenGraphics2D.setColor(c); + } + + /** + * Return an integer of power 2 greater than x + */ + static int getGreaterPowerOf2(int x) { + int i = -1; + if (x >= 0) { + for (i = 1; i < x; i <<= 1); + } + return i; + } + + /** + * MC may not scheduler Renderer thread or Renderer thread + * may not process message FLUSH. This will hang user + * thread. + */ + synchronized void runMonitor(int action) { + if (action == J3dThread.WAIT) { + // Issue 279 - loop until ready + while (threadWaiting) { + try { + wait(); + } catch (InterruptedException e){} + } + } else if (action == J3dThread.NOTIFY) { + notify(); + threadWaiting = false; + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dClock.java b/j3d-core/src/classes/share/javax/media/j3d/J3dClock.java new file mode 100644 index 0000000..7809fe2 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dClock.java @@ -0,0 +1,101 @@ +/* + * $RCSfile: J3dClock.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/05/22 18:10:39 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Utility class to provide a more accurate replacement for + * System.currentTimeMillis(). + */ +class J3dClock { + + // Issue 543 - Flag to indicate whether clock skews are taken in account + // and corrected. false by default. Set by the "j3d.adjustClockSkew" property. + private static boolean skewAdjustedClock = false; + + private static long deltaTime; + private static final long nsecPerMsec = 1000000; + + /** + * Private constructor, since no instance should ever be created. + */ + private J3dClock() { + } + + /** + * Returns the current time in milliseconds. This is a more + * accurate version of System.currentTimeMillis and should be used in + * its place. + * + * @return the current time in milliseconds. + */ + static long currentTimeMillis() { + if (!skewAdjustedClock) { + return (System.nanoTime() / nsecPerMsec) + deltaTime; + } else { + // Issue 543 - Adjust for possible clock skew + long time = (System.nanoTime() / nsecPerMsec) + deltaTime; + long sysTime = System.currentTimeMillis(); + if (Math.abs(time - sysTime) > 50) { + long baseTime, baseTimerValue; + synchronized (J3dClock.class) { + baseTime = System.currentTimeMillis(); + baseTimerValue = System.nanoTime(); + } + deltaTime = baseTime - (baseTimerValue / nsecPerMsec); + time = (System.nanoTime() / nsecPerMsec) + deltaTime; + } + return time; + } + } + + static { + // Issue 543: get property for clock skew adjustment + skewAdjustedClock = MasterControl.getBooleanProperty("j3d.adjustClockSkew", + skewAdjustedClock, "clock skew adjustment"); + + // Call time methods once without using their values to ensure that + // the methods are "warmed up". We need to make sure that the actual + // calls that we use take place as close together as possible in time. + System.currentTimeMillis(); + System.nanoTime(); + + // Compute deltaTime between System.currentTimeMillis() + // and the high-res timer, use a synchronized block to force both calls + // to be made before the integer divide + long baseTime, baseTimerValue; + synchronized (J3dClock.class) { + baseTime = System.currentTimeMillis(); + baseTimerValue = System.nanoTime(); + } + deltaTime = baseTime - (baseTimerValue / nsecPerMsec); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dDebug.java b/j3d-core/src/classes/share/javax/media/j3d/J3dDebug.java new file mode 100644 index 0000000..2674cec --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dDebug.java @@ -0,0 +1,461 @@ +/* + * $RCSfile: J3dDebug.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class J3dDebug { + + // For production release devPhase is set to false. + + // Do no debugging. + static final int NO_DEBUG = 0; + + // How much debugging information do we want ? + // (LEVEL_1 is very terse, LEVEL_5 is very verbose) + static final int LEVEL_1 = 1; + static final int LEVEL_2 = 2; + static final int LEVEL_3 = 3; + static final int LEVEL_4 = 4; + static final int LEVEL_5 = 5; + + // This static final variable is used to turn on/off debugging, + // checking, and initializing codes that may be preferred in + // development phase but not necessarily required in the + // production release. + // + // Beside for debugging, use this variable to do initialization, + // checking objects existence, and other checks that may help in + // uncovering potential bugs during code development. This + // variable should be turned off during production release as it + // may cause performance hit. + static final boolean devPhase = VersionInfo.isDevPhase; + + // This is a property variable. It allows a true/false be sent to + // J3d from command line, to on/off code segments. To avoid + // performance hit in production release, this variable MUST be + // used with devPhase when guarding code segments for execution. + // eg. if(J3dDebug.devPhase && J3dDebug.debug) + // do code_segment; + // Note: devPhase is a static final variable and debug isn't. If + // devPhase is put before debug, smart compiler will not include + // code_segment when devPhase is false. + static boolean debug; + + // Class debug variable, there is one debug variable per class. + // Set one of the 5 debug levels to the class debug variable when + // debugging. + // For example, alpha = !devPhase?NO_DEBUG:LEVEL_2; will cause + // code segments guarded by LEVEL_1 and LEVEL_2 be executed. And + // alpha = !devPhase?NO_DEBUG:NO_DEBUG; means do no debug. + static final int alpha = !devPhase?NO_DEBUG:NO_DEBUG; + static final int alternateAppearance = !devPhase?NO_DEBUG:NO_DEBUG; + static final int ambientLight = !devPhase?NO_DEBUG:NO_DEBUG; + static final int ambientLightRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int appearance = !devPhase?NO_DEBUG:NO_DEBUG; + static final int appearanceRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int assertionFailureException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int attributeBin = !devPhase?NO_DEBUG:NO_DEBUG; + static final int audioDevice = !devPhase?NO_DEBUG:NO_DEBUG; + static final int audioDevice3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int audioDeviceEnumerator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int auralAttributes = !devPhase?NO_DEBUG:NO_DEBUG; + static final int auralAttributesRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int bHInsertStructure = !devPhase?NO_DEBUG:NO_DEBUG; + static final int bHInternalNode = !devPhase?NO_DEBUG:NO_DEBUG; + static final int bHLeafInterface = !devPhase?NO_DEBUG:NO_DEBUG; + static final int bHLeafNode = !devPhase?NO_DEBUG:NO_DEBUG; + static final int bHNode = !devPhase?NO_DEBUG:NO_DEBUG; + static final int bHTree = !devPhase?NO_DEBUG:NO_DEBUG; + static final int background = !devPhase?NO_DEBUG:NO_DEBUG; + static final int backgroundRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int backgroundSound = !devPhase?NO_DEBUG:NO_DEBUG; + static final int backgroundSoundRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int badTransformException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int behavior = !devPhase?NO_DEBUG:NO_DEBUG; + static final int behaviorRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int behaviorScheduler = !devPhase?NO_DEBUG:NO_DEBUG; + static final int behaviorStructure = !devPhase?NO_DEBUG:NO_DEBUG; + static final int billboard = !devPhase?NO_DEBUG:NO_DEBUG; + static final int boundingBox = !devPhase?NO_DEBUG:NO_DEBUG; + static final int boundingLeaf = !devPhase?NO_DEBUG:NO_DEBUG; + static final int boundingLeafRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int boundingPolytope = !devPhase?NO_DEBUG:NO_DEBUG; + static final int boundingSphere = !devPhase?NO_DEBUG:NO_DEBUG; + static final int bounds = !devPhase?NO_DEBUG:NO_DEBUG; + static final int branchGroup = !devPhase?NO_DEBUG:NO_DEBUG; + static final int branchGroupRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int cachedFrustum = !devPhase?NO_DEBUG:NO_DEBUG; + static final int canvas3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int canvasViewCache = !devPhase?NO_DEBUG:NO_DEBUG; + static final int canvasViewEventCatcher = !devPhase?NO_DEBUG:NO_DEBUG; + static final int capabilityBits = !devPhase?NO_DEBUG:NO_DEBUG; + static final int capabilityNotSetException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int clip = !devPhase?NO_DEBUG:NO_DEBUG; + static final int clipRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int colorInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int coloringAttributes = !devPhase?NO_DEBUG:NO_DEBUG; + static final int coloringAttributesRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int compileState = !devPhase?NO_DEBUG:LEVEL_3; + static final int compressedGeometry = !devPhase?NO_DEBUG:NO_DEBUG; + static final int compressedGeometryHeader = !devPhase?NO_DEBUG:NO_DEBUG; + static final int compressedGeometryRenderMethod = !devPhase?NO_DEBUG:NO_DEBUG; + static final int compressedGeometryRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int coneSound = !devPhase?NO_DEBUG:NO_DEBUG; + static final int coneSoundRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int danglingReferenceException = !devPhase?NO_DEBUG:NO_DEBUG; + + static final int decalGroup = !devPhase?NO_DEBUG:NO_DEBUG; + static final int decalGroupRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int defaultRenderMethod = !devPhase?NO_DEBUG:NO_DEBUG; + static final int depthComponent = !devPhase?NO_DEBUG:NO_DEBUG; + static final int depthComponentFloat = !devPhase?NO_DEBUG:NO_DEBUG; + static final int depthComponentFloatRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int depthComponentInt = !devPhase?NO_DEBUG:NO_DEBUG; + static final int depthComponentIntRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int depthComponentNative = !devPhase?NO_DEBUG:NO_DEBUG; + static final int depthComponentNativeRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int depthComponentRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int directionalLight = !devPhase?NO_DEBUG:NO_DEBUG; + static final int directionalLightRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int displayListRenderMethod = !devPhase?NO_DEBUG:NO_DEBUG; + static final int distanceLOD = !devPhase?NO_DEBUG:NO_DEBUG; + static final int environmentSet = !devPhase?NO_DEBUG:NO_DEBUG; + static final int eventCatcher = !devPhase?NO_DEBUG:NO_DEBUG; + static final int exponentialFog = !devPhase?NO_DEBUG:NO_DEBUG; + static final int exponentialFogRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int fog = !devPhase?NO_DEBUG:NO_DEBUG; + static final int fogRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int font3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int fontExtrusion = !devPhase?NO_DEBUG:NO_DEBUG; + static final int generalizedStrip = !devPhase?NO_DEBUG:NO_DEBUG; + static final int generalizedStripFlags = !devPhase?NO_DEBUG:NO_DEBUG; + static final int generalizedVertexList = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometry = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryAtom = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryDecompressor = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryDecompressorRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryDecompressorShape3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryLock = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryLockInterface = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryStripArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryStripArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryStructure = !devPhase?NO_DEBUG:NO_DEBUG; + static final int geometryUpdater = !devPhase?NO_DEBUG:NO_DEBUG; + static final int graphicsConfigTemplate3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int graphicsContext3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int group = !devPhase?NO_DEBUG:NO_DEBUG; + static final int groupRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int hashKey = !devPhase?NO_DEBUG:NO_DEBUG; + static final int hiResCoord = !devPhase?NO_DEBUG:NO_DEBUG; + static final int illegalRenderingStateException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int illegalSharingException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int imageComponent = !devPhase?NO_DEBUG:NO_DEBUG; + static final int imageComponent2D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int imageComponent2DRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int imageComponent3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int imageComponent3DRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int imageComponentRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedGeometryArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedGeometryArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedGeometryStripArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedGeometryStripArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedLineArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedLineArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedLineStripArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedLineStripArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedPointArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedPointArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedQuadArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedQuadArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedTriangleArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedTriangleArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedTriangleFanArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedTriangleFanArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedTriangleStripArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int indexedTriangleStripArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int inputDevice = !devPhase?NO_DEBUG:NO_DEBUG; + static final int inputDeviceBlockingThread = !devPhase?NO_DEBUG:NO_DEBUG; + static final int inputDeviceScheduler = !devPhase?NO_DEBUG:NO_DEBUG; + static final int interpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dDataInputStream = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dDataOutputStream = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dDebug = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dI18N = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dMessage = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dNodeTable = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dQueryProps = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dStructure = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dThread = !devPhase?NO_DEBUG:NO_DEBUG; + static final int j3dThreadData = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lOD = !devPhase?NO_DEBUG:NO_DEBUG; + static final int leaf = !devPhase?NO_DEBUG:NO_DEBUG; + static final int leafRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int light = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lightBin = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lightRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lightSet = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lineArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lineArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lineAttributes = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lineAttributesRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lineStripArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int lineStripArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int linearFog = !devPhase?NO_DEBUG:NO_DEBUG; + static final int linearFogRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int link = !devPhase?NO_DEBUG:NO_DEBUG; + static final int linkRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int locale = !devPhase?NO_DEBUG:NO_DEBUG; + static final int mRSWLock = !devPhase?NO_DEBUG:NO_DEBUG; + static final int masterControl = !devPhase?NO_DEBUG:NO_DEBUG; + static final int material = !devPhase?NO_DEBUG:NO_DEBUG; + static final int materialRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int mediaContainer = !devPhase?NO_DEBUG:NO_DEBUG; + static final int mediaContainerRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int modelClip = !devPhase?NO_DEBUG:NO_DEBUG; + static final int modelClipRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int morph = !devPhase?NO_DEBUG:NO_DEBUG; + static final int morphRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int multipleParentException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int node = !devPhase?NO_DEBUG:NO_DEBUG; + static final int nodeComponent = !devPhase?NO_DEBUG:NO_DEBUG; + static final int nodeComponentRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int nodeReferenceTable = !devPhase?NO_DEBUG:NO_DEBUG; + static final int nodeRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int objectUpdate = !devPhase?NO_DEBUG:NO_DEBUG; + static final int orderedBin = !devPhase?NO_DEBUG:NO_DEBUG; + static final int orderedCollection = !devPhase?NO_DEBUG:NO_DEBUG; + static final int orderedGroup = !devPhase?NO_DEBUG:NO_DEBUG; + static final int orderedGroupRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pathInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int physicalBody = !devPhase?NO_DEBUG:NO_DEBUG; + static final int physicalEnvironment = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pickBounds = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pickCone = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pickCylinderRay = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pickCylinderSegment = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pickPoint = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pickRay = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pickSegment = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pickShape = !devPhase?NO_DEBUG:NO_DEBUG; + static final int picking = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pointArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pointArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pointAttributes = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pointAttributesRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pointLight = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pointLightRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pointSound = !devPhase?NO_DEBUG:NO_DEBUG; + static final int pointSoundRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int polygonAttributes = !devPhase?NO_DEBUG:NO_DEBUG; + static final int polygonAttributesRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int positionInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int positionPathInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int quadArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int quadArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int raster = !devPhase?NO_DEBUG:NO_DEBUG; + static final int rasterRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderAtom = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderBin = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderBinLock = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderMethod = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderMolecule = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderer = !devPhase?NO_DEBUG:NO_DEBUG; + static final int rendererStructure = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderingAttributes = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderingAttributesRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderingAttributesStructure = !devPhase?NO_DEBUG:NO_DEBUG; + static final int renderingEnvironmentStructure = !devPhase?NO_DEBUG:NO_DEBUG; + static final int restrictedAccessException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int rotPosPathInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int rotPosScalePathInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int rotationInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int rotationPathInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int scaleInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sceneGraphCycleException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sceneGraphObject = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sceneGraphObjectRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sceneGraphPath = !devPhase?NO_DEBUG:NO_DEBUG; + static final int screen3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int screenViewCache = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sensor = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sensorRead = !devPhase?NO_DEBUG:NO_DEBUG; + static final int setLiveState = !devPhase?NO_DEBUG:NO_DEBUG; + static final int shape3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int shape3DRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sharedGroup = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sharedGroupRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int sound = !devPhase?NO_DEBUG:NO_DEBUG; + static final int soundException = !devPhase?NO_DEBUG:NO_DEBUG; + static final int soundRenderer = !devPhase?NO_DEBUG:NO_DEBUG; + static final int soundRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int soundScheduler = !devPhase?NO_DEBUG:NO_DEBUG; + static final int soundStructure = !devPhase?NO_DEBUG:NO_DEBUG; + static final int soundscape = !devPhase?NO_DEBUG:NO_DEBUG; + static final int soundscapeRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int spotLight = !devPhase?NO_DEBUG:NO_DEBUG; + static final int spotLightRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int structureUpdateThread = !devPhase?NO_DEBUG:NO_DEBUG; + + // switch is a reserved word. + static final int Switch = !devPhase?NO_DEBUG:NO_DEBUG; + static final int switchRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int switchValueInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int table = !devPhase?NO_DEBUG:NO_DEBUG; + static final int texCoordGeneration = !devPhase?NO_DEBUG:NO_DEBUG; + static final int texCoordGenerationRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int text3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int text3DRenderMethod = !devPhase?NO_DEBUG:NO_DEBUG; + static final int text3DRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int texture = !devPhase?NO_DEBUG:NO_DEBUG; + static final int texture2D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int texture2DRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int texture3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int texture3DRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int textureAttributes = !devPhase?NO_DEBUG:NO_DEBUG; + static final int textureAttributesRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int textureBin = !devPhase?NO_DEBUG:NO_DEBUG; + static final int textureRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int textureSetting = !devPhase?NO_DEBUG:NO_DEBUG; + static final int timerThread = !devPhase?NO_DEBUG:NO_DEBUG; + static final int transform3D = !devPhase?NO_DEBUG:NO_DEBUG; + static final int transformGroup = !devPhase?NO_DEBUG:NO_DEBUG; + static final int transformGroupRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int transformStructure = !devPhase?NO_DEBUG:J3dDebug.LEVEL_3; + static final int transparencyAttributes = !devPhase?NO_DEBUG:NO_DEBUG; + static final int transparencyAttributesRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int transparencyInterpolator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int triangleArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int triangleArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int triangleFanArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int triangleFanArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int triangleStripArray = !devPhase?NO_DEBUG:NO_DEBUG; + static final int triangleStripArrayRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int unorderList = !devPhase?NO_DEBUG:NO_DEBUG; + static final int vertexArrayRenderMethod = !devPhase?NO_DEBUG:NO_DEBUG; + static final int view = !devPhase?NO_DEBUG:NO_DEBUG; + static final int viewCache = !devPhase?NO_DEBUG:NO_DEBUG; + static final int viewPlatform = !devPhase?NO_DEBUG:NO_DEBUG; + static final int viewPlatformRetained = !devPhase?NO_DEBUG:NO_DEBUG; + static final int virtualUniverse = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupAnd = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupAndOfOrs = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupCondition = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupCriteriaEnumerator = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupCriterion = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnAWTEvent = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnActivation = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnBehaviorPost = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnCollisionEntry = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnCollisionExit = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnCollisionMovement = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnDeactivation = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnElapsedFrames = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnElapsedTime = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnElapsedTimeHeap = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnSensorEntry = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnSensorExit = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnTransformChange = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnViewPlatformEntry = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOnViewPlatformExit = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOr = !devPhase?NO_DEBUG:NO_DEBUG; + static final int wakeupOrOfAnds = !devPhase?NO_DEBUG:NO_DEBUG; + + + static boolean doDebug(int j3dClassLevel, int level, String str) { + if(j3dClassLevel >= level) { + System.err.print(str); + return true; + } + return false; + } + + static boolean doDebug(int j3dClassLevel, int level) { + if(j3dClassLevel >= level) { + return true; + } + return false; + } + + static void doAssert(boolean expr, String str) { + if (! expr) { + throw new AssertionFailureException("(" + str + ")" + "is false"); + } + } + + static void pkgInfo(ClassLoader classLoader, + String pkgName, + String className) { + + try { + classLoader.loadClass(pkgName + "." + className); + + Package p = Package.getPackage(pkgName); + if (p == null) { + System.err.println("WARNING: Package.getPackage(" + + pkgName + + ") is null"); + } + else { + if(devPhase && debug) { + System.err.println(p); + System.err.println("Specification Title = " + + p.getSpecificationTitle()); + System.err.println("Specification Vendor = " + + p.getSpecificationVendor()); + System.err.println("Specification Version = " + + p.getSpecificationVersion()); + System.err.println("Implementation Vendor = " + + p.getImplementationVendor()); + System.err.println("Implementation Version = " + + p.getImplementationVersion()); + } + else if(devPhase) + System.err.println(", Java 3D " + p.getImplementationVersion() + "."); + } + } + catch (ClassNotFoundException e) { + System.err.println("Unable to load " + pkgName); + } + + // System.err.println(); + } + + + static { + // initialize the debug flag + debug = false; + } + +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dI18N.java b/j3d-core/src/classes/share/javax/media/j3d/J3dI18N.java new file mode 100644 index 0000000..f17bfc4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dI18N.java @@ -0,0 +1,50 @@ +/* + * $RCSfile: J3dI18N.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.io.*; +import java.util.*; + + +class J3dI18N { + static String getString(String key) { + String s; + try { + s = (String) ResourceBundle.getBundle("javax.media.j3d.ExceptionStrings").getString(key); + } + catch (MissingResourceException e) { + System.err.println("J3dI18N: Error looking up: " + key); + s = key; + } + return s; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dMessage.java b/j3d-core/src/classes/share/javax/media/j3d/J3dMessage.java new file mode 100644 index 0000000..74ebc92 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dMessage.java @@ -0,0 +1,190 @@ +/* + * $RCSfile: J3dMessage.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.11 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The J3dMessage is the super class of all messages in Java 3D. It implements + * all of the common data members needed. + */ + +class J3dMessage extends Object { + /** + * The various message types. + */ + static final int INVALID_TYPE = -1; + static final int INSERT_NODES = 0; + static final int REMOVE_NODES = 1; + static final int RUN = 2; + static final int TRANSFORM_CHANGED = 3; + static final int UPDATE_VIEW = 4; + static final int STOP_THREAD = 5; + static final int COLORINGATTRIBUTES_CHANGED = 6; + static final int LINEATTRIBUTES_CHANGED = 7; + static final int POINTATTRIBUTES_CHANGED = 8; + static final int POLYGONATTRIBUTES_CHANGED = 9; + static final int RENDERINGATTRIBUTES_CHANGED = 10; + static final int TEXTUREATTRIBUTES_CHANGED = 11; + static final int TRANSPARENCYATTRIBUTES_CHANGED = 12; + static final int MATERIAL_CHANGED = 13; + static final int TEXCOORDGENERATION_CHANGED = 14; + static final int TEXTURE_CHANGED = 15; + static final int MORPH_CHANGED = 16; + static final int GEOMETRY_CHANGED = 17; + static final int APPEARANCE_CHANGED = 18; + static final int LIGHT_CHANGED = 19; + static final int BACKGROUND_CHANGED = 20; + static final int CLIP_CHANGED = 21; + static final int FOG_CHANGED = 22; + static final int BOUNDINGLEAF_CHANGED = 23; + static final int SHAPE3D_CHANGED = 24; + static final int TEXT3D_TRANSFORM_CHANGED = 25; + static final int TEXT3D_DATA_CHANGED = 26; + static final int SWITCH_CHANGED = 27; + static final int COND_MET = 28; + static final int BEHAVIOR_ENABLE = 29; + static final int BEHAVIOR_DISABLE = 30; + static final int INSERT_RENDERATOMS = 31; + static final int ORDERED_GROUP_INSERTED = 32; + static final int ORDERED_GROUP_REMOVED = 33; + static final int COLLISION_BOUND_CHANGED = 34; + static final int REGION_BOUND_CHANGED = 35; + static final int MODELCLIP_CHANGED = 36; + static final int BOUNDS_AUTO_COMPUTE_CHANGED = 37; + static final int SOUND_ATTRIB_CHANGED = 38; + static final int AURALATTRIBUTES_CHANGED = 39; + static final int SOUNDSCAPE_CHANGED = 40; + static final int ALTERNATEAPPEARANCE_CHANGED = 41; + static final int RENDER_OFFSCREEN = 42; + static final int RENDER_RETAINED = 43; + static final int RENDER_IMMEDIATE = 44; + static final int SOUND_STATE_CHANGED = 45; + static final int ORIENTEDSHAPE3D_CHANGED = 46; + static final int TEXTURE_UNIT_STATE_CHANGED = 47; + static final int UPDATE_VIEWPLATFORM = 48; + static final int BEHAVIOR_ACTIVATE = 49; + static final int GEOMETRYARRAY_CHANGED = 50; + static final int MEDIA_CONTAINER_CHANGED = 51; + static final int RESIZE_CANVAS = 52; + static final int TOGGLE_CANVAS = 53; + static final int IMAGE_COMPONENT_CHANGED = 54; + static final int SCHEDULING_INTERVAL_CHANGED = 55; + static final int VIEWSPECIFICGROUP_CHANGED = 56; + static final int VIEWSPECIFICGROUP_INIT = 57; + static final int VIEWSPECIFICGROUP_CLEAR = 58; + static final int ORDERED_GROUP_TABLE_CHANGED = 59; + static final int BEHAVIOR_REEVALUATE = 60; + static final int CREATE_OFFSCREENBUFFER = 61; + static final int DESTROY_CTX_AND_OFFSCREENBUFFER = 62; + static final int SHADER_ATTRIBUTE_CHANGED = 63; + static final int SHADER_ATTRIBUTE_SET_CHANGED = 64; + static final int SHADER_APPEARANCE_CHANGED = 65; + static final int ALLOCATE_CANVASID = 66; + static final int FREE_CANVASID = 67; + + /** + * This is the time snapshot at which this change occured + */ + long time = -1; + + /** + * This is the number of references to this message + */ + private int refcount = 0; + + /** + * This is a bitmask of the types of threads that need to be run + * once this message is consumed. + */ + int threads = 0; + + /** + * The universe that this message originated from + */ + VirtualUniverse universe; + + /** + * This holds the type of this message + */ + int type = -1; + + /** + * This holds the target view of this message, null means all views + */ + View view = null; + + + /** + * The arguements for a message, 5 for now + */ + static final int MAX_ARGS = 6; + + Object[] args = new Object[MAX_ARGS]; + + /** + * This constructor does nothing + */ + J3dMessage() { + } + + final synchronized void clear() { + // System.err.println("J3dMessage : " + this ); + view = null; + universe = null; + args[0] = null; + args[1] = null; + args[2] = null; + args[3] = null; + args[4] = null; + args[5] = null; + } + + /** + * This increments the reference count for this message + */ + final synchronized void incRefcount() { + refcount++; + } + + /** + * This decrements the reference count for this message. If it goes + * to 0, the message is put on the MasterControl freelist. + */ + final synchronized void decRefcount() { + if (--refcount == 0) { + clear(); + } + } + + final synchronized int getRefcount() { + return refcount; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dNodeTable.java b/j3d-core/src/classes/share/javax/media/j3d/J3dNodeTable.java new file mode 100644 index 0000000..93972d1 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dNodeTable.java @@ -0,0 +1,309 @@ +/* + * $RCSfile: J3dNodeTable.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.io.DataOutputStream; +import java.io.OutputStream; +import java.util.Hashtable; +import javax.vecmath.Color3f; +import javax.vecmath.Tuple3f; + +/** + * The J3dNodeTable object provides utilities for the save/load + * methods in the Java3d nodes. Specifically, it holds an enumerated + * list of the Java3D node types and their respective Class names. + * It keeps these lists in a Hashtable and an array and allows + * other classes to get an enumerated value associated with an Object + * type or an instance of an Object associated with an enumerated value. + * + */ +class J3dNodeTable { + + // nodeTable holds the enumerated value/Classname pairs. This is + // used to look up enumerated values given a Class name. + Hashtable nodeTable = new Hashtable(); + + // nodeArray holds the value/Classname pairs also, but allows lookups + // in the other direction (given a value, what's the Class name?) + String nodeArray[]; + + // Following is a list of the current scene graph objects of java3D. + // In order to make later node insertion easier, and to add some logic to + // this arbitrary list, the groups of nodes are grouped in terms of + // similar functionality of node types. + + // Maximum number of nodes + static final int MAX_NUM_NODES = 200; + + // Nothing occupies slot 0 - thus we can return 0 from this class' + // methods to denote failure. + static final int NOTHING = 0; + + // 1 - 9: Groups + static final int GROUP = 1; + static final int TRANSFORM_GROUP = 2; + static final int SWITCH_GROUP = 3; + static final int ORDERED_GROUP = 4; + static final int BRANCH_GROUP = 5; + static final int ENDGROUP = 9; // denotes done with group + + // 10 - 19: Shape3D (in a class by itself) + static final int SHAPE3D = 10; + + // 20 - 49: Appearance and all of its attributes + static final int APPEARANCE = 20; + static final int MATERIAL = 21; + static final int TEXTURE = 22; + static final int TEX_COORD_GENERATION = 23; + static final int TEXTURE_ATTRIBUTES = 24; + static final int COLORING_ATTRIBUTES = 25; + static final int TRANSPARENCY_ATTRIBUTES = 26; + static final int RENDERING_ATTRIBUTES = 27; + static final int POLYGON_ATTRIBUTES = 28; + static final int LINE_ATTRIBUTES = 29; + static final int POINT_ATTRIBUTES = 30; + static final int TEXTURE_2D = 31; + static final int TEXTURE_3D = 32; + static final int IMAGE_COMPONENT = 33; + static final int IMAGE_COMPONENT_2D = 34; + static final int IMAGE_COMPONENT_3D = 35; + static final int ENDAPPEARANCE = 49; + + // 100 - 149: All Geometry types + static final int GEOMETRY = 100; + static final int COMPRESSED_GEOMETRY = 101; + static final int GEOMETRY_ARRAY = 102; + static final int GEOMETRY_STRIP_ARRAY = 103; + static final int INDEXED_GEOMETRY_ARRAY = 104; + static final int INDEXED_GEOMETRY_STRIP_ARRAY = 105; + static final int INDEXED_LINE_ARRAY = 106; + static final int INDEXED_LINE_STRIP_ARRAY = 107; + static final int INDEXED_POINT_ARRAY = 108; + static final int INDEXED_QUAD_ARRAY = 109; + static final int INDEXED_TRIANGLE_ARRAY = 110; + static final int INDEXED_TRIANGLE_FAN_ARRAY = 111; + static final int INDEXED_TRIANGLE_STRIP_ARRAY = 112; + static final int LINE_ARRAY = 113; + static final int LINE_STRIP_ARRAY = 114; + static final int POINT_ARRAY = 115; + static final int QUAD_ARRAY = 116; + static final int TRIANGLE_ARRAY = 117; + static final int TRIANGLE_FAN_ARRAY = 118; + static final int TRIANGLE_STRIP_ARRAY = 119; + static final int BACKGROUND_SOUND = 120; + static final int POINT_SOUND = 121; + static final int CONE_SOUND = 122; + static final int MEDIA_CONTAINER = 123; + + // 150 - 169: Behaviors + static final int ROTATION_INTERPOLATOR = 150; + static final int ROTPOSSCALEPATH_INTERPOLATOR = 151; + static final int ROTATIONPATH_INTERPOLATOR = 152; + static final int POSITIONPATH_INTERPOLATOR = 153; + static final int ROTPOSPATH_INTERPOLATOR = 154; + static final int POSITION_INTERPOLATOR = 155; + static final int SWITCHVALUE_INTERPOLATOR = 156; + static final int COLOR_INTERPOLATOR = 157; + static final int SCALE_INTERPOLATOR = 158; + // Problem: these next two are non j3d-core items + static final int SOUND_PLAYER = 159; + static final int SOUND_FADER = 160; + + // 170 - 189: Various utility nodes + static final int BOUNDS = 170; + static final int BOUNDING_SPHERE = 171; + static final int BOUNDING_BOX = 172; + static final int BOUNDING_POLYTOPE = 173; + static final int TRANSFORM3D = 180; + static final int BACKGROUND = 181; + + // 190 - 199: Lights + static final int LIGHT = 190; + static final int POINT_LIGHT = 191; + static final int SPOT_LIGHT = 192; + static final int DIRECTIONAL_LIGHT = 193; + static final int AMBIENT_LIGHT = 194; + + + /** + * Constructs this Object, which initializes the array and Hashtable + */ + J3dNodeTable() { + nodeArray = new String[MAX_NUM_NODES]; + //Initialize all table entries to null + for (int i = 0; i < MAX_NUM_NODES; ++i) + nodeArray[i] = null; + // Setup slots of nodeArray where there should be valid values + nodeArray[GROUP] = "Group"; + nodeArray[TRANSFORM_GROUP] = "TransformGroup"; + nodeArray[SWITCH_GROUP] = "Switch"; + nodeArray[ORDERED_GROUP] = "OrderedGroup"; + nodeArray[BRANCH_GROUP] = "BranchGroup"; + + nodeArray[SHAPE3D] = "Shape3D"; + + nodeArray[APPEARANCE] = "Appearance"; + nodeArray[MATERIAL] = "Material"; + nodeArray[TEXTURE] = "Texture"; + nodeArray[TEXTURE_2D] = "Texture2D"; + nodeArray[TEXTURE_3D] = "Texture3D"; + nodeArray[IMAGE_COMPONENT] = "ImageComponent"; + nodeArray[IMAGE_COMPONENT_2D] = "ImageComponent2D"; + nodeArray[IMAGE_COMPONENT_3D] = "ImageComponent3D"; + nodeArray[TRANSPARENCY_ATTRIBUTES] = "TransparencyAttributes"; + + nodeArray[GEOMETRY] = "Geometry"; + nodeArray[COMPRESSED_GEOMETRY] = "CompressedGeometry"; + nodeArray[GEOMETRY_ARRAY] = "GeometryArray"; + nodeArray[GEOMETRY_STRIP_ARRAY] = "GeometryStripArray"; + nodeArray[INDEXED_GEOMETRY_ARRAY] = "IndexedGeometryArray"; + nodeArray[INDEXED_GEOMETRY_STRIP_ARRAY] = "IndexedGeometryStripArray"; + nodeArray[INDEXED_LINE_ARRAY] = "IndexedLineArray"; + nodeArray[INDEXED_LINE_STRIP_ARRAY] = "IndexedLineStripArray"; + nodeArray[INDEXED_POINT_ARRAY] = "IndexedPointArray"; + nodeArray[INDEXED_QUAD_ARRAY] = "IndexedQuadArray"; + nodeArray[INDEXED_TRIANGLE_ARRAY] = "IndexedTriangleArray"; + nodeArray[INDEXED_TRIANGLE_FAN_ARRAY] = "IndexedTriangleFanArray"; + nodeArray[INDEXED_TRIANGLE_STRIP_ARRAY] = "indexedTriangleStripArray"; + nodeArray[LINE_ARRAY] = "LineArray"; + nodeArray[LINE_STRIP_ARRAY] = "LineStripArray"; + nodeArray[POINT_ARRAY] = "PointArray"; + nodeArray[QUAD_ARRAY] = "QuadArray"; + nodeArray[TRIANGLE_ARRAY] = "TriangleArray"; + nodeArray[TRIANGLE_FAN_ARRAY] = "TriangleFanArray"; + nodeArray[TRIANGLE_STRIP_ARRAY] = "TriangleStripArray"; + nodeArray[BACKGROUND_SOUND] = "BackgroundSound"; + nodeArray[POINT_SOUND] = "PointSound"; + nodeArray[CONE_SOUND] = "ConeSound"; + nodeArray[MEDIA_CONTAINER] = "MediaContainer"; + + nodeArray[ROTATION_INTERPOLATOR] = "RotationInterpolator"; + nodeArray[ROTPOSSCALEPATH_INTERPOLATOR] = "RotPosScalePathInterpolator"; + nodeArray[ROTATIONPATH_INTERPOLATOR] = "RotationPathInterpolator"; + nodeArray[POSITIONPATH_INTERPOLATOR] = "PositionPathInterpolator"; + nodeArray[ROTPOSPATH_INTERPOLATOR] = "RotPosPathInterpolator"; + nodeArray[POSITION_INTERPOLATOR] = "PositionInterpolator"; + nodeArray[SWITCHVALUE_INTERPOLATOR] = "SwitchValueInterpolator"; + nodeArray[COLOR_INTERPOLATOR] = "ColorInterpolator"; + nodeArray[SCALE_INTERPOLATOR] = "ScaleInterpolator"; + nodeArray[SOUND_PLAYER] = "SoundPlayer"; + nodeArray[SOUND_FADER] = "SoundFader"; + + nodeArray[BOUNDS] = "Bounds"; + nodeArray[BOUNDING_SPHERE] = "BoundingSphere"; + nodeArray[BOUNDING_BOX] = "BoundingBox"; + nodeArray[BOUNDING_POLYTOPE] = "BoundingPolytope"; + nodeArray[TRANSFORM3D] = "Transform3D"; + nodeArray[BACKGROUND] = "Background"; + + nodeArray[LIGHT] = "Light"; + nodeArray[POINT_LIGHT] = "PointLight"; + nodeArray[SPOT_LIGHT] = "SpotLight"; + nodeArray[DIRECTIONAL_LIGHT] = "DirectionalLight"; + nodeArray[AMBIENT_LIGHT] = "AmbientLight"; + + for (int i = 0; i < MAX_NUM_NODES; ++i) { + if (nodeArray[i] != null) + nodeTable.put(nodeArray[i], new Integer(i)); + } + + } + + /** + * Returns the enumerated value associated with an Object. This + * method retrieves the base class name (with no package name and + * with no "Retained" portion (if it's part of the Object's name); + * we're just looking for the base Java3d node type here. + */ + int getNodeValue(Object object) { + Integer i; + String fullName = object.getClass().getName(); + int firstIndex; + int lastIndex ; + if ((firstIndex = fullName.lastIndexOf(".")) == -1) + firstIndex = 0; + else + firstIndex++; + if ((lastIndex = fullName.lastIndexOf("Retained")) == -1) + lastIndex = fullName.length(); + String nodeName = fullName.substring(firstIndex, lastIndex); + if ((i = (Integer)nodeTable.get(nodeName)) + != null) { + return i.intValue(); + } + else { + // This conditional exists because if a group node is + // actually a subclass of some standard Java3d Group type + // (e.g., VrmlParser), then we'll just save it and reload + // it as a Group. + if (object instanceof TransformGroup || + object instanceof TransformGroupRetained) + return TRANSFORM_GROUP; + else if (object instanceof BranchGroup || + object instanceof BranchGroupRetained) + return BRANCH_GROUP; + else if (object instanceof Switch || + object instanceof SwitchRetained) + return SWITCH_GROUP; + else if (object instanceof Group || + object instanceof GroupRetained) + return GROUP; + else if (object instanceof Shape3D) + return SHAPE3D; // For Text2D object in particular + else { + System.err.println("Warning: Don't know how to save object of type " + object); + return 0; + } + } + } + + /** + * Returns new instance of an object with the Class name + * associated with the given enumerated value. + */ + Object getObject(int nodeValue) { + try { + if (nodeArray[nodeValue] != null) { + String nodeName = "javax.media.j3d." + nodeArray[nodeValue]; + return Class.forName(nodeName).newInstance(); + } + } + catch (Exception e) { + throw new RuntimeException("Exception creating object for nodeValue " + + nodeValue + "\n nodeName = javax.media.j3d." + + nodeArray[nodeValue]); + } + return null; + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dNotification.java b/j3d-core/src/classes/share/javax/media/j3d/J3dNotification.java new file mode 100644 index 0000000..d5db279 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dNotification.java @@ -0,0 +1,63 @@ +/* + * $RCSfile: J3dNotification.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * J3dNotification is used to hold data for asynchronous error notification. + */ + +class J3dNotification extends Object { + /** + * The various notification types. + */ + static final int INVALID_TYPE = -1; + static final int SHADER_ERROR = 0; + static final int RENDERING_ERROR = 1; + + /** + * This holds the type of this message + */ + int type = INVALID_TYPE; + + /** + * The universe that this message originated from + */ + VirtualUniverse universe; + + /** + * The arguements for a message, 6 for now + */ + static final int MAX_ARGS = 6; + + Object[] args = new Object[MAX_ARGS]; + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dQueryProps.java b/j3d-core/src/classes/share/javax/media/j3d/J3dQueryProps.java new file mode 100644 index 0000000..b167c18 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dQueryProps.java @@ -0,0 +1,129 @@ +/* + * $RCSfile: J3dQueryProps.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + + +/** + * Properties object for query operations. It is a read-only Map backed + * up by a Hashtable. + */ +class J3dQueryProps extends AbstractMap { + private Hashtable table; + private Set entrySet = null; + + + /** + * Constructs a new J3dQueryProps object using the specified + * array of keys and the specified values. The arrays must be + * the same size. + */ + J3dQueryProps(String[] keys, Object[] values) { + table = new Hashtable(); + for (int i = 0; i < keys.length; i++) { + table.put(keys[i], values[i]); + } + } + + /** + * Gets value corresponding to specified key + */ + public Object get(Object key) { + return table.get(key); + } + + /** + * Returns true if the specified key is contained in this Map + */ + public boolean containsKey(Object key) { + return table.containsKey(key); + } + + /** + * Returns true if the specified value is contained in this Map + */ + public boolean containsValue(Object value) { + return table.containsValue(value); + } + + /** + * Returns a new Set object for the entries of this map + */ + public Set entrySet() { + if (entrySet == null) + entrySet = new EntrySet(); + + return entrySet; + } + + + /** + * Entry set class + */ + private class EntrySet extends AbstractSet { + private EntrySet() { + } + + public int size() { + return table.size(); + } + + public Iterator iterator() { + return new MapIterator(); + } + } + + + /** + * Entry set class + */ + private class MapIterator implements Iterator { + private Iterator i; + + private MapIterator() { + i = table.entrySet().iterator(); + } + + public boolean hasNext() { + return i.hasNext(); + } + + public Object next() { + return i.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dStructure.java b/j3d-core/src/classes/share/javax/media/j3d/J3dStructure.java new file mode 100644 index 0000000..fa9b7de --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dStructure.java @@ -0,0 +1,172 @@ +/* + * $RCSfile: J3dStructure.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * The J3dStructure is the super class of all structures in Java 3D. + * A structure is a object that organizes a collection of objects. + */ + +abstract class J3dStructure extends Object { + /** + * This is the list of messages to be processed by this structure + */ + UnorderList messageList = new UnorderList(5, J3dMessage.class); + + /** + * This is the update Thread for this structure + */ + + StructureUpdateThread updateThread = null; + + /** + * This is the type of update thread + */ + int threadType = -1; + + /** + * The universe of this structure + */ + VirtualUniverse universe = null; + + /** + * The thread data for the update thread + */ + J3dThreadData threadData = new J3dThreadData(); + + /** + * number of messages for this snapshot of time + */ + int nMessage = 0; + J3dMessage[] msgList = new J3dMessage[5]; + + /** + * This constructor does nothing + */ + J3dStructure(VirtualUniverse u, int type) { + universe = u; + threadType = type; + threadData.threadType = type; + } + + /** + * This returns the thread data for this thread. + */ + final J3dThreadData getUpdateThreadData() { + return (threadData); + } + + /** + * This adds a message to the list of messages for this structure + */ + final void addMessage(J3dMessage message) { + + if (threadData != null) { + threadData.lastUpdateTime = message.time; + } else { + // this force message to consume when initialized + message.time = -1; + } + message.incRefcount(); + messageList.add(message); + } + + + /** + * This returns whether or not there are any pending messages + */ + final J3dMessage[] getMessages(long referenceTime) { + int sz, n = 0; + + synchronized (messageList) { + if ((sz = messageList.size()) > 0) { + J3dMessage mess[] = (J3dMessage []) messageList.toArray(false); + for (n = 0; n < sz; n++) { + if (mess[n].time > referenceTime) { + break; + } + } + if (n > 0) { + if (msgList.length < n) { + msgList = new J3dMessage[n]; + } + messageList.shift(msgList, n); + } + } + } + + nMessage = n; + return msgList; + } + + final void clearMessages() { + synchronized (messageList) { + int nmessage = messageList.size(); + if (nmessage > 0) { + J3dMessage mess[] = (J3dMessage []) messageList.toArray(false); + for (int i = nmessage-1; i >=0; i--) { + mess[i].decRefcount(); + } + messageList.clear(); + } + nMessage = 0; + msgList = new J3dMessage[5]; + } + + } + + int getNumMessage() { + return nMessage; + } + + /** + * This gets overriden by the structure + */ + abstract void processMessages(long referenceTime); + + /** + * This is used by MasterControl to process any unused message + * for final cleanup. DON'T decrememt message count in + * the method, as it is done by MasterControl. + */ + abstract void removeNodes(J3dMessage m); + + /** + * Release resource associate with this structure before GC + * We need to clear all those IndexedUnorderSet/WakeupIndexedList + * so that the listIdx associate with IndexedObject reset to -1. + */ + abstract void cleanup(); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/J3dThread.java b/j3d-core/src/classes/share/javax/media/j3d/J3dThread.java new file mode 100644 index 0000000..f98b9f3 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/J3dThread.java @@ -0,0 +1,358 @@ +/* + * $RCSfile: J3dThread.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The J3dThread is the super class of all slave threads in Java 3D. It implements + * all of the common flow control constructs. + */ + +abstract class J3dThread extends Thread { + /** + * These are the thread types that a message may affect + */ + static final int BEHAVIOR_SCHEDULER = 0x01; + static final int SOUND_SCHEDULER = 0x02; + static final int INPUT_DEVICE_SCHEDULER = 0x04; + static final int RENDER_THREAD = 0x10; +// static final int COLLISION_THREAD = 0x20; + static final int UPDATE_GEOMETRY = 0x40; + static final int UPDATE_RENDER = 0x80; + static final int UPDATE_BEHAVIOR = 0x100; + static final int UPDATE_SOUND = 0x200; + static final int UPDATE_RENDERING_ATTRIBUTES = 0x400; + static final int UPDATE_RENDERING_ENVIRONMENT = 0x1000; + static final int UPDATE_TRANSFORM = 0x2000; + + /** + * The classification types. + */ + static final int WORK_THREAD = 0x01; + static final int UPDATE_THREAD = 0x02; + + /** + * This runMonitor action puts the thread into an initial wait state + */ + static final int WAIT = 0; + + /** + * This runMonitor action notifies MasterControl that this thread + * has completed and wait. + */ + static final int NOTIFY_AND_WAIT = 1; + + /** + * This is used by Canvas3D Renderer to notify user thread + * that swap is completed. + */ + static final int NOTIFY = 2; + + /** + * This runMonitor action tells the thread to run N number of + * iterations. + */ + static final int RUN = 2; + + /** + * This runMonitor action tells the thread to stop running + */ + static final int STOP = 3; + + /** + * This indicates that this thread has been activated by MC + */ + boolean active = false; + + /** + * This indicates that this thread is alive and running + */ + private volatile boolean running = true; + + /** + * This flag is set by the RUN action of runMonitor to indicate that the + * waiting thread has work to do. + */ + private volatile boolean ready = false; + + /** + * The thread data for this thread + */ + private J3dThreadData[] data = null; + + /** + * This indicates that this thread is started and able to accept work + */ + private volatile boolean started = false; + + /** + * The time values passed into this thread + */ + long referenceTime; + + /** + * Use to assign threadOpts WAIT_ALL_THREADS + */ + long lastWaitTimestamp = 0; + + /** + * The type of this thread. It is one of the above constants. + */ + int type; + + /** + * The classification of this thread. It is one of the above constants. + */ + int classification = WORK_THREAD; + + /** + * The arguments passed in for this thread + */ + Object[] args = null; + + /** + * Flag to indicate that user initiate a thread stop + */ + volatile boolean userStop = false; + + /** + * Flag to indicate that this thread is waiting to be notify + */ + private volatile boolean waiting = false; + + /** + * Some variables used to name threads correctly + */ + private static int numInstances = 0; + private int instanceNum = -1; + + private synchronized int newInstanceNum() { + return (++numInstances); + } + + int getInstanceNum() { + if (instanceNum == -1) + instanceNum = newInstanceNum(); + return instanceNum; + } + + /** + * This method is defined by all slave threads to implement + * one iteration of work. + */ + abstract void doWork(long referenceTime); + + /** + * This constructor simply assigns the given id. + */ + J3dThread(ThreadGroup t) { + super(t, ""); + } + + /** + * This returns the thread data for this thread. + */ + synchronized J3dThreadData getThreadData(View v, Canvas3D c) { + J3dThreadData threadData; + int i, j; + J3dThreadData[] newData; + + if (type != RENDER_THREAD) { // Regular Thread + if (data == null) { + data = new J3dThreadData[1]; + data[0] = new J3dThreadData(); + data[0].thread = this; + data[0].threadType = type; + data[0].view = null; + data[0].canvas = null; + } + threadData = data[0]; + } else { // Render thread + + // Note: each renderer has multiple thread data mappings + // for its render and swap threads + + if (data == null) { + data = new J3dThreadData[1]; + data[0] = new J3dThreadData(); + data[0].thread = this; + data[0].threadType = type; + data[0].view = v; + data[0].canvas = c; + data[0].threadArgs = new Object[4]; + threadData = data[0]; + } else { + for (i=0; i= 0) + removeSwitch(index); + } + + + /** + * Removes all switch nodes from this LOD node. + * + * @since Java 3D 1.3 + */ + public void removeAllSwitches() { + int numSwitches = switches.size(); + + // Remove in reverse order to ensure valid indices + for (int index = numSwitches - 1; index >= 0; index--) { + removeSwitch(index); + } + } + + + /** + * Copies all LOD information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + LOD lod = (LOD) originalNode; + + int numSwitch = lod.numSwitches(); + for (int i = 0; i < numSwitch; i++) { + addSwitch(lod.getSwitch(i)); + } + } + + /** + * Callback used to allow a node to check if any nodes referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any node references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding Node in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * node is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + int numSwitch = numSwitches(); + + for (int i = 0; i < numSwitch; i++) { + Switch curSwitch = getSwitch(i); + if (curSwitch != null) { + setSwitch((Switch) + referenceTable.getNewObjectReference(curSwitch), i); + } + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Leaf.java b/j3d-core/src/classes/share/javax/media/j3d/Leaf.java new file mode 100644 index 0000000..c9b445c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Leaf.java @@ -0,0 +1,53 @@ +/* + * $RCSfile: Leaf.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The Leaf node is an abstract class for all scene graph nodes that + * have no children. + * Leaf nodes specify lights, geometry, and sounds. They specify special + * linking and instancing capabilities for sharing scene graphs and + * provide a view platform for positioning and orienting a view in the + * virtual world. + *

+ * NOTE: Applications should not extend this class directly. + */ + +public abstract class Leaf extends Node { + + /** + * Construct and initialize the Leaf object. + */ + public Leaf(){ + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LeafRetained.java b/j3d-core/src/classes/share/javax/media/j3d/LeafRetained.java new file mode 100644 index 0000000..e1d2f85 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LeafRetained.java @@ -0,0 +1,67 @@ +/* + * $RCSfile: LeafRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.Hashtable; + +import java.util.ArrayList; + +/** + * LeafRetained node. + */ +abstract class LeafRetained extends NodeRetained { + + SwitchState switchState = null; + + // temporary variable used during bounds computation, since + // multiple mirror shapes could be pointing to the same shape3D + boolean boundsDirty = false; + + // Appicable only to the mirror object + void updateBoundingLeaf() { + + } + protected Object clone(boolean forceDuplicate) { + return super.clone(); + } + + void updateMirrorObject(Object[] args) { + } + + void updateTransformChange() { + } + + void updateBounds() { + } + + void getMirrorObjects(ArrayList l, HashKey k) { + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Light.java b/j3d-core/src/classes/share/javax/media/j3d/Light.java new file mode 100644 index 0000000..474e29d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Light.java @@ -0,0 +1,731 @@ +/* + * $RCSfile: Light.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; +import java.util.Enumeration; + +/** + * The Light leaf node is an abstract class that defines a set of + * parameters common to all + * types of light. These parameters include the light color, an enable + * flag, and a region of influence in which this Light node is active. + * A Light node also contains a list of Group nodes that specifies the + * hierarchical scope of this Light. If the scope list is empty, + * the Light node has universe scope: all nodes within the region of + * influence are affected by this Light node. If the scope list is + * non-empty, only those Leaf nodes under the Group nodes in the + * scope list are affected by this Light node (subject to the + * influencing bounds). + *

+ * The light in a scene may come from several light sources that can + * be individually defined. Some of the light in a scene may + * come from a specific direction, known as a directional light, + * from a specific position, known as a point light, or + * from no particular direction or source as with ambient light. + *

+ * Java 3D supports an arbitrary number of lights. However, the number + * of lights that can be active within the region of influence is + * implementation-dependent and cannot be defined here. + *

+ * Light Color + *

+ * The Java 3D lighting model approximates the way light works in + * the real world. Light is defined in terms of the red, green, and + * blue components that combine to create the light color. The + * three color components represent the amount of light emitted + * by the source. + *

+ * Each of the three colors is represented by a + * floating point value that ranges from 0.0 to 1.0. A combination + * of the three colors such as (1.0, 1.0, 1.0), representing + * the red, green, and blue color values respectively, creates a white + * light with maximum brightness. A combination such as (0.0, 0.0, + * 0.0) creates no light (black). Values between the minimum and + * maximum values of the range produce corresponding brightness + * and colors. For example, a combination of (0.5, 0.5, 0.5) + * produces a 50% grey light. A combination of (1.0, 1.0, 0.0), + * red and green but no blue, produces a yellow light. + *

+ * If a scene has multiple lights and all lights illuminate an object, + * the effect of the light on the object is the sum of the + * lights. For example, in a scene with two lights, if the first + * light emits (R1, G1, B1) and + * the second light emits (R2, G2, + * B2), the components are added together giving + * (R1+R2, G1+G2, + * B1+B2). + * If the sums of any of the color values is greater than 1.0, + * brighter than the maximum brightness permitted, the color value is + * clamped to 1.0. + *

+ * Material Colors + *

+ * In the Java 3D lighting model, the light sources have an effect + * on the scene only when there are object surfaces to absorb or + * reflect the light. Java 3D approximates an object's color + * by calculating the percentage of red, green, and blue light + * the object reflects. An object with a surface color of pure green + * absorbs all of the red and blue light that strikes it and + * reflects all of the green light. Viewing the object in a + * white light, the green color is reflected and you see a green + * object. However, if the green object is viewed in a red light, + * all of the red light is absorbed and the object appears black. + *

+ * The surface of each object in the scene has + * certain material properties that define how light affects its + * appearance. The object might reflect light in various ways, + * depending on the object's surface type. The object + * might even emit its own light. The Java 3D lighting model specifies + * these material properties as five independent components: emitted + * color, ambient color, diffuse color, specular color, and shininess. + * All of these properties are computed independently, then added + * together to define how the surface of the object appears under + * light (an exception is Ambient light, which does not contribute + * to specular reflection). The material properties are defined + * in the Material class. + *

+ * Influencing Bounds + *

+ * Since a scene may be quite large, as large as the universe for + * example, it is often reasonable to limit the influence of lighting + * to a region that is within viewing range. There is no reason + * to waste all that computing power on illuminating objects that + * are too far away to be viewed. In Java 3D, the influencing bounds + * is defined by a Bounds object or a BoundingLeaf object. It should + * be noted that a BoundingLeaf object overrides a Bounds object, + * should both objects be set. + *

+ * A Bounds object represents a convex, closed volume. Bounds + * defines three different types of containing + * volumes: an axis-aligned-box volume, a spherical volume, and a + * bounding polytope. A BoundingLeaf object also specifies a region + * of influence, but allows an application to specify a bounding + * region in one coordinate system (the local coordinate system of + * the BoundingLeaf node) other than the local coordinate + * system of the node that references the bounds (the Light). + *

+ * Limiting the Scope + *

+ * In addition to limiting the lighting calculations to a given + * region of a scene, lighting can also be limited to groups of + * nodes, defined by a Group object. This is known as "scoping." + * All nodes attached to a Group node define a list of scopes. + * Methods in the Light class permit the setting, addition, insertion, + * removal, and enumeration of nodes in the list of scopes. + *

+ * Two-sided Lighting of Polygons + *

+ * Java 3D performs lighting calculations for all polygons, whether + * they are front-facing or back-facing. Since most polygon objects + * are constructed with the front face in mind, the back-facing + * portion may not be correctly illuminated. For example, a sphere + * with part of the face cut away so you can see its inside. + * You might want to have the inside surface lit as well as the + * outside surface and you mught also want to define a different + * Material description to reduce shininess, specular color, etc. + *

+ * For more information, see the "Face culling" and "Back-facing + * normal flip" descriptions in the PolygonAttributes class + * description. + *

+ * Turning on the Lights + *

+ * Lighting needs to be explicitly enabled with the setEnable method + * or with the lightOn parameter in the constructor + * before any of the child light sources have any effect on illuminating + * the scene. The child lights may also be enabled or disabled individually. + *

+ * If lighting is not enabled, the current color of an + * object in the scene is simply mapped onto the object, and none of + * the lighting equations regarding Material properties, such as ambient + * color, diffuse color, specular color, and shininess, are performed. + * However, an object's emitted color, if specified and enabled, will + * still affect that object's appearance. + *

+ * To disable lighting, call setEnable with false as + * the argument. + * + * @see Material + * @see Bounds + * @see BoundingLeaf + * @see Group + * @see PolygonAttributes + */ + +public abstract class Light extends Leaf { + /** + * Specifies that this Light allows read access to its current state + * information at runtime. + */ + public static final int + ALLOW_STATE_READ = CapabilityBits.LIGHT_ALLOW_STATE_READ; + + /** + * Specifies that this Light allows write access to its current state + * information at runtime. + */ + public static final int + ALLOW_STATE_WRITE = CapabilityBits.LIGHT_ALLOW_STATE_WRITE; + + /** + * Specifies that this Light allows read access to its color + * information at runtime. + */ + public static final int + ALLOW_COLOR_READ = CapabilityBits.LIGHT_ALLOW_COLOR_READ; + + /** + * Specifies that this Light allows write access to its color + * information at runtime. + */ + public static final int + ALLOW_COLOR_WRITE = CapabilityBits.LIGHT_ALLOW_COLOR_WRITE; + + /** + * Specifies that this Light allows read access to its + * influencing bounds and bounds leaf information. + */ + public static final int + ALLOW_INFLUENCING_BOUNDS_READ = CapabilityBits.LIGHT_ALLOW_INFLUENCING_BOUNDS_READ; + + /** + * Specifies that this Light allows write access to its + * influencing bounds and bounds leaf information. + */ + public static final int + ALLOW_INFLUENCING_BOUNDS_WRITE = CapabilityBits.LIGHT_ALLOW_INFLUENCING_BOUNDS_WRITE; + + /** + * Specifies that this Light allows read access to its scope + * information at runtime. + */ + public static final int + ALLOW_SCOPE_READ = CapabilityBits.LIGHT_ALLOW_SCOPE_READ; + + /** + * Specifies that this Light allows write access to its scope + * information at runtime. + */ + public static final int + ALLOW_SCOPE_WRITE = CapabilityBits.LIGHT_ALLOW_SCOPE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_STATE_READ, + ALLOW_COLOR_READ, + ALLOW_INFLUENCING_BOUNDS_READ, + ALLOW_SCOPE_READ + }; + + /** + * Constructs a Light node with default parameters. The default + * values are as follows: + *

    + * enable flag : true
    + * color : white (1,1,1)
    + * scope : empty (universe scope)
    + * influencing bounds : null
    + * influencing bounding leaf : null
    + *
+ */ + public Light() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a Light node using the specified color. + * @param color the color of the light source + */ + public Light(Color3f color) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((LightRetained)this.retained).initColor(color); + } + + /** + * Constructs and initializes a Light node using the specified enable + * flag and color. + * @param lightOn flag indicating whether this light is on or off + * @param color the color of the light source + */ + public Light(boolean lightOn, Color3f color) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((LightRetained)this.retained).initEnable(lightOn); + ((LightRetained)this.retained).initColor(color); + } + + /** + * Turns the light on or off. + * @param state true or false to set light on or off + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setEnable(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_STATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light0")); + + if (isLive()) + ((LightRetained)this.retained).setEnable(state); + else + ((LightRetained)this.retained).initEnable(state); + } + + /** + * Retrieves this Light's current state (on/off). + * @return this node's current state (on/off) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getEnable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_STATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Light1")); + + return ((LightRetained)this.retained).getEnable(); + } + + /** + * Sets the Light's current color. + * @param color the value of this node's new color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setColor(Color3f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light2")); + + if (isLive()) + ((LightRetained)this.retained).setColor(color); + else + ((LightRetained)this.retained).initColor(color); + } + + /** + * Gets this Light's current color and places it in the parameter specified. + * @param color the vector that will receive this node's color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getColor(Color3f color) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Light3")); + + ((LightRetained)this.retained).getColor(color); + } + + /** + * Replaces the node at the specified index in this Light node's + * list of scopes with the specified Group node. + * By default, Light nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be stored at the specified index. + * @param index the index of the Group node to be replaced. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void setScope(Group scope, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light4")); + + if (isLive()) + ((LightRetained)this.retained).setScope(scope, index); + else + ((LightRetained)this.retained).initScope(scope, index); + } + + + /** + * Retrieves the Group node at the specified index from this Light node's + * list of scopes. + * @param index the index of the Group node to be returned. + * @return the Group node at the specified index. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Group getScope(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Light5")); + + return ((LightRetained)this.retained).getScope(index); + } + + + /** + * Inserts the specified Group node into this Light node's + * list of scopes at the specified index. + * By default, Light nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be inserted at the specified index. + * @param index the index at which the Group node is inserted. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void insertScope(Group scope, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light6")); + + if (isLive()) + ((LightRetained)this.retained).insertScope(scope, index); + else + ((LightRetained)this.retained).initInsertScope(scope, index); + } + + + /** + * Removes the node at the specified index from this Light node's + * list of scopes. If this operation causes the list of scopes to + * become empty, then this Light will have universe scope: all nodes + * within the region of influence will be affected by this Light node. + * @param index the index of the Group node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the group node at the + * specified index is part of a compiled scene graph + */ + public void removeScope(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light7")); + + if (isLive()) + ((LightRetained)this.retained).removeScope(index); + else + ((LightRetained)this.retained).initRemoveScope(index); + } + + + /** + * Returns an enumeration of this Light node's list of scopes. + * @return an Enumeration object containing all nodes in this Light node's + * list of scopes. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Enumeration getAllScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Light8")); + + return (Enumeration) ((LightRetained)this.retained).getAllScopes(); + } + + + /** + * Appends the specified Group node to this Light node's list of scopes. + * By default, Light nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be appended. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void addScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light9")); + + if (isLive()) + ((LightRetained)this.retained).addScope(scope); + else + ((LightRetained)this.retained).initAddScope(scope); + } + + + /** + * Returns the number of nodes in this Light node's list of scopes. + * If this number is 0, then the list of scopes is empty and this + * Light node has universe scope: all nodes within the region of + * influence are affected by this Light node. + * @return the number of nodes in this Light node's list of scopes. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int numScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Light8")); + + return ((LightRetained)this.retained).numScopes(); + } + + + /** + * Retrieves the index of the specified Group node in this + * Light node's list of scopes. + * + * @param scope the Group node to be looked up. + * @return the index of the specified Group node; + * returns -1 if the object is not in the list. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int indexOfScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Light8")); + + return ((LightRetained)this.retained).indexOfScope(scope); + } + + + /** + * Removes the specified Group node from this Light + * node's list of scopes. If the specified object is not in the + * list, the list is not modified. If this operation causes the + * list of scopes to become empty, then this Light + * will have universe scope: all nodes within the region of + * influence will be affected by this Light node. + * + * @param scope the Group node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light7")); + + if (isLive()) + ((LightRetained)this.retained).removeScope(scope); + else + ((LightRetained)this.retained).initRemoveScope(scope); + } + + + /** + * Removes all Group nodes from this Light node's + * list of scopes. The Light node will then have + * universe scope: all nodes within the region of influence will + * be affected by this Light node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if any group node in this + * node's list of scopes is part of a compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeAllScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light7")); + + if (isLive()) + ((LightRetained)this.retained).removeAllScopes(); + else + ((LightRetained)this.retained).initRemoveAllScopes(); + } + + + /** + * Sets the Light's influencing region to the specified bounds. + * This is used when the influencing bounding leaf is set to null. + * @param region the bounds that contains the Light's new influencing + * region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInfluencingBounds(Bounds region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light11")); + + if (isLive()) + ((LightRetained)this.retained).setInfluencingBounds(region); + else + ((LightRetained)this.retained).initInfluencingBounds(region); + } + + /** + * Retrieves the Light node's influencing bounds. + * @return this Light's influencing bounds information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getInfluencingBounds() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Light12")); + + return ((LightRetained)this.retained).getInfluencingBounds(); + } + + /** + * Sets the Light's influencing region to the specified bounding leaf. + * When set to a value other than null, this overrides the influencing + * bounds object. + * @param region the bounding leaf node used to specify the Light + * node's new influencing region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInfluencingBoundingLeaf(BoundingLeaf region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Light11")); + + if (isLive()) + ((LightRetained)this.retained).setInfluencingBoundingLeaf(region); + else + ((LightRetained)this.retained).initInfluencingBoundingLeaf(region); + } + + /** + * Retrieves the Light node's influencing bounding leaf. + * @return this Light's influencing bounding leaf information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BoundingLeaf getInfluencingBoundingLeaf() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INFLUENCING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Light12")); + + return ((LightRetained)this.retained).getInfluencingBoundingLeaf(); + } + + + + /** + * Copies all Light information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + LightRetained attr = (LightRetained) originalNode.retained; + LightRetained rt = (LightRetained) retained; + + Color3f c = new Color3f(); + attr.getColor(c); + rt.initColor(c); + rt.initInfluencingBounds(attr.getInfluencingBounds()); + + Enumeration elm = attr.getAllScopes(); + while (elm.hasMoreElements()) { + // this reference will set correctly in updateNodeReferences() callback + rt.initAddScope((Group) elm.nextElement()); + } + + // this reference will set correctly in updateNodeReferences() callback + rt.initInfluencingBoundingLeaf(attr.getInfluencingBoundingLeaf()); + + rt.initEnable(attr.getEnable()); + } + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + + + LightRetained rt = (LightRetained) retained; + BoundingLeaf bl = rt.getInfluencingBoundingLeaf(); + + if (bl != null) { + Object o = referenceTable.getNewObjectReference(bl); + rt.initInfluencingBoundingLeaf((BoundingLeaf)o); + } + + int num = rt.numScopes(); + for (int i=0; i < num; i++) { + rt.initScope((Group) referenceTable. + getNewObjectReference(rt.getScope(i)), i); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LightBin.java b/j3d-core/src/classes/share/javax/media/j3d/LightBin.java new file mode 100644 index 0000000..f456fdd --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LightBin.java @@ -0,0 +1,470 @@ +/* + * $RCSfile: LightBin.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; + +/** + * The LightBin manages a collection of EnvironmentSet objects. + * The number of objects managed depends upon the number of Lights + * in each EnvironmentSet and the number of lights supported by + * the underlying rendering layer. + */ + +class LightBin extends Object implements ObjectUpdate { + + /** + * The maximum number of lights in a LightBin + */ + int maxLights = -1; + + /** + * The Array of Light references in this LightBin. + * This array is always maxLights in length. + */ + LightRetained[] lights = null; + + /** + * An Array of reference counts for shared lights in + * among EnvirionmentSets + */ + int[] lightsRef = null; + + /** + * The number of empty light slots in this LightBin + */ + int numEmptySlots = -1; + + /** + * The RenderBin for this object + */ + RenderBin renderBin = null; + + /** + * The references to the next and previous LightBins in the + * list. + */ + LightBin next = null; + LightBin prev = null; + + /** + * The list of EnvironmentSets in this LightBin. + */ + EnvironmentSet environmentSetList = null; + + /** + * List of envSet to be added for the next iteration + */ + ArrayList insertEnvSet = new ArrayList(); + + + + /** + * cache of the canvasDirty + */ + int canvasDirty = 0; + + /** + * lightDirty Mask cache , used to + * mark the lightdirty bits for next frame + */ + int lightDirtyMaskCache = 0; + + + /** + * lightDirty Mask used during rendering + */ + int lightDirtyMask = 0; + + /** + * List of pointLts in this lightbin + * Need to reload these lights when vworld scale changes + */ + ArrayList pointLts = new ArrayList(); + int[] pointLtsSlotIndex; + + // OrderedGroup info + OrderedCollection orderedCollection = null; + + boolean onUpdateList = false; + + // background node that contains geometry + BackgroundRetained geometryBackground = null; + + + + LightBin(int maxLights, RenderBin rb, boolean isOpaque) { + this.maxLights = maxLights; + this.numEmptySlots = maxLights; + lights = new LightRetained[maxLights]; + lightsRef = new int[maxLights]; + renderBin = rb; + } + + void reset(boolean inOpaque) { + prev = null; + next = null; + orderedCollection = null; + environmentSetList = null; + onUpdateList = false; + geometryBackground = null; + // No need to reset the lights and lightRef + if (J3dDebug.devPhase && J3dDebug.debug) { + for (int i=0; i numEmptySlots) { + return (false); + } else { + return (true); + } + } + + /** + * Adds the new EnvironmentSet to this LightBin. + */ + void addEnvironmentSet(EnvironmentSet e, RenderBin rb) { + int i, j, numEsLights; + LightRetained light; + + numEsLights = e.lights.size(); + for (i=0; i 0) { + e = (EnvironmentSet)insertEnvSet.get(0); + if (environmentSetList == null) { + environmentSetList = e; + } + else { + e.next = environmentSetList; + environmentSetList.prev = e; + environmentSetList = e; + } + for (i = 1; i < insertEnvSet.size(); i++) { + e = (EnvironmentSet)insertEnvSet.get(i); + e.next = environmentSetList; + environmentSetList.prev = e; + environmentSetList = e; + } + } + + + insertEnvSet.clear(); + if (canvasDirty != 0) { + + Canvas3D canvases[] = renderBin.view.getCanvases(); + for (i = 0; i < canvases.length; i++) { + canvases[i].canvasDirty |= canvasDirty; + } + lightDirtyMask = lightDirtyMaskCache; + canvasDirty = 0; + lightDirtyMaskCache = 0; + } + onUpdateList = false; + } + + + + /** + * Removes the given EnvironmentSet from this LightBin. + */ + void removeEnvironmentSet(EnvironmentSet e) { + int i, j, numEsLights; + LightRetained light; + + e.lightBin = null; + // If envSet being remove is contained in envSet, then + // remove the envSet from the addList + if (insertEnvSet.contains(e)) { + insertEnvSet.remove(insertEnvSet.indexOf(e)); + } + else { + numEsLights = e.lights.size(); + for (i=0; i>= 1; + i++; + } + + cv.canvasDirty &= ~Canvas3D.LIGHTBIN_DIRTY; + } + else if ((pointLts.size() > 0) && ((cv.canvasDirty & Canvas3D.VIEW_MATRIX_DIRTY) != 0 )) { + if (geometryBackground == null) { + scale = cv.canvasViewCache.getVworldToCoexistenceScale(); + cv.setModelViewMatrix(cv.ctx, cv.vpcToEc.mat, + renderBin.vworldToVpc); + } else { + scale = cv.canvasViewCache.getInfVworldToCoexistenceScale(); + cv.setModelViewMatrix(cv.ctx, cv.vpcToEc.mat, + renderBin.infVworldToVpc); + } + for (i = 0; i < pointLts.size(); i++) { + LightRetained lt = (LightRetained) pointLts.get(i); + lt.update(cv.ctx, pointLtsSlotIndex[i], scale); + cv.lights[pointLtsSlotIndex[i]] = lt; + cv.frameCount[pointLtsSlotIndex[i]] = frameCount; + } + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LightRetained.java b/j3d-core/src/classes/share/javax/media/j3d/LightRetained.java new file mode 100644 index 0000000..9729b2f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LightRetained.java @@ -0,0 +1,1081 @@ +/* + * $RCSfile: LightRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.Enumeration; +import java.util.Vector; +import java.util.ArrayList; + +/** + * LightRetained is an abstract class that contains instance variable common to + * all lights. + */ + +abstract class LightRetained extends LeafRetained { + + // Statics used when something in the light changes + static final int ENABLE_CHANGED = 0x0001; + static final int SCOPE_CHANGED = 0x0002; + static final int BOUNDS_CHANGED = 0x0004; + static final int COLOR_CHANGED = 0x0008; + static final int BOUNDINGLEAF_CHANGED = 0x0010; + static final int INIT_MIRROR = 0x0020; + static final int CLEAR_MIRROR = 0x0040; + static final int LAST_DEFINED_BIT = 0x0040; + + // Indicates whether the light is turned on. + boolean lightOn = true; + + // The color of the light (white by default). + Color3f color = new Color3f(1.0f, 1.0f, 1.0f); + + // This node which specifies the hierarchical scope of the + // light. A null reference means that this light has universal + // scope. + Vector scopes = new Vector(); + + /** + * The Boundary object defining the lights's region of influence. + */ + Bounds regionOfInfluence = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * The transformed value of the applicationRegion. + */ + Bounds region = null; + + /** + * This bitmask is set when something changes in the light + */ + int lightDirty = 0xffff; + + // This is a copy of the sgLight's dirty bits + int sgLightDirty = 0xffff; + + // The type of light + int lightType = -1; + + // This is true when this light is needed in the current light set + boolean isNeeded = false; + + // This is true when this light is referenced in an immediate mode context + boolean inImmCtx = false; + + // A back reference to the scene graph light, when this is a mirror light + LightRetained sgLight = null; + + // A HashKey for lights in a shared group + HashKey key = null; + + // An array of mirror lights, one for each instance of this light in a + // shared group. Entry 0 is the only one valid if we are not in a shared + // group. + LightRetained[] mirrorLights = new LightRetained[1]; + + // The number of valid lights in mirrorLights + int numMirrorLights = 0; + + // Indicated whether the light is a scoped light + boolean isScoped = false; + + // The object that contains the dynamic HashKey - a string type object + // Used in scoping + HashKey tempKey = new HashKey(250); + + /** + * A list of all the EnvironmentSets that reference this light. + * Note that multiple RenderBin update thread may access + * this shared environmentSets simultaneously. + * So we use UnorderList when sync. all the operations. + */ + UnorderList environmentSets = new UnorderList(1, EnvironmentSet.class); + + // Is true, if the mirror light is viewScoped + boolean isViewScoped = false; + + + /** + * Temporary list of newly added mirror lights, during any setlive + */ + ArrayList newlyAddedMirrorLights = new ArrayList(); + + // Target threads to be notified when light changes + static final int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_RENDER; + + /** + * Initialize the light on or off. + * @param state true or false to enable or disable the light + */ + void initEnable(boolean state) { + this.lightOn = state; + } + + /** + * Turns the light on or off and send a message + * @param state true or false to enable or disable the light + */ + void setEnable(boolean state) { + initEnable(state); + sendMessage(ENABLE_CHANGED, + (state ? Boolean.TRUE: Boolean.FALSE)); + } + + + /** + * Returns the state of the light (on/off). + * @return true if the light is on, false if the light is off. + */ + boolean getEnable() { + return this.lightOn; + } + + /** + * Initialize the color of this light node. + * @param color the value of this new light color + */ + void initColor(Color3f color) { + this.color.set(color); + } + + /** + * Sets the color of this light node and send a message + * @param color the value of this new light color + */ + void setColor(Color3f color) { + initColor(color); + sendMessage(COLOR_CHANGED, new Color3f(color)); + } + + /** + * Retrieves the color of this light. + * @param color the vector that will receive the color of this light + */ + void getColor(Color3f color) { + color.set(this.color); + } + + /** + * Initializes the specified scope with the scope provided. + * @param scope the new scope + * @param index which scope to replace + */ + void initScope(Group scope, int index) { + GroupRetained group = (GroupRetained)scope.retained; + scopes.setElementAt(group, index); + + } + + + /** + * Replaces the specified scope with the scope provided and + * send a message + * @param scope the new scope + * @param index which scope to replace + */ + void setScope(Group scope, int index) { + ArrayList addScopeList = new ArrayList(); + ArrayList removeScopeList = new ArrayList(); + GroupRetained group; + Object[] scopeInfo = new Object[3]; + + group = (GroupRetained) scopes.get(index); + tempKey.reset(); + group.removeAllNodesForScopedLight((inSharedGroup?numMirrorLights:1), mirrorLights, removeScopeList, tempKey); + + + group = (GroupRetained)scope.retained; + tempKey.reset(); + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + group.addAllNodesForScopedLight((inSharedGroup?numMirrorLights:1), mirrorLights,addScopeList, tempKey); + + + initScope(scope, index); + J3dMessage createMessage = new J3dMessage(); + scopeInfo[0] = addScopeList; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + /** + * Inserts the specified scope at specified index. + * @param scope the new scope + * @param index position to insert new scope at + */ + void initInsertScope(Group scope, int index) { + GroupRetained group = (GroupRetained)scope.retained; + scopes.insertElementAt(group, index); + group.setLightScope(); + } + + /** + * Inserts the specified scope at specified index. + * @param scope the new scope + * @param index position to insert new scope at + */ + void insertScope(Group scope, int index) { + + Object[] scopeInfo = new Object[3]; + ArrayList addScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scope.retained; + + tempKey.reset(); + group.addAllNodesForScopedLight((inSharedGroup?numMirrorLights:1), mirrorLights,addScopeList, tempKey); + + initInsertScope(scope, index); + scopeInfo[0] = addScopeList; + scopeInfo[1] = null; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + + /** + * Removes the scope at specified index. + * @param index which scope to remove + */ + void initRemoveScope(int index) { + GroupRetained group = (GroupRetained)scopes.elementAt(index); + scopes.removeElementAt(index); + group.removeLightScope(); + } + + + /** + * Removes the scope at specified index. + * @param index which scope to remove + */ + void removeScope(int index) { + + Object[] scopeInfo = new Object[3]; + ArrayList removeScopeList = new ArrayList(); + + GroupRetained group = (GroupRetained)scopes.elementAt(index); + tempKey.reset(); + group.removeAllNodesForScopedLight((inSharedGroup?numMirrorLights:1), mirrorLights, removeScopeList, tempKey); + initRemoveScope(index); scopeInfo[0] = null; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + + /** + * Removes the specified scope + * @param scope to be removed + */ + void removeScope(Group scope) { + int ind = indexOfScope(scope); + if(ind >= 0) + removeScope(ind); + } + + void initRemoveScope(Group scope) { + int ind = indexOfScope(scope); + if(ind >= 0) + initRemoveScope(ind); + } + + /** + * Removes all the scopes from this Light's list of scopes + */ + void removeAllScopes() { + int n = scopes.size(); + Object[] scopeInfo = new Object[3]; + ArrayList removeScopeList = new ArrayList(); + GroupRetained group; + + for(int index = n-1; index >= 0; index--) { + group = (GroupRetained)scopes.elementAt(index); + tempKey.reset(); + group.removeAllNodesForScopedLight((inSharedGroup?numMirrorLights:1), mirrorLights, removeScopeList, tempKey); + initRemoveScope(index); + } + scopeInfo[0] = null; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + void initRemoveAllScopes() { + int n = scopes.size(); + for(int i = n-1; i >= 0; i--) + initRemoveScope(i); + } + + /** + * Returns the scope specified by the index. + * @param index of the scope to be returned + * @return the scope at location index + */ + Group getScope(int index) { + return (Group)(((GroupRetained)(scopes.elementAt(index))).source); + } + + /** + * Returns an enumeration object of the scope + * @return an enumeration object of the scope + */ + Enumeration getAllScopes() { + Enumeration elm = scopes.elements(); + Vector v = new Vector(scopes.size()); + while (elm.hasMoreElements()) { + v.add( ((GroupRetained) elm.nextElement()).source); + } + return v.elements(); + } + + /** + * Appends the specified scope to this node's list of scopes. + * @param scope the scope to add to this node's list of scopes + */ + void initAddScope(Group scope) { + GroupRetained group = (GroupRetained)scope.retained; + scopes.addElement(group); + group.setLightScope(); + } + + /** + * Appends the specified scope to this node's list of scopes. + * @param scope the scope to add to this node's list of scopes + */ + void addScope(Group scope) { + Object[] scopeInfo = new Object[3]; + ArrayList addScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scope.retained; + + initAddScope(scope); + tempKey.reset(); + group.addAllNodesForScopedLight((inSharedGroup?numMirrorLights:1), mirrorLights,addScopeList, tempKey); + scopeInfo[0] = addScopeList; + scopeInfo[1] = null; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo); + } + + /** + * Returns a count of this nodes' scopes. + * @return the number of scopes descendant from this node + */ + int numScopes() { + return scopes.size(); + } + + /** + * Returns the index of the specified scope + * @return index of the scope in this Light's list of scopes + */ + int indexOfScope(Group scope) { + if(scope != null) + return scopes.indexOf((GroupRetained)scope.retained); + else + return scopes.indexOf(null); + } + + /** + * Initializes the Light's region of influence. + * @param region a region that contains the Light's new region of influence + */ + void initInfluencingBounds(Bounds region) { + if (region != null) { + regionOfInfluence = (Bounds) region.clone(); + if (staticTransform != null) { + regionOfInfluence.transform(staticTransform.transform); + } + } else { + regionOfInfluence = null; + } + } + + + /** + * Set the Light's region of influence and send a message + * @param region a region that contains the Light's new region of influence + */ + void setInfluencingBounds(Bounds region) { + initInfluencingBounds(region); + sendMessage(BOUNDS_CHANGED, + (region != null ? region.clone() : null)); + } + + /** + * Get the Light's region of influence + * @return this Light's region of influence information + */ + Bounds getInfluencingBounds() { + Bounds b = null; + + if (regionOfInfluence != null) { + b = (Bounds) regionOfInfluence.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + } + return b; + } + + /** + * Initializes the Light's region of influence to the specified Leaf node. + */ + void initInfluencingBoundingLeaf(BoundingLeaf region) { + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + } else { + boundingLeaf = null; + } + } + + /** + * Set the Light's region of influence to the specified Leaf node. + */ + void setInfluencingBoundingLeaf(BoundingLeaf region) { + int i, numLgts; + + numLgts = numMirrorLights; + if (numMirrorLights == 0) + numLgts = 1; + + if (boundingLeaf != null) { + // Remove the mirror lights as users of the original bounding leaf + for (i = 0; i < numLgts; i++) { + boundingLeaf.mirrorBoundingLeaf.removeUser(mirrorLights[i]); + } + } + + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + // Add all mirror lights as user of this bounding leaf + for (i = 0; i < numLgts; i++) { + boundingLeaf.mirrorBoundingLeaf.addUser(mirrorLights[i]); + } + } else { + boundingLeaf = null; + } + + sendMessage(BOUNDINGLEAF_CHANGED, + (boundingLeaf != null ? + boundingLeaf.mirrorBoundingLeaf : null)); + } + + /** + * Get the Light's region of influence. + */ + BoundingLeaf getInfluencingBoundingLeaf() { + return (boundingLeaf != null ? + (BoundingLeaf)boundingLeaf.source : null); + } + + /** + * This sets the immedate mode context flag + */ + void setInImmCtx(boolean inCtx) { + inImmCtx = inCtx; + } + + /** + * This gets the immedate mode context flag + */ + boolean getInImmCtx() { + return (inImmCtx); + } + + + // Called on the parent Light object and loops over the mirror object + void initMirrorObject(Object[] args) { + Shape3DRetained shape; + Object[] scopeInfo = (Object[])((Object[])args[4])[5]; + ArrayList gAtomList = (ArrayList)scopeInfo[1]; + Boolean scoped = (Boolean)scopeInfo[0]; + BoundingLeafRetained bl=(BoundingLeafRetained)((Object[])args[4])[0]; + Bounds bnds = (Bounds)((Object[])args[4])[1]; + int numLgts = ((Integer)args[2]).intValue(); + LightRetained[] mLgts = (LightRetained[]) args[3]; + int k; + + for ( k = 0; k < numLgts; k++) { + for (int i = 0; i < gAtomList.size(); i++) { + shape = ((GeometryAtom)gAtomList.get(i)).source; + shape.addLight(mLgts[k]); + } + mLgts[k].isScoped = scoped.booleanValue(); + } + + for (k = 0; k < numLgts; k++) { + mLgts[k].inBackgroundGroup = ((Boolean)((Object[])args[4])[2]).booleanValue(); + mLgts[k].geometryBackground = (BackgroundRetained)((Object[])args[4])[3]; + + + if (bl != null) { + mLgts[k].boundingLeaf = bl.mirrorBoundingLeaf; + mLgts[k].region = mLgts[k].boundingLeaf.transformedRegion; + } else { + mLgts[k].boundingLeaf = null; + mLgts[k].region = null; + } + + if (bnds != null) { + mLgts[k].regionOfInfluence = bnds; + if (mLgts[k].region == null) { + mLgts[k].region = (Bounds)regionOfInfluence.clone(); + mLgts[k].region.transform(regionOfInfluence, getLastLocalToVworld()); + } + } + else { + mLgts[k].regionOfInfluence = null; + } + mLgts[k].lightOn = ((Boolean)((Object[])args[4])[4]).booleanValue(); + + } + // if its a ambient light,then do a immediate update of color + if (this instanceof AmbientLightRetained) { + Color3f clr = (Color3f) ((Object[])args[4])[6]; + for (int i = 0; i < numLgts; i++) { + mLgts[i].color.set(clr); + } + } + + } + + /** + * This method is implemented by each light for rendering + * context updates. This default one does nothing. + */ + abstract void update(Context ctx, int lightSlot, double scale); + + + // This routine is called when rendering Env structure + // get a message, this routine updates values in the mirror object + // that are not used by the renderer + void updateImmediateMirrorObject(Object[] objs) { + Transform3D trans = null; + int component = ((Integer)objs[1]).intValue(); + int numLgts = ((Integer)objs[2]).intValue(); + LightRetained[] mLgts = (LightRetained[]) objs[3]; + + // Color changed called immediately only for ambient lights + if ((component & COLOR_CHANGED) != 0) { + for (int i = 0; i < numLgts; i++) { + mLgts[i].color.set(((Color3f)objs[4])); + } + } + else if ((component & ENABLE_CHANGED) != 0) { + for (int i = 0; i < numLgts; i++) + mLgts[i].lightOn = ((Boolean)objs[4]).booleanValue(); + } + else if ((component & BOUNDS_CHANGED) != 0) { + for (int i = 0; i < numLgts; i++) { + mLgts[i].regionOfInfluence = (Bounds) objs[4]; + if (mLgts[i].boundingLeaf == null) { + if (objs[4] != null) { + mLgts[i].region = + ((Bounds)mLgts[i].regionOfInfluence).copy(mLgts[i].region); + mLgts[i].region.transform(mLgts[i].regionOfInfluence, + mLgts[i].getCurrentLocalToVworld()); + } + else { + mLgts[i].region = null; + } + } + } + } + else if ((component & BOUNDINGLEAF_CHANGED) != 0) { + for (int i = 0; i < numLgts; i++) { + mLgts[i].boundingLeaf=((BoundingLeafRetained)objs[4]); + if (objs[4] != null) { + mLgts[i].region = (Bounds)mLgts[i].boundingLeaf.transformedRegion; + } + else { // evaluate regionOfInfluence if not null + if (mLgts[i].regionOfInfluence != null) { + mLgts[i].region = + ((Bounds)mLgts[i].regionOfInfluence).copy(mLgts[i].region); + mLgts[i].region.transform(mLgts[i].regionOfInfluence, + mLgts[i].getCurrentLocalToVworld()); + } + else { + mLgts[i].region = null; + } + } + } + } + else if ((component & SCOPE_CHANGED) != 0) { + int nscopes, j, i; + GroupRetained group; + Vector currentScopes; + Object[] scopeList = (Object[])objs[4]; + ArrayList addList = (ArrayList)scopeList[0]; + ArrayList removeList = (ArrayList)scopeList[1]; + boolean isScoped = ((Boolean)scopeList[2]).booleanValue(); + + if (addList != null) { + for (i = 0; i < numLgts; i++) { + mLgts[i].isScoped = isScoped; + for (j = 0; j < addList.size(); j++) { + Shape3DRetained obj = ((GeometryAtom)addList.get(j)).source; + obj.addLight(mLgts[i]); + } + } + } + + if (removeList != null) { + for (i = 0; i < numLgts; i++) { + mLgts[i].isScoped = isScoped; + for (j = 0; j < removeList.size(); j++) { + Shape3DRetained obj = ((GeometryAtom)removeList.get(j)).source; + ((Shape3DRetained)obj).removeLight(mLgts[i]); + } + } + } + } + + + } + + + + // The update Object function called during RenderingEnv objUpdate + // Note : if you add any more fields here , you need to update + // updateLight() in RenderingEnvironmentStructure + void updateMirrorObject(Object[] objs) { + + Transform3D trans = null; + int component = ((Integer)objs[1]).intValue(); + int numLgts = ((Integer)objs[2]).intValue(); + LightRetained[] mLgts = (LightRetained[]) objs[3]; + + if ((component & COLOR_CHANGED) != 0) { + for (int i = 0; i < numLgts; i++) { + mLgts[i].color.set(((Color3f)objs[4])); + } + } + + if ((component & INIT_MIRROR) != 0) { + for (int i = 0; i < numLgts; i++) { + Color3f clr = (Color3f) ((Object[])objs[4])[6]; + mLgts[i].color.set(clr); + } + } + } + + /** Note: This routine will only be called on + * the mirror object - will update the object's + * cached region and transformed region + */ + + void updateBoundingLeaf() { + // This is necessary, if for example, the region + // changes from sphere to box. + if (boundingLeaf != null && boundingLeaf.switchState.currentSwitchOn) { + region = boundingLeaf.transformedRegion; + } else { // evaluate regionOfInfluence if not null + if (regionOfInfluence != null) { + region = regionOfInfluence.copy(region); + region.transform(regionOfInfluence, getCurrentLocalToVworld()); + } else { + region = null; + } + } + } + void getMirrorObjects(ArrayList leafList, HashKey key) { + if (!inSharedGroup) { + leafList.add(mirrorLights[0]); + } + else { + for (int i=0; i 0) { + J3dMessage createMessage = new J3dMessage(); + LightRetained[] mlts = new LightRetained[newlyAddedMirrorLights.size()]; + for (int i = 0; i < mlts.length; i++) { + mlts[i] = (LightRetained)newlyAddedMirrorLights.get(i); + } + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.universe = universe; + createMessage.type = J3dMessage.LIGHT_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(CLEAR_MIRROR); + ArrayList removeScopeList = new ArrayList(); + for (int i = 0; i < scopes.size(); i++) { + GroupRetained group = (GroupRetained)scopes.get(i); + tempKey.reset(); + group.removeAllNodesForScopedLight(mlts.length, mlts, removeScopeList, tempKey); + } + createMessage.args[2] = removeScopeList; + createMessage.args[3] = new Integer(mlts.length); + createMessage.args[4] = mlts; + VirtualUniverse.mc.processMessage(createMessage); + } + } + + void clearMirrorObject(Object[] args) { + Shape3DRetained shape; + ArrayList shapeList = (ArrayList)args[2]; + ArrayList removeScopeList = new ArrayList(); + LightRetained[] mLgts = (LightRetained[]) args[4]; + int numLgts = ((Integer)args[3]).intValue(); + + for (int k = 0; k < numLgts; k++) { + for (int i = 0; i < shapeList.size(); i++) { + shape = ((GeometryAtom)shapeList.get(i)).source; + shape.removeLight(mLgts[k]); + } + mLgts[k].isScoped = false; + + } + + } + + + + /** + * Clones only the retained side, internal use only + */ + protected Object clone() { + LightRetained lr = (LightRetained)super.clone(); + lr.color = new Color3f(color); + lr.scopes = (Vector) scopes.clone(); + lr.initInfluencingBoundingLeaf(getInfluencingBoundingLeaf()); + lr.region = null; + lr.lightDirty = 0xffff; + lr.sgLightDirty = 0xffff; + lr.universe = null; + lr.isNeeded = false; + lr.inImmCtx = false; + lr.sgLight = null; + lr.key = null; + lr.mirrorLights = new LightRetained[1]; + lr.numMirrorLights = 0; + lr.environmentSets = new UnorderList(1, EnvironmentSet.class); + return lr; + } + + + // Called during RenderingEnv object update + void updateTransformChange() { + } + + // Called on mirror object and updated when message is received + void updateImmediateTransformChange() { + // If bounding leaf is null, tranform the bounds object + if (boundingLeaf == null) { + if (regionOfInfluence != null) { + region = regionOfInfluence.copy(region); + region.transform(regionOfInfluence, + getCurrentLocalToVworld()); + } + + } + } + + void sendMessage(int attrMask, Object attr) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.type = J3dMessage.LIGHT_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + if (inSharedGroup) + createMessage.args[2] = new Integer(numMirrorLights); + else + createMessage.args[2] = new Integer(1); + + createMessage.args[3] = mirrorLights.clone(); + createMessage.args[4] = attr; + VirtualUniverse.mc.processMessage(createMessage); + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + if (regionOfInfluence != null) { + regionOfInfluence.transform(xform.transform); + } + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/LightSet.java b/j3d-core/src/classes/share/javax/media/j3d/LightSet.java new file mode 100644 index 0000000..761e708 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LightSet.java @@ -0,0 +1,110 @@ +/* + * $RCSfile: LightSet.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.Vector; + +class LightSet extends Object { + /** + * The Lights that make up this set + */ + LightRetained[] lights = null; + + // The number of lights in this lightset, may be less than lights.length + int nlights = 0; + + // A reference to the next LightSet + LightSet next = null; + + // A reference to the previous LightSet + LightSet prev = null; + + // A flag that indicates that lighting is on + boolean lightingOn = true; + + // A flag that indicates that this light set has changed. + boolean isDirty = true; + + /** + * Constructs a new LightSet + */ + LightSet(RenderBin rb, RenderAtom ra, LightRetained[] lights, + int nlights, boolean lightOn) { + this.reset(rb, ra, lights, nlights, lightOn); + } + + void reset(RenderBin rb, RenderAtom ra, LightRetained[] lights, + int nlights, boolean lightOn) { + int i; + + this.isDirty = true; + this.lightingOn = lightOn; + if (this.lights == null || this.lights.length < nlights) { + this.lights = new LightRetained[nlights]; + } + + for (i=0; inot a multiple of 2 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public LineArray(int vertexCount, int vertexFormat) { + super(vertexCount,vertexFormat); + + if (vertexCount < 2 || ((vertexCount%2) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("LineArray0")); + } + + /** + * Constructs an empty LineArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 2 + * or vertexCount is not a multiple of 2 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public LineArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap); + + if (vertexCount < 2 || ((vertexCount%2) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("LineArray0")); + } + + /** + * Constructs an empty LineArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 2 + * or vertexCount is not a multiple of 3 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public LineArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + + if (vertexCount < 2 || ((vertexCount%2) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("LineArray0")); + } + + /** + * Creates the retained mode LineArrayRetained object that this + * LineArray object will point to. + */ + void createRetained() { + this.retained = new LineArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + LineArrayRetained rt = (LineArrayRetained) retained; + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + LineArray l = new LineArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes); + l.duplicateNodeComponent(this); + return l; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LineArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/LineArrayRetained.java new file mode 100644 index 0000000..5fec6d6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LineArrayRetained.java @@ -0,0 +1,455 @@ +/* + * $RCSfile: LineArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The LineArray object draws the array of vertices as individual + * line segments. Each pair of vertices defines a line to be drawn. + */ + +class LineArrayRetained extends GeometryArrayRetained implements Cloneable { + + LineArrayRetained() { + this.geoType = GEO_TYPE_LINE_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[2]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int[] vtxIndexArr = new int[2]; + + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<2; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectLineAndRay(pnts[0], pnts[1], pickRay.origin, + pickRay.direction, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + Vector3d dir = + new Vector3d(pickSegment.end.x - pickSegment.start.x, + pickSegment.end.y - pickSegment.start.y, + pickSegment.end.z - pickSegment.start.z); + + while (i < validVertexCount) { + for(int j=0; j<2; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectLineAndRay(pnts[0], pnts[1], + pickSegment.start, + dir, sdist, iPnt) && + (sdist[0] <= 1.0)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + while (i < validVertexCount) { + for(int j=0; j<2; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + for(int j=0; j<2; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + for(int j=0; j<2; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingPolytope(pnts, bpolytope, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<2; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<2; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("LineArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + + } + + boolean intersect(Point3d[] pnts) { + Point3d[] points = new Point3d[2]; + double dist[] = new double[1]; + Vector3d dir; + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + points[0] = new Point3d(); + points[1] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle + case 4: // Quad + while (i + *

  • Pattern - specifies the pattern used to draw the line:

    + *

      + *
    • PATTERN_SOLID - draws a solid line with no pattern. This is + * the default.
    • + *

      + *

    • PATTERN_DASH - draws dashed lines. Ideally, these will be drawn with + * a repeating pattern of 8 pixels on and 8 pixels off.
    • + *

      + *

    • PATTERN_DOT - draws dotted lines. Ideally, these will be drawn with + * a repeating pattern of 1 pixel on and 7 pixels off.
    • + *

      + *

    • PATTERN_DASH_DOT - draws dashed-dotted lines. Ideally, these will be + * drawn with a repeating pattern of 7 pixels on, 4 pixels off, 1 pixel on, + * and 4 pixels off.
    • + *

      + *

    • PATTERN_USER_DEFINED - draws lines with a user-defined line pattern. + * See "User-defined Line Patterns," below.
    • + *

    + *

    + *

  • Antialiasing (enabled or disabled). By default, antialiasing + * is disabled.
  • + *

    + *

    + * If antialiasing is enabled, the lines are considered transparent + * for rendering purposes. They are rendered with all the other transparent + * objects and adhere to the other transparency settings such as the + * View transparency sorting policy and the View depth buffer freeze + * transparent enable. + *

    + *
  • Width (in pixels). The default is a line width of one pixel. + *

+ * + * User-defined Line Patterns + *

+ * A user-defined line pattern is specified with a pattern mask and + * an optional scale factor. + *

+ * The Pattern Mask

+ * + * The pattern is specified + * using a 16-bit mask that specifies on and off segments. Bit 0 in + * the pattern mask corresponds to the first pixel of the line or line + * strip primitive. A value of 1 for a bit in the pattern mask indicates + * that the corresponding pixel is drawn, while a value of 0 + * indicates that the corresponding pixel is not drawn. After all 16 bits + * in the pattern are used, the pattern is repeated. + *

+ * For example, a mask of 0x00ff defines a dashed line with a repeating + * pattern of 8 pixels on followed by 8 pixels off. A value of 0x0101 + * defines a a dotted line with a repeating pattern of 1 pixel on and 7 + * pixels off. + *

+ * The pattern continues around individual line segments of a line strip + * primitive. It is restarted at the beginning of each new line strip. + * For line array primitives, the pattern is restarted at the beginning + * of each line. + *

+ * The Scale Factor + *

+ * The pattern is multiplied by the scale factor such that each bit in + * the pattern mask corresponds to that many consecutive pixels. + * For example, a scale factor of 3 applied to a pattern mask of 0x001f + * would produce a repeating pattern of 15 pixels on followed by 33 + * pixels off. The valid range for this attribute is [1,15]. Values + * outside this range are clamped.

+ * + * @see Appearance + * @see View + */ +public class LineAttributes extends NodeComponent { + + /** + * Specifies that this LineAttributes object allows reading its + * line width information. + */ + public static final int + ALLOW_WIDTH_READ = CapabilityBits.LINE_ATTRIBUTES_ALLOW_WIDTH_READ; + + /** + * Specifies that this LineAttributes object allows writing its + * line width information. + */ + public static final int + ALLOW_WIDTH_WRITE = CapabilityBits.LINE_ATTRIBUTES_ALLOW_WIDTH_WRITE; + + /** + * Specifies that this LineAttributes object allows reading its + * line pattern information. + */ + public static final int + ALLOW_PATTERN_READ = CapabilityBits.LINE_ATTRIBUTES_ALLOW_PATTERN_READ; + + /** + * Specifies that this LineAttributes object allows writing its + * line pattern information. + */ + public static final int + ALLOW_PATTERN_WRITE = CapabilityBits.LINE_ATTRIBUTES_ALLOW_PATTERN_WRITE; + + /** + * Specifies that this LineAttributes object allows reading its + * line antialiasing flag. + */ + public static final int + ALLOW_ANTIALIASING_READ = CapabilityBits.LINE_ATTRIBUTES_ALLOW_ANTIALIASING_READ; + + /** + * Specifies that this LineAttributes object allows writing its + * line antialiasing flag. + */ + public static final int + ALLOW_ANTIALIASING_WRITE = CapabilityBits.LINE_ATTRIBUTES_ALLOW_ANTIALIASING_WRITE; + + + /** + * Draw solid lines with no pattern. + * @see #setLinePattern + */ + public static final int PATTERN_SOLID = 0; + + /** + * Draw dashed lines. Ideally, these will be drawn with + * a repeating pattern of 8 pixels on and 8 pixels off. + * @see #setLinePattern + */ + public static final int PATTERN_DASH = 1; + + /** + * Draw dotted lines. Ideally, these will be drawn with + * a repeating pattern of 1 pixel on and 7 pixels off. + * @see #setLinePattern + */ + public static final int PATTERN_DOT = 2; + + /** + * Draw dashed-dotted lines. Ideally, these will be drawn with + * a repeating pattern of 7 pixels on, 4 pixels off, 1 pixel on, + * and 4 pixels off. + * @see #setLinePattern + */ + public static final int PATTERN_DASH_DOT = 3; + + /** + * Draw lines with a user-defined line pattern. The line pattern + * is specified with a pattern mask and scale factor. + * @see #setLinePattern + * @see #setPatternMask + * @see #setPatternScaleFactor + * + * @since Java 3D 1.2 + */ + public static final int PATTERN_USER_DEFINED = 4; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_ANTIALIASING_READ, + ALLOW_PATTERN_READ, + ALLOW_WIDTH_READ + }; + + /** + * Constructs a LineAttributes object with default parameters. + * The default values are as follows: + *

    + * line width : 1
    + * line pattern : PATTERN_SOLID
    + * pattern mask : 0xffff
    + * pattern scale factor : 1
    + * line antialiasing : false
    + *
+ */ + public LineAttributes(){ + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a LineAttributes object with specified values. + * @param lineWidth the width of lines in pixels + * @param linePattern the line pattern, one of PATTERN_SOLID, + * PATTERN_DASH, PATTERN_DOT, or PATTERN_DASH_DOT + * @param lineAntialiasing flag to set line antialising ON or OFF + */ + public LineAttributes(float lineWidth, int linePattern, + boolean lineAntialiasing){ + + if (linePattern < PATTERN_SOLID || linePattern > PATTERN_DASH_DOT) + throw new IllegalArgumentException(J3dI18N.getString("LineAttributes0")); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((LineAttributesRetained)this.retained).initLineWidth(lineWidth); + ((LineAttributesRetained)this.retained).initLinePattern(linePattern); + ((LineAttributesRetained)this.retained).initLineAntialiasingEnable(lineAntialiasing); + } + + /** + * Sets the line width for this LineAttributes component object. + * @param lineWidth the width, in pixels, of line primitives + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setLineWidth(float lineWidth) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_WIDTH_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes1")); + if (isLive()) + ((LineAttributesRetained)this.retained).setLineWidth(lineWidth); + else + ((LineAttributesRetained)this.retained).initLineWidth(lineWidth); + + } + + /** + * Gets the line width for this LineAttributes component object. + * @return the width, in pixels, of line primitives + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getLineWidth() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_WIDTH_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes2")); + return ((LineAttributesRetained)this.retained).getLineWidth(); + } + + /** + * Sets the line pattern for this LineAttributes component object. + * @param linePattern the line pattern to be used, one of: + * PATTERN_SOLID, PATTERN_DASH, PATTERN_DOT, PATTERN_DASH_DOT, or + * PATTERN_USER_DEFINED. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setLinePattern(int linePattern) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PATTERN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes3")); + + if (linePattern < PATTERN_SOLID || linePattern > PATTERN_USER_DEFINED) + throw new IllegalArgumentException(J3dI18N.getString("LineAttributes4")); + + if (isLive()) + ((LineAttributesRetained)this.retained).setLinePattern(linePattern); + else + ((LineAttributesRetained)this.retained).initLinePattern(linePattern); + + +} + + /** + * Gets the line pattern for this LineAttributes component object. + * @return the line pattern + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getLinePattern() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PATTERN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes5")); + + return ((LineAttributesRetained)this.retained).getLinePattern(); + } + + + /** + * Sets the line pattern mask to the specified value. This is + * used when the linePattern attribute is set to + * PATTERN_USER_DEFINED. In this mode, the pattern is specified + * using a 16-bit mask that specifies on and off segments. Bit 0 + * in the pattern mask corresponds to the first pixel of the line + * or line strip primitive. A value of 1 for a bit in the pattern + * mask indicates that the corresponding pixel is drawn, while a + * value of 0 indicates that the corresponding pixel is not drawn. + * After all 16 bits in the pattern are used, the pattern is + * repeated. For example, a mask of 0x00ff defines a dashed line + * with a repeating pattern of 8 pixels on followed by 8 pixels + * off. A value of 0x0101 defines a a dotted line with a + * repeating pattern of 1 pixel on and 7 pixels off + *

+ * The pattern continues around individual line segments of a line + * strip primitive. It is restarted at the beginning of each new + * line strip. For line array primitives, the pattern is + * restarted at the beginning of each line. + * @param mask the new line pattern mask + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @see #setPatternScaleFactor + * + * @since Java 3D 1.2 + */ + public void setPatternMask(int mask) { + if (isLiveOrCompiled() && + !this.getCapability(ALLOW_PATTERN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes8")); + + if (isLive()) + ((LineAttributesRetained)this.retained).setPatternMask(mask); + else + ((LineAttributesRetained)this.retained).initPatternMask(mask); + } + + + /** + * Retrieves the line pattern mask. + * @return the line pattern mask + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getPatternMask() { + if (isLiveOrCompiled() && + !this.getCapability(ALLOW_PATTERN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes9")); + + return ((LineAttributesRetained)this.retained).getPatternMask(); + } + + + /** + * Sets the line pattern scale factor to the specified value. + * This is used in conjunction with the patternMask when the + * linePattern attribute is set to PATTERN_USER_DEFINED. The + * pattern is multiplied by the scale factor such that each bit in + * the pattern mask corresponds to that many consecutive pixels. + * For example, a scale factor of 3 applied to a pattern mask of + * 0x001f would produce a repeating pattern of 15 pixels on + * followed by 33 pixels off. The valid range for this attribute + * is [1,15]. Values outside this range are clamped. + * @param scaleFactor the new line pattern scale factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @see #setPatternMask + * + * @since Java 3D 1.2 + */ + public void setPatternScaleFactor(int scaleFactor) { + if (isLiveOrCompiled() && + !this.getCapability(ALLOW_PATTERN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes10")); + + if (isLive()) + ((LineAttributesRetained)this.retained).setPatternScaleFactor(scaleFactor); + else + ((LineAttributesRetained)this.retained).initPatternScaleFactor(scaleFactor); + } + + + /** + * Retrieves the line pattern scale factor. + * @return the line pattern scale factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getPatternScaleFactor() { + if (isLiveOrCompiled() && + !this.getCapability(ALLOW_PATTERN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes11")); + + return ((LineAttributesRetained)this.retained).getPatternScaleFactor(); + } + + + /** + * Enables or disables line antialiasing + * for this LineAttributes component object. + *

+ * If antialiasing is enabled, the lines are considered transparent + * for rendering purposes. They are rendered with all the other + * transparent objects and adhere to the other transparency settings + * such as the View transparency sorting policy and the View depth buffer + * freeze transparent enable. + *

+ * @param state true or false to enable or disable line antialiasing + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @see View + */ + public void setLineAntialiasingEnable(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANTIALIASING_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes6")); + if (isLive()) + ((LineAttributesRetained)this.retained).setLineAntialiasingEnable(state); + else + ((LineAttributesRetained)this.retained).initLineAntialiasingEnable(state); + + + } + + /** + * Retrieves the state of the line antialiasing flag. + * @return true if line antialiasing is enabled, + * false if line antialiasing is disabled + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getLineAntialiasingEnable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANTIALIASING_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("LineAttributes7")); + + return ((LineAttributesRetained)this.retained).getLineAntialiasingEnable(); + } + + /** + * Creates a retained mode LineAttributesRetained object that this + * LineAttributes component object will point to. + */ + void createRetained() { + this.retained = new LineAttributesRetained(); + this.retained.setSource(this); + } + + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + LineAttributes la = new LineAttributes(); + la.duplicateNodeComponent(this); + return la; + } + + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, + forceDuplicate); + + LineAttributesRetained attr = (LineAttributesRetained) + originalNodeComponent.retained; + LineAttributesRetained rt = (LineAttributesRetained) retained; + + rt.initLineWidth(attr.getLineWidth()); + rt.initLinePattern(attr.getLinePattern()); + rt.initLineAntialiasingEnable(attr.getLineAntialiasingEnable()); + rt.initPatternMask(attr.getPatternMask()); + rt.initPatternScaleFactor(attr.getPatternScaleFactor()); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LineAttributesRetained.java b/j3d-core/src/classes/share/javax/media/j3d/LineAttributesRetained.java new file mode 100644 index 0000000..dac3c42 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LineAttributesRetained.java @@ -0,0 +1,345 @@ +/* + * $RCSfile: LineAttributesRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * The LineAttributesRetained object defines all rendering state that can be set + * as a component object of a Shape3D node. + */ +class LineAttributesRetained extends NodeComponentRetained { + // A list of pre-defined bits to indicate which component + // in this LineAttributesRetained object changed. + static final int LINE_WIDTH_CHANGED = 0x01; + static final int LINE_PATTERN_CHANGED = 0x02; + static final int LINE_AA_CHANGED = 0x04; + static final int LINE_PATTERN_MASK_CHANGED = 0x08; + static final int LINE_PATTERN_SCALEFACTOR_CHANGED = 0x10; + + // Width, in pixels, of line primitives + float lineWidth = 1.0f; + + // The line pattern to be used + int linePattern = LineAttributes.PATTERN_SOLID; + + // Line antialiasing switch + boolean lineAntialiasing = false; + + // user-defined line pattern mask + int linePatternMask = 0xffff; + + // line mask pattern scale factor + int linePatternScaleFactor = 1; + + /** + * Sets the line width for this lineAttributes component object. + * @param lineWidth the width, in pixels, of line primitives + */ + final void initLineWidth(float lineWidth) { + this.lineWidth = lineWidth; + } + + /** + * Sets the line width for this lineAttributes component object and sends a + * message notifying the interested structures of the change. + * @param lineWidth the width, in pixels, of line primitives + */ + final void setLineWidth(float lineWidth) { + initLineWidth(lineWidth); + sendMessage(LINE_WIDTH_CHANGED, new Float(lineWidth)); + } + + /** + * Gets the line width for this lineAttributes component object. + * @return the width, in pixels, of line primitives + */ + final float getLineWidth() { + return lineWidth; + } + + /** + * Sets the line pattern for this lineAttributes component object + * @param linePattern the line pattern to be used, one of: + * PATTERN_SOLID, PATTERN_DASH, PATTERN_DOT, or PATTERN_DASH_DOT + */ + final void initLinePattern(int linePattern) { + this.linePattern = linePattern; + } + /** + * Sets the line pattern for this lineAttributes component object + * and sends a message notifying the interested structures of the change. + * @param linePattern the line pattern to be used, one of: + * PATTERN_SOLID, PATTERN_DASH, PATTERN_DOT, or PATTERN_DASH_DOT + */ + final void setLinePattern(int linePattern) { + initLinePattern(linePattern); + sendMessage(LINE_PATTERN_CHANGED, new Integer(linePattern)); + } + + /** + * Gets the line pattern for this lineAttributes component object. + * @return the line pattern + */ + final int getLinePattern() { + return linePattern; + } + + /** + * Enables or disables line antialiasing + * for this lineAttributes component object and sends a + * message notifying the interested structures of the change. + * @param state true or false to enable or disable line antialiasing + */ + final void initLineAntialiasingEnable(boolean state) { + lineAntialiasing = state; + } + /** + * Enables or disables line antialiasing + * for this lineAttributes component object and sends a + * message notifying the interested structures of the change. + * @param state true or false to enable or disable line antialiasing + */ + final void setLineAntialiasingEnable(boolean state) { + initLineAntialiasingEnable(state); + sendMessage(LINE_AA_CHANGED, + (state ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Retrieves the state of the line antialiasing flag. + * @return true if line antialiasing is enabled, + * false if line antialiasing is disabled + */ + final boolean getLineAntialiasingEnable() { + return lineAntialiasing; + } + + + /** + * Sets the pattern mask for this LineAttributes component object. + * This is used when the linePattern attribute is set to + * PATTERN_USER_DEFINED. + * @param mask the line pattern mask to be used. + */ + final void initPatternMask(int mask) { + this.linePatternMask = mask; + } + + /** + * Sets the pattern mask for this LineAttributes component object + * and sends a message notifying the interested structures of change. + * This is used when the linePattern attribute is set to + * PATTERN_USER_DEFINED. + * @param mask the line pattern mask to be used. + */ + final void setPatternMask(int mask) { + initPatternMask(mask); + sendMessage(LINE_PATTERN_MASK_CHANGED, new Integer(mask)); + } + + /** + * Retrieves the pattern mask for this LineAttributes component object. + * @return the user-defined pattern mask + */ + final int getPatternMask() { + return linePatternMask; + } + + /** + * Sets the pattern mask scale factor for this LineAttributes + * component object. This is used when the linePattern attribute + * is set to PATTERN_USER_DEFINED. + * @param scaleFactor the scale factor of mask, clamp to [1, 15] + */ + final void initPatternScaleFactor(int scaleFactor) { + if (scaleFactor < 1) { + scaleFactor = 1; + } else if (scaleFactor > 15) { + scaleFactor = 15; + } + this.linePatternScaleFactor = scaleFactor; + } + + /** + * Sets the pattern mask scale factor for this LineAttributes + * component object and sends a message notifying the interested + * structures of change. This is used when the linePattern + * attribute is set to PATTERN_USER_DEFINED. + * @param scaleFactor the scale factor of mask, clamp to [1, 15] + */ + final void setPatternScaleFactor(int scaleFactor) { + initPatternScaleFactor(scaleFactor); + sendMessage(LINE_PATTERN_SCALEFACTOR_CHANGED, new Integer(scaleFactor)); + } + + /** + * Retrieves the pattern scale factor for this LineAttributes + * component object. + * @return the pattern mask scale factor + */ + final int getPatternScaleFactor() { + return linePatternScaleFactor; + } + + /** + * Creates and initializes a mirror object, point the mirror object + * to the retained object if the object is not editable + */ + synchronized void createMirrorObject() { + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror = this; + } else { + LineAttributesRetained mirrorLa = new LineAttributesRetained(); + mirrorLa.source = source; + mirrorLa.set(this); + mirror = mirrorLa; + } + } else { + ((LineAttributesRetained) mirror).set(this); + } + } + + + /** + * This method updates the native context. + */ + void updateNative(Context ctx) { + Pipeline.getPipeline().updateLineAttributes(ctx, + lineWidth, linePattern, linePatternMask, + linePatternScaleFactor, lineAntialiasing); + } + + + /** + * Initializes a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + ((LineAttributesRetained)mirror).set(this); + } + + /** Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + LineAttributesRetained mirrorLa = (LineAttributesRetained) mirror; + + if ((component & LINE_WIDTH_CHANGED) != 0) { + mirrorLa.lineWidth = ((Float)value).floatValue(); + } + else if ((component & LINE_PATTERN_CHANGED) != 0) { + mirrorLa.linePattern = ((Integer)value).intValue(); + } + else if ((component & LINE_AA_CHANGED) != 0) { + mirrorLa.lineAntialiasing = ((Boolean)value).booleanValue(); + } + else if ((component & LINE_PATTERN_MASK_CHANGED) != 0) { + mirrorLa.linePatternMask = ((Integer)value).intValue(); + } + else if ((component & LINE_PATTERN_SCALEFACTOR_CHANGED) != 0) + { + mirrorLa.linePatternScaleFactor = ((Integer)value).intValue(); + } + } + + + boolean equivalent(LineAttributesRetained lr) { + return ((lr != null) && + (lineWidth == lr.lineWidth) && + (linePattern == lr.linePattern) && + (lineAntialiasing == lr.lineAntialiasing) && + (linePatternMask == lr.linePatternMask) && + (linePatternScaleFactor == lr.linePatternScaleFactor)); + + } + + protected void set(LineAttributesRetained lr) { + super.set(lr); + lineWidth = lr.lineWidth; + linePattern = lr.linePattern; + linePatternScaleFactor = lr.linePatternScaleFactor; + linePatternMask = lr.linePatternMask; + lineAntialiasing = lr.lineAntialiasing; + } + + final void sendMessage(int attrMask, Object attr) { + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.LINEATTRIBUTES_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i + * See {@link GeometryStripArray#GeometryStripArray(int,int,int[])} + * for more exceptions that can be thrown + */ + public LineStripArray(int vertexCount, + int vertexFormat, + int stripVertexCounts[]) { + + super(vertexCount, vertexFormat, stripVertexCounts); + + if (vertexCount < 2 ) + throw new IllegalArgumentException(J3dI18N.getString("LineStripArray0")); + } + + /** + * Constructs an empty LineStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param stripVertexCounts + * see {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 2 + * or any element in the stripVertexCounts array is less than 2 + * ;
+ * See {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public LineStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int stripVertexCounts[]) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + stripVertexCounts); + + if (vertexCount < 2 ) + throw new IllegalArgumentException(J3dI18N.getString("LineStripArray0")); + } + + /** + * Constructs an empty LineStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param stripVertexCounts + * see {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int,int[],int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 2 + * or any element in the stripVertexCounts array is less than 2 + * ;
+ * See {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int,int[],int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public LineStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int[] stripVertexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + stripVertexCounts); + + if (vertexCount < 2 ) + throw new IllegalArgumentException(J3dI18N.getString("LineStripArray0")); + } + + /** + * Creates the retained mode LineStripArrayRetained object that this + * LineStripArray object will point to. + */ + void createRetained() { + this.retained = new LineStripArrayRetained(); + this.retained.setSource(this); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + LineStripArrayRetained rt = (LineStripArrayRetained) retained; + int stripcounts[] = new int[rt.getNumStrips()]; + rt.getStripVertexCounts(stripcounts); + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + LineStripArray l = new LineStripArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + stripcounts); + l.duplicateNodeComponent(this); + return l; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LineStripArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/LineStripArrayRetained.java new file mode 100644 index 0000000..81de3b9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LineStripArrayRetained.java @@ -0,0 +1,555 @@ +/* + * $RCSfile: LineStripArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The LineStripArray object draws an array of vertices as a set of + * connected line strips. An array of per-strip vertex counts specifies + * where the separate strips appear in the vertex array. + * For every strip in the set, each vertex, beginning with + * the second vertex in the array, defines a line segment to be drawn + * from the previous vertex to the current vertex. + */ + +class LineStripArrayRetained extends GeometryStripArrayRetained { + + LineStripArrayRetained() { + this.geoType = GEO_TYPE_LINE_STRIP_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[2]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int j, end; + int i = 0; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + int[] vtxIndexArr = new int[2]; + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while(i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + vtxIndexArr[0] = j; + getVertexData(j++, pnts[0]); + while (j < end) { + vtxIndexArr[1] = j; + getVertexData(j++, pnts[1]); + if (intersectLineAndRay(pnts[0], pnts[1], pickRay.origin, + pickRay.direction, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + Vector3d dir = + new Vector3d(pickSegment.end.x - pickSegment.start.x, + pickSegment.end.y - pickSegment.start.y, + pickSegment.end.z - pickSegment.start.z); + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + vtxIndexArr[0] = j; + getVertexData(j++, pnts[0]); + while (j < end) { + vtxIndexArr[1] = j; + getVertexData(j++, pnts[1]); + if (intersectLineAndRay(pnts[0], pnts[1], + pickSegment.start, + dir, sdist, iPnt) && + (sdist[0] <= 1.0)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + vtxIndexArr[0] = j; + getVertexData(j++, pnts[0]); + while (j < end) { + vtxIndexArr[1] = j; + getVertexData(j++, pnts[1]); + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + vtxIndexArr[0] = j; + getVertexData(j++, pnts[0]); + while (j < end) { + vtxIndexArr[1] = j; + getVertexData(j++, pnts[1]); + if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + vtxIndexArr[0] = j; + getVertexData(j++, pnts[0]); + while (j < end) { + vtxIndexArr[1] = j; + getVertexData(j++, pnts[1]); + if (intersectBoundingPolytope(pnts, bpolytope, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + vtxIndexArr[0] = j; + getVertexData(j++, pnts[0]); + while (j < end) { + vtxIndexArr[1] = j; + getVertexData(j++, pnts[1]); + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + vtxIndexArr[0] = j; + getVertexData(j++, pnts[0]); + while (j < end) { + vtxIndexArr[1] = j; + getVertexData(j++, pnts[1]); + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("LineStripArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + boolean intersect(Point3d[] pnts) { + int j, end; + Point3d[] points = new Point3d[2]; + double dist[] = new double[1]; + Vector3d dir; + int i = 0; + + points[0] = new Point3d(); + points[1] = new Point3d(); + + + + switch (pnts.length) { + case 3: + case 4: // Triangle, Quad + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + while (j < end) { + getVertexData(j++, points[1]); + if (intersectSegment(pnts, points[0], points[1], + dist, null)) { + return true; + } + points[0].set(points[1]); + } + } + break; + case 2: // Line + dir = new Vector3d(); + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + while (j < end) { + getVertexData(j++, points[1]); + dir.x = points[1].x - points[0].x; + dir.y = points[1].y - points[0].y; + dir.z = points[1].z - points[0].z; + if (intersectLineAndRay(pnts[0], pnts[1], + points[0], dir, dist, null) && + (dist[0] <= 1.0)) { + return true; + } + points[0].set(points[1]); + } + } + break; + case 1: // Point + dir = new Vector3d(); + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + while (j < end) { + getVertexData(j++, points[1]); + dir.x = points[1].x - points[0].x; + dir.y = points[1].y - points[0].y; + dir.z = points[1].z - points[0].z; + if (intersectPntAndRay(pnts[0], points[0], dir, + dist) && + (dist[0] <= 1.0)) { + return true; + } + points[0].set(points[1]); + } + } + break; + } + return false; + } + + boolean intersect(Transform3D thisToOtherVworld, + GeometryRetained geom) { + int i = 0; + int j, end; + Point3d[] pnts = new Point3d[2]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + thisToOtherVworld.transform(pnts[0]); + while (j < end) { + getVertexData(j++, pnts[1]); + thisToOtherVworld.transform(pnts[1]); + if (geom.intersect(pnts)) { + return true; + } + pnts[0].set(pnts[1]); + } + } + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + int i = 0; + int j, offset, end; + Point3d[] pnts = new Point3d[2]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + + + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + while ( j < end) { + getVertexData(j++, pnts[1]); + if (intersectBoundingBox(pnts, box, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + while ( j < end) { + getVertexData(j++, pnts[1]); + if (intersectBoundingSphere(pnts, bsphere, null, + null)) { + return true; + } + pnts[0].set(pnts[1]); + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + while ( j < end) { + getVertexData(j++, pnts[1]); + if (intersectBoundingPolytope(pnts, bpolytope, + null, null)) { + return true; + } + pnts[0].set(pnts[1]); + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + + return false; + } + + // From Graphics Gems IV (pg5) and Graphics Gems II, Pg170 + void computeCentroid() { + int i = 0; + int j; + double length; + double totallength = 0; + int start, end; + boolean replaceVertex1; + Point3d pnt0 = new Point3d(); + Point3d pnt1 = new Point3d(); + + centroid.x = 0; + centroid.y = 0; + centroid.z = 0; + + + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnt0); + replaceVertex1 = true; + while (j < end) { + if (replaceVertex1) { + getVertexData(j++, pnt1); + replaceVertex1 = false; + } else { + getVertexData(j++, pnt0); + replaceVertex1 = true; + } + length = pnt0.distance(pnt1); + centroid.x += (pnt0.x + pnt1.x) * length; + centroid.y += (pnt0.y + pnt1.y) * length; + centroid.z += (pnt0.z + pnt1.z) * length; + totallength += length; + } + } + if (totallength != 0.0) { + length = 1.0/(2.0 * totallength); + centroid.x *= length; + centroid.y *= length; + centroid.z *= length; + } + } + + int getClassType() { + return LINE_TYPE; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LinearFog.java b/j3d-core/src/classes/share/javax/media/j3d/LinearFog.java new file mode 100644 index 0000000..bfa9733 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LinearFog.java @@ -0,0 +1,274 @@ +/* + * $RCSfile: LinearFog.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; + +/** + * The LinearFog leaf node defines fog distance parameters for + * linear fog. + * LinearFog extends the Fog node by adding a pair of distance values, + * in Z, at which the fog should start obscuring the scene and should maximally + * obscure the scene. + *

+ * The front and back fog distances are defined in the local coordinate system of + * the node, but the actual fog equation will ideally take place in eye + * coordinates. + *

+ * The linear fog blending factor, f, is computed as follows: + *

    + * f = (backDistance - z) / (backDistance - frontDistance) + *
+ * where: + *
    + * z is the distance from the viewpoint.
    + * frontDistance is the distance at which fog starts obscuring objects.
    + * backDistance is the distance at which fog totally obscurs objects. + *
+ */ +public class LinearFog extends Fog { + /** + * Specifies that this LinearFog node allows read access to its distance + * information. + */ + public static final int + ALLOW_DISTANCE_READ = CapabilityBits.LINEAR_FOG_ALLOW_DISTANCE_READ; + + /** + * Specifies that this LinearFog node allows write access to its distance + * information. + */ + public static final int + ALLOW_DISTANCE_WRITE = CapabilityBits.LINEAR_FOG_ALLOW_DISTANCE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_DISTANCE_READ + }; + + /** + * Constructs a LinearFog node with default parameters. + * The default values are as follows: + *
    + * front distance : 0.1
    + * back distance : 1.0
    + *
+ */ + public LinearFog() { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a LinearFog node with the specified fog color. + * @param color the fog color + */ + public LinearFog(Color3f color) { + super(color); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a LinearFog node with the specified fog color and distances. + * @param color the fog color + * @param frontDistance the front distance for the fog + * @param backDistance the back distance for the fog + */ + public LinearFog(Color3f color, double frontDistance, double backDistance) { + super(color); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((LinearFogRetained)this.retained).initFrontDistance(frontDistance); + ((LinearFogRetained)this.retained).initBackDistance(backDistance); + } + + /** + * Constructs a LinearFog node with the specified fog color. + * @param r the red component of the fog color + * @param g the green component of the fog color + * @param b the blue component of the fog color + */ + public LinearFog(float r, float g, float b) { + super(r, g, b); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a LinearFog node with the specified fog color and distances. + * @param r the red component of the fog color + * @param g the green component of the fog color + * @param b the blue component of the fog color + * @param frontDistance the front distance for the fog + * @param backDistance the back distance for the fog + */ + public LinearFog(float r, float g, float b, + double frontDistance, double backDistance) { + super(r, g, b); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((LinearFogRetained)this.retained).initFrontDistance(frontDistance); + ((LinearFogRetained)this.retained).initBackDistance(backDistance); + } + + /** + * Sets front distance for fog. + * @param frontDistance the distance at which fog starts obscuring objects + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setFrontDistance(double frontDistance) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("LinearFog0")); + + if (isLive()) + ((LinearFogRetained)this.retained).setFrontDistance(frontDistance); + else + ((LinearFogRetained)this.retained).initFrontDistance(frontDistance); + + } + + /** + * Gets front distance for fog. + * @return the distance at which fog starts obscuring objects + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public double getFrontDistance() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("LinearFog1")); + + return ((LinearFogRetained)this.retained).getFrontDistance(); + } + + /** + * Sets back distance for fog. + * @param backDistance the distance at which fog totally obscurs objects + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setBackDistance(double backDistance) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("LinearFog0")); + if (isLive()) + ((LinearFogRetained)this.retained).setBackDistance(backDistance); + else + ((LinearFogRetained)this.retained).initBackDistance(backDistance); + + } + + /** + * Gets back distance for fog. + * @return the distance at which fog totally obscurs objects + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public double getBackDistance() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("LinearFog1")); + + return ((LinearFogRetained)this.retained).getBackDistance(); + } + + /** + * Creates the retained mode LinearFogRetained object that this + * LinearFog node will point to. + */ + void createRetained() { + this.retained = new LinearFogRetained(); + this.retained.setSource(this); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + LinearFog lf = new LinearFog(); + lf.duplicateNode(this, forceDuplicate); + return lf; + } + + + /** + * Copies all LinearFog information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + LinearFogRetained attr = (LinearFogRetained) originalNode.retained; + LinearFogRetained rt = (LinearFogRetained) retained; + + rt.initFrontDistance(attr.getFrontDistance()); + rt.initBackDistance(attr.getBackDistance()); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LinearFogRetained.java b/j3d-core/src/classes/share/javax/media/j3d/LinearFogRetained.java new file mode 100644 index 0000000..ed88f49 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LinearFogRetained.java @@ -0,0 +1,204 @@ +/* + * $RCSfile: LinearFogRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; +import javax.vecmath.*; +import java.util.ArrayList; + +/** + * The LinearFog leaf node defines distance parameters for + * linear fog. + */ +class LinearFogRetained extends FogRetained { + /** + * Fog front and back distance + */ + private double frontDistance = 0.1; + private double backDistance = 1.0; + private double frontDistanceInEc; + private double backDistanceInEc; + + // dirty bits for LinearFog + static final int FRONT_DISTANCE_CHANGED = FogRetained.LAST_DEFINED_BIT << 1; + static final int BACK_DISTANCE_CHANGED = FogRetained.LAST_DEFINED_BIT << 2; + + LinearFogRetained() { + this.nodeType = NodeRetained.LINEARFOG; + } + + /** + * Initializes front distance for fog before the object is live + */ + void initFrontDistance(double frontDistance){ + this.frontDistance = frontDistance; + } + + /** + * Sets front distance for fog and sends a message + */ + void setFrontDistance(double frontDistance){ + this.frontDistance = frontDistance; + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.type = J3dMessage.FOG_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(FRONT_DISTANCE_CHANGED); + createMessage.args[2] = new Double(frontDistance); + VirtualUniverse.mc.processMessage(createMessage); + + } + + /** + * Gets front distance for fog + */ + double getFrontDistance(){ + return this.frontDistance; + } + + /** + * Initializes back distance for fog + */ + void initBackDistance(double backDistance){ + this.backDistance = backDistance; + } + /** + * Sets back distance for fog + */ + void setBackDistance(double backDistance){ + this.backDistance = backDistance; + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.type = J3dMessage.FOG_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(BACK_DISTANCE_CHANGED); + createMessage.args[2] = new Double(backDistance); + VirtualUniverse.mc.processMessage(createMessage); + } + + /** + * Gets back distance for fog + */ + double getBackDistance(){ + return this.backDistance; + } + /** + * This method and its native counterpart update the native context + * fog values. + */ + void update(Context ctx, double scale) { + validateDistancesInEc(scale); + Pipeline.getPipeline().updateLinearFog(ctx, + color.x, color.y, color.z, frontDistanceInEc, backDistanceInEc); + } + + + + void setLive(SetLiveState s) { + GroupRetained group; + + super.setLive(s); + + // Initialize the mirror object, this needs to be done, when + // renderBin is not accessing any of the fields + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.universe = universe; + createMessage.type = J3dMessage.FOG_CHANGED; + createMessage.args[0] = this; + // a snapshot of all attributes that needs to be initialized + // in the mirror object + createMessage.args[1]= new Integer(INIT_MIRROR); + ArrayList addScopeList = new ArrayList(); + for (int i = 0; i < scopes.size(); i++) { + group = (GroupRetained)scopes.get(i); + tempKey.reset(); + group.addAllNodesForScopedFog(mirrorFog, addScopeList, tempKey); + } + Object[] scopeInfo = new Object[2]; + scopeInfo[0] = ((scopes.size() > 0) ? Boolean.TRUE:Boolean.FALSE); + scopeInfo[1] = addScopeList; + createMessage.args[2] = scopeInfo; + Color3f clr = new Color3f(color); + createMessage.args[3] = clr; + + Object[] obj = new Object[6]; + obj[0] = boundingLeaf; + obj[1] = (regionOfInfluence != null?regionOfInfluence.clone():null); + obj[2] = (inBackgroundGroup? Boolean.TRUE:Boolean.FALSE); + obj[3] = geometryBackground; + obj[4] = new Double(frontDistance); + obj[5] = new Double(backDistance); + + createMessage.args[4] = obj; + VirtualUniverse.mc.processMessage(createMessage); + + } + + + // The update Object function. + // Note : if you add any more fields here , you need to update + // updateFog() in RenderingEnvironmentStructure + synchronized void updateMirrorObject(Object[] objs) { + + int component = ((Integer)objs[1]).intValue(); + Transform3D trans; + + if ((component & FRONT_DISTANCE_CHANGED) != 0) + ((LinearFogRetained)mirrorFog).frontDistance = ((Double)objs[2]).doubleValue(); + if ((component & BACK_DISTANCE_CHANGED) != 0) + ((LinearFogRetained)mirrorFog).backDistance = ((Double)objs[2]).doubleValue(); + if ((component & INIT_MIRROR) != 0) { + ((LinearFogRetained)mirrorFog).frontDistance = ((Double)((Object[])objs[4])[4]).doubleValue(); + ((LinearFogRetained)mirrorFog).backDistance = ((Double)((Object[])objs[4])[5]).doubleValue(); + + } + ((LinearFogRetained)mirrorFog).setLocalToVworldScale(getLastLocalToVworld().getDistanceScale()); + + super.updateMirrorObject(objs); + } + + /** + * Scale distances from local to eye coordinate + */ + protected void validateDistancesInEc(double vworldToCoexistenceScale) { + // vworldToCoexistenceScale can be used here since + // CoexistenceToEc has a unit scale + double localToEcScale = getLocalToVworldScale() * vworldToCoexistenceScale; + + frontDistanceInEc = frontDistance * localToEcScale; + backDistanceInEc = backDistance * localToEcScale; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Link.java b/j3d-core/src/classes/share/javax/media/j3d/Link.java new file mode 100644 index 0000000..e330eea --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Link.java @@ -0,0 +1,169 @@ +/* + * $RCSfile: Link.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:25 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A Link leaf node allows an application to reference a shared graph, + * rooted by a SharedGroup node, from within a branch graph or another + * shared graph. + * Any number of Link nodes can refer to the same SharedGroup node. + */ + +public class Link extends Leaf { + /** + * For Link nodes, specifies that the node allows access to + * its object's SharedGroup information. + */ + public static final int + ALLOW_SHARED_GROUP_READ = CapabilityBits.LINK_ALLOW_SHARED_GROUP_READ; + + /** + * For Link nodes, specifies that the node allows writing + * its object's SharedGroup information. + */ + public static final int + ALLOW_SHARED_GROUP_WRITE = CapabilityBits.LINK_ALLOW_SHARED_GROUP_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SHARED_GROUP_READ + }; + + /** + * Constructs a Link node object that does not yet point to a + * SharedGroup node. + */ + public Link() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a Link node object that points to the specified + * SharedGroup node. + * @param sharedGroup the SharedGroup node + */ + public Link(SharedGroup sharedGroup) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((LinkRetained)this.retained).setSharedGroup(sharedGroup); + } + + /** + * Creates the retained mode LinkRetained object that this + * Link object will point to. + */ + void createRetained() { + this.retained = new LinkRetained(); + this.retained.setSource(this); + } + + /** + * Sets the node's SharedGroup reference. + * @param sharedGroup the SharedGroup node to reference + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setSharedGroup(SharedGroup sharedGroup) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SHARED_GROUP_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Link0")); + ((LinkRetained)this.retained).setSharedGroup(sharedGroup); + } + + /** + * Retrieves the node's SharedGroup reference. + * @return the SharedGroup node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public SharedGroup getSharedGroup() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SHARED_GROUP_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Link1")); + return ((LinkRetained)this.retained).getSharedGroup(); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + *
+ * The cloned Link node will refer to the same + * SharedGroup as the original node. The SharedGroup referred to by + * this Link node will not be cloned. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Link l = new Link(); + l.duplicateNode(this, forceDuplicate); + return l; + } + + /** + * Copies all Link information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + ((LinkRetained) retained).setSharedGroup( + ((LinkRetained) originalNode.retained).getSharedGroup()); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/LinkRetained.java b/j3d-core/src/classes/share/javax/media/j3d/LinkRetained.java new file mode 100644 index 0000000..479d1ca --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/LinkRetained.java @@ -0,0 +1,349 @@ +/* + * $RCSfile: LinkRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.*; + +/** + * A Link leaf node consisting of a reference to a SharedGroup node. + */ + +class LinkRetained extends LeafRetained { + /** + * The SharedGroup component of the link node. + */ + SharedGroupRetained sharedGroup; + + static String plus = "+"; + + // This is used when setLive to check for cycle scene graph + boolean visited = false; + + LinkRetained() { + this.nodeType = NodeRetained.LINK; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + /** + * Sets the SharedGroup reference. + * @param sharedGroup the SharedGroup node + */ + void setSharedGroup(SharedGroup sharedGroup) { + // Note that it is possible that the sharedGroup pass + // in already link to another link and live. + HashKey newKeys[] = null; + boolean abort = false; + + if (source.isLive()) { + // bug 4370407: if sharedGroup is a parent, then don't do anything + if (sharedGroup != null) { + synchronized(universe.sceneGraphLock) { + NodeRetained pa; + for (pa = parent; pa != null; pa = pa.parent) { + if (pa == (NodeRetained)sharedGroup.retained) { + abort = true; + throw new SceneGraphCycleException(J3dI18N.getString("LinkRetained1")); + } + } + } + if (abort) + return; + } + + newKeys = getNewKeys(locale.nodeId, localToVworldKeys); + + if (this.sharedGroup != null) { + ((GroupRetained) parent).checkClearLive(this.sharedGroup, + newKeys, true, null, + 0, 0, this); + this.sharedGroup.parents.removeElement(this); + } + } + + if (sharedGroup != null) { + this.sharedGroup = + (SharedGroupRetained)sharedGroup.retained; + } else { + this.sharedGroup = null; + } + + if (source.isLive() && (sharedGroup != null)) { + + this.sharedGroup.parents.addElement(this); + visited = true; + try { + int ci = ((GroupRetained) parent).indexOfChild((Node)this.sharedGroup.source); + ((GroupRetained) parent).checkSetLive(this.sharedGroup, ci, + newKeys, true, null, + 0, this); + } catch (SceneGraphCycleException e) { + throw e; + } finally { + visited = false; + } + } + + } + + /** + * Retrieves the SharedGroup reference. + * @return the SharedGroup node + */ + SharedGroup getSharedGroup() { + return (sharedGroup != null ? + (SharedGroup)this.sharedGroup.source : null); + } + + void computeCombineBounds(Bounds bounds) { + + if (boundsAutoCompute) { + sharedGroup.computeCombineBounds(bounds); + } else { + // Should this be lock too ? ( MT safe ? ) + synchronized(localBounds) { + bounds.combine(localBounds); + } + } + } + + + /** + * Gets the bounding object of a node. + * @return the node's bounding object + */ + Bounds getBounds() { + return (boundsAutoCompute ? + (Bounds)sharedGroup.getBounds().clone() : + super.getBounds()); + } + + + /** + * assign a name to this node when it is made live. + */ + void setLive(SetLiveState s) { + + super.doSetLive(s); + + if (inBackgroundGroup) { + throw new + IllegalSceneGraphException(J3dI18N.getString("LinkRetained0")); + } + + if (nodeId == null) { + nodeId = universe.getNodeId(); + } + + if (sharedGroup != null) { + this.sharedGroup.parents.addElement(this); + HashKey newKeys[] = getNewKeys(s.locale.nodeId, s.keys); + HashKey oldKeys[] = s.keys; + s.keys = newKeys; + s.inSharedGroup = true; + if (visited) { + throw new SceneGraphCycleException(J3dI18N.getString("LinkRetained1")); + } + visited = true; + try { + this.sharedGroup.setLive(s); + } catch (SceneGraphCycleException e) { + throw e; + } finally { + visited = false; + } + + s.inSharedGroup = inSharedGroup; + s.keys = oldKeys; + + localBounds.setWithLock(this.sharedGroup.localBounds); + } + + super.markAsLive(); + } + + void setNodeData(SetLiveState s) { + + super.setNodeData(s); + + // add this node to parentTransformLink's childTransformLink + if (s.childTransformLinks != null) { + // do not duplicate shared nodes + synchronized(s.childTransformLinks) { + if(!inSharedGroup || !s.childTransformLinks.contains(this)) { + s.childTransformLinks.add(this); + } + } + } + + // add this node to parentSwitchLink's childSwitchLink + if (s.childSwitchLinks != null) { + if(!inSharedGroup || + // only add if not already added in sharedGroup + !s.childSwitchLinks.contains(this)) { + s.childSwitchLinks.add(this); + } + } + } + + + void recombineAbove() { + localBounds.setWithLock(sharedGroup.localBounds); + parent.recombineAbove(); + } + + /** + * assign a name to this node when it is made live. + */ + void clearLive(SetLiveState s) { + + if (sharedGroup != null) { + HashKey newKeys[] = getNewKeys(s.locale.nodeId, s.keys); + super.clearLive(s); + HashKey oldKeys[] = s.keys; + s.keys = newKeys; + s.inSharedGroup = true; + this.sharedGroup.parents.removeElement(this); + this.sharedGroup.clearLive(s); + s.inSharedGroup = inSharedGroup; + s.keys = oldKeys; + } else { + super.clearLive(s); + } + } + + void removeNodeData(SetLiveState s) { + if(refCount <= 0) { + // either not in sharedGroup or last instance in sharedGroup + // remove this node from parentTransformLink's childTransformLink + if (parentTransformLink != null) { + ArrayList obj; + if (parentTransformLink instanceof TransformGroupRetained) { + obj = ((TransformGroupRetained) + parentTransformLink).childTransformLinks; + } else { + obj = ((SharedGroupRetained) + parentTransformLink).childTransformLinks; + } + synchronized(obj) { + obj.remove(this); + } + } + + // remove this node from parentSwitchLink's childSwitchLink + if (parentSwitchLink != null) { + ArrayList switchLinks; + for(int i=0; i=0; i--) { + newKeys[i] = new HashKey(oldKeys[i].toString() + + plus + nodeId); + } + } + return newKeys; + } + + void searchGeometryAtoms(UnorderList list) { + if (sharedGroup != null) { + sharedGroup.searchGeometryAtoms(list); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Locale.java b/j3d-core/src/classes/share/javax/media/j3d/Locale.java new file mode 100644 index 0000000..02ffa6b --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Locale.java @@ -0,0 +1,1094 @@ +/* + * $RCSfile: Locale.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.Vector; +import java.util.Enumeration; +import java.util.ArrayList; + +/** + * A Locale object defines a high-resolution position within a + * VirtualUniverse, and serves as a container for a collection of + * BranchGroup-rooted subgraphs (branch graphs), at that position. + * Objects within a Locale are defined using standard double-precision + * coordinates, relative to the origin of the Locale. This origin + * defines the Virtual World coordinate system for that Locale. + *

+ * A Locale object defines methods to set and get its high-resolution + * coordinates, and methods to add, remove, and enumerate the branch + * graphs. + * + *

+ * For more information, see the + * Introduction to the Java 3D API and + * Scene Graph Superstructure + * documents. + * + * @see VirtualUniverse + * @see HiResCoord + * @see BranchGroup + */ + +public class Locale extends Object { + + /** + * The virtual universe that this Locale object is contained within. + */ + VirtualUniverse universe; + + /** + * The high resolution coordinate associated with this Locale object. + */ + HiResCoord hiRes; + + /** + * List of BranchGroup objects included in this Locale + */ + Vector branchGroups = new Vector(); + + // locale's identifier + String nodeId = null; + + /** + * Constructs and initializes a new high resolution Locale object + * located at (0, 0, 0). + * @param universe the virtual universe that will contain this + * Locale object + */ + public Locale(VirtualUniverse universe) { + this.universe = universe; + this.universe.addLocale(this); + this.hiRes = new HiResCoord(); + nodeId = universe.getNodeId(); + } + + /** + * Constructs and initializes a new high resolution Locale object + * from the parameters provided. + * @param universe the virtual universe that will contain this + * Locale object + * @param x an eight element array specifying the x position + * @param y an eight element array specifying the y position + * @param z an eight element array specifying the z position + */ + public Locale(VirtualUniverse universe, int[] x, int[] y, int[] z) { + this.universe = universe; + this.universe.addLocale(this); + this.hiRes = new HiResCoord(x, y, z); + nodeId = universe.getNodeId(); + } + + /** + * Constructs and initializes a new high resolution Locale object + * at the location specified by the HiResCoord argument. + * @param universe the virtual universe that will contain this + * Locale object + * @param hiRes the HiRes coordinate to use in creating this Locale + */ + public Locale(VirtualUniverse universe, HiResCoord hiRes) { + this.universe = universe; + this.universe.addLocale(this); + this.hiRes = new HiResCoord(hiRes); + nodeId = universe.getNodeId(); + } + + /** + * Retrieves the virtual universe within which this Locale object + * is contained. A null reference indicates that this + * Locale has been removed from its VirtualUniverse. + * @return the virtual universe within which this Locale object + * is contained. + */ + public VirtualUniverse getVirtualUniverse() { + return universe; + } + + /** + * Sets the HiRes coordinate of this Locale to the location + * specified by the parameters provided. + * @param x an eight element array specifying the x position + * @param y an eight element array specifying the y position + * @param z an eight element array specifying the z position + */ + public void setHiRes(int[] x, int[] y, int[] z) { + this.hiRes.setHiResCoord(x, y, z); + } + + /** + * Sets the HiRes coordinate of this Locale + * to the location specified by the HiRes argument. + * @param hiRes the HiRes coordinate specifying this node's new location + */ + public void setHiRes(HiResCoord hiRes) { + this.hiRes.setHiResCoord(hiRes); + } + + /** + * Returns this node's HiResCoord. + * @param hiRes a HiResCoord object that will receive the + * HiRes coordinate of this Locale node + */ + public void getHiRes(HiResCoord hiRes) { + this.hiRes.getHiResCoord(hiRes); + } + + /** + * Add a new branch graph rooted at BranchGroup to + * the list of branch graphs. + * @param branchGroup root of the branch graph to be added + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * @exception MultipleParentException if the specified BranchGroup node + * is already live. + */ + public void addBranchGraph(BranchGroup branchGroup){ + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + // if the BranchGroup already has a parent, or has already been + // added to a locale, throw MultipleParentException + if ((((BranchGroupRetained)branchGroup.retained).parent != null) || + (branchGroup.isLive())) { + throw new MultipleParentException(J3dI18N.getString("Locale0")); + } + + universe.notifyStructureChangeListeners(true, this, branchGroup); + universe.resetWaitMCFlag(); + synchronized (universe.sceneGraphLock) { + doAddBranchGraph(branchGroup); + universe.setLiveState.reset(this); + } + universe.waitForMC(); + } + + // The method that does the work once the lock is acquired. + void doAddBranchGraph(BranchGroup branchGroup) { + BranchGroupRetained bgr = (BranchGroupRetained)branchGroup.retained; + J3dMessage createMessage; + SetLiveState s = universe.setLiveState; + + // bgr.setLocale(this); + + // addElement needs to precede setLive or else any liveness checks + // in the initialize() call of a user behavior (ie, calling collision + // or picking constructor with a SceneGraphPath) will fail + // when SceneGraphPath.validate() attempts to verify that + // the proper Locale is associated with that SceneGraphPath + bgr.attachedToLocale = true; + branchGroups.addElement(branchGroup); + s.reset(this); + s.currentTransforms[0] = new Transform3D[2]; + s.currentTransforms[0][0] = new Transform3D(); + s.currentTransforms[0][1] = new Transform3D(); + s.currentTransformsIndex[0] = new int[2]; + s.currentTransformsIndex[0][0] = 0; + s.currentTransformsIndex[0][1] = 0; + + s.localToVworld = s.currentTransforms; + s.localToVworldIndex = s.currentTransformsIndex; + + s.branchGroupPaths = new ArrayList(); + s.branchGroupPaths.add(new BranchGroupRetained[0]); + + s.orderedPaths = new ArrayList(1); + s.orderedPaths.add(new OrderedPath()); + + s.switchStates = new ArrayList(1); + s.switchStates.add(new SwitchState(false)); + + bgr.setLive(s); + + createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDER| J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.type = J3dMessage.ORDERED_GROUP_INSERTED; + createMessage.universe = universe; + createMessage.args[0] = s.ogList.toArray(); + createMessage.args[1] = s.ogChildIdList.toArray(); + createMessage.args[2] = s.ogOrderedIdList.toArray(); + createMessage.args[3] = s.ogCIOList.toArray(); + createMessage.args[4] = s.ogCIOTableList.toArray(); + + VirtualUniverse.mc.processMessage(createMessage); + + createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.type = J3dMessage.VIEWSPECIFICGROUP_INIT; + createMessage.universe = universe; + createMessage.args[0] = s.changedViewGroup; + createMessage.args[1] = s.changedViewList; + createMessage.args[2] = s.keyList; + VirtualUniverse.mc.processMessage(createMessage); + + + createMessage = new J3dMessage(); + createMessage.threads = s.notifyThreads; + createMessage.type = J3dMessage.INSERT_NODES; + createMessage.universe = universe; + createMessage.args[0] = s.nodeList.toArray(); + createMessage.args[1] = null; + createMessage.args[2] = null; + if (s.viewScopedNodeList != null) { + createMessage.args[3] = s.viewScopedNodeList; + createMessage.args[4] = s.scopedNodesViewList; + } + VirtualUniverse.mc.processMessage(createMessage); + + int sz = s.behaviorNodes.size(); + for (int i=0; i< sz; i++) { + BehaviorRetained b; + b = (BehaviorRetained)s.behaviorNodes.get(i); + b.executeInitialize(); + } + + createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_BEHAVIOR; + createMessage.type = J3dMessage.BEHAVIOR_ACTIVATE; + createMessage.universe = universe; + VirtualUniverse.mc.processMessage(createMessage); + + // Free up memory. + s.reset(null); + } + + /** + * Removes a branch graph rooted at BranchGroup from + * the list of branch graphs. + * @param branchGroup root of the branch graph to be removed + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * @exception CapabilityNotSetException if the ALLOW_DETACH capability is + * not set in the specified BranchGroup node. + */ + public void removeBranchGraph(BranchGroup branchGroup){ + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + if (! branchGroup.getCapability(BranchGroup.ALLOW_DETACH)) { + throw new CapabilityNotSetException(J3dI18N.getString("Locale1")); + } + universe.resetWaitMCFlag(); + synchronized (universe.sceneGraphLock) { + doRemoveBranchGraph(branchGroup, null, 0); + universe.setLiveState.reset(this); + } + universe.waitForMC(); + } + + + // Method to remove all branch graphs from this Locale and remove + // this Locale from the VirtualUniverse + void removeFromUniverse() { + if (branchGroups.size() > 0) { + universe.resetWaitMCFlag(); + synchronized (universe.sceneGraphLock) { + // Make a copy of the branchGroups list so that we can safely + // iterate over it. + Object[] bg = branchGroups.toArray(); + for (int i = 0; i < bg.length; i++) { + doRemoveBranchGraph((BranchGroup)bg[i], null, 0); + } + } + // Put after sceneGraphLock to prevent deadlock + universe.waitForMC(); + } + + // free nodeId + if (nodeId != null) { + universe.nodeIdFreeList.addElement(nodeId); + nodeId = null; + } + + // Set universe pointer to null, indicating that this Locale + // has been removed from its universe + universe = null; + } + + + // The method that does the work once the lock is acquired. + void doRemoveBranchGraph(BranchGroup branchGroup, + J3dMessage messages[], int startIndex) { + + BranchGroupRetained bgr = (BranchGroupRetained)branchGroup.retained; + J3dMessage destroyMessage; + + if (!branchGroup.isLive()) + return; + bgr.attachedToLocale = false; + branchGroups.removeElement(branchGroup); + universe.setLiveState.reset(this); + bgr.clearLive(universe.setLiveState); + bgr.setParent(null); + bgr.setLocale(null); + + if (messages == null) { + destroyMessage = new J3dMessage(); + } else { + destroyMessage = messages[startIndex++]; + } + destroyMessage.threads = J3dThread.UPDATE_RENDER| J3dThread.UPDATE_RENDERING_ENVIRONMENT; + destroyMessage.type = J3dMessage.ORDERED_GROUP_REMOVED; + destroyMessage.universe = universe; + destroyMessage.args[0] = universe.setLiveState.ogList.toArray(); + destroyMessage.args[1] = universe.setLiveState.ogChildIdList.toArray(); + destroyMessage.args[3] = universe.setLiveState.ogCIOList.toArray(); + destroyMessage.args[4] = universe.setLiveState.ogCIOTableList.toArray(); + + // Issue 312: We need to send the REMOVE_NODES message to the + // RenderingEnvironmentStructure before we send VIEWSPECIFICGROUP_CLEAR, + // since the latter clears the list of views that is referred to by + // scopedNodesViewList and used by removeNodes. + if (messages == null) { + VirtualUniverse.mc.processMessage(destroyMessage); + destroyMessage = new J3dMessage(); + } else { + destroyMessage = messages[startIndex++]; + } + destroyMessage.threads = universe.setLiveState.notifyThreads; + destroyMessage.type = J3dMessage.REMOVE_NODES; + destroyMessage.universe = universe; + destroyMessage.args[0] = universe.setLiveState.nodeList.toArray(); + if (universe.setLiveState.viewScopedNodeList != null) { + destroyMessage.args[3] = universe.setLiveState.viewScopedNodeList; + destroyMessage.args[4] = universe.setLiveState.scopedNodesViewList; + } + + if (messages == null) { + VirtualUniverse.mc.processMessage(destroyMessage); + destroyMessage = new J3dMessage(); + } else { + destroyMessage = messages[startIndex++]; + } + destroyMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + destroyMessage.type = J3dMessage.VIEWSPECIFICGROUP_CLEAR; + destroyMessage.universe = universe; + destroyMessage.args[0] = universe.setLiveState.changedViewGroup; + destroyMessage.args[1] = universe.setLiveState.keyList; + + if (messages == null) { + VirtualUniverse.mc.processMessage(destroyMessage); + } else { + destroyMessage = messages[startIndex++]; + } + + if (universe.isEmpty()) { + VirtualUniverse.mc.postRequest(MasterControl.EMPTY_UNIVERSE, + universe); + } + universe.setLiveState.reset(null); // cleanup memory + universe.notifyStructureChangeListeners(false, this, branchGroup); + } + + /** + * Replaces the branch graph rooted at oldGroup in the list of + * branch graphs with the branch graph rooted at + * newGroup. + * @param oldGroup root of the branch graph to be replaced. + * @param newGroup root of the branch graph that will replace the old + * branch graph. + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * @exception CapabilityNotSetException if the ALLOW_DETACH capability is + * not set in the old BranchGroup node. + * @exception MultipleParentException if the new BranchGroup node + * is already live. + */ + public void replaceBranchGraph(BranchGroup oldGroup, + BranchGroup newGroup){ + + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + if (! oldGroup.getCapability(BranchGroup.ALLOW_DETACH)) { + throw new CapabilityNotSetException(J3dI18N.getString("Locale1")); + } + + if (((BranchGroupRetained)newGroup.retained).parent != null) { + throw new MultipleParentException(J3dI18N.getString("Locale3")); + } + universe.resetWaitMCFlag(); + universe.notifyStructureChangeListeners(true, this, newGroup); + synchronized (universe.sceneGraphLock) { + doReplaceBranchGraph(oldGroup, newGroup); + universe.setLiveState.reset(this); + } + universe.notifyStructureChangeListeners(false, this, oldGroup); + universe.waitForMC(); + } + + // The method that does the work once the lock is acquired. + void doReplaceBranchGraph(BranchGroup oldGroup, + BranchGroup newGroup){ + BranchGroupRetained obgr = (BranchGroupRetained)oldGroup.retained; + BranchGroupRetained nbgr = (BranchGroupRetained)newGroup.retained; + J3dMessage createMessage; + J3dMessage destroyMessage; + + + branchGroups.removeElement(oldGroup); + obgr.attachedToLocale = false; + universe.setLiveState.reset(this); + obgr.clearLive(universe.setLiveState); + + destroyMessage = new J3dMessage(); + + destroyMessage.threads = J3dThread.UPDATE_RENDER| J3dThread.UPDATE_RENDERING_ENVIRONMENT; + destroyMessage.type = J3dMessage.ORDERED_GROUP_REMOVED; + destroyMessage.universe = universe; + destroyMessage.args[0] = universe.setLiveState.ogList.toArray(); + destroyMessage.args[1] = universe.setLiveState.ogChildIdList.toArray(); + destroyMessage.args[3] = universe.setLiveState.ogCIOList.toArray(); + destroyMessage.args[4] = universe.setLiveState.ogCIOTableList.toArray(); + VirtualUniverse.mc.processMessage(destroyMessage); + + destroyMessage = new J3dMessage(); + destroyMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + destroyMessage.type = J3dMessage.VIEWSPECIFICGROUP_CLEAR; + destroyMessage.universe = universe; + destroyMessage.args[0] = universe.setLiveState.changedViewGroup; + destroyMessage.args[1] = universe.setLiveState.keyList; + VirtualUniverse.mc.processMessage(destroyMessage); + + + destroyMessage = new J3dMessage(); + destroyMessage.threads = universe.setLiveState.notifyThreads; + destroyMessage.type = J3dMessage.REMOVE_NODES; + destroyMessage.universe = universe; + destroyMessage.args[0] = universe.setLiveState.nodeList.toArray(); + VirtualUniverse.mc.processMessage(destroyMessage); + + branchGroups.addElement(newGroup); + nbgr.attachedToLocale = true; + universe.setLiveState.reset(this); + universe.setLiveState.currentTransforms[0] = new Transform3D[2]; + universe.setLiveState.currentTransforms[0][0] = new Transform3D(); + universe.setLiveState.currentTransforms[0][1] = new Transform3D(); + universe.setLiveState.currentTransformsIndex[0] = new int[2]; + universe.setLiveState.currentTransformsIndex[0][0] = 0; + universe.setLiveState.currentTransformsIndex[0][1] = 0; + + universe.setLiveState.localToVworld = + universe.setLiveState.currentTransforms; + universe.setLiveState.localToVworldIndex = + universe.setLiveState.currentTransformsIndex; + + universe.setLiveState.branchGroupPaths = new ArrayList(); + universe.setLiveState.branchGroupPaths.add(new BranchGroupRetained[0]); + + universe.setLiveState.orderedPaths = new ArrayList(1); + universe.setLiveState.orderedPaths.add(new OrderedPath()); + + universe.setLiveState.switchStates = new ArrayList(1); + universe.setLiveState.switchStates.add(new SwitchState(false)); + + nbgr.setLive(universe.setLiveState); + + + createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDER| J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.type = J3dMessage.ORDERED_GROUP_INSERTED; + createMessage.universe = universe; + createMessage.args[0] = universe.setLiveState.ogList.toArray(); + createMessage.args[1] = universe.setLiveState.ogChildIdList.toArray(); + createMessage.args[2] = universe.setLiveState.ogOrderedIdList.toArray(); + createMessage.args[3] = universe.setLiveState.ogCIOList.toArray(); + createMessage.args[4] = universe.setLiveState.ogCIOTableList.toArray(); + VirtualUniverse.mc.processMessage(createMessage); + + // XXXX: make these two into one message + createMessage = new J3dMessage(); + createMessage.threads = universe.setLiveState.notifyThreads; + createMessage.type = J3dMessage.INSERT_NODES; + createMessage.universe = universe; + createMessage.args[0] = universe.setLiveState.nodeList.toArray(); + createMessage.args[1] = null; + createMessage.args[2] = null; + if (universe.setLiveState.viewScopedNodeList != null) { + createMessage.args[3] = universe.setLiveState.viewScopedNodeList; + createMessage.args[4] = universe.setLiveState.scopedNodesViewList; + } + VirtualUniverse.mc.processMessage(createMessage); + + Object behaviorNodes[] = universe.setLiveState.behaviorNodes.toArray(); + + if (universe.isEmpty()) { + VirtualUniverse.mc.postRequest(MasterControl.EMPTY_UNIVERSE, + universe); + } + + for (int i=0; i< behaviorNodes.length; i++) { + ((BehaviorRetained) behaviorNodes[i]).executeInitialize(); + } + + createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_BEHAVIOR; + createMessage.type = J3dMessage.BEHAVIOR_ACTIVATE; + createMessage.universe = universe; + VirtualUniverse.mc.processMessage(createMessage); + + // Free up memory. + universe.setLiveState.reset(null); + } + + /** + * Get number of branch graphs in this Locale. + * @return number of branch graphs in this Locale. + */ + public int numBranchGraphs(){ + return branchGroups.size(); + } + + /** + * Gets an Enumeration object of all branch graphs in this Locale. + * @return an Enumeration object of all branch graphs. + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + */ + public Enumeration getAllBranchGraphs(){ + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + return branchGroups.elements(); + } + + + void validateModeFlagAndPickShape(int mode, int flags, PickShape pickShape) { + + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + if((mode != PickInfo.PICK_BOUNDS) && (mode != PickInfo.PICK_GEOMETRY)) { + + throw new IllegalArgumentException(J3dI18N.getString("Locale5")); + } + + if((pickShape instanceof PickPoint) && (mode == PickInfo.PICK_GEOMETRY)) { + throw new IllegalArgumentException(J3dI18N.getString("Locale6")); + } + + if(((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) && + ((flags & PickInfo.ALL_GEOM_INFO) != 0)) { + throw new IllegalArgumentException(J3dI18N.getString("Locale7")); + } + + if((mode == PickInfo.PICK_BOUNDS) && + (((flags & (PickInfo.CLOSEST_GEOM_INFO | + PickInfo.ALL_GEOM_INFO | + PickInfo.CLOSEST_DISTANCE | + PickInfo.CLOSEST_INTERSECTION_POINT)) != 0))) { + + throw new IllegalArgumentException(J3dI18N.getString("Locale8")); + } + + if((pickShape instanceof PickBounds) && + (((flags & (PickInfo.CLOSEST_GEOM_INFO | + PickInfo.ALL_GEOM_INFO | + PickInfo.CLOSEST_DISTANCE | + PickInfo.CLOSEST_INTERSECTION_POINT)) != 0))) { + + throw new IllegalArgumentException(J3dI18N.getString("Locale9")); + } + } + + /** + * Returns an array referencing all the items that are pickable below this + * Locale that intersect with PickShape. + * The resultant array is unordered. + * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * + * @see BranchGroup#pickAll + */ + public SceneGraphPath[] pickAll( PickShape pickShape ) { + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + PickInfo[] pickInfoArr = pickAll( PickInfo.PICK_BOUNDS, + PickInfo.SCENEGRAPHPATH, pickShape); + + if(pickInfoArr == null) { + return null; + } + SceneGraphPath[] sgpArr = new SceneGraphPath[pickInfoArr.length]; + for( int i=0; iLocale that intersect with PickShape. + * The accuracy of the pick is set by the pick mode. The mode include : + * PickInfo.PICK_BOUNDS and PickInfo.PICK_GEOMETRY. The amount of information returned + * is specified via a masked variable, flags, indicating which components are + * present in each returned PickInfo object. + * + * @param mode picking mode, one of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * + * @param flags a mask indicating which components are present in each PickInfo object. + * This is specified as one or more individual bits that are bitwise "OR"ed together to + * describe the PickInfo data. The flags include : + *

    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalArgumentException if flags contains both CLOSEST_GEOM_INFO and + * ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is a PickPoint and pick mode + * is set to PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is neither PICK_BOUNDS + * nor PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is PICK_BOUNDS + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is PickBounds + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are as follows : + *
    + *
  • By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ
  • + *
  • By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ
  • + *
  • Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above)
  • + *
+ * + * @see BranchGroup#pickAll(int,int,javax.media.j3d.PickShape) + * @see PickInfo + * + * @since Java 3D 1.4 + * + */ + public PickInfo[] pickAll( int mode, int flags, PickShape pickShape ) { + + validateModeFlagAndPickShape(mode, flags, pickShape); + + GeometryAtom geomAtoms[] = universe.geometryStructure.pickAll(this, pickShape); + + return PickInfo.pick(this, geomAtoms, mode, flags, pickShape, PickInfo.PICK_ALL); + + } + + /** + * Returns a sorted array of references to all the pickable items + * that intersect with the pickShape. Element [0] references the + * item closest to origin of PickShape successive array + * elements are further from the origin + *
+ * NOTE: If pickShape is of type PickBounds, the resulting array + * is unordered. + * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * + * @see BranchGroup#pickAllSorted + */ + public SceneGraphPath[] pickAllSorted( PickShape pickShape ) { + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + PickInfo[] pickInfoArr = pickAllSorted( PickInfo.PICK_BOUNDS, + PickInfo.SCENEGRAPHPATH, pickShape); + + if(pickInfoArr == null) { + return null; + } + SceneGraphPath[] sgpArr = new SceneGraphPath[pickInfoArr.length]; + for( int i=0; iorigin of PickShape successive array + * elements are further from the origin + * The accuracy of the pick is set by the pick mode. The mode include : + * PickInfo.PICK_BOUNDS and PickInfo.PICK_GEOMETRY. The amount of information returned + * is specified via a masked variable, flags, indicating which components are + * present in each returned PickInfo object. + * + * @param mode picking mode, one of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * + * @param flags a mask indicating which components are present in each PickInfo object. + * This is specified as one or more individual bits that are bitwise "OR"ed together to + * describe the PickInfo data. The flags include : + *
    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalArgumentException if flags contains both CLOSEST_GEOM_INFO and + * ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is a PickPoint and pick mode + * is set to PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is neither PICK_BOUNDS + * nor PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is PICK_BOUNDS + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is PickBounds + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are as follows : + *
    + *
  • By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ
  • + *
  • By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ
  • + *
  • Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above)
  • + *
+ * + * @see BranchGroup#pickAllSorted(int,int,javax.media.j3d.PickShape) + * @see PickInfo + * + * @since Java 3D 1.4 + * + */ + public PickInfo[] pickAllSorted( int mode, int flags, PickShape pickShape ) { + + validateModeFlagAndPickShape(mode, flags, pickShape); + GeometryAtom geomAtoms[] = universe.geometryStructure.pickAll(this, pickShape); + + if ((geomAtoms == null) || (geomAtoms.length == 0)) { + return null; + } + + PickInfo[] pickInfoArr = null; + + if (mode == PickInfo.PICK_GEOMETRY) { + // Need to have closestDistance set + flags |= PickInfo.CLOSEST_DISTANCE; + pickInfoArr= PickInfo.pick(this, geomAtoms, mode, flags, pickShape, PickInfo.PICK_ALL); + if (pickInfoArr != null) { + PickInfo.sortPickInfoArray(pickInfoArr); + } + } + else { + PickInfo.sortGeomAtoms(geomAtoms, pickShape); + pickInfoArr= PickInfo.pick(this, geomAtoms, mode, flags, pickShape, PickInfo.PICK_ALL); + } + + return pickInfoArr; + } + + /** + * Returns a SceneGraphPath which references the pickable item + * which is closest to the origin of pickShape. + *
+ * NOTE: If pickShape is of type PickBounds, the return is any + * pickable node below this Locale. + * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * + * @see BranchGroup#pickClosest + */ + public SceneGraphPath pickClosest( PickShape pickShape ) { + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + PickInfo pickInfo = pickClosest( PickInfo.PICK_BOUNDS, + PickInfo.SCENEGRAPHPATH, pickShape); + + if(pickInfo == null) { + return null; + } + return pickInfo.getSceneGraphPath(); + } + + /** + * Returns a PickInfo which references the pickable item + * which is closest to the origin of pickShape. + * The accuracy of the pick is set by the pick mode. The mode include : + * PickInfo.PICK_BOUNDS and PickInfo.PICK_GEOMETRY. The amount of information returned + * is specified via a masked variable, flags, indicating which components are + * present in each returned PickInfo object. + * + * @param mode picking mode, one of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * + * @param flags a mask indicating which components are present in each PickInfo object. + * This is specified as one or more individual bits that are bitwise "OR"ed together to + * describe the PickInfo data. The flags include : + *
    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalArgumentException if flags contains both CLOSEST_GEOM_INFO and + * ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is a PickPoint and pick mode + * is set to PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is neither PICK_BOUNDS + * nor PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is PICK_BOUNDS + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is PickBounds + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are as follows : + *
    + *
  • By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ
  • + *
  • By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ
  • + *
  • Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above)
  • + *
+ * + * @see BranchGroup#pickClosest(int,int,javax.media.j3d.PickShape) + * @see PickInfo + * + * @since Java 3D 1.4 + * + */ + public PickInfo pickClosest( int mode, int flags, PickShape pickShape ) { + + PickInfo[] pickInfoArr = null; + + pickInfoArr = pickAllSorted( mode, flags, pickShape ); + + if(pickInfoArr == null) { + return null; + } + + return pickInfoArr[0]; + + } + + /** + * Returns a reference to any item that is Pickable below this + * Locale which intersects with pickShape. + * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * + * @see BranchGroup#pickAny + */ + public SceneGraphPath pickAny( PickShape pickShape ) { + if (universe == null) { + throw new IllegalStateException(J3dI18N.getString("Locale4")); + } + + PickInfo pickInfo = pickAny( PickInfo.PICK_BOUNDS, + PickInfo.SCENEGRAPHPATH, pickShape); + + if(pickInfo == null) { + return null; + } + return pickInfo.getSceneGraphPath(); + + } + + /** + * Returns a PickInfo which references the pickable item below this + * Locale which intersects with pickShape. + * The accuracy of the pick is set by the pick mode. The mode include : + * PickInfo.PICK_BOUNDS and PickInfo.PICK_GEOMETRY. The amount of information returned + * is specified via a masked variable, flags, indicating which components are + * present in each returned PickInfo object. + * + * @param mode picking mode, one of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * + * @param flags a mask indicating which components are present in each PickInfo object. + * This is specified as one or more individual bits that are bitwise "OR"ed together to + * describe the PickInfo data. The flags include : + *
    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * + * @param pickShape the description of this picking volume or area. + * + * @exception IllegalArgumentException if flags contains both CLOSEST_GEOM_INFO and + * ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is a PickPoint and pick mode + * is set to PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is neither PICK_BOUNDS + * nor PICK_GEOMETRY. + * + * @exception IllegalArgumentException if pick mode is PICK_BOUNDS + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalArgumentException if pickShape is PickBounds + * and flags includes any of CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, + * CLOSEST_GEOM_INFO or ALL_GEOM_INFO. + * + * @exception IllegalStateException if this Locale has been + * removed from its VirtualUniverse. + * + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are as follows : + *
    + *
  • By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ
  • + *
  • By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ
  • + *
  • Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above)
  • + *
+ * + * @see BranchGroup#pickAny(int,int,javax.media.j3d.PickShape) + * @see PickInfo + * + * @since Java 3D 1.4 + * + */ + public PickInfo pickAny( int mode, int flags, PickShape pickShape ) { + + validateModeFlagAndPickShape(mode, flags, pickShape); + GeometryAtom geomAtoms[] = universe.geometryStructure.pickAll(this, pickShape); + + PickInfo[] pickInfoArr = PickInfo.pick(this, geomAtoms, mode, flags, pickShape, PickInfo.PICK_ANY); + + if(pickInfoArr == null) { + return null; + } + + return pickInfoArr[0]; + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/MRSWLock.java b/j3d-core/src/classes/share/javax/media/j3d/MRSWLock.java new file mode 100644 index 0000000..aee9bd9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/MRSWLock.java @@ -0,0 +1,93 @@ +/* + * $RCSfile: MRSWLock.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Use this lock to allow multiple reads/single write synchronization. + * To prevent deadlock a read/writeLock call must match with a read/writeUnlock call. + * Write request has precedence over read request. + */ + +class MRSWLock { + + static boolean debug = false; + + private int readCount; + private boolean write; + private int writeRequested; + private int lockRequested; + + MRSWLock() { + readCount = 0; + write = false; + writeRequested = 0; + lockRequested = 0; + } + + synchronized final void readLock() { + lockRequested++; + while((write == true) || (writeRequested > 0)) { + try { wait(); } catch(InterruptedException e){} + } + lockRequested--; + readCount++; + } + + synchronized final void readUnlock() { + if(readCount>0) + readCount--; + else + if(debug) System.err.println("ReadWriteLock.java : Problem! readCount is >= 0."); + + if(lockRequested>0) + notifyAll(); + } + + synchronized final void writeLock() { + lockRequested++; + writeRequested++; + while((readCount>0)||(write == true)) { + try { wait(); } catch(InterruptedException e){} + } + write = true; + lockRequested--; + writeRequested--; + } + + synchronized final void writeUnlock() { + write = false; + + if(lockRequested>0) + notifyAll(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/MasterControl.java b/j3d-core/src/classes/share/javax/media/j3d/MasterControl.java new file mode 100644 index 0000000..33785bb --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/MasterControl.java @@ -0,0 +1,3978 @@ +/* + * $RCSfile: MasterControl.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.40 $ + * $Date: 2008/05/22 18:10:39 $ + * $State: Exp $ + */ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +package javax.media.j3d; + +import java.util.*; +import java.awt.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +class MasterControl { + + /** + * Options for the runMonitor + */ + static final int CHECK_FOR_WORK = 0; + static final int SET_WORK = 1; + static final int RUN_THREADS = 2; + static final int THREAD_DONE = 3; + static final int SET_WORK_FOR_REQUEST_RENDERER = 5; + static final int RUN_RENDERER_CLEANUP = 6; + + // The thread states for MC + static final int SLEEPING = 0; + static final int RUNNING = 1; + static final int WAITING_FOR_THREADS = 3; + static final int WAITING_FOR_CPU = 4; + static final int WAITING_FOR_RENDERER_CLEANUP = 5; + + // Constants used in renderer thread argument + static final Integer REQUESTRENDER = new Integer(Renderer.REQUESTRENDER); + static final Integer RENDER = new Integer(Renderer.RENDER); + static final Integer SWAP = new Integer(Renderer.SWAP); + + // Constants used for request from user threads + static final Integer ACTIVATE_VIEW = new Integer(1); + static final Integer DEACTIVATE_VIEW = new Integer(2); + static final Integer START_VIEW = new Integer(3); + static final Integer STOP_VIEW = new Integer(4); + static final Integer REEVALUATE_CANVAS = new Integer(5); + static final Integer UNREGISTER_VIEW = new Integer(6); + static final Integer PHYSICAL_ENV_CHANGE = new Integer(7); + static final Integer INPUTDEVICE_CHANGE = new Integer(8); + static final Integer EMPTY_UNIVERSE = new Integer(9); + static final Integer START_RENDERER = new Integer(10); + static final Integer STOP_RENDERER = new Integer(11); + static final Integer RENDER_ONCE = new Integer(12); + static final Integer FREE_CONTEXT = new Integer(13); + static final Integer FREE_DRAWING_SURFACE = new Integer(14); + static final Integer FREE_MESSAGE = new Integer(15); + static final Integer RESET_CANVAS = new Integer(16); + static final Integer GETBESTCONFIG = new Integer(17); + static final Integer ISCONFIGSUPPORT = new Integer(18); + static final Integer SET_GRAPHICSCONFIG_FEATURES = new Integer(19); + static final Integer SET_QUERYPROPERTIES = new Integer(20); + static final Integer SET_VIEW = new Integer(21); + + // Developer logger for reporting informational messages; see getDevLogger() + private static boolean devLoggerEnabled = false; + private static Logger devLogger; + + // Stats logger for reporting runtime statistics; see getStatsLogger() + private static boolean statsLoggerEnabled = false; + private static Logger statsLogger; + + // Core logger for reporting internal errors, warning, and + // informational messages; see getCoreLogger() + private static boolean coreLoggerEnabled = false; + private static Logger coreLogger; + + // Flag indicating that the rendering pipeline libraries are loaded + private static boolean librariesLoaded = false; + + // Issue 257: flag indicating that we are running in "appletLauncher" mode + // and should use JNLPAppletLauncher to load any native libraries + private static boolean appletLauncher = false; + + /** + * reference to MasterControl thread + */ + private MasterControlThread mcThread = null; + + /** + * The list of views that are currently registered + */ + private UnorderList views = new UnorderList(1, View.class); + + + /** + * by MIK OF CLASSX + * + * the flag to indicate whether the background of the offscreen + * canvas must be transparent or not false by default + */ + boolean transparentOffScreen = false; + + /** + * Flag to indicate whether Pbuffers are used for off-screen + * rendering; true by default. Set by the "j3d.usePbuffer" + * property, When this flag is set to false, Bitmap (Windows) or + * Pixmap (UNIX) rendering will be used + */ + boolean usePbuffer = true; + + /** + * Flag to indicate whether should renderer view frustum culling is done; + * true by default. + * Set by the -Dj3d.viewFrustumCulling property, When this flag is + * set to false, the renderer view frustum culling is turned off. + */ + boolean viewFrustumCulling = true; + + /** + * the flag to indicate whether the geometry should be locked or not + */ + + private boolean lockGeometry = false; + + /** + * The number of registered views that are active + */ + private int numActiveViews = 0; + + /** + * The list of active universes get from View + */ + private UnorderList activeUniverseList = new UnorderList(VirtualUniverse.class); + + /** + * The list of universes register from View + */ + private UnorderList regUniverseList = new UnorderList(VirtualUniverse.class); + + /** + * A lock used for accessing time structures. + */ + private Object timeLock = new Object(); + + + /** + * The current "time" value + */ + private long time = 0; + + /** + * Use to assign threadOpts in Renderer thread. + */ + private long waitTimestamp = 0; + + /** + * The current list of work threads + */ + private UnorderList stateWorkThreads = + new UnorderList(J3dThreadData.class); + private UnorderList renderWorkThreads = + new UnorderList(J3dThreadData.class); + private UnorderList requestRenderWorkThreads = + new UnorderList(J3dThreadData.class); + + /** + * The current list of work threads + */ + private UnorderList renderThreadData = new UnorderList(J3dThreadData.class); + + /** + * The list of input device scheduler thread + */ + private UnorderList inputDeviceThreads = + new UnorderList(1, InputDeviceScheduler.class); + + /** + * A flag that is true when the thread lists need updating + */ + private boolean threadListsChanged; + + + /** + * Markers for the last transform structure update thread + * and the last update thread. + */ + private int lastTransformStructureThread = 0; + private int lastStructureUpdateThread = 0; + + /** + * The current time snapshots + */ + private long currentTime; + + // Only one Timer thread in the system. + TimerThread timerThread; + + // Only one Notification thread in the system. + private NotificationThread notificationThread; + + /** + * This flag indicates that MC is running + */ + volatile boolean running = true; + + /** + * This flag indicates that MC has work to do + */ + private boolean workToDo = false; + + /** + * This flag indicates that there is work for requestRenderer + */ + private boolean requestRenderWorkToDo = false; + + /** + * The number of THREAD_DONE messages pending + */ + private int threadPending = 0; + private int renderPending = 0; + private int statePending = 0; + + /** + * State variables for work lists + */ + private boolean renderWaiting = false; + private boolean stateWaiting = false; + + /** + * The current state of the MC thread + */ + private int state = SLEEPING; + + // time for sleep in order to met the minimum frame duration + private long sleepTime = 0; + + + /** + * The number of cpu's Java 3D may use + */ + private int cpuLimit; + + /** + * A list of mirror objects to be updated + */ + private UnorderList mirrorObjects = new UnorderList(ObjectUpdate.class); + + /** + * The renderingAttributesStructure for updating node component + * objects + */ + private RenderingAttributesStructure renderingAttributesStructure = + new RenderingAttributesStructure(); + + /** + * The default rendering method + */ + private DefaultRenderMethod defaultRenderMethod = null; + + /** + * The text3D rendering method + */ + private Text3DRenderMethod text3DRenderMethod = null; + + /** + * The vertex array rendering method + */ + private VertexArrayRenderMethod vertexArrayRenderMethod = null; + + /** + * The displayList rendering method + */ + private DisplayListRenderMethod displayListRenderMethod = null; + + /** + * The compressed geometry rendering method + */ + private CompressedGeometryRenderMethod compressedGeometryRenderMethod = null; + + /** + * The oriented shape3D rendering method + */ + private OrientedShape3DRenderMethod orientedShape3DRenderMethod = null; + + /** + * This is the start time upon which alpha's and behaviors + * are synchronized to. It is initialized once, the first time + * that a MasterControl object is created. + */ + static long systemStartTime = 0L; + + // Flag indicating that we are on a Windows OS + private static boolean isWindowsOs = false; + + // Flag indicating we are on MacOS + private static boolean isMacOs = false; + + // This is a counter for texture id's, valid id starts from 1 + private int textureIdCount = 0; + + // This is lock for both 2D/3D textureIds; + private Object textureIdLock = new Object(); + + // This is a time stamp used when context is created + private long contextTimeStamp = 0; + + // This is an array of canvasIds in used + private boolean[] canvasIds = null; + private int canvasFreeIndex = 0; + private Object canvasIdLock = new Object(); + + // This is a counter for rendererBit + private int rendererCount = 0; + + // Flag that indicates whether to shared display context or not + boolean isSharedCtx = false; + + // Flag that tells us to use NV_register_combiners + boolean useCombiners = false; + + // Flag that indicates whether compile is disabled or not + boolean disableCompile = false; + + // Flag that indicates whether or not compaction occurs + boolean doCompaction = true; + + // Flag that indicates whether separate specular color is disabled or not + boolean disableSeparateSpecularColor = false; + + // Flag that indicates whether DisplayList is used or not + boolean isDisplayList = true; + + // If this flag is set, then by-ref geometry will not be + // put in display list + boolean buildDisplayListIfPossible = false; + + // If this flag is set, then geometry arrays with vertex attributes can + // be in display list. + boolean vertexAttrsInDisplayList = false; + + // Issue 249 - flag that indicates whether the soleUser optimization is permitted + boolean allowSoleUser = false; + + // Issue 266 - Flag indicating whether null graphics configs are allowed + // Set by -Dj3d.allowNullGraphicsConfig property + // Setting this flag causes Canvas3D to allow a null GraphicsConfiguration + // for on-screen canvases. This is only for backward compatibility with + // legacy applications. + boolean allowNullGraphicsConfig = false; + + // Issue 239 - Flag indicating whether the stencil buffer is cleared by + // default each frame when the color and depth buffers are cleared. + // Note that this is a partial solution, since we eventually want an API + // to control this. + boolean stencilClear = false; + + // The global shading language being used. Using a ShaderProgram + // with a shading language other than the one specified by + // globalShadingLanguage will cause a ShaderError to be generated, + static int globalShadingLanguage = Shader.SHADING_LANGUAGE_GLSL; + + // Flags indicating whether the Cg or GLSL libraries are available; we still need + // to check for the actual extension support when the Canvas3D with its associated context + // is created. Note that these are qualifed by the above globalShadingLanguage, so at + // most one of these two flags will be true; + static boolean cgLibraryAvailable = false; + static boolean glslLibraryAvailable = false; + + + // REQUESTCLEANUP messages argument + static Integer REMOVEALLCTXS_CLEANUP = new Integer(1); + static Integer REMOVECTX_CLEANUP = new Integer(2); + static Integer REMOVENOTIFY_CLEANUP = new Integer(3); + static Integer RESETCANVAS_CLEANUP = new Integer(4); + static Integer FREECONTEXT_CLEANUP = new Integer(5); + + // arguments for renderer resource cleanup run + Object rendererCleanupArgs[] = {new Integer(Renderer.REQUESTCLEANUP), + null, null}; + + + // Context creation should obtain this lock, so that + // first_time and all the extension initilialization + // are done in the MT safe manner + Object contextCreationLock = new Object(); + + // Flag that indicates whether to lock the DSI while rendering + boolean doDsiRenderLock = false; + + // Flag that indicates the pre-1.5 behavior of enforcing power-of-two + // textures. If set, then any non-power-of-two textures will throw an + // exception. + boolean enforcePowerOfTwo = false; + + // Flag that indicates whether the framebuffer is sharing the + // Z-buffer with both the left and right eyes when in stereo mode. + // If this is true, we need to clear the Z-buffer between rendering + // to the left and right eyes. + boolean sharedStereoZBuffer = true; + + // True to disable all underlying multisampling API so it uses + // the setting in the driver. + boolean implicitAntialiasing = false; + + // False to disable compiled vertex array extensions if support + boolean isCompiledVertexArray = true; + + // Number of reserved vertex attribute locations for GLSL (must be at + // least 1). + // Issue 269 - need to reserve up to 6 vertex attribtue locations to ensure + // that we don't collide with a predefined gl_* attribute on nVidia cards. + int glslVertexAttrOffset = 6; + + // Hashtable that maps a GraphicsDevice to its associated + // Screen3D--this is only used for on-screen Canvas3Ds + Hashtable deviceScreenMap = new Hashtable(); + + // Use to store all requests from user threads. + UnorderList requestObjList = new UnorderList(); + private UnorderList requestTypeList = new UnorderList(Integer.class); + + // Temporary storage to store stop request for requestViewList + private UnorderList tempViewList = new UnorderList(); + private UnorderList renderOnceList = new UnorderList(); + + // This flag is true when there is pending request + // i.e. false when the above requestxxx Lists are all empty. + private boolean pendingRequest = false; + + // Root ThreadGroup for creating Java 3D threads + private static ThreadGroup rootThreadGroup; + + // Thread priority for all Java 3D threads + private static int threadPriority; + + static private Object mcThreadLock = new Object(); + + private ArrayList timestampUpdateList = new ArrayList(3); + + private UnorderList freeMessageList = new UnorderList(8); + + // Native AWT object + long awt; + + // Maximum number of lights + int maxLights; + + // This is used for D3D only + int resendTexTimestamp = 0; + + // Indicates that the property to disable Xinerama mode was set and + // successfully disabled. + boolean xineramaDisabled = false; + + // Set by the -Dj3d.sortShape3DBounds property, When this flag is + // set to true, the bounds of the Shape3D node will be used in + // place of the computed GeometryArray bounds for transparency + // sorting for those Shape3D nodes whose boundsAutoCompute + // attribute is set to false. + boolean sortShape3DBounds = false; + + //Set by -Dj3d.forceReleaseView property. + //Setting this flag as true disables the bug fix 4267395 in View deactivate(). + //The bug 4267395 can lock-up *some* systems, but the bug fix can + //produce memory leaks in applications which creates and destroy Canvas3D + //from time to time. + //Set as true if you have memory leaks after disposing Canvas3D. + //Default false value does affect Java3D View dispose behavior. + boolean forceReleaseView = false; + + // Issue 561: Set by -Dj3d.releaseBoundingBoxMemory property. + // When set to true, the per-instance fields used in bounding box + // transformation are released at the end of transform methods. This saves + // a significant amount of memory in large scenes containing huge amounts + // of bounding boxes. Setting this false can improve performance when + // lots of transforms are performed. The default is false. + boolean releaseBoundingBoxMemory = false; + + // Issue 480: Cache the bounds of nodes so that getBounds does not + // recompute the boounds of the entire graph per call + boolean cacheAutoComputedBounds = false; + + // issue 544 + boolean useBoxForGroupBounds = false; + + /** + * Constructs a new MasterControl object. Note that there is + * exatly one MasterControl object, created statically by + * VirtualUniverse. + */ + MasterControl() { + assert librariesLoaded; + + // Get AWT handle + awt = Pipeline.getPipeline().getAWT(); + + // Initialize the start time upon which alpha's and behaviors + // are synchronized to (if it isn't already set). + if (systemStartTime == 0L) { + systemStartTime = J3dClock.currentTimeMillis(); + } + + if(J3dDebug.devPhase) { + // Check to see whether debug mode is allowed + J3dDebug.debug = getBooleanProperty("j3d.debug", false, + "J3dDebug.debug"); + } + + // Check to see whether shared contexts are allowed + if (!isD3D()) { + isSharedCtx = + getBooleanProperty("j3d.sharedctx", isSharedCtx, "shared contexts"); + } + + doCompaction = getBooleanProperty("j3d.docompaction", doCompaction, + "compaction"); + + // by MIK OF CLASSX + transparentOffScreen = getBooleanProperty("j3d.transparentOffScreen", transparentOffScreen, "transparent OffScreen"); + + usePbuffer = getBooleanProperty("j3d.usePbuffer", + usePbuffer, + "Off-screen Pbuffer"); + + viewFrustumCulling = getBooleanProperty("j3d.viewFrustumCulling", viewFrustumCulling,"View frustum culling in the renderer is"); + + sortShape3DBounds = + getBooleanProperty("j3d.sortShape3DBounds", sortShape3DBounds, + "Shape3D bounds enabled for transparency sorting", + "Shape3D bounds *ignored* for transparency sorting"); + + forceReleaseView = + getBooleanProperty("j3d.forceReleaseView", forceReleaseView, + "forceReleaseView after Canvas3D dispose enabled", + "forceReleaseView after Canvas3D dispose disabled"); + + releaseBoundingBoxMemory = getBooleanProperty("j3d.releaseBoundingBoxMemory", + releaseBoundingBoxMemory, "releasing memory after bounding box transform"); + + useCombiners = getBooleanProperty("j3d.usecombiners", useCombiners, + "Using NV_register_combiners if available", + "NV_register_combiners disabled"); + + if (getProperty("j3d.disablecompile") != null) { + disableCompile = true; + System.err.println("Java 3D: BranchGroup.compile disabled"); + } + + if (getProperty("j3d.disableSeparateSpecular") != null) { + disableSeparateSpecularColor = true; + System.err.println("Java 3D: separate specular color disabled if possible"); + } + + isDisplayList = getBooleanProperty("j3d.displaylist", isDisplayList, + "display list"); + + implicitAntialiasing = + getBooleanProperty("j3d.implicitAntialiasing", + implicitAntialiasing, + "implicit antialiasing"); + + isCompiledVertexArray = + getBooleanProperty("j3d.compiledVertexArray", + isCompiledVertexArray, + "compiled vertex array"); + + boolean j3dOptimizeSpace = + getBooleanProperty("j3d.optimizeForSpace", true, + "optimize for space"); + + if (isDisplayList) { + // Build Display list for by-ref geometry + // ONLY IF optimizeForSpace is false + if (!j3dOptimizeSpace) { + buildDisplayListIfPossible = true; + } + + // Build display lists for geometry with vertex attributes + // ONLY if we are in GLSL mode and GLSL shaders are available + if (glslLibraryAvailable) { + vertexAttrsInDisplayList = true; + } + } + + // Check to see whether Renderer can run without DSI lock + doDsiRenderLock = getBooleanProperty("j3d.renderLock", + doDsiRenderLock, + "render lock"); + + // Check to see whether we enforce power-of-two textures + enforcePowerOfTwo = getBooleanProperty("j3d.textureEnforcePowerOfTwo", + enforcePowerOfTwo, + "checking power-of-two textures"); + + // Issue 249 - check to see whether the soleUser optimization is permitted + allowSoleUser = getBooleanProperty("j3d.allowSoleUser", + allowSoleUser, + "sole-user mode"); + + // Issue 266 - check to see whether null graphics configs are allowed + allowNullGraphicsConfig = getBooleanProperty("j3d.allowNullGraphicsConfig", + allowNullGraphicsConfig, + "null graphics configs"); + + // Issue 239 - check to see whether per-frame stencil clear is enabled + stencilClear = getBooleanProperty("j3d.stencilClear", + stencilClear, + "per-frame stencil clear"); + + // Check to see if stereo mode is sharing the Z-buffer for both eyes. + sharedStereoZBuffer = + getBooleanProperty("j3d.sharedstereozbuffer", + sharedStereoZBuffer, + "shared stereo Z buffer"); + + // Get the maximum number of concurrent threads (CPUs) + final int defaultThreadLimit = getNumberOfProcessors() + 1; + Integer threadLimit = + (Integer) java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + return Integer.getInteger("j3d.threadLimit", + defaultThreadLimit); + } + }); + + cpuLimit = threadLimit.intValue(); + if (cpuLimit < 1) + cpuLimit = 1; + if (J3dDebug.debug || cpuLimit != defaultThreadLimit) { + System.err.println("Java 3D: concurrent threadLimit = " + + cpuLimit); + } + + // Get the input device scheduler sampling time + Integer samplingTime = + (Integer) java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + return Integer.getInteger("j3d.deviceSampleTime", 0); + } + }); + + if (samplingTime.intValue() > 0) { + InputDeviceScheduler.samplingTime = + samplingTime.intValue(); + System.err.println("Java 3D: Input device sampling time = " + + samplingTime + " ms"); + } + + // Get the glslVertexAttrOffset + final int defaultGLSLVertexAttrOffset = glslVertexAttrOffset; + Integer vattrOffset = + (Integer) java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + return Integer.getInteger("j3d.glslVertexAttrOffset", + defaultGLSLVertexAttrOffset); + } + }); + + glslVertexAttrOffset = vattrOffset.intValue(); + if (glslVertexAttrOffset < 1) { + glslVertexAttrOffset = 1; + } + if (J3dDebug.debug || glslVertexAttrOffset != defaultGLSLVertexAttrOffset) { + System.err.println("Java 3D: glslVertexAttrOffset = " + + glslVertexAttrOffset); + } + + // See if Xinerama should be disabled for better performance. + boolean disableXinerama = false; + if (getProperty("j3d.disableXinerama") != null) { + disableXinerama = true; + } + + // Issue 480 : Cache bounds returned by getBounds() + cacheAutoComputedBounds = + getBooleanProperty("j3d.cacheAutoComputeBounds", + cacheAutoComputedBounds, + "Cache AutoCompute Bounds, accelerates getBounds()"); + + // Issue 544 + useBoxForGroupBounds = + getBooleanProperty("j3d.useBoxForGroupBounds", + useBoxForGroupBounds, + "Use of BoundingBox for group geometric bounds"); + + // Initialize the native J3D library + if (!Pipeline.getPipeline().initializeJ3D(disableXinerama)) { + throw new RuntimeException(J3dI18N.getString("MasterControl0")); + } + + if (xineramaDisabled) { + // initializeJ3D() successfully disabled Xinerama. + System.err.println("Java 3D: Xinerama disabled"); + } + else if (disableXinerama) { + // j3d.disableXinerama is true, but attempt failed. + System.err.println("Java 3D: could not disable Xinerama"); + } + + // Check for obsolete properties + String[] obsoleteProps = { + "j3d.backgroundtexture", + "j3d.forceNormalized", + "j3d.g2ddrawpixel", + "j3d.simulatedMultiTexture", + "j3d.useFreeLists", + }; + for (int i = 0; i < obsoleteProps.length; i++) { + if (getProperty(obsoleteProps[i]) != null) { + System.err.println("Java 3D: " + obsoleteProps[i] + " property ignored"); + } + } + + // Get the maximum Lights + maxLights = Pipeline.getPipeline().getMaximumLights(); + + // create the freelists + FreeListManager.createFreeLists(); + + // create an array canvas use registers + // The 32 limit can be lifted once the + // resourceXXXMasks in other classes + // are change not to use integer. + canvasIds = new boolean[32]; + for(int i=0; ibefore + * the MasterControl object is created. + */ + static void loadLibraries() { + assert !librariesLoaded; + + // Get platform system properties + String osName = getProperty("os.name").toLowerCase(); + String sunArchDataModel = getProperty("sun.arch.data.model"); + + // Set global flags based on platform architecture + isMacOs = osName != null && osName.startsWith("mac"); + isWindowsOs = osName != null && osName.startsWith("windows"); + boolean isWindowsVista = isWindowsOs && osName.indexOf("vista") != -1; + boolean is64Bit = (sunArchDataModel != null) && sunArchDataModel.equals("64"); + + // Issue 257: check to see if the sun.jnlp.applet.launcher property is set to true + String sunAppletLauncher = getProperty("sun.jnlp.applet.launcher"); + appletLauncher = Boolean.valueOf(sunAppletLauncher); + + if (isCoreLoggable(Level.CONFIG)) { + StringBuffer strBuf = new StringBuffer(); + strBuf.append("MasterControl.loadLibraries()\n"). + append(" osName [lower-case] = \""). + append(osName). + append("\""). + append(", sunArchDataModel = "). + append(sunArchDataModel). + append("\n"). + append(" is64Bit = "). + append(is64Bit). + append(", isWindowsOs = "). + append(isWindowsOs). + append(", isMacOs = "). + append(isMacOs). + append(", isWindowsVista = "). + append(isWindowsVista); + getCoreLogger().config(strBuf.toString()); + } + + // Initialize the Pipeline object associated with the + // renderer specified by the "j3d.rend" system property. + // + // XXXX : We should consider adding support for a more flexible, + // dynamic selection scheme via an API call. + + // Default rendering pipeline is the JOGL pipeline on MacOS and the + // native OpenGL pipeline on all other platforms. + Pipeline.Type pipelineType = + isMacOs ? Pipeline.Type.JOGL : Pipeline.Type.NATIVE_OGL; + + final String rendStr = getProperty("j3d.rend"); + boolean nativeOglRequested = false; + if (rendStr == null) { + // Use default pipeline + } else if (rendStr.equals("ogl") && !isMacOs) { + pipelineType = Pipeline.Type.NATIVE_OGL; + nativeOglRequested = true; + } else if (rendStr.equals("d3d") && isWindowsOs) { + pipelineType = Pipeline.Type.NATIVE_D3D; + } else if (rendStr.equals("jogl")) { + pipelineType = Pipeline.Type.JOGL; + } else if (rendStr.equals("noop")) { + pipelineType = Pipeline.Type.NOOP; + } else { + System.err.println("Java 3D: Unrecognized renderer: " + rendStr); + // Use default pipeline + } + + // Issue 452 : if we are on 32-bit Windows, then check whether we + // can and should use OpenGL. Note that we can't do this on 64-bit + // Windows until we have a 64-bit D3D pipeline. + if (isWindowsOs && !is64Bit && pipelineType == Pipeline.Type.NATIVE_OGL) { + if (!Pipeline.useNativeOgl(isWindowsVista, nativeOglRequested)) { + pipelineType = Pipeline.Type.NATIVE_D3D; + } + } + + // Construct the singleton Pipeline instance + Pipeline.createPipeline(pipelineType); + + // Get the global j3d.shadingLanguage system property + final String slStr = getProperty("j3d.shadingLanguage"); + if (slStr != null) { + boolean found = false; + if (slStr.equals("GLSL")) { + globalShadingLanguage = Shader.SHADING_LANGUAGE_GLSL; + found = true; + } else if (slStr.equals("Cg")) { + globalShadingLanguage = Shader.SHADING_LANGUAGE_CG; + found = true; + } + + if (found) { + System.err.println("Java 3D: Setting global shading language to " + slStr); + } else { + System.err.println("Java 3D: Unrecognized shading language: " + slStr); + } + } + + // Load all required libraries + Pipeline.getPipeline().loadLibraries(globalShadingLanguage); + + // Check whether the Cg library is available + if (globalShadingLanguage == Shader.SHADING_LANGUAGE_CG) { + cgLibraryAvailable = Pipeline.getPipeline().isCgLibraryAvailable(); + } + + // Check whether the GLSL library is available + if (globalShadingLanguage == Shader.SHADING_LANGUAGE_GLSL) { + glslLibraryAvailable = Pipeline.getPipeline().isGLSLLibraryAvailable(); + } + + assert !(glslLibraryAvailable && cgLibraryAvailable) : + "ERROR: cannot support both GLSL and CG at the same time"; + + librariesLoaded = true; + } + + + /** + * Invoke from InputDeviceScheduler to create an + * InputDeviceBlockingThread. + */ + InputDeviceBlockingThread getInputDeviceBlockingThread( + final InputDevice device) { + + return (InputDeviceBlockingThread) + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + synchronized (rootThreadGroup) { + Thread thread = new InputDeviceBlockingThread( + rootThreadGroup, device); + thread.setPriority(threadPriority); + return thread; + } + } + } + ); + } + + /** + * Set thread priority to all threads under Java3D thread group. + */ + void setThreadPriority(final int pri) { + synchronized (rootThreadGroup) { + threadPriority = pri; + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + Thread list[] = new + Thread[rootThreadGroup.activeCount()]; + int count = rootThreadGroup.enumerate(list); + for (int i=count-1; i >=0; i--) { + list[i].setPriority(pri); + } + return null; + } + }); + } + } + + + /** + * Return Java3D thread priority + */ + int getThreadPriority() { + return threadPriority; + } + + /** + * This returns the a unused renderer bit + */ + int getRendererBit() { + return (1 << rendererCount++); + } + + + /** + * This returns the a unused renderer bit + */ + int getRendererId() { + return rendererCount++; + } + + /** + * This returns a context creation time stamp + * Note: this has to be called under the contextCreationLock + */ + long getContextTimeStamp() { + return (++contextTimeStamp); + } + + + /** + * This returns the a unused displayListId + */ + Integer getDisplayListId() { + return (Integer) FreeListManager.getObject(FreeListManager.DISPLAYLIST); + } + + void freeDisplayListId(Integer id) { + FreeListManager.freeObject(FreeListManager.DISPLAYLIST, id); + } + + /** + * This returns the a unused textureId + */ + int getTexture2DId() { + // MasterControl has to handle the ID itself. 2D and 3D ideas must + // never be the same, so the counter has to be in the MasterControl + MemoryFreeList textureIds = + FreeListManager.getFreeList(FreeListManager.TEXTURE2D); + int id; + + synchronized (textureIdLock) { + if (textureIds.size() > 0) { + id = ((Integer)FreeListManager. + getObject(FreeListManager.TEXTURE2D)).intValue(); + } else { + id = (++textureIdCount); + } + return id; + } + } + + int getTexture3DId() { + // MasterControl has to handle the ID itself. 2D and 3D ideas must + // never be the same, so the counter has to be in the MasterControl + MemoryFreeList textureIds = + FreeListManager.getFreeList(FreeListManager.TEXTURE3D); + synchronized (textureIdLock) { + if (textureIds.size > 0) { + return ((Integer)FreeListManager. + getObject(FreeListManager.TEXTURE3D)).intValue(); + } + else return (++textureIdCount); + } + } + + void freeTexture2DId(int id) { + FreeListManager.freeObject(FreeListManager.TEXTURE2D, new Integer(id)); + } + + void freeTexture3DId(int id) { + FreeListManager.freeObject(FreeListManager.TEXTURE3D, new Integer(id)); + } + + int getCanvasId() { + int i; + + synchronized(canvasIdLock) { + // Master control need to keep count itself + for(i=canvasFreeIndex; i= canvasIds.length) { + throw new RuntimeException("Cannot render to more than 32 Canvas3Ds"); + } + + canvasIds[i] = true; + canvasFreeIndex = i + 1; + } + + return i; + + } + + void freeCanvasId(int canvasId) { + // Valid range is [0, 31] + synchronized(canvasIdLock) { + + canvasIds[canvasId] = false; + if(canvasFreeIndex > canvasId) { + canvasFreeIndex = canvasId; + } + } + } + + + /** + * Create a Renderer if it is not already done so. + * This is used for GraphicsConfigTemplate3D passing + * graphics call to RequestRenderer, and for creating + * an off-screen buffer for an off-screen Canvas3D. + */ + private Renderer createRenderer(GraphicsConfiguration gc) { + final GraphicsDevice gd = gc.getDevice(); + + Renderer rdr = (Renderer) Screen3D.deviceRendererMap.get(gd); + if (rdr != null) { + return rdr; + } + + + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + Renderer r; + synchronized (rootThreadGroup) { + r = new Renderer(rootThreadGroup); + r.initialize(); + r.setPriority(threadPriority); + Screen3D.deviceRendererMap.put(gd, r); + } + return null; + } + }); + + threadListsChanged = true; + + return (Renderer) Screen3D.deviceRendererMap.get(gd); + } + + /** + * Post the request in queue + */ + void postRequest(Integer type, Object obj) { + + synchronized (mcThreadLock) { + synchronized (requestObjList) { + if (mcThread == null) { + if ((type == ACTIVATE_VIEW) || + (type == GETBESTCONFIG) || + (type == SET_VIEW) || + (type == ISCONFIGSUPPORT) || + (type == SET_QUERYPROPERTIES) || + (type == SET_GRAPHICSCONFIG_FEATURES)) { + createMasterControlThread(); + requestObjList.add(obj); + requestTypeList.add(type); + pendingRequest = true; + } else if (type == EMPTY_UNIVERSE) { + destroyUniverseThreads((VirtualUniverse) obj); + } else if (type == STOP_VIEW) { + View v = (View) obj; + v.stopViewCount = -1; + v.isRunning = false; + } else if (type == STOP_RENDERER) { + if (obj instanceof Canvas3D) { + ((Canvas3D) obj).isRunningStatus = false; + } else { + ((Renderer) obj).userStop = true; + } + } else if (type == UNREGISTER_VIEW) { + ((View) obj).doneUnregister = true; + } else { + requestObjList.add(obj); + requestTypeList.add(type); + pendingRequest = true; + } + } else { + requestObjList.add(obj); + requestTypeList.add(type); + pendingRequest = true; + } + } + } + + setWork(); + } + + + + + /** + * This procedure is invoked when isRunning is false. + * Return true when there is no more pending request so that + * Thread can terminate. Otherwise we have to recreate + * the MC related threads. + */ + boolean mcThreadDone() { + synchronized (mcThreadLock) { + synchronized (requestObjList) { + if (!pendingRequest) { + mcThread = null; + if (renderingAttributesStructure.updateThread != + null) { + renderingAttributesStructure.updateThread.finish(); + renderingAttributesStructure.updateThread = + null; + } + renderingAttributesStructure = new RenderingAttributesStructure(); + if (timerThread != null) { + timerThread.finish(); + timerThread = null; + } + if (notificationThread != null) { + notificationThread.finish(); + notificationThread = null; + } + requestObjList.clear(); + requestTypeList.clear(); + return true; + } + running = true; + createMCThreads(); + return false; + } + } + } + + /** + * Returns whether we are using D3D. + * TODO: most code that cares about this should move into the pipeline + */ + final boolean isD3D() { + return Pipeline.getPipeline().getPipelineType() == Pipeline.Type.NATIVE_D3D; + } + + /** + * Returns whether we are running on Windows + * TODO: most code that cares about this should move into the pipeline + */ + static final boolean isWindows() { + return isWindowsOs; + } + + /** + * Returns a flag indicating whether the sun.jnlp.applet.launcher system + * property is set to true. + */ + static boolean isAppletLauncher() { + return appletLauncher; + } + + /** + * This method increments and returns the next time value + * timeLock must get before this procedure is invoked + */ + final long getTime() { + return (time++); + } + + + /** + * This takes a given message and parses it out to the structures and + * marks its time value. + */ + void processMessage(J3dMessage message) { + + synchronized (timeLock) { + message.time = getTime(); + sendMessage(message); + } + setWork(); + } + + /** + * This takes an array of messages and parses them out to the structures and + * marks the time value. Make sure, setWork() is done at the very end + * to make sure all the messages will be processed in the same frame + */ + void processMessage(J3dMessage[] messages) { + + synchronized (timeLock) { + long time = getTime(); + + for (int i = 0; i < messages.length; i++) { + messages[i].time = time; + sendMessage(messages[i]); + } + } + setWork(); + } + + /** + * This takes the specified notification message and sends it to the + * notification thread for processing. + */ + void sendNotification(J3dNotification notification) { + notificationThread.addNotification(notification); + } + + /** + * Create and start the MasterControl Thread. + */ + void createMasterControlThread() { + // Issue 364: don't create master control thread if already created + if (mcThread != null) { + return; + } + + running = true; + workToDo = true; + state = RUNNING; + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + synchronized (rootThreadGroup) { + mcThread = new + MasterControlThread(rootThreadGroup); + mcThread.setPriority(threadPriority); + } + return null; + } + }); + } + + // assuming the timeLock is already acquired + + /** + * Send a message to another Java 3D thread. + */ + void sendMessage(J3dMessage message) { + + synchronized (message) { + VirtualUniverse u = message.universe; + int targetThreads = message.threads; + + if (isCoreLoggable(Level.FINEST)) { + dumpMessage("sendMessage", message); + } + + if ((targetThreads & J3dThread.UPDATE_RENDERING_ATTRIBUTES) != 0) { + renderingAttributesStructure.addMessage(message); + } + + // GraphicsContext3D send message with universe = null + if (u != null) { + if ((targetThreads & J3dThread.UPDATE_GEOMETRY) != 0) { + u.geometryStructure.addMessage(message); + } + if ((targetThreads & J3dThread.UPDATE_TRANSFORM) != 0) { + u.transformStructure.addMessage(message); + } + if ((targetThreads & J3dThread.UPDATE_BEHAVIOR) != 0) { + u.behaviorStructure.addMessage(message); + } + if ((targetThreads & J3dThread.UPDATE_SOUND) != 0) { + u.soundStructure.addMessage(message); + } + if ((targetThreads & J3dThread.UPDATE_RENDERING_ENVIRONMENT) != 0) { + u.renderingEnvironmentStructure.addMessage(message); + } + } + + if ((targetThreads & J3dThread.SOUND_SCHEDULER) != 0) { + // Note that we don't check for active view + if (message.view != null && message.view.soundScheduler != null ) { + // This make sure that message won't lost even + // though this view not yet register + message.view.soundScheduler.addMessage(message); + } else { + synchronized (views) { + View v[] = (View []) views.toArray(false); + int i = views.arraySize()-1; + if (u == null) { + while (i>=0) { + v[i--].soundScheduler.addMessage(message); + } + } else { + while (i>=0) { + if (v[i].universe == u) { + v[i].soundScheduler.addMessage(message); + } + i--; + } + } + } + } + } + + if ((targetThreads & J3dThread.UPDATE_RENDER) != 0) { + // Note that we don't check for active view + if (message.view != null && message.view.renderBin != null) { + // This make sure that message won't lost even + // though this view not yet register + message.view.renderBin.addMessage(message); + } else { + synchronized (views) { + View v[] = (View []) views.toArray(false); + int i = views.arraySize()-1; + if (u == null) { + while (i>=0) { + v[i--].renderBin.addMessage(message); + } + } + else { + while (i>=0) { + if (v[i].universe == u) { + v[i].renderBin.addMessage(message); + } + i--; + } + } + } + } + } + + if (message.getRefcount() == 0) { + message.clear(); + } + } + } + + + /** + * Send a message to another Java 3D thread. + * This variant is only call by TimerThread for Input Device Scheduler + * or to redraw all View for RenderThread + */ + void sendRunMessage(int targetThreads) { + + synchronized (timeLock) { + + long time = getTime(); + + if ((targetThreads & J3dThread.INPUT_DEVICE_SCHEDULER) != 0) { + synchronized (inputDeviceThreads) { + InputDeviceScheduler ds[] = (InputDeviceScheduler []) + inputDeviceThreads.toArray(false); + for (int i=inputDeviceThreads.size()-1; i >=0; i--) { + if (ds[i].physicalEnv.activeViewRef > 0) { + ds[i].getThreadData().lastUpdateTime = + time; + } + } + + // timerThread instance in MC will set to null in + // destroyUniverseThreads() so we need to check if + // TimerThread kick in to sendRunMessage() after that. + // It happens because TimerThread is the only thread run + // asychronizously with MasterControl thread. + + if (timerThread != null) { + // Notify TimerThread to wakeup this procedure + // again next time. + timerThread.addInputDeviceSchedCond(); + } + } + } + if ((targetThreads & J3dThread.RENDER_THREAD) != 0) { + synchronized (renderThreadData) { + J3dThreadData[] threads = (J3dThreadData []) + renderThreadData.toArray(false); + int i=renderThreadData.arraySize()-1; + J3dThreadData thr; + while (i>=0) { + thr = threads[i--]; + if ( thr.view.renderBinReady) { + thr.lastUpdateTime = time; + } + } + } + } + } + setWork(); + } + + /** + * Send a message to another Java 3D thread. + * This variant is only call by TimerThread for Sound Scheduler + */ + void sendRunMessage(long waitTime, View view, int targetThreads) { + + synchronized (timeLock) { + + long time = getTime(); + + if ((targetThreads & J3dThread.SOUND_SCHEDULER) != 0) { + if (view.soundScheduler != null) { + view.soundScheduler.threadData.lastUpdateTime = time; + } + // wakeup this procedure next time + // QUESTION: waitTime calculated some milliseconds BEFORE + // this methods getTime() called - shouldn't actual + // sound Complete time be passed by SoundScheduler + // QUESTION: will this wake up only soundScheduler associated + // with this view?? (since only it's lastUpdateTime is set) + // or all soundSchedulers?? + timerThread.addSoundSchedCond(time+waitTime); + } + } + setWork(); + } + + /** + * Send a message to another Java 3D thread. + * This variant is only called to update Render Thread + */ + void sendRunMessage(View v, int targetThreads) { + + synchronized (timeLock) { + long time = getTime(); + + if ((targetThreads & J3dThread.RENDER_THREAD) != 0) { + synchronized (renderThreadData) { + J3dThreadData[] threads = (J3dThreadData []) + renderThreadData.toArray(false); + int i=renderThreadData.arraySize()-1; + J3dThreadData thr; + while (i>=0) { + thr = threads[i--]; + if (thr.view == v && v.renderBinReady) { + thr.lastUpdateTime = time; + } + } + } + } + } + setWork(); + } + + + /** + * This sends a run message to the given threads. + */ + void sendRunMessage(VirtualUniverse u, int targetThreads) { + // We don't sendRunMessage to update structure except Behavior + + synchronized (timeLock) { + long time = getTime(); + + if ((targetThreads & J3dThread.BEHAVIOR_SCHEDULER) != 0) { + if (u.behaviorScheduler != null) { + u.behaviorScheduler.getThreadData(null, + null).lastUpdateTime = time; + } + } + + if ((targetThreads & J3dThread.UPDATE_BEHAVIOR) != 0) { + u.behaviorStructure.threadData.lastUpdateTime = time; + } + + if ((targetThreads & J3dThread.UPDATE_GEOMETRY) != 0) { + u.geometryStructure.threadData.lastUpdateTime = time; + } + + if ((targetThreads & J3dThread.UPDATE_SOUND) != 0) { + u.soundStructure.threadData.lastUpdateTime = time; + } + + if ((targetThreads & J3dThread.SOUND_SCHEDULER) != 0) { + synchronized (views) { + View v[] = (View []) views.toArray(false); + for (int i= views.arraySize()-1; i >=0; i--) { + if ((v[i].soundScheduler != null) && + (v[i].universe == u)) { + v[i].soundScheduler.threadData.lastUpdateTime = time; + } + } + } + } + + if ((targetThreads & J3dThread.RENDER_THREAD) != 0) { + + synchronized (renderThreadData) { + J3dThreadData[] threads = (J3dThreadData []) + renderThreadData.toArray(false); + int i=renderThreadData.arraySize()-1; + J3dThreadData thr; + while (i>=0) { + thr = threads[i--]; + if (thr.view.universe == u && thr.view.renderBinReady) { + thr.lastUpdateTime = time; + } + } + } + } + } + + setWork(); + } + + + /** + * Return a clone of View, we can't access + * individual element of View after getting the size + * in separate API call without synchronized views. + */ + UnorderList cloneView() { + return (UnorderList) views.clone(); + } + + /** + * Return true if view is already registered with MC + */ + boolean isRegistered(View view) { + return views.contains(view); + } + + /** + * This snapshots the time values to be used for this iteration. + * Note that this method is called without the timeLock held. + * We must synchronize on timeLock to prevent updating + * thread.lastUpdateTime from user thread in sendMessage() + * or sendRunMessage(). + */ + private void updateTimeValues() { + synchronized (timeLock) { + int i=0; + J3dThreadData lastThread=null; + J3dThreadData thread=null; + long lastTime = currentTime; + + currentTime = getTime(); + + J3dThreadData threads[] = (J3dThreadData []) + stateWorkThreads.toArray(false); + int size = stateWorkThreads.arraySize(); + + while (i thread.lastRunTime) && + !thread.thread.userStop) { + lastThread = thread; + thread.needsRun = true; + thread.threadOpts = J3dThreadData.CONT_THREAD; + thread.lastRunTime = currentTime; + } else { + thread.needsRun = false; + } + } + + if (lastThread != null) { + lastThread.threadOpts = J3dThreadData.WAIT_ALL_THREADS; + lastThread = null; + } + + while (i thread.lastRunTime) && + !thread.thread.userStop) { + lastThread = thread; + thread.needsRun = true; + thread.threadOpts = J3dThreadData.CONT_THREAD; + thread.lastRunTime = currentTime; + } else { + thread.needsRun = false; + } + } + if (lastThread != null) { + lastThread.threadOpts = J3dThreadData.WAIT_ALL_THREADS; + lastThread = null; + } + + while (i thread.lastRunTime) && + !thread.thread.userStop) { + lastThread = thread; + thread.needsRun = true; + thread.threadOpts = J3dThreadData.CONT_THREAD; + thread.lastRunTime = currentTime; + } else { + thread.needsRun = false; + } + } + if (lastThread != null) { + lastThread.threadOpts = J3dThreadData.WAIT_ALL_THREADS; + lastThread = null; + } + + + threads = (J3dThreadData []) renderWorkThreads.toArray(false); + size = renderWorkThreads.arraySize(); + View v; + J3dThreadData lastRunThread = null; + waitTimestamp++; + sleepTime = 0L; + + boolean threadToRun = false; // Not currently used + + // Fix for Issue 12: loop through the list of threads, calling + // computeCycleTime() exactly once per view. This ensures that + // all threads for a given view see consistent values for + // isMinCycleTimeAchieve and sleepTime. + v = null; + for (i=0; i sleepTime) { + sleepTime = thread.view.sleepTime; + } + } + v = thread.view; + } + + v = null; + for (i=0; i thread.lastRunTime) && + !thread.thread.userStop) { + + if (thread.thread.lastWaitTimestamp == waitTimestamp) { + // This renderer thread is repeated. We must wait + // until all previous renderer threads done before + // allowing this thread to continue. Note that + // lastRunThread can't be null in this case. + waitTimestamp++; + if (thread.view != v) { + // A new View is start + v = thread.view; + threadToRun = true; + lastRunThread.threadOpts = + (J3dThreadData.STOP_TIMER | + J3dThreadData.WAIT_ALL_THREADS); + ((Object []) lastRunThread.threadArgs)[3] = lastRunThread.view; + thread.threadOpts = (J3dThreadData.START_TIMER | + J3dThreadData.CONT_THREAD); + } else { + if ((lastRunThread.threadOpts & + J3dThreadData.START_TIMER) != 0) { + lastRunThread.threadOpts = + (J3dThreadData.START_TIMER | + J3dThreadData.WAIT_ALL_THREADS); + + } else { + lastRunThread.threadOpts = + J3dThreadData.WAIT_ALL_THREADS; + } + thread.threadOpts = J3dThreadData.CONT_THREAD; + + } + } else { + if (thread.view != v) { + v = thread.view; + threadToRun = true; + // Although the renderer thread is not + // repeated. We still need to wait all + // previous renderer threads if new View + // start. + if (lastRunThread != null) { + lastRunThread.threadOpts = + (J3dThreadData.STOP_TIMER | + J3dThreadData.WAIT_ALL_THREADS); + ((Object []) lastRunThread.threadArgs)[3] + = lastRunThread.view; + } + thread.threadOpts = (J3dThreadData.START_TIMER | + J3dThreadData.CONT_THREAD); + } else { + thread.threadOpts = J3dThreadData.CONT_THREAD; + } + } + thread.thread.lastWaitTimestamp = waitTimestamp; + thread.needsRun = true; + thread.lastRunTime = currentTime; + lastRunThread = thread; + } else { + thread.needsRun = false; + } + } + + + if (lastRunThread != null) { + lastRunThread.threadOpts = + (J3dThreadData.STOP_TIMER | + J3dThreadData.WAIT_ALL_THREADS| + J3dThreadData.LAST_STOP_TIMER); + lockGeometry = true; + ((Object []) lastRunThread.threadArgs)[3] = lastRunThread.view; + } else { + lockGeometry = false; + } + } + + // Issue 275 - go to sleep without holding timeLock + // Sleep for the amount of time needed to satisfy the minimum + // cycle time for all views. + if (sleepTime > 0) { + // System.err.println("MasterControl: sleep(" + sleepTime + ")"); + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + System.err.println(e); + } + // System.err.println("MasterControl: done sleeping"); + } + } + + private void createUpdateThread(J3dStructure structure) { + final J3dStructure s = structure; + + if (s.updateThread == null) { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + synchronized (rootThreadGroup) { + s.updateThread = new StructureUpdateThread( + rootThreadGroup, s, s.threadType); + s.updateThread.setPriority(threadPriority); + } + return null; + } + }); + s.updateThread.initialize(); + s.threadData.thread = s.updateThread; + // This takes into accout for thread that just destroy and + // create again. In this case the threadData may receive + // message before the thread actually created. We don't want + // the currentTime to overwrite the update time of which + // is set by threadData when get message. + s.threadData.lastUpdateTime = Math.max(currentTime, + s.threadData.lastUpdateTime); + } + } + + private void emptyMessageList(J3dStructure structure, View v) { + if (structure != null) { + if (v == null) { + if (structure.threadData != null) { + structure.threadData.thread = null; + } + + if (structure.updateThread != null) { + structure.updateThread.structure = null; + } + structure.updateThread = null; + } + boolean otherViewExist = false; + if ((v != null) && (v.universe != null)) { + // Check if there is any other View register with the + // same universe + for (int i=views.size()-1; i >= 0; i--) { + if (((View) views.get(i)).universe == v.universe) { + otherViewExist = true; + break; + } + } + } + + + UnorderList mlist = structure.messageList; + // Note that message is add at the end of array + synchronized (mlist) { + int size = mlist.size(); + if (size > 0) { + J3dMessage mess[] = (J3dMessage []) mlist.toArray(false); + J3dMessage m; + int i = 0; + + Object oldRef= null; + while (i < size) { + m = mess[i]; + if ((v == null) || (m.view == v) || + ((m.view == null) && !otherViewExist)) { + if (m.type == J3dMessage.INSERT_NODES) { + // There is another View register request + // immediately following, so no need + // to remove message. + break; + } + // Some other thread may still using this + // message so we should not directly + // add this message to free lists + m.decRefcount(); + mlist.removeOrdered(i); + size--; + } else { + i++; + } + } + } + } + } + } + + private void destroyUpdateThread(J3dStructure structure) { + // If unregisterView message got before EMPTY_UNIVERSE + // message, then updateThread is already set to null. + if (structure.updateThread != null) { + structure.updateThread.finish(); + structure.updateThread.structure = null; + structure.updateThread = null; + } + structure.threadData.thread = null; + structure.clearMessages(); + } + + /** + * This register a View with MasterControl. + * The View has at least one Canvas3D added to a container. + */ + private void registerView(View v) { + final VirtualUniverse univ = v.universe; + + if (views.contains(v) && regUniverseList.contains(univ)) { + return; // already register + } + + if (timerThread == null) { + // This handle the case when MC shutdown and restart in + // a series of pending request + running = true; + createMCThreads(); + } + // If viewId is null, assign one .. + v.assignViewId(); + + // Create thread if not done before + createUpdateThread(univ.behaviorStructure); + createUpdateThread(univ.geometryStructure); + createUpdateThread(univ.soundStructure); + createUpdateThread(univ.renderingEnvironmentStructure); + createUpdateThread(univ.transformStructure); + + // create Behavior scheduler + J3dThreadData threadData = null; + + if (univ.behaviorScheduler == null) { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + synchronized (rootThreadGroup) { + univ.behaviorScheduler = new BehaviorScheduler( + rootThreadGroup, univ); + univ.behaviorScheduler.setPriority(threadPriority); + } + return null; + } + }); + univ.behaviorScheduler.initialize(); + univ.behaviorScheduler.userStop = v.stopBehavior; + threadData = univ.behaviorScheduler.getThreadData(null, null); + threadData.thread = univ.behaviorScheduler; + threadData.threadType = J3dThread.BEHAVIOR_SCHEDULER; + threadData.lastUpdateTime = Math.max(currentTime, + threadData.lastUpdateTime); + } + + createUpdateThread(v.renderBin); + createUpdateThread(v.soundScheduler); + + if (v.physicalEnvironment != null) { + v.physicalEnvironment.addUser(v); + } + // create InputDeviceScheduler + evaluatePhysicalEnv(v); + + regUniverseList.addUnique(univ); + views.addUnique(v); + } + + + + /** + * This unregister a View with MasterControl. + * The View no longer has any Canvas3Ds in a container. + */ + private void unregisterView(View v) { + + if (!views.remove(v)) { + v.active = false; + v.doneUnregister = true; + return; // already unregister + } + + if (v.active) { + viewDeactivate(v); + } + + if(J3dDebug.devPhase) { + J3dDebug.doDebug(J3dDebug.masterControl, J3dDebug.LEVEL_1, + "MC: Destroy Sound Scheduler and RenderBin Update thread"); + } + + v.soundScheduler.updateThread.finish(); + v.renderBin.updateThread.finish(); + v.soundScheduler.updateThread = null; + v.renderBin.updateThread = null; + + // remove VirtualUniverse related threads if Universe + // is empty + VirtualUniverse univ = v.universe; + int i; + + synchronized (timeLock) { + // The reason we need to sync. with timeLock is because we + // don't want user thread running sendMessage() to + // dispatch it in different structure queue when + // part of the structure list is empty at the same time. + // This will cause inconsistence in the message reference + // count. + emptyMessageList(v.soundScheduler, v); + emptyMessageList(v.renderBin, v); + + if (univ.isEmpty()) { + destroyUniverseThreads(univ); + } else { + emptyMessageList(univ.behaviorStructure, v); + emptyMessageList(univ.geometryStructure, v); + emptyMessageList(univ.soundStructure, v); + emptyMessageList(univ.renderingEnvironmentStructure, v); + emptyMessageList(univ.transformStructure, v); + } + } + + if (v.physicalEnvironment != null) { + v.physicalEnvironment.removeUser(v); + } + + // remove all InputDeviceScheduler if this is the last View + UnorderList list = new UnorderList(1, PhysicalEnvironment.class); + for (Enumeration e = PhysicalEnvironment.physicalEnvMap.keys(); + e.hasMoreElements(); ) { + PhysicalEnvironment phyEnv = (PhysicalEnvironment) e.nextElement(); + InputDeviceScheduler sched = (InputDeviceScheduler) + PhysicalEnvironment.physicalEnvMap.get(phyEnv); + for (i=phyEnv.users.size()-1; i>=0; i--) { + if (views.contains((View) phyEnv.users.get(i))) { + // at least one register view refer to it. + break; + } + } + if (i < 0) { + if(J3dDebug.devPhase) { + J3dDebug.doDebug(J3dDebug.masterControl, J3dDebug.LEVEL_1, + "MC: Destroy InputDeviceScheduler thread " + + sched); + } + sched.finish(); + phyEnv.inputsched = null; + list.add(phyEnv); + } + } + for (i=list.size()-1; i>=0; i--) { + PhysicalEnvironment.physicalEnvMap.remove(list.get(i)); + } + + + freeContext(v); + + if (views.isEmpty()) { + if(J3dDebug.devPhase) { + J3dDebug.doDebug(J3dDebug.masterControl, J3dDebug.LEVEL_1, + "MC: Destroy all Renderers"); + } + // remove all Renderers if this is the last View + for (Enumeration e = Screen3D.deviceRendererMap.elements(); + e.hasMoreElements(); ) { + Renderer rdr = (Renderer) e.nextElement(); + Screen3D scr; + + rendererCleanupArgs[2] = REMOVEALLCTXS_CLEANUP; + runMonitor(RUN_RENDERER_CLEANUP, null, null, null, rdr); + scr = rdr.onScreen; + if (scr != null) { + if (scr.renderer != null) { + rendererCleanupArgs[2] = REMOVEALLCTXS_CLEANUP; + runMonitor(RUN_RENDERER_CLEANUP, null, null, + null, scr.renderer); + scr.renderer = null; + } + + } + scr = rdr.offScreen; + if (scr != null) { + if (scr.renderer != null) { + rendererCleanupArgs[2] = REMOVEALLCTXS_CLEANUP; + runMonitor(RUN_RENDERER_CLEANUP, null, null, + null, scr.renderer); + scr.renderer = null; + } + } + rdr.onScreen = null; + rdr.offScreen = null; + } + + // cleanup ThreadData corresponds to the view in renderer + for (Enumeration e = Screen3D.deviceRendererMap.elements(); + e.hasMoreElements(); ) { + Renderer rdr = (Renderer) e.nextElement(); + rdr.cleanup(); + } + // We have to reuse renderer even though MC exit + // see bug 4363279 + // Screen3D.deviceRendererMap.clear(); + + } else { + // cleanup ThreadData corresponds to the view in renderer + for (Enumeration e = Screen3D.deviceRendererMap.elements(); + e.hasMoreElements(); ) { + Renderer rdr = (Renderer) e.nextElement(); + rdr.cleanupView(); + } + } + + + freeMessageList.add(univ); + freeMessageList.add(v); + + evaluateAllCanvases(); + stateWorkThreads.clear(); + renderWorkThreads.clear(); + requestRenderWorkThreads.clear(); + threadListsChanged = true; + + // This notify VirtualUniverse waitForMC() thread to continue + v.doneUnregister = true; + } + + + /** + * This procedure create MC thread that start together with MC. + */ + void createMCThreads() { + + // There is only one renderingAttributesUpdate Thread globally + createUpdateThread(renderingAttributesStructure); + + // Create timer thread + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + synchronized (rootThreadGroup) { + timerThread = new TimerThread(rootThreadGroup); + timerThread.setPriority(threadPriority); + } + return null; + } + }); + timerThread.start(); + + // Create notification thread + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + synchronized (rootThreadGroup) { + notificationThread = new NotificationThread(rootThreadGroup); + notificationThread.setPriority(threadPriority); + } + return null; + } + }); + notificationThread.start(); + } + + /** + * Destroy all VirtualUniverse related threads. + * This procedure may call two times when Locale detach in a + * live viewPlatform. + */ + private void destroyUniverseThreads(VirtualUniverse univ) { + + if (regUniverseList.contains(univ)) { + if (J3dDebug.devPhase) { + J3dDebug.doDebug(J3dDebug.masterControl, J3dDebug.LEVEL_1, + "MC: Destroy universe threads " + univ); + } + destroyUpdateThread(univ.behaviorStructure); + destroyUpdateThread(univ.geometryStructure); + destroyUpdateThread(univ.soundStructure); + destroyUpdateThread(univ.renderingEnvironmentStructure); + destroyUpdateThread(univ.transformStructure); + univ.behaviorScheduler.finish(); + univ.behaviorScheduler.free(); + univ.behaviorScheduler = null; + univ.initMCStructure(); + activeUniverseList.remove(univ); + regUniverseList.remove(univ); + } else { + emptyMessageList(univ.behaviorStructure, null); + emptyMessageList(univ.geometryStructure, null); + emptyMessageList(univ.soundStructure, null); + emptyMessageList(univ.renderingEnvironmentStructure, null); + emptyMessageList(univ.transformStructure, null); + } + + if (regUniverseList.isEmpty() && views.isEmpty()) { + if(J3dDebug.devPhase) { + J3dDebug.doDebug(J3dDebug.masterControl, J3dDebug.LEVEL_1, + "MC: Destroy RenderingAttributes Update and Timer threads"); + } + if (renderingAttributesStructure.updateThread != null) { + renderingAttributesStructure.updateThread.finish(); + renderingAttributesStructure.updateThread = null; + } + renderingAttributesStructure.messageList.clear(); + renderingAttributesStructure.objList = new ArrayList(); + renderingAttributesStructure = new RenderingAttributesStructure(); + if (timerThread != null) { + timerThread.finish(); + timerThread = null; + } + if (notificationThread != null) { + notificationThread.finish(); + notificationThread = null; + } + + // shouldn't all of these be synchronized ??? + synchronized (VirtualUniverse.mc.deviceScreenMap) { + deviceScreenMap.clear(); + } + + mirrorObjects.clear(); + // Note: We should not clear the DISPLAYLIST/TEXTURE + // list here because other structure may release them + // later + + for(int i=0; i=0; i--) { + viewArr[i].getCanvasList(true); // force canvas cache update + Screen3D screens[] = viewArr[i].getScreens(); + for (int j=screens.length-1; j>=0; j--) { + screens[j].canvasCount = 0; + } + } + + + // Third create render thread and message thread + for (int i=views.size()-1; i>=0; i--) { + View v = viewArr[i]; + Canvas3D canvasList[][] = v.getCanvasList(false); + if (!v.active) { + continue; + } + + for (int j=canvasList.length-1; j>=0; j--) { + boolean added = false; + + for (int k=canvasList[j].length-1; k>=0; k--) { + Canvas3D cv = canvasList[j][k]; + + final Screen3D screen = cv.screen; + + if (cv.active) { + if (screen.canvasCount++ == 0) { + // Create Renderer, one per screen + if (screen.renderer == null) { + // get the renderer created for the graphics + // device of the screen of the canvas + // No need to synchronized since only + // MC use it. + Renderer rdr = + (Renderer) screen.deviceRendererMap.get( + cv.screen.graphicsDevice); + if (rdr == null) { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + + synchronized (rootThreadGroup) { + screen.renderer + = new Renderer( + rootThreadGroup); + screen.renderer.setPriority(threadPriority); + } + return null; + } + }); + screen.renderer.initialize(); + screen.deviceRendererMap.put( + screen.graphicsDevice, screen.renderer); + } else { + screen.renderer = rdr; + } + } + } + // offScreen canvases will be handled by the + // request renderer, so don't add offScreen canvas + // the render list + // + // Issue 131: Automatic offscreen canvases need to + // be added to onscreen list. Special case. + // + // TODO KCR Issue 131: this should probably be + // changed to a list of screens since multiple + // off-screen canvases (either auto or manual) can + // be used by the same renderer + if (!cv.manualRendering) { + screen.renderer.onScreen = screen; + } else { + screen.renderer.offScreen = screen; + continue; + } + + if (!added) { + // Swap message data thread, one per + // screen only. Note that we don't set + // lastUpdateTime for this thread so + // that it won't run in the first round + J3dThreadData renderData = + screen.renderer.getThreadData(v, null); + renderThreadData.add(renderData); + + // only if renderBin is ready then we + // update the lastUpdateTime to make it run + if (v.renderBinReady) { + renderData.lastUpdateTime = + Math.max(currentTime, + renderData.lastUpdateTime); + } + added = true; + } + // Renderer message data thread + J3dThreadData renderData = + screen.renderer.getThreadData(v, cv); + renderThreadData.add(renderData); + if (v.renderBinReady) { + renderData.lastUpdateTime = + Math.max(currentTime, + renderData.lastUpdateTime); + } + } + } + } + + } + } + + threadListsChanged = true; + } + + private void evaluatePhysicalEnv(View v) { + final PhysicalEnvironment env = v.physicalEnvironment; + + if (env.inputsched == null) { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + synchronized (rootThreadGroup) { + env.inputsched = new InputDeviceScheduler( + rootThreadGroup, + env); + env.inputsched.setPriority(threadPriority); + } + return null; + } + }); + env.inputsched.start(); + PhysicalEnvironment.physicalEnvMap.put(env, env.inputsched); + } + threadListsChanged = true; + } + + final private void addToStateThreads(J3dThreadData threadData) { + if (threadData.thread.active) { + stateWorkThreads.add(threadData); + } + } + + + private void assignNewPrimaryView(VirtualUniverse univ) { + + View currentPrimary = univ.getCurrentView(); + + if (currentPrimary != null) { + currentPrimary.primaryView = false; + } + + View v[] = (View []) views.toArray(false); + int nviews = views.size(); + for (int i=0; i=0; j--) { + for (int k=canvasList[j].length-1; k>=0; k--) { + Canvas3D cv = canvasList[j][k]; + if (!cv.validCanvas) { + if ((cv.screen != null) && + (cv.screen.renderer != null)) { + rendererCleanupArgs[1] = cv; + rendererCleanupArgs[2] = FREECONTEXT_CLEANUP; + runMonitor(RUN_RENDERER_CLEANUP, null, null, null, + cv.screen.renderer); + rendererCleanupArgs[1] = null; + } + } + } + } + } + + /** + * This notifies MasterControl that the given view has been deactivated + */ + private void viewDeactivate(View v) { + + if (!views.contains(v) || !v.active) { + v.active = false; + evaluateAllCanvases(); + return; + } + + VirtualUniverse univ = v.universe; + + if (v.isRunning) { + // if stopView() invoke before, no need to decrement count + --numActiveViews; + --univ.activeViewCount; + } + + if (numActiveViews == 0) { + renderingAttributesStructure.updateThread.active = false; + } + + if (univ.activeViewCount == 0) { + // check if destroyUniverseThread invoked before + if (univ.behaviorScheduler != null) { + univ.behaviorScheduler.deactivate(); + univ.transformStructure.updateThread.active = false; + univ.geometryStructure.updateThread.active = false; + univ.behaviorStructure.updateThread.active = false; + univ.soundStructure.updateThread.active = false; + univ.renderingEnvironmentStructure.updateThread.active + = false; + activeUniverseList.remove(univ); + } + } + + v.soundScheduler.deactivate(); + v.renderBin.updateThread.active = false; + v.active = false; + if (--v.physicalEnvironment.activeViewRef == 0) { + v.physicalEnvironment.inputsched.deactivate(); + } + assignNewPrimaryView(univ); + + + evaluateAllCanvases(); + + freeContext(v); + + v.inRenderThreadData = false; + threadListsChanged = true; + } + + + /** + * This notifies MasterControl to start given view + */ + private void startView(View v) { + + if (!views.contains(v) || v.isRunning || !v.active) { + v.isRunning = true; + return; + } + + numActiveViews++; + renderingAttributesStructure.updateThread.active = true; + + VirtualUniverse univ = v.universe; + + univ.activeViewCount++; + univ.transformStructure.updateThread.active = true; + univ.geometryStructure.updateThread.active = true; + univ.soundStructure.updateThread.active = true; + univ.renderingEnvironmentStructure.updateThread.active = true; + v.renderBin.updateThread.active = true; + v.soundScheduler.activate(); + v.isRunning = true; + if (univ.getCurrentView() == null) { + assignNewPrimaryView(univ); + } + threadListsChanged = true; + } + + + /** + * This notifies MasterControl to stop given view + */ + private void stopView(View v) { + if (!views.contains(v) || !v.isRunning || !v.active) { + v.isRunning = false; + return; + } + + if (--numActiveViews == 0) { + renderingAttributesStructure.updateThread.active = false; + } + VirtualUniverse univ = v.universe; + + if (--univ.activeViewCount == 0) { + univ.transformStructure.updateThread.active = false; + univ.geometryStructure.updateThread.active = false; + univ.renderingEnvironmentStructure.updateThread.active = false; + univ.soundStructure.updateThread.active = false; + } + + v.renderBin.updateThread.active = false; + v.soundScheduler.deactivate(); + v.isRunning = false; + assignNewPrimaryView(univ); + threadListsChanged = true; + } + + // Call from user thread + void addInputDeviceScheduler(InputDeviceScheduler ds) { + synchronized (inputDeviceThreads) { + inputDeviceThreads.add(ds); + if (inputDeviceThreads.size() == 1) { + timerThread.addInputDeviceSchedCond(); + } + } + postRequest(INPUTDEVICE_CHANGE, null); + } + + // Call from user thread + void removeInputDeviceScheduler(InputDeviceScheduler ds) { + inputDeviceThreads.remove(ds); + postRequest(INPUTDEVICE_CHANGE, null); + } + + /** + * Add an object to the mirror object list + */ + void addMirrorObject(ObjectUpdate o) { + mirrorObjects.add(o); + } + + /** + * This updates any mirror objects. It is called when threads + * are done. + */ + void updateMirrorObjects() { + ObjectUpdate objs[] = (ObjectUpdate []) mirrorObjects.toArray(false); + int sz = mirrorObjects.arraySize(); + + for (int i = 0; i< sz; i++) { + objs[i].updateObject(); + } + mirrorObjects.clear(); + } + + + /** + * This fun little method does all the hard work of setting up the + * work thread list. + */ + private void updateWorkThreads() { + + stateWorkThreads.clear(); + renderWorkThreads.clear(); + requestRenderWorkThreads.clear(); + + // First the global rendering attributes structure update + if (numActiveViews > 0) { + addToStateThreads(renderingAttributesStructure.getUpdateThreadData()); + } + + // Next, each of the transform structure updates + VirtualUniverse universes[] = (VirtualUniverse []) + activeUniverseList.toArray(false); + VirtualUniverse univ; + int i; + int size = activeUniverseList.arraySize(); + + for (i=size-1; i>=0; i--) { + addToStateThreads(universes[i].transformStructure.getUpdateThreadData()); + } + lastTransformStructureThread = stateWorkThreads.size(); + + // Next, the GeometryStructure, BehaviorStructure, + // RenderingEnvironmentStructure, and SoundStructure + for (i=size-1; i>=0; i--) { + univ = universes[i]; + addToStateThreads(univ.geometryStructure.getUpdateThreadData()); + addToStateThreads(univ.behaviorStructure.getUpdateThreadData()); + addToStateThreads(univ.renderingEnvironmentStructure.getUpdateThreadData()); + addToStateThreads(univ.soundStructure.getUpdateThreadData()); + } + + lastStructureUpdateThread = stateWorkThreads.size(); + + // Next, the BehaviorSchedulers + for (i=size-1; i>=0; i--) { + addToStateThreads(universes[i].behaviorScheduler. + getThreadData(null, null)); + } + + + // Now InputDeviceScheduler + + InputDeviceScheduler ds[] = (InputDeviceScheduler []) + inputDeviceThreads.toArray(true); + for (i=inputDeviceThreads.size()-1; i >=0; i--) { + J3dThreadData threadData = ds[i].getThreadData(); + threadData.thread.active = true; + addToStateThreads(threadData); + } + + // Now the RenderBins and SoundSchedulers + View viewArr[] = (View []) views.toArray(false); + J3dThreadData thread; + + for (i=views.size()-1; i>=0; i--) { + View v = viewArr[i]; + if (v.active && v.isRunning) { + addToStateThreads(v.renderBin.getUpdateThreadData()); + addToStateThreads(v.soundScheduler.getUpdateThreadData()); + Canvas3D canvasList[][] = v.getCanvasList(false); + int longestScreenList = v.getLongestScreenList(); + Object args[] = null; + // renderer render + for (int j=0; j=0; i--) { + if (v[i].active) { + v[i].updateViewCache(); + // update OrientedShape3D + if ((v[i].viewCache.vcDirtyMask != 0 && + !v[i].renderBin.orientedRAs.isEmpty()) || + (v[i].renderBin.cachedDirtyOrientedRAs != null && + !v[i].renderBin.cachedDirtyOrientedRAs.isEmpty())) { + v[i].renderBin.updateOrientedRAs(); + } + } + } + + runMonitor(RUN_THREADS, stateWorkThreads, renderWorkThreads, + requestRenderWorkThreads, null); + + if (renderOnceList.size() > 0) { + clearRenderOnceList(); + } + + manageMemory(); + + } + + private void handlePendingRequest() { + + Object objs[]; + Integer types[]; + int size; + boolean rendererRun = false; + + objs = requestObjList.toArray(false); + types = (Integer []) requestTypeList.toArray(false); + size = requestObjList.size(); + + for (int i=0; i < size; i++) { + // need to process request in order + Integer type = types[i]; + Object o = objs[i]; + if (type == RESET_CANVAS) { + Canvas3D cv = (Canvas3D) o; + if ((cv.screen != null) && + (cv.screen.renderer != null)) { + rendererCleanupArgs[1] = o; + rendererCleanupArgs[2] = RESETCANVAS_CLEANUP; + runMonitor(RUN_RENDERER_CLEANUP, null, null, null, + cv.screen.renderer); + rendererCleanupArgs[1] = null; + } + cv.reset(); + cv.view = null; + cv.computeViewCache(); + } + else if (type == ACTIVATE_VIEW) { + viewActivate((View) o); + } + else if (type == DEACTIVATE_VIEW) { + viewDeactivate((View) o); + } else if (type == REEVALUATE_CANVAS) { + evaluateAllCanvases(); + } else if (type == INPUTDEVICE_CHANGE) { + inputDeviceThreads.clearMirror(); + threadListsChanged = true; + } else if (type == START_VIEW) { + startView((View) o); + } else if (type == STOP_VIEW) { + View v = (View) o; + // Collision takes 3 rounds to finish its request + if (++v.stopViewCount > 4) { + v.stopViewCount = -1; // reset counter + stopView(v); + } else { + tempViewList.add(v); + } + } else if (type == UNREGISTER_VIEW) { + unregisterView((View) o); + } else if (type == PHYSICAL_ENV_CHANGE) { + evaluatePhysicalEnv((View) o); + } else if (type == EMPTY_UNIVERSE) { + // Issue 81: We need to process this message as long + // as there are no views associated with this + // universe. Previously, this message was ignored if + // there were views associated with *any* universe, + // which led to a memory / thread leak. + boolean foundView = false; + VirtualUniverse univ = (VirtualUniverse) o; + View v[] = (View []) views.toArray(false); + for (int j = views.size() - 1; j >= 0; j--) { + if (v[j].universe == univ) { + foundView = true; + break; + } + } + if (!foundView) { + destroyUniverseThreads(univ); + threadListsChanged = true; + } + } else if (type == START_RENDERER) { + if (o instanceof Canvas3D) { + Canvas3D c3d = (Canvas3D) o; + if (!c3d.isFatalError()) { + c3d.isRunningStatus = true; + } + } else { + ((Renderer) o).userStop = false; + } + threadListsChanged = true; + } else if (type == STOP_RENDERER) { + if (o instanceof Canvas3D) { + ((Canvas3D) o).isRunningStatus = false; + } else { + ((Renderer) o).userStop = true; + } + threadListsChanged = true; + } else if (type == RENDER_ONCE) { + View v = (View) o; + // temporary start View for renderonce + // it will stop afterwards + startView(v); + renderOnceList.add(v); + sendRunMessage(v, J3dThread.UPDATE_RENDER); + threadListsChanged = true; + rendererRun = true; + } else if (type == FREE_CONTEXT) { + Canvas3D cv = (Canvas3D ) ((Object []) o)[0]; + if ((cv.screen != null) && + (cv.screen.renderer != null)) { + rendererCleanupArgs[1] = o; + rendererCleanupArgs[2] = REMOVECTX_CLEANUP; + runMonitor(RUN_RENDERER_CLEANUP, null, null, null, + cv.screen.renderer); + rendererCleanupArgs[1] = null; + } + rendererRun = true; + } else if (type == FREE_DRAWING_SURFACE) { + Pipeline.getPipeline().freeDrawingSurfaceNative(o); + } else if (type == GETBESTCONFIG) { + GraphicsConfiguration gc = ((GraphicsConfiguration []) + ((GraphicsConfigTemplate3D) o).testCfg)[0]; + sendRenderMessage(gc, o, type); + rendererRun = true; + } else if (type == ISCONFIGSUPPORT) { + GraphicsConfiguration gc = (GraphicsConfiguration) + ((GraphicsConfigTemplate3D) o).testCfg; + sendRenderMessage(gc, o, type); + rendererRun = true; + } else if ((type == SET_GRAPHICSCONFIG_FEATURES) || + (type == SET_QUERYPROPERTIES)) { + GraphicsConfiguration gc = (GraphicsConfiguration) + ((Canvas3D) o).graphicsConfiguration; + sendRenderMessage(gc, o, type); + rendererRun = true; + } else if (type == SET_VIEW) { + Canvas3D cv = (Canvas3D) o; + cv.view = cv.pendingView; + cv.computeViewCache(); + } + } + + // Do it only after all universe/View is register + for (int i=0; i < size; i++) { + Integer type = types[i]; + if (type == FREE_MESSAGE) { + if (objs[i] instanceof VirtualUniverse) { + VirtualUniverse u = (VirtualUniverse) objs[i]; + if (!regUniverseList.contains(u)) { + emptyMessageList(u.behaviorStructure, null); + emptyMessageList(u.geometryStructure, null); + emptyMessageList(u.soundStructure, null); + emptyMessageList(u.renderingEnvironmentStructure, null); + } + } else if (objs[i] instanceof View) { + View v = (View) objs[i]; + if (!views.contains(v)) { + emptyMessageList(v.soundScheduler, v); + emptyMessageList(v.renderBin, v); + if (v.resetUnivCount == v.universeCount) { + v.reset(); + v.universe = null; + if (running == false) { + // MC is about to terminate + + /* + // Don't free list cause there may + // have some other thread returning ID + // after it. + FreeListManager.clearList(FreeListManager.DISPLAYLIST); + FreeListManager.clearList(FreeListManager.TEXTURE2D); + FreeListManager.clearList(FreeListManager.TEXTURE3D); + + synchronized (textureIdLock) { + textureIdCount = 0; + } + */ + } + } + } + } + + } + + } + requestObjList.clear(); + requestTypeList.clear(); + + size = tempViewList.size(); + if (size > 0) { + if (running) { + for (int i=0; i < size; i++) { + requestTypeList.add(STOP_VIEW); + requestObjList.add(tempViewList.get(i)); + } + setWork(); + } else { // MC will shutdown + for (int i=0; i < size; i++) { + View v = (View) tempViewList.get(i); + v.stopViewCount = -1; + v.isRunning = false; + } + } + tempViewList.clear(); + pendingRequest = true; + } else { + pendingRequest = rendererRun || (requestObjList.size() > 0); + + } + + size = freeMessageList.size(); + if (size > 0) { + for (int i=0; i < size; i++) { + requestTypeList.add(FREE_MESSAGE); + requestObjList.add(freeMessageList.get(i)); + } + pendingRequest = true; + freeMessageList.clear(); + } + if (!running && (renderOnceList.size() > 0)) { + clearRenderOnceList(); + } + + if (pendingRequest) { + setWork(); + } + + if (rendererRun || requestRenderWorkToDo) { + running = true; + } + + } + + private void clearRenderOnceList() { + for (int i=renderOnceList.size()-1; i>=0; i--) { + View v = (View) renderOnceList.get(i); + v.renderOnceFinish = true; + // stop after render once + stopView(v); + } + renderOnceList.clear(); + threadListsChanged = true; + + } + + synchronized void runMonitor(int action, + UnorderList stateThreadList, + UnorderList renderThreadList, + UnorderList requestRenderThreadList, + J3dThread nthread) { + + switch (action) { + case RUN_THREADS: + int currentStateThread = 0; + int currentRenderThread = 0; + int currentRequestRenderThread = 0; + View view; + boolean done; + J3dThreadData thread; + J3dThreadData renderThreads[] = (J3dThreadData []) + renderThreadList.toArray(false); + J3dThreadData stateThreads[] = (J3dThreadData []) + stateThreadList.toArray(false); + J3dThreadData requestRenderThreads[] = (J3dThreadData []) + requestRenderThreadList.toArray(false); + int renderThreadSize = renderThreadList.arraySize(); + int stateThreadSize = stateThreadList.arraySize(); + int requestRenderThreadSize = requestRenderThreadList.arraySize(); + + done = false; + + //lock all the needed geometry and image component + View[] allView = (View []) views.toArray(false); + View currentV; + int i; + + if (lockGeometry) + { + for( i = views.arraySize()-1; i >= 0; i--) { + currentV = allView[i]; + currentV.renderBin.lockGeometry(); + } + } + + while (!done) { + // First try a RenderThread + while (!renderWaiting && + currentRenderThread != renderThreadSize) { + thread = renderThreads[currentRenderThread++]; + if (!thread.needsRun) { + continue; + } + if ((thread.threadOpts & J3dThreadData.START_TIMER) != 0) { + view = (View)((Object[])thread.threadArgs)[2]; + view.frameNumber++; + view.startTime = J3dClock.currentTimeMillis(); + } + + + renderPending++; + + if (cpuLimit == 1) { + thread.thread.args = (Object[])thread.threadArgs; + thread.thread.doWork(currentTime); + } else { + threadPending++; + thread.thread.runMonitor(J3dThread.RUN, + currentTime, + (Object[])thread.threadArgs); + } + + if ((thread.threadOpts & J3dThreadData.STOP_TIMER) != 0) { + view = (View)((Object[])thread.threadArgs)[3]; + timestampUpdateList.add(view); + } + + if ((thread.threadOpts & J3dThreadData.LAST_STOP_TIMER) != 0) { + // release lock on locked geometry and image component + for( i = 0; i < views.arraySize(); i++) { + currentV = allView[i]; + currentV.renderBin.releaseGeometry(); + } + } + + if ((cpuLimit != 1) && + (thread.threadOpts & + J3dThreadData.WAIT_ALL_THREADS) != 0) { + + renderWaiting = true; + } + + + if ((cpuLimit != 1) && (cpuLimit <= threadPending)) { + state = WAITING_FOR_CPU; + try { + wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + state = RUNNING; + } + + } + // Now try state threads + while (!stateWaiting && + currentStateThread != stateThreadSize) { + thread = stateThreads[currentStateThread++]; + + if (!thread.needsRun) { + continue; + } + + statePending++; + + if (cpuLimit == 1) { + thread.thread.args = (Object[])thread.threadArgs; + thread.thread.doWork(currentTime); + } else { + threadPending++; + thread.thread.runMonitor(J3dThread.RUN, + currentTime, + (Object[])thread.threadArgs); + } + if (cpuLimit != 1 && (thread.threadOpts & + J3dThreadData.WAIT_ALL_THREADS) != 0) { + stateWaiting = true; + } + + if ((cpuLimit != 1) && (cpuLimit <= threadPending)) { + // Fix bug 4686766 - always allow + // renderer thread to continue if not finish + // geomLock can release for Behavior thread to + // continue. + if (currentRenderThread == renderThreadSize) { + state = WAITING_FOR_CPU; + try { + wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + state = RUNNING; + } else { + // Run renderer thread next time + break; + } + + } + } + + // Now try requestRender threads + if (!renderWaiting && + (currentRenderThread == renderThreadSize)) { + currentRequestRenderThread = 0; + while (!renderWaiting && + (currentRequestRenderThread != + requestRenderThreadSize)) { + + thread = + requestRenderThreads[currentRequestRenderThread++]; + + renderPending++; + + if (cpuLimit == 1) { + thread.thread.args = (Object[])thread.threadArgs; + thread.thread.doWork(currentTime); + } else { + threadPending++; + thread.thread.runMonitor(J3dThread.RUN, + currentTime, + (Object[])thread.threadArgs); + } + if (cpuLimit != 1 && (thread.threadOpts & + J3dThreadData.WAIT_ALL_THREADS) != 0) { + renderWaiting = true; + } + if (cpuLimit != 1 && cpuLimit <= threadPending) { + state = WAITING_FOR_CPU; + try { + wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + state = RUNNING; + } + } + } + + if (cpuLimit != 1) { + if ((renderWaiting && + (currentStateThread == stateThreadSize)) || + (stateWaiting && + currentRenderThread == renderThreadSize) || + (renderWaiting && stateWaiting)) { + if (!requestRenderWorkToDo) { + state = WAITING_FOR_THREADS; + try { + wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + state = RUNNING; + } + requestRenderWorkToDo = false; + } + } + + if ((currentStateThread == stateThreadSize) && + (currentRenderThread == renderThreadSize) && + (currentRequestRenderThread == requestRenderThreadSize) && + (threadPending == 0)) { + for (int k=timestampUpdateList.size()-1; k >=0; + k--) { + View v = (View) timestampUpdateList.get(k); + v.setFrameTimingValues(); + v.universe.behaviorStructure.incElapsedFrames(); + } + timestampUpdateList.clear(); + updateMirrorObjects(); + done = true; + + if (isStatsLoggable(Level.INFO)) { + // Instrumentation of Java 3D renderer + logTimes(); + } + } + } + break; + + case THREAD_DONE: + if (state != WAITING_FOR_RENDERER_CLEANUP) { + + threadPending--; + assert threadPending >= 0 : ("threadPending = " + threadPending); + if (nthread.type == J3dThread.RENDER_THREAD) { + View v = (View) nthread.args[3]; + if (v != null) { // STOP_TIMER + v.stopTime = J3dClock.currentTimeMillis(); + } + + if (--renderPending == 0) { + renderWaiting = false; + } + assert renderPending >= 0 : ("renderPending = " + renderPending); + } else { + if (--statePending == 0) { + stateWaiting = false; + } + assert statePending >= 0 : ("statePending = " + statePending); + } + if (state == WAITING_FOR_CPU || state == WAITING_FOR_THREADS) { + notify(); + } + } else { + notify(); + state = RUNNING; + } + break; + + case CHECK_FOR_WORK: + if (!workToDo) { + state = SLEEPING; + // NOTE: this could wakeup spuriously (see issue 279), but it + // will not cause any problems. + try { + wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + state = RUNNING; + } + workToDo = false; + break; + + case SET_WORK: + workToDo = true; + if (state == SLEEPING) { + notify(); + } + break; + + case SET_WORK_FOR_REQUEST_RENDERER: + requestRenderWorkToDo = true; + workToDo = true; + if (state == WAITING_FOR_CPU || state == WAITING_FOR_THREADS || + state == SLEEPING) { + notify(); + } + break; + + case RUN_RENDERER_CLEANUP: + nthread.runMonitor(J3dThread.RUN, currentTime, + rendererCleanupArgs); + state = WAITING_FOR_RENDERER_CLEANUP; + // Issue 279 - loop until state is set to running + while (state != RUNNING) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + } + break; + + default: + // Should never get here + assert false : "missing case in switch statement"; + } + } + + // Static initializer + static { + // create ThreadGroup + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + ThreadGroup parent; + Thread thread = Thread.currentThread(); + threadPriority = thread.getPriority(); + rootThreadGroup = thread.getThreadGroup(); + while ((parent = rootThreadGroup.getParent()) != null) { + rootThreadGroup = parent; + } + rootThreadGroup = new ThreadGroup(rootThreadGroup, + "Java3D"); + // use the default maximum group priority + return null; + } + }); + + // Initialize loggers + try { + initLoggers(); + } catch (RuntimeException ex) { + System.err.println(ex); + } + } + + + static String mtype[] = { + "INSERT_NODES", + "REMOVE_NODES", + "RUN", + "TRANSFORM_CHANGED", + "UPDATE_VIEW", + "STOP_THREAD", + "COLORINGATTRIBUTES_CHANGED", + "LINEATTRIBUTES_CHANGED", + "POINTATTRIBUTES_CHANGED", + "POLYGONATTRIBUTES_CHANGED", + "RENDERINGATTRIBUTES_CHANGED", + "TEXTUREATTRIBUTES_CHANGED", + "TRANSPARENCYATTRIBUTES_CHANGED", + "MATERIAL_CHANGED", + "TEXCOORDGENERATION_CHANGED", + "TEXTURE_CHANGED", + "MORPH_CHANGED", + "GEOMETRY_CHANGED", + "APPEARANCE_CHANGED", + "LIGHT_CHANGED", + "BACKGROUND_CHANGED", + "CLIP_CHANGED", + "FOG_CHANGED", + "BOUNDINGLEAF_CHANGED", + "SHAPE3D_CHANGED", + "TEXT3D_TRANSFORM_CHANGED", + "TEXT3D_DATA_CHANGED", + "SWITCH_CHANGED", + "COND_MET", + "BEHAVIOR_ENABLE", + "BEHAVIOR_DISABLE", + "INSERT_RENDERATOMS", + "ORDERED_GROUP_INSERTED", + "ORDERED_GROUP_REMOVED", + "COLLISION_BOUND_CHANGED", + "REGION_BOUND_CHANGED", + "MODELCLIP_CHANGED", + "BOUNDS_AUTO_COMPUTE_CHANGED", + "SOUND_ATTRIB_CHANGED", + "AURALATTRIBUTES_CHANGED", + "SOUNDSCAPE_CHANGED", + "ALTERNATEAPPEARANCE_CHANGED", + "RENDER_OFFSCREEN", + "RENDER_RETAINED", + "RENDER_IMMEDIATE", + "SOUND_STATE_CHANGED", + "ORIENTEDSHAPE3D_CHANGED", + "TEXTURE_UNIT_STATE_CHANGED", + "UPDATE_VIEWPLATFORM", + "BEHAVIOR_ACTIVATE", + "GEOMETRYARRAY_CHANGED", + "MEDIA_CONTAINER_CHANGED", + "RESIZE_CANVAS", + "TOGGLE_CANVAS", + "IMAGE_COMPONENT_CHANGED", + "SCHEDULING_INTERVAL_CHANGED", + "VIEWSPECIFICGROUP_CHANGED", + "VIEWSPECIFICGROUP_INIT", + "VIEWSPECIFICGROUP_CLEAR", + "ORDERED_GROUP_TABLE_CHANGED", + "BEHAVIOR_REEVALUATE", + "CREATE_OFFSCREENBUFFER", + "DESTROY_CTX_AND_OFFSCREENBUFFER", + "SHADER_ATTRIBUTE_CHANGED", + "SHADER_ATTRIBUTE_SET_CHANGED", + "SHADER_APPEARANCE_CHANGED", + "ALLOCATE_CANVASID", + "FREE_CANVASID", + }; + + private String dumpThreads(int threads) { + StringBuffer strBuf = new StringBuffer(); + strBuf.append("threads:"); + //dump Threads type + if ((threads & J3dThread.BEHAVIOR_SCHEDULER) != 0) { + strBuf.append(" BEHAVIOR_SCHEDULER"); + } + if ((threads & J3dThread.SOUND_SCHEDULER) != 0) { + strBuf.append(" SOUND_SCHEDULER"); + } + if ((threads & J3dThread.INPUT_DEVICE_SCHEDULER) != 0) { + strBuf.append(" INPUT_DEVICE_SCHEDULER"); + } + if ((threads & J3dThread.RENDER_THREAD) != 0) { + strBuf.append(" RENDER_THREAD"); + } + if ((threads & J3dThread.UPDATE_GEOMETRY) != 0) { + strBuf.append(" UPDATE_GEOMETRY"); + } + if ((threads & J3dThread.UPDATE_RENDER) != 0) { + strBuf.append(" UPDATE_RENDER"); + } + if ((threads & J3dThread.UPDATE_BEHAVIOR) != 0) { + strBuf.append(" UPDATE_BEHAVIOR"); + } + if ((threads & J3dThread.UPDATE_SOUND) != 0) { + strBuf.append(" UPDATE_SOUND"); + } + if ((threads & J3dThread.UPDATE_RENDERING_ATTRIBUTES) != 0) { + strBuf.append(" UPDATE_RENDERING_ATTRIBUTES"); + } + if ((threads & J3dThread.UPDATE_RENDERING_ENVIRONMENT) != 0) { + strBuf.append(" UPDATE_RENDERING_ENVIRONMENT"); + } + if ((threads & J3dThread.UPDATE_TRANSFORM) != 0) { + strBuf.append(" UPDATE_TRANSFORM"); + } + + return strBuf.toString(); + } + + // Method to log the specified message. Note that the caller + // should check for isCoreLoggable(FINEST) before calling + private void dumpMessage(String str, J3dMessage m) { + StringBuffer strBuf = new StringBuffer(); + strBuf.append(str).append(" "); + if (m.type >= 0 && m.type < mtype.length) { + strBuf.append(mtype[m.type]); + } else { + strBuf.append(""); + } + strBuf.append(" ").append(dumpThreads(m.threads)); + getCoreLogger().finest(strBuf.toString()); + } + + + int frameCount = 0; + private int frameCountCutoff = 100; + + private void manageMemory() { + if (++frameCount > frameCountCutoff) { + FreeListManager.manageLists(); + frameCount = 0; + } + } + + /** + * Yields the current thread, by sleeping for a small amount of + * time. Unlike Thread.yield(), this method + * guarantees that the current thread will yield to another thread + * waiting to run. It also ensures that the other threads will + * run for at least a small amount of time before the current + * thread runs again. + */ + static final void threadYield() { + // Note that we can't just use Thread.yield(), since it + // doesn't guarantee that it will actually yield the thread + // (and, in fact, it appears to be a no-op under Windows). So + // we will sleep for 1 msec instead. Since most threads use + // wait/notify, and only use this when they are waiting for + // another thread to finish something, this shouldn't be a + // performance concern. + + //Thread.yield(); + try { + Thread.sleep(1); + } + catch (InterruptedException e) { + // Do nothing, since we really don't care how long (or + // even whether) we sleep + } + } + + // Return the number of available processors + private int getNumberOfProcessors() { + return Runtime.getRuntime().availableProcessors(); + } + + // + // The following framework supports code instrumentation. To use it, + // add code of the following form to areas that you want to enable for + // timing: + // + // long startTime = System.nanoTime(); + // sortTransformGroups(tSize, tgs); + // long deltaTime = System.nanoTime() - startTime; + // VirtualUniverse.mc.recordTime(MasterControl.TimeType.XXXXX, deltaTime); + // + // where "XXXXX" is the enum representing the code segment being timed. + // Additional enums can be defined for new subsystems. + // + + static enum TimeType { + TOTAL_FRAME, + RENDER, + BEHAVIOR, + // TRANSFORM_UPDATE, + // ... + } + + private long[] statTimes = new long[TimeType.values().length]; + private int[] statCounts = new int[TimeType.values().length]; + private boolean[] statSeen = new boolean[TimeType.values().length]; + private int frameCycleTick = 0; + private long frameCycleNumber = 0L; + + // Method to record times -- should not be called unless the stats logger + // level is set to INFO or lower + synchronized void recordTime(TimeType type, long deltaTime) { + int idx = type.ordinal(); + statTimes[idx] += deltaTime; + statCounts[idx]++; + statSeen[idx] = true; + } + + // Method to record times -- this is not called unless the stats logger + // level is set to INFO or lower + private synchronized void logTimes() { + ++frameCycleNumber; + if (++frameCycleTick >= 10) { + StringBuffer strBuf = new StringBuffer(); + strBuf.append("----------------------------------------------\n"). + append(" Frame Number = "). + append(frameCycleNumber). + append("\n"); + for (int i = 0; i < statTimes.length; i++) { + if (statSeen[i]) { + strBuf.append(" "); + if (statCounts[i] > 0) { + strBuf.append(TimeType.values()[i]). + append(" ["). + append(statCounts[i]). + append("] = "). + append((double)statTimes[i] / 1000000.0 / (double)statCounts[i]). + append(" msec per call\n"); + statTimes[i] = 0L; + statCounts[i] = 0; + } else { + assert statTimes[i] == 0L; + strBuf.append(TimeType.values()[i]). + append(" [0] = 0.0 msec\n"); + } + } + } + getStatsLogger().info(strBuf.toString()); + frameCycleTick = 0; + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/MasterControlThread.java b/j3d-core/src/classes/share/javax/media/j3d/MasterControlThread.java new file mode 100644 index 0000000..e81a6ad --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/MasterControlThread.java @@ -0,0 +1,80 @@ +/* + * $RCSfile: MasterControlThread.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Master control thread. The MasterControlThread object and thread + * are created dynamically whenever needed. Once created, the thread + * runs until all other threads are terminated. Then the master + * control thread terminates. There is never more than one + * MasterControl object or thread in existence at any one time. + */ +class MasterControlThread extends Thread { + + private static int numInstances = 0; + private int instanceNum = -1; + + private static synchronized int newInstanceNum() { + return (++numInstances); + } + + private int getInstanceNum() { + if (instanceNum == -1) + instanceNum = newInstanceNum(); + return instanceNum; + } + + MasterControlThread(ThreadGroup threadGroup) { + super(threadGroup, ""); + setName("J3D-MasterControl-" + getInstanceNum()); + VirtualUniverse.mc.createMCThreads(); + this.start(); + } + + public void run() { + + do { + while (VirtualUniverse.mc.running) { + VirtualUniverse.mc.doWork(); + + // NOTE: no need to call Thread.yield(), since we will + // call wait() if there is no work to do (yield seems + // to be a no-op on Windows anyway) + } + } while (!VirtualUniverse.mc.mcThreadDone()); + + if(J3dDebug.devPhase) { + J3dDebug.doDebug(J3dDebug.masterControl, J3dDebug.LEVEL_1, + "MC: MasterControl Thread Terminate"); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Material.java b/j3d-core/src/classes/share/javax/media/j3d/Material.java new file mode 100644 index 0000000..86a888a --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Material.java @@ -0,0 +1,718 @@ +/* + * $RCSfile: Material.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; + +/** + * The Material object defines the appearance of an object under + * illumination. + * If the Material object in an Appearance object is null, + * lighting is disabled for all nodes that use that Appearance object. + *

+ * The properties that can be set for a Material object are: + *

    + *
  • Ambient color - the ambient RGB color reflected off the surface + * of the material. The range of values is 0.0 to 1.0. The default ambient + * color is (0.2, 0.2, 0.2).

  • + *
  • Diffuse color - the RGB color of the material when illuminated. + * The range of values is 0.0 to 1.0. The default diffuse color is + * (1.0, 1.0, 1.0).

  • + *
  • Specular color - the RGB specular color of the material (highlights). + * The range of values is 0.0 to 1.0. The default specular color + * is (1.0, 1.0, 1.0).

  • + *
  • Emissive color - the RGB color of the light the material emits, if + * any. The range of values is 0.0 to 1.0. The default emissive + * color is (0.0, 0.0, 0.0).

  • + *
  • Shininess - the material's shininess, in the range [1.0, 128.0] + * with 1.0 being not shiny and 128.0 being very shiny. Values outside + * this range are clamped. The default value for the material's + * shininess is 64.

  • + *
  • Color target - the material color target for per-vertex colors, + * one of: AMBIENT, EMISSIVE, DIFFUSE, SPECULAR, or AMBIENT_AND_DIFFUSE. + * The default target is DIFFUSE.

  • + *
+ * + * The Material object also enables or disables lighting. + */ +public class Material extends NodeComponent { + + /** + * For material object, specifies that Material allows reading + * individual component field information. + */ + public static final int + ALLOW_COMPONENT_READ = CapabilityBits.MATERIAL_ALLOW_COMPONENT_READ; + + /** + * For material object, specifies that Material allows reading + * individual component field information. + */ + public static final int + ALLOW_COMPONENT_WRITE = CapabilityBits.MATERIAL_ALLOW_COMPONENT_WRITE; + + /** + * Specifies that per-vertex colors replace the ambient material color. + * @see #setColorTarget + * + * @since Java 3D 1.3 + */ + public static final int AMBIENT = 0; + + /** + * Specifies that per-vertex colors replace the emissive material color. + * @see #setColorTarget + * + * @since Java 3D 1.3 + */ + public static final int EMISSIVE = 1; + + /** + * Specifies that per-vertex colors replace the diffuse material color. + * This is the default target. + * @see #setColorTarget + * + * @since Java 3D 1.3 + */ + public static final int DIFFUSE = 2; + + /** + * Specifies that per-vertex colors replace the specular material color. + * @see #setColorTarget + * + * @since Java 3D 1.3 + */ + public static final int SPECULAR = 3; + + /** + * Specifies that per-vertex colors replace both the ambient and the + * diffuse material color. + * @see #setColorTarget + * + * @since Java 3D 1.3 + */ + public static final int AMBIENT_AND_DIFFUSE = 4; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_COMPONENT_READ + }; + + /** + * Constructs and initializes a Material object using default parameters. + * The default values are as follows: + *
    + * lighting enable : true
    + * ambient color : (0.2, 0.2, 0.2)
    + * emmisive color : (0.0, 0.0, 0.0)
    + * diffuse color : (1.0, 1.0, 1.0)
    + * specular color : (1.0, 1.0, 1.0)
    + * shininess : 64
    + * color target : DIFFUSE + *
+ */ + public Material() { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a new material object using the specified + * parameters. Lighting is enabled by default. + * @param ambientColor the material's ambient color + * @param emissiveColor the material's emissive color + * @param diffuseColor the material's diffuse color when illuminated by a + * light + * @param specularColor the material's specular color when illuminated + * to generate a highlight + * @param shininess the material's shininess in the + * range [1.0, 128.0] with 1.0 being not shiny and 128.0 being very shiny. + * Values outside this range are clamped. + */ + public Material(Color3f ambientColor, + Color3f emissiveColor, + Color3f diffuseColor, + Color3f specularColor, + float shininess) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((MaterialRetained)this.retained).createMaterial(ambientColor, + emissiveColor, diffuseColor, specularColor, + shininess); + } + + /** + * Creates a retained mode MaterialRetained object that this + * Material component object will point to. + */ + void createRetained() { + this.retained = new MaterialRetained(); + this.retained.setSource(this); + } + + /** + * Sets this material's ambient color. + * This specifies how much ambient light is reflected by + * the surface. + * The ambient color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is either AMBIENT or AMBIENT_AND_DIFFUSE, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's ambient color in the lighting equation. + * + * @param color the material's ambient color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setAmbientColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + if (isLive()) { + ((MaterialRetained)this.retained).setAmbientColor(color); + } + else { + ((MaterialRetained)this.retained).initAmbientColor(color); + } + } + + /** + * Sets this material's ambient color. + * This specifies how much ambient light is reflected by + * the surface. + * The ambient color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is either AMBIENT or AMBIENT_AND_DIFFUSE, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's ambient color in the lighting equation. + * + * @param r the new ambient color's red component + * @param g the new ambient color's green component + * @param b the new ambient color's blue component + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setAmbientColor(float r, float g, float b) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + if (isLive()) { + ((MaterialRetained)this.retained).setAmbientColor(r,g,b); + } + else { + ((MaterialRetained)this.retained).initAmbientColor(r,g,b); + } + } + + /** + * Retrieves this material's ambient color. + * @param color that will contain the material's ambient color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getAmbientColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Material2")); + + ((MaterialRetained)this.retained).getAmbientColor(color); + } + + /** + * Sets this material's emissive color. + * This is the color of light, if any, that the material emits. + * The emissive color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is EMISSIVE, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's emissive color in the lighting equation. + * + * @param color the new emissive color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setEmissiveColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + if (isLive()) + ((MaterialRetained)this.retained).setEmissiveColor(color); + else + ((MaterialRetained)this.retained).initEmissiveColor(color); + + + + + } + + /** + * Sets this material's emissive color. + * This is the color of light, if any, that the material emits. + * The emissive color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is EMISSIVE, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's emissive color in the lighting equation. + * + * @param r the new emissive color's red component + * @param g the new emissive color's green component + * @param b the new emissive color's blue component + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setEmissiveColor(float r, float g, float b) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + + if (isLive()) + ((MaterialRetained)this.retained).setEmissiveColor(r,g,b); + else + ((MaterialRetained)this.retained).initEmissiveColor(r,g,b); + } + + /** + * Retrieves this material's emissive color and stores it in the + * argument provided. + * @param color the vector that will receive this material's emissive color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getEmissiveColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Material2")); + + ((MaterialRetained)this.retained).getEmissiveColor(color); + } + + /** + * Sets this material's diffuse color. + * This is the color of the material when illuminated by a light source. + * The diffuse color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is either DIFFUSE or AMBIENT_AND_DIFFUSE, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's diffuse color in the lighting equation. + * + * @param color the new diffuse color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setDiffuseColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + + if (isLive()) + ((MaterialRetained)this.retained).setDiffuseColor(color); + else + ((MaterialRetained)this.retained).initDiffuseColor(color); + } + + /** + * Sets this material's diffuse color. + * This is the color of the material when illuminated by a light source. + * The diffuse color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is either DIFFUSE or AMBIENT_AND_DIFFUSE, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's diffuse color in the lighting equation. + * + * @param r the new diffuse color's red component + * @param g the new diffuse color's green component + * @param b the new diffuse color's blue component + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setDiffuseColor(float r, float g, float b) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + + if (isLive()) + ((MaterialRetained)this.retained).setDiffuseColor(r,g,b); + else + ((MaterialRetained)this.retained).initDiffuseColor(r,g,b); + } + + /** + * Sets this material's diffuse color plus alpha. + * This is the color of the material when illuminated by a light source. + * The diffuse color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is either DIFFUSE or AMBIENT_AND_DIFFUSE, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's diffuse color in the lighting equation. + * + * @param r the new diffuse color's red component + * @param g the new diffuse color's green component + * @param b the new diffuse color's blue component + * @param a the alpha component used to set transparency + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setDiffuseColor(float r, float g, float b, float a) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + + if (isLive()) + ((MaterialRetained)this.retained).setDiffuseColor(r,g,b,a); + else + ((MaterialRetained)this.retained).initDiffuseColor(r,g,b,a); + } + + /** + * Retrieves this material's diffuse color. + * @param color the vector that will receive this material's diffuse color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDiffuseColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Material2")); + + ((MaterialRetained)this.retained).getDiffuseColor(color); + } + + /** + * Sets this material's specular color. + * This is the specular highlight color of the material. + * The specular color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is SPECULAR, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's specular color in the lighting equation. + * + * @param color the new specular color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setSpecularColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + + if (isLive()) + ((MaterialRetained)this.retained).setSpecularColor(color); + else + ((MaterialRetained)this.retained).initSpecularColor(color); + } + + /** + * Sets this material's specular color. + * This is the specular highlight color of the material. + * The specular color in this Material object may be overridden by + * per-vertex colors in some cases. If vertex colors are present + * in the geometry, and lighting is enabled, and the colorTarget + * is SPECULAR, and vertex colors are + * not being ignored, then the vertex colors are used in place of + * this Material's specular color in the lighting equation. + * + * @param r the new specular color's red component + * @param g the new specular color's green component + * @param b the new specular color's blue component + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see #setColorTarget + */ + public void setSpecularColor(float r, float g, float b) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + + if (isLive()) + ((MaterialRetained)this.retained).setSpecularColor(r,g,b); + else + ((MaterialRetained)this.retained).initSpecularColor(r,g,b); + } + + /** + * Retrieves this material's specular color. + * @param color the vector that will receive this material's specular color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getSpecularColor(Color3f color) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Material2")); + + ((MaterialRetained)this.retained).getSpecularColor(color); + } + + /** + * Sets this material's shininess. + * This specifies a material specular scattering exponent, or + * shininess. It takes a floating point number in the range [1.0, 128.0] + * with 1.0 being not shiny and 128.0 being very shiny. + * Values outside this range are clamped. + * @param shininess the material's shininess + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setShininess(float shininess) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material0")); + + if (isLive()) + ((MaterialRetained)this.retained).setShininess(shininess); + else + ((MaterialRetained)this.retained).initShininess(shininess); + } + + /** + * Retrieves this material's shininess. + * @return the material's shininess + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getShininess() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Material2")); + + return ((MaterialRetained)this.retained).getShininess(); + } + + /** + * Enables or disables lighting for this appearance component object. + * @param state true or false to enable or disable lighting + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setLightingEnable(boolean state) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material15")); + if (isLive()) + ((MaterialRetained)this.retained).setLightingEnable(state); + else + ((MaterialRetained)this.retained).initLightingEnable(state); + } + + /** + * Retrieves the state of the lighting enable flag. + * @return true if lighting is enabled, false if lighting is disabled + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getLightingEnable() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Material16")); + return ((MaterialRetained)this.retained).getLightingEnable(); + } + + /** + * Sets the color target for per-vertex colors. When lighting is + * enabled and per-vertex colors are present (and not ignored) in + * the geometry for a given Shape3D node, those per-vertex colors + * are used in place of the specified material color(s) for this + * Material object. The color target is ignored when lighting is + * disabled or when per-vertex colors are not used. + * The ColorInterpolator behavior also uses the color target to + * determine which color in the associated Material is modified. + * The default target is DIFFUSE. + * + * @param colorTarget one of: AMBIENT, EMISSIVE, DIFFUSE, SPECULAR, or + * AMBIENT_AND_DIFFUSE. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see RenderingAttributes#setIgnoreVertexColors + * @see ColorInterpolator + * + * @since Java 3D 1.3 + */ + public void setColorTarget(int colorTarget) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Material3")); + + if (isLive()) + ((MaterialRetained)this.retained).setColorTarget(colorTarget); + else + ((MaterialRetained)this.retained).initColorTarget(colorTarget); + } + + /** + * Retrieves the current color target for this material. + * + * @return one of: AMBIENT, EMISSIVE, DIFFUSE, SPECULAR, or + * AMBIENT_AND_DIFFUSE. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getColorTarget() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COMPONENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Material4")); + + return ((MaterialRetained)this.retained).getColorTarget(); + } + + /** + * Returns a String representation of this Materials values. + * If the scene graph is live only those values with their + * Capability read bit set will be displayed. + */ + public String toString() { + StringBuffer str = new StringBuffer(getNamePrefix()); + str.append("javax.media.j3d.Material: "); + Color3f color=new Color3f(); + try { + getAmbientColor(color); + str.append("AmbientColor="+color); + } catch (CapabilityNotSetException e) {str.append("AmbientColor=N/A");} + try { + getEmissiveColor(color); + str.append(" EmissiveColor="+color); + } catch (CapabilityNotSetException ex) {str.append(" EmissiveColor=N/A");} + try { + getDiffuseColor(color); + str.append(" DiffuseColor="+color); + } catch (CapabilityNotSetException exc) {str.append(" DiffuseColor=N/A");} + try { + getSpecularColor(color); + str.append(" SpecularColor="+color); + } catch (CapabilityNotSetException exce) {str.append(" SpecularColor=N/A");} + try { + float f=getShininess(); + str.append(" Shininess="+f); + } catch (CapabilityNotSetException excep) {str.append(" Shininess=N/A");} + try { + boolean b=getLightingEnable(); + str.append(" LightingEnable="+b); + } catch (CapabilityNotSetException except) {str.append(" LightingEnable=N/A");} + try { + int i=getColorTarget(); + str.append(" ColorTarget="+i); + } catch (CapabilityNotSetException except) {str.append(" ColorTarget=N/A");} + return new String(str); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + Material m = new Material(); + m.duplicateNodeComponent(this); + return m; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, + forceDuplicate); + + MaterialRetained mat = (MaterialRetained) + originalNodeComponent.retained; + MaterialRetained rt = (MaterialRetained) retained; + + Color3f c = new Color3f(); + mat.getAmbientColor(c); + + rt.initAmbientColor(c); + mat.getEmissiveColor(c); + rt.initEmissiveColor(c); + mat.getDiffuseColor(c); + rt.initDiffuseColor(c); + mat.getSpecularColor(c); + rt.initSpecularColor(c); + rt.initShininess(mat.getShininess()); + rt.initLightingEnable(mat.getLightingEnable()); + rt.initColorTarget(mat.getColorTarget()); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/MaterialRetained.java b/j3d-core/src/classes/share/javax/media/j3d/MaterialRetained.java new file mode 100644 index 0000000..11c231c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/MaterialRetained.java @@ -0,0 +1,563 @@ +/* + * $RCSfile: MaterialRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; +import java.util.ArrayList; + +/** + * The MaterialRetained object defines the appearance of an object under + * illumination. + */ +class MaterialRetained extends NodeComponentRetained { + // Initialize default values for all class variables + Color3f ambientColor = new Color3f(0.2f, 0.2f, 0.2f); + Color3f emissiveColor = new Color3f(0.0f, 0.0f, 0.0f); + Color3f diffuseColor = new Color3f(1.0f, 1.0f, 1.0f); + Color3f specularColor = new Color3f(1.0f, 1.0f, 1.0f); + float shininess = 64.0f; + int colorTarget = Material.DIFFUSE; + + // Lighting enable switch for this material object + boolean lightingEnable = true; + + // A list of pre-defined bits to indicate which component + // in this Material object changed. + static final int AMBIENT_COLOR_CHANGED = 0x01; + + static final int EMISSIVE_COLOR_CHANGED = 0x02; + + static final int DIFFUSE_COLOR_CHANGED = 0x04; + + static final int SPECULAR_COLOR_CHANGED = 0x08; + + static final int SHININESS_CHANGED = 0x10; + + static final int ENABLE_CHANGED = 0x20; + + static final int COLORTARGET_CHANGED = 0x40; + + /** + * Constructs and initializes a new material object using the specified + * parameters. + * @param ambientColor the material's ambient color + * @param emissiveColor the material's emissive color + * @param diffuseColor the material's diffuse color when illuminated by a + * light + * @param specularColor the material's specular color when illuminated + * to generate a highlight + * @param shininess the material's shininess in the + * range [1.0, 128.0] with 1.0 being not shiny and 128.0 being very shiny + */ + void createMaterial(Color3f aColor, + Color3f eColor, + Color3f dColor, + Color3f sColor, + float shine) + { + ambientColor.set(aColor); + emissiveColor.set(eColor); + diffuseColor.set(dColor); + specularColor.set(sColor); + shininess = shine; + } + + /** Initializes this material's ambient color + * This specifies how much ambient light is reflected by + * the surface. The ambient light color is the product of this + * color and the material diffuseColor. + * @param color the material's ambient color + */ + final void initAmbientColor(Color3f color) { + this.ambientColor.set(color); + } + + /** + * Sets this material's ambient color and sends a message notifying + * the interested structures of the change. + * This specifies how much ambient light is reflected by + * the surface. The ambient light color is the product of this + * color and the material diffuseColor. + * @param color the material's ambient color + */ + final void setAmbientColor(Color3f color) { + initAmbientColor(color); + sendMessage(AMBIENT_COLOR_CHANGED, new Color3f(color)); + } + + /** + * Sets this material's ambient color + * @param r the new ambient color's red component + * @param g the new ambient color's green component + * @param b the new ambient color's blue component + */ + final void initAmbientColor(float r, float g, float b) { + this.ambientColor.set(r, g, b); + } + + + /** + * Sets this material's ambient color and sends a message notifying + * the interested structures of the change. + * @param r the new ambient color's red component + * @param g the new ambient color's green component + * @param b the new ambient color's blue component + */ + final void setAmbientColor(float r, float g, float b) { + initAmbientColor(r, g, b); + sendMessage(AMBIENT_COLOR_CHANGED, new Color3f(r, g, b)); + } + + /** + * Retrieves this material's ambient color. + * @return the material's ambient color + */ + final void getAmbientColor(Color3f color) { + color.set(this.ambientColor); + } + + /** + * Sets this material's emissive color + * This is the color of light, if any, that the material emits. + * @param color the new emissive color + */ + final void initEmissiveColor(Color3f color) { + this.emissiveColor.set(color); + } + + /** + * Sets this material's emissive color and sends a message notifying + * the interested structures of the change. + * This is the color of light, if any, that the material emits. + * @param color the new emissive color + */ + final void setEmissiveColor(Color3f color) { + initEmissiveColor(color); + sendMessage(EMISSIVE_COLOR_CHANGED, new Color3f(color)); + } + + /** + * Sets this material's emissive color. + * This is the color of light, if any, that the material emits. + * @param r the new emissive color's red component + * @param g the new emissive color's green component + * @param b the new emissive color's blue component + */ + final void initEmissiveColor(float r, float g, float b) { + this.emissiveColor.set(r, g, b); + } + + /** + * Sets this material's emissive color and sends a message notifying + * the interested structures of the change. + * This is the color of light, if any, that the material emits. + * @param r the new emissive color's red component + * @param g the new emissive color's green component + * @param b the new emissive color's blue component + */ + final void setEmissiveColor(float r, float g, float b) { + initEmissiveColor(r, g, b); + sendMessage(EMISSIVE_COLOR_CHANGED, new Color3f(r, g, b)); + } + + /** + * Retrieves this material's emissive color and stores it in the + * argument provided. + * @param color the vector that will receive this material's emissive color + */ + final void getEmissiveColor(Color3f color) { + color.set(this.emissiveColor); + } + + /** + * Sets this material's diffuse color. + * This is the color of the material when illuminated by a light source. + * @param color the new diffuse color + */ + final void initDiffuseColor(Color3f color) { + this.diffuseColor.set(color); + } + + /** + * Sets this material's diffuse color and sends a message notifying + * the interested structures of the change. + * This is the color of the material when illuminated by a light source. + * @param color the new diffuse color + */ + final void setDiffuseColor(Color3f color) { + initDiffuseColor(color); + sendMessage(DIFFUSE_COLOR_CHANGED, new Color3f(color)); + } + + /** + * Sets this material's diffuse color. + * @param r the new diffuse color's red component + * @param g the new diffuse color's green component + * @param b the new diffuse color's blue component + */ + final void initDiffuseColor(float r, float g, float b) { + this.diffuseColor.set(r, g, b); + } + + /** + * Sets this material's diffuse color and sends a message notifying + * the interested structures of the change. + * @param r the new diffuse color's red component + * @param g the new diffuse color's green component + * @param b the new diffuse color's blue component + */ + final void setDiffuseColor(float r, float g, float b) { + initDiffuseColor(r, g, b); + sendMessage(DIFFUSE_COLOR_CHANGED, new Color3f(r, g, b)); + } + + /** + * Sets this material's diffuse color plus alpha. + * This is the color of the material when illuminated by a light source. + * @param r the new diffuse color's red component + * @param g the new diffuse color's green component + * @param b the new diffuse color's blue component + * @param a the alpha component used to set transparency + */ + final void initDiffuseColor(float r, float g, float b, float a) { + this.diffuseColor.set(r, g, b); + } + + /** + * Sets this material's diffuse color plus alpha and sends + * a message notifying the interested structures of the change. + * This is the color of the material when illuminated by a light source. + * @param r the new diffuse color's red component + * @param g the new diffuse color's green component + * @param b the new diffuse color's blue component + * @param a the alpha component used to set transparency + */ + final void setDiffuseColor(float r, float g, float b, float a) { + initDiffuseColor(r, g, b); + sendMessage(DIFFUSE_COLOR_CHANGED, new Color3f(r, g, b)); + } + + /** + * Retrieves this material's diffuse color. + * @param color the vector that will receive this material's diffuse color + */ + final void getDiffuseColor(Color3f color) { + color.set(this.diffuseColor); + } + + /** + * Sets this material's specular color. + * This is the specular highlight color of the material. + * @param color the new specular color + */ + final void initSpecularColor(Color3f color) { + this.specularColor.set(color); + } + + /** + * Sets this material's specular color and sends a message notifying + * the interested structures of the change. + * This is the specular highlight color of the material. + * @param color the new specular color + */ + final void setSpecularColor(Color3f color) { + initSpecularColor(color); + sendMessage(SPECULAR_COLOR_CHANGED, new Color3f(color)); + } + + /** + * Sets this material's specular color. + * This is the specular highlight color of the material. + * @param r the new specular color's red component + * @param g the new specular color's green component + * @param b the new specular color's blue component + */ + final void initSpecularColor(float r, float g, float b) { + this.specularColor.set(r, g, b); + } + + + /** + * Sets this material's specular color and sends a message notifying + * the interested structures of the change. + * This is the specular highlight color of the material. + * @param r the new specular color's red component + * @param g the new specular color's green component + * @param b the new specular color's blue component + */ + final void setSpecularColor(float r, float g, float b) { + initSpecularColor(r, g, b); + sendMessage(SPECULAR_COLOR_CHANGED, new Color3f(r, g, b)); + } + + /** + * Retrieves this material's specular color. + * @param color the vector that will receive this material's specular color + */ + final void getSpecularColor(Color3f color) { + color.set(this.specularColor); + } + + /** + * Sets this material's shininess. + * This specifies a material specular exponent, or shininess. + * It takes a floating point number in the range [1.0, 128.0] + * with 1.0 being not shiny and 128.0 being very shiny. + * @param shininess the material's shininess + */ + final void initShininess(float shininess) { + // Clamp shininess value + if (shininess < 1.0f) + this.shininess = 1.0f; + else if (shininess > 128.0f) + this.shininess = 128.0f; + else + this.shininess = shininess; + + } + + /** + * Sets this material's shininess and sends a message notifying + * the interested structures of the change. + * This specifies a material specular exponent, or shininess. + * It takes a floating point number in the range [1.0, 128.0] + * with 1.0 being not shiny and 128.0 being very shiny. + * @param shininess the material's shininess + */ + final void setShininess(float shininess) { + initShininess(shininess); + sendMessage(SHININESS_CHANGED, new Float(this.shininess)); + } + + /** + * Retrieves this material's shininess. + * @return the material's shininess + */ + final float getShininess() { + return this.shininess; + } + + /** + * Enables or disables lighting for this appearance component object. + * @param state true or false to enable or disable lighting + */ + void initLightingEnable(boolean state) { + lightingEnable = state; + } + + /** + * Enables or disables lighting for this appearance component object + * and sends a message notifying + * the interested structures of the change. + * @param state true or false to enable or disable lighting + */ + void setLightingEnable(boolean state) { + initLightingEnable(state); + sendMessage(ENABLE_CHANGED, + (state ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Retrieves the state of the lighting enable flag. + * @return true if lighting is enabled, false if lighting is disabled + */ + boolean getLightingEnable() { + return lightingEnable; + } + + void initColorTarget(int colorTarget) { + this.colorTarget = colorTarget; + } + + final void setColorTarget(int colorTarget) { + initColorTarget(colorTarget); + sendMessage(COLORTARGET_CHANGED, new Integer(colorTarget)); + } + + final int getColorTarget() { + return colorTarget; + } + + synchronized void createMirrorObject() { + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror = this; + } else { + MaterialRetained mirrorMat = new MaterialRetained(); + mirrorMat.set(this); + mirrorMat.source = source; + mirror = mirrorMat; + } + } else { + ((MaterialRetained) mirror).set(this); + } + } + + + /** + * Updates the native context. + */ + void updateNative(Context ctx, + float red, float green, float blue, float alpha, + boolean enableLighting) { + Pipeline.getPipeline().updateMaterial(ctx, red, green, blue, alpha, + ambientColor.x, ambientColor.y, ambientColor.z, + emissiveColor.x, emissiveColor.y, emissiveColor.z, + diffuseColor.x, diffuseColor.y, diffuseColor.z, + specularColor.x, specularColor.y, specularColor.z, + shininess, colorTarget, enableLighting); + } + + + /** + * Creates a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + MaterialRetained mirrorMaterial = (MaterialRetained)mirror; + mirrorMaterial.set(this); + } + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + MaterialRetained mirrorMaterial = (MaterialRetained)mirror; + if ((component & AMBIENT_COLOR_CHANGED) != 0) { + mirrorMaterial.ambientColor = (Color3f)value; + } + else if ((component & EMISSIVE_COLOR_CHANGED) != 0) { + mirrorMaterial.emissiveColor = (Color3f)value; + } + else if ((component & DIFFUSE_COLOR_CHANGED) != 0) { + mirrorMaterial.diffuseColor = (Color3f)value; + } + else if ((component & SPECULAR_COLOR_CHANGED) != 0) { + mirrorMaterial.specularColor = (Color3f)value; + } + else if ((component & SHININESS_CHANGED) != 0) { + mirrorMaterial.shininess = ((Float)value).floatValue(); + } + else if ((component & ENABLE_CHANGED) != 0) { + mirrorMaterial.lightingEnable = ((Boolean)value).booleanValue(); + } + else if ((component & COLORTARGET_CHANGED) != 0) { + mirrorMaterial.colorTarget = ((Integer)value).intValue(); + } + + } + + + boolean equivalent(MaterialRetained m) { + return ((m != null) && + lightingEnable == m.lightingEnable && + diffuseColor.equals(m.diffuseColor) && + emissiveColor.equals(m.emissiveColor) && + specularColor.equals(m.specularColor) && + ambientColor.equals(m.ambientColor) && + colorTarget == m.colorTarget && + shininess == m.shininess); + } + + + // This functions clones the retained side only and is used + // internally + protected Object clone() { + MaterialRetained mr = (MaterialRetained)super.clone(); + // color can't share the same reference + mr.ambientColor = new Color3f(ambientColor); + mr.emissiveColor = new Color3f(emissiveColor); + mr.diffuseColor = new Color3f(diffuseColor); + mr.specularColor = new Color3f(specularColor); + // other attributes are copy by clone() automatically + return mr; + } + + protected void set(MaterialRetained mat) { + super.set(mat); + + // duplicate any referenced data + ambientColor.set(mat.ambientColor); + emissiveColor.set(mat.emissiveColor); + diffuseColor.set(mat.diffuseColor); + specularColor.set(mat.specularColor); + shininess = mat.shininess; + lightingEnable = mat.lightingEnable; + colorTarget = mat.colorTarget; + } + + + final void sendMessage(int attrMask, Object attr) { + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.MATERIAL_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + int size = univList.size(); + for(int i=0; isetURLString, setURLObject, + * or setInputStream may be + * non-null (or they may all be null). An attempt to set more + * than one of these attributes to a non-null reference will + * result in an exception being thrown. If all sound media data + * references are null, there is no sound associated with this + * MediaContainer and Sound nodes referencing this object cannot + * be played. + */ +public class MediaContainer extends NodeComponent { + /** + * For MediaContainer component objects, specifies that this object + * allows the reading of its cached flag. + */ + public static final int + ALLOW_CACHE_READ = CapabilityBits.MEDIA_CONTAINER_ALLOW_CACHE_READ; + + /** + * For MediaContainer component objects, specifies that this object + * allows the writing of its cached flag. + */ + public static final int + ALLOW_CACHE_WRITE = CapabilityBits.MEDIA_CONTAINER_ALLOW_CACHE_WRITE; + + /** + * For MediaContainer component objects, specifies that this object + * allows the reading of it's sound data. + */ + public static final int + ALLOW_URL_READ = CapabilityBits.MEDIA_CONTAINER_ALLOW_URL_READ; + + /** + * For MediaContainer component objects, specifies that this object + * allows the writing of it's URL path. + */ + public static final int + ALLOW_URL_WRITE = CapabilityBits.MEDIA_CONTAINER_ALLOW_URL_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_CACHE_READ, + ALLOW_URL_READ + }; + + /** + * Constructs a MediaContainer object with default parameters. + * The default values are as follows: + *
    + * URL String data : null
    + * URL object data : null
    + * InputStream data : null
    + * cache enable : true
    + *
+ */ + public MediaContainer() { + // Just use default values + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a MediaContainer object using specified + * parameters. + * @param path string of URL path containing sound data + * @exception SoundException if the URL is not valid or cannot be opened + */ + public MediaContainer(String path) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((MediaContainerRetained)this.retained).setURLString(path); + } + + /** + * Constructs and initializes a MediaContainer object using specified + * parameters. + * @param url URL path containing sound data + * @exception SoundException if the URL is not valid or cannot be opened + */ + public MediaContainer(URL url) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((MediaContainerRetained)this.retained).setURLObject(url); + } + + /** + * Constructs and initializes a MediaContainer object using specified + * parameters. + * @param stream input stream containing sound data + * + * @since Java 3D 1.2 + */ + public MediaContainer(InputStream stream) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((MediaContainerRetained)this.retained).setInputStream(stream); + } + + /** + * Creates the retained mode MediaContainerRetained object that this + * component object will point to. + */ + void createRetained() { + this.retained = new MediaContainerRetained(); + this.retained.setSource(this); + } + + /** + * Set Cache Enable state flag. + * Allows the writing of sound data explicitly into the MediaContainer + * rather than just referencing a JavaMedia container. + * @param flag boolean denoting if sound data is cached in this instance + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setCacheEnable(boolean flag) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CACHE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer1")); + + ((MediaContainerRetained)this.retained).setCacheEnable(flag); + } + + /** + * Retrieve Cache Enable state flag. + * @return flag denoting is sound data is non-cached or cached + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getCacheEnable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CACHE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer2")); + + return ((MediaContainerRetained)this.retained).getCacheEnable(); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setURLString + */ + public void setURL(String path) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_URL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer3")); + } + + ((MediaContainerRetained)this.retained).setURLString(path); + } + /** + * @deprecated As of Java 3D version 1.2, replaced by + * setURLObject + */ + public void setURL(URL url) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_URL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer3")); + ((MediaContainerRetained)this.retained).setURLObject(url); + } + + /** + * Set URL String. + * @param path string of URL containing sound data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception SoundException if the URL is not valid or cannot be opened + * @exception IllegalArgumentException if the specified sound data is + * non-null and any other sound data reference is also non-null. + * @since Java 3D 1.2 + */ + public void setURLString(String path) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_URL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer3")); + } + ((MediaContainerRetained)this.retained).setURLString(path); + } + + /** + * Set URL Object. + * @param url URL object containing sound data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception SoundException if the URL is not valid or cannot be opened + * @exception IllegalArgumentException if the specified sound data is + * non-null and any other sound data reference is also non-null. + * @since Java 3D 1.2 + */ + public void setURLObject(URL url) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_URL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer3")); + ((MediaContainerRetained)this.retained).setURLObject(url); + } + + /** + * Set Input Stream. + * @param stream input stream object containing sound data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception SoundException if InputStream is bad + * @exception IllegalArgumentException if the specified sound data is + * non-null and any other sound data reference is also non-null. + * @since Java 3D 1.2 + */ + public void setInputStream(InputStream stream) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_URL_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer3")); + ((MediaContainerRetained)this.retained).setInputStream(stream); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * getURLString + */ + public String getURL() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_URL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer4")); + return ((MediaContainerRetained)this.retained).getURLString(); + } + + /** + * Retrieve URL String. + * @return string of URL containing sound data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.2 + */ + public String getURLString() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_URL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer4")); + return ((MediaContainerRetained)this.retained).getURLString(); + } + + /** + * Retrieve URL Object. + * @return URL containing sound data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.2 + */ + public URL getURLObject() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_URL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer4")); + return ((MediaContainerRetained)this.retained).getURLObject(); + } + + /** + * Retrieve Input Stream. + * @return reference to input stream containing sound data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.2 + */ + public InputStream getInputStream() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_URL_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("MediaContainer4")); + return ((MediaContainerRetained)this.retained).getInputStream(); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced with + * cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + MediaContainer mc = new MediaContainer(); + mc.duplicateNodeComponent(this); + return mc; + } + + + /** + * Copies all MediaContainer information from + * originalNodeComponent into + * the current node. This method is called from the + * cloneNodeComponent method and duplicateNodeComponent + * method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNodeComponent the original node component to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node component's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + MediaContainerRetained mc = (MediaContainerRetained) + originalNodeComponent.retained; + MediaContainerRetained rt = (MediaContainerRetained) retained; + rt.setCacheEnable(mc.getCacheEnable()); + rt.setURLString(mc.getURLString(), false); + rt.setURLObject(mc.getURLObject(), false); + rt.setInputStream(mc.getInputStream(), false); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/MediaContainerRetained.java b/j3d-core/src/classes/share/javax/media/j3d/MediaContainerRetained.java new file mode 100644 index 0000000..508205d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/MediaContainerRetained.java @@ -0,0 +1,211 @@ +/* + * $RCSfile: MediaContainerRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.net.URL; +import java.io.InputStream; + +/** + * The MediaContainerRetained object defines all rendering state that can + * be set as a component object of a retained Soundscape node. + */ +class MediaContainerRetained extends NodeComponentRetained { + /** + * Gain Scale Factor applied to source with this attribute + */ + boolean cached = true; + + /** + * URL string that references the sound data + */ + URL url = null; + String urlString = null; + InputStream inputStream = null; + + + /** + * Set Cached flag + * @param state flag denoting sound data is cached by app within node + */ + void setCacheEnable(boolean state) { + this.cached = state; + // changing this AFTER sound data attached to node is ignored + // notifyUsers(); + } + + /** + * Retrieve Attrribute Gain (amplitude) + * @return gain amplitude scale factor + */ + boolean getCacheEnable() { + return this.cached; + } + + /** + * Set URL object that references the sound data + * @param url URL object that references the sound data + */ + void setURLObject(URL url) { + setURLObject(url, true); + } + + /** + * Set URL object that references the sound data + * @param url URL object that references the sound data + * @param forceLoad ensures that message about change is sent to scheduler + */ + void setURLObject(URL url, boolean forceLoad) { + // can NOT set URL object field unless the other related fields are null + if (url != null) { + if (urlString != null || inputStream != null) + throw new IllegalArgumentException(J3dI18N.getString("MediaContainer5")); + // Test if url object is valid by openning it + try { + InputStream stream; + stream = url.openStream(); + stream.close(); + } + catch (Exception e) { + throw new SoundException(javax.media.j3d.J3dI18N.getString("MediaContainer0")); + } + } + this.url = url; + // notifyUsers(); + // avoid re-loading SAME MediaContainer when duplicateAttrib calls + if (forceLoad) + dispatchMessage(); + } + + /** + * Set URL path that references the sound data + * @param path string of URL that references the sound data + */ + void setURLString(String path) { + setURLString(path, true); + } + + /** + * Set URL path that references the sound data + * @param path string of URL that references the sound data + * @param forceLoad ensures that message about change is sent to scheduler + */ + void setURLString(String path, boolean forceLoad) { + // can NOT set string field unless the other related fields are null + if (path != null) { + if (this.url != null || inputStream != null) + throw new IllegalArgumentException(J3dI18N.getString("MediaContainer5")); + // Test if path string is valid URL by trying to generate a URL + // and then openning it + try { + URL url = new URL(path); + InputStream stream; + stream = url.openStream(); + stream.close(); + } + catch (Exception e) { + throw new SoundException(javax.media.j3d.J3dI18N.getString("MediaContainer0")); + } + } + this.urlString = path; + // notifyUsers(); + // avoid re-loading SAME MediaContainer when duplicateAttrib calls + if (forceLoad) + dispatchMessage(); + } + + /** + * Set input stream reference to sound data + * @param stream InputStream that references the sound data + * @param forceLoad ensures that message about change is sent to scheduler + */ + void setInputStream(InputStream stream) { + setInputStream(stream, true); + } + + /** + * Set input stream reference to sound data + * @param stream InputStream that references the sound data + */ + void setInputStream(InputStream stream, boolean forceLoad) { + // XXXX: AudioDevice not intellegent enough to process InputStreams yet + // can NOT set stream field unless the other related fields are null + if (stream != null) { + if (url != null || urlString != null) + throw new IllegalArgumentException(J3dI18N.getString("MediaContainer5")); + } + this.inputStream = stream; + // notifyUsers(); + // avoid re-loading SAME MediaContainer when duplicateAttrib calls + if (forceLoad) + dispatchMessage(); + } + + /** + * Retrieve URL String + * @return URL string that references the sound data + */ + String getURLString() { + return this.urlString; + } + + /** + * Retrieve URL objects + * @return URL object that references the sound data + */ + URL getURLObject() { + return this.url; + } + + /** + * Retrieve InputData + * @return InputString that references the sound data + */ + InputStream getInputStream() { + return this.inputStream; + } + + /** + * Dispatch a message about a media container change + */ + void dispatchMessage() { + // Send message including a integer argumentD + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.SOUND_SCHEDULER; + createMessage.type = J3dMessage.MEDIA_CONTAINER_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(SoundRetained.SOUND_DATA_DIRTY_BIT); + createMessage.args[2]= new Integer(users.size()); + createMessage.args[3] = users; + VirtualUniverse.mc.processMessage(createMessage); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/MemoryFreeList.java b/j3d-core/src/classes/share/javax/media/j3d/MemoryFreeList.java new file mode 100644 index 0000000..b14844f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/MemoryFreeList.java @@ -0,0 +1,283 @@ +/* + * $RCSfile: MemoryFreeList.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * Class for storing various free lists. This class must be + * synchronized because different threads may try to access the lists. + */ +class MemoryFreeList { + + // never go smaller than the initial capacity + ArrayList elementData = null; + int size = 0; + int currBlockSize = 10; + Object[] currBlock = null; + int currBlockIndex = 0; + int spaceUsed = 0; + int numBlocks = 0; + int capacity = 0; + int minBlockSize = 0; + boolean justShrunk = false; + int initcap = 10; + + // the minimum size since the last shrink + int minSize = 0; + + Class c = null; + + MemoryFreeList(String className) { + this(className, 10); + } + + MemoryFreeList(String className, int initialCapacity) { + if (initialCapacity < 0) { + throw new IllegalArgumentException ("Illegal Capacity: " + + initialCapacity); + } + + try { + c = Class.forName(className); + } + catch (Exception e) { + System.err.println(e); + } + + initcap = initialCapacity; + currBlockSize = initialCapacity; + minBlockSize = currBlockSize; + elementData = new ArrayList(); + // add the first block of memory to the arraylist + currBlock = new Object[currBlockSize]; + elementData.add(currBlock); + numBlocks++; + capacity += currBlockSize; + } + + /* + MemoryFreeList(String className, Collection collection) { + try { + c = Class.forName(className); + } + catch (Exception e) { +// System.err.println(e); + } + + size = collection.size(); + initcap = size; + currBlockSize = size; + minBlockSize = currBlockSize; + elementData = new ArrayList(); + currBlock = new Object[currBlockSize]; + collection.toArray(currBlock); + elementData.add(currBlock); + numBlocks++; + capacity += currBlockSize; + spaceUsed = size; + } + */ + + synchronized int size() { + return size; + } + + + synchronized boolean add(Object o) { + if (justShrunk) { + // empty some space out in the current block instead of + // adding this message + if ((currBlockSize/2) < spaceUsed) { + size -= (spaceUsed - (currBlockSize/2)); + spaceUsed = (currBlockSize/2); + Arrays.fill(currBlock, spaceUsed, currBlockSize-1, null); + } + justShrunk = false; + return false; + } + else { + ensureCapacity(size+1); + + // check to see if the whole block is used and if so, reset the + // current block +// System.err.println("spaceUsed = " + spaceUsed + " currBlockSize = " + +// currBlockSize + " currBlockIndex = " + +// currBlockIndex + " currBlock = " + currBlock); + if ((currBlockIndex == -1) || (spaceUsed >= currBlockSize)) { + currBlockIndex++; + currBlock = (Object[])elementData.get(currBlockIndex); + currBlockSize = currBlock.length; + spaceUsed = 0; + } + int index = spaceUsed++; + currBlock[index] = o; + size++; + + return true; + } + } + + protected synchronized Object removeLastElement() { +// System.err.println("removeLastElement: size = " + size); + int index = --spaceUsed; +// System.err.println("index = " + index); + Object elm = currBlock[index]; + currBlock[index] = null; + size--; + + // see if this block is empty now, and if it is set the previous + // block to the current block + if (spaceUsed == 0) { + currBlockIndex--; + if (currBlockIndex < 0) { + currBlock = null; + currBlockSize = 0; + } + else { + currBlock = (Object[])elementData.get(currBlockIndex); + currBlockSize = currBlock.length; + } + spaceUsed = currBlockSize; + } + + return elm; + } + + + synchronized void shrink() { +// System.err.println("shrink size = " + size + " minSize = " + +// minSize); + if ((minSize > minBlockSize) && (numBlocks > 1)) { + justShrunk = true; + +// System.err.println("removing a block"); +// Runtime r = Runtime.getRuntime(); +// r.gc(); +// System.err.println("numBlocks = " + numBlocks + " size = " + size); +// System.err.println("free memory before shrink: " + r.freeMemory()); + + // remove the last block + Object[] block = (Object[])elementData.remove(numBlocks-1); + numBlocks--; + capacity -= block.length; + + // we only need to do this if the block removed was the current + // block. otherwise we just removed a null block. + if (numBlocks == currBlockIndex) { + size -= spaceUsed; + // set the current block to the last one + currBlockIndex = numBlocks-1; + currBlock = (Object[])elementData.get(currBlockIndex); + currBlockSize = currBlock.length; + + spaceUsed = currBlockSize; + + } + +// r.gc(); +// System.err.println("free memory after shrink: " + r.freeMemory()); +// System.err.println("numBlocks = " + numBlocks + " size = " + size); + } + else { + justShrunk = false; + } + minSize = size; + } + + synchronized void ensureCapacity(int minCapacity) { +// System.err.println("ensureCapacity: size = " + size + " capacity: " + +// elementData.length); +// System.err.println("minCapacity = " + minCapacity + " capacity = " +// + capacity); + + if (minCapacity > capacity) { +// System.err.println("adding a block: numBlocks = " + numBlocks); + int lastBlockSize = + ((Object[])elementData.get(numBlocks-1)).length; + int prevBlockSize = 0; + if (numBlocks > 1) { + prevBlockSize = + ((Object[])elementData.get(numBlocks-2)).length; + } + currBlockSize = lastBlockSize + prevBlockSize; + currBlock = new Object[currBlockSize]; + elementData.add(currBlock); + numBlocks++; + currBlockIndex++; + capacity += currBlockSize; + // there is nothing used in this block yet + spaceUsed = 0; + } + } + + synchronized void rangeCheck(int index) { + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + + ", Size: " + size); + } + } + + public synchronized void clear() { +// System.err.println("clear"); + elementData.clear(); + + // put an empty block in + currBlockSize = initcap; + minBlockSize = currBlockSize; + currBlock = new Object[currBlockSize]; + elementData.add(currBlock); + numBlocks = 1; + capacity = currBlockSize; + spaceUsed = 0; + size = 0; + currBlockIndex = 0; + justShrunk = false; + } + + synchronized Object getObject() { + if (size > 0) { + return removeLastElement(); + } + else { + try { + return c.newInstance(); + } + catch (Exception e) { + System.err.println(e); + return null; + } + } + } + +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/ModelClip.java b/j3d-core/src/classes/share/javax/media/j3d/ModelClip.java new file mode 100644 index 0000000..38c75de --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ModelClip.java @@ -0,0 +1,737 @@ +/* + * $RCSfile: ModelClip.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.Enumeration; + +/** + * The ModelClip leaf node defines a set of 6 arbitrary clipping + * planes in the virtual universe. The planes are specified in the + * local coordinate system of this node, and may be individually + * enabled or disabled. This node also specifies a region of + * influence in which this set of planes is active. + *

+ * A ModelClip node also contains a list of Group nodes that specifies the + * hierarchical scope of this ModelClip. If the scope list is empty, then + * the ModelClip node has universe scope: all nodes within the region of + * influence are affected by this ModelClip node. If the scope list is + * non-empty, then only those Leaf nodes under the Group nodes in the + * scope list are affected by this ModelClip node (subject to the + * influencing bounds). + *

+ * If the regions of influence of multiple ModelClip nodes overlap, the + * Java 3D system will choose a single set of model clip planes for those + * objects that lie in the intersection. This is done in an + * implementation-dependent manner, but in general, the ModelClip node that + * is "closest" to the object is chosen. + *

+ * The individual planes specify a half-space defined by the equation: + *

    + * Ax + By + Cz + D <= 0 + *
+ * where A, B, C, D are the parameters that specify the plane. The + * parameters are passed in the x, y, z, and w fields, respectively, + * of a Vector4d object. The intersection of the set of half-spaces + * corresponding to the enabled planes in this ModelClip node defines + * a region in which points are accepted. Points in this acceptance + * region will be rendered (subject to view clipping and other + * attributes). Points that are not in the acceptance region will not + * be rendered. + * + * @since Java 3D 1.2 + */ + +public class ModelClip extends Leaf { + /** + * Specifies that the ModelClip node allows read access to its influencing + * bounds and bounding leaf at runtime. + */ + public static final int ALLOW_INFLUENCING_BOUNDS_READ = + CapabilityBits.MODEL_CLIP_ALLOW_INFLUENCING_BOUNDS_READ; + + /** + * Specifies that the ModelClip node allows write access to its influencing + * bounds and bounding leaf at runtime. + */ + public static final int ALLOW_INFLUENCING_BOUNDS_WRITE = + CapabilityBits.MODEL_CLIP_ALLOW_INFLUENCING_BOUNDS_WRITE; + + /** + * Specifies that the ModelClip node allows read access to its planes + * at runtime. + */ + public static final int ALLOW_PLANE_READ = + CapabilityBits.MODEL_CLIP_ALLOW_PLANE_READ; + + /** + * Specifies that the ModelClip node allows write access to its planes + * at runtime. + */ + public static final int ALLOW_PLANE_WRITE = + CapabilityBits.MODEL_CLIP_ALLOW_PLANE_WRITE; + + /** + * Specifies that the ModelClip node allows read access to its enable + * flags at runtime. + */ + public static final int ALLOW_ENABLE_READ = + CapabilityBits.MODEL_CLIP_ALLOW_ENABLE_READ; + + /** + * Specifies that the ModelClip node allows write access to its enable + * flags at runtime. + */ + public static final int ALLOW_ENABLE_WRITE = + CapabilityBits.MODEL_CLIP_ALLOW_ENABLE_WRITE; + + /** + * Specifies that this ModelClip node allows read access to its scope + * information at runtime. + */ + public static final int ALLOW_SCOPE_READ = + CapabilityBits.MODEL_CLIP_ALLOW_SCOPE_READ; + + /** + * Specifies that this ModelClip node allows write access to its scope + * information at runtime. + */ + public static final int ALLOW_SCOPE_WRITE = + CapabilityBits.MODEL_CLIP_ALLOW_SCOPE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SCOPE_READ, + ALLOW_ENABLE_READ, + ALLOW_INFLUENCING_BOUNDS_READ, + ALLOW_PLANE_READ + }; + + /** + * Constructs a ModelClip node with default parameters. The default + * values are as follows: + *
    + * planes[0] : x <= 1 (1,0,0,-1)
    + * planes[1] : -x <= 1 (-1,0,0,-1)
    + * planes[2] : y <= 1 (0,1,0,-1)
    + * planes[3] : -y <= 1 (0,-1,0,-1)
    + * planes[4] : z <= 1 (0,0,1,-1)
    + * planes[5] : -z <= 1 (0,0,-1,-1)
    + * enables : all planes enabled
    + * scope : empty (universe scope)
    + * influencing bounds : null
    + * influencing bounding leaf : null
    + *
+ */ + public ModelClip() { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + } + + + /** + * Constructs a ModelClip node using the specified planes. The individual + * planes are copied into this node. All planes are enabled. + * @param planes an array of 6 model clipping planes + */ + public ModelClip(Vector4d[] planes) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ModelClipRetained)this.retained).initPlanes(planes); + } + + + /** + * Constructs a ModelClip node using the specified planes and enable + * flags. The individual + * planes and enable flags are copied into this node. + * @param planes an array of 6 model clipping planes + * @param enables an array of 6 enable flags + */ + public ModelClip(Vector4d[] planes, boolean[] enables) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ModelClipRetained)this.retained).initPlanes(planes); + ((ModelClipRetained)this.retained).initEnables(enables); + } + + + /** + * Set the ModelClip node's influencing region to the specified bounds. + * This is used when the influencing bounding leaf is set to null. + * @param region the bounds that contains the new influencing + * region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInfluencingBounds(Bounds region) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip0")); + + if (isLive()) + ((ModelClipRetained)this.retained).setInfluencingBounds(region); + else + ((ModelClipRetained)this.retained).initInfluencingBounds(region); + } + + + /** + * Retrieves the ModelClip node's influencing bounds. + * @return this node's influencing bounds information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getInfluencingBounds() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_INFLUENCING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip1")); + + return ((ModelClipRetained)this.retained).getInfluencingBounds(); + } + + + /** + * Set the ModelClip node's influencing region to the specified + * bounding leaf. + * When set to a value other than null, this overrides the influencing + * bounds object. + * @param region the bounding leaf node used to specify the + * new influencing region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInfluencingBoundingLeaf(BoundingLeaf region) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip13")); + + if (isLive()) + ((ModelClipRetained)this.retained).setInfluencingBoundingLeaf(region); + else + ((ModelClipRetained)this.retained).initInfluencingBoundingLeaf(region); + } + + + /** + * Retrieves the ModelClip node's influencing bounding leaf. + * @return this node's influencing bounding leaf information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BoundingLeaf getInfluencingBoundingLeaf() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_INFLUENCING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip14")); + + return ((ModelClipRetained)this.retained).getInfluencingBoundingLeaf(); + } + + + /** + * Replaces the node at the specified index in this ModelClip node's + * list of scopes with the specified Group node. + * By default, ModelClip nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be stored at the specified index. + * @param index the index of the Group node to be replaced. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void setScope(Group scope, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip7")); + + if (isLive()) + ((ModelClipRetained)this.retained).setScope(scope, index); + else + ((ModelClipRetained)this.retained).initScope(scope, index); + } + + + /** + * Retrieves the Group node at the specified index from this ModelClip node's + * list of scopes. + * @param index the index of the Group node to be returned. + * @return the Group node at the specified index. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Group getScope(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip8")); + + return ((ModelClipRetained)this.retained).getScope(index); + } + + + /** + * Inserts the specified Group node into this ModelClip node's + * list of scopes at the specified index. + * By default, ModelClip nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be inserted at the specified index. + * @param index the index at which the Group node is inserted. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void insertScope(Group scope, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip9")); + + if (isLive()) + ((ModelClipRetained)this.retained).insertScope(scope, index); + else + ((ModelClipRetained)this.retained).initInsertScope(scope, index); + } + + + /** + * Removes the node at the specified index from this ModelClip node's + * list of scopes. If this operation causes the list of scopes to + * become empty, then this ModelClip will have universe scope: all nodes + * within the region of influence will be affected by this ModelClip node. + * @param index the index of the Group node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the group node at the + * specified index is part of a compiled scene graph + */ + public void removeScope(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip10")); + + if (isLive()) + ((ModelClipRetained)this.retained).removeScope(index); + else + ((ModelClipRetained)this.retained).initRemoveScope(index); + } + + + /** + * Returns an enumeration of this ModelClip node's list of scopes. + * @return an Enumeration object containing all nodes in this ModelClip node's + * list of scopes. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Enumeration getAllScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip11")); + + return (Enumeration) ((ModelClipRetained)this.retained).getAllScopes(); + } + + + /** + * Appends the specified Group node to this ModelClip node's list of scopes. + * By default, ModelClip nodes are scoped only by their influencing + * bounds. This allows them to be further scoped by a list of + * nodes in the hierarchy. + * @param scope the Group node to be appended. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + */ + public void addScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip12")); + + if (isLive()) + ((ModelClipRetained)this.retained).addScope(scope); + else + ((ModelClipRetained)this.retained).initAddScope(scope); + } + + + /** + * Returns the number of nodes in this ModelClip node's list of scopes. + * If this number is 0, then the list of scopes is empty and this + * ModelClip node has universe scope: all nodes within the region of + * influence are affected by this ModelClip node. + * @return the number of nodes in this ModelClip node's list of scopes. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int numScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip11")); + + return ((ModelClipRetained)this.retained).numScopes(); + } + + + /** + * Retrieves the index of the specified Group node in this + * ModelClip node's list of scopes. + * + * @param scope the Group node to be looked up. + * @return the index of the specified Group node; + * returns -1 if the object is not in the list. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int indexOfScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip8")); + return ((ModelClipRetained)this.retained).indexOfScope(scope); + } + + + /** + * Removes the specified Group node from this ModelClip + * node's list of scopes. If the specified object is not in the + * list, the list is not modified. If this operation causes the + * list of scopes to become empty, then this ModelClip + * will have universe scope: all nodes within the region of + * influence will be affected by this ModelClip node. + * + * @param scope the Group node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if the specified group node + * is part of a compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeScope(Group scope) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip10")); + if (isLive()) + ((ModelClipRetained)this.retained).removeScope(scope); + else + ((ModelClipRetained)this.retained).initRemoveScope(scope); + } + + + /** + * Removes all Group nodes from this ModelClip node's + * list of scopes. The ModelClip node will then have + * universe scope: all nodes within the region of influence will + * be affected by this ModelClip node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if any group node in this + * node's list of scopes is part of a compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeAllScopes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCOPE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip10")); + if (isLive()) + ((ModelClipRetained)this.retained).removeAllScopes(); + else + ((ModelClipRetained)this.retained).initRemoveAllScopes(); + } + + + /** + * Sets the clipping planes of this ModelClip node to the + * specified planes. + * The individual planes are copied into this node. + * @param planes an array of 6 model clipping planes + */ + public void setPlanes(Vector4d[] planes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_PLANE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip2")); + + if (isLive()) + ((ModelClipRetained)this.retained).setPlanes(planes); + else + ((ModelClipRetained)this.retained).initPlanes(planes); + } + + + /** + * Retrieves the clipping planes from this ModelClip node. + * The individual planes are copied into the specified planes, which + * must be allocated by the caller. The array must be large + * enough to hold all of the vectors. + * @param planes an array of 6 vectors that will receive the model + * clipping planes from this node + */ + public void getPlanes(Vector4d[] planes) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_PLANE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip3")); + + ((ModelClipRetained)this.retained).getPlanes(planes); + } + + + /** + * Sets the specified clipping plane of this ModelClip node. + * The specified plane is copied into this node. + * @param planeNum specifies which model clipping plane (0-5) is replaced + * @param plane new model clipping plane + */ + public void setPlane(int planeNum, Vector4d plane) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_PLANE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip2")); + + if (isLive()) + ((ModelClipRetained)this.retained).setPlane(planeNum, plane); + else + ((ModelClipRetained)this.retained).initPlane(planeNum, plane); + + } + + + /** + * Retrieves the specified clipping plane from this ModelClip node. + * The plane is copied into the specified plane, which + * must be allocated by the caller. + * @param planeNum specifies which model clipping plane (0-5) is retrieved + * @param plane a vector that will receive the specified model + * clipping plane from this node + */ + public void getPlane(int planeNum, Vector4d plane) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_PLANE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip3")); + + ((ModelClipRetained)this.retained).getPlane(planeNum, plane); + } + + + /** + * Sets the per-plane enable flags of this ModelClip node to the + * specified values. + * @param enables an array of 6 enable flags + */ + public void setEnables(boolean[] enables) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ENABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip4")); + + if (isLive()) + ((ModelClipRetained)this.retained).setEnables(enables); + else + ((ModelClipRetained)this.retained).initEnables(enables); + } + + + /** + * Retrieves the per-plane enable flags from this ModelClip node. + * The enable flags are copied into the specified array. + * The array must be large enough to hold all of the enables. + * @param enables an array of 6 booleans that will receive the + * enable flags from this node + */ + public void getEnables(boolean[] enables) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ENABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip5")); + + ((ModelClipRetained)this.retained).getEnables(enables); + } + + + /** + * Sets the specified enable flag of this ModelClip node. + * @param planeNum specifies which enable flag (0-5) is set + * @param enable new enable flag + */ + public void setEnable(int planeNum, boolean enable) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ENABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip4")); + + if (isLive()) + ((ModelClipRetained)this.retained).setEnable(planeNum, enable); + else + ((ModelClipRetained)this.retained).initEnable(planeNum, enable); + } + + + /** + * Retrieves the specified enable flag from this ModelClip node. + * @param planeNum specifies which enable flag (0-5) is retrieved + * @return the specified enable flag + */ + public boolean getEnable(int planeNum) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ENABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ModelClip5")); + + return ((ModelClipRetained)this.retained).getEnable(planeNum); + } + + /** + * Creates the retained mode ModelClipRetained object that + * this ModelClip node will point to. + */ + void createRetained() { + this.retained = new ModelClipRetained(); + this.retained.setSource(this); + } + + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + ModelClip c = new ModelClip(); + c.duplicateNode(this, forceDuplicate); + return c; + } + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + ModelClipRetained rt = (ModelClipRetained) retained; + BoundingLeaf bl = rt.getInfluencingBoundingLeaf(); + + // check for influencingBoundingLeaf + if (bl != null) { + Object o = referenceTable.getNewObjectReference( bl); + rt.initInfluencingBoundingLeaf((BoundingLeaf) o); + } + + int num = rt.numScopes(); + for (int i=0; i < num; i++) { + rt.initScope((Group) referenceTable. + getNewObjectReference(rt.getScope(i)), i); + } + } + + + /** + * Copies all Clip information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + ModelClipRetained attr = (ModelClipRetained) + originalNode.retained; + ModelClipRetained rt = (ModelClipRetained) retained; + + Vector4d plane = new Vector4d(); + + for (int i=5; i >=0; i--) { + attr.getPlane(i, plane); + rt.initPlane(i, plane); + rt.initEnable(i, attr.getEnable(i)); + } + rt.initInfluencingBounds(attr.getInfluencingBounds()); + + Enumeration elm = attr.getAllScopes(); + while (elm.hasMoreElements()) { + // this reference will set correctly in updateNodeReferences() callback + rt.initAddScope((Group) elm.nextElement()); + } + + // correct value will set in updateNodeReferences + rt.initInfluencingBoundingLeaf(attr.getInfluencingBoundingLeaf()); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ModelClipRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ModelClipRetained.java new file mode 100644 index 0000000..9add074 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ModelClipRetained.java @@ -0,0 +1,1071 @@ +/* + * $RCSfile: ModelClipRetained.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Enumeration; +import java.util.Vector; +import java.util.ArrayList; +import javax.vecmath.*; + +/** + * The ModelClip retained object. + */ +class ModelClipRetained extends LeafRetained { + + // Statics used when something in the fog changes + static final int PLANE_CHANGED = 0x0001; + static final int PLANES_CHANGED = 0x0002; + static final int ENABLE_CHANGED = 0x0004; + static final int ENABLES_CHANGED = 0x0008; + static final int BOUNDS_CHANGED = 0x0010; + static final int BOUNDINGLEAF_CHANGED = 0x0020; + static final int SCOPE_CHANGED = 0x0040; + static final int INIT_MIRROR = 0x0080; + static final int CLEAR_MIRROR = 0x0100; + static final int LAST_DEFINED_BIT = 0x0100; + + /** + * The clip planes and the enable bits + */ + Vector4d[] planes = new Vector4d[6]; + boolean[] enables = new boolean[6]; + + Vector4d[] xformPlanes = new Vector4d[6]; + + // enableFlag is true if one of the enables is true + // only used by mirror object + boolean enableFlag = false; + + /** + * The Boundary object defining the model clip's region of influencing + */ + Bounds regionOfInfluence = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * The transformed value of the influencingRegion. + */ + Bounds region = null; + + /** + * Vector of GroupRetained nodes that scopes this model clip. + */ + Vector scopes = new Vector(); + + //Boolean to indicate if this object is scoped (only used for mirror objects + boolean isScoped = false; + + // The object that contains the dynamic HashKey - a string type object + // Used in scoping + HashKey tempKey = new HashKey(250); + + // This is true when this model clip is referenced in an immediate mode context + boolean inImmCtx = false; + + // The mirror copy of this modelClip + ModelClipRetained mirrorModelClip = null; + + // A reference to the scene graph model clip + ModelClipRetained sgModelClip = null; + + // Target threads to be notified when model clip changes + final static int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_RENDER; + + /** + * The EnvironmentSets which reference this model clip. + * Note that multiple RenderBin update thread may access + * this shared environmentSets simultaneously. + * So we use UnorderList which sync. all the operations. + */ + UnorderList environmentSets = new UnorderList(1, EnvironmentSet.class); + + // Is true, if the mirror clip is viewScoped + boolean isViewScoped = false; + + /** + * Constructs and initializes model clip planes + */ + ModelClipRetained() { + + // planes contains the negate default values + planes[0] = new Vector4d( 1.0, 0.0, 0.0,-1.0); + planes[1] = new Vector4d(-1.0, 0.0, 0.0,-1.0); + planes[2] = new Vector4d( 0.0, 1.0, 0.0,-1.0); + planes[3] = new Vector4d( 0.0,-1.0, 0.0,-1.0); + planes[4] = new Vector4d( 0.0, 0.0, 1.0,-1.0); + planes[5] = new Vector4d( 0.0, 0.0, -1.0,-1.0); + + for (int i = 0; i < 6; i++) + xformPlanes[i] = new Vector4d(planes[i]); + + enables[0] = enables[1] = enables[2] = enables[3] = + enables[4] = enables[5] = true; + } + + /** + * Initializes planes before the object is live + */ + void initPlanes(Vector4d[] planes) { + + if (staticTransform != null) { + Transform3D xform = staticTransform.getNormalTransform(); + for (int i = 0; i < 6; i++) { + this.planes[i].set(planes[i]); + xform.transform(this.planes[i], this.xformPlanes[i]); + } + } else { + for (int i = 0; i < 6; i++) { + this.planes[i].set(planes[i]); + this.xformPlanes[i].set(this.planes[i]); + } + } + } + + /** + * Sets the clip planes and send a message + */ + void setPlanes(Vector4d[] planes) { + Vector4d[] pl = new Vector4d[6]; + initPlanes(planes); + + for (int i = 0; i < 6; i++) { + pl[i] = new Vector4d(this.xformPlanes[i]); + } + + sendMessage(PLANES_CHANGED, pl, null); + } + + /** + * Initializes planes before the object is live + */ + void initPlane(int planeNum, Vector4d plane) { + if (planeNum < 0 || planeNum > 5) + throw new IllegalArgumentException(J3dI18N.getString("ModelClip6")); + + if (staticTransform != null) { + Transform3D xform = staticTransform.getNormalTransform(); + this.planes[planeNum].set(plane); + xform.transform(this.planes[planeNum], this.xformPlanes[planeNum]); + } else { + this.planes[planeNum].set(plane); + this.xformPlanes[planeNum].set(plane); + } + } + + /** + * Sets the clip planes and send a message + */ + void setPlane(int planeNum, Vector4d plane) { + initPlane(planeNum, plane); + sendMessage(PLANE_CHANGED, + new Integer(planeNum), + new Vector4d(this.xformPlanes[planeNum])); + } + + /** + * Gets planes + */ + void getPlanes(Vector4d[] planes){ + + for (int i = 0; i < 6; i++) { + planes[i].set(this.planes[i]); + } + } + + /** + * Gets the specified clipping plane + */ + void getPlane(int planeNum, Vector4d plane) { + if (planeNum < 0 || planeNum > 5) + throw new IllegalArgumentException(J3dI18N.getString("ModelClip6")); + plane.set(this.planes[planeNum]); + } + + /** + * Initializes planes before the object is live + */ + void initEnables(boolean[] enables) { + this.enables[0] = enables[0]; + this.enables[1] = enables[1]; + this.enables[2] = enables[2]; + this.enables[3] = enables[3]; + this.enables[4] = enables[4]; + this.enables[5] = enables[5]; + } + + /** + * Sets the clip planes and send a message + */ + void setEnables(boolean[] enables) { + Boolean[] en = new Boolean[6]; + + initEnables(enables); + en[0] = (enables[0] ? Boolean.TRUE: Boolean.FALSE); + en[1] = (enables[1] ? Boolean.TRUE: Boolean.FALSE); + en[2] = (enables[2] ? Boolean.TRUE: Boolean.FALSE); + en[3] = (enables[3] ? Boolean.TRUE: Boolean.FALSE); + en[4] = (enables[4] ? Boolean.TRUE: Boolean.FALSE); + en[5] = (enables[5] ? Boolean.TRUE: Boolean.FALSE); + + sendMessage(ENABLES_CHANGED, en, null); + } + + /** + * Initializes planes before the object is live + */ + void initEnable(int planeNum, boolean enable) { + if (planeNum < 0 || planeNum > 5) + throw new IllegalArgumentException(J3dI18N.getString("ModelClip6")); + this.enables[planeNum] = enable; + } + + /** + * Sets the clip planes and send a message + */ + void setEnable(int planeNum, boolean enable) { + initEnable(planeNum, enable); + sendMessage(ENABLE_CHANGED, + new Integer(planeNum), + (enable ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Gets enables + */ + void getEnables(boolean[] enables) { + enables[0] = this.enables[0]; + enables[1] = this.enables[1]; + enables[2] = this.enables[2]; + enables[3] = this.enables[3]; + enables[4] = this.enables[4]; + enables[5] = this.enables[5]; + } + + /** + * Gets the specified enable + */ + boolean getEnable(int planeNum) { + if (planeNum < 0 || planeNum > 5) + throw new IllegalArgumentException(J3dI18N.getString("ModelClip6")); + return (this.enables[planeNum]); + } + + /** + * Set the Model Clip's region of influencing + */ + void initInfluencingBounds(Bounds region) { + if (region != null) { + this.regionOfInfluence = (Bounds) region.clone(); + if (staticTransform != null) { + regionOfInfluence.transform(staticTransform.transform); + } + } else { + this.regionOfInfluence = null; + } + } + + /** + * Set the Model Clip's region of influencing and send message + */ + void setInfluencingBounds(Bounds region) { + initInfluencingBounds(region); + sendMessage(BOUNDS_CHANGED, + (region != null ? (Bounds) region.clone(): null), + null); + } + + /** + * Get the Model Clip's region of influencing. + */ + Bounds getInfluencingBounds() { + Bounds b = null; + + if (regionOfInfluence != null) { + b = (Bounds) regionOfInfluence.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + } + return b; + } + + /** + * Set the Model Clip's region of influencing to the specified Leaf node. + */ + void initInfluencingBoundingLeaf(BoundingLeaf region) { + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + } else { + boundingLeaf = null; + } + } + + /** + * Set the Model Clip's region of influencing to the specified Leaf node. + */ + void setInfluencingBoundingLeaf(BoundingLeaf region) { + if (boundingLeaf != null) + boundingLeaf.mirrorBoundingLeaf.removeUser(mirrorModelClip); + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + boundingLeaf.mirrorBoundingLeaf.addUser(mirrorModelClip); + } else { + boundingLeaf = null; + } + + sendMessage(BOUNDINGLEAF_CHANGED, + (boundingLeaf != null ? + boundingLeaf.mirrorBoundingLeaf : null), + null); + } + + + /** + * Get the Model Clip's region of influencing. + */ + BoundingLeaf getInfluencingBoundingLeaf() { + return (boundingLeaf != null ? + (BoundingLeaf)boundingLeaf.source : null); + } + + /** + * Replaces the specified scope with the scope provided. + * @param scope the new scope + * @param index which scope to replace + */ + void initScope(Group scope, int index) { + scopes.setElementAt((GroupRetained)(scope.retained), index); + } + + /** + * Replaces the specified scope with the scope provided. + * @param scope the new scope + * @param index which scope to replace + */ + void setScope(Group scope, int index) { + + ArrayList addScopeList = new ArrayList(); + ArrayList removeScopeList = new ArrayList(); + GroupRetained group; + Object[] scopeInfo = new Object[3]; + + group = (GroupRetained) scopes.get(index); + tempKey.reset(); + group.removeAllNodesForScopedModelClip(mirrorModelClip, removeScopeList, tempKey); + + group = (GroupRetained)scope.retained; + initScope(scope, index); + tempKey.reset(); + // If its a group, then add the scope to the group, if + // its a shape, then keep a list to be added during + // updateMirrorObject + group.addAllNodesForScopedModelClip(mirrorModelClip,addScopeList, tempKey); + scopeInfo[0] = addScopeList; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE:Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo, null); + } + + /** + * Inserts the specified scope at specified index + * @param scope the new scope + * @param index position to insert new scope at + */ + void initInsertScope(Node scope, int index) { + GroupRetained group = (GroupRetained)scope.retained; + group.setMclipScope(); + scopes.insertElementAt((GroupRetained)(scope.retained), index); + } + + /** + * Inserts the specified scope at specified index and sends + * a message + * @param scope the new scope + * @param index position to insert new scope at + */ + void insertScope(Node scope, int index) { + Object[] scopeInfo = new Object[3]; + ArrayList addScopeList = new ArrayList(); + + initInsertScope(scope, index); + GroupRetained group = (GroupRetained)scope.retained; + tempKey.reset(); + group.addAllNodesForScopedModelClip(mirrorModelClip,addScopeList, tempKey); + scopeInfo[0] = addScopeList; + scopeInfo[1] = null; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo, null); + } + + + void initRemoveScope(int index) { + GroupRetained group = (GroupRetained)scopes.elementAt(index); + group.removeMclipScope(); + scopes.removeElementAt(index); + + } + + void removeScope(int index) { + + Object[] scopeInfo = new Object[3]; + ArrayList removeScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scopes.elementAt(index); + + initRemoveScope(index); + tempKey.reset(); + group.removeAllNodesForScopedModelClip(mirrorModelClip, removeScopeList, tempKey); + + scopeInfo[0] = null; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo, null); + } + + /** + * Removes the specified Group node from this ModelClip's list of + * scopes if the specified node is not found in the list of scoped + * nodes, method returns quietly. + * + * @param Group node to be removed + */ + void removeScope(Group node) { + int ind = indexOfScope(node); + if(ind >= 0) + removeScope(ind); + } + + void initRemoveScope(Group node) { + int ind = indexOfScope(node); + if(ind >= 0) + initRemoveScope(ind); + } + + /** + * Removes all the Group nodes from the ModelClip's scope + * list. The ModelClip reverts to universal scope. + */ + void removeAllScopes() { + Object[] scopeInfo = new Object[3]; + ArrayList removeScopeList = new ArrayList(); + int n = scopes.size(); + for(int index = n-1; index >= 0; index--) { + GroupRetained group = (GroupRetained)scopes.elementAt(index); + initRemoveScope(index); + tempKey.reset(); + group.removeAllNodesForScopedModelClip(mirrorModelClip, removeScopeList, tempKey); + } + + scopeInfo[0] = null; + scopeInfo[1] = removeScopeList; + scopeInfo[2] = (Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo, null); + } + + + void initRemoveAllScopes() { + int n = scopes.size(); + for(int i = n-1; i >= 0; i--) { + initRemoveScope(i); + } + } + + /** + * Returns the scope specified by the index. + * @param index which scope to return + * @return the scoperen at location index + */ + Group getScope(int index) { + return (Group)(((GroupRetained)(scopes.elementAt(index))).source); + } + + /** + * Returns an enumeration object of the scoperen. + * @return an enumeration object of the scoperen + */ + Enumeration getAllScopes() { + Enumeration elm = scopes.elements(); + Vector v = new Vector(scopes.size()); + while (elm.hasMoreElements()) { + v.add( ((GroupRetained) elm.nextElement()).source); + } + return v.elements(); + } + + /** + * Appends the specified scope to this node's list of scopes before + * the fog is alive + * @param scope the scope to add to this node's list of scopes + */ + void initAddScope(Group scope) { + GroupRetained group = (GroupRetained)scope.retained; + scopes.addElement((GroupRetained)(scope.retained)); + group.setMclipScope(); + } + + /** + * Appends the specified scope to this node's list of scopes. + * @param scope the scope to add to this node's list of scopes + */ + void addScope(Group scope) { + + Object[] scopeInfo = new Object[3]; + ArrayList addScopeList = new ArrayList(); + GroupRetained group = (GroupRetained)scope.retained; + + initAddScope(scope); + tempKey.reset(); + group.addAllNodesForScopedModelClip(mirrorModelClip,addScopeList, tempKey); + scopeInfo[0] = addScopeList; + scopeInfo[1] = null; + scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE); + sendMessage(SCOPE_CHANGED, scopeInfo, null); + } + + /** + * Returns a count of this nodes' scopes. + * @return the number of scopes descendant from this node + */ + int numScopes() { + return scopes.size(); + } + + /** + * Returns the index of the specified Group node within the ModelClip's list of scoped + * Group nodes + * @param Group node whose index is desired + * @return index of this node + */ + int indexOfScope(Group node) { + if(node != null) + return scopes.indexOf((GroupRetained)node.retained); + else + return scopes.indexOf(null); + } + + /** + * This sets the immedate mode context flag + */ + void setInImmCtx(boolean inCtx) { + inImmCtx = inCtx; + } + + /** + * This gets the immedate mode context flag + */ + boolean getInImmCtx() { + return (inImmCtx); + } + + + /** + * This method and its native counterpart update the native context + * model clip planes. + */ + void update(Canvas3D cv, int enableMask) { + cv.setModelViewMatrix(cv.ctx, + cv.vworldToEc.mat, + getLastLocalToVworld()); + update(cv.ctx, enableMask, getLastLocalToVworld()); + } + + void update(Context ctx, int enableMask, Transform3D trans) { + if (!VirtualUniverse.mc.isD3D()) { + for (int i = 0; i < 6; i ++) { + Pipeline.getPipeline().updateModelClip(ctx, i, ((enableMask & (1 << i)) != 0), + xformPlanes[i].x, xformPlanes[i].y, + xformPlanes[i].z, xformPlanes[i].w); + } + return; + } + + // For D3D we need to transform the plane equations from local to + // world coordinate. + Transform3D invtrans = new Transform3D(trans); + + // can't call getNormalTransform() since it will cache + // normalTransform and may return previous result next time. + invtrans.invert(); + invtrans.transpose(); + + for (int i=0; i < 6; i++) { + if ((enableMask & (1 << i)) != 0) { + + Vector4d vec = new Vector4d(xformPlanes[i].x, xformPlanes[i].y, + xformPlanes[i].z, xformPlanes[i].w); + vec.normalize(); + invtrans.transform(vec); + Pipeline.getPipeline().updateModelClip(ctx, i, true, vec.x, vec.y, vec.z, vec.w); + + } else { + Pipeline.getPipeline().updateModelClip(ctx, i, false, 0, 0, 0, 0); + } + } + } + + void initMirrorObject(Object[] args) { + Shape3DRetained shape; + Object[] scopeInfo = (Object[]) args[2]; + Boolean scoped = (Boolean)scopeInfo[0]; + ArrayList shapeList = (ArrayList)scopeInfo[1]; + BoundingLeafRetained bl=(BoundingLeafRetained)((Object[])args[4])[0]; + Bounds bnds = (Bounds)((Object[])args[4])[1]; + + for (int i = 0; i < shapeList.size(); i++) { + shape = ((GeometryAtom)shapeList.get(i)).source; + shape.addModelClip(mirrorModelClip); + } + mirrorModelClip.isScoped = scoped.booleanValue(); + + if (bl != null) { + mirrorModelClip.boundingLeaf = bl.mirrorBoundingLeaf; + mirrorModelClip.region = boundingLeaf.transformedRegion; + } else { + mirrorModelClip.boundingLeaf = null; + mirrorModelClip.region = null; + } + + if (bnds != null) { + mirrorModelClip.regionOfInfluence = bnds; + if (mirrorModelClip.region == null) { + mirrorModelClip.region = (Bounds)regionOfInfluence.clone(); + mirrorModelClip.region.transform(regionOfInfluence, getLastLocalToVworld()); + } + } + else { + mirrorModelClip.regionOfInfluence = null; + } + boolean[] ens = (boolean[])((Object[])args[4])[2]; + + for (int i = 0; i < ens.length; i++) { + mirrorModelClip.enables[i] = ens[i]; + } + mirrorModelClip.enableFlag = mirrorModelClip.enables[0] | + mirrorModelClip.enables[1] | + mirrorModelClip.enables[2] | + mirrorModelClip.enables[3] | + mirrorModelClip.enables[4] | + mirrorModelClip.enables[5] ; + + } + + + + void updateMirrorObject(Object[] objs) { + int component = ((Integer)objs[1]).intValue(); + if ((component & PLANES_CHANGED) != 0) { + Vector4d[] pl = ((Vector4d[]) objs[2]); + + for (int i = 0; i < 6; i++) { + mirrorModelClip.xformPlanes[i].set(pl[i]); + } + } + else if ((component & PLANE_CHANGED) != 0) { + int planeNum = ((Integer)objs[2]).intValue(); + + mirrorModelClip.xformPlanes[planeNum].set((Vector4d)objs[3]); + } + else if ((component & INIT_MIRROR) != 0) { + Vector4d[] pl = (Vector4d[]) objs[3]; + for (int i = 0; i < 6; i++) { + mirrorModelClip.xformPlanes[i].set(pl[i]); + } + } + } + + // The update Object function. + void updateImmediateMirrorObject(Object[] objs) { + int component = ((Integer)objs[1]).intValue(); + Transform3D trans; + + + if ((component & BOUNDINGLEAF_CHANGED) != 0) { + mirrorModelClip.boundingLeaf = (BoundingLeafRetained)objs[2]; + if (objs[2] != null) { + mirrorModelClip.region = + (Bounds)mirrorModelClip.boundingLeaf.transformedRegion; + } + else { + if (mirrorModelClip.regionOfInfluence != null) { + mirrorModelClip.region = + ((Bounds)mirrorModelClip.regionOfInfluence).copy(mirrorModelClip.region); + mirrorModelClip.region.transform(mirrorModelClip.regionOfInfluence, + getCurrentLocalToVworld()); + } + else { + mirrorModelClip.region = null; + } + + } + } + + if ((component & BOUNDS_CHANGED) != 0) { + mirrorModelClip.regionOfInfluence = (Bounds) objs[2]; + if (mirrorModelClip.boundingLeaf == null) { + if (objs[2] != null) { + mirrorModelClip.region = + ((Bounds)mirrorModelClip.regionOfInfluence).copy(mirrorModelClip.region); + + mirrorModelClip.region.transform(mirrorModelClip.regionOfInfluence, + getCurrentLocalToVworld()); + } + else { + mirrorModelClip.region = null; + } + } + } + + if ((component & SCOPE_CHANGED) != 0) { + Object[] scopeList = (Object[])objs[2]; + ArrayList addList = (ArrayList)scopeList[0]; + ArrayList removeList = (ArrayList)scopeList[1]; + boolean isScoped = ((Boolean)scopeList[2]).booleanValue(); + + if (addList != null) { + mirrorModelClip.isScoped = isScoped; + for (int i = 0; i < addList.size(); i++) { + Shape3DRetained obj = ((GeometryAtom)addList.get(i)).source; + obj.addModelClip(mirrorModelClip); + } + } + + if (removeList != null) { + mirrorModelClip.isScoped = isScoped; + for (int i = 0; i < removeList.size(); i++) { + Shape3DRetained obj = ((GeometryAtom)removeList.get(i)).source; + obj.removeModelClip(mirrorModelClip); + } + } + } + + if ((component & ENABLES_CHANGED) != 0) { + Boolean[] en = ((Boolean[]) objs[2]); + + mirrorModelClip.enables[0] = en[0].booleanValue(); + mirrorModelClip.enables[1] = en[1].booleanValue(); + mirrorModelClip.enables[2] = en[2].booleanValue(); + mirrorModelClip.enables[3] = en[3].booleanValue(); + mirrorModelClip.enables[4] = en[4].booleanValue(); + mirrorModelClip.enables[5] = en[5].booleanValue(); + mirrorModelClip.enableFlag = mirrorModelClip.enables[0] | + mirrorModelClip.enables[1] | + mirrorModelClip.enables[2] | + mirrorModelClip.enables[3] | + mirrorModelClip.enables[4] | + mirrorModelClip.enables[5] ; + } else if ((component & ENABLE_CHANGED) != 0) { + int planeNum = ((Integer)objs[2]).intValue(); + + mirrorModelClip.enables[planeNum] = ((Boolean)objs[3]).booleanValue(); + mirrorModelClip.enableFlag = mirrorModelClip.enables[0] | + mirrorModelClip.enables[1] | + mirrorModelClip.enables[2] | + mirrorModelClip.enables[3] | + mirrorModelClip.enables[4] | + mirrorModelClip.enables[5] ; + } + } + + + /** Note: This routine will only be called on + * the mirror object - will update the object's + * cached region and transformed region + */ + void updateBoundingLeaf() { + if (boundingLeaf != null && boundingLeaf.switchState.currentSwitchOn) { + region = boundingLeaf.transformedRegion; + } else { + if (regionOfInfluence != null) { + region = regionOfInfluence.copy(region); + region.transform(regionOfInfluence, getCurrentLocalToVworld()); + } else { + region = null; + } + } + } + + + void setLive(SetLiveState s) { + GroupRetained group; + + super.doSetLive(s); + + if (inSharedGroup) { + throw new + IllegalSharingException(J3dI18N.getString("ModelClipRetained1")); + } + + // Create the mirror object + + + if (mirrorModelClip == null) { + mirrorModelClip = (ModelClipRetained)this.clone(); + mirrorModelClip.boundingLeaf = null; + mirrorModelClip.sgModelClip = this; + } + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(mirrorModelClip); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(mirrorModelClip); + } + + // If bounding leaf is not null, add the mirror object as a user + // so that any changes to the bounding leaf will be received + if (boundingLeaf != null) { + boundingLeaf.mirrorBoundingLeaf.addUser(mirrorModelClip); + } + // process switch leaf + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(mirrorModelClip, Targets.ENV_TARGETS); + } + mirrorModelClip.switchState = (SwitchState)s.switchStates.get(0); + + // add this model clip to the transform target + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(mirrorModelClip, Targets.ENV_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + + s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER; + super.markAsLive(); + + + // Initialize the mirror object, this needs to be done, when + // renderBin is not accessing any of the fields + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.universe = universe; + createMessage.type = J3dMessage.MODELCLIP_CHANGED; + createMessage.args[0] = this; + // a snapshot of all attributes that needs to be initialized + // in the mirror object + createMessage.args[1]= new Integer(INIT_MIRROR); + ArrayList addScopeList = new ArrayList(); + for (int i = 0; i < scopes.size(); i++) { + group = (GroupRetained)scopes.get(i); + tempKey.reset(); + group.addAllNodesForScopedModelClip(mirrorModelClip, addScopeList, tempKey); + } + Object[] scopeInfo = new Object[2]; + scopeInfo[0] = ((scopes.size() > 0) ? Boolean.TRUE:Boolean.FALSE); + scopeInfo[1] = addScopeList; + createMessage.args[2] = scopeInfo; + createMessage.args[3] = xformPlanes.clone(); + + Object[] obj = new Object[3]; + obj[0] = boundingLeaf; + obj[1] = (regionOfInfluence != null?regionOfInfluence.clone():null); + obj[2] = enables.clone(); + createMessage.args[4] = obj; + VirtualUniverse.mc.processMessage(createMessage); + + + } + + + /** + * This clearLive routine first calls the superclass's method, then + * it removes itself to the list of model clip + */ + void clearLive(SetLiveState s) { + + super.clearLive(s); + s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER; + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(mirrorModelClip, Targets.ENV_TARGETS); + } + // Remove this mirror light as users of the bounding leaf + if (mirrorModelClip.boundingLeaf != null) + mirrorModelClip.boundingLeaf.removeUser(mirrorModelClip); + + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(mirrorModelClip); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(mirrorModelClip); + } + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(mirrorModelClip, Targets.ENV_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + + + if (scopes.size() > 0) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; + createMessage.universe = universe; + createMessage.type = J3dMessage.MODELCLIP_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(CLEAR_MIRROR); + ArrayList removeScopeList = new ArrayList(); + for (int i = 0; i < scopes.size(); i++) { + GroupRetained group = (GroupRetained)scopes.get(i); + tempKey.reset(); + group.removeAllNodesForScopedModelClip(mirrorModelClip, removeScopeList, tempKey); + } + createMessage.args[2] = removeScopeList; + VirtualUniverse.mc.processMessage(createMessage); + } + } + + // This is called on the parent object + void clearMirrorObject(Object[] args) { + Shape3DRetained shape; + ArrayList shapeList = (ArrayList)args[2]; + ArrayList removeScopeList = new ArrayList(); + + for (int i = 0; i < shapeList.size(); i++) { + shape = ((GeometryAtom)shapeList.get(i)).source; + shape.removeModelClip(mirrorModelClip); + } + + mirrorModelClip.isScoped = false; + + } + + + // Clone the retained side only, internal use only + protected Object clone() { + ModelClipRetained mc = (ModelClipRetained)super.clone(); + + mc.planes = new Vector4d[6]; + for (int i = 0; i < 6; i++) { + mc.planes[i] = new Vector4d(this.planes[i]); + mc.xformPlanes[i] = new Vector4d(this.xformPlanes[i]); + } + + mc.enables = new boolean[6]; + getEnables(mc.enables); + + // Derive the enables flag + mc.enableFlag = (mc.enables[0] | + mc.enables[1] | + mc.enables[2] | + mc.enables[3] | + mc.enables[4] | + mc.enables[5] ); + + mc.inImmCtx = false; + mc.region = null; + mc.sgModelClip = null; + mc.mirrorModelClip = null; + mc.environmentSets = new UnorderList(1, EnvironmentSet.class); + + if (regionOfInfluence != null) { + mc.regionOfInfluence = (Bounds) regionOfInfluence.clone(); + } + + return mc; + } + + + // Called on mirror object + void updateImmediateTransformChange() { + // If bounding leaf is null, tranform the bounds object + if (boundingLeaf == null) { + if (regionOfInfluence != null) { + region = regionOfInfluence.copy(region); + region.transform(regionOfInfluence, + sgModelClip.getCurrentLocalToVworld()); + } + + } + } + + + void printPlane(int index, String string) + { + System.err.println(string + " : < " + planes[index].toString() + + " > " + enables[index]); + } + + void printPlanes(String string, Vector4d[] planes) + { + System.err.println(string); + printPlane(0, "[0]"); + printPlane(1, "[1]"); + printPlane(2, "[2]"); + printPlane(3, "[3]"); + printPlane(4, "[4]"); + printPlane(5, "[5]"); + } + + + void printEnables(String string, boolean[] enables) + { + System.err.println(string); + System.err.println("[0] : < " + enables[0] + " >"); + System.err.println("[1] : < " + enables[1] + " >"); + System.err.println("[2] : < " + enables[2] + " >"); + System.err.println("[3] : < " + enables[3] + " >"); + System.err.println("[4] : < " + enables[4] + " >"); + System.err.println("[5] : < " + enables[5] + " >"); + } + + final void sendMessage(int attrMask, Object attr1, Object attr2) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.type = J3dMessage.MODELCLIP_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr1; + createMessage.args[3] = attr2; + VirtualUniverse.mc.processMessage(createMessage); + } + + void mergeTransform(TransformGroupRetained staticTransform) { + super.mergeTransform(staticTransform); + + if (regionOfInfluence != null) { + regionOfInfluence.transform(staticTransform.transform); + } + + Transform3D xform = staticTransform.getNormalTransform(); + for (int i = 0; i < 6; i++) { + xform.transform(planes[i], xformPlanes[i]); + } + } + void getMirrorObjects(ArrayList leafList, HashKey key) { + leafList.add(mirrorModelClip); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Morph.java b/j3d-core/src/classes/share/javax/media/j3d/Morph.java new file mode 100644 index 0000000..d5e0d86 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Morph.java @@ -0,0 +1,707 @@ +/* + * $RCSfile: Morph.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Hashtable; +import javax.vecmath.*; + +/** + * The Morph leaf node permits an application to morph between + * multiple GeometryArrays. The Morph node contains a single + * Appearance node, an array of GeometryArray objects, and an array of + * corresponding weights. The Morph node combines these GeometryArrays + * into an aggregate shape based on each GeometryArray's corresponding + * weight. Typically, Behavior nodes will modify the weights to + * achieve various morphing effects. + * + *

+ * The following restrictions apply to each GeometryArray object + * in the specified array of GeometryArray objects: + * + *

    + *
  • + * All N geometry arrays must be of the + * same type (that is, the same subclass of GeometryArray). + *
  • + * + *

    + *

  • + * The vertexFormat, texCoordSetCount, and validVertexCount must be + * the same for all N geometry arrays. + *
  • + * + *

    + *

  • + * The texCoordSetMap array must be identical (element-by-element) for + * all N geometry arrays. + *
  • + * + *

    + *

  • + * For IndexedGeometryArray objects, the validIndexCount must be the same + * for all N geometry arrays. + *
  • + * + *

    + *

  • + * For GeometryStripArray objects, the stripVertexCounts array must + * be identical (element-by-element) for all N geometry arrays. + *
  • + * + *

    + *

  • + * For IndexedGeometryStripArray objects, the stripIndexCounts array must + * be identical (element-by-element) for all N geometry arrays. + *
  • + * + *

    + *

  • + * For indexed geometry by-reference, the array lengths of each + * enabled vertex component (coord, color, normal, texcoord) + * must be the same for all N geometry arrays. + *
  • + *
+ * + *

+ * For IndexedGeometryArray objects, the vertex arrays are morphed + * before the indexes are applied. Only the indexes in the + * first geometry array (geometry[0]) are used when rendering the + * geometry. + * + * @deprecated As of Java 3D version 1.4. + */ + +public class Morph extends Leaf { + + /** + * Specifies that the node allows read access to its geometry information. + */ + public static final int + ALLOW_GEOMETRY_ARRAY_READ = CapabilityBits.MORPH_ALLOW_GEOMETRY_ARRAY_READ; + + /** + * Specifies that the node allows write access to its geometry information. + */ + public static final int + ALLOW_GEOMETRY_ARRAY_WRITE = CapabilityBits.MORPH_ALLOW_GEOMETRY_ARRAY_WRITE; + + /** + * Specifies that the node allows read access to its appearance information. + */ + public static final int + ALLOW_APPEARANCE_READ = CapabilityBits.MORPH_ALLOW_APPEARANCE_READ; + + /** + * Specifies that the node allows write access to its appearance information. + */ + public static final int + ALLOW_APPEARANCE_WRITE = CapabilityBits.MORPH_ALLOW_APPEARANCE_WRITE; + + /** + * Specifies that the node allows read access to its morph + * weight vector. + */ + public static final int + ALLOW_WEIGHTS_READ = CapabilityBits.MORPH_ALLOW_WEIGHTS_READ; + + /** + * Specifies that the node allows write access to its morph + * weight vector. + */ + public static final int + ALLOW_WEIGHTS_WRITE = CapabilityBits.MORPH_ALLOW_WEIGHTS_WRITE; + + /** + * Specifies that the node allows reading its collision Bounds. + */ + public static final int + ALLOW_COLLISION_BOUNDS_READ = CapabilityBits.MORPH_ALLOW_COLLISION_BOUNDS_READ; + + /** + * Specifies the node allows writing its collision Bounds. + */ + public static final int + ALLOW_COLLISION_BOUNDS_WRITE = CapabilityBits.MORPH_ALLOW_COLLISION_BOUNDS_WRITE; + + /** + * Specifies that this node allows reading its appearance override + * enable flag. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_APPEARANCE_OVERRIDE_READ = + CapabilityBits.MORPH_ALLOW_APPEARANCE_OVERRIDE_READ; + + /** + * Specifies that this node allows writing its appearance override + * enable flag. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_APPEARANCE_OVERRIDE_WRITE = + CapabilityBits.MORPH_ALLOW_APPEARANCE_OVERRIDE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_GEOMETRY_ARRAY_READ, + ALLOW_APPEARANCE_READ, + ALLOW_WEIGHTS_READ, + ALLOW_COLLISION_BOUNDS_READ, + ALLOW_APPEARANCE_OVERRIDE_READ + }; + + // non public default constructor + Morph() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a Morph node with the specified array + * of GeometryArray objects. Default values are used for all other + * parameters as follows: + *

    + * appearance : null
    + * weights : [1, 0, 0, 0, ...]
    + * collision bounds : null
    + * appearance override enable : false
    + *

+ * A null appearance object specifies that default values are used + * for all appearance attributes. + * + * @param geometryArrays the geometry components of the morph; + * a null or zero-length array of GeometryArray objects is + * permitted, and specifies that no geometry is drawn. In this case, + * the array of weights is initialized to a zero-length array. + * + * @exception IllegalArgumentException if any of the specified + * geometry array objects differ from each other in any of the + * following ways: + *

    + *
  • Type of geometry array object (subclass of GeometryArray)
  • + *
  • vertexFormat
  • + *
  • texCoordSetCount
  • + *
  • texCoordSetMap
  • + *
  • validVertexCount
  • + *
  • validIndexCount, for IndexedGeometryArray objects
  • + *
  • stripVertexCounts array, for GeometryStripArray objects
  • + *
  • stripIndexCounts array, for IndexedGeometryStripArray objects
  • + *
  • the array lengths of each enabled vertex component + * (coord, color, normal, texcoord), + * for indexed geometry by-reference
  • + *
+ * + * @exception UnsupportedOperationException if the specified + * geometry arrays contain vertex attributes (that is, if their + * vertexFormat includes the VERTEX_ATTRIBUTES flag). + */ + public Morph(GeometryArray geometryArrays[]) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((MorphRetained)retained).setGeometryArrays(geometryArrays); + } + + /** + * Constructs and initializes a Morph node with the specified array + * of GeometryArray objects and the specified appearance object. + * + * @param geometryArrays the geometry components of the Morph node + * a null or zero-length array of GeometryArray objects is + * permitted, and specifies that no geometry is drawn. In this case, + * the array of weights is initialized to a zero-length array. + * @param appearance the appearance component of the Morph node + * + * @exception IllegalArgumentException if any of the specified + * geometry array objects differ from each other in any of the + * following ways: + *
    + *
  • Type of geometry array object (subclass of GeometryArray)
  • + *
  • vertexFormat
  • + *
  • texCoordSetCount
  • + *
  • texCoordSetMap
  • + *
  • validVertexCount
  • + *
  • validIndexCount, for IndexedGeometryArray objects
  • + *
  • stripVertexCounts array, for GeometryStripArray objects
  • + *
  • stripIndexCounts array, for IndexedGeometryStripArray objects
  • + *
  • the array lengths of each enabled vertex component + * (coord, color, normal, texcoord), + * for indexed geometry by-reference
  • + *
+ * + * @exception UnsupportedOperationException if the specified + * geometry arrays contain vertex attributes (that is, if their + * vertexFormat includes the VERTEX_ATTRIBUTES flag). + */ + public Morph(GeometryArray geometryArrays[], Appearance appearance) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((MorphRetained)retained).setGeometryArrays(geometryArrays); + ((MorphRetained)this.retained).setAppearance(appearance); + } + + /** + * Creates the retained mode MorphRetained object that this + * Morph object will point to. + */ + void createRetained() { + retained = new MorphRetained(); + retained.setSource(this); + } + + /** + * Sets the collision bounds of a node. + * @param bounds the collision bounding object for a node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setCollisionBounds(Bounds bounds) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLLISION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph0")); + + ((MorphRetained)this.retained).setCollisionBounds(bounds); + } + + /** + * Returns the collision bounding object of this node. + * @return the node's collision bounding object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getCollisionBounds() { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLLISION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph1")); + + return ((MorphRetained)this.retained).getCollisionBounds(); + } + + + /** + * Sets the geometryArrays component of the Morph node. + * + * If the current array of GeometryArrays in this Morph object is + * non-null with a length greater than 0, the specified array of + * GeometryArrays must be the same length as the current array. + * If the current array of GeometryArrays in this Morph object is + * null or has a length of 0, and the specified array of + * GeometryArrays is non-null with a length greater than 0, the + * length of the incoming array defines the number of the geometry + * objects that will be morphed. In this case, the weights array + * is allocated to be of the same length as the geometry array; + * the first element (weights[0]) is initialized to 1.0 and all of + * the other weights are initialized to 0.0. + * + * @param geometryArrays the new geometryArrays component + * for the Morph node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + *

+ * + * @exception IllegalArgumentException if the length of the + * specified array of geometry arrays is not equal to the length + * of this Morph node's current array of geometry arrays (and the + * current array's length is non-zero), or if any of the specified + * geometry array objects differ from each other in any of the + * following ways: + *

    + *
  • Type of geometry array object (subclass of GeometryArray)
  • + *
  • vertexFormat
  • + *
  • texCoordSetCount
  • + *
  • texCoordSetMap
  • + *
  • validVertexCount
  • + *
  • validIndexCount, for IndexedGeometryArray objects
  • + *
  • stripVertexCounts array, for GeometryStripArray objects
  • + *
  • stripIndexCounts array, for IndexedGeometryStripArray objects
  • + *
  • the array lengths of each enabled vertex component + * (coord, color, normal, texcoord), + * for indexed geometry by-reference
  • + *
+ * + * @exception UnsupportedOperationException if the specified + * geometry arrays contain vertex attributes (that is, if their + * vertexFormat includes the VERTEX_ATTRIBUTES flag). + */ + public void setGeometryArrays(GeometryArray geometryArrays[]) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_GEOMETRY_ARRAY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph2")); + + ((MorphRetained)this.retained).setGeometryArrays(geometryArrays); + } + + /** + * Retrieves the geometryArray component of this Morph node. + * @param index the index of GeometryArray to be returned + * @return the geometryArray component of this Morph node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public GeometryArray getGeometryArray(int index) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_GEOMETRY_ARRAY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph3")); + + return ((MorphRetained)this.retained).getGeometryArray(index); + } + + /** + * Sets the appearance component of this Morph node. A null + * appearance component specifies that default values are used for all + * appearance attributes. + * @param appearance the new appearance component for this Morph node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAppearance(Appearance appearance) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPEARANCE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph4")); + + ((MorphRetained)this.retained).setAppearance(appearance); + } + + /** + * Retrieves the appearance component of this morph node. + * @return the appearance component of this morph node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Appearance getAppearance() { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPEARANCE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph5")); + + return ((MorphRetained)this.retained).getAppearance(); + } + + + /** + * Checks whether the geometry in this morph node intersects with + * the specified pickShape. + * + * @param path the SceneGraphPath to this morph node + * @param pickShape the PickShape to be intersected + * + * @return true if the pick shape intersects this node; false + * otherwise. + * + * @exception IllegalArgumentException if pickShape is a PickPoint. + * Java 3D doesn't have spatial information of the surface. + * Use PickBounds with BoundingSphere and a small radius, instead. + * + * @exception CapabilityNotSetException if the Geometry.ALLOW_INTERSECT + * capability bit is not set in all of the Geometry objects + * referred to by this morph node. + */ + public boolean intersect(SceneGraphPath path, PickShape pickShape) { + return intersect(path, pickShape, null); + } + + + /** + * Checks whether the geometry in this morph node intersects with + * the specified pickRay. + * + * @param path the SceneGraphPath to this morph node + * @param pickRay the PickRay to be intersected + * @param dist the closest distance of the intersection + * + * @return true if the pick shape intersects this node; false + * otherwise. If true, dist contains the closest distance of + * intersection. + * + * @exception CapabilityNotSetException if the Geometry.ALLOW_INTERSECT + * capability bit is not set in all of the Geometry objects + * referred to by this morph node. + */ + public boolean intersect(SceneGraphPath path, + PickRay pickRay, + double[] dist) { + + if (isLiveOrCompiled()) { + checkForAllowIntersect(); + } + + return ((MorphRetained)this.retained).intersect(path, pickRay, dist); + } + + + /** + * Checks whether the geometry in this morph node intersects with + * the specified pickShape. + * + * @param path the SceneGraphPath to this morph node + * @param pickShape the PickShape to be intersected + * @param dist the closest distance of the intersection + * + * @return true if the pick shape intersects this node; false + * otherwise. If true, dist contains the closest distance of + * intersection. + * + * @exception IllegalArgumentException if pickShape is a PickPoint. + * Java 3D doesn't have spatial information of the surface. + * Use PickBounds with BoundingSphere and a small radius, instead. + * + * @exception CapabilityNotSetException if the Geometry.ALLOW_INTERSECT + * capability bit is not set in all of the Geometry objects + * referred to by this morph node. + * + * @since Java 3D 1.3 + */ + public boolean intersect(SceneGraphPath path, + PickShape pickShape, + double[] dist) { + + if (isLiveOrCompiled()) { + checkForAllowIntersect(); + } + + if (pickShape instanceof PickPoint) { + throw new IllegalArgumentException(J3dI18N.getString("Morph10")); + } + + return ((MorphRetained)this.retained).intersect(path, pickShape, dist); + } + + + /** + * Sets this Morph node's morph weight vector. The Morph node "weights" + * the corresponding GeometryArray by the amount specified. + * The weights apply a morph weight vector component that creates + * the desired morphing effect. + * The length + * of the weights parameter must be equal to the length + * of the array with which this Morph node was created, otherwise + * an IllegalArgumentException is thown. + * @param weights the morph weight vector that the morph node will + * use in combining the node's geometryArrays. The morph node will "weight" + * the corresponding GeometryArray by the amount specified. + * N.B.: the sum of the weights should equal 1.0 + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if sum of all 'weights' is + * NOT 1.0 or number of weights is NOT exqual to number of GeometryArrays. + */ + public void setWeights(double weights[]) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_WEIGHTS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph8")); + + ((MorphRetained)this.retained).setWeights(weights); + } + + /** + * Retrieves the Morph node's morph weight vector. + * @return the morph weight vector component of this morph node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public double[] getWeights() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_WEIGHTS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph9")); + + return ((MorphRetained)this.retained).getWeights(); + } + + /** + * Sets a flag that indicates whether this node's appearance can + * be overridden. If the flag is true, this node's + * appearance may be overridden by an AlternateAppearance leaf + * node, regardless of the value of the ALLOW_APPEARANCE_WRITE + * capability bit. + * The default value is false. + * + * @param flag the apperance override enable flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see AlternateAppearance + * + * @since Java 3D 1.2 + */ + public void setAppearanceOverrideEnable(boolean flag) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_APPEARANCE_OVERRIDE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph11")); + + ((MorphRetained)this.retained).setAppearanceOverrideEnable(flag); + } + + /** + * Retrieves the appearanceOverrideEnable flag for this node. + * @return true if the appearance can be overridden; false + * otherwise. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public boolean getAppearanceOverrideEnable() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_APPEARANCE_OVERRIDE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Morph12")); + + return ((MorphRetained)this.retained).getAppearanceOverrideEnable(); + } + + /** + * Creates a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Morph m = new Morph(); + m.duplicateNode(this, forceDuplicate); + return m; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @exception ClassCastException if originalNode is not an instance of + * Morph + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + checkDuplicateNode(originalNode, forceDuplicate); + } + + /** + * Copies all Morph information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + MorphRetained attr = (MorphRetained) originalNode.retained; + MorphRetained rt = (MorphRetained) retained; + + Hashtable hashtable = originalNode.nodeHashtable; + + double weights[] = attr.getWeights(); + + rt.setCollisionBounds(attr.getCollisionBounds()); + rt.setAppearance((Appearance) getNodeComponent( + attr.getAppearance(), + forceDuplicate, + hashtable)); + + GeometryArray ga[] = new GeometryArray[weights.length]; + + for (int i=weights.length-1; i>=0; i--) { + ga[i] = (GeometryArray) getNodeComponent( + attr.getGeometryArray(i), + forceDuplicate, + hashtable); + } + rt.setGeometryArrays(ga); + rt.setWeights(weights); + } + + // Method to check whether all geometries have allow intersect + // capability bit set; it will throw an exception if any don't + // have the bit set. + private void checkForAllowIntersect() { + MorphRetained morphR = ((MorphRetained)this.retained); + int numGeometryArrays = morphR.getNumGeometryArrays(); + for (int i = 0; i < numGeometryArrays; i++) { + if (!morphR.geometryArrays[i].source. + getCapability(Geometry.ALLOW_INTERSECT)) { + + throw new CapabilityNotSetException(J3dI18N.getString("Morph6")); + } + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/MorphRetained.java b/j3d-core/src/classes/share/javax/media/j3d/MorphRetained.java new file mode 100644 index 0000000..cbcff38 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/MorphRetained.java @@ -0,0 +1,1959 @@ +/* + * $RCSfile: MorphRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; +import java.util.Vector; + +/** + * A morph leaf node consisting of geometery and appearance properties. + */ + +class MorphRetained extends LeafRetained implements GeometryUpdater { + + // These bits should match the Shape3D bits ...(Since the mirrors for + // both are Shape3DRetained + static final int GEOMETRY_CHANGED = 0x00001; + static final int APPEARANCE_CHANGED = 0x00002; + static final int COLLISION_CHANGED = 0x00004; + static final int BOUNDS_CHANGED = 0x00008; + static final int APPEARANCEOVERRIDE_CHANGED = 0x00010; + static final int UPDATE_MORPH = 0x00020; + + private static final double TOLERANCE = 1.0e-4; + + + /** + * The mirror Shape3DRetained nodes for this object. There is one + * mirror for each instance of this Shape3D node. If it is not in + * a SharedGroup, only index 0 is valid. + */ + ArrayList mirrorShape3D = new ArrayList(); + + + // Target threads to be notified when morph changes + final static int targetThreads = (J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_GEOMETRY); + + /** + * The appearance component of the morph node. + */ + AppearanceRetained appearance = null; + + /** + * The Geosets associated with the morph node. + */ + GeometryArrayRetained geometryArrays[]; + + private int numGeometryArrays = 0; + + /** + * The weight vector the morph node. + */ + double weights[]; + + /** + * Reference to the BranchGroup path of this mirror shape + * This is used for picking only. + */ + BranchGroupRetained branchGroupPath[]; + + + // cache value for picking in mirror shape. + // True if all the node of the path from this to root are all pickable + boolean isPickable = true; + + + // cache value for collidable in mirror shape. + // True if all the node of the path from this to root are all collidable + boolean isCollidable = true; + + + // closest switch parent + SwitchRetained closestSwitchParent = null; + + // the child index from the closest switch parent + int closestSwitchIndex = -1; + + // Is this Morph visible ? The default is true. + boolean visible = true; + + // geometry Bounds in local coordinate + Bounds bounds = null; + + // geometry Bounds in virtual world coordinate + BoundingBox vwcBounds = new BoundingBox(); + + // collision Bound in local coordinate + Bounds collisionBound = null; + + // collision Bounds in virtual world coordinate + Bounds collisionVwcBound = null; + + + GeometryArray morphedGeometryArray = null; + + // Morph data + float[] Mcoord = null; + float[] Mcolor = null; + float[] Mnormal = null; + // First dimension is the coordSet, second dimenension is the vertex index + // each vertex has 2 or 3floats + float[][]MtexCoord = null; + + // Whether the normal appearance is overrided by the alternate app + boolean appearanceOverrideEnable = false; + + int changedFrequent = 0; + + + MorphRetained() { + this.nodeType = NodeRetained.MORPH; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + /** + * Sets the collision bounds of a node. + * @param bounds the bounding object for the node + */ + void setCollisionBounds(Bounds bounds) { + if (bounds != null) { + collisionBound = (Bounds)bounds.clone(); + } else { + collisionBound = null; + } + if (source.isLive()) { + // Notify Geometry Structure to set mirror shape collision + // bound and check for collision + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.COLLISION_BOUND_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM; + message.universe = universe; + message.args[1] = collisionBound; + VirtualUniverse.mc.processMessage(message); + } + } + + /** + * Sets the geometric bounds of a node. + * @param bounds the bounding object for the node + */ + void setBounds(Bounds bounds) { + super.setBounds(bounds); + if (source.isLive() && !boundsAutoCompute) { + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.REGION_BOUND_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM | + targetThreads; + message.universe = universe; + message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D); + message.args[1] = localBounds; + VirtualUniverse.mc.processMessage(message); + } + } + + /** + * Gets the collision bounds of a node. + * @return the node's bounding object + */ + Bounds getCollisionBounds() { + return (collisionBound == null? null : (Bounds)collisionBound.clone()); + } + + /** + * Sets the geometryArrays component of the Morph node. + * @param geometryArrays the new vector of geometryArrays for the morph node + */ + void setGeometryArrays(GeometryArray geometryArrays[]) { + int i; + + if ((geometryArrays == null || geometryArrays.length == 0) && numGeometryArrays == 0) + return; + + GeometryArrayRetained geo, prevGeo; + + if (numGeometryArrays != 0 && (geometryArrays == null || numGeometryArrays != geometryArrays.length)) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained0")); + + + for (i=1;i < geometryArrays.length;i++) { + if (geometryArrays[i] == null || geometryArrays[i-1] == null) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + geo = (GeometryArrayRetained)geometryArrays[i].retained; + prevGeo = (GeometryArrayRetained)geometryArrays[i-1].retained; + if (prevGeo == null || geo == null) { + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + + } + doErrorCheck(prevGeo, geo); + } + + // Check the first one for vertex attributes + geo = (GeometryArrayRetained)geometryArrays[0].retained; + if ((geo.vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + throw new UnsupportedOperationException(J3dI18N.getString("MorphRetained9")); + } + + // Check if the first one is in Immediate context + if (geometryArrays[0] != null) { + geo = (GeometryArrayRetained)geometryArrays[0].retained; + } + + if (numGeometryArrays == 0) { + this.geometryArrays = new GeometryArrayRetained[geometryArrays.length]; + numGeometryArrays = geometryArrays.length; + } + + for (i=0;i < numGeometryArrays;i++) { + geo = (GeometryArrayRetained)geometryArrays[i].retained; + if (((Morph)this.source).isLive()) { + if (this.geometryArrays[i] != null) { + this.geometryArrays[i].clearLive(refCount); + this.geometryArrays[i].removeMorphUser(this); + } + if (geo != null) { + geo.setLive(inBackgroundGroup, refCount); + geo.addMorphUser(this); + } + } + + this.geometryArrays[i] = geo; + } + if (this.geometryArrays[0] == null) + return; + + + if (weights == null) { + weights = new double[numGeometryArrays]; + weights[0] = 1.0; + int vFormat = this.geometryArrays[0].vertexFormat; + // default is zero when new array + //for (i=1; i < numGeometryArrays;i++) weights[i] = 0.0; + + int texCoordSetCount = this.geometryArrays[0].getTexCoordSetCount(); + if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained) { + Mcoord = new float[this.geometryArrays[0].getNumCoordCount()* 3]; + + if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) + Mcolor = new float[this.geometryArrays[0].getNumColorCount()* 3]; + else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) + Mcolor = new float[this.geometryArrays[0].getNumColorCount()* 4]; + + MtexCoord = new float[texCoordSetCount][]; + if ((vFormat & GeometryArray.NORMALS) != 0) + Mnormal = new float[this.geometryArrays[0].getNumNormalCount() *3]; + for (int k = 0; k < texCoordSetCount; k++) { + if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) + MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 2]; + else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0)) + MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 3]; + else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)) + MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 4]; + } + } + else { + Mcoord = new float[this.geometryArrays[0].validVertexCount* 3]; + + if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) { + Mcolor = new float[this.geometryArrays[0].validVertexCount* 3]; + } else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + Mcolor = new float[this.geometryArrays[0].validVertexCount* 4]; + } + MtexCoord = new float[texCoordSetCount][]; + if ((vFormat & GeometryArray.NORMALS) != 0) { + Mnormal = new float[this.geometryArrays[0].validVertexCount *3]; + } + for (int k = 0; k < texCoordSetCount; k++) { + if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) + MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 2]; + else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0)) + MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 3]; + else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)) + MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 4]; + } + } + } + + // create a new morphedGeometryArray + initMorphedGeometry(); + + if (source.isLive()) { + + Shape3DRetained shape = (Shape3DRetained)mirrorShape3D.get(0); + + shape.setMorphGeometry(morphedGeometryArray, mirrorShape3D); + + J3dMessage mChangeMessage = null; + mChangeMessage = new J3dMessage(); + mChangeMessage.type = J3dMessage.MORPH_CHANGED; + mChangeMessage.threads = (J3dThread.UPDATE_GEOMETRY | + J3dThread.UPDATE_TRANSFORM); + // If its a indexed geometry array, unindexify in renderBin + if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained) + mChangeMessage.threads |= J3dThread.UPDATE_RENDERING_ATTRIBUTES; + mChangeMessage.args[0] = this; + mChangeMessage.args[1]= new Integer(GEOMETRY_CHANGED); + // a shadow copy of this ArrayList instance. (The elements themselves are not copied.) + mChangeMessage.args[3] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D); + mChangeMessage.universe = universe; + VirtualUniverse.mc.processMessage(mChangeMessage); + + if (boundsAutoCompute) { + GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained; + // Compute the bounds once + mga.incrComputeGeoBounds();// This compute the bbox if dirty + mga.decrComputeGeoBounds(); + } + } + + + + } + + /** + * Retrieves the geometryArrays component of this Morph node. + * @param index the index of GeometryArray to be returned + * @return the geometryArray component of this morph node + */ + GeometryArray getGeometryArray(int index) { + return (GeometryArray)this.geometryArrays[index].source; + } + + /** + * Sets the appearance component of this Morph node. + * @param appearance the new apearance component for this morph node + */ + void setAppearance(Appearance newAppearance) { + boolean visibleIsDirty = false; + + if (((Morph)this.source).isLive()) { + + if (appearance != null) { + this.appearance.clearLive(refCount); + for (int i=mirrorShape3D.size()-1; i>=0; i--) { + this.appearance.removeAMirrorUser( + (Shape3DRetained)mirrorShape3D.get(i)); + } + } + + if (newAppearance != null) { + ((AppearanceRetained)newAppearance.retained).setLive(inBackgroundGroup, refCount); + appearance = ((AppearanceRetained)newAppearance.retained); + int size= mirrorShape3D.size(); + for (int i=0; i=0; i--) { + sum += weights[i]; + } + + if (Math.abs(sum - 1.0) > TOLERANCE) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained8")); + + // Weights array is ALWAYS malloced in setGeometryArrays method + for (i=numGeometryArrays-1; i>=0; i--) + this.weights[i] = weights[i]; + + + if (source.isLive()) { + ((GeometryArrayRetained)morphedGeometryArray.retained).updateData(this); + J3dMessage mChangeMessage = null; + mChangeMessage = new J3dMessage(); + mChangeMessage.type = J3dMessage.MORPH_CHANGED; + mChangeMessage.threads = (J3dThread.UPDATE_GEOMETRY | + J3dThread.UPDATE_TRANSFORM); + // If its a indexed geometry array, unindexify in renderBin + if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained) + mChangeMessage.threads |= J3dThread.UPDATE_RENDERING_ATTRIBUTES; + mChangeMessage.args[0] = this; + mChangeMessage.args[1]= new Integer(GEOMETRY_CHANGED); + mChangeMessage.args[3] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D); + mChangeMessage.universe = universe; + VirtualUniverse.mc.processMessage(mChangeMessage); + } + + } + + /** + * Retrieves the Morph node's weight vector + * @return the morph node's weight vector. + */ + double[] getWeights() { + return (double[]) weights.clone(); + } + + /** + * Gets the bounding object of a node. + * @return the node's bounding object + */ + Bounds getBounds() { + if(boundsAutoCompute) { + GeometryArrayRetained mga = + (GeometryArrayRetained)morphedGeometryArray.retained; + if (mga != null) { + synchronized(mga.geoBounds) { + return (Bounds) mga.geoBounds.clone(); + } + } else { + return null; + } + } else { + return super.getBounds(); + } + } + + Bounds getEffectiveBounds() { + if(boundsAutoCompute) { + return getBounds(); + } + else { + return super.getEffectiveBounds(); + } + } + + /** + * ONLY needed for SHAPE, MORPH, and LINK node type. + * Compute the combine bounds of bounds and its localBounds. + */ + void computeCombineBounds(Bounds bounds) { + + if(boundsAutoCompute) { + GeometryArrayRetained mga = + (GeometryArrayRetained)morphedGeometryArray.retained; + if (mga != null) { + synchronized(mga.geoBounds) { + bounds.combine((Bounds) mga.geoBounds); + } + } + } else { + // Should this be lock too ? ( MT safe ? ) + synchronized(localBounds) { + bounds.combine((Bounds) localBounds); + } + } + } + + // Return the number of geometry arrays in this MorphRetained object. + int getNumGeometryArrays() { + return numGeometryArrays; + } + + // If the geometry of a morph changes, make sure that the + // validVertexCount has not changed + void updateMorphedGeometryArray(GeometryArrayRetained geo, boolean coordinatesChanged) { + if (numGeometryArrays > 0) { + // check if not the first geo, then compare with the first geometry + if (geometryArrays[0] != geo) { + doErrorCheck(geo, geometryArrays[0]); + } + else { + // if first geo, compare with the second geo + if (numGeometryArrays > 1) { + doErrorCheck(geo, geometryArrays[1]); + } + + } + } + + + ((GeometryArrayRetained)morphedGeometryArray.retained).updateData(this); + // Compute the bounds once + if (boundsAutoCompute && coordinatesChanged) { + GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained; + mga.incrComputeGeoBounds(); // This compute the bbox if dirty + mga.decrComputeGeoBounds(); + } + } + + /** + * Update GeometryArray computed by morphing input GeometryArrays + * with weights + */ + public void updateData(Geometry mga) { + + int i,j,k, vFormat, geoType, stripVCount[]; + int iCount = 0; + int numStrips = 0; + int texCoordSetCount = 0; + float coord[] = new float[3], color[] = new float[4], + normal[] = new float[3], texCoord[] = new float[3]; + + vFormat = geometryArrays[0].vertexFormat; + geoType = ((GeometryArrayRetained)geometryArrays[0]).geoType; + texCoordSetCount = geometryArrays[0].getTexCoordSetCount(); + + + + int vc = 0, nc = 0, cc = 0, n = 0; + int count = 0; + if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){ + count = geometryArrays[0].getNumCoordCount(); + } else { + count = geometryArrays[0].validVertexCount; + } + + for (i=0; i < count; i++) { + Mcoord[vc++] = Mcoord[vc++] = Mcoord[vc++] = 0.0f; + } + + + if ((vFormat & GeometryArray.COLOR) != 0) { + if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){ + count = geometryArrays[0].getNumColorCount(); + } else { + count = geometryArrays[0].validVertexCount; + } + for (i=0; i < count; i++) { + if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) + Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = 0.0f; + + else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) + Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = 0.0f; + } + } + + + if ((vFormat & GeometryArray.NORMALS) != 0) { + if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){ + count = geometryArrays[0].getNumNormalCount(); + } else { + count = geometryArrays[0].validVertexCount; + } + for (i=0; i < count; i++) { + Mnormal[nc++] = Mnormal[nc++] = Mnormal[nc++] = 0.0f; + } + } + + if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (k = 0; k < texCoordSetCount; k++) { + if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){ + count = geometryArrays[0].getNumTexCoordCount(k); + } else { + count = geometryArrays[0].validVertexCount; + } + int tcount = 0; + for (i=0; i < count; i++) { + MtexCoord[k][tcount++] = MtexCoord[k][tcount++] = 0.0f; + if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + MtexCoord[k][tcount++] = 0.0f; + } else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + MtexCoord[k][tcount++] = 0.0f; + MtexCoord[k][tcount++] = 0.0f; + } + } + } + } + // If by copy, then ... + if ((vFormat & GeometryArray.BY_REFERENCE) == 0) { + count = 0; + for (j=0;j < numGeometryArrays;j++) { + double w = weights[j]; + if (w != 0) { + vc = 0; nc = 0; cc = 0; + int initialVertex = 0; + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + initialVertex = 0; + count = geometryArrays[j].getNumCoordCount(); + } + else { + initialVertex = geometryArrays[j].getInitialVertexIndex(); + count = geometryArrays[j].validVertexCount; + } + int endVertex = initialVertex + count; + for (i=initialVertex; i< endVertex; i++) { + geometryArrays[j].getCoordinate(i, coord); + Mcoord[vc++] += coord[0]*w; + Mcoord[vc++] += coord[1]*w; + Mcoord[vc++] += coord[2]*w; + } + + if ((vFormat & GeometryArray.COLOR) != 0) { + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + count = geometryArrays[j].getNumColorCount(); + } + endVertex = initialVertex + count; + for (i=initialVertex; i< endVertex; i++) { + geometryArrays[j].getColor(i, color); + Mcolor[cc++] += color[0]*w; + Mcolor[cc++] += color[1]*w; + Mcolor[cc++] += color[2]*w; + if ((vFormat & GeometryArray.WITH_ALPHA) != 0) + Mcolor[cc++] += color[3]*w; + } + } + if ((vFormat & GeometryArray.NORMALS) != 0) { + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + count = geometryArrays[j].getNumNormalCount(); + } + endVertex = initialVertex + count; + for (i=initialVertex; i< endVertex; i++) { + geometryArrays[j].getNormal(i, normal); + Mnormal[nc++] += normal[0]*w; + Mnormal[nc++] += normal[1]*w; + Mnormal[nc++] += normal[2]*w; + } + } + + if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (k = 0; k < texCoordSetCount; k++) { + int tcount = 0; + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + count = geometryArrays[j].getNumTexCoordCount(i); + } + endVertex = initialVertex + count; + for (i=initialVertex; i< endVertex; i++) { + geometryArrays[j].getTextureCoordinate(k, i, texCoord); + MtexCoord[k][tcount++] += texCoord[0]*w; + MtexCoord[k][tcount++] += texCoord[1]*w; + if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + MtexCoord[k][tcount++] += texCoord[2]*w; + } else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + MtexCoord[k][tcount++] += texCoord[2]*w; + MtexCoord[k][tcount++] += texCoord[3]*w; + } + } + } + } + } + } + } + else { + int vIndex, tIndex, cIndex, nIndex, tstride = 0, cstride = 0; + if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + tstride = 2; + } else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + tstride = 3; + } else { + tstride = 4; + } + } + + if ((vFormat & GeometryArray.COLOR) != 0) { + cstride = 3; + if ((vFormat & GeometryArray.WITH_ALPHA) != 0) + cstride = 4; + } + + if ((vFormat & GeometryArray.INTERLEAVED) != 0) { + float[] vdata; + int stride; + + stride = geometryArrays[0].stride(); + int coffset = geometryArrays[0].colorOffset(); + int noffset = geometryArrays[0].normalOffset(); + int voffset = geometryArrays[0].coordinateOffset(); + int offset = 0; + + int initialVertex = 0; + for (j=0;j < numGeometryArrays;j++) { + double w = weights[j]; + if (w != 0) { + vc = 0; nc = 0; cc = 0; n = 0; + vdata = geometryArrays[j].getInterleavedVertices(); + if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (k = 0; k < texCoordSetCount; k++) { + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + tIndex = 0; + count = geometryArrays[j].getNumCoordCount(); + } + else { + tIndex = geometryArrays[j].getInitialVertexIndex(); + count = geometryArrays[j].validVertexCount; + } + offset = (tIndex * stride)+k*tstride; + int tcount = 0; + for (i = 0; i < count; i++, offset += stride) { + MtexCoord[k][tcount++] += vdata[offset] * w; + MtexCoord[k][tcount++] += vdata[offset+1] * w; + if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + MtexCoord[k][tcount++] += vdata[offset+2]*w; + } else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + MtexCoord[k][tcount++] += vdata[offset+2]*w; + MtexCoord[k][tcount++] += vdata[offset+3]*w; + } + } + } + + } + if ((vFormat & GeometryArray.COLOR) != 0) { + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + cIndex = 0; + count = geometryArrays[j].getNumCoordCount(); + } + else { + cIndex = geometryArrays[j].getInitialVertexIndex(); + count = geometryArrays[j].validVertexCount; + } + offset = (cIndex * stride)+coffset; + for (i = 0; i < count; i++, offset += stride) { + Mcolor[cc++] += vdata[offset]*w; + Mcolor[cc++] += vdata[offset+1]*w; + Mcolor[cc++] += vdata[offset+2]*w; + if ((vFormat & GeometryArray.WITH_ALPHA)!= 0) + Mcolor[cc++] += vdata[offset+3]*w; + + } + } + + if ((vFormat & GeometryArray.NORMALS) != 0) { + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + nIndex = 0; + count = geometryArrays[j].getNumCoordCount(); + } + else { + nIndex = geometryArrays[j].getInitialVertexIndex(); + count = geometryArrays[j].validVertexCount; + } + offset = (nIndex * stride)+noffset; + for (i = 0; i < count; i++, offset += stride) { + Mnormal[nc++] += vdata[offset]*w; + Mnormal[nc++] += vdata[offset+1]*w; + Mnormal[nc++] += vdata[offset+2]*w; + } + } + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + vIndex = 0; + count = geometryArrays[j].getNumCoordCount(); + } + else { + vIndex = geometryArrays[j].getInitialVertexIndex(); + count = geometryArrays[j].validVertexCount; + } + offset = (vIndex * stride)+voffset; + for (i = 0; i < count; i++, offset += stride) { + Mcoord[vc++] += vdata[offset]*w; + Mcoord[vc++] += vdata[offset+1]*w; + Mcoord[vc++] += vdata[offset+2]*w; + + } + } + } + } + else { + float byteToFloatScale = 1.0f/255.0f; + for (j=0;j < numGeometryArrays;j++) { + double w = weights[j]; + if (w != 0) { + if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + switch ((geometryArrays[j].vertexType & GeometryArrayRetained.TEXCOORD_DEFINED)) { + case GeometryArrayRetained.TF: + for (k = 0; k < texCoordSetCount; k++) { + float[] tf = geometryArrays[j].getTexCoordRefFloat(k); + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + tIndex = 0; + count = geometryArrays[j].getNumTexCoordCount(k); + } + else { + tIndex = geometryArrays[j].getInitialTexCoordIndex(k); + count = geometryArrays[j].validVertexCount; + } + tIndex *= tstride; + int tcount = 0; + for (i=0; i< count; i++) { + MtexCoord[k][tcount++] += tf[tIndex++]*w; + MtexCoord[k][tcount++] += tf[tIndex++]*w; + if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) + MtexCoord[k][tcount++] += tf[tIndex++]*w; + } + } + break; + case GeometryArrayRetained.T2F: + for (k = 0; k < texCoordSetCount; k++) { + int tcount = 0; + float[] tf = geometryArrays[j].getTexCoordRefFloat(k); + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + tIndex = 0; + count = geometryArrays[j].getNumTexCoordCount(k); + } + else { + tIndex = geometryArrays[j].getInitialTexCoordIndex(k); + count = geometryArrays[j].validVertexCount; + } + TexCoord2f[] t2f = geometryArrays[j].getTexCoordRef2f(k); + for (i=0; i< count; i++, tIndex++) { + MtexCoord[k][tcount++] += t2f[tIndex].x*w; + MtexCoord[k][tcount++] += t2f[tIndex].y*w; + } + } + break; + case GeometryArrayRetained.T3F: + for (k = 0; k < texCoordSetCount; k++) { + int tcount = 0; + TexCoord3f[] t3f = geometryArrays[j].getTexCoordRef3f(k); + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + tIndex = 0; + count = geometryArrays[j].getNumTexCoordCount(k); + } + else { + tIndex = geometryArrays[j].getInitialTexCoordIndex(k); + count = geometryArrays[j].validVertexCount; + } + for (i=0; i< count; i++, tIndex++) { + MtexCoord[k][tcount++] += t3f[tIndex].x*w; + MtexCoord[k][tcount++] += t3f[tIndex].y*w; + MtexCoord[k][tcount++] += t3f[tIndex].z*w; + } + } + break; + + } + } + if ((vFormat & GeometryArray.COLOR) != 0) { + double val = byteToFloatScale * w; + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + cIndex = 0; + count = geometryArrays[j].getNumColorCount(); + } + else { + cIndex = geometryArrays[j].getInitialColorIndex(); + count = geometryArrays[j].validVertexCount; + } + + switch ((geometryArrays[j].vertexType & GeometryArrayRetained.COLOR_DEFINED)) { + case GeometryArrayRetained.CF: + float[] cf = geometryArrays[j].getColorRefFloat(); + cc = 0; + cIndex *= cstride; + for (i=0; i< count; i++) { + Mcolor[cc++] += cf[cIndex++]*w; + Mcolor[cc++] += cf[cIndex++]*w; + Mcolor[cc++] += cf[cIndex++]*w; + if ((vFormat & GeometryArray.WITH_ALPHA)!= 0) + Mcolor[cc++] += cf[cIndex++]*w; + } + break; + case GeometryArrayRetained.CUB: + byte[] cub = geometryArrays[j].getColorRefByte(); + cc = 0; + cIndex *= cstride; + for (i=0; i< count; i++) { + Mcolor[cc++] += (cub[cIndex++] & 0xff) * val; + Mcolor[cc++] += (cub[cIndex++] & 0xff) *val; + Mcolor[cc++] += (cub[cIndex++] & 0xff) *val; + if ((vFormat & GeometryArray.WITH_ALPHA)!= 0) + Mcolor[cc++] += (cub[cIndex++] & 0xff) *val; + } + + break; + case GeometryArrayRetained.C3F: + Color3f[] c3f = geometryArrays[j].getColorRef3f(); + cc = 0; + for (i=0; i< count; i++, cIndex++) { + Mcolor[cc++] += c3f[cIndex].x * w; + Mcolor[cc++] += c3f[cIndex].y * w; + Mcolor[cc++] += c3f[cIndex].z * w; + } + break; + case GeometryArrayRetained.C4F: + Color4f[] c4f = geometryArrays[j].getColorRef4f(); + cc = 0; + for (i=0; i< count; i++, cIndex++) { + Mcolor[cc++] += c4f[cIndex].x * w; + Mcolor[cc++] += c4f[cIndex].y * w; + Mcolor[cc++] += c4f[cIndex].z * w; + Mcolor[cc++] += c4f[cIndex].w * w; + } + break; + case GeometryArrayRetained.C3UB: + Color3b[] c3b = geometryArrays[j].getColorRef3b(); + cc = 0; + for (i=0; i< count; i++, cIndex++) { + Mcolor[cc++] += (c3b[cIndex].x & 0xff)* val; + Mcolor[cc++] += (c3b[cIndex].y & 0xff) * val; + Mcolor[cc++] += (c3b[cIndex].z & 0xff) * val; + } + break; + case GeometryArrayRetained.C4UB: + Color4b[] c4b = geometryArrays[j].getColorRef4b(); + cc = 0; + for (i=0; i< count; i++, cIndex++) { + Mcolor[cc++] += (c4b[cIndex].x & 0xff)* val; + Mcolor[cc++] += (c4b[cIndex].y & 0xff) * val; + Mcolor[cc++] += (c4b[cIndex].z & 0xff) * val; + Mcolor[cc++] += (c4b[cIndex].w & 0xff) * val; + } + break; + + } + } + if ((vFormat & GeometryArray.NORMALS) != 0) { + nc = 0; + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + nIndex = 0; + count = geometryArrays[j].getNumNormalCount(); + } + else { + nIndex = geometryArrays[j].getInitialNormalIndex(); + count = geometryArrays[j].validVertexCount; + } + switch ((geometryArrays[j].vertexType & GeometryArrayRetained.NORMAL_DEFINED)) { + case GeometryArrayRetained.NF: + float[] nf = geometryArrays[j].getNormalRefFloat(); + nIndex *= 3; + for (i=0; i< count; i++) { + Mnormal[nc++] += nf[nIndex++]*w; + Mnormal[nc++] += nf[nIndex++]*w; + Mnormal[nc++] += nf[nIndex++]*w; + } + break; + case GeometryArrayRetained.N3F: + Vector3f[] n3f = geometryArrays[j].getNormalRef3f(); + for (i=0; i< count; i++, nIndex++) { + Mnormal[nc++] += n3f[nIndex].x*w; + Mnormal[nc++] += n3f[nIndex].y*w; + Mnormal[nc++] += n3f[nIndex].z*w; + } + break; + } + } + // Handle vertices .. + vc = 0; + if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) { + vIndex = 0; + count = geometryArrays[j].getNumCoordCount(); + } + else { + vIndex = geometryArrays[j].getInitialCoordIndex(); + count = geometryArrays[j].validVertexCount; + } + switch ((geometryArrays[j].vertexType & GeometryArrayRetained.VERTEX_DEFINED)) { + case GeometryArrayRetained.PF: + float[] pf = geometryArrays[j].getCoordRefFloat(); + vIndex *= 3; + for (i=0; i< count; i++) { + Mcoord[vc++] += pf[vIndex++]*w; + Mcoord[vc++] += pf[vIndex++]*w; + Mcoord[vc++] += pf[vIndex++]*w; + } + break; + case GeometryArrayRetained.PD: + double[] pd = geometryArrays[j].getCoordRefDouble(); + vIndex *= 3; + for (i=0; i< count; i++) { + Mcoord[vc++] += (float)pd[vIndex++]*w; + Mcoord[vc++] += (float)pd[vIndex++]*w; + Mcoord[vc++] += (float)pd[vIndex++]*w; + } + break; + case GeometryArrayRetained.P3F: + Point3f[] p3f = geometryArrays[j].getCoordRef3f(); + for (i=0; i< count; i++, vIndex++) { + Mcoord[vc++] += p3f[vIndex].x*w; + Mcoord[vc++] += p3f[vIndex].y*w; + Mcoord[vc++] += p3f[vIndex].z*w; + } + break; + case GeometryArrayRetained.P3D: + Point3d[] p3d = geometryArrays[j].getCoordRef3d(); + for (i=0; i< count; i++, vIndex++) { + Mcoord[vc++] += (float)p3d[vIndex].x*w; + Mcoord[vc++] += (float)p3d[vIndex].y*w; + Mcoord[vc++] += (float)p3d[vIndex].z*w; + } + break; + + } + + } + } + } + } + + GeometryArrayRetained mgaR = + (GeometryArrayRetained)mga.retained; + + mgaR.setCoordRefFloat(Mcoord); + + if ((vFormat & GeometryArray.COLOR) != 0) + mgaR.setColorRefFloat(Mcolor); + + // *******Need to normalize normals + if ((vFormat & GeometryArray.NORMALS) != 0) + mgaR.setNormalRefFloat(Mnormal); + + if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (k = 0; k < texCoordSetCount; k++) { + mgaR.setTexCoordRefFloat(k, MtexCoord[k]); + } + } + } + + void updateImmediateMirrorObject(Object[] objs) { + int i; + + int component = ((Integer)objs[1]).intValue(); + Shape3DRetained[] msArr = (Shape3DRetained[]) objs[2]; + if ((component & APPEARANCE_CHANGED) != 0) { + Object[] arg = (Object[])objs[3]; + int val = ((Integer)arg[1]).intValue(); + for ( i = msArr.length-1; i >=0; i--) { + msArr[i].appearance = (AppearanceRetained)arg[0]; + msArr[i].changedFrequent = val; + } + } + if ((component & APPEARANCEOVERRIDE_CHANGED) != 0) { + Object[] arg = (Object[])objs[3]; + int val = ((Integer)arg[1]).intValue(); + System.err.println("ChangedFrequent = "+changedFrequent); + for ( i = msArr.length-1; i >=0; i--) { + msArr[i].appearanceOverrideEnable = ((Boolean)arg[0]).booleanValue(); + msArr[i].changedFrequent = val; + } + } + } + + /** + * assign a name to this node when it is made live. + */ + void setLive(SetLiveState s) { + int i, j; + Shape3DRetained shape; + ArrayList msList = new ArrayList(); + GeometryAtom ga; + int oldrefCount = refCount; + + super.doSetLive(s); + nodeId = universe.getNodeId(); + + + for (i = 0; i < numGeometryArrays; i++) { + synchronized(geometryArrays[i].liveStateLock) { + geometryArrays[i].setLive(inBackgroundGroup, s.refCount); + // Add this morph object as user the first time + if (oldrefCount <= 0) { + geometryArrays[i].addMorphUser(this); + } + } + } + + if (this.morphedGeometryArray == null){ + initMorphedGeometry(); + + } + ((GeometryArrayRetained)(morphedGeometryArray.retained)).setLive(inBackgroundGroup, s.refCount); + + if (boundsAutoCompute) { + GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained; + // Compute the bounds once + mga.incrComputeGeoBounds(); // This compute the bbox if dirty + mga.decrComputeGeoBounds(); + localBounds.setWithLock(mga.geoBounds); + } + + + if (inSharedGroup) { + for (i=0; i=0) { + return (Shape3DRetained) mirrorShape3D.get(i); + } + + // Not possible + throw new RuntimeException("Shape3DRetained: MirrorShape Not found!"); + } + + void getMirrorObjects(ArrayList leafList, HashKey key) { + Shape3DRetained ms; + if (inSharedGroup) { + ms = getMirrorShape(key); + } + else { + ms = (Shape3DRetained)mirrorShape3D.get(0); + } + GeometryAtom ga = Shape3DRetained.getGeomAtom(ms); + leafList.add(ga); + + } + + void setBoundsAutoCompute(boolean autoCompute) { + if (autoCompute != boundsAutoCompute) { + if (autoCompute) { + // localBounds may not have been set to bbox + localBounds = new BoundingBox(); + if (source.isLive() && morphedGeometryArray != null) { + GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained; + mga.incrComputeGeoBounds(); // This compute the bbox if dirty + mga.decrComputeGeoBounds(); + } + } + + + localBounds = getBounds(); + super.setBoundsAutoCompute(autoCompute); + if (source.isLive()) { + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM | + J3dThread.UPDATE_GEOMETRY | + J3dThread.UPDATE_RENDER; + message.universe = universe; + message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D); + message.args[1] = localBounds; + VirtualUniverse.mc.processMessage(message); + } + } + } + + void updateBounds() { + localBounds = getEffectiveBounds(); + if (source.isLive()) { + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM | + J3dThread.UPDATE_GEOMETRY | + J3dThread.UPDATE_RENDER; + message.universe = universe; + message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D); + message.args[1] = localBounds; + VirtualUniverse.mc.processMessage(message); + } + } + + /** + * Initialization of morphed geometry + */ + void initMorphedGeometry() { + int vFormat, geoType, stripVCount[]; + int iCount = 0; + int numStrips = 0; + int texCoordSetCount = 0; + int texCoordSetMapLen = 0; + int [] texCoordSetMap = null; + int k; + GeometryArrayRetained geo = geometryArrays[0]; + vFormat = ((geo.getVertexFormat() | (GeometryArray.BY_REFERENCE)) & ~(GeometryArray.INTERLEAVED)) ; + texCoordSetCount = geo.getTexCoordSetCount(); + texCoordSetMapLen = geo.getTexCoordSetMapLength(); + if (texCoordSetMapLen > 0) { + texCoordSetMap = new int[texCoordSetMapLen]; + geo.getTexCoordSetMap(texCoordSetMap); + } + geoType = geo.geoType; + + switch (geoType){ + case GeometryRetained.GEO_TYPE_QUAD_SET: + this.morphedGeometryArray = + new QuadArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount, + texCoordSetMap); + break; + case GeometryRetained.GEO_TYPE_TRI_SET: + this.morphedGeometryArray = + new TriangleArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount, + texCoordSetMap); + break; + case GeometryRetained.GEO_TYPE_POINT_SET: + this.morphedGeometryArray = + new PointArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount, + texCoordSetMap); + break; + case GeometryRetained.GEO_TYPE_LINE_SET: + this.morphedGeometryArray = + new LineArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount, + texCoordSetMap); + break; + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET: + numStrips = ((TriangleStripArrayRetained)geo).getNumStrips(); + stripVCount = new int[numStrips]; + ((TriangleStripArrayRetained)geo).getStripVertexCounts(stripVCount); + this.morphedGeometryArray = + new TriangleStripArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount, + texCoordSetMap, stripVCount); + break; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET: + numStrips = ((TriangleFanArrayRetained)geo).getNumStrips(); + stripVCount = new int[numStrips]; + ((TriangleFanArrayRetained)geo).getStripVertexCounts(stripVCount); + this.morphedGeometryArray = + new TriangleFanArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount, + texCoordSetMap, stripVCount); + break; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: + numStrips = ((LineStripArrayRetained)geo).getNumStrips(); + stripVCount = new int[numStrips]; + ((LineStripArrayRetained)geo).getStripVertexCounts(stripVCount); + this.morphedGeometryArray = + new LineStripArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount, + texCoordSetMap, stripVCount); + break; + + case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET: + iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount(); + this.morphedGeometryArray = + new IndexedQuadArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount, + texCoordSetMap, iCount); + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET: + iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount(); + this.morphedGeometryArray = + new IndexedTriangleArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount, + texCoordSetMap, iCount); + break; + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: + iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount(); + this.morphedGeometryArray = + new IndexedPointArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount, + texCoordSetMap, iCount); + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET: + iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount(); + this.morphedGeometryArray = + new IndexedLineArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount, + texCoordSetMap, iCount); + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET: + iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount(); + numStrips = ((IndexedTriangleStripArrayRetained)geo).getNumStrips(); + stripVCount = new int[numStrips]; + ((IndexedTriangleStripArrayRetained)geo).getStripIndexCounts(stripVCount); + this.morphedGeometryArray = + new IndexedTriangleStripArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount, + texCoordSetMap, iCount, stripVCount);break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET: + iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount(); + numStrips = ((IndexedTriangleFanArrayRetained)geo).getNumStrips(); + stripVCount = new int[numStrips]; + ((IndexedTriangleFanArrayRetained)geo).getStripIndexCounts(stripVCount); + this.morphedGeometryArray = + new IndexedTriangleFanArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount, + texCoordSetMap, iCount, stripVCount);break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount(); + numStrips = ((IndexedLineStripArrayRetained)geo).getNumStrips(); + stripVCount = new int[numStrips]; + ((IndexedLineStripArrayRetained)geo).getStripIndexCounts(stripVCount); + this.morphedGeometryArray = + new IndexedLineStripArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount, + texCoordSetMap, iCount, stripVCount);break; + } + if (geometryArrays[0] instanceof IndexedGeometryArrayRetained) { + IndexedGeometryArrayRetained igeo = (IndexedGeometryArrayRetained) + geometryArrays[0]; + IndexedGeometryArray morphedGeo = (IndexedGeometryArray) + morphedGeometryArray; + if ((vFormat & GeometryArray.COORDINATES) != 0) { + morphedGeo.setCoordinateIndices(0, igeo.indexCoord); + } + if ((vFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) { + if ((vFormat & GeometryArray.NORMALS) != 0) { + morphedGeo.setNormalIndices(0, igeo.indexNormal); + } + if ((vFormat & GeometryArray.COLOR) != 0) { + morphedGeo.setColorIndices(0, igeo.indexColor); + } + if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) { + for (k = 0; k < texCoordSetCount; k++) { + morphedGeo.setTextureCoordinateIndices(k, 0, + igeo.indexTexCoord[k]); + } + } + } + } + this.morphedGeometryArray.setCapability(GeometryArray.ALLOW_REF_DATA_WRITE); + + GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained; + mga.updateData(this); + + + } + + void getMirrorShape3D(ArrayList list, HashKey k) { + Shape3DRetained ms; + if (inSharedGroup) { + ms = getMirrorShape(k); + } + else { + ms = (Shape3DRetained)mirrorShape3D.get(0); + } + list.add(ms); + + } + + void compile(CompileState compState) { + + super.compile(compState); + + // XXXX: for now keep the static transform in the parent tg + compState.keepTG = true; + + if (J3dDebug.devPhase && J3dDebug.debug) { + compState.numMorphs++; + } + } + + void doErrorCheck(GeometryArrayRetained prevGeo, GeometryArrayRetained geo) { + + // If indexed Geometry array check the entire list instead of just the vcount + if ((prevGeo.vertexFormat != geo.vertexFormat) || + (prevGeo.validVertexCount != geo.validVertexCount) || + (prevGeo.geoType != geo.geoType) || + (prevGeo.texCoordSetCount != geo.texCoordSetCount)) { + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + } + if (geo.getTexCoordSetMapLength() != prevGeo.getTexCoordSetMapLength()){ + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + } + int texCoordSetMapLen = geo.getTexCoordSetMapLength(); + int[] prevSvc= prevGeo.texCoordSetMap; + int[] svc= geo.texCoordSetMap; + for (int k = 0; k < texCoordSetMapLen; k++) { + if (prevSvc[k] != svc[k]) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + } + + if (geo instanceof GeometryStripArrayRetained) { + prevSvc= ((GeometryStripArrayRetained)prevGeo).stripVertexCounts; + svc= ((GeometryStripArrayRetained)geo).stripVertexCounts; + if (prevSvc.length != svc.length) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + for (int k = 0; k < prevSvc.length; k++) { + if (prevSvc[k] != svc[k]) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + } + } else if (geo instanceof IndexedGeometryArrayRetained) { + if (((IndexedGeometryArrayRetained)prevGeo).validIndexCount != ((IndexedGeometryArrayRetained)geo).validIndexCount) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + + // If by reference, then all array lengths should be same + if (geo.getNumCoordCount() != prevGeo.getNumCoordCount() || + geo.getNumColorCount() != prevGeo.getNumColorCount() || + geo.getNumNormalCount() != prevGeo.getNumNormalCount()) { + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + } + int texCoordSetCount = geo.getTexCoordSetCount(); + for (int k = 0; k < texCoordSetCount; k++) { + if (geo.getNumTexCoordCount(k) != prevGeo.getNumTexCoordCount(k)) { + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + } + } + + if (geo instanceof IndexedGeometryStripArrayRetained) { + prevSvc= ((IndexedGeometryStripArrayRetained)prevGeo).stripIndexCounts; + svc= ((IndexedGeometryStripArrayRetained)geo).stripIndexCounts; + if (prevSvc.length != svc.length) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + for (int k = 0; k < prevSvc.length; k++) { + if (prevSvc[k] != svc[k]) + throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1")); + } + } + } + } + + void handleFrequencyChange(int bit) { + int mask = 0; + if (bit == Morph.ALLOW_GEOMETRY_ARRAY_WRITE) { + mask = GEOMETRY_CHANGED; + } + else if (bit == Morph.ALLOW_APPEARANCE_WRITE) { + mask = APPEARANCE_CHANGED; + } + else if (bit == Morph.ALLOW_APPEARANCE_OVERRIDE_WRITE) { + mask = APPEARANCEOVERRIDE_CHANGED; + } + if (mask != 0) { + if (source.getCapabilityIsFrequent(bit)) + changedFrequent |= mask; + else if (!source.isLive()) { + changedFrequent &= ~mask; + } + } + } + + void searchGeometryAtoms(UnorderList list) { + list.add(Shape3DRetained.getGeomAtom( + (Shape3DRetained) mirrorShape3D.get(0))); + } +} + + + + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/MultipleParentException.java b/j3d-core/src/classes/share/javax/media/j3d/MultipleParentException.java new file mode 100644 index 0000000..12af1b7 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/MultipleParentException.java @@ -0,0 +1,56 @@ +/* + * $RCSfile: MultipleParentException.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates + * an attempt to add a node that is already a child of one + * group node, into another group node. + */ +public class MultipleParentException extends IllegalSharingException { + +/** + * Create the exception object with default values. + */ + public MultipleParentException(){ + } + +/** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public MultipleParentException(String str){ + + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NativeConfigTemplate3D.java b/j3d-core/src/classes/share/javax/media/j3d/NativeConfigTemplate3D.java new file mode 100644 index 0000000..abfbae2 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NativeConfigTemplate3D.java @@ -0,0 +1,127 @@ +/* + * $RCSfile: NativeConfigTemplate3D.java,v $ + * + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.2 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsConfiguration; + +/** + * Native config template class. A singleton instance of the appropriate + * concrete subclass is created by a factory method using reflection. + */ +abstract class NativeConfigTemplate3D { + // These definitions are used by both the X11 and Win32 subclasses + final static int RED_SIZE = 0; + final static int GREEN_SIZE = 1; + final static int BLUE_SIZE = 2; + final static int ALPHA_SIZE = 3; + final static int ACCUM_BUFFER = 4; + final static int DEPTH_SIZE = 5; + final static int DOUBLEBUFFER = 6; + final static int STEREO = 7; + final static int ANTIALIASING = 8; + final static int STENCIL_SIZE = 9; + final static int NUM_ITEMS = 10; + + private static final String x11ClassName = "javax.media.j3d.X11NativeConfigTemplate3D"; + private static final String win32ClassName = "javax.media.j3d.Win32NativeConfigTemplate3D"; + + // The singleton instance of this class + private static NativeConfigTemplate3D nativeConfigTemplate3D = null; + + protected NativeConfigTemplate3D() { + } + + // This method is called exactly once by the initialization method of + // the NativePipeline class + synchronized static void createNativeConfigTemplate3D() { + String className; + if (MasterControl.isWindows()) { + className = win32ClassName; + } else { + className = x11ClassName; + } + + final String templateClassName = className; + nativeConfigTemplate3D = (NativeConfigTemplate3D) + java.security.AccessController.doPrivileged(new + java.security.PrivilegedAction() { + public Object run() { + try { + Class templateClass = Class.forName(templateClassName); + return templateClass.newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + static NativeConfigTemplate3D getNativeConfigTemplate3D() { + return nativeConfigTemplate3D; + } + + + /* + * Chooses the best FBConfig for Java 3D apps. + */ + abstract GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate3D template, + GraphicsConfiguration[] gc); + + /* + * Determine if a given GraphicsConfiguration object can be used + * by Java 3D. + */ + abstract boolean isGraphicsConfigSupported(GraphicsConfigTemplate3D template, + GraphicsConfiguration gc); + + + // Return whether stereo is available. + abstract boolean hasStereo(Canvas3D c3d); + + // Return the stencil of this canvas. + abstract int getStencilSize(Canvas3D c3d); + + // Return whether a double buffer is available. + abstract boolean hasDoubleBuffer(Canvas3D c3d); + + // Return whether scene antialiasing is available. + abstract boolean hasSceneAntialiasingAccum(Canvas3D c3d); + + + // Return whether scene antialiasing is available. + abstract boolean hasSceneAntialiasingMultisample(Canvas3D c3d); + + // Ensure that the native libraries are loaded + static { + VirtualUniverse.loadLibraries(); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NativeContext.java b/j3d-core/src/classes/share/javax/media/j3d/NativeContext.java new file mode 100644 index 0000000..0b4cd34 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NativeContext.java @@ -0,0 +1,50 @@ +/* + * $RCSfile: NativeContext.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Graphics context objects for native rendering pipeline. + */ +class NativeContext implements Context { + + // Native context pointer + private long nativeCtx; + + NativeContext(long nativeCtx) { + this.nativeCtx = nativeCtx; + } + + long getNativeCtx() { + return nativeCtx; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NativeDrawable.java b/j3d-core/src/classes/share/javax/media/j3d/NativeDrawable.java new file mode 100644 index 0000000..2fb29df --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NativeDrawable.java @@ -0,0 +1,51 @@ +/* + * $RCSfile: NativeDrawable.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Graphics Drawable objects for native rendering pipeline. + */ +class NativeDrawable implements Drawable { + + // Native drawable pointer. On Windows it is the native HDC. + // On X11 it is the handle to the native X11 drawable. + private long nativeDrawable; + + NativeDrawable(long nativeDrawable) { + this.nativeDrawable = nativeDrawable; + } + + long getNativeDrawable() { + return nativeDrawable; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NativePipeline.java b/j3d-core/src/classes/share/javax/media/j3d/NativePipeline.java new file mode 100644 index 0000000..2bb780f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NativePipeline.java @@ -0,0 +1,3411 @@ +/* + * $RCSfile: NativePipeline.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.13 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.util.ArrayList; + +/** + * Concrete implementation of Pipeline class for native OGL and D3D rendering + * pipeline. + */ +class NativePipeline extends Pipeline { + + // System properties containing the native library search PATH + // The order listed is the order in which they will be searched + private static final String[] systemPathProps = { + "sun.boot.library.path", + "java.library.path" + }; + + // Prefix for native libraries + private static final String libPrefix = "j3dcore"; + + // Boolean indicating whether we are using D3D or OGL + private boolean isD3D; + + // Renderer name, either "ogl" or "d3d" + private String rendererName; + + // Flags indicating whether the Cg or GLSL libraries are available. + private boolean cgLibraryAvailable = false; + private boolean glslLibraryAvailable = false; + + // Flag indicating that the ogl-chk library has been loaded + private static boolean oglChkLibraryLoaded = false; + + // Method to return the vendor string for the native OpenGL pipeline. + // If the native library cannot be loaded, or if GL_VERSION < 1.2 + // then null is returned. + static String getSupportedOglVendor() { + if (!oglChkLibraryLoaded) { + try { + loadLibrary("j3dcore-ogl-chk", true); + } catch (Exception ex) { + MasterControl.getCoreLogger().severe(ex.toString()); + return null; + } catch (Error ex) { + MasterControl.getCoreLogger().severe(ex.toString()); + return null; + } + oglChkLibraryLoaded = true; + } + return getSupportedOglVendorNative(); + } + + // Native method to return the vendor string + private static native String getSupportedOglVendorNative(); + + /** + * Constructor for singleton NativePipeline instance + */ + protected NativePipeline() { + } + + /** + * Initialize the pipeline + */ + void initialize(Pipeline.Type pipelineType) { + super.initialize(pipelineType); + + // This works around a native load library bug + try { + java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit(); + toolkit = null; // just making sure GC collects this + } catch (java.awt.AWTError e) { + } + + switch (pipelineType) { + case NATIVE_OGL: + isD3D = false; + rendererName = "ogl"; + break; + case NATIVE_D3D: + isD3D = true; + rendererName = "d3d"; + break; + default: + assert false; // Should never get here + } + + // Create the singleton, OS-dependent NativeConfigTemplate3D and + // NativeScreenInfo objects. + NativeConfigTemplate3D.createNativeConfigTemplate3D(); + NativeScreenInfo.createNativeScreenInfo(); + } + + /** + * Load all of the required libraries + */ + void loadLibraries(int globalShadingLanguage) { + // Load the native JAWT library as a workaround for a problem whereby + // the native libraries can't find it in some cases. + // Issue 257: ignore UnsatisfiedLinkError exception as a result of + // trying to load the library more than once. Try to continue in + // all cases if the load library fails, since it is just a workaround + // for a native bug. + try { + loadLibrary("jawt", false); + } catch (UnsatisfiedLinkError ex) { + if (ex.getMessage().indexOf("already loaded") == -1) { + // If it failed for a reason other than already being + // loaded, log the error. In either case, we will continue + MasterControl.getCoreLogger().severe(ex.toString()); + } + } catch (Error ex) { + MasterControl.getCoreLogger().severe(ex.toString()); + } catch (Exception ex) { + MasterControl.getCoreLogger().severe(ex.toString()); + } + + // Load the native rendering library + String libraryName = libPrefix + "-" + rendererName; + loadLibrary(libraryName, true); + + // Check whether the Cg library is available + if (globalShadingLanguage == Shader.SHADING_LANGUAGE_CG) { + String cgLibraryName = libPrefix + "-" + rendererName + "-cg"; + String[] libpath = setupLibPath(cgLibraryName); + cgLibraryAvailable = loadNativeCgLibrary(libpath); + } + + // Check whether the GLSL library is available + if (globalShadingLanguage == Shader.SHADING_LANGUAGE_GLSL) { + if (getPipelineType() == Pipeline.Type.NATIVE_OGL) { + // No need to verify that GLSL is available, since GLSL is part + // of OpenGL as an extension (or part of core in 2.0) + glslLibraryAvailable = true; + } + } + } + + /** + * Returns true if the Cg library is loaded and available. Note that this + * does not necessarily mean that Cg is supported by the graphics card. + */ + boolean isCgLibraryAvailable() { + return cgLibraryAvailable; + } + + /** + * Returns true if the GLSL library is loaded and available. Note that this + * does not necessarily mean that GLSL is supported by the graphics card. + */ + boolean isGLSLLibraryAvailable() { + return glslLibraryAvailable; + } + + /** + * Load the specified native library. If we are running in "appletLauncher" + * mode, we will use JNLPAppletLauncher to load the native library. + * Otherwise, we will use System.loadLibrary(). + */ + private static void loadLibrary(final String libName, boolean allowAppletLauncher) { + // Issue 257: Call JNLPAppletLauncher to load native libraries if needed + final boolean useAppletLauncher = allowAppletLauncher && MasterControl.isAppletLauncher(); + AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + boolean loaded = false; + if (useAppletLauncher) { + try { + Class jnlpAppletLauncherClass = Class.forName("org.jdesktop.applet.util.JNLPAppletLauncher"); + Method loadLibraryMethod = jnlpAppletLauncherClass.getDeclaredMethod("loadLibrary", String.class); + loadLibraryMethod.invoke(null, libName); + loaded = true; + } catch (ClassNotFoundException ex) { + System.err.println("Java 3D: loadLibrary(" + libName + ")"); + System.err.println(ex); + System.err.println("Attempting to use System.loadLibrary instead"); + } catch (Exception ex) { + Throwable t = ex; + if (t instanceof InvocationTargetException) { + t = ((InvocationTargetException) t).getTargetException(); + } + if (t instanceof Error) { + throw (Error) t; + } + if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } + // Throw UnsatisfiedLinkError for best compatibility with System.loadLibrary() + throw (UnsatisfiedLinkError) new UnsatisfiedLinkError().initCause(ex); + } + } + + if (!loaded) { + System.loadLibrary(libName); + } + return null; + } + }); + } + + /** + * Parse the specified System properties containing a PATH and return an + * array of Strings, where each element is an absolute filename consisting of + * the individual component of the path concatenated with the (relative) + * library file name. Only those absolute filenames that exist are included. + * If no absolute filename is found, we will try the relative library name. + */ + private String[] setupLibPath(String libName) { + final String libraryName = libName; + return (String[]) + AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + ArrayList pathList = new ArrayList(); + + String filename = System.mapLibraryName(libraryName); + for (int n = 0; n < systemPathProps.length; n++) { + String pathString = System.getProperty(systemPathProps[n]); + boolean done = false; + int posStart = 0; + while (!done) { + int posEnd = pathString.indexOf(File.pathSeparator, posStart); + if (posEnd == -1) { + posEnd = pathString.length(); + done = true; + } + String pathDir = pathString.substring(posStart, posEnd); + File pathFile = new File(pathDir, filename); + if (pathFile.exists()) { + pathList.add(pathFile.getAbsolutePath()); + } + + posStart = posEnd + 1; + } + } + + // If no absolute path names exist, add in the relative library name + if (pathList.size() == 0) { + pathList.add(filename); + } + + return (String[])pathList.toArray(new String[0]); + } + }); + } + + // Method to verify whether the native Cg library is available + private native boolean loadNativeCgLibrary(String[] libpath); + + + // + // Methods to box/unbox various native objects + // + + private long unbox(Context ctx) { + if (ctx == null) { + return 0; + } else { + return ((NativeContext)ctx).getNativeCtx(); + } + } + + private Context boxContext(long nativeCtx) { + if (nativeCtx == 0) { + return null; + } else { + return new NativeContext(nativeCtx); + } + } + + private long unbox(Drawable drawable) { + if (drawable == null) { + return 0; + } else { + return ((NativeDrawable)drawable).getNativeDrawable(); + } + } + + private Drawable boxDrawable(long nativeDrawable) { + if (nativeDrawable == 0) { + return null; + } else { + return new NativeDrawable(nativeDrawable); + } + } + + private long unbox(ShaderProgramId shaderProgramId) { + if (shaderProgramId == null) { + return 0; + } else { + return ((NativeShaderObject)shaderProgramId).getNativeId(); + } + } + + private ShaderProgramId boxShaderProgramId(long nativeId) { + if (nativeId == 0) { + return null; + } else { + return new NativeShaderObject(nativeId); + } + } + + private long unbox(ShaderId shaderId) { + if (shaderId == null) { + return 0; + } else { + return ((NativeShaderObject)shaderId).getNativeId(); + } + } + + private ShaderId boxShaderId(long nativeId) { + if (nativeId == 0) { + return null; + } else { + return new NativeShaderObject(nativeId); + } + } + + private long unbox(ShaderAttrLoc attrLoc) { + if (attrLoc == null) { + return -1; + } else { + return ((NativeShaderObject)attrLoc).getNativeId(); + } + } + + private ShaderAttrLoc boxShaderAttrLoc(long nativeId) { + if (nativeId == -1) { + return null; + } else { + return new NativeShaderObject(nativeId); + } + } + + // --------------------------------------------------------------------- + + // + // GeometryArrayRetained methods + // + + // Used by D3D to free vertex buffer + native void freeD3DArray(GeometryArrayRetained geo, boolean deleteVB); + + // used for GeometryArrays by Copy or interleaved + native void execute(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + int vertexAttrCount, int[] vertexAttrSizes, + float[] varray, float[] cdata, int cdirty); + + void execute(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + int vertexAttrCount, int[] vertexAttrSizes, + float[] varray, float[] cdata, int cdirty) { + execute(unbox(ctx), + geo, geo_type, + isNonUniformScale, + useAlpha, + ignoreVertexColors, + startVIndex, vcount, vformat, + texCoordSetCount, texCoordSetMap, + texCoordSetMapLen, + texCoordSetOffset, + numActiveTexUnitState, + vertexAttrCount, vertexAttrSizes, + varray, cdata, cdirty); + } + + // used by GeometryArray by Reference with java arrays + native void executeVA(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, float[] vfcoords, double[] vdcoords, + int colorIndex, float[] cfdata, byte[] cbdata, + int normalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty); + + void executeVA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, float[] vfcoords, double[] vdcoords, + int colorIndex, float[] cfdata, byte[] cbdata, + int normalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty) { + executeVA(unbox(ctx), + geo, geo_type, + isNonUniformScale, + ignoreVertexColors, + vcount, + vformat, + vdefined, + coordIndex, vfcoords, vdcoords, + colorIndex, cfdata, cbdata, + normalIndex, ndata, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndex, vertexAttrData, + texcoordmaplength, + texcoordoffset, + numActiveTexUnitState, + texIndex, texstride, texCoords, + cdirty); + } + + // used by GeometryArray by Reference with NIO buffer + native void executeVABuffer(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, + Object vcoords, + int colorIndex, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + int normalIndex, Object ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, Object[] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty); + + void executeVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, + Object vcoords, + int colorIndex, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + int normalIndex, Object ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, Object[] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty) { + executeVABuffer(unbox(ctx), + geo, geo_type, + isNonUniformScale, + ignoreVertexColors, + vcount, + vformat, + vdefined, + coordIndex, + vcoords, + colorIndex, + cdataBuffer, + cfdata, cbdata, + normalIndex, ndata, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndex, vertexAttrData, + texcoordmaplength, + texcoordoffset, + numActiveTexUnitState, + texIndex, texstride, texCoords, + cdirty); + } + + // used by GeometryArray by Reference in interleaved format with NIO buffer + native void executeInterleavedBuffer(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + Object varray, float[] cdata, int cdirty); + + void executeInterleavedBuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + Object varray, float[] cdata, int cdirty) { + executeInterleavedBuffer(unbox(ctx), + geo, geo_type, + isNonUniformScale, + useAlpha, + ignoreVertexColors, + startVIndex, vcount, vformat, + texCoordSetCount, texCoordSetMap, + texCoordSetMapLen, + texCoordSetOffset, + numActiveTexUnitState, + varray, cdata, cdirty); + } + + native void setVertexFormat(long ctx, GeometryArrayRetained geo, + int vformat, boolean useAlpha, boolean ignoreVertexColors); + + void setVertexFormat(Context ctx, GeometryArrayRetained geo, + int vformat, boolean useAlpha, boolean ignoreVertexColors) { + setVertexFormat(unbox(ctx), geo, + vformat, useAlpha, ignoreVertexColors); + } + + native void disableGlobalAlpha(long ctx, GeometryArrayRetained geo, int vformat, + boolean useAlpha, boolean ignoreVertexColors); + + void disableGlobalAlpha(Context ctx, GeometryArrayRetained geo, int vformat, + boolean useAlpha, boolean ignoreVertexColors) { + disableGlobalAlpha(unbox(ctx), geo, vformat, + useAlpha, ignoreVertexColors); + } + + // used for GeometryArrays + native void buildGA(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int startVIndex, + int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, int[] texCoordSetMapOffset, + int vertexAttrCount, int[] vertexAttrSizes, + double[] xform, double[] nxform, + float[] varray); + + void buildGA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int startVIndex, + int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, int[] texCoordSetMapOffset, + int vertexAttrCount, int[] vertexAttrSizes, + double[] xform, double[] nxform, + float[] varray) { + buildGA(unbox(ctx), + geo, geo_type, + isNonUniformScale, updateAlpha, + alpha, + ignoreVertexColors, + startVIndex, + vcount, vformat, + texCoordSetCount, texCoordSetMap, + texCoordSetMapLen, texCoordSetMapOffset, + vertexAttrCount, vertexAttrSizes, + xform, nxform, + varray); + } + + // used to Build Dlist GeometryArray by Reference with java arrays + native void buildGAForByRef(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, float[] vfcoords, double[] vdcoords, + int colorIndex, float[] cfdata, byte[] cbdata, + int normalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int[] texIndex, int texstride, Object[] texCoords, + double[] xform, double[] nxform); + + void buildGAForByRef(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, float[] vfcoords, double[] vdcoords, + int colorIndex, float[] cfdata, byte[] cbdata, + int normalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int[] texIndex, int texstride, Object[] texCoords, + double[] xform, double[] nxform) { + buildGAForByRef(unbox(ctx), + geo, geo_type, + isNonUniformScale, updateAlpha, + alpha, + ignoreVertexColors, + vcount, + vformat, + vdefined, + coordIndex, vfcoords, vdcoords, + colorIndex, cfdata, cbdata, + normalIndex, ndata, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndex, vertexAttrData, + texcoordmaplength, + texcoordoffset, + texIndex, texstride, texCoords, + xform, nxform); + } + + // --------------------------------------------------------------------- + + // + // IndexedGeometryArrayRetained methods + // + + // by-copy or interleaved, by reference, Java arrays + native void executeIndexedGeometry(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + float[] varray, float[] cdata, + int cdirty, + int[] indexCoord); + + void executeIndexedGeometry(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + float[] varray, float[] cdata, + int cdirty, + int[] indexCoord) { + executeIndexedGeometry(unbox(ctx), + geo, geo_type, + isNonUniformScale, + useAlpha, + ignoreVertexColors, + initialIndexIndex, + indexCount, + vertexCount, vformat, + vertexAttrCount, vertexAttrSizes, + texCoordSetCount, texCoordSetMap, + texCoordSetMapLen, + texCoordSetOffset, + numActiveTexUnitState, + varray, cdata, + cdirty, + indexCoord); + } + + // interleaved, by reference, nio buffer + native void executeIndexedGeometryBuffer(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + Object varray, float[] cdata, + int cdirty, + int[] indexCoord); + + void executeIndexedGeometryBuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + Object varray, float[] cdata, + int cdirty, + int[] indexCoord) { + executeIndexedGeometryBuffer(unbox(ctx), + geo, geo_type, + isNonUniformScale, + useAlpha, + ignoreVertexColors, + initialIndexIndex, + indexCount, + vertexCount, vformat, + texCoordSetCount, texCoordSetMap, + texCoordSetMapLen, + texCoordSetOffset, + numActiveTexUnitState, + varray, cdata, + cdirty, + indexCoord); + } + + // non interleaved, by reference, Java arrays + native void executeIndexedGeometryVA(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + float[] vfcoords, double[] vdcoords, + float[] cfdata, byte[] cbdata, + float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texstride, Object[] texCoords, + int cdirty, + int[] indexCoord); + + void executeIndexedGeometryVA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + float[] vfcoords, double[] vdcoords, + float[] cfdata, byte[] cbdata, + float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texstride, Object[] texCoords, + int cdirty, + int[] indexCoord) { + executeIndexedGeometryVA(unbox(ctx), + geo, geo_type, + isNonUniformScale, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + vertexCount, + vformat, + vdefined, + vfcoords, vdcoords, + cfdata, cbdata, + ndata, + vertexAttrCount, vertexAttrSizes, + vertexAttrData, + texcoordmaplength, + texcoordoffset, + numActiveTexUnitState, + texstride, texCoords, + cdirty, + indexCoord); + } + + // non interleaved, by reference, nio buffer + native void executeIndexedGeometryVABuffer(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + Object vcoords, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + Object normal, + int vertexAttrCount, int[] vertexAttrSizes, + Object[] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texstride, Object[] texCoords, + int cdirty, + int[] indexCoord); + + void executeIndexedGeometryVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + Object vcoords, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + Object normal, + int vertexAttrCount, int[] vertexAttrSizes, + Object[] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texstride, Object[] texCoords, + int cdirty, + int[] indexCoord) { + executeIndexedGeometryVABuffer(unbox(ctx), + geo, geo_type, + isNonUniformScale, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + vertexCount, + vformat, + vdefined, + vcoords, + cdataBuffer, + cfdata, cbdata, + normal, + vertexAttrCount, vertexAttrSizes, + vertexAttrData, + texcoordmaplength, + texcoordoffset, + numActiveTexUnitState, + texstride, texCoords, + cdirty, + indexCoord); + } + + // by-copy geometry + native void buildIndexedGeometry(long ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetMapOffset, + double[] xform, double[] nxform, + float[] varray, int[] indexCoord); + + void buildIndexedGeometry(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetMapOffset, + double[] xform, double[] nxform, + float[] varray, int[] indexCoord) { + buildIndexedGeometry(unbox(ctx), + geo, geo_type, + isNonUniformScale, updateAlpha, + alpha, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + vertexCount, + vformat, + vertexAttrCount, vertexAttrSizes, + texCoordSetCount, texCoordSetMap, + texCoordSetMapLen, + texCoordSetMapOffset, + xform, nxform, + varray, indexCoord); + } + + + // --------------------------------------------------------------------- + + // + // GraphicsContext3D methods + // + + native void readRaster(long ctx, + int type, int xSrcOffset, int ySrcOffset, + int width, int height, int hCanvas, + int imageDataType, + int imageFormat, + Object imageBuffer, + int depthFormat, + Object depthBuffer); + + void readRaster(Context ctx, + int type, int xSrcOffset, int ySrcOffset, + int width, int height, int hCanvas, + int imageDataType, + int imageFormat, + Object imageBuffer, + int depthFormat, + Object depthBuffer) { + readRaster(unbox(ctx), + type, xSrcOffset, ySrcOffset, + width, height, hCanvas, + imageDataType, + imageFormat, imageBuffer, + depthFormat, depthBuffer); + } + + // --------------------------------------------------------------------- + + // + // CgShaderProgramRetained methods + // + + // ShaderAttributeValue methods + + native ShaderError setCgUniform1i(long ctx, + long shaderProgramId, + long uniformLocation, + int value); + + ShaderError setCgUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + return setCgUniform1i(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniform1f(long ctx, + long shaderProgramId, + long uniformLocation, + float value); + + ShaderError setCgUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + return setCgUniform1f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniform2i(long ctx, + long shaderProgramId, + long uniformLocation, + int[] value); + + ShaderError setCgUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return setCgUniform2i(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniform2f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setCgUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setCgUniform2f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniform3i(long ctx, + long shaderProgramId, + long uniformLocation, + int[] value); + + ShaderError setCgUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return setCgUniform3i(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniform3f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setCgUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setCgUniform3f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniform4i(long ctx, + long shaderProgramId, + long uniformLocation, + int[] value); + + ShaderError setCgUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return setCgUniform4i(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniform4f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setCgUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setCgUniform4f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniformMatrix3f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setCgUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setCgUniformMatrix3f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setCgUniformMatrix4f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setCgUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setCgUniformMatrix4f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + // ShaderAttributeArray methods + + native ShaderError setCgUniform1iArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + int[] value); + + ShaderError setCgUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return setCgUniform1iArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniform1fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setCgUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setCgUniform1fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniform2iArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + int[] value); + + ShaderError setCgUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return setCgUniform2iArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniform2fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setCgUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setCgUniform2fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniform3iArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + int[] value); + + ShaderError setCgUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return setCgUniform3iArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniform3fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setCgUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setCgUniform3fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniform4iArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + int[] value); + + ShaderError setCgUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return setCgUniform4iArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniform4fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setCgUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setCgUniform4fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniformMatrix3fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setCgUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setCgUniformMatrix3fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setCgUniformMatrix4fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setCgUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setCgUniformMatrix4fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + // Native interfaces for shader compilation, etc. + native ShaderError createCgShader(long ctx, int shaderType, long[] shaderId); + + ShaderError createCgShader(Context ctx, int shaderType, ShaderId[] shaderId) { + long[] nativeId = new long[1]; + ShaderError err = createCgShader(unbox(ctx), shaderType, nativeId); + shaderId[0] = boxShaderId(nativeId[0]); + return err; + } + + native ShaderError destroyCgShader(long ctx, long shaderId); + + ShaderError destroyCgShader(Context ctx, ShaderId shaderId) { + return destroyCgShader(unbox(ctx), unbox(shaderId)); + } + + native ShaderError compileCgShader(long ctx, long shaderId, String program); + + ShaderError compileCgShader(Context ctx, ShaderId shaderId, String program) { + return compileCgShader(unbox(ctx), unbox(shaderId), program); + } + + native ShaderError createCgShaderProgram(long ctx, long[] shaderProgramId); + + ShaderError createCgShaderProgram(Context ctx, ShaderProgramId[] shaderProgramId) { + long[] nativeId = new long[1]; + ShaderError err = createCgShaderProgram(unbox(ctx), nativeId); + shaderProgramId[0] = boxShaderProgramId(nativeId[0]); + return err; + } + + native ShaderError destroyCgShaderProgram(long ctx, long shaderProgramId); + + ShaderError destroyCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return destroyCgShaderProgram(unbox(ctx), unbox(shaderProgramId)); + } + + native ShaderError linkCgShaderProgram(long ctx, long shaderProgramId, + long[] shaderIds); + + ShaderError linkCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId, + ShaderId[] shaderIds) { + + assert shaderIds != null; + long[] nativeIds = new long[shaderIds.length]; + for (int i = 0; i < shaderIds.length; i++) { + nativeIds[i] = unbox(shaderIds[i]); + } + return linkCgShaderProgram(unbox(ctx), unbox(shaderProgramId), + nativeIds); + } + + native void lookupCgVertexAttrNames(long ctx, long shaderProgramId, + int numAttrNames, String[] attrNames, boolean[] errArr); + + void lookupCgVertexAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, boolean[] errArr) { + lookupCgVertexAttrNames(unbox(ctx), unbox(shaderProgramId), + numAttrNames, attrNames, errArr); + } + + native void lookupCgShaderAttrNames(long ctx, long shaderProgramId, + int numAttrNames, String[] attrNames, long[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr); + + void lookupCgShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, ShaderAttrLoc[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr) { + + assert numAttrNames == locArr.length; + long[] nativeLocArr = new long[numAttrNames]; + for (int i = 0; i < numAttrNames; i++) { + // Initialize to invalid native location + nativeLocArr[i] = -1; + } + lookupCgShaderAttrNames(unbox(ctx), unbox(shaderProgramId), + numAttrNames, attrNames, nativeLocArr, + typeArr, sizeArr, isArrayArr); + for (int i = 0; i < numAttrNames; i++) { + locArr[i] = boxShaderAttrLoc(nativeLocArr[i]); + } + } + + native ShaderError useCgShaderProgram(long ctx, long shaderProgramId); + + ShaderError useCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return useCgShaderProgram(unbox(ctx), unbox(shaderProgramId)); + } + + // --------------------------------------------------------------------- + + // + // GLSLShaderProgramRetained methods + // + + // ShaderAttributeValue methods + + native ShaderError setGLSLUniform1i(long ctx, + long shaderProgramId, + long uniformLocation, + int value); + + ShaderError setGLSLUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + return setGLSLUniform1i(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniform1f(long ctx, + long shaderProgramId, + long uniformLocation, + float value); + + ShaderError setGLSLUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + return setGLSLUniform1f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniform2i(long ctx, + long shaderProgramId, + long uniformLocation, + int[] value); + + ShaderError setGLSLUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return setGLSLUniform2i(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniform2f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setGLSLUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setGLSLUniform2f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniform3i(long ctx, + long shaderProgramId, + long uniformLocation, + int[] value); + + ShaderError setGLSLUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return setGLSLUniform3i(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniform3f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setGLSLUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setGLSLUniform3f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniform4i(long ctx, + long shaderProgramId, + long uniformLocation, + int[] value); + + ShaderError setGLSLUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return setGLSLUniform4i(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniform4f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setGLSLUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setGLSLUniform4f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniformMatrix3f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setGLSLUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setGLSLUniformMatrix3f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + native ShaderError setGLSLUniformMatrix4f(long ctx, + long shaderProgramId, + long uniformLocation, + float[] value); + + ShaderError setGLSLUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return setGLSLUniformMatrix4f(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + value); + } + + // ShaderAttributeArray methods + + native ShaderError setGLSLUniform1iArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + int[] value); + + ShaderError setGLSLUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return setGLSLUniform1iArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniform1fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setGLSLUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setGLSLUniform1fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniform2iArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + int[] value); + + ShaderError setGLSLUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return setGLSLUniform2iArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniform2fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setGLSLUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setGLSLUniform2fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniform3iArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + int[] value); + + ShaderError setGLSLUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return setGLSLUniform3iArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniform3fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setGLSLUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setGLSLUniform3fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniform4iArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + int[] value); + + ShaderError setGLSLUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return setGLSLUniform4iArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniform4fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setGLSLUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setGLSLUniform4fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniformMatrix3fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setGLSLUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setGLSLUniformMatrix3fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + native ShaderError setGLSLUniformMatrix4fArray(long ctx, + long shaderProgramId, + long uniformLocation, + int numElements, + float[] value); + + ShaderError setGLSLUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return setGLSLUniformMatrix4fArray(unbox(ctx), + unbox(shaderProgramId), + unbox(uniformLocation), + numElements, + value); + } + + // native interfaces for shader compilation, etc. + native ShaderError createGLSLShader(long ctx, int shaderType, long[] shaderId); + + ShaderError createGLSLShader(Context ctx, int shaderType, ShaderId[] shaderId) { + long[] nativeId = new long[1]; + ShaderError err = createGLSLShader(unbox(ctx), shaderType, nativeId); + shaderId[0] = boxShaderId(nativeId[0]); + return err; + } + native ShaderError destroyGLSLShader(long ctx, long shaderId); + + ShaderError destroyGLSLShader(Context ctx, ShaderId shaderId) { + return destroyGLSLShader(unbox(ctx), unbox(shaderId)); + } + native ShaderError compileGLSLShader(long ctx, long shaderId, String program); + + ShaderError compileGLSLShader(Context ctx, ShaderId shaderId, String program) { + return compileGLSLShader(unbox(ctx), unbox(shaderId), program); + } + + native ShaderError createGLSLShaderProgram(long ctx, long[] shaderProgramId); + + ShaderError createGLSLShaderProgram(Context ctx, ShaderProgramId[] shaderProgramId) { + long[] nativeId = new long[1]; + ShaderError err = createGLSLShaderProgram(unbox(ctx), nativeId); + shaderProgramId[0] = boxShaderProgramId(nativeId[0]); + return err; + } + native ShaderError destroyGLSLShaderProgram(long ctx, long shaderProgramId); + + ShaderError destroyGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return destroyGLSLShaderProgram(unbox(ctx), unbox(shaderProgramId)); + } + native ShaderError linkGLSLShaderProgram(long ctx, long shaderProgramId, + long[] shaderId); + + ShaderError linkGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId, + ShaderId[] shaderIds) { + assert shaderIds != null; + long[] nativeIds = new long[shaderIds.length]; + for (int i = 0; i < shaderIds.length; i++) { + nativeIds[i] = unbox(shaderIds[i]); + } + return linkGLSLShaderProgram(unbox(ctx), unbox(shaderProgramId), + nativeIds); + } + native ShaderError bindGLSLVertexAttrName(long ctx, long shaderProgramId, + String attrName, int attrIndex); + + ShaderError bindGLSLVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, + String attrName, int attrIndex) { + return bindGLSLVertexAttrName(unbox(ctx), unbox(shaderProgramId), + attrName, attrIndex); + } + native void lookupGLSLShaderAttrNames(long ctx, long shaderProgramId, + int numAttrNames, String[] attrNames, long[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr); + + void lookupGLSLShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, ShaderAttrLoc[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr) { + + assert numAttrNames == locArr.length; + long[] nativeLocArr = new long[numAttrNames]; + for (int i = 0; i < numAttrNames; i++) { + // Initialize to invalid native location + nativeLocArr[i] = -1; + } + lookupGLSLShaderAttrNames(unbox(ctx), unbox(shaderProgramId), + numAttrNames, attrNames, nativeLocArr, + typeArr, sizeArr, isArrayArr); + for (int i = 0; i < numAttrNames; i++) { + locArr[i] = boxShaderAttrLoc(nativeLocArr[i]); + } + } + + native ShaderError useGLSLShaderProgram(long ctx, long shaderProgramId); + + ShaderError useGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return useGLSLShaderProgram(unbox(ctx), unbox(shaderProgramId)); + } + + + // --------------------------------------------------------------------- + + // + // Renderer methods + // + + native void cleanupRenderer(); + + + // --------------------------------------------------------------------- + + // + // ColoringAttributesRetained methods + // + + native void updateColoringAttributes(long ctx, + float dRed, float dGreen, float dBlue, + float red, float green, float blue, + float alpha, + boolean lEnable, + int shadeModel); + + void updateColoringAttributes(Context ctx, + float dRed, float dGreen, float dBlue, + float red, float green, float blue, + float alpha, + boolean lEnable, + int shadeModel) { + updateColoringAttributes(unbox(ctx), + dRed, dGreen, dBlue, + red, green, blue, + alpha, + lEnable, + shadeModel); + } + + + // --------------------------------------------------------------------- + + // + // DirectionalLightRetained methods + // + + native void updateDirectionalLight(long ctx, + int lightSlot, float red, float green, + float blue, float x, float y, float z); + + void updateDirectionalLight(Context ctx, + int lightSlot, float red, float green, + float blue, float x, float y, float z) { + updateDirectionalLight(unbox(ctx), + lightSlot, red, green, + blue, x, y, z); + } + + + // --------------------------------------------------------------------- + + // + // PointLightRetained methods + // + + native void updatePointLight(long ctx, + int lightSlot, float red, float green, + float blue, float ax, float ay, float az, + float px, float py, float pz); + + void updatePointLight(Context ctx, + int lightSlot, float red, float green, + float blue, float ax, float ay, float az, + float px, float py, float pz) { + updatePointLight(unbox(ctx), + lightSlot, red, green, + blue, ax, ay, az, + px, py, pz); + } + + + // --------------------------------------------------------------------- + + // + // SpotLightRetained methods + // + + native void updateSpotLight(long ctx, + int lightSlot, float red, float green, + float blue, float ax, float ay, float az, + float px, float py, float pz, float spreadAngle, + float concentration, float dx, float dy, + float dz); + + void updateSpotLight(Context ctx, + int lightSlot, float red, float green, + float blue, float ax, float ay, float az, + float px, float py, float pz, float spreadAngle, + float concentration, float dx, float dy, + float dz) { + updateSpotLight(unbox(ctx), + lightSlot, red, green, + blue, ax, ay, az, + px, py, pz, spreadAngle, + concentration, dx, dy, + dz); + } + + + // --------------------------------------------------------------------- + + // + // ExponentialFogRetained methods + // + + native void updateExponentialFog(long ctx, + float red, float green, float blue, + float density); + + void updateExponentialFog(Context ctx, + float red, float green, float blue, + float density) { + updateExponentialFog(unbox(ctx), + red, green, blue, + density); + } + + + // --------------------------------------------------------------------- + + // + // LinearFogRetained methods + // + + native void updateLinearFog(long ctx, + float red, float green, float blue, + double fdist, double bdist); + + void updateLinearFog(Context ctx, + float red, float green, float blue, + double fdist, double bdist) { + updateLinearFog(unbox(ctx), + red, green, blue, + fdist, bdist); + } + + + // --------------------------------------------------------------------- + + // + // LineAttributesRetained methods + // + + native void updateLineAttributes(long ctx, + float lineWidth, int linePattern, + int linePatternMask, + int linePatternScaleFactor, + boolean lineAntialiasing); + + void updateLineAttributes(Context ctx, + float lineWidth, int linePattern, + int linePatternMask, + int linePatternScaleFactor, + boolean lineAntialiasing) { + updateLineAttributes(unbox(ctx), + lineWidth, linePattern, + linePatternMask, + linePatternScaleFactor, + lineAntialiasing); + } + + + // --------------------------------------------------------------------- + + // + // MaterialRetained methods + // + + native void updateMaterial(long ctx, + float red, float green, float blue, float alpha, + float ared, float agreen, float ablue, + float ered, float egreen, float eblue, + float dred, float dgreen, float dblue, + float sred, float sgreen, float sblue, + float shininess, int colorTarget, boolean enable); + + void updateMaterial(Context ctx, + float red, float green, float blue, float alpha, + float ared, float agreen, float ablue, + float ered, float egreen, float eblue, + float dred, float dgreen, float dblue, + float sred, float sgreen, float sblue, + float shininess, int colorTarget, boolean enable) { + updateMaterial(unbox(ctx), + red, green, blue, alpha, + ared, agreen, ablue, + ered, egreen, eblue, + dred, dgreen, dblue, + sred, sgreen, sblue, + shininess, colorTarget, enable); + } + + + // --------------------------------------------------------------------- + + // + // ModelClipRetained methods + // + + native void updateModelClip(long ctx, int planeNum, boolean enableFlag, + double A, double B, double C, double D); + + void updateModelClip(Context ctx, int planeNum, boolean enableFlag, + double A, double B, double C, double D) { + updateModelClip(unbox(ctx), planeNum, enableFlag, + A, B, C, D); + } + + + // --------------------------------------------------------------------- + + // + // PointAttributesRetained methods + // + + native void updatePointAttributes(long ctx, float pointSize, boolean pointAntialiasing); + + void updatePointAttributes(Context ctx, float pointSize, boolean pointAntialiasing) { + updatePointAttributes(unbox(ctx), pointSize, pointAntialiasing); + } + + + // --------------------------------------------------------------------- + + // + // PolygonAttributesRetained methods + // + + native void updatePolygonAttributes(long ctx, + int polygonMode, int cullFace, + boolean backFaceNormalFlip, + float polygonOffset, + float polygonOffsetFactor); + + void updatePolygonAttributes(Context ctx, + int polygonMode, int cullFace, + boolean backFaceNormalFlip, + float polygonOffset, + float polygonOffsetFactor) { + updatePolygonAttributes(unbox(ctx), + polygonMode, cullFace, + backFaceNormalFlip, + polygonOffset, + polygonOffsetFactor); + } + + + // --------------------------------------------------------------------- + + // + // RenderingAttributesRetained methods + // + + // TODO : Need to handle stencil operation on the native side -- Chien + native void updateRenderingAttributes(long ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride, + boolean depthBufferEnable, + boolean depthBufferWriteEnable, + int depthTestFunction, + float alphaTestValue, int alphaTestFunction, + boolean ignoreVertexColors, + boolean rasterOpEnable, int rasterOp, + boolean userStencilAvailable, boolean stencilEnable, + int stencilFailOp, int stencilZFailOp, int stencilZPassOp, + int stencilFunction, int stencilReferenceValue, + int stencilCompareMask, int stencilWriteMask ); + + void updateRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride, + boolean depthBufferEnable, + boolean depthBufferWriteEnable, + int depthTestFunction, + float alphaTestValue, int alphaTestFunction, + boolean ignoreVertexColors, + boolean rasterOpEnable, int rasterOp, + boolean userStencilAvailable, boolean stencilEnable, + int stencilFailOp, int stencilZFailOp, int stencilZPassOp, + int stencilFunction, int stencilReferenceValue, + int stencilCompareMask, int stencilWriteMask ) { + updateRenderingAttributes(unbox(ctx), + depthBufferWriteEnableOverride, + depthBufferEnableOverride, + depthBufferEnable, + depthBufferWriteEnable, + depthTestFunction, + alphaTestValue, alphaTestFunction, + ignoreVertexColors, + rasterOpEnable, rasterOp, + userStencilAvailable, stencilEnable, + stencilFailOp, stencilZFailOp, stencilZPassOp, + stencilFunction, stencilReferenceValue, + stencilCompareMask, stencilWriteMask ); + } + + + // --------------------------------------------------------------------- + + // + // TexCoordGenerationRetained methods + // + + /** + * This method updates the native context: + * trans contains eyeTovworld transform in d3d + * trans contains vworldToEye transform in ogl + */ + native void updateTexCoordGeneration(long ctx, + boolean enable, int genMode, int format, + float planeSx, float planeSy, float planeSz, float planeSw, + float planeTx, float planeTy, float planeTz, float planeTw, + float planeRx, float planeRy, float planeRz, float planeRw, + float planeQx, float planeQy, float planeQz, float planeQw, + double[] trans); + + void updateTexCoordGeneration(Context ctx, + boolean enable, int genMode, int format, + float planeSx, float planeSy, float planeSz, float planeSw, + float planeTx, float planeTy, float planeTz, float planeTw, + float planeRx, float planeRy, float planeRz, float planeRw, + float planeQx, float planeQy, float planeQz, float planeQw, + double[] trans) { + updateTexCoordGeneration(unbox(ctx), + enable, genMode, format, + planeSx, planeSy, planeSz, planeSw, + planeTx, planeTy, planeTz, planeTw, + planeRx, planeRy, planeRz, planeRw, + planeQx, planeQy, planeQz, planeQw, + trans); + } + + + // --------------------------------------------------------------------- + + // + // TransparencyAttributesRetained methods + // + + native void updateTransparencyAttributes(long ctx, + float alpha, int geometryType, + int polygonMode, + boolean lineAA, boolean pointAA, + int transparencyMode, + int srcBlendFunction, + int dstBlendFunction); + + void updateTransparencyAttributes(Context ctx, + float alpha, int geometryType, + int polygonMode, + boolean lineAA, boolean pointAA, + int transparencyMode, + int srcBlendFunction, + int dstBlendFunction) { + updateTransparencyAttributes(unbox(ctx), + alpha, geometryType, + polygonMode, + lineAA, pointAA, + transparencyMode, + srcBlendFunction, + dstBlendFunction); + } + + + // --------------------------------------------------------------------- + + // + // TextureAttributesRetained methods + // + + native void updateTextureAttributes(long ctx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, float red, + float green, float blue, float alpha, + int textureFormat); + + void updateTextureAttributes(Context ctx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, float red, + float green, float blue, float alpha, + int textureFormat) { + updateTextureAttributes(unbox(ctx), + transform, isIdentity, textureMode, + perspCorrectionMode, red, + green, blue, alpha, + textureFormat); + } + + native void updateRegisterCombiners(long ctx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, float red, + float green, float blue, float alpha, + int textureFormat, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale); + + void updateRegisterCombiners(Context ctx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, float red, + float green, float blue, float alpha, + int textureFormat, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale) { + updateRegisterCombiners(unbox(ctx), + transform, isIdentity, textureMode, + perspCorrectionMode, red, + green, blue, alpha, + textureFormat, + combineRgbMode, combineAlphaMode, + combineRgbSrc, combineAlphaSrc, + combineRgbFcn, combineAlphaFcn, + combineRgbScale, combineAlphaScale); + } + + native void updateTextureColorTable(long ctx, int numComponents, + int colorTableSize, + int[] colorTable); + + void updateTextureColorTable(Context ctx, int numComponents, + int colorTableSize, + int[] colorTable) { + updateTextureColorTable(unbox(ctx), numComponents, + colorTableSize, + colorTable); + } + + native void updateCombiner(long ctx, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale); + + void updateCombiner(Context ctx, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale) { + updateCombiner(unbox(ctx), + combineRgbMode, combineAlphaMode, + combineRgbSrc, combineAlphaSrc, + combineRgbFcn, combineAlphaFcn, + combineRgbScale, combineAlphaScale); + } + + + // --------------------------------------------------------------------- + + // + // TextureUnitStateRetained methods + // + + native void updateTextureUnitState(long ctx, int unitIndex, boolean enableFlag); + + void updateTextureUnitState(Context ctx, int unitIndex, boolean enableFlag) { + updateTextureUnitState(unbox(ctx), unitIndex, enableFlag); + } + + + // --------------------------------------------------------------------- + + // + // TextureRetained methods + // Texture2DRetained methods + // + + native void bindTexture2D(long ctx, int objectId, boolean enable); + + void bindTexture2D(Context ctx, int objectId, boolean enable) { + bindTexture2D(unbox(ctx), objectId, enable); + } + + native void updateTexture2DImage(long ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int imageDataType, Object data, boolean useAutoMipMap); + + void updateTexture2DImage(Context ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int imageDataType, Object data, boolean useAutoMipMap) { + updateTexture2DImage(unbox(ctx), + numLevels, level, + textureFormat, imageFormat, + width, height, + boundaryWidth, + imageDataType, data, useAutoMipMap); + } + + native void updateTexture2DSubImage(long ctx, + int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int imageDataType, Object data, boolean useAutoMipMap); + + void updateTexture2DSubImage(Context ctx, + int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int imageDataType, Object data, boolean useAutoMipMap) { + updateTexture2DSubImage(unbox(ctx), + level, xoffset, yoffset, + textureFormat, imageFormat, + imgXOffset, imgYOffset, + tilew, width, height, + imageDataType, data, useAutoMipMap); + } + + native void updateTexture2DLodRange(long ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod); + + void updateTexture2DLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + updateTexture2DLodRange(unbox(ctx), + baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + native void updateTexture2DLodOffset(long ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ); + + void updateTexture2DLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + updateTexture2DLodOffset(unbox(ctx), + lodOffsetX, lodOffsetY, + lodOffsetZ); + } + + native void updateTexture2DBoundary(long ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha); + + void updateTexture2DBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + updateTexture2DBoundary(unbox(ctx), + boundaryModeS, boundaryModeT, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + native void updateTexture2DFilterModes(long ctx, + int minFilter, int magFilter); + + void updateTexture2DFilterModes(Context ctx, + int minFilter, int magFilter) { + updateTexture2DFilterModes(unbox(ctx), + minFilter, magFilter); + } + + native void updateTexture2DSharpenFunc(long ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts); + + void updateTexture2DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + updateTexture2DSharpenFunc(unbox(ctx), + numSharpenTextureFuncPts, + sharpenTextureFuncPts); + } + + native void updateTexture2DFilter4Func(long ctx, + int numFilter4FuncPts, + float[] filter4FuncPts); + + void updateTexture2DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + updateTexture2DFilter4Func(unbox(ctx), + numFilter4FuncPts, + filter4FuncPts); + } + + native void updateTexture2DAnisotropicFilter(long ctx, float degree); + + void updateTexture2DAnisotropicFilter(Context ctx, float degree) { + updateTexture2DAnisotropicFilter(unbox(ctx), degree); + } + + + // --------------------------------------------------------------------- + + // + // Texture3DRetained methods + // + + native void bindTexture3D(long ctx, int objectId, boolean enable); + + void bindTexture3D(Context ctx, int objectId, boolean enable) { + bindTexture3D(unbox(ctx), objectId, enable); + } + + native void updateTexture3DImage(long ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, int depth, + int boundaryWidth, + int imageDataType, Object imageData, boolean useAutoMipMap); + + void updateTexture3DImage(Context ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, int depth, + int boundaryWidth, + int imageDataType, Object imageData, boolean useAutoMipMap) { + updateTexture3DImage(unbox(ctx), + numLevels, level, + textureFormat, imageFormat, + width, height, depth, + boundaryWidth, + imageDataType, imageData, useAutoMipMap); + } + + native void updateTexture3DSubImage(long ctx, + int level, + int xoffset, int yoffset, int zoffset, + int textureFormat, int imageFormat, + int imgXoffset, int imgYoffset, int imgZoffset, + int tilew, int tileh, + int width, int height, int depth, + int imageDataType, Object imageData, boolean useAutoMipMap); + + void updateTexture3DSubImage(Context ctx, + int level, + int xoffset, int yoffset, int zoffset, + int textureFormat, int imageFormat, + int imgXoffset, int imgYoffset, int imgZoffset, + int tilew, int tileh, + int width, int height, int depth, + int imageDataType, Object imageData, boolean useAutoMipMap) { + updateTexture3DSubImage(unbox(ctx), + level, + xoffset, yoffset, zoffset, + textureFormat, imageFormat, + imgXoffset, imgYoffset, imgZoffset, + tilew, tileh, + width, height, depth, + imageDataType, imageData, useAutoMipMap); + } + + native void updateTexture3DLodRange(long ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod); + + void updateTexture3DLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + updateTexture3DLodRange(unbox(ctx), + baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + native void updateTexture3DLodOffset(long ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ); + + void updateTexture3DLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + updateTexture3DLodOffset(unbox(ctx), + lodOffsetX, lodOffsetY, + lodOffsetZ); + } + + native void updateTexture3DBoundary(long ctx, + int boundaryModeS, int boundaryModeT, + int boundaryModeR, float boundaryRed, + float boundaryGreen, float boundaryBlue, + float boundaryAlpha); + + + void updateTexture3DBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + int boundaryModeR, float boundaryRed, + float boundaryGreen, float boundaryBlue, + float boundaryAlpha) { + updateTexture3DBoundary(unbox(ctx), + boundaryModeS, boundaryModeT, + boundaryModeR, boundaryRed, + boundaryGreen, boundaryBlue, + boundaryAlpha); + } + + native void updateTexture3DFilterModes(long ctx, + int minFilter, int magFilter); + + void updateTexture3DFilterModes(Context ctx, + int minFilter, int magFilter) { + updateTexture3DFilterModes(unbox(ctx), + minFilter, magFilter); + } + + native void updateTexture3DSharpenFunc(long ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts); + + void updateTexture3DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + updateTexture3DSharpenFunc(unbox(ctx), + numSharpenTextureFuncPts, + sharpenTextureFuncPts); + } + + native void updateTexture3DFilter4Func(long ctx, + int numFilter4FuncPts, + float[] filter4FuncPts); + + void updateTexture3DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + updateTexture3DFilter4Func(unbox(ctx), + numFilter4FuncPts, + filter4FuncPts); + } + + native void updateTexture3DAnisotropicFilter(long ctx, float degree); + + void updateTexture3DAnisotropicFilter(Context ctx, float degree) { + updateTexture3DAnisotropicFilter(unbox(ctx), degree); + } + + + // --------------------------------------------------------------------- + + // + // TextureCubeMapRetained methods + // + + native void bindTextureCubeMap(long ctx, int objectId, boolean enable); + + void bindTextureCubeMap(Context ctx, int objectId, boolean enable) { + bindTextureCubeMap(unbox(ctx), objectId, enable); + } + + native void updateTextureCubeMapImage(long ctx, + int face, int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int imageDataType, Object imageData, boolean useAutoMipMap); + + void updateTextureCubeMapImage(Context ctx, + int face, int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int imageDataType, Object imageData, boolean useAutoMipMap) { + updateTextureCubeMapImage(unbox(ctx), + face, numLevels, level, + textureFormat, imageFormat, + width, height, + boundaryWidth, + imageDataType, imageData, useAutoMipMap); + } + + native void updateTextureCubeMapSubImage(long ctx, + int face, int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int imageDataType, Object imageData, boolean useAutoMipMap); + + void updateTextureCubeMapSubImage(Context ctx, + int face, int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int imageDataType, Object imageData, boolean useAutoMipMap) { + updateTextureCubeMapSubImage(unbox(ctx), + face, level, xoffset, yoffset, + textureFormat, imageFormat, + imgXOffset, imgYOffset, + tilew, width, height, + imageDataType, imageData, useAutoMipMap); + } + + native void updateTextureCubeMapLodRange(long ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod); + + void updateTextureCubeMapLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + updateTextureCubeMapLodRange(unbox(ctx), + baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + native void updateTextureCubeMapLodOffset(long ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ); + + void updateTextureCubeMapLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + updateTextureCubeMapLodOffset(unbox(ctx), + lodOffsetX, lodOffsetY, + lodOffsetZ); + } + + native void updateTextureCubeMapBoundary(long ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha); + + void updateTextureCubeMapBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + updateTextureCubeMapBoundary(unbox(ctx), + boundaryModeS, boundaryModeT, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + native void updateTextureCubeMapFilterModes(long ctx, + int minFilter, int magFilter); + + void updateTextureCubeMapFilterModes(Context ctx, + int minFilter, int magFilter) { + updateTextureCubeMapFilterModes(unbox(ctx), + minFilter, magFilter); + } + + native void updateTextureCubeMapSharpenFunc(long ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts); + + void updateTextureCubeMapSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + updateTextureCubeMapSharpenFunc(unbox(ctx), + numSharpenTextureFuncPts, + sharpenTextureFuncPts); + } + + native void updateTextureCubeMapFilter4Func(long ctx, + int numFilter4FuncPts, + float[] filter4FuncPts); + + void updateTextureCubeMapFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + updateTextureCubeMapFilter4Func(unbox(ctx), + numFilter4FuncPts, + filter4FuncPts); + } + + native void updateTextureCubeMapAnisotropicFilter(long ctx, float degree); + + void updateTextureCubeMapAnisotropicFilter(Context ctx, float degree) { + updateTextureCubeMapAnisotropicFilter(unbox(ctx), degree); + } + + // --------------------------------------------------------------------- + + // + // MasterControl methods + // + + // Method to return the AWT object + native long getAWT(); + + // Method to initialize the native J3D library + native boolean initializeJ3D(boolean disableXinerama); + + // Maximum lights supported by the native API + native int getMaximumLights(); + + + // --------------------------------------------------------------------- + + // + // Canvas3D methods + // + + // This is the native method for creating the underlying graphics context. + native long createNewContext(Canvas3D cv, long display, long drawable, + long fbConfig, long shareCtx, boolean isSharedCtx, + boolean offScreen, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable); + + // This is the native method for creating the underlying graphics context. + Context createNewContext(Canvas3D cv, long display, Drawable drawable, + long fbConfig, Context shareCtx, boolean isSharedCtx, + boolean offScreen, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + + long nativeCtx = createNewContext(cv, display, unbox(drawable), + fbConfig, unbox(shareCtx), isSharedCtx, + offScreen, + glslLibraryAvailable, + cgLibraryAvailable); + + return boxContext(nativeCtx); + } + + native void createQueryContext(Canvas3D cv, long display, long drawable, + long fbConfig, boolean offScreen, int width, int height, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable); + + void createQueryContext(Canvas3D cv, long display, Drawable drawable, + long fbConfig, boolean offScreen, int width, int height, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + + createQueryContext(cv, display, unbox(drawable), + fbConfig, offScreen, width, height, + glslLibraryAvailable, + cgLibraryAvailable); + } + + // This is the native for creating offscreen buffer + native long createOffScreenBuffer(Canvas3D cv, long ctx, long display, long fbConfig, int width, int height); + + Drawable createOffScreenBuffer(Canvas3D cv, Context ctx, long display, long fbConfig, int width, int height) { + long nativeDrawable = createOffScreenBuffer(cv, unbox(ctx), display, fbConfig, width, height); + return boxDrawable(nativeDrawable); + } + + native void destroyOffScreenBuffer(Canvas3D cv, long ctx, long display, long fbConfig, long drawable); + + void destroyOffScreenBuffer(Canvas3D cv, Context ctx, long display, long fbConfig, Drawable drawable) { + destroyOffScreenBuffer(cv, unbox(ctx), display, fbConfig, unbox(drawable)); + } + + // This is the native for reading the image from the offscreen buffer + native void readOffScreenBuffer(Canvas3D cv, long ctx, int format, int type, Object data, int width, int height); + + void readOffScreenBuffer(Canvas3D cv, Context ctx, int format, int type, Object data, int width, int height) { + readOffScreenBuffer(cv, unbox(ctx), format, type, data, width, height); + } + + // The native method for swapBuffers + native int swapBuffers(Canvas3D cv, long ctx, long dpy, long drawable); + + int swapBuffers(Canvas3D cv, Context ctx, long dpy, Drawable drawable) { + return swapBuffers(cv, unbox(ctx), dpy, unbox(drawable)); + } + + + // notify D3D that Canvas is resize + native int resizeD3DCanvas(Canvas3D cv, long ctx); + + int resizeD3DCanvas(Canvas3D cv, Context ctx) { + return resizeD3DCanvas(cv, unbox(ctx)); + } + + + // notify D3D to toggle between FullScreen and window mode + native int toggleFullScreenMode(Canvas3D cv, long ctx); + + int toggleFullScreenMode(Canvas3D cv, Context ctx) { + return toggleFullScreenMode(cv, unbox(ctx)); + } + + + // native method for setting Material when no material is present + native void updateMaterialColor(long ctx, float r, float g, float b, float a); + + void updateMaterialColor(Context ctx, float r, float g, float b, float a) { + updateMaterialColor(unbox(ctx), r, g, b, a); + } + + + native void destroyContext(long display, long drawable, long ctx); + + void destroyContext(long display, Drawable drawable, Context ctx) { + assert display != 0 || VirtualUniverse.mc.isWindows(); + assert ctx != null; + assert drawable != null; + destroyContext(display, unbox(drawable), unbox(ctx)); + } + + + // This is the native method for doing accumulation. + native void accum(long ctx, float value); + + void accum(Context ctx, float value) { + accum(unbox(ctx), value); + } + + + // This is the native method for doing accumulation return. + native void accumReturn(long ctx); + + void accumReturn(Context ctx) { + accumReturn(unbox(ctx)); + } + + + // This is the native method for clearing the accumulation buffer. + native void clearAccum(long ctx); + + void clearAccum(Context ctx) { + clearAccum(unbox(ctx)); + } + + + // This is the native method for getting the number of lights the underlying + // native library can support. + native int getNumCtxLights(long ctx); + + int getNumCtxLights(Context ctx) { + return getNumCtxLights(unbox(ctx)); + } + + + // Native method for decal 1st child setup + native boolean decal1stChildSetup(long ctx); + + boolean decal1stChildSetup(Context ctx) { + return decal1stChildSetup(unbox(ctx)); + } + + + // Native method for decal nth child setup + native void decalNthChildSetup(long ctx); + + void decalNthChildSetup(Context ctx) { + decalNthChildSetup(unbox(ctx)); + } + + + // Native method for decal reset + native void decalReset(long ctx, boolean depthBufferEnable); + + void decalReset(Context ctx, boolean depthBufferEnable) { + decalReset(unbox(ctx), depthBufferEnable); + } + + + // Native method for decal reset + native void ctxUpdateEyeLightingEnable(long ctx, boolean localEyeLightingEnable); + + void ctxUpdateEyeLightingEnable(Context ctx, boolean localEyeLightingEnable) { + ctxUpdateEyeLightingEnable(unbox(ctx), localEyeLightingEnable); + } + + + // The following three methods are used in multi-pass case + + // native method for setting blend color + native void setBlendColor(long ctx, float red, float green, + float blue, float alpha); + + void setBlendColor(Context ctx, float red, float green, + float blue, float alpha) { + setBlendColor(unbox(ctx), red, green, + blue, alpha); + } + + + // native method for setting blend func + native void setBlendFunc(long ctx, int src, int dst); + + void setBlendFunc(Context ctx, int src, int dst) { + setBlendFunc(unbox(ctx), src, dst); + } + + + // native method for setting fog enable flag + native void setFogEnableFlag(long ctx, boolean enableFlag); + + void setFogEnableFlag(Context ctx, boolean enableFlag) { + setFogEnableFlag(unbox(ctx), enableFlag); + } + + + // Setup the full scene antialising in D3D and ogl when GL_ARB_multisamle supported + native void setFullSceneAntialiasing(long ctx, boolean enable); + + void setFullSceneAntialiasing(Context ctx, boolean enable) { + setFullSceneAntialiasing(unbox(ctx), enable); + } + + + native void setGlobalAlpha(long ctx, float alpha); + + void setGlobalAlpha(Context ctx, float alpha) { + setGlobalAlpha(unbox(ctx), alpha); + } + + + // Native method to update separate specular color control + native void updateSeparateSpecularColorEnable(long ctx, boolean control); + + void updateSeparateSpecularColorEnable(Context ctx, boolean control) { + updateSeparateSpecularColorEnable(unbox(ctx), control); + } + + + // Initialization for D3D when scene begin + native void beginScene(long ctx); + + void beginScene(Context ctx) { + beginScene(unbox(ctx)); + } + + native void endScene(long ctx); + + void endScene(Context ctx) { + endScene(unbox(ctx)); + } + + + // True under Solaris, + // False under windows when display mode <= 8 bit + native boolean validGraphicsMode(); + + // native method for setting light enables + native void setLightEnables(long ctx, long enableMask, int maxLights); + + void setLightEnables(Context ctx, long enableMask, int maxLights) { + setLightEnables(unbox(ctx), enableMask, maxLights); + } + + + // native method for setting scene ambient + native void setSceneAmbient(long ctx, float red, float green, float blue); + + void setSceneAmbient(Context ctx, float red, float green, float blue) { + setSceneAmbient(unbox(ctx), red, green, blue); + } + + + // native method for disabling fog + native void disableFog(long ctx); + + void disableFog(Context ctx) { + disableFog(unbox(ctx)); + } + + + // native method for disabling modelClip + native void disableModelClip(long ctx); + + void disableModelClip(Context ctx) { + disableModelClip(unbox(ctx)); + } + + + // native method for setting default RenderingAttributes + native void resetRenderingAttributes(long ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride); + + void resetRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride) { + resetRenderingAttributes(unbox(ctx), + depthBufferWriteEnableOverride, + depthBufferEnableOverride); + } + + + // native method for setting default texture + native void resetTextureNative(long ctx, int texUnitIndex); + + void resetTextureNative(Context ctx, int texUnitIndex) { + resetTextureNative(unbox(ctx), texUnitIndex); + } + + + // native method for activating a particular texture unit + native void activeTextureUnit(long ctx, int texUnitIndex); + + void activeTextureUnit(Context ctx, int texUnitIndex) { + activeTextureUnit(unbox(ctx), texUnitIndex); + } + + + // native method for setting default TexCoordGeneration + native void resetTexCoordGeneration(long ctx); + + void resetTexCoordGeneration(Context ctx) { + resetTexCoordGeneration(unbox(ctx)); + } + + + // native method for setting default TextureAttributes + native void resetTextureAttributes(long ctx); + + void resetTextureAttributes(Context ctx) { + resetTextureAttributes(unbox(ctx)); + } + + + // native method for setting default PolygonAttributes + native void resetPolygonAttributes(long ctx); + + void resetPolygonAttributes(Context ctx) { + resetPolygonAttributes(unbox(ctx)); + } + + + // native method for setting default LineAttributes + native void resetLineAttributes(long ctx); + + void resetLineAttributes(Context ctx) { + resetLineAttributes(unbox(ctx)); + } + + + // native method for setting default PointAttributes + native void resetPointAttributes(long ctx); + + void resetPointAttributes(Context ctx) { + resetPointAttributes(unbox(ctx)); + } + + + // native method for setting default TransparencyAttributes + native void resetTransparency(long ctx, int geometryType, + int polygonMode, boolean lineAA, + boolean pointAA); + + void resetTransparency(Context ctx, int geometryType, + int polygonMode, boolean lineAA, + boolean pointAA) { + resetTransparency(unbox(ctx), geometryType, + polygonMode, lineAA, + pointAA); + } + + + // native method for setting default ColoringAttributes + native void resetColoringAttributes(long ctx, + float r, float g, + float b, float a, + boolean enableLight); + + void resetColoringAttributes(Context ctx, + float r, float g, + float b, float a, + boolean enableLight) { + resetColoringAttributes(unbox(ctx), + r, g, + b, a, + enableLight); + } + + /** + * This native method makes sure that the rendering for this canvas + * gets done now. + */ + native void syncRender(long ctx, boolean wait); + + void syncRender(Context ctx, boolean wait) { + syncRender(unbox(ctx), wait); + } + + + // The native method that sets this ctx to be the current one + native boolean useCtx(long ctx, long display, long drawable); + + boolean useCtx(Context ctx, long display, Drawable drawable) { + assert display != 0 || VirtualUniverse.mc.isWindows(); + return useCtx(unbox(ctx), display, unbox(drawable)); + } + + native void clear(long ctx, float r, float g, float b, boolean clearStencil); + + void clear(Context ctx, float r, float g, float b, boolean clearStencil) { + clear(unbox(ctx), r, g, b, clearStencil); + + } + + native void textureFillBackground(long ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, boolean useBiliearFilter); + + void textureFillBackground(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, boolean useBiliearFilter) { + textureFillBackground(unbox(ctx), texMinU, texMaxU, texMinV, texMaxV, + mapMinX, mapMaxX, mapMinY, mapMaxY, useBiliearFilter); + } + + native void textureFillRaster(long ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, float mapZ, float alpha, + boolean useBiliearFilter); + + void textureFillRaster(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, float mapZ, float alpha, + boolean useBiliearFilter) { + textureFillRaster(unbox(ctx), texMinU, texMaxU, texMinV, texMaxV, + mapMinX, mapMaxX, mapMinY, mapMaxY, mapZ, alpha, useBiliearFilter); + } + + native void executeRasterDepth(long ctx, float posX, float posY, float posZ, + int srcOffsetX, int srcOffsetY, int rasterWidth, int rasterHeight, + int depthWidth, int depthHeight, int depthType, Object depthData); + + void executeRasterDepth(Context ctx, float posX, float posY, float posZ, + int srcOffsetX, int srcOffsetY, int rasterWidth, int rasterHeight, + int depthWidth, int depthHeight, int depthType, Object depthData) { + executeRasterDepth(unbox(ctx), posX, posY, posZ, srcOffsetX, srcOffsetY, + rasterWidth, rasterHeight, depthWidth, depthHeight, depthType, depthData); + } + + // The native method for setting the ModelView matrix. + native void setModelViewMatrix(long ctx, double[] viewMatrix, double[] modelMatrix); + + void setModelViewMatrix(Context ctx, double[] viewMatrix, double[] modelMatrix) { + setModelViewMatrix(unbox(ctx), viewMatrix, modelMatrix); + } + + + // The native method for setting the Projection matrix. + native void setProjectionMatrix(long ctx, double[] projMatrix); + + void setProjectionMatrix(Context ctx, double[] projMatrix) { + setProjectionMatrix(unbox(ctx), projMatrix); + } + + + // The native method for setting the Viewport. + native void setViewport(long ctx, int x, int y, int width, int height); + + void setViewport(Context ctx, int x, int y, int width, int height) { + setViewport(unbox(ctx), x, y, width, height); + } + + + // used for display Lists + native void newDisplayList(long ctx, int displayListId); + + void newDisplayList(Context ctx, int displayListId) { + newDisplayList(unbox(ctx), displayListId); + } + + native void endDisplayList(long ctx); + + void endDisplayList(Context ctx) { + endDisplayList(unbox(ctx)); + } + + native void callDisplayList(long ctx, int id, boolean isNonUniformScale); + + void callDisplayList(Context ctx, int id, boolean isNonUniformScale) { + callDisplayList(unbox(ctx), id, isNonUniformScale); + } + + + native void freeDisplayList(long ctx, int id); + + void freeDisplayList(Context ctx, int id) { + freeDisplayList(unbox(ctx), id); + } + + native void freeTexture(long ctx, int id); + + void freeTexture(Context ctx, int id) { + freeTexture(unbox(ctx), id); + } + + native void texturemapping(long ctx, + int px, int py, + int xmin, int ymin, int xmax, int ymax, + int texWidth, int texHeight, + int rasWidth, + int format, int objectId, + byte[] image, + int winWidth, int winHeight); + + void texturemapping(Context ctx, + int px, int py, + int xmin, int ymin, int xmax, int ymax, + int texWidth, int texHeight, + int rasWidth, + int format, int objectId, + byte[] image, + int winWidth, int winHeight) { + texturemapping(unbox(ctx), + px, py, + xmin, ymin, xmax, ymax, + texWidth, texHeight, + rasWidth, + format, objectId, + image, + winWidth, winHeight); + } + + + native boolean initTexturemapping(long ctx, int texWidth, + int texHeight, int objectId); + + boolean initTexturemapping(Context ctx, int texWidth, + int texHeight, int objectId) { + return initTexturemapping(unbox(ctx), texWidth, + texHeight, objectId); + } + + + + // Set internal render mode to one of FIELD_ALL, FIELD_LEFT or + // FIELD_RIGHT. Note that it is up to the caller to ensure that + // stereo is available before setting the mode to FIELD_LEFT or + // FIELD_RIGHT. The boolean isTRUE for double buffered mode, FALSE + // foe single buffering. + native void setRenderMode(long ctx, int mode, boolean doubleBuffer); + + void setRenderMode(Context ctx, int mode, boolean doubleBuffer) { + setRenderMode(unbox(ctx), mode, doubleBuffer); + } + + + // Set glDepthMask. + native void setDepthBufferWriteEnable(long ctx, boolean mode); + + void setDepthBufferWriteEnable(Context ctx, boolean mode) { + setDepthBufferWriteEnable(unbox(ctx), mode); + } + + + + // --------------------------------------------------------------------- + + // + // Canvas3D / GraphicsConfigTemplate3D methods - logic dealing with + // native graphics configuration or drawing surface + // + + // Return a graphics config based on the one passed in. Note that we can + // assert that the input config is non-null and was created from a + // GraphicsConfigTemplate3D. + // This method must return a valid GraphicsConfig, or else it must throw + // an exception if one cannot be returned. + GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) { +//KCR: System.err.println("NativePipeline.getGraphicsConfig()"); + + // Just return the input graphics config + return gconfig; + } + + // Get the native FBconfig pointer + long getFbConfig(GraphicsConfigInfo gcInfo) { + long fbConfig = ((Long)gcInfo.getPrivateData()).longValue(); + if (fbConfig == 0L) { + throw new IllegalArgumentException(J3dI18N.getString("Canvas3D23")); + } + + return fbConfig; + } + + // Get best graphics config from pipeline + GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate3D gct, + GraphicsConfiguration[] gc) { + return NativeConfigTemplate3D.getNativeConfigTemplate3D().getBestConfiguration(gct, gc); + } + + // Determine whether specified graphics config is supported by pipeline + boolean isGraphicsConfigSupported(GraphicsConfigTemplate3D gct, + GraphicsConfiguration gc) { + return NativeConfigTemplate3D.getNativeConfigTemplate3D().isGraphicsConfigSupported(gct, gc); + } + + // Methods to get actual capabilities from Canvas3D + boolean hasDoubleBuffer(Canvas3D cv) { + return NativeConfigTemplate3D.getNativeConfigTemplate3D().hasDoubleBuffer(cv); + } + + boolean hasStereo(Canvas3D cv) { + return NativeConfigTemplate3D.getNativeConfigTemplate3D().hasStereo(cv); + } + + int getStencilSize(Canvas3D cv) { + return NativeConfigTemplate3D.getNativeConfigTemplate3D().getStencilSize(cv); + } + + boolean hasSceneAntialiasingMultisample(Canvas3D cv) { + return NativeConfigTemplate3D.getNativeConfigTemplate3D().hasSceneAntialiasingMultisample(cv); + } + + boolean hasSceneAntialiasingAccum(Canvas3D cv) { + return NativeConfigTemplate3D.getNativeConfigTemplate3D().hasSceneAntialiasingAccum(cv); + } + + // Methods to get native WS display and screen + long getDisplay() { + return NativeScreenInfo.getNativeScreenInfo().getDisplay(); + } + int getScreen(GraphicsDevice graphicsDevice) { + return NativeScreenInfo.getNativeScreenInfo().getScreen(graphicsDevice); + } + + // --------------------------------------------------------------------- + + // + // DrawingSurfaceObject methods + // + + // Method to construct a new DrawingSurfaceObject + DrawingSurfaceObject createDrawingSurfaceObject(Canvas3D cv) { + return new DrawingSurfaceObjectAWT(cv, + VirtualUniverse.mc.awt, cv.screen.display, cv.screen.screen, + VirtualUniverse.mc.xineramaDisabled); + } + + + // Method to free the drawing surface object + // (called from Canvas3D.removeNotify) + void freeDrawingSurface(Canvas3D cv, DrawingSurfaceObject drawingSurfaceObject) { + synchronized (drawingSurfaceObject) { + DrawingSurfaceObjectAWT dso = + (DrawingSurfaceObjectAWT)drawingSurfaceObject; + // get nativeDS before it is set to 0 in invalidate() + long ds = dso.getDS(); + long ds_struct[] = {ds, dso.getDSI()}; + if (ds != 0) { + VirtualUniverse.mc.postRequest( + MasterControl.FREE_DRAWING_SURFACE, + ds_struct); + } + + drawingSurfaceObject.invalidate(); + } + } + + // Method to free the native drawing surface object + void freeDrawingSurfaceNative(Object o) { + DrawingSurfaceObjectAWT.freeDrawingSurface(o); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NativeScreenInfo.java b/j3d-core/src/classes/share/javax/media/j3d/NativeScreenInfo.java new file mode 100644 index 0000000..9f25a8d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NativeScreenInfo.java @@ -0,0 +1,88 @@ +/* + * $RCSfile: NativeScreenInfo.java,v $ + * + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.2 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsDevice; + +/** + * Native screen info class. A singleton instance of the appropriate + * concrete subclass is created by a factory method using reflection. + */ +abstract class NativeScreenInfo { + private static final String x11ClassName = "javax.media.j3d.X11NativeScreenInfo"; + private static final String win32ClassName = "javax.media.j3d.Win32NativeScreenInfo"; + + // The singleton instance of this class + private static NativeScreenInfo nativeScreenInfo = null; + + protected NativeScreenInfo() { + } + + // This method is called exactly once by the initialization method of + // the NativePipeline class + synchronized static void createNativeScreenInfo() { + String className; + if (MasterControl.isWindows()) { + className = win32ClassName; + } else { + className = x11ClassName; + } + + final String scrInfoClassName = className; + nativeScreenInfo = (NativeScreenInfo) + java.security.AccessController.doPrivileged(new + java.security.PrivilegedAction() { + public Object run() { + try { + Class scrInfoClass = Class.forName(scrInfoClassName); + return scrInfoClass.newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + static NativeScreenInfo getNativeScreenInfo() { + return nativeScreenInfo; + } + + /** + * Get the display handle + */ + abstract long getDisplay(); + + /** + * Get the screen number for the given graphics device + */ + abstract int getScreen(GraphicsDevice graphicsDevice); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NativeShaderObject.java b/j3d-core/src/classes/share/javax/media/j3d/NativeShaderObject.java new file mode 100644 index 0000000..ba7de3e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NativeShaderObject.java @@ -0,0 +1,50 @@ +/* + * $RCSfile: NativeShaderObject.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Shader objects for native rendering pipeline. + */ +class NativeShaderObject implements ShaderProgramId, ShaderId, ShaderAttrLoc { + + // Native shader object; + private long nativeId; + + NativeShaderObject(long nativeId) { + this.nativeId = nativeId; + } + + long getNativeId() { + return nativeId; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NioImageBuffer.java b/j3d-core/src/classes/share/javax/media/j3d/NioImageBuffer.java new file mode 100644 index 0000000..4d4e5ef --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NioImageBuffer.java @@ -0,0 +1,398 @@ +/* + * $RCSfile: NioImageBuffer.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; + +/** + * The NioImageBuffer class is a container for an image whose DataBuffer + * is specified via a java.nio.Buffer. An an NioImageBuffer can be wrapped by + * an ImageComponent and used for texture mapping, or for rendering Raster + * objects or background images. An NioImageBuffer must not be used as the + * buffer of an off-screen Canvas3D, or for reading back a raster image. + * + * @see ImageComponent2D + * @see ImageComponent3D + * + * @since Java 3D 1.5 + */ +public class NioImageBuffer { + + /** + * Used to specify the type of the image. + */ + public enum ImageType { + /** + * Represents an image with 8-bit RGB color components, + * corresponding to a Windows-style BGR color model, with the + * colors Blue, Green, and Red stored in 3 consecutive + * bytes for each pixel. + * The data buffer must be a ByteBuffer when using this imageType. + */ + TYPE_3BYTE_BGR, + + /** + * Represents an image with 8-bit RGB color components with + * Red, Green, and Blue, stored in 3 consecutive + * bytes for each pixel. + * The data buffer must be a ByteBuffer when using this imageType. + */ + TYPE_3BYTE_RGB, + + /** + * Represents an image with 8-bit RGBA color components with + * Alpha, Blue, Green, and Red stored in 4 consecutive + * bytes for each pixel. + * The data buffer must be a ByteBuffer when using this imageType. + */ + TYPE_4BYTE_ABGR, + + /** + * Represents an image with 8-bit RGBA color components with + * Red, Green, Blue, and Alpha stored in 4 consecutive + * bytes for each pixel. + * The data buffer must be a ByteBuffer when using this imageType. + */ + TYPE_4BYTE_RGBA, + + /** + * Represents a unsigned byte grayscale image, non-indexed. + * The data buffer must be a ByteBuffer when using this imageType. + */ + TYPE_BYTE_GRAY, + + /** + * Represents an image with 8-bit RGBA color components packed + * into integer pixels. + * The data buffer must be an IntBuffer when using this imageType. + */ + TYPE_INT_ARGB, + + /** + * Represents an image with 8-bit RGB color components, + * corresponding to a Windows- or Solaris- style BGR color model, + * with the colors Blue, Green, and Red packed into integer + * pixels. + * The data buffer must be an IntBuffer when using this imageType. + */ + TYPE_INT_BGR, + + /** + * Represents an image with 8-bit RGB color components packed into + * integer pixels. + * The data buffer must be an IntBuffer when using this imageType. + */ + TYPE_INT_RGB, + + } + + + /** + * Enum for type of buffer + */ + enum BufferType { + BYTE_BUFFER, + INT_BUFFER, + } + + + // Width and height of image + int width; + int height; + + // TYpe of image + ImageType imageType; + + // Cached buffer + Buffer buffer; + + // Type of NIO Buffer: byte or int + BufferType bufferType; + + // Number of bytes allocated per pixel + int bytesPerPixel; + + // Number of byte or int elements per pixel + int elementsPerPixel; + + /** + * Constructs an NIO image buffer of the specified size and type. + * A direct NIO buffer of the correct type (ByteBuffer or IntBuffer) + * and size to match the input parameters + * is allocated. + * + * @param width width of the image + * @param height height of the image + * @param imageType type of the image. + * + * @exception IllegalArgumentException if width < 1 or height < 1 + * @exception NullPointerException if imageType is null + */ + public NioImageBuffer(int width, int height, ImageType imageType) { + + processParams(width, height, imageType); + + ByteBuffer tmpBuffer = ByteBuffer.allocateDirect(width * height * bytesPerPixel); + switch (bufferType) { + case BYTE_BUFFER: + buffer = tmpBuffer; + break; + + case INT_BUFFER: + buffer = tmpBuffer.order(ByteOrder.nativeOrder()).asIntBuffer(); + break; + + default: + // We should never get here + throw new AssertionError("missing case statement"); + } + } + + /** + * Constructs an NIO image buffer of the specified size and type, using + * the specified dataBuffer. + * The the byte order of the specified dataBuffer must match the native + * byte order of the underlying platform. + * For best performance, the NIO buffer should be a direct buffer. + * + * @param width width of the image + * @param height height of the image + * @param imageType type of the image. + * @param dataBuffer an NIO buffer of the correct type (ByteBuffer or + * IntBuffer) to match the specified imageType. + * This constructor will create a new view of + * the buffer, and will call rewind on that view, + * such that elements 0 through dataBuffer.limit()-1 + * will be available internally. The number of elements in + * the buffer must be exactly width*height*numElementsPerPixel, + * where numElementsPerPixel is + * 3 for TYPE_3BYTE_BGR and TYPE_3BYTE_RGB, + * 4 for TYPE_4BYTE_ABGR and TYPE_4BYTE_RGBA, + * and 1 for all other types. + * + * @exception IllegalArgumentException if width < 1 or height < 1 + * @exception NullPointerException if imageType or dataBuffer is null + * @exception IllegalArgumentException if the type of the dataBuffer does + * not match the imageType + * @exception IllegalArgumentException if dataBuffer.limit() != + * width*height*numElementsPerPixel + * @exception IllegalArgumentException if the byte order of the specified + * dataBuffer does not match the native byte order of the underlying + * platform. + */ + public NioImageBuffer(int width, int height, ImageType imageType, + Buffer dataBuffer) { + + processParams(width, height, imageType); + setDataBuffer(dataBuffer); + } + + /** + * Gets the width of this data buffer. + * + * @return the width of this data buffer. + */ + public int getWidth() { + return width; + } + + /** + * Gets the height of this data buffer. + * + * @return the width of this data buffer. + */ + public int getHeight() { + return height; + } + + /** + * Gets the image type of this data buffer. + * + * @return the image type of this data buffer. + */ + public ImageType getImageType() { + return imageType; + } + + /** + * Sets the data buffer to the specified input data buffer. + * The the byte order of the specified dataBuffer must match the native + * byte order of the underlying platform. + * For best performance, the NIO buffer should be a direct buffer. + * + * @param dataBuffer an NIO buffer of the correct type (ByteBuffer or + * IntBuffer) to match the imageType of this + * NioImageBuffer. This method will create a new view of + * the buffer, and will call rewind on that view, + * such that elements 0 through dataBuffer.limit()-1 + * will be available internally. The number of elements in + * the buffer must be exactly width*height*numElementsPerPixel, + * where numElementsPerPixel is + * 3 for TYPE_3BYTE_BGR and TYPE_3BYTE_RGB, + * 4 for TYPE_4BYTE_ABGR and TYPE_4BYTE_RGBA, + * and 1 for all other types. + * + * @exception NullPointerException if dataBuffer is null + * @exception IllegalArgumentException if the type of the dataBuffer does + * not match the imageType + * @exception IllegalArgumentException if dataBuffer.limit() != + * width*height*numElementsPerPixel + * @exception IllegalArgumentException if the byte order of the specified + * dataBuffer does not match the native byte order of the underlying + * platform. + */ + public void setDataBuffer(Buffer dataBuffer) { + if (dataBuffer == null) { + throw new NullPointerException(); + } + + if (dataBuffer.limit() != width*height*elementsPerPixel) { + throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer3")); + } + + switch (bufferType) { + case BYTE_BUFFER: + if (!(dataBuffer instanceof ByteBuffer)) { + throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer4")); + } + buffer = ((ByteBuffer)dataBuffer).duplicate().rewind(); + break; + + case INT_BUFFER: + if (!(dataBuffer instanceof IntBuffer)) { + throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer4")); + } + + if (((IntBuffer)dataBuffer).order() != ByteOrder.nativeOrder()) { + throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer5")); + } + buffer = ((IntBuffer)dataBuffer).duplicate().rewind(); + break; + + default: + // We should never get here + throw new AssertionError("missing case statement"); + } + } + + /** + * Gets the data buffer to the specified input data buffer. + * + * @return a view of the current data buffer for this NIO image buffer. + * This view will be rewound such that elements 0 + * through dataBuffer.limit()-1 are available. + */ + public Buffer getDataBuffer() { + Buffer tmpBuffer = null; + + switch (bufferType) { + case BYTE_BUFFER: + tmpBuffer = ((ByteBuffer)buffer).duplicate(); + break; + + case INT_BUFFER: + tmpBuffer = ((IntBuffer)buffer).duplicate(); + break; + + default: + // We should never get here + throw new AssertionError("missing case statement"); + } + + return tmpBuffer.rewind(); + } + + + // Sanity check the input parameters, calculate the buffer type and + // the number of bytes per pixel + private void processParams(int width, int height, ImageType imageType) { + if (width < 1) { + throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer0")); + } + + if (height < 1) { + throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer1")); + } + + switch (imageType) { + case TYPE_3BYTE_BGR: + bufferType = BufferType.BYTE_BUFFER; + bytesPerPixel = 3; + elementsPerPixel = 3; + break; + + case TYPE_3BYTE_RGB: + bufferType = BufferType.BYTE_BUFFER; + bytesPerPixel = 3; + elementsPerPixel = 3; + break; + + case TYPE_4BYTE_ABGR: + bufferType = BufferType.BYTE_BUFFER; + bytesPerPixel = 4; + elementsPerPixel = 4; + break; + + case TYPE_4BYTE_RGBA: + bufferType = BufferType.BYTE_BUFFER; + bytesPerPixel = 4; + elementsPerPixel = 4; + break; + + case TYPE_BYTE_GRAY: + bufferType = BufferType.BYTE_BUFFER; + bytesPerPixel = 1; + elementsPerPixel = 1; + break; + + case TYPE_INT_ARGB: + case TYPE_INT_BGR: + case TYPE_INT_RGB: + bufferType = BufferType.INT_BUFFER; + bytesPerPixel = 4; + elementsPerPixel = 1; + break; + + default: + // We should never get here + throw new AssertionError("missing case statement"); + } + + this.width = width; + this.height = height; + this.imageType = imageType; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NnuId.java b/j3d-core/src/classes/share/javax/media/j3d/NnuId.java new file mode 100644 index 0000000..7321a41 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NnuId.java @@ -0,0 +1,44 @@ +/* + * $RCSfile: NnuId.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Defines a "not necessarily unique ID" + */ + +interface NnuId { + + abstract int equal(NnuId obj); + + abstract int getId(); + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NnuIdManager.java b/j3d-core/src/classes/share/javax/media/j3d/NnuIdManager.java new file mode 100644 index 0000000..40211b0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NnuIdManager.java @@ -0,0 +1,352 @@ +/* + * $RCSfile: NnuIdManager.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class NnuIdManager { + static int nnuId = 0; + + final static int getId() { + if(nnuId == Integer.MAX_VALUE) { + nnuId = 0; + } + + return nnuId++; + } + + final static int equals(NnuId nnuIdArr[], NnuId key, int start, int end) { + int mid; + + mid = start +((end - start)/ 2); + if(nnuIdArr[mid] != null) { + int test = key.equal(nnuIdArr[mid]); + + if((test < 0) && (start != mid)) + return equals(nnuIdArr, key, start, mid); + else if((test > 0) && (start != mid)) + return equals(nnuIdArr, key, mid, end); + else if(test == 0) { + // Since id is not necessary unique, we've to do + // some extra check. + + // check for equal reference. + if(key == nnuIdArr[mid]) { + return mid; + } + + int temp = mid - 1; + // Look to the left. + while((temp >= start) && (key.equal(nnuIdArr[temp]) == 0)) { + if(key == nnuIdArr[temp]) { + return temp; + } + temp--; + } + + // Look to the right. + temp = mid + 1; + while((temp < end) && (key.equal(nnuIdArr[temp]) == 0)) { + if(key == nnuIdArr[temp]) { + return temp; + } + temp++; + } + + // Fail equal reference check. + return -1; + } + else + return -1; + } + // A null NnuId object encountered. + return -2; + } + + final static boolean equals(NnuId nnuIdArr[], NnuId key, int[] index, + int start, int end) { + + int mid; + + mid = start +((end - start)/ 2); + + if(nnuIdArr[mid] != null) { + int test = key.equal(nnuIdArr[mid]); + + if(start != mid) { + if(test < 0) { + return equals(nnuIdArr, key, index, start, mid); + } + else if(test > 0) { + return equals(nnuIdArr, key, index, mid, end); + } + } + else { // (start == mid) + if(test < 0) { + index[0] = mid; + return false; + } + else if(test > 0) { + index[0] = mid+1; + return false; + } + } + + // (test == 0) + // Since id is not necessary unique, we've to do + // some extra check. + + // check for equal reference. + if(key == nnuIdArr[mid]) { + index[0] = mid; + return true; + } + + int temp = mid - 1; + // Look to the left. + while((temp >= start) && (key.equal(nnuIdArr[temp]) == 0)) { + if(key == nnuIdArr[temp]) { + index[0] = temp; + return true; + } + temp--; + } + + // Look to the right. + temp = mid + 1; + while((temp < end) && (key.equal(nnuIdArr[temp]) == 0)) { + if(key == nnuIdArr[temp]) { + index[0] = temp; + return true; + } + temp++; + } + + // Fail equal reference check. + index[0] = temp; + return false; + + } + // A null entry encountered. + // But we still want to return the index where we encounter it. + index[0] = mid; + return false; + } + + final static void sort(NnuId nnuIdArr[]) { + if (nnuIdArr.length < 20) { + insertSort(nnuIdArr); + } else { + quicksort(nnuIdArr, 0, nnuIdArr.length-1); + } + } + + // Insertion sort on smaller array + final static void insertSort(NnuId nnuIdArr[]) { + + + for (int i=0; i0 && + (nnuIdArr[j-1].getId() > nnuIdArr[j].getId()); j--) { + NnuId temp = nnuIdArr[j]; + nnuIdArr[j] = nnuIdArr[j-1]; + nnuIdArr[j-1] = temp; + } + } + } + + final static void quicksort( NnuId nnuIdArr[], int l, int r ) { + int i = l; + int j = r; + int k = nnuIdArr[(l+r) / 2].getId(); + + do { + while (nnuIdArr[i].getId() < k) i++; + while (k < nnuIdArr[j].getId()) j--; + if (i<=j) { + NnuId tmp = nnuIdArr[i]; + nnuIdArr[i] = nnuIdArr[j]; + nnuIdArr[j] = tmp; + + i++; + j--; + } + } while (i<=j); + + if (l 0) { + NnuId newNnuIdArr[] = new NnuId[size]; + + for(i=0; i= 0) { + found = true; + if(index == curStart) { + curStart++; + } + else { + len = index - curStart; + System.arraycopy(nnuIdArr0, curStart, + newNnuIdArr, newStart, len); + + curStart = index+1; + newStart = newStart + len; + } + } + else { + found = false; + MasterControl.getCoreLogger().severe("Can't Find matching nnuId."); + } + } + + if((found == true) && (curStart < nnuIdArr0.length)) { + len = nnuIdArr0.length - curStart; + System.arraycopy(nnuIdArr0, curStart, newNnuIdArr, newStart, len); + } + + return newNnuIdArr; + } + else if( size == 0) { + // Remove all. + } + else { + // We are in trouble !!! + } + + return null; + + } + + + // This method assumes that nnuIdArr0 and nnuIdArr1 are sorted. + final static NnuId[] merge( NnuId nnuIdArr0[], NnuId nnuIdArr1[] ) { + + int index[] = new int[1]; + int indexPlus1, blkSize, i, j; + + int size = nnuIdArr0.length + nnuIdArr1.length; + + NnuId newNnuIdArr[] = new NnuId[size]; + + // Copy the nnuIdArr0 data into the newly created newNnuIdArr. + System.arraycopy(nnuIdArr0, 0, newNnuIdArr, 0, nnuIdArr0.length); + + for(i=nnuIdArr0.length, j=0; i= 0) { + blkSize = lenLess1 - index[0]; + System.arraycopy(nnuIdArr, index[0]+1, + nnuIdArr, index[0], blkSize); + nnuIdArr[lenLess1] = null; + } + else { + MasterControl.getCoreLogger().severe("Can't Find matching nnuId."); + } + + // insert new to nnuIdArr. + equals(nnuIdArr, newObj, index, 0, lenLess1); + + if(index[0] == lenLess1) { // Append to last. + nnuIdArr[index[0]] = newObj; + } + else { // Insert in between array elements. + blkSize = lenLess1 - index[0]; + + // Shift the later portion of array elements by one position. + // This is the make room for the new data entry. + System.arraycopy(nnuIdArr, index[0], nnuIdArr, + index[0]+1, blkSize); + + nnuIdArr[index[0]] = newObj; + } + + + } + + + final static void printIds(NnuId nnuIdArr[]) { + for(int i=0; i + * For more information, see the + * Introduction to the Java 3D API. + * + *

+ * NOTE: Applications should not extend this class directly. + */ +public abstract class Node extends SceneGraphObject { + + /** + * Specifies that this Node will be reported in the pick + * SceneGraphPath if a pick occurs. This capability is only + * specifiable for Group nodes; it is ignored for leaf nodes. + * The default for Group nodes is false. All interior nodes not + * needed for uniqueness in a SceneGraphPath that don't have + * ENABLE_PICK_REPORTING set to true will not be reported in the + * SceneGraphPath. + * @see SceneGraphPath + */ + public static final int + ENABLE_PICK_REPORTING = CapabilityBits.NODE_ENABLE_PICK_REPORTING; + + /** + * Specifies that this Node will be reported in the collision + * SceneGraphPath if a collision occurs. This capability is only + * specifiable for Group nodes; it is ignored for leaf nodes. + * The default for Group nodes is false. All interior nodes not + * needed for uniqueness in a SceneGraphPath that don't have + * ENABLE_COLLISION_REPORTING set to true will not be reported + * in the SceneGraphPath. + * @see SceneGraphPath + */ + public static final int + ENABLE_COLLISION_REPORTING = CapabilityBits.NODE_ENABLE_COLLISION_REPORTING; + + /** + * Specifies that this Node allows read access to its bounds + * information. + */ + public static final int + ALLOW_BOUNDS_READ = CapabilityBits.NODE_ALLOW_BOUNDS_READ; + + /** + * Specifies that this Node allows write access to its bounds + * information. + */ + public static final int + ALLOW_BOUNDS_WRITE = CapabilityBits.NODE_ALLOW_BOUNDS_WRITE; + + /** + * Specifies that this Node allows reading its pickability state. + */ + public static final int + ALLOW_PICKABLE_READ = CapabilityBits.NODE_ALLOW_PICKABLE_READ; + + /** + * Specifies that this Node allows write access its pickability state. + */ + public static final int + ALLOW_PICKABLE_WRITE = CapabilityBits.NODE_ALLOW_PICKABLE_WRITE; + + /** + * Specifies that this Node allows reading its collidability state. + */ + public static final int + ALLOW_COLLIDABLE_READ = CapabilityBits.NODE_ALLOW_COLLIDABLE_READ; + + /** + * Specifies that this Node allows write access its collidability state. + */ + public static final int + ALLOW_COLLIDABLE_WRITE = CapabilityBits.NODE_ALLOW_COLLIDABLE_WRITE; + + /** + * Specifies that this Node allows read access to its bounds + * auto compute information. + */ + public static final int + ALLOW_AUTO_COMPUTE_BOUNDS_READ = CapabilityBits.NODE_ALLOW_AUTO_COMPUTE_BOUNDS_READ; + + /** + * Specifies that this Node allows write access to its bounds + * auto compute information. + */ + public static final int + ALLOW_AUTO_COMPUTE_BOUNDS_WRITE = CapabilityBits.NODE_ALLOW_AUTO_COMPUTE_BOUNDS_WRITE; + + /** + * Specifies that this Node allows read access to its local + * coordinates to virtual world (Vworld) coordinates transform. + */ + public static final int + ALLOW_LOCAL_TO_VWORLD_READ = CapabilityBits.NODE_ALLOW_LOCAL_TO_VWORLD_READ; + + /** + * Specifies that this Node allows read access to its parent Group node. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_PARENT_READ = CapabilityBits.NODE_ALLOW_PARENT_READ; + + /** + * Specifies that this Node allows read access to its Locale. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_LOCALE_READ = CapabilityBits.NODE_ALLOW_LOCALE_READ; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_BOUNDS_READ, + ALLOW_PICKABLE_READ, + ALLOW_COLLIDABLE_READ, + ALLOW_AUTO_COMPUTE_BOUNDS_READ, + ALLOW_LOCAL_TO_VWORLD_READ, + ALLOW_PARENT_READ, + ALLOW_LOCALE_READ + }; + + // for checking for cycles + private boolean visited = false; + + + /** + * Constructs a Node object with default parameters. The default + * values are as follows: + *

    + * pickable : true
    + * collidable : true
    + * bounds auto compute : true
    + * bounds : N/A (automatically computed)
    + *
+ */ + public Node() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + + * @return the parent of this node, or null if this node has no parent + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Node getParent() { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_PARENT_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("Node0")); + } + } + + NodeRetained nr = ((NodeRetained)this.retained).getParent(); + return (nr == null ? null : (Node) nr.getSource()); + } + + /** + * Sets the geometric bounds of a node. + * @param bounds the bounding object for a node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setBounds(Bounds bounds) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Node1")); + + ((NodeRetained)this.retained).setBounds(bounds); + } + + /** + * Returns the bounding object of a node. + * @return the node's bounding object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + */ + public Bounds getBounds() { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_BOUNDS_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("Node2")); + } + } + else { + // this will throw a SceneGraphCycleException if there is + // a cycle + checkForCycle(); + } + + return ((NodeRetained)this.retained).getBounds(); + } + + /** + * Returns the collidable value; this value determines whether this node + * and it's children, if a group node, can be considered for collision + * purposes; if it is set to false, then neither this node nor any + * children nodes will be traversed for collision purposes; the default + * value is true. The collidable setting is the way that an + * application can perform collision culling. + * @return the present collidable value for this node + */ + public boolean getCollidable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLLIDABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node16")); + + return ((NodeRetained)retained).getCollidable(); + } + + /** + * Sets the collidable value; determines whether this node and any of its + * children, if a group node, can be considered for collision purposes. + * @param collidable the new collidable value for this node + */ + public void setCollidable( boolean collidable ) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLLIDABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Node4")); + + ((NodeRetained)retained).setCollidable(collidable); + } + + /** + * Turns the automatic calcuation of geometric bounds of a node on/off. + * @param autoCompute indicates if the node's bounding object is + * automatically computed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setBoundsAutoCompute(boolean autoCompute) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_AUTO_COMPUTE_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Node5")); + + ((NodeRetained)this.retained).setBoundsAutoCompute(autoCompute); + } + + /** + * Gets the value indicating if the automatic calcuation of geometric bounds of a node is on/off. + * @return the node's auto compute flag for the geometric bounding object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getBoundsAutoCompute() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_AUTO_COMPUTE_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node6")); + + return ((NodeRetained)this.retained).getBoundsAutoCompute(); + } + + /** + * Retrieves the local coordinates to virtual world coordinates + * transform for this node in the scene graph. This is the composite + * of all transforms in the scene graph from the root down to + * this node. It is only valid + * for nodes that are part of a live scene graph. + * If the node is not part of a live scene graph then the coordinates are + * calculated as if the graph was attached at the origin of a locale. + * @param t the object that will receive the local coordinates to + * Vworld coordinates transform. + * @exception RestrictedAccessException if the node is compiled but not + * part of a live scene graph + * @exception CapabilityNotSetException if appropriate capability is + * not set and this node is part of live or compiled scene graph + * @exception IllegalSharingException if the node is a descendant + * of a SharedGroup node. + */ + public void getLocalToVworld(Transform3D t) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_LOCAL_TO_VWORLD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node8")); + } + + if (!isLive()) { + // TODO Support compiled graphs + if (isCompiled()) + throw new RestrictedAccessException(J3dI18N.getString("Node7")); + + // In 1.4 we support getLocalToVworld for non live nodes + ((NodeRetained)this.retained).computeNonLiveLocalToVworld(t, this); + //throw new RestrictedAccessException(J3dI18N.getString("Node7")); + } else { + ((NodeRetained)this.retained).getLocalToVworld(t); + } + } + + + /** + * Retrieves the local coordinates to virtual world coordinates + * transform for the particular path in the scene graph ending with + * this node. This is the composite + * of all transforms in the scene graph from the root down to + * this node via the specified Link nodes. It is + * only valid for nodes that are part of a live scene graph. + * @param path the specific path from the node to the Locale + * @param t the object that will receive the local coordinates to + * Vworld coordinates transform. + * @exception RestrictedAccessException if the node is not + * part of a live scene graph + * @exception CapabilityNotSetException if appropriate capability is + * not set and this node is part of live scene graph + * @exception IllegalArgumentException if the specified path does + * not contain a valid Locale, or if the last node in the path is + * different from this node + * @exception IllegalSharingException if the node is not a descendant + * of a SharedGroup node. + */ + public void getLocalToVworld(SceneGraphPath path, Transform3D t) { + if (!isLive()) { + throw new RestrictedAccessException(J3dI18N.getString("Node7")); + } + + if(!this.getCapability(ALLOW_LOCAL_TO_VWORLD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node8")); + + ((NodeRetained)this.retained).getLocalToVworld(path,t); + + } + + /** + * Retrieves the locale to which this node is attached. If the + * node is not part of a live scene graph, null is returned. + * + * @return the locale to which this node is attached. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this node is part of live scene graph + * @exception IllegalSharingException if the node is a descendant + * of a SharedGroup node. + * + * @since Java 3D 1.4 + */ + public Locale getLocale() { + if (!isLive()) { + return null; + } + + if(!this.getCapability(ALLOW_LOCALE_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("Node17")); + } + + return ((NodeRetained)this.retained).getLocale(); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to cloneNode + * and then cloneTree + * is called for each child node. For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * duplicateOnCloneTree flag found in every Leaf Node's + * component data class and by the forceDuplicate paramter. + * @return a reference to the cloned sub-graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneTree() { + return cloneTree(new NodeReferenceTable(), false, false); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to cloneNode + * and then cloneTree is called for each child node. + * For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * duplicateOnCloneTree flag found in every Leaf Node's + * component data class and by the forceDuplicate paramter. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree determines whether data is + * duplicated or copied. + * @return a reference to the cloned scene graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneTree(boolean forceDuplicate) { + return cloneTree(new NodeReferenceTable(), forceDuplicate, false); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to cloneNode and + * then cloneTree is called for each child node. For + * Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * duplicateOnCloneTree flag found in every Leaf Node's + * component data class and by the forceDuplicate paramter. + * + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree + * flag to be ignored. When false, the value of each node's + * duplicateOnCloneTree determines whether data is + * duplicated or copied. + * + * @param allowDanglingReferences when set to true allows + * the cloneTree + * method to complete even whan a dangling reference is discovered. When + * this parameter is false a + * DanglingReferenceException is generated as + * soon as cloneTree detects this situation. + * + * @return a reference to the cloned scene graph. + * + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation and the + * allowDanglingReference parameter is false. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneTree(boolean forceDuplicate, + boolean allowDanglingReferences) { + return cloneTree(new NodeReferenceTable(), + forceDuplicate, allowDanglingReferences); + } + + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to cloneNode + * and then cloneTree + * is called for each child node. For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * duplicateOnCloneTree flag found in every Leaf Node's + * component data class and by the forceDuplicate paramter. + * @param referenceTable table that stores the mapping between + * original and cloned nodes. All previous values in the + * referenceTable will be cleared before the clone is made. + * @return a reference to the cloned sub-graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + * @since Java 3D 1.2 + */ + public Node cloneTree(NodeReferenceTable referenceTable) { + return cloneTree(referenceTable, false, false); + } + + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to cloneNode + * and then cloneTree is called for each child node. + * For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * duplicateOnCloneTree flag found in every Leaf Node's + * component data class and by the forceDuplicate paramter. + * @param referenceTable table that stores the mapping between + * original and cloned nodes. All previous values in the + * referenceTable will be cleared before the clone is made. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree determines whether data is + * duplicated or copied. + * @return a reference to the cloned scene graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + * @since Java 3D 1.2 + */ + public Node cloneTree(NodeReferenceTable referenceTable, + boolean forceDuplicate) { + return cloneTree(referenceTable, forceDuplicate, false); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to cloneNode + * and then cloneTree is called for each child node. + * For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * duplicateOnCloneTree flag found in every Leaf Node's + * component data class and by the forceDuplicate paramter. + * @param referenceTable table that stores the mapping between + * original and cloned nodes. All previous values in the + * referenceTable will be cleared before the clone is made. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree determines whether data is + * duplicated or copied. + * + * @param allowDanglingReferences when set to true allows + * the cloneTree + * method to complete even whan a dangling reference is discovered. When + * this parameter is false a + * DanglingReferenceException is generated as + * soon as cloneTree detects this situation. + * + * @return a reference to the cloned scene graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + * @since Java 3D 1.2 + */ + public Node cloneTree(NodeReferenceTable referenceTable, + boolean forceDuplicate, + boolean allowDanglingReferences) { + + if (!isLiveOrCompiled()) { + // this will throw a SceneGraphCycleException if there is + // a cycle + checkForCycle(); + } + + referenceTable.set(allowDanglingReferences, new Hashtable()); + Node n = cloneTree(forceDuplicate, referenceTable.objectHashtable); + + // go through hash table looking for Leaf nodes. + // call updateNodeReferences for each. + Enumeration e = referenceTable.objectHashtable.elements(); + + while (e.hasMoreElements()) { + SceneGraphObject o = (SceneGraphObject) e.nextElement(); + o.updateNodeReferences(referenceTable); + } + return n; + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to cloneNode and + * then cloneTree is called for each child node. For + * Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * duplicateOnCloneTree flag found in every Leaf Node's + * component data class and by the forceDuplicate paramter. + * + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree + * flag to be ignored. When false, the value of each node's + * duplicateOnCloneTree determines whether data is + * duplicated or copied. + * + * @param nodeHashtable a hashtable used to map orignal node references to + * their cloned counterpart. + * + * @return a reference to the cloned scene graph. + * + * @see NodeComponent#setDuplicateOnCloneTree + */ + Node cloneTree(boolean forceDuplicate, Hashtable nodeHashtable) { + Node l; + this.nodeHashtable = nodeHashtable; + try { + l = cloneNode(forceDuplicate); + } catch (RuntimeException e) { + this.nodeHashtable = null; + throw e; + } + // must reset to null so that we can tell whether the call is from user + // or cloneTree + this.nodeHashtable = null; + nodeHashtable.put(this, l); + return l; + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * cloneNode should be overridden by any user subclassed + * objects. All subclasses must have their cloneNode + * method consist of the following lines: + *

+     *     public Node cloneNode(boolean forceDuplicate) {
+     *         UserSubClass usc = new UserSubClass();
+     *         usc.duplicateNode(this, forceDuplicate);
+     *         return usc;
+     *     }
+     * 
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + throw new RuntimeException(J3dI18N.getString("Node12")); + } + + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Group#cloneNode + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, + boolean forceDuplicate) { + duplicateAttributes(originalNode, forceDuplicate); + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from subclass of + * duplicateNode method which is, in turn, called by the + * cloneNode method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Group#cloneNode + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + final void checkDuplicateNode(Node originalNode, + boolean forceDuplicate) { + if (originalNode.nodeHashtable != null) { + duplicateAttributes(originalNode, forceDuplicate); + } else { + // user call cloneNode() or duplicateNode() directly + // instead of via cloneTree() + originalNode.nodeHashtable = new Hashtable(); + duplicateAttributes(originalNode, forceDuplicate); + originalNode.nodeHashtable = null; + } + } + + + /** + * Copies all Node information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if originalNode object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + + if (originalNode.isLiveOrCompiled()) { + throw new RestrictedAccessException(J3dI18N.getString("Node13")); + } + super.duplicateSceneGraphObject(originalNode); + NodeRetained attr = (NodeRetained) originalNode.retained; + NodeRetained rt = (NodeRetained) retained; + + rt.setPickable(attr.getPickable()); + rt.setCollidable(attr.getCollidable()); + } + + + /** + * When set to true this Node can be Picked. + * Setting to false indicates that this node and it's children + * are ALL unpickable. + * + * @param pickable Indicates if this node should be pickable or not + */ + public void setPickable( boolean pickable ) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PICKABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Node14")); + + ((NodeRetained)retained).setPickable(pickable); + } + + /** + * Returns true if this Node is pickable, + * false if it is not pickable. + */ + public boolean getPickable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PICKABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node3")); + + return ((NodeRetained)retained).getPickable(); + } + + /** + * checks for cycles in the scene graph + */ + void checkForCycle() { + if (visited) { + throw new SceneGraphCycleException(J3dI18N.getString("Node15")); + } + visited = true; + Node parent = getParent(); + if (parent != null) { + parent.checkForCycle(); + } + visited = false; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NodeComponent.java b/j3d-core/src/classes/share/javax/media/j3d/NodeComponent.java new file mode 100644 index 0000000..90c572a --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NodeComponent.java @@ -0,0 +1,312 @@ +/* + * $RCSfile: NodeComponent.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.Hashtable; + +/** + * NodeComponent is a common superclass for all scene graph node + * component objects such as: Geometry, Appearance, Material, Texture, etc. + * + *

+ * For more information, see the + * Introduction to the Java 3D API. + */ +public abstract class NodeComponent extends SceneGraphObject { + + // This is use for cloneTree only, set to false after the operation + boolean forceDuplicate = false; + /** + * Constructs a NodeComponent object with default parameters. + * The default values are as follows: + *

    + * duplicate on clone tree : false
    + *
+ */ + public NodeComponent() { + } + + /** + * Sets this node's duplicateOnCloneTree value. The + * duplicateOnCloneTree value is used to determine if NodeComponent + * objects are to be duplicated or referenced during a + * cloneTree operation. A value of true means + * that this NodeComponent object should be duplicated, while a value + * of false indicates that this NodeComponent object's + * reference will be copied into the newly cloned object. This value + * can be overriden via the forceDuplicate parameter of + * the cloneTree method. + * @param duplicate the value to set. + * @see Node#cloneTree + */ + public void setDuplicateOnCloneTree(boolean duplicate) { + ((NodeComponentRetained)retained).setDuplicateOnCloneTree(duplicate); + } + + /** + * Returns this node's duplicateOnCloneTree value. The + * duplicateOnCloneTree value is used to determine if NodeComponent + * objects are to be duplicated or referenced during a + * cloneTree operation. A value of true means + * that this NodeComponent object should be duplicated, while a value + * of false indicates that this NodeComponent object's + * reference will be copied into the newly cloned object. This value + * can be overriden via the forceDuplicate parameter of + * the cloneTree method. + * @return the value of this node's duplicateOnCloneTree + * @see Node#cloneTree + */ + public boolean getDuplicateOnCloneTree() { + return ((NodeComponentRetained)retained).getDuplicateOnCloneTree(); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + throw new RuntimeException(J3dI18N.getString("NodeComponent0")); + } + + + /** + * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @deprecated As of Java 3D version 1.2, replaced by + * duplicateNodeComponent(NodeComponent + * originalNodeComponent, boolean forceDuplicate) + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent) { + duplicateAttributes(originalNodeComponent, + originalNodeComponent.forceDuplicate); + } + + /** + * Copies all node information from originalNodeComponent into + * the current node component. This method is called from subclass of + * duplicateNodeComponent method which is, in turn, called by the + * cloneNodeComponent method. + * + * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + * @param originalNodeComponent the original node component to duplicate. + */ + final void checkDuplicateNodeComponent( + NodeComponent originalNodeComponent) { + + if (originalNodeComponent.nodeHashtable != null) { + duplicateAttributes(originalNodeComponent, + originalNodeComponent.forceDuplicate); + } else { + // user call cloneNodeComponent() or duplicateNodeComponent() + // directly instead of via cloneTree() + originalNodeComponent.nodeHashtable = new Hashtable(); + duplicateAttributes(originalNodeComponent, + originalNodeComponent.forceDuplicate); + originalNodeComponent.nodeHashtable = null; + } + } + + /** + * Copies all node information from originalNodeComponent + * into the current node. This method is called from the + * cloneNodeComponent method which is, in turn, called + * by the cloneNode method. + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNodeComponent the node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if forceDuplicate is set and + * this object is part of a compiled scenegraph + * + * @see NodeComponent#cloneNodeComponent + * @see Node#cloneNode + * @see Node#cloneTree + * + * @since Java 3D 1.2 + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + originalNodeComponent.forceDuplicate = forceDuplicate; + try { + duplicateNodeComponent(originalNodeComponent); + } catch (RuntimeException e) { + originalNodeComponent.forceDuplicate = false; + throw e; + } + originalNodeComponent.forceDuplicate = false; + } + + /** + * Used to create a new instance of a NodeComponent object. This + * routine is called by cloneNode to duplicate the + * current node.
+ * + * cloneNodeComponent should be overridden by any user + * subclassed NodeComponent objects. All subclasses must have their + * cloneNodeComponent + * method consist of the following lines: + *

+   *     public NodeComponent cloneNodeComponent(boolean forceDuplicate) {
+   *         UserNodeComponent unc = new UserNodeComponent();
+   *         unc.duplicateNodeComponent(this, forceDuplicate);
+   *         return unc;
+   *     }
+   * 
+ * + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if forceDuplicate is set and + * this object is part of a compiled scenegraph + * + * @see NodeComponent#duplicateNodeComponent + * @see Node#cloneNode + * @see Node#cloneTree + * + * @since Java 3D 1.2 + */ + public NodeComponent cloneNodeComponent(boolean forceDuplicate) { + // For backward compatibility ! + // + // If user did not overwrite this procedure, it will fall back + // to call cloneNodeComponent() + // So for core API, + // don't implement cloneNodeComponent(boolean forceDuplicate) + // otherwise this prcedure will not call and the user + // cloneNodeComponent() will not invoke. + NodeComponent nc; + this.forceDuplicate = forceDuplicate; + try { + nc = cloneNodeComponent(); + } catch (RuntimeException e) { + this.forceDuplicate = false; + throw e; + } + this.forceDuplicate = false; + return nc; + } + + + /** + * Copies all NodeComponent information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Group#cloneNode + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNode, + boolean forceDuplicate) { + + if (forceDuplicate && originalNode.isCompiled()) { + throw new RestrictedAccessException( + J3dI18N.getString("NodeComponent1")); + } + + super.duplicateSceneGraphObject(originalNode); + setDuplicateOnCloneTree(originalNode.getDuplicateOnCloneTree()); + } + + /** + * Creates the retained mode NodeComponentRetained object that this + * NodeComponent object will point to. + */ + void createRetained() { + this.retained = new NodeComponentRetained(); + this.retained.setSource(this); + } + + /** + * This function is called from getNodeComponent() to see if any of + * the sub-NodeComponents duplicateOnCloneTree flag is true. + * If it is the case, current NodeComponent needs to + * duplicate also even though current duplicateOnCloneTree flag is false. + * This should be overwrite by NodeComponent which contains sub-NodeComponent. + */ + boolean duplicateChild() { + return getDuplicateOnCloneTree(); + } + + /* + * @exception IllegalSharingException if this NodeComponent is live and + * the specified image is being used by a Canvas3D as an off-screen buffer. + * + * @exception IllegalSharingException if this NodeComponent is + * being used by an immediate mode context and + * the specified image is being used by a Canvas3D as an off-screen buffer. + */ + void validateImageIllegalSharing(ImageComponent image) { + // Do illegal sharing check + if(image != null) { + ImageComponentRetained imageRetained = (ImageComponentRetained) image.retained; + NodeComponentRetained ncRetained = (NodeComponentRetained)this.retained; + if(imageRetained.getUsedByOffScreen()) { + if(isLive()) { + throw new IllegalSharingException(J3dI18N.getString("NodeComponent2")); + } + if(ncRetained.getInImmCtx()) { + throw new IllegalSharingException(J3dI18N.getString("NodeComponent3")); + } + } + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NodeComponentRetained.java b/j3d-core/src/classes/share/javax/media/j3d/NodeComponentRetained.java new file mode 100644 index 0000000..b07e35d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NodeComponentRetained.java @@ -0,0 +1,252 @@ +/* + * $RCSfile: NodeComponentRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * Retained version of NodeComponent + */ + +class NodeComponentRetained extends SceneGraphObjectRetained { + + // duplicate or make a reference when cloneTree() is called + // on this object. + boolean duplicateOnCloneTree = false; + + // This keeps track of how many times this NodeComponent is referenced in + // the Scene Graph + int refCount = 0; // this is used in setLive + int refCnt = 0; // this is used in compile + + // This is true when this appearance is referenced in an immediate mode context + private boolean inImmCtx = false; + + // A list of NodeRetained Objects that refer, directly or indirectly, to this + // NodeComponentRetained + ArrayList users = new ArrayList(1); + + // Mirror object of this node compoenent object + NodeComponentRetained mirror = null; + + // Sole User FrequencyBit + // In the case of Appearance, its a bitmask of all components + int changedFrequent = 0; + int compChanged = 0; + + // Increment the refcount. If this is the first, mark it as live. + void doSetLive(boolean inBackgroundGroup, int refCount) { + int oldRefCount = this.refCount; + this.refCount += refCount; + if (oldRefCount <= 0) { + super.doSetLive(inBackgroundGroup); + + // Create and init a mirror object if not already there + // The two procedures is combined since it is redunctant to + // call initMirrorObject() if mirror == this (static object). + createMirrorObject(); + } + } + + void setLive(boolean inBackgroundGroup, int refCount) { + int oldRefCount = this.refCount; + doSetLive(inBackgroundGroup, refCount); + if (oldRefCount <= 0) { + super.markAsLive(); + } + } + + + + // Decrement the refcount. If this is the last, mark it as not live. + void clearLive(int refCount) { + this.refCount -= refCount; + + if (this.refCount <= 0) { + super.clearLive(); + } + } + + // increment the compile reference count + synchronized void incRefCnt() { + refCnt++; + } + + // decrement the compile reference count + synchronized void decRefCnt() { + refCnt--; + } + + // remove mirror shape from the list of users + void removeAMirrorUser(Shape3DRetained ms) { + synchronized(mirror.users) { + mirror.users.remove(ms); + } + } + + // Add a mirror shape to the list of users + void addAMirrorUser(Shape3DRetained ms) { + synchronized(mirror.users) { + mirror.users.add(ms); + } + } + + // Copy the list of useres passed in into this + void copyMirrorUsers(NodeComponentRetained node) { + synchronized(mirror.users) { + synchronized(node.mirror.users) { + int size = node.mirror.users.size(); + for (int i=0; i=0; i--) { + mirror.users.remove(mirror.users.indexOf(node.mirror.users.get(i))); + } + } + } + } + + // Add a user to the list of users + synchronized void removeUser(NodeRetained node) { + if (node.source.isLive()) + users.remove(users.indexOf(node)); + } + + // Add a user to the list of users + synchronized void addUser(NodeRetained node) { + if (node.source.isLive()) + users.add(node); + } + + + // Add a user to the list of users + synchronized void notifyUsers() { + + if (source == null || !source.isLive()) { + return; + } + + for (int i=users.size()-1; i >=0; i--) { + ((NodeRetained)users.get(i)).notifySceneGraphChanged(false); + } + } + + /** + * This sets the immedate mode context flag + */ + void setInImmCtx(boolean inCtx) { + inImmCtx = inCtx; + } + + /** + * This gets the immedate mode context flag + */ + boolean getInImmCtx() { + return (inImmCtx); + } + + /** + * Sets this node's duplicateOnCloneTree value. The + * duplicateOnCloneTree value is used to determine if NodeComponent + * objects are to be duplicated or referenced during a + * cloneTree operation. A value of true means + * that this NodeComponent object should be duplicated, while a value + * of false indicates that this NodeComponent object's + * reference will be copied into the newly cloned object. This value + * can be overriden via the forceDuplicate parameter of + * the cloneTree method. + * @param duplicate the value to set. + * @see Node#cloneTree + */ + void setDuplicateOnCloneTree(boolean duplicate) { + duplicateOnCloneTree = duplicate; + } + + /** + * Returns this node's duplicateOnCloneTree value. The + * duplicateOnCloneTree value is used to determine if NodeComponent + * objects are to be duplicated or referenced during a + * cloneTree operation. A value of true means + * that this NodeComponent object should be duplicated, while a value + * of false indicates that this NodeComponent object's + * reference will be copied into the newly cloned object. This value + * can be overriden via the forceDuplicate parameter of + * the cloneTree method. + * @return the value of this node's duplicateOnCloneTree + * @see Node#cloneTree + */ + boolean getDuplicateOnCloneTree() { + return duplicateOnCloneTree; + } + + + void initMirrorObject() { + } + + void updateMirrorObject(int component, Object obj) { + } + + void createMirrorObject() { + // Overridden by appearance and other classes + initMirrorObject(); + mirror = null; + } + + void setFrequencyChangeMask(int bit, int mask) { + if (source.getCapabilityIsFrequent(bit)) + changedFrequent |= mask; + else if (!source.isLive()) { + // Record the freq->infreq change only for non-live node components + changedFrequent &= ~mask; + } + } + + protected Object clone() { + NodeComponentRetained ncr = (NodeComponentRetained)super.clone(); + ncr.changedFrequent = changedFrequent; + return ncr; + } + + protected void set(NodeComponentRetained nc) { + changedFrequent = nc.changedFrequent; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NodeComponentUpdate.java b/j3d-core/src/classes/share/javax/media/j3d/NodeComponentUpdate.java new file mode 100644 index 0000000..21ecafe --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NodeComponentUpdate.java @@ -0,0 +1,45 @@ +/* + * $RCSfile: NodeComponentUpdate.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A Node Component Update interface. Any object that can be put in the + * node component updateCheck list must implement this interface. + */ + +interface NodeComponentUpdate { + + /** + * The actual update function. + */ + abstract void updateNodeComponentCheck(); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NodeData.java b/j3d-core/src/classes/share/javax/media/j3d/NodeData.java new file mode 100644 index 0000000..277a9a0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NodeData.java @@ -0,0 +1,40 @@ +/* + * $RCSfile: NodeData.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +class NodeData { + // per path node data + // XXXX: replace per path mirror objects with node data + // XXXX: move other basic node's data here + SwitchState switchState = null; +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NodeReferenceTable.java b/j3d-core/src/classes/share/javax/media/j3d/NodeReferenceTable.java new file mode 100644 index 0000000..7a49ff6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NodeReferenceTable.java @@ -0,0 +1,140 @@ +/* + * $RCSfile: NodeReferenceTable.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Hashtable; + +/** + * The NodeReferenceTable object is used by a leaf node's + * updateNodeReferences method called by the + * cloneTree method. + * The NodeReferenceTable maps nodes from the original subgraph + * to the new nodes in the cloned subgraph. This information + * can then be used to update any cloned leaf node references + * to reference nodes in the cloned subgraph. + *

+ * During a cloneTree call, after all nodes have been duplicated, + * each SceneGraphObject's updateNodeReferences method is called. + * This method takes a NodeReferenceTable object as a parameter. The + * SceneGraphObject's updateNodeReferences method can then use the + * getNewObjectReference method from this object to get updated + * references to objects that have been duplicated in the new cloneTree + * sub-graph. If a match is found, a + * reference to the corresponding SceneGraphObject in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown by the cloneTree + * method or a reference to the original + * SceneGraphObject is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + * @see SceneGraphObject#updateNodeReferences + * @see Node#cloneTree + * @see DanglingReferenceException + */ +public class NodeReferenceTable extends Object { + + Hashtable objectHashtable; + boolean allowDanglingReferences; + + /** + * Constructs an empty NodeReferenceTable. + * @since Java 3D 1.2 + */ + public NodeReferenceTable() { + } + + // Constructor - this is NOT public! + NodeReferenceTable(boolean allowDanglingReferences, + Hashtable objectHashtable) { + set(allowDanglingReferences, objectHashtable); + } + + void set(boolean allowDanglingReferences, + Hashtable objectHashtable) { + this.objectHashtable = objectHashtable; + this.allowDanglingReferences = allowDanglingReferences; + } + + + /** + * This method is used in conjunction with the cloneTree + * method. It can be used by the updateNodeReferences + * method to see if a SceneGraphObject that is being referenced has been duplicated + * in the new cloneTree sub-graph. + *

+ * A SceneGraphObject's updateNodeReferences method would use this + * method by calling it with the reference to the old (existed before + * the cloneTree operation) object. If the object has been duplicated + * in the cloneTree sub-graph, the corresponding object in the cloned + * sub-graph is returned. If no corresponding reference is found, either + * a DanglingReferenceException is thrown or a reference to the original + * SceneGraphObject is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + * + * @param oldReference the reference to the object in + * the original sub-graph. + * + * @return A reference to the corresponding object in the cloned + * sub-graph. If no corresponding object exists, either a + * DanglingReferenceException will be generated by the + * cloneTree method or a reference to the original object + * is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + * + * @see SceneGraphObject#updateNodeReferences + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public final SceneGraphObject + getNewObjectReference(SceneGraphObject oldReference) { + + // look up original SceneGraphObject in hash table + SceneGraphObject newObject = + (SceneGraphObject)objectHashtable.get(oldReference); + + if (newObject != null) { + // found new reference + return newObject; + } + + // dangling reference found! + if (allowDanglingReferences == true) { + return oldReference; + } + + // dangling references not allowed + throw new DanglingReferenceException(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NodeRetained.java b/j3d-core/src/classes/share/javax/media/j3d/NodeRetained.java new file mode 100644 index 0000000..978db02 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NodeRetained.java @@ -0,0 +1,987 @@ +/* + * $RCSfile: NodeRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:26 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +import java.util.Vector; +import java.util.Hashtable; +import java.util.ArrayList; + +/** + * The Node class provides an abstract class for all Group and Leaf + * Nodes. It provides a common framework for constructing a Java 3D + * scene graph, including bounding volumes and parent pointers. + */ +abstract class NodeRetained extends SceneGraphObjectRetained implements NnuId { + + // All the node types in the scene graph + static final int BACKGROUND = 1; + static final int CLIP = 2; + static final int LINEARFOG = 3; + static final int EXPONENTIALFOG = 4; + static final int AMBIENTLIGHT = 5; + static final int DIRECTIONALLIGHT = 6; + static final int POINTLIGHT = 7; + static final int SPOTLIGHT = 8; + static final int LINK = 9; + static final int MORPH = 10; + static final int SHAPE = 11; + static final int BACKGROUNDSOUND = 12; + static final int POINTSOUND = 13; + static final int CONESOUND = 14; + static final int SOUNDSCAPE = 15; + static final int VIEWPLATFORM = 16; + static final int BEHAVIOR = 17; + + static final int SWITCH = 18; + static final int BRANCHGROUP = 19; + static final int ORDEREDGROUP = 20; + static final int DECALGROUP = 21; + static final int SHAREDGROUP = 22; + static final int GROUP = 23; + static final int TRANSFORMGROUP = 24; + static final int BOUNDINGLEAF = 25; + static final int MODELCLIP = 26; + static final int ALTERNATEAPPEARANCE= 27; + static final int ORIENTEDSHAPE3D = 28; + static final int VIEWSPECIFICGROUP = 29; + static final int NUMNODES = 29; + + // traverse flags + static final int CONTAINS_VIEWPLATFORM = 0x1; + + + /** + * The universe that we are in + */ + VirtualUniverse universe = null; + + /** + * The locale that this node is attatched to. This is only non-null + * if this instance is directly linked into a locale. + */ + Locale locale = null; + + /** + * The node's parent. + */ + NodeRetained parent = null; + + /** + * The node's internal identifier. + */ + String nodeId = null; + + /** + * An int that represents the nodes type. Used for quick if tests + * in the traverser. + */ + int nodeType; + + // This keeps track of how many times this Node is refernced, refCount > 1 + // if node is in a shared group + int refCount = 0; + + /** + * This is the index for the child, as seen by its parent. + */ + int childIndex = -1; + + /** + * This boolean is true when the node is in a sharedGroup + */ + boolean inSharedGroup = false; + + /** + * This indicates if the node is pickable. If this node is not + * pickable then neither are any children + */ + boolean pickable = true; + + /** + * The collidable setting; see getCollidable and setCollidable. + */ + boolean collidable = true; + + // A list of localToVworld transforms. If inSharedGroup is false, + // then only localToVworld[0][] is valid. + // Note: this contains reference to the actual transforms in the + // TransformGroupRetained + Transform3D localToVworld[][] = null; + int localToVworldIndex[][] = null; + + static final int LAST_LOCAL_TO_VWORLD = 0; + static final int CURRENT_LOCAL_TO_VWORLD = 1; + + // A parallel array to localToVworld. This is the keys for + // localToVworld transforms in shared groups. + HashKey localToVworldKeys[] = null; + + /** + * This boolean is true when the geometric bounds for the node is + * automatically updated + */ + boolean boundsAutoCompute = true; + + // "effective" bounds in local coordinate if boundsAutoCompute == F, + // used for internal operations, not used if boundsAutoCompute == T + Bounds localBounds; + + // Bounds set by the API + Bounds apiBounds; + + protected Bounds cachedBounds=null; // Cached auto compute bounds, could we use localBounds ? + protected boolean validCachedBounds = false; // Fix to Issue 514 + /** + * Each element, p, of branchGroupPaths is a list of BranchGroup from + * root of the tree to this. + * For BranchGroup under a non-shared group this size of + * branchGroupPaths is always 1. Otherwise, the size is equal to + * the number of possible paths to reach this node. + * This variable is used to cached BranchGroup for fast picking. + * For non BranchGroupRetained class this is a reference to + * the previous BranchGroupRetained branchGroupPaths. + */ + ArrayList branchGroupPaths = new ArrayList(1); + + // background node whose geometry branch contains this node + BackgroundRetained geometryBackground = null; + + // closest parent which is a TransformGroupRetained or sharedGroupRetained + GroupRetained parentTransformLink = null; + + // closest parent which is a SwitchRetained or sharedGroupRetained + GroupRetained parentSwitchLink = null; + + // static transform if a parent transform group is merged during compile. + TransformGroupRetained staticTransform = null; + + // orderedId assigned by OrderedGroup parent + Integer orderedId = null; + + // Id use for quick search. + int nnuId; + + NodeRetained() { + // Get a not necessary unique Id. + nnuId = NnuIdManager.getId(); + + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setUpper(-1.0, -1.0, -1.0); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + } + + + public int getId() { + return nnuId; + } + + public int equal(NnuId obj) { + int keyId = obj.getId(); + if(nnuId < keyId) { + return -1; + } + else if(nnuId > keyId) { + return 1; + } + else { // Found it! + return 0; + } + } + + Bounds getLocalBounds(Bounds bounds) { + return (Bounds)bounds.clone(); + } + + /** + * Sets the geometric bounds of a node. + * @param bounds the bounding object for the node + */ + void setBounds(Bounds bounds) { + apiBounds = bounds; + if (source.isLive()) { + if (!boundsAutoCompute) { + if (bounds != null) { + localBounds = getLocalBounds(bounds); + if (staticTransform != null) { + localBounds.transform(staticTransform.transform); + } + } else { + if(localBounds != null) { + localBounds.set((Bounds)null); + } + else { + localBounds = new BoundingBox((Bounds)null); + } + } + } + } else { + if (bounds != null) { + localBounds = getLocalBounds(bounds); + if (staticTransform != null) { + localBounds.transform(staticTransform.transform); + } + } else { + if(localBounds != null) { + localBounds.set((Bounds)null); + } + else { + localBounds = new BoundingBox((Bounds)null); + } + } + } + } + + /** + * Gets the bounding object of a node. + * @return the node's bounding object + */ + Bounds getEffectiveBounds() { + Bounds b = null; + if (localBounds != null && !localBounds.isEmpty()) { + b = (Bounds) localBounds.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + } + return b; + } + + Bounds getBounds() { + return apiBounds; + } + + /** + * ONLY needed for SHAPE, MORPH, and LINK node type. + * Compute the combine bounds of bounds and its localBounds. + */ + void computeCombineBounds(Bounds bounds) { + // Do nothing except for Group, Shape3D, Morph, and Link node. + } + + + /** + * Sets the automatic calcuation of geometric bounds of a node. + * @param autoCompute is a boolean value indicating if automatic calcuation + * of bounds + */ + void setBoundsAutoCompute(boolean autoCompute) { + if (this.boundsAutoCompute==autoCompute) { + return; + } + + this.boundsAutoCompute = autoCompute; + dirtyBoundsCache(); + } + + /** + * Gets the auto Compute flag for the geometric bounds. + * @return the node's auto Compute flag for the geometric bounding object + */ + boolean getBoundsAutoCompute() { + return boundsAutoCompute; + } + + /** + * Replaces the specified parent by a new parent. + * @param parent the new parent + */ + void setParent(NodeRetained parent) { + this.parent = parent; + } + + /** + * Returns the parent of the node. + * @return the parent. + */ + NodeRetained getParent() { + return (NodeRetained)parent; + } + + // Transform the input bound by the current LocalToVWorld + void transformBounds(SceneGraphPath path, Bounds bound) { + if (!((NodeRetained) path.item.retained).inSharedGroup) { + bound.transform(getCurrentLocalToVworld()); + } else { + HashKey key = new HashKey(""); + path.getHashKey(key); + bound.transform(getCurrentLocalToVworld(key)); + } + } + + + // Note : key will get modified in this method. + private void computeLocalToVworld( NodeRetained caller, NodeRetained nodeR, + HashKey key, Transform3D l2Vw) { + int i; + + // To handle localToVworld under a SG. + if(nodeR instanceof SharedGroupRetained) { + // Get the immediate parent's id and remove last id from key. + String nodeId = key.getLastNodeId(); + + SharedGroupRetained sgRetained = (SharedGroupRetained) nodeR; + + // Search for the right parent. + for(i=0; i= 0) { + return localToVworld[i][localToVworldIndex[i][CURRENT_LOCAL_TO_VWORLD]]; + } + } + } + return new Transform3D(); + } + + /** + * Get the last localToVworld transform for a node + */ + Transform3D getLastLocalToVworld() { + + if (localToVworld != null) { + return localToVworld[0][localToVworldIndex[0][LAST_LOCAL_TO_VWORLD]]; + } else { + return new Transform3D(); + } + } + + Transform3D getLastLocalToVworld(int index) { + return localToVworld[index][localToVworldIndex[index][LAST_LOCAL_TO_VWORLD]]; + } + + Transform3D getLastLocalToVworld(HashKey key) { + + if (localToVworld != null) { + if (!inSharedGroup) { + return localToVworld[0][localToVworldIndex[0][LAST_LOCAL_TO_VWORLD]]; + } else { + int i = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + if(i>= 0) { + return localToVworld[i][localToVworldIndex[i][LAST_LOCAL_TO_VWORLD]]; + } + } + } + return new Transform3D(); + } + + // Do nothing for NodeRetained. + void setAuxData(SetLiveState s, int index, int hkIndex) { + + } + + void setNodeData(SetLiveState s) { + localToVworld = s.localToVworld; + localToVworldIndex = s.localToVworldIndex; + localToVworldKeys = s.localToVworldKeys; + + // reference to the last branchGroupPaths + branchGroupPaths = s.parentBranchGroupPaths; + + parentTransformLink = s.parentTransformLink; + parentSwitchLink = s.parentSwitchLink; + } + + + // set pickable, recursively update cache result + void setPickable(boolean pickable) { + if (this.pickable == pickable) + return; + + this.pickable = pickable; + + if (source.isLive()) { + synchronized(universe.sceneGraphLock) { + boolean pick[]; + if (!inSharedGroup) { + pick = new boolean[1]; + } else { + pick = new boolean[localToVworldKeys.length]; + } + + findPickableFlags(pick); + updatePickable(localToVworldKeys, pick); + } + } + } + + void updatePickable(HashKey pickKeys[], boolean pick[]) { + for (int i=0; i < pick.length; i++) { + if (!pickable) { + pick[i] = false; + } + } + } + + // get pickable + boolean getPickable() { + return pickable; + } + + + // set collidable, recursively update cache result + void setCollidable(boolean collidable) { + if (this.collidable == collidable) + return; + + this.collidable = collidable; + + if (source.isLive()) { + synchronized(universe.sceneGraphLock) { + boolean collide[]; + if (!inSharedGroup) { + collide = new boolean[1]; + } else { + collide = new boolean[localToVworldKeys.length]; + } + + findCollidableFlags(collide); + updateCollidable(localToVworldKeys, collide); + } + } + } + + + // get collidable + boolean getCollidable() { + return collidable; + } + + + void updateCollidable(HashKey keys[], boolean collide[]) { + for (int i=0; i < collide.length; i++) { + if (!collidable) { + collide[i] = false; + } + } + } + + /** + * For the default, just pass up to parent + */ + void notifySceneGraphChanged(boolean globalTraverse){} + + void recombineAbove() {} + + synchronized void updateLocalToVworld() {} + + + void setLive(SetLiveState s) { + int oldrefCount = refCount; + + doSetLive(s); + if (oldrefCount <= 0) + super.markAsLive(); + } + + // The default set of setLive actions. + void doSetLive(SetLiveState s) { + int i; + int oldrefCount = refCount; + + refCount += s.refCount; + if(!(locale == null || universe == s.universe)) + throw new IllegalSharingException(J3dI18N.getString("NodeRetained3")); + if(s.locale == null) + System.err.println("NodeRetained.setLive() locale is null"); + + + locale = s.locale; + inSharedGroup = s.inSharedGroup; + + if (oldrefCount <= 0) { + if (listIdx == null) { + universe = s.universe; + } else { + // sync with getIdxUsed() + if (s.universe != universe) { + synchronized (this) { + universe = s.universe; + incIdxUsed(); + } + } + } + } + s.universe.numNodes++; + + // pickable & collidable array have the same length + for (i=0; i < s.pickable.length; i++) { + if (!pickable) { + s.pickable[i] = false; + } + if (!collidable) { + s.collidable[i] = false; + } + } + + + if (oldrefCount <= 0) + super.doSetLive(s); + + if (inBackgroundGroup) { + geometryBackground = s.geometryBackground; + } + + setNodeData(s); + } + + + /** + * remove the localToVworld transform for this node. + */ + void removeNodeData(SetLiveState s) { + + if (refCount <= 0) { + localToVworld = null; + localToVworldIndex = null; + localToVworldKeys = null; + // restore to default and avoid calling clear() + // that may clear parent reference branchGroupPaths + branchGroupPaths = new ArrayList(1); + parentTransformLink = null; + parentSwitchLink = null; + } + else { + // Set it back to its parent localToVworld data. This is b/c the parent has + // changed it localToVworld data arrays. + localToVworld = s.localToVworld; + localToVworldIndex = s.localToVworldIndex; + localToVworldKeys = s.localToVworldKeys; + + // Reference of parent branchGroupPaths will not change + + // no need to reset parentSwitchLink or parentTransformLink + // because there are not per path data + } + + } + + // The default set of clearLive actions + void clearLive(SetLiveState s) { + + refCount-=s.refCount; + + if (refCount <= 0) { + super.clearLive(); + + // don't remove the nodeId unless there are no more references + if (nodeId != null) { + universe.nodeIdFreeList.addElement(nodeId); + nodeId = null; + } + } + + universe.numNodes--; + + + removeNodeData(s); + + if(refCount <= 0) { + locale = null; + geometryBackground = null; + } + } + + // search up the parent to determine if this node is pickable + void findPickableFlags(boolean pick[]) { + NodeRetained nodeR = this; + + + if (!inSharedGroup) { + pick[0] = true; + nodeR = nodeR.parent; + while (nodeR != null) { + if (!nodeR.pickable) { + pick[0] = false; + break; + } + nodeR = nodeR.parent; + } + } else { + HashKey key; + for (int i=0; i < pick.length; i++) { + nodeR = this; + pick[i] = true; + key = new HashKey(localToVworldKeys[i]); + + do { + if (nodeR instanceof SharedGroupRetained) { + String nodeId = key.getLastNodeId(); + Vector parents = ((SharedGroupRetained) nodeR).parents; + int sz = parents.size(); + NodeRetained prevNodeR = nodeR; + for(int j=0; j< sz; j++) { + NodeRetained linkR = (NodeRetained) parents.elementAt(j); + if (linkR.nodeId.equals(nodeId)) { + nodeR = linkR; + break; + } + } + if (prevNodeR == nodeR) { + // branch is already detach + return; + } + } else { + nodeR = nodeR.parent; + } + if (nodeR == null) + break; + if (!nodeR.pickable) { + pick[i] = false; + break; + } + } while (true); + } + } + } + + + // search up the parent to determine if this node is collidable + void findCollidableFlags(boolean collide[]) { + NodeRetained nodeR = this; + + if (!inSharedGroup) { + collide[0] = true; + nodeR = nodeR.parent; + while (nodeR != null) { + if (!nodeR.collidable) { + collide[0] = false; + break; + } + nodeR = nodeR.parent; + } + } else { + HashKey key; + for (int i=0; i < collide.length; i++) { + nodeR = this; + collide[i] = true; + key = new HashKey(localToVworldKeys[i]); + + do { + if (nodeR instanceof SharedGroupRetained) { + String nodeId = key.getLastNodeId(); + Vector parents = ((SharedGroupRetained) nodeR).parents; + int sz = parents.size(); + NodeRetained prevNodeR = nodeR; + for(int j=0; j< sz; j++) { + NodeRetained linkR = (NodeRetained) parents.elementAt(j); + if (linkR.nodeId.equals(nodeId)) { + nodeR = linkR; + break; + } + } + if (nodeR == prevNodeR) { + return; + } + } else { + nodeR = nodeR.parent; + } + if (nodeR == null) + break; + if (!nodeR.collidable) { + collide[i] = false; + break; + } + } while (true); + } + } + } + + void findTransformLevels(int transformLevels[]) { + NodeRetained nodeR = this; + TransformGroupRetained tg; + + if (!inSharedGroup) { + transformLevels[0] = -1; + while (nodeR != null) { + if (nodeR.nodeType == NodeRetained.TRANSFORMGROUP) { + tg = (TransformGroupRetained)nodeR; + transformLevels[0] = tg.transformLevels[0]; + break; + } + nodeR = nodeR.parent; + } + } else { + HashKey key; + int i,j; + for (i=0; i < transformLevels.length; i++) { + nodeR = this; + transformLevels[i] = -1; + key = new HashKey(localToVworldKeys[i]); + + do { + if (nodeR == null) + break; + else if (nodeR instanceof SharedGroupRetained) { + // note that key is truncated after getLastNodeId + String nodeId = key.getLastNodeId(); + Vector parents = ((SharedGroupRetained) nodeR).parents; + int sz = parents.size(); + NodeRetained prevNodeR = nodeR; + for (j=0; j< sz; j++) { + NodeRetained linkR = + (NodeRetained) parents.elementAt(j); + if (linkR.nodeId.equals(nodeId)) { + nodeR = linkR; + break; + } + } + if (prevNodeR == nodeR) { + // branch is already detach + return; + } + } + else if (nodeR.nodeType == NodeRetained.TRANSFORMGROUP) { + tg = (TransformGroupRetained)nodeR; + if (tg.inSharedGroup) { + + j = key.equals(tg.localToVworldKeys, 0, + tg.localToVworldKeys.length); + + transformLevels[i] = tg.transformLevels[j]; + } else { + transformLevels[i] = tg.transformLevels[0]; + } + break; + } + + nodeR = nodeR.parent; + } while (true); + } + } + } + + + boolean isStatic() { + if (source.getCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ) || + source.getCapability(Node.ALLOW_PARENT_READ) || + source.getCapability(Node.ENABLE_PICK_REPORTING) || + source.getCapability(Node.ENABLE_COLLISION_REPORTING) || + source.getCapability(Node.ALLOW_BOUNDS_READ) || + source.getCapability(Node.ALLOW_BOUNDS_WRITE) || + source.getCapability(Node.ALLOW_PICKABLE_READ) || + source.getCapability(Node.ALLOW_PICKABLE_WRITE) || + source.getCapability(Node.ALLOW_COLLIDABLE_READ) || + source.getCapability(Node.ALLOW_COLLIDABLE_WRITE) || + source.getCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_READ) || + source.getCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE)) { + return false; + } + return true; + } + + void merge(CompileState compState) { + staticTransform = compState.staticTransform; + if (compState.parentGroup != null) { + compState.parentGroup.compiledChildrenList.add(this); + } + parent = compState.parentGroup; + if (staticTransform != null) { + mergeTransform(staticTransform); + } + } + + void mergeTransform(TransformGroupRetained xform) { + if (localBounds != null) { + localBounds.transform(xform.transform); + } + } + int[] processViewSpecificInfo(int mode, HashKey k, View v, ArrayList vsgList, int[] keyList, + ArrayList leafList) { + return keyList; + + } + + VirtualUniverse getVirtualUniverse() { + return universe; + } + + void searchGeometryAtoms(UnorderList list) {} + + /** + * Make the boundsCache of this node and all its parents dirty + */ + void dirtyBoundsCache() { + // Possible optimisation is to not traverse up the tree + // if the cachedBounds==null. However this is not the case + // if the node is the child of a SharedGroup + if (VirtualUniverse.mc.cacheAutoComputedBounds) { + // Issue 514 : NPE in Wonderland : triggered in cached bounds computation + validCachedBounds = false; + if (parent!=null) { + parent.dirtyBoundsCache(); + } + } + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/NoopDrawingSurfaceObject.java b/j3d-core/src/classes/share/javax/media/j3d/NoopDrawingSurfaceObject.java new file mode 100644 index 0000000..91cfd69 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NoopDrawingSurfaceObject.java @@ -0,0 +1,76 @@ +/* + * $RCSfile: NoopDrawingSurfaceObject.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The DrawingSurfaceObject class is used to manage native drawing surface + */ +class NoopDrawingSurfaceObject extends DrawingSurfaceObject { + + NoopDrawingSurfaceObject(Canvas3D cv) { + super(cv); + + System.err.println("NoopDrawingSurfaceObject constructed"); + } + + synchronized boolean renderLock() { +// System.err.println("NoopDrawingSurfaceObject.renderLock()"); + gotDsiLock = true; + return true; + } + + synchronized void unLock() { +// System.err.println("NoopDrawingSurfaceObject.unLock()"); + gotDsiLock = false; + } + + synchronized void getDrawingSurfaceObjectInfo() { + if (canvas.drawable == null) { + System.err.println( + "NoopDrawingSurfaceObject.getDrawingSurfaceObjectInfo: window = " + + canvas.drawable); + + canvas.drawable = new NoopDrawable(); + } + } + + synchronized void invalidate() { + System.err.println("NoopDrawingSurfaceObject.invalidate()"); + } + + /** + * Dummy drawable for noop pipeline + */ + static class NoopDrawable implements Drawable { + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NoopPipeline.java b/j3d-core/src/classes/share/javax/media/j3d/NoopPipeline.java new file mode 100644 index 0000000..2e2acb9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NoopPipeline.java @@ -0,0 +1,1569 @@ +/* + * $RCSfile: NoopPipeline.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; + +/** + * Concrete implementation of Pipeline class for the noop rendering + * pipeline. + */ +class NoopPipeline extends Pipeline { + + // Flags indicating whether the Cg or GLSL libraries are available. + private boolean cgLibraryAvailable = false; + + /** + * Constructor for singleton NoopPipeline instance + */ + protected NoopPipeline() { + } + + /** + * Initialize the pipeline + */ + void initialize(Pipeline.Type pipelineType) { + super.initialize(pipelineType); + + assert pipelineType == Pipeline.Type.NOOP; + } + + /** + * Load all of the required libraries + */ + void loadLibraries(int globalShadingLanguage) { + } + + /** + * Returns true if the Cg library is loaded and available. Note that this + * does not necessarily mean that Cg is supported by the graphics card. + */ + boolean isCgLibraryAvailable() { + return cgLibraryAvailable; + } + + /** + * Returns true if the GLSL library is loaded and available. Note that this + * does not necessarily mean that GLSL is supported by the graphics card. + */ + boolean isGLSLLibraryAvailable() { + return true; + } + + + // --------------------------------------------------------------------- + + // + // GeometryArrayRetained methods + // + + // Used by D3D to free vertex buffer + void freeD3DArray(GeometryArrayRetained geo, boolean deleteVB) { + } + + // used for GeometryArrays by Copy or interleaved + void execute(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + int vertexAttrCount, int[] vertexAttrSizes, + float[] varray, float[] cdata, int cdirty) { + } + + // used by GeometryArray by Reference with java arrays + void executeVA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, float[] vfcoords, double[] vdcoords, + int colorIndex, float[] cfdata, byte[] cbdata, + int normalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty) { + } + + // used by GeometryArray by Reference with NIO buffer + void executeVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, + Object vcoords, + int colorIndex, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + int normalIndex, Object ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, Object[] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty) { + } + + // used by GeometryArray by Reference in interleaved format with NIO buffer + void executeInterleavedBuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + Object varray, float[] cdata, int cdirty) { + } + + void setVertexFormat(Context ctx, GeometryArrayRetained geo, + int vformat, boolean useAlpha, boolean ignoreVertexColors) { + } + + void disableGlobalAlpha(Context ctx, GeometryArrayRetained geo, int vformat, + boolean useAlpha, boolean ignoreVertexColors) { + } + + // used for GeometryArrays + void buildGA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int startVIndex, + int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, int[] texCoordSetMapOffset, + int vertexAttrCount, int[] vertexAttrSizes, + double[] xform, double[] nxform, + float[] varray) { + } + + // used to Build Dlist GeometryArray by Reference with java arrays + void buildGAForByRef(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int coordIndex, float[] vfcoords, double[] vdcoords, + int colorIndex, float[] cfdata, byte[] cbdata, + int normalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndex, float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int[] texIndex, int texstride, Object[] texCoords, + double[] xform, double[] nxform) { + } + + + // --------------------------------------------------------------------- + + // + // IndexedGeometryArrayRetained methods + // + + // by-copy or interleaved, by reference, Java arrays + void executeIndexedGeometry(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + float[] varray, float[] cdata, + int cdirty, + int[] indexCoord) { + } + + // interleaved, by reference, nio buffer + void executeIndexedGeometryBuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + Object varray, float[] cdata, + int cdirty, + int[] indexCoord) { + } + + // non interleaved, by reference, Java arrays + void executeIndexedGeometryVA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + float[] vfcoords, double[] vdcoords, + float[] cfdata, byte[] cbdata, + float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + float[][] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texstride, Object[] texCoords, + int cdirty, + int[] indexCoord) { + } + + // non interleaved, by reference, nio buffer + void executeIndexedGeometryVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + Object vcoords, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + Object normal, + int vertexAttrCount, int[] vertexAttrSizes, + Object[] vertexAttrData, + int texcoordmaplength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texstride, Object[] texCoords, + int cdirty, + int[] indexCoord) { + } + + // by-copy geometry + void buildIndexedGeometry(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetMapOffset, + double[] xform, double[] nxform, + float[] varray, int[] indexCoord) { + } + + + // --------------------------------------------------------------------- + + // + // GraphicsContext3D methods + // + + void readRaster(Context ctx, + int type, int xSrcOffset, int ySrcOffset, + int width, int height, int hCanvas, + int imageDataType, int imageFormat, + Object imageBuffer, + int depthFormat, + Object depthBuffer) { + + } + + // --------------------------------------------------------------------- + + // + // CgShaderProgramRetained methods + // + + // ShaderAttributeValue methods + + ShaderError setCgUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + return null; + } + + ShaderError setCgUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + return null; + } + + ShaderError setCgUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return null; + } + + ShaderError setCgUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + ShaderError setCgUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return null; + } + + ShaderError setCgUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + ShaderError setCgUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return null; + } + + ShaderError setCgUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + ShaderError setCgUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + ShaderError setCgUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + // ShaderAttributeArray methods + + ShaderError setCgUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return null; + } + + ShaderError setCgUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setCgUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return null; + } + + ShaderError setCgUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setCgUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return null; + } + + ShaderError setCgUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setCgUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return null; + } + + ShaderError setCgUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setCgUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setCgUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + // interfaces for shader compilation, etc. + ShaderError createCgShader(Context ctx, int shaderType, ShaderId[] shaderId) { + return null; + } + ShaderError destroyCgShader(Context ctx, ShaderId shaderId) { + return null; + } + ShaderError compileCgShader(Context ctx, ShaderId shaderId, String program) { + return null; + } + + ShaderError createCgShaderProgram(Context ctx, ShaderProgramId[] shaderProgramId) { + return null; + } + ShaderError destroyCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return null; + } + ShaderError linkCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId, + ShaderId[] shaderIds) { + return null; + } + void lookupCgVertexAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, boolean[] errArr) { + } + void lookupCgShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, ShaderAttrLoc[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr) { + } + + ShaderError useCgShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return null; + } + + + // --------------------------------------------------------------------- + + // + // GLSLShaderProgramRetained methods + // + + // ShaderAttributeValue methods + + ShaderError setGLSLUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + return null; + } + + ShaderError setGLSLUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + return null; + } + + ShaderError setGLSLUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return null; + } + + ShaderError setGLSLUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + ShaderError setGLSLUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return null; + } + + ShaderError setGLSLUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + ShaderError setGLSLUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + return null; + } + + ShaderError setGLSLUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + ShaderError setGLSLUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + ShaderError setGLSLUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + return null; + } + + // ShaderAttributeArray methods + + ShaderError setGLSLUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return null; + } + + ShaderError setGLSLUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setGLSLUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return null; + } + + ShaderError setGLSLUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setGLSLUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return null; + } + + ShaderError setGLSLUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setGLSLUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + return null; + } + + ShaderError setGLSLUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setGLSLUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + ShaderError setGLSLUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + return null; + } + + // interfaces for shader compilation, etc. + ShaderError createGLSLShader(Context ctx, int shaderType, ShaderId[] shaderId) { + return null; + } + ShaderError destroyGLSLShader(Context ctx, ShaderId shaderId) { + return null; + } + ShaderError compileGLSLShader(Context ctx, ShaderId shaderId, String program) { + return null; + } + + ShaderError createGLSLShaderProgram(Context ctx, ShaderProgramId[] shaderProgramId) { + return null; + } + ShaderError destroyGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return null; + } + ShaderError linkGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId, + ShaderId[] shaderIds) { + return null; + } + ShaderError bindGLSLVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, + String attrName, int attrIndex) { + return null; + } + void lookupGLSLShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, ShaderAttrLoc[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr) { + } + + ShaderError useGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + return null; + } + + + // --------------------------------------------------------------------- + + // + // Renderer methods + // + + void cleanupRenderer() { + } + + + // --------------------------------------------------------------------- + + // + // ColoringAttributesRetained methods + // + + void updateColoringAttributes(Context ctx, + float dRed, float dGreen, float dBlue, + float red, float green, float blue, + float alpha, + boolean lEnable, + int shadeModel) { + } + + + // --------------------------------------------------------------------- + + // + // DirectionalLightRetained methods + // + + void updateDirectionalLight(Context ctx, + int lightSlot, float red, float green, + float blue, float x, float y, float z) { + } + + + // --------------------------------------------------------------------- + + // + // PointLightRetained methods + // + + void updatePointLight(Context ctx, + int lightSlot, float red, float green, + float blue, float ax, float ay, float az, + float px, float py, float pz) { + } + + + // --------------------------------------------------------------------- + + // + // SpotLightRetained methods + // + + void updateSpotLight(Context ctx, + int lightSlot, float red, float green, + float blue, float ax, float ay, float az, + float px, float py, float pz, float spreadAngle, + float concentration, float dx, float dy, + float dz) { + } + + + // --------------------------------------------------------------------- + + // + // ExponentialFogRetained methods + // + + void updateExponentialFog(Context ctx, + float red, float green, float blue, + float density) { + } + + + // --------------------------------------------------------------------- + + // + // LinearFogRetained methods + // + + void updateLinearFog(Context ctx, + float red, float green, float blue, + double fdist, double bdist) { + } + + + // --------------------------------------------------------------------- + + // + // LineAttributesRetained methods + // + + void updateLineAttributes(Context ctx, + float lineWidth, int linePattern, + int linePatternMask, + int linePatternScaleFactor, + boolean lineAntialiasing) { + } + + + // --------------------------------------------------------------------- + + // + // MaterialRetained methods + // + + void updateMaterial(Context ctx, + float red, float green, float blue, float alpha, + float ared, float agreen, float ablue, + float ered, float egreen, float eblue, + float dred, float dgreen, float dblue, + float sred, float sgreen, float sblue, + float shininess, int colorTarget, boolean enable) { + } + + + // --------------------------------------------------------------------- + + // + // ModelClipRetained methods + // + + void updateModelClip(Context ctx, int planeNum, boolean enableFlag, + double A, double B, double C, double D) { + } + + + // --------------------------------------------------------------------- + + // + // PointAttributesRetained methods + // + + void updatePointAttributes(Context ctx, float pointSize, boolean pointAntialiasing) { + } + + + // --------------------------------------------------------------------- + + // + // PolygonAttributesRetained methods + // + + void updatePolygonAttributes(Context ctx, + int polygonMode, int cullFace, + boolean backFaceNormalFlip, + float polygonOffset, + float polygonOffsetFactor) { + } + + + // --------------------------------------------------------------------- + + // + // RenderingAttributesRetained methods + // + + void updateRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride, + boolean depthBufferEnable, + boolean depthBufferWriteEnable, + int depthTestFunction, + float alphaTestValue, int alphaTestFunction, + boolean ignoreVertexColors, + boolean rasterOpEnable, int rasterOp, + boolean userStencilAvailable, boolean stencilEnable, + int stencilFailOp, int stencilZFailOp, int stencilZPassOp, + int stencilFunction, int stencilReferenceValue, + int stencilCompareMask, int stencilWriteMask ) { + } + + + // --------------------------------------------------------------------- + + // + // TexCoordGenerationRetained methods + // + + /** + * This method updates the native context: + * trans contains eyeTovworld transform in d3d + * trans contains vworldToEye transform in ogl + */ + void updateTexCoordGeneration(Context ctx, + boolean enable, int genMode, int format, + float planeSx, float planeSy, float planeSz, float planeSw, + float planeTx, float planeTy, float planeTz, float planeTw, + float planeRx, float planeRy, float planeRz, float planeRw, + float planeQx, float planeQy, float planeQz, float planeQw, + double[] trans) { + } + + + // --------------------------------------------------------------------- + + // + // TransparencyAttributesRetained methods + // + + void updateTransparencyAttributes(Context ctx, + float alpha, int geometryType, + int polygonMode, + boolean lineAA, boolean pointAA, + int transparencyMode, + int srcBlendFunction, + int dstBlendFunction) { + } + + + // --------------------------------------------------------------------- + + // + // TextureAttributesRetained methods + // + + void updateTextureAttributes(Context ctx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, float red, + float green, float blue, float alpha, + int textureFormat) { + } + + void updateRegisterCombiners(Context ctx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, float red, + float green, float blue, float alpha, + int textureFormat, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale) { + } + + void updateTextureColorTable(Context ctx, int numComponents, + int colorTableSize, + int[] colorTable) { + } + + void updateCombiner(Context ctx, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale) { + } + + + // --------------------------------------------------------------------- + + // + // TextureUnitStateRetained methods + // + + void updateTextureUnitState(Context ctx, int unitIndex, boolean enableFlag) { + } + + + // --------------------------------------------------------------------- + + // + // TextureRetained methods + // Texture2DRetained methods + // + + void bindTexture2D(Context ctx, int objectId, boolean enable) { + } + + void updateTexture2DImage(Context ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int imageDataType, Object data, boolean useAutoMipMap) { + } + + void updateTexture2DSubImage(Context ctx, + int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int imageDataType, Object data, boolean useAutoMipMap) { + } + + void updateTexture2DLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + } + + void updateTexture2DLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + } + + void updateTexture2DBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + } + + void updateTexture2DFilterModes(Context ctx, + int minFilter, int magFilter) { + } + + void updateTexture2DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + } + + void updateTexture2DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + } + + void updateTexture2DAnisotropicFilter(Context ctx, float degree) { + } + + + // --------------------------------------------------------------------- + + // + // Texture3DRetained methods + // + + void bindTexture3D(Context ctx, int objectId, boolean enable) { + } + + void updateTexture3DImage(Context ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, int depth, + int boundaryWidth, + int imageDataType, Object imageData, boolean useAutoMipMap) { + } + + void updateTexture3DSubImage(Context ctx, + int level, + int xoffset, int yoffset, int zoffset, + int textureFormat, int imageFormat, + int imgXoffset, int imgYoffset, int imgZoffset, + int tilew, int tileh, + int width, int height, int depth, + int imageTypeData, Object imageData, boolean useAutoMipMap) { + } + + void updateTexture3DLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + } + + void updateTexture3DLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + } + + void updateTexture3DBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + int boundaryModeR, float boundaryRed, + float boundaryGreen, float boundaryBlue, + float boundaryAlpha) { + } + + void updateTexture3DFilterModes(Context ctx, + int minFilter, int magFilter) { + } + + void updateTexture3DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + } + + void updateTexture3DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + } + + void updateTexture3DAnisotropicFilter(Context ctx, float degree) { + } + + + // --------------------------------------------------------------------- + + // + // TextureCubeMapRetained methods + // + + void bindTextureCubeMap(Context ctx, int objectId, boolean enable) { + } + + void updateTextureCubeMapImage(Context ctx, + int face, int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int imageDataType, Object imageData, boolean useAutoMipMap) { + } + + void updateTextureCubeMapSubImage(Context ctx, + int face, int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int imageDataType, Object imageData, boolean useAutoMipMap) { + } + + void updateTextureCubeMapLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + } + + void updateTextureCubeMapLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + } + + void updateTextureCubeMapBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + } + + void updateTextureCubeMapFilterModes(Context ctx, + int minFilter, int magFilter) { + } + + void updateTextureCubeMapSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + } + + void updateTextureCubeMapFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + } + + void updateTextureCubeMapAnisotropicFilter(Context ctx, float degree) { + } + + // --------------------------------------------------------------------- + + // + // MasterControl methods + // + + // Method to return the AWT object + long getAWT() { + return 0L; + } + + // Method to initialize the native J3D library + boolean initializeJ3D(boolean disableXinerama) { + return true; + } + + // Maximum lights supported by the native API + int getMaximumLights() { + return 8; + } + + + // --------------------------------------------------------------------- + + // + // Canvas3D methods - native wrappers + // + + // This is the native method for creating the underlying graphics context. + Context createNewContext(Canvas3D cv, long display, Drawable drawable, + long fbConfig, Context shareCtx, boolean isSharedCtx, + boolean offScreen, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + return new NoopContext(); + } + + void createQueryContext(Canvas3D cv, long display, Drawable drawable, + long fbConfig, boolean offScreen, int width, int height, + boolean glslLibraryAvailable, + boolean cgLibraryAvailable) { + } + + // This is the native for creating offscreen buffer + Drawable createOffScreenBuffer(Canvas3D cv, Context ctx, long display, long fbConfig, int width, int height) { + return null; + } + + void destroyOffScreenBuffer(Canvas3D cv, Context ctx, long display, long fbConfig, Drawable drawable) { + } + + // This is the native for reading the image from the offscreen buffer + void readOffScreenBuffer(Canvas3D cv, Context ctx, int format, int type, Object data, int width, int height) { + } + + // The native method for swapBuffers + int swapBuffers(Canvas3D cv, Context ctx, long dpy, Drawable drawable) { + return 0; + } + + // notify D3D that Canvas is resize + int resizeD3DCanvas(Canvas3D cv, Context ctx) { + return 0; + } + + // notify D3D to toggle between FullScreen and window mode + int toggleFullScreenMode(Canvas3D cv, Context ctx) { + return 0; + } + + // native method for setting Material when no material is present + void updateMaterialColor(Context ctx, float r, float g, float b, float a) { + } + + void destroyContext(long display, Drawable drawable, Context ctx) { + } + + // This is the native method for doing accumulation. + void accum(Context ctx, float value) { + } + + // This is the native method for doing accumulation return. + void accumReturn(Context ctx) { + } + + // This is the native method for clearing the accumulation buffer. + void clearAccum(Context ctx) { + } + + // This is the native method for getting the number of lights the underlying + // native library can support. + int getNumCtxLights(Context ctx) { + return 0; + } + + // Native method for decal 1st child setup + boolean decal1stChildSetup(Context ctx) { + return false; + } + + // Native method for decal nth child setup + void decalNthChildSetup(Context ctx) { + } + + // Native method for decal reset + void decalReset(Context ctx, boolean depthBufferEnable) { + } + + // Native method for decal reset + void ctxUpdateEyeLightingEnable(Context ctx, boolean localEyeLightingEnable) { + } + + // The following three methods are used in multi-pass case + + // native method for setting blend color + void setBlendColor(Context ctx, float red, float green, + float blue, float alpha) { + } + + // native method for setting blend func + void setBlendFunc(Context ctx, int src, int dst) { + } + + // native method for setting fog enable flag + void setFogEnableFlag(Context ctx, boolean enableFlag) { + } + + // Setup the full scene antialising in D3D and ogl when GL_ARB_multisamle supported + void setFullSceneAntialiasing(Context ctx, boolean enable) { + } + + void setGlobalAlpha(Context ctx, float alpha) { + } + + // Native method to update separate specular color control + void updateSeparateSpecularColorEnable(Context ctx, boolean control) { + } + + // Initialization for D3D when scene begin + void beginScene(Context ctx) { + } + void endScene(Context ctx) { + } + + // True under Solaris, + // False under windows when display mode <= 8 bit + boolean validGraphicsMode() { + return true; + } + + // native method for setting light enables + void setLightEnables(Context ctx, long enableMask, int maxLights) { + } + + // native method for setting scene ambient + void setSceneAmbient(Context ctx, float red, float green, float blue) { + } + + // native method for disabling fog + void disableFog(Context ctx) { + } + + // native method for disabling modelClip + void disableModelClip(Context ctx) { + } + + // native method for setting default RenderingAttributes + void resetRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride) { + } + + // native method for setting default texture + void resetTextureNative(Context ctx, int texUnitIndex) { + } + + // native method for activating a particular texture unit + void activeTextureUnit(Context ctx, int texUnitIndex) { + } + + // native method for setting default TexCoordGeneration + void resetTexCoordGeneration(Context ctx) { + } + + // native method for setting default TextureAttributes + void resetTextureAttributes(Context ctx) { + } + + // native method for setting default PolygonAttributes + void resetPolygonAttributes(Context ctx) { + } + + // native method for setting default LineAttributes + void resetLineAttributes(Context ctx) { + } + + // native method for setting default PointAttributes + void resetPointAttributes(Context ctx) { + } + + // native method for setting default TransparencyAttributes + void resetTransparency(Context ctx, int geometryType, + int polygonMode, boolean lineAA, + boolean pointAA) { + } + + // native method for setting default ColoringAttributes + void resetColoringAttributes(Context ctx, + float r, float g, + float b, float a, + boolean enableLight) { + } + + /** + * This native method makes sure that the rendering for this canvas + * gets done now. + */ + void syncRender(Context ctx, boolean wait) { + } + + // The native method that sets this ctx to be the current one + boolean useCtx(Context ctx, long display, Drawable drawable) { + return true; + } + + void clear(Context ctx, float r, float g, float b, boolean clearStencil) { + + } + + void textureFillBackground(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, boolean useBiliearFilter) { + + } + + void textureFillRaster(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, float mapZ, float alpha, + boolean useBiliearFilter) { + + } + + void executeRasterDepth(Context ctx, float posX, float posY, float posZ, + int srcOffsetX, int srcOffsetY, int rasterWidth, int rasterHeight, + int depthWidth, int depthHeight, int depthType, Object depthData) { + + } + + // The native method for setting the ModelView matrix. + void setModelViewMatrix(Context ctx, double[] viewMatrix, double[] modelMatrix) { + } + + // The native method for setting the Projection matrix. + void setProjectionMatrix(Context ctx, double[] projMatrix) { + } + + // The native method for setting the Viewport. + void setViewport(Context ctx, int x, int y, int width, int height) { + } + + // used for display Lists + void newDisplayList(Context ctx, int displayListId) { + } + void endDisplayList(Context ctx) { + } + void callDisplayList(Context ctx, int id, boolean isNonUniformScale) { + } + + void freeDisplayList(Context ctx, int id) { + } + void freeTexture(Context ctx, int id) { + } + + void texturemapping(Context ctx, + int px, int py, + int xmin, int ymin, int xmax, int ymax, + int texWidth, int texHeight, + int rasWidth, + int format, int objectId, + byte[] image, + int winWidth, int winHeight) { + } + + boolean initTexturemapping(Context ctx, int texWidth, + int texHeight, int objectId) { + return true; + } + + + // Set internal render mode to one of FIELD_ALL, FIELD_LEFT or + // FIELD_RIGHT. Note that it is up to the caller to ensure that + // stereo is available before setting the mode to FIELD_LEFT or + // FIELD_RIGHT. The boolean isTRUE for double buffered mode, FALSE + // foe single buffering. + void setRenderMode(Context ctx, int mode, boolean doubleBuffer) { + } + + // Set glDepthMask. + void setDepthBufferWriteEnable(Context ctx, boolean mode) { + } + + + // --------------------------------------------------------------------- + + // + // Canvas3D / GraphicsConfigTemplate3D methods - logic dealing with + // native graphics configuration or drawing surface + // + + // Return a graphics config based on the one passed in. Note that we can + // assert that the input config is non-null and was created from a + // GraphicsConfigTemplate3D. + // This method must return a valid GraphicsConfig, or else it must throw + // an exception if one cannot be returned. + GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) { + System.err.println("NoopPipeline.getGraphicsConfig()"); + return gconfig; + } + + // Get the native FBconfig pointer + long getFbConfig(GraphicsConfigInfo gcInfo) { + return 0L; + } + + + // Get best graphics config from pipeline + GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate3D gct, + GraphicsConfiguration[] gc) { + + GraphicsConfiguration gc1 = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + // We need to cache the GraphicsTemplate3D + synchronized (Canvas3D.graphicsConfigTable) { + if (Canvas3D.graphicsConfigTable.get(gc1) == null) { + GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(gct); +// gcInfo.setPrivateData(privateData); + Canvas3D.graphicsConfigTable.put(gc1, gcInfo); + } + } + return gc1; + } + + // Determine whether specified graphics config is supported by pipeline + boolean isGraphicsConfigSupported(GraphicsConfigTemplate3D gct, + GraphicsConfiguration gc) { + return true; + } + + // Methods to get actual capabilities from Canvas3D + boolean hasDoubleBuffer(Canvas3D cv) { + return true; + } + + boolean hasStereo(Canvas3D cv) { + return false; + } + + int getStencilSize(Canvas3D cv) { + return 0; + } + + boolean hasSceneAntialiasingMultisample(Canvas3D cv) { + return false; + } + + boolean hasSceneAntialiasingAccum(Canvas3D cv) { + return false; + } + + // Methods to get native WS display and screen + long getDisplay() { + return 0L; + } + + int getScreen(GraphicsDevice graphicsDevice) { + return 0; + } + + + // --------------------------------------------------------------------- + + // + // DrawingSurfaceObject methods + // + + // Method to construct a new DrawingSurfaceObject + DrawingSurfaceObject createDrawingSurfaceObject(Canvas3D cv) { + return new NoopDrawingSurfaceObject(cv); + } + + // Method to free the drawing surface object + void freeDrawingSurface(Canvas3D cv, DrawingSurfaceObject drawingSurfaceObject) { + // This method is a no-op + } + + // Method to free the native drawing surface object + void freeDrawingSurfaceNative(Object o) { + // This method is a no-op + } + + /** + * Dummy context for noop pipeline + */ + static class NoopContext implements Context { + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/NotificationThread.java b/j3d-core/src/classes/share/javax/media/j3d/NotificationThread.java new file mode 100644 index 0000000..69fc7cf --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/NotificationThread.java @@ -0,0 +1,142 @@ +/* + * $RCSfile: NotificationThread.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.LinkedList; + +/** + * The NotificationThread class is used for asynchronous error notification, + * such as notifying ShaderError listeners. + */ +class NotificationThread extends Thread { + // action flag for runMonitor + private static final int WAIT = 0; + private static final int NOTIFY = 1; + private static final int STOP = 2; + + private volatile boolean running = true; + private boolean waiting = false; + private boolean ready = false; + + private LinkedList notificationQueue = new LinkedList(); + + /** + * Creates a new instance of NotificationThread + */ + NotificationThread(ThreadGroup t) { + // Only one notification thread for the entire system + super(t, "J3D-NotificationThread"); + } + + /** + * Adds a notification message to the queue + */ + synchronized void addNotification(J3dNotification n) { + notificationQueue.add(n); + runMonitor(NOTIFY); + } + + /** + * Gets the list of queued notification messages + */ + private synchronized J3dNotification[] getNotifications() { + J3dNotification[] notifications = (J3dNotification[])notificationQueue.toArray(new J3dNotification[0]); + notificationQueue.clear(); + return notifications; + } + + /** + * Processes all pending notification messages + */ + private void processNotifications() { + J3dNotification[] notifications = getNotifications(); + + for (int i = 0; i < notifications.length; i++) { + J3dNotification n = notifications[i]; + switch (n.type) { + case J3dNotification.SHADER_ERROR: + n.universe.notifyShaderErrorListeners((ShaderError)n.args[0]); + break; + case J3dNotification.RENDERING_ERROR: + VirtualUniverse.notifyRenderingErrorListeners((RenderingError)n.args[0]); + break; + default: + System.err.println("J3dNotification.processNotifications: unrecognized type = " + n.type); + } + } + } + + // Called from MasterControlThread + void finish() { + runMonitor(STOP); + } + + public void run() { + while (running) { + runMonitor(WAIT); + + processNotifications(); + } +// System.err.println("Notification thread finished"); + } + + + private synchronized void runMonitor(int action) { + switch (action) { + case WAIT: + while (running && !ready) { + waiting = true; + try { + wait(); + } catch (InterruptedException e) { + } + waiting = false; + } + ready = false; + break; + case NOTIFY: + ready = true; + if (waiting) { + notify(); + } + break; + case STOP: + running = false; + notify(); + break; + default: + // Should never get here... + assert(false); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ObjectUpdate.java b/j3d-core/src/classes/share/javax/media/j3d/ObjectUpdate.java new file mode 100644 index 0000000..0bfc1ca --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ObjectUpdate.java @@ -0,0 +1,45 @@ +/* + * $RCSfile: ObjectUpdate.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/* + * A Object Update interface. Any object that can be put in the ObjectUpdate list + * must implement this interface. + */ + +interface ObjectUpdate { + + /** + * The actual update function. + */ + abstract void updateObject(); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/OrderedBin.java b/j3d-core/src/classes/share/javax/media/j3d/OrderedBin.java new file mode 100644 index 0000000..ab415b3 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/OrderedBin.java @@ -0,0 +1,128 @@ +/* + * $RCSfile: OrderedBin.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * An OrderedBin contains an array of OrderedCollection, each represents + * a child of the OrderedGroup + */ +class OrderedBin extends Object { + // ArrayList of orderedCollection, one for each child of the orderedGroup + ArrayList orderedCollections = new ArrayList(); + + // orderedGroup source + OrderedGroupRetained source; + OrderedChildInfo childInfoList= null; + OrderedChildInfo lastChildInfo = null; + + boolean onUpdateList = false; + + // Value of already existing orderedCollection + ArrayList setOCForCI = new ArrayList(); + ArrayList valueOfSetOCForCI = new ArrayList(); + + // Value of orderedCollection based on oi, these arrays + // have size > 0 only during update_view; + ArrayList setOCForOI = new ArrayList(); + ArrayList valueOfSetOCForOI = new ArrayList(); + + OrderedBin(int nchildren, OrderedGroupRetained src){ + int i; + for (i=0; i< nchildren; i++) { + orderedCollections.add(null); + } + source = src; + } + + void addRemoveOrderedCollection() { + int i, index; + + // Add the setValues first, since they reflect already existing + // orderedCollection + for (i = 0; i < setOCForCI.size(); i++) { + index = ((Integer)setOCForCI.get(i)).intValue(); + OrderedCollection oc = (OrderedCollection)valueOfSetOCForCI.get(i); + orderedCollections.set(index, oc); + } + + setOCForCI.clear(); + valueOfSetOCForCI.clear(); + + while (childInfoList != null) { + if (childInfoList.type == OrderedChildInfo.ADD) { + orderedCollections.add(childInfoList.childId, childInfoList.value); + } + else if (childInfoList.type == OrderedChildInfo.REMOVE) { + orderedCollections.remove(childInfoList.childId); + } + childInfoList = childInfoList.next; + } + + // Now update the sets based on oi, since the og.orderedChildIdTable reflects + // the childIds for the next frame, use the table to set the oc at the + // correct place + for (i = 0; i < setOCForOI.size(); i++) { + index = ((Integer)setOCForOI.get(i)).intValue(); + OrderedCollection oc = (OrderedCollection)valueOfSetOCForOI.get(i); + int ci = source.orderedChildIdTable[index]; + orderedCollections.set(ci, oc); + } + setOCForOI.clear(); + valueOfSetOCForOI.clear(); + + onUpdateList = false; + lastChildInfo = null; + + + } + void addChildInfo(OrderedChildInfo cinfo) { + // Add this cinfo at the end + if (childInfoList == null) { + childInfoList = cinfo; + lastChildInfo = cinfo; + } + else { + // Add at the end + cinfo.prev = lastChildInfo; + lastChildInfo.next = cinfo; + cinfo.next = null; + // Update this to be the last child + lastChildInfo = cinfo; + } + + } + +} + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/OrderedChildInfo.java b/j3d-core/src/classes/share/javax/media/j3d/OrderedChildInfo.java new file mode 100644 index 0000000..6238b02 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/OrderedChildInfo.java @@ -0,0 +1,83 @@ +/* + * $RCSfile: OrderedChildInfo.java,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * List of orderedGroup children that needs to be added/removed for + * the next frame. Note that the order in which they are removed and + * added should be maintained after the renderer is done to get the + * correct order of rendering. + */ +class OrderedChildInfo extends Object { + + static int ADD = 0x1; + static int REMOVE = 0x2; + + + /** + * Type of operation, could be add/remove or set + */ + int type; + + /** + * Ordered index at which this operation takes place + */ + int orderedId; + + /** + * Child index at which this operation takes place + */ + int childId; + + /** + * Value of the orderedCollection, only relavent for + * add and set + */ + OrderedCollection value; + + + // Maintains the order in which the ordered children + // were added and removed + OrderedChildInfo next; + OrderedChildInfo prev; + + OrderedChildInfo(int t, int cid, int oid, OrderedCollection val) { + type = t; + orderedId = oid; + childId = cid; + value = val; + prev = null; + next = null; + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/OrderedCollection.java b/j3d-core/src/classes/share/javax/media/j3d/OrderedCollection.java new file mode 100644 index 0000000..a86f4d6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/OrderedCollection.java @@ -0,0 +1,77 @@ +/* + * $RCSfile: OrderedCollection.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + + +/** + * An OrderCollections contains a LightBin and an ArrayList of + * of all top level OrderedGroups under this OrderCollection + */ +class OrderedCollection extends Object implements ObjectUpdate{ + + LightBin lightBin = null; + + // a list of top level orderedBins under this orderedCollection + ArrayList childOrderedBins = new ArrayList(); + + // LightBin used for next frame + LightBin nextFrameLightBin = null; + + // LightBins to be added for this frame + LightBin addLightBins = null; + + boolean onUpdateList = false; + + public void updateObject() { + int i; + LightBin lb; + lightBin = nextFrameLightBin; + if (addLightBins != null) { + if (lightBin != null) { + addLightBins.prev = lightBin; + lightBin.next = addLightBins; + } + else { + lightBin = addLightBins; + nextFrameLightBin = lightBin; + } + } + addLightBins = null; + onUpdateList = false; + } + + + +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/OrderedGroup.java b/j3d-core/src/classes/share/javax/media/j3d/OrderedGroup.java new file mode 100644 index 0000000..03d2a2d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/OrderedGroup.java @@ -0,0 +1,483 @@ +/* + * $RCSfile: OrderedGroup.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Arrays; + +/** + * The OrderedGroup node is a Group that ensures its children render + * in a specified order. In addition to the list of children + * inherited from the base Group class, OrderedGroup defines an + * integer array of child indices that specify the order in which its + * children are rendered. This provides a level of indirection in + * determining the rendering order of its children. By default, the + * child index order array is null, and the children are rendered in + * increasing index order. + * + *

+ * When the child index order array is non-null, it must be the same + * length as the number of children. Every entry in the array must + * have a unique value between 0 and numChildren-1 (i.e., + * there must be no duplicate values and no missing indices). The + * order that the child indices appear in the child index order array + * determines the order in which the children are rendered. The child + * at childIndexOrder[0] is rendered first, followed by + * childIndexOrder[1], and so on, with the child at + * childIndexOrder[numChildren-1] rendered + * last. + * + *

+ * The child index order array only affects rendering. List + * operations that refer to a child by index, such as getChild(index), + * will not be altered by the entries in this array. They will get, + * enumerate, add, remove, etc., the children based on the actual + * index in the group node. However, some of the list operations, + * such as addChild, removeChild, etc., will update the child index + * order array as a result of their operation. For example, + * removeChild will remove the entry in the child index order array + * corresponding to the removed child's index and adjust the remaining + * entries accordingly. See the documentation for these methods for + * more details. + */ + +public class OrderedGroup extends Group { + + private boolean checkArr[] = null; + + /** + * Specifies that this OrderedGroup node + * allows reading its child index order information. + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_CHILD_INDEX_ORDER_READ = + CapabilityBits.ORDERED_GROUP_ALLOW_CHILD_INDEX_ORDER_READ; + + /** + * Specifies that this OrderedGroup node + * allows writing its child index order information. + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_CHILD_INDEX_ORDER_WRITE = + CapabilityBits.ORDERED_GROUP_ALLOW_CHILD_INDEX_ORDER_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_CHILD_INDEX_ORDER_READ + }; + + /** + * Constructs and initializes a new OrderedGroup node object. + * The childIndexOrder array is initialized to null, meaning + * that its children are rendered in increasing index order. + */ + public OrderedGroup() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + + /** + * Sets the childIndexOrder array. If the specified array is + * null, this node's childIndexOrder array is set to null. Its + * children will then be rendered in increasing index order. If + * the specified array is not null, the entire array is copied to + * this node's childIndexOrder array. In this case, the length of + * the array must be equal to the number of children in this + * group, and every entry in the array must have a unique value + * between 0 and numChildren-1 (i.e., there must be + * no duplicate values and no missing indices). + * + * @param childIndexOrder the array that is copied into this + * node's child index order array; this can be null + * + * @exception IllegalArgumentException if the specified array is + * non-null and any of the following are true: + *

    + *
  • childIndexOrder.length != numChildren;
  • + *
  • childIndexOrder[i] < 0, + * for i in [0, numChildren-1];
  • + *
  • childIndexOrder[i] >= numChildren, + * for i in [0, numChildren-1];
  • + *
  • childIndexOrder[i] == + * childIndexOrder[j], + * for i,j in [0, numChildren-1], + * i != j;
  • + *
+ * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setChildIndexOrder(int[] childIndexOrder) { + verifyChildIndexOrderArray(childIndexOrder, 0); + + ((OrderedGroupRetained)retained).setChildIndexOrder(childIndexOrder); + } + + + /** + * Retrieves the current childIndexOrder array. + * + * @return a copy of this node's childIndexOrder array; this + * can be null. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int[] getChildIndexOrder() { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHILD_INDEX_ORDER_READ)) + throw new + CapabilityNotSetException(J3dI18N.getString("OrderedGroup5")); + + return ((OrderedGroupRetained)this.retained).getChildIndexOrder(); + } + + /** + * Appends the specified child node to this group node's list of + * children, and sets the child index order array to the specified + * array. If the specified array is null, this node's + * childIndexOrder array is set to null. Its children will then + * be rendered in increasing index order. If the specified array + * is not null, the entire array is copied to this node's + * childIndexOrder array. In this case, the length of the array + * must be equal to the number of children in this group after the + * new child has been added, and every entry in the array must + * have a unique value between 0 and numChildren-1 + * (i.e., there must be no duplicate values and no missing + * indices). + * + * @param child the child to add to this node's list of children + * + * @param childIndexOrder the array that is copied into this + * node's child index order array; this can be null + * + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * + * @exception RestrictedAccessException if this group node is part + * of live + * or compiled scene graph and the child node being added is not + * a BranchGroup node + * + * @exception MultipleParentException if child has already + * been added as a child of another group node. + * + * @exception IllegalArgumentException if the specified array is + * non-null and any of the following are true: + *
    + *
  • childIndexOrder.length != numChildren;
  • + *
  • childIndexOrder[i] < 0, + * for i in [0, numChildren-1];
  • + *
  • childIndexOrder[i] >= numChildren, + * for i in [0, numChildren-1];
  • + *
  • childIndexOrder[i] == + * childIndexOrder[j], + * for i,j in [0, numChildren-1], + * i != j;
  • + *
+ * + * @since Java 3D 1.3 + */ + public void addChild(Node child, int[] childIndexOrder) { + + verifyAddStates(child); + verifyChildIndexOrderArray(childIndexOrder, 1); + + ((OrderedGroupRetained)retained).addChild(child, childIndexOrder); + + } + + + // Overridden methods from Group + + /** + * Appends the specified child node to this group node's list of children. + * + *

+ * If the current child index order array is non-null, the array + * is increased in size by one element, and a new element + * containing the index of the new child is added to the end of + * the array. Thus, this new child will be rendered last. + * + * @param child the child to add to this node's list of children + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part + * of live + * or compiled scene graph and the child node being added is not + * a BranchGroup node + * @exception MultipleParentException if child has already + * been added as a child of another group node. + * + * @since Java 3D 1.3 + */ + public void addChild(Node child) { + // Just call super -- the extra work is done by the retained class + super.addChild(child); + } + + /** + * Inserts the specified child node in this group node's list of + * children at the specified index. + * This method is only supported when the child index order array + * is null. + * + * @param child the new child + * @param index at which location to insert. The index + * must be a value + * greater than or equal to 0 and less than or equal to + * numChildren(). + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live + * or compiled scene graph and the child node being inserted is not + * a BranchGroup node + * @exception MultipleParentException if child has already + * been added as a child of another group node. + * @exception IndexOutOfBoundsException if index is invalid. + * @exception IllegalStateException if the childIndexOrder array is + * not null. + * + * @since Java 3D 1.3 + */ + public void insertChild(Node child, int index) { + if (((OrderedGroupRetained)retained).userChildIndexOrder != null) { + throw new IllegalStateException(J3dI18N.getString("OrderedGroup6")); + } + + // Just call super -- the extra work is done by the retained class + super.insertChild(child, index); + } + + /** + * Removes the child node at the specified index from this group node's + * list of children. + * + *

+ * If the current child index order array is non-null, the element + * containing the removed child's index will be removed from the + * child index order array, and the array will be reduced in size + * by one element. If the child removed was not the last child in + * the Group, the values of the child index order array will be + * updated to reflect the indices that were renumbered. More + * formally, each child whose index in the Group node was greater + * than the removed element (before removal) will have its index + * decremented by one. + * + * @param index which child to remove. The index + * must be a value + * greater than or equal to 0 and less than numChildren(). + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live or compiled scene graph and the child node being removed is not + * a BranchGroup node + * @exception IndexOutOfBoundsException if index is invalid. + * + * @since Java 3D 1.3 + */ + public void removeChild(int index) { + // Just call super -- the extra work is done by the retained class + super.removeChild(index); + } + + + /** + * Moves the specified branch group node from its existing location to + * the end of this group node's list of children. + * + *

+ * If the current child index order array is non-null, the array + * is increased in size by one element, and a new element + * containing the index of the new child is added to the end of + * the array. Thus, this new child will be rendered last. + * + * @param branchGroup the branch group node to move to this node's list + * of children + * @exception CapabilityNotSetException if the appropriate capability is + * not set and this group node is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void moveTo(BranchGroup branchGroup) { + // Just call super -- the extra work is done by the retained class + super.moveTo(branchGroup); + } + + /** + * Removes the specified child node from this group node's + * list of children. + * If the specified object is not in the list, the list is not modified. + * + *

+ * If the current child index order array is non-null, the element + * containing the removed child's index will be removed from the + * child index order array, and the array will be reduced in size + * by one element. If the child removed was not the last child in + * the Group, the values of the child index order array will be + * updated to reflect the indices that were renumbered. More + * formally, each child whose index in the Group node was greater + * than the removed element (before removal) will have its index + * decremented by one. + * + * @param child the child node to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live or compiled scene graph and the child node being removed is not + * a BranchGroup node + * + * @since Java 3D 1.3 + */ + public void removeChild(Node child) { + // Just call super -- the extra work is done by the retained class + super.removeChild(child); + } + + /** + * Removes all children from this Group node. + * + *

+ * If the current child index order array is non-null, then it is set to + * a zero-length array (the empty set). Note that a zero-length + * child index order array is not the same as a null array in that + * as new elements are added, the child index order array will grow + * and will be used instead of the Group's natural child order. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception RestrictedAccessException if this group node is part of + * live or compiled scene graph and any of the children being removed are + * not BranchGroup nodes + * + * @since Java 3D 1.3 + */ + public void removeAllChildren() { + // Just call super -- the extra work is done by the retained class + super.removeAllChildren(); + } + + + /** + * Creates the retained mode OrderedGroupRetained object that this + * OrderedGroup component object will point to. + */ + void createRetained() { + this.retained = new OrderedGroupRetained(); + this.retained.setSource(this); + } + + void verifyAddStates(Node child) { + + if (child instanceof SharedGroup) { + throw new IllegalArgumentException(J3dI18N.getString("Group2")); + } + + if (isLiveOrCompiled()) { + if (! (child instanceof BranchGroup)) + throw new RestrictedAccessException(J3dI18N.getString("Group12")); + + if(!this.getCapability(ALLOW_CHILDREN_EXTEND)) + throw new CapabilityNotSetException(J3dI18N.getString("Group16")); + } + } + + void verifyChildIndexOrderArray(int[] cIOArr, int plus) { + + if (isLiveOrCompiled()) { + + if(!this.getCapability(ALLOW_CHILD_INDEX_ORDER_WRITE)) + throw new + CapabilityNotSetException(J3dI18N.getString("OrderedGroup4")); + } + + if(cIOArr != null) { + + if(cIOArr.length != (((GroupRetained)retained).children.size() + plus)) { + throw new + IllegalArgumentException(J3dI18N.getString("OrderedGroup0")); + } + + if((checkArr == null) || (checkArr.length != cIOArr.length)) { + checkArr = new boolean[cIOArr.length]; + } + + Arrays.fill(checkArr, false); + + for(int i=0; i= cIOArr.length) { + throw new + IllegalArgumentException(J3dI18N.getString("OrderedGroup2")); + } + else if(checkArr[cIOArr[i]]) { + throw new + IllegalArgumentException(J3dI18N.getString("OrderedGroup3")); + } + else { + checkArr[cIOArr[i]] = true; + } + } + } + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + OrderedGroup og = new OrderedGroup(); + og.duplicateNode(this, forceDuplicate); + return og; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/OrderedGroupRetained.java b/j3d-core/src/classes/share/javax/media/j3d/OrderedGroupRetained.java new file mode 100644 index 0000000..ced6674 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/OrderedGroupRetained.java @@ -0,0 +1,520 @@ +/* + * $RCSfile: OrderedGroupRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * The OrderedGroup is a group node that ensures its children rendered + * in index increasing order. + */ + +class OrderedGroupRetained extends GroupRetained { + // mapping of ordered child id to child index + int orderedChildIdTable[]; + + // This is a counter for ordered child id + private int orderedChildIdCount = 0; + + // This is a vector of free orderedChildId + private ArrayList orderedChildIdFreeList = new ArrayList(); + + // One OrderedBin per view + OrderedBin[] orderedBin = new OrderedBin[0]; + + // child id of the newly added child + Integer newChildId; + + // ChildCount used by renderBin to initialize the + // orderedCollection in each orderedBin (per view) + int childCount = 0; + + // per children ordered path data + ArrayList childrenOrderedPaths = new ArrayList(1); + + + // child index order - set by the user. + int[] userChildIndexOrder = null; + + // child index order - use by j3d internal. + int[] childIndexOrder = null; + + + OrderedGroupRetained() { + this.nodeType = NodeRetained.ORDEREDGROUP; + } + + + void setChildIndexOrder(int[] cIOArr) { + if(cIOArr != null) { + if((userChildIndexOrder == null) || + (userChildIndexOrder.length != cIOArr.length)) { + userChildIndexOrder = new int[cIOArr.length]; + } + + System.arraycopy(cIOArr, 0, userChildIndexOrder, + 0, userChildIndexOrder.length); + } + else { + userChildIndexOrder = null; + } + + if (source.isLive()) { + int[] newArr = new int[cIOArr.length]; + System.arraycopy(cIOArr, 0, newArr, + 0, newArr.length); + J3dMessage m; + m = new J3dMessage(); + m.threads = J3dThread.UPDATE_RENDER; + m.type = J3dMessage.ORDERED_GROUP_TABLE_CHANGED; + m.universe = universe; + m.args[3] = this; + m.args[4] = newArr; + VirtualUniverse.mc.processMessage(m); + } + } + + int[] getChildIndexOrder() { + if (userChildIndexOrder == null) { + return null; + } + + int[] newArr = new int[userChildIndexOrder.length]; + System.arraycopy(userChildIndexOrder, 0, + newArr, 0, userChildIndexOrder.length); + return newArr; + + } + + Integer getOrderedChildId() { + Integer orderedChildId; + synchronized(orderedChildIdFreeList) { + if (orderedChildIdFreeList.size() == 0) { + orderedChildId = new Integer(orderedChildIdCount); + orderedChildIdCount++; + } else { + orderedChildId = (Integer)orderedChildIdFreeList.remove(0); + } + } + return(orderedChildId); + } + + void freeOrderedChildId(int id) { + synchronized(orderedChildIdFreeList) { + orderedChildIdFreeList.add(new Integer(id)); + } + } + + int getOrderedChildCount() { + int count; + + synchronized (orderedChildIdFreeList) { + count = orderedChildIdCount; + } + return count; + } + + void addChild(Node child) { + if(userChildIndexOrder != null) { + doAddChildIndexEntry(); + } + + // GroupRetained.addChild have to check for case of non-null child index order + // array and handle it. + super.addChild(child); + + } + + void addChild(Node child, int[] cIOArr) { + if(cIOArr != null) { + userChildIndexOrder = new int[cIOArr.length]; + + System.arraycopy(cIOArr, 0, userChildIndexOrder, + 0, userChildIndexOrder.length); + } + else { + userChildIndexOrder = null; + } + + // GroupRetained.addChild have to check for case of non-null child + // index order array and handle it. + super.addChild(child); + + } + + void moveTo(BranchGroup bg) { + if(userChildIndexOrder != null) { + doAddChildIndexEntry(); + } + + // GroupRetained.moveto have to check for case of non-null child + // index order array and handle it. + super.moveTo(bg); + } + + + void doRemoveChildIndexEntry(int index) { + + int[] newArr = new int[userChildIndexOrder.length - 1]; + + for(int i=0, j=0; i index) { + newArr[j] = userChildIndexOrder[i] - 1; + j++; + } + else if(userChildIndexOrder[i] < index) { + newArr[j] = userChildIndexOrder[i]; + j++; + } + } + + userChildIndexOrder = newArr; + + } + + void doAddChildIndexEntry() { + int[] newArr = new int[userChildIndexOrder.length + 1]; + + System.arraycopy(userChildIndexOrder, 0, newArr, + 0, userChildIndexOrder.length); + + newArr[userChildIndexOrder.length] = userChildIndexOrder.length; + + userChildIndexOrder = newArr; + } + + /** + * Compiles the children of the OrderedGroup, preventing shape merging at + * this level or above + */ + void compile(CompileState compState) { + + super.compile(compState); + + // don't remove this group node + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + + if (J3dDebug.devPhase && J3dDebug.debug) { + compState.numOrderedGroups++; + } + } + + void setOrderedBin(OrderedBin ob, int index) { + synchronized (orderedBin) { + orderedBin[index] = ob; + } + } + + + // Get the orderedBin for this view index + OrderedBin getOrderedBin(int index) { + OrderedBin ob; + synchronized (orderedBin) { + if (index >= orderedBin.length) { + OrderedBin[] newList = new OrderedBin[index+1]; + for (int i= 0; i < orderedBin.length; i++) { + newList[i] = orderedBin[i]; + } + newList[index] = null; + orderedBin = newList; + } + } + return (orderedBin[index]); + } + + void updateChildIdTableInserted(int childId, int orderedId) { + int size = 0; + int i; + + //System.err.println("updateChildIdTableInserted childId " + childId + " orderedId " + orderedId + " " + this); + if (orderedChildIdTable != null) { + size = orderedChildIdTable.length; + for (i=0; i= childId) { + orderedChildIdTable[i]++; // shift upward + } + } + } + } + if (orderedId >= size) { + int newTable[]; + newTable = new int[orderedId+1]; + if (size > 0) { + System.arraycopy(orderedChildIdTable,0,newTable,0, + orderedChildIdTable.length); + } + else { + for (i = 0; i < newTable.length; i++) { + newTable[i] = -1; + } + } + orderedChildIdTable = newTable; + } + orderedChildIdTable[orderedId] = childId; + //printTable(orderedChildIdTable); + + } + + void updateChildIdTableRemoved(int childId ) { + // If the orderedGroup itself has been clearLived, then the ids + // have been returned, if only some of the children of the + // OGs is removed, then removed the specific entries + // from the table + if (orderedChildIdTable == null) + return; + + for (int i=0; i childId) { + orderedChildIdTable[i]--; // shift downward + } + else if (orderedChildIdTable[i] == childId) { + orderedChildIdTable[i] = -1; + //System.err.println("og.updateChildIdTableRemoved freeId " + i); + freeOrderedChildId(i); + } + } + } + + } + + void setAuxData(SetLiveState s, int index, int hkIndex) { + OrderedPath setLiveStateOrderedPath, newOrderedPath; + ArrayList childOrderedPaths; + NodeRetained child; + + setLiveStateOrderedPath = (OrderedPath) s.orderedPaths.get(hkIndex); + for (int i=0; i= 0) { + setAuxData(s, j, hkIndex); + + } else { + MasterControl.getCoreLogger().severe("Can't Find matching hashKey in setNodeData."); + } + } + } + // Note s.orderedPaths is to be updated in GroupRetained.setLive + // for each of its children + } + + void removeNodeData(SetLiveState s) { + + if((inSharedGroup) && (s.keys.length != localToVworld.length)) { + int i, index; + ArrayList childOrderedPaths; + + // Must be in reverse, to preserve right indexing. + for (i = s.keys.length-1; i >= 0; i--) { + index = s.keys[i].equals(localToVworldKeys, 0, + localToVworldKeys.length); + if(index >= 0) { + for (int j=0; jz axis of the object to point at the viewer's eye + * position. This is done regardless of the transforms above this + * OrientedShape3D node in the scene graph. It optionally defines a + * scale value along with a constant scale enable flag that causes + * this node to be scale invariant, subject only to its scale. + * + *

+ * OrientedShape3D is similar in functionality to the Billboard + * behavior, but OrientedShape3D nodes will orient themselves + * correctly for each view, and they can be used within a SharedGroup. + * + *

+ * If the alignment mode is ROTATE_ABOUT_AXIS, then the rotation will be + * around the specified axis. If the alignment mode is + * ROTATE_ABOUT_POINT, then the rotation will be about the specified + * point, with an additional rotation to align the +y axis of the + * TransformGroup with the +y axis in the View. + * + *

+ * If the constant scale enable flag is set, the object will be drawn + * the same size in absolute screen coordinates (meters), regardless + * of the following: any transforms above this OrientedShape3D node in + * the scene graph, the view scale, the window scale, or the effects + * of perspective correction. This is done by scaling the geometry + * about the local origin of this node, such that 1 unit in local + * coordinates is equal to the number of meters specified by this + * node's scale value. If the constant scale enable flag is set to + * false, then the scale is not used. The default scale is 1.0 + * meters. + * + *

+ * OrientedShape3D nodes are ideal for drawing screen-aligned text or + * for drawing roughly-symmetrical objects. A typical use might + * consist of a quadrilateral that contains a texture of a tree. + * + *

+ * Note that in a multiple View system, picking and interestion test + * is done with the primary View only. + * + * @see Billboard + * + * @since Java 3D 1.2 + */ + +public class OrientedShape3D extends Shape3D { + + /** + * Specifies that rotation should be about the specified axis. + * @see #setAlignmentMode + */ + public static final int ROTATE_ABOUT_AXIS = 0; + + /** + * Specifies that rotation should be about the specified point and + * that the children's Y-axis should match the view object's Y-axis. + * @see #setAlignmentMode + */ + public static final int ROTATE_ABOUT_POINT = 1; + + /** + * Specifies that no rotation is done. The OrientedShape3D will + * not be aligned to the view. + * @see #setAlignmentMode + * + * @since Java 3D 1.3 + */ + public static final int ROTATE_NONE = 2; + + + /** + * Specifies that this OrientedShape3D node + * allows reading its alignment mode information. + */ + public static final int ALLOW_MODE_READ = + CapabilityBits.ORIENTED_SHAPE3D_ALLOW_MODE_READ; + + /** + * Specifies that this OrientedShape3D node + * allows writing its alignment mode information. + */ + public static final int ALLOW_MODE_WRITE = + CapabilityBits.ORIENTED_SHAPE3D_ALLOW_MODE_WRITE; + + /** + * Specifies that this OrientedShape3D node + * allows reading its alignment axis information. + */ + public static final int ALLOW_AXIS_READ = + CapabilityBits.ORIENTED_SHAPE3D_ALLOW_AXIS_READ; + + /** + * Specifies that this OrientedShape3D node + * allows writing its alignment axis information. + */ + public static final int ALLOW_AXIS_WRITE = + CapabilityBits.ORIENTED_SHAPE3D_ALLOW_AXIS_WRITE; + + /** + * Specifies that this OrientedShape3D node + * allows reading its rotation point information. + */ + public static final int ALLOW_POINT_READ = + CapabilityBits.ORIENTED_SHAPE3D_ALLOW_POINT_READ; + + /** + * Specifies that this OrientedShape3D node + * allows writing its rotation point information. + */ + public static final int ALLOW_POINT_WRITE = + CapabilityBits.ORIENTED_SHAPE3D_ALLOW_POINT_WRITE; + + /** + * Specifies that this OrientedShape3D node + * allows reading its scale and constant scale enable information. + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_SCALE_READ = + CapabilityBits.ORIENTED_SHAPE3D_ALLOW_SCALE_READ; + + /** + * Specifies that this OrientedShape3D node + * allows writing its scale and constant scale enable information. + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_SCALE_WRITE = + CapabilityBits.ORIENTED_SHAPE3D_ALLOW_SCALE_WRITE; + + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_MODE_READ, + ALLOW_AXIS_READ, + ALLOW_POINT_READ, + ALLOW_SCALE_READ + }; + + /** + * Constructs an OrientedShape3D node with default parameters. + * The default values are as follows: + *

    + * alignment mode : ROTATE_ABOUT_AXIS
    + * alignment axis : Y-axis (0,1,0)
    + * rotation point : (0,0,1)
    + * constant scale enable : false
    + * scale : 1.0
    + *
+ */ + public OrientedShape3D() { + super(); + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + + /** + * Constructs an OrientedShape3D node with the specified geometry + * component, appearance component, mode, and axis. + * The specified axis must not be parallel to the Z + * axis--(0,0,z) for any value of z. It is not + * possible for the +Z axis to point at the viewer's eye + * position by rotating about itself. The target transform will + * be set to the identity if the axis is (0,0,z). + * + * @param geometry the geometry component with which to initialize + * this shape node + * @param appearance the appearance component of the shape node + * @param mode alignment mode, one of: ROTATE_ABOUT_AXIS, + * ROTATE_ABOUT_POINT, or ROTATE_NONE + * @param axis the ray about which the OrientedShape3D rotates + */ + public OrientedShape3D(Geometry geometry, + Appearance appearance, + int mode, + Vector3f axis) { + + super(geometry, appearance); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((OrientedShape3DRetained)retained).initAlignmentMode(mode); + ((OrientedShape3DRetained)retained).initAlignmentAxis(axis); + } + + /** + * Constructs an OrientedShape3D node with the specified geometry + * component, appearance component, mode, and rotation point. + * + * @param geometry the geometry component with which to initialize + * this shape node + * @param appearance the appearance component of the shape node + * @param mode alignment mode, one of: ROTATE_ABOUT_AXIS, + * ROTATE_ABOUT_POINT, or ROTATE_NONE + * @param point the position about which the OrientedShape3D rotates + */ + public OrientedShape3D(Geometry geometry, + Appearance appearance, + int mode, + Point3f point) { + + super(geometry, appearance); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((OrientedShape3DRetained)retained).initAlignmentMode(mode); + ((OrientedShape3DRetained)retained).initRotationPoint(point); + + } + + + /** + * Constructs an OrientedShape3D node with the specified geometry + * component, appearance component, mode, axis, constant scale + * enable flag, and scale + * The specified axis must not be parallel to the Z + * axis--(0,0,z) for any value of z. It is not + * possible for the +Z axis to point at the viewer's eye + * position by rotating about itself. The target transform will + * be set to the identity if the axis is (0,0,z). + * + * @param geometry the geometry component with which to initialize + * this shape node + * @param appearance the appearance component of the shape node + * @param mode alignment mode, one of: ROTATE_ABOUT_AXIS, + * ROTATE_ABOUT_POINT, or ROTATE_NONE + * @param axis the ray about which the OrientedShape3D rotates + * @param constantScaleEnable a flag indicating whether to enable + * constant scale + * @param scale scale value used when constant scale is enabled + * + * @since Java 3D 1.3 + */ + public OrientedShape3D(Geometry geometry, + Appearance appearance, + int mode, + Vector3f axis, + boolean constantScaleEnable, + double scale) { + + super(geometry, appearance); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((OrientedShape3DRetained)retained).initAlignmentMode(mode); + ((OrientedShape3DRetained)retained).initAlignmentAxis(axis); + ((OrientedShape3DRetained)retained). + initConstantScaleEnable(constantScaleEnable); + ((OrientedShape3DRetained)retained).initScale(scale); + } + + /** + * Constructs an OrientedShape3D node with the specified geometry + * component, appearance component, mode, and rotation point. + * + * @param geometry the geometry component with which to initialize + * this shape node + * @param appearance the appearance component of the shape node + * @param mode alignment mode, one of: ROTATE_ABOUT_AXIS, + * ROTATE_ABOUT_POINT, or ROTATE_NONE + * @param point the position about which the OrientedShape3D rotates + * @param constantScaleEnable a flag indicating whether to enable + * constant scale + * @param scale scale value used when constant scale is enabled + * + * @since Java 3D 1.3 + */ + public OrientedShape3D(Geometry geometry, + Appearance appearance, + int mode, + Point3f point, + boolean constantScaleEnable, + double scale) { + + super(geometry, appearance); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((OrientedShape3DRetained)retained).initAlignmentMode(mode); + ((OrientedShape3DRetained)retained).initRotationPoint(point); + ((OrientedShape3DRetained)retained). + initConstantScaleEnable(constantScaleEnable); + ((OrientedShape3DRetained)retained).initScale(scale); + } + + + /** + * Creates the retained mode OrientedShape3DRetained object that this + * OrientedShape3D object will point to. + */ + void createRetained() { + retained = new OrientedShape3DRetained(); + retained.setSource(this); + } + + + /** + * Sets the alignment mode. + * + * @param mode alignment mode, one of: ROTATE_ABOUT_AXIS, + * ROTATE_ABOUT_POINT, or ROTATE_NONE + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAlignmentMode(int mode) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MODE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D0")); + if (isLive()) + ((OrientedShape3DRetained)retained).setAlignmentMode(mode); + else + ((OrientedShape3DRetained)retained).initAlignmentMode(mode); + } + + + /** + * Retrieves the alignment mode. + * + * @return one of: ROTATE_ABOUT_AXIS, ROTATE_ABOUT_POINT, + * or ROTATE_NONE + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getAlignmentMode() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D1")); + return((OrientedShape3DRetained)retained).getAlignmentMode(); + } + + + /** + * Sets the new alignment axis. This is the ray about which this + * OrientedShape3D rotates when the mode is ROTATE_ABOUT_AXIS. + * The specified axis must not be parallel to the Z + * axis--(0,0,z) for any value of z. It is not + * possible for the +Z axis to point at the viewer's eye + * position by rotating about itself. The target transform will + * be set to the identity if the axis is (0,0,z). + * + * @param axis the new alignment axis + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAlignmentAxis(Vector3f axis) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_AXIS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D2")); + if (isLive()) + ((OrientedShape3DRetained)retained).setAlignmentAxis(axis); + else + ((OrientedShape3DRetained)retained).initAlignmentAxis(axis); + } + + + /** + * Sets the new alignment axis. This is the ray about which this + * OrientedShape3D rotates when the mode is ROTATE_ABOUT_AXIS. + * The specified axis must not be parallel to the Z + * axis--(0,0,z) for any value of z. It is not + * possible for the +Z axis to point at the viewer's eye + * position by rotating about itself. The target transform will + * be set to the identity if the axis is (0,0,z). + * + * @param x the x component of the alignment axis + * @param y the y component of the alignment axis + * @param z the z component of the alignment axis + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAlignmentAxis(float x, float y, float z) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_AXIS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D2")); + if (isLive()) + ((OrientedShape3DRetained)retained).setAlignmentAxis(x,y,z); + else + ((OrientedShape3DRetained)retained).initAlignmentAxis(x,y,z); + } + + + /** + * Retrieves the alignment axis of this OrientedShape3D node, + * and copies it into the specified vector. + * + * @param axis the vector that will contain the alignment axis + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getAlignmentAxis(Vector3f axis) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_AXIS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D3")); + ((OrientedShape3DRetained)retained).getAlignmentAxis(axis); + } + + /** + * Sets the new rotation point. This is the point about which the + * OrientedShape3D rotates when the mode is ROTATE_ABOUT_POINT. + * + * @param point the new rotation point + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setRotationPoint(Point3f point) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_POINT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D4")); + if (isLive()) + ((OrientedShape3DRetained)retained).setRotationPoint(point); + else + ((OrientedShape3DRetained)retained).initRotationPoint(point); + } + + + /** + * Sets the new rotation point. This is the point about which the + * OrientedShape3D rotates when the mode is ROTATE_ABOUT_POINT. + * + * @param x the x component of the rotation point + * @param y the y component of the rotation point + * @param z the z component of the rotation point + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setRotationPoint(float x, float y, float z) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_POINT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D4")); + if (isLive()) + ((OrientedShape3DRetained)retained).setRotationPoint(x,y,z); + else + ((OrientedShape3DRetained)retained).initRotationPoint(x,y,z); + } + + + /** + * Retrieves the rotation point of this OrientedShape3D node, + * and copies it into the specified vector. + * + * @param point the point that will contain the rotation point + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getRotationPoint(Point3f point) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_POINT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D5")); + ((OrientedShape3DRetained)retained).getRotationPoint(point); + } + + + /** + * Sets the constant scale enable flag. + * + * @param constantScaleEnable a flag indicating whether to enable + * constant scale + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setConstantScaleEnable(boolean constantScaleEnable) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SCALE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D6")); + + if (isLive()) + ((OrientedShape3DRetained)retained). + setConstantScaleEnable(constantScaleEnable); + else + ((OrientedShape3DRetained)retained). + initConstantScaleEnable(constantScaleEnable); + } + + + /** + * Retrieves the constant scale enable flag. + * + * @return the current constant scale enable flag + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public boolean getConstantScaleEnable() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SCALE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D7")); + + return ((OrientedShape3DRetained)retained).getConstantScaleEnable(); + } + + + /** + * Sets the scale for this OrientedShape3D. This scale is used when + * the constant scale enable flag is set to true. + * + * @param scale the scale value + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setScale(double scale) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SCALE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D8")); + + if (isLive()) + ((OrientedShape3DRetained)retained).setScale(scale); + else + ((OrientedShape3DRetained)retained).initScale(scale); + } + + + /** + * Retrieves the scale value for this OrientedShape3D. + * + * @return the current scale value + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public double getScale() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_SCALE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("OrientedShape3D9")); + + return ((OrientedShape3DRetained)retained).getScale(); + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * cloneNode should be overridden by any user subclassed + * objects. All subclasses must have their cloneNode + * method consist of the following lines: + *

+     *     public Node cloneNode(boolean forceDuplicate) {
+     *         UserSubClass usc = new UserSubClass();
+     *         usc.duplicateNode(this, forceDuplicate);
+     *         return usc;
+     *     }
+     * 
+ * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + OrientedShape3D s = new OrientedShape3D(); + s.duplicateNode(this, forceDuplicate); + return s; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @exception ClassCastException if originalNode is not an instance of + * Shape3D + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + checkDuplicateNode(originalNode, forceDuplicate); + } + + + + /** + * Copies all Shape3D information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + + super.duplicateAttributes(originalNode, forceDuplicate); + OrientedShape3DRetained attr = (OrientedShape3DRetained) + originalNode.retained; + OrientedShape3DRetained rt = (OrientedShape3DRetained) retained; + + rt.setAlignmentMode(attr.getAlignmentMode()); + Vector3f axis = new Vector3f(); + attr.getAlignmentAxis(axis); + rt.setAlignmentAxis(axis); + Point3f point = new Point3f(); + attr.getRotationPoint(point); + rt.setRotationPoint(point); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/OrientedShape3DRenderMethod.java b/j3d-core/src/classes/share/javax/media/j3d/OrientedShape3DRenderMethod.java new file mode 100644 index 0000000..61166b5 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/OrientedShape3DRenderMethod.java @@ -0,0 +1,125 @@ +/* + * $RCSfile: OrientedShape3DRenderMethod.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The OrientedShape3DRenderMethod provides a render method to render + * OrientedShape3D nodes. + * The RenderMethod interface is used to create various ways to render + * different geometries. + */ + +class OrientedShape3DRenderMethod implements RenderMethod { + + public boolean render(RenderMolecule rm, Canvas3D cv, + RenderAtomListInfo ra, int dirtyBits) { + boolean useAlpha; + boolean isNonUniformScale; + Transform3D trans=null; + + useAlpha = rm.useAlpha; + + GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry(); + geo.setVertexFormat((rm.useAlpha && + ((geo.vertexFormat & GeometryArray.COLOR) != 0)), + rm.textureBin.attributeBin.ignoreVertexColors, cv.ctx); + + if (rm.doInfinite) { + cv.updateState(dirtyBits); + while (ra != null) { + trans = ra.infLocalToVworld; + isNonUniformScale = !trans.isCongruent(); + + cv.setModelViewMatrix(cv.ctx, cv.vworldToEc.mat, trans); + ra.geometry().execute(cv, ra.renderAtom, isNonUniformScale, + (useAlpha && ra.geometry().noAlpha), + rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin.ignoreVertexColors); + ra = ra.next; + } + return true; + } + + boolean isVisible = false; // True if any of the RAs is visible. + while (ra != null) { + if (cv.ra == ra.renderAtom) { + if (cv.raIsVisible) { + cv.updateState(dirtyBits); + trans = ra.localToVworld; + isNonUniformScale = !trans.isCongruent(); + + cv.setModelViewMatrix(cv.ctx, cv.vworldToEc.mat, trans); + ra.geometry().execute(cv, ra.renderAtom, isNonUniformScale, + (useAlpha && ra.geometry().noAlpha), + rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin. + ignoreVertexColors); + isVisible = true; + } + } + else { + if (!VirtualUniverse.mc.viewFrustumCulling || + ra.renderAtom.localeVwcBounds.intersect(cv.viewFrustum)) { + cv.updateState(dirtyBits); + cv.raIsVisible = true; + trans = ra.localToVworld; + isNonUniformScale = !trans.isCongruent(); + + cv.setModelViewMatrix(cv.ctx, cv.vworldToEc.mat, trans); + ra.geometry().execute(cv, ra.renderAtom, isNonUniformScale, + (useAlpha && ra.geometry().noAlpha), + rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin. + ignoreVertexColors); + isVisible = true; + } + else { + cv.raIsVisible = false; + } + cv.ra = ra.renderAtom; + + } + ra = ra.next; + + } + + + geo.disableGlobalAlpha(cv.ctx, + (rm.useAlpha && + ((geo.vertexFormat & GeometryArray.COLOR) != 0)), + rm.textureBin.attributeBin.ignoreVertexColors); + return isVisible; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/OrientedShape3DRetained.java b/j3d-core/src/classes/share/javax/media/j3d/OrientedShape3DRetained.java new file mode 100644 index 0000000..28a62a7 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/OrientedShape3DRetained.java @@ -0,0 +1,611 @@ +/* + * $RCSfile: OrientedShape3DRetained.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; + +class OrientedShape3DRetained extends Shape3DRetained { + + static final int ALIGNMENT_CHANGED = LAST_DEFINED_BIT << 1; + static final int AXIS_CHANGED = LAST_DEFINED_BIT << 2; + static final int ROTATION_CHANGED = LAST_DEFINED_BIT << 3; + static final int CONSTANT_SCALE_CHANGED = LAST_DEFINED_BIT << 4; + static final int SCALE_FACTOR_CHANGED = LAST_DEFINED_BIT << 5; + + + int mode = OrientedShape3D.ROTATE_ABOUT_AXIS; + + // Axis about which to rotate. + Vector3f axis = new Vector3f(0.0f, 1.0f, 0.0f); + Point3f rotationPoint = new Point3f(0.0f, 0.0f, 1.0f); + private Vector3d nAxis = new Vector3d(0.0, 1.0, 0.0); // normalized axis + + // reused temporaries + private Point3d viewPosition = new Point3d(); + private Point3d yUpPoint = new Point3d(); + + private Vector3d eyeVec = new Vector3d(); + private Vector3d yUp = new Vector3d(); + private Vector3d zAxis = new Vector3d(); + private Vector3d yAxis = new Vector3d(); + private Vector3d vector = new Vector3d(); + + private AxisAngle4d aa = new AxisAngle4d(); + + private Transform3D xform = new Transform3D(); // used several times + private Transform3D zRotate = new Transform3D(); + + // For scale invariant mode + boolean constantScale = false; + double scaleFactor = 1.0; + + // Frequently used variables for scale invariant computation + // Left and right Vworld to Clip coordinates transforms + private Transform3D left_xform = new Transform3D(); + private Transform3D right_xform = new Transform3D(); + + // Transform for scaling the OrientedShape3D to correct for + // perspective foreshortening + Transform3D scaleXform = new Transform3D(); + + // Variables for converting between clip to local world coords + private Vector4d im_vec[] = {new Vector4d(), new Vector4d()}; + private Vector4d lvec = new Vector4d(); + + boolean orientedTransformDirty = true; + + Transform3D[] orientedTransforms = new Transform3D[1]; + static final double EPSILON = 1.0e-6; + + + /** + * Constructs a OrientedShape3D node with default parameters. + * The default values are as follows: + *

    + * alignment mode : ROTATE_ABOUT_AXIS
    + * alignment axis : Y-axis (0,1,0)
    + * rotation point : (0,0,1)
    + *
+ */ + public OrientedShape3DRetained() { + super(); + this.nodeType = NodeRetained.ORIENTEDSHAPE3D; + } + + // initializes alignment mode + void initAlignmentMode(int mode) { + this.mode = mode; + } + + /** + * Sets the alignment mode. + * @param mode one of: ROTATE_ABOUT_AXIS or ROTATE_ABOUT_POINT + */ + void setAlignmentMode(int mode) { + if (this.mode != mode) { + initAlignmentMode(mode); + sendChangedMessage(ALIGNMENT_CHANGED, new Integer(mode)); + } + } + + /** + * Retrieves the alignment mode. + * @return one of: ROTATE_ABOUT_AXIS or ROTATE_ABOUT_POINT + */ + int getAlignmentMode() { + return(mode); + } + + // initializes alignment axis + void initAlignmentAxis(Vector3f axis) { + initAlignmentAxis(axis.x, axis.y, axis.z); + } + + // initializes alignment axis + void initAlignmentAxis(float x, float y, float z) { + this.axis.set(x,y,z); + double invMag; + invMag = 1.0/Math.sqrt(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); + nAxis.x = (double)axis.x*invMag; + nAxis.y = (double)axis.y*invMag; + nAxis.z = (double)axis.z*invMag; + } + + /** + * Sets the new alignment axis. This is the ray about which this + * OrientedShape3D rotates when the mode is ROTATE_ABOUT_AXIS. + * @param axis the new alignment axis + */ + void setAlignmentAxis(Vector3f axis) { + setAlignmentAxis(axis.x, axis.y, axis.z); + } + + /** + * Sets the new alignment axis. This is the ray about which this + * OrientedShape3D rotates when the mode is ROTATE_ABOUT_AXIS. + * @param x the x component of the alignment axis + * @param y the y component of the alignment axis + * @param z the z component of the alignment axis + */ + void setAlignmentAxis(float x, float y, float z) { + initAlignmentAxis(x,y,z); + + if (mode == OrientedShape3D.ROTATE_ABOUT_AXIS) { + sendChangedMessage(AXIS_CHANGED, new Vector3f(x,y,z)); + } + } + + /** + * Retrieves the alignment axis of this OrientedShape3D node, + * and copies it into the specified vector. + * @param axis the vector that will contain the alignment axis + */ + void getAlignmentAxis(Vector3f axis) { + axis.set(this.axis); + } + + // initializes rotation point + void initRotationPoint(Point3f point) { + rotationPoint.set(point); + } + + // initializes rotation point + void initRotationPoint(float x, float y, float z) { + rotationPoint.set(x,y,z); + } + + /** + * Sets the new rotation point. This is the point about which the + * OrientedShape3D rotates when the mode is ROTATE_ABOUT_POINT. + * @param point the new rotation point + */ + void setRotationPoint(Point3f point) { + setRotationPoint(point.x, point.y, point.z); + } + + /** + * Sets the new rotation point. This is the point about which the + * OrientedShape3D rotates when the mode is ROTATE_ABOUT_POINT. + * @param x the x component of the rotation point + * @param y the y component of the rotation point + * @param z the z component of the rotation point + */ + void setRotationPoint(float x, float y, float z) { + initRotationPoint(x,y,z); + + if (mode == OrientedShape3D.ROTATE_ABOUT_POINT) { + sendChangedMessage(ROTATION_CHANGED, new Point3f(x,y,z)); + } + } + + /** + * Retrieves the rotation point of this OrientedShape3D node, + * and copies it into the specified vector. + * @param axis the point that will contain the rotation point + */ + void getRotationPoint(Point3f point) { + point.set(rotationPoint); + } + + void setConstantScaleEnable(boolean enable) { + if(constantScale != enable) { + initConstantScaleEnable(enable); + sendChangedMessage(CONSTANT_SCALE_CHANGED, new Boolean(enable)); + } + } + + boolean getConstantScaleEnable() { + return constantScale; + } + + void initConstantScaleEnable(boolean cons_scale) { + constantScale = cons_scale; + } + + void setScale(double scale) { + initScale(scale); + if(constantScale) + sendChangedMessage(SCALE_FACTOR_CHANGED, new Double(scale)); + } + + void initScale(double scale) { + scaleFactor = scale; + } + + double getScale() { + return scaleFactor; + } + + void sendChangedMessage(int component, Object attr) { + J3dMessage changeMessage = new J3dMessage(); + changeMessage.type = J3dMessage.ORIENTEDSHAPE3D_CHANGED; + changeMessage.threads = targetThreads ; + changeMessage.universe = universe; + changeMessage.args[0] = getGeomAtomsArray(mirrorShape3D); + changeMessage.args[1] = new Integer(component); + changeMessage.args[2] = attr; + OrientedShape3DRetained[] o3dArr = + new OrientedShape3DRetained[mirrorShape3D.size()]; + mirrorShape3D.toArray(o3dArr); + changeMessage.args[3] = o3dArr; + changeMessage.args[4] = this; + VirtualUniverse.mc.processMessage(changeMessage); + } + + void updateImmediateMirrorObject(Object[] args) { + int component = ((Integer)args[1]).intValue(); + if ((component & (ALIGNMENT_CHANGED | + AXIS_CHANGED | + ROTATION_CHANGED | + CONSTANT_SCALE_CHANGED | + SCALE_FACTOR_CHANGED)) != 0) { + OrientedShape3DRetained[] msArr = (OrientedShape3DRetained[])args[3]; + Object obj = args[2]; + if ((component & ALIGNMENT_CHANGED) != 0) { + int mode = ((Integer)obj).intValue(); + for (int i=0; i< msArr.length; i++) { + msArr[i].initAlignmentMode(mode); + } + } + else if ((component & AXIS_CHANGED) != 0) { + Vector3f axis =(Vector3f) obj; + for (int i=0; i< msArr.length; i++) { + msArr[i].initAlignmentAxis(axis); + } + } + else if ((component & ROTATION_CHANGED) != 0) { + Point3f point =(Point3f) obj; + for (int i=0; i< msArr.length; i++) { + msArr[i].initRotationPoint(point); + } + } + else if((component & CONSTANT_SCALE_CHANGED) != 0) { + boolean bool = ((Boolean)obj).booleanValue(); + for (int i=0; i< msArr.length; i++) { + msArr[i].initConstantScaleEnable(bool); + } + } + else if((component & SCALE_FACTOR_CHANGED) != 0) { + double scale = ((Double)obj).doubleValue(); + for (int i=0; i< msArr.length; i++) { + msArr[i].initScale(scale); + } + } + } + else { + super.updateImmediateMirrorObject(args); + } + } + + + Transform3D getOrientedTransform(int viewIndex) { + synchronized(orientedTransforms) { + if (viewIndex >= orientedTransforms.length) { + Transform3D xform = new Transform3D(); + Transform3D[] newList = new Transform3D[viewIndex+1]; + for (int i = 0; i < orientedTransforms.length; i++) { + newList[i] = orientedTransforms[i]; + } + newList[viewIndex] = xform; + orientedTransforms = newList; + } + else { + if (orientedTransforms[viewIndex] == null) { + orientedTransforms[viewIndex] = new Transform3D(); + } + } + } + return orientedTransforms[viewIndex]; + } + + // called on the parent object + // Should be synchronized so that the user thread does not modify the + // OrientedShape3D params while computing the transform + synchronized void updateOrientedTransform(Canvas3D canvas, int viewIndex) { + double angle = 0.0; + double sign; + boolean status; + + Transform3D orientedxform = getOrientedTransform(viewIndex); + // get viewplatforms's location in virutal world + if (mode == OrientedShape3D.ROTATE_ABOUT_AXIS) { // rotate about axis + canvas.getCenterEyeInImagePlate(viewPosition); + canvas.getImagePlateToVworld(xform); // xform is imagePlateToLocal + xform.transform(viewPosition); + + // get billboard's transform + xform.set(getCurrentLocalToVworld()); + xform.invert(); // xform is now vWorldToLocal + + // transform the eye position into the billboard's coordinate system + xform.transform(viewPosition); + + + // eyeVec is a vector from the local origin to the eye pt in local + eyeVec.set(viewPosition); + eyeVec.normalize(); + + // project the eye into the rotation plane + status = projectToPlane(eyeVec, nAxis); + + if (status) { + // project the z axis into the rotation plane + zAxis.x = 0.0; + zAxis.y = 0.0; + zAxis.z = 1.0; + status = projectToPlane(zAxis, nAxis); + } + if (status) { + + // compute the sign of the angle by checking if the cross product + // of the two vectors is in the same direction as the normal axis + vector.cross(eyeVec, zAxis); + if (vector.dot(nAxis) > 0.0) { + sign = 1.0; + } else { + sign = -1.0; + } + + // compute the angle between the projected eye vector and the + // projected z + + double dot = eyeVec.dot(zAxis); + if (dot > 1.0f) { + dot = 1.0f; + } else if (dot < -1.0f) { + dot = -1.0f; + } + + angle = sign*Math.acos(dot); + + // use -angle because xform is to *undo* rotation by angle + aa.x = nAxis.x; + aa.y = nAxis.y; + aa.z = nAxis.z; + aa.angle = -angle; + orientedxform.set(aa); + } + else { + orientedxform.setIdentity(); + } + + } else { // rotate about point + // Need to rotate Z axis to point to eye, and Y axis to be + // parallel to view platform Y axis, rotating around rotation pt + + // get the eye point + canvas.getCenterEyeInImagePlate(viewPosition); + + // derive the yUp point + yUpPoint.set(viewPosition); + yUpPoint.y += 0.01; // one cm in Physical space + + // transform the points to the Billboard's space + canvas.getImagePlateToVworld(xform); // xform is ImagePlateToVworld + xform.transform(viewPosition); + xform.transform(yUpPoint); + + // get billboard's transform + xform.set(getCurrentLocalToVworld()); + xform.invert(); // xform is vWorldToLocal + + // transfom points to local coord sys + xform.transform(viewPosition); + xform.transform(yUpPoint); + + // Make a vector from viewPostion to 0,0,0 in the BB coord sys + eyeVec.set(viewPosition); + eyeVec.normalize(); + + // create a yUp vector + yUp.set(yUpPoint); + yUp.sub(viewPosition); + yUp.normalize(); + + + // find the plane to rotate z + zAxis.x = 0.0; + zAxis.y = 0.0; + zAxis.z = 1.0; + + // rotation axis is cross product of eyeVec and zAxis + vector.cross(eyeVec, zAxis); // vector is cross product + + // if cross product is non-zero, vector is rotation axis and + // rotation angle is acos(eyeVec.dot(zAxis))); + double length = vector.length(); + if (length > 0.0001) { + double dot = eyeVec.dot(zAxis); + if (dot > 1.0f) { + dot = 1.0f; + } else if (dot < -1.0f) { + dot = -1.0f; + } + angle = Math.acos(dot); + aa.x = vector.x; + aa.y = vector.y; + aa.z = vector.z; + aa.angle = -angle; + zRotate.set(aa); + } else { + // no rotation needed, set to identity (scale = 1.0) + zRotate.set(1.0); + } + + // Transform the yAxis by zRotate + yAxis.x = 0.0; + yAxis.y = 1.0; + yAxis.z = 0.0; + zRotate.transform(yAxis); + + // project the yAxis onto the plane perp to the eyeVec + status = projectToPlane(yAxis, eyeVec); + + + if (status) { + // project the yUp onto the plane perp to the eyeVec + status = projectToPlane(yUp, eyeVec); + } + + if (status) { + // rotation angle is acos(yUp.dot(yAxis)); + double dot = yUp.dot(yAxis); + + // Fix numerical error, otherwise acos return NULL + if (dot > 1.0f) { + dot = 1.0f; + } else if (dot < -1.0f) { + dot = -1.0f; + } + + angle = Math.acos(dot); + + // check the sign by looking a the cross product vs the eyeVec + vector.cross(yUp, yAxis); // vector is cross product + if (eyeVec.dot(vector) < 0) { + angle *= -1; + } + aa.x = eyeVec.x; + aa.y = eyeVec.y; + aa.z = eyeVec.z; + aa.angle = -angle; + xform.set(aa); // xform is now yRotate + + // rotate around the rotation point + vector.x = rotationPoint.x; + vector.y = rotationPoint.y; + vector.z = rotationPoint.z; // vector to translate to RP + orientedxform.set(vector); // translate to RP + orientedxform.mul(xform); // yRotate + orientedxform.mul(zRotate); // zRotate + vector.scale(-1.0); // vector to translate back + xform.set(vector); // xform to translate back + orientedxform.mul(xform); // translate back + } + else { + orientedxform.setIdentity(); + } + + } + //Scale invariant computation + if(constantScale) { + // Back Xform a unit vector to local world coords + canvas.getInverseVworldProjection(left_xform, right_xform); + + // the two endpts of the vector have to be transformed + // individually because the Xform is not affine + im_vec[0].set(0.0, 0.0, 0.0, 1.0); + im_vec[1].set(1.0, 0.0, 0.0, 1.0); + left_xform.transform(im_vec[0]); + left_xform.transform(im_vec[1]); + + left_xform.set(getCurrentLocalToVworld()); + left_xform.invert(); + left_xform.transform(im_vec[0]); + left_xform.transform(im_vec[1]); + lvec.set(im_vec[1]); + lvec.sub(im_vec[0]); + + // We simply need the direction of this vector + lvec.normalize(); + im_vec[0].set(0.0, 0.0, 0.0, 1.0); + im_vec[1].set(lvec); + im_vec[1].w = 1.0; + + // Forward Xfrom to clip coords + left_xform.set(getCurrentLocalToVworld()); + left_xform.transform(im_vec[0]); + left_xform.transform(im_vec[1]); + + canvas.getVworldProjection(left_xform, right_xform); + left_xform.transform(im_vec[0]); + left_xform.transform(im_vec[1]); + + // Perspective division + im_vec[0].x /= im_vec[0].w; + im_vec[0].y /= im_vec[0].w; + im_vec[0].z /= im_vec[0].w; + + im_vec[1].x /= im_vec[1].w; + im_vec[1].y /= im_vec[1].w; + im_vec[1].z /= im_vec[1].w; + + lvec.set(im_vec[1]); + lvec.sub(im_vec[0]); + + // Use the length of this vector to determine the scaling + // factor + double scale = 1/lvec.length(); + + // Convert to meters + scale *= scaleFactor*canvas.getPhysicalWidth()/2; + + // Scale object so that it appears the same size + scaleXform.setScale(scale); + orientedxform.mul(scaleXform); + } + + } + + + private boolean projectToPlane(Vector3d projVec, Vector3d planeVec) { + double dis = planeVec.dot(projVec); + projVec.x = projVec.x - planeVec.x*dis; + projVec.y = projVec.y - planeVec.y*dis; + projVec.z = projVec.z - planeVec.z*dis; + + double length = projVec.length(); + if (length < EPSILON) { // projVec is parallel to planeVec + return false; + } + projVec.scale(1 / length); + return true; + } + + void compile(CompileState compState) { + + super.compile(compState); + + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + + // don't push the static transform to orientedShape3D + // because orientedShape3D is rendered using vertex array; + // it's not worth pushing the transform here + + compState.keepTG = true; + } + + void searchGeometryAtoms(UnorderList list) { + list.add(getGeomAtom(getMirrorShape(key))); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PathInterpolator.java b/j3d-core/src/classes/share/javax/media/j3d/PathInterpolator.java new file mode 100644 index 0000000..4bc02d6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PathInterpolator.java @@ -0,0 +1,297 @@ +/* + * $RCSfile: PathInterpolator.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Enumeration; + +/** + * PathInterpolator behavior. This class defines the base class for + * all Path Interpolators. Subclasses have access to the + * computePathInterpolation() method, which computes the + * currentInterpolationValue given the current time and alpha. + * The method also computes the currentKnotIndex, which is based on + * the currentInterpolationValue. + * The currentInterpolationValue is calculated + * by linearly interpolating among a series of predefined knots + * (using the value generated by the specified Alpha object). + * The first knot must have a value of 0.0 and the last knot must have a + * value of 1.0. An intermediate knot with index k must have a value + * strictly greater than any knot with index less than k. + */ + +public abstract class PathInterpolator extends TransformInterpolator { + + // Array of knots + private float knots[]; + + /** + * This value is the ratio between knot values indicated by + * the currentKnotIndex variable. So if a subclass wanted to + * interpolate between knot values, it would use the currentKnotIndex + * to get the bounding knots for the "real" value, then use the + * currentInterpolationValue to interpolate between the knots. + * To calculate this variable, a subclass needs to call + * the computePathInterpolation(alphaValue) method from the subclass's + * computeTransform() method. Then this variable will hold a valid + * value which can be used in further calculations by the subclass. + */ + protected float currentInterpolationValue; + + /** + * This value is the index of the current base knot value, as + * determined by the alpha function. A subclass wishing to + * interpolate between bounding knots would use this index and + * the one following it, and would use the currentInterpolationValue + * variable as the ratio between these indices. + * To calculate this variable, a subclass needs to call + * the computePathInterpolation(alphaValue) method from the subclass's + * computeTransform() method. Then this variable will hold a valid + * value which can be used in further calculations by the subclass. + */ + protected int currentKnotIndex; + + + /** + * Constructs a PathInterpolator node with a null alpha value and + * a null target of TransformGroup + * + * since Java 3D 1.3 + */ + PathInterpolator() { + } + + + /** + * Constructs a new PathInterpolator object that interpolates + * between the knot values in the knots array. The array of knots + * is copied into this PathInterpolator object. + * @param alpha the alpha object for this interpolator. + * @param knots an array of knot values that specify interpolation + * points. + * + * @deprecated As of Java 3D version 1.3, replaced by + * PathInterpolator(Alpha, TransformGroup, float[]) + */ + public PathInterpolator(Alpha alpha, float[] knots) { + this(alpha, null, knots); + } + + /** + * Constructs a new PathInterpolator object that interpolates + * between the knot values in the knots array. The array of knots + * is copied into this PathInterpolator object. + * @param alpha the alpha object for this interpolator. + * @param target the transformgroup node effected by this pathInterpolator + * @param knots an array of knot values that specify interpolation + * points. + * + * @since Java 3D 1.3 + */ + + public PathInterpolator(Alpha alpha,TransformGroup target, + float[] knots) { + super(alpha, target); + setKnots(knots); + } + + + /** + * Constructs a new PathInterpolator object that interpolates + * between the knot values in the knots array. The array of knots + * is copied into this PathInterpolator object. + * @param alpha the alpha object for this interpolator. + * @param target the transform node effected by this positionInterpolator + * @param axisOfTransform the transform that defines the local coordinate + * @param knots an array of knot values that specify interpolation + * points. + * + * @since Java 3D 1.3 + */ + public PathInterpolator(Alpha alpha,TransformGroup target, Transform3D axisOfTransform, + float[] knots) { + super(alpha, target, axisOfTransform); + setKnots(knots); + } + + /** + * Retrieves the length of the knots array. + * @return the array length + */ + public int getArrayLengths(){ + return knots.length; + } + + + /** + * Sets the knot at the specified index for this interpolator. + * @param index the index to be changed + * @param knot the new knot value + */ + public void setKnot(int index, float knot) { + this.knots[index] = knot; + } + + + /** + * Retrieves the knot at the specified index. + * @param index the index of the value requested + * @return the interpolator's knot value at the associated index + */ + public float getKnot(int index) { + return this.knots[index]; + } + + + /** + * Replaces the existing array of knot values with + * the specified array. The array of knots is copied into this + * interpolator object. Prior to calling this method, + * subclasses should verify that the lengths of the new knots array + * and subclass-specific parameter arrays are the same. + * @param knots a new array of knot values that specify + * interpolation points. + * + * @since Java 3D 1.2 + */ + protected void setKnots(float[] knots) { + if (knots[0] < -0.0001 || knots[0] > 0.0001) { + throw new IllegalArgumentException(J3dI18N.getString("PathInterpolator0")); + } + + if ((knots[knots.length-1] - 1.0f) < -0.0001 || (knots[knots.length-1] - 1.0f) > 0.0001) { + throw new IllegalArgumentException(J3dI18N.getString("PathInterpolator1")); + } + + this.knots = new float[knots.length]; + for (int i = 0; i < knots.length; i++) { + if (i>0 && knots[i] < knots[i-1]) { + throw new IllegalArgumentException(J3dI18N.getString("PathInterpolator2")); + } + this.knots[i] = knots[i]; + } + } + + + /** + * Copies the array of knots from this interpolator + * into the specified array. + * The array must be large enough to hold all of the knots. + * @param knots array that will receive the knots. + * + * @since Java 3D 1.2 + */ + public void getKnots(float[] knots) { + for (int i = 0; i < this.knots.length; i++) { + knots[i] = this.knots[i]; + } + } + + /** + * Computes the base knot index and interpolation value + * given the specified value of alpha and the knots[] array. If + * the index is 0 and there should be no interpolation, both the + * index variable and the interpolation variable are set to 0. + * Otherwise, currentKnotIndex is set to the lower index of the + * two bounding knot points and the currentInterpolationValue + * variable is set to the ratio of the alpha value between these + * two bounding knot points. + * @param alphaValue alpha value between 0.0 and 1.0 + * + * @since Java 3D 1.3 + */ + protected void computePathInterpolation(float alphaValue ) { + + int i; + + for (i = 0; i < knots.length; i++) { + if ((i == 0 && alphaValue <= knots[i]) || + (i > 0 && alphaValue >= knots[i-1] && alphaValue <= knots[i])) { + + if (i==0) { + currentInterpolationValue = 0f; + currentKnotIndex = 0; + } + else { + currentInterpolationValue = + (alphaValue - knots[i-1])/(knots[i] - knots[i-1]); + currentKnotIndex = i - 1; + } + break; + } + } + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * computePathInterpolation(float) + */ + protected void computePathInterpolation() { + float value = this.alpha.value(); + computePathInterpolation(value); + } + + + /** + * Copies all PathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + PathInterpolator pi = (PathInterpolator) originalNode; + + int len = pi.getArrayLengths(); + + // No API available to set knots size + knots = new float[len]; + + for (int i = 0; i < len; i++) + setKnot(i, pi.getKnot(i)); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PhysicalBody.java b/j3d-core/src/classes/share/javax/media/j3d/PhysicalBody.java new file mode 100644 index 0000000..8118485 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PhysicalBody.java @@ -0,0 +1,375 @@ +/* + * $RCSfile: PhysicalBody.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; + +/** + * This object contains a specification of the user's head. + * Attributes of this object are defined in the head coordinate system. + * The orgin is defined to be halfway between the left and right eye + * in the plane of the face. + * The x-axis extends to the right (of the head looking out from the head). + * The y-axis extends up. The z-axis extends to the rear of the head. + * + * @see View + */ + +public class PhysicalBody extends Object { + // The X offset for each eye is 1/2 of the inter-pupilary distance + // This constant specifies the default IPD. + private static final double HALF_IPD = 0.033; + + // These offsets specify the default ear positions relative to the + // "center eye". + private static final double EAR_X = 0.080; + private static final double EAR_Y = -0.030; + private static final double EAR_Z = 0.095; + + /** + * The user's left eye's position in head coordinates. + */ + Point3d leftEyePosition = new Point3d(-HALF_IPD, 0.0, 0.0); + + /** + * The user's right eye's position in head coordinates. + */ + Point3d rightEyePosition = new Point3d(HALF_IPD, 0.0, 0.0); + + /** + * The user's left ear's position in head coordinates. + */ + Point3d leftEarPosition = new Point3d(-EAR_X, EAR_Y, EAR_Z); + + /** + * The user's right ear's position in head coordinates. + */ + Point3d rightEarPosition = new Point3d(EAR_X, EAR_Y, EAR_Z); + + /** + * The user's nominal eye height as measured + * from the ground plane. + */ + double nominalEyeHeightFromGround = 1.68; + + /** + * The amount to offset the system's + * viewpoint from the user's current eye-point. This offset + * distance allows an "Over the shoulder" view of the scene + * as seen by the user. + * + * By default, we will use a Z value of 0.4572 meters (18 inches). + */ + double nominalEyeOffsetFromNominalScreen = 0.4572; + + // Head to head-tracker coordinate system transform. + // If head tracking is enabled, this transform is a calibration + // constant. If head tracking is not enabled, this transform is + // not used. + // This is used in both SCREEN_VIEW and HMD_VIEW modes. + Transform3D headToHeadTracker = new Transform3D(); + + // A list of View Objects that refer to this + ArrayList users = new ArrayList(); + + // Mask that indicates this PhysicalBody's view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + int pbDirtyMask = (View.PB_EYE_POSITION_DIRTY + | View.PB_EAR_POSITION_DIRTY + | View.PB_NOMINAL_EYE_HEIGHT_FROM_GROUND_DIRTY + | View.PB_NOMINAL_EYE_OFFSET_FROM_NOMINAL_SCREEN_DIRTY); + + /** + * Constructs a PhysicalBody object with default parameters. + * The default values are as follows: + *

    + * left eye position : (-0.033, 0.0, 0.0)
    + * right eye position : (0.033, 0.0, 0.0)
    + * left ear position : (-0.080, -0.030, 0.095)
    + * right ear position : (0.080, -0.030, 0.095)
    + * nominal eye height from ground : 1.68
    + * nominal eye offset from nominal screen : 0.4572
    + * head to head tracker transform : identity
    + *
+ */ + public PhysicalBody() { + // Just use the defaults + initHeadToHeadTracker(); + } + + // Add a user to the list of users + synchronized void removeUser(View view) { + int idx = users.indexOf(view); + if (idx >= 0) { + users.remove(idx); + } + } + + // Add a user to the list of users + synchronized void addUser(View view) { + int idx = users.indexOf(view); + if (idx < 0) { + users.add(view); + } + } + + // Add a user to the list of users + synchronized void notifyUsers() { + for (int i=users.size()-1; i>=0; i--) { + View view = (View)users.get(i); + // XXXX: notifyUsers should have a parameter denoting field changed + if (view.soundScheduler != null) { + view.soundScheduler.setListenerFlag( + SoundScheduler.EAR_POSITIONS_CHANGED | + SoundScheduler.EYE_POSITIONS_CHANGED ); + } + view.repaint(); + } + } + + /** + * Constructs and initializes a PhysicalBody object from the + * specified parameters. + * @param leftEyePosition the user's left eye position + * @param rightEyePosition the user's right eye position + */ + public PhysicalBody(Point3d leftEyePosition, Point3d rightEyePosition) { + this.leftEyePosition.set(leftEyePosition); + this.rightEyePosition.set(rightEyePosition); + initHeadToHeadTracker(); + } + + /** + * Constructs and initializes a PhysicalBody object from the + * specified parameters. + * @param leftEyePosition the user's left eye position + * @param rightEyePosition the user's right eye position + * @param leftEarPosition the user's left ear position + * @param rightEarPosition the user's right ear position + */ + public PhysicalBody(Point3d leftEyePosition, + Point3d rightEyePosition, + Point3d leftEarPosition, + Point3d rightEarPosition) { + + this.leftEyePosition.set(leftEyePosition); + this.rightEyePosition.set(rightEyePosition); + this.leftEarPosition.set(leftEarPosition); + this.rightEarPosition.set(rightEarPosition); + initHeadToHeadTracker(); + } + + /** + * Returns a string representation of this PhysicalBody's values. + */ + + public String toString() { + return "eyePosition = (" + this.leftEyePosition + ", " + + this.rightEyePosition + ")\n" + + "earPosition = (" + this.leftEarPosition + ", " + + this.rightEarPosition + ")"; + } + + /** + * Retrieves the user head object's left eye position and places + * that value in the specified object. + * @param position the object that will receive the left-eye's position + * in head coordinates + */ + public void getLeftEyePosition(Point3d position) { + position.set(this.leftEyePosition); + } + + /** + * Sets the user head object's left eye position. + * @param position the left-eye's position in head coordinates + */ + public void setLeftEyePosition(Point3d position) { + synchronized(this) { + this.leftEyePosition.set(position); + pbDirtyMask |= View.PB_EYE_POSITION_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the user head object's right eye position and places + * that value in the specified object. + * @param position the object that will receive the right-eye's position + * in head coordinates + */ + public void getRightEyePosition(Point3d position) { + position.set(this.rightEyePosition); + } + + /** + * Sets the user head object's right eye position. + * @param position the right-eye's position in head coordinates + */ + public void setRightEyePosition(Point3d position) { + synchronized(this) { + this.rightEyePosition.set(position); + pbDirtyMask |= View.PB_EYE_POSITION_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the user head object's left ear position and places + * that value in the specified object. + * @param position the object that will receive the left-ear's position + * in head coordinates + */ + public void getLeftEarPosition(Point3d position) { + position.set(this.leftEarPosition); + } + + /** + * Sets the user head object's left ear position. + * @param position the left-ear's position in head coordinates + */ + public void setLeftEarPosition(Point3d position) { + synchronized(this) { + this.leftEarPosition.set(position); + pbDirtyMask |= View.PB_EAR_POSITION_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the user head object's right ear position and places + * that value in the specified object. + * @param position the object that will receive the right-ear's position + * in head coordinates + */ + public void getRightEarPosition(Point3d position) { + position.set(this.rightEarPosition); + } + + /** + * Sets the user head object's right ear position. + * @param position the right-ear's position in head coordinates + */ + public void setRightEarPosition(Point3d position) { + synchronized(this) { + this.rightEarPosition.set(position); + pbDirtyMask |= View.PB_EAR_POSITION_DIRTY; + } + notifyUsers(); + } + + /** + * Sets the nominal eye height from the ground plane. + * This parameter defines + * the distance from the origin of the user's head (the eyepoint) to + * the ground. + * It is used when the view attach policy is NOMINAL_FEET. + * @param height the nominal height of the eye above the ground plane + */ + public void setNominalEyeHeightFromGround(double height) { + synchronized(this) { + nominalEyeHeightFromGround = height; + pbDirtyMask |= View.PB_NOMINAL_EYE_HEIGHT_FROM_GROUND_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the nominal eye height from the ground plane. + * @return the current nominal eye height above the ground plane + */ + public double getNominalEyeHeightFromGround() { + return nominalEyeHeightFromGround; + } + + /** + * Sets the nominal eye offset from the display screen. + * This parameter defines + * the distance from the origin of the user's head (the eyepoint), in it's + * nominal position, to + * the screen. + * It is used when the view attach policy is NOMINAL_HEAD or NOMINAL_FEET. + * This value is overridden to be the actual eyepoint when the window + * eyepoint policy is RELATIVE_TO_FIELD_OF_VIEW. + * @param offset the nominal offset from the eye to the screen + */ + public void setNominalEyeOffsetFromNominalScreen(double offset) { + synchronized(this) { + nominalEyeOffsetFromNominalScreen = offset; + pbDirtyMask |= View.PB_NOMINAL_EYE_OFFSET_FROM_NOMINAL_SCREEN_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the nominal eye offset from the display screen. + * @return the current nominal offset from the eye to the display screen + */ + public double getNominalEyeOffsetFromNominalScreen() { + return nominalEyeOffsetFromNominalScreen; + } + + /** + * Sets the head to head-tracker coordinate system transform. + * If head tracking is enabled, this transform is a calibration + * constant. If head tracking is not enabled, this transform is + * not used. + * This is used in both SCREEN_VIEW and HMD_VIEW modes. + * @param t the new transform + * @exception BadTransformException if the transform is not rigid + */ + public void setHeadToHeadTracker(Transform3D t) { + if (!t.isRigid()) { + throw new BadTransformException(J3dI18N.getString("PhysicalBody0")); + } + headToHeadTracker.setWithLock(t); + notifyUsers(); + } + + /** + * Retrieves the head to head-tracker coordinate system transform. + * @param t the object that will receive the transform + */ + public void getHeadToHeadTracker(Transform3D t) { + t.set(headToHeadTracker); + } + + // Initialize the head to head-tracker transform + private void initHeadToHeadTracker() { + // By default the center of the crystal eyes tracker is 20mm down + // and 35 mm closer to the screen from the origin of head coordinates + // (the center eye). + Vector3d v = new Vector3d(0.0, 0.020, 0.035); + headToHeadTracker.set(v); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PhysicalEnvironment.java b/j3d-core/src/classes/share/javax/media/j3d/PhysicalEnvironment.java new file mode 100644 index 0000000..02b54c5 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PhysicalEnvironment.java @@ -0,0 +1,532 @@ +/* + * $RCSfile: PhysicalEnvironment.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.awt.*; +import java.util.*; + +/** + * This object contains a specification of the physical environment in + * which the view will be generated. It is used to set up input + * devices (sensors) for head-tracking and other uses, and the audio + * output device. Sensors are indexed starting at zero. + * + * @see View + */ + +public class PhysicalEnvironment extends Object { + /** + * The Sensor Index associated with the Head + */ + int HeadIndex = 0; + + // The Sensor index associated with the Right Hand + int RightHandIndex = 1; + + // The Sensor index associated with the Left Hand + int LeftHandIndex = 2; + + // The current Dominant Hand Sensor Index + int DominantHandIndex = 1; + + // The current Non Dominant Hand Sensor Index + int NonDominantHandIndex = 2; + + // + // Coexistence coordinate system to tracker-base coordinate + // system transform. If head tracking is enabled, this transform + // is a calibration constant. If head tracking is not enabled, + // this transform is not used. + // This is used in both SCREEN_VIEW and HMD_VIEW modes. + // + Transform3D coexistenceToTrackerBase = new Transform3D(); + + // + // Indicates whether the underlying hardware implementation + // supports tracking. + // + boolean trackingAvailable = false; + + // The view associated with this physical environment + // View view; + + // + // This variable specifies the policy Java 3D will use in placing + // the user's eye position relative to the user's head position + // (NOMINAL_SCREEN, NOMINAL_HEAD, or NOMINAL_FEET). + // It is used in the calibration process. + // + // TODO: this needs better explanation in the spec + int coexistenceCenterInPworldPolicy = View.NOMINAL_SCREEN; + + // Mask that indicates this PhysicalEnv's view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + int peDirtyMask = (View.PE_COE_TO_TRACKER_BASE_DIRTY + | View.PE_TRACKING_AVAILABLE_DIRTY + | View.PE_COE_CENTER_IN_PWORLD_POLICY_DIRTY); + + +//// /** +//// * The offset in the user's dominant-hand-tracker coordinates +//// * to that hand's hot spot. This value is a calibration constant. +//// */ +//// Vector3d dominantHandTrackerHotspotOffset; +//// +//// /** +//// * The offset in the user's non-dominant-hand-tracker coordinates +//// * to that hand's hot spot. This value is a calibration constant. +//// */ +//// Vector3d nondominantHandTrackerHotspotOffset; + + // + // The number of sensor stored within the PhysicalEnvironment + // + int sensorCount; + + // + // Array of sensors + // + Sensor[] sensors; + + // Audio device associated with this PhysicalEnvironment + AudioDevice audioDevice = null; + + boolean sensorListChanged = false; + + Sensor[] sensorList = null; + + // A list of View Objects that refer to this + ArrayList users = new ArrayList(); + + // Scheduler for input devices + InputDeviceScheduler inputsched; + + // store all inputDevices + Vector devices = new Vector(1); + + // Number of active view users + int activeViewRef = 0; + + // Hashtable that maps a PhysicalEnvironment to its InputDeviceScheduler + static Hashtable physicalEnvMap = new Hashtable(); + + /** + * Constructs a PhysicalEnvironment object with default parameters. + * The default values are as follows: + *
    + * sensor count : 3
    + * sensors : null (for all array elements)
    + * head index : 0
    + * right hand index : 1
    + * left hand index : 2
    + * dominant hand index : 1
    + * nondominant hand index : 2
    + * tracking available : false
    + * audio device : null
    + * input device list : empty
    + * coexistence to tracker base transform : identity
    + * coexistence center in pworld policy : View.NOMINAL_SCREEN
    + *
+ */ + public PhysicalEnvironment() { + this(3); + } + + // Add a user to the list of users + synchronized void removeUser(View view) { + int idx = users.indexOf(view); + if (idx >= 0) { + users.remove(idx); + } + } + + // Add a user to the list of users + synchronized void addUser(View view) { + int idx = users.indexOf(view); + if (idx < 0) { + users.add(view); + } + } + + // Add a user to the list of users + synchronized void notifyUsers() { + for (int i=users.size()-1; i>=0; i--) { + View view = (View)users.get(i); + view.repaint(); + } + } + + /** + * Constructs and initializes a PhysicalEnvironment object with + * the specified number of sensors. + * @param sensorCount the number of sensors to create. + */ + public PhysicalEnvironment(int sensorCount) { + this.sensorCount = sensorCount; + sensors = new Sensor[sensorCount]; + for(int i=sensorCount-1; i>=0; i--) { + sensors[i] = null; + } + } + + + + /** + * Returns copy of Sensor references. Returns null for zero + * sensors, so user of method must check for null. Also, any of + * these sensors could be null. + */ + Sensor[] getSensorList() { + synchronized(sensors) { + if(sensorListChanged) { // note: this is a rare case + sensorList = new Sensor[sensors.length]; + for(int i=0 ; iPI/64. + */ + public PickCone() { + this.origin = new Point3d(); + this.direction = new Vector3d(); + this.spreadAngle = Math.PI / 64.0; + } + + /** + * Gets the origin of this PickCone. + * @param origin the Point3d object into which the origin will be copied. + */ + public void getOrigin(Point3d origin) { + origin.set(this.origin); + } + + /** + * Gets the direction of this PickCone. + * @param direction the Vector3d object into which the direction + * will be copied. + */ + public void getDirection(Vector3d direction) { + direction.set(this.direction); + } + + + /** + * Gets the spread angle of this PickCone. + * @return the spread angle. + */ + public double getSpreadAngle() { + return spreadAngle; + } + + /** + * Gets the radius of this PickCone at the specified distance. + * @param distance the distance from the origin at which we want + * the radius of the cone + * @return the radius at the specified distance + */ + double getRadius(double distance) { + return distance * Math.tan (spreadAngle); + } + + /** + * Return true if shape intersect with bounds. + * The point of intersection is stored in pickPos. + */ + abstract boolean intersect(Bounds bounds, Point4d pickPos); + + Point3d getStartPoint() { + return origin; + } + + int getPickType() { + return PICKCONE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PickConeRay.java b/j3d-core/src/classes/share/javax/media/j3d/PickConeRay.java new file mode 100644 index 0000000..c4fee7e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PickConeRay.java @@ -0,0 +1,285 @@ +/* + * $RCSfile: PickConeRay.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import com.sun.j3d.internal.Distance; + +/** + * PickConeRay is an infinite cone ray pick shape. It can + * be used as an argument to the picking methods in BranchGroup and Locale. + * + * @see BranchGroup#pickAll + * @see Locale#pickAll + * + * @since Java 3D 1.2 + */ +public final class PickConeRay extends PickCone { + + /** + * Constructs an empty PickConeRay. + * The origin and direction of the cone are + * initialized to (0,0,0). The spread angle is initialized + * to PI/64 radians. + */ + public PickConeRay() { + } + + /** + * Constructs an infinite cone pick shape from the specified + * parameters. + * @param origin the origin of the cone + * @param direction the direction of the cone + * @param spreadAngle the spread angle of the cone in radians + */ + public PickConeRay(Point3d origin, Vector3d direction, double spreadAngle) { + this.origin = new Point3d(origin); + this.direction = new Vector3d(direction); + this.spreadAngle = spreadAngle; + } + + /** + * Sets the parameters of this PickCone to the specified values. + * @param origin the origin of the cone + * @param direction the direction of the cone + * @param spreadAngle the spread angle of the cone in radians + */ + public void set(Point3d origin, Vector3d direction, double spreadAngle) { + this.origin.set(origin); + this.direction.set(direction); + this.spreadAngle = spreadAngle; + } + + /** + * Return true if shape intersect with bounds. + * The point of intersection is stored in pickPos. + * @param bounds the bounds object to check + * @param pickPos the location of the point of intersection (not used for + * method. Provided for compatibility). + */ + final boolean intersect(Bounds bounds, Point4d pickPos) { + + Point4d iPnt = new Point4d(); + Vector3d vector = new Vector3d(); + double distance; + double radius; + Point3d rayPt = new Point3d(); + + // + // ================ BOUNDING SPHERE ================ + // + if (bounds instanceof BoundingSphere) { + Point3d sphCenter = ((BoundingSphere)bounds).getCenter(); + double sphRadius = ((BoundingSphere)bounds).getRadius(); + double sqDist = + Distance.pointToRay (sphCenter, origin, direction, rayPt, null); + vector.sub (rayPt, origin); + distance = vector.length(); + radius = getRadius (distance); + if (sqDist <= (sphRadius+radius)*(sphRadius+radius)) { + return true; + } + return false; // we are too far to intersect + } + // + // ================ BOUNDING BOX ================ + // + else if (bounds instanceof BoundingBox) { + // Calculate radius of BoundingBox + Point3d lower = new Point3d(); + ((BoundingBox)bounds).getLower (lower); + + Point3d center = ((BoundingBox)bounds).getCenter (); + + // First, see if cone is too far away from BoundingBox + double sqDist = + Distance.pointToRay (center, origin, direction, rayPt, null); + + vector.sub (rayPt, origin); + distance = vector.length(); + radius = getRadius (distance); + + double temp = (center.x - lower.x + radius); + double boxRadiusSquared = temp*temp; + temp = (center.y - lower.y + radius); + boxRadiusSquared += temp*temp; + temp = (center.z - lower.z + radius); + boxRadiusSquared += temp*temp; + + + if (sqDist > boxRadiusSquared) { + return false; // we are too far to intersect + } + else if (sqDist < (radius*radius)) { + return true; // center is in cone + } + + // Then, see if ray intersects + if (((BoundingBox)bounds).intersect (origin, direction, iPnt)) { + return true; + } + + // Ray does not intersect, test for distance with each edge + Point3d upper = new Point3d(); + ((BoundingBox)bounds).getUpper (upper); + + Point3d[][] edges = { + // Top horizontal 4 + {upper, new Point3d (lower.x, upper.y, upper.z)}, + {new Point3d(lower.x, upper.y, upper.z), new Point3d(lower.x, lower.y, upper.z)}, + {new Point3d(lower.x, lower.y, upper.z), new Point3d(upper.x, lower.y, upper.z)}, + {new Point3d(upper.x, lower.y, upper.z), upper}, + // Bottom horizontal 4 + {lower, new Point3d(lower.x, upper.y, lower.z)}, + {new Point3d(lower.x, upper.y, lower.z), new Point3d(upper.x, upper.y, lower.z)}, + {new Point3d(upper.x, upper.y, lower.z), new Point3d(upper.x, lower.y, lower.z)}, + {new Point3d(upper.x, lower.y, lower.z), lower}, + // Vertical 4 + {lower, new Point3d(lower.x, lower.y, upper.z)}, + {new Point3d(lower.x, upper.y, lower.z), new Point3d(lower.x, upper.y, upper.z)}, + {new Point3d(upper.x, upper.y, lower.z), new Point3d(upper.x, upper.y, upper.z)}, + {new Point3d(upper.x, lower.y, lower.z), new Point3d(upper.x, lower.y, upper.z)} + }; + + for (int i=0;i (sphRadius+radius)*(sphRadius+radius)) { + return false; // we are too far to intersect + } + + // Now check to see if ray intersects with polytope + if (bounds.intersect (origin, direction, iPnt)) { + return true; + } + + // Now check distance to edges. Since we don't know a priori how + // the polytope is structured, we will cycle through. We discard edges + // when their center is not on the polytope surface. + BoundingPolytope ptope = (BoundingPolytope)bounds; + Point3d midpt = new Point3d(); + double distToEdge; + for (i=0;iPI/64 radians. + */ + public PickConeSegment() { + end = new Point3d(); + } + + /** + * Constructs a finite cone pick shape from the specified + * parameters. + * @param origin the origin of the cone + * @param end the end of the cone along the direction vector + * @param spreadAngle the spread angle of the cone in radians + */ + public PickConeSegment (Point3d origin, Point3d end, double spreadAngle) { + this.origin = new Point3d(origin); + this.end = new Point3d(end); + this.direction = new Vector3d(); + this.spreadAngle = spreadAngle; + calcDirection(); // calculate direction, based on start and end + } + + /** + * Sets the parameters of this PickCone to the specified values. + * @param origin the origin of the cone + * @param end the end of the cone + * @param spreadAngle the spread angle of the cone in radians + */ + public void set(Point3d origin, Point3d end, double spreadAngle) { + this.origin.set(origin); + this.end.set (end); + this.spreadAngle = spreadAngle; + calcDirection(); // calculate direction, based on start and end + } + + /** + * Gets the end point of this PickConeSegment. + * @param end the Point3d object into which the end point + * will be copied. + */ + public void getEnd(Point3d end) { + end.set(this.end); + } + + /** Calculates the direction for this PickCylinderSegment, based on start + and end points. + */ + private void calcDirection() { + this.direction.x = end.x - origin.x; + this.direction.y = end.y - origin.y; + this.direction.z = end.z - origin.z; + } + + /** + * Return true if shape intersect with bounds. + * The point of intersection is stored in pickPos. + * @param bounds the bounds object to check + * @param pickPos the location of the point of intersection (not used for + * method. Provided for compatibility). + */ + final boolean intersect(Bounds bounds, Point4d pickPos) { + Point4d iPnt = new Point4d(); + Vector3d vector = new Vector3d(); + Point3d rayPt = new Point3d(); + + double distance; + double radius; + + // + // ================ BOUNDING SPHERE ================ + // + if (bounds instanceof BoundingSphere) { + Point3d sphCenter = ((BoundingSphere)bounds).getCenter(); + double sphRadius = ((BoundingSphere)bounds).getRadius(); + double sqDist = + Distance.pointToSegment (sphCenter, origin, end, rayPt, null); + + vector.sub (rayPt, origin); + distance = vector.length(); + radius = getRadius (distance); + if (sqDist <= (sphRadius+radius)*(sphRadius+radius)) { + return true; + } + return false; // we are too far to intersect + } + // + // ================ BOUNDING BOX ================ + // + else if (bounds instanceof BoundingBox) { + // Calculate radius of BoundingBox + Point3d lower = new Point3d(); + ((BoundingBox)bounds).getLower (lower); + + Point3d center = ((BoundingBox)bounds).getCenter (); + + // First, see if cone is too far away from BoundingBox + double sqDist = + Distance.pointToSegment (center, origin, end, rayPt, null); + + vector.sub (rayPt, origin); + distance = vector.length(); + radius = getRadius (distance); + + double temp = (center.x - lower.x + radius); + double boxRadiusSquared = temp*temp; + temp = (center.y - lower.y + radius); + boxRadiusSquared += temp*temp; + temp = (center.z - lower.z + radius); + boxRadiusSquared += temp*temp; + + if (sqDist > boxRadiusSquared) { + return false; // we are too far to intersect + } + else if (sqDist < (radius*radius)) { + return true; // center is in cone + } + + // Then, see if ray intersects + if (((BoundingBox)bounds).intersect (origin, direction, iPnt)) { + return true; + } + + // Ray does not intersect, test for distance with each edge + Point3d upper = new Point3d(); + ((BoundingBox)bounds).getUpper (upper); + + Point3d[][] edges = { + // Top horizontal 4 + {upper, new Point3d (lower.x, upper.y, upper.z)}, + {new Point3d(lower.x, upper.y, upper.z), new Point3d(lower.x, lower.y, upper.z)}, + {new Point3d(lower.x, lower.y, upper.z), new Point3d(upper.x, lower.y, upper.z)}, + {new Point3d(upper.x, lower.y, upper.z), upper}, + // Bottom horizontal 4 + {lower, new Point3d(lower.x, upper.y, lower.z)}, + {new Point3d(lower.x, upper.y, lower.z), new Point3d(upper.x, upper.y, lower.z)}, + {new Point3d(upper.x, upper.y, lower.z), new Point3d(upper.x, lower.y, lower.z)}, + {new Point3d(upper.x, lower.y, lower.z), lower}, + // Vertical 4 + {lower, new Point3d(lower.x, lower.y, upper.z)}, + {new Point3d(lower.x, upper.y, lower.z), new Point3d(lower.x, upper.y, upper.z)}, + {new Point3d(upper.x, upper.y, lower.z), new Point3d(upper.x, upper.y, upper.z)}, + {new Point3d(upper.x, lower.y, lower.z), new Point3d(upper.x, lower.y, upper.z)} + }; + for (int i=0;i (sphRadius+radius)*(sphRadius+radius)) { + return false; // we are too far to intersect + } + + // Now check to see if ray intersects with polytope + if (bounds.intersect (origin, direction, iPnt)) { + return true; + } + + // Now check distance to edges. Since we don't know a priori how + // the polytope is structured, we will cycle through. We discard edges + // when their center is not on the polytope surface. + BoundingPolytope ptope = (BoundingPolytope)bounds; + Point3d midpt = new Point3d(); + double distToEdge; + for (i=0;i= 0) { + p = ptope.planes[i--]; + if (( x*p.x + y*p.y + z*p.z + p.w ) > Bounds.EPSILON) { + return false; + } + } + return true; + } + + Point3d getStartPoint() { + return origin; + } + + int getPickType() { + return PICKCYLINDER; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PickCylinderRay.java b/j3d-core/src/classes/share/javax/media/j3d/PickCylinderRay.java new file mode 100644 index 0000000..5266eba --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PickCylinderRay.java @@ -0,0 +1,267 @@ +/* + * $RCSfile: PickCylinderRay.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:27 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import com.sun.j3d.internal.Distance; + +/** + * PickCylinderRay is an infinite cylindrical ray pick shape. It can + * be used as an argument to the picking methods in BranchGroup and Locale. + * + * @see BranchGroup#pickAll + * @see Locale#pickAll + * + * @since Java 3D 1.2 + */ + +public final class PickCylinderRay extends PickCylinder { + + /** + * Constructs an empty PickCylinderRay. + * The origin and direction of the cylindrical ray are + * initialized to (0,0,0). The radius is initialized + * to 0. + */ + public PickCylinderRay() { + } + + /** + * Constructs an infinite cylindrical ray pick shape from the specified + * parameters. + * @param origin the origin of the cylindrical ray. + * @param direction the direction of the cylindrical ray. + * @param radius the radius of the cylindrical ray. + */ + public PickCylinderRay(Point3d origin, Vector3d direction, double radius) { + this.origin = new Point3d(origin); + this.direction = new Vector3d(direction); + this.radius = radius; + } + + + /** + * Sets the parameters of this PickCylinderRay to the specified values. + * @param origin the origin of the cylindrical ray. + * @param direction the direction of the cylindrical ray. + * @param radius the radius of the cylindrical ray. + */ + public void set(Point3d origin, Vector3d direction, double radius) { + this.origin.set(origin); + this.direction.set(direction); + this.radius = radius; + } + + /** + * Return true if shape intersect with bounds. + * The point of intersection is stored in pickPos. + * @param bounds the bounds object to check + * @param pickPos the location of the point of intersection (not used for + * method. Provided for compatibility). + */ + final boolean intersect(Bounds bounds, Point4d pickPos) { + Point4d iPnt = new Point4d(); + + // + // ================ BOUNDING SPHERE ================ + // + if (bounds instanceof BoundingSphere) { + Point3d sphCenter = ((BoundingSphere)bounds).getCenter(); + double sphRadius = ((BoundingSphere)bounds).getRadius(); + double sqDist = + Distance.pointToRay (sphCenter, origin, direction); + if (sqDist <= (sphRadius+radius)*(sphRadius+radius)) { + return true; + } + return false; + } + // + // ================ BOUNDING BOX ================ + // + else if (bounds instanceof BoundingBox) { + // Calculate radius of BoundingBox + Point3d lower = new Point3d(); + ((BoundingBox)bounds).getLower (lower); + + Point3d center = ((BoundingBox)bounds).getCenter (); + + double temp = (center.x - lower.x + radius); + double boxRadiusSquared = temp*temp; + temp = (center.y - lower.y + radius); + boxRadiusSquared += temp*temp; + temp = (center.z - lower.z + radius); + boxRadiusSquared += temp*temp; + + // First, see if cylinder is too far away from BoundingBox + double sqDist = + Distance.pointToRay (center, origin, direction); + + if (sqDist > boxRadiusSquared ) { + return false; // we are too far to intersect + } + else if (sqDist < (radius*radius)) { + return true; // center is in cylinder + } + + // Then, see if ray intersects + if (bounds.intersect (origin, direction, iPnt)) { + return true; + } + + // Ray does not intersect, test for distance with each edge + Point3d upper = new Point3d(); + ((BoundingBox)bounds).getUpper (upper); + + Point3d[][] edges = { + // Top horizontal 4 + {upper, new Point3d (lower.x, upper.y, upper.z)}, + {new Point3d(lower.x, upper.y, upper.z), new Point3d(lower.x, lower.y, upper.z)}, + {new Point3d(lower.x, lower.y, upper.z), new Point3d(upper.x, lower.y, upper.z)}, + {new Point3d(upper.x, lower.y, upper.z), upper}, + // Bottom horizontal 4 + {lower, new Point3d(lower.x, upper.y, lower.z)}, + {new Point3d(lower.x, upper.y, lower.z), new Point3d(upper.x, upper.y, lower.z)}, + {new Point3d(upper.x, upper.y, lower.z), new Point3d(upper.x, lower.y, lower.z)}, + {new Point3d(upper.x, lower.y, lower.z), lower}, + // Vertical 4 + {lower, new Point3d(lower.x, lower.y, upper.z)}, + {new Point3d(lower.x, upper.y, lower.z), new Point3d(lower.x, upper.y, upper.z)}, + {new Point3d(upper.x, upper.y, lower.z), new Point3d(upper.x, upper.y, upper.z)}, + {new Point3d(upper.x, lower.y, lower.z), new Point3d(upper.x, lower.y, upper.z)} + }; + + for (int i=0;i (sphRadius+radius) * (sphRadius+radius)) { + return false; // we are too far to intersect + } + + // Now check to see if ray intersects with polytope + if (bounds.intersect (origin, direction, iPnt)) { + return true; + } + + // Now check distance to edges. Since we don't know a priori how + // the polytope is structured, we will cycle through. We discard edges + // when their center is not on the polytope surface. + BoundingPolytope ptope = (BoundingPolytope)bounds; + Point3d midpt = new Point3d(); + double distToEdge; + for (i=0;i boxRadiusSquared) { + return false; // we are too far to intersect + } + else if (sqDist < (radius*radius)) { + return true; // center is in cylinder + } + + // Then, see if ray intersects + if (((BoundingBox)bounds).intersect (origin, end, iPnt)) { + return true; + } + + // Ray does not intersect, test for distance with each edge + Point3d upper = new Point3d(); + ((BoundingBox)bounds).getUpper (upper); + + Point3d[][] edges = { + // Top horizontal 4 + {upper, new Point3d (lower.x, upper.y, upper.z)}, + {new Point3d(lower.x, upper.y, upper.z), new Point3d(lower.x, lower.y, upper.z)}, + {new Point3d(lower.x, lower.y, upper.z), new Point3d(upper.x, lower.y, upper.z)}, + {new Point3d(upper.x, lower.y, upper.z), upper}, + // Bottom horizontal 4 + {lower, new Point3d(lower.x, upper.y, lower.z)}, + {new Point3d(lower.x, upper.y, lower.z), new Point3d(upper.x, upper.y, lower.z)}, + {new Point3d(upper.x, upper.y, lower.z), new Point3d(upper.x, lower.y, lower.z)}, + {new Point3d(upper.x, lower.y, lower.z), lower}, + // Vertical 4 + {lower, new Point3d(lower.x, lower.y, upper.z)}, + {new Point3d(lower.x, upper.y, lower.z), new Point3d(lower.x, upper.y, upper.z)}, + {new Point3d(upper.x, upper.y, lower.z), new Point3d(upper.x, upper.y, upper.z)}, + {new Point3d(upper.x, lower.y, lower.z), new Point3d(upper.x, lower.y, upper.z)} + }; + for (int i=0;i (sphRadius+radius)*(sphRadius+radius)) { + return false; // we are too far to intersect + } + + // Now check to see if ray intersects with polytope + if (bounds.intersect (origin, direction, iPnt)) { + return true; + } + + // Now check distance to edges. Since we don't know a priori how + // the polytope is structured, we will cycle through. We discard edges + // when their center is not on the polytope surface. + BoundingPolytope ptope = (BoundingPolytope)bounds; + Point3d midpt = new Point3d(); + double distToEdge; + for (i=0;i + * + * @see Locale + * @see BranchGroup + * + * @since Java 3D 1.4 + */ + + +public class PickInfo extends Object { + + static final int PICK_ALL = 1; + + static final int PICK_ANY = 2; + + /* The SceneGraphPath of the intersected pickable item */ + private SceneGraphPath sgp; + + /* The intersected pickable node object */ + private Node node; + + /* A copy of LocalToVworld transform of the pickable node */ + private Transform3D l2vw; + + /* The closest intersection point */ + private Point3d closestIntersectionPoint; + + /* Distance between start point of pickShape and closest intersection point */ + private double closestDistance; + + /* An array to store intersection results */ + private IntersectionInfo[] intersectionInfoArr; + + /* The following references are for internal geometry computation use only */ + private ArrayList intersectionInfoList = new ArrayList(); + private boolean intersectionInfoListSorted = false; + private Transform3D l2vwRef; + private Node nodeRef; + + /** + * Specifies a Pick using the bounds of the pickable nodes. + */ + public static final int PICK_BOUNDS = 1; + + /** + * Specifies a Pick using the geometry of the pickable nodes. + */ + public static final int PICK_GEOMETRY = 2; + + /** + * Specifies that this PickInfo returns the computed SceneGraphPath object. + */ + public static final int SCENEGRAPHPATH = 0x01; + + /** + * Specifies that this PickInfo returns the computed intersected Node object. + */ + public static final int NODE = 0x02; + + /** + * Specifies that this PickInfo returns the computed local to vworld transform. + */ + public static final int LOCAL_TO_VWORLD = 0x04; + + /** + * Specifies that this PickInfo returns the closest intersection point. + */ + public static final int CLOSEST_INTERSECTION_POINT = 0x08; + + /** + * Specifies that this PickInfo returns the closest intersection distance. + */ + public static final int CLOSEST_DISTANCE = 0x10; + + /** + * Specifies that this PickInfo returns only the closest intersection + * geometry information. + */ + public static final int CLOSEST_GEOM_INFO = 0x20; + + /** + * Specifies that this PickInfo returns all the closest intersection + * geometry informations. + */ + public static final int ALL_GEOM_INFO = 0x40; + + + /** PickInfo Constructor */ + PickInfo() { + + } + + void setSceneGraphPath(SceneGraphPath sgp) { + this.sgp = sgp; + } + + void setNode(Node node) { + this.node = node; + } + + void setLocalToVWorld(Transform3D l2vw) { + this.l2vw = l2vw; + } + + void setClosestIntersectionPoint(Point3d cIPt) { + this.closestIntersectionPoint = cIPt; + } + + void setClosestDistance(double cDist) { + this.closestDistance = cDist; + } + + void setLocalToVWorldRef(Transform3D l2vwRef) { + this.l2vwRef = l2vwRef; + } + + void setNodeRef(Node nodeRef) { + this.nodeRef = nodeRef; + } + + IntersectionInfo createIntersectionInfo() { + return new IntersectionInfo(); + } + + void insertIntersectionInfo(IntersectionInfo iInfo) { + intersectionInfoList.add(iInfo); + intersectionInfoListSorted = false; + } + + void sortIntersectionInfoArray(IntersectionInfo[] iInfoArr) { + + class Sort { + + IntersectionInfo iInfoArr[]; + + Sort(IntersectionInfo[] iInfoArr) { + // System.err.println("Sort IntersectionInfo ..."); + this.iInfoArr = iInfoArr; + } + + void sorting() { + if (iInfoArr.length < 7) { + // System.err.println(" -- insertSort."); + insertSort(); + } else { + // System.err.println(" -- quicksort."); + quicksort(0, iInfoArr.length-1); + } + } + + // Insertion sort on smallest arrays + final void insertSort() { + for (int i=0; i0 && + (iInfoArr[j-1].distance > iInfoArr[j].distance); j--) { + IntersectionInfo iInfo = iInfoArr[j]; + iInfoArr[j] = iInfoArr[j-1]; + iInfoArr[j-1] = iInfo; + } + } + } + + final void quicksort( int l, int r ) { + int i = l; + int j = r; + double k = iInfoArr[(l+r) / 2].distance; + + do { + while (iInfoArr[i].distance0 && + (pIArr[j-1].closestDistance > pIArr[j].closestDistance); j--) { + PickInfo pI = pIArr[j]; + pIArr[j] = pIArr[j-1]; + pIArr[j-1] = pI; + } + } + } + + final void quicksort( int l, int r ) { + int i = l; + int j = r; + double k = pIArr[(l+r) / 2].closestDistance; + + do { + while (pIArr[i].closestDistanceN
IntersectionInfo objects containing all intersections of + * the picked node in sorted order if flag is to set ALL_GEOM_INFO, or null if neither + * bit is set. + * @see Locale + * @see BranchGroup + */ + public IntersectionInfo[] getIntersectionInfos() { + if (intersectionInfoListSorted == false) { + intersectionInfoArr = new IntersectionInfo[intersectionInfoList.size()]; + intersectionInfoArr = + (IntersectionInfo []) intersectionInfoList.toArray(intersectionInfoArr); + + sortIntersectionInfoArray(intersectionInfoArr); + } + + return intersectionInfoArr; + } + + /** + * Search the path from nodeR up to Locale. + * Return the search path as ArrayList if found. + * Note that the locale will not insert into path. + */ + static ArrayList initSceneGraphPath(NodeRetained nodeR) { + ArrayList path = new ArrayList(5); + + do { + if (nodeR.source.getCapability(Node.ENABLE_PICK_REPORTING)){ + path.add(nodeR); + } + nodeR = nodeR.parent; + } while (nodeR != null); // reach Locale + + return path; + } + + static private Node[] createPath(NodeRetained srcNode, + BranchGroupRetained bgRetained, + GeometryAtom geomAtom, + ArrayList initpath) { + + ArrayList path = retrievePath(srcNode, bgRetained, + geomAtom.source.key); + assert(path != null); + + return mergePath(path, initpath); + + } + + + /** + * Return true if bg is inside cachedBG or bg is null + */ + static private boolean inside(BranchGroupRetained bgArr[], + BranchGroupRetained bg) { + + if ((bg == null) || (bgArr == null)) { + return true; + } + + for (int i=0; i < bgArr.length; i++) { + if (bgArr[i] == bg) { + return true; + } + } + return false; + } + + /** + * search the full path from the bottom of the scene graph - + * startNode, up to the Locale if endNode is null. + * If endNode is not null, the path is found up to, but not + * including, endNode or return null if endNode not hit + * during the search. + */ + static private ArrayList retrievePath(NodeRetained startNode, + NodeRetained endNode, + HashKey key) { + + ArrayList path = new ArrayList(5); + NodeRetained nodeR = startNode; + + if (nodeR.inSharedGroup) { + // getlastNodeId() will destroy this key + key = new HashKey(key); + } + + do { + if (nodeR == endNode) { // we found it ! + return path; + } + + if (nodeR.source.getCapability(Node.ENABLE_PICK_REPORTING)) { + path.add(nodeR); + } + + if (nodeR instanceof SharedGroupRetained) { + // retrieve the last node ID + String nodeId = key.getLastNodeId(); + Vector parents = ((SharedGroupRetained) nodeR).parents; + int sz = parents.size(); + NodeRetained prevNodeR = nodeR; + for(int i=0; i< sz; i++) { + NodeRetained linkR = (NodeRetained) parents.elementAt(i); + if (linkR.nodeId.equals(nodeId)) { + nodeR = linkR; + // Need to add Link to the path report + path.add(nodeR); + // since !(endNode instanceof Link), we + // can skip the check (nodeR == endNode) and + // proceed to parent of link below + break; + } + } + if (nodeR == prevNodeR) { + // branch is already detach + return null; + } + } + nodeR = nodeR.parent; + } while (nodeR != null); // reach Locale + + if (endNode == null) { + // user call pickxxx(Locale locale, PickShape shape) + return path; + } + + // user call pickxxx(BranchGroup endNode, PickShape shape) + // if locale is reached and endNode not hit, this is not + // the path user want to select + return null; + } + + /** + * copy p1, (follow by) p2 into a new array, p2 can be null + * The path is then reverse before return. + */ + static private Node[] mergePath(ArrayList p1, ArrayList p2) { + int s = p1.size(); + int len; + int i; + int l; + if (p2 == null) { + len = s; + } else { + len = s + p2.size(); + } + + Node nodes[] = new Node[len]; + l = len-1; + for (i=0; i < s; i++) { + nodes[l-i] = (Node) ((NodeRetained) p1.get(i)).source; + } + for (int j=0; i< len; i++, j++) { + nodes[l-i] = (Node) ((NodeRetained) p2.get(j)).source; + } + return nodes; + } + + /** + * Sort the GeometryAtoms distance from shape in ascending order + * geomAtoms.length must be >= 1 + */ + static void sortGeomAtoms(GeometryAtom geomAtoms[], + PickShape shape) { + + final double distance[] = new double[geomAtoms.length]; + Point4d pickPos = new Point4d(); + + for (int i=0; i < geomAtoms.length; i++) { + shape.intersect(geomAtoms[i].source.vwcBounds, pickPos); + distance[i] = pickPos.w; + } + + class Sort { + + GeometryAtom atoms[]; + + Sort(GeometryAtom[] atoms) { + this.atoms = atoms; + } + + void sorting() { + if (atoms.length < 7) { + insertSort(); + } else { + quicksort(0, atoms.length-1); + } + } + + // Insertion sort on smallest arrays + final void insertSort() { + for (int i=0; i0 && + (distance[j-1] > distance[j]); j--) { + double t = distance[j]; + distance[j] = distance[j-1]; + distance[j-1] = t; + GeometryAtom p = atoms[j]; + atoms[j] = atoms[j-1]; + atoms[j-1] = p; + } + } + } + + final void quicksort( int l, int r ) { + int i = l; + int j = r; + double k = distance[(l+r) / 2]; + + do { + while (distance[i] 0)) { + + //System.err.println("PickInfo.pick() - In geometry case : pickInfoList.size() is " + pickInfoListSize); + PickInfo pickInfo = null; + Node pickNode = null; + + // Order is impt. Need to do in reverse order. + for(int i = pickInfoListSize - 1; i >= 0; i--) { + pickInfo = (PickInfo) pickInfoList.get(i); + + pickNode = pickInfo.getNode(); + if( pickNode == null) { + // Use the piggy reference from getPickInfos() + pickNode = pickInfo.getNodeRef(); + } + + if (pickNode instanceof Shape3D) { + + /* + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are + * as follows : + * + * By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ + * By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ + * Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above) + * + */ + + if (!pickNode.getCapability(Shape3D.ALLOW_GEOMETRY_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo0")); + } + + for (int j = 0; j < ((Shape3D)pickNode).numGeometries(); j++) { + Geometry geo = ((Shape3D)pickNode).getGeometry(j); + + if(geo == null) { + continue; + } + + if(!geo.getCapability(Geometry.ALLOW_INTERSECT)) { + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo1")); + } + + if (geo instanceof GeometryArray) { + if(!geo.getCapability(GeometryArray.ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo2")); + if(!geo.getCapability(GeometryArray.ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo3")); + if(!geo.getCapability(GeometryArray.ALLOW_FORMAT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo4")); + if (geo instanceof IndexedGeometryArray) { + if(!geo.getCapability(IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo5")); + } + } else if (geo instanceof CompressedGeometry) { + if(!geo.getCapability(CompressedGeometry.ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo0")); + } + } + + if (((Shape3DRetained)(pickNode.retained)).intersect(pickInfo, pickShape, flags) == false) { + // System.err.println(" ---- geom " + i + " not intersected"); + + pickInfoList.remove(i); + + } + else if(pickType == PICK_ANY) { + pickInfoArr = new PickInfo[1]; + pickInfoArr[0] = pickInfo; + return pickInfoArr; + } + } else if (pickNode instanceof Morph) { + + /* + * @exception CapabilityNotSetException if the mode is + * PICK_GEOMETRY and the Geometry.ALLOW_INTERSECT capability bit + * is not set in any Geometry objects referred to by any shape + * node whose bounds intersects the PickShape. + * + * @exception CapabilityNotSetException if flags contains any of + * CLOSEST_INTERSECTION_POINT, CLOSEST_DISTANCE, CLOSEST_GEOM_INFO + * or ALL_GEOM_INFO, and the capability bits that control reading of + * coordinate data are not set in any GeometryArray object referred + * to by any shape node that intersects the PickShape. + * The capability bits that must be set to avoid this exception are + * as follows : + * + * By-copy geometry : GeometryArray.ALLOW_COORDINATE_READ + * By-reference geometry : GeometryArray.ALLOW_REF_DATA_READ + * Indexed geometry : IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ + * (in addition to one of the above) + * + */ + + if (!pickNode.getCapability(Morph.ALLOW_GEOMETRY_ARRAY_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo6")); + } + + int numGeo = ((MorphRetained)(pickNode.retained)).getNumGeometryArrays(); + for (int j = 0; j < numGeo; j++) { + GeometryArray geo = ((Morph)pickNode).getGeometryArray(j); + + if(geo == null) { + continue; + } + + if(!geo.getCapability(Geometry.ALLOW_INTERSECT)) { + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo1")); + } + + if(!geo.getCapability(GeometryArray.ALLOW_COORDINATE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo2")); + if(!geo.getCapability(GeometryArray.ALLOW_COUNT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo3")); + if(!geo.getCapability(GeometryArray.ALLOW_FORMAT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo4")); + + if (geo instanceof IndexedGeometryArray) { + if(!geo.getCapability(IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PickInfo5")); + } + } + + if (((MorphRetained)(pickNode.retained)).intersect(pickInfo, pickShape, flags) == false) { + pickInfoList.remove(i); + } + else if(pickType == PICK_ANY) { + pickInfoArr = new PickInfo[1]; + pickInfoArr[0] = pickInfo; + return pickInfoArr; + } + } + } + } + + // System.err.println("PickInfo : pickInfoList " + pickInfoList); + + if ((pickInfoList != null) && (pickInfoList.size() > 0)) { + // System.err.println(" --- : pickInfoList.size() " + pickInfoList.size()); + // System.err.println(" --- : pickInfoList's sgp " + + // ((PickInfo)(pickInfoList.get(0))).getSceneGraphPath()); + pickInfoArr = new PickInfo[pickInfoList.size()]; + return (PickInfo []) pickInfoList.toArray(pickInfoArr); + } + + return null; + + } + + /** + * The IntersectionInfo object holds extra information about an intersection + * of a PickShape with a Node as part of a PickInfo. Information such as + * the intersected geometry, the intersected point, and the vertex indices + * can be inquired. + * The local coordinates, normal, color and texture coordiantes of at the + * intersection can be computed, if they are present and readable, using the + * interpolation weights and vertex indices. + *

+ * If the Shape3D being picked has multiple geometry arrays, the possible arrays + * of IntersectionInfo are stored in the PickInfo and referred to by a geometry + * index. If the picked geometry is of type, Text3D or CompressGeometry, + * getVertexIndices is invalid. If the picked Node is an Morph + * object, the geometry used in pick computation is alway at index 0. + *

+ * + * @since Java 3D 1.4 + */ + + public class IntersectionInfo extends Object { + + /* The index to the intersected geometry in the pickable node */ + private int geomIndex; + + /* The reference to the intersected geometry in the pickable object */ + private Geometry geom; + + /* The intersection point */ + private Point3d intersectionPoint; + + /* Distance between start point of pickShape and intersection point */ + private double distance; + + /* The vertex indices of the intersected primitive in the geometry */ + private int[] vertexIndices; + + /* The interpolation weights for each of the verticies of the primitive */ + // private float[] weights; Not supported. Should be done in util. package + + /** IntersectionInfo Constructor */ + IntersectionInfo() { + + } + + void setGeometryIndex(int geomIndex) { + this.geomIndex = geomIndex; + } + + void setGeometry(Geometry geom) { + this.geom = geom; + } + + void setIntersectionPoint(Point3d intersectionPoint) { + assert(intersectionPoint != null); + this.intersectionPoint = new Point3d(intersectionPoint); + } + + void setDistance(double distance) { + this.distance = distance; + } + + void setVertexIndices(int[] vertexIndices) { + assert(vertexIndices != null); + this.vertexIndices = new int[vertexIndices.length]; + for(int i=0; i + * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public PointArray(int vertexCount, int vertexFormat) { + super(vertexCount,vertexFormat); + + if (vertexCount < 1 ) + throw new IllegalArgumentException(J3dI18N.getString("PointArray0")); + } + + /** + * Constructs an empty PointArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public PointArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap); + + if (vertexCount < 1 ) + throw new IllegalArgumentException(J3dI18N.getString("PointArray0")); + } + + /** + * Constructs an empty PointArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 1 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public PointArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + + if (vertexCount < 1 ) + throw new IllegalArgumentException(J3dI18N.getString("PointArray0")); + } + + /** + * Creates the retained mode PointArrayRetained object that this + * PointArray object will point to. + */ + void createRetained() { + this.retained = new PointArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + PointArrayRetained rt = (PointArrayRetained) retained; + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + PointArray p = new PointArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes); + p.duplicateNodeComponent(this); + return p; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PointArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/PointArrayRetained.java new file mode 100644 index 0000000..0fdfb93 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PointArrayRetained.java @@ -0,0 +1,308 @@ +/* + * $RCSfile: PointArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The PointArray object draws the array of vertices as individual points. + */ + +class PointArrayRetained extends GeometryArrayRetained { + + PointArrayRetained() { + this.geoType = GEO_TYPE_POINT_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + Point3d pnt = new Point3d(); + int[] vtxIndexArr = new int[1]; + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < validVertexCount) { + vtxIndexArr[0] = i; + getVertexData(i++, pnt); + if (intersectPntAndRay(pnt, pickRay.origin, + pickRay.direction, sdist)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + Vector3d dir = + new Vector3d(pickSegment.end.x - pickSegment.start.x, + pickSegment.end.y - pickSegment.start.y, + pickSegment.end.z - pickSegment.start.z); + while (i < validVertexCount) { + vtxIndexArr[0] = i; + getVertexData(i++, pnt); + if (intersectPntAndRay(pnt, pickSegment.start, + dir, sdist) && + (sdist[0] <= 1.0)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGBOX: + case PickShape.PICKBOUNDINGSPHERE: + case PickShape.PICKBOUNDINGPOLYTOPE: + Bounds bounds = ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + vtxIndexArr[0] = i; + getVertexData(i++, pnt); + if (bounds.intersect(pnt)) { + if (flags == 0) { + return true; + } + sdist[0] = pickShape.distance(pnt); + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < validVertexCount) { + vtxIndexArr[0] = i; + getVertexData(i++, pnt); + if (intersectCylinder(pnt, pickCylinder, sdist)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < validVertexCount) { + vtxIndexArr[0] = i; + getVertexData(i++, pnt); + if (intersectCone(pnt, pickCone, sdist)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = pnt.x; + y = pnt.y; + z = pnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("PointArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + boolean intersect(Point3d[] pnts) { + Point3d point = new Point3d(); + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + switch (pnts.length) { + case 3: // Triangle + while (i < validVertexCount) { + getVertexData(i++, point); + if (intersectTriPnt(pnts[0], pnts[1], pnts[2], point)) { + return true; + } + } + break; + case 4: // Quad + while (i < validVertexCount) { + getVertexData(i++, point); + if (intersectTriPnt(pnts[0], pnts[1], pnts[2], point) || + intersectTriPnt(pnts[0], pnts[2], pnts[3], point)) { + return true; + } + } + break; + case 2: // Line + double dist[] = new double[1]; + Vector3d dir = new Vector3d(); + + while (i < validVertexCount) { + getVertexData(i++, point); + dir.x = pnts[1].x - pnts[0].x; + dir.y = pnts[1].y - pnts[0].y; + dir.z = pnts[1].z - pnts[0].z; + if (intersectPntAndRay(point, pnts[0], dir, dist) && + (dist[0] <= 1.0)) { + return true; + } + } + break; + case 1: // Point + while (i < validVertexCount) { + getVertexData(i++, point); + if ((pnts[0].x == point.x) && + (pnts[0].y == point.y) && + (pnts[0].z == point.z)) { + return true; + } + } + break; + } + return false; + } + + + boolean intersect(Transform3D thisToOtherVworld, + GeometryRetained geom) { + + Point3d[] pnt = new Point3d[1]; + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + pnt[0] = new Point3d(); + + while (i < validVertexCount) { + getVertexData(i++, pnt[0]); + thisToOtherVworld.transform(pnt[0]); + if (geom.intersect(pnt)) { + return true; + } + } + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + Point3d pnt = new Point3d(); + + while (i < validVertexCount) { + getVertexData(i++, pnt); + if (targetBound.intersect(pnt)) { + return true; + } + } + return false; + } + + int getClassType() { + return POINT_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PointAttributes.java b/j3d-core/src/classes/share/javax/media/j3d/PointAttributes.java new file mode 100644 index 0000000..f568ef9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PointAttributes.java @@ -0,0 +1,238 @@ +/* + * $RCSfile: PointAttributes.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The PointAttributes object defines all attributes that apply to + * point primitives. The point attributes that can be defined are:

+ *

    + *
  • Size - the size of the point, in pixels. The default is a point + * size of one pixel.
  • + *

  • Antialiasing - for points greater than one-pixel in size, + * antialiasing smooths the outline of the point when it is rendered.
  • + *

+ * If antialiasing is disabled (the default), fractional point sizes + * are rounded to integer sizes, and a screen-aligned square region + * of pixels is drawn.

+ *

+ * If antialiasing is enabled, the points are considered transparent + * for rendering purposes. They are rendered with all the other transparent + * objects and adhere to the other transparency settings such as the + * View transparency sorting policy and the View depth buffer freeze + * transparent enable. + *

+ * + * @see Appearance + * @see View + */ +public class PointAttributes extends NodeComponent { + + /** + * Specifies that this PointAttributes object allows reading its + * point size information. + */ + public static final int + ALLOW_SIZE_READ = CapabilityBits.POINT_ATTRIBUTES_ALLOW_SIZE_READ; + + /** + * Specifies that this PointAttributes object allows writing its + * point size information. + */ + public static final int + ALLOW_SIZE_WRITE = CapabilityBits.POINT_ATTRIBUTES_ALLOW_SIZE_WRITE; + + /** + * Specifies that this PointAttributes object allows reading its + * point antialiasing flag. + */ + public static final int + ALLOW_ANTIALIASING_READ = CapabilityBits.POINT_ATTRIBUTES_ALLOW_ANTIALIASING_READ; + + /** + * Specifies that this PointAttributes object allows writing its + * point antialiasing flag. + */ + public static final int + ALLOW_ANTIALIASING_WRITE = CapabilityBits.POINT_ATTRIBUTES_ALLOW_ANTIALIASING_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SIZE_READ, + ALLOW_ANTIALIASING_READ + }; + + /** + * Constructs a PointAttributes object with default parameters. + * The default values are as follows: + *
    + * point size : 1
    + * point antialiasing : false
    + *
+ */ + public PointAttributes(){ + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a PointAttributes object with specified values. + * @param pointSize the size of points, in pixels + * @param pointAntialiasing flag to set point antialising ON or OFF + */ + public PointAttributes(float pointSize, boolean pointAntialiasing){ + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointAttributesRetained)this.retained).initPointSize(pointSize); + ((PointAttributesRetained)this.retained).initPointAntialiasingEnable(pointAntialiasing); + } + + /** + * Sets the point size for this appearance component object. + * @param pointSize the size, in pixels, of point primitives + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPointSize(float pointSize) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SIZE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointAttributes0")); + + if (isLive()) + ((PointAttributesRetained)this.retained).setPointSize(pointSize); + else + ((PointAttributesRetained)this.retained).initPointSize(pointSize); + + } + + /** + * Gets the point size for this appearance component object. + * @return the size, in pixels, of point primitives + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getPointSize() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SIZE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PointAttributes1")); + return ((PointAttributesRetained)this.retained).getPointSize(); + } + + /** + * Enables or disables point antialiasing + * for this appearance component object. + *

+ * If antialiasing is enabled, the points are considered transparent + * for rendering purposes. They are rendered with all the other + * transparent objects and adhere to the other transparency settings + * such as the View transparency sorting policy and the View depth + * buffer freeze transparent enable. + *

+ * @param state true or false to enable or disable point antialiasing + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @see View + */ + public void setPointAntialiasingEnable(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANTIALIASING_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointAttributes2")); + if (isLive()) + ((PointAttributesRetained)this.retained).setPointAntialiasingEnable(state); + else + ((PointAttributesRetained)this.retained).initPointAntialiasingEnable(state); + + } + + /** + * Retrieves the state of the point antialiasing flag. + * @return true if point antialiasing is enabled, + * false if point antialiasing is disabled + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getPointAntialiasingEnable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ANTIALIASING_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PointAttributes3")); + return ((PointAttributesRetained)this.retained).getPointAntialiasingEnable(); + } + + /** + * Creates a retained mode PointAttributesRetained object that this + * PointAttributes component object will point to. + */ + void createRetained() { + this.retained = new PointAttributesRetained(); + this.retained.setSource(this); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + PointAttributes pa = new PointAttributes(); + pa.duplicateNodeComponent(this); + return pa; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + PointAttributesRetained attr = (PointAttributesRetained) + originalNodeComponent.retained; + PointAttributesRetained rt = (PointAttributesRetained) retained; + + rt.initPointSize(attr.getPointSize()); + rt.initPointAntialiasingEnable(attr.getPointAntialiasingEnable()); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PointAttributesRetained.java b/j3d-core/src/classes/share/javax/media/j3d/PointAttributesRetained.java new file mode 100644 index 0000000..c5b6191 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PointAttributesRetained.java @@ -0,0 +1,222 @@ +/* + * $RCSfile: PointAttributesRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * The PointAttributesRetained object defines all rendering state that can be set + * as a component object of a Shape3D node. + */ +class PointAttributesRetained extends NodeComponentRetained { + // A list of pre-defined bits to indicate which component + // in this LineAttributesRetained object changed. + static final int POINT_SIZE_CHANGED = 0x01; + static final int POINT_AA_CHANGED = 0x02; + + // Size, in pixels, of point primitives + float pointSize = 1.0f; + + // Point antialiasing switch + boolean pointAntialiasing = false; + + + /** + * Sets the point size for this appearance component object. + * @param pointSize the size, in pixels, of point primitives + */ + final void initPointSize(float pointSize) { + this.pointSize = pointSize; + } + + /** + * Sets the point size for this appearance component object and sends a + * message notifying the interested structures of the change. + * @param pointSize the size, in pixels, of point primitives + */ + final void setPointSize(float pointSize) { + initPointSize(pointSize); + sendMessage(POINT_SIZE_CHANGED, new Float(pointSize)); + } + + /** + * Gets the point size for this appearance component object. + * @return the size, in pixels, of point primitives + */ + final float getPointSize() { + return pointSize; + } + + /** + * Enables or disables point antialiasing + * for this appearance component object. + * @param state true or false to enable or disable point antialiasing + */ + final void initPointAntialiasingEnable(boolean state) { + pointAntialiasing = state; + } + + /** + * Enables or disables point antialiasing + * for this appearance component object and sends a + * message notifying the interested structures of the change. + * @param state true or false to enable or disable point antialiasing + */ + final void setPointAntialiasingEnable(boolean state) { + initPointAntialiasingEnable(pointAntialiasing); + sendMessage(POINT_AA_CHANGED, + (state ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Retrieves the state of the point antialiasing flag. + * @return true if point antialiasing is enabled, + * false if point antialiasing is disabled + */ + final boolean getPointAntialiasingEnable() { + return pointAntialiasing; + } + + /** + * Creates and initializes a mirror object, point the mirror object + * to the retained object if the object is not editable + */ + synchronized void createMirrorObject() { + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror = this; + } else { + PointAttributesRetained mirrorPa + = new PointAttributesRetained(); + mirrorPa.set(this); + mirrorPa.source = source; + mirror = mirrorPa; + } + } else { + ((PointAttributesRetained) mirror).set(this); + } + } + + /** + * Update the native context + */ + void updateNative(Context ctx) { + Pipeline.getPipeline().updatePointAttributes(ctx, pointSize, pointAntialiasing); + } + + + /** + * Initializes a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + ((PointAttributesRetained)mirror).set(this); + } + + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + PointAttributesRetained mirrorPa = (PointAttributesRetained) mirror; + + if ((component & POINT_SIZE_CHANGED) != 0) { + mirrorPa.pointSize = ((Float)value).floatValue(); + } + else if ((component & POINT_AA_CHANGED) != 0) { + mirrorPa.pointAntialiasing = ((Boolean)value).booleanValue(); + } + } + + boolean equivalent(PointAttributesRetained pr) { + return ((pr != null) && + (pr.pointSize == pointSize) && + (pr.pointAntialiasing == pointAntialiasing)); + } + + + protected void set(PointAttributesRetained pr) { + super.set(pr); + pointSize = pr.pointSize; + pointAntialiasing = pr.pointAntialiasing; + } + + + final void sendMessage(int attrMask, Object attr) { + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.POINTATTRIBUTES_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i + * A point light contributes to diffuse and specular reflections, + * which in turn depend on the orientation and position of a + * surface. A point light does not contribute to ambient reflections. + *

+ * A PointLight is attenuated by multiplying the contribution of the + * light by an attenuation factor. The attenuation factor causes the + * the PointLight's brightness to decrease as distance from the light + * source increases. + * A PointLight's attenuation factor contains three values: + *

    + *
  • Constant attenuation
  • + *
  • Linear attenuation
  • + *
  • Quadratic attenuation
+ *

+ * A PointLight is attenuated by the reciprocal of the sum of: + *

+ *

    + * The constant attenuation factor
    + * The Linear attenuation factor times the distance between the light + * and the vertex being illuminated
    + * The quadratic attenuation factor times the square of the distance + * between the light and the vertex + *
+ *

+ * By default, the constant attenuation value is 1 and the other + * two values are 0, resulting in no attenuation. + */ + +public class PointLight extends Light { + /** + * Specifies that this PointLight node allows reading its position + * information. + */ + public static final int + ALLOW_POSITION_READ = CapabilityBits.POINT_LIGHT_ALLOW_POSITION_READ; + + /** + * Specifies that this PointLight node allows writing its position + * information. + */ + public static final int + ALLOW_POSITION_WRITE = CapabilityBits.POINT_LIGHT_ALLOW_POSITION_WRITE; + + /** + * Specifies that this PointLight node allows reading its attenuation + * information. + */ + public static final int + ALLOW_ATTENUATION_READ = CapabilityBits.POINT_LIGHT_ALLOW_ATTENUATION_READ; + + /** + * Specifies that this PointLight node allows writing its attenuation + * information. + */ + public static final int + ALLOW_ATTENUATION_WRITE = CapabilityBits.POINT_LIGHT_ALLOW_ATTENUATION_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_POSITION_READ, + ALLOW_ATTENUATION_READ + }; + + /** + * Constructs a PointLight node with default parameters. + * The default values are as follows: + *

    + * position : (0,0,0)
    + * attenuation : (1,0,0)
    + *
+ */ + public PointLight() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a point light. + * @param color the color of the light source + * @param position the position of the light in three-space + * @param attenuation the attenutation (constant, linear, quadratic) of the light + */ + public PointLight(Color3f color, + Point3f position, + Point3f attenuation) { + super(color); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointLightRetained)this.retained).initPosition(position); + ((PointLightRetained)this.retained).initAttenuation(attenuation); + } + + /** + * Constructs and initializes a point light. + * @param lightOn flag indicating whether this light is on or off + * @param color the color of the light source + * @param position the position of the light in three-space + * @param attenuation the attenuation (constant, linear, quadratic) of the light + */ + public PointLight(boolean lightOn, + Color3f color, + Point3f position, + Point3f attenuation) { + super(lightOn, color); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointLightRetained)this.retained).initPosition(position); + ((PointLightRetained)this.retained).initAttenuation(attenuation); + } + + /** + * Creates the retained mode PointLightRetained object that this + * PointLight component object will point to. + */ + void createRetained() { + this.retained = new PointLightRetained(); + this.retained.setSource(this); + } + + + /** + * Set light position. + * @param position the new position + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPosition(Point3f position) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointLight0")); + + if (isLive()) + ((PointLightRetained)this.retained).setPosition(position); + else + ((PointLightRetained)this.retained).initPosition(position); + } + + /** + * Set light position. + * @param x the new X position + * @param y the new Y position + * @param z the new Z position + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPosition(float x, float y, float z) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointLight1")); + + if (isLive()) + ((PointLightRetained)this.retained).setPosition(x,y,z); + else + ((PointLightRetained)this.retained).initPosition(x,y,z); + } + + /** + * Gets this Light's current position and places it in the parameter specified. + * @param position the vector that will receive this node's position + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getPosition(Point3f position) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PointLight2")); + + ((PointLightRetained)this.retained).getPosition(position); + } + + /** + * Sets this Light's current attenuation values and places it in the parameter specified. + * @param attenuation the vector that will receive the attenuation values + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAttenuation(Point3f attenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ATTENUATION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointLight3")); + + if (isLive()) + ((PointLightRetained)this.retained).setAttenuation(attenuation); + else + ((PointLightRetained)this.retained).initAttenuation(attenuation); + } + + /** + * Sets this Light's current attenuation values and places it in the parameter specified. + * @param constant the light's constant attenuation + * @param linear the light's linear attenuation + * @param quadratic the light's quadratic attenuation + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAttenuation(float constant, float linear, float quadratic) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ATTENUATION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointLight3")); + + if (isLive()) + ((PointLightRetained)this.retained).setAttenuation(constant, linear, quadratic); + else + ((PointLightRetained)this.retained).initAttenuation(constant, linear, quadratic); + } + + /** + * Gets this Light's current attenuation values and places it in the parameter specified. + * @param attenuation the vector that will receive the attenuation values + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getAttenuation(Point3f attenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ATTENUATION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PointLight5")); + + ((PointLightRetained)this.retained).getAttenuation(attenuation); + } + + + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + PointLight p = new PointLight(); + p.duplicateNode(this, forceDuplicate); + return p; + } + + + /** + * Copies all PointLight information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + PointLightRetained attr = (PointLightRetained) originalNode.retained; + PointLightRetained rt = (PointLightRetained) retained; + + Point3f p = new Point3f(); + attr.getPosition(p); + rt.initPosition(p); + + attr.getAttenuation(p); + rt.initAttenuation(p); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PointLightRetained.java b/j3d-core/src/classes/share/javax/media/j3d/PointLightRetained.java new file mode 100644 index 0000000..54b1086 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PointLightRetained.java @@ -0,0 +1,337 @@ +/* + * $RCSfile: PointLightRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * A Retained PointLight source. + */ +class PointLightRetained extends LightRetained { + static final int POSITION_CHANGED = LAST_DEFINED_BIT << 1; + static final int ATTENUATION_CHANGED = LAST_DEFINED_BIT << 2; + static final int LAST_POINTLIGHT_DEFINED_BIT = ATTENUATION_CHANGED; + + /** + * The attenuation vector consisting of + * constant, linear, and quadratic coefficients. + */ + Point3f attenuation = new Point3f(1.0f, 0.0f, 0.0f); + + // The position at which this light source exists. + Point3f position = new Point3f(); + + // The transformed position of this light + Point3f xformPosition = new Point3f(); + + // local to vworld scale for attenuation + double localToVworldScale; + + // scaled linearAttenuation from lc to ec + float linearAttenuationInEc; + + // scaled quadraticAttenuation from lc to ec + float quadraticAttenuationInEc; + + PointLightRetained() { + this.nodeType = NodeRetained.POINTLIGHT; + lightType = 3; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + /** + * Initializes this light's position from the vector provided. + * @param position the new position + */ + void initPosition(Point3f position) { + this.position.set(position); + + if (staticTransform != null) { + staticTransform.transform.transform(this.position, this.position); + } + } + + /** + * Sets this light's position from the vector provided. + * @param position the new position + */ + void setPosition(Point3f position) { + initPosition(position); + sendMessage(POSITION_CHANGED, new Point3f(position)); + } + + + /** + * Initializes this light's position from the three values provided. + * @param x the new x position + * @param y the new y position + * @param z the new z position + */ + void initPosition(float x, float y, float z) { + this.position.x = x; + this.position.y = y; + this.position.z = z; + + if (staticTransform != null) { + staticTransform.transform.transform(this.position, this.position); + } + } + + + /** + * Sets this light's position from the three values provided. + * @param x the new x position + * @param y the new y position + * @param z the new z position + */ + void setPosition(float x, float y, float z) { + setPosition(new Point3f(x, y, z)); + } + + + /** + * Retrieves this light's position and places it in the + * vector provided. + * @param position the variable to receive the position vector + */ + void getPosition(Point3f position) { + position.set(this.position); + + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + invTransform.transform(position, position); + } + } + + + /** + * Initializes the point light's attenuation constants. + * @param attenuation a vector consisting of constant, linear, and quadratic coefficients + */ + void initAttenuation(Point3f attenuation) { + this.attenuation.set(attenuation); + } + + /** + * Sets the point light's attenuation constants. + * @param attenuation a vector consisting of constant, linear, and quadratic coefficients + */ + void setAttenuation(Point3f attenuation) { + initAttenuation(attenuation); + sendMessage(ATTENUATION_CHANGED, new Point3f(attenuation)); + } + + /** + * Sets the point light's attenuation. + * @param constant the point light's constant attenuation + * @param linear the linear attenuation of the light + * @param quadratic the quadratic attenuation of the light + */ + void initAttenuation(float constant, + float linear, + float quadratic) { + this.attenuation.x = constant; + this.attenuation.y = linear; + this.attenuation.z = quadratic; + } + + /** + * Sets the point light's attenuation. + * @param constant the point light's constant attenuation + * @param linear the linear attenuation of the light + * @param quadratic the quadratic attenuation of the light + */ + void setAttenuation(float constant, + float linear, + float quadratic) { + setAttenuation(new Point3f(constant, linear, quadratic)); + } + + /** + * Retrieves the light's attenuation and places the value in the parameter + * specified. + * @param attenuation the variable that will contain the attenuation + */ + void getAttenuation(Point3f attenuation) { + attenuation.set(this.attenuation); + } + + /** + * This update function, and its native counterpart, + * updates a point light. This includes its color, attenuation, + * and its transformed position. + */ + void update(Context ctx, int lightSlot, double scale) { + validateAttenuationInEc(scale); + Pipeline.getPipeline().updatePointLight(ctx, + lightSlot, color.x, color.y, color.z, + attenuation.x, linearAttenuationInEc, + quadraticAttenuationInEc, + xformPosition.x, xformPosition.y, + xformPosition.z); + } + + void setLive(SetLiveState s) { + super.setLive(s); + J3dMessage createMessage = super.initMessage(9); + Object[] objs = (Object[])createMessage.args[4]; + objs[7] = new Point3f(position); + objs[8] = new Point3f(attenuation); + + VirtualUniverse.mc.processMessage(createMessage); + } + + // This is called only from SpotLightRetained, so as + // to not create a message for initialization. for spotlight + // the initialization of the message is done by SpotLightRetained + void doSetLive(SetLiveState s) { + super.setLive(s); + } + + J3dMessage initMessage(int num) { + J3dMessage createMessage = super.initMessage(num); + Object[] objs = (Object[])createMessage.args[4]; + objs[7] = new Point3f(position); + objs[8] = new Point3f(attenuation); + return createMessage; + } + + + // Note : if you add any more fields here , you need to update + // updateLight() in RenderingEnvironmentStructure + void updateMirrorObject(Object[] objs) { + + int component = ((Integer)objs[1]).intValue(); + Transform3D mlLastLocalToVworld; + int i; + int numLgts = ((Integer)objs[2]).intValue(); + LightRetained[] mLgts = (LightRetained[]) objs[3]; + + + if ((component & POSITION_CHANGED) != 0) { + for (i = 0; i < numLgts; i++) { + if (mLgts[i] instanceof PointLightRetained) { + PointLightRetained ml = (PointLightRetained)mLgts[i]; + mlLastLocalToVworld = ml.getLastLocalToVworld(); + ml.position = (Point3f) objs[4]; + mlLastLocalToVworld.transform(ml.position, + ml.xformPosition); + ml.localToVworldScale = + mlLastLocalToVworld.getDistanceScale(); + } + } + } + else if ((component & ATTENUATION_CHANGED) != 0) { + for (i = 0; i < numLgts; i++) { + if (mLgts[i] instanceof PointLightRetained) { + PointLightRetained ml = (PointLightRetained)mLgts[i]; + ml.attenuation.set((Point3f)objs[4]); + } + } + } + else if ((component & INIT_MIRROR) != 0) { + for (i = 0; i < numLgts; i++) { + if (mLgts[i] instanceof PointLightRetained) { + PointLightRetained ml = (PointLightRetained)mirrorLights[i]; + ml.position = (Point3f)((Object[]) objs[4])[7]; + ml.attenuation.set((Point3f)((Object[]) objs[4])[8]); + mlLastLocalToVworld = ml.getLastLocalToVworld(); + mlLastLocalToVworld.transform(ml.position, + ml.xformPosition); + ml.localToVworldScale = + mlLastLocalToVworld.getDistanceScale(); + } + } + } + + // call the parent's mirror object update routine + super.updateMirrorObject(objs); + } + + void validateAttenuationInEc(double vworldToCoexistenceScale) { + double localToEcScale = localToVworldScale * vworldToCoexistenceScale; + + linearAttenuationInEc = (float)(attenuation.y / localToEcScale); + quadraticAttenuationInEc = + (float)(attenuation.z / (localToEcScale * localToEcScale)); + } + + + + // Clones only the retained side, internal use only + protected Object clone() { + PointLightRetained pr = + (PointLightRetained)super.clone(); + + pr.attenuation = new Point3f(attenuation); + pr.position = new Point3f(position); + pr.xformPosition = new Point3f(); + return pr; + } + + + // Called on the mirror object + void updateTransformChange() { + super.updateTransformChange(); + + Transform3D lastLocalToVworld = getLastLocalToVworld(); + + lastLocalToVworld.transform(position, xformPosition); + localToVworldScale = lastLocalToVworld.getDistanceScale(); + + validateAttenuationInEc(0.0861328125); + } + + void sendMessage(int attrMask, Object attr) { + + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.universe = universe; + createMessage.type = J3dMessage.LIGHT_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + if (inSharedGroup) + createMessage.args[2] = new Integer(numMirrorLights); + else + createMessage.args[2] = new Integer(1); + createMessage.args[3] = mirrorLights.clone(); + createMessage.args[4] = attr; + VirtualUniverse.mc.processMessage(createMessage); + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + xform.transform.transform(position, position); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PointSound.java b/j3d-core/src/classes/share/javax/media/j3d/PointSound.java new file mode 100644 index 0000000..6dbfc96 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PointSound.java @@ -0,0 +1,581 @@ +/* + * $RCSfile: PointSound.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Point2f; +import javax.vecmath.Point3f; + + +/** + * The PointSound node (a sub-class of the Sound node) defines a spatially + * located sound source whose waves radiate uniformly in all directions from + * a given location in space. It has the same attributes as a Sound object + * with the addition of a location and the specification of distance-based + * gain attenuation for listener positions between an array of distances. + *

+ * A sound's amplitude is attenuated based on the distance between the listener + * and the sound source position. A piecewise linear curve (defined in terms of + * pairs of distance and gain scale factor) specifies the gain scale factor slope. + * + * The PointSound's location and attenuation distances are defined in the local + * coordinate system of the node. + *

+ * Distance Gain Attenuation + *

    + * Associated with distances from the listener to the sound source via an + * array of (distance, gain-scale-factor) pairs. The gain scale factor + * applied to the sound source is the linear interpolated gain value between + * the distance value range that includes the current distance from + * the listener to the sound source. If the distance from the listener to + * the sound source is less than the first distance in the array, the first + * gain scale factor is applied to the sound source. This creates a + * spherical region around the listener within which all sound gain is + * uniformly scaled by the first gain in the array. If the distance from + * the listener to the sound source is greater than the last distance in + * the array, the last gain scale factor is applied to the sound source. + *

    + * Distance elements in this array of Point2f is a monotonically-increasing + * set of floating point numbers measured from the location of the sound + * source. Gain scale factors elements in this list of pairs can be any + * positive floating point numbers. While for most applications this list + * of gain scale factors will usually be monotonically-decreasing, they + * do not have to be. + * If this + * is not set, no distance gain attenuation is performed (equivalent to + * using a distance gain of 1.0 for all distances). + *

    + * getDistanceGainLength method returns the length of the distance gain + * attenuation arrays. Arrays passed into getDistanceGain methods should all + * be at least this size. + *

    + * There are two methods for getDistanceGain, one returning an array of + * points, the other returning separate arrays for each attenuation + * component.

+ */ + +public class PointSound extends Sound { + // Constants + // + // These flags, when enabled using the setCapability method, allow an + // application to invoke methods that respectively read and write the position + // and the distance gain array. These capability flags are enforced only when + // the node is part of a live or compiled scene graph + + /** + * Specifies that this node allows access to its object's position + * information. + */ + public static final int + ALLOW_POSITION_READ = CapabilityBits.POINT_SOUND_ALLOW_POSITION_READ; + + /** + * Specifies that this node allows writing to its object's position + * information. + */ + public static final int + ALLOW_POSITION_WRITE = CapabilityBits.POINT_SOUND_ALLOW_POSITION_WRITE; + + /** + * Specifies that this node allows access to its object's distance + * gain attenuation information. + */ + public static final int + ALLOW_DISTANCE_GAIN_READ = CapabilityBits.POINT_SOUND_ALLOW_DISTANCE_GAIN_READ; + + /** + * Specifies that this node allows writing to its object's distance + * gain attenuation information. + */ + public static final int + ALLOW_DISTANCE_GAIN_WRITE = CapabilityBits.POINT_SOUND_ALLOW_DISTANCE_GAIN_WRITE; + + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_POSITION_READ, + ALLOW_DISTANCE_GAIN_READ + }; + + /** + * Constructs and initializes a new PointSound node using default + * parameters. The following default values are used: + *
    + * position vector: (0.0, 0.0, 0.0)
    + * Back attenuation: null
    + * distance gain attenuation: null (no attenuation performed)
    + *
+ */ + public PointSound() { + // Uses default values defined for Sound and PointSound nodes + super(); + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + } + + /** + * Constructs a PointSound node object using only the provided parameter + * values for sound data, sample gain, and position. The remaining fields + * are set to the above default values. This form uses a point as input for + * its position. + * @param soundData sound data associated with this sound source node + * @param initialGain amplitude scale factor applied to sound source + * @param position 3D location of source + */ + public PointSound(MediaContainer soundData, + float initialGain, + Point3f position) { + super(soundData, initialGain); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointSoundRetained)this.retained).setPosition(position); + } + + /** + * Constructs a PointSound node object using only the provided parameter + * values for sound data, sample gain, and position. The remaining fields + * are set to to the above default values. This form uses individual float + * parameters for the elements of the position point. + * @param soundData sound data associated with this sound source node + * @param initialGain amplitude scale factor applied to sound source data + * @param posX x coordinate of location of source + * @param posY y coordinate of location of source + * @param posZ z coordinate of location of source + */ + public PointSound(MediaContainer soundData, + float initialGain, + float posX, float posY, float posZ ) { + super(soundData, initialGain); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointSoundRetained)this.retained).setPosition(posX,posY,posZ); + } + + // The next four constructors fill all this classes fields with the provided + // arguments values. + // See the header for the setDistanceGain method for details on how the + // those arrays are interpreted. + + /** + * Construct a PointSound object accepting Point3f as input for the position + * and accepting an array of Point2f for the distance attenuation values + * where each pair in the array contains a distance and a gain scale factor. + * @param soundData sound data associated with this sound source node + * @param initialGain amplitude scale factor applied to sound source + * @param loopCount number of times loop is looped + * @param release flag denoting playing sound data to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param position 3D location of source + * @param distanceGain array of (distance,gain) pairs controling attenuation + */ + public PointSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + Point3f position, + Point2f[] distanceGain) { + + super(soundData, initialGain, loopCount, release, continuous, + enable, region, priority ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointSoundRetained)this.retained).setPosition(position); + ((PointSoundRetained)this.retained).setDistanceGain(distanceGain); + } + + /** + * Construct a PointSound object accepting individual float parameters for + * the elements of the position point, and accepting an array of Point2f for + * the distance attenuation values where each pair in the array contains a + * distance and a gain scale factor. + * @param soundData sound data associated with this sound source node + * @param initialGain amplitude scale factor applied to sound source + * @param loopCount number of times loop is looped + * @param release flag denoting playing sound to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param posX x coordinate of location of source + * @param posY y coordinate of location of source + * @param posZ z coordinate of location of source + * @param distanceGain array of (distance,gain) pairs controling attenuation + */ + public PointSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + float posX, float posY, float posZ, + Point2f[] distanceGain) { + + super(soundData, initialGain, loopCount, release, + continuous, enable, region, priority ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointSoundRetained)this.retained).setPosition(posX,posY,posZ); + ((PointSoundRetained)this.retained).setDistanceGain(distanceGain); + } + + /** + * Construct a PointSound object accepting points as input for the position. + * and accepting separate arrays for the distance and gain scale factors + * components of distance attenuation. + * @param soundData sound data associated with this sound source node + * @param initialGain amplitude scale factor applied to sound source + * @param loopCount number of times loop is looped + * @param release flag denoting playing sound data to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param position 3D location of source + * @param attenuationDistance array of distance values used for attenuation + * @param attenuationGain array of gain scale factors used for attenuation + */ + public PointSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + Point3f position, + float[] attenuationDistance, + float[] attenuationGain) { + + super(soundData, initialGain, loopCount, release, continuous, + enable, region, priority ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointSoundRetained)this.retained).setPosition(position); + ((PointSoundRetained)this.retained).setDistanceGain( + attenuationDistance, attenuationGain); + } + + /** + * Construct a PointSound object accepting individual float parameters for + * the elements of the position points, and accepting separate arrays for + * the distance and gain scale factors components of distance attenuation. + * @param soundData sound data associated with this sound source node + * @param initialGain amplitude scale factor applied to sound source + * @param loopCount number of times loop is looped + * @param release flag denoting playing sound to end + * @param continuous denotes that sound silently plays when disabled + * @param enable sound switched on/off + * @param region scheduling bounds + * @param priority playback ranking value + * @param posX x coordinate of location of source + * @param posY y coordinate of location of source + * @param posZ z coordinate of location of source + * @param attenuationDistance array of distance values used for attenuation + * @param attenuationGain array of gain scale factors used for attenuation + */ + public PointSound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + float posX, float posY, float posZ, + float[] attenuationDistance, + float[] attenuationGain) { + + super(soundData, initialGain, loopCount, release, + continuous, enable, region, priority ); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PointSoundRetained)this.retained).setPosition(posX,posY,posZ); + ((PointSoundRetained)this.retained).setDistanceGain( + attenuationDistance, attenuationGain); + } + + /** + * Creates the retained mode PointSoundRetained object that this + * PointSound object will point to. + */ + void createRetained() { + this.retained = new PointSoundRetained(); + this.retained.setSource(this); + } + + /** + * Sets this sound's location from the vector provided. + * @param position the new location + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPosition(Point3f position) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointSound0")); + + ((PointSoundRetained)this.retained).setPosition(position); + } + + /** + * Sets this sound's position from the three values provided. + * @param x the new x position + * @param y the new y position + * @param z the new z position + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPosition(float x, float y, float z) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointSound0")); + + ((PointSoundRetained)this.retained).setPosition(x,y,z); + } + + /** + * Retrieves this sound's direction and places it in the + * vector provided. + * @param position the variable to receive the direction vector + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getPosition(Point3f position) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PointSound2")); + + ((PointSoundRetained)this.retained).getPosition(position); + } + + /** + * Sets this sound's distance gain attenuation - where gain scale factor + * is applied to sound based on distance listener is from sound source. + * This form of setDistanceGain takes these pairs of values as an array of + * Point2f. + * @param attenuation defined by pairs of (distance,gain-scale-factor) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDistanceGain(Point2f[] attenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointSound3")); + + ((PointSoundRetained)this.retained).setDistanceGain(attenuation); + } + + /** + * Sets this sound's distance gain attenuation as an array of Point2fs. + * This form of setDistanceGain accepts two separate arrays for these values. + * The distance and gainScale arrays should be of the same length. If the + * gainScale array length is greater than the distance array length, the + * gainScale array elements beyond the length of the distance array are + * ignored. If the gainScale array is shorter than the distance array, the + * last gainScale array value is repeated to fill an array of length equal + * to distance array. + * @param distance array of monotonically-increasing floats + * @param gain array of non-negative scale factors + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDistanceGain(float[] distance, float[] gain) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PointSound3")); + + ((PointSoundRetained)this.retained).setDistanceGain(distance, gain); + } + + /** + * Get the length of this node's distance gain attenuation arrays. + * @return distance gain attenuation array length + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getDistanceGainLength() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PointSound4")); + + return (((PointSoundRetained)this.retained).getDistanceGainLength()); + } + + /** + * Gets this sound's distance attenuation. The distance attenuation + * pairs are copied into the specified array. + * The array must be large enough to hold all of the points. + * The individual array elements must be allocated by the caller. + * @param attenuation arrays containing distance attenuation pairs + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDistanceGain(Point2f[] attenuation) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PointSound4")); + + ((PointSoundRetained)this.retained).getDistanceGain(attenuation); + } + + /** + * Gets this sound's distance gain attenuation values in separate arrays. + * The arrays must be large enough to hold all of the values. + * @param distance array of float distance from sound source + * @param gain array of non-negative scale factors associated with + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDistanceGain(float[] distance, float[] gain) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DISTANCE_GAIN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PointSound4")); + + ((PointSoundRetained)this.retained).getDistanceGain(distance,gain); + } + + /** + * Creates a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + PointSound p = new PointSound(); + p.duplicateNode(this, forceDuplicate); + return p; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @exception ClassCastException if originalNode is not an instance of + * PointSound + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + checkDuplicateNode(originalNode, forceDuplicate); + } + + + /** + * Copies all PointSound information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + PointSoundRetained orgRetained = (PointSoundRetained)originalNode.retained; + PointSoundRetained thisRetained = (PointSoundRetained)this.retained; + + Point3f p = new Point3f(); + orgRetained.getPosition(p); + thisRetained.setPosition(p); + + int len = orgRetained.getDistanceGainLength(); + float distance[] = new float[len]; + float gain[] = new float[len]; + orgRetained.getDistanceGain(distance, gain); + thisRetained.setDistanceGain(distance, gain); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PointSoundRetained.java b/j3d-core/src/classes/share/javax/media/j3d/PointSoundRetained.java new file mode 100644 index 0000000..d790f3b --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PointSoundRetained.java @@ -0,0 +1,311 @@ +/* + * $RCSfile: PointSoundRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.lang.Math; +import java.net.URL; +import javax.vecmath.Point3f; +import javax.vecmath.Point3d; +import javax.vecmath.Point2f; + +/** + * The PointSoundRetained node (a sub-class of the SoundRetained node) defines + * a spatially-located sound source whose waves radiate uniformly in all + * directions from a given location in space. + */ + +class PointSoundRetained extends SoundRetained { + /** + * Origin of Sound source in Listener's space. + */ + Point3f position = new Point3f(0.0f, 0.0f, 0.0f); + + /** + * The transformed position of this sound + */ + Point3f xformPosition = new Point3f(); + Transform3D trans = new Transform3D(); + + // Pairs of distances and gain scale factors that define piecewise linear + // gain attenuation between each pair. + float[] attenuationDistance; + float[] attenuationGain; + + PointSoundRetained() { + this.nodeType = NodeRetained.POINTSOUND; + } + + /** + * Sets this sound's location from the vector provided. + * @param position the new location + */ + void setPosition(Point3f position) { + if (staticTransform != null) { + staticTransform.transform.transform(position, this.position); + } else { + this.position.set(position); + } + + getLastLocalToVworld().transform(position, xformPosition); + + dispatchAttribChange(POSITION_DIRTY_BIT, (new Point3f(this.position))); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Sets this sound's position from the three values provided. + * @param x the new x position + * @param y the new y position + * @param z the new z position + */ + void setPosition(float x, float y, float z) { + position.x = x; + position.y = y; + position.z = z; + if (staticTransform != null) { + staticTransform.transform.transform(this.position); + } + + getLastLocalToVworld().transform(position, xformPosition); + + dispatchAttribChange(POSITION_DIRTY_BIT, (new Point3f(this.position))); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Retrieves this sound's location and places it in the vector provided. + * @param position the variable to receive the location vector + */ + void getPosition(Point3f position) { + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + invTransform.transform(this.position, position); + } else { + position.set(this.position); + } + } + + void getXformPosition(Point3f position) { + position.set(this.xformPosition); + } + + /** + * Sets this sound's distance gain attenuation - where gain scale factor + * is applied to sound based on distance listener is from sound source. + * @param distance attenuation pairs of (distance,gain-scale-factor) + */ + void setDistanceGain(Point2f[] attenuation) { + // if attenuation array null set both attenuation components to null + if (attenuation == null) { + this.attenuationDistance = null; + this.attenuationGain = null; + // QUESTION: is this needed so that dispatch***() doesn't + // fail with null? + return; + } + + int attenuationLength = attenuation.length; + this.attenuationDistance = new float[attenuationLength]; + this.attenuationGain = new float[attenuationLength]; + for (int i = 0; i < attenuationLength; i++) { + this.attenuationDistance[i] = attenuation[i].x; + this.attenuationGain[i] = attenuation[i].y; + } + dispatchAttribChange(DISTANCE_GAIN_DIRTY_BIT, attenuation); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Sets this sound's distance gain given separate arrays. + * applied to sound based on distance listener is from sound source. + * @param distance array of monotonically-increasing floats. + * @param gain array of amplitude scale factors associated with distances. + */ + void setDistanceGain(float[] distance, float[] gain) { + // if distance or gain arrays are null then treat both as null + if (distance == null) { + this.attenuationDistance = null; + this.attenuationGain = null; + // QUESTION: is this needed so that dispatch***() doesn't + // fail with null? + return; + } + + int gainLength = gain.length; + int distanceLength = distance.length; + this.attenuationDistance = new float[distanceLength]; + this.attenuationGain = new float[distanceLength]; + // Copy the distance array into nodes field + System.arraycopy(distance, 0, this.attenuationDistance, 0, distanceLength); + // Copy the gain array an array of same length as the distance array + if (distanceLength <= gainLength) { + System.arraycopy(gain, 0, this.attenuationGain, 0, distanceLength); + } + else { + System.arraycopy(gain, 0, this.attenuationGain, 0, gainLength); + // Extend gain array to length of distance array + // replicate last gain values. + for (int i=gainLength; i< distanceLength; i++) { + this.attenuationGain[i] = gain[gainLength - 1]; + } + } + Point2f [] attenuation = new Point2f[distanceLength]; + for (int i=0; i attenuationLength) + distanceLength = attenuationLength; + for (int i=0; i< distanceLength; i++) { + attenuation[i].x = attenuationDistance[i]; + attenuation[i].y = attenuationGain[i]; + } + } + + /** + * Retieves this sound's attenuation distance and gain arrays, returned in + * separate arrays. + * @param distance array of monotonically-increasing floats. + * @param gain array of amplitude scale factors associated with distances. + */ + void getDistanceGain(float[] distance, float[] gain) { + // write into arrays passed in, don't do a new + if (distance == null || gain == null) + return; + if (this.attenuationDistance == null || this.attenuationGain == null) + return; + // These two array length should be the same + int attenuationLength = this.attenuationDistance.length; + int distanceLength = distance.length; + if (distanceLength > attenuationLength) + distanceLength = attenuationLength; + System.arraycopy(this.attenuationDistance, 0, distance, 0, distanceLength); + attenuationLength = this.attenuationDistance.length; + int gainLength = gain.length; + if (gainLength > attenuationLength) + gainLength = attenuationLength; + System.arraycopy(this.attenuationGain, 0, gain, 0, gainLength); + } + + /** + * This updates the positional fields of point sound. + * + * Distance gain attenuation field not maintained in mirror object. + */ + void updateMirrorObject(Object[] objs) { + if (debugFlag) + debugPrint("PointSoundRetained:updateMirrorObj()"); + int component = ((Integer)objs[1]).intValue(); + int numSnds = ((Integer)objs[2]).intValue(); + SoundRetained[] mSnds = (SoundRetained[]) objs[3]; + if (component == -1) { + // update every field + initMirrorObject(((PointSoundRetained)objs[2])); + return; + } + if ((component & POSITION_DIRTY_BIT) != 0) { + for (int i = 0; i < numSnds; i++) { + PointSoundRetained point = (PointSoundRetained) mSnds[i]; + Object o = objs[4]; + if (o instanceof Point3f) { + point.position = (Point3f) objs[4]; + point.getLastLocalToVworld().transform(point.position, + point.xformPosition); + } + } + } + + // call the parent's mirror object update routine + super.updateMirrorObject(objs); + } + + synchronized void initMirrorObject(PointSoundRetained ms) { + super.initMirrorObject(ms); + ms.position.set(this.position); + ms.xformPosition.set(this.xformPosition); + } + + // Called on the mirror object + void updateTransformChange() { + super.updateTransformChange(); + getLastLocalToVworld().transform(position, xformPosition); + // set flag looked at by Scheduler to denote Transform change + // this flag will force resneding transformed position to AudioDevice + if (debugFlag) + debugPrint("PointSoundRetained xformPosition is (" + xformPosition.x + + ", " + xformPosition.y + ", "+ xformPosition.z + ")"); + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + xform.transform.transform(position, position); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PolygonAttributes.java b/j3d-core/src/classes/share/javax/media/j3d/PolygonAttributes.java new file mode 100644 index 0000000..05c6228 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PolygonAttributes.java @@ -0,0 +1,496 @@ +/* + * $RCSfile: PolygonAttributes.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * The PolygonAttributes object defines attributes for rendering polygon + * primitives. + * Polygon primitives include triangles, triangle strips, triangle fans, + * and quads. + * The polygon attributes that can be defined are: + *

    + *
  • Rasterization mode - defines how the polygon is drawn: as points, + * outlines, or filled.

    + *

      + *
    • POLYGON_POINT - the polygon is rendered as points + * drawn at the vertices.
    • + *

    • POLYGON_LINE - the polygon is rendered as lines + * drawn between consecutive vertices.
    • + *

    • POLYGON_FILL - the polygon is rendered by filling the interior + * between the vertices. The default mode.
    • + *

    + *
  • Face culling - defines which polygons are culled (discarded) + * before they are converted to screen coordinates.

    + *

      + *
    • CULL_NONE - disables face culling.
    • + *
    • CULL_BACK - culls all back-facing polygons. The default.
    • + *
    • CULL_FRONT - culls all front-facing polygons.
    • + *

    + *
  • Back-face normal flip - specifies whether vertex normals of + * back-facing polygons are flipped (negated) prior to lighting. The + * setting is either true, meaning to flip back-facing normals, or + * false. The default is false.
  • + *

    + *

  • Offset - the depth values of all pixels generated by polygon + * rasterization can be offset by a value that is computed for that + * polygon. Two values are used to specify the offset:
  • + *

      + *
    • Offset bias - the constant polygon offset that is added to + * the final device coordinate Z value of polygon primitives.
    • + *

      + *

    • Offset factor - the factor to be multiplied by the + * slope of the polygon and then added to the final, device coordinate + * Z value of the polygon primitives.
    • + *

    + * These values can be either positive or negative. The default + * for both of these values is 0.0.

    + *

+ * + * @see Appearance + */ +public class PolygonAttributes extends NodeComponent { + + /** + * Specifies that this PolygonAttributes object allows reading its + * cull face information. + */ + public static final int + ALLOW_CULL_FACE_READ = CapabilityBits.POLYGON_ATTRIBUTES_ALLOW_CULL_FACE_READ; + + /** + * Specifies that this PolygonAttributes object allows writing its + * cull face information. + */ + public static final int + ALLOW_CULL_FACE_WRITE = CapabilityBits.POLYGON_ATTRIBUTES_ALLOW_CULL_FACE_WRITE; + + /** + * Specifies that this PolygonAttributes object allows reading its + * back face normal flip flag. + */ + public static final int + ALLOW_NORMAL_FLIP_READ = CapabilityBits.POLYGON_ATTRIBUTES_ALLOW_NORMAL_FLIP_READ; + + /** + * Specifies that this PolygonAttributes object allows writing its + * back face normal flip flag. + */ + public static final int + ALLOW_NORMAL_FLIP_WRITE = CapabilityBits.POLYGON_ATTRIBUTES_ALLOW_NORMAL_FLIP_WRITE; + + /** + * Specifies that this PolygonAttributes object allows reading its + * polygon mode information. + */ + public static final int + ALLOW_MODE_READ = CapabilityBits.POLYGON_ATTRIBUTES_ALLOW_MODE_READ; + + /** + * Specifies that this PolygonAttributes object allows writing its + * polygon mode information. + */ + public static final int + ALLOW_MODE_WRITE = CapabilityBits.POLYGON_ATTRIBUTES_ALLOW_MODE_WRITE; + + /** + * Specifies that this PolygonAttributes object allows reading its + * polygon offset information. + */ + public static final int + ALLOW_OFFSET_READ = CapabilityBits.POLYGON_ATTRIBUTES_ALLOW_OFFSET_READ; + + /** + * Specifies that this PolygonAttributes object allows writing its + * polygon offset information. + */ + public static final int + ALLOW_OFFSET_WRITE = CapabilityBits.POLYGON_ATTRIBUTES_ALLOW_OFFSET_WRITE; + + // Polygon rasterization modes + /** + * Render polygonal primitives as points drawn at the vertices + * of the polygon. + */ + public static final int POLYGON_POINT = 0; + /** + * Render polygonal primitives as lines drawn between consecutive + * vertices of the polygon. + */ + public static final int POLYGON_LINE = 1; + /** + * Render polygonal primitives by filling the interior of the polygon. + */ + public static final int POLYGON_FILL = 2; + + /** + * Don't perform any face culling. + */ + public static final int CULL_NONE = 0; + /** + * Cull all back-facing polygons. This is the default mode. + */ + public static final int CULL_BACK = 1; + /** + * Cull all front-facing polygons. + */ + public static final int CULL_FRONT = 2; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_CULL_FACE_READ, + ALLOW_MODE_READ, + ALLOW_NORMAL_FLIP_READ, + ALLOW_OFFSET_READ + }; + + /** + * Constructs a PolygonAttributes object with default parameters. + * The default values are as follows: + *
    + * cull face : CULL_BACK
    + * back face normal flip : false
    + * polygon mode : POLYGON_FILL
    + * polygon offset : 0.0
    + * polygon offset factor : 0.0
    + *
+ */ + public PolygonAttributes() { + // Just use defaults for all attributes + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a PolygonAttributes object with specified values. + * @param polygonMode polygon rasterization mode; one of POLYGON_POINT, + * POLYGON_LINE, or POLYGON_FILL + * @param cullFace polygon culling mode; one of CULL_NONE, + * CULL_BACK, or CULL_FRONT + * @param polygonOffset constant polygon offset + */ + public PolygonAttributes(int polygonMode, + int cullFace, + float polygonOffset) { + this(polygonMode, cullFace, polygonOffset, false, 0.0f); + } + + /** + * Constructs PolygonAttributes object with specified values. + * @param polygonMode polygon rasterization mode; one of POLYGON_POINT, + * POLYGON_LINE, or POLYGON_FILL + * @param cullFace polygon culling mode; one of CULL_NONE, + * CULL_BACK, or CULL_FRONT + * @param polygonOffset constant polygon offset + * @param backFaceNormalFlip back face normal flip flag; true or false + */ + public PolygonAttributes(int polygonMode, + int cullFace, + float polygonOffset, + boolean backFaceNormalFlip) { + this(polygonMode, cullFace, polygonOffset, backFaceNormalFlip, 0.0f); + } + + /** + * Constructs PolygonAttributes object with specified values. + * @param polygonMode polygon rasterization mode; one of POLYGON_POINT, + * POLYGON_LINE, or POLYGON_FILL + * @param cullFace polygon culling mode; one of CULL_NONE, + * CULL_BACK, or CULL_FRONT + * @param polygonOffset constant polygon offset + * @param backFaceNormalFlip back face normal flip flag; true or false + * @param polygonOffsetFactor polygon offset factor for slope-based polygon + * offset + * + * @since Java 3D 1.2 + */ + public PolygonAttributes(int polygonMode, + int cullFace, + float polygonOffset, + boolean backFaceNormalFlip, + float polygonOffsetFactor) { + + if (polygonMode < POLYGON_POINT || polygonMode > POLYGON_FILL) + throw new IllegalArgumentException(J3dI18N.getString("PolygonAttributes0")); + + if (cullFace < CULL_NONE || cullFace > CULL_FRONT) + throw new IllegalArgumentException(J3dI18N.getString("PolygonAttributes12")); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((PolygonAttributesRetained)this.retained).initPolygonMode(polygonMode); + ((PolygonAttributesRetained)this.retained).initCullFace(cullFace); + ((PolygonAttributesRetained)this.retained).initPolygonOffset(polygonOffset); + ((PolygonAttributesRetained)this.retained).initBackFaceNormalFlip(backFaceNormalFlip); + ((PolygonAttributesRetained)this.retained).initPolygonOffsetFactor(polygonOffsetFactor); + } + + /** + * Sets the face culling for this + * appearance component object. + * @param cullFace the face to be culled, one of: + * CULL_NONE, CULL_FRONT, or CULL_BACK + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setCullFace(int cullFace) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CULL_FACE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes2")); + + if (cullFace < CULL_NONE || cullFace > CULL_FRONT) + throw new IllegalArgumentException(J3dI18N.getString("PolygonAttributes3")); + if (isLive()) + ((PolygonAttributesRetained)this.retained).setCullFace(cullFace); + else + ((PolygonAttributesRetained)this.retained).initCullFace(cullFace); + + } + + /** + * Gets the face culling for this + * appearance component object. + * @return the face to be culled + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getCullFace() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CULL_FACE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes4")); + + return ((PolygonAttributesRetained)this.retained).getCullFace(); + } + + /** + * Sets the back face normal flip flag to the specified value. + * This flag indicates whether vertex normals of back facing polygons + * should be flipped (negated) prior to lighting. When this flag + * is set to true and back face culling is disabled, polygons are + * rendered as if the polygon had two sides with opposing normals. + * This feature is disabled by default. + * @param backFaceNormalFlip the back face normal flip flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setBackFaceNormalFlip(boolean backFaceNormalFlip) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_FLIP_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes5")); + if (isLive()) + ((PolygonAttributesRetained)this.retained).setBackFaceNormalFlip(backFaceNormalFlip); + else + ((PolygonAttributesRetained)this.retained).initBackFaceNormalFlip(backFaceNormalFlip); + + } + + /** + * Gets the back face normal flip flag. + * @return the back face normal flip flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getBackFaceNormalFlip() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_NORMAL_FLIP_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes6")); + + return ((PolygonAttributesRetained)this.retained).getBackFaceNormalFlip(); + } + + /** + * Sets the polygon rasterization mode for this + * appearance component object. + * @param polygonMode the polygon rasterization mode to be used; one of + * POLYGON_FILL, POLYGON_LINE, or POLYGON_POINT + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPolygonMode(int polygonMode) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_MODE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes7")); + + if (polygonMode < POLYGON_POINT || polygonMode > POLYGON_FILL) + throw new IllegalArgumentException(J3dI18N.getString("PolygonAttributes8")); + if (isLive()) + ((PolygonAttributesRetained)this.retained).setPolygonMode(polygonMode); + else + ((PolygonAttributesRetained)this.retained).initPolygonMode(polygonMode); + + } + + /** + * Gets the polygon rasterization mode for this + * appearance component object. + * @return the polygon rasterization mode + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getPolygonMode() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes9")); + + return ((PolygonAttributesRetained)this.retained).getPolygonMode(); + } + + /** + * Sets the constant polygon offset to the specified value. + * This screen space + * offset is added to the final, device coordinate Z value of polygon + * primitives. + * @param polygonOffset the constant polygon offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPolygonOffset(float polygonOffset) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes10")); + + if (isLive()) + ((PolygonAttributesRetained)this.retained).setPolygonOffset(polygonOffset); + else + ((PolygonAttributesRetained)this.retained).initPolygonOffset(polygonOffset); + + } + + /** + * Gets the constant polygon offset. + * @return the constant polygon offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getPolygonOffset() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes11")); + + return ((PolygonAttributesRetained)this.retained).getPolygonOffset(); + } + + /** + * Sets the polygon offset factor to the specified value. + * This factor is multiplied by the slope of the polygon, and + * then added to the final, device coordinate Z value of polygon + * primitives. + * @param polygonOffsetFactor the polygon offset factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public void setPolygonOffsetFactor(float polygonOffsetFactor) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes10")); + + if (isLive()) + ((PolygonAttributesRetained)this.retained). + setPolygonOffsetFactor(polygonOffsetFactor); + else + ((PolygonAttributesRetained)this.retained). + initPolygonOffsetFactor(polygonOffsetFactor); + } + + /** + * Gets the polygon offset factor. + * @return the polygon offset factor. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public float getPolygonOffsetFactor() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("PolygonAttributes11")); + + return ((PolygonAttributesRetained)this.retained).getPolygonOffsetFactor(); + } + + /** + * Creates a retained mode PolygonAttributesRetained object that this + * PolygonAttributes component object will point to. + */ + void createRetained() { + this.retained = new PolygonAttributesRetained(); + this.retained.setSource(this); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + PolygonAttributes pga = new PolygonAttributes(); + pga.duplicateNodeComponent(this); + return pga; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + PolygonAttributesRetained attr = (PolygonAttributesRetained) + originalNodeComponent.retained; + + PolygonAttributesRetained rt = (PolygonAttributesRetained) retained; + + rt.initCullFace(attr.getCullFace()); + rt.initBackFaceNormalFlip(attr.getBackFaceNormalFlip()); + rt.initPolygonMode(attr.getPolygonMode()); + rt.initPolygonOffset(attr.getPolygonOffset()); + rt.initPolygonOffsetFactor(attr.getPolygonOffsetFactor()); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PolygonAttributesRetained.java b/j3d-core/src/classes/share/javax/media/j3d/PolygonAttributesRetained.java new file mode 100644 index 0000000..b5f048b --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PolygonAttributesRetained.java @@ -0,0 +1,361 @@ +/* + * $RCSfile: PolygonAttributesRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * The PolygonAttributes object defines all rendering state that can be set + * as a component object of a Shape3D node. + */ +class PolygonAttributesRetained extends NodeComponentRetained { + // A list of pre-defined bits to indicate which component + // in this LineAttributesRetained object changed. + static final int POLYGON_MODE_CHANGED = 0x01; + static final int POLYGON_CULL_CHANGED = 0x02; + static final int POLYGON_OFFSET_CHANGED = 0x04; + static final int POLYGON_BACKFACENORMALFLIP_CHANGED = 0x08; + static final int POLYGON_OFFSETFACTOR_CHANGED = 0x10; + + // Polygon rasterization mode (point, line, fill) + int polygonMode = PolygonAttributes.POLYGON_FILL; + + // Face culling mode + int cullFace = PolygonAttributes.CULL_BACK; + + // back face normal flip flag + boolean backFaceNormalFlip = false; + + // constant polygon offset + float polygonOffset; + + // polygon offset factor + float polygonOffsetFactor; + + /** + * Sets the face culling for this + * appearance component object, + * @param cullFace the face to be culled, one of: + * CULL_NONE, CULL_FRONT, or CULL_BACK + */ + final void initCullFace(int cullFace) { + this.cullFace = cullFace; + } + + /** + * Sets the face culling for this + * appearance component object and sends a message notifying + * the interested structures of the change. + * @param cullFace the face to be culled, one of: + * CULL_NONE, CULL_FRONT, or CULL_BACK + */ + final void setCullFace(int cullFace) { + initCullFace(cullFace); + sendMessage(POLYGON_CULL_CHANGED, new Integer(cullFace)); + } + + /** + * Gets the face culling for this + * appearance component object. + * @return the face to be culled + */ + final int getCullFace() { + return cullFace; + } + + /** + * Sets the back face normal flip flag to the specified value + * This flag indicates whether vertex normals of back facing polygons + * should be flipped (negated) prior to lighting. When this flag + * is set to true and back face culling is disabled, polygons are + * rendered as if the polygon had two sides with opposing normals. + * This feature is disabled by default + * @param backFaceNormalFlip the back face normal flip flag + */ + final void initBackFaceNormalFlip(boolean backFaceNormalFlip) { + this.backFaceNormalFlip = backFaceNormalFlip; + } + + /** + * Sets the back face normal flip flag to the specified value + * and sends a message notifying + * the interested structures of the change. + * This flag indicates whether vertex normals of back facing polygons + * should be flipped (negated) prior to lighting. When this flag + * is set to true and back face culling is disabled, polygons are + * rendered as if the polygon had two sides with opposing normals. + * This feature is disabled by default + * @param backFaceNormalFlip the back face normal flip flag + */ + final void setBackFaceNormalFlip(boolean backFaceNormalFlip) { + initBackFaceNormalFlip(backFaceNormalFlip); + sendMessage(POLYGON_BACKFACENORMALFLIP_CHANGED, + (backFaceNormalFlip ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Gets the back face normal flip flag. + * @return the back face normal flip flag + */ + final boolean getBackFaceNormalFlip() { + return backFaceNormalFlip; + } + + /** + * Sets the polygon rasterization mode for this + * appearance component object. + * @param polygonMode the polygon rasterization mode to be used; one of + * POLYGON_FILL, POLYGON_LINE, or POLYGON_POINT + */ + final void initPolygonMode(int polygonMode) { + this.polygonMode = polygonMode; + } + + /** + * Sets the polygon rasterization mode for this + * appearance component object and sends a message notifying + * the interested structures of the change. + * @param polygonMode the polygon rasterization mode to be used; one of + * POLYGON_FILL, POLYGON_LINE, or POLYGON_POINT + */ + final void setPolygonMode(int polygonMode) { + initPolygonMode(polygonMode); + sendMessage(POLYGON_MODE_CHANGED, new Integer(polygonMode)); + } + + /** + * Gets the polygon rasterization mode for this + * appearance component object. + * @return polygonMode the polygon rasterization mode + */ + final int getPolygonMode() { + return polygonMode; + } + + /** + * Sets the polygon offset to the specified value and sends a + * message notifying the interested structures of the change. + * This screen space offset is added to the final, device + * coordinate Z value of polygon primitives. + * @param polygonOffset the polygon offset + */ + final void initPolygonOffset(float polygonOffset) { + this.polygonOffset = polygonOffset; + } + + /** + * Sets the polygon offset to the specified value and sends a + * message notifying the interested structures of the change. + * This screen space offset is added to the final, device + * coordinate Z value of polygon primitives. + * @param polygonOffset the polygon offset + */ + final void setPolygonOffset(float polygonOffset) { + initPolygonOffset(polygonOffset); + sendMessage(POLYGON_OFFSET_CHANGED, new Float(polygonOffset)); + } + + + /** + * Gets the polygon offset. + * @return polygonOffset the polygon offset + */ + final float getPolygonOffset() { + return polygonOffset; + } + + + /** + * Sets the polygon offset factor to the specified value and sends a + * message notifying the interested structures of the change. + * This factor is multiplied by the slope of the polygon, and + * then added to the final, device coordinate Z value of polygon + * primitives. + * @param polygonOffsetFactor the polygon offset factor + */ + final void initPolygonOffsetFactor(float polygonOffsetFactor) { + this.polygonOffsetFactor = polygonOffsetFactor; + } + + /** + * Sets the polygon offset factor to the specified value and sends a + * message notifying the interested structures of the change. + * This factor is multiplied by the slope of the polygon, and + * then added to the final, device coordinate Z value of polygon + * primitives. + * @param polygonOffsetFactor the polygon offset + */ + final void setPolygonOffsetFactor(float polygonOffsetFactor) { + initPolygonOffsetFactor(polygonOffsetFactor); + sendMessage(POLYGON_OFFSETFACTOR_CHANGED, + new Float(polygonOffsetFactor)); + } + + + /** + * Gets the polygon offset factor. + * @return polygonOffset the polygon offset factor + */ + final float getPolygonOffsetFactor() { + return polygonOffsetFactor; + } + + /** + * Creates and initializes a mirror object, point the mirror object + * to the retained object if the object is not editable + */ + synchronized void createMirrorObject() { + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror = this; + } else { + PolygonAttributesRetained mirrorPa = new PolygonAttributesRetained(); + mirrorPa.set(this); + mirrorPa.source = source; + mirror = mirrorPa; + } + } else { + ((PolygonAttributesRetained) mirror).set(this); + } + } + + + /** + * Updates the native context + */ + void updateNative(Context ctx) { + Pipeline.getPipeline().updatePolygonAttributes(ctx, + polygonMode, cullFace, backFaceNormalFlip, + polygonOffset, polygonOffsetFactor); + } + + /** + * Initializes a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + ((PolygonAttributesRetained) mirror).set(this); + } + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + PolygonAttributesRetained mirrorPa = (PolygonAttributesRetained) mirror; + + if ((component & POLYGON_MODE_CHANGED) != 0) { + mirrorPa.polygonMode = ((Integer)value).intValue(); + } + else if ((component & POLYGON_CULL_CHANGED) != 0) { + mirrorPa.cullFace = ((Integer)value).intValue(); + } + else if ((component & POLYGON_BACKFACENORMALFLIP_CHANGED) != 0) { + mirrorPa.backFaceNormalFlip = ((Boolean)value).booleanValue(); + } + else if ((component & POLYGON_OFFSET_CHANGED) != 0) { + mirrorPa.polygonOffset = ((Float)value).floatValue(); + } + else if ((component & POLYGON_OFFSETFACTOR_CHANGED) != 0) { + mirrorPa.polygonOffsetFactor = ((Float) value).floatValue(); + } + } + + + boolean equivalent(PolygonAttributesRetained pr) { + return ((pr != null) && + (pr.cullFace == cullFace) && + (pr.backFaceNormalFlip == backFaceNormalFlip) && + (pr.polygonOffset == polygonOffset) && + (pr.polygonMode == polygonMode) && + (pr.polygonOffsetFactor == polygonOffsetFactor)); + } + + protected void set(PolygonAttributesRetained pr) { + super.set(pr); + cullFace = pr.cullFace; + backFaceNormalFlip = pr.backFaceNormalFlip; + polygonMode = pr.polygonMode; + polygonOffset = pr.polygonOffset; + polygonOffsetFactor = pr.polygonOffsetFactor; + } + + final void sendMessage(int attrMask, Object attr) { + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.POLYGONATTRIBUTES_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; iTransformInterpolator.setTransformAxis(Transform3D) + */ + public void setAxisOfTranslation(Transform3D axisOfTranslation) { + setTransformAxis(axisOfTranslation); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.getTransformAxis() + */ + public Transform3D getAxisOfTranslation() { + return getTransformAxis(); + } + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + + double val = (1.0-alphaValue)*startPosition + alphaValue*endPosition; + + // construct a Transform3D from: axis * translation * axisInverse + transv.set(val, 0.0, 0.0); + translation.setTranslation(transv); + + transform.mul(axis, translation); + transform.mul(transform, axisInverse); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + PositionInterpolator pi = new PositionInterpolator(); + pi.duplicateNode(this, forceDuplicate); + return pi; + } + + /** + * Copies all PositionInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + PositionInterpolator pi = (PositionInterpolator) originalNode; + + setStartPosition(pi.getStartPosition()); + setEndPosition(pi.getEndPosition()); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/PositionPathInterpolator.java b/j3d-core/src/classes/share/javax/media/j3d/PositionPathInterpolator.java new file mode 100644 index 0000000..e60944c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/PositionPathInterpolator.java @@ -0,0 +1,282 @@ +/* + * $RCSfile: PositionPathInterpolator.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + + +/** + * PositionPathInterpolator behavior. This class defines a behavior + * that modifies the translational component of its target TransformGroup + * by linearly interpolating among a series of predefined knot/position + * pairs (using the value generated by the specified Alpha object). The + * interpolated position is used to generate a translation transform + * in the local coordinate system of this interpolator. The first knot + * must have a value of 0.0. The last knot must have a value of 1.0. An + * intermediate knot with index k must have a value strictly greater + * than any knot with index less than k. + */ + +public class PositionPathInterpolator extends PathInterpolator { + private Transform3D position = new Transform3D(); + private Vector3f pos = new Vector3f(); + + // Array of positions at each knot + private Point3f positions[]; + private float prevInterpolationValue = Float.NaN; + + // We can't use a boolean flag since it is possible + // that after alpha change, this procedure only run + // once at alpha.finish(). So the best way is to + // detect alpha value change. + private float prevAlphaValue = Float.NaN; + private WakeupCriterion passiveWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0, true); + + // non-public, default constructor used by cloneNode + PositionPathInterpolator() { + } + + + /** + * Constructs a new PositionPathInterpolator that varies the transform + * of the target TransformGroup. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this translator + * @param axisOfTransform the transform that defines the local + * coordinate system in which this interpolator operates + * @param knots an array of knot values that specify interpolation points. + * @param positions an array of position values at the knots. + * @exception IllegalArgumentException if the lengths of the + * knots and positions arrays are not the same. + */ + public PositionPathInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + float[] knots, + Point3f[] positions) { + + super(alpha, target, axisOfTransform, knots); + + if (knots.length != positions.length) + throw new IllegalArgumentException(J3dI18N.getString("PositionPathInterpolator0")); + setPathArrays(positions); + } + + + /** + * Sets the position at the specified index for this + * interpolator. + * @param index the index of the position to be changed + * @param position the new position at the index + */ + public void setPosition(int index, Point3f position) { + this.positions[index].set(position); + } + + + /** + * Retrieves the position value at the specified index. + * @param index the index of the value requested + * @param position the variable to receive the position value at + * the specified index + */ + public void getPosition(int index, Point3f position) { + position.set(this.positions[index]); + } + + + /** + * Replaces the existing arrays of knot values + * and position values with the specified arrays. + * The arrays of knots and positions are copied + * into this interpolator object. + * @param knots a new array of knot values that specify + * interpolation points + * @param positions a new array of position values at the knots + * @exception IllegalArgumentException if the lengths of the + * knots and positions arrays are not the same. + * + * @since Java 3D 1.2 + */ + public void setPathArrays(float[] knots, + Point3f[] positions) { + + if (knots.length != positions.length) + throw new IllegalArgumentException(J3dI18N.getString("PositionPathInterpolator0")); + + setKnots(knots); + setPathArrays(positions); + } + + + // Set the specific arrays for this path interpolator + private void setPathArrays(Point3f[] positions) { + + this.positions = new Point3f[positions.length]; + for(int i = 0; i < positions.length; i++) { + this.positions[i] = new Point3f(); + this.positions[i].set(positions[i]); + } + } + + + /** + * Copies the array of position values from this interpolator + * into the specified array. + * The array must be large enough to hold all of the positions. + * The individual array elements must be allocated by the caller. + * @param positions array that will receive the positions + * + * @since Java 3D 1.2 + */ + public void getPositions(Point3f[] positions) { + for (int i = 0; i < this.positions.length; i++) { + positions[i].set(this.positions[i]); + } + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.setTransformAxis(Transform3D) + */ + public void setAxisOfTranslation(Transform3D axisOfTranslation) { + setTransformAxis(axisOfTranslation); + } + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.getTransformAxis() + */ + public Transform3D getAxisOfTranslation() { + return getTransformAxis(); + } + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + + computePathInterpolation(alphaValue); + + if (currentKnotIndex == 0 && + currentInterpolationValue == 0f) { + pos.x = positions[0].x; + pos.y = positions[0].y; + pos.z = positions[0].z; + } else { + pos.x = positions[currentKnotIndex].x + + (positions[currentKnotIndex+1].x - + positions[currentKnotIndex].x) * currentInterpolationValue; + pos.y = positions[currentKnotIndex].y + + (positions[currentKnotIndex+1].y - + positions[currentKnotIndex].y) * currentInterpolationValue; + pos.z = positions[currentKnotIndex].z + + (positions[currentKnotIndex+1].z - + positions[currentKnotIndex].z) * currentInterpolationValue; + } + position.setIdentity(); + position.setTranslation(pos); + + // construct a Transform3D from: axis * position * axisInverse + transform.mul(axis, position); + transform.mul(transform, axisInverse); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + PositionPathInterpolator ppi = new PositionPathInterpolator(); + ppi.duplicateNode(this, forceDuplicate); + return ppi; + } + + + /** + * Copies all PositionPathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + PositionPathInterpolator pi = + (PositionPathInterpolator) originalNode; + + int len = pi.getArrayLengths(); + + // No API available to set the size of positions + positions = new Point3f[len]; + + Point3f dupPoint = new Point3f(); + for (int i = 0; i < len; i++) { + positions[i] = new Point3f(); + pi.getPosition(i, dupPoint); + setPosition(i, dupPoint); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/QuadArray.java b/j3d-core/src/classes/share/javax/media/j3d/QuadArray.java new file mode 100644 index 0000000..f64da6d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/QuadArray.java @@ -0,0 +1,196 @@ +/* + * $RCSfile: QuadArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * The QuadArray object draws the array of vertices as individual + * quadrilaterals. Each group + * of four vertices defines a quadrilateral to be drawn. + */ + +public class QuadArray extends GeometryArray { + + // non-public, no parameter constructor + QuadArray() {} + + /** + * Constructs an empty QuadArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 4 + * or vertexCount is not a multiple of 4 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public QuadArray(int vertexCount, int vertexFormat) { + super(vertexCount,vertexFormat); + + if (vertexCount < 4 || ((vertexCount%4) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("QuadArray0")); + } + + /** + * Constructs an empty QuadArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 4 + * or vertexCount is not a multiple of 4 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public QuadArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap); + + if (vertexCount < 4 || ((vertexCount%4) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("QuadArray0")); + } + + /** + * Constructs an empty QuadArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 4 + * or vertexCount is not a multiple of 4 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public QuadArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + + if (vertexCount < 4 || ((vertexCount%4) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("QuadArray0")); + } + + /** + * Creates the retained mode QuadArrayRetained object that this + * QuadArray object will point to. + */ + void createRetained() { + this.retained = new QuadArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + QuadArrayRetained rt = (QuadArrayRetained) retained; + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + QuadArray q = new QuadArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes); + q.duplicateNodeComponent(this); + return q; + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/QuadArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/QuadArrayRetained.java new file mode 100644 index 0000000..e6c738e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/QuadArrayRetained.java @@ -0,0 +1,524 @@ +/* + * $RCSfile: QuadArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The QuadArray object draws the array of vertices as individual + * quadrilaterals. Each group + * of four vertices defines a quadrilateral to be drawn. + */ + +class QuadArrayRetained extends GeometryArrayRetained { + + QuadArrayRetained() { + this.geoType = GEO_TYPE_QUAD_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + + Point3d pnts[] = new Point3d[4]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int[] vtxIndexArr = new int[4]; + + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + pnts[3] = new Point3d(); + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectRay(pnts, pickRay, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectSegment(pnts, pickSegment.start, + pickSegment.end, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + while (i < validVertexCount) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingPolytope(pnts, bpolytope, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<4; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("QuadArrayRetained0")); + default: + throw new RuntimeException("PickShape not supported for intersection "); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + + } + + // intersect pnts[] with every quad in this object + boolean intersect(Point3d[] pnts) { + Point3d[] points = new Point3d[4]; + double dist[] = new double[1]; + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + points[3] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle + while (i < validVertexCount) { + getVertexData(i++, points[0]); + getVertexData(i++, points[1]); + getVertexData(i++, points[2]); + getVertexData(i++, points[3]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[2], points[3], + pnts[0], pnts[1], pnts[2])) { + return true; + } + } + break; + case 4: // Quad + + while (i < validVertexCount) { + getVertexData(i++, points[0]); + getVertexData(i++, points[1]); + getVertexData(i++, points[2]); + getVertexData(i++, points[3]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[2], pnts[3]) || + intersectTriTri(points[0], points[2], points[3], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[2], points[3], + pnts[0], pnts[2], pnts[3])) { + return true; + } + } + break; + case 2: // Line + while (i < validVertexCount) { + getVertexData(i++, points[0]); + getVertexData(i++, points[1]); + getVertexData(i++, points[2]); + getVertexData(i++, points[3]); + if (intersectSegment(points, pnts[0], pnts[1], dist, + null)) { + return true; + } + } + break; + case 1: // Point + while (i < validVertexCount) { + getVertexData(i++, points[0]); + getVertexData(i++, points[1]); + getVertexData(i++, points[2]); + getVertexData(i++, points[3]); + if (intersectTriPnt(points[0], points[1], points[2], + pnts[0]) || + intersectTriPnt(points[0], points[2], points[3], + pnts[0])) { + return true; + } + } + break; + } + return false; + } + + + boolean intersect(Transform3D thisToOtherVworld, GeometryRetained geom) { + + Point3d[] points = new Point3d[4]; + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + points[3] = new Point3d(); + + while (i < validVertexCount) { + getVertexData(i++, points[0]); + getVertexData(i++, points[1]); + getVertexData(i++, points[2]); + getVertexData(i++, points[3]); + thisToOtherVworld.transform(points[0]); + thisToOtherVworld.transform(points[1]); + thisToOtherVworld.transform(points[2]); + thisToOtherVworld.transform(points[3]); + if (geom.intersect(points)) { + return true; + } + } // for each quad + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + Point3d[] points = new Point3d[4]; + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + points[3] = new Point3d(); + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while (i < validVertexCount) { + getVertexData(i++, points[0]); + getVertexData(i++, points[1]); + getVertexData(i++, points[2]); + getVertexData(i++, points[3]); + if (intersectBoundingBox(points, box, null, null)) { + return true; + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + + while (i < validVertexCount) { + getVertexData(i++, points[0]); + getVertexData(i++, points[1]); + getVertexData(i++, points[2]); + getVertexData(i++, points[3]); + if (intersectBoundingSphere(points, bsphere, null, + null)) { + return true; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + + while (i < validVertexCount) { + getVertexData(i++, points[0]); + getVertexData(i++, points[1]); + getVertexData(i++, points[2]); + getVertexData(i++, points[3]); + if (intersectBoundingPolytope(points, bpolytope, null, null)) { + return true; + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + return false; + } + + // From Graphics Gems IV (pg5) and Graphics Gems II, Pg170 + // The centroid is the area-weighted sum of the centroids of + // disjoint triangles that make up the polygon. + void computeCentroid() { + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + Point3d pnt0 = new Point3d(); + Point3d pnt1 = new Point3d(); + Point3d pnt2 = new Point3d(); + Point3d pnt3 = new Point3d(); + Vector3d vec = new Vector3d(); + Vector3d normal = new Vector3d(); + Vector3d tmpvec = new Vector3d(); + + double area; + double totalarea = 0; + + centroid.x = 0; + centroid.y = 0; + centroid.z = 0; + + while (i < validVertexCount) { + getVertexData(i++, pnt0); + getVertexData(i++, pnt1); + getVertexData(i++, pnt2); + getVertexData(i++, pnt3); + + // Determine the normal + tmpvec.sub(pnt0, pnt1); + vec.sub(pnt1, pnt2); + + // Do the cross product + normal.cross(tmpvec, vec); + normal.normalize(); + // If a degenerate triangle, don't include + if (Double.isNaN(normal.x+normal.y+normal.z)) + continue; + tmpvec.set(0,0,0); + // compute the area of each triangle + getCrossValue(pnt0, pnt1, tmpvec); + getCrossValue(pnt1, pnt2, tmpvec); + getCrossValue(pnt2, pnt0, tmpvec); + area = normal.dot(tmpvec); + totalarea += area; + centroid.x += (pnt0.x+pnt1.x+pnt2.x) * area; + centroid.y += (pnt0.y+pnt1.y+pnt2.y) * area; + centroid.z += (pnt0.z+pnt1.z+pnt2.z) * area; + + // compute the area of each triangle + tmpvec.set(0,0,0); + getCrossValue(pnt0, pnt2, tmpvec); + getCrossValue(pnt2, pnt3, tmpvec); + getCrossValue(pnt3, pnt0, tmpvec); + area = normal.dot(tmpvec); + totalarea += area; + centroid.x += (pnt3.x+pnt0.x+pnt2.x) * area; + centroid.y += (pnt3.y+pnt0.y+pnt2.y) * area; + centroid.z += (pnt3.z+pnt0.z+pnt2.z) * area; + } + if (totalarea != 0.0) { + area = 1.0/(3.0 * totalarea); + centroid.x *= area; + centroid.y *= area; + centroid.z *= area; + } + } + + int getClassType() { + return QUAD_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Raster.java b/j3d-core/src/classes/share/javax/media/j3d/Raster.java new file mode 100644 index 0000000..3dbcbe9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Raster.java @@ -0,0 +1,821 @@ +/* + * $RCSfile: Raster.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.awt.Point; +import java.awt.Dimension; + + +/** + * The Raster object extends Geometry to allow drawing a raster image + * that is attached to a 3D location in the virtual world. + * It contains a 3D point that is defined in the local object + * coordinate system of the Shape3D node that references the Raster. + * It also contains a type specifier, a clipping mode, a reference to + * a ImageComponent2D object and/or a DepthComponent object, an + * integer x,y source offset and a size (width, height) to allow + * reading or writing a portion of the referenced image, and an + * integer x,y destination offset to position the raster relative to + * the transformed 3D point. + * In addition to being used as a type of geometry for drawing, + * a Raster may be used to readback pixel data (color and/or z-buffer) + * from the frame buffer in immediate mode. + *

+ * The geometric extent of a Raster object is a single 3D point, specified + * by the raster position. This means that geometry-based picking or + * collision with a Raster object will only intersect the object at + * this single point; the 2D raster image is neither pickable + * nor collidable. + */ + +public class Raster extends Geometry { + /** + * Specifies a Raster object with color data. + * In this mode, the image reference must point to + * a valid ImageComponent object. + * + * @see #setType + */ + public static final int RASTER_COLOR = 0x1; + + /** + * Specifies a Raster object with depth (z-buffer) data. + * In this mode, the depthImage reference must point to + * a valid DepthComponent object. + * + * @see #setType + */ + public static final int RASTER_DEPTH = 0x2; + + /** + * Specifies a Raster object with both color and depth (z-buffer) data. + * In this mode, the image reference must point to + * a valid ImageComponent object, and the depthImage reference + * must point to a valid DepthComponent object. + * + * @see #setType + */ + public static final int RASTER_COLOR_DEPTH = RASTER_COLOR | RASTER_DEPTH; + + + /** + * Specifies that this raster object is not drawn + * if the raster position is outside the viewing volume. + * In this mode, the raster is not drawn when the transformed + * raster position is clipped out, even if part of the raster would + * have been visible. This is the default mode. + * + * @see #setClipMode + * + * @since Java 3D 1.3 + */ + public static final int CLIP_POSITION = 0; + + /** + * Specifies that the raster object is clipped as an image after + * the raster position has been transformed. In this mode, part + * of the raster may be drawn even when the transformed raster + * position is clipped out. + * + * @see #setClipMode + * + * @since Java 3D 1.3 + */ + public static final int CLIP_IMAGE = 1; + + + /** + * Specifies that this Raster allows reading the position. + */ + public static final int + ALLOW_POSITION_READ = CapabilityBits.RASTER_ALLOW_POSITION_READ; + + /** + * Specifies that this Raster allows writing the position. + */ + public static final int + ALLOW_POSITION_WRITE = CapabilityBits.RASTER_ALLOW_POSITION_WRITE; + + /** + * Specifies that this Raster allows reading the source or + * destination offset. + */ + public static final int + ALLOW_OFFSET_READ = CapabilityBits.RASTER_ALLOW_OFFSET_READ; + + /** + * Specifies that this Raster allows writing the source or + * destination offset. + */ + public static final int + ALLOW_OFFSET_WRITE = CapabilityBits.RASTER_ALLOW_OFFSET_WRITE; + + /** + * Specifies that this Raster allows reading the image. + */ + public static final int + ALLOW_IMAGE_READ = CapabilityBits.RASTER_ALLOW_IMAGE_READ; + + /** + * Specifies that this Raster allows writing the image. + */ + public static final int + ALLOW_IMAGE_WRITE = CapabilityBits.RASTER_ALLOW_IMAGE_WRITE; + + /** + * Specifies that this Raster allows reading the depth component. + */ + public static final int + ALLOW_DEPTH_COMPONENT_READ = CapabilityBits.RASTER_ALLOW_DEPTH_COMPONENT_READ; + + /** + * Specifies that this Raster allows writing the depth component. + */ + public static final int + ALLOW_DEPTH_COMPONENT_WRITE = CapabilityBits.RASTER_ALLOW_DEPTH_COMPONENT_WRITE; + + /** + * Specifies that this Raster allows reading the size. + */ + public static final int + ALLOW_SIZE_READ = CapabilityBits.RASTER_ALLOW_SIZE_READ; + + /** + * Specifies that this Raster allows writing the size. + */ + public static final int + ALLOW_SIZE_WRITE = CapabilityBits.RASTER_ALLOW_SIZE_WRITE; + + /** + * Specifies that this Raster allows reading the type. + */ + public static final int + ALLOW_TYPE_READ = CapabilityBits.RASTER_ALLOW_TYPE_READ; + + /** + * Specifies that this Raster allows reading the clip mode. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_CLIP_MODE_READ = CapabilityBits.RASTER_ALLOW_CLIP_MODE_READ; + + /** + * Specifies that this Raster allows writing the clip mode. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_CLIP_MODE_WRITE = CapabilityBits.RASTER_ALLOW_CLIP_MODE_WRITE; + + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_POSITION_READ, + ALLOW_OFFSET_READ, + ALLOW_IMAGE_READ, + ALLOW_DEPTH_COMPONENT_READ, + ALLOW_SIZE_READ, + ALLOW_TYPE_READ, + ALLOW_CLIP_MODE_READ + }; + + /** + * Constructs a Raster object with default parameters. + * The default values are as follows: + *

    + * type : RASTER_COLOR
    + * clipMode : CLIP_POSITION
    + * position : (0,0,0)
    + * srcOffset : (0,0)
    + * size : (0,0)
    + * dstOffset : (0,0)
    + * image : null
    + * depth component : null
    + *
+ */ + public Raster() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a new Raster object with the specified values. + * @param pos the position in object coordinates of the upper-left + * corner of the raster + * @param type the type of raster object, one of: RASTER_COLOR, + * RASTER_DEPTH, or RASTER_COLOR_DEPTH + * @param xSrcOffset the x offset within the source array of pixels + * at which to start copying + * @param ySrcOffset the y offset within the source array of pixels + * at which to start copying + * @param width the number of columns of pixels to copy + * @param height the number of rows of pixels to copy + * @param image the ImageComponent2D object containing the + * color data + * @param depthComponent the DepthComponent object containing the depth + * (z-buffer) data + * + * @exception IllegalArgumentException if the image class of the specified + * ImageComponent2D is ImageClass.NIO_IMAGE_BUFFER. + */ + public Raster(Point3f pos, + int type, + int xSrcOffset, + int ySrcOffset, + int width, + int height, + ImageComponent2D image, + DepthComponent depthComponent) { + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((RasterRetained)this.retained).setPosition(pos); + ((RasterRetained)this.retained).setType(type); + ((RasterRetained)this.retained).setSrcOffset(xSrcOffset, ySrcOffset); + ((RasterRetained)this.retained).setSize(width, height); + ((RasterRetained)this.retained).setImage(image); + ((RasterRetained)this.retained).setDepthComponent(depthComponent); + } + + /** + * Constructs a new Raster object with the specified values. + * @param pos the position in object coordinates of the upper-left + * corner of the raster + * @param type the type of raster object, one of: RASTER_COLOR, + * RASTER_DEPTH, or RASTER_COLOR_DEPTH + * @param srcOffset the offset within the source array of pixels + * at which to start copying + * @param size the width and height of the image to be copied + * @param image the ImageComponent2D object containing the + * color data + * @param depthComponent the DepthComponent object containing the depth + * (z-buffer) data + * + * @exception IllegalArgumentException if the image class of the specified + * ImageComponent2D is ImageClass.NIO_IMAGE_BUFFER. + */ + public Raster(Point3f pos, + int type, + Point srcOffset, + Dimension size, + ImageComponent2D image, + DepthComponent depthComponent) { + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((RasterRetained)this.retained).setPosition(pos); + ((RasterRetained)this.retained).setType(type); + ((RasterRetained)this.retained).setSrcOffset(srcOffset.x, srcOffset.y); + ((RasterRetained)this.retained).setSize(size.width, size.height); + ((RasterRetained)this.retained).setImage(image); + ((RasterRetained)this.retained).setDepthComponent(depthComponent); + } + + /** + * Constructs a new Raster object with the specified values. + * @param pos the position in object coordinates of the upper-left + * corner of the raster + * @param type the type of raster object, one of: RASTER_COLOR, + * RASTER_DEPTH, or RASTER_COLOR_DEPTH + * @param clipMode the clipping mode of the raster object, one of: + * CLIP_POSITION or CLIP_IMAGE + * @param srcOffset the offset within the source array of pixels + * at which to start copying + * @param size the width and height of the image to be copied + * @param dstOffset the destination pixel offset of the upper-left + * corner of the rendered image relative to the transformed position + * @param image the ImageComponent2D object containing the + * color data + * @param depthComponent the DepthComponent object containing the depth + * (z-buffer) data + * + * @exception IllegalArgumentException if the image class of the specified + * ImageComponent2D is ImageClass.NIO_IMAGE_BUFFER. + * + * @since Java 3D 1.3 + */ + public Raster(Point3f pos, + int type, + int clipMode, + Point srcOffset, + Dimension size, + Point dstOffset, + ImageComponent2D image, + DepthComponent depthComponent) { + + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((RasterRetained)this.retained).setPosition(pos); + ((RasterRetained)this.retained).setType(type); + ((RasterRetained)this.retained).setClipMode(clipMode); + ((RasterRetained)this.retained).setSrcOffset(srcOffset.x, srcOffset.y); + ((RasterRetained)this.retained).setSize(size.width, size.height); + ((RasterRetained)this.retained).setDstOffset(dstOffset.x, dstOffset.y); + ((RasterRetained)this.retained).setImage(image); + ((RasterRetained)this.retained).setDepthComponent(depthComponent); + } + + /** + * Creates the retained mode Raster object that this + * Raster object will point to. + */ + void createRetained() { + retained = new RasterRetained(); + retained.setSource(this); + } + + /** + * Sets the position in object coordinates of this raster. This + * position is transformed into device coordinates and is used as + * the upper-left corner of the raster. + * @param pos the new position of this raster + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPosition(Point3f pos) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster0")); + ((RasterRetained)this.retained).setPosition(pos); + } + + /** + * Retrieves the current position in object coordinates of this raster. + * @param pos the vector that will receive the current position + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getPosition(Point3f pos) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster1")); + + ((RasterRetained)this.retained).getPosition(pos); + } + + /** + * Sets the type of this raster object to one of: RASTER_COLOR, + * RASTER_DEPTH, or RASTER_COLOR_DEPTH. + * @param type the new type of this raster + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + public void setType(int type) { + checkForLiveOrCompiled(); + ((RasterRetained)this.retained).setType(type); + } + + + /** + * Retrieves the current type of this raster object, one of: RASTER_COLOR, + * RASTER_DEPTH, or RASTER_COLOR_DEPTH. + * @return type the type of this raster + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getType() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TYPE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster2")); + return (((RasterRetained)this.retained).getType()); + } + + + /** + * Sets the clipping mode of this raster object. + * @param clipMode the new clipping mode of this raster, + * one of: CLIP_POSITION or CLIP_IMAGE. The default mode + * is CLIP_POSITION. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setClipMode(int clipMode) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CLIP_MODE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster10")); + + ((RasterRetained)this.retained).setClipMode(clipMode); + } + + + /** + * Retrieves the current clipping mode of this raster object. + * @return clipMode the clipping mode of this raster, + * one of: CLIP_POSITION or CLIP_IMAGE. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getClipMode() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CLIP_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster11")); + + return (((RasterRetained)this.retained).getClipMode()); + } + + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * setSrcOffset(int,int) + */ + public void setOffset(int xSrcOffset, int ySrcOffset) { + setSrcOffset(xSrcOffset, ySrcOffset); + } + + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * setSrcOffset(java.awt.Point) + */ + public void setOffset(Point srcOffset) { + setSrcOffset(srcOffset); + } + + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * getSrcOffset(java.awt.Point) + */ + public void getOffset(Point srcOffset) { + getSrcOffset(srcOffset); + } + + + /** + * Sets the offset within the source array of pixels + * at which to start copying. + * @param xSrcOffset the x offset within the source array of pixels + * at which to start copying + * @param ySrcOffset the y offset within the source array of pixels + * at which to start copying + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setSrcOffset(int xSrcOffset, int ySrcOffset) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster7")); + + ((RasterRetained)this.retained).setSrcOffset(xSrcOffset, ySrcOffset); + } + + + /** + * Sets the offset within the source array of pixels + * at which to start copying. + * @param srcOffset the new source pixel offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setSrcOffset(Point srcOffset) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster7")); + + ((RasterRetained)this.retained).setSrcOffset(srcOffset.x, srcOffset.y); + } + + + /** + * Retrieves the current source pixel offset. + * @param srcOffset the object that will receive the source offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getSrcOffset(Point srcOffset) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster8")); + + ((RasterRetained)this.retained).getSrcOffset(srcOffset); + } + + + /** + * Sets the number of pixels to be copied from the pixel array. + * @param width the number of columns in the array of pixels to copy + * @param height the number of rows in the array of pixels to copy + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setSize(int width, int height) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SIZE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster9")); + + ((RasterRetained)this.retained).setSize(width, height); + } + + /** + * Sets the size of the array of pixels to be copied. + * @param size the new size + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setSize(Dimension size) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SIZE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster9")); + + ((RasterRetained)this.retained).setSize(size.width, size.height); + } + + + /** + * Retrieves the current raster size. + * @param size the object that will receive the size + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getSize(Dimension size) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SIZE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster1")); + + ((RasterRetained)this.retained).getSize(size); + } + + + /** + * Sets the destination pixel offset of the upper-left corner of + * the rendered image relative to the transformed position. This + * pixel offset is added to the transformed raster position prior + * to rendering the image. + * + * @param xDstOffset the x coordinate of the new offset + * @param yDstOffset the y coordinate of the new offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setDstOffset(int xDstOffset, int yDstOffset) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster7")); + + ((RasterRetained)this.retained).setDstOffset(xDstOffset, yDstOffset); + } + + + /** + * Sets the destination pixel offset of the upper-left corner of + * the rendered image relative to the transformed position. This + * pixel offset is added to the transformed raster position prior + * to rendering the image. + * + * @param dstOffset the new destination pixel offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setDstOffset(Point dstOffset) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster7")); + + ((RasterRetained)this.retained).setDstOffset(dstOffset.x, dstOffset.y); + } + + + /** + * Retrieves the current destination pixel offset. + * @param dstOffset the object that will receive the destination offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getDstOffset(Point dstOffset) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_OFFSET_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster8")); + + ((RasterRetained)this.retained).getDstOffset(dstOffset); + } + + + /** + * Sets the pixel array used to copy pixels to/from a Canvas3D. + * This is used when the type is RASTER_COLOR or RASTER_COLOR_DEPTH. + * + * @param image the ImageComponent2D object containing the + * color data + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalSharingException if this Raster is live and + * the specified image is being used by a Canvas3D as an off-screen buffer. + * + * @exception IllegalArgumentException if the image class of the specified + * ImageComponent2D is ImageClass.NIO_IMAGE_BUFFER. + * + */ + public void setImage(ImageComponent2D image) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_IMAGE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster3")); + + // Do illegal sharing check + if(image != null) { + ImageComponent2DRetained imageRetained = (ImageComponent2DRetained) image.retained; + if(imageRetained.getUsedByOffScreen()) { + if(isLive()) { + throw new IllegalSharingException(J3dI18N.getString("Raster12")); + } + } + } + + ((RasterRetained)this.retained).setImage(image); + } + + /** + * Retrieves the current pixel array object. + * @return image the ImageComponent2D object containing the + * color data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ImageComponent2D getImage() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_IMAGE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster4")); + return (((RasterRetained)this.retained).getImage()); + } + + /** + * Sets the depth image used to copy pixels to/from a Canvas3D. + * This is used when the type is RASTER_DEPTH or RASTER_COLOR_DEPTH. + * @param depthComponent the DepthComponent object containing the + * depth (z-buffer) data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDepthComponent(DepthComponent depthComponent) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DEPTH_COMPONENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster5")); + ((RasterRetained)this.retained).setDepthComponent(depthComponent); + } + + /** + * Retrieves the current depth image object. + * @return depthImage DepthComponent containing the + * depth (z-buffer) data + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public DepthComponent getDepthComponent() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DEPTH_COMPONENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Raster6")); + return (((RasterRetained)this.retained).getDepthComponent()); + } + + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + Raster r = new Raster(); + r.duplicateNodeComponent(this); + return r; + } + + + /** + * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @deprecated replaced with duplicateNodeComponent( + * NodeComponent originalNodeComponent, boolean forceDuplicate) + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent) { + checkDuplicateNodeComponent(originalNodeComponent); + } + + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + RasterRetained raster = (RasterRetained) originalNodeComponent.retained; + RasterRetained rt = (RasterRetained) retained; + + Point3f p = new Point3f(); + raster.getPosition(p); + rt.setPosition(p); + rt.setType(raster.getType()); + rt.setClipMode(raster.getClipMode()); + Point offset = new Point(); + raster.getSrcOffset(offset); + rt.setSrcOffset(offset.x, offset.y); + raster.getDstOffset(offset); + rt.setDstOffset(offset.x, offset.y); + Dimension dim = new Dimension(); + raster.getSize(dim); + rt.setSize(dim.width, dim.height); + rt.setImage((ImageComponent2D) getNodeComponent( + raster.getImage(), + forceDuplicate, + originalNodeComponent.nodeHashtable)); + rt.setDepthComponent((DepthComponent) getNodeComponent( + raster.getDepthComponent(), + forceDuplicate, + originalNodeComponent.nodeHashtable)); + } + + + /** + * This function is called from getNodeComponent() to see if any of + * the sub-NodeComponents duplicateOnCloneTree flag is true. + * If it is the case, current NodeComponent needs to + * duplicate also even though current duplicateOnCloneTree flag is false. + * This should be overwrite by NodeComponent which contains sub-NodeComponent. + */ + boolean duplicateChild() { + if (getDuplicateOnCloneTree()) + return true; + RasterRetained rt = (RasterRetained) retained; + + NodeComponent nc = rt.getImage(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getDepthComponent(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + return false; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RasterRetained.java b/j3d-core/src/classes/share/javax/media/j3d/RasterRetained.java new file mode 100644 index 0000000..33bd678 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RasterRetained.java @@ -0,0 +1,683 @@ +/* + * $RCSfile: RasterRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.awt.Point; +import java.awt.Dimension; +import java.util.ArrayList; + +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; + +/** + * A Retained Raster. + */ + +class RasterRetained extends GeometryRetained { + + /** + * Raster type + */ + int type = Raster.RASTER_COLOR; + + private int clipMode = Raster.CLIP_POSITION; + private Point3f position = new Point3f(); + private int xSrcOffset = 0; + private int ySrcOffset = 0; + private int width = 0; + private int height = 0; + private int xDstOffset = 0; + private int yDstOffset = 0; + ImageComponent2DRetained image = null; + Texture2DRetained texture = null; + DepthComponentRetained depthComponent = null; + + RasterRetained() { + this.geoType = GEO_TYPE_RASTER; + } + + /** + * Set the Raster position + * @param position new raster position + */ + final void setPosition(Point3f pos) { + geomLock.getLock(); + position.x = pos.x; + position.y = pos.y; + position.z = pos.z; + geomLock.unLock(); + sendChangedMessage(J3dThread.UPDATE_GEOMETRY, null, null); + } + + /** + * Retrieves the Raster's position + * @param position the variable to receive the position vector + */ + final void getPosition(Point3f pos) { + pos.x = position.x; + pos.y = position.y; + pos.z = position.z; + } + + /** + * Sets the type of this raster object to one of: RASTER_COLOR, + * RASTER_DEPTH, or RASTER_COLOR_DEPTH. + * @param type the new type of this raster + */ + final void setType(int type) { + geomLock.getLock(); + this.type = type; + geomLock.unLock(); + } + + + /** + * Retrieves the current type of this raster object, one of: RASTER_COLOR, + * RASTER_DEPTH, or RASTER_COLOR_DEPTH. + * @return type the type of this raster + */ + final int getType() { + return type; + } + + /** + * Sets the clipping mode of this raster object. + * @param clipMode the new clipping mode of this raster, + * one of: CLIP_POSITION or CLIP_IMAGE. The default mode + * is CLIP_POSITION. + */ + final void setClipMode(int clipMode) { + + geomLock.getLock(); + this.clipMode = clipMode; + geomLock.unLock(); + computeBoundingBox(); + if(source.isLive()) { + //update the Shape3Ds that refer to this Raster + int un = userLists.size(); + ArrayList shapeList; + Shape3DRetained ms, shape; + int sn; + for(int i = 0; i < un; i++) { + shapeList = (ArrayList)userLists.get(i); + sn = shapeList.size(); + for(int j = 0; j < sn; j++) { + ms = (Shape3DRetained)shapeList.get(j); + shape = (Shape3DRetained)ms.sourceNode; + shape.setBoundsAutoCompute(false); + shape.setBounds(geoBounds); + } + } + } + + } + + + /** + * Retrieves the current clipping mode of this raster object. + * @return clipMode the clipping mode of this raster, + * one of: CLIP_POSITION or CLIP_IMAGE. + */ + final int getClipMode() { + return clipMode; + } + + /** + * Sets the offset within the source array of pixels at which + * to start copying. + * @param xSrcOffset the x offset within the source array of pixels + * at which to start copying + * @param ySrcOffset the y offset within the source array of pixels + * at which to start copying + */ + final void setSrcOffset(int xSrcOffset, int ySrcOffset) { + geomLock.getLock(); + this.xSrcOffset = xSrcOffset; + this.ySrcOffset = ySrcOffset; + geomLock.unLock(); + } + + /** + * Retrieves the current source pixel offset. + * @param srcOffset the object that will receive the source offset + */ + final void getSrcOffset(Point srcOffset) { + srcOffset.setLocation(xSrcOffset, ySrcOffset); + } + + /** + * Sets the number of pixels to be copied from the pixel array. + * @param width the number of columns in the array of pixels to copy + * @param height the number of rows in the array of pixels to copy + */ + final void setSize(int width, int height) { + geomLock.getLock(); + this.width = width; + this.height = height; + geomLock.unLock(); + } + + /** + * Gets the size of the array of pixels to be copied. + * @param size the new size + */ + final void getSize(Dimension size) { + size.setSize(width, height); + } + + /** + * Sets the destination pixel offset of the upper-left + * corner of the rendered image relative to the transformed position. + * @param xDstOffset the x coordinate of the new offset + * @param yDstOffset the y coordinate of the new offset + */ + final void setDstOffset(int xDstOffset, int yDstOffset) { + geomLock.getLock(); + this.xDstOffset = xDstOffset; + this.yDstOffset = yDstOffset; + geomLock.unLock(); + } + + /** + * Retrieves the current destination pixel offset. + * @param dstOffset the object that will receive the destination offset + */ + final void getDstOffset(Point dstOffset) { + dstOffset.setLocation(xDstOffset, yDstOffset); + } + + + /** + * Initializes the raster image to the specified image. + * @param image new ImageCompoent2D object used as the raster image + */ + final void initImage(ImageComponent2D img) { + + int texFormat; + + if(img == null) { + image = null; + texture = null; + return; + } + + image = (ImageComponent2DRetained) img.retained; + image.setEnforceNonPowerOfTwoSupport(true); + switch(image.getNumberOfComponents()) { + case 1: + texFormat = Texture.INTENSITY; + break; + case 2: + texFormat = Texture.LUMINANCE_ALPHA; + break; + case 3: + texFormat = Texture.RGB; + break; + case 4: + texFormat = Texture.RGBA; + break; + default: + assert false; + return; + } + + Texture2D tex2D = new Texture2D(Texture.BASE_LEVEL, texFormat, + img.getWidth(), img.getHeight()); + texture = (Texture2DRetained) tex2D.retained; + texture.setUseAsRaster(true); + // Fix to issue 372 : ImageComponent.set(BufferedImage) ignored when used by Raster + image.addUser(texture); + texture.initImage(0,img); + + } + + /** + * Sets the pixel array used to copy pixels to/from a Canvas3D. + * This is used when the type is RASTER_COLOR or RASTER_COLOR_DEPTH. + * @param image the ImageComponent2D object containing the + * color data + */ + final void setImage(ImageComponent2D img) { + + if((img != null) && + (img.getImageClass() == ImageComponent.ImageClass.NIO_IMAGE_BUFFER)) { + throw new IllegalArgumentException(J3dI18N.getString("Background14")); + } + + TextureRetained oldTex = this.texture; + if (source.isLive()) { + if (this.texture != null) { + this.texture.clearLive(refCount); + } + } + + // Issue 370: only hold the geomLock while calling initImage + // (cannot hold it while sending a message). + geomLock.getLock(); + initImage(img); + geomLock.unLock(); + + if (source.isLive()) { + if (texture != null) { + texture.setLive(inBackgroundGroup, refCount); + } + + sendChangedMessage((J3dThread.UPDATE_RENDER|J3dThread.UPDATE_RENDERING_ATTRIBUTES), + oldTex, this.texture); + } + } + + /** + * Retrieves the current pixel array object. + * @return image the ImageComponent2D object containing the + * color data + */ + final ImageComponent2D getImage() { + return (image == null ? null : (ImageComponent2D)image.source); + } + + /** + * Sets the depth image used to copy pixels to/from a Canvas3D. + * This is used when the type is RASTER_DEPTH or RASTER_COLOR_DEPTH. + * @param depthImage the DepthComponent object containing the + * depth (z-buffer) data + */ + final void setDepthComponent(DepthComponent depthComponent) { + geomLock.getLock(); + if (this.source.isLive()) { + if (this.depthComponent != null) { + this.depthComponent.clearLive(refCount); + } + if (depthComponent != null) { + ((DepthComponentRetained)depthComponent.retained).setLive(inBackgroundGroup, refCount); + } + } + + if (depthComponent == null) { + this.depthComponent = null; + } else { + this.depthComponent = + (DepthComponentRetained)depthComponent.retained; + } + geomLock.unLock(); + } + + /** + * Retrieves the current depth image object. + * @return depthImage DepthComponent containing the + * depth (z-buffer) data + */ + final DepthComponent getDepthComponent() { + return (depthComponent == null ? null : + (DepthComponent)depthComponent.source); + } + + void setLive(boolean inBackgroundGroup, int refCount) { + super.doSetLive(inBackgroundGroup, refCount); + if (texture != null) { + texture.setLive(inBackgroundGroup, refCount); + } + if (depthComponent != null) { + depthComponent.setLive(inBackgroundGroup, refCount); + } + isEditable = source.getCapability(Raster.ALLOW_OFFSET_WRITE) || + source.getCapability(Raster.ALLOW_POSITION_WRITE) || + ((type & Raster.RASTER_COLOR) != 0 && + source.getCapability(Raster.ALLOW_IMAGE_WRITE)) || + ((type & Raster.RASTER_DEPTH) != 0 && + source.getCapability( + Raster.ALLOW_DEPTH_COMPONENT_WRITE)) || + source.getCapability( Raster.ALLOW_SIZE_WRITE); + + super.markAsLive(); + } + + void clearLive(int refCount) { + super.clearLive(refCount); + if (texture != null) + texture.clearLive(refCount); + if (depthComponent != null) + depthComponent.clearLive(refCount); + } + /* + // Simply pass along to the NodeComponents + void compile(CompileState compState) { + setCompiled(); + + if (image != null) + image.compile(compState); + + if (depthComponent != null) + depthComponent.compile(compState); + } + */ + + void computeBoundingBox() { + if(clipMode == Raster.CLIP_IMAGE) { + // Disable view frustum culling by setting the raster's bounds to + // infinity. + Point3d minBounds = new Point3d(Double.NEGATIVE_INFINITY, + Double.NEGATIVE_INFINITY, + Double.NEGATIVE_INFINITY); + Point3d maxBounds = new Point3d(Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY); + geoBounds.setUpper(maxBounds); + geoBounds.setLower(minBounds); + } else { + Point3d center = new Point3d(); + center.x = position.x; + center.y = position.y; + center.z = position.z; + geoBounds.setUpper(center); + geoBounds.setLower(center); + } + } + + void update() { + computeBoundingBox(); + } + + private void sendChangedMessage(int threads, Object arg1, Object arg2) { + + synchronized(liveStateLock) { + if (source.isLive()) { + synchronized (universeList) { + int numMessages = universeList.size(); + J3dMessage[] m = new J3dMessage[numMessages]; + for (int i=0; i 0) && (winCoord.y > 0)) { + return; + } + + // Check if the Raster point will be culled + // Note that w use 1 instead of 0, because when hardware + // tranform the coordinate back to winCoord it may get + // a small negative value due to numerically inaccurancy. + // This clip the Raster away and cause flickering + // (see bug 4732965) + if(winCoord.x < 1) { + // Negate the window position and use this as the offset + srcOffset.x = (int)-winCoord.x+1; + winCoord.x = 1; + } + + if(winCoord.y < 1) { + // Negate the window position and use this as the offset + srcOffset.y = (int)-winCoord.y+1; + winCoord.y = 1; + } + + //check if user-specified subimage is smaller than the clipped image + if (srcOffset.x < xSrcOffset) + srcOffset.x = xSrcOffset; + if(srcOffset.y < ySrcOffset) + srcOffset.y = ySrcOffset; + + } + + + private boolean isRasterClipPositionInside(Point3d clipCoord) { + return (clipCoord.x >= -1.0) && (clipCoord.x <= 1.0) && + (clipCoord.y >= -1.0) && (clipCoord.y <= 1.0); + } + + private void computeObjCoord(Canvas3D canvas, Point2d winCoord, Point3d objCoord, + Transform3D localToImagePlate) { + // Back transform this pt. from window to object coordinates + // Assumes this method is ALWAYS called after computeWinCoord has been + // called. computeWinCoord calculates the Vworld to Image Plate Xform. + // This method simply uses it without recomputing it. + + canvas.getPixelLocationInImagePlate(winCoord.x, winCoord.y, objCoord.z, + objCoord); + // Get image plate to object coord transform + // inv(P x M) + localToImagePlate.invert(); + localToImagePlate.transform(objCoord); + } + + private Point3d computeWinCoord(Canvas3D canvas, RenderAtom ra, + Point2d winCoord, Point3d objCoord, + Transform3D localToImagePlate) { + // Get local to Vworld transform + RenderMolecule rm = ra.renderMolecule; + + if (rm == null) { + // removeRenderAtom() may set ra.renderMolecule to null + // in RenderBin before this renderer thread run. + return null; + } + + // MT safe issue: We can't reference ra.renderMolecule below since + // RenderBin thread may set it to null anytime. Use rm instead. + + Transform3D lvw = rm.localToVworld[rm.localToVworldIndex[ + NodeRetained.LAST_LOCAL_TO_VWORLD]]; + + + Point3d clipCoord3 = new Point3d(); + clipCoord3.set(objCoord); + Point4d clipCoord4 = new Point4d(); + + // Transform point from local coord. to clipping coord. + lvw.transform(clipCoord3); + canvas.vworldToEc.transform(clipCoord3); + canvas.projTrans.transform(clipCoord3, clipCoord4); + + // clip check in Z + if((clipCoord4.w <= 0.0) || + (clipCoord4.z > clipCoord4.w) || (-clipCoord4.z > clipCoord4.w)) { + + return null; + } + double invW = 1.0 / clipCoord4.w; + + clipCoord3.x = clipCoord4.x * invW; + clipCoord3.y = clipCoord4.y * invW; + clipCoord3.z = clipCoord4.z * invW; + + // Get Vworld to image plate Xform + canvas.getLastVworldToImagePlate(localToImagePlate); + + // v' = vwip x lvw x v + // where v' = transformed vertex, + // lvw = local to Vworld Xform + // vwip = Vworld to Image plate Xform + // v = vertex + + // Compute composite local to image plate Xform + localToImagePlate.mul(lvw); + + // Transform the Raster's position from object to world coordinates + localToImagePlate.transform(objCoord); + + + // Get the window coordinates of this point + canvas.getPixelLocationFromImagePlate(objCoord, winCoord); + + return clipCoord3; + } + + int getClassType() { + return RASTER_TYPE; + } + + // notifies the Raster mirror object that the image data in a referenced + // ImageComponent object is changed. + // Currently we are not making use of this information. + + void notifyImageComponentImageChanged(ImageComponentRetained image, + ImageComponentUpdateInfo value) { + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + return false; + } + + boolean intersect(Bounds targetBound) { + return false; + } + + boolean intersect(Point3d[] pnts) { + return false; + } + boolean intersect(Transform3D thisToOtherVworld, GeometryRetained + geom) { + return false; + } + boolean intersect(Transform3D thisLocalToVworld, + Transform3D otherLocalToVworld, + GeometryRetained geom) { + return false; + } + + boolean intersect(Transform3D thisLocalToVworld, Bounds targetBound) { + return false; + } + void handleFrequencyChange(int bit) { + if (bit == Raster.ALLOW_IMAGE_WRITE) + setFrequencyChangeMask(bit, 0x1); + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderAtom.java b/j3d-core/src/classes/share/javax/media/j3d/RenderAtom.java new file mode 100644 index 0000000..5312ec5 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderAtom.java @@ -0,0 +1,385 @@ +/* + * $RCSfile: RenderAtom.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import javax.vecmath.*; + +/** + * A RenderAtom is a wrapper for a GeometryAtom in a given RenderBin. + */ + +class RenderAtom extends Object implements ObjectUpdate { + /** + * The geometry atom of this render atom + */ + GeometryAtom geometryAtom = null; + + /** + * The RenderMolecule for this RenderAtom + */ + RenderMolecule renderMolecule = null; + + + /** + * The lights that influence this RenderAtom + */ + LightRetained[] lights = null; + + /** + * The fog that influences this RenderAtom + */ + FogRetained fog = null; + + /** + * The model clip that influences this RenderAtom + */ + ModelClipRetained modelClip = null; + + /** + * The appearance that influences this RenderAtom + */ + AppearanceRetained app = null; + + // + // Convert all boolean to a bitmask, saves memory since + // there are many RenderAtoms per view + // + + /** + * Indicates whether or not this object is in + * the render bin. + */ + static int IN_RENDERBIN = 0x1; + + // True if the above localeVwcBounds is a local copy rather + // than a reference to the bounds in shape + static int HAS_SEPARATE_LOCALE_VWC_BOUNDS = 0x2; + + // true if one of the geometries not going to a display list, hence + // need to maintain a local localeVwcBounds in order to avoid + // conflict with the vwcBounds in shape which is CURRENT + // while the checking of localeVwcBounds in rendering time + // should be LAST. In order words, localeVwcBounds contain + // the last vwcBounds, whereas, shape.vwcBounds contain the + // current vwcBounds + // + static int NEED_SEPARATE_LOCALE_VWC_BOUNDS = 0x4; + + static int ON_UPDATELIST = 0x8; + static int ON_LOCALE_VWC_BOUNDS_UPDATELIST = 0x10; + // true if comes from Oriented Shape3D + static int IS_ORIENTED = 0x20; + // true if in dirty oriented render atom list + static int IN_DIRTY_ORIENTED_RAs = 0x40; + + // true if in dirty depth sort position list + static int IN_SORTED_POS_DIRTY_TRANSP_LIST = 0x80; + + // A bitmask for all the bit specified above in this renderAtom + int dirtyMask = 0; + + /** + * Environment set that this renderAtom belongs to, used + * to compare the new env set with the old one when the + * scoping/bounds of a light/fog changes + */ + EnvironmentSet envSet; + + /** + * Used for non-text3d + */ + BoundingBox localeVwcBounds = null; + + + /** + * The last time this atom was reported visible + */ + long lastVisibleTime = -1; + + /** + * Next and Previous references for the list of RenderAtoms + * groupType is a mask set to true if this renderAtom is part of the displaylist array + * of the renderMolecule + * One per geometry in the geometryArr in the geometryAtom, since + * each geometry in the geometryAtom can end up in a different + * atomList(primary, secondary, seperatedlist) of the renderMoceule + */ + RenderAtomListInfo[] rListInfo; + + /** + * Used in depthSorted transparency, once per rInfo + */ + TransparentRenderingInfo[] parentTInfo = null; + + /** + * Used when depth sorted transparecy is turned on + * one dlist per rinfo + */ + int[] dlistIds = null; + + // One per geometry in the geometryArr in the geometryAtom + static int TEXT3D = 0x1; + static int DLIST = 0x2; + static int CG = 0x4; + static int OTHER = 0x8; + static int SEPARATE_DLIST_PER_GEO = 0x10; + static int VARRAY = 0x20; + static int SEPARATE_DLIST_PER_RINFO = 0x40; + static int PRIMARY = TEXT3D | DLIST | CG | OTHER|SEPARATE_DLIST_PER_RINFO; + + // Rendermolecule to which its currently being added + RenderMolecule added = null; + + // Rendermolecule from which its currently being removed + RenderMolecule removed = null; + + // non-null, if part of the add list(for the next frame) in the renderMolecule + RenderAtom nextAdd = null; + RenderAtom prevAdd = null; + + // non-null, if part of the remove list(for the next frame) in the renderMolecule + RenderAtom nextRemove = null; + RenderAtom prevRemove = null; + + RenderAtom() { + } + + /** + * This sets the inRenderBin flag + */ + synchronized void setRenderBin(boolean value) { + if (value == false) { + app = null; + dirtyMask &= ~IN_RENDERBIN; + dirtyMask &= ~ON_LOCALE_VWC_BOUNDS_UPDATELIST; + dirtyMask &= ~ON_UPDATELIST; + } + else { + dirtyMask |= IN_RENDERBIN; + } + + } + + /** + * This returns whether or not this atom goes into the opaque + * light bin + */ + boolean isOpaque() { + AppearanceRetained app = geometryAtom.source.appearance; + + if (app == null) { + return true; + } + + TransparencyAttributesRetained ta = app.transparencyAttributes; + + if (!VirtualUniverse.mc.isD3D()) { + // D3D doesn't support line/point antialiasing + switch (geometryAtom.geoType) { + case GeometryRetained.GEO_TYPE_POINT_SET: + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: + if ((app.pointAttributes != null) && + app.pointAttributes.pointAntialiasing) { + return false; + } + break; + case GeometryRetained.GEO_TYPE_LINE_SET: + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET: + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + if ((app.lineAttributes != null) && + app.lineAttributes.lineAntialiasing) { + return false; + } + break; + case GeometryRetained.GEO_TYPE_RASTER: + case GeometryRetained.GEO_TYPE_COMPRESSED: + break; + default: + if (app.polygonAttributes != null) { + if ((app.polygonAttributes.polygonMode == + PolygonAttributes.POLYGON_POINT) && + (app.pointAttributes != null) && + app.pointAttributes.pointAntialiasing) { + return false; + } else if ((app.polygonAttributes.polygonMode == + PolygonAttributes.POLYGON_LINE) && + (app.lineAttributes != null) && + app.lineAttributes.lineAntialiasing) { + return false; + } + } + break; + } + + return ((ta == null) || + (ta.transparencyMode == + TransparencyAttributes.NONE) || + (ta.transparencyMode == + TransparencyAttributes.SCREEN_DOOR)); + } else { + return ((ta == null) || + (ta.transparencyMode == + TransparencyAttributes.NONE)); + } + } + + boolean inRenderBin() { + return ((dirtyMask & IN_RENDERBIN) != 0); + } + + boolean hasSeparateLocaleVwcBounds() { + return ((dirtyMask & HAS_SEPARATE_LOCALE_VWC_BOUNDS) != 0); + } + + boolean needSeparateLocaleVwcBounds() { + return ((dirtyMask & NEED_SEPARATE_LOCALE_VWC_BOUNDS) != 0); + } + + boolean onUpdateList() { + return ((dirtyMask & ON_UPDATELIST) != 0); + } + + boolean onLocaleVwcBoundsUpdateList() { + return ((dirtyMask & ON_LOCALE_VWC_BOUNDS_UPDATELIST) != 0); + } + + boolean isOriented() { + return ((dirtyMask & IS_ORIENTED) != 0); + } + + boolean inDepthSortList() { + return ((dirtyMask & IN_SORTED_POS_DIRTY_TRANSP_LIST) != 0); + } + + + boolean inDirtyOrientedRAs() { + return ((dirtyMask & IN_DIRTY_ORIENTED_RAs) != 0); + } + + public void updateObject() { + if (inRenderBin()) { + int lastLVWIndex = + renderMolecule.localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]; + + for (int i = 0; i < rListInfo.length; i++) { + if (rListInfo[i].geometry() == null) + continue; + + if (geometryAtom.source.inBackgroundGroup) { + if (rListInfo[i].infLocalToVworld == null) + rListInfo[i].infLocalToVworld = new Transform3D(); + + // to preserve the character transformation for Text3D atoms + renderMolecule.localToVworld[lastLVWIndex].getRotation( + rListInfo[i].infLocalToVworld); + rListInfo[i].infLocalToVworld.mul( + geometryAtom.lastLocalTransformArray[i]); + } else { + rListInfo[i].localToVworld.mul( + renderMolecule.localeLocalToVworld[lastLVWIndex], + geometryAtom.lastLocalTransformArray[i]); + } + } + } + dirtyMask &= ~ON_UPDATELIST; + } + + void updateOrientedTransform() { + int lastLVWIndex = + renderMolecule.localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]; + Transform3D orientedTransform = + ((OrientedShape3DRetained)geometryAtom.source). + getOrientedTransform(renderMolecule.renderBin.view.viewIndex); + for (int i = 0; i < rListInfo.length; i++) { + + if (geometryAtom.geoType == GeometryRetained.GEO_TYPE_TEXT3D && + geometryAtom.lastLocalTransformArray[i] != null) { + if (geometryAtom.source.inBackgroundGroup) { + if (rListInfo[i].infLocalToVworld == null) + rListInfo[i].infLocalToVworld = new Transform3D(); + + rListInfo[i].infLocalToVworld.mul( + renderMolecule.infLocalToVworld[lastLVWIndex], + orientedTransform); + rListInfo[i].infLocalToVworld.mul( + geometryAtom.lastLocalTransformArray[i]); + } else { + rListInfo[i].localToVworld.mul( + renderMolecule.localeLocalToVworld[lastLVWIndex], + orientedTransform); + rListInfo[i].localToVworld.mul( + geometryAtom.lastLocalTransformArray[i]); + } + } else { + if (geometryAtom.source.inBackgroundGroup) { + if (rListInfo[i].infLocalToVworld == null) + rListInfo[i].infLocalToVworld = new Transform3D(); + + rListInfo[i].infLocalToVworld.mul( + renderMolecule.infLocalToVworld[lastLVWIndex], + orientedTransform); + } else { + rListInfo[i].localToVworld.mul( + renderMolecule.localeLocalToVworld[lastLVWIndex], + orientedTransform); + } + } + } + } + + // updateLocaleVwcBounds is called from RenderBin.updateObject() + // to update the local copy of the localeVwcBounds + + void updateLocaleVwcBounds() { + + // it is possible that inRenderBin could be false because + // the renderAtom could have been removed from RenderBin + // in the same frame, and removeRenderAtoms does happen + // before updateLocaleVwcBounds + if (inRenderBin()) { + // Check if the locale of this is different from the + // locale on which the view is,then compute the translated + // localeVwcBounds + if (renderMolecule.renderBin.locale != geometryAtom.source.locale) { + + geometryAtom.source.locale. + hiRes.difference(renderMolecule.renderBin.locale.hiRes, + renderMolecule.renderBin.localeTranslation); + localeVwcBounds.translate(geometryAtom.source.vwcBounds, + renderMolecule.renderBin.localeTranslation); + } else { + localeVwcBounds.set(geometryAtom.source.vwcBounds); + } + dirtyMask &= ~ON_LOCALE_VWC_BOUNDS_UPDATELIST; + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderAtomListInfo.java b/j3d-core/src/classes/share/javax/media/j3d/RenderAtomListInfo.java new file mode 100644 index 0000000..dd1fb28 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderAtomListInfo.java @@ -0,0 +1,62 @@ +/* + * $RCSfile: RenderAtomListInfo.java,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; +/** + * Information per geometry in the renderAtom, there are several + * of these per RenderAtom, one per geometry in GeometryAtom + */ +class RenderAtomListInfo extends Object { + // RenderAtom that its a part of + + RenderAtom renderAtom = null; + + // Specific geometry index in the GeometryAtom geometryArr list that + // corresponds to this RenderAtomListInfo + int index; + + // Prev and next pointer + RenderAtomListInfo next = null; + RenderAtomListInfo prev = null; + + // Which bucket in the renderMolecule that it falls info + int groupType = 0; + + // Used only for Text3D + // background geometry rendering + Transform3D infLocalToVworld = null; + Transform3D localToVworld = null; + + + GeometryRetained geometry() { + return renderAtom.geometryAtom.geometryArray[index]; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderBin.java b/j3d-core/src/classes/share/javax/media/j3d/RenderBin.java new file mode 100644 index 0000000..31c820c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderBin.java @@ -0,0 +1,7134 @@ +/* + * $RCSfile: RenderBin.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.18 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.*; + +/** + * The RenderBin is a structure that optimizes rendering by doing efficient + * state sorting of objects to be rendered. + */ + +class RenderBin extends J3dStructure implements ObjectUpdate { + + /** + * The list of RenderAtoms + */ + ArrayList renderAtoms = new ArrayList(5); + + /** + * A couple ArrayLists used during light Processing + */ + ArrayList lightMessageList = new ArrayList(5); + + // Messges retrieved when a message is sent to RenderingEnv Structure + J3dMessage[] m; + + /** + * List of renderMolecules that are soleUser + * have to do a 2 pass, first update values + * then sort based on equivalent material + */ + ArrayList rmUpdateList = new ArrayList(); + ArrayList aBinUpdateList = new ArrayList(); + + /** + * List of ShaderBin that are soleUser that + * needs to have its components updated @updateObject time + */ + ArrayList sBinUpdateList = new ArrayList(); + + /** + * List of TextureBin that are soleUser that + * needs to have its components updated @updateObject time + */ + ArrayList tbUpdateList = new ArrayList(); + + /** + * List of Bins that are soleUser that have new renderAtom + * added into, which requires a pre-update screening to + * check if any of its node component changes could have been + * missed because the changes happen when all the render atoms + * are temporarily removed from the bin. + */ + ArrayList updateCheckList = new ArrayList(); + + /** + * The number of lights supported by the underlying context. + */ + int maxLights; + + /** + * The opaque objects + */ + LightBin opaqueBin = null; + + /** + * OpaqueBins to be added for the next frame + */ + LightBin addOpaqueBin = null; + + // This is a list of textureBins to be rendered, if the transpSortPolicy + // is NONE, otherwise, if the transpSortPolicy is geometry, then + // this is the list of renderAtoms to be rendered + ArrayList allTransparentObjects = new ArrayList(5); + + TransparentRenderingInfo transparentInfo; + + /** + * List of RenderAtoms whose postion have changed - only used for + * depth sorted transparency + */ + ArrayList positionDirtyList = new ArrayList(5); + + /** + * Used when ColoringAttributes is null + */ + Color3f white = new Color3f(1.0f, 1.0f, 1.0f); + + /** + * Used when Background is null + */ + Color3f black = new Color3f(0.0f, 0.0f, 0.0f); + + /** + * The backgound color data. + */ + BackgroundRetained background = new BackgroundRetained(); + + /** + * The view platform transforms. + */ + // used for rendering - lights and fog modelling + Transform3D vworldToVpc = new Transform3D(); + + // used for updating vpSchedSphere + Transform3D vpcToVworld = new Transform3D(); + + /** + * Two bounding spheres to track the scheduling region of + * the view platform. + */ + BoundingSphere vpSchedSphereInVworld = new BoundingSphere(); + + /** + * To cache the view frustum bounding box. + */ + BoundingBox viewFrustumBBox = new BoundingBox(); + BoundingBox canvasFrustumBBox = new BoundingBox(); + + /** + * To ensure that vpcToVworld is valid (not null) for the first pass + */ + boolean afterFirst = false; + + /** + * back clip distance in vworld + */ + double backClipDistanceInVworld; + + boolean backClipActive = false; + + /** + * These variables control when compaction occurs + */ + int frameCount = 0; + int frameCountCutoff = 150; + int notVisibleCount = 75; + long removeCutoffTime = -1; + + /** + * variables to process transform messages + */ + boolean transformMsg = false; + UpdateTargets targets = null; + ArrayList blUsers = null; + + /** + * The View for this render bin + */ + View view = null; + + private Comparator transparencySortComparator = null; + + private ArrayList toBeAddedTextureResourceFreeList = new ArrayList(5); + private ArrayList displayListResourceFreeList = new ArrayList(5); + + // a list of top level OrderedGroups + ArrayList orderedBins = new ArrayList(5); + + // List of changed elements in the environment that needs to + // be reloaded + ArrayList changedLts = new ArrayList(5); + ArrayList changedFogs = new ArrayList(5); + ArrayList changedModelClips = new ArrayList(5); + + // Flag to indicate whether the canvas should be marked + static int REEVALUATE_LIGHTS = 0x1; + static int REEVALUATE_FOG = 0x2; + static int REEVALUATE_MCLIP = 0x4; + static int REEVALUATE_ALL_ENV = REEVALUATE_LIGHTS | REEVALUATE_FOG | REEVALUATE_MCLIP; + int envDirty = 0; + + + private boolean reEvaluateBg = true; + private boolean reloadBgTexture = true; + + boolean reEvaluateClip = true; + + boolean reEvaluateSortMode = false; + + + // list of renderMolecule + // RenderBin will not reused in two different universe, so it is + // safe to pass null in last parameters in new IndexedUnorderSet() + IndexedUnorderSet renderMoleculeList = + new IndexedUnorderSet(RenderMolecule.class, + RenderMolecule.RENDER_MOLECULE_LIST, null); + + // List of renderAtoms that have a shared dlist (due to geo.refCount > 1) + // Fix for Issue 5: change this to a Set rather than a list to + // avoid duplicates entried + Collection sharedDList = new HashSet(); + + ArrayList dirtyRenderMoleculeList = new ArrayList(5); + + + /** + * ArrayList of objects to be updated + */ + ArrayList objUpdateList = new ArrayList(5); + + ArrayList raLocaleVwcBoundsUpdateList = new ArrayList(5); + + /** + * remove the bins first before adding them to new ones + */ + IndexedUnorderSet removeRenderAtomInRMList = + new IndexedUnorderSet(RenderMolecule.class, + RenderMolecule.REMOVE_RENDER_ATOM_IN_RM_LIST, null); + + + /** + * list of affect OrderedGroups with childIndexOrder changed. + */ + ArrayList ogCIOList = new ArrayList(5); + + /** + * list of ordered bins from which orderedCollection are added/removed + */ + ArrayList obList = new ArrayList(5); + + /** + * Ordered Bin processing + */ + ArrayList orderedBinsList = new ArrayList(5); + ArrayList toBeAddedBinList = new ArrayList(5); + + /** + * arraylist of geometry that should be locked to ensure + * that the same snapshot of the geometry is rendered + * across all canvases + */ + ArrayList lockGeometryList = new ArrayList(5); + + + /** + * arraylist of dlist that will be rebuilt + */ + ArrayList dlistLockList = new ArrayList(5); + + // Background node that contains geometry + BackgroundRetained geometryBackground = null; + + // background geometry processing + LightBin bgOpaqueBin = null; + LightBin bgAddOpaqueBin = null; + ArrayList bgOrderedBins = new ArrayList(5); + TransparentRenderingInfo bgTransparentInfo; + + + // vworldToVpc for background geometry + Transform3D infVworldToVpc = new Transform3D(); + + // true if vpcToVworld has been modified + boolean vpcToVworldDirty = true; + + // current active background + BackgroundRetained currentActiveBackground = new BackgroundRetained(); + + // Flag to indicate that alternate app is dirty + boolean altAppearanceDirty = true; + + + // List of node components that need special processing, due to + // extensions + ArrayList nodeComponentList = new ArrayList(5); + + + // List of node components ***for this frame*** that need special + // processing due to extension + ArrayList newNodeComponentList = new ArrayList(5); + ArrayList removeNodeComponentList = new ArrayList(5); + ArrayList dirtyNodeComponentList = new ArrayList(5); + + ArrayList textureBinList = new ArrayList(5); + + /** + * arraylist of refernce geometry that should be locked when transparency + * is on, so that we can make a mirror copy of the colors safely + */ + ArrayList dirtyReferenceGeomList = new ArrayList(5); + + // list of all Oriented RenderAtoms + ArrayList orientedRAs = new ArrayList(5); + + // list of Oriented RenderAtoms whose orientedTransforms require update + ArrayList dirtyOrientedRAs = new ArrayList(5); + + // Cached copy of dirty oriented RAs to be updated in MasterControl + ArrayList cachedDirtyOrientedRAs = null; + + // list of offScreen message that + ArrayList offScreenMessage = new ArrayList(5); + + // Vector used for locale translation + Vector3d localeTranslation = new Vector3d(); + + // Separate dlists that were added/removed in this snapshot + private HashSet addDlist = new HashSet(); + private HashSet removeDlist = new HashSet(); + + // Separate dlists per rinfo that were added/removed in this snapshot + ArrayList addDlistPerRinfo = new ArrayList(5); + ArrayList removeDlistPerRinfo = new ArrayList(5); + + Locale locale = null; + + // Set to true if locale changes as part of UPDATE_VIEW message + boolean localeChanged = false; + + + // Cached copy to be used by all RenderMolecules + DisplayListRenderMethod dlistRenderMethod = null; + + // Need to query BHTree again with visibility policy change + boolean reactivateView = false; + + /** + * A flag indicates that the cached visible GeometryAtoms for this RenderBin might + * be invalid. + */ + private boolean visGAIsDirty = false; + + /** + * A flag indicates that a visibility query to the GeometryStructure is needed. + */ + private boolean visQuery = false; + + // Temporary dirtylist + ArrayList dirtyList = new ArrayList(5); + + // Transaprency sort mode + int transpSortMode = View.TRANSPARENCY_SORT_NONE; + int cachedTranspSortMode = View.TRANSPARENCY_SORT_NONE; + + + // Temporary dirtylist + private LinkedHashSet dirtyDepthSortRenderAtom = new LinkedHashSet(); + private int numDirtyTinfo = 0; + + // Eye position in vworld + Point3d eyeInVworld = new Point3d(); + // Number of RenderAtomListInfo in the depthSortedList + int nElements = 0; + + + + /** + * Constructs a new RenderBin + */ + RenderBin(VirtualUniverse u, View v) { + super(u, J3dThread.UPDATE_RENDER); + vworldToVpc.setIdentity(); + universe = u; + view = v; + transpSortMode = v.transparencySortingPolicy; + cachedTranspSortMode = v.transparencySortingPolicy; + maxLights = VirtualUniverse.mc.maxLights; + ViewPlatform vp = view.getViewPlatform(); + if (vp != null) { + locale = ((ViewPlatformRetained) (vp.retained)).locale; + } + dlistRenderMethod = (DisplayListRenderMethod) + VirtualUniverse.mc.getDisplayListRenderMethod(); + } + + /** + * updateObject + */ + public void updateObject() { + int i, j, k; + RenderMolecule rm; + RenderAtomListInfo ra; + LightBin tmp; + float radius; + BackgroundRetained bg; + ObjectUpdate ob; + OrderedBin orderBin; + TextureRetained tex; + Integer texIdObj; + int size; + + // System.err.println("dirtyRenderMoleculeList.size = "+dirtyRenderMoleculeList.size()); + // System.err.println("reEvaluateBg = "+reEvaluateBg); + // System.err.println("reEvaluateClip = "+reEvaluateClip); + // System.err.println("<========+End All Cached Values===========>"); + // Add the new lightBins that have been created + // System.err.println("objUpdateList.size = "+objUpdateList.size()); + // System.err.println("addOpaqueBin = "+addOpaqueBin); + // System.err.println("opaqueBin = "+opaqueBin); + + // List of renderMolecule from which renderAtoms have been removed + size = removeRenderAtomInRMList.size(); + if (size > 0) { + RenderMolecule[] rmArr = (RenderMolecule[]) + removeRenderAtomInRMList.toArray(false); + for (i=0 ; i 0) { + for (i = 0 ; i < size; i++) { + orderBin = (OrderedBin)obList.get(i); + orderBin.addRemoveOrderedCollection(); + } + } + + size = ogCIOList.size(); + if(size > 0) { + J3dMessage m; + for(i=0; i 0 ) { + + for (i = 0; i < size; i++) { + ArrayList obs= (ArrayList) orderedBinsList.get(i); + ArrayList list = (ArrayList) toBeAddedBinList.get(i); + + int lSize = list.size(); + for (j = 0; j < lSize; j++) { + obs.add(list.get(j)); + } + } + } + + + size = raLocaleVwcBoundsUpdateList.size(); + if ( size > 0) { + RenderAtom renderAtom; + for (i = 0; i < size; i++) { + renderAtom = (RenderAtom)raLocaleVwcBoundsUpdateList.get(i); + renderAtom.updateLocaleVwcBounds(); + } + } + + if ((size = aBinUpdateList.size()) > 0) { + for (i = 0; i < size; i++) { + AttributeBin abin = (AttributeBin)aBinUpdateList.get(i); + abin.updateNodeComponent(); + } + } + + if ((size = sBinUpdateList.size()) > 0) { + for (i = 0; i < size; i++) { + ShaderBin sbin = (ShaderBin)sBinUpdateList.get(i); + sbin.updateNodeComponent(); + } + } + + // Update the sole user TextureBins. + if (tbUpdateList.size() > 0) { + TextureBin tb; + size = tbUpdateList.size(); + for (i = 0; i < size; i++) { + tb = (TextureBin) tbUpdateList.get(i); + tb.updateNodeComponent(); + } + + // do another pass to re-sort TextureBin based on the + // texture in the first texture unit state + for (i = 0; i < size; i++) { + tb = (TextureBin) tbUpdateList.get(i); + // Bug Id : 4701430 - Have to be sure tb.shaderBin is + // not equal to null. This is a temporary fix for j3d1.3. + if (((tb.tbFlag & TextureBin.RESORT) != 0) && + (tb.shaderBin != null)) { + + tb.shaderBin.reInsertTextureBin(tb); + tb.tbFlag &= ~TextureBin.RESORT; + } + } + } + + + // Update the soleUser node components first + // This way material equivalence during insertion + // of new RMs is based on the updated ones + if ((size = rmUpdateList.size()) > 0) { + for (i = 0; i < size; i++) { + rm = (RenderMolecule)rmUpdateList.get(i); + + boolean changeLists = rm.updateNodeComponent(); + // If an existing rm went from opaque to transparent or vice-versa + // and has not been removed, then switch the RM + if (changeLists && rm.textureBin != null) { + rm.textureBin.changeLists(rm); + } + } + for (i = 0; i < size; i++) { + rm = (RenderMolecule)rmUpdateList.get(i); + rm.reEvaluateEquivalence(); + } + } + + + + size = objUpdateList.size(); + if ( size > 0) { + for (i = 0; i < size; i++) { + ob = (ObjectUpdate)objUpdateList.get(i); + ob.updateObject(); + } + } + + size = dirtyReferenceGeomList.size(); + if ( size > 0) { + GeometryArrayRetained geo; + Canvas3D canvases[] = view.getCanvases(); + + for (i = 0; i < size; i++) { + geo = (GeometryArrayRetained) dirtyReferenceGeomList.get(i); + // Evaluate the nodeComponentList for all the canvases + geo.geomLock.getLock(); + j = 0; + // Do the setup only once{if necessary} for each geometry + boolean found = false; + while(j < canvases.length && !found) { + if ((canvases[j].extensionsSupported & Canvas3D.SUN_GLOBAL_ALPHA) == 0) { + if ((geo.vertexFormat & GeometryArray.INTERLEAVED) != 0) { + geo.setupMirrorInterleavedColorPointer(true); + found = true; + } + else { + geo.setupMirrorColorPointer((geo.vertexType & GeometryArrayRetained.COLOR_DEFINED),true); + found = true; + } + } + j++; + } + geo.geomLock.unLock(); + + } + + } + + if (reEvaluateBg) { + setBackground(currentActiveBackground); + } + + size = textureBinList.size(); +//System.err.println("textureBinList.size= " + size); + if (size > 0) { + Canvas3D canvasList[][] = view.getCanvasList(false); + Canvas3D cv; + boolean useSharedCtx = false; + TextureRetained texture; + + // do a quick check to see if there is any canvas using + // shared context + for (j = 0; j < canvasList.length && !useSharedCtx; j++) { + cv = canvasList[j][0]; + if (cv.useSharedCtx) { + useSharedCtx = true; + } + } + + for (int m = 0; m 0) { +//System.err.println("newNodeComponentlist.size= " + size); + Canvas3D canvases[] = view.getCanvases(); + for (i = 0; i < size; i++) { + // Evaluate the nodeComponentList for all the canvases + ImageComponentRetained nc = (ImageComponentRetained)newNodeComponentList.get(i); + if (nc.isByReference()) { + nc.geomLock.getLock(); + for (j = 0; j 0) { + for (i = 0; i < size; i++) { + nodeComponentList.remove(removeNodeComponentList.get(i)); + } + } + + + // reevaluate dirty node component + size = dirtyNodeComponentList.size(); + if (size > 0) { + Canvas3D canvases[] = view.getCanvases(); + for (i = 0; i < size; i++) { + // Evaluate the nodeComponentList for all the canvases + ImageComponentRetained nc = + (ImageComponentRetained)dirtyNodeComponentList.get(i); + if (nc.isByReference()) { + nc.geomLock.getLock(); + for (j = 0; j 1); + + // renderBin is ready now, so send the offScreen message + size = offScreenMessage.size(); + if ( size > 0) { + J3dMessage m; + for (i=size-1; i>=0; i--) { + m = (J3dMessage) offScreenMessage.get(i); + m.threads = J3dThread.RENDER_THREAD; + ((Canvas3D)m.args[0]).screen.renderer.rendererStructure.addMessage(m); + + // the above call will increment the reference count again + m.decRefcount(); + } + } + + // called from renderBin when there are dirtyOrientedRAs + // This routin cache the dirtyOrintedRAs to be updated + // by mastercontrol + if (dirtyOrientedRAs.size() > 0) { + // Keep a copy to be handled by mastercontrol + cachedDirtyOrientedRAs = (ArrayList)dirtyOrientedRAs.clone(); + } + boolean sortAll = false; + if (reEvaluateSortMode && transpSortMode != cachedTranspSortMode) { + convertTransparentRenderingStruct(transpSortMode, cachedTranspSortMode); + transpSortMode = cachedTranspSortMode; + if (transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY) { + if (transparentInfo != null){ + sortAll = true; + } + } + } + + if (vpcToVworldDirty) { + vworldToVpc.invert(vpcToVworld); + // Have the send down the lights, so set the canvas + // lightbin to null + Canvas3D canvases[] = view.getCanvases(); + for (i = 0; i < canvases.length; i++) { + canvases[i].lightBin = null; + } + if (canvases.length > 0) { + Transform3D xform; + canvases[0].getCenterEyeInImagePlate(eyeInVworld); + // xform is imagePlateToLocal + xform = canvases[0].canvasViewCache.getImagePlateToVworld(); + xform.transform(eyeInVworld); + } + if (transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY && transparentInfo != null) { + // System.err.println("sortAll 1"); + sortAll = true; + } + } + size = dirtyDepthSortRenderAtom.size(); + + + if (sortAll || size > 0) { + int tsize = allTransparentObjects.size(); + + double zVal; + for (i = 0; i < tsize; i++) { + RenderAtom renderAtom = (RenderAtom)allTransparentObjects.get(i); + for (k = 0; k < renderAtom.rListInfo.length; k++) { + if (renderAtom.rListInfo[k].geometry() == null) + continue; + zVal = renderAtom.geometryAtom.centroid[k].distanceSquared(eyeInVworld); + renderAtom.parentTInfo[k].zVal = zVal; + renderAtom.parentTInfo[k].geometryAtom = renderAtom.geometryAtom; + } + } + + // Check to see if a majority of the transparent Objects have changed + // If less than 66% of all transparentStructs are dirty + // then, remove and insert, otherwise resort everything + + + if (size > 0 && 1.5f * numDirtyTinfo > nElements) { + // System.err.println("sortAll 3, size = "+size); + sortAll = true; + } + + if (size > 0) { + TransparentRenderingInfo dirtyList = null, rList; + Iterator dirtyDepthSortIterator = dirtyDepthSortRenderAtom.iterator(); + while (dirtyDepthSortIterator.hasNext()) { + RenderAtom renderAtom = (RenderAtom)dirtyDepthSortIterator.next(); + if (!renderAtom.inRenderBin()) + continue; + renderAtom.dirtyMask &= ~RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST; + if (!sortAll) { + dirtyList = collectDirtyTRInfo(dirtyList, renderAtom); + } + } + + if (dirtyList != null) { + // System.err.println("====> sort Some"); + dirtyList = depthSortAll(dirtyList); + // Now merge the newly sorted list with the old one + transparentInfo = mergeDepthSort(transparentInfo, dirtyList); + } + } + // Sort all the transparent renderAtoms + if (sortAll) { + transparentInfo = depthSortAll(transparentInfo); + } + } + + // Remove entries that are found on both the add and remove lists + if (addDlist.size() > 0 && removeDlist.size() > 0) { + RenderAtomListInfo arr[] = new RenderAtomListInfo[addDlist.size()]; + arr = (RenderAtomListInfo []) addDlist.toArray(arr); + for (i = 0; i < arr.length; i++) { + if (removeDlist.contains(arr[i])) { + addDlist.remove(arr[i]); + removeDlist.remove(arr[i]); + } + } + } + + if (addDlist.size() > 0 || removeDlist.size() > 0) { + Canvas3D canvasList[][] = view.getCanvasList(false); + Canvas3D cv; + ArrayList rlist = new ArrayList(5); + + for (i = 0; i < canvasList.length; i++) { + cv = canvasList[i][0]; + if (cv.useSharedCtx) { + // Do this only once per renderer for this view + if (!rlist.contains(cv.screen.renderer)) { + rlist.add(cv.screen.renderer); + updateDlistRendererResource(cv.screen.renderer); + } + } else { + updateDlistCanvasResource(canvasList[i]); + } + } + + } + + + + if (dirtyRenderMoleculeList.size() > 0 || + addDlistPerRinfo.size() > 0 || + removeDlistPerRinfo.size() > 0 || + displayListResourceFreeList.size() > 0 || + toBeAddedTextureResourceFreeList.size() > 0 ) { + + Canvas3D canvasList[][] = view.getCanvasList(false); + Canvas3D cv; + + for (i = 0; i < canvasList.length; i++) { + cv = canvasList[i][0]; + if (cv.useSharedCtx && (cv.screen.renderer != null)) { + updateRendererResource(cv.screen.renderer); + } else { + updateCanvasResource(canvasList[i]); + } + } + + Integer id; + size = displayListResourceFreeList.size(); + for (i = 0; i < size; i++) { + id = (Integer)displayListResourceFreeList.get(i); + VirtualUniverse.mc.freeDisplayListId(id); + } + + // lock list of dlist + // XXXX: Instead of copying could we keep 2 arrays + // and just toggle? + size = dirtyRenderMoleculeList.size(); + for (i = 0; i < size; i++) { + rm = (RenderMolecule)dirtyRenderMoleculeList.get(i); + rm.onUpdateList = 0; + ra = rm.primaryRenderAtomList; + while (ra != null) { + dlistLockList.add(ra.geometry()); + ra = ra.next; + } + } + size = addDlistPerRinfo.size(); + for (i = 0; i < size; i++) { + ra = (RenderAtomListInfo)addDlistPerRinfo.get(i); + if (ra.geometry() != null) { + dlistLockList.add(ra.geometry()); + } + } + + } + + clearAllUpdateObjectState(); + /* + if (opaqueBin != null) { + System.err.println(this + "***** Begin Dumping OpaqueBin *****"); + dumpBin(opaqueBin); + System.err.println("***** End Dumping OpaqueBin *****"); + } + */ + + } + + + // Shared context case + void updateDlistRendererResource(Renderer rdr) { + int i; + int size = 0; + RenderAtomListInfo arr[]; + RenderAtomListInfo ra; + + // XXXX: there is a possible problem in the case of multiple + // renderers (i.e., multiple screens). Unless the + // MasterControl sends us a separate message for each + // renderer, we won't create a new display list for renderers + // other than the one passed into this method. + + if (rdr == null) { + return; + } + + if ((size = addDlist.size()) > 0) { + arr = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) addDlist.toArray(arr); + for (i = 0; i < size; i++) { + ra = arr[i]; + GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry(); + + // First time thru this renderer or the context that + // it is built for no longer matches the context + // used in the renderer, create a dlist + sharedDList.add(ra); + geo.addDlistUser(this, ra); + + if (((geo.resourceCreationMask & rdr.rendererBit) == 0) || + (geo.getDlistTimeStamp(rdr.rendererBit) != + rdr.sharedCtxTimeStamp)) { + geo.resourceCreationMask |= rdr.rendererBit; + dirtyList.add(ra); + } + } + } + + if ((size = removeDlist.size()) > 0) { + arr = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) removeDlist.toArray(arr); + for (i = 0; i < size; i++) { + ra = arr[i]; + sharedDList.remove(ra); + + GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry(); + geo.removeDlistUser(this, ra); + // System.err.println("========> geo.refcount = "+geo.refCount); + // add this geometry's dlist to be freed + if (geo.isDlistUserSetEmpty(this)) { + rdr.displayListResourceFreeList.add(geo.dlistObj); + geo.resourceCreationMask &= ~rdr.rendererBit; + // All Dlist on all renderer have been freed, then return dlistID + if (geo.resourceCreationMask == 0) { + geo.freeDlistId(); + } + } + } + } + if ((size = dirtyList.size()) > 0) { + for (i = 0; i < size; i++) { + ra = (RenderAtomListInfo)dirtyList.get(i); + GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry(); + if ( (geo.resourceCreationMask & rdr.rendererBit) != 0) { + rdr.dirtyRenderAtomList.add(ra); + } + } + rdr.dirtyDisplayList = true; + dirtyList.clear(); + } + } + + // Non-shared context case + void updateDlistCanvasResource(Canvas3D[] canvases) { + int i, j; + Canvas3D cv; + int size = 0; + RenderAtomListInfo arr[]; + RenderAtomListInfo ra; + + // Add the newly added dlist to the sharedList + if ((size = addDlist.size()) > 0) { + arr = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) addDlist.toArray(arr); + for (i = 0; i 0) { + arr = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) removeDlist.toArray(arr); + for (i = 0; i < size; i++) { + sharedDList.remove(arr[i]); + // Fix for Issue 5: remove this render atom from the list of users + // of its geometry for this RenderBin + GeometryArrayRetained geo = (GeometryArrayRetained) arr[i].geometry(); + geo.removeDlistUser(this, arr[i]); + } + } + + // add to the dirty list per canvas + for (j = 0; j < canvases.length; j++) { + cv = canvases[j]; + + if ((size = addDlist.size()) > 0) { + arr = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) addDlist.toArray(arr); + for (i = 0; i 0) { + arr = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) removeDlist.toArray(arr); + for (i = 0; i < size; i++) { + GeometryArrayRetained geo = + (GeometryArrayRetained) arr[i].geometry(); + + // add this geometry's dlist to be freed + if (geo.isDlistUserSetEmpty(this)) { + if (cv.ctx != null) { + canvases[j].displayListResourceFreeList.add(geo.dlistObj); + } + geo.resourceCreationMask &= ~canvases[j].canvasBit; + // All Dlist on all canvases have been freed, then return dlistID + if (geo.resourceCreationMask == 0) + geo.freeDlistId(); + } + } + } + if ((size = dirtyList.size()) > 0) { + for (i = 0; i 0) { + for (int j = 0; j < size; j++) { + RenderAtomListInfo rinfo = (RenderAtomListInfo)addDlistPerRinfo.get(j); + if (rinfo.renderAtom.inRenderBin()) { + Object[] obj = new Object[2]; + obj[0] = rinfo; + obj[1] = rinfo.renderAtom.renderMolecule; + rdr.dirtyDlistPerRinfoList.add(obj); + } + } + rdr.dirtyDisplayList = true; + } + + + // Take care of display lists that should be rebuilt + size = dirtyRenderMoleculeList.size(); + if (size > 0) { + for (int j = 0; j < size; j++) { + rm =(RenderMolecule)dirtyRenderMoleculeList.get(j); + rdr.dirtyRenderMoleculeList.add(rm); + } + rdr.dirtyDisplayList = true; + } + + // Take care of texture that should be freed + size = toBeAddedTextureResourceFreeList.size(); + int id; + for (int j=0; j < size; j++) { + tex = (TextureRetained)toBeAddedTextureResourceFreeList.get(j); + id = tex.objectId; + if ((id >= rdr.textureIDResourceTable.size()) || + (id <= 0) || + (rdr.textureIDResourceTable.get(id) != tex)) { + // tex.objectId may change by another Renderer thread, + // need find original texID from searching + // rdr.textureIdResourceTable + id = rdr.textureIDResourceTable.indexOf(tex); + + if (id <= 0) { + continue; + } + } + + // Since multiple renderBins (in the same screen) + // can share a texture object, make sure that + // we are not duplicating what has been added + // by a different renderBin in the same screen + if ((tex.resourceCreationMask & rdr.rendererBit) != 0) { + texIdObj = new Integer(id); + if (!rdr.textureIdResourceFreeList.contains(texIdObj)) { + rdr.textureIdResourceFreeList.add(texIdObj); + tex.resourceCreationMask &= ~rdr.rendererBit; + } + } + } + + // Take care of display list that should be freed + size = displayListResourceFreeList.size(); + Integer displayListIDObj; + + for (int j=0; j 0) { + for ( j = 0; j < size; j++) { + RenderAtomListInfo rinfo = (RenderAtomListInfo)addDlistPerRinfo.get(j); + if (rinfo.renderAtom.inRenderBin()) { + Object[] obj = new Object[2]; + obj[0] = rinfo; + obj[1] = rinfo.renderAtom.renderMolecule; + cv.dirtyDlistPerRinfoList.add(obj); + } + } + cv.dirtyDisplayList = true; + } + // Take care of display lists that should be rebuilt + size = dirtyRenderMoleculeList.size(); + if (size > 0) { + for (j = 0; j < size; j++) { + rm = (RenderMolecule)dirtyRenderMoleculeList.get(j); + cv.dirtyRenderMoleculeList.add(rm); + } + cv.dirtyDisplayList = true; + } + // Take care of texture that should be freed + size = toBeAddedTextureResourceFreeList.size(); + int id; + for (j=0; j < size; j++) { + tex = (TextureRetained)toBeAddedTextureResourceFreeList.get(j); + id = tex.objectId; + if ((id >= cv.textureIDResourceTable.size()) || + (id <= 0) || + (cv.textureIDResourceTable.get(id) != tex)) { + // tex.objectId may change by another Renderer thread, + // need find original texID from searching + // rdr.textureIdResourceTable + id = cv.textureIDResourceTable.indexOf(tex); + + if (id <= 0) { + continue; + } + } + + if ((tex.resourceCreationMask & cv.canvasBit) != 0) { + texIdObj = new Integer(id); + cv.textureIdResourceFreeList.add(texIdObj); + tex.resourceCreationMask &= ~cv.canvasBit; + } + } + // Take care of display list that should be freed + size = displayListResourceFreeList.size(); + for (j=0; j < size; j++) { + cv.displayListResourceFreeList.add(displayListResourceFreeList.get(j)); + } + // Take care of display list that should be freed + size = removeDlistPerRinfo.size(); + for (j=0; j < size; j++) { + RenderAtomListInfo ra = (RenderAtomListInfo)removeDlistPerRinfo.get(j); + cv.displayListResourceFreeList.add(new Integer(ra.renderAtom.dlistIds[ra.index])); + ra.groupType = 0; + ra.renderAtom.dlistIds[ra.index] = -1; + + } + } + + } + + void processMessages(long referenceTime) { + int i,j, index; + Object[] nodes; + J3dMessage messages[], m; + int component; + + messages = getMessages(referenceTime); + int nMsg = getNumMessage(); + + if (nMsg > 0) { + for (i=0; i < nMsg; i++) { + m = messages[i]; + switch (m.type) { + case J3dMessage.INSERT_NODES: + insertNodes(m); + m.decRefcount(); + break; + case J3dMessage.REMOVE_NODES: + removeNodes(m); + m.decRefcount(); + break; + case J3dMessage.TRANSFORM_CHANGED: + transformMsg = true; + m.decRefcount(); + break; + case J3dMessage.LIGHT_CHANGED: + // if none of the mirror lights are scoped to this view + // ignore this message + LightRetained[] mLts =(LightRetained[])m.args[3] ; + for (int k = 0; k < mLts.length; k++) { + if (universe.renderingEnvironmentStructure.isLightScopedToThisView(mLts[k], view)) { + lightMessageList.add(m); + break; + } + + } + break; + case J3dMessage.SWITCH_CHANGED: + visGAIsDirty = true; + visQuery = true; + processSwitchChanged(m, referenceTime); + // may need to process dirty switched-on transform + if (universe.transformStructure.getLazyUpdate()) { + transformMsg = true; + } + m.decRefcount(); + break; + case J3dMessage.BACKGROUND_CHANGED: + BackgroundRetained bg = (BackgroundRetained)m.args[0]; + if (universe.renderingEnvironmentStructure.isBgScopedToThisView(bg, view)) { + reEvaluateBg = true; + reloadBgTexture = true; + } + m.decRefcount(); + break; + case J3dMessage.CLIP_CHANGED: + ClipRetained c = (ClipRetained)m.args[0]; + if (universe.renderingEnvironmentStructure.isClipScopedToThisView(c, view)) + reEvaluateClip = true; + m.decRefcount(); + break; + case J3dMessage.TRANSPARENCYATTRIBUTES_CHANGED: + { + NodeComponentRetained nc = (NodeComponentRetained) m.args[0]; + GeometryAtom[] gaArr = (GeometryAtom[])m.args[3]; + RenderAtom ra = null; + int start = -1; + + // Get the first ra that is visible + for (int k = 0; (k < gaArr.length && (start < 0)); k++) { + ra = gaArr[k].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) { + continue; + } + else { + start = k; + } + } + + if (start >= 0) { + boolean restructure = (nc.mirror.changedFrequent == 0 || + ra.renderMolecule.definingTransparency != nc.mirror); + processRenderMoleculeNodeComponentChanged(m.args, + RenderMolecule.TRANSPARENCY_DIRTY, + start, restructure); + } + m.decRefcount(); + break; + } + case J3dMessage.POLYGONATTRIBUTES_CHANGED: + { + NodeComponentRetained nc = (NodeComponentRetained) m.args[0]; + GeometryAtom[] gaArr = (GeometryAtom[])m.args[3]; + RenderAtom ra = null; + int start = -1; + + // Get the first ra that is visible + // Get the first ra that is visible + for (int k = 0; (k < gaArr.length && (start < 0)); k++) { + ra = gaArr[k].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) { + continue; + } + else { + start = k; + } + } + + if (start >= 0) { + boolean restructure = (nc.mirror.changedFrequent == 0 || + ra.renderMolecule.definingPolygonAttributes != nc.mirror); + processRenderMoleculeNodeComponentChanged(m.args, + RenderMolecule.POLYGONATTRS_DIRTY, + start, restructure); + } + m.decRefcount(); + break; + } + case J3dMessage.LINEATTRIBUTES_CHANGED: + { + NodeComponentRetained nc = (NodeComponentRetained) m.args[0]; + GeometryAtom[] gaArr = (GeometryAtom[])m.args[3]; + RenderAtom ra = null; + int start = -1; + + // Get the first ra that is visible + // Get the first ra that is visible + for (int k = 0; (k < gaArr.length && (start < 0)); k++) { + ra = gaArr[k].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) { + continue; + } + else { + start = k; + } + } + + if (start >= 0) { + boolean restructure = (nc.mirror.changedFrequent == 0 || + ra.renderMolecule.definingLineAttributes != nc.mirror); + processRenderMoleculeNodeComponentChanged(m.args, + RenderMolecule.LINEATTRS_DIRTY, + start, restructure); + } + m.decRefcount(); + break; + } + case J3dMessage.POINTATTRIBUTES_CHANGED: + { + NodeComponentRetained nc = (NodeComponentRetained) m.args[0]; + GeometryAtom[] gaArr = (GeometryAtom[])m.args[3]; + RenderAtom ra = null; + int start = -1; + // Get the first ra that is visible + // Get the first ra that is visible + for (int k = 0; (k < gaArr.length && (start < 0)); k++) { + ra = gaArr[k].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) { + continue; + } + else { + start = k; + } + } + + if (start >= 0) { + boolean restructure = (nc.mirror.changedFrequent == 0 || + ra.renderMolecule.definingPointAttributes != nc.mirror); + + processRenderMoleculeNodeComponentChanged(m.args, + RenderMolecule.POINTATTRS_DIRTY, + start, restructure); + } + m.decRefcount(); + break; + } + case J3dMessage.MATERIAL_CHANGED: + { + NodeComponentRetained nc = (NodeComponentRetained) m.args[0]; + GeometryAtom[] gaArr = (GeometryAtom[])m.args[3]; + RenderAtom ra = null; + int start = -1; + + // Get the first ra that is visible + // Get the first ra that is visible + for (int k = 0; (k < gaArr.length && (start < 0)); k++) { + ra = gaArr[k].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) { + continue; + } + else { + start = k; + } + } + + if (start >= 0) { + boolean restructure = (nc.mirror.changedFrequent == 0 || + ra.renderMolecule.definingMaterial != nc.mirror); + processRenderMoleculeNodeComponentChanged(m.args, + RenderMolecule.MATERIAL_DIRTY, + start, restructure); + } + m.decRefcount(); + break; + } + case J3dMessage.COLORINGATTRIBUTES_CHANGED: + { + NodeComponentRetained nc = (NodeComponentRetained) m.args[0]; + GeometryAtom[] gaArr = (GeometryAtom[])m.args[3]; + RenderAtom ra = null; + int start = -1; + + // Get the first ra that is visible + // Get the first ra that is visible + for (int k = 0; (k < gaArr.length && (start < 0)); k++) { + ra = gaArr[k].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) { + continue; + } + else { + start = k; + } + } + + if (start >= 0) { + boolean restructure = (nc.mirror.changedFrequent == 0 || + ra.renderMolecule.definingColoringAttributes != nc.mirror); + processRenderMoleculeNodeComponentChanged(m.args, + RenderMolecule.COLORINGATTRS_DIRTY, + start, restructure); + } + m.decRefcount(); + break; + } + case J3dMessage.TEXTUREATTRIBUTES_CHANGED: + processTextureAttributesChanged( + (NodeComponentRetained) m.args[0], + (GeometryAtom[])m.args[3]); + m.decRefcount(); + break; + case J3dMessage.IMAGE_COMPONENT_CHANGED: + addDirtyNodeComponent((NodeComponentRetained)m.args[0]); + m.decRefcount(); + break; + case J3dMessage.TEXTURE_UNIT_STATE_CHANGED: + processTextureUnitStateChanged( + (NodeComponentRetained) m.args[0], + (GeometryAtom[])m.args[3]); + m.decRefcount(); + break; + case J3dMessage.TEXCOORDGENERATION_CHANGED: + processTexCoordGenerationChanged( (NodeComponentRetained) m.args[0], + (GeometryAtom[])m.args[3]); + m.decRefcount(); + break; + case J3dMessage.TEXTURE_CHANGED: + // Texture is always in a sole user position + processTextureChanged((NodeComponentRetained) m.args[0], + (GeometryAtom[])m.args[3], + m.args); + m.decRefcount(); + break; + case J3dMessage.SHADER_APPEARANCE_CHANGED: + case J3dMessage.SHADER_ATTRIBUTE_SET_CHANGED: + case J3dMessage.SHADER_ATTRIBUTE_CHANGED: + processShaderComponentChanged(m.args); + m.decRefcount(); + break; + case J3dMessage.RENDERINGATTRIBUTES_CHANGED: + processAttributeBinNodeComponentChanged(m.args); + component = ((Integer)m.args[1]).intValue(); + if (component == RenderingAttributesRetained.VISIBLE) { + visGAIsDirty = true; + visQuery = true; + } + m.decRefcount(); + break; + case J3dMessage.APPEARANCE_CHANGED: + processAppearanceChanged(m.args); + m.decRefcount(); + break; + case J3dMessage.FOG_CHANGED: + FogRetained mfog = ((FogRetained)m.args[0]).mirrorFog; + if (universe.renderingEnvironmentStructure.isFogScopedToThisView(mfog, view)) { + processFogChanged(m.args); + } + m.decRefcount(); + break; + case J3dMessage.ALTERNATEAPPEARANCE_CHANGED: + AlternateAppearanceRetained maltapp = ((AlternateAppearanceRetained)m.args[0]).mirrorAltApp; + if (universe.renderingEnvironmentStructure.isAltAppScopedToThisView(maltapp, view)) { + altAppearanceDirty = true; + } + m.decRefcount(); + break; + case J3dMessage.MODELCLIP_CHANGED: + ModelClipRetained mc= ((ModelClipRetained)m.args[0]).mirrorModelClip; + if (universe.renderingEnvironmentStructure.isMclipScopedToThisView(mc, view)) { + processModelClipChanged(m.args); + } + m.decRefcount(); + break; + case J3dMessage.BOUNDINGLEAF_CHANGED: + processBoundingLeafChanged(m.args, + referenceTime); + m.decRefcount(); + break; + case J3dMessage.SHAPE3D_CHANGED: + processShapeChanged(m.args, referenceTime); + m.decRefcount(); + break; + case J3dMessage.ORIENTEDSHAPE3D_CHANGED: + processOrientedShape3DChanged((Object[])m.args[0]); + m.decRefcount(); + break; + case J3dMessage.MORPH_CHANGED: + processMorphChanged(m.args, referenceTime); + component = ((Integer)m.args[1]).intValue(); + if ((component & MorphRetained.GEOMETRY_CHANGED) == 0) { + visGAIsDirty = true; + visQuery = true; + } + m.decRefcount(); + break; + case J3dMessage.UPDATE_VIEW: + { + View v = (View)m.args[0]; + ViewPlatform vp = v.getViewPlatform(); + int comp = ((Integer)(m.args[2])).intValue(); + int value = ((Integer)(m.args[3])).intValue(); + if (comp == View.TRANSP_SORT_POLICY_CHANGED) { + if (value != transpSortMode) { + reEvaluateSortMode = true; + cachedTranspSortMode = value; + } + } else if (vp != null) { + if (value != transpSortMode) { + reEvaluateSortMode = true; + cachedTranspSortMode = value; + } + updateViewPlatform((ViewPlatformRetained)vp.retained, + ((Float)m.args[1]).floatValue()); + visQuery = true; + // XXXX : Handle view.visibilityPolicy changed. + if(((View.VISIBILITY_POLICY_DIRTY != 0) && + (View.VISIBILITY_DRAW_ALL != view.viewCache.visibilityPolicy)) || + locale != ((ViewPlatformRetained) (vp.retained)).locale) { + + for (int n = (renderAtoms.size() - 1); n>=0 ; n--) { + removeARenderAtom((RenderAtom) renderAtoms.get(n)); + } + renderAtoms.clear(); + visGAIsDirty = true; + if (locale != ((ViewPlatformRetained) (vp.retained)).locale) { + locale = ((ViewPlatformRetained) (vp.retained)).locale; + localeChanged = true; + } + } + } + m.decRefcount(); + } + break; + case J3dMessage.UPDATE_VIEWPLATFORM: + updateViewPlatform((ViewPlatformRetained) m.args[0], + ((Float)m.args[1]).floatValue()); + m.decRefcount(); + break; + case J3dMessage.TEXT3D_DATA_CHANGED: + processDataChanged((Object[])m.args[0], + (Object[])m.args[1], + referenceTime); + m.decRefcount(); + break; + case J3dMessage.GEOMETRY_CHANGED: + processGeometryChanged(m.args); + visGAIsDirty = true; + visQuery = true; + m.decRefcount(); + break; + + case J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED: + case J3dMessage.REGION_BOUND_CHANGED: + processGeometryAtomsChanged((Object[])m.args[0]); + visGAIsDirty = true; + visQuery = true; + m.decRefcount(); + break; + case J3dMessage.TEXT3D_TRANSFORM_CHANGED: + processText3DTransformChanged((Object[])m.args[0], + (Object[])m.args[1], + referenceTime); + visQuery = true; + m.decRefcount(); + break; + case J3dMessage.ORDERED_GROUP_INSERTED: + processOrderedGroupInserted(m); + // Do not do decRefcount() here. We'll do it in updateObject(). + ogCIOList.add(m); + break; + case J3dMessage.ORDERED_GROUP_REMOVED: + processOrderedGroupRemoved(m); + // Do not do decRefcount() here. We'll do it in updateObject(). + ogCIOList.add(m); + break; + case J3dMessage.ORDERED_GROUP_TABLE_CHANGED: + // Do not do decRefcount() here. We'll do it in updateObject(). + ogCIOList.add(m); + break; + case J3dMessage.RENDER_OFFSCREEN: + offScreenMessage.add(m); + break; + case J3dMessage.VIEWSPECIFICGROUP_CHANGED: + processViewSpecificGroupChanged(m); + visQuery = true; + m.decRefcount(); + break; + default: + m.decRefcount(); + } + } + + if (transformMsg) { + processTransformChanged(referenceTime); + transformMsg = false; + } + if (lightMessageList.size() > 0) { + processLightChanged(); + lightMessageList.clear(); + } + VirtualUniverse.mc.addMirrorObject(this); + + // clear the array to prevent memory leaks + Arrays.fill(messages, 0, nMsg, null); + } + + if (reEvaluateBg) { + currentActiveBackground = universe.renderingEnvironmentStructure. + getApplicationBackground(vpSchedSphereInVworld, locale, view); + } + + + if (visQuery) { + GeometryAtom[] bgGeometryAtoms; + boolean allEnComp; + + // computeViewFrustumBox in VisibilityStructure. + computeViewFrustumBBox(viewFrustumBBox); + // System.err.println("viewFrustumBBox = " + this); + + ViewPlatform vp = view.getViewPlatform(); + if (vp != null) { + allEnComp = universe.geometryStructure. + getVisibleBHTrees(this, viewFrustumBBox, + locale, referenceTime, + visGAIsDirty || reactivateView || localeChanged || + ((view.viewCache.vcDirtyMask & + View.VISIBILITY_POLICY_DIRTY) != 0), + view.viewCache.visibilityPolicy); + + reactivateView = false; + // process background geometry atoms + if (currentActiveBackground != null && + currentActiveBackground.geometryBranch != null) { + bgGeometryAtoms = + currentActiveBackground.getBackgroundGeometryAtoms(); + if (bgGeometryAtoms != null) { + processBgGeometryAtoms(bgGeometryAtoms, referenceTime); + } + } + + if(!allEnComp) { + // Increment the framecount for compaction ... + frameCount++; + if (frameCount > frameCountCutoff) { + frameCount = 0; + checkForCompaction(); + } + else if (frameCount == notVisibleCount) { + removeCutoffTime = referenceTime; + } + } + } + // Reset dirty bits. + visGAIsDirty = false; + visQuery = false; + + } + // Two environments are dirty + // If lights, fog or model clip have been added/removed, then + // reEvaluate RenderAtoms and mark the lightbin and + // env set dirty if applicable + if (envDirty == REEVALUATE_ALL_ENV || envDirty == 3 || + envDirty > 4) { + reEvaluateEnv(changedLts, changedFogs, changedModelClips, true, + altAppearanceDirty); + } + else if (envDirty == 0 && altAppearanceDirty) { + reEvaluateAlternateAppearance(); + } + else { + if ((envDirty & REEVALUATE_LIGHTS) != 0) { + reEvaluateLights(altAppearanceDirty); + } + else if ((envDirty & REEVALUATE_FOG) != 0) + reEvaluateFog(changedFogs, (changedFogs.size() > 0), altAppearanceDirty); + else if ((envDirty & REEVALUATE_MCLIP) != 0) + reEvaluateModelClip(changedModelClips, (changedModelClips.size() > 0), altAppearanceDirty); + } + + + + // do any pre-update node component screening + + if (updateCheckList.size() > 0) { + int size = updateCheckList.size(); + NodeComponentUpdate bin; + for (int k = 0; k < size; k++) { + bin = (NodeComponentUpdate) updateCheckList.get(k); + bin.updateNodeComponentCheck(); + } + updateCheckList.clear(); + } + + + changedLts.clear(); + changedFogs.clear(); + changedModelClips.clear(); + envDirty = 0; + altAppearanceDirty = false; + + view.renderBinReady = true; + + VirtualUniverse.mc.sendRunMessage(view, + J3dThread.RENDER_THREAD); + } + + + void processSwitchChanged(J3dMessage m, long refTime) { + int i; + UnorderList arrList; + int size; + Object[] nodes, nodesArr; + LeafRetained leaf; + + RenderingEnvironmentStructure rdrEnvStr = + universe.renderingEnvironmentStructure; + + UpdateTargets targets = (UpdateTargets)m.args[0]; + arrList = targets.targetList[Targets.ENV_TARGETS]; + + if (arrList != null) { + size = arrList.size(); + nodesArr = arrList.toArray(false); + + for (int h=0; h= 0) { + + // Issue 471 - Don't check ATTRIBUTE_VALUE_UPDATE, there is no need + // to do anything to the shader bins when a value changes. + boolean spUpdate = + ((component & ShaderAppearanceRetained.SHADER_PROGRAM) != 0); + boolean sasUpdate = + (((component & ShaderAppearanceRetained.SHADER_ATTRIBUTE_SET) != 0) || + ((component & ShaderConstants.ATTRIBUTE_SET_PUT) != 0) || + ((component & ShaderConstants.ATTRIBUTE_SET_REMOVE) != 0) || + ((component & ShaderConstants.ATTRIBUTE_SET_CLEAR) != 0)); + + if (spUpdate) { + /* TODO : JADA - Sole user logic is incomplete. Will disable for JavaOne */ + //if (false && (sApp.mirror.changedFrequent & component) != 0) { + if(false) { + /* + System.err.println("RenderBin : Shader sole user (SHADER_PROGRAM)" + + ra.renderMolecule.textureBin.shaderBin); + */ + + ShaderBin sBin; + + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + sBin = ra.renderMolecule.textureBin.shaderBin; + + if (sBin.componentDirty == 0) { + sBinUpdateList.add(sBin); + sBin.componentDirty |= ShaderBin.SHADER_PROGRAM_DIRTY; + } + } + } else { + /* + System.err.println("RenderBin : not soleUser (SHADER_PROGRAM)" + + ra.renderMolecule.textureBin.shaderBin); + */ + + for (i = 0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + AttributeBin attrBin = ra.renderMolecule.textureBin.attributeBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertShaderBin(attrBin, ra); + } + } + } else if (sasUpdate) { + /* TODO : JADA - Sole user logic is incomplete. Will disable for JavaOne */ + //if (false && (sApp.mirror.changedFrequent & component) != 0) { + if(false) { + /* + System.err.println("RenderBin : sole user (SHADER_ATTRIBUTE_SET)" + + ra.renderMolecule.textureBin.shaderBin); + */ + + ShaderBin sBin; + + for (i = 0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + + sBin = ra.renderMolecule.textureBin.shaderBin; + + if (sBin.componentDirty == 0) { + sBinUpdateList.add(sBin); + sBin.componentDirty |= ShaderBin.SHADER_ATTRIBUTE_SET_DIRTY; + } + } + } else { + /* + System.err.println("RenderBin :not soleUser (SHADER_ATTRIBUTE_SET) " + + ra.renderMolecule.textureBin.shaderBin); + */ + + for (i = 0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + AttributeBin attrBin = ra.renderMolecule.textureBin.attributeBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertShaderBin(attrBin, ra); + } + } + } + } + + } + + + void processFogChanged(Object[] args) { + FogRetained fog = (FogRetained)args[0]; + EnvironmentSet e; + int component = ((Integer)args[1]).intValue(); + + if ((component &(FogRetained.SCOPE_CHANGED | + FogRetained.BOUNDS_CHANGED | + FogRetained.BOUNDINGLEAF_CHANGED)) != 0){ + envDirty |= REEVALUATE_FOG; + } + else { + UnorderList list = fog.mirrorFog.environmentSets; + synchronized (list) { + EnvironmentSet envsets[] = (EnvironmentSet []) list.toArray(false); + int size = list.size(); + for (int i = 0; i < size; i++) { + e = envsets[i]; + e.canvasDirty |= Canvas3D.FOG_DIRTY; + if (!e.onUpdateList) { + objUpdateList.add(e); + e.onUpdateList = true; + } + } + } + } + } + + + /** + * This routine get called whenever a component of the appearance + * changes + */ + void processAppearanceChanged(Object[] args){ + int component = ((Integer)args[1]).intValue(); + int i; + GeometryAtom[] gaArr = (GeometryAtom[] )args[3]; + GeometryAtom ga; + RenderAtom ra = null; + AppearanceRetained app = (AppearanceRetained) args[0]; + int TEXTURE_STATE_CHANGED = + AppearanceRetained.TEXTURE_UNIT_STATE | + AppearanceRetained.TEXTURE | + AppearanceRetained.TEXTURE_ATTR | + AppearanceRetained.TEXCOORD_GEN ; + + int start = -1; + + // Get the first ra that is visible + for (i = 0; (i < gaArr.length && (start < 0)); i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) { + continue; + } + else { + start = i; + } + } + + if (start >= 0) { + + if ((component & TEXTURE_STATE_CHANGED) != 0) { + + + if (((app.mirror.changedFrequent & TEXTURE_STATE_CHANGED) != 0) && + ((ra.renderMolecule.textureBin.tbFlag & + TextureBin.SOLE_USER) != 0)) { + +/* +System.err.println("renderbin. texture state changed tb sole user " + + ra.renderMolecule.textureBin + " tb.tbFlag= " + + ra.renderMolecule.textureBin.tbFlag); +*/ + + TextureBin tb; + + + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + tb = ra.renderMolecule.textureBin; + if (tb.soleUserCompDirty == 0) { + tbUpdateList.add(tb); + } + + // mark that the texture unit state ref is changed + // also mark that the TextureBin needs to reevaluate + // number of active textures + tb.soleUserCompDirty |= + TextureBin.SOLE_USER_DIRTY_REF; + } + } else { +/* +System.err.println("renderbin. texture state changed tb not sole user " + + ra.renderMolecule.textureBin + " tb.tbFlag= " + + ra.renderMolecule.textureBin.tbFlag); + +System.err.println("......tb.soleUser= " + + ((ra.renderMolecule.textureBin.tbFlag & TextureBin.SOLE_USER) != 0) + + " app.mirror.changedFrequent= " + + ((app.mirror.changedFrequent & TEXTURE_STATE_CHANGED) != 0)); + +*/ + + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + ShaderBin sb = ra.renderMolecule.textureBin.shaderBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertTextureBin(sb, ra); + } + } + } else if ((component & AppearanceRetained.RENDERING) != 0) { + boolean visible = ((Boolean)args[4]).booleanValue(); + visGAIsDirty = true; + visQuery = true; + if (!visible) { + // remove all gaAttrs + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + + if (ra== null || !ra.inRenderBin()) + continue; + renderAtoms.remove(renderAtoms.indexOf(ra)); + removeARenderAtom(ra); + } + } + else { + if ((app.mirror.changedFrequent & component) != 0 && + ra.renderMolecule.textureBin.attributeBin.soleUser) { + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + AttributeBin aBin = ra.renderMolecule.textureBin.attributeBin; + if ((aBin.onUpdateList & AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST) == 0 ) { + aBinUpdateList.add(aBin); + aBin.onUpdateList |= AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST; + } + + } + } + else { + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + EnvironmentSet e = ra.renderMolecule.textureBin.environmentSet; + ra.renderMolecule.removeRenderAtom(ra); + reInsertAttributeBin(e, ra); + } + } + } + } + + else if ((component & (AppearanceRetained.COLOR | + AppearanceRetained.MATERIAL| + AppearanceRetained.TRANSPARENCY| + AppearanceRetained.POLYGON | + AppearanceRetained.LINE| + AppearanceRetained.POINT)) != 0) { + // System.err.println("AppearanceRetained.POINT = "+AppearanceRetained.POINT); + // System.err.println("(app.mirror.changedFrequent & component) != 0 "+app.mirror.changedFrequent ); + // System.err.println("ra.renderMolecule.soleUser "+ra.renderMolecule.soleUser); + if ((app.mirror.changedFrequent & component) != 0 && + ra.renderMolecule.soleUser) { + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + if ((ra.renderMolecule.soleUserCompDirty& RenderMolecule.ALL_DIRTY_BITS) == 0 ) { + rmUpdateList.add(ra.renderMolecule); + } + ra.renderMolecule.soleUserCompDirty |= component; + + } + + } + else { + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + TextureBin tb = ra.renderMolecule.textureBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertRenderAtom(tb, ra); + + } + } + } + } else { + // Nothing is visible + if ((component & AppearanceRetained.RENDERING) != 0) { + // Rendering attributes change + visGAIsDirty = true; + visQuery = true; + } + } + } + + + + + void processModelClipChanged(Object[] args) { + ModelClipRetained modelClip = + (ModelClipRetained)args[0]; + EnvironmentSet e; + int component = ((Integer)args[1]).intValue(); + + if ((component & (ModelClipRetained.SCOPE_CHANGED | + ModelClipRetained.BOUNDS_CHANGED | + ModelClipRetained.BOUNDINGLEAF_CHANGED)) != 0){ + envDirty |= REEVALUATE_MCLIP; + + } else if ((component & (ModelClipRetained.ENABLE_CHANGED | + ModelClipRetained.ENABLES_CHANGED)) != 0) { + // need to render modelclip + if (!changedModelClips.contains(modelClip.mirrorModelClip)) + changedModelClips.add(modelClip.mirrorModelClip); + + // need to reevaluate envset + envDirty |= REEVALUATE_MCLIP; + + } else { + UnorderList list = modelClip.mirrorModelClip.environmentSets; + synchronized (list) { + EnvironmentSet envsets[] = (EnvironmentSet []) list.toArray(false); + int size = list.size(); + for (int i = 0; i < size; i++) { + e = envsets[i]; + e.canvasDirty |= Canvas3D.MODELCLIP_DIRTY; + if (!e.onUpdateList) { + objUpdateList.add(e); + e.onUpdateList = true; + } + } + } + } + } + + + /** + * This routine get called whenever a region of the boundingleaf + * changes + */ + void processBoundingLeafChanged(Object[] args, long refTime){ + // Notify all users of this bounding leaf, it may + // result in the re-evaluation of the lights/fogs/backgrounds + Object[] users = (Object[])(args[3]); + int i; + + // XXXX: Handle other object affected by bounding leaf changes + for (i = 0; i < users.length; i++) { + LeafRetained leaf = (LeafRetained)users[i]; + switch(leaf.nodeType) { + case NodeRetained.AMBIENTLIGHT: + case NodeRetained.POINTLIGHT: + case NodeRetained.SPOTLIGHT: + case NodeRetained.DIRECTIONALLIGHT: + if (universe.renderingEnvironmentStructure.isLightScopedToThisView(leaf, view)) + envDirty |= REEVALUATE_LIGHTS; + break; + case NodeRetained.LINEARFOG: + case NodeRetained.EXPONENTIALFOG: + if (universe.renderingEnvironmentStructure.isFogScopedToThisView(leaf, view)) + envDirty |= REEVALUATE_FOG; + break; + case NodeRetained.BACKGROUND: + if (universe.renderingEnvironmentStructure.isBgScopedToThisView(leaf, view)) + reEvaluateBg = true; + break; + case NodeRetained.CLIP: + if (universe.renderingEnvironmentStructure.isClipScopedToThisView(leaf, view)) + reEvaluateClip = true; + break; + case NodeRetained.MODELCLIP: + if (universe.renderingEnvironmentStructure.isMclipScopedToThisView(leaf, view)) + envDirty |= REEVALUATE_MCLIP; + break; + case NodeRetained.ALTERNATEAPPEARANCE: + if (universe.renderingEnvironmentStructure.isAltAppScopedToThisView(leaf, view)) altAppearanceDirty = true; + break; + default: + break; + } + } + + } + + void processOrientedShape3DChanged(Object[] gaArr) { + + RenderAtom ra; + for (int i = 0; i < gaArr.length; i++) { + ra = ((GeometryAtom)gaArr[i]).getRenderAtom(view); + if (ra!= null && ra.inRenderBin() && !ra.inDirtyOrientedRAs()) { + dirtyOrientedRAs.add(ra); + ra.dirtyMask |= RenderAtom.IN_DIRTY_ORIENTED_RAs; + } + } + } + + + void processShapeChanged(Object[] args, long refTime) { + + int component = ((Integer)args[1]).intValue(); + int i; + RenderAtom ra; + RenderAtom raNext; + EnvironmentSet e; + TextureBin tb; + if ((component & Shape3DRetained.APPEARANCE_CHANGED) != 0) { + GeometryAtom[] gaArr = (GeometryAtom[])args[4]; + if (gaArr.length > 0) { + if (!gaArr[0].source.appearanceOverrideEnable) { + for (i =0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra == null || !ra.inRenderBin()) { + continue; + } + ra.app = ra.geometryAtom.source.appearance; + e = ra.renderMolecule.textureBin.environmentSet; + ra.renderMolecule.removeRenderAtom(ra); + reInsertAttributeBin(e, ra); + } + } + else { + for (i =0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra == null || !ra.inRenderBin()) { + continue; + } + // if its using the alternate appearance continue .. + if (ra.app == ra.geometryAtom.source.otherAppearance) + continue; + ra.app = ra.geometryAtom.source.appearance; + e = ra.renderMolecule.textureBin.environmentSet; + ra.renderMolecule.removeRenderAtom(ra); + reInsertAttributeBin(e, ra); + } + } + } + } + else if ((component & Shape3DRetained.GEOMETRY_CHANGED) != 0) { + processDataChanged((Object[])args[2], (Object[])args[3], refTime); + } + else if ((component & Shape3DRetained.APPEARANCEOVERRIDE_CHANGED) != 0) { + AppearanceRetained app, saveApp = null; + Shape3DRetained saveShape = null; + GeometryAtom[] gaArr = (GeometryAtom[])args[4]; + Object[] retVal; + for (i =0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra == null || !ra.inRenderBin()) + continue; + // Once shape could have many geometryAtoms, add the + // mirrorShape as a user of an appearance only once + + if (saveShape != ra.geometryAtom.source) { + saveShape = ra.geometryAtom.source; + if (ra.geometryAtom.source.appearanceOverrideEnable) { + retVal =universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view); + saveShape.otherAppearance = (AppearanceRetained)retVal[1]; + if (retVal[0] == Boolean.TRUE) { + app = (AppearanceRetained)retVal[1]; + if (app != null) { + app.sgApp.addAMirrorUser(saveShape); + } + } + else {// use the default + app = ra.geometryAtom.source.appearance; + } + } + else { + // If it were using the alternate appearance + // remove itself as the user + if (ra.app == saveShape.otherAppearance && + ra.app != null) { + ra.app.sgApp.removeAMirrorUser(saveShape); + } + app = ra.geometryAtom.source.appearance; + saveShape.otherAppearance = null; + } + saveApp = app; + } + else { + app = saveApp; + } + ra.app = app; + e = ra.renderMolecule.textureBin.environmentSet; + ra.renderMolecule.removeRenderAtom(ra); + reInsertAttributeBin(e, ra); + } + } + + } + + + /** + * Process a Text3D data change. This involves removing all the + * old geometry atoms in the list, and the creating new ones. + */ + void processDataChanged(Object[] oldGaList, + Object[] newGaList, long referenceTime) { + Shape3DRetained s, src; + RenderAtom ra; + RenderMolecule rm; + int i, j; + Transform3D trans; + ArrayList rmChangedList = new ArrayList(5); + GeometryRetained geo; + GeometryAtom ga; + + for (i=0; i 0) { + if (!gaArr[0].source.appearanceOverrideEnable) { + for (i =0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra == null || !ra.inRenderBin()) { + continue; + } + ra.app = ra.geometryAtom.source.appearance; + e = ra.renderMolecule.textureBin.environmentSet; + ra.renderMolecule.removeRenderAtom(ra); + reInsertAttributeBin(e, ra); + } + } + else { + for (i =0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra == null || !ra.inRenderBin()) + continue; + + // if its using the alternate appearance continue .. + if (ra.app == ra.geometryAtom.source.otherAppearance) + continue; + ra.app = ra.geometryAtom.source.appearance; + e = ra.renderMolecule.textureBin.environmentSet; + ra.renderMolecule.removeRenderAtom(ra); + reInsertAttributeBin(e, ra); + } + } + } + } + else if ((component & MorphRetained.APPEARANCEOVERRIDE_CHANGED) != 0) { + AppearanceRetained app, saveApp = null; + Shape3DRetained saveShape = null; + GeometryAtom[] gaArr = (GeometryAtom[])args[4]; + Object[] retVal; + + for (i =0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra == null || !ra.inRenderBin()) + continue; + // Once shape could have many geometryAtoms, add the + // mirrorShape as a user of an appearance only once + + if (saveShape != ra.geometryAtom.source) { + saveShape = ra.geometryAtom.source; + if (ra.geometryAtom.source.appearanceOverrideEnable) { + retVal =universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view); + saveShape.otherAppearance = (AppearanceRetained)retVal[1]; + if (retVal[0] == Boolean.TRUE) { + app = (AppearanceRetained)retVal[1]; + if (app != null) { + app.sgApp.addAMirrorUser(saveShape); + } + } + else {// use the default + app = ra.geometryAtom.source.appearance; + } + } + else { + // If it were using the alternate appearance + // remove itself as the user + if (ra.app == saveShape.otherAppearance && + ra.app != null) { + ra.app.sgApp.removeAMirrorUser(saveShape); + } + app = ra.geometryAtom.source.appearance; + saveShape.otherAppearance = null; + } + saveApp = app; + } + else { + app = saveApp; + } + ra.app = app; + e = ra.renderMolecule.textureBin.environmentSet; + ra.renderMolecule.removeRenderAtom(ra); + reInsertAttributeBin(e, ra); + } + } + + } + + + + /** + * This routine gets called whenever the position of the view platform + * has changed. + */ + void updateViewPlatform(ViewPlatformRetained vp, float radius) { + Transform3D trans = null; + ViewPlatform viewP = view.getViewPlatform(); + if (viewP != null && (ViewPlatformRetained)viewP.retained == vp) { + vpcToVworld = vp.getCurrentLocalToVworld(null); + vpcToVworldDirty = true; + synchronized(vp) { + vp.vprDirtyMask |= View.VPR_VIEWPLATFORM_DIRTY; + } + + // vp schedSphere is already set and transform in + // BehaviorStructure thread which is run before + // RenderBin using vp.updateActivationRadius() + vpSchedSphereInVworld = vp.schedSphere; + reEvaluateBg = true; + reEvaluateClip = true; + } + + } + + + + /** + * This routine removes the GeometryAtoms from RenderBin + */ + void processGeometryAtomsChanged(Object[] gaArr) { + int i; + RenderAtom ra; + + for (i = 0; i < gaArr.length; i++) { + ra = ((GeometryAtom)gaArr[i]).getRenderAtom(view); + if (ra != null && ra.inRenderBin()) { + renderAtoms.remove(renderAtoms.indexOf(ra)); + removeARenderAtom(ra); + } + } + } + + /** + * process Geometry changed, mark the display list + * in which renderMolecule is as dirty + */ + void processGeometryChanged(Object[] args) { + + Object[] gaList = (Object[]) args[0]; + + GeometryRetained g = (GeometryRetained)args[1]; + GeometryAtom ga; + + int i; + + for (i = 0; i < gaList.length; i++) { + ga = ((GeometryAtom)gaList[i]); + RenderAtom renderAtom = ga.getRenderAtom(view); + if (renderAtom == null || !renderAtom.inRenderBin()) { + continue; + } + + + // Add the renderMolecule to the dirty list so that + // display list will be recreated + int j = 0; + for ( j = 0; j < renderAtom.rListInfo.length; j++) { + if (g == renderAtom.rListInfo[j].geometry()) + break; + } + RenderAtomListInfo ra = (RenderAtomListInfo)renderAtom.rListInfo[j]; + if ((ra.groupType & RenderAtom.DLIST) != 0) + addDirtyRenderMolecule(ra.renderAtom.renderMolecule); + + if ((ra.groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0) { + addDlistPerRinfo.add(ra); + } + + if ((ra.groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) + addGeometryDlist(ra); + + // Raster send this message only for setImage() + if (g instanceof RasterRetained) { + Object[] objs = (Object[]) args[2]; + Texture2DRetained oldTex = (Texture2DRetained) objs[0]; + Texture2DRetained newTex = (Texture2DRetained) objs[1]; + + RasterRetained geo = (RasterRetained)ra.geometry(); + if (oldTex != null) { + addTextureResourceFreeList(oldTex); + ImageComponentRetained oldImage = oldTex.images[0][0]; + if (oldImage != null) { + removeNodeComponent(oldImage); + } + } + if (newTex != null) { + ImageComponentRetained newImage = newTex.images[0][0]; + if (newImage != null) { + addNodeComponent(newImage); + } + } + } + + } + + } + + void addTextureBin(TextureBin tb) { + textureBinList.add(tb); + } + + + void removeTextureBin(TextureBin tb) { + textureBinList.remove(tb); + } + + void addDirtyRenderMolecule(RenderMolecule rm) { + int i; + + if ((rm.onUpdateList & RenderMolecule.IN_DIRTY_RENDERMOLECULE_LIST) == 0) { + if (rm.onUpdateList == 0) { + objUpdateList.add(rm); + } + rm.onUpdateList |= RenderMolecule.IN_DIRTY_RENDERMOLECULE_LIST; + dirtyRenderMoleculeList.add(rm); + } + } + + + + void removeDirtyRenderMolecule(RenderMolecule rm) { + int i; + if ((rm.onUpdateList & RenderMolecule.IN_DIRTY_RENDERMOLECULE_LIST) != 0) { + rm.onUpdateList &= ~RenderMolecule.IN_DIRTY_RENDERMOLECULE_LIST; + if (rm.onUpdateList == 0) { + objUpdateList.remove(rm); + } + dirtyRenderMoleculeList.remove(dirtyRenderMoleculeList.indexOf(rm)); + } + } + + void updateDirtyDisplayLists(Canvas3D cv, + ArrayList rmList, ArrayList dlistPerRinfoList, + ArrayList raList, boolean useSharedCtx ) { + int size, i, bitMask; + Context ctx; + long timeStamp; + + if (useSharedCtx) { + ctx = cv.screen.renderer.sharedCtx; + cv.makeCtxCurrent(ctx); + bitMask = cv.screen.renderer.rendererBit; + timeStamp = cv.screen.renderer.sharedCtxTimeStamp; + } else { + ctx = cv.ctx; + bitMask = cv.canvasBit; + timeStamp = cv.ctxTimeStamp; + } + + size = rmList.size(); + + if (size > 0) { + for (i = size-1; i >= 0; i--) { + RenderMolecule rm = (RenderMolecule)rmList.get(i); + rm.updateDisplayList(cv); + } + rmList.clear(); + } + + size = dlistPerRinfoList.size(); + + if (size > 0) { + for (i = size-1; i >= 0 ; i--) { + Object[] obj = (Object[])dlistPerRinfoList.get(i); + dlistRenderMethod.buildDlistPerRinfo((RenderAtomListInfo)obj[0], (RenderMolecule)obj[1], cv); + } + dlistPerRinfoList.clear(); + } + + size = raList.size(); + if (size > 0) { + RenderAtomListInfo ra; + GeometryArrayRetained geo; + + for (i = size-1; i >= 0; i--) { + ra = (RenderAtomListInfo)raList.get(i); + geo = (GeometryArrayRetained) ra.geometry(); + geo.resourceCreationMask &= ~bitMask; + } + + for (i = size-1; i >= 0; i--) { + ra = (RenderAtomListInfo)raList.get(i); + geo = (GeometryArrayRetained) ra.geometry(); + if ((geo.resourceCreationMask & bitMask) == 0) { + dlistRenderMethod.buildIndividualDisplayList(ra, cv, ctx); + geo.resourceCreationMask |= bitMask; + geo.setDlistTimeStamp(bitMask, timeStamp); + } + } + raList.clear(); + } + + if (useSharedCtx) { + cv.makeCtxCurrent(cv.ctx); + } + } + + void removeRenderMolecule(RenderMolecule rm) { + + if ((rm.primaryMoleculeType &(RenderMolecule.DLIST_MOLECULE|RenderMolecule.SEPARATE_DLIST_PER_RINFO_MOLECULE)) != 0) + renderMoleculeList.remove(rm); + } + + void updateAllRenderMolecule(Canvas3D cv) { + int i; + int size = renderMoleculeList.size(); + + if (size > 0) { + RenderMolecule[] rmArr = (RenderMolecule[]) + renderMoleculeList.toArray(false); + for (i = size-1 ; i >= 0; i--) { + rmArr[i].updateAllPrimaryDisplayLists(cv); + } + } + + size = sharedDList.size(); + if (size > 0) { + RenderAtomListInfo ra; + GeometryArrayRetained geo; + RenderAtomListInfo arr[] = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) sharedDList.toArray(arr); + int bitMask = cv.canvasBit; + + // We need two passes to avoid extra buildDisplayList + // when geo are the same. The first pass clean the + // rendererBit. Note that we can't rely on + // resourceCreation since it is a force recreate. + + for (i = size-1; i >= 0; i--) { + geo = (GeometryArrayRetained) arr[i].geometry(); + geo.resourceCreationMask &= ~bitMask; + } + + for (i = size-1; i >= 0; i--) { + ra = arr[i]; + geo = (GeometryArrayRetained) ra.geometry(); + if ((geo.resourceCreationMask & bitMask) == 0) { + dlistRenderMethod.buildIndividualDisplayList(ra, cv, cv.ctx); + geo.resourceCreationMask |= bitMask; + geo.setDlistTimeStamp(bitMask, cv.ctxTimeStamp); + } + } + } + } + + /** + * This method is called to update all renderMolecule + * for a shared context of a renderer + */ + void updateAllRenderMolecule(Renderer rdr, Canvas3D cv) { + int i; + boolean setCtx = false; + GeometryArrayRetained geo; + int size = renderMoleculeList.size(); + + if (size > 0) { + RenderMolecule[] rmArr = (RenderMolecule[]) + renderMoleculeList.toArray(false); + + cv.makeCtxCurrent(rdr.sharedCtx); + setCtx = true; + for (i = size-1 ; i >= 0; i--) { + rmArr[i].updateAllPrimaryDisplayLists(cv); + } + } + + size = sharedDList.size(); + if (size > 0) { + RenderAtomListInfo arr[] = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) sharedDList.toArray(arr); + RenderAtomListInfo ra; + + if (!setCtx) { + cv.makeCtxCurrent(rdr.sharedCtx); + setCtx = true; + } + + // We need two passes to avoid extra buildDisplayList + // when geo are the same. The first pass clean the + // rendererBit. + int bitMask = cv.screen.renderer.rendererBit; + long timeStamp = cv.screen.renderer.sharedCtxTimeStamp; + + for (i = size-1; i >= 0; i--) { + geo = (GeometryArrayRetained) arr[i].geometry(); + geo.resourceCreationMask &= ~bitMask; + } + + for (i = size-1; i >= 0; i--) { + ra = arr[i]; + geo = (GeometryArrayRetained) ra.geometry(); + if ((geo.resourceCreationMask & bitMask) == 0) { + dlistRenderMethod.buildIndividualDisplayList(ra, cv, + rdr.sharedCtx); + geo.resourceCreationMask |= bitMask; + geo.setDlistTimeStamp(bitMask, timeStamp); + } + } + } + if (setCtx) { + cv.makeCtxCurrent(cv.ctx); + } + } + + private void processText3DTransformChanged(Object[] list, + Object[] transforms, + long referenceTime) { + int i, j, numShapes; + GeometryAtom ga; + RenderMolecule rm; + RenderAtom ra; + + if (transforms.length != 0) { + numShapes = list.length; + for (i=0; i adding to the dirty list .., transpSortMode = "+transpSortMode); + if (dirtyDepthSortRenderAtom.add(ra)) { + numDirtyTinfo += ra.rListInfo.length; + } + /* + else { + System.err.println("processTransformChanged: attempt to add RenderAtom already in dirty list"); + } + */ + ra.dirtyMask |= RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST; + + } + continue; + } + // If the appearance has changed .. + if (ra.app != app) { + if (ra.geometryAtom.source.appearanceOverrideEnable) { + // If it was using the alternate appearance, then .. + if (ra.app == ra.geometryAtom.source.otherAppearance) { + if (ra.app != null) { + // remove this mirror shape from the user list + ra.geometryAtom.source.otherAppearance.sgApp.removeAMirrorUser(ra.geometryAtom.source); + ra.geometryAtom.source.otherAppearance = null; + } + } + // if we are using the alternate app, add the mirror + // shape to the userlist + if (app != ra.geometryAtom.source.appearance) { + // Second check is needed to prevent, + // the mirror shape + // that has multiple ra's to be added more than + // once + if (app != null && app != ra.geometryAtom.source.otherAppearance) { + app.sgApp.addAMirrorUser(ra.geometryAtom.source); + ra.geometryAtom.source.otherAppearance = app; + } + } + + } + } + + + // Remove the renderAtom from the current + // renderMolecule and reinsert + getNewEnvironment(ra, lights, fog, modelClip, app); + } + } + } + } + + // process misc environment nodes + arrList = targets.targetList[Targets.ENV_TARGETS]; + if (arrList != null) { + size = arrList.size(); + nodesArr = arrList.toArray(false); + for (n = 0; n < size; n++) { + list = (Object[])nodesArr[n]; + for (i=0; i 0) { + envsets = (EnvironmentSet []) list.toArray(false); + for (j = 0; j < size; j++) { + e = envsets[j]; + e.canvasDirty |= Canvas3D.AMBIENTLIGHT_DIRTY; + if (!e.onUpdateList) { + objUpdateList.add(e); + e.onUpdateList = true; + } + } + } else { + if ((component & LightRetained.ENABLE_CHANGED) != 0) { + boolean value = lti.lightOn; + if (value) { + if (!changedLts.contains(lti)) + changedLts.add(lti); + envDirty |= REEVALUATE_LIGHTS; + } + } + } + } + } + } else { + for (i = 0; i < mLts.length; i++) { + LightRetained lti = mLts[i]; + if ((component & LightRetained.ENABLE_CHANGED) != 0) { + boolean value = ((Boolean)args[4]).booleanValue(); + if (value) { + if (!changedLts.contains(lti)) + changedLts.add(lti); + + envDirty |= REEVALUATE_LIGHTS; + } + } + UnorderList list = lti.environmentSets; + EnvironmentSet envsets[]; + synchronized (list) { + int size = list.size(); + int lsize; + if (size > 0) { + envsets = (EnvironmentSet []) list.toArray(false); + if ((component & LightRetained.ENABLE_CHANGED) != 0) { + boolean value = ((Boolean)args[4]).booleanValue(); + for (j = 0; j = og.orderedChildIdTable.length) { + // Create a new category that adds Info based only on oi + // which will be added to the orderedBin after the + // idTable reflects the correct childId for the next frame + ob.setOCForOI.add(new Integer(oi)); + oc = new OrderedCollection(); + ob.valueOfSetOCForOI.add(oc); + if (!ob.onUpdateList) { + obList.add(ob); + ob.onUpdateList = true; + } + } + else { + ci = og.orderedChildIdTable[oi]; + + for (n = 0; n < ob.setOCForCI.size(); n++) { + val = ((Integer)ob.setOCForCI.get(n)).intValue(); + if (val == ci) { + + oc=(OrderedCollection)ob.valueOfSetOCForCI.get(n); + if (oc == null) { + oc = new OrderedCollection(); + ob.valueOfSetOCForCI.set(n, oc); + } + + break; + } + } + if (n == ob.setOCForCI.size()) { + oc = (OrderedCollection)ocs.get(ci); + if (oc == null) { + oc = new OrderedCollection(); + ob.setOCForCI.add(new Integer(ci)); + ob.valueOfSetOCForCI.add(oc); + if (!ob.onUpdateList) { + obList.add(ob); + ob.onUpdateList = true; + } + } + } + } + } + if (oc.nextFrameLightBin == null) { + oc.nextFrameLightBin = getLightBin(maxLights, + ga.source.geometryBackground, false); + oc.nextFrameLightBin.setOrderedInfo(oc); + + if (!oc.onUpdateList) { + objUpdateList.add(oc); + oc.onUpdateList = true; + } + } + + parentChildOrderedBins = oc.childOrderedBins; + parentOrderedBin = ob; + parentOrderedChildId = oi; + } + return (oc); + } + + private void removeOrderedHeadLightBin(LightBin lightBin) { + int i, k; + int oi; // an id which identifies a children of the orderedGroup + int ci; // child index of the ordered group + ArrayList ocs; + OrderedCollection oc; + OrderedBin ob, savedOb; + int n, val; + + + + oc = lightBin.orderedCollection; + + oc.lightBin = lightBin.next; + oc.nextFrameLightBin = oc.lightBin; + + + + if (oc.lightBin != null) { + // Make this lightBin the head of the lightBin; + oc.lightBin.prev = null; + oc.lightBin.orderedCollection = oc; + } + + + } + + + /** + * This gets a new EnviornmentSet. It creates one if there are none + * on the freelist. + */ + private EnvironmentSet getEnvironmentSet(RenderAtom ra, LightRetained[] lights, + FogRetained fog, ModelClipRetained modelClip) { + EnvironmentSet envSet; + + envSet = new EnvironmentSet(ra, lights, fog, modelClip, this); + return (envSet); + } + + /** + * This finds or creates an AttributeBin for a given RenderAtom. + */ + private AttributeBin findAttributeBin(EnvironmentSet envSet, RenderAtom ra) { + int i; + AttributeBin currentBin; + RenderingAttributesRetained renderingAttributes; + if (ra.app == null) { + renderingAttributes = null; + } else { + renderingAttributes = ra.app.renderingAttributes; + } + + currentBin = envSet.attributeBinList; + while (currentBin != null) { + if (currentBin.equals(renderingAttributes, ra)) { + return(currentBin); + } + currentBin = currentBin.next; + } + // Check the "to-be-added" list of attributeBins for a match + for (i = 0; i < envSet.addAttributeBins.size(); i++) { + currentBin = (AttributeBin)envSet.addAttributeBins.get(i); + if (currentBin.equals(renderingAttributes, ra)) { + return(currentBin); + } + } + currentBin = getAttributeBin(ra.app, renderingAttributes); + envSet.addAttributeBin(currentBin, this); + return(currentBin); + } + + /** + * This finds or creates an ShaderBin for a given RenderAtom. + */ + private ShaderBin findShaderBin(AttributeBin attributeBin, RenderAtom ra) { + int i, size; + ShaderBin currentBin; + ShaderAppearanceRetained sApp; + + if((ra != null) && (ra.app instanceof ShaderAppearanceRetained)) + sApp = (ShaderAppearanceRetained)ra.app; + else + sApp = null; + + currentBin = attributeBin.shaderBinList; + while (currentBin != null) { + if (currentBin.equals(sApp)) { + return currentBin; + } + currentBin = currentBin.next; + } + + // Check the "to-be-added" list of shaderBins for a match + size = attributeBin.addShaderBins.size(); + for (i = 0; i < size; i++) { + currentBin = (ShaderBin)attributeBin.addShaderBins.get(i); + if (currentBin.equals(sApp)) { + return currentBin; + } + } + + currentBin = getShaderBin(sApp); + attributeBin.addShaderBin(currentBin, this, sApp); + return currentBin; + } + + /** + * This finds or creates a TextureBin for a given RenderAtom. + */ + private TextureBin findTextureBin(ShaderBin shaderBin, RenderAtom ra) { + int i, size; + TextureBin currentBin; + TextureRetained texture; + TextureUnitStateRetained texUnitState[]; + + if (ra.app == null) { + texUnitState = null; + } else { + texUnitState = ra.app.texUnitState; + } + + currentBin = shaderBin.textureBinList; + while (currentBin != null) { + if (currentBin.equals(texUnitState, ra)) { + //System.err.println("1: Equal"); + return(currentBin); + } + currentBin = currentBin.next; + } + // Check the "to-be-added" list of TextureBins for a match + size = shaderBin.addTextureBins.size(); + for (i = 0; i < size; i++) { + currentBin = (TextureBin)shaderBin.addTextureBins.get(i); + if (currentBin.equals(texUnitState, ra)) { + //System.err.println("2: Equal"); + return(currentBin); + } + } + // get a new texture bin for this texture unit state + currentBin = getTextureBin(texUnitState, ra.app); + shaderBin.addTextureBin(currentBin, this, ra); + return(currentBin); + } + + /** + * This finds or creates a RenderMolecule for a given RenderAtom. + */ + private RenderMolecule findRenderMolecule(TextureBin textureBin, + RenderAtom ra) { + + RenderMolecule currentBin; + PolygonAttributesRetained polygonAttributes; + LineAttributesRetained lineAttributes; + PointAttributesRetained pointAttributes; + MaterialRetained material; + ColoringAttributesRetained coloringAttributes; + TransparencyAttributesRetained transparencyAttributes; + int i; + ArrayList list; + TextureUnitStateRetained texUnitState[]; + RenderingAttributesRetained renderingAttributes; + HashMap rmap = null, addmap = null; + + if (ra.app == null) { + polygonAttributes = null; + lineAttributes = null; + pointAttributes = null; + material = null; + coloringAttributes = null; + transparencyAttributes = null; + renderingAttributes = null; + texUnitState = null; + } else { + polygonAttributes = ra.app.polygonAttributes; + lineAttributes = ra.app.lineAttributes; + pointAttributes = ra.app.pointAttributes; + material = ra.app.material; + coloringAttributes = ra.app.coloringAttributes; + transparencyAttributes = ra.app.transparencyAttributes; + renderingAttributes = ra.app.renderingAttributes; + texUnitState = ra.app.texUnitState; + } + + // Get the renderMoleculelist for this xform + if (ra.isOpaque()) { + rmap = textureBin.opaqueRenderMoleculeMap; + addmap = textureBin.addOpaqueRMs; + } + else { + rmap = textureBin.transparentRenderMoleculeMap; + addmap = textureBin.addTransparentRMs; + } + currentBin = (RenderMolecule)rmap.get(ra.geometryAtom.source.localToVworld[0]); + + while (currentBin != null) { + if (currentBin.equals(ra, + polygonAttributes, lineAttributes, + pointAttributes, material, + coloringAttributes, + transparencyAttributes, + ra.geometryAtom.source.localToVworld[0])) { + + currentBin.addRenderAtom(ra, this); + ra.envSet = ra.renderMolecule.textureBin.environmentSet; + // If the locale has changed for an existing renderMolecule + // handle the RmlocaleToVworld + return(currentBin); + } + currentBin = currentBin.next; + } + // Check the "to-be-added" list of renderMolecules for a match + if ((list = (ArrayList)addmap.get(ra.geometryAtom.source.localToVworld[0])) != null) { + for (i = 0; i < list.size(); i++) { + currentBin = (RenderMolecule)list.get(i); + if (currentBin.equals(ra, + polygonAttributes, lineAttributes, + pointAttributes, material, + coloringAttributes, + transparencyAttributes, + ra.geometryAtom.source.localToVworld[0])) { + currentBin.addRenderAtom(ra, this); + return(currentBin); + } + } + } + + + currentBin = getRenderMolecule(ra.geometryAtom, + polygonAttributes, + lineAttributes, + pointAttributes, + material, + coloringAttributes, + transparencyAttributes, + renderingAttributes, + texUnitState, + ra.geometryAtom.source.localToVworld[0], + ra.geometryAtom.source.localToVworldIndex[0]); + textureBin.addRenderMolecule(currentBin, this); + currentBin.addRenderAtom(ra, this); + return(currentBin); + } + + /** + * This gets a new ShaderBin. It creates one if there are none + * on the freelist. + */ + private ShaderBin getShaderBin(ShaderAppearanceRetained sApp) { + return new ShaderBin( sApp, this); + } + + /** + * This gets a new AttributeBin. It creates one if there are none + * on the freelist. + */ + private AttributeBin getAttributeBin(AppearanceRetained app, RenderingAttributesRetained ra) { + return new AttributeBin(app, ra, this); + } + + /** + * This gets a new LightBin. It creates one if there are none + * on the freelist. + */ + private LightBin getLightBin(int maxLights, BackgroundRetained bg, boolean inOpaque) { + LightBin lightBin; + + lightBin = new LightBin(maxLights, this, inOpaque); + + lightBin.geometryBackground = bg; + return (lightBin); + } + + /** + * This gets a new TextureBin. It creates one if there are none + * on the freelist. + */ + private TextureBin getTextureBin(TextureUnitStateRetained texUnitState[], + AppearanceRetained app) { + return new TextureBin(texUnitState, app, this); + } + + /** + * This gets a new RenderMolecule. It creates one if there are none + * on the freelist. + */ + private RenderMolecule getRenderMolecule(GeometryAtom ga, + PolygonAttributesRetained polya, + LineAttributesRetained linea, + PointAttributesRetained pointa, + MaterialRetained material, + ColoringAttributesRetained cola, + TransparencyAttributesRetained transa, + RenderingAttributesRetained ra, + TextureUnitStateRetained[] texUnits, + Transform3D[] transform, + int[] transformIndex) { + + return new RenderMolecule(ga, polya, linea, pointa, + material, cola, transa, ra, + texUnits, + transform, transformIndex, this); + } + + + /** + * This finds or creates an EnviornmentSet for a given RenderAtom. + * This also deals with empty LightBin lists. + */ + private EnvironmentSet findEnvironmentSet(RenderAtom ra) { + LightBin currentBin, lightBin ; + EnvironmentSet currentEnvSet, newBin; + int i; + LightBin addBin = null; + OrderedCollection oc = null; + + if (ra.geometryAtom.source.geometryBackground == null) { + if (ra.geometryAtom.source.orderedPath != null) { + oc = findOrderedCollection(ra.geometryAtom, false); + currentBin = oc.nextFrameLightBin; + addBin = oc.addLightBins; + } else { + currentBin = opaqueBin; + addBin = addOpaqueBin; + } + } else { + if (ra.geometryAtom.source.orderedPath != null) { + oc = findOrderedCollection(ra.geometryAtom, true); + currentBin = oc.nextFrameLightBin; + addBin = oc.addLightBins; + } else { + currentBin = bgOpaqueBin; + addBin = bgAddOpaqueBin; + + } + } + lightBin = currentBin; + + + ra.lights = universe.renderingEnvironmentStructure. + getInfluencingLights(ra, view); + ra.fog = universe.renderingEnvironmentStructure. + getInfluencingFog(ra, view); + ra.modelClip = universe.renderingEnvironmentStructure. + getInfluencingModelClip(ra, view); + + while (currentBin != null) { + // this test is always true for non-backgroundGeo bins + if (currentBin.geometryBackground == + ra.geometryAtom.source.geometryBackground) { + + currentEnvSet = currentBin.environmentSetList; + while (currentEnvSet != null) { + if (currentEnvSet.equals(ra, ra.lights, ra.fog, ra.modelClip)) { + return(currentEnvSet); + } + currentEnvSet = currentEnvSet.next; + } + // Check the "to-be-added" list of environmentSets for a match + for (i = 0; i < currentBin.insertEnvSet.size(); i++) { + newBin = (EnvironmentSet)currentBin.insertEnvSet.get(i); + if (newBin.equals(ra, ra.lights, ra.fog, ra.modelClip)) { + return(newBin); + } + } + } + currentBin = currentBin.next; + } + + // Now check the to-be added lightbins + currentBin = addBin; + while (currentBin != null) { + + // this following test is always true for non-backgroundGeo bins + if (currentBin.geometryBackground == + ra.geometryAtom.source.geometryBackground) { + + // Check the "to-be-added" list of environmentSets for a match + for (i = 0; i < currentBin.insertEnvSet.size(); i++) { + newBin = (EnvironmentSet)currentBin.insertEnvSet.get(i); + if (newBin.equals(ra, ra.lights, ra.fog, ra.modelClip)) { + return(newBin); + } + } + } + currentBin = currentBin.next; + } + + + // Need a new one + currentEnvSet = getEnvironmentSet(ra, ra.lights, ra.fog, ra.modelClip); + currentBin = lightBin; + + // Find a lightbin that envSet fits into + while (currentBin != null) { + + // the first test is always true for non-backgroundGeo bins + if (currentBin.geometryBackground == + ra.geometryAtom.source.geometryBackground && + currentBin.willEnvironmentSetFit(currentEnvSet)) { + break; + } + currentBin = currentBin.next; + } + + // Now check the to-be added lightbins + if (currentBin == null) { + currentBin = addBin; + while (currentBin != null) { + + // the first test is always true for non-backgroundGeo bins + if (currentBin.geometryBackground == + ra.geometryAtom.source.geometryBackground && + currentBin.willEnvironmentSetFit(currentEnvSet)) { + + break; + } + currentBin = currentBin.next; + } + } + + if (currentBin == null) { + // Need a new lightbin + currentBin = getLightBin(maxLights, + ra.geometryAtom.source.geometryBackground, false); + if (addBin != null) { + currentBin.next = addBin; + addBin.prev = currentBin; + } + if (ra.geometryAtom.source.orderedPath != null) { + if (!oc.onUpdateList) { + objUpdateList.add(oc); + oc.onUpdateList = true; + } + oc.addLightBins = currentBin; + } else { + if (ra.geometryAtom.source.geometryBackground == null) + addOpaqueBin = currentBin; + else + bgAddOpaqueBin = currentBin; + } + } + + currentBin.addEnvironmentSet(currentEnvSet, this); + return (currentEnvSet); + } + + void removeLightBin(LightBin lbin) { + if (lbin.prev == null) { // At the head of the list + + if (lbin.orderedCollection != null) + removeOrderedHeadLightBin(lbin); + + if (lbin.geometryBackground == null) { + if (opaqueBin == lbin) { + opaqueBin = lbin.next; + } + } else { + if (bgOpaqueBin == lbin) { + bgOpaqueBin = lbin.next; + } + } + if (lbin.next != null) { + lbin.next.prev = null; + } + } else { // In the middle or at the end. + lbin.prev.next = lbin.next; + if (lbin.next != null) { + lbin.next.prev = lbin.prev; + } + } + Canvas3D canvases[] = view.getCanvases(); + for (int i = 0; i < canvases.length; i++) { + // Mark the environmentSet cached by all the canvases as null + // to force to reEvaluate when it comes back from the freelist + // During LightBin::render(), we only check for the pointers not + // being the same, so we need to take care of the env set + // gotten from the freelist from one frame to another + canvases[i].lightBin = null; + } + lbin.prev = null; + lbin.next = null; + } + + void addDisplayListResourceFreeList(RenderMolecule rm) { + displayListResourceFreeList.add(rm.displayListIdObj); + } + + /** + * This renders the background scene graph. + */ + void renderBackground(Canvas3D cv) { + LightBin currentBin; + boolean savedDepthBufferWriteEnable; + + cv.setDepthBufferWriteEnableOverride(true); + savedDepthBufferWriteEnable = cv.depthBufferWriteEnable; + cv.setDepthBufferWriteEnable(false); + // render background opaque + currentBin = bgOpaqueBin; + while (currentBin != null) { + if (currentBin.geometryBackground == geometryBackground) + currentBin.render(cv); + currentBin = currentBin.next; + } + + // render background ordered + if (bgOrderedBins.size() > 0) { + renderOrderedBins(cv, bgOrderedBins, true); + } + + TransparentRenderingInfo tinfo = bgTransparentInfo; + while (tinfo != null) { + tinfo.render(cv); + tinfo = tinfo.next; + } + cv.setDepthBufferWriteEnableOverride(false); + cv.setDepthBufferWriteEnable(savedDepthBufferWriteEnable); + } + + /** + * This renders the opaque objects + */ + void renderOpaque(Canvas3D cv) { + LightBin currentBin = opaqueBin; + //System.err.println("========> renderOpaque"); + while (currentBin != null) { + //System.err.println("====> rendering Opaque Bin "); + currentBin.render(cv); + currentBin = currentBin.next; + } + + } + + /** + * This renders the transparent objects + */ + void renderTransparent(Canvas3D cv) { + boolean savedDepthBufferWriteEnable = true; + + //System.err.println("====> renderTransparent"); + TransparentRenderingInfo tinfo = transparentInfo; + if (tinfo != null) { + //System.err.println("====> rendering transparent Bin"); + + if (cv.view.depthBufferFreezeTransparent) { + cv.setDepthBufferWriteEnableOverride(true); + savedDepthBufferWriteEnable = cv.depthBufferWriteEnable; + cv.setDepthBufferWriteEnable(false); + } + + if (transpSortMode == View.TRANSPARENCY_SORT_NONE) { + while (tinfo != null) { + tinfo.render(cv); + tinfo = tinfo.next; + } + } + else if (transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY) { + while (tinfo != null ) { + tinfo.sortRender(cv); + tinfo = tinfo.next; + } + } + if (cv.view.depthBufferFreezeTransparent) { + cv.setDepthBufferWriteEnableOverride(false); + cv.setDepthBufferWriteEnable(savedDepthBufferWriteEnable); + } + } + } + + /** + * This renders the ordered objects + */ + void renderOrdered(Canvas3D cv) { + // System.err.println("******renderOrdered, orderedBins.size() = "+orderedBins.size()+" RenderBin = "+this); + if (orderedBins.size() > 0) + renderOrderedBins(cv, orderedBins, false); + } + + void renderOrderedBins(Canvas3D cv, ArrayList bins, boolean doInfinite) { + int sz = bins.size(); + + for (int i=0; i 0) + updateCanvasForDirtyLights(changedLts); + + } + + void updateCanvasForDirtyLights(ArrayList mLts) { + int n, i, j, lmask; + EnvironmentSet e; + UnorderList list; + EnvironmentSet envsets[]; + int sz = mLts.size(); + int envsize; + int ltsize; + + for (n = 0; n < sz; n++) { + LightRetained lt = (LightRetained)mLts.get(n); + list = lt.environmentSets; + synchronized (list) { + envsets = (EnvironmentSet []) list.toArray(false); + envsize = list.size(); + + if (lt.nodeType == LightRetained.AMBIENTLIGHT) { + for (i = 0; i < envsize; i++) { + e = envsets[i]; + e.canvasDirty |= Canvas3D.AMBIENTLIGHT_DIRTY; + if (!e.onUpdateList) { + objUpdateList.add(e); + e.onUpdateList = true; + } + } + } else { + for (i = 0; i < envsize; i++) { + e = envsets[i]; + lmask = 0; + ltsize = e.lights.size(); + for (j = 0; j < ltsize; j++) { + LightRetained curLt = (LightRetained)e.lights.get(j); + if (lt == curLt) { + lmask = (1 << e.ltPos[j]); + if (curLt.lightOn == true) { + e.enableMaskCache |= (1 << e.ltPos[j]); + } + else { + e.enableMaskCache &= (1 << e.ltPos[j]); + } + break; + } + } + e.canvasDirty |= Canvas3D.LIGHTENABLES_DIRTY; + if (!e.onUpdateList) { + objUpdateList.add(e); + e.onUpdateList = true; + } + if(e.lightBin != null) { + e.lightBin.canvasDirty |= Canvas3D.LIGHTBIN_DIRTY; + e.lightBin.lightDirtyMaskCache |= lmask; + if (!e.lightBin.onUpdateList) { + e.lightBin.onUpdateList = true; + objUpdateList.add(e.lightBin); + } + } + } + } + } + } + } + + void addTextureResourceFreeList(TextureRetained tex) { + toBeAddedTextureResourceFreeList.add(tex); + } + + + void reEvaluateEnv(ArrayList mLts, ArrayList fogs, + ArrayList modelClips, + boolean updateDirty, + boolean altAppDirty) { + + reEvaluateAllRenderAtoms(altAppDirty); + + // Done only for xform changes, not for bounding leaf change + if (updateDirty) { + // Update canvases for dirty lights and fog + if (mLts.size()> 0) + updateCanvasForDirtyLights(mLts); + if (fogs.size() > 0) + updateCanvasForDirtyFog(fogs); + if (modelClips.size() > 0) + updateCanvasForDirtyModelClip(modelClips); + } + + } + + void updateInfVworldToVpc() { + vworldToVpc.getRotation(infVworldToVpc); + } + + + // Lock all geometry before rendering into the any canvas + // in the case of display list, for each renderer, + // release after building the display list (which happens + // for the first canvas rendered) + void lockGeometry() { + GeometryRetained geo; + int i, size; + + + // Vertex array is locked for every time renderer is run + size = lockGeometryList.size(); + for (i = 0; i < size; i++) { + geo = (GeometryRetained) lockGeometryList.get(i); + geo.geomLock.getLock(); + + } + + // dlist is locked only when they are rebuilt + size = dlistLockList.size(); + for (i = 0; i < size ; i++) { + geo = (GeometryRetained) dlistLockList.get(i); + geo.geomLock.getLock(); + + } + + // Lock all the by reference image components + size = nodeComponentList.size(); + for (i = 0; i < size; i++) { + ImageComponentRetained nc = (ImageComponentRetained)nodeComponentList.get(i); + nc.geomLock.getLock(); + } + } + + // Release all geometry after rendering to the last canvas + void releaseGeometry() { + GeometryRetained geo; + int i, size; + + size = lockGeometryList.size(); + for (i = 0; i < size; i++) { + geo = (GeometryRetained) lockGeometryList.get(i); + geo.geomLock.unLock(); + } + + size = dlistLockList.size(); + for (i = 0; i < size; i++) { + geo = (GeometryRetained) dlistLockList.get(i); + geo.geomLock.unLock(); + } + // Clear the display list clear list + dlistLockList.clear(); + // Lock all the by reference image components + size = nodeComponentList.size(); + for (i = 0; i < size; i++) { + ImageComponentRetained nc = (ImageComponentRetained)nodeComponentList.get(i); + nc.geomLock.unLock(); + } + } + + void addGeometryToLockList(Object geo) { + // just add it to the list, if its a shared geometry + // it may be added more than once, thats OK since we + // now have nested locks! + lockGeometryList.add(geo); + } + + void removeGeometryFromLockList(Object geo) { + lockGeometryList.remove(geo); + + } + + + void addDirtyReferenceGeometry(Object geo) { + // just add it to the list, if its a shared geometry + // it may be added more than once, thats OK since we + // now have nested locks! + dirtyReferenceGeomList.add(geo); + } + + + void addNodeComponent(Object nc) { + newNodeComponentList.add(nc); + } + + void removeNodeComponent (Object nc) { + removeNodeComponentList.add(nc); + } + + void addDirtyNodeComponent(Object nc) { + dirtyNodeComponentList.add(nc); + } + + + void clearDirtyOrientedRAs() { + int i, nRAs; + Canvas3D cv; + RenderAtom ra; + OrientedShape3DRetained os; + nRAs = dirtyOrientedRAs.size(); + + // clear the dirtyMask + for(i=0; i 0) { + cv = canvases[0]; + } + + if (cv != null) { + if (view.viewCache.vcDirtyMask != 0) { + nRAs = orientedRAs.size(); + + // Update ra's localToVworld given orientedTransform + // Mark Oriented shape as dirty, since multiple ra could point + // to the same OrientShape3D, compute the xform only once + for(i=0; i remove ga = "+ra.geometryAtom); + ra.setRenderBin(false); + ra.renderMolecule.removeRenderAtom(ra); + if (ra.inDirtyOrientedRAs()) { + dirtyOrientedRAs.remove(dirtyOrientedRAs.indexOf(ra)); + ra.dirtyMask &= ~RenderAtom.IN_DIRTY_ORIENTED_RAs; + } + if (ra.inDepthSortList()) { + dirtyDepthSortRenderAtom.remove(ra); + ra.dirtyMask &= ~RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST; + numDirtyTinfo -= ra.rListInfo.length; + } + + // Assertion check in debug mode + if (VersionInfo.isDebug && dirtyDepthSortRenderAtom.contains(ra)) { + System.err.println("removeARenderAtom: ERROR: RenderAtom not removed from dirty list"); + } + } + + void removeAllRenderAtoms() { + int i; + J3dMessage m; + RenderAtom ra; + RenderMolecule rm; + int sz = renderAtoms.size(); + + for (i = 0; i < sz; i++) { + ra = (RenderAtom) renderAtoms.get(i); + rm = ra.renderMolecule; + removeARenderAtom(ra); + rm.updateRemoveRenderAtoms(); + } + renderAtoms.clear(); + + clearAllUpdateObjectState(); + + // Clear the arrayList that are kept from one frame to another + renderMoleculeList.clear(); + sharedDList.clear(); + lockGeometryList.clear(); + // clear out this orderedBin's entry in the orderedGroup + for (i = 0; i < orderedBins.size(); i++) { + removeOrderedBin((OrderedBin) orderedBins.get(i)); + } + orderedBins.clear(); + bgOrderedBins.clear(); + nodeComponentList.clear(); + orientedRAs.clear(); + + // clean up any messages that are queued up, since they are + // irrelevant + // clearMessages(); + geometryBackground = null; + } + + void removeOrderedBin(OrderedBin ob) { + int i, k; + for (i = 0; i < ob.orderedCollections.size(); i++) { + OrderedCollection oc = (OrderedCollection) ob.orderedCollections.get(i); + if (oc == null) + continue; + + for (k = 0; k < oc.childOrderedBins.size(); k++) { + removeOrderedBin((OrderedBin)(oc.childOrderedBins.get(k))); + } + } + if (ob.source != null) { + ob.source.setOrderedBin(null, view.viewIndex); + ob.source = null; + } + } + + + void removeGeometryDlist(RenderAtomListInfo ra) { + removeDlist.add(ra); + } + + + void addGeometryDlist(RenderAtomListInfo ra) { + addDlist.add(ra); + } + + + void dumpBin(LightBin bin) { + LightBin obin = bin; + while (obin != null) { + System.err.println("LightBin = "+obin); + EnvironmentSet envSet = obin.environmentSetList; + while (envSet != null) { + System.err.println(" EnvSet = "+envSet); + AttributeBin abin = envSet.attributeBinList; + while (abin != null) { + System.err.println(" ABin = "+abin); + ShaderBin sbin = abin.shaderBinList; + while (sbin != null) { + System.err.println(" SBin = "+sbin); + TextureBin tbin = sbin.textureBinList; + while (tbin != null) { + System.err.println(" Tbin = "+tbin); + RenderMolecule rm = tbin.opaqueRMList; + System.err.println("===> Begin Dumping OpaqueBin"); + dumpRM(rm); + System.err.println("===> End Dumping OpaqueBin"); + rm = tbin.transparentRMList; + System.err.println("===> Begin Dumping transparentBin"); + dumpRM(rm); + System.err.println("===> End Dumping transparentBin"); + tbin = tbin.next; + } + sbin = sbin.next; + } + abin = abin.next; + } + envSet = envSet.next; + } + obin = obin.next; + } + + } + + void dumpRM(RenderMolecule rm) { + while (rm != null) { + System.err.println(" rm = "+rm+" numRAs = "+rm.numRenderAtoms); + System.err.println(" primaryRenderAtomList = "+ + rm.primaryRenderAtomList); + RenderAtomListInfo rinfo = rm.primaryRenderAtomList; + while (rinfo != null) { + System.err.println(" rinfo = "+rinfo); + System.err.println(" rinfo.ra.localeVwcBounds = " + + rinfo.renderAtom.localeVwcBounds); + System.err.println(" rinfo.ra.ga.so.vwcBounds = " + + rinfo.renderAtom.geometryAtom.source.vwcBounds); + System.err.println(" geometry = "+rinfo.geometry()); + + rinfo = rinfo.next; + } + System.err.println(" separateDlistRenderAtomList = "+ + rm.separateDlistRenderAtomList); + rinfo = rm.separateDlistRenderAtomList; + while (rinfo != null) { + System.err.println(" rinfo = "+rinfo); + System.err.println(" rinfo.ra.localeVwcBounds = " + + rinfo.renderAtom.localeVwcBounds); + System.err.println(" rinfo.ra.ga.so.vwcBounds = " + + rinfo.renderAtom.geometryAtom.source.vwcBounds); + System.err.println(" geometry = "+rinfo.geometry()); + rinfo = rinfo.next; + } + System.err.println(" vertexArrayRenderAtomList = "+ + rm.vertexArrayRenderAtomList); + if (rm.next == null) { + rm= rm.nextMap; + } + else { + rm = rm.next; + } + } + } + + void removeTransparentObject (Object obj) { + // System.err.println("&&&&&&&&&&&&removeTransparentObject r = "+obj); + if (obj instanceof TextureBin) { + TextureBin tb = (TextureBin) obj; + if (tb.environmentSet.lightBin.geometryBackground != null) { + TransparentRenderingInfo t = tb.parentTInfo; + + // Remove the element from the transparentInfo struct + if (t == bgTransparentInfo) { + bgTransparentInfo = bgTransparentInfo.next; + if (bgTransparentInfo != null) + bgTransparentInfo.prev = null; + } + else { + t.prev.next = t.next; + if (t.next != null) + t.next.prev = t.prev; + } + t.prev = null; + t.next = null; + tb.parentTInfo = null; + } + else { + int index = allTransparentObjects.indexOf(obj); + if (index == -1) { + // System.err.println("==> DEBUG1: Should never come here!"); + return; + } + allTransparentObjects.remove(index); + + TransparentRenderingInfo t = tb.parentTInfo; + + // Remove the element from the transparentInfo struct + if (t == transparentInfo) { + transparentInfo = transparentInfo.next; + if (transparentInfo != null) + transparentInfo.prev = null; + } + else { + t.prev.next = t.next; + if (t.next != null) + t.next.prev = t.prev; + } + t.prev = null; + t.next = null; + tb.parentTInfo = null; + } + + } + else { + int index = allTransparentObjects.indexOf(obj); + if (index == -1) { + // System.err.println("==> DEBUG2: Should never come here!"); + return; + } + + allTransparentObjects.remove(index); + RenderAtom r = (RenderAtom)obj; + for (int i = 0; i < r.parentTInfo.length; i++) { + // Remove the element from the transparentInfo struct + TransparentRenderingInfo t = r.parentTInfo[i]; + // This corresponds to null geometry + if (t == null) + continue; + + // Remove the element from the transparentInfo struct + if (t == transparentInfo) { + transparentInfo = transparentInfo.next; + if (transparentInfo != null) + transparentInfo.prev = null; + } + else { + t.prev.next = t.next; + if (t.next != null) + t.next.prev = t.prev; + } + t.prev = null; + t.next = null; + nElements--; + r.parentTInfo[i] = null; + } + } + + } + + void updateTransparentInfo(RenderAtom r) { + // System.err.println("===> update transparent Info"); + for (int i = 0; i < r.parentTInfo.length; i++) { + + if (r.parentTInfo[i] == null) + continue; + /* + r.parentTInfo[i].lightBin = r.envSet.lightBin; + r.parentTInfo[i].envSet = r.envSet; + r.parentTInfo[i].aBin = r.renderMolecule.textureBin.attributeBin; + */ + r.parentTInfo[i].rm = r.renderMolecule; + } + } + + void addTransparentObject (Object obj) { + // System.err.println("&&&&&&&&&&&&addTransparentObject r = "+obj); + if (obj instanceof TextureBin) { + TextureBin tb = (TextureBin) obj; + // Background geometry + if (tb.environmentSet.lightBin.geometryBackground != null) { + bgTransparentInfo = computeDirtyAcrossTransparentBins(tb, bgTransparentInfo); + } + else { + allTransparentObjects.add(obj); + transparentInfo = computeDirtyAcrossTransparentBins(tb, transparentInfo); + } + } + else { + allTransparentObjects.add(obj); + RenderAtom r = (RenderAtom)obj; + if (r.parentTInfo == null) { + r.parentTInfo = new TransparentRenderingInfo[r.rListInfo.length]; + } + computeDirtyAcrossTransparentBins(r); + // System.err.println("update Centroid 2, ga = "+r.geometryAtom); + r.geometryAtom.updateCentroid(); + if (dirtyDepthSortRenderAtom.add(r)) { + numDirtyTinfo += r.rListInfo.length; + } + /* + else { + System.err.println("addTransparentObject: attempt to add RenderAtom already in dirty list"); + } + */ + r.dirtyMask |= RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST; + // System.err.println("transparentInfo ="+transparentInfo); + } + } + + TransparentRenderingInfo getTransparentInfo() { + return new TransparentRenderingInfo(); + } + + TransparentRenderingInfo computeDirtyAcrossTransparentBins(TextureBin tb, TransparentRenderingInfo startinfo) { + TransparentRenderingInfo tinfo = getTransparentInfo(); + /* + tinfo.lightBin = tb.environmentSet.lightBin; + tinfo.envSet = tb.environmentSet; + tinfo.aBin = tb.attributeBin; + */ + tinfo.rm = tb.transparentRMList; + tb.parentTInfo = tinfo; + if (startinfo == null) { + startinfo = tinfo; + tinfo.prev = null; + tinfo.next = null; + + } + else { + tinfo.next = startinfo; + startinfo.prev = tinfo; + startinfo = tinfo; + } + return startinfo; + } + void computeDirtyAcrossTransparentBins(RenderAtom r) { + + for (int i = 0; i < r.parentTInfo.length; i++) { + if (r.rListInfo[i].geometry() == null) { + r.parentTInfo[i] = null; + continue; + } + nElements++; + TransparentRenderingInfo tinfo = getTransparentInfo(); + /* + tinfo.lightBin = r.envSet.lightBin; + tinfo.envSet = r.envSet; + tinfo.aBin = r.renderMolecule.textureBin.attributeBin; + */ + tinfo.rm = r.renderMolecule; + tinfo.rInfo = r.rListInfo[i]; + r.parentTInfo[i] = tinfo; + if (transparentInfo == null) { + transparentInfo = tinfo; + tinfo.prev = null; + tinfo.next = null; + } + else { + tinfo.prev = null; + tinfo.next = transparentInfo; + transparentInfo.prev = tinfo; + transparentInfo = tinfo; + } + + } + + } + + void processRenderAtomTransparentInfo(RenderAtomListInfo rinfo, ArrayList newList) { + while (rinfo != null) { + // If either the renderAtom has never been in transparent mode + // or if it was previously in that mode and now going back + // to that mode + if (rinfo.renderAtom.parentTInfo == null) { + rinfo.renderAtom.parentTInfo = new TransparentRenderingInfo[rinfo.renderAtom.rListInfo.length]; + computeDirtyAcrossTransparentBins(rinfo.renderAtom); + rinfo.renderAtom.geometryAtom.updateCentroid(); + newList.add(rinfo.renderAtom); + } + else { + GeometryRetained geo = null; + int i = 0; + while (geo == null && i < rinfo.renderAtom.rListInfo.length) { + geo = rinfo.renderAtom.rListInfo[i].geometry(); + i++; + } + // If there is atleast one non-null geometry in this renderAtom + if (geo != null) { + if (rinfo.renderAtom.parentTInfo[i-1] == null) { + computeDirtyAcrossTransparentBins(rinfo.renderAtom); + rinfo.renderAtom.geometryAtom.updateCentroid(); + newList.add(rinfo.renderAtom); + } + } + } + rinfo = rinfo.next; + + } + } + + void convertTransparentRenderingStruct(int oldMode, int newMode) { + int i, size; + ArrayList newList = new ArrayList(5); + RenderAtomListInfo rinfo; + // Reset the transparentInfo; + transparentInfo = null; + if (oldMode == View.TRANSPARENCY_SORT_NONE && newMode == View.TRANSPARENCY_SORT_GEOMETRY) { + size = allTransparentObjects.size(); + + for (i = 0; i < size; i++) { + TextureBin tb = (TextureBin)allTransparentObjects.get(i); + tb.parentTInfo = null; + RenderMolecule r = tb.transparentRMList; + // For each renderMolecule + while (r != null) { + // If this was a dlist molecule, since we will be rendering + // as separate dlist per rinfo, destroy the display list + if ((r.primaryMoleculeType &RenderMolecule.DLIST_MOLECULE) != 0) { + // System.err.println("&&&&&&&&& changing from dlist to dlist_per_rinfo"); + addDisplayListResourceFreeList(r); + removeDirtyRenderMolecule(r); + + r.vwcBounds.set(null); + r.displayListId = 0; + r.displayListIdObj = null; + // Change the group type for all the rlistInfo in the primaryList + rinfo = r.primaryRenderAtomList; + while (rinfo != null) { + rinfo.groupType = RenderAtom.SEPARATE_DLIST_PER_RINFO; + if (rinfo.renderAtom.dlistIds == null) { + rinfo.renderAtom.dlistIds = new int[rinfo.renderAtom.rListInfo.length]; + + for (int k = 0; k < rinfo.renderAtom.dlistIds.length; k++) { + rinfo.renderAtom.dlistIds[k] = -1; + } + } + if (rinfo.renderAtom.dlistIds[rinfo.index] == -1) { + rinfo.renderAtom.dlistIds[rinfo.index] = VirtualUniverse.mc.getDisplayListId().intValue(); + addDlistPerRinfo.add(rinfo); + } + rinfo = rinfo.next; + } + r.primaryMoleculeType = RenderMolecule.SEPARATE_DLIST_PER_RINFO_MOLECULE; + } + // Get all the renderAtoms in the list + processRenderAtomTransparentInfo(r.primaryRenderAtomList, newList); + processRenderAtomTransparentInfo(r.vertexArrayRenderAtomList, newList); + processRenderAtomTransparentInfo(r.separateDlistRenderAtomList, newList); + if (r.next == null) { + r = r.nextMap; + } + else { + r = r.next; + } + } + } + allTransparentObjects = newList; + } + else if (oldMode == View.TRANSPARENCY_SORT_GEOMETRY && newMode == View.TRANSPARENCY_SORT_NONE) { + // System.err.println("oldMode = TRANSPARENCY_SORT_GEOMETRY, newMode = TRANSPARENCY_SORT_NONE"); + size = allTransparentObjects.size(); + for (i = 0; i < size; i++) { + RenderAtom r= (RenderAtom)allTransparentObjects.get(i); + r.dirtyMask &= ~RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST; + for (int j = 0; j < r.parentTInfo.length; j++) { + // Corresponds to null geometry + if (r.parentTInfo[j] == null) + continue; + + r.parentTInfo[j] = null; + } + if (r.renderMolecule.textureBin.parentTInfo == null) { + transparentInfo = computeDirtyAcrossTransparentBins(r.renderMolecule.textureBin, transparentInfo); + newList.add(r.renderMolecule.textureBin); + } + } + allTransparentObjects = newList; + dirtyDepthSortRenderAtom.clear(); + numDirtyTinfo = 0; + } + } + + TransparentRenderingInfo mergeDepthSort(TransparentRenderingInfo oldList, TransparentRenderingInfo newList) { + TransparentRenderingInfo input1 = oldList , input2 = newList, nextN; + TransparentRenderingInfo lastInput1 = oldList; + double zval1, zval2; + // System.err.println("&&&&&&&&mergeDepthSort"); + /* + TransparentRenderingInfo t = oldList; + System.err.println(""); + while (t != null) { + System.err.println("==> old t = "+t); + t = t.next; + } + System.err.println(""); + t = newList; + while (t != null) { + System.err.println("==> new t = "+t); + t = t.next; + } + */ + + while (input1 != null && input2 != null) { + lastInput1 = input1; + nextN = input2.next; + zval1 = input1.zVal; + zval2 = input2.zVal; + // Put the newList before the current one + +// System.err.print("Code path 1 "); +// if (transparencySortComparator!=null) +// if (zval2 > zval1 && (transparencySortComparator.compare(input2, input1)>0)) +// System.err.println("PASS"); +// else +// System.err.println("FAIL"); + + if ((transparencySortComparator==null && zval2 > zval1) || + (transparencySortComparator!=null && (transparencySortComparator.compare(input2, input1)>0))){ + // System.err.println("===> path1"); + if (input1.prev == null) { + input1.prev = input2; + input2.prev = null; + input2.next = oldList; + oldList = input2; + } + else { + // System.err.println("===> path2"); + input2.prev = input1.prev; + input1.prev.next = input2; + input2.next = input1; + input1.prev = input2; + } + input2 = nextN; + } + else { + // System.err.println("===> path3"); + input1 = input1.next; + } + } + if (input1 == null && input2 != null) { + // add at then end + if (lastInput1 == null) { + oldList = input2; + input2.prev = null; + } + else { + lastInput1.next = input2; + input2.prev = lastInput1; + } + } + return oldList; + } + +// void insertDepthSort(RenderAtom r) { +// TransparentRenderingInfo tinfo = null; +// // System.err.println("&&&&&&&&insertDepthSort"); +// for (int i = 0; i < r.rListInfo.length; i++) { +// if (r.parentTInfo[i] == null) +// continue; +// +// if (transparentInfo == null) { +// transparentInfo = r.parentTInfo[i]; +// transparentInfo.prev = null; +// transparentInfo.next = null; +// } +// else { +// tinfo = transparentInfo; +// TransparentRenderingInfo prevInfo = transparentInfo; +// if (transparencySortComparator==null) +// while (tinfo != null && r.parentTInfo[i].zVal < tinfo.zVal) { +// prevInfo = tinfo; +// tinfo = tinfo.next; +// } +// else { +// System.err.println("Code Path 2 "); +// if (tinfo!=null && (transparencySortComparator.compare(r.parentTInfo[i], tinfo)<0)==r.parentTInfo[i].zVal < tinfo.zVal) +// System.err.println("PASS"); +// else +// System.err.println("FAIL"); +// while (tinfo != null && transparencySortComparator.compare(r.parentTInfo[i], tinfo)<0) { +// prevInfo = tinfo; +// tinfo = tinfo.next; +// } +// } +// r.parentTInfo[i].prev = prevInfo; +// if (prevInfo.next != null) { +// prevInfo.next.prev = r.parentTInfo[i]; +// } +// r.parentTInfo[i].next = prevInfo.next; +// prevInfo.next = r.parentTInfo[i]; +// +// } +// +// } +// } + + TransparentRenderingInfo collectDirtyTRInfo( TransparentRenderingInfo dirtyList, + RenderAtom r) { + + for (int i = 0; i < r.rListInfo.length; i++) { + TransparentRenderingInfo t = r.parentTInfo[i]; + if (t == null) + continue; + if (t == transparentInfo) { + transparentInfo = transparentInfo.next; + if (transparentInfo != null) + transparentInfo.prev = null; + } + else { + if (t == dirtyList) { + // This means that the the item has already been + // added to the dirtyList and is at the head of + // the list; since we ensure no duplicate + // renderAtoms, this should never happen. If it + // does, don't try to add it again. + System.err.println("collectDirtyTRInfo: ERROR: t == dirtyList"); + continue; + } + + // assert(t.prev != null); + t.prev.next = t.next; + if (t.next != null) + t.next.prev = t.prev; + } + if (dirtyList == null) { + dirtyList = t; + t.prev = null; + t.next = null; + } else { + t.next = dirtyList; + t.prev = null; + dirtyList.prev = t; + dirtyList = t; + } + } + + return dirtyList; + } + + + TransparentRenderingInfo depthSortAll(TransparentRenderingInfo startinfo) { + transparencySortComparator = com.sun.j3d.utils.scenegraph.transparency.TransparencySortController.getComparator(view); + TransparentRenderingInfo tinfo, previnfo, nextinfo; + double curZ; + // System.err.println("&&&&&&&&&&&depthSortAll"); + // Do insertion sort + /* + tinfo = startinfo; + while (tinfo != null) { + System.err.println("Soreted tinfo= "+tinfo+" tinfo.prev = "+tinfo.prev+" tinfo.next = "+tinfo.next); + tinfo = tinfo.next; + } + */ + tinfo = startinfo.next; + while (tinfo != null) { + // System.err.println("====> Doing tinfo = "+tinfo); + nextinfo = tinfo.next; + curZ = tinfo.zVal; + previnfo = tinfo.prev; + // Find the correct location for tinfo + + if (transparencySortComparator==null) { + while (previnfo != null && previnfo.zVal < curZ) { + previnfo = previnfo.prev; + } + } else { +// System.err.println("Code Path 3 "); +// if (tinfo!=null && (transparencySortComparator.compare(previnfo, tinfo)<0)==previnfo.zVal < curZ) +// System.err.println("PASS"); +// else +// System.err.println("FAIL"); + while (previnfo != null && transparencySortComparator.compare(previnfo,tinfo)<0) { + previnfo = previnfo.prev; + } + } + + if (tinfo.prev != previnfo) { + if (previnfo == null) { + if (tinfo.next != null) { + tinfo.next.prev = tinfo.prev; + } + // tinfo.prev is not null + tinfo.prev.next = tinfo.next; + tinfo.next = startinfo; + startinfo.prev = tinfo; + startinfo = tinfo; + tinfo.prev = null; + } + else { + if (tinfo.next != null) { + tinfo.next.prev = tinfo.prev; + } + if (tinfo.prev != null) { + tinfo.prev.next = tinfo.next; + } + tinfo.next = previnfo.next; + if (previnfo.next != null) + previnfo.next.prev = tinfo; + tinfo.prev = previnfo; + previnfo.next = tinfo; + // System.err.println("path2, tinfo.prev = "+tinfo.prev); + // System.err.println("path2, tinfo.next = "+tinfo.next); + } + + } + /* + TransparentRenderingInfo tmp = startinfo; + while (tmp != null) { + System.err.println("Soreted tmp= "+tmp+" tmp.prev = "+tmp.prev+" tmp.next = "+tmp.next); + tmp = tmp.next; + } + */ + + tinfo = nextinfo; + + } + /* + tinfo = startinfo; + double prevZ = 0.0; + while (tinfo != null) { + tinfo.render = false; + curZ = ((double[])distMap.get(tinfo.rInfo.renderAtom))[tinfo.rInfo.index]; + nextinfo = tinfo.next; + if (nextinfo != null) { + double nextZ = ((double[])distMap.get(nextinfo.rInfo.renderAtom))[tinfo.rInfo.index]; + if (Math.abs(curZ - nextZ) < 1.0e-6 && curZ < 400) { + tinfo.render = true; + } + } + + if (Math.abs(curZ - prevZ) < 1.0e-6 && curZ < 400) { + tinfo.render = true; + } + + prevZ = curZ; + tinfo = tinfo.next; + + } + tinfo = startinfo; + while (tinfo != null) { + System.err.println("z = "+((double[])distMap.get(tinfo.rInfo.renderAtom))[tinfo.rInfo.index]+" ga = "+tinfo.rInfo.renderAtom.geometryAtom); + tinfo = tinfo.next; + } + System.err.println("\n\n"); + tinfo = startinfo; + while (tinfo != null) { + if (tinfo.render) { + System.err.println("same z = "+((double[])distMap.get(tinfo.rInfo.renderAtom))[tinfo.rInfo.index]+" ga = "+tinfo.rInfo.renderAtom.geometryAtom); + GeometryAtom ga = tinfo.rInfo.renderAtom.geometryAtom; + System.err.println("ga.geometryArray.length = "+ga.geometryArray.length); + for (int k = 0; k < ga.geometryArray.length; k++) { + System.err.println("geometry "+k+" = "+ga.geometryArray[k]); + if (ga.geometryArray[k] != null) { + System.err.println(" vcount = "+((GeometryArrayRetained)ga.geometryArray[k]).getVertexCount()); + ((GeometryArrayRetained)ga.geometryArray[k]).printCoordinates(); + } + } + } + tinfo = tinfo.next; + } + */ + return startinfo; + } + + void processViewSpecificGroupChanged(J3dMessage m) { + int component = ((Integer)m.args[0]).intValue(); + Object[] objAry = (Object[])m.args[1]; + if (((component & ViewSpecificGroupRetained.ADD_VIEW) != 0) || + ((component & ViewSpecificGroupRetained.SET_VIEW) != 0)) { + int i; + Object obj; + View v = (View)objAry[0]; + ArrayList leafList = (ArrayList)objAry[2]; + // View being added is this view + if (v == view) { + int size = leafList.size(); + for (i = 0; i < size; i++) { + obj = leafList.get(i); + if (obj instanceof LightRetained) { + envDirty |= REEVALUATE_LIGHTS; + if (!changedLts.contains(obj)) + changedLts.add(obj); + } + else if (obj instanceof FogRetained) { + envDirty |= REEVALUATE_FOG; + if (!changedFogs.contains(obj)) + changedFogs.add(obj); + } + else if (obj instanceof AlternateAppearanceRetained) { + altAppearanceDirty = true; + + } + else if (obj instanceof ModelClipRetained) { + envDirty |= REEVALUATE_MCLIP; + if (!changedModelClips.contains(obj)) + changedModelClips.add(obj); + } + else if (obj instanceof BackgroundRetained) { + reEvaluateBg = true; + } + + else if (obj instanceof ClipRetained) { + reEvaluateClip = true; + + } else if (obj instanceof GeometryAtom) { + visGAIsDirty = true; + visQuery = true; + } + } + + } + + } + if (((component & ViewSpecificGroupRetained.REMOVE_VIEW) != 0)|| + ((component & ViewSpecificGroupRetained.SET_VIEW) != 0)) { + int i; + Object obj; + ArrayList leafList; + View v; + + if ((component & ViewSpecificGroupRetained.REMOVE_VIEW) != 0) { + v = (View)objAry[0]; + leafList = (ArrayList)objAry[2]; + } + else { + v = (View)objAry[4]; + leafList = (ArrayList)objAry[6]; + } + if (v == view) { + int size = leafList.size(); + for (i = 0; i < size; i++) { + obj = leafList.get(i); + if (obj instanceof GeometryAtom) { + RenderAtom ra = ((GeometryAtom)obj).getRenderAtom(view); + if (ra != null && ra.inRenderBin()) { + renderAtoms.remove(renderAtoms.indexOf(ra)); + removeARenderAtom(ra); + } + } + else if (obj instanceof LightRetained) { + envDirty |= REEVALUATE_LIGHTS; + } + else if (obj instanceof FogRetained) { + envDirty |= REEVALUATE_FOG; + } + else if (obj instanceof AlternateAppearanceRetained) { + altAppearanceDirty = true; + + } + else if (obj instanceof ModelClipRetained) { + envDirty |= REEVALUATE_MCLIP; + + } + else if (obj instanceof BackgroundRetained) { + reEvaluateBg = true; + } + + else if (obj instanceof ClipRetained) { + reEvaluateClip = true; + + } + } + } + } + + } + + void insertNodes(J3dMessage m) { + Object nodes[]; + ArrayList viewScopedNodes = (ArrayList)m.args[3]; + ArrayList scopedNodesViewList = (ArrayList)m.args[4]; + int i, j; + Object n; + nodes = (Object[])m.args[0]; + for (j = 0; j < nodes.length; j++) { + if (nodes[j] instanceof LightRetained) { + envDirty |= REEVALUATE_LIGHTS; + if (!changedLts.contains(nodes[j])) + changedLts.add(nodes[j]); + } else if (nodes[j] instanceof FogRetained) { + envDirty |= REEVALUATE_FOG; + if (!changedFogs.contains(nodes[j])) + changedFogs.add(nodes[j]); + } else if (nodes[j] instanceof BackgroundRetained) { + // If a new background is inserted, then + // re_evaluate to determine if this background + // should be used + reEvaluateBg = true; + } else if (nodes[j] instanceof ClipRetained) { + reEvaluateClip = true; + } else if (nodes[j] instanceof ModelClipRetained) { + envDirty |= REEVALUATE_MCLIP; + if (!changedModelClips.contains(nodes[j])) + changedModelClips.add(nodes[j]); + } else if (nodes[j] instanceof GeometryAtom) { + visGAIsDirty = true; + visQuery = true; + } else if (nodes[j] instanceof AlternateAppearanceRetained) { + altAppearanceDirty = true; + } + } + + // Handle ViewScoped Nodes + if (viewScopedNodes != null) { + int size = viewScopedNodes.size(); + int vlsize; + for (i = 0; i < size; i++) { + n = (NodeRetained)viewScopedNodes.get(i); + ArrayList vl = (ArrayList) scopedNodesViewList.get(i); + // If the node object is scoped to this view, then .. + if (vl.contains(view)) { + if (n instanceof LightRetained) { + envDirty |= REEVALUATE_LIGHTS; + if (!changedLts.contains(n)) + changedLts.add(n); + } else if (n instanceof FogRetained) { + envDirty |= REEVALUATE_FOG; + if (!changedFogs.contains(n)) + changedFogs.add(n); + } else if (n instanceof BackgroundRetained) { + // If a new background is inserted, then + // re_evaluate to determine if this backgrouns + // should be used + reEvaluateBg = true; + } else if (n instanceof ClipRetained) { + reEvaluateClip = true; + } else if (n instanceof ModelClipRetained) { + envDirty |= REEVALUATE_MCLIP; + if (!changedModelClips.contains(n)) + changedModelClips.add(n); + } else if (n instanceof AlternateAppearanceRetained) { + altAppearanceDirty = true; + } + } + // Note: geometryAtom is not part of viewScopedNodes + // Its a part of orginal nodes even if scoped + + } + } + } + + + void removeNodes(J3dMessage m) { + Object[] nodes; + ArrayList viewScopedNodes = (ArrayList)m.args[3]; + ArrayList scopedNodesViewList = (ArrayList)m.args[4]; + int i, j; + nodes = (Object[])m.args[0]; + for (int n = 0; n < nodes.length; n++) { + if (nodes[n] instanceof GeometryAtom) { + visGAIsDirty = true; + visQuery = true; + RenderAtom ra = + ((GeometryAtom)nodes[n]).getRenderAtom(view); + if (ra != null && ra.inRenderBin()) { + renderAtoms.remove(renderAtoms.indexOf(ra)); + removeARenderAtom(ra); + } + + // This code segment is to handle the texture resource cleanup + // for Raster object. + GeometryAtom geomAtom = (GeometryAtom) nodes[n]; + if(geomAtom.geometryArray != null) { + for(int ii=0; ii 0) { + RenderMolecule[] rmArr = (RenderMolecule[]) + renderMoleculeList.toArray(false); + + for (i = 0 ; i < size; i++) { + rmArr[i].releaseAllPrimaryDisplayListResources(cv, ctx); + } + } + + size = sharedDList.size(); + if (size > 0) { + RenderAtomListInfo arr[] = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) sharedDList.toArray(arr); + + GeometryArrayRetained geo; + int mask = (cv.useSharedCtx ? rdr.rendererBit : cv.canvasBit); + + for (i = 0; i < size; i++) { + geo = (GeometryArrayRetained)arr[i].geometry(); + // Fix for Issue 5: free all native display lists and clear the + // context creation bits for this canvas, but don't do anything + // with the geo's user list. + if (geo.dlistId > 0) { + // XXXX: for the shared ctx case, we really should + // only free the display lists if this is the last + // Canvas in the renderer. However, since the + // display lists will be recreated, it doesn't + // really matter. + cv.freeDisplayList(ctx, geo.dlistId); + geo.resourceCreationMask &= ~mask; + } + } + } + } + + + // put displayListID back to MC + void releaseAllDisplayListID() { + int i; + int size = renderMoleculeList.size(); + + if (size > 0) { + RenderMolecule[] rmArr = (RenderMolecule[]) + renderMoleculeList.toArray(false); + + for (i = 0 ; i < size; i++) { + rmArr[i].releaseAllPrimaryDisplayListID(); + } + } + + size = sharedDList.size(); + if (size > 0) { + RenderAtomListInfo arr[] = new RenderAtomListInfo[size]; + arr = (RenderAtomListInfo []) sharedDList.toArray(arr); + GeometryArrayRetained geo; + + for (i = 0; i < size; i++) { + geo = (GeometryArrayRetained)arr[i].geometry(); + if (geo.resourceCreationMask == 0) { + geo.freeDlistId(); + } + } + } + } + + + /* + void handleFrequencyBitChanged(J3dMessage m) { + NodeComponentRetained nc = (NodeComponentRetained)m.args[0]; + GeometryAtom[] gaArr = (GeometryAtom[])m.args[3]; + int i; + RenderAtom ra; + Boolean value = (Boolean)m.args[1]; + int mask = ((Integer)m.args[2]).intValue(); + + // Currently, we do not handle the case of + // going from frequent to infrequent + if (value == Boolean.FALSE) + return; + + ra = null; + // Get the first ra that is visible + for (i = 0; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + } + + if (ra == null) + return; + + int start = i; + // Check if the removed renderAtom is already in + // a separate bin - this is to handle the case + // when it has been changed to frequent, then to + // infrequent and then to frequent again! + if ((nc instanceof MaterialRetained && ra.renderMolecule.definingMaterial != ra.renderMolecule.material) || + (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.MATERIAL) == 0))) { + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + TextureBin tb = ra.renderMolecule.textureBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertRenderAtom(tb, ra); + } + } + else if ((nc instanceof PolygonAttributesRetained && ra.renderMolecule.definingPolygonAttributes != ra.renderMolecule.polygonAttributes) || + (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.POLYGON) == 0))) { + // Check if the removed renderAtom is already in + // a separate bin - this is to handle the case + // when it has been changed to frequent, then to + // infrequent and then to frequent again! + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + TextureBin tb = ra.renderMolecule.textureBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertRenderAtom(tb, ra); + } + } + else if ((nc instanceof PointAttributesRetained && ra.renderMolecule.definingPointAttributes != ra.renderMolecule.pointAttributes) || + (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.POINT) == 0))) { + // Check if the removed renderAtom is already in + // a separate bin - this is to handle the case + // when it has been changed to frequent, then to + // infrequent and then to frequent again! + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + TextureBin tb = ra.renderMolecule.textureBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertRenderAtom(tb, ra); + } + } + else if ((nc instanceof LineAttributesRetained && ra.renderMolecule.definingLineAttributes != ra.renderMolecule.lineAttributes) || + (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.LINE) == 0))) { + // Check if the removed renderAtom is already in + // a separate bin - this is to handle the case + // when it has been changed to frequent, then to + // infrequent and then to frequent again! + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + TextureBin tb = ra.renderMolecule.textureBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertRenderAtom(tb, ra); + } + } + else if((nc instanceof TransparencyAttributesRetained&& ra.renderMolecule.definingTransparency != ra.renderMolecule.transparency) || + (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.TRANSPARENCY) == 0))) { + // Check if the removed renderAtom is already in + // a separate bin - this is to handle the case + // when it has been changed to frequent, then to + // infrequent and then to frequent again! + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + TextureBin tb = ra.renderMolecule.textureBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertRenderAtom(tb, ra); + } + } + else if ((nc instanceof ColoringAttributesRetained&& ra.renderMolecule.definingColoringAttributes != ra.renderMolecule.coloringAttributes) || + (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.COLOR) == 0))) { + // Check if the removed renderAtom is already in + // a separate bin - this is to handle the case + // when it has been changed to frequent, then to + // infrequent and then to frequent again! + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + TextureBin tb = ra.renderMolecule.textureBin; + ra.renderMolecule.removeRenderAtom(ra); + reInsertRenderAtom(tb, ra); + } + } + else if ((nc instanceof RenderingAttributesRetained && ra.renderMolecule.textureBin.attributeBin.definingRenderingAttributes != ra.renderMolecule.textureBin.attributeBin.renderingAttrs) || + (nc instanceof AppearanceRetained && ((ra.renderMolecule.textureBin.attributeBin.soleUser & AppearanceRetained.RENDER) == 0))) { + for (i = start; i < gaArr.length; i++) { + ra = gaArr[i].getRenderAtom(view); + if (ra== null || !ra.inRenderBin()) + continue; + + EnvironmentSet e= ra.renderMolecule.textureBin.environmentSet; + ra.renderMolecule.removeRenderAtom(ra); + reInsertAttributeBin(e, ra); + } + } + else { + + // XXXX: handle texture + } + + + } + */ + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderMethod.java b/j3d-core/src/classes/share/javax/media/j3d/RenderMethod.java new file mode 100644 index 0000000..e08e9bd --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderMethod.java @@ -0,0 +1,46 @@ +/* + * $RCSfile: RenderMethod.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The RenderMethod interface is used to create various ways to render + * different geometries. + */ + +interface RenderMethod { + + /** + * The actual rendering code for this RenderMethod + */ + abstract boolean render(RenderMolecule rm, Canvas3D cv, + RenderAtomListInfo ra, int dirtyBits); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderMolecule.java b/j3d-core/src/classes/share/javax/media/j3d/RenderMolecule.java new file mode 100644 index 0000000..b298503 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderMolecule.java @@ -0,0 +1,3097 @@ +/* + * $RCSfile: RenderMolecule.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.*; + +/** + * The RenderMolecule manages a collection of RenderAtoms. + */ + +class RenderMolecule extends IndexedObject implements ObjectUpdate, NodeComponentUpdate { + + + // different types of IndexedUnorderedSet that store RenderMolecule + static final int REMOVE_RENDER_ATOM_IN_RM_LIST = 0; + static final int RENDER_MOLECULE_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + /** + * Values for the geometryType field + */ + static final int POINT = 0x01; + static final int LINE = 0x02; + static final int SURFACE = 0x04; + static final int RASTER = 0x08; + static final int COMPRESSED = 0x10; + + static int RM_COMPONENTS = (AppearanceRetained.POLYGON | + AppearanceRetained.LINE | + AppearanceRetained.POINT | + AppearanceRetained.MATERIAL | + AppearanceRetained.TRANSPARENCY| + AppearanceRetained.COLOR); + + // XXXX: use definingMaterial etc. instead of these + // when sole user is completely implement + PolygonAttributesRetained polygonAttributes = null; + LineAttributesRetained lineAttributes = null; + PointAttributesRetained pointAttributes = null; + MaterialRetained material = null; + ColoringAttributesRetained coloringAttributes = null; + TransparencyAttributesRetained transparency = null; + + // Use Object instead of AppearanceRetained class for + // state caching optimation memory performance + + boolean normalPresent = true; + + + // Equivalent bits + static final int POINTATTRS_DIRTY = AppearanceRetained.POINT; + static final int LINEATTRS_DIRTY = AppearanceRetained.LINE; + static final int POLYGONATTRS_DIRTY = AppearanceRetained.POLYGON; + static final int MATERIAL_DIRTY = AppearanceRetained.MATERIAL; + static final int TRANSPARENCY_DIRTY = AppearanceRetained.TRANSPARENCY; + static final int COLORINGATTRS_DIRTY = AppearanceRetained.COLOR; + + static final int ALL_DIRTY_BITS = POINTATTRS_DIRTY | LINEATTRS_DIRTY | POLYGONATTRS_DIRTY | MATERIAL_DIRTY | TRANSPARENCY_DIRTY | COLORINGATTRS_DIRTY; + + /** + * bit mask of all attr fields that are equivalent across + * renderMolecules + */ + int dirtyAttrsAcrossRms = ALL_DIRTY_BITS; + + + // Mask set to true is any of the component have changed + int soleUserCompDirty = 0; + + /** + * The PolygonAttributes for this RenderMolecule + */ + PolygonAttributesRetained definingPolygonAttributes = null; + + /** + * The LineAttributes for this RenderMolecule + */ + LineAttributesRetained definingLineAttributes = null; + + /** + * The PointAttributes for this RenderMolecule + */ + PointAttributesRetained definingPointAttributes = null; + + /** + * The TextureBin that this RenderMolecule resides + */ + TextureBin textureBin = null; + + /** + * The localToVworld for this RenderMolecule + */ + Transform3D[] localToVworld = null; + int[] localToVworldIndex = null; + + /** + * The Material reference for this RenderMolecule + */ + MaterialRetained definingMaterial = null; + + + /** + * The ColoringAttribute reference for this RenderMolecule + */ + ColoringAttributesRetained definingColoringAttributes = null; + + + /** + * The Transparency reference for this RenderMolecule + */ + TransparencyAttributesRetained definingTransparency = null; + + /** + * Transform3D - point to the right one based on bg or not + */ + Transform3D[] trans = null; + + + /** + * specify whether scale is nonuniform + */ + boolean isNonUniformScale = false; + + /** + * number of renderAtoms to be rendered in this RenderMolecule + */ + int numRenderAtoms = 0; + + /** + * number of render atoms, used during the renderBin update time + */ + int numEditingRenderAtoms = 0; + + RenderAtom addRAs = null; + RenderAtom removeRAs = null; + + /** + * The cached ColoringAttributes color value. It is + * 1.0, 1.0, 1.0 if there is no ColoringAttributes. + */ + float red = 1.0f; + float green = 1.0f; + float blue = 1.0f; + + + /** + * Cached diffuse color value + */ + float dRed = 1.0f; + float dGreen = 1.0f; + float dBlue = 1.0f; + + + + /** + * The cached TransparencyAttributes transparency value. It is + * 0.0 if there is no TransparencyAttributes. + */ + float alpha = 0.0f; + + /** + * The geometry type for this RenderMolecule + */ + int geometryType = -1; + + /** + * A boolean indicating whether or not lighting should be on. + */ + boolean enableLighting = false; + + /** + * A boolean indicating whether or not this molecule rendered Text3D + */ + + int primaryMoleculeType = 0; + static int COMPRESSED_MOLECULE = 0x1; + static int TEXT3D_MOLECULE = 0x2; + static int DLIST_MOLECULE = 0x4; + static int RASTER_MOLECULE = 0x8; + static int ORIENTEDSHAPE3D_MOLECULE = 0x10; + static int SEPARATE_DLIST_PER_RINFO_MOLECULE = 0x20; + + + /** + * Cached values for polygonMode, line antialiasing, and point antialiasing + */ + int polygonMode = PolygonAttributes.POLYGON_FILL; + boolean lineAA = false; + boolean pointAA = false; + + /** + * The vertex format for this RenderMolecule. Only looked + * at for GeometryArray and CompressedGeometry objects. + */ + int vertexFormat = -1; + + /** + * The texCoordSetMap length for this RenderMolecule. + */ + int texCoordSetMapLen = 0; + + /** + * The primary renderMethod object for this RenderMolecule + * this is either a Text3D, display list, or compressed geometry renderer. + */ + RenderMethod primaryRenderMethod = null; + + /** + * The secondary renderMethod object for this RenderMolecule + * this is used for geometry that is shared + */ + RenderMethod secondaryRenderMethod = null; + + /** + * The RenderBino for this molecule + */ + RenderBin renderBin = null; + + /** + * The references to the next and previous RenderMolecule in the + * list. + */ + RenderMolecule next = null; + RenderMolecule prev = null; + + + /** + * The list of RenderAtoms in this RenderMolecule that are not using + * vertex arrays. + */ + RenderAtomListInfo primaryRenderAtomList = null; + + + /** + * The list of RenderAtoms in this RenderMolecule that are using + * separte dlist . + */ + RenderAtomListInfo separateDlistRenderAtomList = null; + + + /** + * The list of RenderAtoms in this RenderMolecule that are using vertex + * arrays. + */ + RenderAtomListInfo vertexArrayRenderAtomList = null; + + /** + * This BoundingBox is used for View Frustum culling on the primary + * list + */ + BoundingBox vwcBounds = null; + + + /** + * If this is end of the linked list for this xform, then + * this field is non-null, if there is a map after this + */ + RenderMolecule nextMap = null; + RenderMolecule prevMap = null; + + /** + * If the any of the node component of the appearance in RM will be changed + * frequently, then confine it to a separate bin + */ + boolean soleUser = false; + Object appHandle = null; + + + VertexArrayRenderMethod cachedVertexArrayRenderMethod = + (VertexArrayRenderMethod) + VirtualUniverse.mc.getVertexArrayRenderMethod(); + + // In D3D separate Quad/Triangle Geometry with others in RenderMolecule + // Since we need to dynamically switch whether to use DisplayList + // or not in render() as a group. + boolean isQuadGeometryArray = false; + boolean isTriGeometryArray = false; + + // display list id, valid id starts from 1 + int displayListId = 0; + Integer displayListIdObj = null; + + int onUpdateList = 0; + static int NEW_RENDERATOMS_UPDATE = 0x1; + static int BOUNDS_RECOMPUTE_UPDATE = 0x2; + static int LOCALE_TRANSLATION = 0x4; + static int UPDATE_BACKGROUND_TRANSFORM = 0x8; + static int IN_DIRTY_RENDERMOLECULE_LIST = 0x10; + static int LOCALE_CHANGED = 0x20; + static int ON_UPDATE_CHECK_LIST = 0x40; + + + // background geometry rendering + boolean doInfinite; + Transform3D[] infLocalToVworld; + + // Whether alpha is used in this renderMolecule + boolean useAlpha = false; + + // Support for multiple locales + Locale locale = null; + + // Transform when locale is different from the view's locale + Transform3D[] localeLocalToVworld = null; + + // Vector used for locale translation + Vector3d localeTranslation = null; + + boolean primaryChanged = false; + + boolean isOpaqueOrInOG = true; + boolean inOrderedGroup = false; + + + // closest switch parent + SwitchRetained closestSwitchParent = null; + + // the child index from the closest switch parent + int closestSwitchIndex = -1; + + + RenderMolecule(GeometryAtom ga, + PolygonAttributesRetained polygonAttributes, + LineAttributesRetained lineAttributes, + PointAttributesRetained pointAttributes, + MaterialRetained material, + ColoringAttributesRetained coloringAttributes, + TransparencyAttributesRetained transparency, + RenderingAttributesRetained renderAttrs, + TextureUnitStateRetained[] texUnits, + Transform3D[] transform, int[] transformIndex, + RenderBin rb) { + renderBin = rb; + IndexedUnorderSet.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + + reset(ga, polygonAttributes, lineAttributes, pointAttributes, + material, coloringAttributes, transparency, renderAttrs, + texUnits, transform, + transformIndex); + } + + void reset(GeometryAtom ga, + PolygonAttributesRetained polygonAttributes, + LineAttributesRetained lineAttributes, + PointAttributesRetained pointAttributes, + MaterialRetained material, + ColoringAttributesRetained coloringAttributes, + TransparencyAttributesRetained transparency, + RenderingAttributesRetained renderAttrs, + TextureUnitStateRetained[] texUnits, + Transform3D[] transform, int[] transformIndex) { + primaryMoleculeType = 0; + numRenderAtoms = 0; + numEditingRenderAtoms = 0; + onUpdateList = 0; + dirtyAttrsAcrossRms = ALL_DIRTY_BITS; + primaryRenderMethod = null; + isNonUniformScale = false; + primaryChanged = false; + this.material = material; + this.polygonAttributes = polygonAttributes; + this.lineAttributes = lineAttributes; + this.pointAttributes = pointAttributes; + this.coloringAttributes = coloringAttributes; + this.transparency = transparency; + + closestSwitchParent = ga.source.closestSwitchParent; + closestSwitchIndex = ga.source.closestSwitchIndex; + + int i1; + // Find the first non-null geometey + GeometryRetained geo = null; + int k = 0; + isOpaqueOrInOG = true; + inOrderedGroup = false; + while (geo == null && (k < ga.geometryArray.length)) { + geo = ga.geometryArray[k]; + k++; + } + + // Issue 249 - check for sole user only if property is set + soleUser = false; + if (VirtualUniverse.mc.allowSoleUser) { + if (ga.source.appearance != null) { + soleUser = ((ga.source.appearance.changedFrequent & RM_COMPONENTS) != 0); + } + } + + // Set the appearance only for soleUser case + if (soleUser) + appHandle = ga.source.appearance; + else + appHandle = (Object)this; + + // If its of type GeometryArrayRetained + if (ga.geoType <= GeometryRetained.GEO_TYPE_GEOMETRYARRAY || + ga.geoType == GeometryRetained.GEO_TYPE_TEXT3D) { + + if (ga.source instanceof OrientedShape3DRetained) { + primaryRenderMethod = + VirtualUniverse.mc.getOrientedShape3DRenderMethod(); + primaryMoleculeType = ORIENTEDSHAPE3D_MOLECULE; + } else if (ga.geoType == GeometryRetained.GEO_TYPE_TEXT3D) { + primaryRenderMethod = + VirtualUniverse.mc.getText3DRenderMethod(); + primaryMoleculeType = TEXT3D_MOLECULE; + } else { + // Make determination of dlist or not during addRenderAtom + secondaryRenderMethod = cachedVertexArrayRenderMethod; + } + } + else { + if (ga.geoType == GeometryRetained.GEO_TYPE_COMPRESSED) { + primaryRenderMethod = + VirtualUniverse.mc.getCompressedGeometryRenderMethod(); + primaryMoleculeType = COMPRESSED_MOLECULE; + } + else if (geo instanceof RasterRetained) { + primaryRenderMethod = + VirtualUniverse.mc.getDefaultRenderMethod(); + primaryMoleculeType = RASTER_MOLECULE; + } + } + + prev = null; + next = null; + prevMap = null; + nextMap = null; + + primaryRenderAtomList = null; + vertexArrayRenderAtomList = null; + + + + switch (ga.geoType) { + case GeometryRetained.GEO_TYPE_POINT_SET: + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: + this.geometryType = POINT; + break; + case GeometryRetained.GEO_TYPE_LINE_SET: + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET: + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + this.geometryType = LINE; + break; + case GeometryRetained.GEO_TYPE_RASTER: + this.geometryType = RASTER; + break; + case GeometryRetained.GEO_TYPE_COMPRESSED: + this.geometryType = COMPRESSED; + + switch (((CompressedGeometryRetained)geo).getBufferType()) { + case CompressedGeometryHeader.POINT_BUFFER: + this.geometryType |= POINT ; + break ; + case CompressedGeometryHeader.LINE_BUFFER: + this.geometryType |= LINE ; + break ; + default: + case CompressedGeometryHeader.TRIANGLE_BUFFER: + this.geometryType |= SURFACE ; + if (polygonAttributes != null) { + if (polygonAttributes.polygonMode == + PolygonAttributes.POLYGON_POINT) { + this.geometryType |= POINT; + } else if (polygonAttributes.polygonMode == + PolygonAttributes.POLYGON_LINE) { + this.geometryType |= LINE; + } + } + break ; + } + break; + default: + this.geometryType = SURFACE; + if (polygonAttributes != null) { + if (polygonAttributes.polygonMode == + PolygonAttributes.POLYGON_POINT) { + this.geometryType |= POINT; + } else if (polygonAttributes.polygonMode == + PolygonAttributes.POLYGON_LINE) { + this.geometryType |= LINE; + } + } + break; + } + + isQuadGeometryArray = (geo.getClassType() == + GeometryRetained.QUAD_TYPE); + isTriGeometryArray = (geo.getClassType() == + GeometryRetained.TRIANGLE_TYPE); + + this.localToVworld = transform; + this.localToVworldIndex = transformIndex; + doInfinite = ga.source.inBackgroundGroup; + if (doInfinite) { + if (infLocalToVworld == null) { + infLocalToVworld = new Transform3D[2]; + infLocalToVworld[0] = infLocalToVworld[1] = new Transform3D(); + } + localToVworld[0].getRotation(infLocalToVworld[0]); + } + int mask = 0; + if (polygonAttributes != null) { + if (polygonAttributes.changedFrequent != 0) { + definingPolygonAttributes = polygonAttributes; + + mask |= POLYGONATTRS_DIRTY; + } + else { + if (definingPolygonAttributes != null) { + definingPolygonAttributes.set(polygonAttributes); + } + else { + definingPolygonAttributes = (PolygonAttributesRetained)polygonAttributes.clone(); + } + } + polygonMode = definingPolygonAttributes.polygonMode; + } else { + polygonMode = PolygonAttributes.POLYGON_FILL; + definingPolygonAttributes = null; + } + + if (lineAttributes != null) { + if (lineAttributes.changedFrequent != 0) { + definingLineAttributes = lineAttributes; + mask |= LINEATTRS_DIRTY; + } + else { + if (definingLineAttributes != null) { + definingLineAttributes.set(lineAttributes); + } + else { + definingLineAttributes = (LineAttributesRetained)lineAttributes.clone(); + } + } + lineAA = definingLineAttributes.lineAntialiasing; + } else { + lineAA = false; + definingLineAttributes = null; + } + + if (pointAttributes != null) { + if (pointAttributes.changedFrequent != 0) { + definingPointAttributes = pointAttributes; + mask |= POINTATTRS_DIRTY; + + } + else { + if (definingPointAttributes != null) { + definingPointAttributes.set(pointAttributes); + } + else { + definingPointAttributes = (PointAttributesRetained)pointAttributes.clone(); + } + } + pointAA = definingPointAttributes.pointAntialiasing; + } else { + pointAA = false; + definingPointAttributes = null; + } + + normalPresent = true; + if (geo instanceof GeometryArrayRetained) { + GeometryArrayRetained gr = (GeometryArrayRetained)geo; + this.vertexFormat = gr.vertexFormat; + + if (gr.texCoordSetMap != null) { + this.texCoordSetMapLen = gr.texCoordSetMap.length; + } else { + this.texCoordSetMapLen = 0; + } + + // Throw an exception if lighting is enabled, but no normals defined + if ((vertexFormat & GeometryArray.NORMALS) == 0) { + // Force lighting to false + normalPresent = false; + } + + } + else if (geo instanceof CompressedGeometryRetained) { + this.vertexFormat = + ((CompressedGeometryRetained)geo).getVertexFormat(); + // Throw an exception if lighting is enabled, but no normals defined + if ((vertexFormat & GeometryArray.NORMALS) == 0) { + // Force lighting to false + normalPresent = false; + } + + this.texCoordSetMapLen = 0; + + } else { + this.vertexFormat = -1; + this.texCoordSetMapLen = 0; + } + + if (material != null) { + if (material.changedFrequent != 0) { + definingMaterial = material; + mask |= MATERIAL_DIRTY; + } + else { + if (definingMaterial != null) + definingMaterial.set(material); + else { + definingMaterial = (MaterialRetained)material.clone(); + } + } + + } + else { + definingMaterial = null; + } + evalMaterialCachedState(); + if (coloringAttributes != null) { + if (coloringAttributes.changedFrequent != 0) { + definingColoringAttributes = coloringAttributes; + mask |= COLORINGATTRS_DIRTY; + } + else { + if (definingColoringAttributes != null) { + definingColoringAttributes.set(coloringAttributes); + } + else { + definingColoringAttributes = (ColoringAttributesRetained)coloringAttributes.clone(); + } + } + red = coloringAttributes.color.x; + green = coloringAttributes.color.y; + blue = coloringAttributes.color.z; + } else { + red = 1.0f; + green = 1.0f; + blue = 1.0f; + definingColoringAttributes = null; + } + + if (transparency != null) { + + if (transparency.changedFrequent != 0) { + definingTransparency = transparency; + mask |= TRANSPARENCY_DIRTY; + } + else { + if (definingTransparency != null) { + definingTransparency.set(transparency); + } + else { + definingTransparency = + (TransparencyAttributesRetained)transparency.clone(); + } + } + alpha = 1.0f - transparency.transparency; + + } else { + alpha = 1.0f; + definingTransparency = null; + + } + + locale = ga.source.locale; + if (locale != renderBin.locale) { + if (localeLocalToVworld == null) { + localeLocalToVworld = new Transform3D[2]; + } + localeLocalToVworld[0] = new Transform3D(); + localeLocalToVworld[1] = new Transform3D(); + localeTranslation = new Vector3d(); + ga.locale.hiRes.difference(renderBin.locale.hiRes, localeTranslation); + translate(); + } + else { + localeLocalToVworld = localToVworld; + } + + if (doInfinite) { + trans = infLocalToVworld; + } + else { + trans = localeLocalToVworld; + } + + evalAlphaUsage(renderAttrs, texUnits); + isOpaqueOrInOG = isOpaque() || (ga.source.orderedPath != null); + inOrderedGroup = (ga.source.orderedPath != null); + // System.err.println("isOpaque = "+isOpaque() +" OrInOG = "+isOpaqueOrInOG); + if (mask != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= mask; + } + } + + + /** + * This tests if the given attributes matches this TextureBin + */ + boolean equals(RenderAtom ra, + PolygonAttributesRetained polygonAttributes, + LineAttributesRetained lineAttributes, + PointAttributesRetained pointAttributes, + MaterialRetained material, + ColoringAttributesRetained coloringAttributes, + TransparencyAttributesRetained transparency, + Transform3D[] transform) { + int geoType = 0; + GeometryAtom ga = ra.geometryAtom; + int eAttrs = 0; + + if (this.localToVworld != transform) { + return (false); + } + + if (locale != ra.geometryAtom.source.locale) { + return (false); + } + + if (ra.geometryAtom.source.closestSwitchParent != closestSwitchParent || + ra.geometryAtom.source.closestSwitchIndex != closestSwitchIndex) { + return (false); + } + + // Find the first non-null geometey + GeometryRetained geo = null; + int k = 0; + while (geo == null && (k < ga.geometryArray.length)) { + geo = ga.geometryArray[k]; + k++; + } + + // XXXX: Add tags + switch (ga.geoType) { + case GeometryRetained.GEO_TYPE_POINT_SET: + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: + geoType = POINT; + break; + case GeometryRetained.GEO_TYPE_LINE_SET: + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET: + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + geoType = LINE; + break; + case GeometryRetained.GEO_TYPE_RASTER: + geoType = RASTER; + break; + case GeometryRetained.GEO_TYPE_COMPRESSED: + geoType = COMPRESSED; + switch (((CompressedGeometryRetained)geo).getBufferType()) { + case CompressedGeometryHeader.POINT_BUFFER: + geoType |= POINT ; + break ; + case CompressedGeometryHeader.LINE_BUFFER: + geoType |= LINE ; + break ; + default: + case CompressedGeometryHeader.TRIANGLE_BUFFER: + geoType |= SURFACE ; + break ; + } + break; + default: + geoType = SURFACE; + if (polygonAttributes != null) { + if (polygonAttributes.polygonMode == + PolygonAttributes.POLYGON_POINT) { + geoType |= POINT; + } else if (polygonAttributes.polygonMode == + PolygonAttributes.POLYGON_LINE) { + geoType |= LINE; + } + } + break; + } + + if (this.geometryType != geoType) { + return (false); + } + /* + // XXXX : Check this + if (useDisplayList && + (ga.geometry.isEditable || + ga.geometry.refCount > 1 || + ((GroupRetained)ga.source.parent).switchLevel >= 0 || + ga.alphaEditable)) { + return (false); + } + */ + if (ga.geoType == GeometryRetained.GEO_TYPE_TEXT3D && + primaryMoleculeType != 0 && + ((primaryMoleculeType & TEXT3D_MOLECULE) == 0)) { + return (false); + } + + + if(!(ra.geometryAtom.source instanceof OrientedShape3DRetained) + && ((primaryMoleculeType & ORIENTEDSHAPE3D_MOLECULE) != 0)) { + //System.err.println("RA's NOT a OrientedShape3DRetained and RM is a ORIENTEDSHAPE3D_MOLECULE "); + + return (false); + } + + // XXXX: Its is necessary to have same vformat for dl, + // Howabout iteration, should we have 2 vformats in rm? + if (geo instanceof GeometryArrayRetained) { + GeometryArrayRetained gr = (GeometryArrayRetained)geo; + if (this.vertexFormat != gr.vertexFormat) { + return (false); + } + + + // we are requiring that texCoordSetMap length to be the same + // so that we can either put all multi-tex ga to a display list, + // or punt all to vertex array. And we don't need to worry + // about some of the ga can be in display list for this canvas, + // and some other can be in display list for the other canvas. + if (((gr.texCoordSetMap != null) && + (this.texCoordSetMapLen != gr.texCoordSetMap.length)) || + ((gr.texCoordSetMap == null) && (this.texCoordSetMapLen != 0))) { + return (false); + } + + if (VirtualUniverse.mc.isD3D() && + (((geo.getClassType() == GeometryRetained.QUAD_TYPE) + && !isQuadGeometryArray) || + ((geo.getClassType() == GeometryRetained.TRIANGLE_TYPE) + && !isTriGeometryArray))) { + return false; + } + + } else if (geo instanceof CompressedGeometryRetained) { + if (this.vertexFormat != + ((CompressedGeometryRetained)geo).getVertexFormat()) { + return (false); + } + } else { + //XXXX: compare isEditable + if (this.vertexFormat != -1) { + return (false); + } + } + + // If the any reference to the appearance components that is cached renderMolecule + // can change frequently, make a separate bin + if (soleUser || (ra.geometryAtom.source.appearance != null && + ((ra.geometryAtom.source.appearance.changedFrequent & RM_COMPONENTS) != 0))) { + if (appHandle == (Object)ra.geometryAtom.source.appearance) { + + // if this RenderMolecule is currently on a zombie state, + // we'll need to put it on the update list to reevaluate + // the state, because while it is on a zombie state, + // state could have been changed. Example, + // application could have detached an appearance, + // made changes to the appearance state, and then + // reattached the appearance. In this case, the + // changes would not have reflected to the RenderMolecule + + if (numEditingRenderAtoms == 0) { + + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= ALL_DIRTY_BITS; + } + return true; + } + else { + return false; + } + + } + // Assign the cloned value as the original value + + // Either a changedFrequent or a null case + // and the incoming one is not equal or null + // then return; + // This check also handles null == null case + if (definingPolygonAttributes != null) { + if ((this.definingPolygonAttributes.changedFrequent != 0) || + (polygonAttributes !=null && polygonAttributes.changedFrequent != 0)) + if (definingPolygonAttributes == polygonAttributes) { + if (definingPolygonAttributes.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= POLYGONATTRS_DIRTY; + } + } + else { + return false; + } + else if (!definingPolygonAttributes.equivalent(polygonAttributes)) { + return false; + } + } + else if (polygonAttributes != null) { + return false; + } + + if (definingLineAttributes != null) { + if ((this.definingLineAttributes.changedFrequent != 0) || + (lineAttributes !=null && lineAttributes.changedFrequent != 0)) + if (definingLineAttributes == lineAttributes) { + if (definingLineAttributes.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= LINEATTRS_DIRTY; + } + } + else { + return false; + } + else if (!definingLineAttributes.equivalent(lineAttributes)) { + return false; + } + } + else if (lineAttributes != null) { + return false; + } + + + if (definingPointAttributes != null) { + if ((this.definingPointAttributes.changedFrequent != 0) || + (pointAttributes !=null && pointAttributes.changedFrequent != 0)) + if (definingPointAttributes == pointAttributes) { + if (definingPointAttributes.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= POINTATTRS_DIRTY; + } + } + else { + return false; + } + else if (!definingPointAttributes.equivalent(pointAttributes)) { + return false; + } + } + else if (pointAttributes != null) { + return false; + } + + + + + if (definingMaterial != null) { + if ((this.definingMaterial.changedFrequent != 0) || + (material !=null && material.changedFrequent != 0)) + if (definingMaterial == material) { + if (definingMaterial.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= MATERIAL_DIRTY; + } + } + else { + return false; + } + else if (!definingMaterial.equivalent(material)) { + return false; + } + } + else if (material != null) { + return false; + } + + + + if (definingColoringAttributes != null) { + if ((this.definingColoringAttributes.changedFrequent != 0) || + (coloringAttributes !=null && coloringAttributes.changedFrequent != 0)) + if (definingColoringAttributes == coloringAttributes) { + if (definingColoringAttributes.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= COLORINGATTRS_DIRTY; + } + } + else { + return false; + } + else if (!definingColoringAttributes.equivalent(coloringAttributes)) { + return false; + } + } + else if (coloringAttributes != null) { + return false; + } + + // if the definingTransparency is a non cloned values and the incoming + // one is equivalent, then check if the component is dirty + // this happens when all the RAs from this RM have been removed + // but new ones are not added yet (rbin visibility) not run yet + // and when there is a change in nc based on the new RA, we wil; + // miss the change, doing this check will catch the change durin + // new RAs insertRenderAtom + if (definingTransparency != null) { + if ((this.definingTransparency.changedFrequent != 0) || + (transparency !=null && transparency.changedFrequent != 0)) + if (definingTransparency == transparency) { + if (definingTransparency.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= TRANSPARENCY_DIRTY; + } + } + else { + return false; + } + else if (!definingTransparency.equivalent(transparency)) { + return false; + } + } + else if (transparency != null) { + return false; + } + + return (true); + } + + public void updateRemoveRenderAtoms() { + int i; + RenderAtom r; + RenderAtomListInfo rinfo; + + // Check if this renderMolecule was created and destroyed this frame. + // so, no display list was created + if (numRenderAtoms == 0 && removeRAs == null && addRAs == null) { + textureBin.removeRenderMolecule(this); + return; + } + + while (removeRAs != null) { + r = (RenderAtom)removeRAs; + r.removed = null; + numRenderAtoms--; + + // Loop thru all geometries in the renderAtom, they could + // potentially be in different buckets in the rendermoleulce + for (int index = 0; index < r.rListInfo.length; index++) { + rinfo = r.rListInfo[index]; + // Don't remove null geo + if (rinfo.geometry() == null) + continue; + + if ((rinfo.groupType & RenderAtom.PRIMARY) != 0) { + primaryChanged = true; + if (rinfo.prev == null) { // At the head of the list + primaryRenderAtomList = rinfo.next; + if (rinfo.next != null) { + rinfo.next.prev = null; + } + } else { // In the middle or at the end. + rinfo.prev.next = rinfo.next; + if (rinfo.next != null) { + rinfo.next.prev = rinfo.prev; + } + } + + // If the molecule type is Raster, then add it to the lock list + if (primaryMoleculeType == RASTER) { + RasterRetained geo = (RasterRetained)rinfo.geometry(); + renderBin.removeGeometryFromLockList(geo); + if (geo.image != null) + renderBin.removeNodeComponent(geo.image); + + } + else if ((rinfo.groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0) { + if (!rinfo.renderAtom.inRenderBin()) { + renderBin.removeDlistPerRinfo.add(rinfo); + } + } + } + else if ((rinfo.groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) { + if (rinfo.prev == null) { // At the head of the list + separateDlistRenderAtomList = rinfo.next; + if (rinfo.next != null) { + rinfo.next.prev = null; + } + } else { // In the middle or at the end. + rinfo.prev.next = rinfo.next; + if (rinfo.next != null) { + rinfo.next.prev = rinfo.prev; + } + } + renderBin.removeGeometryDlist(rinfo); + + } + else { + if (rinfo.prev == null) { // At the head of the list + vertexArrayRenderAtomList = rinfo.next; + if (rinfo.next != null) { + rinfo.next.prev = null; + } + } else { // In the middle or at the end. + rinfo.prev.next = rinfo.next; + if (rinfo.next != null) { + rinfo.next.prev = rinfo.prev; + } + } + // For indexed geometry there is no need to lock since + // the mirror is changed only when the renderer is not + // running + // For indexed geometry, if use_coord is set, then either we + // are using the index geometry as is or we will be unindexifying + // on the fly, so its better to lock + GeometryArrayRetained geo = (GeometryArrayRetained)rinfo.geometry(); + if (!(geo instanceof IndexedGeometryArrayRetained) || + ((geo.vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0)) { + renderBin.removeGeometryFromLockList(geo); + } + } + rinfo.prev = null; + rinfo.next = null; + } + removeRAs = removeRAs.nextRemove; + r.nextRemove = null; + r.prevRemove = null; + if (r.isOriented()) { + renderBin.orientedRAs.remove(renderBin.orientedRAs.indexOf(r)); + } + + if ((textureBin.environmentSet.lightBin.geometryBackground == null) && + !isOpaqueOrInOG && renderBin.transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY) { + renderBin.removeTransparentObject(r); + } + } + // If this renderMolecule will not be touched for adding new RenderAtoms + // then .. + if (addRAs == null) { + // If there are no more renderAtoms and there will be no more + // renderatoms added to this renderMolecule , then remove + if (numRenderAtoms == 0) { + // If both lists are empty remove this renderMolecule + if ((primaryMoleculeType &DLIST_MOLECULE) != 0) { + renderBin.addDisplayListResourceFreeList(this); + vwcBounds.set(null); + displayListId = 0; + displayListIdObj = null; + } + if (locale != renderBin.locale) { + localeLocalToVworld = null; + } + textureBin.removeRenderMolecule(this); + } else { + if ((primaryMoleculeType &DLIST_MOLECULE) != 0 && primaryChanged) { + + // If a renderAtom is added to the display list + // structure then add this to the dirty list of rm + // for which the display list needs to be recreated + renderBin.addDirtyRenderMolecule(this); + vwcBounds.set(null); + rinfo = primaryRenderAtomList; + while (rinfo != null) { + vwcBounds.combine(rinfo.renderAtom.localeVwcBounds); + rinfo = rinfo.next; + } + primaryChanged = false; + } + } + } + numEditingRenderAtoms = numRenderAtoms; + } + + public void updateObject() { + int i; + RenderAtom renderAtom; + RenderAtomListInfo r; + if (textureBin == null) { + return; + } + + if (addRAs != null) { + while (addRAs != null) { + + numRenderAtoms++; + renderAtom = (RenderAtom)addRAs; + renderAtom.renderMolecule = this; + renderAtom.added = null; + for (int j = 0; j < renderAtom.rListInfo.length; j++) { + r = (RenderAtomListInfo)renderAtom.rListInfo[j]; + // Don't add null geo + if (r.geometry() == null) + continue; + r.groupType = evalRinfoGroupType(r); + if ((r.groupType & RenderAtom.PRIMARY) != 0) { + if ((r.groupType & RenderAtom.DLIST) != 0 && primaryRenderMethod == null) { + primaryMoleculeType = DLIST_MOLECULE; + renderBin.renderMoleculeList.add(this); + + if (vwcBounds == null) + vwcBounds = new BoundingBox((BoundingBox)null); + primaryRenderMethod = + VirtualUniverse.mc.getDisplayListRenderMethod(); + // Assign a displayListId for this renderMolecule + if (displayListId == 0) { + displayListIdObj = VirtualUniverse.mc.getDisplayListId(); + displayListId = displayListIdObj.intValue(); + } + } + else if ((r.groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0 && + primaryRenderMethod == null) { + primaryMoleculeType = SEPARATE_DLIST_PER_RINFO_MOLECULE; + renderBin.renderMoleculeList.add(this); + primaryRenderMethod = + VirtualUniverse.mc.getDisplayListRenderMethod(); + + } + primaryChanged = true; + if (primaryRenderAtomList == null) { + primaryRenderAtomList = r; + } + else { + r.next = primaryRenderAtomList; + primaryRenderAtomList.prev = r; + primaryRenderAtomList = r; + } + if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { + if (r.renderAtom.dlistIds == null) { + r.renderAtom.dlistIds = new int[r.renderAtom.rListInfo.length]; + + for (int k = 0; k < r.renderAtom.dlistIds.length; k++) { + r.renderAtom.dlistIds[k] = -1; + } + } + if (r.renderAtom.dlistIds[r.index] == -1) { + r.renderAtom.dlistIds[r.index] = VirtualUniverse.mc.getDisplayListId().intValue(); + renderBin.addDlistPerRinfo.add(r); + } + } + + // If the molecule type is Raster, then add it to the lock list + if (primaryMoleculeType == RASTER) { + RasterRetained geo = (RasterRetained)r.geometry(); + renderBin.addGeometryToLockList(geo); + if (geo.image != null) + renderBin.addNodeComponent(geo.image); + } + } + else if ((r.groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) { + if (separateDlistRenderAtomList == null) { + separateDlistRenderAtomList = r; + } + else { + r.next = separateDlistRenderAtomList; + separateDlistRenderAtomList.prev = r; + separateDlistRenderAtomList = r; + } + ((GeometryArrayRetained)r.geometry()).assignDlistId(); + renderBin.addGeometryDlist(r); + } + else { + if (secondaryRenderMethod == null) + secondaryRenderMethod = cachedVertexArrayRenderMethod; + if (vertexArrayRenderAtomList == null) { + vertexArrayRenderAtomList = r; + } + else { + r.next = vertexArrayRenderAtomList; + vertexArrayRenderAtomList.prev = r; + vertexArrayRenderAtomList = r; + } + // For indexed geometry there is no need to lock since + // the mirror is changed only when the renderer is not + // running + // For indexed geometry, if use_coord is set, then either we + // are using the index geometry as is or we will be unindexifying + // on the fly, so its better to loc + GeometryArrayRetained geo = (GeometryArrayRetained)r.geometry(); + if (!(geo instanceof IndexedGeometryArrayRetained) || + ((geo.vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0)) { + renderBin.addGeometryToLockList(geo); + // Add the geometry to the dirty list only if the geometry is by + // refernce and there is color and we need to use alpha + // Issue 113 - ignore multiScreen + if ((( geo.vertexFormat & GeometryArray.BY_REFERENCE)!=0) && + (geo.c4fAllocated == 0) && + ((geo.vertexFormat & GeometryArray.COLOR) != 0) && + useAlpha) { + renderBin.addDirtyReferenceGeometry(geo); + } + } + } + } + addRAs = addRAs.nextAdd; + renderAtom.nextAdd = null; + renderAtom.prevAdd = null; + if (renderAtom.isOriented()) { + renderBin.orientedRAs.add(renderAtom); + + } + // If transparent and not in bg geometry and is depth sorted transparency + if (!isOpaqueOrInOG && (textureBin.environmentSet.lightBin.geometryBackground == null)&& + (renderBin.transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY)) { + GeometryRetained geo = null; + int k = 0; + while (geo == null && k < renderAtom.rListInfo.length) { + geo = renderAtom.rListInfo[k].geometry(); + k++; + } + if (geo != null) { + if (renderAtom.parentTInfo != null && renderAtom.parentTInfo[k-1] != null) { + renderBin.updateTransparentInfo(renderAtom); + } + // Newly added renderAtom + else { + renderBin.addTransparentObject(renderAtom); + } + } + // Moving within the renderBin + + } + } + + if ((primaryMoleculeType &DLIST_MOLECULE) != 0 && primaryChanged) { + + // If a renderAtom is added to the display list + // structure then add this to the dirty list of rm + // for which the display list needs to be recreated + renderBin.addDirtyRenderMolecule(this); + vwcBounds.set(null); + r = primaryRenderAtomList; + while (r != null) { + vwcBounds.combine(r.renderAtom.localeVwcBounds); + r = r.next; + } + primaryChanged = false; + } + + + if ((onUpdateList & LOCALE_CHANGED) != 0) { + handleLocaleChange(); + } + + if (locale != renderBin.locale) { + translate(); + } + } + else { + // The flag LOCALE_CHANGED only gets sets when there is a new additon + // There are cases when RM updateObject() get called (due to addition + // in renderBin - see processTransformChanged()), we need to + // evaluate locale change for this case as well + if (renderBin.localeChanged) { + handleLocaleChange(); + } + + if (locale != renderBin.locale) { + translate(); + } + + if ((onUpdateList & UPDATE_BACKGROUND_TRANSFORM) != 0) { + i = localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]; + localeLocalToVworld[i].getRotation(infLocalToVworld[i]); + } + + // No new renderAtoms were added, but need to + // recompute vwcBounds in response to xform change + if ((onUpdateList & BOUNDS_RECOMPUTE_UPDATE) != 0) { + vwcBounds.set(null); + r = primaryRenderAtomList; + while (r != null) { + vwcBounds.combine(r.renderAtom.localeVwcBounds); + r = r.next; + } + } + } + + // Clear all bits except the IN_DIRTY_LIST + onUpdateList &= IN_DIRTY_RENDERMOLECULE_LIST; + + numEditingRenderAtoms = numRenderAtoms; + } + + boolean canBeInDisplayList(GeometryRetained geo, GeometryAtom ga) { + if (ga.source.sourceNode instanceof MorphRetained) { + return false; + } + + return geo.canBeInDisplayList(ga.alphaEditable); + } + + // If dlist will be altered due to alpha or ignoreVertexColors, then don't + // put in a separate dlist that can be shared ... + final boolean geoNotAltered(GeometryArrayRetained geo) { + return !(((geo.vertexFormat & GeometryArray.COLOR) != 0) && + (textureBin.attributeBin.ignoreVertexColors || useAlpha)); + } + + int evalRinfoGroupType(RenderAtomListInfo r) { + int groupType = 0; + + GeometryRetained geo = r.geometry(); + if (geo == null) + return groupType; + + if ((primaryMoleculeType & (COMPRESSED_MOLECULE | + RASTER_MOLECULE | + TEXT3D_MOLECULE | + ORIENTEDSHAPE3D_MOLECULE)) != 0) { + groupType = RenderAtom.OTHER; + } + else if (canBeInDisplayList(geo, r.renderAtom.geometryAtom)) { + // if geometry is under share group we immediate set the + // dlistID to something other than -1 + if ( !((GeometryArrayRetained)geo).isShared || + // if we do a compiled and push the transform down to + // Geometry, we can't share the displayList + (r.renderAtom.geometryAtom.source.staticTransform != null)) { + // If the molecule is already defined to be SEPARATE_DLIST_PER_RINFO_MOLECULE + // continue adding in that mode even if it was switched back to + // no depth sorted mode + // System.err.println("isOpaqueOrInOG ="+isOpaqueOrInOG+" primaryMoleculeType ="+primaryMoleculeType+" renderBin.transpSortMode ="+renderBin.transpSortMode); + if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { + groupType = RenderAtom.SEPARATE_DLIST_PER_RINFO; + } + else { + if (isOpaqueOrInOG || + renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE) { + groupType = RenderAtom.DLIST; + } + else { + groupType = RenderAtom.SEPARATE_DLIST_PER_RINFO; + } + } + + } else if (geoNotAltered((GeometryArrayRetained)r.geometry()) ) { + groupType = RenderAtom.SEPARATE_DLIST_PER_GEO; + } + else { + groupType = RenderAtom.VARRAY; + } + } + else { + groupType = RenderAtom.VARRAY; + } + return groupType; + } + + /** + * Adds the given RenderAtom to this RenderMolecule. + */ + void addRenderAtom(RenderAtom renderAtom, RenderBin rb) { + int i, n; + RenderAtomListInfo r; + int index; + + renderAtom.envSet = textureBin.environmentSet; + renderAtom.renderMolecule = this; + renderAtom.dirtyMask &= ~RenderAtom.NEED_SEPARATE_LOCALE_VWC_BOUNDS; + + AppearanceRetained raApp = renderAtom.geometryAtom.source.appearance; + + MaterialRetained mat = (raApp == null)? null : raApp.material; + if (!soleUser && material != mat) { + // no longer sole user + material = definingMaterial; + } + + if ((geometryType & SURFACE) != 0) { + PolygonAttributesRetained pgAttrs = + (raApp == null)? null : raApp.polygonAttributes; + if (!soleUser && polygonAttributes != pgAttrs) { + // no longer sole user + polygonAttributes = definingPolygonAttributes; + } + + } + if ((geometryType & LINE) != 0) { + LineAttributesRetained lnAttrs = + (raApp == null)? null : raApp.lineAttributes; + if (!soleUser && lineAttributes != lnAttrs) { + // no longer sole user + lineAttributes = definingLineAttributes; + } + + } + if ((geometryType & POINT) != 0) { + PointAttributesRetained pnAttrs = + (raApp == null)? null : raApp.pointAttributes; + if (!soleUser && pointAttributes != pnAttrs) { + // no longer sole user + pointAttributes = definingPointAttributes; + } + } + + ColoringAttributesRetained coAttrs = + (raApp == null)? null : raApp.coloringAttributes; + if (!soleUser && coloringAttributes != coAttrs) { + // no longer sole user + coloringAttributes = definingColoringAttributes; + } + + TransparencyAttributesRetained trAttrs = + (raApp == null)? null : raApp.transparencyAttributes; + if (!soleUser && transparency != trAttrs) { + // no longer sole user + transparency = definingTransparency; + } + + + + // If the renderAtom is being inserted first time, then evaluate + // the groupType to determine if need separate localeVwcBounds + if (!renderAtom.inRenderBin()) { + for (i = 0; i < renderAtom.rListInfo.length; i++) { + if (renderAtom.rListInfo[i].geometry() == null) + continue; + int groupType = evalRinfoGroupType(renderAtom.rListInfo[i]); + if (groupType != RenderAtom.DLIST) { + renderAtom.dirtyMask |= RenderAtom.NEED_SEPARATE_LOCALE_VWC_BOUNDS; + } + } + } + if (renderAtom.removed == this) { + // Remove the renderAtom from the list of removeRAs + // If this is at the head of the list + if (renderAtom == removeRAs) { + removeRAs = renderAtom.nextRemove; + if (removeRAs != null) + removeRAs.prevRemove = null; + renderAtom.nextRemove = null; + renderAtom.prevRemove = null; + } + // Somewhere in the middle + else { + renderAtom.prevRemove.nextRemove = renderAtom.nextRemove; + if (renderAtom.nextRemove != null) + renderAtom.nextRemove.prevRemove = renderAtom.prevRemove; + renderAtom.nextRemove = null; + renderAtom.prevRemove = null; + } + + renderAtom.removed = null; + // Redo any dlist etc, because it has been added + for ( i = 0; i < renderAtom.rListInfo.length; i++) { + if (renderAtom.rListInfo[i].geometry() == null) + continue; + if ((renderAtom.rListInfo[i].groupType & RenderAtom.DLIST) != 0) + renderBin.addDirtyRenderMolecule(this); + else if ((renderAtom.rListInfo[i].groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0) { + renderBin.addDlistPerRinfo.add(renderAtom.rListInfo[i]); + } + else if ((renderAtom.rListInfo[i].groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) + renderBin.addGeometryDlist(renderAtom.rListInfo[i]); + + } + if (removeRAs == null) + rb.removeRenderAtomInRMList.remove(this); + } + else { + // Add this renderAtom to the addList + if (addRAs == null) { + addRAs = renderAtom; + renderAtom.nextAdd = null; + renderAtom.prevAdd = null; + } + else { + renderAtom.nextAdd = addRAs; + renderAtom.prevAdd = null; + addRAs.prevAdd = renderAtom; + addRAs = renderAtom; + } + renderAtom.added = this; + if (onUpdateList == 0) + rb.objUpdateList.add(this); + onUpdateList |= NEW_RENDERATOMS_UPDATE; + + } + if (renderBin.localeChanged && !doInfinite) { + if (onUpdateList == 0) + rb.objUpdateList.add(this); + onUpdateList |= LOCALE_CHANGED; + } + + // inform the texture bin that this render molecule is no longer + // in zombie state + + if (numEditingRenderAtoms == 0) { + textureBin.incrActiveRenderMolecule(); + } + numEditingRenderAtoms++; + } + + /** + * Removes the given RenderAtom from this RenderMolecule. + */ + void removeRenderAtom(RenderAtom r) { + int index; + + r.renderMolecule = null; + if (r.added == this) { + //Remove this renderAtom from the addRAs list + + // If this is at the head of the list + if (r == addRAs) { + addRAs = r.nextAdd; + if (addRAs != null) + addRAs.prevAdd = null; + r.nextAdd = null; + r.prevAdd = null; + } + // Somewhere in the middle + else { + r.prevAdd.nextAdd = r.nextAdd; + if (r.nextAdd != null) + r.nextAdd.prevAdd = r.prevAdd; + r.nextAdd = null; + r.prevAdd = null; + } + + r.added = null; + r.envSet = null; + // If the number of renderAtoms is zero, and it is on the + // update list for adding new renderatroms only (not for + // bounds update), then remove this rm from the update list + + // Might be expensive to remove this entry from the renderBin + // objUpdateList, just let it call the renderMolecule + /* + if (addRAs == null) { + if (onUpdateList == NEW_RENDERATOMS_UPDATE){ + renderBin.objUpdateList.remove(renderBin.objUpdateList.indexOf(this)); + } + onUpdateList &= ~NEW_RENDERATOMS_UPDATE; + } + */ + + } + else { + // Add this renderAtom to the remove list + if (removeRAs == null) { + removeRAs = r; + r.nextRemove = null; + r.prevRemove = null; + } + else { + r.nextRemove = removeRAs; + r.prevRemove = null; + removeRAs.prevRemove = r; + removeRAs = r; + } + r.removed = this; + } + + // Add it to the removeRenderAtom List , in case the renderMolecule + // needs to be removed + if (!renderBin.removeRenderAtomInRMList.contains(this)) { + renderBin.removeRenderAtomInRMList.add(this); + } + + // decrement the number of editing render atoms in this render molecule + numEditingRenderAtoms--; + + // if there is no more editing render atoms, inform the texture bin + // that this render molecule is going to zombie state + + if (numEditingRenderAtoms == 0) { + textureBin.decrActiveRenderMolecule(); + } + } + + /** + * Recalculates the vwcBounds for a RenderMolecule + */ + void recalcBounds() { + RenderAtomListInfo ra; + + if (primaryRenderMethod == + VirtualUniverse.mc.getDisplayListRenderMethod()) { + vwcBounds.set(null); + ra = primaryRenderAtomList; + while (ra != null) { + vwcBounds.combine(ra.renderAtom.localeVwcBounds); + ra = ra.next; + } + } + } + + void evalAlphaUsage(RenderingAttributesRetained renderAttrs, + TextureUnitStateRetained[] texUnits) { + boolean alphaBlend, alphaTest, textureBlend = false; + + alphaBlend = + definingTransparency != null && + definingTransparency.transparencyMode != + TransparencyAttributes.NONE && + (VirtualUniverse.mc.isD3D() || + !VirtualUniverse.mc.isD3D() && + definingTransparency.transparencyMode != + TransparencyAttributes.SCREEN_DOOR); + + + if (texUnits != null) { + for (int i = 0; + textureBlend == false && i < texUnits.length; + i++) { + if (texUnits[i] != null && + texUnits[i].texAttrs != null) { + textureBlend = textureBlend || + (texUnits[i].texAttrs.textureMode == + TextureAttributes.BLEND); + } + } + } + + alphaTest = + renderAttrs != null && renderAttrs.alphaTestFunction != RenderingAttributes.ALWAYS; + + boolean oldUseAlpha = useAlpha; + useAlpha = alphaBlend || alphaTest || textureBlend; + + if( !oldUseAlpha && useAlpha) { + GeometryArrayRetained geo = null; + + if(vertexArrayRenderAtomList != null) + geo = (GeometryArrayRetained)vertexArrayRenderAtomList.geometry(); + + if(geo != null) { + if (!(geo instanceof IndexedGeometryArrayRetained) || + ((geo.vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0)) { + renderBin.addGeometryToLockList(geo); + // Add the geometry to the dirty list only if the geometry is by + // reference and there is color and we need to use alpha + // Issue 113 - ignore multiScreen + if ((( geo.vertexFormat & GeometryArray.BY_REFERENCE)!=0) && + (geo.c4fAllocated == 0) && + ((geo.vertexFormat & GeometryArray.COLOR) != 0) && + useAlpha) { + renderBin.addDirtyReferenceGeometry(geo); + } + } + } + } + } + + final boolean isSwitchOn() { + // The switchOn status of the entire RM can be determined + // by the switchOn status of any renderAtoms below. + // This is possible because renderAtoms generated from a common + // switch branch are placed in the same renderMolecule + if (primaryRenderAtomList != null) { + return primaryRenderAtomList.renderAtom.geometryAtom. + source.switchState.lastSwitchOn; + + } + + if (vertexArrayRenderAtomList != null) { + return vertexArrayRenderAtomList.renderAtom.geometryAtom. + source.switchState.lastSwitchOn; + + } + + if (separateDlistRenderAtomList != null) { + return separateDlistRenderAtomList.renderAtom.geometryAtom. + source.switchState.lastSwitchOn; + } + return false; + } + + /** + * Renders this RenderMolecule + */ + boolean render(Canvas3D cv, int pass, int dirtyBits) { + assert pass < 0; + + boolean isVisible = isSwitchOn(); + + if (!isVisible) { + return false; + } + + isVisible = false; + + // include this LightBin to the to-be-updated list in Canvas + cv.setStateToUpdate(Canvas3D.RENDERMOLECULE_BIT, this); + + boolean modeSupportDL = true; + isNonUniformScale = !trans[localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]].isCongruent(); + // We have to dynamically switch between using displaymode + // mode or not instead of decide in canBeInDisplayList(), + // since polygonAttribute can be change by editable Appearance + // or editable polygonAttribute which mode we can't take + // advantage of display list mode in many cases just because + // there are three special cases to handle. + + // Another case for punting to vertex array is if pass specifies + // something other than -1. That means, we are in the + // multi-texturing multi-pass case. Then we'll use vertex array + // instead. Or the length of the texCoordSetMap is greater than + // the number of texture units supported by the Canvas, then + // we'll have to punt to vertex array as well. + + if ((pass != TextureBin.USE_DISPLAYLIST) || + (texCoordSetMapLen > cv.maxTexCoordSets) || + (VirtualUniverse.mc.isD3D() && + (((definingPolygonAttributes != null) && + ((isQuadGeometryArray && + (definingPolygonAttributes.polygonMode == + PolygonAttributes.POLYGON_LINE))|| + (isTriGeometryArray && + (definingPolygonAttributes.polygonMode == + PolygonAttributes.POLYGON_POINT)))) || + cv.texLinearMode))) { + modeSupportDL = false; + } + + /* + System.err.println("texCoord " + texCoordSetMapLen + " " + + cv.maxTexCoordSets + " " + modeSupportDL); + + System.err.println("primaryMoleculeType = "+primaryMoleculeType+" primaryRenderAtomList ="+primaryRenderAtomList+" separateDlistRenderAtomList ="+separateDlistRenderAtomList+" vertexArrayRenderAtomList ="+vertexArrayRenderAtomList); + */ + // Send down the model view only once, if its not of type text + if ((primaryMoleculeType & (TEXT3D_MOLECULE| ORIENTEDSHAPE3D_MOLECULE)) == 0) { + + if (primaryRenderAtomList != null) { + if ((primaryRenderMethod != VirtualUniverse.mc.getDisplayListRenderMethod()) || + modeSupportDL) { + if (primaryMoleculeType != SEPARATE_DLIST_PER_RINFO_MOLECULE) { + + if (primaryRenderMethod.render(this, cv, primaryRenderAtomList,dirtyBits)) + isVisible = true; + } + else { + if (renderBin.dlistRenderMethod.renderSeparateDlistPerRinfo(this, cv, primaryRenderAtomList,dirtyBits)) + isVisible = true; + + } + } else { + if(cachedVertexArrayRenderMethod.render(this, cv, + primaryRenderAtomList, + dirtyBits)) { + isVisible = true; + } + } + } + } + else { // TEXT3D or ORIENTEDSHAPE3D + + if (primaryRenderAtomList != null) { + if(primaryRenderMethod.render(this, cv, primaryRenderAtomList, + dirtyBits)) { + isVisible = true; + } + } + } + + if (separateDlistRenderAtomList != null) { + if (modeSupportDL) { + if(renderBin.dlistRenderMethod.renderSeparateDlists(this, cv, + separateDlistRenderAtomList, + dirtyBits)) { + isVisible = true; + } + + } else { + if(cachedVertexArrayRenderMethod.render(this, cv, + separateDlistRenderAtomList, + dirtyBits)) { + isVisible = true; + } + } + + } + + // XXXX: In the case of independent primitives such as quads, + // it would still be better to call multi draw arrays + if (vertexArrayRenderAtomList != null) { + if(cachedVertexArrayRenderMethod.render(this, cv, + vertexArrayRenderAtomList, + dirtyBits)) { + isVisible = true; + } + } + return isVisible; + } + + void updateAttributes(Canvas3D cv, int dirtyBits) { + + + boolean setTransparency = false; + + // If this is a beginning of a frame OR diff. geometryType + // then reload everything for the first rendermolecule + // System.err.println("updateAttributes"); + int bitMask = geometryType | Canvas3D.MATERIAL_DIRTY| + Canvas3D.COLORINGATTRS_DIRTY| + Canvas3D.TRANSPARENCYATTRS_DIRTY; + + // If beginning of a frame then reload all the attributes + if ((cv.canvasDirty & bitMask) != 0) { + if ((geometryType & SURFACE) != 0) { + if (definingPolygonAttributes == null) { + cv.resetPolygonAttributes(cv.ctx); + } else { + definingPolygonAttributes.updateNative(cv.ctx); + } + cv.polygonAttributes = polygonAttributes; + } + if ((geometryType & LINE) != 0) { + if (definingLineAttributes == null) { + cv.resetLineAttributes(cv.ctx); + } else { + definingLineAttributes.updateNative(cv.ctx); + } + cv.lineAttributes = lineAttributes; + } + if ((geometryType & POINT) != 0) { + if (definingPointAttributes == null) { + cv.resetPointAttributes(cv.ctx); + } else { + definingPointAttributes.updateNative(cv.ctx); + } + cv.pointAttributes = pointAttributes; + } + + if (definingTransparency == null) { + cv.resetTransparency(cv.ctx, geometryType, + polygonMode, lineAA, pointAA); + } else { + definingTransparency.updateNative(cv.ctx, + alpha, geometryType, + polygonMode, lineAA, + pointAA); + } + cv.transparency = transparency; + + if (definingMaterial == null) { + cv.updateMaterial(cv.ctx, red, green, blue, alpha); + } else { + definingMaterial.updateNative(cv.ctx, + red, green, blue, alpha, + enableLighting); + } + cv.material = material; + cv.enableLighting = enableLighting; + + if (definingColoringAttributes == null) { + cv.resetColoringAttributes(cv.ctx, red, green, blue, + alpha, enableLighting); + } else { + definingColoringAttributes.updateNative(cv.ctx, + dRed, + dBlue, + dGreen,alpha, + enableLighting); + } + cv.coloringAttributes = coloringAttributes; + + // Use Object instead of AppearanceRetained class for + // state caching optimation for memory performance + cv.appHandle = appHandle; + } + + // assuming neighbor dirty bits ORing is implemented + // note that we need to set it to ALL_DIRTY at the + // begining of textureBin first and only do the ORing + // whenever encounter a non-visible rm + + else if (cv.renderMolecule != this && (dirtyBits != 0)) { + + // no need to download states if appHandle is the same + if (cv.appHandle != appHandle) { + + // Check if the attribute bundle in the canvas is the same + // as the attribute bundle in this renderMolecule + + if (cv.transparency != transparency && + (dirtyBits & TRANSPARENCY_DIRTY) != 0) { + setTransparency = true; + if (definingTransparency == null) { + + cv.resetTransparency(cv.ctx, geometryType, + polygonMode, lineAA, pointAA); + } else { + definingTransparency.updateNative(cv.ctx, alpha, + geometryType, polygonMode, + lineAA, pointAA); + } + cv.transparency = transparency; + } + + if (setTransparency || ((cv.enableLighting != enableLighting) || + (cv.material != material) && + (dirtyBits & MATERIAL_DIRTY) != 0)){ + if (definingMaterial == null) { + cv.updateMaterial(cv.ctx, red, green, blue, alpha); + } else { + definingMaterial.updateNative(cv.ctx, red, green, + blue, alpha, + enableLighting); + } + cv.material = material; + cv.enableLighting = enableLighting; + } + + if (((geometryType & SURFACE) != 0) && + cv.polygonAttributes != polygonAttributes && + (dirtyBits & POLYGONATTRS_DIRTY) != 0) { + + if (definingPolygonAttributes == null) { + cv.resetPolygonAttributes(cv.ctx); + } else { + definingPolygonAttributes.updateNative(cv.ctx); + } + cv.polygonAttributes = polygonAttributes; + } + + if (((geometryType & LINE) != 0) && + cv.lineAttributes != lineAttributes && + (dirtyBits & LINEATTRS_DIRTY) != 0) { + + if (definingLineAttributes == null) { + cv.resetLineAttributes(cv.ctx); + } else { + definingLineAttributes.updateNative(cv.ctx); + } + cv.lineAttributes = lineAttributes; + } + + if (((geometryType & POINT) != 0) && + cv.pointAttributes != pointAttributes && + (dirtyBits & POINTATTRS_DIRTY) != 0) { + + if (definingPointAttributes == null) { + cv.resetPointAttributes(cv.ctx); + } else { + definingPointAttributes.updateNative(cv.ctx); + } + cv.pointAttributes = pointAttributes; + } + + // Use Object instead of AppearanceRetained class for + // state caching optimation for memory performance + cv.appHandle = appHandle; + } + // no state caching for color attrs, which can also be + // changed by primitive with colors + if(setTransparency || ((dirtyBits & COLORINGATTRS_DIRTY) != 0)) { + + if (definingColoringAttributes == null) { + cv.resetColoringAttributes(cv.ctx, + red, green, blue, alpha, + enableLighting); + } else { + definingColoringAttributes.updateNative(cv.ctx, + dRed, + dBlue, + dGreen,alpha, + enableLighting); + + } + cv.coloringAttributes = coloringAttributes; + } + + } + + if ((primaryMoleculeType & (TEXT3D_MOLECULE| ORIENTEDSHAPE3D_MOLECULE)) == 0) { + /* System.err.println("updateAttributes setModelViewMatrix (1)"); */ + + Transform3D modelMatrix = + trans[localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]]; + + if (cv.modelMatrix != modelMatrix) { + /* System.err.println("updateAttributes setModelViewMatrix (2)"); */ + + cv.setModelViewMatrix(cv.ctx, cv.vworldToEc.mat, + modelMatrix); + } + } + + cv.canvasDirty &= ~bitMask; + cv.renderMolecule = this; + } + + void transparentSortRender(Canvas3D cv, int pass, TransparentRenderingInfo tinfo) { + assert pass < 0; + + Transform3D modelMatrix = + trans[localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]]; + + // include this LightBin to the to-be-updated list in Canvas + cv.setStateToUpdate(Canvas3D.RENDERMOLECULE_BIT, this); + + + boolean modeSupportDL = true; + + // We have to dynamically switch between using displaymode + // mode or not instead of decide in canBeInDisplayList(), + // since polygonAttribute can be change by editable Appearance + // or editable polygonAttribute which mode we can't take + // advantage of display list mode in many cases just because + // there are three special cases to handle. + + // Another case for punting to vertex array is if pass specifies + // something other than -1. That means, we are in the + // multi-texturing multi-pass case. Then we'll use vertex array + // instead. + + if ((pass != TextureBin.USE_DISPLAYLIST) || + (texCoordSetMapLen > cv.maxTexCoordSets) || + (VirtualUniverse.mc.isD3D() && + (((definingPolygonAttributes != null) && + ((isQuadGeometryArray && + (definingPolygonAttributes.polygonMode == + PolygonAttributes.POLYGON_LINE)) || + (isTriGeometryArray && + (definingPolygonAttributes.polygonMode == + PolygonAttributes.POLYGON_POINT)))) + || + cv.texLinearMode))) { + modeSupportDL = false; + } + + // System.err.println("r.isOpaque = "+isOpaque+" rinfo = "+tinfo.rInfo+" groupType = "+tinfo.rInfo.groupType); + // Only support individual dlist or varray + // If this rInfo is a part of a bigger dlist, render as VA + // XXXX: What to do with Text3D, Raster, CG? + if ((tinfo.rInfo.groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0) { + RenderAtomListInfo save= tinfo.rInfo.next; + // Render only one geometry + tinfo.rInfo.next = null; + // System.err.println("cachedVertexArrayRenderMethod = "+cachedVertexArrayRenderMethod); + // System.err.println("tinfo.rInfo = "+tinfo.rInfo); + if (modeSupportDL) { + renderBin.dlistRenderMethod.renderSeparateDlistPerRinfo(this, cv, + tinfo.rInfo, + ALL_DIRTY_BITS); + } + else { + cachedVertexArrayRenderMethod.render(this, cv, tinfo.rInfo,ALL_DIRTY_BITS); + } + tinfo.rInfo.next = save; + } + else if ((tinfo.rInfo.groupType & (RenderAtom.VARRAY| RenderAtom.DLIST)) != 0) { + RenderAtomListInfo save= tinfo.rInfo.next; + // Render only one geometry + tinfo.rInfo.next = null; + // System.err.println("cachedVertexArrayRenderMethod = "+cachedVertexArrayRenderMethod); + // System.err.println("tinfo.rInfo = "+tinfo.rInfo); + cachedVertexArrayRenderMethod.render(this, cv, tinfo.rInfo, + ALL_DIRTY_BITS); + tinfo.rInfo.next = save; + } + + // Only support individual dlist or varray + else if ((tinfo.rInfo.groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) { + RenderAtomListInfo save= tinfo.rInfo.next; + tinfo.rInfo.next = null; + if (modeSupportDL) { + renderBin.dlistRenderMethod.renderSeparateDlists(this, cv, + tinfo.rInfo, + ALL_DIRTY_BITS); + } + else { + cachedVertexArrayRenderMethod.render(this, cv, tinfo.rInfo, + ALL_DIRTY_BITS); + } + tinfo.rInfo.next = save; + } + else { + RenderAtomListInfo save= tinfo.rInfo.next; + primaryRenderMethod.render(this, cv, primaryRenderAtomList, + ALL_DIRTY_BITS); + tinfo.rInfo.next = save; + } + + } + + + /** + * This render method is used to render the transparency attributes. + * It is used in the multi-texture multi-pass case to reset the + * transparency attributes to what it was + */ + void updateTransparencyAttributes(Canvas3D cv) { + if (definingTransparency == null) { + cv.resetTransparency(cv.ctx, geometryType, polygonMode, + lineAA, pointAA); + } else { + definingTransparency.updateNative(cv.ctx, alpha, geometryType, + polygonMode, lineAA, pointAA); + } + } + + void updateDisplayList(Canvas3D cv) { + // This function only gets called when primaryRenderAtomsList are + if (primaryRenderAtomList != null) { + ((DisplayListRenderMethod)primaryRenderMethod).buildDisplayList(this, cv); + } + } + + void releaseAllPrimaryDisplayListID() { + + if (primaryRenderAtomList != null) { + if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { + RenderAtomListInfo ra = primaryRenderAtomList; + int id; + + while (ra != null) { + id = ra.renderAtom.dlistIds[ra.index]; + + if (id > 0) { + VirtualUniverse.mc.freeDisplayListId(new Integer(id)); + ra.renderAtom.dlistIds[ra.index] = -1; + } + ra = ra.next; + } + } + else if (primaryMoleculeType == DLIST_MOLECULE) { + if (displayListIdObj != null) { + VirtualUniverse.mc.freeDisplayListId(displayListIdObj); + displayListIdObj = null; + displayListId = -1; + } + } + } + + } + + void releaseAllPrimaryDisplayListResources(Canvas3D cv, Context ctx) { + if (primaryRenderAtomList != null) { + if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { + RenderAtomListInfo ra = primaryRenderAtomList; + int id; + while (ra != null) { + id = ra.renderAtom.dlistIds[ra.index]; + if (id > 0) { + cv.freeDisplayList(ctx, id); + } + ra = ra.next; + } + } + else if (primaryMoleculeType == DLIST_MOLECULE) { + if (displayListId > 0) { + cv.freeDisplayList(ctx, displayListId); + } + } + } + } + + void updateAllPrimaryDisplayLists(Canvas3D cv) { + // This function only gets called when primaryRenderAtomsList are + if (primaryRenderAtomList != null) { + if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { + RenderAtomListInfo ra = primaryRenderAtomList; + while (ra != null) { + renderBin.dlistRenderMethod.buildDlistPerRinfo(ra, this, cv); + ra = ra.next; + } + } + else if(primaryMoleculeType == DLIST_MOLECULE) { + ((DisplayListRenderMethod)primaryRenderMethod).buildDisplayList(this, cv); + } + } + } + + void checkEquivalenceWithBothNeighbors(int dirtyBits) { + RenderMolecule leftRm = prev; + RenderMolecule rightRm = next; + dirtyAttrsAcrossRms = ALL_DIRTY_BITS; + boolean reload_color = true; + + if (prev != null) { + checkEquivalenceWithLeftNeighbor(prev, dirtyBits); + } + if (next != null) { + next.checkEquivalenceWithLeftNeighbor(this, dirtyBits); + } + } + + boolean reloadColor(RenderMolecule rm) { + if (((rm.vertexFormat & GeometryArray.COLOR) == 0) || + (((rm.vertexFormat & GeometryArray.COLOR) != 0) && + (vertexFormat & GeometryArray.COLOR) != 0)) { + return false; + } + return true; + } + + void checkEquivalenceWithLeftNeighbor(RenderMolecule rm, int dirtyBits) { + boolean reload_color = reloadColor(rm); + // XXXX : For now ignore the dirtyBits being sent in + dirtyAttrsAcrossRms = ALL_DIRTY_BITS ; + + + + // There is some interdepenency between the different components + // in the way it is sent down to the native code + // Material is affected by transparency and coloring attrs + // Transparency is affected by poly/line/pointAA + // ColoringAttrs is affected by material and transaparency + int materialColoringDirty = (MATERIAL_DIRTY | + TRANSPARENCY_DIRTY | + COLORINGATTRS_DIRTY); + + int transparencyDirty = (TRANSPARENCY_DIRTY| + POLYGONATTRS_DIRTY | + LINEATTRS_DIRTY | + POINTATTRS_DIRTY); + + if ((dirtyAttrsAcrossRms & POLYGONATTRS_DIRTY) != 0) { + if (rm.geometryType == geometryType && + (rm.polygonAttributes == polygonAttributes || + ((rm.definingPolygonAttributes != null) && + (rm.definingPolygonAttributes.equivalent(definingPolygonAttributes))))) + dirtyAttrsAcrossRms &= ~POLYGONATTRS_DIRTY; + + } + + if ((dirtyAttrsAcrossRms & POINTATTRS_DIRTY) != 0) { + if (rm.geometryType == geometryType && + ((rm.pointAttributes == pointAttributes) || + ((rm.definingPointAttributes != null) && + (rm.definingPointAttributes.equivalent(definingPointAttributes))))) + dirtyAttrsAcrossRms &= ~POINTATTRS_DIRTY; + + } + + if ((dirtyAttrsAcrossRms & LINEATTRS_DIRTY) != 0) { + if (rm.geometryType == geometryType && + ((rm.lineAttributes == lineAttributes) || + ((rm.definingLineAttributes != null) && + (rm.definingLineAttributes.equivalent(definingLineAttributes))))) + dirtyAttrsAcrossRms &= ~LINEATTRS_DIRTY; + } + + if ((dirtyAttrsAcrossRms & materialColoringDirty) != 0) { + if (materialEquivalent(rm, reload_color)) { + dirtyAttrsAcrossRms &= ~MATERIAL_DIRTY; + } + else { + dirtyAttrsAcrossRms |= MATERIAL_DIRTY; + } + } + + + + + if ((dirtyAttrsAcrossRms & materialColoringDirty) != 0) { + if (coloringEquivalent(rm, reload_color)) { + dirtyAttrsAcrossRms &= ~COLORINGATTRS_DIRTY; + } + else { + dirtyAttrsAcrossRms |= COLORINGATTRS_DIRTY; + } + } + + if ((dirtyAttrsAcrossRms & transparencyDirty) != 0) { + if (transparencyEquivalent(rm)) { + dirtyAttrsAcrossRms &= ~TRANSPARENCY_DIRTY; + } + else { + dirtyAttrsAcrossRms |= TRANSPARENCY_DIRTY; + } + } + } + void translate() { + // System.err.println("onUpdateList = "+onUpdateList+" renderBin.localeChanged = "+renderBin.localeChanged+" rm = "+this); + int i = localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]; + + localeLocalToVworld[i].mat[0] = localToVworld[i].mat[0]; + localeLocalToVworld[i].mat[1] = localToVworld[i].mat[1]; + localeLocalToVworld[i].mat[2] = localToVworld[i].mat[2]; + localeLocalToVworld[i].mat[3] = localToVworld[i].mat[3] + localeTranslation.x ; + localeLocalToVworld[i].mat[4] = localToVworld[i].mat[4]; + localeLocalToVworld[i].mat[5] = localToVworld[i].mat[5]; + localeLocalToVworld[i].mat[6] = localToVworld[i].mat[6]; + localeLocalToVworld[i].mat[7] = localToVworld[i].mat[7]+ localeTranslation.y; + localeLocalToVworld[i].mat[8] = localToVworld[i].mat[8]; + localeLocalToVworld[i].mat[9] = localToVworld[i].mat[9]; + localeLocalToVworld[i].mat[10] = localToVworld[i].mat[10]; + localeLocalToVworld[i].mat[11] = localToVworld[i].mat[11]+ localeTranslation.z; + localeLocalToVworld[i].mat[12] = localToVworld[i].mat[12]; + localeLocalToVworld[i].mat[13] = localToVworld[i].mat[13]; + localeLocalToVworld[i].mat[14] = localToVworld[i].mat[14]; + localeLocalToVworld[i].mat[15] = localToVworld[i].mat[15]; + // System.err.println("rm = "+this+" localTovworld = "+localeLocalToVworld[i]+" localeTranslation = "+localeTranslation); + } + + + boolean isOpaque() { + if (!VirtualUniverse.mc.isD3D()) { + // D3D doesn't support line/point antialiasing + if ((geometryType & SURFACE) != 0) { + if (definingPolygonAttributes != null) { + if ((definingPolygonAttributes.polygonMode == + PolygonAttributes.POLYGON_POINT) && + (definingPointAttributes != null) && + definingPointAttributes.pointAntialiasing) { + return false; + } else if ((definingPolygonAttributes.polygonMode == + PolygonAttributes.POLYGON_LINE) && + (definingLineAttributes != null) && + definingLineAttributes.lineAntialiasing) { + return false; + } + } + } else if ((geometryType & POINT) != 0) { + if ((definingPointAttributes != null) && + definingPointAttributes.pointAntialiasing) { + return false; + } + } else if ((geometryType & LINE) != 0) { + if ((definingLineAttributes != null) && + definingLineAttributes.lineAntialiasing) { + return false; + } + } + return ((definingTransparency == null) || + (definingTransparency.transparencyMode == + TransparencyAttributes.NONE) || + (definingTransparency.transparencyMode == + TransparencyAttributes.SCREEN_DOOR)); + } else { + return ((definingTransparency == null) || + (definingTransparency.transparencyMode == + TransparencyAttributes.NONE)); + } + } + + + boolean updateNodeComponent() { + // System.err.println("soleUser = "+soleUser+" rm = "+this); + if ((soleUserCompDirty & MATERIAL_DIRTY) != 0) { + // Note: this RM is a soleUser(only then this function is called) + // and if definingMaterial == material, then the material is freq + // changed and therefore is not cloned, only other time it can be + // same is when an equivalent material is added in and this can + // never be true when a bin is a soleUser of a appearance + + // Evaluate before replacing the old Value + if (soleUser) { + boolean cloned = definingMaterial != null && definingMaterial != material; + // System.err.println("===>Rm = "+this); + + // System.err.println("===> updating node component, cloned = "+cloned+" material.changedFrequent = "+material.changedFrequent); + // System.err.println("===> definingMaterial ="+definingMaterial+" material = "+material); + + material = ((AppearanceRetained)appHandle).material; + if (material == null) + definingMaterial = null; + else { + if (material.changedFrequent != 0) { + definingMaterial = material; + } + else { + // If the one replaced is a cloned copy, then .. + if (cloned) { + definingMaterial.set(material); + } + else { + definingMaterial = (MaterialRetained)material.clone(); + } + } + } + } + evalMaterialCachedState(); + } + if ((soleUserCompDirty & LINEATTRS_DIRTY) != 0) { + if (soleUser) { + // Evaluate before replacing the old Value + boolean cloned = definingLineAttributes != null && definingLineAttributes != lineAttributes; + + lineAttributes = ((AppearanceRetained)appHandle).lineAttributes; + if (lineAttributes == null) { + lineAA = false; + definingLineAttributes = null; + } else { + if (lineAttributes.changedFrequent != 0) { + definingLineAttributes = lineAttributes; + } + else { + // If the one replaced is a cloned copy, then .. + if (cloned) { + definingLineAttributes.set(lineAttributes); + } + else { + definingLineAttributes = (LineAttributesRetained)lineAttributes.clone(); + } + } + lineAA = definingLineAttributes.lineAntialiasing; + } + } + else { + lineAA = definingLineAttributes.lineAntialiasing; + } + } + if ((soleUserCompDirty & POINTATTRS_DIRTY) != 0) { + if (soleUser) { + // Evaluate before replacing the old Value + boolean cloned = definingPointAttributes != null && definingPointAttributes != pointAttributes; + + pointAttributes = ((AppearanceRetained)appHandle).pointAttributes; + if (pointAttributes == null) { + pointAA = false; + definingPointAttributes = null; + } else { + if (pointAttributes.changedFrequent != 0) { + definingPointAttributes = pointAttributes; + } + else { + // If the one replaced is a cloned copy, then .. + if (cloned) { + definingPointAttributes.set(pointAttributes); + } + else { + definingPointAttributes = (PointAttributesRetained)pointAttributes.clone(); + } + } + pointAA = definingPointAttributes.pointAntialiasing; + } + } + else { + pointAA = definingPointAttributes.pointAntialiasing; + } + + } + if ((soleUserCompDirty & POLYGONATTRS_DIRTY) != 0) { + if (soleUser) { + // Evaluate before replacing the old Value + boolean cloned = definingPolygonAttributes != null && definingPolygonAttributes != polygonAttributes; + + + polygonAttributes = ((AppearanceRetained)appHandle).polygonAttributes; + + if (polygonAttributes == null) { + polygonMode = PolygonAttributes.POLYGON_FILL; + definingPolygonAttributes = null; + } else { + if (polygonAttributes.changedFrequent != 0) { + definingPolygonAttributes = polygonAttributes; + } + else { + // If the one replaced is a cloned copy, then .. + if (cloned) { + definingPolygonAttributes.set(polygonAttributes); + } + else { + definingPolygonAttributes = (PolygonAttributesRetained)polygonAttributes.clone(); + } + } + + polygonMode = definingPolygonAttributes.polygonMode; + } + } + else { + polygonMode = definingPolygonAttributes.polygonMode; + } + + if (polygonMode == PolygonAttributes.POLYGON_LINE) { + geometryType |= LINE; + } else if (polygonMode == PolygonAttributes.POLYGON_POINT) { + geometryType |= POINT; + } + } + + if ((soleUserCompDirty & TRANSPARENCY_DIRTY) != 0) { + if (soleUser) { + // Evaluate before replacing the old Value + boolean cloned = definingTransparency != null && definingTransparency != transparency; + transparency = ((AppearanceRetained)appHandle).transparencyAttributes; + + if (transparency == null) { + alpha = 1.0f ; + definingTransparency = null; + } else { + if (transparency.changedFrequent != 0) { + definingTransparency = transparency; + } + else { + // If the one replaced is a cloned copy, then .. + if (cloned) { + definingTransparency.set(transparency); + } + else { + definingTransparency = (TransparencyAttributesRetained)transparency.clone(); + } + } + + alpha = 1.0f - definingTransparency.transparency; + } + } + else { + alpha = 1.0f - definingTransparency.transparency; + } + } + + if ((soleUserCompDirty & COLORINGATTRS_DIRTY) != 0) { + if (soleUser) { + // Evaluate before replacing the old Value + boolean cloned = definingColoringAttributes != null && definingColoringAttributes != coloringAttributes; + + coloringAttributes = ((AppearanceRetained)appHandle).coloringAttributes; + // System.err.println("coloringAttributes and soleUser"); + // System.err.println("coloringAttributes ="+coloringAttributes); + if (coloringAttributes == null) { + definingColoringAttributes = null; + red = 1.0f; + green = 1.0f; + blue = 1.0f; + } else { + // System.err.println("coloringAttributes.changedFrequent = "+coloringAttributes.changedFrequent ); + if (coloringAttributes.changedFrequent != 0) { + definingColoringAttributes = coloringAttributes; + } + else { + // If the one replaced is a cloned copy, then .. + if (cloned) { + definingColoringAttributes.set(coloringAttributes); + } + else { + definingColoringAttributes = (ColoringAttributesRetained)coloringAttributes.clone(); + } + } + red = definingColoringAttributes.color.x; + green = definingColoringAttributes.color.y; + blue = definingColoringAttributes.color.z; + } + } + else { + red = definingColoringAttributes.color.x; + green = definingColoringAttributes.color.y; + blue = definingColoringAttributes.color.z; + } + } + // System.err.println("rm = "+this+"red = "+red+" green = "+green+" blue = "+blue); + boolean newVal = isOpaque() || inOrderedGroup; + return (isOpaqueOrInOG != newVal); + + } + + // Issue 129: method to add or remove all rendering atoms in this + // RenderMolecule to or from the transparent info list when we are + // in depth sorted transparency mode and the RenderMolecule + // changes from opaque to transparent or vice versa. + void addRemoveTransparentObject(RenderBin renderBin, boolean add) { + addRemoveTransparentObject(renderBin, add, primaryRenderAtomList); + addRemoveTransparentObject(renderBin, add, separateDlistRenderAtomList); + addRemoveTransparentObject(renderBin, add, vertexArrayRenderAtomList); + } + + private void addRemoveTransparentObject(RenderBin renderBin, + boolean add, + RenderAtomListInfo rinfo) { + while (rinfo != null) { + if (add) { + renderBin.addTransparentObject(rinfo.renderAtom); + } + else { + renderBin.removeTransparentObject(rinfo.renderAtom); + } + rinfo = rinfo.next; + } + } + + void evalMaterialCachedState() { + if (definingMaterial == null) { + enableLighting = false;; + definingMaterial = null; + dRed = 1.0f; + dGreen = 1.0f; + dBlue = 1.0f; + } + else { + if ((geometryType & RASTER) != 0) { + enableLighting = false; + dRed = 1.0f; + dGreen = 1.0f; + dBlue = 1.0f; + } else { + if (normalPresent) + enableLighting = definingMaterial.lightingEnable; + else + enableLighting = false; + dRed = definingMaterial.diffuseColor.x; + dGreen = definingMaterial.diffuseColor.y; + dBlue = definingMaterial.diffuseColor.z; + } + } + } + + + void markBitsAsDirty(int leftBits, int rightBits) { + if (prev != null) { + checkEquivalenceWithLeftNeighbor(prev, leftBits); + prev.soleUserCompDirty &= ~ALL_DIRTY_BITS; + } + else if (prevMap != null) { + checkEquivalenceWithLeftNeighbor(prevMap, leftBits); + prevMap.soleUserCompDirty &= ~ALL_DIRTY_BITS; + } + if (next != null) { + if ((next.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { + next.checkEquivalenceWithLeftNeighbor(this, rightBits); + } else { + next.soleUserCompDirty = rightBits; + } + } + else if (nextMap != null) { + if ((nextMap.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { + nextMap.checkEquivalenceWithLeftNeighbor(this, rightBits); + } else { + nextMap.soleUserCompDirty = rightBits; + } + } + + } + + void handleMaterialEquivalence() { + // Check if it has equivalent material to any of the "non-dirty" + // renderMolecules before this one + RenderMolecule curPrevRm = null; + RenderMolecule curNextRm = null; + boolean found = false; + int leftBits = ALL_DIRTY_BITS; + int rightBits = ALL_DIRTY_BITS; + if (prev != null) { + curPrevRm = prev.prev; + if (materialEquivalent(prev, reloadColor(prev))) { + found = true; + leftBits = (((soleUserCompDirty | prev.soleUserCompDirty) &ALL_DIRTY_BITS) & ~MATERIAL_DIRTY); + rightBits = (soleUserCompDirty & ALL_DIRTY_BITS); + markBitsAsDirty(leftBits, rightBits); + } + } + else if (!found && next != null) { + curNextRm = next.next; + + if (materialEquivalent(next, reloadColor(next))) { + found = true; + int bits = 0; + if (prev != null) + bits = prev.soleUserCompDirty; + else if (prevMap != null) + bits = prevMap.soleUserCompDirty; + + leftBits = ((soleUserCompDirty |bits) &ALL_DIRTY_BITS); + rightBits = ((soleUserCompDirty & ALL_DIRTY_BITS) & ~MATERIAL_DIRTY); + markBitsAsDirty(leftBits, rightBits); + + } + } + // try place it next to a equivalent material on the left + while (!found && curPrevRm != null) { + if (materialEquivalent(curPrevRm, reloadColor(curPrevRm))) { + found = true; + // Remove the renderMolecule from it place + prev.next = next; + prev.nextMap = nextMap; + if (next != null) { + next.prev = prev; + if ((next.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { + next.checkEquivalenceWithLeftNeighbor(prev, ALL_DIRTY_BITS); + } + else { + next.soleUserCompDirty = ALL_DIRTY_BITS; + } + } + else if (nextMap != null) { + nextMap.prevMap = prev; + if ((nextMap.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { + nextMap.checkEquivalenceWithLeftNeighbor(prev,ALL_DIRTY_BITS); + } + else { + nextMap.soleUserCompDirty |= ALL_DIRTY_BITS; + } + } + + // Insert it after the equivalent RM + next = curPrevRm.next; + nextMap = curPrevRm.nextMap; + curPrevRm.nextMap = null; + if (next != null) { + next.prev = this; + } + else if (nextMap != null) { + nextMap.prevMap = this; + } + prev = curPrevRm; + curPrevRm.next = this; + leftBits = (ALL_DIRTY_BITS & ~MATERIAL_DIRTY); + markBitsAsDirty(leftBits, ALL_DIRTY_BITS); + } + curPrevRm = curPrevRm.prev; + } + + // Check if it has equivalent material to any of the renderMolecules after + // this one + while (!found && curNextRm != null) { + if (materialEquivalent(curNextRm, reloadColor(curNextRm))) { + found = true; + // switch the pointers + next.prev = prev; + next.prevMap = prevMap; + if (prev != null) { + prev.next = next; + if ((next.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { + next.checkEquivalenceWithLeftNeighbor(prev, ALL_DIRTY_BITS); + } + else { + next.soleUserCompDirty = ALL_DIRTY_BITS; + } + } + else if (prevMap != null) { + prevMap.nextMap = next; + if ((next.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { + next.checkEquivalenceWithLeftNeighbor(prevMap, ALL_DIRTY_BITS); + } + else { + next.soleUserCompDirty = ALL_DIRTY_BITS; + } + } + + // Insert it before the equivalent RM + prev = curNextRm.prev; + prevMap = curNextRm.prevMap; + curNextRm.prevMap = null; + if (curNextRm.prev != null) { + curNextRm.prev.next = this; + } + else if (prevMap != null) { + prevMap.nextMap = this; + } + next = curNextRm; + curNextRm.prev = this; + rightBits = (ALL_DIRTY_BITS & ~MATERIAL_DIRTY); + markBitsAsDirty(ALL_DIRTY_BITS, rightBits); + } + curNextRm = curNextRm.next; + } + // If there are no equivalent ones, evaluate the dirty bits in the current place + if (!found) { + if (prev != null) { + leftBits = ((soleUserCompDirty|prev.soleUserCompDirty) & ALL_DIRTY_BITS); + } + else if (prevMap != null) { + leftBits = ((soleUserCompDirty|prevMap.soleUserCompDirty) & ALL_DIRTY_BITS); + } + if (next != null) { + rightBits = ((soleUserCompDirty|next.soleUserCompDirty) & ALL_DIRTY_BITS); + } + else if (nextMap != null) { + rightBits = ((soleUserCompDirty|nextMap.soleUserCompDirty) & ALL_DIRTY_BITS); + } + markBitsAsDirty(leftBits, rightBits); + } + + } + + void reEvaluateEquivalence () { + // If Material changed, reInsert next to a equivalent material under + // the same transform group + // to prevent unnecessary material download + // This RM may have been evaluated due to an other RM is the same list + // If not, ... + if ((soleUserCompDirty & ALL_DIRTY_BITS) != 0) { + if ((soleUserCompDirty & MATERIAL_DIRTY) != 0) { + handleMaterialEquivalence(); + } + else { + int dirtyBits = (soleUserCompDirty & ALL_DIRTY_BITS); + if (prev != null) { + checkEquivalenceWithLeftNeighbor(prev, ((dirtyBits|prev.soleUserCompDirty) & ALL_DIRTY_BITS)); + prev.soleUserCompDirty = 0; + } else if (prevMap != null) { + checkEquivalenceWithLeftNeighbor(prevMap, ((dirtyBits|prevMap.soleUserCompDirty) & ALL_DIRTY_BITS)); + prevMap.soleUserCompDirty = 0; + } + if (next != null) { + next.checkEquivalenceWithLeftNeighbor(this,((next.soleUserCompDirty|soleUserCompDirty) & ALL_DIRTY_BITS)); + } else if (nextMap != null) { + nextMap.checkEquivalenceWithLeftNeighbor(this,((nextMap.soleUserCompDirty | soleUserCompDirty) & ALL_DIRTY_BITS)); + } + } + } + soleUserCompDirty &= ~ALL_DIRTY_BITS; + } + + + boolean materialEquivalent(RenderMolecule rm, boolean reloadColor) { + if (!reloadColor) { + if (((this.material == rm.material) || + ((rm.definingMaterial != null) && + (rm.definingMaterial.equivalent(definingMaterial)))) && + rm.alpha == alpha && + enableLighting == rm.enableLighting && + (enableLighting || + (!enableLighting && + rm.red ==red && + rm.green == green && + rm.blue == blue))) { + return true; + } + } + return false; + } + + boolean coloringEquivalent(RenderMolecule rm, boolean reload_color) { + if (!reload_color) { + if (((rm.coloringAttributes == coloringAttributes) || + ((rm.definingColoringAttributes != null) && + (rm.definingColoringAttributes.equivalent(definingColoringAttributes)))) && + (!enableLighting || (enableLighting && (dRed == rm.dRed && dBlue == rm.dBlue && dGreen == rm.dGreen)))) { + return true; + } + } + return false; + } + + boolean transparencyEquivalent(RenderMolecule rm) { + if (((rm.transparency == transparency) || + ((rm.definingTransparency != null) && + (rm.definingTransparency.equivalent(definingTransparency))) && + (rm.definingTransparency.transparencyMode < TransparencyAttributes.SCREEN_DOOR && + blendOn() == rm.blendOn()))) { + return true; + } + return false; + } + + boolean blendOn() { + if (lineAA && ((((geometryType & LINE) != 0) || + polygonMode == PolygonAttributes.POLYGON_LINE))) { + return true; + } + if (pointAA && ((((geometryType & POINT) != 0) || + polygonMode == PolygonAttributes.POLYGON_POINT))) { + return true; + } + return false; + } + + VirtualUniverse getVirtualUniverse() { + return null; + } + + + void handleLocaleChange() { + if (locale == renderBin.locale) { + if (localToVworld != localeLocalToVworld) { + localeLocalToVworld = localToVworld; + localeTranslation = null; + } + } + else { + // Using the localToVworl then, go back to making a new copy + if (localeTranslation == null) { + localeLocalToVworld = new Transform3D[2]; + localeLocalToVworld[0] = new Transform3D(); + localeLocalToVworld[1] = new Transform3D(); + + localeTranslation = new Vector3d(); + locale.hiRes.difference(renderBin.locale.hiRes, localeTranslation); + translate(); + int i = localToVworldIndex[NodeRetained.CURRENT_LOCAL_TO_VWORLD]; + + localeLocalToVworld[i].mat[0] = localToVworld[i].mat[0]; + localeLocalToVworld[i].mat[1] = localToVworld[i].mat[1]; + localeLocalToVworld[i].mat[2] = localToVworld[i].mat[2]; + localeLocalToVworld[i].mat[3] = localToVworld[i].mat[3] + localeTranslation.x ; + localeLocalToVworld[i].mat[4] = localToVworld[i].mat[4]; + localeLocalToVworld[i].mat[5] = localToVworld[i].mat[5]; + localeLocalToVworld[i].mat[6] = localToVworld[i].mat[6]; + localeLocalToVworld[i].mat[7] = localToVworld[i].mat[7]+ localeTranslation.y; + localeLocalToVworld[i].mat[8] = localToVworld[i].mat[8]; + localeLocalToVworld[i].mat[9] = localToVworld[i].mat[9]; + localeLocalToVworld[i].mat[10] = localToVworld[i].mat[10]; + localeLocalToVworld[i].mat[11] = localToVworld[i].mat[11]+ localeTranslation.z; + localeLocalToVworld[i].mat[12] = localToVworld[i].mat[12]; + localeLocalToVworld[i].mat[13] = localToVworld[i].mat[13]; + localeLocalToVworld[i].mat[14] = localToVworld[i].mat[14]; + localeLocalToVworld[i].mat[15] = localToVworld[i].mat[15]; + } + } + + trans = localeLocalToVworld; + } + + + /** + * updateNodeComponentCheck is called for each soleUser RenderMolecule + * into which new renderAtom has been added. This method is called before + * updateNodeComponent() to allow RenderMolecule to catch any node + * component changes that have been missed because the changes + * come when there is no active renderAtom associated with the + * TextureBin. See bug# 4503926 for details. + */ + public void updateNodeComponentCheck() { + + // If the renderMolecule has been removed, do nothing .. + if ((onUpdateList &ON_UPDATE_CHECK_LIST ) == 0) + return; + + onUpdateList &= ~ON_UPDATE_CHECK_LIST; + NodeComponentRetained nc = (NodeComponentRetained)appHandle; + if ((nc.compChanged & RM_COMPONENTS) != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= (nc.compChanged & RM_COMPONENTS); + } + if (definingPolygonAttributes != null && + definingPolygonAttributes == polygonAttributes) { + if (definingPolygonAttributes.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= POLYGONATTRS_DIRTY; + } + } + if (definingLineAttributes != null && + definingLineAttributes == lineAttributes) { + if (definingLineAttributes.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= LINEATTRS_DIRTY; + } + } + if (definingPointAttributes != null && + definingPointAttributes.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= POINTATTRS_DIRTY; + } + + if (definingMaterial != null && + definingMaterial == material) { + if (definingMaterial.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= MATERIAL_DIRTY; + } + } + + if (definingColoringAttributes != null && + definingColoringAttributes == coloringAttributes) { + if (definingColoringAttributes.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= COLORINGATTRS_DIRTY; + } + } + + if (definingTransparency != null && + definingTransparency == transparency) { + if (definingTransparency.compChanged != 0) { + if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { + renderBin.rmUpdateList.add(this); + } + soleUserCompDirty |= TRANSPARENCY_DIRTY; + } + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Renderer.java b/j3d-core/src/classes/share/javax/media/j3d/Renderer.java new file mode 100644 index 0000000..74b22fa --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Renderer.java @@ -0,0 +1,1822 @@ +/* + * $RCSfile: Renderer.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.25 $ + * $Date: 2008/05/15 19:11:57 $ + * $State: Exp $ + */ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +package javax.media.j3d; + +import java.util.logging.Level; +import javax.vecmath.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + + +class Renderer extends J3dThread { + + // This action causes this thread to wait + static final int WAIT = 0; + + // This action causes this thread to notify the view, and then wait. + static final int NOTIFY_AND_WAIT = 1; + + // This action causes this thread to be notified + static final int NOTIFY = 2; + + // The following are DecalGroup rendering states + static final int DECAL_NONE = 0; + static final int DECAL_1ST_CHILD = 1; + static final int DECAL_NTH_CHILD = 2; + + // stuff for scene antialiasing + static final int NUM_ACCUMULATION_SAMPLES = 8; + + static final float ACCUM_SAMPLES_X[] = + { -0.54818f, 0.56438f, 0.39462f, -0.54498f, + -0.83790f, -0.39263f, 0.32254f, 0.84216f}; + + static final float ACCUM_SAMPLES_Y[] = + { 0.55331f, -0.53495f, 0.41540f, -0.52829f, + 0.82102f, -0.27383f, 0.09133f, -0.84399f}; + + static final float accumValue = 1.0f / NUM_ACCUMULATION_SAMPLES; + + // The following are Render arguments + static final int RENDER = 0; + static final int SWAP = 1; + static final int REQUESTRENDER = 2; + static final int REQUESTCLEANUP = 3; + + // Renderer Structure used for the messaging to the renderer + RendererStructure rendererStructure = new RendererStructure(); + + + // vworldtoVpc matrix for background geometry + Transform3D bgVworldToVpc = new Transform3D(); + + private static int numInstances = 0; + private int instanceNum = -1; + + // Local copy of sharedStereZBuffer flag + boolean sharedStereoZBuffer; + + // This is the id for the underlying sharable graphics context + Context sharedCtx = null; + + // since the sharedCtx id can be the same as the previous one, + // we need to keep a time stamp to differentiate the contexts with the + // same id + long sharedCtxTimeStamp = 0; + + // display and drawable, used to free shared context + private long sharedCtxDisplay = 0; + private Drawable sharedCtxDrawable = null; + + /** + * This is the id of the current rendering context + */ + Context currentCtx = null; + + /** + * This is the id of the current rendering drawable + */ + Drawable currentDrawable = null; + + // an unique bit to identify this renderer + int rendererBit = 0; + // an unique number to identify this renderer : ( rendererBit = 1 << rendererId) + int rendererId = 0; + + // List of renderMolecules that are dirty due to additions + // or removal of renderAtoms from their display list set + // of renderAtoms + ArrayList dirtyRenderMoleculeList = new ArrayList(); + + // List of individual dlists that need to be rebuilt + ArrayList dirtyRenderAtomList = new ArrayList(); + + // List of (Rm, rInfo) pair of individual dlists that need to be rebuilt + ArrayList dirtyDlistPerRinfoList = new ArrayList(); + + + // Texture and display list that should be freed + ArrayList textureIdResourceFreeList = new ArrayList(); + ArrayList displayListResourceFreeList = new ArrayList(); + + // Texture that should be reload + ArrayList textureReloadList = new ArrayList(); + + + J3dMessage[] renderMessage; + + // The screen for this Renderer. Note that this renderer may share + // by both on screen and off screen. When view unregister, we need + // to set both reference to null. + Screen3D onScreen; + Screen3D offScreen; + + // full screen anti-aliasing projection matrices + Transform3D accumLeftProj = new Transform3D(); + Transform3D accumRightProj = new Transform3D(); + Transform3D accumInfLeftProj = new Transform3D(); + Transform3D accumInfRightProj = new Transform3D(); + + // rendering messages + J3dMessage m[]; + int nmesg = 0; + + // List of contexts created + ArrayList listOfCtxs = new ArrayList(); + + // Parallel list of canvases + ArrayList listOfCanvases = new ArrayList(); + + boolean needToRebuildDisplayList = false; + boolean needToResendTextureDown = false; + + // True when either one of dirtyRenderMoleculeList, + // dirtyDlistPerRinfoList, dirtyRenderAtomList size > 0 + boolean dirtyDisplayList = false; + + // Remember OGL context resources to free + // before context is destroy. + // It is used when sharedCtx = true; + ArrayList textureIDResourceTable = new ArrayList(5); + + // Instrumentation of Java 3D renderer + private long lastSwapTime = System.nanoTime(); + + private synchronized int newInstanceNum() { + return (++numInstances); + } + + int getInstanceNum() { + if (instanceNum == -1) + instanceNum = newInstanceNum(); + return instanceNum; + } + + /** + * Constructs a new Renderer + */ + Renderer(ThreadGroup t) { + super(t); + setName("J3D-Renderer-" + getInstanceNum()); + + type = J3dThread.RENDER_THREAD; + rendererId = VirtualUniverse.mc.getRendererId(); + rendererBit = (1 << rendererId); + renderMessage = new J3dMessage[1]; + } + + + /** + * The main loop for the renderer. + */ + void doWork(long referenceTime) { + RenderAtom ra; + RenderBin renderBin = null; + Canvas3D cv, canvas=null; + Object firstArg; + View view = null; + Color3f col; + int stereo_mode; + int num_stereo_passes, num_render_passes, num_accum_passes = 1; + int pass, apass, i, j, k; + boolean doAccum = false; + double accumDx = 0.0f, accumDy = 0.0f; + double accumDxFactor = 1.0f, accumDyFactor = 1.0f; + + double accumLeftX = 0.0, accumLeftY = 0.0, + accumRightX = 0.0, accumRightY = 0.0, + accumInfLeftX = 0.0, accumInfLeftY = 0.0, + accumInfRightX = 0.0, accumInfRightY = 0.0; + int opArg, status; + boolean done = false; + Transform3D t3d = null; + + opArg = ((Integer)args[0]).intValue(); + + try { + if (opArg == SWAP) { + + Object [] swapArray = (Object[])args[2]; + + view = (View)args[3]; + + for (i=0; i 0; + + c.userStencilAvailable = + (userOwnsStencil && (c.actualStencilSize > 0)); + c.systemStencilAvailable = + (!userOwnsStencil && (c.actualStencilSize > 0)); + + c.sceneAntialiasingMultiSamplesAvailable = + c.hasSceneAntialiasingMultisample(); + + if (c.sceneAntialiasingMultiSamplesAvailable) { + c.sceneAntialiasingAvailable = true; + } else { + c.sceneAntialiasingAvailable = + c.hasSceneAntialiasingAccum(); + } + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : indicate fatal error and notify error listeners + c.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR, + J3dI18N.getString("Renderer1")); + err.setCanvas3D(c); + err.setGraphicsDevice(c.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + GraphicsConfigTemplate3D.runMonitor(J3dThread.NOTIFY); + } else if (reqType == MasterControl.SET_QUERYPROPERTIES){ + try { + c.createQueryContext(); + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : indicate fatal error and notify error listeners + c.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.CONTEXT_CREATION_ERROR, + J3dI18N.getString("Renderer2")); + err.setCanvas3D(c); + err.setGraphicsDevice(c.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + // currentCtx change after we create a new context + GraphicsConfigTemplate3D.runMonitor(J3dThread.NOTIFY); + currentCtx = null; + currentDrawable = null; + } + } else if (secondArg instanceof Integer) { + // Issue 121 - This was formerly used as a message from + // the now-nonexistant TextureRetained finalize() method + // to free the texture id + throw new AssertionError(); + } else if (secondArg instanceof GeometryArrayRetained) { + // message from GeometryArrayRetained + // clearLive() to free D3D array + ((GeometryArrayRetained) secondArg).freeD3DArray(false); + } else if (secondArg instanceof GraphicsConfigTemplate3D) { + GraphicsConfigTemplate3D gct = + (GraphicsConfigTemplate3D) secondArg; + Integer reqType = (Integer) m[nmesg].args[2]; + if (reqType == MasterControl.GETBESTCONFIG) { + GraphicsConfiguration gcfg = null; + GraphicsConfiguration [] gcList = (GraphicsConfiguration []) gct.testCfg; + try { + gcfg = Pipeline.getPipeline().getBestConfiguration(gct, gcList); + } catch (NullPointerException npe) { + npe.printStackTrace(); + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : notify error listeners + RenderingError err = + new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR, + J3dI18N.getString("Renderer3")); + err.setGraphicsDevice(gcList[0].getDevice()); + notifyErrorListeners(err); + } + + gct.testCfg = gcfg; + } else if (reqType == MasterControl.ISCONFIGSUPPORT) { + boolean rval = false; + GraphicsConfiguration gc = (GraphicsConfiguration) gct.testCfg; + try { + if (Pipeline.getPipeline().isGraphicsConfigSupported(gct, gc)) { + rval = true; + } + } catch (NullPointerException npe) { + npe.printStackTrace(); + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : notify error listeners + RenderingError err = + new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR, + J3dI18N.getString("Renderer4")); + err.setGraphicsDevice(gc.getDevice()); + notifyErrorListeners(err); + } + + gct.testCfg = Boolean.valueOf(rval); + } + gct.runMonitor(J3dThread.NOTIFY); + } + + m[nmesg++].decRefcount(); + continue; + } + + canvas = (Canvas3D) firstArg; + + renderType = m[nmesg].type; + + if (renderType == J3dMessage.CREATE_OFFSCREENBUFFER) { + // Fix for issue 18. + // Fix for issue 20. + + canvas.drawable = null; + try { + // Issue 396. Pass in a null ctx for 2 reasons : + // 1) We should not use ctx field directly without buffering in a msg. + // 2) canvas.ctx should be null. + canvas.drawable = + canvas.createOffScreenBuffer(null, + canvas.screen.display, + canvas.fbConfig, + canvas.offScreenCanvasSize.width, + canvas.offScreenCanvasSize.height); + } catch (RuntimeException ex) { + ex.printStackTrace(); + } + + if (canvas.drawable == null) { + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.OFF_SCREEN_BUFFER_ERROR, + J3dI18N.getString("Renderer5")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + + canvas.offScreenBufferPending = false; + m[nmesg++].decRefcount(); + continue; + } + else if (renderType == J3dMessage.DESTROY_CTX_AND_OFFSCREENBUFFER) { + Object[] obj = m[nmesg].args; + + // Fix for issue 175: destroy ctx & off-screen buffer + // Fix for issue 340: get display, drawable & ctx from msg + removeCtx(canvas, + ((Long) obj[1]).longValue(), + (Drawable) obj[2], + (Context) obj[3], + false, !canvas.offScreen, true); + + canvas.offScreenBufferPending = false; + m[nmesg++].decRefcount(); + continue; + } else if (renderType == J3dMessage.ALLOCATE_CANVASID) { + canvas.allocateCanvasId(); + } else if (renderType == J3dMessage.FREE_CANVASID) { + canvas.freeCanvasId(); + } + + if ((canvas.view == null) || !canvas.firstPaintCalled) { + // This happen when the canvas just remove from the View + if (renderType == J3dMessage.RENDER_OFFSCREEN) { + canvas.offScreenRendering = false; + } + m[nmesg++].decRefcount(); + continue; + } + + if (!canvas.validCanvas && + (renderType != J3dMessage.RENDER_OFFSCREEN)) { + m[nmesg++].decRefcount(); + continue; + } + + if (renderType == J3dMessage.RESIZE_CANVAS) { + canvas.d3dResize(); + // render the image again after resize + VirtualUniverse.mc.sendRunMessage(canvas.view, J3dThread.RENDER_THREAD); + m[nmesg++].decRefcount(); + } else if (renderType == J3dMessage.TOGGLE_CANVAS) { + canvas.d3dToggle(); + VirtualUniverse.mc.sendRunMessage(canvas.view, J3dThread.RENDER_THREAD); + m[nmesg++].decRefcount(); + } else if (renderType == J3dMessage.RENDER_IMMEDIATE) { + int command = ((Integer)m[nmesg].args[1]).intValue(); + //System.err.println("command= " + command); + if (needToResendTextureDown) { + VirtualUniverse.mc.resendTexTimestamp++; + needToResendTextureDown = false; + } + + if (canvas.isFatalError()) { + continue; + } + + try { + if (canvas.ctx != null) { + // ctx may not construct until doClear(); + canvas.beginScene(); + } + + switch (command) { + case GraphicsContext3D.CLEAR: + canvas.graphicsContext3D.doClear(); + break; + case GraphicsContext3D.DRAW: + canvas.graphicsContext3D.doDraw( + (Geometry)m[nmesg].args[2]); + break; + case GraphicsContext3D.SWAP: + canvas.doSwap(); + break; + case GraphicsContext3D.READ_RASTER: + canvas.graphicsContext3D.doReadRaster( + (Raster)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_APPEARANCE: + canvas.graphicsContext3D.doSetAppearance( + (Appearance)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_BACKGROUND: + canvas.graphicsContext3D.doSetBackground( + (Background)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_FOG: + canvas.graphicsContext3D.doSetFog( + (Fog)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_LIGHT: + canvas.graphicsContext3D.doSetLight( + (Light)m[nmesg].args[2], + ((Integer)m[nmesg].args[3]).intValue()); + break; + case GraphicsContext3D.INSERT_LIGHT: + canvas.graphicsContext3D.doInsertLight( + (Light)m[nmesg].args[2], + ((Integer)m[nmesg].args[3]).intValue()); + break; + case GraphicsContext3D.REMOVE_LIGHT: + canvas.graphicsContext3D.doRemoveLight( + ((Integer)m[nmesg].args[2]).intValue()); + break; + case GraphicsContext3D.ADD_LIGHT: + canvas.graphicsContext3D.doAddLight( + (Light)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_HI_RES: + canvas.graphicsContext3D.doSetHiRes( + (HiResCoord)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_MODEL_TRANSFORM: + t3d = (Transform3D)m[nmesg].args[2]; + canvas.graphicsContext3D.doSetModelTransform(t3d); + break; + case GraphicsContext3D.MULTIPLY_MODEL_TRANSFORM: + t3d = (Transform3D)m[nmesg].args[2]; + canvas.graphicsContext3D.doMultiplyModelTransform(t3d); + break; + case GraphicsContext3D.SET_SOUND: + canvas.graphicsContext3D.doSetSound( + (Sound)m[nmesg].args[2], + ((Integer)m[nmesg].args[3]).intValue()); + break; + case GraphicsContext3D.INSERT_SOUND: + canvas.graphicsContext3D.doInsertSound( + (Sound)m[nmesg].args[2], + ((Integer)m[nmesg].args[3]).intValue()); + break; + case GraphicsContext3D.REMOVE_SOUND: + canvas.graphicsContext3D.doRemoveSound( + ((Integer)m[nmesg].args[2]).intValue()); + break; + case GraphicsContext3D.ADD_SOUND: + canvas.graphicsContext3D.doAddSound( + (Sound)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_AURAL_ATTRIBUTES: + canvas.graphicsContext3D.doSetAuralAttributes( + (AuralAttributes)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_BUFFER_OVERRIDE: + canvas.graphicsContext3D.doSetBufferOverride( + ((Boolean)m[nmesg].args[2]).booleanValue()); + break; + case GraphicsContext3D.SET_FRONT_BUFFER_RENDERING: + canvas.graphicsContext3D.doSetFrontBufferRendering( + ((Boolean)m[nmesg].args[2]).booleanValue()); + break; + case GraphicsContext3D.SET_STEREO_MODE: + canvas.graphicsContext3D.doSetStereoMode( + ((Integer)m[nmesg].args[2]).intValue()); + break; + case GraphicsContext3D.FLUSH: + canvas.graphicsContext3D.doFlush( + ((Boolean)m[nmesg].args[2]).booleanValue()); + break; + case GraphicsContext3D.FLUSH2D: + canvas.graphics2D.doFlush(); + break; + case GraphicsContext3D.DRAWANDFLUSH2D: + Object ar[] = m[nmesg].args; + canvas.graphics2D.doDrawAndFlushImage( + (BufferedImage) ar[2], + ((Point) ar[3]).x, + ((Point) ar[3]).y, + (ImageObserver) ar[4]); + break; + case GraphicsContext3D.DISPOSE2D: + // Issue 583 - the graphics2D field may be null here + if (canvas.graphics2D != null) { + canvas.graphics2D.doDispose(); + } + break; + case GraphicsContext3D.SET_MODELCLIP: + canvas.graphicsContext3D.doSetModelClip( + (ModelClip)m[nmesg].args[2]); + break; + default: + break; + } + + if (canvas.ctx != null) { + canvas.endScene(); + } + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.CONTEXT_CREATION_ERROR, + J3dI18N.getString("Renderer6")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + + m[nmesg++].decRefcount(); + } else { // retained mode rendering + long startRenderTime = 0L; + if (MasterControl.isStatsLoggable(Level.INFO)) { + // Instrumentation of Java 3D renderer + startRenderTime = System.nanoTime(); + } + + m[nmesg++].decRefcount(); + + if (canvas.isFatalError()) { + continue; + } + + ImageComponent2DRetained offBufRetained = null; + + if (renderType == J3dMessage.RENDER_OFFSCREEN) { + // Issue 131: set offScreenRendering flag here, since it + // otherwise won't be set for auto-off-screen rendering + // (which doesn't use renderOffScreenBuffer) + canvas.offScreenRendering = true; + if (canvas.drawable == null || !canvas.active) { + canvas.offScreenRendering = false; + continue; + } else { + offBufRetained = (ImageComponent2DRetained) + canvas.offScreenBuffer.retained; + + if (offBufRetained.isByReference()) { + offBufRetained.geomLock.getLock(); + } + + offBufRetained.evaluateExtensions(canvas); + + } + + } else if (!canvas.active) { + continue; + } + + // Issue 78 - need to get the drawingSurface info every + // frame; this is necessary since the HDC (window ID) + // on Windows can become invalidated without our + // being notified! + if (!canvas.offScreen) { + canvas.drawingSurfaceObject.getDrawingSurfaceObjectInfo(); + } + + renderBin = canvas.view.renderBin; + + // setup rendering context + + // We need to catch NullPointerException when the dsi + // gets yanked from us during a remove. + + if (canvas.useSharedCtx) { + + if (sharedCtx == null) { + sharedCtxDisplay = canvas.screen.display; + sharedCtxDrawable = canvas.drawable; + + // Always lock for context create + if (!canvas.drawingSurfaceObject.renderLock()) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + synchronized (VirtualUniverse.mc.contextCreationLock) { + sharedCtx = null; + try { + sharedCtx = canvas.createNewContext(null, true); + } catch (RuntimeException ex) { + ex.printStackTrace(); + } + + if (sharedCtx == null) { + canvas.drawingSurfaceObject.unLock(); + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.CONTEXT_CREATION_ERROR, + J3dI18N.getString("Renderer7")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + + break doneRender; + } + sharedCtxTimeStamp = + VirtualUniverse.mc.getContextTimeStamp(); + + needToRebuildDisplayList = true; + } + + canvas.drawingSurfaceObject.unLock(); + } + } + + if (canvas.ctx == null) { + + // Always lock for context create + if (!canvas.drawingSurfaceObject.renderLock()) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + synchronized (VirtualUniverse.mc.contextCreationLock) { + canvas.ctx = null; + try { + canvas.ctx = canvas.createNewContext(sharedCtx, false); + } catch (RuntimeException ex) { + ex.printStackTrace(); + } + + if (canvas.ctx == null) { + canvas.drawingSurfaceObject.unLock(); + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.CONTEXT_CREATION_ERROR, + J3dI18N.getString("Renderer7")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + + break doneRender; + } + + if (canvas.graphics2D != null) { + canvas.graphics2D.init(); + } + + canvas.ctxTimeStamp = + VirtualUniverse.mc.getContextTimeStamp(); + listOfCtxs.add(canvas.ctx); + listOfCanvases.add(canvas); + + if (renderBin.nodeComponentList.size() > 0) { + for (i = 0; i < renderBin.nodeComponentList.size(); i++) { + NodeComponentRetained nc = (NodeComponentRetained)renderBin.nodeComponentList.get(i); + if(nc instanceof ImageComponentRetained) { + ((ImageComponentRetained)nc).evaluateExtensions(canvas); + } + } + } + + // enable separate specular color + canvas.enableSeparateSpecularColor(); + } + + // create the cache texture state in canvas + // for state download checking purpose + if (canvas.texUnitState == null) { + canvas.createTexUnitState(); + } + + canvas.resetImmediateRendering(Canvas3D.NOCHANGE); + canvas.drawingSurfaceObject.contextValidated(); + + if (!canvas.useSharedCtx) { + canvas.needToRebuildDisplayList = true; + } + canvas.drawingSurfaceObject.unLock(); + } else { + + if (canvas.isRunning) { + canvas.makeCtxCurrent(); + } + } + + + if (renderBin != null) { + if ((VirtualUniverse.mc.doDsiRenderLock) && + (!canvas.drawingSurfaceObject.renderLock())) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + if (needToResendTextureDown) { + VirtualUniverse.mc.resendTexTimestamp++; + needToResendTextureDown = false; + } + // handle free resource + if (canvas.useSharedCtx) { + freeResourcesInFreeList(canvas); + } else { + canvas.freeResourcesInFreeList(canvas.ctx); + } + + if (VirtualUniverse.mc.doDsiRenderLock) { + canvas.drawingSurfaceObject.unLock(); + } + + // Issue 109 : removed copyOfCvCache now that we have + // a separate canvasViewCache for computing view frustum + CanvasViewCache cvCache = canvas.canvasViewCache; + + // Deadlock if we include updateViewCache in + // drawingSurfaceObject sync. + canvas.updateViewCache(false, null, null, + renderBin.geometryBackground != null); + + if ((VirtualUniverse.mc.doDsiRenderLock) && + (!canvas.drawingSurfaceObject.renderLock())) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + // setup viewport + canvas.setViewport(canvas.ctx, 0, 0, + cvCache.getCanvasWidth(), + cvCache.getCanvasHeight()); + + + + // rebuild the display list of all dirty renderMolecules. + if (canvas.useSharedCtx) { + if (needToRebuildDisplayList) { + renderBin.updateAllRenderMolecule( + this, canvas); + needToRebuildDisplayList = false; + } + + if (dirtyDisplayList) { + renderBin.updateDirtyDisplayLists(canvas, + dirtyRenderMoleculeList, + dirtyDlistPerRinfoList, + dirtyRenderAtomList,true); + dirtyDisplayList = false; + } + + // for shared context, download textures upfront + // to minimize the context switching overhead + int sz = textureReloadList.size(); + + if (sz > 0) { + for (j = sz-1; j>=0; j--) { + ((TextureRetained)textureReloadList.get(j)). + reloadTextureSharedContext(canvas); + } + textureReloadList.clear(); + } + + } else { + // update each canvas + if (canvas.needToRebuildDisplayList) { + renderBin.updateAllRenderMolecule(canvas); + canvas.needToRebuildDisplayList = false; + } + if (canvas.dirtyDisplayList) { + renderBin.updateDirtyDisplayLists(canvas, + canvas.dirtyRenderMoleculeList, + canvas.dirtyDlistPerRinfoList, + canvas.dirtyRenderAtomList, false); + canvas.dirtyDisplayList = false; + } + } + + // lighting setup + if (canvas.view.localEyeLightingEnable != + canvas.ctxEyeLightingEnable) { + canvas.ctxUpdateEyeLightingEnable(canvas.ctx, + canvas.view.localEyeLightingEnable); + canvas.ctxEyeLightingEnable = + canvas.view.localEyeLightingEnable; + } + + + // stereo setup + boolean useStereo = cvCache.getUseStereo(); + if (useStereo) { + num_stereo_passes = 2; + stereo_mode = Canvas3D.FIELD_LEFT; + + sharedStereoZBuffer = + VirtualUniverse.mc.sharedStereoZBuffer; + } else { + num_stereo_passes = 1; + stereo_mode = Canvas3D.FIELD_ALL; + + // just in case user set flag - + // disable since we are not in stereo + sharedStereoZBuffer = false; + } + + // full screen anti-aliasing setup + if (canvas.view.getSceneAntialiasingEnable() && + canvas.sceneAntialiasingAvailable) { + + if (!VirtualUniverse.mc.isD3D() && + ((canvas.extensionsSupported & Canvas3D.MULTISAMPLE) == 0) || + !canvas.sceneAntialiasingMultiSamplesAvailable) { + doAccum = true; + num_accum_passes = NUM_ACCUMULATION_SAMPLES; + + System.arraycopy( + cvCache.getLeftProjection().mat, + 0, accumLeftProj.mat, 0, 16); + + + accumDxFactor = ( + canvas.canvasViewCache.getPhysicalWindowWidth() / + canvas.canvasViewCache.getCanvasWidth())*canvas.view.fieldOfView; + + accumDyFactor = ( + canvas.canvasViewCache.getPhysicalWindowHeight() / + canvas.canvasViewCache.getCanvasHeight())*canvas.view.fieldOfView; + + + accumLeftX = accumLeftProj.mat[3]; + accumLeftY = accumLeftProj.mat[7]; + + if (useStereo) { + System.arraycopy( + cvCache.getRightProjection().mat, + 0, accumRightProj.mat, 0, 16); + accumRightX = accumRightProj.mat[3]; + accumRightY = accumRightProj.mat[7]; + } + + if (renderBin.geometryBackground != null) { + System.arraycopy( + cvCache.getInfLeftProjection().mat, + 0, accumInfLeftProj.mat, 0, 16); + accumInfLeftX = accumInfLeftProj.mat[3]; + accumInfLeftY = accumInfLeftProj.mat[7]; + if (useStereo) { + System.arraycopy( + cvCache.getInfRightProjection().mat, + 0, accumInfRightProj.mat, 0, 16); + accumInfRightX = accumInfRightProj.mat[3]; + accumInfRightY = accumInfRightProj.mat[7]; + } + } + } else { + + if (!canvas.antialiasingSet) { + // System.err.println("Renderer : Enable FullSceneAntialiasing"); + + canvas.setFullSceneAntialiasing(canvas.ctx, true); + canvas.antialiasingSet = true; + } + } + } else { + + if (canvas.antialiasingSet) { + // System.err.println("Renderer : Disable SceneAntialiasing"); + canvas.setFullSceneAntialiasing(canvas.ctx, false); + canvas.antialiasingSet = false; + } + } + + // background geometry setup + if (renderBin.geometryBackground != null) { + renderBin.updateInfVworldToVpc(); + } + + // setup default render mode - render to both eyes + canvas.setRenderMode(canvas.ctx, + Canvas3D.FIELD_ALL, + canvas.useDoubleBuffer); + + canvas.beginScene(); + + // this is if the background image resizes with the canvas + int winWidth = cvCache.getCanvasWidth(); + int winHeight = cvCache.getCanvasHeight(); + + + // clear background if not full screen antialiasing + // and not in stereo mode + if (!doAccum && !sharedStereoZBuffer) { + BackgroundRetained bg = renderBin.background; + + canvas.clear(bg, winWidth, winHeight); + + } + + // handle preRender callback + if (VirtualUniverse.mc.doDsiRenderLock) { + canvas.drawingSurfaceObject.unLock(); + } + canvas.view.inCanvasCallback = true; + + try { + canvas.preRender(); + } catch (RuntimeException e) { + System.err.println("Exception occurred during Canvas3D callback:"); + e.printStackTrace(); + } catch (Error e) { + // Issue 264 - catch Error so Renderer doesn't die + System.err.println("Error occurred during Canvas3D callback:"); + e.printStackTrace(); + } + canvas.view.inCanvasCallback = false; + + if ((VirtualUniverse.mc.doDsiRenderLock) && + (!canvas.drawingSurfaceObject.renderLock())) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + // render loop + for (pass = 0; pass < num_stereo_passes; pass++) { + if (doAccum) { + canvas.clearAccum(canvas.ctx); + } + canvas.setRenderMode(canvas.ctx, stereo_mode, + canvas.useDoubleBuffer); + + + + for (apass = 0; apass < num_accum_passes; apass++) { + + // jitter projection matrix and clear background + // for full screen anti-aliasing rendering + if (doAccum) { + accumDx = ACCUM_SAMPLES_X[apass] * + accumDxFactor; + accumDy = ACCUM_SAMPLES_Y[apass] * + accumDyFactor; + + accumLeftProj.mat[3] = accumLeftX + + accumLeftProj.mat[0] * accumDx + + accumLeftProj.mat[1] * accumDy; + + accumLeftProj.mat[7] = accumLeftY + + accumLeftProj.mat[4] * accumDx + + accumLeftProj.mat[5] * accumDy; + + if (useStereo) { + accumRightProj.mat[3] = accumRightX + + accumRightProj.mat[0] * accumDx + + accumRightProj.mat[1] * accumDy; + + accumRightProj.mat[7] = accumRightY + + accumRightProj.mat[4] * accumDx + + accumRightProj.mat[5] * accumDy; + } + + if (renderBin.geometryBackground != null) { + accumInfLeftProj.mat[3] = accumInfLeftX + + accumInfLeftProj.mat[0] * accumDx + + accumInfLeftProj.mat[1] * accumDy; + + accumInfLeftProj.mat[7] = accumInfLeftY + + accumInfLeftProj.mat[4] * accumDx + + accumInfLeftProj.mat[5] * accumDy; + + if (useStereo) { + accumInfRightProj.mat[3] = + accumInfRightX + + accumInfRightProj.mat[0] * accumDx + + accumInfRightProj.mat[1] * accumDy; + + accumInfRightProj.mat[7] = + accumInfRightY + + accumInfRightProj.mat[4] * accumDx + + accumInfRightProj.mat[5] * accumDy; + } + } + } + + // clear background for stereo and + // accumulation buffer cases + if (doAccum || sharedStereoZBuffer) { + BackgroundRetained bg = renderBin.background; + + canvas.clear(bg, winWidth, winHeight); + + } + + // render background geometry + if (renderBin.geometryBackground != null) { + + // setup rendering matrices + if (pass == 0) { + canvas.vpcToEc = + cvCache.getInfLeftVpcToEc(); + if (doAccum) { + canvas.setProjectionMatrix( + canvas.ctx, accumInfLeftProj); + } else { + canvas.setProjectionMatrix( + canvas.ctx, + cvCache.getInfLeftProjection()); + } + } else { + canvas.vpcToEc = + cvCache.getInfRightVpcToEc(); + if (doAccum) { + canvas.setProjectionMatrix( + canvas.ctx, accumInfRightProj); + } else { + canvas.setProjectionMatrix( + canvas.ctx, + cvCache.getInfRightProjection()); + } + } + canvas.vworldToEc.mul(canvas.vpcToEc, + cvCache.getInfVworldToVpc()); + + // render background geometry + renderBin.renderBackground(canvas); + } + + // setup rendering matrices + if (pass == 0) { + canvas.vpcToEc = cvCache.getLeftVpcToEc(); + if (doAccum) { + canvas.setProjectionMatrix(canvas.ctx, accumLeftProj); + } else { + canvas.setProjectionMatrix(canvas.ctx, + cvCache.getLeftProjection()); + } + } else { + canvas.vpcToEc = cvCache.getRightVpcToEc(); + if (doAccum) { + canvas.setProjectionMatrix( + canvas.ctx, accumRightProj); + } else { + canvas.setProjectionMatrix(canvas.ctx, + cvCache.getRightProjection()); + } + } + canvas.vworldToEc.mul(canvas.vpcToEc, + cvCache.getVworldToVpc()); + + + synchronized (cvCache) { + if (pass == 0) { + canvas.setFrustumPlanes(cvCache.getLeftFrustumPlanesInVworld()); + } else { + canvas.setFrustumPlanes(cvCache.getRightFrustumPlanesInVworld()); + } + } + + // Force view matrix dirty for each eye. + if (useStereo) { + canvas.canvasDirty |= Canvas3D.VIEW_MATRIX_DIRTY; + } + + // render opaque geometry + renderBin.renderOpaque(canvas); + + // render ordered geometry + renderBin.renderOrdered(canvas); + + // handle renderField callback + if (VirtualUniverse.mc.doDsiRenderLock) { + canvas.drawingSurfaceObject.unLock(); + } + canvas.view.inCanvasCallback = true; + try { + canvas.renderField(stereo_mode); + } catch (RuntimeException e) { + System.err.println("Exception occurred during Canvas3D callback:"); + e.printStackTrace(); + } catch (Error e) { + // Issue 264 - catch Error so Renderer doesn't die + System.err.println("Error occurred during Canvas3D callback:"); + e.printStackTrace(); + } + canvas.view.inCanvasCallback = false; + if ((VirtualUniverse.mc.doDsiRenderLock) && + (!canvas.drawingSurfaceObject.renderLock())) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + // render transparent geometry + renderBin.renderTransparent(canvas); + + if (doAccum) + canvas.accum(canvas.ctx, accumValue); + } + + if (doAccum) + canvas.accumReturn(canvas.ctx); + if (useStereo) { + stereo_mode = Canvas3D.FIELD_RIGHT; + canvas.rightStereoPass = true; + } + } + canvas.imageReady = true; + canvas.rightStereoPass = false; + + // reset renderMode + canvas.setRenderMode(canvas.ctx, + Canvas3D.FIELD_ALL, + canvas.useDoubleBuffer); + + // handle postRender callback + if (VirtualUniverse.mc.doDsiRenderLock) { + canvas.drawingSurfaceObject.unLock(); + } + canvas.view.inCanvasCallback = true; + + try { + canvas.postRender(); + } catch (RuntimeException e) { + System.err.println("Exception occurred during Canvas3D callback:"); + e.printStackTrace(); + } catch (Error e) { + // Issue 264 - catch Error so Renderer doesn't die + System.err.println("Error occurred during Canvas3D callback:"); + e.printStackTrace(); + } + canvas.view.inCanvasCallback = false; + + // end offscreen rendering + if (canvas.offScreenRendering) { + + canvas.syncRender(canvas.ctx, true); + canvas.endOffScreenRendering(); + canvas.offScreenRendering = false; + + // Issue 489 - don't call postSwap here for auto-offscreen, + // since it will be called later by the SWAP operation + if (canvas.manualRendering) { + // do the postSwap for offscreen here + canvas.view.inCanvasCallback = true; + try { + canvas.postSwap(); + } catch (RuntimeException e) { + System.err.println("Exception occurred during Canvas 3D callback:"); + e.printStackTrace(); + } catch (Error e) { + // Issue 264 - catch Error so Renderer doesn't die + System.err.println("Error occurred during Canvas3D callback:"); + e.printStackTrace(); + } + + if (offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + + canvas.view.inCanvasCallback = false; + + canvas.releaseCtx(); + } + } + + canvas.endScene(); + + if (MasterControl.isStatsLoggable(Level.INFO)) { + // Instrumentation of Java 3D renderer + long deltaTime = System.nanoTime() - startRenderTime; + VirtualUniverse.mc.recordTime(MasterControl.TimeType.RENDER, deltaTime); + } + + } else { // if (renderBin != null) + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + } + } + } + + // clear array to prevent memory leaks + if (opArg == RENDER) { + m[0] = null; + } else { + Arrays.fill(m, 0, totalMessages, null); + } + } + } catch (NullPointerException ne) { + // Print NPE, but otherwise ignore it + ne.printStackTrace(); + if (canvas != null) { + if (canvas.ctx != null) { + canvas.endScene(); + } + // drawingSurfaceObject will safely ignore + // this request if this is not lock before + canvas.drawingSurfaceObject.unLock(); + + } + } catch (RuntimeException ex) { + ex.printStackTrace(); + + if (canvas != null) { + if (canvas.ctx != null) { + canvas.endScene(); + } + // drawingSurfaceObject will safely ignore + // this request if this is not lock before + canvas.drawingSurfaceObject.unLock(); + } + + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.UNEXPECTED_RENDERING_ERROR, + J3dI18N.getString("Renderer8")); + err.setCanvas3D(canvas); + if (canvas != null) { + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + } + notifyErrorListeners(err); + } + } + + // resource clean up + void shutdown() { + removeAllCtxs(); + Pipeline.getPipeline().cleanupRenderer(); + } + + void cleanup() { + super.cleanup(); + renderMessage = new J3dMessage[1]; + rendererStructure = new RendererStructure(); + bgVworldToVpc = new Transform3D(); + sharedCtx = null; + sharedCtxTimeStamp = 0; + sharedCtxDisplay = 0; + sharedCtxDrawable = null; + dirtyRenderMoleculeList.clear(); + dirtyRenderAtomList.clear(); + dirtyDlistPerRinfoList.clear(); + textureIdResourceFreeList.clear(); + displayListResourceFreeList.clear(); + onScreen = null; + offScreen = null; + m = null; + nmesg = 0; + } + + + // This is only invoked from removeCtx()/removeAllCtxs() + // with drawingSurface already lock + final void makeCtxCurrent(Context sharedCtx, long display, Drawable drawable) { + if (sharedCtx != currentCtx || drawable != currentDrawable) { + Canvas3D.useCtx(sharedCtx, display, drawable); + /* + if(!Canvas3D.useCtx(sharedCtx, display, drawable)) { + Thread.dumpStack(); + System.err.println("useCtx Fail"); + } + */ + currentCtx = sharedCtx; + currentDrawable = drawable; + } + } + + // No need to free graphics2d and background if it is from + // Canvas3D postRequest() offScreen rendering since the + // user thread will not wait for it. Also we can just + // reuse it as Canvas3D did not destroy. + private void removeCtx(Canvas3D cv, long display, Drawable drawable, Context ctx, + boolean resetCtx, boolean freeBackground, + boolean destroyOffScreenBuffer) { + + synchronized (VirtualUniverse.mc.contextCreationLock) { + if (ctx != null) { + int idx = listOfCtxs.indexOf(ctx); + if (idx >= 0) { + listOfCtxs.remove(idx); + listOfCanvases.remove(idx); + // Issue 326 : don't check display variable here + if ((drawable != null) && cv.added) { + // cv.ctx may reset to -1 here so we + // always use the ctx pass in. + if (cv.drawingSurfaceObject.renderLock()) { + // if it is the last one, free shared resources + if (sharedCtx != null) { + if (listOfCtxs.isEmpty()) { + makeCtxCurrent(sharedCtx, sharedCtxDisplay, sharedCtxDrawable); + freeResourcesInFreeList(null); + freeContextResources(); + Canvas3D.destroyContext(sharedCtxDisplay, sharedCtxDrawable, sharedCtx); + currentCtx = null; + currentDrawable = null; + } else { + freeResourcesInFreeList(cv); + } + cv.makeCtxCurrent(ctx, display, drawable); + } else { + cv.makeCtxCurrent(ctx, display, drawable); + cv.freeResourcesInFreeList(ctx); + } + cv.freeContextResources(this, freeBackground, ctx); + Canvas3D.destroyContext(display, drawable, ctx); + currentCtx = null; + currentDrawable = null; + cv.drawingSurfaceObject.unLock(); + } + } + } + + if (resetCtx) { + cv.ctx = null; + } + + if ((sharedCtx != null) && listOfCtxs.isEmpty()) { + sharedCtx = null; + sharedCtxTimeStamp = 0; + } + cv.ctxTimeStamp = 0; + } + + // Fix for issue 18. + // Since we are now the renderer thread, + // we can safely execute destroyOffScreenBuffer. + if(destroyOffScreenBuffer) { + cv.destroyOffScreenBuffer(ctx, display, cv.fbConfig, drawable); + cv.offScreenBufferPending = false; + } + } + } + + void removeAllCtxs() { + Canvas3D cv; + + synchronized (VirtualUniverse.mc.contextCreationLock) { + + for (int i=listOfCanvases.size()-1; i >=0; i--) { + cv = (Canvas3D) listOfCanvases.get(i); + + if ((cv.screen != null) && (cv.ctx != null)) { + // Issue 326 : don't check display variable here + if ((cv.drawable != null) && cv.added) { + if (cv.drawingSurfaceObject.renderLock()) { + // We need to free sharedCtx resource + // first before last non-sharedCtx to + // workaround Nvidia driver bug under Linux + // that crash on freeTexture ID:4685156 + if ((i == 0) && (sharedCtx != null)) { + makeCtxCurrent(sharedCtx, sharedCtxDisplay, sharedCtxDrawable); + freeResourcesInFreeList(null); + freeContextResources(); + Canvas3D.destroyContext(sharedCtxDisplay, sharedCtxDrawable, sharedCtx); + currentCtx = null; + currentDrawable = null; + } + cv.makeCtxCurrent(); + cv.freeResourcesInFreeList(cv.ctx); + cv.freeContextResources(this, true, cv.ctx); + Canvas3D.destroyContext(cv.screen.display, + cv.drawable, + cv.ctx); + currentCtx = null; + currentDrawable = null; + cv.drawingSurfaceObject.unLock(); + } + } + } + + cv.ctx = null; + cv.ctxTimeStamp = 0; + } + + if (sharedCtx != null) { + sharedCtx = null; + sharedCtxTimeStamp = 0; + } + listOfCanvases.clear(); + listOfCtxs.clear(); + } + } + + // handle free resource in the FreeList + void freeResourcesInFreeList(Canvas3D cv) { + Iterator it; + boolean isFreeTex = (textureIdResourceFreeList.size() > 0); + boolean isFreeDL = (displayListResourceFreeList.size() > 0); + ArrayList list; + int i, val; + GeometryArrayRetained geo; + + if (isFreeTex || isFreeDL) { + if (cv != null) { + cv.makeCtxCurrent(sharedCtx); + } + + if (isFreeDL) { + for (it = displayListResourceFreeList.iterator(); it.hasNext();) { + val = ((Integer) it.next()).intValue(); + if (val <= 0) { + continue; + } + Canvas3D.freeDisplayList(sharedCtx, val); + } + displayListResourceFreeList.clear(); + } + if (isFreeTex) { + for (it = textureIdResourceFreeList.iterator(); it.hasNext();) { + val = ((Integer) it.next()).intValue(); + if (val <= 0) { + continue; + } + if (val >= textureIDResourceTable.size()) { + MasterControl.getCoreLogger().severe( + "Error in freeResourcesInFreeList : ResourceIDTableSize = " + + textureIDResourceTable.size() + + " val = " + val); + } else { + Object obj = textureIDResourceTable.get(val); + if (obj instanceof TextureRetained) { + TextureRetained tex = (TextureRetained) obj; + synchronized (tex.resourceLock) { + tex.resourceCreationMask &= ~rendererBit; + if (tex.resourceCreationMask == 0) { + tex.freeTextureId(val); + } + } + } + + textureIDResourceTable.set(val, null); + } + Canvas3D.freeTexture(sharedCtx, val); + } + textureIdResourceFreeList.clear(); + } + if (cv != null) { + cv.makeCtxCurrent(cv.ctx); + } + } + } + + final void addTextureResource(int id, Object obj) { + if (textureIDResourceTable.size() <= id) { + for (int i=textureIDResourceTable.size(); + i < id; i++) { + textureIDResourceTable.add(null); + } + textureIDResourceTable.add(obj); + } else { + textureIDResourceTable.set(id, obj); + } + } + + void freeContextResources() { + Object obj; + TextureRetained tex; + + for (int id = textureIDResourceTable.size()-1; id >= 0; id--) { + obj = textureIDResourceTable.get(id); + if (obj == null) { + continue; + } + Canvas3D.freeTexture(sharedCtx, id); + if (obj instanceof TextureRetained) { + tex = (TextureRetained) obj; + synchronized (tex.resourceLock) { + tex.resourceCreationMask &= ~rendererBit; + if (tex.resourceCreationMask == 0) { + tex.freeTextureId(id); + } + } + } + } + textureIDResourceTable.clear(); + + // displayList is free in Canvas.freeContextResources() + } + + /** + * Send a message to the notification thread, which will call the + * shader error listeners. + */ + static void notifyErrorListeners(RenderingError err) { + J3dNotification notification = new J3dNotification(); + notification.type = J3dNotification.RENDERING_ERROR; + notification.universe = null;//cv.view.universe; + notification.args[0] = err; + VirtualUniverse.mc.sendNotification(notification); + } + + + // Default rendering error listener class + private static RenderingErrorListener defaultErrorListener = null; + + synchronized static RenderingErrorListener getDefaultErrorListener() { + if (defaultErrorListener == null) { + defaultErrorListener = new DefaultErrorListener(); + } + + return defaultErrorListener; + } + + static class DefaultErrorListener implements RenderingErrorListener { + public void errorOccurred(RenderingError error) { + System.err.println(); + System.err.println("DefaultRenderingErrorListener.errorOccurred:"); + error.printVerbose(); + System.exit(1); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RendererStructure.java b/j3d-core/src/classes/share/javax/media/j3d/RendererStructure.java new file mode 100644 index 0000000..a03f8e8 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RendererStructure.java @@ -0,0 +1,75 @@ +/* + * $RCSfile: RendererStructure.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:28 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * A renderer structure is an object that organizes messages + * to the renderer thread. + */ +class RendererStructure extends J3dStructure{ + + /** + * This constructor does nothing + */ + RendererStructure() { + super(null, J3dThread.RENDER_THREAD); + } + + /** + * Returns all messages in the queue. + */ + J3dMessage[] getMessages() { + int sz; + + synchronized (messageList) { + if ((sz = messageList.size()) > 0) { + if (msgList.length < sz) { + msgList = new J3dMessage[sz]; + } + messageList.toArrayAndClear(msgList); + } + } + + nMessage = sz; + return msgList; + } + + + void processMessages(long referenceTime) {} + + void removeNodes(J3dMessage m) {} + + void cleanup() {} +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderingAttributes.java b/j3d-core/src/classes/share/javax/media/j3d/RenderingAttributes.java new file mode 100644 index 0000000..4af76a2 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderingAttributes.java @@ -0,0 +1,1503 @@ +/* + * $RCSfile: RenderingAttributes.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The RenderingAttributes object defines common rendering attributes + * for all primitive types. The rendering attributes are:

+ *

    + *
  • Depth test function - used to compare the incoming (source) depth of + * each pixel with depth of the pixel stored in frame buffer. If the test + * passes, the pixel is written, otherwise the pixel is not written. The depth test + * function is set with the setDepthTestFunction + * method. By default, LESS_OR_EQUAL is the function used. The depth test + * function is one of the following:
  • + *

      + *
    • ALWAYS - pixels are always drawn, irrespective of the depth + * value. This effectively disables depth testing.
    • + * + *

    • NEVER - pixels are never drawn, irrespective of the depth + * value.
    • + * + *

    • EQUAL - pixels are drawn if the incoming pixel depth is equal + * to the stored pixel depth in the frame buffer.
    • + * + *

    • NOT_EQUAL - pixels are drawn if the incoming pixel depth is + * not equal to the stored pixel depth in the frame buffer.
    • + * + *

    • LESS - pixels are drawn if the incoming pixel depth is less + * than the stored pixel depth in the frame buffer.
    • + * + *

    • LESS_OR_EQUAL - pixels are drawn if the incoming pixel depth + * is less than or equal to the stored pixel depth in the frame buffer. + * This is the default setting.
    • + * + *

    • GREATER - pixels are drawn if the incoming pixel depth is greater + * than the stored pixel depth in the frame buffer.
    • + * + *

    • GREATER_OR_EQUAL - pixels are drawn if the incoming pixel depth + * is greater than or equal to the stored pixel depth in the frame buffer.
    • + *

    + * + *
  • Alpha test function - used to compare the incoming (source) alpha value + * of each pixel with the alpha test value. If the test passes, the pixel is + * written, otherwise the pixel is not written. The alpha test + * function is set with the setAlphaTestFunction + * method. The alpha test + * function is one of the following:
  • + *

      + *
    • ALWAYS - pixels are always drawn, irrespective of the alpha + * value. This effectively disables alpha testing. + * This is the default setting.
    • + * + *

    • NEVER - pixels are never drawn, irrespective of the alpha + * value.
    • + * + *

    • EQUAL - pixels are drawn if the incoming pixel alpha value is equal + * to the alpha test value.
    • + * + *

    • NOT_EQUAL - pixels are drawn if the incoming pixel alpha value is + * not equal to the alpha test value.
    • + * + *

    • LESS - pixels are drawn if the incoming pixel alpha value is less + * than the alpha test value.
    • + * + *

    • LESS_OR_EQUAL - pixels are drawn if the incoming pixel alpha value + * is less than or equal to the alpha test value.
    • + * + *

    • GREATER - pixels are drawn if the incoming pixel alpha value is greater + * than the alpha test value.
    • + * + *

    • GREATER_OR_EQUAL - pixels are drawn if the incoming pixel alpha + * value is greater than or equal to the alpha test value.
    • + *

    + * + *
  • Alpha test value - the test value used by the alpha test function. + * This value is compared to the alpha value of each rendered pixel. + * The alpha test value is set with the setAlphaTestValue + * method. The default alpha test value is 0.0.
  • + * + *

  • Raster operation - the raster operation function for this + * RenderingAttributes component object. The raster operation is + * set with the setRasterOp method. The raster operation + * is enabled or disabled with the setRasterOpEnable + * method. The raster operation is one of the following:
  • + *

      + *
    • ROP_CLEAR - DST = 0.
    • + *
    • ROP_AND DST = SRC & DST.
    • + *
    • ROP_AND_REVERSE DST = SRC & ~DST.
    • + *
    • ROP_COPY - DST = SRC. This is the default operation.
    • + *
    • ROP_AND_INVERTED - DST = ~SRC & DST.
    • + *
    • ROP_NOOP - DST = DST.
    • + *
    • ROP_XOR - DST = SRC ^ DST.
    • + *
    • ROP_OR - DST = DST | SRC.
    • + *
    • ROP_NOR - DST = ~( DST | SRC .)
    • + *
    • ROP_EQUIV - DST = ~( DST ^ SRC .)
    • + *
    • ROP_INVERT - DST = ~DST.
    • + *
    • ROP_OR_REVERSE - DST = src | ~DST.
    • + *
    • ROP_COPY_INVERTED - DST = ~SRC.
    • + *
    • ROP_OR_INVERTED - DST = ~SRC | DST.
    • + *
    • ROP_NAND - DST = ~(SRC & DST.)
    • + *
    • ROP_SET - DST = 1.
    • + *

    + *
  • Vertex colors - vertex colors can be ignored for this + * RenderingAttributes object. This capability is set with the + * setIgnoreVertexColors method. If + * ignoreVertexColors is false, per-vertex colors are used, when + * present in the associated geometry objects, taking + * precedence over the ColoringAttributes color and the + * specified Material color(s). If ignoreVertexColors is true, per-vertex + * colors are ignored. In this case, if lighting is enabled, the + * Material diffuse color will be used as the object color. + * if lighting is disabled, the ColoringAttributes color is + * used. The default value is false.
  • + * + *

  • Visibility flag - when set, invisible objects are + * not rendered (subject to the visibility policy for + * the current view), but they can be picked or collided with. + * This flag is set with the setVisible + * method. By default, the visibility flag is true.
  • + * + *

  • Depth buffer - can be enabled or disabled for this + * RenderingAttributes component object. The + * setDepthBufferEnable method enables + * or disabled the depth buffer. The + * setDepthBufferWriteEnable method enables or disables + * writing the depth buffer for this object. During the transparent + * rendering pass, this attribute can be overridden by the + * depthBufferFreezeTransparent attribute in the View + * object. Transparent objects include BLENDED transparent and + * antialiased lines and points. Transparent objects do not + * include opaque objects or primitives rendered with + * SCREEN_DOOR transparency. By default, the depth buffer + * is enabled and the depth buffer write is enabled.
  • + * + *

  • Stencil buffer - can be enabled or disabled for this RenderingAttributes + * component object using the setStencilEnable method. If the + * stencil buffer is disabled, the stencil operation and function are ignored. + * If a scene graph is rendered on a Canvas3D that does not have a stencil + * buffer, the stencil buffer will be implicitly disabled for that + * canvas.
  • + * + *

  • Stencil write mask - mask that controls which bits of the stencil + * buffer are written when the stencil buffer is enabled. The default value is + * ~0 (all ones).
  • + * + *

  • Stencil operation - a set of three stencil operations performed + * when: 1) the stencil test fails; 2) the stencil test passes, but + * the depth test fails; or 3) both the stencil test and depth test pass. + * The stencil operations are set with the setStencilOp + * method. The stencil operation is one of the following:
  • + *

      + *
    • STENCIL_KEEP - keeps the current value (no operation performed). + * This is the default setting.
    • + *
    • STENCIL_ZERO - Sets the stencil buffer value to 0.
    • + *
    • STENCIL_REPLACE - Sets the stencil buffer value to + * refValue, as specified by setStencilFunction.
    • + *
    • STENCIL_INCR - Increments the current stencil buffer value.
    • + *
    • STENCIL_DECR - Decrements the current stencil buffer value.
    • + *
    • STENCIL_INVERT - Bitwise inverts the current stencil buffer value.
    • + *

    + * + *
  • Stencil test function - used to compare the stencil reference value with + * the per-pixel stencil value stored in the frame buffer. If the test passes, + * the pixel is written, otherwise the pixel is not written. The stencil + * test function, reference value, and comparison mask are set with the + * setStencilFunction method. The stencil comparison mask is + * bitwise-ANDed with both the stencil reference value and the stored stencil + * value prior to doing the comparison. The default value for the reference value + * is 0. The default value for the comparison mask is ~0 (all ones). + * The stencil test function is one of the following:
  • + *

      + *
    • ALWAYS - pixels are always drawn, irrespective of the stencil + * value. This effectively disables stencil testing. + * This is the default setting.
    • + * + *

    • NEVER - pixels are never drawn, irrespective of the stencil + * value.
    • + * + *

    • EQUAL - pixels are drawn if the stencil reference value is equal + * to the stored stencil value in the frame buffer.
    • + * + *

    • NOT_EQUAL - pixels are drawn if the stencil reference value is + * not equal to the stored stencil value in the frame buffer.
    • + * + *

    • LESS - pixels are drawn if the stencil reference value is less + * than the stored stencil value in the frame buffer.
    • + * + *

    • LESS_OR_EQUAL - pixels are drawn if the stencil reference value + * is less than or equal to the stored stencil value in the frame buffer.
    • + * + *

    • GREATER - pixels are drawn if the stencil reference value is greater + * than the stored stencil value in the frame buffer.
    • + * + *

    • GREATER_OR_EQUAL - pixels are drawn if the stencil reference value + * is greater than or equal to the stored stencil value in the frame buffer.
    • + *

    + * + *
+ * + *

Note: the alpha test, depth test, and stencil functions all use + * the same enums.

+ * + * @see Appearance + */ +public class RenderingAttributes extends NodeComponent { + + /** + * Specifies that this RenderingAttributes object + * allows reading its alpha test value component information. + */ + public static final int + ALLOW_ALPHA_TEST_VALUE_READ = CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_ALPHA_TEST_VALUE_READ; + + /** + * Specifies that this RenderingAttributes object + * allows writing its alpha test value component information. + */ + public static final int + ALLOW_ALPHA_TEST_VALUE_WRITE = CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_ALPHA_TEST_VALUE_WRITE; + + /** + * Specifies that this RenderingAttributes object + * allows reading its alpha test function component information. + */ + public static final int + ALLOW_ALPHA_TEST_FUNCTION_READ = CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_ALPHA_TEST_FUNCTION_READ; + + /** + * Specifies that this RenderingAttributes object + * allows writing its alpha test function component information. + */ + public static final int + ALLOW_ALPHA_TEST_FUNCTION_WRITE = CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_ALPHA_TEST_FUNCTION_WRITE; + + /** + * Specifies that this RenderingAttributes object + * allows reading its depth test function component information. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_DEPTH_TEST_FUNCTION_READ = CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_DEPTH_TEST_FUNCTION_READ; + + /** + * Specifies that this RenderingAttributes object + * allows writing its depth test function component information. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_DEPTH_TEST_FUNCTION_WRITE = CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_DEPTH_TEST_FUNCTION_WRITE; + + /** + * Specifies that this RenderingAttributes object + * allows reading its depth buffer enable and depth buffer write enable + * component information. + */ + public static final int + ALLOW_DEPTH_ENABLE_READ = CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_DEPTH_ENABLE_READ; + + /** + * Specifies that this RenderingAttributes object + * allows writing its depth buffer enable and depth buffer write enable + * component information. + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_DEPTH_ENABLE_WRITE = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_DEPTH_ENABLE_WRITE; + + /** + * Specifies that this RenderingAttributes object + * allows reading its visibility information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_VISIBLE_READ = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_VISIBLE_READ; + + /** + * Specifies that this RenderingAttributes object + * allows writing its visibility information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_VISIBLE_WRITE = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_VISIBLE_WRITE; + + /** + * Specifies that this RenderingAttributes object + * allows reading its ignore vertex colors information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_IGNORE_VERTEX_COLORS_READ = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_IGNORE_VERTEX_COLORS_READ; + + /** + * Specifies that this RenderingAttributes object + * allows writing its ignore vertex colors information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_IGNORE_VERTEX_COLORS_WRITE = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_IGNORE_VERTEX_COLORS_WRITE; + + /** + * Specifies that this RenderingAttributes object + * allows reading its raster operation information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_RASTER_OP_READ = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_RASTER_OP_READ; + + /** + * Specifies that this RenderingAttributes object + * allows writing its raster operation information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_RASTER_OP_WRITE = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_RASTER_OP_WRITE; + + /** + * Specifies that this RenderingAttributes object allows reading + * its stencil enable, stencil op, stencil function, and + * stencil write mask information. + * + * @since Java 3D 1.4 + */ + public static final int ALLOW_STENCIL_ATTRIBUTES_READ = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_STENCIL_ATTRIBUTES_READ; + + /** + * Specifies that this RenderingAttributes object allows writing + * its stencil enable, stencil op, stencil function, and + * stencil write mask information. + * + * @since Java 3D 1.4 + */ + public static final int ALLOW_STENCIL_ATTRIBUTES_WRITE = + CapabilityBits.RENDERING_ATTRIBUTES_ALLOW_STENCIL_ATTRIBUTES_WRITE; + + + // + // Enums for alpha test, depth test, and stencil test + // + + /** + * Specifies that pixels are always drawn irrespective of the + * values being tested. + * Can be used to specify the alpha test function, the depth test function, + * or the stencil function. + * This setting effectively disables alpha, depth, or stencil testing. + * + * @see #setAlphaTestFunction + * @see #setDepthTestFunction + * @see #setStencilFunction(int,int,int) + */ + public static final int ALWAYS = 0; + + /** + * Specifies that pixels are never drawn irrespective of the + * values being tested. + * Can be used to specify the alpha test function, the depth test function, + * or the stencil function. + * + * @see #setAlphaTestFunction + * @see #setDepthTestFunction + * @see #setStencilFunction(int,int,int) + */ + public static final int NEVER = 1; + + /** + * Specifies that pixels are drawn if the two values being tested are equal. + * Can be used to specify the alpha test function, the depth test function, + * or the stencil function. + * + * @see #setAlphaTestFunction + * @see #setDepthTestFunction + * @see #setStencilFunction(int,int,int) + */ + public static final int EQUAL = 2; + + /** + * Specifies that pixels are drawn if the two values being tested are not equal. + * Can be used to specify the alpha test function, the depth test function, + * or the stencil function. + * + * @see #setAlphaTestFunction + * @see #setDepthTestFunction + * @see #setStencilFunction(int,int,int) + */ + public static final int NOT_EQUAL = 3; + + /** + * Specifies that pixels are drawn if the source/reference value is less + * than the destination/test value. + * Can be used to specify the alpha test function, the depth test function, + * or the stencil function. + * + * @see #setAlphaTestFunction + * @see #setDepthTestFunction + * @see #setStencilFunction(int,int,int) + */ + public static final int LESS = 4; + + /** + * Specifies that pixels are drawn if the source/reference value is less + * than or equal to the destination/test value. + * Can be used to specify the alpha test function, the depth test function, + * or the stencil function. + * + * @see #setAlphaTestFunction + * @see #setDepthTestFunction + * @see #setStencilFunction(int,int,int) + */ + public static final int LESS_OR_EQUAL = 5; + + /** + * Specifies that pixels are drawn if the source/reference value is greater + * than the destination/test value. + * Can be used to specify the alpha test function, the depth test function, + * or the stencil function. + * + * @see #setAlphaTestFunction + * @see #setDepthTestFunction + * @see #setStencilFunction(int,int,int) + */ + public static final int GREATER = 6; + + /** + * Specifies that pixels are drawn if the source/reference value is greater + * than or equal to the destination/test value. + * Can be used to specify the alpha test function, the depth test function, + * or the stencil function. + * + * @see #setAlphaTestFunction + * @see #setDepthTestFunction + * @see #setStencilFunction(int,int,int) + */ + public static final int GREATER_OR_EQUAL = 7; + + + // + // Raster op enums + // + + /** + * Raster operation: DST = 0. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_CLEAR = 0x0; + + /** + * Raster operation: DST = SRC & DST. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_AND = 0x1; + + /** + * Raster operation: DST = SRC & ~DST. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_AND_REVERSE = 0x2; + + /** + * Raster operation: DST = SRC. + * @see #setRasterOp + * + * @since Java 3D 1.2 + */ + public static final int ROP_COPY = 0x3; + + /** + * Raster operation: DST = ~SRC & DST. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_AND_INVERTED = 0x4; + + /** + * Raster operation: DST = DST. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_NOOP = 0x5; + + /** + * Raster operation: DST = SRC ^ DST. + * @see #setRasterOp + * + * @since Java 3D 1.2 + */ + public static final int ROP_XOR = 0x6; + + /** + * Raster operation: DST = DST | SRC. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_OR = 0x7; + + /** + * Raster operation: DST = ~( DST | SRC ). + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_NOR = 0x8; + + /** + * Raster operation: DST = ~( DST ^ SRC ). + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_EQUIV = 0x9; + + /** + * Raster operation: DST = ~DST. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_INVERT = 0xA; + + /** + * Raster operation: DST = src | ~DST. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_OR_REVERSE = 0xB; + + /** + * Raster operation: DST = ~SRC. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_COPY_INVERTED = 0xC; + + /** + * Raster operation: DST = ~SRC | DST. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_OR_INVERTED = 0xD; + + /** + * Raster operation: DST = ~(SRC & DST). + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_NAND = 0xE; + + /** + * Raster operation: DST = 1. + * @see #setRasterOp + * + * @since Java 3D 1.4 + */ + public static final int ROP_SET = 0xF; + + + // + // Stencil op enums + // + + /** + * Stencil operation: DST = DST + * @see #setStencilOp(int,int,int) + * + * @since Java 3D 1.4 + */ + public static final int STENCIL_KEEP = 1; + + /** + * Stencil operation: DST = 0 + * @see #setStencilOp(int,int,int) + * + * @since Java 3D 1.4 + */ + public static final int STENCIL_ZERO = 2; + + /** + * Stencil operation: DST = REF + * @see #setStencilOp(int,int,int) + * + * @since Java 3D 1.4 + */ + public static final int STENCIL_REPLACE = 3; + + /** + * Stencil operation: DST = DST + 1 + * @see #setStencilOp(int,int,int) + * + * @since Java 3D 1.4 + */ + public static final int STENCIL_INCR = 4; + + /** + * Stencil operation: DST = DST - 1 + * @see #setStencilOp(int,int,int) + * + * @since Java 3D 1.4 + */ + public static final int STENCIL_DECR = 5; + + /** + * Stencil operation: DST = ~DST + * @see #setStencilOp(int,int,int) + * + * @since Java 3D 1.4 + */ + public static final int STENCIL_INVERT = 6; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_ALPHA_TEST_FUNCTION_READ, + ALLOW_ALPHA_TEST_VALUE_READ, + ALLOW_DEPTH_ENABLE_READ, + ALLOW_DEPTH_TEST_FUNCTION_READ, + ALLOW_IGNORE_VERTEX_COLORS_READ, + ALLOW_RASTER_OP_READ, + ALLOW_STENCIL_ATTRIBUTES_READ, + ALLOW_VISIBLE_READ + }; + + /** + * Constructs a RenderingAttributes object with default parameters. + * The default values are as follows: + *
    + * depth buffer enable : true
    + * depth buffer write enable : true
    + * alpha test function : ALWAYS
    + * alpha test value : 0.0f
    + * visible : true
    + * ignore vertex colors : false
    + * raster operation enable : false
    + * raster operation : ROP_COPY
    + * depth test: LESS_OR_EQUAL
    + * stencil enable : false
    + * stencil write mask : ~0 (all ones)
    + * stencil op - failOp : STENCIL_KEEP
    + * stencil op - zFailOp : STENCIL_KEEP
    + * stencil op - zPassOp : STENCIL_KEEP
    + * stencil function : ALWAYS
    + * stencil reference value : 0
    + * stencil comparison mask : ~0 (all ones) + *
+ */ + public RenderingAttributes() { + // Just use default attributes + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a RenderingAttributes object with specified values. + * @param depthBufferEnable a flag to turn depth buffer on/off + * @param depthBufferWriteEnable a flag to to make depth buffer + * read/write or read only + * @param alphaTestValue the alpha test reference value + * @param alphaTestFunction the function for comparing alpha values + */ + public RenderingAttributes(boolean depthBufferEnable, + boolean depthBufferWriteEnable, + float alphaTestValue, + int alphaTestFunction){ + + this(depthBufferEnable, depthBufferWriteEnable, alphaTestValue, + alphaTestFunction, true, false, false, ROP_COPY); + } + + /** + * Constructs a RenderingAttributes object with specified values + * @param depthBufferEnable a flag to turn depth buffer on/off + * @param depthBufferWriteEnable a flag to make depth buffer + * read/write or read only + * @param alphaTestValue the alpha test reference value + * @param alphaTestFunction the function for comparing alpha values + * @param visible a flag that specifies whether the object is visible + * @param ignoreVertexColors a flag to enable or disable + * the ignoring of per-vertex colors + * @param rasterOpEnable a flag that specifies whether logical + * raster operations are enabled for this RenderingAttributes object. + * This disables all alpha blending operations. + * @param rasterOp the logical raster operation, one of: + * ROP_CLEAR, ROP_AND, ROP_AND_REVERSE, ROP_COPY, ROP_AND_INVERTED, + * ROP_NOOP, ROP_XOR, ROP_OR, ROP_NOR, ROP_EQUIV, ROP_INVERT, + * ROP_OR_REVERSE, ROP_COPY_INVERTED, ROP_OR_INVERTED, ROP_NAND or ROP_SET + * + * @since Java 3D 1.2 + */ + public RenderingAttributes(boolean depthBufferEnable, + boolean depthBufferWriteEnable, + float alphaTestValue, + int alphaTestFunction, + boolean visible, + boolean ignoreVertexColors, + boolean rasterOpEnable, + int rasterOp) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((RenderingAttributesRetained)this.retained).initDepthBufferEnable(depthBufferEnable); + ((RenderingAttributesRetained)this.retained).initDepthBufferWriteEnable(depthBufferWriteEnable); + ((RenderingAttributesRetained)this.retained).initAlphaTestValue(alphaTestValue); + ((RenderingAttributesRetained)this.retained).initAlphaTestFunction(alphaTestFunction); + ((RenderingAttributesRetained)this.retained).initVisible(visible); + + + ((RenderingAttributesRetained)this.retained).initIgnoreVertexColors(ignoreVertexColors); + ((RenderingAttributesRetained)this.retained).initRasterOpEnable(rasterOpEnable); + ((RenderingAttributesRetained)this.retained).initRasterOp(rasterOp); + } + + /** + * Enables or disables depth buffer mode for this RenderingAttributes + * component object. + * + * @param state true or false to enable or disable depth buffer mode + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see GraphicsConfigTemplate3D#setDepthSize + */ + public void setDepthBufferEnable(boolean state){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DEPTH_ENABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes0")); + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setDepthBufferEnable(state); + else + ((RenderingAttributesRetained)this.retained).initDepthBufferEnable(state); + + } + + /** + * Retrieves the state of zBuffer Enable flag + * @return true if depth buffer mode is enabled, false + * if depth buffer mode is disabled + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getDepthBufferEnable(){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DEPTH_ENABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes1")); + + return ((RenderingAttributesRetained)this.retained).getDepthBufferEnable(); + } + + /** + * Enables or disables writing the depth buffer for this object. + * During the transparent rendering pass, + * this attribute can be overridden by + * the depthBufferFreezeTransparent attribute in the View object. + * @param state true or false to enable or disable depth buffer Write mode + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @see View#setDepthBufferFreezeTransparent + */ + public void setDepthBufferWriteEnable(boolean state) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DEPTH_ENABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes2")); + if (isLive()) + ((RenderingAttributesRetained)this.retained).setDepthBufferWriteEnable(state); + else + ((RenderingAttributesRetained)this.retained).initDepthBufferWriteEnable(state); + } + + /** + * Retrieves the state of Depth Buffer Write Enable flag. + * @return true if depth buffer is writable, false + * if depth buffer is read-only + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getDepthBufferWriteEnable(){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DEPTH_ENABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes3")); + + return ((RenderingAttributesRetained)this.retained).getDepthBufferWriteEnable(); + } + + /** + * Set alpha test value used by alpha test function. This value is + * compared to the alpha value of each rendered pixel. + * @param value the alpha test value + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAlphaTestValue(float value){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ALPHA_TEST_VALUE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes4")); + if (isLive()) + ((RenderingAttributesRetained)this.retained).setAlphaTestValue(value); + else + ((RenderingAttributesRetained)this.retained).initAlphaTestValue(value); + + } + + /** + * Retrieves the alpha test value. + * @return the alpha test value. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getAlphaTestValue(){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ALPHA_TEST_VALUE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes5")); + + return ((RenderingAttributesRetained)this.retained).getAlphaTestValue(); + } + + /** + * Set alpha test function. This function is used to compare + * each incoming (source) per-pixel alpha value with the alpha test value. + * If the test passes, the pixel is written otherwise the pixel is not + * written. + * @param function the new alpha test function. One of + * ALWAYS, NEVER, EQUAL, NOT_EQUAL, LESS, LESS_OR_EQUAL, GREATER, + * GREATER_OR_EQUAL + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAlphaTestFunction(int function){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ALPHA_TEST_FUNCTION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes6")); + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setAlphaTestFunction(function); + else + ((RenderingAttributesRetained)this.retained).initAlphaTestFunction(function); + + } + + /** + * Retrieves current alpha test function. + * @return the current alpha test function + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getAlphaTestFunction(){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ALPHA_TEST_FUNCTION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes7")); + + return ((RenderingAttributesRetained)this.retained).getAlphaTestFunction(); + } + + /** + * Sets the visibility flag for this RenderingAttributes + * component object. Invisible objects are not rendered (subject to + * the visibility policy for the current view), but they can be picked + * or collided with. The default value is true. + * @param visible true or false to enable or disable visibility + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see View#setVisibilityPolicy + * + * @since Java 3D 1.2 + */ + public void setVisible(boolean visible) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VISIBLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes8")); + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setVisible(visible); + else + ((RenderingAttributesRetained)this.retained).initVisible(visible); + } + + /** + * Retrieves the visibility flag for this RenderingAttributes object. + * @return true if the object is visible; false + * if the object is invisible. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public boolean getVisible() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VISIBLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes9")); + + return ((RenderingAttributesRetained)this.retained).getVisible(); + } + + /** + * Sets a flag that indicates whether vertex colors are ignored + * for this RenderingAttributes object. If + * ignoreVertexColors is false, per-vertex + * colors are used, when present in the associated Geometry + * objects, taking precedence over the ColoringAttributes color + * and the specified Material color(s). If ignoreVertexColors + * is true, per-vertex colors are ignored. In this case, if + * lighting is enabled, the Material diffuse color will be + * used as the object color. If lighting is disabled, the + * ColoringAttributes color will be used. The default value is false. + * + * @param ignoreVertexColors true or false to enable or disable + * the ignoring of per-vertex colors + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see ColoringAttributes + * @see Material + * + * @since Java 3D 1.2 + */ + public void setIgnoreVertexColors(boolean ignoreVertexColors) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_IGNORE_VERTEX_COLORS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes12")); + + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setIgnoreVertexColors(ignoreVertexColors); + else + ((RenderingAttributesRetained)this.retained).initIgnoreVertexColors(ignoreVertexColors); + } + + /** + * Retrieves the ignoreVertexColors flag for this + * RenderingAttributes object. + * @return true if per-vertex colors are ignored; false + * if per-vertex colors are used. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public boolean getIgnoreVertexColors() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_IGNORE_VERTEX_COLORS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes13")); + + + return ((RenderingAttributesRetained)this.retained).getIgnoreVertexColors(); + } + + /** + * Sets the rasterOp enable flag for this RenderingAttributes + * component object. When set to true, this enables logical + * raster operations as specified by the setRasterOp method. + * Enabling raster operations effectively disables alpha blending, + * which is used for transparency and antialiasing. Raster + * operations, especially XOR mode, are primarily useful when + * rendering to the front buffer in immediate mode. Most + * applications will not wish to enable this mode. + * + * @param rasterOpEnable true or false to enable or disable + * raster operations + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #setRasterOp + * + * @since Java 3D 1.2 + */ + public void setRasterOpEnable(boolean rasterOpEnable) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_RASTER_OP_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes10")); + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setRasterOpEnable(rasterOpEnable); + else + ((RenderingAttributesRetained)this.retained).initRasterOpEnable(rasterOpEnable); + } + + /** + * Retrieves the rasterOp enable flag for this RenderingAttributes + * object. + * @return true if raster operations are enabled; false + * if raster operations are disabled. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public boolean getRasterOpEnable() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_RASTER_OP_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes11")); + + + return ((RenderingAttributesRetained)this.retained).getRasterOpEnable(); + } + + /** + * Sets the raster operation function for this RenderingAttributes + * component object. + * + * @param rasterOp the logical raster operation, one of: + * ROP_CLEAR, ROP_AND, ROP_AND_REVERSE, ROP_COPY, ROP_AND_INVERTED, + * ROP_NOOP, ROP_XOR, ROP_OR, ROP_NOR, ROP_EQUIV, ROP_INVERT, + * ROP_OR_REVERSE, ROP_COPY_INVERTED, ROP_OR_INVERTED, ROP_NAND or ROP_SET. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public void setRasterOp(int rasterOp) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_RASTER_OP_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes10")); + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setRasterOp(rasterOp); + else + ((RenderingAttributesRetained)this.retained).initRasterOp(rasterOp); + } + + /** + * Retrieves the current raster operation for this RenderingAttributes + * object. + * @return one of: + * ROP_CLEAR, ROP_AND, ROP_AND_REVERSE, ROP_COPY, ROP_AND_INVERTED, + * ROP_NOOP, ROP_XOR, ROP_OR, ROP_NOR, ROP_EQUIV, ROP_INVERT, + * ROP_OR_REVERSE, ROP_COPY_INVERTED, ROP_OR_INVERTED, ROP_NAND or ROP_SET + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getRasterOp() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_RASTER_OP_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes11")); + + return ((RenderingAttributesRetained)this.retained).getRasterOp(); + } + + /** + * Creates a retained mode RenderingAttributesRetained object that this + * RenderingAttributes component object will point to. + */ + void createRetained() { + this.retained = new RenderingAttributesRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + RenderingAttributes ra = new RenderingAttributes(); + ra.duplicateNodeComponent(this); + return ra; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + RenderingAttributesRetained attr = + (RenderingAttributesRetained) originalNodeComponent.retained; + RenderingAttributesRetained rt = + (RenderingAttributesRetained) retained; + + rt.initDepthBufferEnable(attr.getDepthBufferEnable()); + rt.initDepthBufferWriteEnable(attr.getDepthBufferWriteEnable()); + rt.initDepthTestFunction(attr.getDepthTestFunction()); + rt.initAlphaTestValue(attr.getAlphaTestValue()); + rt.initAlphaTestFunction(attr.getAlphaTestFunction()); + rt.initVisible(attr.getVisible()); + rt.initIgnoreVertexColors(attr.getIgnoreVertexColors()); + rt.initRasterOpEnable(attr.getRasterOpEnable()); + rt.initRasterOp(attr.getRasterOp()); + rt.initStencilEnable(attr.getStencilEnable()); + int[] ops = new int[3]; + attr.getStencilOp(ops); + rt.initStencilOp(ops[0], ops[1], ops[2]); + attr.getStencilFunction(ops); + rt.initStencilFunction(ops[0], ops[1], ops[2]); + rt.initStencilWriteMask(attr.getStencilWriteMask()); + + } + + /** + * Set depth test function. This function is used to compare each + * incoming (source) per-pixel depth test value with the stored per-pixel + * depth value in the frame buffer. If the test + * passes, the pixel is written, otherwise the pixel is not + * written. + * @param function the new depth test function. One of + * ALWAYS, NEVER, EQUAL, NOT_EQUAL, LESS, LESS_OR_EQUAL, GREATER, + * or GREATER_OR_EQUAL. + * The default value is LESS_OR_EQUAL. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public void setDepthTestFunction(int function){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DEPTH_TEST_FUNCTION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes14")); + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setDepthTestFunction(function); + else + ((RenderingAttributesRetained)this.retained).initDepthTestFunction(function); + } + + /** + * Retrieves current depth test function. + * @return the current depth test function + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public int getDepthTestFunction(){ + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DEPTH_TEST_FUNCTION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes15")); + + return ((RenderingAttributesRetained)this.retained).getDepthTestFunction(); + } + + /** + * Enables or disables the stencil buffer for this RenderingAttributes + * component object. If the stencil buffer is disabled, the + * stencil operation and function are ignored. If a scene graph + * is rendered on a Canvas3D that does not have a stencil buffer, + * the stencil buffer will be implicitly disabled for that canvas. + * + * @param state true or false to enable or disable stencil buffer + * operations. + * If this is set to false, the stencilOp and stencilFunction parameters + * are not used. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see GraphicsConfigTemplate3D#setStencilSize + * + * @since Java 3D 1.4 + */ + public void setStencilEnable(boolean state) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes16")); + } + } + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setStencilEnable(state); + else + ((RenderingAttributesRetained)this.retained).initStencilEnable(state); + + } + + /** + * Retrieves the stencil buffer enable flag for this RenderingAttributes + * object. + * + * @return true if stencil buffer operations are enabled; false + * if stencil buffer operations are disabled. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public boolean getStencilEnable() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes17")); + } + } + + return ((RenderingAttributesRetained)this.retained).getStencilEnable(); + } + + /** + * Sets the stencil operations for this RenderingAttributes object to the + * specified parameters. + * + * @param failOp operation performed when the stencil test fails, one of: + * STENCIL_KEEP, STENCIL_ZERO, STENCIL_REPLACE, STENCIL_INCR, STENCIL_DECR, + * or STENCIL_INVERT. + * + * @param zFailOp operation performed when the stencil test passes and the + * depth test fails, one of: + * STENCIL_KEEP, STENCIL_ZERO, STENCIL_REPLACE, STENCIL_INCR, STENCIL_DECR, + * or STENCIL_INVERT. + * + * @param zPassOp operation performed when both the stencil test and the + * depth test pass, one of: + * STENCIL_KEEP, STENCIL_ZERO, STENCIL_REPLACE, STENCIL_INCR, STENCIL_DECR, + * or STENCIL_INVERT. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public void setStencilOp(int failOp, int zFailOp, int zPassOp) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes16")); + } + } + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setStencilOp(failOp, + zFailOp, + zPassOp); + else + ((RenderingAttributesRetained)this.retained).initStencilOp(failOp, + zFailOp, + zPassOp); + + } + + /** + * Sets the stencil operations for this RenderingAttributes object to the + * specified parameters. + * + * @param stencilOps an array of three integers that specifies the new + * set of stencil operations. Element 0 of the array specifies the + * failOp parameter, element 1 specifies the + * zFailOp parameter, and element 2 specifies the + * zPassOp parameter. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #setStencilOp(int,int,int) + * + * @since Java 3D 1.4 + */ + public void setStencilOp(int[] stencilOps) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes16")); + } + } + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setStencilOp(stencilOps[0], + stencilOps[1], + stencilOps[2]); + else + ((RenderingAttributesRetained)this.retained).initStencilOp(stencilOps[0], + stencilOps[1], + stencilOps[2]); + } + + /** + * Retrieves the current set of stencil operations, and copies them + * into the specified array. The caller must ensure that this array + * has been allocated with enough space to hold the results. + * + * @param stencilOps array that will receive the current set of + * three stencil operations. The failOp parameter is copied + * into element 0 of the array, the zFailOp parameter is copied + * into element 1, and the zPassOp parameter is copied + * into element 2. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public void getStencilOp(int[] stencilOps) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes17")); + } + } + + ((RenderingAttributesRetained)this.retained).getStencilOp(stencilOps); + } + + /** + * Sets the stencil function, reference value, and comparison mask + * for this RenderingAttributes object to the specified parameters. + * + * @param function the stencil test function, used to compare the + * stencil reference value with the stored per-pixel + * stencil value in the frame buffer. If the test + * passes, the pixel is written, otherwise the pixel is not + * written. The stencil function is one of: + * ALWAYS, NEVER, EQUAL, NOT_EQUAL, LESS, LESS_OR_EQUAL, GREATER, + * or GREATER_OR_EQUAL. + * + * @param refValue the stencil reference value that is tested against + * the stored per-pixel stencil value + * + * @param compareMask a mask that limits which bits are compared; it is + * bitwise-ANDed with both the stencil reference value and the stored + * per-pixel stencil value before doing the comparison. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public void setStencilFunction(int function, int refValue, int compareMask) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes16")); + } + } + if (isLive()) + ((RenderingAttributesRetained)this.retained).setStencilFunction(function, + refValue, + compareMask); + else + ((RenderingAttributesRetained)this.retained).initStencilFunction(function, + refValue, + compareMask); + } + + /** + * Sets the stencil function, reference value, and comparison mask + * for this RenderingAttributes object to the specified parameters. + * + * @param params an array of three integers that specifies the new + * stencil function, reference value, and comparison mask. + * Element 0 of the array specifies the + * stencil function, element 1 specifies the + * reference value, and element 2 specifies the + * comparison mask. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #setStencilFunction(int,int,int) + * + * @since Java 3D 1.4 + */ + public void setStencilFunction(int[] params) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes16")); + } + } + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setStencilFunction(params[0], + params[1], + params[2]); + else + ((RenderingAttributesRetained)this.retained).initStencilFunction(params[0], + params[1], + params[2]); + + } + + /** + * Retrieves the stencil function, reference value, and comparison mask, + * and copies them into the specified array. The caller must ensure + * that this array has been allocated with enough space to hold the results. + * + * @param params array that will receive the current stencil function, + * reference value, and comparison mask. The stencil function is copied + * into element 0 of the array, the reference value is copied + * into element 1, and the comparison mask is copied + * into element 2. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public void getStencilFunction(int[] params) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes17")); + } + } + + ((RenderingAttributesRetained)this.retained).getStencilFunction(params); + } + + /** + * Sets the stencil write mask for this RenderingAttributes + * object. This mask controls which bits of the + * stencil buffer are written. + * The default value is ~0 (all ones). + * + * @param mask the new stencil write mask. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public void setStencilWriteMask(int mask) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_WRITE)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes16")); + } + } + + if (isLive()) + ((RenderingAttributesRetained)this.retained).setStencilWriteMask(mask); + else + ((RenderingAttributesRetained)this.retained).initStencilWriteMask(mask); + } + + /** + * Retrieves the current stencil write mask for this RenderingAttributes + * object. + * + * @return the stencil write mask. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.4 + */ + public int getStencilWriteMask() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_STENCIL_ATTRIBUTES_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("RenderingAttributes17")); + } + } + + return ((RenderingAttributesRetained)this.retained).getStencilWriteMask(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderingAttributesRetained.java b/j3d-core/src/classes/share/javax/media/j3d/RenderingAttributesRetained.java new file mode 100644 index 0000000..b302187 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderingAttributesRetained.java @@ -0,0 +1,730 @@ +/* + * $RCSfile: RenderingAttributesRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * The RenderingAttributes object defines all rendering state that can be set + * as a component object of a Shape3D node. + */ +class RenderingAttributesRetained extends NodeComponentRetained { + // A list of pre-defined bits to indicate which component + // in this RenderingAttributes object changed. + static final int DEPTH_ENABLE = 0x01; + + static final int DEPTH_WRITE_ENABLE = 0x02; + + static final int ALPHA_TEST_VALUE = 0x04; + + static final int ALPHA_TEST_FUNC = 0x08; + + static final int VISIBLE = 0x10; + + static final int IGNORE_VCOLOR = 0x20; + + static final int RASTER_OP_ENABLE = 0x40; + + static final int RASTER_OP_VALUE = 0x80; + + static final int DEPTH_TEST_FUNC = 0x100; + + static final int STENCIL_ENABLE = 0x200; + + static final int STENCIL_OP_VALUES = 0x400; + + static final int STENCIL_FUNC = 0x800; + + static final int STENCIL_WRITE_MASK = 0x1000; + + // depth buffer Enable for hidden surface removal + boolean depthBufferEnable = true; + + boolean depthBufferWriteEnable = true; + + float alphaTestValue = 0.0f; + + int alphaTestFunction = RenderingAttributes.ALWAYS; + + int depthTestFunction = RenderingAttributes.LESS_OR_EQUAL; + + boolean visible = true; + + boolean ignoreVertexColors = false; + + // raster operation + boolean rasterOpEnable = false; + int rasterOp = RenderingAttributes.ROP_COPY; + + // stencil operation + boolean stencilEnable = false; + int stencilFailOp = RenderingAttributes.STENCIL_KEEP; + int stencilZFailOp = RenderingAttributes.STENCIL_KEEP; + int stencilZPassOp = RenderingAttributes.STENCIL_KEEP; + int stencilFunction = RenderingAttributes.ALWAYS; + int stencilReferenceValue = 0; + int stencilCompareMask = ~0; + int stencilWriteMask = ~0; + + // depth buffer comparison function. Used by multi-texturing only + //[PEPE] NOTE: they are both unused. Candidates for removal. + static final int LESS = 0; + static final int LEQUAL = 1; + + /** + * Sets the visibility flag for this RenderingAttributes component object. + * @param visible true or false to enable or disable visibility + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see View#setVisibilityPolicy + */ + final void initVisible(boolean state){ + visible = state; + } + + /** + * Sets the visibility flag for this RenderingAttributes + * component object. Invisible objects are not rendered (subject to + * the visibility policy for the current view), but they can be picked + * or collided with. + * @param visible true or false to enable or disable visibility + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see View#setVisibilityPolicy + */ + final void setVisible(boolean state){ + // Optimize : If new state equal to current state, should I simply return ? + // Is it safe ? + initVisible(state); + + // Need to call sendMessage twice. Not an efficient approach, but + // it simplified code logic and speed up the common case; where + // perUniv is false. + + + sendMessage(VISIBLE, (state ? Boolean.TRUE: Boolean.FALSE)); + + } + + /** + * Retrieves the visibility flag for this RenderingAttributes object. + * @return true if the object is visible; false + * if the object is invisible. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + final boolean getVisible() { + return visible; + } + + + /** + * Enables or disables vertex colors for this RenderAttributes + * component object. + * @param state true or false to enable or disable vertex colors + */ + final void initIgnoreVertexColors(boolean state) { + ignoreVertexColors = state; + } + + /** + * Enables or disables vertex colors for this RenderAttributes + * component object and sends a + * message notifying the interested structures of the change. + * @param state true or false to enable or disable depth vertex colors + */ + final void setIgnoreVertexColors(boolean state) { + initIgnoreVertexColors(state); + sendMessage(IGNORE_VCOLOR, + (state ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Retrieves the state of vertex color Enable flag + * @return true if vertex colors are enabled, false + * if vertex colors are disabled + */ + final boolean getIgnoreVertexColors() { + return ignoreVertexColors; + } + + /** + * Enables or disables depth buffer mode for this RenderAttributes + * component object. + * @param state true or false to enable or disable depth buffer mode + */ + final void initDepthBufferEnable(boolean state){ + depthBufferEnable = state; + } + + /** + * Enables or disables depth buffer mode for this RenderAttributes + * component object and sends a + * message notifying the interested structures of the change. + * @param state true or false to enable or disable depth buffer mode + */ + final void setDepthBufferEnable(boolean state){ + initDepthBufferEnable(state); + sendMessage(DEPTH_ENABLE, (state ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Retrieves the state of zBuffer Enable flag + * @return true if depth buffer mode is enabled, false + * if depth buffer mode is disabled + */ + final boolean getDepthBufferEnable(){ + return depthBufferEnable; + } + + /** + * Enables or disables writing the depth buffer for this object. + * During the transparent rendering pass, + * this attribute can be overridden by + * the depthBufferFreezeTransparent attribute in the View object. + * @param state true or false to enable or disable depth buffer Write mode + * @see View#setDepthBufferFreezeTransparent + */ + final void initDepthBufferWriteEnable(boolean state){ + depthBufferWriteEnable = state; + } + + /** + * Enables or disables writing the depth buffer for this object and sends + * a message notifying the interested structures of the change. + * During the transparent rendering pass, + * this attribute can be overridden by + * the depthBufferFreezeTransparent attribute in the View object. + * @param state true or false to enable or disable depth buffer Write mode + * @see View#setDepthBufferFreezeTransparent + */ + final void setDepthBufferWriteEnable(boolean state){ + + initDepthBufferWriteEnable(state); + sendMessage(DEPTH_WRITE_ENABLE, (state ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Retrieves the state of Depth Buffer Write Enable flag + * @return true if depth buffer is writable, false + * if depth buffer is read-only + */ + final boolean getDepthBufferWriteEnable(){ + return depthBufferWriteEnable; + } + + /** + * Set alpha test value used by alpha test function. This value is + * compared to the alpha value of each rendered pixel. + * @param value the alpha value + */ + final void initAlphaTestValue(float value){ + alphaTestValue = value; + } + /** + * Set alpha test value used by alpha test function and sends a + * message notifying the interested structures of the change. + * This value is compared to the alpha value of each rendered pixel. + * @param value the alpha value + */ + final void setAlphaTestValue(float value){ + + initAlphaTestValue(value); + sendMessage(ALPHA_TEST_VALUE, new Float(value)); + } + + /** + * Retrieves the alpha test value. + * @return the alpha test value. + */ + final float getAlphaTestValue(){ + return alphaTestValue; + } + + + /** + * Set alpha test function. This function is used to compare the + * alpha test value with each per-pixel alpha value. If the test + * passes, then the pixel is written otherwise the pixel is not + * written. + * @param function the new alpha test function. One of: + * ALWAYS, NEVER, EQUAL, NOT_EQUAL, LESS, LESS_OR_EQUAL, GREATER, + * GREATER_OR_EQUAL. + */ + final void initAlphaTestFunction(int function){ + alphaTestFunction = function; + } + + + /** + * Set alpha test function and sends a + * message notifying the interested structures of the change. + * This function is used to compare the + * alpha test value with each per-pixel alpha value. If the test + * passes, then the pixel is written otherwise the pixel is not + * written. + * @param function the new alpha test function. One of: + * ALWAYS, NEVER, EQUAL, NOT_EQUAL, LESS, LESS_OR_EQUAL, GREATER, + * GREATER_OR_EQUAL. + */ + final void setAlphaTestFunction(int function){ + + initAlphaTestFunction(function); + sendMessage(ALPHA_TEST_FUNC, new Integer(function)); + } + + /** + * Retrieves current alpha test function. + * @return the current alpha test function + */ + final int getAlphaTestFunction(){ + return alphaTestFunction; + } + + /** + * Set depth test function. This function is used to compare the + * depth test value with each per-pixel alpha value. If the test + * passes, then the pixel is written otherwise the pixel is not + * written. + * @param function the new depth test function. One of: + * ALWAYS, NEVER, EQUAL, NOT_EQUAL, LESS, LESS_OR_EQUAL, GREATER, + * GREATER_OR_EQUAL. + * Default value is LESS_OR_EQUAL + */ + final void initDepthTestFunction(int function){ + depthTestFunction = function; + } + + /** + * Set depth test function. This function is used to compare the + * depth test value with each per-pixel depth value. If the test + * passes, the pixel is written otherwise the pixel is not + * written. + * @param function the new depth test function. One of + * ALWAYS, NEVER, EQUAL, NOT_EQUAL, LESS, LESS_OR_EQUAL, GREATER, + * GREATER_OR_EQUAL + * Default value is LESS_OR_EQUAL + */ + final void setDepthTestFunction(int function){ + initDepthTestFunction(function); + sendMessage(DEPTH_TEST_FUNC, new Integer(function)); + } + + /** + * Retrieves current depth test function. + * @return the current depth test function + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + final int getDepthTestFunction(){ + return depthTestFunction; + } + + /** + * Initialize the raster op enable flag + */ + final void initRasterOpEnable(boolean flag) { + rasterOpEnable = flag; + } + + /** + * Set the raster op enable flag + */ + final void setRasterOpEnable(boolean flag) { + initRasterOpEnable(flag); + sendMessage(RASTER_OP_ENABLE, new Boolean(flag)); + } + + /** + * Retrieves the current raster op enable flag. + */ + final boolean getRasterOpEnable() { + return rasterOpEnable; + } + + /** + * Initialize the raster op value + */ + final void initRasterOp(int op) { + rasterOp = op; + } + + /** + * Set the raster op value + */ + final void setRasterOp(int op) { + initRasterOp(op); + sendMessage(RASTER_OP_VALUE, new Integer(op)); + } + + /** + * Retrieves the current raster op value. + */ + final int getRasterOp() { + return rasterOp; + } + + + // Stencil operations + /** + * Initialize the stencil enable state + */ + final void initStencilEnable(boolean state) { + stencilEnable = state; + } + + /** + * Set the stencil enable state + */ + final void setStencilEnable(boolean state) { + initStencilEnable(state); + sendMessage(STENCIL_ENABLE, new Boolean(state)); + } + + /** + * Retrieves the current stencil enable state. + */ + final boolean getStencilEnable() { + return stencilEnable; + } + + /** + * Initialize the stencil op. value + */ + final void initStencilOp(int failOp, int zFailOp, int zPassOp) { + stencilFailOp = failOp; + stencilZFailOp = zFailOp; + stencilZPassOp = zPassOp; + } + + /** + * Set the stencil op. value + */ + final void setStencilOp(int failOp, int zFailOp, int zPassOp) { + initStencilOp(failOp, zFailOp, zPassOp); + + ArrayList arrList = new ArrayList(3); + arrList.add(new Integer(failOp)); + arrList.add(new Integer(zFailOp)); + arrList.add(new Integer(zPassOp)); + sendMessage(STENCIL_OP_VALUES, arrList); + } + + /** + * Retrieves the current stencil op. value + */ + final void getStencilOp(int[] stencilOps) { + stencilOps[0] = stencilFailOp; + stencilOps[1] = stencilZFailOp; + stencilOps[2] = stencilZPassOp; + } + + + /** + * Initialize the stencil function value + */ + final void initStencilFunction(int function, int refValue, int compareMask) { + stencilFunction = function; + stencilReferenceValue = refValue; + stencilCompareMask = compareMask; + } + + /** + * Set the stencil function value + */ + final void setStencilFunction(int function, int refValue, int compareMask) { + initStencilOp(function, refValue, compareMask); + + ArrayList arrList = new ArrayList(3); + arrList.add(new Integer(function)); + arrList.add(new Integer(refValue)); + arrList.add(new Integer(compareMask)); + sendMessage(STENCIL_FUNC, arrList); + } + + /** + * Retrieves the current stencil op. value + */ + final void getStencilFunction(int[] params) { + params[0] = stencilFunction; + params[1] = stencilReferenceValue; + params[2] = stencilCompareMask; + } + + + /** + * Initialize the stencil write mask + */ + final void initStencilWriteMask(int mask) { + stencilWriteMask = mask; + } + + /** + * Set the stencil write mask + */ + final void setStencilWriteMask(int mask) { + initStencilWriteMask(mask); + sendMessage(STENCIL_WRITE_MASK, new Integer(mask)); + } + + /** + * Retrieves the current stencil write mask + */ + final int getStencilWriteMask() { + return stencilWriteMask; + } + + + /** + * Updates the native context. + */ + + /** + * Updates the native context. + */ + void updateNative(Canvas3D c3d, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride) { + Pipeline.getPipeline().updateRenderingAttributes(c3d.ctx, + depthBufferWriteEnableOverride, depthBufferEnableOverride, + depthBufferEnable, depthBufferWriteEnable, depthTestFunction, + alphaTestValue, alphaTestFunction, ignoreVertexColors, + rasterOpEnable, rasterOp, c3d.userStencilAvailable, stencilEnable, + stencilFailOp, stencilZFailOp, stencilZPassOp, + stencilFunction, stencilReferenceValue, stencilCompareMask, + stencilWriteMask ); + } + + /** + * Creates and initializes a mirror object, point the mirror object + * to the retained object if the object is not editable + */ + synchronized void createMirrorObject() { + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror = this; + } + else { + RenderingAttributesRetained mirrorRa + = new RenderingAttributesRetained(); + mirrorRa.set(this); + mirrorRa.source = source; + mirror = mirrorRa; + } + } else { + ((RenderingAttributesRetained) mirror).set(this); + } + } + + /** + * Initializes a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + ((RenderingAttributesRetained)mirror).set(this); + } + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + RenderingAttributesRetained mirrorRa = (RenderingAttributesRetained)mirror; + + if ((component & DEPTH_ENABLE) != 0) { + mirrorRa.depthBufferEnable = ((Boolean)value).booleanValue(); + } + else if ((component & DEPTH_WRITE_ENABLE) != 0) { + mirrorRa.depthBufferWriteEnable = ((Boolean)value).booleanValue(); + } + else if ((component & DEPTH_TEST_FUNC) != 0) { + mirrorRa.depthTestFunction = ((Integer)value).intValue(); + } + else if ((component & ALPHA_TEST_VALUE) != 0) { + mirrorRa.alphaTestValue = ((Float)value).floatValue(); + } + else if ((component & ALPHA_TEST_FUNC) != 0) { + mirrorRa.alphaTestFunction = ((Integer)value).intValue(); + } + else if ((component & VISIBLE) != 0) { + mirrorRa.visible = (((Boolean)value).booleanValue()); + } + else if ((component & IGNORE_VCOLOR) != 0) { + mirrorRa.ignoreVertexColors = (((Boolean)value).booleanValue()); + } + else if ((component & RASTER_OP_ENABLE) != 0) { + mirrorRa.rasterOpEnable = (((Boolean)value).booleanValue()); + } + else if ((component & RASTER_OP_VALUE) != 0) { + mirrorRa.rasterOp = (((Integer)value).intValue()); + } + else if ((component & STENCIL_ENABLE) != 0) { + mirrorRa.stencilEnable = (((Boolean)value).booleanValue()); + } + else if ((component & STENCIL_OP_VALUES) != 0) { + ArrayList arrlist = (ArrayList) value; + mirrorRa.stencilFailOp = (((Integer)arrlist.get(0)).intValue()); + mirrorRa.stencilZFailOp = (((Integer)arrlist.get(1)).intValue()); + mirrorRa.stencilZPassOp = (((Integer)arrlist.get(2)).intValue()); + } + else if ((component & STENCIL_FUNC) != 0) { + ArrayList arrlist = (ArrayList) value; + mirrorRa.stencilFunction = (((Integer)arrlist.get(0)).intValue()); + mirrorRa.stencilReferenceValue = (((Integer)arrlist.get(1)).intValue()); + mirrorRa.stencilCompareMask = (((Integer)arrlist.get(2)).intValue()); + } + else if ((component & STENCIL_WRITE_MASK) != 0) { + mirrorRa.stencilWriteMask = (((Integer)value).intValue()); + } + } + + boolean equivalent(RenderingAttributesRetained rr) { + return (this == rr) || + ((rr != null) && + (rr.depthBufferEnable == depthBufferEnable) && + (rr.depthBufferWriteEnable == depthBufferWriteEnable) && + (rr.alphaTestValue == alphaTestValue) && + (rr.alphaTestFunction == alphaTestFunction) && + (rr.visible == visible) && + (rr.ignoreVertexColors == ignoreVertexColors) && + (rr.rasterOpEnable == rasterOpEnable) && + (rr.rasterOp == rasterOp) && + (rr.depthTestFunction == depthTestFunction) && + (rr.stencilEnable == stencilEnable) && + (rr.stencilFailOp == stencilFailOp) && + (rr.stencilZFailOp == stencilZFailOp) && + (rr.stencilZPassOp == stencilZPassOp) && + (rr.stencilFunction == stencilFunction) && + (rr.stencilReferenceValue == stencilReferenceValue) && + (rr.stencilCompareMask == stencilCompareMask) && + (rr.stencilWriteMask == stencilWriteMask)); + } + + protected void set(RenderingAttributesRetained ra) { + super.set(ra); + depthBufferEnable = ra.depthBufferEnable; + depthBufferWriteEnable = ra.depthBufferWriteEnable; + alphaTestValue = ra.alphaTestValue; + alphaTestFunction = ra.alphaTestFunction; + depthTestFunction = ra.depthTestFunction; + visible = ra.visible; + ignoreVertexColors = ra.ignoreVertexColors; + rasterOpEnable = ra.rasterOpEnable; + rasterOp = ra.rasterOp; + stencilEnable = ra.stencilEnable; + stencilFailOp = ra.stencilFailOp; + stencilZFailOp = ra.stencilZFailOp; + stencilZPassOp = ra.stencilZPassOp; + stencilFunction = ra.stencilFunction; + stencilReferenceValue = ra.stencilReferenceValue; + stencilCompareMask = ra.stencilCompareMask; + stencilWriteMask = ra.stencilWriteMask; + + } + + final void sendMessage(int attrMask, Object attr) { + + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.RENDERINGATTRIBUTES_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + // System.err.println("changedFreqent1 = "+changedFrequent); + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i retlights.length) + retlights = new LightRetained[numberOfLights]; + if (intersectedFogs.length < numberOfFogs) + intersectedFogs = new FogRetained[numberOfFogs]; + if (intersectedAltApps.length < numberOfAltApps) + intersectedAltApps = new AlternateAppearanceRetained[numberOfAltApps]; + if (intersectedBacks.length < numberOfBgs) + intersectedBacks = new BackgroundRetained[numberOfBgs]; + if (intersectedClips.length < numberOfClips) + intersectedClips = new ClipRetained[numberOfClips]; + if (intersectedModelClips.length < numberOfModelClips) + intersectedModelClips = new ModelClipRetained[numberOfModelClips]; + } + + void removeNodes(J3dMessage m) { + Object[] nodes = (Object[])m.args[0]; + ArrayList viewScopedNodes = (ArrayList)m.args[3]; + ArrayList scopedNodesViewList = (ArrayList)m.args[4]; + Object n; + int i; + GeometryAtom ga; + LeafRetained oldsrc = null; + + // System.err.println("RE : removeNodes message " + m); + // System.err.println("RE : removeNodes m.args[0] " + m.args[0]); + + for (i=0; i 0) { + for (i=0; i 1) { + closestBounds = + bounds.closestIntersection(intersectedBounds); + for (j=0; j < nclips; j++) { + if (intersectedBounds[j] == closestBounds) { + distance = intersectedClips[j].backDistanceInVworld; + backClipActive = true; + break; + } + } + } + if (backClipActive) { + backClipDistance = new double[1]; + backClipDistance[0] = distance; + } + return (backClipDistance); + } + } + + int processClips(ArrayList globalClips, BoundingSphere bounds, int nclips) { + int i; + int size = globalClips.size(); + ClipRetained clip; + + for (i=0 ; i 1) { + closestBounds = bounds.closestIntersection(intersectedBounds); + for (j= 0; j < nAltApp; j++) { + if (intersectedBounds[j] == closestBounds) { + altApp = intersectedAltApps[j]; + break; + } + } + } + if (altApp == null) { + retVal[0] = Boolean.FALSE; + return retVal; + } else { + retVal[0] = Boolean.TRUE; + retVal[1] = altApp.appearance; + return retVal; + } + } + } + + // Called while holding lockObj lock + int processAltApps(ArrayList globalAltApps, RenderAtom ra, int nAltApp) { + int size = globalAltApps.size(); + AlternateAppearanceRetained altApp; + int i, k, n; + Bounds bounds = ra.localeVwcBounds; + AlternateAppearanceRetained[] shapeScopedAltApp; + + + if (size > 0) { + for (i = 0; i < size; i++) { + altApp = (AlternateAppearanceRetained) globalAltApps.get(i); + // System.err.println("altApp.region = "+altApp.region+" altApp.switchState.currentSwitchOn = "+altApp.switchState.currentSwitchOn+" intersect = "+altApp.region.intersect(ra.geometryAtom.vwcBounds)); + // System.err.println("altApp.isScoped = "+altApp.isScoped); + // Note : There is no enable check for fog + if (altApp.region != null && altApp.switchState.currentSwitchOn) { + if (altApp.region.intersect(bounds) == true) { + n = ((Shape3DRetained)ra.geometryAtom.source).numAltApps; + shapeScopedAltApp = ((Shape3DRetained)ra.geometryAtom.source).altApps; + if (altApp.isScoped) { + for (k = 0; k < n; k++) { + // then check if the light is scoped to + // this group + if (altApp == shapeScopedAltApp[k]) { + + intersectedBounds[nAltApp] = altApp.region; + intersectedAltApps[nAltApp++] = altApp; + break; + } + } + } + else { + intersectedBounds[nAltApp] = altApp.region; + intersectedAltApps[nAltApp++] = altApp; + } + } + } + } + } + return nAltApp; + } + + void initViewSpecificInfo(J3dMessage m) { + int[] keys = (int[])m.args[2]; + ArrayList vlists = (ArrayList)m.args[1]; + ArrayList vsgs = (ArrayList)m.args[0]; + if (vsgs != null) { + // System.err.println("===> non null Vsg"); + int size = vsgs.size(); + for (int i = 0; i < size; i++) { + ViewSpecificGroupRetained v = (ViewSpecificGroupRetained)vsgs.get(i); + ArrayList l = (ArrayList)vlists.get(i); + int index = keys[i]; + // System.err.println("v = "+v+" index = "+index+" l = "+l); + v.cachedViewList.add(index, l); + /* + for (int k = 0; k < v.cachedViewList.size(); k++) { + System.err.println("v = "+v+" k = "+k+" v.cachedViewList.get(k) = "+v.cachedViewList.get(k)); + } + */ + } + } + } + + void clearViewSpecificInfo(J3dMessage m) { + int[] keys = (int[])m.args[1]; + ArrayList vsgs = (ArrayList)m.args[0]; + if (vsgs != null) { + int size = vsgs.size(); + for (int i = 0; i < size; i++) { + ViewSpecificGroupRetained v = (ViewSpecificGroupRetained)vsgs.get(i); + int index = keys[i]; + if (index == -1) { + int csize = v.cachedViewList.size(); + for (int j = 0; j< csize; j++) { + ArrayList l = (ArrayList)v.cachedViewList.get(j); + l.clear(); + } + v.cachedViewList.clear(); + } + else { + ArrayList l = (ArrayList) v.cachedViewList.remove(index); + l.clear(); + } + } + } + } + + void updateViewSpecificGroupChanged(J3dMessage m) { + int component = ((Integer)m.args[0]).intValue(); + Object[] objAry = (Object[])m.args[1]; + + ArrayList ltList = null; + ArrayList fogList = null; + ArrayList mclipList = null; + ArrayList altAppList = null; + ArrayList bgList = null; + ArrayList clipList = null; + int idx; + + if (((component & ViewSpecificGroupRetained.ADD_VIEW) != 0) || + ((component & ViewSpecificGroupRetained.SET_VIEW) != 0)) { + int i; + Object obj; + View view = (View)objAry[0]; + ArrayList vsgList = (ArrayList)objAry[1]; + ArrayList leafList = (ArrayList)objAry[2]; + int[] keyList = (int[])objAry[3]; + int size = vsgList.size(); + // Don't add null views + + if (view != null) { + for (i = 0; i < size; i++) { + ViewSpecificGroupRetained vsg = (ViewSpecificGroupRetained)vsgList.get(i); + int index = keyList[i]; + vsg.updateCachedInformation(ViewSpecificGroupRetained.ADD_VIEW, view, index); + + } + size = leafList.size(); + // Leaves is non-null only for the top VSG + + if (size > 0) { + // Now process the list of affected leaved + for( i = 0; i < size; i++) { + obj = leafList.get(i); + if (obj instanceof LightRetained) { + ((LightRetained)obj).isViewScoped = true; + numberOfLights++; + if (ltList == null) { + if ((ltList = (ArrayList)viewScopedLights.get(view)) == null) { + ltList = new ArrayList(); + viewScopedLights.put(view, ltList); + } + } + ltList.add(obj); + } + if (obj instanceof FogRetained) { + ((FogRetained)obj).isViewScoped = true; + numberOfFogs++; + if (fogList == null) { + if ((fogList= (ArrayList)viewScopedFogs.get(view)) == null) { + fogList = new ArrayList(); + viewScopedFogs.put(view, fogList); + } + } + fogList.add(obj); + } + if (obj instanceof ModelClipRetained) { + ((ModelClipRetained)obj).isViewScoped = true; + numberOfModelClips++; + if (mclipList == null) { + if ((mclipList= (ArrayList)viewScopedModelClips.get(view)) == null) { + mclipList = new ArrayList(); + viewScopedModelClips.put(view, mclipList); + } + } + mclipList.add(obj); + } + if (obj instanceof AlternateAppearanceRetained) { + ((AlternateAppearanceRetained)obj).isViewScoped = true; + numberOfAltApps++; + if (altAppList == null) { + if ((altAppList= (ArrayList)viewScopedAltAppearances.get(view)) == null) { + altAppList = new ArrayList(); + viewScopedAltAppearances.put(view, altAppList); + } + } + altAppList.add(obj); + } + if (obj instanceof ClipRetained) { + ((ClipRetained)obj).isViewScoped = true; + numberOfClips++; + if (clipList == null) { + if ((clipList= (ArrayList)viewScopedClips.get(view)) == null) { + clipList = new ArrayList(); + viewScopedClips.put(view, clipList); + } + } + clipList.add(obj); + } + if (obj instanceof BackgroundRetained) { + ((BackgroundRetained)obj).isViewScoped = true; + numberOfBgs++; + if (bgList == null) { + if ((bgList= (ArrayList)viewScopedBackgrounds.get(view)) == null) { + bgList = new ArrayList(); + viewScopedBackgrounds.put(view, bgList); + } + } + bgList.add(obj); + } + } + if (numberOfLights > retlights.length) + retlights = new LightRetained[numberOfLights]; + if (intersectedFogs.length < numberOfFogs) + intersectedFogs = new FogRetained[numberOfFogs]; + if (intersectedAltApps.length < numberOfAltApps) + intersectedAltApps = new AlternateAppearanceRetained[numberOfAltApps]; + if (intersectedBacks.length < numberOfBgs) + intersectedBacks = new BackgroundRetained[numberOfBgs]; + if (intersectedClips.length < numberOfClips) + intersectedClips = new ClipRetained[numberOfClips]; + if (intersectedModelClips.length < numberOfModelClips) + intersectedModelClips = new ModelClipRetained[numberOfModelClips]; + } + } + } + if (((component & ViewSpecificGroupRetained.REMOVE_VIEW) != 0)|| + ((component & ViewSpecificGroupRetained.SET_VIEW) != 0)) { + int i; + Object obj; + ArrayList vsgList; + ArrayList leafList; + int[] keyList; + View view; + + if ((component & ViewSpecificGroupRetained.REMOVE_VIEW) != 0) { + view = (View)objAry[0]; + vsgList = (ArrayList)objAry[1]; + leafList = (ArrayList)objAry[2]; + keyList = (int[])objAry[3]; + } + else { + view = (View)objAry[4]; + vsgList = (ArrayList)objAry[5]; + leafList = (ArrayList)objAry[6]; + keyList = (int[])objAry[7]; + } + // Don't add null views + if (view != null) { + int size = vsgList.size(); + for (i = 0; i < size; i++) { + ViewSpecificGroupRetained vsg = (ViewSpecificGroupRetained)vsgList.get(i); + int index = keyList[i]; + vsg.updateCachedInformation(ViewSpecificGroupRetained.REMOVE_VIEW, view, index); + + } + size = leafList.size(); + // Leaves is non-null only for the top VSG + if (size > 0) { + // Now process the list of affected leaved + for( i = 0; i < size; i++) { + obj = leafList.get(i); + if (obj instanceof LightRetained) { + ((LightRetained)obj).isViewScoped = false; + numberOfLights--; + if (ltList == null) { + ltList = (ArrayList)viewScopedLights.get(view); + } + ltList.remove(obj); + } + if (obj instanceof FogRetained) { + ((FogRetained)obj).isViewScoped = false; + numberOfFogs--; + if (fogList == null) { + fogList = (ArrayList)viewScopedFogs.get(view); + } + fogList.remove(obj); + } + if (obj instanceof ModelClipRetained) { + ((ModelClipRetained)obj).isViewScoped = false; + numberOfModelClips--; + if (mclipList == null) { + mclipList = (ArrayList)viewScopedModelClips.get(view); + } + mclipList.remove(obj); + } + if (obj instanceof AlternateAppearanceRetained) { + ((AlternateAppearanceRetained)obj).isViewScoped = false; + numberOfAltApps--; + if (altAppList == null) { + altAppList = (ArrayList)viewScopedAltAppearances.get(view); + } + altAppList.remove(obj); + } + if (obj instanceof ClipRetained) { + ((ClipRetained)obj).isViewScoped = false; + numberOfClips--; + if (clipList == null) { + clipList = (ArrayList)viewScopedClips.get(view); + } + clipList.remove(obj); + } + if (obj instanceof BackgroundRetained) { + ((BackgroundRetained)obj).isViewScoped = false; + numberOfBgs++; + if (bgList == null) { + bgList = (ArrayList)viewScopedBackgrounds.get(view); + } + bgList.remove(obj); + } + } + + // If there are no more lights scoped to the view, + // remove the mapping + if (ltList != null && ltList.size() == 0) + viewScopedLights.remove(view); + if (fogList != null && fogList.size() == 0) + viewScopedFogs.remove(view); + if (mclipList != null && mclipList.size() == 0) + viewScopedModelClips.remove(view); + if (altAppList != null && altAppList.size() == 0) + viewScopedAltAppearances.remove(view); + if (clipList != null && clipList.size() == 0) + viewScopedClips.remove(view); + if (bgList != null && bgList.size() == 0) + viewScopedBackgrounds.remove(view); + } + } + } + + } + + boolean isLightScopedToThisView(Object obj, View view) { + LightRetained light = (LightRetained)obj; + if (light.isViewScoped) { + ArrayList l = (ArrayList)viewScopedLights.get(view); + // If this is a scoped lights, but has no views then .. + if (l == null || !l.contains(light)) + return false; + } + return true; + } + + boolean isFogScopedToThisView(Object obj, View view) { + FogRetained fog = (FogRetained)obj; + if (fog.isViewScoped) { + ArrayList l = (ArrayList)viewScopedFogs.get(view); + // If this is a scoped fog, but has no views then .. + if (l ==null || !l.contains(fog)) + return false; + } + return true; + } + + boolean isAltAppScopedToThisView(Object obj, View view) { + AlternateAppearanceRetained altApp = (AlternateAppearanceRetained)obj; + if (altApp.isViewScoped) { + ArrayList l = (ArrayList)viewScopedAltAppearances.get(view); + // If this is a scoped altapp, but has no views then .. + if (l == null || !l.contains(altApp)) + return false; + } + return true; + } + + boolean isBgScopedToThisView(Object obj, View view) { + BackgroundRetained bg = (BackgroundRetained)obj; + if (bg.isViewScoped) { + ArrayList l = (ArrayList)viewScopedBackgrounds.get(view); + // If this is a scoped bg, but has no views then .. + if (l == null || !l.contains(bg)) + return false; + } + return true; + } + + boolean isClipScopedToThisView(Object obj, View view) { + ClipRetained clip = (ClipRetained)obj; + if (clip.isViewScoped) { + ArrayList l = (ArrayList)viewScopedClips.get(view); + // If this is a scoped clip, but has no views then .. + if (l == null || !l.contains(clip)) + return false; + } + return true; + } + + + boolean isMclipScopedToThisView(Object obj, View view) { + ModelClipRetained mclip = (ModelClipRetained)obj; + if (mclip.isViewScoped) { + ArrayList l = (ArrayList)viewScopedModelClips.get(view); + // If this is a scoped mclip, but has no views then .. + if (l == null || !l.contains(mclip)) + return false; + } + return true; + } + + void cleanup() {} +} + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderingError.java b/j3d-core/src/classes/share/javax/media/j3d/RenderingError.java new file mode 100644 index 0000000..be98279 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderingError.java @@ -0,0 +1,272 @@ +/* + * $RCSfile: RenderingError.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsDevice; +import java.io.PrintStream; + +/** + * RenderingError is a container object that holds the details of + * a runtime error that occurs in the Java 3D rendering system. + * + * @since Java 3D 1.5 + */ +public class RenderingError extends Object { + private int errorCode = NO_ERROR; + private String errorMessage = null; + private String detailMessage = null; + private GraphicsDevice graphicsDevice = null; + private Canvas3D canvas = null; + + /** + * Indicates that no error occurred. + */ + public static final int NO_ERROR = 0; + + /** + * Indicates that an unexpected rendering exception was caught by the + * Java 3D renderer thread. + */ + public static final int UNEXPECTED_RENDERING_ERROR = 1; + + /** + * Indicates that an error occurred while getting the best graphics + * configuration or while testing whether a given graphics config is + * supported. + */ + public static final int GRAPHICS_CONFIG_ERROR = 2; + + /** + * Indicates that an error occurred while creating an OpenGL or D3D + * graphics context. This can happen either when querying + * the Canvas3D properties or when rendering. + */ + public static final int CONTEXT_CREATION_ERROR = 3; + + /** + * Indicates a error in creating a rendering buffer for an off-screen + * Canvas3D. + */ + public static final int OFF_SCREEN_BUFFER_ERROR = 4; + + + /** + * Constructs a new RenderingError object indicating no error. The + * error code is set to NO_ERROR. All other fields + * are initialized to null, including the error message. + */ + public RenderingError() { + } + + /** + * Constructs a new RenderingError object with the given error code + * and message. All other fields are initialized to null. + * + * @param errorCode the error code for this rendering error. + * @param errorMessage a short error message describing this + * rendering error. + */ + public RenderingError(int errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + /** + * Prints a verbose error report to System.err. This verbose + * output includes the error code, error message, detail message, + * and all relevant Java 3D objects. + */ + public void printVerbose() { + printVerbose(System.err); + } + + /** + * Prints a verbose error report to the specified PrintStream. + * This verbose output includes the error code, error message, + * detail message, and all relevant Java 3D objects. + * + * @param printStream the print stream on which to print the error + * report. + */ + public void printVerbose(PrintStream printStream) { + printStream.println(this); + if (graphicsDevice != null) { + printStream.println("graphicsDevice = " + graphicsDevice); + } + if (canvas != null) { + printStream.println("canvas = " + canvas); + } + + if (detailMessage != null) { + printStream.println(); + printStream.println("Detail Message"); + printStream.println("--------------"); + printStream.println(detailMessage); + } + } + + /** + * Sets the error code for this rendering error. This represents the + * type of error that occurred. + * + * @param errorCode the error code for this rendering error. + */ + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + /** + * Returns the error code for this rendering error. + * + * @return the error code. + */ + public int getErrorCode() { + return errorCode; + } + + /** + * Sets the error message for this rendering error. This is a short + * message describing the error, and is included as part of + * toString(). + * + * @param errorMessage a short error message describing this + * rendering error. + */ + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + /** + * Returns the error message for this rendering error. + * + * @return a short error message describing this rendering error. + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the detail message for this rendering error. This is a more + * detailed error message that is not included as part of toString(). + * + * @param detailMessage a detailed message describing this + * error in more detail. + */ + public void setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + } + + /** + * Returns the detail message for this rendering error. + * + * @return the detail message for this rendering error. + */ + public String getDetailMessage() { + return detailMessage; + } + + /** + * Sets the graphics device associated with this rendering error. + * + * @param graphicsDevice the graphics device associated with this rendering error. + */ + public void setGraphicsDevice(GraphicsDevice graphicsDevice) { + this.graphicsDevice = graphicsDevice; + } + + /** + * Returns the graphics device associated with this rendering error. + * + * @return the graphics device associated with this rendering error. + */ + public GraphicsDevice getGraphicsDevice() { + return this.graphicsDevice; + } + + /** + * Sets the canvas associated with this rendering error. + * + * @param canvas the canvas associated with this rendering error. + */ + public void setCanvas3D(Canvas3D canvas) { + this.canvas = canvas; + } + + /** + * Returns the canvas associated with this rendering error. + * + * @return the canvas associated with this rendering error. + */ + public Canvas3D getCanvas3D() { + return this.canvas; + } + + + /** + * Returns a short string that describes this rendering error. The + * string is composed of the textual description of the errorCode, + * a ": ", and the errorMessage field. If the errorMessage is + * null then the ": " and the errorMessage are omitted. + * + * @return a string representation of this rendering error. + */ + public String toString() { + // Concatenate string representation of error code with error message + String errorCodeStr; + switch (errorCode) { + case NO_ERROR: + errorCodeStr = "NO_ERROR"; + break; + case UNEXPECTED_RENDERING_ERROR: + errorCodeStr = "UNEXPECTED_RENDERING_ERROR"; + break; + case GRAPHICS_CONFIG_ERROR: + errorCodeStr = "GRAPHICS_CONFIG_ERROR"; + break; + case CONTEXT_CREATION_ERROR: + errorCodeStr = "CONTEXT_CREATION_ERROR"; + break; + case OFF_SCREEN_BUFFER_ERROR: + errorCodeStr = "OFF_SCREEN_BUFFER_ERROR"; + break; + + default: + errorCodeStr = "UNKNOWN ERROR CODE (" + errorCode + ")"; + } + + if (errorMessage == null) { + return errorCodeStr; + } + + return errorCodeStr + ": " + errorMessage; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RenderingErrorListener.java b/j3d-core/src/classes/share/javax/media/j3d/RenderingErrorListener.java new file mode 100644 index 0000000..96d4aa3 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RenderingErrorListener.java @@ -0,0 +1,48 @@ +/* + * $RCSfile: RenderingErrorListener.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Listener interface for monitoring Java 3D rendering errors. + * + * @see VirtualUniverse#addRenderingErrorListener + * + * @since Java 3D 1.5 + */ +public interface RenderingErrorListener { + /** + * Invoked when an error occurs in the Java 3D rendering system. + * + * @param error object that contains the details of the error. + */ + public void errorOccurred(RenderingError error); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RestrictedAccessException.java b/j3d-core/src/classes/share/javax/media/j3d/RestrictedAccessException.java new file mode 100644 index 0000000..f4b859e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RestrictedAccessException.java @@ -0,0 +1,56 @@ +/* + * $RCSfile: RestrictedAccessException.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates an attempt to access or modify a state variable + * without permission to do so. For example, invoking a set + * method for a state variable that is currently read-only. + */ +public class RestrictedAccessException extends RuntimeException { + +/** + * Create the exception object with default values. + */ + public RestrictedAccessException(){ + } + +/** + * Create the exception object that outputs a message. + * @param str the message string to be output. + */ + public RestrictedAccessException(String str) { + + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RotPosPathInterpolator.java b/j3d-core/src/classes/share/javax/media/j3d/RotPosPathInterpolator.java new file mode 100644 index 0000000..da2be4f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RotPosPathInterpolator.java @@ -0,0 +1,397 @@ +/* + * $RCSfile: RotPosPathInterpolator.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Vector3f; +import javax.vecmath.Quat4f; +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3f; + + +/** + * RotPosPathInterpolator behavior. This class defines a behavior that + * modifies the rotational and translational components of its target + * TransformGroup by linearly interpolating among a series of predefined + * knot/positon and knot/orientation pairs (using the value generated + * by the specified Alpha object). The interpolated position and + * orientation are used to generate a transform in the local coordinate + * system of this interpolator. + */ + +public class RotPosPathInterpolator extends PathInterpolator { + private Transform3D rotation = new Transform3D(); + + private Vector3f pos = new Vector3f(); + private Quat4f tQuat = new Quat4f(); + private Matrix4d tMat = new Matrix4d(); + + // Arrays of quaternions and positions at each knot + private Quat4f quats[]; + private Point3f positions[]; + private float prevInterpolationValue = Float.NaN; + + // We can't use a boolean flag since it is possible + // that after alpha change, this procedure only run + // once at alpha.finish(). So the best way is to + // detect alpha value change. + private float prevAlphaValue = Float.NaN; + private WakeupCriterion passiveWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0, true); + + // non-public, default constructor used by cloneNode + RotPosPathInterpolator() { + } + + + /** + * Constructs a new interpolator that varies the rotation and translation + * of the target TransformGroup's transform. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this translator + * @param axisOfTransform the transform that defines the local coordinate + * system in which this interpolator operates + * @param knots an array of knot values that specify interpolation points. + * @param quats an array of quaternion values at the knots. + * @param positions an array of position values at the knots. + * @exception IllegalArgumentException if the lengths of the + * knots, quats, and positions arrays are not all the same. + */ + public RotPosPathInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + float[] knots, + Quat4f[] quats, + Point3f[] positions) { + super(alpha, target, axisOfTransform, knots); + + if (knots.length != positions.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosPathInterpolator0")); + + if (knots.length != quats.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosPathInterpolator0")); + + setPathArrays(quats, positions); + } + + + /** + * Sets the quat at the specified index for this interpolator. + * @param index the index to be changed + * @param quat the new quat value + */ + public void setQuat(int index, Quat4f quat) { + this.quats[index].set(quat); + } + + + /** + * Retrieves the quat value at the specified index. + * @param index the index of the value requested + * @param quat the quat to receive the quat value at the index + */ + public void getQuat(int index, Quat4f quat) { + quat.set(this.quats[index]); + } + + + /** + * Sets the position at the specified index for this + * interpolator. + * @param index the index to be changed + * @param position the new position value + */ + public void setPosition(int index, Point3f position) { + this.positions[index].set(position); + } + + + /** + * Retrieves the position value at the specified index. + * @param index the index of the value requested + * @param position the position to receive the position value at the index + */ + public void getPosition(int index, Point3f position) { + position.set(this.positions[index]); + } + + + /** + * Replaces the existing arrays of knot values, quaternion + * values, and position values with the specified arrays. + * The arrays of knots, quats, and positions are copied + * into this interpolator object. + * @param knots a new array of knot values that specify + * interpolation points. + * @param quats a new array of quaternion values at the knots. + * @param positions a new array of position values at the knots. + * @exception IllegalArgumentException if the lengths of the + * knots, quats, and positions arrays are not all the same. + * + * @since Java 3D 1.2 + */ + public void setPathArrays(float[] knots, + Quat4f[] quats, + Point3f[] positions) { + + if (knots.length != quats.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosPathInterpolator0")); + + if (knots.length != positions.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosPathInterpolator0")); + + setKnots(knots); + setPathArrays(quats, positions); + } + + + // Set the specific arrays for this path interpolator + private void setPathArrays(Quat4f[] quats, + Point3f[] positions) { + + this.quats = new Quat4f[quats.length]; + for(int i = 0; i < quats.length; i++) { + this.quats[i] = new Quat4f(); + this.quats[i].set(quats[i]); + } + + this.positions = new Point3f[positions.length]; + for(int i = 0; i < positions.length; i++) { + this.positions[i] = new Point3f(); + this.positions[i].set(positions[i]); + } + } + + + /** + * Copies the array of quaternion values from this interpolator + * into the specified array. + * The array must be large enough to hold all of the quats. + * The individual array elements must be allocated by the caller. + * @param quats array that will receive the quats. + * + * @since Java 3D 1.2 + */ + public void getQuats(Quat4f[] quats) { + for (int i = 0; i < this.quats.length; i++) { + quats[i].set(this.quats[i]); + } + } + + + /** + * Copies the array of position values from this interpolator + * into the specified array. + * The array must be large enough to hold all of the positions. + * The individual array elements must be allocated by the caller. + * @param positions array that will receive the positions. + * + * @since Java 3D 1.2 + */ + public void getPositions(Point3f[] positions) { + for (int i = 0; i < this.positions.length; i++) { + positions[i].set(this.positions[i]); + } + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.setTransformAxis(Transform3D) + */ + + public void setAxisOfRotPos(Transform3D axisOfRotPos) { + setTransformAxis(axisOfRotPos); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.getTransformAxis() + */ + public Transform3D getAxisOfRotPos() { + return getTransformAxis(); + } + + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + double quatDot; + + computePathInterpolation(alphaValue); + + if (currentKnotIndex == 0 && + currentInterpolationValue == 0f) { + tQuat.x = quats[0].x; + tQuat.y = quats[0].y; + tQuat.z = quats[0].z; + tQuat.w = quats[0].w; + pos.x = positions[0].x; + pos.y = positions[0].y; + pos.z = positions[0].z; + } else { + quatDot = quats[currentKnotIndex].x * + quats[currentKnotIndex+1].x + + quats[currentKnotIndex].y * + quats[currentKnotIndex+1].y + + quats[currentKnotIndex].z * + quats[currentKnotIndex+1].z + + quats[currentKnotIndex].w * + quats[currentKnotIndex+1].w; + if (quatDot < 0) { + tQuat.x = quats[currentKnotIndex].x + + (-quats[currentKnotIndex+1].x - + quats[currentKnotIndex].x)*currentInterpolationValue; + tQuat.y = quats[currentKnotIndex].y + + (-quats[currentKnotIndex+1].y - + quats[currentKnotIndex].y)*currentInterpolationValue; + tQuat.z = quats[currentKnotIndex].z + + (-quats[currentKnotIndex+1].z - + quats[currentKnotIndex].z)*currentInterpolationValue; + tQuat.w = quats[currentKnotIndex].w + + (-quats[currentKnotIndex+1].w - + quats[currentKnotIndex].w)*currentInterpolationValue; + } else { + tQuat.x = quats[currentKnotIndex].x + + (quats[currentKnotIndex+1].x - + quats[currentKnotIndex].x)*currentInterpolationValue; + tQuat.y = quats[currentKnotIndex].y + + (quats[currentKnotIndex+1].y - + quats[currentKnotIndex].y)*currentInterpolationValue; + tQuat.z = quats[currentKnotIndex].z + + (quats[currentKnotIndex+1].z - + quats[currentKnotIndex].z)*currentInterpolationValue; + tQuat.w = quats[currentKnotIndex].w + + (quats[currentKnotIndex+1].w - + quats[currentKnotIndex].w)*currentInterpolationValue; + } + pos.x = positions[currentKnotIndex].x + + (positions[currentKnotIndex+1].x - + positions[currentKnotIndex].x) * currentInterpolationValue; + pos.y = positions[currentKnotIndex].y + + (positions[currentKnotIndex+1].y - + positions[currentKnotIndex].y) * currentInterpolationValue; + pos.z = positions[currentKnotIndex].z + + (positions[currentKnotIndex+1].z - + positions[currentKnotIndex].z) * currentInterpolationValue; + } + tQuat.normalize(); + + // Set the rotation components + tMat.set(tQuat); + + // Set the translation components. + tMat.m03 = pos.x; + tMat.m13 = pos.y; + tMat.m23 = pos.z; + rotation.set(tMat); + + // construct a Transform3D from: axis * rotation * axisInverse + transform.mul(axis, rotation); + transform.mul(transform, axisInverse); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + RotPosPathInterpolator rppi = new RotPosPathInterpolator(); + rppi.duplicateNode(this, forceDuplicate); + return rppi; + } + + + + /** + * Copies all RotPosPathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + RotPosPathInterpolator ri = (RotPosPathInterpolator) originalNode; + + int len = ri.getArrayLengths(); + + // No API availble to set array size, so explicitly set it here + positions = new Point3f[len]; + quats = new Quat4f[len]; + + Point3f point = new Point3f(); + Quat4f quat = new Quat4f(); + + for (int i = 0; i < len; i++) { + positions[i] = new Point3f(); + ri.getPosition(i, point); + setPosition(i, point); + + quats[i] = new Quat4f(); + ri.getQuat(i, quat); + setQuat(i, quat); + } + + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RotPosScalePathInterpolator.java b/j3d-core/src/classes/share/javax/media/j3d/RotPosScalePathInterpolator.java new file mode 100644 index 0000000..f2a20e4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RotPosScalePathInterpolator.java @@ -0,0 +1,469 @@ +/* + * $RCSfile: RotPosScalePathInterpolator.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Matrix4d; +import javax.vecmath.Quat4f; +import javax.vecmath.Vector3f; +import javax.vecmath.Point3f; + + +/** + * RotPosScalePathInterpolation behavior. This class defines a behavior + * that varies the rotational, translational, and scale components of its + * target TransformGroup by linearly interpolating among a series of + * predefined knot/position, knot/orientation, and knot/scale pairs + * (using the value generated by the specified Alpha object). The + * interpolated position, orientation, and scale are used to generate + * a transform in the local coordinate system of this interpolator. The + * first knot must have a value of 0.0. The last knot must have a value + * of 1.0. An intermediate knot with index k must have a value strictly + * greater than any knot with index less than k. + */ + +public class RotPosScalePathInterpolator extends PathInterpolator { + private Transform3D rotation = new Transform3D(); + + private Vector3f pos = new Vector3f(); + private Quat4f tQuat = new Quat4f(); + private Matrix4d tMat = new Matrix4d(); + private Matrix4d sMat = new Matrix4d(); + + // Arrays of quaternions, positions, and scales at each knot + private Quat4f quats[]; + private Point3f positions[]; + private float scales[]; + + private float prevInterpolationValue = Float.NaN; + + // We can't use a boolean flag since it is possible + // that after alpha change, this procedure only run + // once at alpha.finish(). So the best way is to + // detect alpha value change. + private float prevAlphaValue = Float.NaN; + private WakeupCriterion passiveWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0, true); + + // non-public, default constructor used by cloneNode + RotPosScalePathInterpolator() { + } + + + /** + * Constructs a new RotPosScalePathInterpolator object that varies the + * rotation, translation, and scale of the target TransformGroup's + * transform. + * @param alpha the alpha object for this interpolator. + * @param target the TransformGroup node affected by this interpolator. + * @param axisOfTransform the transform that specifies the local + * coordinate system in which this interpolator operates. + * @param knots an array of knot values that specify interpolation points. + * @param quats an array of quaternion values at the knots. + * @param positions an array of position values at the knots. + * @param scales an array of scale component values at the knots. + * @exception IllegalArgumentException if the lengths of the + * knots, quats, positions, and scales arrays are not all the same. + */ + public RotPosScalePathInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + float[] knots, + Quat4f[] quats, + Point3f[] positions, + float[] scales) { + super(alpha, target, axisOfTransform, knots); + + if (knots.length != quats.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosScalePathInterpolator1")); + + if (knots.length != positions.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosScalePathInterpolator0")); + + if (knots.length != scales.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosScalePathInterpolator2")); + + setPathArrays(quats, positions, scales); + } + + + /** + * Sets the quat value at the specified index for this + * interpolator. + * @param index the index to be changed + * @param quat the new quat value at index + */ + public void setQuat(int index, Quat4f quat) { + this.quats[index].set(quat); + } + + + /** + * Retrieves the quat value at the specified index. + * @param index the index of the value requested + * @param quat returns the interpolator's quat value at the index + */ + public void getQuat(int index, Quat4f quat) { + quat.set(this.quats[index]); + } + + + /** + * Sets the position value at the specified index for + * this interpolator. + * @param index the index to be changed + * @param position the new position value at index + */ + public void setPosition(int index, Point3f position) { + this.positions[index].set(position); + } + + + /** + * Retrieves the position value at the specified index. + * @param index the index of the value requested + * @param position returns the interpolator's position value at the index + */ + public void getPosition(int index, Point3f position) { + position.set(this.positions[index]); + } + + + /** + * Sets the scale at the specified index for this + * interpolator. + * @param index the index to be changed + * @param scale the new scale at index + */ + public void setScale(int index, float scale) { + this.scales[index] = scale; + } + + + /** + * Retrieves the scale at the specified index. + * @param index the index of the value requested + * @return the interpolator's scale value at index + */ + public float getScale(int index) { + return this.scales[index]; + } + + + /** + * Replaces the existing arrays of knot values, quaternion + * values, position values, and scale values with the specified arrays. + * The arrays of knots, quats, positions, and scales are copied + * into this interpolator object. + * @param knots a new array of knot values that specify + * interpolation points. + * @param quats a new array of quaternion values at the knots. + * @param positions a new array of position values at the knots. + * @param scales a new array of scale component values at the knots. + * @exception IllegalArgumentException if the lengths of the + * knots, quats, positions, and scales arrays are not all the same. + * + * @since Java 3D 1.2 + */ + public void setPathArrays(float[] knots, + Quat4f[] quats, + Point3f[] positions, + float[] scales) { + if (knots.length != quats.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosScalePathInterpolator1")); + + if (knots.length != positions.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosScalePathInterpolator0")); + + if (knots.length != scales.length) + throw new IllegalArgumentException(J3dI18N.getString("RotPosScalePathInterpolator2")); + + setKnots(knots); + setPathArrays(quats, positions, scales); + } + + + // Set the specific arrays for this path interpolator + private void setPathArrays(Quat4f[] quats, + Point3f[] positions, + float[] scales) { + + this.quats = new Quat4f[quats.length]; + for(int i = 0; i < quats.length; i++) { + this.quats[i] = new Quat4f(); + this.quats[i].set(quats[i]); + } + + this.positions = new Point3f[positions.length]; + for(int i = 0; i < positions.length; i++) { + this.positions[i] = new Point3f(); + this.positions[i].set(positions[i]); + } + + this.scales = new float[scales.length]; + for(int i = 0; i < scales.length; i++) { + this.scales[i] = scales[i]; + } + } + + + /** + * Copies the array of quaternion values from this interpolator + * into the specified array. + * The array must be large enough to hold all of the quats. + * The individual array elements must be allocated by the caller. + * @param quats array that will receive the quats. + * + * @since Java 3D 1.2 + */ + public void getQuats(Quat4f[] quats) { + for (int i = 0; i < this.quats.length; i++) { + quats[i].set(this.quats[i]); + } + } + + + /** + * Copies the array of position values from this interpolator + * into the specified array. + * The array must be large enough to hold all of the positions. + * The individual array elements must be allocated by the caller. + * @param positions array that will receive the positions. + * + * @since Java 3D 1.2 + */ + public void getPositions(Point3f[] positions) { + for (int i = 0; i < this.positions.length; i++) { + positions[i].set(this.positions[i]); + } + } + + + /** + * Copies the array of scale values from this interpolator + * into the specified array. + * The array must be large enough to hold all of the scales. + * @param scales array that will receive the scales. + * + * @since Java 3D 1.2 + */ + public void getScales(float[] scales) { + for (int i = 0; i < this.scales.length; i++) { + scales[i] = this.scales[i]; + } + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.setTransformAxis(Transform3D) + */ + + public void setAxisOfRotPosScale(Transform3D axisOfRotPosScale) { + setTransformAxis(axisOfRotPosScale); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.geTransformAxis() + */ + public Transform3D getAxisOfRotPosScale() { + return getTransformAxis(); + } + + + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + + float scale; + double quatDot; + + computePathInterpolation(alphaValue); + + if (currentKnotIndex == 0 && + currentInterpolationValue == 0f) { + tQuat.x = quats[0].x; + tQuat.y = quats[0].y; + tQuat.z = quats[0].z; + tQuat.w = quats[0].w; + pos.x = positions[0].x; + pos.y = positions[0].y; + pos.z = positions[0].z; + scale = scales[0]; + } else { + quatDot = quats[currentKnotIndex].x * + quats[currentKnotIndex+1].x + + quats[currentKnotIndex].y * + quats[currentKnotIndex+1].y + + quats[currentKnotIndex].z * + quats[currentKnotIndex+1].z + + quats[currentKnotIndex].w * + quats[currentKnotIndex+1].w; + if (quatDot < 0) { + tQuat.x = quats[currentKnotIndex].x + + (-quats[currentKnotIndex+1].x - + quats[currentKnotIndex].x)*currentInterpolationValue; + tQuat.y = quats[currentKnotIndex].y + + (-quats[currentKnotIndex+1].y - + quats[currentKnotIndex].y)*currentInterpolationValue; + tQuat.z = quats[currentKnotIndex].z + + (-quats[currentKnotIndex+1].z - + quats[currentKnotIndex].z)*currentInterpolationValue; + tQuat.w = quats[currentKnotIndex].w + + (-quats[currentKnotIndex+1].w - + quats[currentKnotIndex].w)*currentInterpolationValue; + } else { + tQuat.x = quats[currentKnotIndex].x + + (quats[currentKnotIndex+1].x - + quats[currentKnotIndex].x)*currentInterpolationValue; + tQuat.y = quats[currentKnotIndex].y + + (quats[currentKnotIndex+1].y - + quats[currentKnotIndex].y)*currentInterpolationValue; + tQuat.z = quats[currentKnotIndex].z + + (quats[currentKnotIndex+1].z - + quats[currentKnotIndex].z)*currentInterpolationValue; + tQuat.w = quats[currentKnotIndex].w + + (quats[currentKnotIndex+1].w - + quats[currentKnotIndex].w)*currentInterpolationValue; + } + pos.x = positions[currentKnotIndex].x + + (positions[currentKnotIndex+1].x - + positions[currentKnotIndex].x) * currentInterpolationValue; + pos.y = positions[currentKnotIndex].y + + (positions[currentKnotIndex+1].y - + positions[currentKnotIndex].y) * currentInterpolationValue; + pos.z = positions[currentKnotIndex].z + + (positions[currentKnotIndex+1].z - + positions[currentKnotIndex].z) * currentInterpolationValue; + scale = scales[currentKnotIndex] + + (scales[currentKnotIndex+1] - + scales[currentKnotIndex]) * currentInterpolationValue; + } + tQuat.normalize(); + + sMat.set(scale); + tMat.set(tQuat); + tMat.mul(sMat); + // Set the translation components. + + tMat.m03 = pos.x; + tMat.m13 = pos.y; + tMat.m23 = pos.z; + rotation.set(tMat); + + // construct a Transform3D from: axis * rotation * axisInverse + transform.mul(axis, rotation); + transform.mul(transform, axisInverse); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + RotPosScalePathInterpolator ri = new RotPosScalePathInterpolator(); + ri.duplicateNode(this, forceDuplicate); + return ri; + } + + + /** + * Copies all RotPosScalePathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + + super.duplicateAttributes(originalNode, forceDuplicate); + + RotPosScalePathInterpolator ri = + (RotPosScalePathInterpolator) originalNode; + + int len = ri.getArrayLengths(); + + // No API available to change size of array, so set here explicitly + positions = new Point3f[len]; + quats = new Quat4f[len]; + scales = new float[len]; + + Point3f point = new Point3f(); + Quat4f quat = new Quat4f(); + + for (int i = 0; i < len; i++) { + positions[i] = new Point3f(); + ri.getPosition(i, point); + setPosition(i, point); + + quats[i] = new Quat4f(); + ri.getQuat(i, quat); + setQuat(i, quat); + + setScale(i, ri.getScale(i)); + } + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RotationInterpolator.java b/j3d-core/src/classes/share/javax/media/j3d/RotationInterpolator.java new file mode 100644 index 0000000..fb3acb1 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RotationInterpolator.java @@ -0,0 +1,221 @@ +/* + * $RCSfile: RotationInterpolator.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * Rotation interpolator behavior. This class defines a behavior + * that modifies the rotational component of its target TransformGroup + * by linearly interpolating between a pair of specified angles + * (using the value generated by the specified Alpha object). + * The interpolated angle is used to generate a rotation transform + * about the local Y-axis of this interpolator. + */ + +public class RotationInterpolator extends TransformInterpolator { + + float minimumAngle; + float maximumAngle; + private Transform3D rotation = new Transform3D(); + + // We can't use a boolean flag since it is possible + // that after alpha change, this procedure only run + // once at alpha.finish(). So the best way is to + // detect alpha value change. + private float prevAlphaValue = Float.NaN; + private WakeupCriterion passiveWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0, true); + + // non-public, default constructor used by cloneNode + RotationInterpolator() { + } + + /** + * Constructs a trivial rotation interpolator with a specified target, + * an default axisOfTranform set to identity, a minimum angle of 0.0f, and + * a maximum angle of 2*pi radians. + * @param alpha The alpha object for this Interpolator + * @param target The target for this rotation Interpolator + */ + public RotationInterpolator(Alpha alpha, TransformGroup target) { + super(alpha, target); + this.minimumAngle = 0.0f; + this.maximumAngle = 2.0f*(float)Math.PI; + } + + + /** + * Constructs a new rotation interpolator that varies the target + * transform node's rotational component. + * @param alpha the alpha generator to use in the rotation computation + * @param target the TransformGroup node affected by this interpolator + * @param axisOfTransform the transform that defines the local coordinate + * system in which this interpolator operates. The rotation is done + * about the Y-axis of this local coordinate system. + * @param minimumAngle the starting angle in radians + * @param maximumAngle the ending angle in radians + */ + public RotationInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + float minimumAngle, + float maximumAngle) { + super(alpha, target, axisOfTransform); + this.minimumAngle = minimumAngle; + this.maximumAngle = maximumAngle; + } + + /** + * This method sets the minimumAngle for this interpolator, in + * radians. + * @param angle the new minimal angle + */ + public void setMinimumAngle(float angle) { + this.minimumAngle = angle; + } + + /** + * This method retrieves this interpolator's minimumAngle, in + * radians. + * @return the interpolator's minimal angle value + */ + public float getMinimumAngle() { + return this.minimumAngle; + } + + /** + * This method sets the maximumAngle for this interpolator, in + * radians. + * @param angle the new maximal angle value + */ + public void setMaximumAngle(float angle) { + this.maximumAngle = angle; + } + + /** + * This method retrieves this interpolator's maximumAngle, in + * radians. + * @return the interpolator's maximal angle value + */ + public float getMaximumAngle() { + return this.maximumAngle; + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.setTransformAxis(Transform3D) + */ + public void setAxisOfRotation(Transform3D axisOfRotation) { + setTransformAxis(axisOfRotation); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.getTransformAxis() + */ + public Transform3D getAxisOfRotation() { + return getTransformAxis(); + } + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + double val = (1.0-alphaValue)*minimumAngle + alphaValue*maximumAngle; + + // construct a Transform3D from: axis * rotation * axisInverse + rotation.rotY(val); + transform.mul(axis, rotation); + transform.mul(transform, axisInverse); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + RotationInterpolator ri = new RotationInterpolator(); + ri.duplicateNode(this, forceDuplicate); + return ri; + } + + + /** + * Copies all RotationInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + RotationInterpolator ri = (RotationInterpolator) originalNode; + + setMinimumAngle(ri.getMinimumAngle()); + setMaximumAngle(ri.getMaximumAngle()); + + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/RotationPathInterpolator.java b/j3d-core/src/classes/share/javax/media/j3d/RotationPathInterpolator.java new file mode 100644 index 0000000..fee1997 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/RotationPathInterpolator.java @@ -0,0 +1,315 @@ +/* + * $RCSfile: RotationPathInterpolator.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Quat4f; + + +/** + * RotationPathInterpolator behavior. This class defines a behavior + * that varies the rotational component of its target TransformGroup + * by linearly interpolating among a series of predefined knot/orientation + * pairs (using the value generated by the specified Alpha object). The + * interpolated orientation is used to generate a rotation transform in + * the local coordinate system. The first knot must have a value of 0.0. + * The last knot must have a value + * of 1.0. An intermediate knot with index k must have a value strictly + * greater than any knot with index less than k. + */ + +public class RotationPathInterpolator extends PathInterpolator { + private Transform3D rotation = new Transform3D(); + + private Quat4f tQuat = new Quat4f(); + + // Array of quaternions at each knot + private Quat4f quats[]; + private float prevInterpolationValue = Float.NaN; + + // We can't use a boolean flag since it is possible + // that after alpha change, this procedure only run + // once at alpha.finish(). So the best way is to + // detect alpha value change. + private float prevAlphaValue = Float.NaN; + private WakeupCriterion passiveWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0, true); + // non-public, default constructor used by cloneNode + RotationPathInterpolator() { + } + + + /** + * Constructs a new RotationPathInterpolator object that varies the + * target TransformGroup node's transform. + * @param alpha the alpha object of this interpolator + * @param target the TransformGroup node affected by this interpolator + * @param axisOfTransform the transform that defines the local coordinate + * system in which this interpolator operates + * @param knots an array of knot values that specify interpolation points + * @param quats an array of quaternion values at the knots + * @exception IllegalArgumentException if the lengths of the + * knots and quats arrays are not the same. + */ + public RotationPathInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + float[] knots, + Quat4f[] quats) { + super(alpha,target, axisOfTransform, knots); + + if (knots.length != quats.length) + throw new IllegalArgumentException(J3dI18N.getString("RotationPathInterpolator0")); + + setPathArrays(quats); + } + + + /** + * Sets the quat value at the specified index for this + * interpolator. + * @param index the index to be changed + * @param quat the new quat value at the index + */ + public void setQuat(int index, Quat4f quat) { + this.quats[index].set(quat); + } + + + /** + * Retrieves the quat value at the specified index. + * @param index the index of the value requested + * @param quat the quat object that will have the + * quat value at index copied into it. + */ + public void getQuat(int index, Quat4f quat) { + quat.set(this.quats[index]); + } + + + /** + * Replaces the existing arrays of knot values and quaternion + * values with the specified arrays. + * The arrays of knots and quats are copied + * into this interpolator object. + * @param knots a new array of knot values that specify + * interpolation points + * @param quats a new array of quaternion values at the knots + * @exception IllegalArgumentException if the lengths of the + * knots and quats arrays are not the same. + * + * @since Java 3D 1.2 + */ + public void setPathArrays(float[] knots, + Quat4f[] quats) { + if (knots.length != quats.length) + throw new IllegalArgumentException(J3dI18N.getString("RotationPathInterpolator0")); + + setKnots(knots); + setPathArrays(quats); + } + + + // Set the specific arrays for this path interpolator + private void setPathArrays(Quat4f[] quats) { + this.quats = new Quat4f[quats.length]; + for(int i = 0; i < quats.length; i++) { + this.quats[i] = new Quat4f(); + this.quats[i].set(quats[i]); + } + } + + + /** + * Copies the array of quaternion values from this interpolator + * into the specified array. + * The array must be large enough to hold all of the quats. + * The individual array elements must be allocated by the caller. + * @param quats array that will receive the quats + * + * @since Java 3D 1.2 + */ + public void getQuats(Quat4f[] quats) { + for (int i = 0; i < this.quats.length; i++) { + quats[i].set(this.quats[i]); + } + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.seTransformAxis(Transform3D) + */ + public void setAxisOfRotation(Transform3D axisOfRotation) { + setTransformAxis(axisOfRotation); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.getTransformAxis() + */ + public Transform3D getAxisOfRotation() { + return getTransformAxis(); + } + + // The RotationPathInterpolator's initialize routine uses the default + // initialization routine. + + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + float tt; + double quatDot; + computePathInterpolation(alphaValue); + // For RPATH, take quaternion average and set rotation in TransformGroup + + if (currentKnotIndex == 0 && + currentInterpolationValue == 0f) { + tQuat.x = quats[0].x; + tQuat.y = quats[0].y; + tQuat.z = quats[0].z; + tQuat.w = quats[0].w; + } else { + quatDot = quats[currentKnotIndex].x * + quats[currentKnotIndex+1].x + + quats[currentKnotIndex].y * + quats[currentKnotIndex+1].y + + quats[currentKnotIndex].z * + quats[currentKnotIndex+1].z + + quats[currentKnotIndex].w * + quats[currentKnotIndex+1].w; + if (quatDot < 0) { + tQuat.x = quats[currentKnotIndex].x + + (-quats[currentKnotIndex+1].x - + quats[currentKnotIndex].x)*currentInterpolationValue; + tQuat.y = quats[currentKnotIndex].y + + (-quats[currentKnotIndex+1].y - + quats[currentKnotIndex].y)*currentInterpolationValue; + tQuat.z = quats[currentKnotIndex].z + + (-quats[currentKnotIndex+1].z - + quats[currentKnotIndex].z)*currentInterpolationValue; + tQuat.w = quats[currentKnotIndex].w + + (-quats[currentKnotIndex+1].w - + quats[currentKnotIndex].w)*currentInterpolationValue; + } else { + tQuat.x = quats[currentKnotIndex].x + + (quats[currentKnotIndex+1].x - + quats[currentKnotIndex].x)*currentInterpolationValue; + tQuat.y = quats[currentKnotIndex].y + + (quats[currentKnotIndex+1].y - + quats[currentKnotIndex].y)*currentInterpolationValue; + tQuat.z = quats[currentKnotIndex].z + + (quats[currentKnotIndex+1].z - + quats[currentKnotIndex].z)*currentInterpolationValue; + tQuat.w = quats[currentKnotIndex].w + + (quats[currentKnotIndex+1].w - + quats[currentKnotIndex].w)*currentInterpolationValue; + } + } + + tQuat.normalize(); + rotation.set(tQuat); + + // construct a Transform3D from: axis * rotation * axisInverse + transform.mul(axis, rotation); + transform.mul(transform, axisInverse); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + RotationPathInterpolator rpi = new RotationPathInterpolator(); + rpi.duplicateNode(this, forceDuplicate); + return rpi; + } + + + /** + * Copies all RotationPathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + RotationPathInterpolator ri = + (RotationPathInterpolator) originalNode; + + int len = ri.getArrayLengths(); + + // No API available to change size of array, so set here explicitly + quats = new Quat4f[len]; + Quat4f quat = new Quat4f(); + + for (int i = 0; i < len; i++) { + quats[i] = new Quat4f(); + ri.getQuat(i, quat); + setQuat(i, quat); + } + + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ScaleInterpolator.java b/j3d-core/src/classes/share/javax/media/j3d/ScaleInterpolator.java new file mode 100644 index 0000000..1e8f667 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ScaleInterpolator.java @@ -0,0 +1,224 @@ +/* + * $RCSfile: ScaleInterpolator.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Scale interpolation behavior. This class defines a behavior + * that modifies the uniform scale component of its target + * TransformGroup by linearly interpolating between a pair of + * specified scale values (using the value generated by the + * specified Alpha object). The interpolated scale value is + * used to generate a scale transform in the local coordinate + * system of this interpolator. + */ + +public class ScaleInterpolator extends TransformInterpolator { + + float minimumScale; + float maximumScale; + private Transform3D scale = new Transform3D(); + + + // We can't use a boolean flag since it is possible + // that after alpha change, this procedure only run + // once at alpha.finish(). So the best way is to + // detect alpha value change. + private float prevAlphaValue = Float.NaN; + private WakeupCriterion passiveWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0, true); + + // non-public, default constructor used by cloneNode + ScaleInterpolator() { + } + + /** + * Constructs a trivial scale interpolator that varies its target + * TransformGroup node between the two specified alpha values + * using the specified alpha, an identity matrix, + * a minimum scale = 0.1f, and a maximum scale = 1.0f. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this interpolator + */ + public ScaleInterpolator(Alpha alpha, + TransformGroup target) { + + super(alpha, target); + this.minimumScale = 0.1f; + this.maximumScale = 1.0f; + } + + /** + * Constructs a new scaleInterpolator object that varies its target + * TransformGroup node's scale component between two scale values + * (minimumScale and maximumScale). + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this interpolator + * @param axisOfTransform the transform that defines the local coordinate + * system in which this interpolator operates; the scale is done + * about the origin of this local coordinate system. + * @param minimumScale the starting scale + * @param maximumScale the ending scale + */ + public ScaleInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + float minimumScale, + float maximumScale) { + + super(alpha, target, axisOfTransform); + + this.minimumScale = minimumScale; + this.maximumScale = maximumScale; + } + + /** + * This method sets the minimumScale for this interpolator. + * @param scale The new minimal scale + */ + public void setMinimumScale(float scale) { + this.minimumScale = scale; + } + + /** + * This method retrieves this interpolator's minimumScale. + * @return the interpolator's minimal scale value + */ + public float getMinimumScale() { + return this.minimumScale; + } + + /** + * This method sets the maximumScale for this interpolator. + * @param scale the new maximum scale + */ + public void setMaximumScale(float scale) { + this.maximumScale = scale; + } + + /** + * This method retrieves this interpolator's maximumScale. + * @return the interpolator's maximum scale vslue + */ + public float getMaximumScale() { + return this.maximumScale; + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.setTransformAxis(Transform3D) + */ + public void setAxisOfScale(Transform3D axisOfScale) { + setTransformAxis(axisOfScale); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.getTransformAxis() + */ + public Transform3D getAxisOfScale() { + return getTransformAxis(); + } + + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + + double val = (1.0-alphaValue)*minimumScale + alphaValue*maximumScale; + + // construct a Transform3D from: axis * scale * axisInverse + scale.set(val); + transform.mul(axis, scale); + transform.mul(transform, axisInverse); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + ScaleInterpolator si = new ScaleInterpolator(); + si.duplicateNode(this, forceDuplicate); + return si; + } + + + /** + * Copies all ScaleInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + + super.duplicateAttributes(originalNode, forceDuplicate); + + ScaleInterpolator si = (ScaleInterpolator) originalNode; + + setMinimumScale(si.getMinimumScale()); + setMaximumScale(si.getMaximumScale()); + + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SceneGraphCycleException.java b/j3d-core/src/classes/share/javax/media/j3d/SceneGraphCycleException.java new file mode 100644 index 0000000..0d2a8d7 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SceneGraphCycleException.java @@ -0,0 +1,63 @@ +/* + * $RCSfile: SceneGraphCycleException.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates a graph that contains a cycle. + * Java 3D scene graphs are directed acyclic graphs and, as such, do not + * permit cycles. + * This exception is thrown when a graph containing a cycle: + *

    + *
  • is made live + *
  • is compiled + *
  • is cloned + *
  • has getBounds() called on it. + *
+ */ +public class SceneGraphCycleException extends IllegalSceneGraphException{ + +/** + * Create the exception object with default values. + */ + public SceneGraphCycleException(){ + } + +/** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public SceneGraphCycleException(String str){ + + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SceneGraphObject.java b/j3d-core/src/classes/share/javax/media/j3d/SceneGraphObject.java new file mode 100644 index 0000000..aad2779 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SceneGraphObject.java @@ -0,0 +1,517 @@ +/* + * $RCSfile: SceneGraphObject.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Hashtable; + +/** + * SceneGraphObject is the common superclass for all scene graph + * objects. Scene graph objects are classified into two main types: + * nodes and node components. The Node object is the common superclass + * of all nodes, which includes TransformGroup, Shape3D, etc. + * The NodeComponent object is the common superclass of all node + * components, which includes Geometry, Appearance, etc. + * + *

+ * All scene graph objects have a name, a user data object, a set of + * capability bits, and a set of capabilityIsFrequent bits. + * + *

+ * Capability bits control whether a particular attribute in a node or + * node component is readable or writable. For live or compiled scene + * graphs, only those attributes whose capabilities are set before the + * scene graph is compiled or made live may be read or written. The + * default value for all read capability bits is true, meaning + * that all attributes may be read by default. The default value for + * all write capability bits is false, meaning that no + * attributes may be written by default. Read capability bits are + * defined as those capability bits of the form ALLOW_*_READ, + * plus the ALLOW_INTERSECT capability bit. Write + * capability bits are defined as those capability bits of the form + * ALLOW_*_WRITE, plus the ALLOW_CHILDREN_EXTEND + * and ALLOW_DETACH capability bits. + * + *

+ * NOTE that the ENABLE_COLLISION_REPORTING and + * ENABLE_PICK_REPORTING bits are not really capability bits, + * although they are set with the setCapability method. The default value + * for each of the ENABLE_*_REPORTING bits is false. + * + *

+ * For more information, see the + * Introduction to the Java 3D API. + */ +public abstract class SceneGraphObject extends Object { + // Any global flags? (e.g., execution cullable, collideable) + + // Reference to the retained-mode scene-graph element. + SceneGraphObjectRetained retained; + + // This object's capability bits + private long capabilityBits = 0L; + + // This object's capabilityIsFrequent bits + private long capabilityIsFrequentBits = ~0L; + + //boolean indicating is Scene Graph is compiled + private boolean compiled = false; + + //boolean indicating if Scene Graph is live. + private boolean live = false; + + //boolean indicating if Scene Graph is live or compiled + private boolean liveOrCompiled = false; + + // A reference to user data + private Object userData = null; + + // Optional name for object. + private String objectName = null; + + // use for cloneTree/cloneNode only, set to null after the operation + Hashtable nodeHashtable = null; + + + + /** + * Constructs a SceneGraphObject with default parameters. The default + * values are as follows: + *

    + * all read capability bits : set (true)
    + * all write capability bits : clear (false)
    + * all capabilityIsFrequent bits : set (true)
    + * isLive : false
    + * isCompiled : false
    + * user data : null
    + * name : null
    + *
+ */ + public SceneGraphObject() { + createRetained(); + } + + /** + * Creates the retained mode object that this scene graph object + * will point to. This should be overridden by those classes + * that have a specific retained mode object. + */ + void createRetained() { + this.retained = null; + + // Non-abstract subclasses of SceneGraphObject should override + // this function with code which is something like the following: + // + // this.retained = new Retained(); + // this.retained.setSource(this); + } + + /** + * Method to set default read capability bits to true + */ + void setDefaultReadCapabilities(int[] bits) { + if (true /*VirtualUniverse.mc.defaultReadCapability*/) { + for (int i=0; i < bits.length; i++) { + setCapability(bits[i]); + } + } + } + + /** + * Retrieves the specified capability bit. Note that only one capability + * bit may be retrieved per method invocation--capability bits cannot + * be ORed together. + * @param bit the bit whose value is returned + * @return true if the bit is set, false if the bit is clear + */ + public final boolean getCapability(int bit) { + return (capabilityBits & (1L << bit)) != 0L; + } + + /** + * Sets the specified capability bit. Note that only one capability bit + * may be set per method invocation--capability bits cannot be ORed + * together. + * @param bit the bit to set + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + */ + public final void setCapability(int bit) { + if (isLiveOrCompiled()) { + throw new RestrictedAccessException(J3dI18N.getString("SceneGraphObject0")); + } + + capabilityBits |= (1L << bit); + retained.handleFrequencyChange(bit); + + } + + /** + * Clear the specified capability bit. Note that only one capability bit + * may be cleared per method invocation--capability bits cannot be ORed + * together. + * @param bit the bit to clear + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + */ + public final void clearCapability(int bit) { + if (isLiveOrCompiled()) + throw new RestrictedAccessException(J3dI18N.getString("SceneGraphObject0")); + + capabilityBits &= ~(1L << bit); + retained.handleFrequencyChange(bit); + } + + + // Internal method, returns true if no capability bits are set + final boolean capabilityBitsEmpty() { + return capabilityBits == 0L; + } + + + /** + * Retrieves the isFrequent bit associated with the specified capability + * bit. + * + * Note that only one isFrequent bit, for a single capability + * bit, may be retrieved per method invocation--capability bits cannot + * be ORed together. + * + * @param bit the bit whose value is returned + * + * @return true if the isFrequent bit is set, false if the isFrequent + * bit is clear + * + * @since Java 3D 1.3 + */ + public final boolean getCapabilityIsFrequent(int bit) { + return (capabilityIsFrequentBits & (1L << bit)) != 0L; + } + + /** + * Sets the isFrequent bit associated with the specified + * capability bit. Setting the isFrequent bit indicates that the + * application may frequently access or modify those attributes + * permitted by the associated capability bit. This can be used + * by Java 3D as a hint to avoid certain optimizations that could + * cause those accesses or modifications to be expensive. By + * default the isFrequent bit associated with each capability bit + * is set. + * + *

+ * Unlike setCapability, this method may be called on a live scene + * graph object (but not on a compiled object). + * + *

+ * Note that only one isFrequent bit, for a single capability bit, + * may be set per method invocation--capability bits cannot be ORed + * together. + * + * @param bit the capability bit for which to set the associated + * isFrequent bit + * + * @exception RestrictedAccessException if this object is part of a + * compiled scene graph + * + * @since Java 3D 1.3 + */ + public final void setCapabilityIsFrequent(int bit) { + if (isCompiled()) + throw new RestrictedAccessException(J3dI18N.getString("SceneGraphObject1")); + + capabilityIsFrequentBits |= (1L << bit); + retained.handleFrequencyChange(bit); + } + + /** + * Clears the isFrequent bit associated with the specified + * capability bit. Clearing the isFrequent bit indicates that the + * application will infrequently access or modify those attributes + * permitted by the associated capability bit. This can be used + * by Java 3D as a hint to enable certain optimizations that it + * might otherwise avoid, for example, optimizations that could + * cause those accesses or modifications to be expensive. + * + *

+ * Unlike clearCapability, this method may be called on a live scene + * graph object (but not on a compiled object). + * + *

+ * Note that only one isFrequent bit, for a single capability bit, + * may be cleared per method invocation--capability bits cannot be ORed + * together. + * + * @param bit the capability bit for which to clear the associated + * isFrequent bit + * + * @exception RestrictedAccessException if this object is part of a + * compiled scene graph + * + * @since Java 3D 1.3 + */ + public final void clearCapabilityIsFrequent(int bit) { + if (isCompiled()) + throw new RestrictedAccessException(J3dI18N.getString("SceneGraphObject1")); + + capabilityIsFrequentBits &= ~(1L << bit); + retained.handleFrequencyChange(bit); + } + + + /** + * Sets an internal flag which indicates that this scene graph object + * has been compiled. + */ + final void setCompiled() { + this.compiled = true; + this.liveOrCompiled = this.live || this.compiled; + } + + /** + * Returns a flag indicating whether the node is part of a scene graph + * that has been compiled. If so, then only those capabilities explicitly + * allowed by the object's capability bits are allowed. + * @return true if node is part of a compiled scene graph, else false + */ + + public final boolean isCompiled() { + return this.compiled; + } + + /** + * Sets an internal flag which indicates that this scene graph object + * is part of a live scene graph. + */ + final void setLive() { + this.live = true; + this.liveOrCompiled = this.live || this.compiled; + } + + /** + * Clears an internal flag which indicates that this scene graph object + * is no longer part of a live scene graph. + */ + final void clearLive() { + this.live = false; + this.liveOrCompiled = this.live || this.compiled; + } + + /** + * Returns a flag indicating whether the node is part of a live + * scene graph. + * @return true if node is part of a live scene graph, else false + */ + public final boolean isLive() { + return this.live; + } + + /** + * Returns a flag indicating whether the node is part of a live + * scene graph or a compiled scene graph. + * @return true if either live or compiled + */ + final boolean isLiveOrCompiled() { + return liveOrCompiled; + } + + final void checkForLiveOrCompiled() { + if (isLiveOrCompiled()) + throw new RestrictedAccessException(J3dI18N.getString("SceneGraphObject2")); + } + + /** + * Sets the userData field associated with this scene graph object. + * The userData field is a reference to an arbitrary object + * and may be used to store any user-specific data associated + * with this scene graph object--it is not used by the Java 3D API. + * If this object is cloned, the userData field is copied + * to the newly cloned object. + * @param userData a reference to the new userData field + */ + public void setUserData(Object userData) { + this.userData = userData; + } + + /** + * Retrieves the userData field from this scene graph object. + * @return the current userData field + */ + public Object getUserData() { + return this.userData; + } + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced by that node have been duplicated via a call to + * cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf + * node and cloned NodeComponent's method + * will be called and the Leaf node/NodeComponent can then look up + * any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + } + + /** + * Sets the name of this object. Object names are for information + * only. + * + * @param name the new name of this object + * + * @since Java 3D 1.4 + */ + public void setName( String name ) { + objectName = name; + } + + /** + * Returns the name of this object. + * + * @return the name of this object + * + * @since Java 3D 1.4 + */ + public String getName() { + return objectName; + } + + /** + * Copies all SceneGraphObject information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * + * @see Group#cloneNode + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + protected void duplicateSceneGraphObject(SceneGraphObject originalNode) { + // Duplicate any class specific data here. + capabilityBits = originalNode.capabilityBits; + userData = originalNode.userData; + objectName = originalNode.objectName; + } + + + /** + * If forceDuplicate is true or + * duplicateOnCloneTree flag is true. This procedure + * will return a clone of originalNode or the value in + * in nodeHashtable if found. Otherwise return + * originalNode + * + * This method is called from the + * duplicateAttributes method during cloneNodeComponent. + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @param nodeHashtable is used to keep track of mapping between old and + * new node references. + */ + NodeComponent getNodeComponent(NodeComponent originalNodeComponent, + boolean forceDuplicate, + Hashtable hashtable) { + if ((originalNodeComponent != null) && + (forceDuplicate || + originalNodeComponent.duplicateChild())) { + NodeComponent nc = (NodeComponent) + hashtable.get(originalNodeComponent); + if (nc == null) { + originalNodeComponent.nodeHashtable = hashtable; + try { + nc = originalNodeComponent. + cloneNodeComponent(forceDuplicate); + } catch (RuntimeException e) { + // must reset nodeHashtable in any case + originalNodeComponent.nodeHashtable = null; + throw e; + } + originalNodeComponent.nodeHashtable = null; + // put link to be shared by other Node + hashtable.put(originalNodeComponent, nc); + } // use the share clone node otherwise + return nc; + } else { + return originalNodeComponent; + } + } + + // Internal method to make a prefix out of the name of this object + String getNamePrefix() { + String name = getName(); + + if (name != null) { + return "[" + name + "] "; + } + + return ""; + } + + /** + * Returns a String representation of this SceneGraphObject. + * If its name is non-null, then it is concatenated with + * super.toString(). + */ + public String toString() { + return getNamePrefix() + super.toString(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SceneGraphObjectRetained.java b/j3d-core/src/classes/share/javax/media/j3d/SceneGraphObjectRetained.java new file mode 100644 index 0000000..85f6b6a --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SceneGraphObjectRetained.java @@ -0,0 +1,189 @@ +/* + * $RCSfile: SceneGraphObjectRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; +import java.util.Hashtable; + +/** + * SceneGraphObjectRetained is a superclass, which has things that + * are common to all retained scene graph component objects. + */ +abstract class SceneGraphObjectRetained extends IndexedObject + implements Cloneable { + + // The object which created this retained mode object + SceneGraphObject source; + + // This boolean is true when the object is in a Background BranchGroup + boolean inBackgroundGroup = false; + + // This boolean is true when the object is in the update list + boolean onUpdateList = false; + + // A flag to indicate if the node is in setLive, note that + // since the live is set to true only at the end, this flag + // is need for scoping to mark the nodes that are inSetLive + + boolean inSetLive = false; + + // A flag used in compile to indicate if this node needs to go + // through the second pass + + final static int DONT_MERGE = 0; + final static int MERGE = 1; + final static int MERGE_DONE = 2; + + int mergeFlag = 0; + + /** + * Caches the source object that created this retained mode object. + * @param source the object which created this retained mode object. + */ + void setSource(SceneGraphObject source) { + this.source = source; + } + + /** + * Returns the cached source object that created this retained mode + * object. + * @return the object which created this retained mode object. + */ + SceneGraphObject getSource() { + return this.source; + } + + void markAsLive() { + this.source.setLive(); + inSetLive = false; + } + + void setLive(boolean inBackgroundGroup) { + doSetLive(inBackgroundGroup); + markAsLive(); + } + boolean isInSetLive() { + return inSetLive; + } + + /** + * Makes the internal node live. + */ + void doSetLive(boolean inBackgroundGroup) { + inSetLive = true; + this.inBackgroundGroup = inBackgroundGroup; + } + + void setLive(SetLiveState s) { + doSetLive(s); + markAsLive(); + } + + /** + * Makes the internal node live. + */ + void doSetLive(SetLiveState s) { + inSetLive = true; + inBackgroundGroup = s.inBackgroundGroup; + } + + /** + * Makes the internal node not live + */ + void clearLive(VirtualUniverse univ, int index, + boolean sharedGroup, HashKey [] keys) { + inBackgroundGroup = false; + this.source.clearLive(); + } + + /** + * Makes the internal node not live + */ + void clearLive() { + inBackgroundGroup = false; + this.source.clearLive(); + } + + /** + * This marks this object as compiled. + */ + void setCompiled() { + this.source.setCompiled(); + } + + + /** + * This is the default compile() method, which just marks the sgo as + * compiled. + */ + void compile(CompileState compState) { + setCompiled(); + } + + void merge(CompileState compState) { + } + + void mergeTransform(TransformGroupRetained xform) { + } + + void traverse(boolean sameLevel, int level) { + + System.err.println(); + for (int i = 0; i < level; i++) { + System.err.print("."); + } + System.err.print(this); + } + + /** + * true if component can't be read or written after compile or setlive() + */ + boolean isStatic() { + return source.capabilityBitsEmpty(); + } + + protected Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + void handleFrequencyChange(int bit) { + } + + VirtualUniverse getVirtualUniverse() { + return null; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SceneGraphPath.java b/j3d-core/src/classes/share/javax/media/j3d/SceneGraphPath.java new file mode 100644 index 0000000..e29fa61 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SceneGraphPath.java @@ -0,0 +1,671 @@ +/* + * $RCSfile: SceneGraphPath.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Point3d; +import javax.vecmath.Point4d; + +/** + * A SceneGraphPath object represents the path from a Locale to a + * terminal node in the scene graph. This path consists of a Locale, a + * terminal node, and an array of internal nodes that are in the path + * from the Locale to the terminal node. The terminal node may be + * either a Leaf node or a Group node. A valid SceneGraphPath must + * uniquely identify a specific instance of the terminal node. For + * nodes that are not under a SharedGroup, the minimal SceneGraphPath + * consists of the Locale and the terminal node itself. For nodes that + * are under a SharedGroup, the minimal SceneGraphPath consists of the + * Locale, the terminal node, and a list of all Link nodes in the path + * from the Locale to the terminal node. A SceneGraphPath may optionally + * contain other interior nodes that are in the path. + * A SceneGraphPath is verified for correctness and uniqueness when + * it is sent as an argument to other methods of Java 3D. + *

+ * In the array of internal nodes, the node at index 0 is the node + * closest to the Locale. The indices increase along the path to the + * terminal node, with the node at index length-1 being the node closest + * to the terminal node. The array of nodes does not contain either the + * Locale (which is not a node) or the terminal node. + *

+ * When a SceneGraphPath is returned from the picking or collision + * methods of Java 3D, it will also contain the value of the + * LocalToVworld transform of the terminal node that was in effect at + * the time the pick or collision occurred. + * Note that ENABLE_PICK_REPORTING and ENABLE_COLLISION_REPORTING are + * disabled by default. This means that the picking and collision + * methods will return the minimal SceneGraphPath by default. + * + * @see Node#ENABLE_PICK_REPORTING + * @see Node#ENABLE_COLLISION_REPORTING + * @see BranchGroup#pickAll + * @see BranchGroup#pickAllSorted + * @see BranchGroup#pickClosest + * @see BranchGroup#pickAny + */ + +public class SceneGraphPath { + + Locale root = null; + Node[] interior = null; + Node item = null; + Transform3D transform = new Transform3D(); + + // Intersect Point for item when picked + Point3d intersectPoint = new Point3d(); + + double pickDistance; // distance to pick location + + /** + * Constructs a SceneGraphPath object with default parameters. + * The default values are as follows: + *

    + * root : null
    + * object : null
    + * list of (interior) nodes : null
    + * transform : identity
    + *
+ */ + public SceneGraphPath() { + // Just use defaults + } + + /** + * Constructs a new SceneGraphPath object. + * @param root the Locale object of this path + * @param object the terminal node of this path + */ + public SceneGraphPath(Locale root, Node object) { + + this.item = object; + this.root = root; + } + + /** + * Constructs a new SceneGraphPath object. + * @param root the Locale object of this path + * @param nodes an array of node objects in the path from + * the Locale to the terminal node + * @param object the terminal node of this path + */ + public SceneGraphPath(Locale root, Node nodes[], Node object) { + + this.item = object; + this.root = root; + this.interior = new Node[nodes.length]; + for (int i = 0; i < nodes.length; i++) + this.interior[i] = nodes[i]; + } + + + /** + * Constructs a new SceneGraphPath object + * @param sgp the SceneGraphPath to copy from + */ + SceneGraphPath(SceneGraphPath sgp) { + set(sgp); + } + + /** + * Sets this path's values to that of the specified path. + * @param newPath the SceneGraphPath to copy + */ + public final void set(SceneGraphPath newPath) { + this.root = newPath.root; + this.item = newPath.item; + this.transform.set(newPath.transform); + if(newPath.interior != null && newPath.interior.length > 0) { + interior = new Node[newPath.interior.length]; + for (int i = 0; i < interior.length; i++) + this.interior[i] = newPath.interior[i]; + } + else + interior = null; + } + + /** + * Sets this path's Locale to the specified Locale. + * @param newLocale The new Locale + */ + public final void setLocale(Locale newLocale) { + root = newLocale; + } + + /** + * Sets this path's terminal node to the specified node object. + * @param object the new terminal node + */ + public final void setObject(Node object) { + this.item = object; + } + + /** + * Sets this path's node objects to the specified node objects. + * @param nodes an array of node objects in the path from + * the Locale to the terminal node + */ + public final void setNodes(Node nodes[]) { + + if(nodes != null && nodes.length > 0) { + interior = new Node[nodes.length]; + for (int i = 0; i < nodes.length; i++) + this.interior[i] = nodes[i]; + } + else + interior = null; + } + + /** + * Replaces the node at the specified index with newNode. + * @param index the index of the node to replace + * @param newNode the new node + * @exception NullPointerException if the node array pointer is null. + * + */ + public final void setNode(int index, Node newNode) { + if(interior == null) + throw new NullPointerException(J3dI18N.getString("SceneGraphPath0")); + + interior[index] = newNode; + } + + /** + * Sets the transform component of this SceneGraphPath to the value of + * the passed transform. + * @param trans the transform to be copied. trans should be the + * localToVworld matrix of this SceneGraphPath object. + */ + public final void setTransform(Transform3D trans) { + transform.set(trans); + } + + /** + * Returns a copy of the transform associated with this SceneGraphPath; + * returns null if there is no transform associated. + * If this SceneGraphPath was returned by a Java 3D picking or + * collision method, the local coordinate to virtual world + * coordinate transform for this scene graph object at the + * time of the pick or collision is recorded. + * @return the local to VWorld transform + */ + public final Transform3D getTransform() { + return new Transform3D(transform); + } + + /** + * Retrieves the path's Locale + * @return this path's Locale + */ + public final Locale getLocale() { + return this.root; + } + + /** + * Retrieves the path's terminal node object. + * @return the terminal node + */ + public final Node getObject() { + return this.item; + } + + /** + * Retrieves the number of nodes in this path. The number of nodes + * does not include the Locale or the terminal node object itself. + * @return a count of the number of nodes in this path + */ + public final int nodeCount() { + if(interior == null) + return 0; + return interior.length; + } + + /** + * Retrieves the node at the specified index. + * @param index the index specifying which node to retrieve + * @return the specified node + */ + public final Node getNode(int index) { + if(interior == null) + throw new + ArrayIndexOutOfBoundsException(J3dI18N.getString("SceneGraphPath1")); + return interior[index]; + } + + /** + * Returns true if all of the data members of path testPath are + * equal to the corresponding data members in this SceneGraphPath and + * if the values of the transforms is equal. + * @param testPath the path we will compare this object's path against. + * @return true or false + */ + public boolean equals(SceneGraphPath testPath) { + boolean result = true; + try { + + if(testPath == null || root != testPath.root || item != testPath.item) + return false; + + result = transform.equals(testPath.transform); + + if(result == false) + return false; + + if(interior == null || testPath.interior == null) { + if(interior != testPath.interior) + return false; + else + result = (root == testPath.root && item == testPath.item); + + } else { + if (interior.length == testPath.interior.length) { + for (int i = 0; i < interior.length; i++) + if (interior[i] != testPath.interior[i]) { + return false; + } + } + else + return false; + } + + } + catch (NullPointerException e2) {return false;} + + return result; + } + + /** + * Returns true if the Object o1 is of type SceneGraphPath and all of the + * data members of o1 are equal to the corresponding data members in + * this SceneGraphPath and if the values of the transforms is equal. + * @param o1 the object we will compare this SceneGraphPath's path against. + * @return true or false + */ + public boolean equals(Object o1) { + boolean result = true; + + try { + SceneGraphPath testPath = (SceneGraphPath)o1; + if(testPath == null || root != testPath.root || item != testPath.item) + return false; + + result = transform.equals(testPath.transform); + + if(result == false) + return false; + + if(interior == null || testPath.interior == null) { + if(interior != testPath.interior) + return false; + else + result = (root == testPath.root && item == testPath.item); + + } else { + if (interior.length == testPath.interior.length) { + for (int i = 0; i < interior.length; i++) + if (interior[i] != testPath.interior[i]) { + return false; + } + } + else + return false; + } + + return result; + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + } + + + /** + * Returns a hash number based on the data values in this + * object. Two different SceneGraphPath objects with identical data + * values (ie, returns true for trans.equals(SceneGraphPath) ) will + * return the same hash number. Two Paths with different data members + * may return the same hash value, although this is not likely. + * @return the integer hash value + */ + public int hashCode() { + HashKey key = new HashKey(250); + // NOTE: Needed to add interior != null because this method is called + // by object.toString() when interior is null. + if(interior != null && item != null) { + for(int i=0; i they are not both null + return false; + + return true; + } + + /** + * Returns a string representation of this object; + * the string contains the class names of all Nodes in the SceneGraphPath, + * the toString() method of any associated user data provided by + * SceneGraphObject.getUserData(), and also prints out the transform, + * if it is not null. + * @return String representation of this object + */ + public String toString() { + + StringBuffer str = new StringBuffer(); + Object obj; + + if(root == null && interior == null && item == null) + return (super.toString()); + + if(root != null) + str.append(root + " : "); + + if(interior != null) { + for(int i=0; i 0) { + if (((SharedGroupRetained) + node).parents.contains(interior[idx].retained)) { + break; + } + } + if (idx < 0) { + return false; + } + node = (NodeRetained) interior[idx].retained; + } else { + node = node.parent; + } + } while (node != null); + + return true; + } + + + // return key of this path or null is not in SharedGroup + void getHashKey(HashKey key) { + if (interior != null) { + key.reset(); + key.append(root.nodeId); + for(int i=0; i=0 ; i--) { + nextNR = (NodeRetained)(interior[i].retained); + currentNR = bottomNR.parent; + if(currentNR == null && bottomNR instanceof SharedGroupRetained) { + if(((SharedGroupRetained)(bottomNR)).parents.contains(nextNR) ) + currentNR = nextNR; + else + throw new IllegalArgumentException(J3dI18N.getString("SceneGraphPath5")); + + } + + while(currentNR != nextNR) { + if(currentNR == null) { + throw new IllegalArgumentException(J3dI18N.getString("SceneGraphPath11")); + } + + if(currentNR instanceof SharedGroupRetained) { + if(((SharedGroupRetained) + (currentNR)).parents.contains(nextNR) ) + currentNR = nextNR; + else + throw new IllegalArgumentException(J3dI18N.getString("SceneGraphPath5")); + + } else { + currentNR = currentNR.parent; + } + } + bottomNR = currentNR; + } + } + + // Now go from bottomNR to Locale + currentNR = bottomNR.parent; + if(currentNR == null && bottomNR instanceof SharedGroupRetained) { + throw new IllegalArgumentException(J3dI18N.getString("SceneGraphPath5")); + } + + while(currentNR != null) { + if(currentNR instanceof LinkRetained) { + throw new IllegalArgumentException(J3dI18N.getString("SceneGraphPath5")); + } + + bottomNR = currentNR; + currentNR = currentNR.parent; + if(currentNR == null && bottomNR instanceof SharedGroupRetained) { + throw new IllegalArgumentException(J3dI18N.getString("SceneGraphPath5")); + } + } + + // get the real BranchGroup from the BranchGroupRetained + currentNode = (Node)(bottomNR.source); + // now bottomNR should be a BranchGroup -- should try an assert here + if(!root.branchGroups.contains(currentNode)) { + throw new IllegalArgumentException(J3dI18N.getString("SceneGraphPath9")); + } + + return true; + } + + /** + * Returns the distance from the intersectPoint for item and + * origin. + */ + double getDistanceFrom( Point3d origin ) { + return intersectPoint.distance(origin); + } + + /** + * Returns the distance of the pick + */ + double getDistance() { + return pickDistance; + } + + final void setIntersectPoint( Point3d point ) { + intersectPoint.set(point); + } + + final void setIntersectPointDis( Point4d pickLocation ) { + // System.err.println( "setIntersectPointDis pickLocation= "+pickLocation); + intersectPoint.x = pickLocation.x; + intersectPoint.y = pickLocation.y; + intersectPoint.z = pickLocation.z; + pickDistance = pickLocation.w; + } + + final Point3d getIntersectPoint() { + return intersectPoint; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Screen3D.java b/j3d-core/src/classes/share/javax/media/j3d/Screen3D.java new file mode 100644 index 0000000..7c31a7b --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Screen3D.java @@ -0,0 +1,516 @@ +/* + * $RCSfile: Screen3D.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.Hashtable; + +/** + * The Screen3D Object contains all information about a particular screen. + * All Canvas3D objects on the same physical screen (display device) + * refer to the same Screen3D object. Note that Screen3D has no public + * constructors--it is obtained from the Canvas3D via the getScreen3D + * method. + *

+ * Default values for Screen3D parameters are as follows: + *

    + * physical screen width : 0.0254/90.0 * screen width (in pixels)
    + * physical screen height : 0.0254/90.0 * screen height (in pixels)
    + * tracker base to image plate transform : identity
    + * head tracker to left image plate transform : identity
    + * head tracker to right image plate transform : identity
    + * off-screen size : (0,0)
    + *
+ *

+ * Offscreen Rendering

+ * New for Java 3D 1.2, an off-screen rendering mode allows rendering + * to a memory image, which is possibly larger than the screen. The + * setSize and getSize methods are defined specifically for this + * mode. Note that the off-screen size, physical width, and physical height + * must be set prior to rendering + * to the associated off-screen canvas. Failure to do so will result + * in an exception.

+ * Calibration Parameters

+ * The Screen3D object must be calibrated with the coexistence volume. + * The Screen3D class provides several methods for defining the + * calibration parameters.

+ *

    Measured Parameters

    + * The screen's (image plate's) physical width and height (in meters) + * is set once, typically by a browser, calibration program, system + * administrator, or system calibrator, not by an applet. These values + * must be determined by measuring the display's active image width + * and height. In the case of a head-mounted display, this should be + * the display's apparent width and height at the focal plane. These + * values are defined by the setPhysicalScreenWidth and + * setPhysicalScreenHeight methods.

    + * + * Head-tracker Coordinate System

    + * If head tracking is enabled, one of two parameters need to be specified:

    + *

    • If the view policy is SCREEN_VIEW, the tracker-base-to-image-plate + * coordinate system must be specified (setTrackerBaseToImagePlate method). + * This coordinate system must be recalibrated whenever the image + * plate moves relative to the tracker.
    • + * + *

    • If the view policy is HMD_VIEW, the head-tracker-to-left-image-plate + * and head-tracker-to-right-image-plate coordinate systems must be + * specified (setHeadTrackerToLeftImagePlate and + * setHeadTrackerToRightImagePlate methods).
    + *

+ * + *

+ * Additional Information + *

+ * For more information, see the + * Introduction to the Java 3D API and + * View Model + * documents. + * + * @see Canvas3D + * @see Canvas3D#getScreen3D + */ + +public class Screen3D extends Object { + private static final boolean debug = false; + + // Assume a default of 90 DPI: 90 pix/inch = 1/90 inch/pix = + // 0.0254/90 meter/pix + private static final double METERS_PER_PIXEL = 0.0254/90.0; + + // GraphicsDevice associated with this Screen3D object. Note that + // all on-screen Canvas3D objects that are created on the same + // GraphicsDevice will share the same Screen3D. + GraphicsDevice graphicsDevice; + + // Flag indicating whether this Screen3D is associated with + // an off-screen Canvas3D or with one or more on-screen Canvas3Ds + boolean offScreen; + + // The display connection (native OGL pipeline on X11 only) + long display; + + // Screen number + int screen; + + // The width and height of the screen in meters. + double physicalScreenWidth; + double physicalScreenHeight; + + // Screen size in pixels + Dimension screenSize = new Dimension(0, 0); + + // + // Tracker-base coordinate system to image-plate coordinate + // system transform. This transform + // is typically a calibration constant. + // This is used only in SCREEN_VIEW mode. + // + Transform3D trackerBaseToImagePlate = new Transform3D(); + + // + // Head-tracker coordinate system to left and right image-plate + // coordinate system transforms. These transforms are typically + // calibration constants. These are used only in HMD_VIEW mode. + // + Transform3D headTrackerToLeftImagePlate = new Transform3D(); + Transform3D headTrackerToRightImagePlate = new Transform3D(); + + + // Physical screen size related field has changed. + static final int PHYSICAL_SCREEN_SIZE_DIRTY = 0x01; + // Screen size field has changed. + static final int SCREEN_SIZE_DIRTY_DIRTY = 0x02; + // Tracker base to image plate field has changed. + static final int TRACKER_BASE_TO_IMAGE_PLATE_DIRTY = 0x04; + // Head tracker to image plate field has changed. + static final int HEAD_TRACKER_TO_IMAGE_PLATE_DIRTY = 0x08; + + // Mask that indicates this Screen3D view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + int scrDirtyMask = (PHYSICAL_SCREEN_SIZE_DIRTY | SCREEN_SIZE_DIRTY_DIRTY + | TRACKER_BASE_TO_IMAGE_PLATE_DIRTY + | HEAD_TRACKER_TO_IMAGE_PLATE_DIRTY); + + // + // View cache for this screen + // + ScreenViewCache screenViewCache = null; + + // The renderer for this screen + Renderer renderer = null; + + // Hashtable that maps a GraphicsDevice to its associated renderer + static Hashtable deviceRendererMap = new Hashtable(); + + // A count of the number of canvases associated with this screen + int canvasCount = 0; + + // A count of the number of active View associated with this screen + UnorderList activeViews = new UnorderList(1, View.class); + + // A list of Canvas3D Objects that refer to this + ArrayList users = new ArrayList(); + + void addActiveView(View v) { + activeViews.addUnique(v); + } + + void removeActiveView(View v) { + activeViews.remove(v); + } + + boolean activeViewEmpty() { + return activeViews.isEmpty(); + } + + // Add a user to the list of users + synchronized void removeUser(Canvas3D c) { + int idx = users.indexOf(c); + if (idx >= 0) { + users.remove(idx); + } + } + + // Add a user to the list of users + synchronized void addUser(Canvas3D c) { + int idx = users.indexOf(c); + if (idx < 0) { + users.add(c); + } + } + + // Add a user to the list of users + synchronized void notifyUsers() { + int i; + Canvas3D c; + + for (i=0; irv is null, a new Dimension object is allocated. + * + * @return rv + * + * @since Java 3D 1.2 + */ + public Dimension getSize(Dimension rv) { + if (rv == null) { + return new Dimension(screenSize); + } + else { + rv.setSize(screenSize); + return rv; + } + } + + /** + * Sets the width and height (in pixels) of this off-screen Screen3D. + * The default size for off-screen Screen3D objects is (0,0). + *
+ * NOTE: the size must be + * set prior to rendering to the associated off-screen canvas. + * Failure to do so will result in an exception. + * + * @param width the new width of this Screen3D object + * @param height the new height of this Screen3D object + * + * @exception IllegalStateException if this Screen3D is not in + * off-screen mode. + * + * @since Java 3D 1.2 + */ + public void setSize(int width, int height) { + + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Screen3D1")); + + synchronized(this) { + screenSize.width = width; + screenSize.height = height; + scrDirtyMask |= SCREEN_SIZE_DIRTY_DIRTY; + } + } + + /** + * Sets the width and height (in pixels) of this off-screen Screen3D. + * The default size for off-screen Screen3D objects is (0,0). + *
+ * NOTE: the size must be + * set prior to rendering to the associated off-screen canvas. + * Failure to do so will result in an exception. + * + * @param d the new dimension of this Screen3D object + * + * @exception IllegalStateException if this Screen3D is not in + * off-screen mode. + * + * @since Java 3D 1.2 + */ + public void setSize(Dimension d) { + if (!offScreen) + throw new IllegalStateException(J3dI18N.getString("Screen3D1")); + + synchronized(this) { + screenSize.width = d.width; + screenSize.height = d.height; + scrDirtyMask |= SCREEN_SIZE_DIRTY_DIRTY; + } + } + + /** + * Sets the screen physical width in meters. In the case of a + * head-mounted display, this should be the apparent width + * at the focal plane. + * @param width the screen's physical width in meters + */ + public void setPhysicalScreenWidth(double width) { + synchronized(this) { + physicalScreenWidth = width; + scrDirtyMask |= PHYSICAL_SCREEN_SIZE_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the screen's physical width in meters. + * @return the screen's physical width in meters + */ + public double getPhysicalScreenWidth() { + return physicalScreenWidth; + } + + /** + * Sets the screen physical height in meters. In the case of a + * head-mounted display, this should be the apparent height + * at the focal plane. + * @param height the screen's physical height in meters + */ + public void setPhysicalScreenHeight(double height) { + synchronized(this) { + physicalScreenHeight = height; + scrDirtyMask |= PHYSICAL_SCREEN_SIZE_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the the screen's physical height in meters. + * @return the screen's physical height in meters + */ + public double getPhysicalScreenHeight() { + return physicalScreenHeight; + } + + public String toString() { + return "Screen3D: size = " + + "(" + getSize().width + " x " + getSize().height + ")" + + ", physical size = " + + "(" + getPhysicalScreenWidth() + "m x " + + getPhysicalScreenHeight() + "m)"; + } + + // Static initializer for Screen3D class + static { + VirtualUniverse.loadLibraries(); + } + + /** + * Construct a new Screen3D object with the specified size in pixels. + * Note that currently, there is no AWT equivalent of screen so Java 3D + * users need to get this through the Canvas3D object (via getScreen()) if + * they need it. + * @param graphicsConfiguration the AWT graphics configuration associated + * with this Screen3D + * @param offScreen a flag that indicates whether this Screen3D is + * associated with an off-screen Canvas3D + */ + Screen3D(GraphicsConfiguration graphicsConfiguration, boolean offScreen) { + this.offScreen = offScreen; + this.graphicsDevice = graphicsConfiguration.getDevice(); + + screenViewCache = new ScreenViewCache(this); + + // Get the display handle and the screen number from the Pipeline + display = Pipeline.getPipeline().getDisplay(); + screen = Pipeline.getPipeline().getScreen(graphicsDevice); + + if (debug) + System.err.println("Screen3D: display " + display + + " screen " + screen + " hashcode " + + this.hashCode()); + + if (!offScreen) { + // Store the information in this screen object + Rectangle bounds = graphicsConfiguration.getBounds(); + screenSize.width = bounds.width; + screenSize.height = bounds.height; + } + + // Set the default physical size based on size in pixels + physicalScreenWidth = screenSize.width * METERS_PER_PIXEL; + physicalScreenHeight = screenSize.height * METERS_PER_PIXEL; + } + + + /** + * Sets the tracker-base coordinate system to image-plate coordinate + * system transform. This transform + * is typically a calibration constant. + * This is used only in SCREEN_VIEW mode. + * @param t the new transform + * @exception BadTransformException if the transform is not rigid + */ + public void setTrackerBaseToImagePlate(Transform3D t) { + synchronized(this) { + if (!t.isRigid()) { + throw new BadTransformException(J3dI18N.getString("Screen3D0")); + } + trackerBaseToImagePlate.setWithLock(t); + scrDirtyMask |= Screen3D.TRACKER_BASE_TO_IMAGE_PLATE_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the tracker-base coordinate system to image-plate + * coordinate system transform and copies it into the specified + * Transform3D object. + * @param t the object that will receive the transform + */ + public void getTrackerBaseToImagePlate(Transform3D t) { + t.set(trackerBaseToImagePlate); + } + + /** + * Sets the head-tracker coordinate system to left image-plate coordinate + * system transform. This transform + * is typically a calibration constant. + * This is used only in HMD_VIEW mode. + * @param t the new transform + * @exception BadTransformException if the transform is not rigid + */ + public void setHeadTrackerToLeftImagePlate(Transform3D t) { + synchronized(this) { + if (!t.isRigid()) { + throw new BadTransformException(J3dI18N.getString("Screen3D0")); + } + headTrackerToLeftImagePlate.setWithLock(t); + scrDirtyMask |= Screen3D.HEAD_TRACKER_TO_IMAGE_PLATE_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the head-tracker coordinate system to left image-plate + * coordinate system transform and copies it into the specified + * Transform3D object. + * @param t the object that will receive the transform + */ + public void getHeadTrackerToLeftImagePlate(Transform3D t) { + t.set(headTrackerToLeftImagePlate); + } + + /** + * Sets the head-tracker coordinate system to right image-plate coordinate + * system transform. This transform + * is typically a calibration constant. + * This is used only in HMD_VIEW mode. + * @param t the new transform + * @exception BadTransformException if the transform is not rigid + */ + public void setHeadTrackerToRightImagePlate(Transform3D t) { + synchronized(this) { + if (!t.isRigid()) { + throw new BadTransformException(J3dI18N.getString("Screen3D0")); + } + headTrackerToRightImagePlate.setWithLock(t); + scrDirtyMask |= Screen3D.HEAD_TRACKER_TO_IMAGE_PLATE_DIRTY; + } + notifyUsers(); + } + + /** + * Retrieves the head-tracker coordinate system to right image-plate + * coordinate system transform and copies it into the specified + * Transform3D object. + * @param t the object that will receive the transform + */ + public void getHeadTrackerToRightImagePlate(Transform3D t) { + t.set(headTrackerToRightImagePlate); + } + + /** + * Update the view cache associated with this screen. + */ + void updateViewCache() { + if (false) + System.err.println("Screen3D.updateViewCache()"); + synchronized(this) { + screenViewCache.snapshot(); + } + } + + /** + * Increment canvas count, initialize renderer if needed + */ + synchronized void incCanvasCount() { + canvasCount++; + } + + /** + * Decrement canvas count, kill renderer if needed + */ + synchronized void decCanvasCount() { + canvasCount--; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ScreenViewCache.java b/j3d-core/src/classes/share/javax/media/j3d/ScreenViewCache.java new file mode 100644 index 0000000..5007362 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ScreenViewCache.java @@ -0,0 +1,141 @@ +/* + * $RCSfile: ScreenViewCache.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.Dimension; +import javax.vecmath.*; + +/** + * The ScreenViewCache class is used to cache all API data + * from the Screen3D object. + */ +class ScreenViewCache extends Object { + // The screen associated with this screen view cache + Screen3D screen; + + // + // API/INPUT DATA + // + + // The width and height of the screen in meters. + double physicalScreenWidth; + double physicalScreenHeight; + + // The width and height of the screen in pixels. + int screenWidth; + int screenHeight; + + // Mask that indicates Screen3D view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + // Issue 163: Array of dirty bits is used because the Renderer and + // RenderBin run asynchronously. Now that they each have a separate + // instance of CanvasViewCache (due to the fix for Issue 109), they + // need separate dirty bits. Array element 0 is used for the Renderer and + // element 1 is used for the RenderBin. + int[] scrvcDirtyMask = new int[2]; + + // + // Tracker-base coordinate system to image-plate coordinate + // system transform. If head tracking is enabled, this transform + // is a calibration constant. If head tracking is not enabled, + // this transform is not used. + // This is used only in SCREEN_VIEW mode. + // + Transform3D trackerBaseToImagePlate = new Transform3D(); + + // + // Head-tracker coordinate system to left and right image-plate coordinate + // system transforms. If head tracking is enabled, these transforms + // are calibration constants. If head tracking is not enabled, + // these transforms are not used. + // These are used only in HMD_VIEW mode. + // + Transform3D headTrackerToLeftImagePlate = new Transform3D(); + Transform3D headTrackerToRightImagePlate = new Transform3D(); + + + // + // DERIVED DATA + // + + // Meters per pixel in the X and Y dimension + double metersPerPixelX; + double metersPerPixelY; + + + /** + * Take snapshot of all per-screen API parameters. + */ + synchronized void snapshot() { + + // accumulate the dirty bits for offscreen because + // the dirty bits will not be processed until renderOffScreen + // or triggered by RenderBin at some little time + if (screen.offScreen) { + scrvcDirtyMask[0] |= screen.scrDirtyMask; + scrvcDirtyMask[1] |= screen.scrDirtyMask; + } else { + scrvcDirtyMask[0] = screen.scrDirtyMask; + scrvcDirtyMask[1] = screen.scrDirtyMask; + } + screen.scrDirtyMask = 0; + + physicalScreenWidth = screen.physicalScreenWidth; + physicalScreenHeight = screen.physicalScreenHeight; + screenWidth = screen.screenSize.width; + screenHeight = screen.screenSize.height; + + screen.trackerBaseToImagePlate.getWithLock(trackerBaseToImagePlate); + + screen.headTrackerToLeftImagePlate.getWithLock + (headTrackerToLeftImagePlate); + screen.headTrackerToRightImagePlate.getWithLock + (headTrackerToRightImagePlate); + + // This isn't really API data, but since we have no other derived + // data, and it's a simple calculation, it's easier if we just do + // it here. + metersPerPixelX = physicalScreenWidth / (double) screenWidth; + metersPerPixelY = physicalScreenHeight / (double) screenHeight; + } + + + /** + * Constructs and initializes a ScreenViewCache object. + */ + ScreenViewCache(Screen3D screen) { + this.screen = screen; + + if (false) + System.err.println("Constructed a ScreenViewCache"); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Sensor.java b/j3d-core/src/classes/share/javax/media/j3d/Sensor.java new file mode 100644 index 0000000..e32dff8 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Sensor.java @@ -0,0 +1,548 @@ +/* + * $RCSfile: Sensor.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The Sensor Class encapsulates an object that provides real-time + * data. Examples include six-degree-of-freedom tracking, a joystick, + * or a data file being read back during a program. A sensor must be + * used in conjuction with an implementation of the InputDevice + * interface.

+ * + * The Sensor object provides an abstract concept of a hardware + * input device. A Sensor consists of a timestamped sequence of + * input values and the state of buttons or switches at the time + * that Java 3D sampled the value. A sensor also contains a hotspot + * offset specified in the sensor's local coordinate system. If not + * specified, the hotspot is (0.0, 0.0, 0.0).

+ * + * Since a typical hardware environment may contain multiple sensing + * elements, Java 3D maintains an array of sensors. Users can access + * a sensor directly from their Java code or they can assign a sensor + * to one of Java 3D's predefined 6DOF entities, such as UserHead.

+ * + * Using a sensor is as easy as accessing an object. Write your + * Java code to extract the associated sensor value from the array of + * sensors. You can then directly apply that value to an element in a + * scene graph or process the sensor values in whatever way necessary.

+ * + * Java 3D includes three special six-degrees-of-freedom (6DOF) entities. + * These include UserHead, DominantHand, and NondominantHand. You + * can assign or change which sensor drives one + * of these predefined entities. Java 3D uses the specified sensor to + * drive the 6DOF entity - most visibly the View.

+ * + * Java 3D does not provide raw tracker or joystick-generated data in + * a sensor. At a minimum, Java 3D normalizes the raw data using the + * registration and calibration parameters either provided by or + * provided for the end user. It additionally may filter and process + * the data to remove noise and improve latency. + * The application programmer can suppress this latter effect on a + * sensor-by-sensor basis.

+ * + * @see SensorRead + */ + +public class Sensor { + + /** + * Set predictor type to do no prediction; this is the default. + * + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public static final int PREDICT_NONE = 1; + + /** + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public static final int PREDICT_NEXT_FRAME_TIME = 2; + + /** + * Use no prediction policy; this is the default. + * + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public static final int NO_PREDICTOR = 16; + + /** + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public static final int HEAD_PREDICTOR = 32; + + /** + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public static final int HAND_PREDICTOR = 64; + + /** + * Default SensorRead object count (30); the number of SensorRead + * objects constructed if no count is specified. + */ + public static final int DEFAULT_SENSOR_READ_COUNT = 30; + + /** + * SENSOR_READ_COUNT_BUFFER is the number of extra sensor reading + * values to store at the end of the circular list. It helps provide + * MT-safeness. This is necessary if someone asks for the last + * k sensor values and k is close to sensor read count. + * This helps avoid some synchronization statements in getRead + * and setNextSensorRead. + */ + static final int SENSOR_READ_COUNT_BUFFER = 15; + + static int num_reads_so_far = 0; + + // specifies whether a DEMAND_DRIVEN device has been added that + // manages this sensor + boolean demand_driven = false; + + // size of the sensor read buffer + int sensorReadCount; + + // Prediction policy -- unused + private int predictionPolicy = NO_PREDICTOR; + + // Predictor type -- unused + private int predictorType = PREDICT_NONE; + + // This sensor's associated device + InputDevice device; + + SensorRead readings[]; + int currentIndex; + int lastIndex; + Point3d hotspot; + int MaxSensorReadIndex; + + // The count of the number of buttons associated with this sensor. + int sensorButtonCount; + + // These matrices used as a temporary workspace for the local SVD + // calculations (thus minimimizing garbage collection). + Matrix3d orig_rot = new Matrix3d(); + Matrix3d orig_rot_transpose = new Matrix3d(); + Matrix3d temp_rot = new Matrix3d(); + Matrix3d local_svd = new Matrix3d(); + + + /** + * Constructs a Sensor object for the specified input device using + * default parameters. The default values are as follows: + *

    + * sensor read count : 30
    + * sensor button count : 0
    + * hot spot : (0,0,0)
    + * predictor : PREDICT_NONE — this attribute is unused
    + * prediction policy : NO_PREDICTOR — this attribute is unused
    + *
+ * @param device the Sensor's associated device. + */ + public Sensor(InputDevice device){ + this(device, DEFAULT_SENSOR_READ_COUNT, 0, new Point3d(0.0, 0.0, 0.0)); + } + + /** + * Constructs a Sensor object for the specified input device using + * the specified number of SensorRead objects. + * Default values are used for all other parameters. + * @param device the Sensor's associated device + * @param sensorReadCount the number of SensorReads to associate with + * this sensor + */ + public Sensor(InputDevice device, int sensorReadCount){ + this(device, sensorReadCount, 0, new Point3d(0.0, 0.0, 0.0)); + } + + /** + * Constructs a Sensor object for the specified input device using + * the specified number of SensorRead objects and number of buttons. + * Default values are used for all other parameters. + * @param device the Sensor's associated device + * @param sensorReadCount the number of SensorReads to associate with + * this sensor + * @param sensorButtonCount the number of buttons associated with each + * sensor read + */ + public Sensor(InputDevice device, int sensorReadCount, + int sensorButtonCount){ + this(device, sensorReadCount, sensorButtonCount, + new Point3d(0.0,0.0, 0.0)); + } + + /** + * Constructs a Sensor object for the specified input device using + * the specified hotspot. + * Default values are used for all other parameters. + * @param device the Sensor's associated device + * @param hotspot the Sensor's hotspot defined in its local coordinate + * system + */ + public Sensor(InputDevice device, Point3d hotspot){ + this(device, DEFAULT_SENSOR_READ_COUNT, 0, hotspot); + } + + /** + * Constructs a Sensor object for the specified input device using + * the specified number of SensorRead objects and hotspot. + * Default values are used for all other parameters. + * @param device the Sensor's associated device + * @param sensorReadCount the number of SensorReads to associate with + * this sensor + * @param hotspot the Sensor's hotspot defined in its local coordinate + * system + */ + public Sensor(InputDevice device, int sensorReadCount, Point3d hotspot){ + this(device, sensorReadCount, 0, hotspot); + } + + /** + * Constructs a Sensor object for the specified input device using + * the specified number of SensorRead objects, number of buttons, and + * hotspot. + * Default values are used for all other parameters. + * @param device the Sensor's associated device + * @param sensorReadCount the number of SensorReads to associate with + * this sensor + * @param sensorButtonCount the number of buttons associated with each + * sensor read + * @param hotspot the Sensor's hotspot defined in its local coordinate + * system + */ + public Sensor(InputDevice device, int sensorReadCount, + int sensorButtonCount, Point3d hotspot){ + this.device = device; + this.sensorReadCount = sensorReadCount; + this.MaxSensorReadIndex = sensorReadCount + SENSOR_READ_COUNT_BUFFER - 1; + this.sensorButtonCount = sensorButtonCount; + readings = new SensorRead[MaxSensorReadIndex + 1]; + for(int i = 0; i < MaxSensorReadIndex + 1; i++){ + readings[i] = new SensorRead(sensorButtonCount); + } + currentIndex = 0; + this.hotspot = new Point3d(hotspot); + } + + // argument of 0 is last reading (ie, currentIndex), argument + // of 1 means next to last index, etc. + int previousIndex(int k){ + int temp = currentIndex - k; + return(temp >= 0 ? temp : MaxSensorReadIndex + temp + 1); + } + + /** + * Sets the type of predictor to use with this sensor. + * Since prediction is not implemented (and never has been), this + * attribute has no effect. + * @param predictor predictor type one of PREDICT_NONE or + * PREDICT_NEXT_FRAME_TIME + * @exception IllegalArgumentException if an invalid predictor type + * is specified. + * + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public void setPredictor(int predictor){ + if (predictor != PREDICT_NONE && predictor != PREDICT_NEXT_FRAME_TIME) { + throw new IllegalArgumentException(J3dI18N.getString("Sensor0")); + } else { + predictorType = predictor; + } + } + + /** + * Returns the type of predictor used by this sensor. + * @return the predictor type. + * + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public int getPredictor(){ + return predictorType; + } + + /** + * Sets the prediction policy use by this sensor. + * Since prediction is not implemented (and never has been), this + * attribute has no effect. + * @param policy prediction policy one of NO_PREDICTOR, HEAD_PREDICTOR, + * or HAND_PREDICTOR + * @exception IllegalArgumentException if an invalid prediction policy + * is specified. + * + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public void setPredictionPolicy(int policy){ + if (policy != NO_PREDICTOR && policy != HEAD_PREDICTOR && + policy != HAND_PREDICTOR) + throw new IllegalArgumentException(J3dI18N.getString("Sensor1")); + else + predictionPolicy = policy; + } + + /** + * Returns the prediction policy used by this sensor. + * @return the prediction policy. + * + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature. + */ + public int getPredictionPolicy(){ + return predictionPolicy; + } + + /** + * Set the sensor's hotspot in this sensor's coordinate system. + * @param hotspot the sensor's new hotspot + */ + public void setHotspot(Point3d hotspot){ + this.hotspot.set(hotspot); + } + + /** + * Get the sensor's hotspot in this sensor's coordinate system. + * @param hotspot the variable to receive the sensor's hotspot + */ + public void getHotspot(Point3d hotspot){ + hotspot.set(this.hotspot); + } + + /** + * Set the sensor's associated input device. + * @param device the sensor's new device + */ + public void setDevice(InputDevice device){ + this.device = device; + } + + /** + * Retrieves the sensor's associated input device. + * @return the sensor's device + */ + public InputDevice getDevice(){ + return device; + } + + /** + * Retrieves the last sensor reading and copies that value into + * the specified argument. + * + * @param read the matrix that will receive the sensor reading + */ + public void getRead(Transform3D read) { + if(demand_driven == true) + device.pollAndProcessInput(); + + read.set(readings[currentIndex].read); + } + + /** + * Retrieves the last sensor reading and copies that value into + * the specified argument. + * + * @param read the matrix that will receive the sensor reading + * @param deltaT this parameter is ignored + * + * @deprecated As of Java 3D version 1.4, prediction is not a + * supported feature; use getRead(Transform3D) instead. + */ + public void getRead(Transform3D read, long deltaT){ + getRead(read); + } + + /** + * Extracts the most recent sensor reading and copies that value into + * the specified argument. + * @param read the matrix that will receive the most recent sensor reading + */ + public void lastRead(Transform3D read){ + read.set(readings[currentIndex].read); + } + + /** + * Extracts the kth-most recent sensor reading and copies that value into + * the specified argument; where 0 is the most recent sensor reading, 1 is + * the next most recent sensor reading, etc. + * @param read the matrix that will receive the most recent sensor reading + * @param kth the kth previous sensor reading + */ + public void lastRead(Transform3D read, int kth){ + if(kth >= sensorReadCount) { + throw new IllegalArgumentException(J3dI18N.getString("Sensor3")); + } + read.set(readings[previousIndex(kth)].read); + } + + /** + * Returns the time associated with the most recent sensor reading. + * @return the time associated with the most recent sensor reading. + */ + public long lastTime(){ + return readings[currentIndex].time; + } + + /** + * Returns the time associated with the kth-most recent sensor reading; + * where 0 is the most recent sensor reading, 1 is the next most recent + * sensor reading, etc. + * @return the time associated with the kth-most recent sensor reading. + */ + public long lastTime(int k){ + if(k >= sensorReadCount) { + throw new IllegalArgumentException(J3dI18N.getString("Sensor4")); + } + return readings[previousIndex(k)].time; + } + + /** + * Places the most recent sensor reading value for each button into + * the array parameter; will throw an ArrayIndexOutOfBoundsException + * if values.length is less than the number of buttons. + * @param values the array into which the button values will be + * placed + */ + public void lastButtons(int[] values) { + System.arraycopy(readings[currentIndex].buttonValues, 0, values, + 0, sensorButtonCount); + } + + /** + * Places the kth-most recent sensor reading value for each button into + * the array parameter; where k=0 is the most recent sensor reading, k=1 + * is the next most recent sensor reading, etc.; will throw an + * ArrayIndexOutOfBoundsException if values.length is less than + * the number of buttons. + * @param k the time associated with the most recent sensor reading + * @param values the array into which the button values will be + * placed. + */ + public void lastButtons(int k, int[] values) { + if(k >= sensorReadCount) { + throw new IllegalArgumentException(J3dI18N.getString("Sensor5")); + } + System.arraycopy(readings[previousIndex(k)].buttonValues, 0, values, + 0, sensorButtonCount); + } + + /** + * Returns the number of SensorRead objects associated with + * this sensor. + * @return the number of SensorReadObjects associated with this sensor + */ + public int getSensorReadCount() { + return this.sensorReadCount; + } + + /** + * Set the number of sensor read objects per Sensor. This is a + * calibration parameter that should normally be set in this + * object's constructor. Calling this method resets all of this + * sensor's values that are already in the buffer. + * It is illegal to change this value after the device has been + * added to the scheduler. + * @param count the new sensor read count + */ + public void setSensorReadCount(int count) { + sensorReadCount = count; + MaxSensorReadIndex = sensorReadCount + SENSOR_READ_COUNT_BUFFER - 1; + readings = new SensorRead[MaxSensorReadIndex + 1]; + for(int i = 0; i < MaxSensorReadIndex + 1; i++){ + readings[i] = new SensorRead(sensorButtonCount); + } + currentIndex = 0; + } + + + /** + * Returns the number of buttons associated with this sensor. + * @return the number of buttons associated with this sensor. + */ + public int getSensorButtonCount() { + return sensorButtonCount; + } + + /** + * Gets the current sensor read. + * @return the current sensor read object + */ + public SensorRead getCurrentSensorRead() { + // not sure if this should return a reference or a copy + SensorRead read = new SensorRead(sensorButtonCount); + read.set(readings[currentIndex]); + return read; + } + + /** + * Sets the next sensor read to the specified values; once these + * values are set via this method they become the current values + * returned by methods such as lastRead(), lastTime(), and + * lastButtons(); note that if there are no buttons associated with + * this sensor, values can just be an empty array. + * @param time the next SensorRead's associated time + * @param transform the next SensorRead's transformation + * @param values the next SensorRead's buttons' states + */ + public void setNextSensorRead(long time, Transform3D transform, + int[] values) { + + int temp = currentIndex + 1; + if (temp > MaxSensorReadIndex) temp = 0; + + readings[temp].setTime(time); + readings[temp].set(transform); + if(sensorButtonCount > 0) + readings[temp].setButtons(values); + currentIndex = temp; + } + + /** + * Sets the next sensor read to the specified values; once these + * values are set via this method they become the current values + * returned by methods such as lastRead(), lastTime(), and + * lastButtons(). + * @param read the next SensorRead's values + */ + public void setNextSensorRead(SensorRead read) { + int temp = currentIndex + 1; + if (temp > MaxSensorReadIndex) temp = 0; + readings[temp].set(read); + currentIndex = temp; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SensorRead.java b/j3d-core/src/classes/share/javax/media/j3d/SensorRead.java new file mode 100644 index 0000000..1f94323 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SensorRead.java @@ -0,0 +1,186 @@ +/* + * $RCSfile: SensorRead.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * A SensorRead encapsulates all the information associated with a single + * reading of a sensor, including a timestamp, a transform, and, + * optionally, button values. + */ + +public class SensorRead { + + /** + * The maximum number of sensor-attached buttons tracked on a per + * sensor basis. + */ + public static final int MAXIMUM_SENSOR_BUTTON_COUNT = 12; + + /** + * This reading's time stamp + */ + long time; + + /** + * The six-degree-of-freedom reading + */ + Transform3D read; + + /** + * The state of the sensor's buttons + */ + int[] buttonValues; + + /** + * The number of buttons associated with this SensorRead + */ + int numButtons; + + /** + * Constructs a SensorRead object with default parameters. + * The default values are as follows: + *
    + * number of buttons : 0
    + * button values : 0 (for all array elements)
    + * transform : identity
    + * time : current time
    + *
+ */ + public SensorRead(){ + this(0); + } + + /** + * Constructs a SensorRead object with the specified number + * of buttons. + * @param numButtons the number of buttons for this SensorRead + */ + public SensorRead(int numButtons){ + this.read = new Transform3D(); + this.numButtons = numButtons; + this.buttonValues = new int[numButtons]; + + // Do this last + this.time = J3dClock.currentTimeMillis(); + } + + final void set(SensorRead sensorRead) { + this.time = sensorRead.time; + this.numButtons = sensorRead.numButtons; + this.read.set(sensorRead.read); + if(numButtons > 0) + System.arraycopy(sensorRead.buttonValues, 0, this.buttonValues, + 0, sensorRead.numButtons); + } + + /** + * Set the SensorRead's transform to the value specified + * @param t1 this sensor's reading + */ + public void set(Transform3D t1) { + read.set(t1); + } + + /** + * Retrieve the SensorRead's transform and place it in result + * @param result the recipient of the this sensor's reading + */ + public void get(Transform3D result) { + result.set(read); + } + + /** + * Sets this SensorRead's time stamp to the specified argument + * @param time the time to associate with this reading + */ + public void setTime(long time) { + this.time = time; + } + + /** + * Retrieve this SensorRead's associated time stamp + * @return the SensorRead's time as a long + */ + public long getTime() { + return this.time; + } + + /** + * Sets the values of all buttons for this SensorRead object. + * @param values array contining the new buttons for this SensorRead + * @exception ArrayIndexOutOfBoundsException if this object + * has 0 buttons or if values.length is less than the number of + * buttons in this object. + */ + public void setButtons(int[] values) { + if(numButtons == 0) + + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("SensorRead1")); + + else if(values.length < numButtons) + + throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("SensorRead0")); + System.arraycopy(values, 0, buttonValues, 0, numButtons); + } + + + /** + * Copies the array of button values for this SensorRead object into + * the specified array. + * This method has no effect + * if this SensorRead object has 0 buttons. The array must be + * large enough to hold all of the buttons. + * @param values array that will receive the values of all buttons + * for this SensorRead + */ + public void getButtons(int[] values) { + if(numButtons > 0) + System.arraycopy(buttonValues, 0, values, 0, numButtons); + } + + + /** + * Returns the number of buttons associated with this SensorRead + * object. + * + * @return the number of buttons associated with this SensorRead + * object + * + * @since Java 3D 1.2 + */ + public int getNumButtons() { + return numButtons; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SetLiveState.java b/j3d-core/src/classes/share/javax/media/j3d/SetLiveState.java new file mode 100644 index 0000000..e6d7299 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SetLiveState.java @@ -0,0 +1,276 @@ +/* + * $RCSfile: SetLiveState.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * SetLiveState is used to encapsulate all state needed when a branch + * group is added to the scene graph + */ + +class SetLiveState extends Object { + // The VirtualUniverse for this branch group + VirtualUniverse universe = null; + + // The Locale for this Branch Graph + Locale locale = null; + + // The transforms used to update state + Transform3D[][] currentTransforms = new Transform3D[1][]; + int[][] currentTransformsIndex = new int[1][]; + + // The keys used when dealing with SharedGroups + HashKey[] keys = null; + + // flags for detecting what we are under + boolean inSharedGroup = false; + boolean inBackgroundGroup = false; + boolean inViewSpecificGroup = false; + + /** + * The list of nodes added/removed during setLive/clearLive + */ + ArrayList nodeList = new ArrayList(); + + /** + * List of nodes that are viewScoped. Note that all nodes + * except Shape3D nodes can be in viewScopedNodeList, shape3D + * nodes will always be in the nodeList regardless of scoped + * or not. Also, only renderbin and renderingEnv structure is + * interested in viewScopedNodeList + */ + ArrayList viewScopedNodeList = null; + + /** + * Parallel list to viewScopedNodeList containing a list of views + * that the viewScopedNode is scoped to + */ + ArrayList scopedNodesViewList = null; + + // Threads to notify after setLive/clearLive + int notifyThreads = 0; + + // The current list of leaf nodes for transform targets + Targets[] transformTargets = null; + + // List of transform level, one per shared path + int transformLevels[] = new int[]{-1}; + + // List of scoped lights + ArrayList lights = null; + + // List of scoped fogs + ArrayList fogs =null; + + // List of scoped modelClips + ArrayList modelClips = null; + + // List of scoped alt app + ArrayList altAppearances =null; + + // List of viewes scoped to this Group, for all subclasses + // of group, except ViewSpecificGroup its a pointer to closest + // ViewSpecificGroup parent + // viewList for this node, if inSharedGroup is + // false then only viewList(0) is valid + ArrayList viewLists = null; + ArrayList changedViewGroup = null; + ArrayList changedViewList = null; + int[] keyList = null; + + + // The current bitmask of types in transformTragets + //int transformTargetThreads = 0; + + ArrayList orderedPaths = null; + + ArrayList ogList = new ArrayList(5); + ArrayList ogChildIdList = new ArrayList(5); + ArrayList ogOrderedIdList = new ArrayList(5); + // ogCIOList contains a list of OG with affected child index order. + ArrayList ogCIOList = new ArrayList(5); + // ogCIOTableList contains a list of affected child index order. + ArrayList ogCIOTableList = new ArrayList(5); + + /** + * List of BranchGroup from this node to the root of tree + * This is used by BranchGroupRetained to construct + * BranchGroup lists for picking. + * + * @see NodeRetained.branchGroupPaths + */ + ArrayList branchGroupPaths = null; + ArrayList parentBranchGroupPaths = null; + + /** + * List of Pickable flags, one for each share path. + * This flag is true when all the NodeRetained.pickable is true + * along the path except current node. + */ + boolean pickable[] = new boolean[]{true}; + + /** + * List of collidable flags, one for each share path. + * This flag is true when all the NodeRetained.pickable is true + * along the path except current node. + */ + boolean collidable[] = new boolean[]{true}; + + // reference count use in set/clear Live to remember how + // many references of the original branch that attach()/detach() + int refCount = 1; + + // background node whose geometry branch contains this node + BackgroundRetained geometryBackground = null; + + // behavior nodes + ArrayList behaviorNodes = new ArrayList(1); + + // The current list of child transform group nodes or link nodes + // under a transform group + ArrayList childTransformLinks = null; + + // closest parent which is a TransformGroupRetained or sharedGroupRetained + GroupRetained parentTransformLink = null; + + // switch Level, start from -1, increment by one for each SwitchNode + // encounter in a branch, one per key + int switchLevels[] = new int[]{-1}; + + // closest switch parent, one per key + SwitchRetained closestSwitchParents[] = new SwitchRetained[]{null}; + + // the child id from the closest switch parent, one per key + int closestSwitchIndices[] = new int[]{-1}; + + // The current list of leaf nodes for switch targets + Targets[] switchTargets = null; + + // The current list of closest child switch nodes or + // link nodes under a switch node + ArrayList childSwitchLinks = null; + + // closest parent which is a SwitchRetained or sharedGroupRetained + GroupRetained parentSwitchLink = null; + + SharedGroupRetained lastSharedGroup = null; + + int traverseFlags = 0; + + // Use for set live. + Transform3D[][] localToVworld = null; + int[][] localToVworldIndex = null; + HashKey[] localToVworldKeys = null; + + // cached hashkey index to eliminate duplicate hash key index search + // currently used by Switch, can be extended for other node types + int[] hashkeyIndex = null; + + ArrayList switchStates = null; + + SetLiveState(VirtualUniverse u) { + universe = u; + } + + + void reset(Locale l) { + locale = l; + clear(); + } + + void clear() { + inSharedGroup = false; + inBackgroundGroup = false; + inViewSpecificGroup = false; + nodeList.clear(); + viewScopedNodeList = null; + scopedNodesViewList = null; + + notifyThreads = 0; + transformTargets = null; + lights = null; + fogs = null; + modelClips = null; + altAppearances = null; + viewLists = null; + changedViewGroup = null; + changedViewList = null; + keyList = null; + + behaviorNodes.clear(); + traverseFlags = 0; + + ogList.clear(); + ogChildIdList.clear(); + ogOrderedIdList.clear(); + ogCIOList.clear(); + ogCIOTableList.clear(); + + pickable = new boolean[]{true}; + collidable = new boolean[]{true}; + refCount = 1; + geometryBackground = null; + transformLevels = new int[]{-1}; + childTransformLinks = null; + parentTransformLink = null; + + switchTargets = null; + switchLevels = new int[]{-1}; + switchStates = null; + closestSwitchIndices = new int[]{-1}; + closestSwitchParents = new SwitchRetained[]{null}; + childSwitchLinks = null; + parentSwitchLink = null; + + lastSharedGroup = null; + + keys = null; + currentTransforms = new Transform3D[1][]; + currentTransformsIndex = new int[1][]; + + localToVworld = null; + localToVworldIndex = null; + localToVworldKeys = null; + + // XXXX: optimization for targetThreads computation, require + // cleanup in GroupRetained.doSetLive() + //transformTargetThreads = 0; + + hashkeyIndex = null; + + // Fix for issue 75 + parentBranchGroupPaths = null; + branchGroupPaths = null; + orderedPaths = null; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Shader.java b/j3d-core/src/classes/share/javax/media/j3d/Shader.java new file mode 100644 index 0000000..64b5152 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Shader.java @@ -0,0 +1,150 @@ +/* + * $RCSfile: Shader.java,v $ + * + * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The Shader object is the abstract base class for programmable + * shader code. Currently, only text-based source code shaders are + * supported, so the only subclass of Shader is SourceCodeShader. We + * leave open the possibility for binary (object code) shaders in the + * future. + * + *

+ * Each instance of a Shader object allows an application to specify + * the source code used in programming the Graphics Pipeline Unit + * (GPU) of the graphics accelerator. A Shader object is constructed + * with modes that specify the shading language and the + * shader type. + * + *

+ * The shading language specifies the language and runtime environment + * used to program the GPU. The currently defined shading languages + * are GLSL (also known as the OpenGL 2.0 shading language) and + * Cg. Note that not all shading languages are supported on all + * platforms. It is up to the application or utility to query whether + * a particular shading language is supported before using it. The + * value of the shadingLanguage mode is one of: + * SHADING_LANGUAGE_GLSL or + * SHADING_LANGUAGE_CG. + * + *

+ * The shader type specifies whether the shader is a vertex + * shader or a fragment shader. A vertex shader replaces + * the fixed-function graphics pipeline for vertex operations + * (transformation and lighting). A fragment shader replaces the + * fixed-function graphics pipeline for fragment shading operations + * (texture mapping, texture application, coloring, shading, and so + * forth). The value of the shaderType mode is one of: + * SHADER_TYPE_VERTEX or + * SHADER_TYPE_FRAGMENT. + * + *

+ * Both the shading language and shader type are immutable modes of + * the Shader object. + * + *

+ * NOTE: Applications should not extend this class. + * + * @see ShaderProgram + * @see Canvas3D#isShadingLanguageSupported + * + * @since Java 3D 1.4 + */ + +public abstract class Shader extends NodeComponent { + + + /** + * This constant indicates the GLSL shading language. It is one + * of the possible values of the shadingLanguage parameter. + */ + public static final int SHADING_LANGUAGE_GLSL = 1; + + /** + * This constant indicates the Cg shading language. It is one + * of the possible values of the shadingLanguage parameter. + */ + public static final int SHADING_LANGUAGE_CG = 2; + + + /** + * This constant indicates that the shader type is a vertex + * shader. It is one of the possible values of the shaderType + * parameter. + */ + public static final int SHADER_TYPE_VERTEX = 1; + + /** + * This constant indicates that the shader type is a fragment + * shader. It is one of the possible values of the shaderType + * parameter. + */ + public static final int SHADER_TYPE_FRAGMENT = 2; + + + /** + * Not a public constructor, for internal use + */ + Shader() { + } + + /** + * Package scope constructor so it can't be subclassed by classes + * outside the javax.media.j3d package. + */ + Shader(int shadingLanguage, int shaderType) { + ((ShaderRetained)this.retained).initializeShader(shadingLanguage, shaderType); + } + + /** + * Returns the shading language of this shader. + * + * @return the shading language of this shader, one of: + * SHADING_LANGUAGE_GLSL or + * SHADING_LANGUAGE_CG. + */ + public int getShadingLanguage() { + return ((ShaderRetained)this.retained).getShadingLanguage(); + } + + /** + * Returns the type of this shader. + * + * @return the shader type, one of: + * SHADER_TYPE_VERTEX or + * SHADER_TYPE_FRAGMENT. + */ + public int getShaderType() { + return ((ShaderRetained)this.retained).getShaderType(); + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAppearance.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAppearance.java new file mode 100644 index 0000000..4b1015d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAppearance.java @@ -0,0 +1,304 @@ +/* + * $RCSfile: ShaderAppearance.java,v $ + * + * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Hashtable; + +/** + *

The ShaderAppearance object defines programmable shading attributes + * that can be set as a component object of a Shape3D node. The + * ShaderAppearance rendering state adds the following attributes in + * addition to those defined by Appearance:

+ * + *
    + *
  • Shader program - specifies the shader program...
  • + * + *

    + *
  • Shader attribute set - specifies the shader parameters, both as + * explicit attributes and as implicit bindings to Java 3D + * state...
  • + *
+ * + *

The ShaderAppearance object modifies the definition of some of the + * attributes in Appearance:

+ * + *
    + *
  • Coloring attributes - XXXXX
  • + * + *

    + *
  • Line attributes - XXXXX
  • + * + *

    + *
  • Point attributes - XXXXX
  • + * + *

    + *
  • Polygon attributes - XXXXX
  • + * + *

    + *
  • Rendering attributes - XXXXX
  • + * + *

    + *
  • Transparency attributes - XXXXX
  • + * + *

    + *
  • Material - XXXXX
  • + * + *

    + *
  • Texture - XXXXX
  • + * + *

    + *
  • Texture attributes - XXXXX
  • + * + *

    + *
  • Texture coordinate generation - XXXXX
  • + * + *

    + *
  • Texture unit state - XXXXX
  • + *
+ * + * @see ShaderProgram + * @see ShaderAttributeSet + * + * @since Java 3D 1.4 + */ +public class ShaderAppearance extends Appearance { + /** + * Specifies that this ShaderAppearance object allows reading its + * ShaderProgram component information. + */ + public static final int + ALLOW_SHADER_PROGRAM_READ = + CapabilityBits.SHADER_APPEARANCE_ALLOW_SHADER_PROGRAM_READ; + + /** + * Specifies that this ShaderAppearance object allows writing its + * ShaderProgram component information. + */ + public static final int + ALLOW_SHADER_PROGRAM_WRITE = + CapabilityBits.SHADER_APPEARANCE_ALLOW_SHADER_PROGRAM_WRITE; + + /** + * Specifies that this ShaderAppearance object allows reading its + * ShaderAttributeSet component information. + */ + public static final int + ALLOW_SHADER_ATTRIBUTE_SET_READ = + CapabilityBits.SHADER_APPEARANCE_ALLOW_SHADER_ATTRIBUTE_SET_READ; + + /** + * Specifies that this ShaderAppearance object allows writing its + * ShaderAttributeSet component information. + */ + public static final int + ALLOW_SHADER_ATTRIBUTE_SET_WRITE = + CapabilityBits.SHADER_APPEARANCE_ALLOW_SHADER_ATTRIBUTE_SET_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SHADER_PROGRAM_READ, + ALLOW_SHADER_ATTRIBUTE_SET_READ + }; + + /** + * Constructs a ShaderAppearance component object using defaults for all + * state variables. All component object references are initialized + * to null. + */ + public ShaderAppearance() { + // Just use default values + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Creates the retained mode ShaderAppearanceRetained object that this + * ShaderAppearance component object will point to. + */ + void createRetained() { + this.retained = new ShaderAppearanceRetained(); + this.retained.setSource(this); + } + + /** + * Sets the ShaderProgram object to the specified object. Setting it to + * null causes a default pass-through shader to be used ??? + * + * @param shaderProgram object that specifies the desired shader program + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setShaderProgram(ShaderProgram shaderProgram) { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_SHADER_PROGRAM_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAppearance0")); + } + + ((ShaderAppearanceRetained)this.retained).setShaderProgram(shaderProgram); + + } + + + /** + * Retrieves the current ShaderProgram object. + * + * @return the ShaderProgram object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ShaderProgram getShaderProgram() { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_SHADER_PROGRAM_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAppearance1")); + } + return ((ShaderAppearanceRetained)this.retained).getShaderProgram(); + } + + + /** + * Sets the ShaderAttributeSet object to the specified object. Setting it to + * null is equivalent to specifying an empty set of attributes. + * + * @param shaderAttributeSet object that specifies the desired shader attributes + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setShaderAttributeSet(ShaderAttributeSet shaderAttributeSet) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_SHADER_ATTRIBUTE_SET_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAppearance2")); + } + + ((ShaderAppearanceRetained)this.retained).setShaderAttributeSet(shaderAttributeSet); + } + + + /** + * Retrieves the current ShaderAttributeSet object. + * + * @return the ShaderAttributeSet object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ShaderAttributeSet getShaderAttributeSet() { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_SHADER_ATTRIBUTE_SET_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAppearance3")); + } + return ((ShaderAppearanceRetained)this.retained).getShaderAttributeSet(); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + ShaderAppearance a = new ShaderAppearance(); + a.duplicateNodeComponent(this); + return a; + } + + /** + * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @deprecated replaced with duplicateNodeComponent( + * NodeComponent originalNodeComponent, boolean forceDuplicate) + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent) { + checkDuplicateNodeComponent(originalNodeComponent); + } + + /** + * Copies all ShaderAppearance information from + * originalNodeComponent into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + Hashtable hashtable = originalNodeComponent.nodeHashtable; + + ShaderAppearanceRetained app = + (ShaderAppearanceRetained) originalNodeComponent.retained; + + ShaderAppearanceRetained rt = (ShaderAppearanceRetained) retained; + + rt.setShaderProgram((ShaderProgram) getNodeComponent(app.getShaderProgram(), + forceDuplicate, + hashtable)); + } + + /** + * This function is called from getNodeComponent() to see if any of + * the sub-NodeComponents duplicateOnCloneTree flag is true. + * If it is the case, current NodeComponent needs to + * duplicate also even though current duplicateOnCloneTree flag is false. + * This should be overwrite by NodeComponent which contains sub-NodeComponent. + */ + boolean duplicateChild() { + if (super.duplicateChild()) + return true; + + if (getDuplicateOnCloneTree()) + return true; + + ShaderAppearanceRetained rt = (ShaderAppearanceRetained) retained; + + NodeComponent nc; + + nc = rt.getShaderProgram(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + return false; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAppearanceRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAppearanceRetained.java new file mode 100644 index 0000000..ee1ef66 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAppearanceRetained.java @@ -0,0 +1,392 @@ +/* + * $RCSfile: ShaderAppearanceRetained.java,v $ + * + * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; +import java.util.BitSet; +import java.util.ArrayList; + + +/** + * The Appearance object defines all rendering state that can be set + * as a component object of a Shape3D node. + */ +class ShaderAppearanceRetained extends AppearanceRetained { + + // Issue 485 - these values must start after the last value in Appearance + static final int SHADER_PROGRAM = 0x0800; + static final int SHADER_ATTRIBUTE_SET = 0x1000; + + // + // State variables: these should all be initialized to approproate + // Java 3D defaults. + // + + protected ShaderProgramRetained shaderProgram = null; + protected ShaderAttributeSetRetained shaderAttributeSet = null; + protected boolean isMirror = false; // For Debugging. + + /** + * Set the shader program object to the specified object. + * @param shaderProgram object that specifies the desired shader program + * and shader program attributes. + */ + void setShaderProgram(ShaderProgram sp) { + synchronized(liveStateLock) { + if (source.isLive()) { + // System.err.println("**** ShaderAppearceRetained.setShaderProgram()"); + + if (this.shaderProgram != null) { + this.shaderProgram.clearLive(refCount); + this.shaderProgram.removeMirrorUsers(this); + } + + if (sp != null) { + ((ShaderProgramRetained)sp.retained).setLive(inBackgroundGroup, + refCount); + ((ShaderProgramRetained)sp.retained).copyMirrorUsers(this); + } + + sendMessage(SHADER_PROGRAM, + (sp != null ? ((ShaderProgramRetained)sp.retained).mirror : null)); + + } + + if (sp == null) { + this.shaderProgram = null; + } else { + this.shaderProgram = (ShaderProgramRetained)sp.retained; + } + } + } + + + /** + * Retrieves the current shader program object. + * @return current shader program object + */ + ShaderProgram getShaderProgram() { + return (shaderProgram == null ? null : (ShaderProgram)shaderProgram.source); + } + + + /** + * Sets the ShaderAttributeSet object to the specified object. Setting it to + * null is equivalent to specifying an empty set of attributes. + * + * @param shaderAttributeSet object that specifies the desired shader attributes + */ + void setShaderAttributeSet(ShaderAttributeSet sas) { + synchronized(liveStateLock) { + if (source.isLive()) { + // System.err.println("**** ShaderAppearceRetained.setShaderAttributeSet()"); + + if (this.shaderAttributeSet != null) { + this.shaderAttributeSet.clearLive(refCount); + this.shaderAttributeSet.removeMirrorUsers(this); + } + + if (sas != null) { + ((ShaderAttributeSetRetained)sas.retained).setLive(inBackgroundGroup, + refCount); + ((ShaderAttributeSetRetained)sas.retained).copyMirrorUsers(this); + } + + // System.err.println(" -- testing needed!"); + sendMessage(SHADER_ATTRIBUTE_SET, + (sas != null ? + ((ShaderAttributeSetRetained)sas.retained).mirror : null)); + + } + + if (sas == null) { + this.shaderAttributeSet = null; + } else { + this.shaderAttributeSet = (ShaderAttributeSetRetained)sas.retained; + } + } + } + + + /** + * Retrieves the current ShaderAttributeSet object. + * @return current ShaderAttributeSet object + */ + ShaderAttributeSet getShaderAttributeSet() { + return (shaderAttributeSet == null ? null : (ShaderAttributeSet)shaderAttributeSet.source); + + } + + + public boolean equals(Object obj) { + return ((obj instanceof ShaderAppearanceRetained) && + equals((ShaderAppearanceRetained) obj)); + } + + boolean equals(ShaderAppearanceRetained sApp) { + boolean flag; + flag = (sApp == this); + + // If the reference is the same, we can stop check. + if(flag) + return flag; + + // Check each member's reference for equal. + flag = ((sApp != null) && + (shaderProgram == sApp.shaderProgram) && + (shaderAttributeSet == sApp.shaderAttributeSet)); + + + if (!flag) + return flag; + + return super.equals(sApp); + + } + + + + synchronized void createMirrorObject() { + // System.err.println("ShaderAppearanceRetained : createMirrorObject()"); + + if (mirror == null) { + // we can't check isStatic() since it sub-NodeComponent + // create a new one, we should create a + // new AppearanceRetained() even though isStatic() = true. + // For simplicity, always create a retained side. + mirror = new ShaderAppearanceRetained(); + ((ShaderAppearanceRetained)mirror).isMirror = true; // For Debugging. + } + initMirrorObject(); + } + + /** + * This routine updates the mirror appearance for this appearance. + * It also calls the update method for each node component if it + * is not null. + */ + synchronized void initMirrorObject() { + // System.err.println("ShaderAppearanceRetained : initMirrorObject()"); + + super.initMirrorObject(); + + ShaderAppearanceRetained mirrorApp = (ShaderAppearanceRetained)mirror; + + if(shaderProgram != null) { + mirrorApp.shaderProgram = (ShaderProgramRetained)shaderProgram.mirror; + } + else { + mirrorApp.shaderProgram = null; + } + + if(shaderAttributeSet != null) { + mirrorApp.shaderAttributeSet = + (ShaderAttributeSetRetained)shaderAttributeSet.mirror; + } + else { + // System.err.println("shaderAttributeSet is null"); + mirrorApp.shaderAttributeSet = null; + } + + } + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + +// System.err.println("ShaderAppearanceRetained : updateMirrorObject(): " + +// "this = " + this + " component = " + component + " value = " + value); + super.updateMirrorObject(component, value); + ShaderAppearanceRetained mirrorApp = (ShaderAppearanceRetained)mirror; + if ((component & SHADER_PROGRAM) != 0) { + mirrorApp.shaderProgram = (ShaderProgramRetained)value; + } + else if ((component & SHADER_ATTRIBUTE_SET) != 0) { + mirrorApp.shaderAttributeSet = (ShaderAttributeSetRetained)value; + } + + } + + /** + * This method calls the setLive method of all appearance bundle + * objects. + */ + void doSetLive(boolean backgroundGroup, int refCount) { + // System.err.println("ShaderAppearceRetained.doSetLive()"); + + + if (shaderProgram != null) { + shaderProgram.setLive(backgroundGroup, refCount); + } + + if (shaderAttributeSet != null) { + shaderAttributeSet.setLive(backgroundGroup, refCount); + } + + + // Increment the reference count and initialize the appearance + // mirror object + super.doSetLive(backgroundGroup, refCount); + } + + + /** + * This clearLive routine first calls the superclass's method, then + * it removes itself to the list of lights + */ + void clearLive(int refCount) { + super.clearLive(refCount); + + if (shaderProgram != null) { + shaderProgram.clearLive(refCount); + } + + if (shaderAttributeSet != null) { + shaderAttributeSet.clearLive(refCount); + } + } + + synchronized void addAMirrorUser(Shape3DRetained shape) { + + super.addAMirrorUser(shape); + if (shaderProgram != null) + shaderProgram.addAMirrorUser(shape); + if (shaderAttributeSet != null) + shaderAttributeSet.addAMirrorUser(shape); + } + + synchronized void removeAMirrorUser(Shape3DRetained shape) { + + super.removeAMirrorUser(shape); + if (shaderProgram != null) + shaderProgram.removeAMirrorUser(shape); + if (shaderAttributeSet != null) + shaderAttributeSet.removeAMirrorUser(shape); + } + + + final void sendMessage(int attrMask, Object attr) { + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.SHADER_APPEARANCE_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + + VirtualUniverse.mc.processMessage(createMessage); + + //System.err.println("univList.size is " + univList.size()); + for(int i=0; i + * There are two ways in which values can be specified for uniform + * attributes: explicitly, by providing a value; and implicitly, by + * defining a binding between a Java 3D system attribute and a uniform + * attribute. This functionality is provided by two subclasses of + * ShaderAttribute as follows: + * + *

    + *
  • ShaderAttributeObject, in which attributes are expressed as + * (attrName, value) pairs, is used for explicitly + * defined attributes
  • + *
  • ShaderAttributeBinding, in which attributes are expressed as + * (attrName, j3dAttrName) pairs, is used for + * implicitly defined, automatically tracked attributes
  • + *
+ * + * @see ShaderAttributeSet + * @see ShaderProgram + * + * @since Java 3D 1.4 + */ + +public abstract class ShaderAttribute extends NodeComponent { + /** + * Name of the shader attribute (immutable) + */ + + /** + * Package scope constructor + * + */ + ShaderAttribute(String attrName) { + if (attrName == null) { + throw new NullPointerException(); + } + + ((ShaderAttributeRetained)this.retained).initializeAttrName(attrName); + } + + /** + * Retrieves the name of this shader attribute. + * + * @return the name of this shader attribute + */ + public String getAttributeName() { + + return ((ShaderAttributeRetained)this.retained).getAttributeName(); + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeArray.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeArray.java new file mode 100644 index 0000000..600140e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeArray.java @@ -0,0 +1,166 @@ +/* + * $RCSfile: ShaderAttributeArray.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ShaderAttributeArray object encapsulates a uniform shader + * attribute whose value is specified explicitly. The shader variable + * attrName is explicitly set to the specified + * value during rendering. attrName must be + * the name of a valid uniform attribute in the shader in which it is + * used. Otherwise, the attribute name will be ignored and a runtime + * error may be generated. The value must be an array + * of one of the allowed classes. The allowed classes are: + * Integer[], Float[], + * Tuple{2,3,4}{i,f}[], Matrix{3,4}f[]. A + * ClassCastException will be thrown if a specified value + * object is not one of the allowed types. Further, the type and length of the + * value is immutable once a ShaderAttributeArray is constructed. + * Subsequent setValue operations must be called with an array of the + * same type and length as the one that was used to construct the + * ShaderAttributeArray. Finally, the type of the value + * object must match the type of the corresponding + * attrName variable in the shader in which it is + * used. Otherwise, the shader will not be able to use the attribute + * and a runtime error may be generated. + * + * @see ShaderAttributeSet + * @see ShaderProgram + * + * @since Java 3D 1.4 + */ + +public class ShaderAttributeArray extends ShaderAttributeObject { + /** + * Constructs a new ShaderAttributeArray object with the specified + * (attrName, value) pair. The specified value + * must be an array of one of the allowed class types. + * A deep copy of the array is stored. + * + * @param attrName the name of the shader attribute + * @param value the value of the shader attribute + * + * @exception NullPointerException if attrName or value is null + * + * @exception ClassCastException if value is not an array of + * one of the allowed classes + */ + public ShaderAttributeArray(String attrName, Object value) { + super(attrName, value); + } + + // Implement abstract getValue method + public Object getValue() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VALUE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeObject0")); + + return ((ShaderAttributeArrayRetained)this.retained).getValue(); + } + + // Implement abstract setValue method + public void setValue(Object value) { + if (value == null) { + throw new NullPointerException(); + } + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VALUE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeObject1")); + + if (isLive()) + ((ShaderAttributeArrayRetained)this.retained).setValue(value); + else + ((ShaderAttributeArrayRetained)this.retained).initValue(value); + + } + + + /** + * Sets the specified array element of the value of this shader + * attribute to the specified value. + * A copy of the object is stored. + * + * @param value the new value of the shader attribute + * + * @exception NullPointerException if value is null + * + * @exception ClassCastException if value is not an instance of + * the same base class as the individual elements of the array object + * used to construct this shader attribute object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setValue(int index, Object value) { + if (value == null) { + throw new NullPointerException(); + } + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VALUE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeObject1")); + + if (isLive()) + ((ShaderAttributeArrayRetained)this.retained).setValue(index, value); + else { + ((ShaderAttributeArrayRetained)this.retained).initValue(index, value); + } + } + + /** + * Returns the number of elements in the value array. + * + * @return the number of elements in the value array + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int length() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VALUE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeObject0")); + + return ((ShaderAttributeArrayRetained)this.retained).length(); + } + + /** + * Creates a retained mode ShaderAttributeArrayRetained object that this + * ShaderAttributeArray component object will point to. + */ + void createRetained() { + this.retained = new ShaderAttributeArrayRetained(); + this.retained.setSource(this); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeArrayRetained.java new file mode 100644 index 0000000..bde466c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeArrayRetained.java @@ -0,0 +1,1005 @@ +/* + * $RCSfile: ShaderAttributeArrayRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ShaderAttributeArray object encapsulates a uniform shader + * attribute whose value is specified explicitly. + */ + +class ShaderAttributeArrayRetained extends ShaderAttributeObjectRetained { + + ShaderAttributeArrayRetained() { + } + + void initValue(int index, Object value) { + /* + System.err.println("ShaderAttributeObjectRetained : attrName = " + attrName + + ", index = " + index + ", value = " + value + + ", value.class = " + value.getClass()); + */ + ((ArrayWrapper)attrWrapper).set(index, value); + + } + + + /** + * Sets the specified array element of the value of this shader + * attribute to the specified value. + * A copy of the object is stored. + * + * @param value the new value of the shader attribute + * + * @exception NullPointerException if value is null + * + * @exception ClassCastException if value is not an instance of + * the same base class as the individual elements of the array object + * used to construct this shader attribute object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + void setValue(int index, Object value) { + initValue(index, value); + // We should only need to update the array instead of replacing it. + // Until this become a really bottleneck, it will just be a convenience + // method for end user. + // An efficient approach is to + // (1) Create a new ShaderAttributeValue object for the "value" object + // and pass it to sendMessage(), (2) Create a new sendMessage that take in + // a third arguement, ie. index. + setValue(attrWrapper.getRef()); + } + + /** + * Returns the number of elements in the value array. + * + * @return the number of elements in the value array + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + int length() { + return ((ArrayWrapper)attrWrapper).length(); + + } + + // Helper methods ... + + synchronized void createMirrorObject() { + // System.err.println("ShaderAttributeArrayRetained : createMirrorObject"); + // This method should only call by setLive(). + if (mirror == null) { + ShaderAttributeArrayRetained mirrorSAA = new ShaderAttributeArrayRetained(); + mirrorSAA.createObjectData(getValue()); + mirror = mirrorSAA; + mirror.source = source; + + } + initMirrorObject(); + } + + + /** + * Computes the base class from the specified object. A + * ClassCastException is thrown if the object is not an array of + * one of the allowed classes. + */ + int computeClassType(Object value) { + Class objClass = value.getClass(); + if (!objClass.isArray()) { + throw new ClassCastException(objClass + " -- must be array class"); + } + + for (int i = 0; i < classTable.length; i++) { + if (classTableArr[i].isInstance(value)) { + return i; + } + } + throw new ClassCastException(objClass + " -- unrecognized class"); + } + + /** + * Returns the base class represented by the specified class type. + */ + Class getBaseClass(int classType) { + return classTableArr[classType]; + } + + /** + * Creates an attribute wrapper object of the specified class + * type, and stores the specified array of objects. + */ + AttrWrapper createAttrWrapper(Object value, int classType) { + ArrayWrapper attrWrapper = null; + switch (classType) { + case TYPE_INTEGER: + attrWrapper = new IntegerArrayWrapper(); + break; + case TYPE_FLOAT: + attrWrapper = new FloatArrayWrapper(); + break; +// case TYPE_DOUBLE: +// attrWrapper = new DoubleArrayWrapper(); +// break; + case TYPE_TUPLE2I: + attrWrapper = new Tuple2iArrayWrapper(); + break; + case TYPE_TUPLE2F: + attrWrapper = new Tuple2fArrayWrapper(); + break; +// case TYPE_TUPLE2D: +// attrWrapper = new Tuple2dArrayWrapper(); +// break; + case TYPE_TUPLE3I: + attrWrapper = new Tuple3iArrayWrapper(); + break; + case TYPE_TUPLE3F: + attrWrapper = new Tuple3fArrayWrapper(); + break; +// case TYPE_TUPLE3D: +// attrWrapper = new Tuple3dArrayWrapper(); +// break; + case TYPE_TUPLE4I: + attrWrapper = new Tuple4iArrayWrapper(); + break; + case TYPE_TUPLE4F: + attrWrapper = new Tuple4fArrayWrapper(); + break; +// case TYPE_TUPLE4D: +// attrWrapper = new Tuple4dArrayWrapper(); +// break; + case TYPE_MATRIX3F: + attrWrapper = new Matrix3fArrayWrapper(); + break; +// case TYPE_MATRIX3D: +// attrWrapper = new Matrix3dArrayWrapper(); +// break; + case TYPE_MATRIX4F: + attrWrapper = new Matrix4fArrayWrapper(); + break; +// case TYPE_MATRIX4D: +// attrWrapper = new Matrix4dArrayWrapper(); +// break; + default: + // Should never get here + assert false; + return null; + } + + attrWrapper.set(value); + return attrWrapper; + } + + + // + // The following wrapper classes are used to store a copy of the + // user-specified shader attribute value. There is a wrapper class + // for each supported base class. + // + + // Base wrapper class for array attribute types + static abstract class ArrayWrapper extends AttrWrapper { + int length = 0; + + /** + * Returns the length of the array + */ + int length() { + return length; + } + + /** + * Sets the specified array element of the value of this + * shader attribute to the specified value. + */ + abstract void set(int index, Object value); + } + + // Wrapper class for Integer + static class IntegerArrayWrapper extends ArrayWrapper { + private int[] value = new int[0]; + + void set(Object value) { + Integer[] arr = (Integer[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new int[this.length]; + } + for (int i = 0; i < this.length; i++) { + this.value[i] = arr[i].intValue(); + } + } + + void set(int index, Object value) { + this.value[index] = ((Integer)value).intValue(); + } + + Object get() { + Integer[] arr = new Integer[this.length]; + for (int i = 0; i < this.length; i++) { + arr[i] = new Integer(this.value[i]); + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + // Wrapper class for Float + static class FloatArrayWrapper extends ArrayWrapper { + private float[] value = new float[0]; + + void set(Object value) { + Float[] arr = (Float[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new float[this.length]; + } + for (int i = 0; i < this.length; i++) { + this.value[i] = arr[i].floatValue(); + } + } + + void set(int index, Object value) { + this.value[index] = ((Float)value).floatValue(); + } + + Object get() { + Float[] arr = new Float[this.length]; + for (int i = 0; i < this.length; i++) { + arr[i] = new Float(this.value[i]); + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + /* + // Wrapper class for Double + static class DoubleArrayWrapper extends ArrayWrapper { + private double[] value = new double[0]; + + void set(Object value) { + Double[] arr = (Double[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new double[this.length]; + } + for (int i = 0; i < this.length; i++) { + this.value[i] = arr[i].doubleValue(); + } + } + + void set(int index, Object value) { + this.value[index] = ((Double)value).doubleValue(); + } + + Object get() { + Double[] arr = new Double[this.length]; + for (int i = 0; i < this.length; i++) { + arr[i] = new Double(this.value[i]); + } + return arr; + } + + Object getRef() { + return this.value; + } + } + */ + + // Wrapper class for Tuple2i + static class Tuple2iArrayWrapper extends ArrayWrapper { + private int[] value = new int[0]; + + void set(Object value) { + Tuple2i[] arr = (Tuple2i[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new int[this.length*2]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 2; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + } + } + + void set(int index, Object value) { + int j = index * 2; + this.value[j+0] = ((Tuple2i)value).x; + this.value[j+1] = ((Tuple2i)value).y; + } + + Object get() { + Tuple2i[] arr = new Tuple2i[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 2; + arr[i] = new Point2i(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + // Wrapper class for Tuple2f + static class Tuple2fArrayWrapper extends ArrayWrapper { + private float[] value = new float[0]; + + void set(Object value) { + Tuple2f[] arr = (Tuple2f[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new float[this.length*2]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 2; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + } + } + + void set(int index, Object value) { + int j = index * 2; + this.value[j+0] = ((Tuple2f)value).x; + this.value[j+1] = ((Tuple2f)value).y; + } + + Object get() { + Tuple2f[] arr = new Tuple2f[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 2; + arr[i] = new Point2f(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + /* + // Wrapper class for Tuple2d + static class Tuple2dArrayWrapper extends ArrayWrapper { + private double[] value = new double[0]; + + void set(Object value) { + Tuple2d[] arr = (Tuple2d[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new double[this.length*2]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 2; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + } + } + + void set(int index, Object value) { + int j = index * 2; + this.value[j+0] = ((Tuple2d)value).x; + this.value[j+1] = ((Tuple2d)value).y; + } + + Object get() { + Tuple2d[] arr = new Tuple2d[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 2; + arr[i] = new Point2d(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + */ + + // Wrapper class for Tuple3i + static class Tuple3iArrayWrapper extends ArrayWrapper { + private int[] value = new int[0]; + + void set(Object value) { + Tuple3i[] arr = (Tuple3i[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new int[this.length*3]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 3; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + this.value[j+2] = arr[i].z; + } + } + + void set(int index, Object value) { + int j = index * 3; + this.value[j+0] = ((Tuple3i)value).x; + this.value[j+1] = ((Tuple3i)value).y; + this.value[j+2] = ((Tuple3i)value).z; + } + + Object get() { + Tuple3i[] arr = new Tuple3i[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 3; + arr[i] = new Point3i(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + arr[i].z = this.value[j+2]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + // Wrapper class for Tuple3f + static class Tuple3fArrayWrapper extends ArrayWrapper { + private float[] value = new float[0]; + + void set(Object value) { + Tuple3f[] arr = (Tuple3f[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new float[this.length*3]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 3; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + this.value[j+2] = arr[i].z; + } + } + + void set(int index, Object value) { + int j = index * 3; + this.value[j+0] = ((Tuple3f)value).x; + this.value[j+1] = ((Tuple3f)value).y; + this.value[j+2] = ((Tuple3f)value).z; + } + + Object get() { + Tuple3f[] arr = new Tuple3f[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 3; + arr[i] = new Point3f(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + arr[i].z = this.value[j+2]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + /* + // Wrapper class for Tuple3d + static class Tuple3dArrayWrapper extends ArrayWrapper { + private double[] value = new double[0]; + + void set(Object value) { + Tuple3d[] arr = (Tuple3d[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new double[this.length*3]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 3; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + this.value[j+2] = arr[i].z; + } + } + + void set(int index, Object value) { + int j = index * 3; + this.value[j+0] = ((Tuple3d)value).x; + this.value[j+1] = ((Tuple3d)value).y; + this.value[j+2] = ((Tuple3d)value).z; + } + + Object get() { + Tuple3d[] arr = new Tuple3d[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 3; + arr[i] = new Point3d(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + arr[i].z = this.value[j+2]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + */ + + // Wrapper class for Tuple4i + static class Tuple4iArrayWrapper extends ArrayWrapper { + private int[] value = new int[0]; + + void set(Object value) { + Tuple4i[] arr = (Tuple4i[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new int[this.length*4]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 4; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + this.value[j+2] = arr[i].z; + this.value[j+3] = arr[i].w; + } + } + + void set(int index, Object value) { + int j = index * 4; + this.value[j+0] = ((Tuple4i)value).x; + this.value[j+1] = ((Tuple4i)value).y; + this.value[j+2] = ((Tuple4i)value).z; + this.value[j+3] = ((Tuple4i)value).w; + } + + Object get() { + Tuple4i[] arr = new Tuple4i[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 4; + arr[i] = new Point4i(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + arr[i].z = this.value[j+2]; + arr[i].w = this.value[j+3]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + // Wrapper class for Tuple4f + static class Tuple4fArrayWrapper extends ArrayWrapper { + private float[] value = new float[0]; + + void set(Object value) { + Tuple4f[] arr = (Tuple4f[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new float[this.length*4]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 4; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + this.value[j+2] = arr[i].z; + this.value[j+3] = arr[i].w; + } + } + + void set(int index, Object value) { + int j = index * 4; + this.value[j+0] = ((Tuple4f)value).x; + this.value[j+1] = ((Tuple4f)value).y; + this.value[j+2] = ((Tuple4f)value).z; + this.value[j+3] = ((Tuple4f)value).w; + } + + Object get() { + Tuple4f[] arr = new Tuple4f[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 4; + arr[i] = new Point4f(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + arr[i].z = this.value[j+2]; + arr[i].w = this.value[j+3]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + /* + // Wrapper class for Tuple4d + static class Tuple4dArrayWrapper extends ArrayWrapper { + private double[] value = new double[0]; + + void set(Object value) { + Tuple4d[] arr = (Tuple4d[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new double[this.length*4]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 4; + this.value[j+0] = arr[i].x; + this.value[j+1] = arr[i].y; + this.value[j+2] = arr[i].z; + this.value[j+3] = arr[i].w; + } + } + + void set(int index, Object value) { + int j = index * 4; + this.value[j+0] = ((Tuple4d)value).x; + this.value[j+1] = ((Tuple4d)value).y; + this.value[j+2] = ((Tuple4d)value).z; + this.value[j+3] = ((Tuple4d)value).w; + } + + Object get() { + Tuple4d[] arr = new Tuple4d[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 4; + arr[i] = new Point4d(); + arr[i].x = this.value[j+0]; + arr[i].y = this.value[j+1]; + arr[i].z = this.value[j+2]; + arr[i].w = this.value[j+3]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + */ + + // Wrapper class for Matrix3f + static class Matrix3fArrayWrapper extends ArrayWrapper { + private float[] value = new float[0]; + + void set(Object value) { + Matrix3f[] arr = (Matrix3f[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new float[this.length * 9]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 9; + this.value[j+0] = arr[i].m00; + this.value[j+1] = arr[i].m01; + this.value[j+2] = arr[i].m02; + this.value[j+3] = arr[i].m10; + this.value[j+4] = arr[i].m11; + this.value[j+5] = arr[i].m12; + this.value[j+6] = arr[i].m20; + this.value[j+7] = arr[i].m21; + this.value[j+8] = arr[i].m22; + } + } + + void set(int index, Object value) { + int j = index * 9; + Matrix3f m = (Matrix3f)value; + + this.value[j+0] = m.m00; + this.value[j+1] = m.m01; + this.value[j+2] = m.m02; + this.value[j+3] = m.m10; + this.value[j+4] = m.m11; + this.value[j+5] = m.m12; + this.value[j+6] = m.m20; + this.value[j+7] = m.m21; + this.value[j+8] = m.m22; + } + + Object get() { + Matrix3f[] arr = new Matrix3f[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 9; + arr[i] = new Matrix3f(); + arr[i].m00 = this.value[j+0]; + arr[i].m01 = this.value[j+1]; + arr[i].m02 = this.value[j+2]; + arr[i].m10 = this.value[j+3]; + arr[i].m11 = this.value[j+4]; + arr[i].m12 = this.value[j+5]; + arr[i].m20 = this.value[j+6]; + arr[i].m21 = this.value[j+7]; + arr[i].m22 = this.value[j+8]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + /* + // Wrapper class for Matrix3d + static class Matrix3dArrayWrapper extends ArrayWrapper { + private double[] value = new double[0]; + + void set(Object value) { + Matrix3d[] arr = (Matrix3d[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new double[this.length * 9]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 9; + this.value[j+0] = arr[i].m00; + this.value[j+1] = arr[i].m01; + this.value[j+2] = arr[i].m02; + this.value[j+3] = arr[i].m10; + this.value[j+4] = arr[i].m11; + this.value[j+5] = arr[i].m12; + this.value[j+6] = arr[i].m20; + this.value[j+7] = arr[i].m21; + this.value[j+8] = arr[i].m22; + } + } + + void set(int index, Object value) { + int j = index * 9; + Matrix3d m = (Matrix3d)value; + + this.value[j+0] = m.m00; + this.value[j+1] = m.m01; + this.value[j+2] = m.m02; + this.value[j+3] = m.m10; + this.value[j+4] = m.m11; + this.value[j+5] = m.m12; + this.value[j+6] = m.m20; + this.value[j+7] = m.m21; + this.value[j+8] = m.m22; + } + + Object get() { + Matrix3d[] arr = new Matrix3d[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 9; + arr[i] = new Matrix3d(); + arr[i].m00 = this.value[j+0]; + arr[i].m01 = this.value[j+1]; + arr[i].m02 = this.value[j+2]; + arr[i].m10 = this.value[j+3]; + arr[i].m11 = this.value[j+4]; + arr[i].m12 = this.value[j+5]; + arr[i].m20 = this.value[j+6]; + arr[i].m21 = this.value[j+7]; + arr[i].m22 = this.value[j+8]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + */ + + // Wrapper class for Matrix4f + static class Matrix4fArrayWrapper extends ArrayWrapper { + private float[] value = new float[0]; + + void set(Object value) { + Matrix4f[] arr = (Matrix4f[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new float[this.length * 16]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 16; + this.value[j+0] = arr[i].m00; + this.value[j+1] = arr[i].m01; + this.value[j+2] = arr[i].m02; + this.value[j+3] = arr[i].m03; + this.value[j+4] = arr[i].m10; + this.value[j+5] = arr[i].m11; + this.value[j+6] = arr[i].m12; + this.value[j+7] = arr[i].m13; + this.value[j+8] = arr[i].m20; + this.value[j+9] = arr[i].m21; + this.value[j+10] = arr[i].m22; + this.value[j+11] = arr[i].m23; + this.value[j+12] = arr[i].m30; + this.value[j+13] = arr[i].m31; + this.value[j+14] = arr[i].m32; + this.value[j+15] = arr[i].m33; + } + } + + void set(int index, Object value) { + int j = index * 16; + Matrix4f m = (Matrix4f)value; + + this.value[j+0] = m.m00; + this.value[j+1] = m.m01; + this.value[j+2] = m.m02; + this.value[j+3] = m.m03; + this.value[j+4] = m.m10; + this.value[j+5] = m.m11; + this.value[j+6] = m.m12; + this.value[j+7] = m.m13; + this.value[j+8] = m.m20; + this.value[j+9] = m.m21; + this.value[j+10] = m.m22; + this.value[j+11] = m.m23; + this.value[j+12] = m.m30; + this.value[j+13] = m.m31; + this.value[j+14] = m.m32; + this.value[j+15] = m.m33; + } + + Object get() { + Matrix4f[] arr = new Matrix4f[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 16; + arr[i] = new Matrix4f(); + arr[i].m00 = this.value[j+0]; + arr[i].m01 = this.value[j+1]; + arr[i].m02 = this.value[j+2]; + arr[i].m03 = this.value[j+3]; + arr[i].m10 = this.value[j+4]; + arr[i].m11 = this.value[j+5]; + arr[i].m12 = this.value[j+6]; + arr[i].m13 = this.value[j+7]; + arr[i].m20 = this.value[j+8]; + arr[i].m21 = this.value[j+9]; + arr[i].m22 = this.value[j+10]; + arr[i].m23 = this.value[j+11]; + arr[i].m30 = this.value[j+12]; + arr[i].m31 = this.value[j+13]; + arr[i].m32 = this.value[j+14]; + arr[i].m33 = this.value[j+15]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + + /* + // Wrapper class for Matrix4d + static class Matrix4dArrayWrapper extends ArrayWrapper { + private double[] value = new double[0]; + + void set(Object value) { + Matrix4d[] arr = (Matrix4d[])value; + if (this.length != arr.length) { + this.length = arr.length; + this.value = new double[this.length * 16]; + } + for (int i = 0; i < this.length; i++) { + int j = i * 16; + this.value[j+0] = arr[i].m00; + this.value[j+1] = arr[i].m01; + this.value[j+2] = arr[i].m02; + this.value[j+3] = arr[i].m03; + this.value[j+4] = arr[i].m10; + this.value[j+5] = arr[i].m11; + this.value[j+6] = arr[i].m12; + this.value[j+7] = arr[i].m13; + this.value[j+8] = arr[i].m20; + this.value[j+9] = arr[i].m21; + this.value[j+10] = arr[i].m22; + this.value[j+11] = arr[i].m23; + this.value[j+12] = arr[i].m30; + this.value[j+13] = arr[i].m31; + this.value[j+14] = arr[i].m32; + this.value[j+15] = arr[i].m33; + } + } + + void set(int index, Object value) { + int j = index * 16; + Matrix4d m = (Matrix4d)value; + + this.value[j+0] = m.m00; + this.value[j+1] = m.m01; + this.value[j+2] = m.m02; + this.value[j+3] = m.m03; + this.value[j+4] = m.m10; + this.value[j+5] = m.m11; + this.value[j+6] = m.m12; + this.value[j+7] = m.m13; + this.value[j+8] = m.m20; + this.value[j+9] = m.m21; + this.value[j+10] = m.m22; + this.value[j+11] = m.m23; + this.value[j+12] = m.m30; + this.value[j+13] = m.m31; + this.value[j+14] = m.m32; + this.value[j+15] = m.m33; + } + + Object get() { + Matrix4d[] arr = new Matrix4d[this.length]; + for (int i = 0; i < this.length; i++) { + int j = i * 16; + arr[i] = new Matrix4d(); + arr[i].m00 = this.value[j+0]; + arr[i].m01 = this.value[j+1]; + arr[i].m02 = this.value[j+2]; + arr[i].m03 = this.value[j+3]; + arr[i].m10 = this.value[j+4]; + arr[i].m11 = this.value[j+5]; + arr[i].m12 = this.value[j+6]; + arr[i].m13 = this.value[j+7]; + arr[i].m20 = this.value[j+8]; + arr[i].m21 = this.value[j+9]; + arr[i].m22 = this.value[j+10]; + arr[i].m23 = this.value[j+11]; + arr[i].m30 = this.value[j+12]; + arr[i].m31 = this.value[j+13]; + arr[i].m32 = this.value[j+14]; + arr[i].m33 = this.value[j+15]; + } + return arr; + } + + Object getRef() { + return this.value; + } + } + */ +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeBinding.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeBinding.java new file mode 100644 index 0000000..bffaea8 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeBinding.java @@ -0,0 +1,147 @@ +/* + * $RCSfile: ShaderAttributeBinding.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ShaderAttributeBinding object encapsulates a uniform attribute + * whose value is bound to a Java 3D system attribute. The + * shader variable attrName is implicitly set to the + * value of the corresponding Java 3D system attribute + * j3dAttrName during rendering. attrName + * must be the name of a valid uniform attribute in the shader in + * which it is used. Otherwise, the attribute name will be ignored and + * a runtime error may be generated. j3dAttrName must be + * the name of a predefined Java 3D system attribute. An + * IllegalArgumentException will be thrown if the specified + * j3dAttrName is not one of the predefined system + * attributes. Further, the type of the j3dAttrName + * attribute must match the type of the corresponding + * attrName variable in the shader in which it is + * used. Otherwise, the shader will not be able to use the attribute + * and a runtime error may be generated. + * + *

+ * Following is the list of predefined Java 3D system attributes:
+ * + *

    + * TODO: replace the following with + * the real system attributes table
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    NameTypeDescription
    somethingFloatThis is something (of course)
    somethingElseTuple3fThis is something else
    + *
+ * + *

+ * Depending on the shading language (and profile) being used, several + * Java 3D state attributes are automatically made available to the + * shader program as pre-defined uniform attributes. The application + * doesn't need to do anything to pass these attributes in to the + * shader program. The implementation of each shader language (e.g., + * Cg, GLSL) defines its own mapping from Java 3D attribute to uniform + * variable name. + * + *

+ * A list of these attributes for each shader language can be found in + * the concrete subclass of ShaderProgram for that shader language. + * + *

+ * NOTE: This class is not yet + * implemented.
+ * + * @see ShaderAttributeSet + * @see ShaderProgram + * + * @since Java 3D 1.4 + */ + +public class ShaderAttributeBinding extends ShaderAttribute { + + /** + * Constructs a new ShaderAttributeBinding from the specified + * (attrName, j3dAttrName) pair. + * + * @param attrName the name of the shader attribute to be added + * @param j3dAttrName the name of the Java 3D attribute + * to bind to the shader attribute + * + * @exception UnsupportedOperationException this class is not + * yet implemented + * + * @exception NullPointerException if attrName or j3dAttrName is null + * + * @exception IllegalArgumentException if j3dAttrName is not the name + * of a valid predefined Java 3D system attribute + */ + public ShaderAttributeBinding(String attrName, String j3dAttrName) { + super(attrName); + ((ShaderAttributeBindingRetained)this.retained).initJ3dAttrName(j3dAttrName); + // TODO: implement this class + throw new UnsupportedOperationException(J3dI18N.getString("ShaderAttributeBinding0")); + } + + /** + * Retrieves the name of the Java 3D system attribute that is bound to this + * shader attribute. + * + * @return the name of the Java 3D system attribute that is bound to this + * shader attribute + */ + public String getJ3DAttributeName() { + return ((ShaderAttributeBindingRetained)this.retained).getJ3DAttributeName(); + } + + /** + * Creates a retained mode ShaderAttributeBindingRetained object that this + * ShaderAttributeBinding component object will point to. + */ + void createRetained() { + this.retained = new ShaderAttributeBindingRetained(); + this.retained.setSource(this); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeBindingRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeBindingRetained.java new file mode 100644 index 0000000..003a46d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeBindingRetained.java @@ -0,0 +1,76 @@ +/* + * $RCSfile: ShaderAttributeBindingRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ShaderAttributeBinding object encapsulates a uniform attribute + * whose value is bound to a Java 3D system attribute. The + * shader variable attrName is implicitly set to the + * value of the corresponding Java 3D system attribute + * j3dAttrName during rendering. attrName + * must be the name of a valid uniform attribute in the shader in + * which it is used. Otherwise, the attribute name will be ignored and + * a runtime error may be generated. j3dAttrName must be + * the name of a predefined Java 3D system attribute. An + * IllegalArgumentException will be thrown if the specified + * j3dAttrName is not one of the predefined system + * attributes. Further, the type of the j3dAttrName + * attribute must match the type of the corresponding + * attrName variable in the shader in which it is + * used. Otherwise, the shader will not be able to use the attribute + * and a runtime error may be generated. + */ + +class ShaderAttributeBindingRetained extends ShaderAttributeRetained { + String j3dAttrName; + + ShaderAttributeBindingRetained() { + } + + void initJ3dAttrName(String j3dAttrName) { + this.j3dAttrName = j3dAttrName; + } + + /** + * Retrieves the name of the Java 3D system attribute that is bound to this + * shader attribute. + * + * @return the name of the Java 3D system attribute that is bound to this + * shader attribute + */ + String getJ3DAttributeName() { + return j3dAttrName; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeObject.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeObject.java new file mode 100644 index 0000000..aab6a6d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeObject.java @@ -0,0 +1,149 @@ +/* + * $RCSfile: ShaderAttributeObject.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ShaderAttributeObject class is an abstract class that + * encapsulates a uniform shader attribute whose value is specified + * explicitly. This class has concrete subclasses for single-value + * attributes (ShaderAttributeValue) and array attributes + * (ShaderAttributeArray). The shader variable attrName + * is explicitly set to the specified value during + * rendering. attrName must be the name of a valid + * uniform attribute in the shader in which it is used. Otherwise, the + * attribute name will be ignored and a runtime error may be + * generated. The value must be an instance of one of the + * allowed classes or an array of one the allowed classes. The allowed + * classes are: Integer, Float, + * Tuple{2,3,4}{i,f}, + * Matrix{3,4}f. A ClassCastException will be thrown + * if a specified value object is not one of the allowed + * types. Further, the type of the value is immutable once a + * ShaderAttributeObject is constructed. Subsequent setValue + * operations must be called with an object of the same type as the + * one that was used to construct the ShaderAttributeObject. Finally, + * the type of the value object must match the type of + * the corresponding attrName variable in the shader in + * which it is used. Otherwise, the shader will not be able to use the + * attribute and a runtime error may be generated. + * + * @see ShaderAttributeSet + * @see ShaderProgram + * + * @since Java 3D 1.4 + */ + +public abstract class ShaderAttributeObject extends ShaderAttribute { + + /** + * Specifies that this ShaderAttributeObject allows reading its value. + */ + public static final int + ALLOW_VALUE_READ = + CapabilityBits.SHADER_ATTRIBUTE_OBJECT_ALLOW_VALUE_READ; + + /** + * Specifies that this ShaderAttributeObject allows writing its value. + */ + public static final int + ALLOW_VALUE_WRITE = + CapabilityBits.SHADER_ATTRIBUTE_OBJECT_ALLOW_VALUE_WRITE; + + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_VALUE_READ + }; + + + /** + * Package scope constructor + */ + ShaderAttributeObject(String attrName, Object value) { + super(attrName); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((ShaderAttributeObjectRetained)this.retained).createObjectData(value); + } + + + /** + * Retrieves the value of this shader attribute. + * A copy of the object is returned. + * + * @return a copy of the value of this shader attribute + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public abstract Object getValue(); + + /** + * Sets the value of this shader attribute to the specified value. + * A copy of the object is stored. + * + * @param value the new value of the shader attribute + * + * @exception NullPointerException if value is null + * + * @exception ClassCastException if value is not an instance of + * the same base class as the object used to construct this shader + * attribute object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public abstract void setValue(Object value); + + /** + * Retrieves the base class of the value of this shader attribute. + * This class will always be one of the allowable classes, even if + * a subclass was used to construct this shader attribute object. + * For example, if this shader attribute object was constructed + * with an instance of javax.vecmath.Point3f, the + * returned class would be javax.vecmath.Tuple3f. + * + * @return the base class of the value of this shader attribute + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Class getValueClass() { + + return ((ShaderAttributeObjectRetained)this.retained).getValueClass(); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeObjectRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeObjectRetained.java new file mode 100644 index 0000000..ceb0cdf --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeObjectRetained.java @@ -0,0 +1,325 @@ +/* + * $RCSfile: ShaderAttributeObjectRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; +import javax.vecmath.*; + +/** + * The ShaderAttributeObjectRetained class is an abstract class that + * encapsulates a uniform shader attribute whose value is specified + * explicitly. + */ + +abstract class ShaderAttributeObjectRetained extends ShaderAttributeRetained { + + private int classType; + private Class baseClass; + AttrWrapper attrWrapper; + + /** + * Package scope constructor + */ + ShaderAttributeObjectRetained() { + } + + void createObjectData(Object value) { + + classType = computeClassType(value); + baseClass = getBaseClass(classType); + attrWrapper = createAttrWrapper(value, classType); + /* + System.err.println(" classType = " + classType + + ", baseClass = " + baseClass + + ", attrWrapper.get() = " + attrWrapper.get()); + */ + } + + + void initValue(Object value) { + /* + System.err.println("ShaderAttributeObjectRetained : attrName = " + attrName + + ", value = " + value + + ", value.class = " + value.getClass()); + */ + attrWrapper.set(value); + + } + + /** + * Retrieves the value of this shader attribute. + * A copy of the object is returned. + */ + Object getValue() { + return attrWrapper.get(); + } + + /** + * Sets the value of this shader attribute to the specified value. + * A copy of the object is stored. + * + * @param value the new value of the shader attribute + * + * @exception NullPointerException if value is null + * + * @exception ClassCastException if value is not an instance of + * the same base class as the object used to construct this shader + * attribute object. + * + */ + void setValue(Object value) { + initValue(value); + AttrWrapper valueWrapper = createAttrWrapper(value, this.classType); + sendMessage(ShaderConstants.ATTRIBUTE_VALUE_UPDATE, valueWrapper); + } + + /** + * Retrieves the base class of the value of this shader attribute. + * This class will always be one of the allowable classes, even if + * a subclass was used to construct this shader attribute object. + * For example, if this shader attribute object was constructed + * with an instance of javax.vecmath.Point3f, the + * returned class would be javax.vecmath.Tuple3f. + * + * @return the base class of the value of this shader attribute + */ + Class getValueClass() { + return baseClass; + } + + /** + * Initializes a mirror object. + */ + synchronized void initMirrorObject() { + super.initMirrorObject(); + ((ShaderAttributeObjectRetained)mirror).initValue(getValue()); + } + + /** + * Update the "component" field of the mirror object with the given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + //System.err.println("ShaderAttributeObjectRetained : updateMirrorObject"); + ShaderAttributeObjectRetained mirrorSAV = (ShaderAttributeObjectRetained)mirror; + if ((component & ShaderConstants.ATTRIBUTE_VALUE_UPDATE) != 0) { + //System.err.println(" -- SHADER_ATTRIBUTE_VALUE_UPDATE"); + mirrorSAV.attrWrapper = (AttrWrapper) value; + } + } + + final void sendMessage(int attrMask, Object attr) { + + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.SHADER_ATTRIBUTE_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + // System.err.println("changedFreqent1 = "+changedFrequent); + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; iinfreq change only for non-live node components + changedFrequent &= ~mask; + } + } + + void handleFrequencyChange(int bit) { + if (bit == ShaderAttributeObject.ALLOW_VALUE_WRITE) { + setFrequencyChangeMask(bit, 0x1); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeRetained.java new file mode 100644 index 0000000..98a4840 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeRetained.java @@ -0,0 +1,71 @@ +/* + * $RCSfile: ShaderAttributeRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ShaderAttributeRetained object encapsulates a uniform attribute for a + * shader programs. + */ + +abstract class ShaderAttributeRetained extends NodeComponentRetained { + + /** + * Name of the shader attribute (immutable) + */ + String attrName; + + /** + * Package scope constructor + */ + ShaderAttributeRetained() { + } + + void initializeAttrName(String attrName) { + this.attrName = attrName; + } + + /** + * Retrieves the name of this shader attribute. + * + * @return the name of this shader attribute + */ + String getAttributeName() { + return attrName; + } + + void initMirrorObject() { + ((ShaderAttributeObjectRetained)mirror).initializeAttrName(this.attrName); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeSet.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeSet.java new file mode 100644 index 0000000..574f5a1 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeSet.java @@ -0,0 +1,282 @@ +/* + * $RCSfile: ShaderAttributeSet.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; +import javax.vecmath.*; + +/** + * The ShaderAttributeSet object provides uniform attributes to shader + * programs. Uniform attributes (variables) are those attributes whose + * values are constant during the rendering of a primitive. Their + * values may change from primitive to primitive, but are constant for + * each vertex (for vertex shaders) or fragment (for fragment shaders) + * of a single primitive. Examples of uniform attributes include a + * transformation matrix, a texture map, lights, lookup tables, etc. + * The ShaderAttributeSet object contains a set of ShaderAttribute + * objects. Each ShaderAttribute object defines the value of a single + * uniform shader variable. The set of attributes is unique with respect + * to attribute names: no two attributes in the set will have the same + * name. + * + *

+ * There are two ways in which values can be specified for uniform + * attributes: explicitly, by providing a value; and implicitly, by + * defining a binding between a Java 3D system attribute and a uniform + * attribute. This functionality is provided by two subclasses of + * ShaderAttribute: ShaderAttributeObject, which is used to specify + * explicitly defined attributes; and ShaderAttributeBinding, which is + * used to specify implicitly defined, automatically tracked attributes. + * + *

+ * Depending on the shading language (and profile) being used, several + * Java 3D state attributes are automatically made available to the + * shader program as pre-defined uniform attributes. The application + * doesn't need to do anything to pass these attributes in to the + * shader program. The implementation of each shader language (e.g., + * Cg, GLSL) defines its own bindings from Java 3D attribute to uniform + * variable name. A list of these attributes for each shader language + * can be found in the concrete subclass of ShaderProgram for that + * shader language. + * + * @see ShaderAttribute + * @see ShaderProgram + * @see ShaderAppearance#setShaderAttributeSet + * + * @since Java 3D 1.4 + */ + +public class ShaderAttributeSet extends NodeComponent { + + /** + * Specifies that this ShaderAttributeSet object allows reading + * its attributes. + */ + public static final int + ALLOW_ATTRIBUTES_READ = + CapabilityBits.SHADER_ATTRIBUTE_SET_ALLOW_ATTRIBUTES_READ; + + /** + * Specifies that this ShaderAttributeSet object allows writing + * its attributes. + */ + public static final int + ALLOW_ATTRIBUTES_WRITE = + CapabilityBits.SHADER_ATTRIBUTE_SET_ALLOW_ATTRIBUTES_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_ATTRIBUTES_READ + }; + + /** + * Constructs an empty ShaderAttributeSet object. The attributes set + * is initially empty. + */ + public ShaderAttributeSet() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + // + // Methods for dealing with the (name, value) pairs for explicit + // attributes + // + + /** + * Adds the specified shader attribute to the attributes set. + * The newly specified attribute replaces an attribute with the + * same name, if one already exists in the attributes set. + * + * @param attr the shader attribute to be added to the set + * + * @exception NullPointerException if attr is null + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void put(ShaderAttribute attr) { + if (attr == null) { + throw new NullPointerException(); + } + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeSet1")); + + ((ShaderAttributeSetRetained)this.retained).put(attr); + + } + + /** + * Retrieves the shader attribute with the specified + * attrName from the attributes set. If attrName does + * not exist in the attributes set, null is returned. + * + * @param attrName the name of the shader attribute to be retrieved + * + * @exception NullPointerException if attrName is null + * + * @return a the shader attribute associated with the specified + * attribute name, or null if the name is not in the attributes + * set + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ShaderAttribute get(String attrName) { + + if (attrName == null) { + throw new NullPointerException(); + } + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeSet0")); + + return ((ShaderAttributeSetRetained)this.retained).get(attrName); + } + + /** + * Removes the shader attribute with the specified + * attrName from the attributes set. If attrName does + * not exist in the attributes set then nothing happens. + * + * @param attrName the name of the shader attribute to be removed + * + * @exception NullPointerException if attrName is null + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void remove(String attrName) { + if (attrName == null) { + throw new NullPointerException(); + } + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeSet1")); + + ((ShaderAttributeSetRetained)this.retained).remove(attrName); + } + + /** + * Removes the specified shader attribute from the attributes + * set. If the attribute does not exist in the attributes set then + * nothing happens. Note that this method will not remove a + * shader object other than the one specified, even if it has the + * same name as the specified attribute. Applications that wish to + * remove an attribute by name should use + * removeAttribute(String). + * + * @param attr the shader attribute to be removed + * + * @exception NullPointerException if attr is null + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void remove(ShaderAttribute attr) { + if (attr == null) { + throw new NullPointerException(); + } + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeSet1")); + + ((ShaderAttributeSetRetained)this.retained).remove(attr); + } + + /** + * Removes all shader attributes from the attributes set. The + * attributes set will be empty following this call. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void clear() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeSet1")); + + ((ShaderAttributeSetRetained)this.retained).clear(); + } + + /** + * Returns a shallow copy of the attributes set. + * + * @return a shallow copy of the attributes set + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ShaderAttribute[] getAll() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeSet0")); + + return ((ShaderAttributeSetRetained)this.retained).getAll(); + } + + /** + * Returns the number of elements in the attributes set. + * + * @return the number of elements in the attributes set + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int size() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeSet0")); + + return ((ShaderAttributeSetRetained)this.retained).size(); + } + + /** + * Creates a retained mode ShaderAttributeSetRetained object that this + * ShaderAttributeSet component object will point to. + */ + void createRetained() { + // System.err.println("ShaderAttributeSet : createRetained() ..."); + this.retained = new ShaderAttributeSetRetained(); + this.retained.setSource(this); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeSetRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeSetRetained.java new file mode 100644 index 0000000..f7ec64e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeSetRetained.java @@ -0,0 +1,386 @@ +/* + * $RCSfile: ShaderAttributeSetRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:29 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; +import javax.vecmath.*; + +/** + * The ShaderAttributeSet object provides uniform attributes to shader + * programs. + */ + +class ShaderAttributeSetRetained extends NodeComponentRetained { + + private Map attrs = new HashMap(); + + // Lock used for synchronization of live state + Object liveStateLock = new Object(); + + /** + * Constructs an empty ShaderAttributeSetretained object. The attributes set + * is initially empty. + */ + ShaderAttributeSetRetained() { + } + + // + // Methods for dealing with the (name, value) pairs for explicit + // attributes + // + + /** + * Adds the specified shader attribute to the attributes set. + * The newly specified attribute replaces an attribute with the + * same name, if one already exists in the attributes set. + * + * @param attr the shader attribute to be added to the set + * + */ + void put(ShaderAttribute attr) { + synchronized(liveStateLock) { + // System.err.println("ShaderAttributeSetRetained : put()"); + ShaderAttributeRetained sAttr = (ShaderAttributeRetained)attr.retained; + // System.err.println("attr is " + attr ); + // System.err.println("attrName is " + sAttr.attrName + " attr.Retained is "+ sAttr ); + assert(sAttr != null); + attrs.put(sAttr.attrName, sAttr); + + if (source.isLive()) { + sAttr.setLive(inBackgroundGroup, refCount); + sAttr.copyMirrorUsers(this); + + sendMessage(ShaderConstants.ATTRIBUTE_SET_PUT, sAttr.mirror); + } + } + } + + /** + * Retrieves the shader attribute with the specified + * attrName from the attributes set. If attrName does + * not exist in the attributes set, null is returned. + * + * @param attrName the name of the shader attribute to be retrieved + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + ShaderAttribute get(String attrName) { + return (ShaderAttribute)((ShaderAttributeRetained)attrs.get(attrName)).source; + } + + /** + * Removes the shader attribute with the specified + * attrName from the attributes set. If attrName does + * not exist in the attributes set then nothing happens. + * + * @param attrName the name of the shader attribute to be removed + */ + void remove(String attrName) { + synchronized(liveStateLock) { + ShaderAttributeRetained sAttr = (ShaderAttributeRetained)attrs.get(attrName); + attrs.remove(attrName); + if (source.isLive()) { + sAttr.clearLive(refCount); + sAttr.removeMirrorUsers(this); + + sendMessage(ShaderConstants.ATTRIBUTE_SET_REMOVE, attrName); + } + } + } + + /** + * Removes the specified shader attribute from the attributes + * set. If the attribute does not exist in the attributes set then + * nothing happens. Note that this method will not remove a + * shader object other than the one specified, even if it has the + * same name as the specified attribute. Applications that wish to + * remove an attribute by name should use + * removeAttribute(String). + * + * @param attr the shader attribute to be removed + */ + void remove(ShaderAttribute attr) { + synchronized(liveStateLock) { + String attrName = attr.getAttributeName(); + if (attrs.get(attrName) == attr) { + attrs.remove(attrName); + if (source.isLive()) { + ((ShaderAttributeRetained)attr.retained).clearLive(refCount); + ((ShaderAttributeRetained)attr.retained).removeMirrorUsers(this); + + sendMessage(ShaderConstants.ATTRIBUTE_SET_REMOVE, attrName); + } + } + } + } + + /** + * Removes all shader attributes from the attributes set. The + * attributes set will be empty following this call. + * + */ + void clear() { + synchronized(liveStateLock) { + attrs.clear(); + if(source.isLive()) { + ShaderAttributeRetained[] sAttrs = new ShaderAttributeRetained[attrs.size()]; + sAttrs = (ShaderAttributeRetained[])attrs.values().toArray(sAttrs); + for (int i = 0; i < sAttrs.length; i++) { + sAttrs[i].clearLive(refCount); + sAttrs[i].removeMirrorUsers(this); + } + sendMessage(ShaderConstants.ATTRIBUTE_SET_CLEAR, null); + } + } + } + + /** + * Returns a shallow copy of the attributes set. + * + * @return a shallow copy of the attributes set + * + */ + ShaderAttribute[] getAll() { + + ShaderAttributeRetained[] sAttrsRetained = new ShaderAttributeRetained[attrs.size()]; + ShaderAttribute[] sAttrs = new ShaderAttribute[sAttrsRetained.length]; + sAttrsRetained = (ShaderAttributeRetained[])attrs.values().toArray(sAttrsRetained); + for(int i=0; i < sAttrsRetained.length; i++) { + sAttrs[i] = (ShaderAttribute) sAttrsRetained[i].source; + } + + return sAttrs; + } + + /** + * Returns the number of elements in the attributes set. + * + * @return the number of elements in the attributes set + * + */ + int size() { + return attrs.size(); + } + + + void updateNative(Canvas3D cv, ShaderProgramRetained shaderProgram) { + shaderProgram.setShaderAttributes(cv, this); + } + + Map getAttrs() { + return attrs; + } + + + void setLive(boolean backgroundGroup, int refCount) { + + // System.err.println("ShaderAttributeSetRetained.setLive()"); + ShaderAttributeRetained[] sAttrsRetained = new ShaderAttributeRetained[attrs.size()]; + sAttrsRetained = (ShaderAttributeRetained[])attrs.values().toArray(sAttrsRetained); + for(int i=0; i < sAttrsRetained.length; i++) { + sAttrsRetained[i].setLive(backgroundGroup, refCount); + } + + super.doSetLive(backgroundGroup, refCount); + super.markAsLive(); + } + + synchronized void addAMirrorUser(Shape3DRetained shape) { + + super.addAMirrorUser(shape); + + ShaderAttributeRetained[] sAttrsRetained = new ShaderAttributeRetained[attrs.size()]; + sAttrsRetained = (ShaderAttributeRetained[])attrs.values().toArray(sAttrsRetained); + for(int i=0; i < sAttrsRetained.length; i++) { + sAttrsRetained[i].addAMirrorUser(shape); + } + } + + synchronized void removeAMirrorUser(Shape3DRetained shape) { + super.removeAMirrorUser(shape); + + ShaderAttributeRetained[] sAttrsRetained = new ShaderAttributeRetained[attrs.size()]; + sAttrsRetained = (ShaderAttributeRetained[])attrs.values().toArray(sAttrsRetained); + for(int i=0; i < sAttrsRetained.length; i++) { + sAttrsRetained[i].removeAMirrorUser(shape); + } + } + + + synchronized void removeMirrorUsers(NodeComponentRetained node) { + super.removeMirrorUsers(node); + + ShaderAttributeRetained[] sAttrsRetained = new ShaderAttributeRetained[attrs.size()]; + sAttrsRetained = (ShaderAttributeRetained[])attrs.values().toArray(sAttrsRetained); + for(int i=0; i < sAttrsRetained.length; i++) { + sAttrsRetained[i].removeMirrorUsers(node); + } + } + + synchronized void copyMirrorUsers(NodeComponentRetained node) { + super.copyMirrorUsers(node); + + ShaderAttributeRetained[] sAttrsRetained = new ShaderAttributeRetained[attrs.size()]; + sAttrsRetained = (ShaderAttributeRetained[])attrs.values().toArray(sAttrsRetained); + for(int i=0; i < sAttrsRetained.length; i++) { + sAttrsRetained[i].copyMirrorUsers(node); + } + } + + void clearLive(int refCount) { + // System.err.println("ShaderAttributeSetRetained.clearLive()"); + + super.clearLive(refCount); + + ShaderAttributeRetained[] sAttrsRetained = new ShaderAttributeRetained[attrs.size()]; + sAttrsRetained = (ShaderAttributeRetained[])attrs.values().toArray(sAttrsRetained); + for(int i=0; i < sAttrsRetained.length; i++) { + sAttrsRetained[i].clearLive(refCount); + } + } + + synchronized void createMirrorObject() { + // System.err.println("ShaderAttributeSetRetained : createMirrorObject"); + // This method should only call by setLive(). + if (mirror == null) { + ShaderAttributeSetRetained mirrorSAS = new ShaderAttributeSetRetained(); + mirror = mirrorSAS; + mirror.source = source; + + } + initMirrorObject(); + } + + void initMirrorObject() { + + ShaderAttributeRetained[] sAttrs = new ShaderAttributeRetained[attrs.size()]; + sAttrs = (ShaderAttributeRetained[])attrs.values().toArray(sAttrs); + // Need to copy the mirror attrs + for (int i = 0; i < sAttrs.length; i++) { + ShaderAttributeRetained mirrorSA = (ShaderAttributeRetained) sAttrs[i].mirror; + assert(mirrorSA != null); + ((ShaderAttributeSetRetained)mirror).attrs.put(mirrorSA.attrName, mirrorSA); + } + } + + /** + * Update the "component" field of the mirror object with the given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + // System.err.println("ShaderAttributeSetRetained : updateMirrorObject"); + + ShaderAttributeSetRetained mirrorSAS = (ShaderAttributeSetRetained)mirror; + + if ((component & ShaderConstants.ATTRIBUTE_SET_PUT) != 0) { + // System.err.println(" -- ATTRIBUTE_SET_PUT"); + ShaderAttributeRetained mirrorSA = (ShaderAttributeRetained)value; + assert(mirrorSA != null); + ((ShaderAttributeSetRetained)mirror).attrs.put(mirrorSA.attrName, mirrorSA); + } + else if((component & ShaderConstants.ATTRIBUTE_SET_REMOVE) != 0) { + // System.err.println(" -- ATTRIBUTE_SET_REMOVE"); + ((ShaderAttributeSetRetained)mirror).attrs.remove((String)value); + } + else if((component & ShaderConstants.ATTRIBUTE_SET_CLEAR) != 0) { + // System.err.println(" -- ATTRIBUTE_SET_CLEAR"); + ((ShaderAttributeSetRetained)mirror).attrs.clear(); + } + else { + assert(false); + } + } + + final void sendMessage(int attrMask, Object attr) { + + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.SHADER_ATTRIBUTE_SET_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + // System.err.println("changedFreqent1 = "+changedFrequent); + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; iinfreq change only for non-live node components + changedFrequent &= ~mask; + } + } + + void handleFrequencyChange(int bit) { + if (bit == ShaderAttributeSet.ALLOW_ATTRIBUTES_WRITE) { + setFrequencyChangeMask(bit, 0x1); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeValue.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeValue.java new file mode 100644 index 0000000..535d8e1 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeValue.java @@ -0,0 +1,119 @@ +/* + * $RCSfile: ShaderAttributeValue.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ShaderAttributeValue object encapsulates a uniform shader + * attribute whose value is specified explicitly. The shader variable + * attrName is explicitly set to the specified + * value during rendering. attrName must be + * the name of a valid uniform attribute in the shader in which it is + * used. Otherwise, the attribute name will be ignored and a runtime + * error may be generated. The value must be an instance + * of one of the allowed classes. The allowed classes are: + * Integer, Float, + * Tuple{2,3,4}{i,f}, Matrix{3,4}f. A + * ClassCastException will be thrown if a specified value + * object is not one of the allowed types. Further, the type of the + * value is immutable once a ShaderAttributeValue is constructed. + * Subsequent setValue operations must be called with an object of the + * same type as the one that was used to construct the + * ShaderAttributeValue. Finally, the type of the value + * object must match the type of the corresponding + * attrName variable in the shader in which it is + * used. Otherwise, the shader will not be able to use the attribute + * and a runtime error may be generated. + * + * @see ShaderAttributeSet + * @see ShaderProgram + * + * @since Java 3D 1.4 + */ + +public class ShaderAttributeValue extends ShaderAttributeObject { + /** + * Constructs a new ShaderAttributeValue object with the specified + * (attrName, value) pair. + * A copy of the object is stored. + * + * @param attrName the name of the shader attribute + * @param value the value of the shader attribute + * + * @exception NullPointerException if attrName or value is null + * + * @exception ClassCastException if value is not an instance of + * one of the allowed classes + */ + public ShaderAttributeValue(String attrName, Object value) { + super(attrName, value); + } + + // Implement abstract getValue method + public Object getValue() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VALUE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeObject0")); + + return ((ShaderAttributeValueRetained)this.retained).getValue(); + } + + // Implement abstract setValue method + public void setValue(Object value) { + + if (value == null) { + throw new NullPointerException(); + } + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VALUE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ShaderAttributeObject1")); + + if (isLive()) + ((ShaderAttributeValueRetained)this.retained).setValue(value); + else + ((ShaderAttributeValueRetained)this.retained).initValue(value); + + } + + /** + * Creates a retained mode ShaderAttributeValueRetained object that this + * ShaderAttributeValue component object will point to. + */ + void createRetained() { + this.retained = new ShaderAttributeValueRetained(); + this.retained.setSource(this); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeValueRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeValueRetained.java new file mode 100644 index 0000000..4173d91 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderAttributeValueRetained.java @@ -0,0 +1,495 @@ +/* + * $RCSfile: ShaderAttributeValueRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ShaderAttributeValueRetained object encapsulates a uniform shader + * attribute whose value is specified explicitly. + */ + +class ShaderAttributeValueRetained extends ShaderAttributeObjectRetained { + + ShaderAttributeValueRetained() { + } + + synchronized void createMirrorObject() { + // System.err.println("ShaderAttributeValueRetained : createMirrorObject"); + // This method should only call by setLive(). + if (mirror == null) { + ShaderAttributeValueRetained mirrorSAV = new ShaderAttributeValueRetained(); + mirrorSAV.createObjectData(getValue()); + mirror = mirrorSAV; + mirror.source = source; + + } + initMirrorObject(); + } + + /** + * Computes the base class from the specified object. A + * ClassCastException is thrown if the object is not an instance + * of one of the allowed classes. + */ + int computeClassType(Object value) { + Class objClass = value.getClass(); + if (objClass.isArray()) { + throw new ClassCastException(objClass + " -- array class not allowed"); + } + + for (int i = 0; i < classTable.length; i++) { + if (classTable[i].isInstance(value)) { + return i; + } + } + throw new ClassCastException(objClass + " -- unrecognized class"); + } + + /** + * Returns the base class represented by the specified class type. + */ + Class getBaseClass(int classType) { + return classTable[classType]; + } + + /** + * Creates an attribute wrapper object of the specified class + * type, and stores the specified object. + */ + AttrWrapper createAttrWrapper(Object value, int classType) { + ValueWrapper attrWrapper = null; + switch (classType) { + case TYPE_INTEGER: + attrWrapper = new IntegerWrapper(); + break; + case TYPE_FLOAT: + attrWrapper = new FloatWrapper(); + break; +// case TYPE_DOUBLE: +// attrWrapper = new DoubleWrapper(); +// break; + case TYPE_TUPLE2I: + attrWrapper = new Tuple2iWrapper(); + break; + case TYPE_TUPLE2F: + attrWrapper = new Tuple2fWrapper(); + break; +// case TYPE_TUPLE2D: +// attrWrapper = new Tuple2dWrapper(); +// break; + case TYPE_TUPLE3I: + attrWrapper = new Tuple3iWrapper(); + break; + case TYPE_TUPLE3F: + attrWrapper = new Tuple3fWrapper(); + break; +// case TYPE_TUPLE3D: +// attrWrapper = new Tuple3dWrapper(); +// break; + case TYPE_TUPLE4I: + attrWrapper = new Tuple4iWrapper(); + break; + case TYPE_TUPLE4F: + attrWrapper = new Tuple4fWrapper(); + break; +// case TYPE_TUPLE4D: +// attrWrapper = new Tuple4dWrapper(); +// break; + case TYPE_MATRIX3F: + attrWrapper = new Matrix3fWrapper(); + break; +// case TYPE_MATRIX3D: +// attrWrapper = new Matrix3dWrapper(); +// break; + case TYPE_MATRIX4F: + attrWrapper = new Matrix4fWrapper(); + break; +// case TYPE_MATRIX4D: +// attrWrapper = new Matrix4dWrapper(); +// break; + default: + // Should never get here + assert false; + return null; + } + + attrWrapper.set(value); + return attrWrapper; + } + + // + // The following wrapper classes are used to store a copy of the + // user-specified shader attribute value. There is a wrapper class + // for each supported base class. + // + + // Base wrapper class for non-array attribute types + static abstract class ValueWrapper extends AttrWrapper { + // No additional fields or methods are defined in this class + } + + // Wrapper class for Integer + static class IntegerWrapper extends ValueWrapper { + private int[] value = new int[1]; + + void set(Object value) { + this.value[0] = ((Integer)value).intValue(); + } + + Object get() { + return new Integer(this.value[0]); + } + + Object getRef() { + return this.value; + } + } + + // Wrapper class for Float + static class FloatWrapper extends ValueWrapper { + private float[] value = new float[1]; + + void set(Object value) { + this.value[0] = ((Float)value).floatValue(); + } + + Object get() { + return new Float(this.value[0]); + } + + Object getRef() { + return this.value; + } + } + + /* + // Wrapper class for Double + static class DoubleWrapper extends ValueWrapper { + private double[] value = new double[1]; + + void set(Object value) { + this.value[0] = ((Double)value).doubleValue(); + } + + Object get() { + return new Double(value[0]); + } + + Object getRef() { + return value; + } + } + */ + + // Wrapper class for Tuple2i + static class Tuple2iWrapper extends ValueWrapper { + private int[] value = new int[2]; + + void set(Object value) { + ((Tuple2i)value).get(this.value); + } + + Object get() { + return new Point2i(value); + } + + Object getRef() { + return value; + } + } + + // Wrapper class for Tuple2f + static class Tuple2fWrapper extends ValueWrapper { + private float[] value = new float[2]; + + void set(Object value) { + ((Tuple2f)value).get(this.value); + } + + Object get() { + return new Point2f(value); + } + + Object getRef() { + return value; + } + } + + /* + // Wrapper class for Tuple2d + static class Tuple2dWrapper extends ValueWrapper { + private double[] value = new double[2]; + + void set(Object value) { + ((Tuple2d)value).get(this.value); + } + + Object get() { + return new Point2d(value); + } + + Object getRef() { + return value; + } + } + */ + + // Wrapper class for Tuple3i + static class Tuple3iWrapper extends ValueWrapper { + private int[] value = new int[3]; + + void set(Object value) { + ((Tuple3i)value).get(this.value); + } + + Object get() { + return new Point3i(value); + } + + Object getRef() { + return value; + } + } + + // Wrapper class for Tuple3f + static class Tuple3fWrapper extends ValueWrapper { + private float[] value = new float[3]; + + void set(Object value) { + ((Tuple3f)value).get(this.value); + } + + Object get() { + return new Point3f(value); + } + + Object getRef() { + return value; + } + } + + /* + // Wrapper class for Tuple3d + static class Tuple3dWrapper extends ValueWrapper { + private double[] value = new double[3]; + + void set(Object value) { + ((Tuple3d)value).get(this.value); + } + + Object get() { + return new Point3d(value); + } + + Object getRef() { + return value; + } + } + */ + + // Wrapper class for Tuple4i + static class Tuple4iWrapper extends ValueWrapper { + private int[] value = new int[4]; + + void set(Object value) { + ((Tuple4i)value).get(this.value); + } + + Object get() { + return new Point4i(value); + } + + Object getRef() { + return value; + } + } + + // Wrapper class for Tuple4f + static class Tuple4fWrapper extends ValueWrapper { + private float[] value = new float[4]; + + void set(Object value) { + ((Tuple4f)value).get(this.value); + } + + Object get() { + return new Point4f(value); + } + + Object getRef() { + return value; + } + } + + /* + // Wrapper class for Tuple4d + static class Tuple4dWrapper extends ValueWrapper { + private double[] value = new double[4]; + + void set(Object value) { + ((Tuple4d)value).get(this.value); + } + + Object get() { + return new Point4d(value); + } + + Object getRef() { + return value; + } + } + */ + + // Wrapper class for Matrix3f + static class Matrix3fWrapper extends ValueWrapper { + private float[] value = new float[9]; + + void set(Object value) { + Matrix3f m = (Matrix3f)value; + this.value[0] = m.m00; + this.value[1] = m.m01; + this.value[2] = m.m02; + this.value[3] = m.m10; + this.value[4] = m.m11; + this.value[5] = m.m12; + this.value[6] = m.m20; + this.value[7] = m.m21; + this.value[8] = m.m22; + } + + Object get() { + return new Matrix3f(value); + } + + Object getRef() { + return value; + } + } + + /* + // Wrapper class for Matrix3d + static class Matrix3dWrapper extends ValueWrapper { + private double[] value = new double[9]; + + void set(Object value) { + Matrix3d m = (Matrix3d)value; + this.value[0] = m.m00; + this.value[1] = m.m01; + this.value[2] = m.m02; + this.value[3] = m.m10; + this.value[4] = m.m11; + this.value[5] = m.m12; + this.value[6] = m.m20; + this.value[7] = m.m21; + this.value[8] = m.m22; + } + + Object get() { + return new Matrix3d(value); + } + + Object getRef() { + return value; + } + } + */ + + // Wrapper class for Matrix4f + static class Matrix4fWrapper extends ValueWrapper { + private float[] value = new float[16]; + + void set(Object value) { + Matrix4f m = (Matrix4f)value; + this.value[0] = m.m00; + this.value[1] = m.m01; + this.value[2] = m.m02; + this.value[3] = m.m03; + this.value[4] = m.m10; + this.value[5] = m.m11; + this.value[6] = m.m12; + this.value[7] = m.m13; + this.value[8] = m.m20; + this.value[9] = m.m21; + this.value[10] = m.m22; + this.value[11] = m.m23; + this.value[12] = m.m30; + this.value[13] = m.m31; + this.value[14] = m.m32; + this.value[15] = m.m33; + } + + Object get() { + return new Matrix4f(value); + } + + Object getRef() { + return value; + } + } + + /* + // Wrapper class for Matrix4d + static class Matrix4dWrapper extends ValueWrapper { + private double[] value = new double[16]; + + void set(Object value) { + Matrix4d m = (Matrix4d)value; + this.value[0] = m.m00; + this.value[1] = m.m01; + this.value[2] = m.m02; + this.value[3] = m.m03; + this.value[4] = m.m10; + this.value[5] = m.m11; + this.value[6] = m.m12; + this.value[7] = m.m13; + this.value[8] = m.m20; + this.value[9] = m.m21; + this.value[10] = m.m22; + this.value[11] = m.m23; + this.value[12] = m.m30; + this.value[13] = m.m31; + this.value[14] = m.m32; + this.value[15] = m.m33; + } + + Object get() { + return new Matrix4d(value); + } + + Object getRef() { + return value; + } + } + */ + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderBin.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderBin.java new file mode 100644 index 0000000..01b99f7 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderBin.java @@ -0,0 +1,374 @@ +/* + * $RCSfile: ShaderBin.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; + + +// XXXX : We should have a common Bin object that all other Bins extend from. + + +//class ShaderBin extends Object implements ObjectUpdate, NodeComponentUpdate { +class ShaderBin implements ObjectUpdate { + + /** + * Node component dirty mask. + */ + static final int SHADER_PROGRAM_DIRTY = 0x1; + static final int SHADER_ATTRIBUTE_SET_DIRTY = 0x2; + + + /** + * The RenderBin for this object + */ + RenderBin renderBin = null; + + /** + * The AttributeBin that this ShaderBin resides + */ + AttributeBin attributeBin = null; + + /** + * The references to the next and previous ShaderBins in the + * list. + */ + ShaderBin next = null; + ShaderBin prev = null; + + /** + * The list of TextureBins in this ShaderBin + */ + TextureBin textureBinList = null; + + /** + * The list of TextureBins to be added for the next frame + */ + ArrayList addTextureBins = new ArrayList(); + + boolean onUpdateList = false; + + int numEditingTextureBins = 0; + + int componentDirty = 0; + ShaderAppearanceRetained shaderAppearance = null; + ShaderProgramRetained shaderProgram = null; + ShaderAttributeSetRetained shaderAttributeSet = new ShaderAttributeSetRetained(); + + ShaderBin(ShaderAppearanceRetained sApp, RenderBin rBin) { + reset(sApp, rBin); + } + + void reset(ShaderAppearanceRetained sApp, RenderBin rBin) { + prev = null; + next = null; + renderBin = rBin; + attributeBin = null; + textureBinList = null; + onUpdateList = false; + numEditingTextureBins = 0; + addTextureBins.clear(); + if(sApp != null) { + shaderProgram = sApp.shaderProgram; + shaderAttributeSet = sApp.shaderAttributeSet; + } + else { + shaderProgram = null; + shaderAttributeSet = null; + } + shaderAppearance = sApp; + } + + void clear() { + reset(null, null); + } + + /** + * This tests if the qiven ra.shaderProgram match this shaderProgram + */ + boolean equals(ShaderAppearanceRetained sApp) { + + ShaderProgramRetained sp; + ShaderAttributeSetRetained ss; + + if (sApp == null) { + sp = null; + ss = null; + } else { + sp = sApp.shaderProgram; + ss = sApp.shaderAttributeSet; + } + + if((shaderProgram != sp) || (shaderAttributeSet != ss)) { + return false; + } + + return true; + + } + + public void updateObject() { + TextureBin t; + int i; + + if (addTextureBins.size() > 0) { + t = (TextureBin)addTextureBins.get(0); + if (textureBinList == null) { + textureBinList = t; + + } + else { + // Look for a TextureBin that has the same texture + insertTextureBin(t); + } + for (i = 1; i < addTextureBins.size() ; i++) { + t = (TextureBin)addTextureBins.get(i); + // Look for a TextureBin that has the same texture + insertTextureBin(t); + + } + } + addTextureBins.clear(); + onUpdateList = false; + + } + + void insertTextureBin(TextureBin t) { + TextureBin tb; + int i; + TextureRetained texture = null; + + if (t.texUnitState != null && t.texUnitState.length > 0) { + if (t.texUnitState[0] != null) { + texture = t.texUnitState[0].texture; + } + } + + // use the texture in the first texture unit as the sorting criteria + if (texture != null) { + tb = textureBinList; + while (tb != null) { + if (tb.texUnitState == null || tb.texUnitState[0] == null || + tb.texUnitState[0].texture != texture) { + tb = tb.next; + } else { + // put it here + t.next = tb; + t.prev = tb.prev; + if (tb.prev == null) { + textureBinList = t; + } + else { + tb.prev.next = t; + } + tb.prev = t; + return; + } + } + } + // Just put it up front + t.prev = null; + t.next = textureBinList; + textureBinList.prev = t; + textureBinList = t; + + t.tbFlag &= ~TextureBin.RESORT; + } + + + /** + * reInsert textureBin if the first texture is different from + * the previous bin and different from the next bin + */ + void reInsertTextureBin(TextureBin tb) { + + TextureRetained texture = null, + prevTexture = null, + nextTexture = null; + + if (tb.texUnitState != null && tb.texUnitState[0] != null) { + texture = tb.texUnitState[0].texture; + } + + if (tb.prev != null && tb.prev.texUnitState != null) { + prevTexture = tb.prev.texUnitState[0].texture; + } + + if (texture != prevTexture) { + if (tb.next != null && tb.next.texUnitState != null) { + nextTexture = tb.next.texUnitState[0].texture; + } + if (texture != nextTexture) { + if (tb.prev != null && tb.next != null) { + tb.prev.next = tb.next; + tb.next.prev = tb.prev; + insertTextureBin(tb); + } + } + } + } + + + + /** + * Adds the given TextureBin to this AttributeBin. + */ + void addTextureBin(TextureBin t, RenderBin rb, RenderAtom ra) { + + t.environmentSet = this.attributeBin.environmentSet; + t.attributeBin = this.attributeBin; + t.shaderBin = this; + + attributeBin.updateFromShaderBin(ra); + addTextureBins.add(t); + + if (!onUpdateList) { + rb.objUpdateList.add(this); + onUpdateList = true; + } + } + + /** + * Removes the given TextureBin from this ShaderBin. + */ + void removeTextureBin(TextureBin t) { + + // If the TextureBin being remove is contained in addTextureBins, + // then remove the TextureBin from the addList + if (addTextureBins.contains(t)) { + addTextureBins.remove(addTextureBins.indexOf(t)); + } + else { + if (t.prev == null) { // At the head of the list + textureBinList = t.next; + if (t.next != null) { + t.next.prev = null; + } + } else { // In the middle or at the end. + t.prev.next = t.next; + if (t.next != null) { + t.next.prev = t.prev; + } + } + } + + t.shaderBin = null; + t.prev = null; + t.next = null; + + t.clear(); + + if (textureBinList == null && addTextureBins.size() == 0 ) { + // Note: Removal of this shaderBin as a user of the rendering + // atttrs is done during removeRenderAtom() in RenderMolecule.java + attributeBin.removeShaderBin(this); + } + } + + /** + * Renders this ShaderBin + */ + void render(Canvas3D cv) { + + TextureBin tb; + + // System.err.println("ShaderBin.render() shaderProgram = " + shaderProgram); + + // include this ShaderBin to the to-be-updated list in canvas + cv.setStateToUpdate(Canvas3D.SHADERBIN_BIT, this); + + tb = textureBinList; + while (tb != null) { + tb.render(cv); + tb = tb.next; + } + } + + void updateAttributes(Canvas3D cv) { + + // System.err.println("ShaderBin.updateAttributes() shaderProgram is " + shaderProgram); + if (shaderProgram != null) { + // Compile, link, and enable shader program + shaderProgram.updateNative(cv, true); + + if (shaderAttributeSet != null) { + shaderAttributeSet.updateNative(cv, shaderProgram); + } + + } + else { + if (cv.shaderProgram != null) { + // Disable shader program + cv.shaderProgram.updateNative(cv, false); + } + } + + cv.shaderBin = this; + cv.shaderProgram = shaderProgram; + } + + void updateNodeComponent() { + // System.err.println("ShaderBin.updateNodeComponent() ..."); + + // We don't need to clone shaderProgram. + // ShaderProgram object can't be modified once it is live, + // so each update should be a new reference. + if ((componentDirty & SHADER_PROGRAM_DIRTY) != 0) { + // System.err.println(" - SHADER_PROGRAM_DIRTY"); + + shaderProgram = shaderAppearance.shaderProgram; + } + + // We need to clone the shaderAttributeSet. + if ((componentDirty & SHADER_ATTRIBUTE_SET_DIRTY) != 0) { + // System.err.println(" - SHADER_ATTRIBUTE_SET_DIRTY"); + + HashMap attrs = (HashMap)shaderAttributeSet.getAttrs(); + attrs.clear(); + if(shaderAppearance.shaderAttributeSet != null) { + attrs.putAll(shaderAppearance.shaderAttributeSet.getAttrs()); + } + } + + componentDirty = 0; + } + + void incrActiveTextureBin() { + numEditingTextureBins++; + } + + void decrActiveTextureBin() { + numEditingTextureBins--; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderConstants.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderConstants.java new file mode 100644 index 0000000..2677363 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderConstants.java @@ -0,0 +1,53 @@ +/* + * $RCSfile: ShaderConstants.java,v $ + * + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.3 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The ShaderConstants class contains internal constants used by other + * Shader classes. + */ +class ShaderConstants extends Object { + + // + // The following bits are used in the messages for various Shader objects. + // + + // ShaderAttributeSet bits -- indicates which attribute + // operation in this ShaderAttributeSet object is needed. + static final int ATTRIBUTE_SET_PUT = 0x0001; + static final int ATTRIBUTE_SET_REMOVE = 0x0002; + static final int ATTRIBUTE_SET_CLEAR = 0x0004; + + // ShaderAttribute bits + static final int ATTRIBUTE_VALUE_UPDATE = 0x0008; + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderError.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderError.java new file mode 100644 index 0000000..79a68f4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderError.java @@ -0,0 +1,429 @@ +/* + * $RCSfile: ShaderError.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.io.PrintStream; + +/** + * ShaderError is a container object that holds the details of + * a runtime error that occurs while compiling or executing a + * programmable shader. + * + * @since Java 3D 1.4 + */ +public class ShaderError extends Object { + private int errorCode = NO_ERROR; + private String errorMessage = null; + private String detailMessage = null; + private Canvas3D canvas = null; + private Shape3D shape = null; + private Geometry geometry = null; + private ShaderAppearance shaderApp = null; + private ShaderProgram shaderProgram = null; + private Shader shader = null; + private ShaderAttributeSet shaderAttributeSet = null; + private ShaderAttribute shaderAttribute = null; + + /** + * Indicates that no error occurred. + */ + public static final int NO_ERROR = 0; + + /** + * Indicates that an error occurred while compiling a shader. + */ + public static final int COMPILE_ERROR = 1; + + /** + * Indicates that an error occurred while linking a shader. + */ + public static final int LINK_ERROR = 2; + + /** + * Indicates a error in looking up a vertex attribute + * name within a given shader program. + */ + public static final int VERTEX_ATTRIBUTE_LOOKUP_ERROR = 3; + + /** + * Indicates a error in looking up the location of a uniform + * shader attribute name within a given shader program. + */ + public static final int SHADER_ATTRIBUTE_LOOKUP_ERROR = 4; + + /** + * Indicates a error caused by a ShaderAttribute whose name does not + * appear in the list of shader attribute names in the corresponding + * ShaderProgram object. + */ + public static final int SHADER_ATTRIBUTE_NAME_NOT_SET_ERROR = 5; + + /** + * Indicates a error in the type of the attribute versus what the shader + * program was expecting. + */ + public static final int SHADER_ATTRIBUTE_TYPE_ERROR = 6; + + /** + * Indicates that the specified shading language is not supported + * on the screen display device. + */ + public static final int UNSUPPORTED_LANGUAGE_ERROR = 7; + + + /** + * Constructs a new ShaderError object indicating no error. The + * error code is set to NO_ERROR. All other fields + * are initialized to null, including the error message. + */ + public ShaderError() { + } + + /** + * Constructs a new ShaderError object with the given error code + * and message. All other fields are initialized to null. + * + * @param errorCode the error code for this shader error. + * + * @param errorMessage a short error message describing this + * shader error. + */ + public ShaderError(int errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + /** + * Prints a verbose error report to System.err. This verbose + * output includes the error code, error message, detail message, + * and all relevant Java 3D objects. + */ + public void printVerbose() { + printVerbose(System.err); + } + + /** + * Prints a verbose error report to the specified PrintStream. + * This verbose output includes the error code, error message, + * detail message, and all relevant Java 3D objects. + * + * @param printStream the print stream on which to print the error + * report. + */ + public void printVerbose(PrintStream printStream) { + printStream.println(this); + if (canvas != null) { + printStream.println("canvas = " + canvas); + } + if (shape != null) { + printStream.println("shape = " + shape); + } + if (geometry != null) { + printStream.println("geometry = " + geometry); + } + if (shaderApp != null) { + printStream.println("shaderApp = " + shaderApp); + } + if (shaderProgram != null) { + printStream.println("shaderProgram = " + shaderProgram); + } + if (shader != null) { + printStream.println("shader = " + shader); + } + if (shaderAttributeSet != null) { + printStream.println("shaderAttributeSet = " + shaderAttributeSet); + } + if (shaderAttribute != null) { + printStream.println("shaderAttribute = " + shaderAttribute); + } + + if (detailMessage != null) { + printStream.println(); + printStream.println("Detail Message"); + printStream.println("--------------"); + printStream.println(detailMessage); + } + } + + /** + * Sets the error code for this shader error. This represents the + * type of error that occurred. + * + * @param errorCode the error code for this shader error. + */ + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + /** + * Returns the error code for this shader error. + * + * @return the error code. + */ + public int getErrorCode() { + return errorCode; + } + + /** + * Sets the error message for this shader error. This is a short + * message describing the error, and is included as part of + * toString(). + * + * @param errorMessage a short error message describing this + * shader error. + */ + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + /** + * Returns the error message for this shader error. + * + * @return a short error message describing this shader error. + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the detail message for this shader error. This is a + * detailed error message, typically produced by the shader + * compiler, and is not included as part of toString(). + * + * @param detailMessage a detailed message describing this shader + * error in more detail. + */ + public void setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + } + + /** + * Returns the detail message for this shader error. + * + * @return the detail message for this shader error. + */ + public String getDetailMessage() { + return detailMessage; + } + + /** + * Sets the canvas associated with this shader error. + * + * @param canvas the canvas associated with this shader error. + */ + public void setCanvas3D(Canvas3D canvas) { + this.canvas = canvas; + } + + /** + * Returns the canvas associated with this shader error. + * + * @return the canvas associated with this shader error. + */ + public Canvas3D getCanvas3D() { + return this.canvas; + } + + /** + * Sets the shape node associated with this shader error. + * + * @param shape the shape node associated with this shader error. + */ + public void setShape3D(Shape3D shape) { + this.shape = shape; + } + + /** + * Returns the shape node associated with this shader error. + * + * @return the shape node associated with this shader error. + */ + public Shape3D getShape3D() { + return this.shape; + } + + /** + * Sets the geometry associated with this shader error. + * + * @param geometry the geometry associated with this shader error. + */ + public void setGeometry(Geometry geometry) { + this.geometry = geometry; + } + + /** + * Returns the geometry associated with this shader error. + * + * @return the geometry associated with this shader error. + */ + public Geometry getGeometry() { + return this.geometry; + } + + /** + * Sets the shader appearance associated with this shader error. + * + * @param shaderApp the shader appearance associated with this shader error. + */ + public void setShaderAppearance(ShaderAppearance shaderApp) { + this.shaderApp = shaderApp; + } + + /** + * Returns the shader appearance associated with this shader error. + * + * @return the shader appearance associated with this shader error. + */ + public ShaderAppearance getShaderAppearance() { + return this.shaderApp; + } + + /** + * Sets the shader program associated with this shader error. + * + * @param shaderProgram the shader program associated with this shader error. + */ + public void setShaderProgram(ShaderProgram shaderProgram) { + this.shaderProgram = shaderProgram; + } + + /** + * Returns the shader program associated with this shader error. + * + * @return the shader program associated with this shader error. + */ + public ShaderProgram getShaderProgram() { + return this.shaderProgram; + } + + /** + * Sets the shader object associated with this shader error. + * + * @param shader the shader object associated with this shader error. + */ + public void setShader(Shader shader) { + this.shader = shader; + } + + /** + * Returns the shader object associated with this shader error. + * + * @return the shader object associated with this shader error. + */ + public Shader getShader() { + return this.shader; + } + + /** + * Sets the shader attribute set associated with this shader error. + * + * @param shaderAttributeSet the shader attribute set associated with this shader error. + */ + public void setShaderAttributeSet(ShaderAttributeSet shaderAttributeSet) { + this.shaderAttributeSet = shaderAttributeSet; + } + + /** + * Returns the shader attribute set associated with this shader error. + * + * @return the shader attribute set associated with this shader error. + */ + public ShaderAttributeSet getShaderAttributeSet() { + return this.shaderAttributeSet; + } + + /** + * Sets the shader attribute associated with this shader error. + * + * @param shaderAttribute the shader attribute associated with this shader error. + */ + public void setShaderAttribute(ShaderAttribute shaderAttribute) { + this.shaderAttribute = shaderAttribute; + } + + /** + * Returns the shader attribute associated with this shader error. + * + * @return the shader attribute associated with this shader error. + */ + public ShaderAttribute getShaderAttribute() { + return this.shaderAttribute; + } + + + /** + * Returns a short string that describes this shader error. The + * string is composed of the textual description of the errorCode, + * a ": ", and the errorMessage field. If the errorMessage is + * null then the ": " and the errorMessage are omitted. + * + * @return a string representation of this shader error. + */ + public String toString() { + // Concatenate string representation of error code with error message + String errorCodeStr; + switch (errorCode) { + case NO_ERROR: + errorCodeStr = "NO_ERROR"; + break; + case COMPILE_ERROR: + errorCodeStr = "COMPILE_ERROR"; + break; + case LINK_ERROR: + errorCodeStr = "LINK_ERROR"; + break; + case VERTEX_ATTRIBUTE_LOOKUP_ERROR: + errorCodeStr = "VERTEX_ATTRIBUTE_LOOKUP_ERROR"; + break; + case SHADER_ATTRIBUTE_LOOKUP_ERROR: + errorCodeStr = "SHADER_ATTRIBUTE_LOOKUP_ERROR"; + break; + case SHADER_ATTRIBUTE_NAME_NOT_SET_ERROR: + errorCodeStr = "SHADER_ATTRIBUTE_NAME_NOT_SET_ERROR"; + break; + case SHADER_ATTRIBUTE_TYPE_ERROR: + errorCodeStr = "SHADER_ATTRIBUTE_TYPE_ERROR"; + break; + case UNSUPPORTED_LANGUAGE_ERROR: + errorCodeStr = "UNSUPPORTED_LANGUAGE_ERROR"; + break; + default: + errorCodeStr = "UNKNOWN ERROR CODE (" + errorCode + ")"; + } + + if (errorMessage == null) { + return errorCodeStr; + } + + return errorCodeStr + ": " + errorMessage; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderErrorListener.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderErrorListener.java new file mode 100644 index 0000000..90c47df --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderErrorListener.java @@ -0,0 +1,52 @@ +/* + * $RCSfile: ShaderErrorListener.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Listener interface for monitoring errors in Shader Programs. + * Compile and link errors are reported by the shader compiler, as are + * runtime errors, such as those resulting from shader attributes that + * aren't found or are of the wrong type. + * + * @see VirtualUniverse#addShaderErrorListener + * + * @since Java 3D 1.4 + */ +public interface ShaderErrorListener { + /** + * Invoked when an error occurs while compiling, linking or + * executing a programmable shader. + * + * @param error object that contains the details of the error. + */ + public void errorOccurred(ShaderError error); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderId.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderId.java new file mode 100644 index 0000000..58e0a0f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderId.java @@ -0,0 +1,41 @@ +/* + * $RCSfile: ShaderId.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Tagging interface for shader objects. The rendering pipelines + * will define concrete classes that implement this interface. All code that + * uses the tagged objects will be in the pipelines. + */ +interface ShaderId { + // No methods or constants defined at this time +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderProgram.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderProgram.java new file mode 100644 index 0000000..65a3610 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderProgram.java @@ -0,0 +1,213 @@ +/* + * $RCSfile: ShaderProgram.java,v $ + * + * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The ShaderProgram node component object is the abstract base class + * for programmable shader programs. Each concrete instance of a + * ShaderProgram is a container for a set of Shader objects. The set + * of Shaders contained in the ShaderProgram is a complete program for + * the Graphics Pipeline Unit (GPU) of the graphics accelerator. It is + * specified using the shader language defined by the + * ShaderProgram. The currently defined shader languages are: Cg and + * GLSL. + * + *

+ * NOTE: Applications should not extend this class. + * + * @see Shader + * @see ShaderAppearance#setShaderProgram + * + * @since Java 3D 1.4 + */ + +public abstract class ShaderProgram extends NodeComponent { + + /** + * Specifies that this ShaderProgram object allows reading + * its shaders. + */ + public static final int ALLOW_SHADERS_READ = + CapabilityBits.SHADER_PROGRAM_ALLOW_SHADERS_READ; + + /** + * Specifies that this ShaderProgram object allows reading + * its shader or vertex attribute names. + */ + public static final int ALLOW_NAMES_READ = + CapabilityBits.SHADER_PROGRAM_ALLOW_NAMES_READ; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SHADERS_READ, + ALLOW_NAMES_READ + }; + + /* + * Default values (copied from GeometryArray.java): + * + * vertexAttrNames : null
+ */ + + /** + * Package scope constructor so it can't be subclassed by classes + * outside the javax.media.j3d package. + */ + ShaderProgram() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Sets the vertex attribute names array for this ShaderProgram + * object. Each element in the array specifies the shader + * attribute name that is bound to the corresponding numbered + * vertex attribute within a GeometryArray object that uses this + * shader program. Array element 0 specifies the name of + * GeometryArray vertex attribute 0, array element 1 specifies the + * name of GeometryArray vertex attribute 1, and so forth. + * The array of names may be null or empty (0 length), but the + * elements of the array must be non-null. + * + * @param vertexAttrNames array of vertex attribute names for this + * shader program. A copy of this array is made. + * + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @exception NullPointerException if any element in the + * vertexAttrNames array is null. + */ + public abstract void setVertexAttrNames(String[] vertexAttrNames); + + /** + * Retrieves the vertex attribute names array from this + * ShaderProgram object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @return a copy of this ShaderProgram's array of vertex attribute names. + */ + public abstract String[] getVertexAttrNames(); + + + /** + * Sets the shader attribute names array for this ShaderProgram + * object. Each element in the array specifies a shader + * attribute name that may be set via a ShaderAttribute object. + * Only those attributes whose names that appear in the shader + * attribute names array can be set for a given shader program. + * The array of names may be null or empty (0 length), but the + * elements of the array must be non-null. + * + *

+ * TODO: finish this. + * + * @param shaderAttrNames array of shader attribute names for this + * shader program. A copy of this array is made. + * + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @exception NullPointerException if any element in the + * shaderAttrNames array is null. + */ + public abstract void setShaderAttrNames(String[] shaderAttrNames); + + /** + * Retrieves the shader attribute names array from this + * ShaderProgram object. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @return a copy of this ShaderProgram's array of shader attribute names. + */ + public abstract String[] getShaderAttrNames(); + + + /** + * Copies the specified array of shaders into this shader + * program. This method makes a shallow copy of the array. The + * array of shaders may be null or empty (0 length), but the + * elements of the array must be non-null. The shading + * language of each shader in the array must match the + * subclass. Subclasses may impose additional restrictions. + * + * @param shaders array of Shader objects to be copied into this + * ShaderProgram + * + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @exception IllegalArgumentException if the shading language of + * any shader in the shaders array doesn't match the type of the + * subclass. + * + * @exception NullPointerException if any element in the + * shaders array is null. + */ + public abstract void setShaders(Shader[] shaders); + + /** + * Retrieves the array of shaders from this shader program. A + * shallow copy of the array is returned. The return value may + * be null. + * + * @return a copy of this ShaderProgram's array of Shader objects + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public abstract Shader[] getShaders(); + + + // Default shader error listener class + private static ShaderErrorListener defaultErrorListener = null; + + synchronized static ShaderErrorListener getDefaultErrorListener() { + if (defaultErrorListener == null) { + defaultErrorListener = new DefaultErrorListener(); + } + + return defaultErrorListener; + } + + static class DefaultErrorListener implements ShaderErrorListener { + public void errorOccurred(ShaderError error) { + System.err.println(); + System.err.println("DefaultShaderErrorListener.errorOccurred:"); + error.printVerbose(); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderProgramId.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderProgramId.java new file mode 100644 index 0000000..4d0986c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderProgramId.java @@ -0,0 +1,41 @@ +/* + * $RCSfile: ShaderProgramId.java,v $ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.4 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Tagging interface for shader program objects. The rendering pipelines + * will define concrete classes that implement this interface. All code that + * uses the tagged objects will be in the pipelines. + */ +interface ShaderProgramId { + // No methods or constants defined at this time +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderProgramRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderProgramRetained.java new file mode 100644 index 0000000..1222684 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderProgramRetained.java @@ -0,0 +1,1233 @@ +/* + * $RCSfile: ShaderProgramRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; +import javax.vecmath.*; + +/** + * The ShaderProgramRetained object is a component object of an AppearanceRetained + * object that defines the shader properties used when programmable shader is + * enabled. ShaderProgramRetained object is an abstract class. All shader program + * objects must be created as either a GLSLShaderProgramRetained object or a + * CgShaderProgramRetained object. + */ +abstract class ShaderProgramRetained extends NodeComponentRetained { + + // Each element in the array corresponds to a unique renderer if shared + // context or a unique canvas otherwise. + protected ShaderProgramData shaderProgramData[]; + + // Flag indicating whether an UNSUPPORTED_LANGUAGE_ERROR has + // already been reported for this shader program object. It is + // set in verifyShaderProgram and cleared in setLive or clearLive. + // TODO KCR: Add code to clear this in setLive or clearLive + private boolean unsupportedErrorReported = false; + + // Flag indicating whether a LINK_ERROR has occurred for this shader program + // object. It is set in updateNative to indicate that the linkShaderProgram + // operation failed. It is cleared in setLive or clearLive. + // TODO KCR: Add code to clear this in setLive or clearLive + private boolean linkErrorOccurred = false; + + // an array of shaders used by this shader program + protected ShaderRetained[] shaders; + + // an array of vertex attribute names + protected String[] vertexAttrNames; + + // an array of (uniform) shader attribute names + protected String[] shaderAttrNames; + + // Set of ShaderAttribute objects for which we have already reported an error + private HashSet shaderAttrErrorSet = null; + + // need to synchronize access from multiple rendering threads + Object resourceLock = new Object(); + + // Package-scope default constructor + ShaderProgramRetained() { + } + + /** + * Sets the vertex attribute names array for this ShaderProgram + * object. Each element in the array specifies the shader + * attribute name that is bound to the corresponding numbered + * vertex attribute within a GeometryArray object that uses this + * shader program. Array element 0 specifies the name of + * GeometryArray vertex attribute 0, array element 1 specifies the + * name of GeometryArray vertex attribute 1, and so forth. + * The array of names may be null or empty (0 length), but the + * elements of the array must be non-null. + * + * @param vertexAttrNames array of vertex attribute names for this + * shader program. A copy of this array is made. + */ + void setVertexAttrNames(String[] vertexAttrNames) { + if (vertexAttrNames == null) { + this.vertexAttrNames = null; + } + else { + this.vertexAttrNames = (String[])vertexAttrNames.clone(); + } + } + + + /** + * Retrieves the vertex attribute names array from this + * ShaderProgram object. + * + * @return a copy of this ShaderProgram's array of vertex attribute names. + */ + String[] getVertexAttrNames() { + + if (vertexAttrNames == null) { + return null; + } + + return (String[])vertexAttrNames.clone(); + + } + + + /** + * Sets the shader attribute names array for this ShaderProgram + * object. Each element in the array specifies a shader + * attribute name that may be set via a ShaderAttribute object. + * Only those attributes whose names that appear in the shader + * attribute names array can be set for a given shader program. + * The array of names may be null or empty (0 length), but the + * elements of the array must be non-null. + * + * @param shaderAttrNames array of shader attribute names for this + * shader program. A copy of this array is made. + */ + void setShaderAttrNames(String[] shaderAttrNames) { + if (shaderAttrNames == null) { + this.shaderAttrNames = null; + } + else { + this.shaderAttrNames = (String[])shaderAttrNames.clone(); + } + } + + + /** + * Retrieves the shader attribute names array from this + * ShaderProgram object. + * + * @return a copy of this ShaderProgram's array of shader attribute names. + */ + + String[] getShaderAttrNames() { + + if (shaderAttrNames == null) { + return null; + } + + return (String[])shaderAttrNames.clone(); + + } + + + + /** + * Copies the specified array of shaders into this shader + * program. This method makes a shallow copy of the array. The + * array of shaders may be null or empty (0 length), but the + * elements of the array must be non-null. The shading + * language of each shader in the array must match the + * subclass. Subclasses may impose additional restrictions. + * + * @param shaders array of Shader objects to be copied into this + * ShaderProgram + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if the shading language of + * any shader in the shaders array doesn't match the type of the + * subclass. + */ + void setShaders(Shader[] shaders) { + + if (shaders == null) { + this.shaders = null; + return; + } + + this.shaders = new ShaderRetained[shaders.length]; + + // Copy vertex and fragment shader + for (int i = 0; i < shaders.length; i++) { + this.shaders[i] = (ShaderRetained)shaders[i].retained; + } + + } + + /** + * Retrieves the array of shaders from this shader program. A + * shallow copy of the array is returned. The return value may + * be null. + * + * @return a copy of this ShaderProgram's array of Shader objects + * + */ + Shader[] getShaders() { + + if (shaders == null) { + return null; + } else { + Shader shads[] = + new Shader[shaders.length]; + for (int i = 0; i < shaders.length; i++) { + if (shaders[i] != null) { + shads[i] = (Shader) shaders[i].source; + } else { + shads[i] = null; + } + } + return shads; + } + } + + /** + * Method to create the native shader. + */ + abstract ShaderError createShader(Context ctx, ShaderRetained shader, ShaderId[] shaderIdArr); + + /** + * Method to destroy the native shader. + */ + abstract ShaderError destroyShader(Context ctx, ShaderId shaderId); + + /** + * Method to compile the native shader. + */ + abstract ShaderError compileShader(Context ctx, ShaderId shaderId, String source); + + /** + * Method to create the native shader program. + */ + abstract ShaderError createShaderProgram(Context ctx, ShaderProgramId[] shaderProgramIdArr); + + /** + * Method to destroy the native shader program. + */ + abstract ShaderError destroyShaderProgram(Context ctx, ShaderProgramId shaderProgramId); + + /** + * Method to link the native shader program. + */ + abstract ShaderError linkShaderProgram(Context ctx, ShaderProgramId shaderProgramId, ShaderId[] shaderIds); + + /** + * Method to bind a vertex attribute name to the specified index. + */ + abstract ShaderError bindVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, String attrName, int attrIndex); + + /** + * Method to lookup a list of (uniform) shader attribute names and return + * information about the attributes. + */ + abstract void lookupShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, String[] attrNames, AttrNameInfo[] attrNameInfoArr); + + /* + * Method to lookup a list of vertex attribute names. + */ + abstract void lookupVertexAttrNames(Context ctx, ShaderProgramId shaderProgramId, String[] attrNames, boolean[] errArr); + + /** + * Method to use the native shader program. + */ + abstract ShaderError enableShaderProgram(Context ctx, ShaderProgramId shaderProgramId); + + /** + * Method to disable the native shader program. + */ + abstract ShaderError disableShaderProgram(Context ctx); + + // ShaderAttributeValue methods + + abstract ShaderError setUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value); + + abstract ShaderError setUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value); + + abstract ShaderError setUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value); + + abstract ShaderError setUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value); + + abstract ShaderError setUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value); + + abstract ShaderError setUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value); + + abstract ShaderError setUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value); + + abstract ShaderError setUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value); + + abstract ShaderError setUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value); + + abstract ShaderError setUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value); + + + // ShaderAttributeArray methods + + abstract ShaderError setUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value); + + abstract ShaderError setUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value); + + abstract ShaderError setUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value); + + abstract ShaderError setUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value); + + abstract ShaderError setUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value); + + abstract ShaderError setUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value); + + abstract ShaderError setUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value); + + abstract ShaderError setUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value); + + abstract ShaderError setUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value); + + abstract ShaderError setUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value); + + + /** + * Method to return a flag indicating whether this + * ShaderProgram is supported on the specified Canvas. + */ + abstract boolean isSupported(Canvas3D cv); + + + void setLive(boolean backgroundGroup, int refCount) { + + // System.err.println("ShaderProgramRetained.setLive()"); + + if (shaders != null) { + for (int i = 0; i < shaders.length; i++){ + shaders[i].setLive(backgroundGroup, refCount); + } + } + + super.doSetLive(backgroundGroup, refCount); + super.markAsLive(); + + } + + void clearLive(int refCount) { + + // System.err.println("ShaderProgramRetained.clearLive()"); + + super.clearLive(refCount); + + if (shaders != null) { + for (int i = 0; i < shaders.length; i++) { + shaders[i].clearLive(refCount); + } + } + } + + /** + * Method to enable the native shader program. + */ + private ShaderError enableShaderProgram(Canvas3D cv, int cvRdrIndex) { + assert(cvRdrIndex >= 0); + synchronized(resourceLock) { + return enableShaderProgram(cv.ctx, + shaderProgramData[cvRdrIndex].getShaderProgramId()); + } + + } + + /** + * Method to disable the native shader program. + */ + private ShaderError disableShaderProgram(Canvas3D cv) { + return disableShaderProgram(cv.ctx); + } + + /** + * Initializes a mirror object. + */ + synchronized void initMirrorObject() { + + // Create mirror copy of shaders + if (this.shaders == null) { + ((ShaderProgramRetained)mirror).shaders = null; + } + else { + ((ShaderProgramRetained)mirror).shaders = new ShaderRetained[this.shaders.length]; + // Copy vertex and fragment shader + for (int i = 0; i < this.shaders.length; i++) { + ((ShaderProgramRetained)mirror).shaders[i] = + (ShaderRetained)this.shaders[i].mirror; + } + } + ((ShaderProgramRetained)mirror).shaderProgramData = null; + + // Create mirror copy of vertex attribute names + if (this.vertexAttrNames == null) { + ((ShaderProgramRetained)mirror).vertexAttrNames = null; + } + else { + ((ShaderProgramRetained)mirror).vertexAttrNames = (String[])this.vertexAttrNames.clone(); + } + + // Create mirror copy of shader attribute names + if (this.shaderAttrNames == null) { + ((ShaderProgramRetained)mirror).shaderAttrNames = null; + } + else { + ((ShaderProgramRetained)mirror).shaderAttrNames = (String[])this.shaderAttrNames.clone(); + } + + // Clear shader attribute error set + ((ShaderProgramRetained)mirror).shaderAttrErrorSet = null; + } + + /** + * Update the "component" field of the mirror object with the given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + // ShaderProgram can't be modified once it is live. + assert(false); + System.err.println("ShaderProgramRetained : updateMirrorObject NOT IMPLEMENTED YET"); + } + + /** + * Method to create a ShaderProgramData object for the specified + * canvas/renderer if it doesn't already exist. + * + * Issue 378 : reset the ShaderProgramData object if the context + * has been recreated for the particular canvas / renderer. + */ + private void createShaderProgramData(int cvRdrIndex, long ctxTimeStamp) { + // Create shaderProgram resources if it has not been done. + synchronized(resourceLock) { + if(shaderProgramData == null) { + // We rely on Java to initial the array elements to null. + shaderProgramData = new ShaderProgramData[cvRdrIndex+1]; + } + else if(shaderProgramData.length <= cvRdrIndex) { + // We rely on Java to initial the array elements to null. + ShaderProgramData[] tempSPData = new ShaderProgramData[cvRdrIndex+1]; + System.arraycopy(shaderProgramData, 0, + tempSPData, 0, + shaderProgramData.length); + shaderProgramData = tempSPData; + } + + if(shaderProgramData[cvRdrIndex] == null) { + shaderProgramData[cvRdrIndex] = new ShaderProgramData(); + } else if (shaderProgramData[cvRdrIndex].getCtxTimeStamp() != ctxTimeStamp) { + // Issue 378 - reset the shader program data for this canvas / renderer + // if the context has been recreated + shaderProgramData[cvRdrIndex].reset(); + } + shaderProgramData[cvRdrIndex].setCtxTimeStamp(ctxTimeStamp); + } + } + + /** + * Method to create the native shader program. We must already have + * called createShaderProgramData for this cvRdrIndex. + */ + private ShaderError createShaderProgram(Canvas3D cv, int cvRdrIndex) { + // Create shaderProgram resources if it has not been done. + synchronized(resourceLock) { + assert shaderProgramData[cvRdrIndex].getShaderProgramId() == null; + + ShaderProgramId[] spIdArr = new ShaderProgramId[1]; + ShaderError err = createShaderProgram(cv.ctx, spIdArr); + if(err != null) { + return err; + } + shaderProgramData[cvRdrIndex].setShaderProgramId(spIdArr[0]); + } + + return null; + } + + /** + * Method to link the native shader program. + */ + private ShaderError linkShaderProgram(Canvas3D cv, int cvRdrIndex, + ShaderRetained[] shaders) { + synchronized(resourceLock) { + ShaderId[] shaderIds = new ShaderId[shaders.length]; + for(int i=0; i cvRdrIndex && + shaderProgramData[cvRdrIndex] != null); + +// // Check whether an entry in the shaderProgramData array has been allocated +// if (shaderProgramData == null || +// shaderProgramData.length <= cvRdrIndex || +// shaderProgramData[cvRdrIndex] == null) { +// return; +// } + + ShaderProgramId shaderProgramId = shaderProgramData[cvRdrIndex].getShaderProgramId(); + // Nothing to do if the shaderProgramId is null + if (shaderProgramId == null) { + return; + } + + // Destroy the native resource, set the ID to null for this canvas/renderer, + // and clear the bit in the resourceCreationMask + // Ignore any possible shader error, because there is no meaningful way to report it + destroyShaderProgram(cv.ctx, shaderProgramId); + // Reset this ShaderProgramData object. + shaderProgramData[cvRdrIndex].reset(); + } + } + + + /** + * updateNative is called while traversing the RenderBin to + * update the shader program state + */ + void updateNative(Canvas3D cv, boolean enable) { + // System.err.println("ShaderProgramRetained.updateNative : "); + + final boolean useSharedCtx = cv.useSharedCtx && cv.screen.renderer.sharedCtx != null; + int cvRdrIndex; + long ctxTimeStamp; + + if (useSharedCtx) { + cvRdrIndex = cv.screen.renderer.rendererId; + ctxTimeStamp = cv.screen.renderer.sharedCtxTimeStamp; + } else { + cvRdrIndex = cv.canvasId; + ctxTimeStamp = cv.ctxTimeStamp; + } + + // Create ShaderProgramData object for this canvas/renderer if it doesn't already exist + createShaderProgramData(cvRdrIndex, ctxTimeStamp); + + // Check whether this shader program type is supported for this canvas + if (!verifyShaderProgramSupported(cv)) { + return; + } + + // Just disable shader program and return if enable parameter is set to false + if (!enable) { + // Given the current design, disableShaderProgram cannot return a non-null value, + // so no need to check it + disableShaderProgram(cv); + return; + } + + // Just disable shader program and return if array of shaders is empty, + // or if a previous attempt to link resulted in an error + if (shaders == null || shaders.length == 0 || linkErrorOccurred) { + disableShaderProgram(cv); + return; + } + + boolean loadShaderProgram = false; // flag indicating whether to reload all shaderProgram states + if (getShaderProgramData(cvRdrIndex).getShaderProgramId() == null) { + loadShaderProgram = true; + } + + //System.err.println(".... loadShaderProgram = " + loadShaderProgram); + //System.err.println(".... resourceCreationMask= " + resourceCreationMask); + + ShaderError err = null; + boolean errorOccurred = false; + if (loadShaderProgram) { + if (useSharedCtx) { + // TODO : Need to test useSharedCtx case. ** Untested case ** + cv.makeCtxCurrent(cv.screen.renderer.sharedCtx); + } + + // Create shader resources if not already done + for(int i=0; i < shaders.length; i++) { + // Create ShaderProgramData object for this canvas/renderer if it doesn't already exist + shaders[i].createShaderData(cvRdrIndex, ctxTimeStamp); + + if (shaders[i].compileErrorOccurred) { + errorOccurred = true; + } + else { + err = createShader(cv, cvRdrIndex, shaders[i]); + if (err != null) { + err.setShaderProgram((ShaderProgram)this.source); + err.setShader((Shader)shaders[i].source); + err.setCanvas3D(cv); + notifyErrorListeners(cv, err); + errorOccurred = true; + } + else { + err = compileShader(cv, cvRdrIndex, shaders[i]); + if (err != null) { + err.setShaderProgram((ShaderProgram)this.source); + err.setShader((Shader)shaders[i].source); + err.setCanvas3D(cv); + notifyErrorListeners(cv, err); + destroyShader(cv, cvRdrIndex, shaders[i]); + shaders[i].compileErrorOccurred = true; + errorOccurred = true; + } + } + } + } + + // Create shader program + if (!errorOccurred) { + err = createShaderProgram(cv, cvRdrIndex); + if (err != null) { + err.setShaderProgram((ShaderProgram)this.source); + err.setCanvas3D(cv); + notifyErrorListeners(cv, err); + errorOccurred = true; + } + } + + boolean linked = getShaderProgramData(cvRdrIndex).isLinked(); + if (!linked) { + // Bind vertex attribute names + if (!errorOccurred) { + if (vertexAttrNames != null) { +// System.err.println("vertexAttrNames.length = " + vertexAttrNames.length); + for (int i = 0; i < vertexAttrNames.length; i++) { + err = bindVertexAttrName(cv, cvRdrIndex, vertexAttrNames[i], i); + // Report non-fatal error, if one was detected + if (err != null) { + err.setShaderProgram((ShaderProgram)this.source); + err.setCanvas3D(cv); + notifyErrorListeners(cv, err); + } + } + } + } + + // Link shader program + if (!errorOccurred) { + err = linkShaderProgram(cv, cvRdrIndex, shaders); + if (err != null) { + err.setShaderProgram((ShaderProgram)this.source); + err.setCanvas3D(cv); + notifyErrorListeners(cv, err); + destroyShaderProgram(cv, cvRdrIndex); + linkErrorOccurred = true; + errorOccurred = true; + } + } + + // lookup vertex attribute names + if (!errorOccurred) { + if (vertexAttrNames != null) { + lookupVertexAttrNames(cv, cvRdrIndex, vertexAttrNames); + } + } + + // Lookup shader attribute names + if (!errorOccurred) { + if (shaderAttrNames != null) { +// System.err.println("shaderAttrNames.length = " + shaderAttrNames.length); + lookupShaderAttrNames(cv, cvRdrIndex, shaderAttrNames); + } + } + } + + // Restore current context if we changed it to the shareCtx + if (useSharedCtx) { + cv.makeCtxCurrent(cv.ctx); + } + + // If compilation or link error occured, disable shader program and return + if (errorOccurred) { + disableShaderProgram(cv); + return; + } + } + + // Now we can enable the shader program + enableShaderProgram(cv, cvRdrIndex); + } + + /** + * Update native value for ShaderAttributeValue class + */ + ShaderError setUniformAttrValue(Context ctx, ShaderProgramId shaderProgramId, + ShaderAttrLoc loc, ShaderAttributeValueRetained sav) { + + switch (sav.getClassType()) { + case ShaderAttributeObjectRetained.TYPE_INTEGER: + return setUniform1i(ctx, shaderProgramId, loc, + ((int[])sav.attrWrapper.getRef())[0]); + + case ShaderAttributeObjectRetained.TYPE_FLOAT: + return setUniform1f(ctx, shaderProgramId, loc, + ((float[])sav.attrWrapper.getRef())[0]); + + case ShaderAttributeObjectRetained.TYPE_TUPLE2I: + return setUniform2i(ctx, shaderProgramId, loc, + (int[])sav.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE2F: + return setUniform2f(ctx, shaderProgramId, loc, + (float[])sav.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE3I: + return setUniform3i(ctx, shaderProgramId, loc, + (int[])sav.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE3F: + return setUniform3f(ctx, shaderProgramId, loc, + (float[])sav.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE4I: + return setUniform4i(ctx, shaderProgramId, loc, + (int[])sav.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE4F: + return setUniform4f(ctx, shaderProgramId, loc, + (float[])sav.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_MATRIX3F: + return setUniformMatrix3f(ctx, shaderProgramId, loc, + (float[])sav.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_MATRIX4F: + return setUniformMatrix4f(ctx, shaderProgramId, loc, + (float[])sav.attrWrapper.getRef()); + + default: + // Should never get here + assert false : "Unrecognized ShaderAttributeValue classType"; + return null; + } + } + + /** + * Update native value for ShaderAttributeArray class + */ + ShaderError setUniformAttrArray(Context ctx, ShaderProgramId shaderProgramId, + ShaderAttrLoc loc, ShaderAttributeArrayRetained saa) { + + switch (saa.getClassType()) { + case ShaderAttributeObjectRetained.TYPE_INTEGER: + return setUniform1iArray(ctx, shaderProgramId, loc, saa.length(), + ((int[])saa.attrWrapper.getRef())); + + case ShaderAttributeObjectRetained.TYPE_FLOAT: + return setUniform1fArray(ctx, shaderProgramId, loc, saa.length(), + ((float[])saa.attrWrapper.getRef())); + + case ShaderAttributeObjectRetained.TYPE_TUPLE2I: + return setUniform2iArray(ctx, shaderProgramId, loc, saa.length(), + (int[])saa.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE2F: + return setUniform2fArray(ctx, shaderProgramId, loc, saa.length(), + (float[])saa.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE3I: + return setUniform3iArray(ctx, shaderProgramId, loc, saa.length(), + (int[])saa.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE3F: + return setUniform3fArray(ctx, shaderProgramId, loc, saa.length(), + (float[])saa.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE4I: + return setUniform4iArray(ctx, shaderProgramId, loc, saa.length(), + (int[])saa.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_TUPLE4F: + return setUniform4fArray(ctx, shaderProgramId, loc, saa.length(), + (float[])saa.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_MATRIX3F: + return setUniformMatrix3fArray(ctx, shaderProgramId, loc, saa.length(), + (float[])saa.attrWrapper.getRef()); + + case ShaderAttributeObjectRetained.TYPE_MATRIX4F: + return setUniformMatrix4fArray(ctx, shaderProgramId, loc, saa.length(), + (float[])saa.attrWrapper.getRef()); + + default: + // Should never get here + assert false : "Unrecognized ShaderAttributeArray classType"; + return null; + } + + } + + + void setShaderAttributes(Canvas3D cv, ShaderAttributeSetRetained attributeSet) { + final boolean useSharedCtx = cv.useSharedCtx && cv.screen.renderer.sharedCtx != null; + final int cvRdrIndex = useSharedCtx ? cv.screen.renderer.rendererId : cv.canvasId; + ShaderProgramData spData = getShaderProgramData(cvRdrIndex); + + // Just return if shader program wasn't linked successfully + if (!spData.isLinked()) { + return; + } + + ShaderProgramId shaderProgramId = spData.getShaderProgramId(); + + Iterator attrs = attributeSet.getAttrs().values().iterator(); + while (attrs.hasNext()) { + ShaderError err = null; + ShaderAttributeRetained saRetained = (ShaderAttributeRetained)attrs.next(); + + // Lookup attribute info for the specified attrName; null means + // that the name does not appear in the ShaderProgram, so we will + // report an error. + AttrNameInfo attrNameInfo = spData.getAttrNameInfo(saRetained.getAttributeName()); + if(attrNameInfo == null) { +// System.err.println("ShaderProgramRetained : attrLocation (" + saRetained.getAttributeName() + ") is null."); + String errMsg = "Attribute name not set in ShaderProgram: " + saRetained.getAttributeName(); // TODO: I18N + err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_NAME_NOT_SET_ERROR, errMsg); + } else { + ShaderAttrLoc loc = attrNameInfo.getLocation(); + if (loc != null) { + if (saRetained instanceof ShaderAttributeValueRetained) { + ShaderAttributeValueRetained savRetained = (ShaderAttributeValueRetained)saRetained; + if (attrNameInfo.isArray() || + (savRetained.getClassType() != attrNameInfo.getType())) { + String errMsg = "Attribute type mismatch: " + savRetained.getAttributeName(); // TODO: I18N + err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_TYPE_ERROR, errMsg); + } + else { + err = setUniformAttrValue(cv.ctx, shaderProgramId, loc, savRetained); + } + } else if (saRetained instanceof ShaderAttributeArrayRetained) { + ShaderAttributeArrayRetained saaRetained = (ShaderAttributeArrayRetained)saRetained; + if (!attrNameInfo.isArray() || + (saaRetained.getClassType() != attrNameInfo.getType())) { + String errMsg = "Attribute type mismatch: " + saaRetained.getAttributeName(); // TODO: I18N + err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_TYPE_ERROR, errMsg); + } + else { + err = setUniformAttrArray(cv.ctx, shaderProgramId, loc, saaRetained); + } + } else if (saRetained instanceof ShaderAttributeBindingRetained) { + assert false; + throw new RuntimeException("not implemented"); + } else { + assert false; + } + } + } + + if (err != null) { + // Before reporting the ShaderAttribute error, check + // whether it has already been reported for this ShaderProgram + if (shaderAttrErrorSet == null) { + shaderAttrErrorSet = new HashSet(); + } + if (shaderAttrErrorSet.add(saRetained.source)) { + err.setShaderProgram((ShaderProgram)this.source); + err.setShaderAttributeSet((ShaderAttributeSet)attributeSet.source); + err.setShaderAttribute((ShaderAttribute)saRetained.source); + err.setCanvas3D(cv); + notifyErrorListeners(cv, err); + } + } + } + } + + class ShaderProgramData extends Object { + + // issue 378 - time stamp of context creation for this Canvas + private long ctxTimeStamp; + + // shaderProgramId use by native code. + private ShaderProgramId shaderProgramId = null; + + // linked flag for native. + private boolean linked = false; + + // A map of locations for ShaderAttributes. + private HashMap attrNameInfoMap = new HashMap(); + + /** ShaderProgramData Constructor */ + ShaderProgramData() { + } + + void reset() { + ctxTimeStamp = 0L; + shaderProgramId = null; + linked = false; + attrNameInfoMap.clear(); + } + + long getCtxTimeStamp() { + return ctxTimeStamp; + } + + void setCtxTimeStamp(long ctxTimeStamp) { + this.ctxTimeStamp = ctxTimeStamp; + } + + void setShaderProgramId(ShaderProgramId shaderProgramId) { + this.shaderProgramId = shaderProgramId; + } + + ShaderProgramId getShaderProgramId() { + return this.shaderProgramId; + } + + void setLinked(boolean linked) { + this.linked = linked; + } + + boolean isLinked() { + return linked; + } + + void setAttrNameInfo(String shaderAttribute, AttrNameInfo attrNameInfo) { + assert(shaderAttribute != null); + attrNameInfoMap.put(shaderAttribute, attrNameInfo); + } + + AttrNameInfo getAttrNameInfo(String shaderAttribute) { + return (AttrNameInfo) attrNameInfoMap.get(shaderAttribute); + } + + } + + // Data associated with an attribute name + class AttrNameInfo { + void setLocation(ShaderAttrLoc loc) { + this.loc = loc; + } + + ShaderAttrLoc getLocation() { + return loc; + } + + void setType(int type) { + this.type = type; + } + + int getType() { + return type; + } + + boolean isArray() { + return isArray; + } + + void setArray(boolean isArray) { + this.isArray = isArray; + } + + // Location of attribute name in linked shader program + private ShaderAttrLoc loc; + + // boolean indicating whether the attribute is an array + private boolean isArray; + + // type of shader attribute + private int type; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ShaderRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ShaderRetained.java new file mode 100644 index 0000000..afcc9f2 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ShaderRetained.java @@ -0,0 +1,172 @@ +/* + * $RCSfile: ShaderRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * The ShaderRetained object is the abstract base class for programmable + * shader code. Currently, only text-based source code shaders are + * supported, so the only subclass of Shader is SourceCodeShader. We + * leave open the possibility for binary (object code) shaders in the + * future. + */ +abstract class ShaderRetained extends NodeComponentRetained { + int shadingLanguage; + int shaderType; + + // Each element in the array corresponds to a unique renderer if shared + // context or a unique canvas otherwise. + // shaderId use by native code. One per Canvas. + ShaderData[] shaderData; + + // Flag indicating whether a COMPILE_ERROR has occurred for this shader + // object. It is set in updateNative to indicate that the compileShader + // operation failed. It is cleared in setLive or clearLive. + // TODO KCR: Add code to clear this in setLive or clearLive + boolean compileErrorOccurred = false; + + // need to synchronize access from multiple rendering threads + Object resourceLock = new Object(); + + void initializeShader(int shadingLanguage, int shaderType) { + this.shadingLanguage = shadingLanguage; + this.shaderType = shaderType; + } + + int getShadingLanguage() { + return shadingLanguage; + } + + int getShaderType() { + return shaderType; + } + + void setLive(boolean inBackgroundGroup, int refCount) { + // System.err.println("SourceCodeShaderRetained.setLive()"); + super.setLive(inBackgroundGroup, refCount); + } + + void clearLive(int refCount) { + // System.err.println("SourceCodeShaderRetained.clearLive()"); + super.clearLive(refCount); + } + + /** + * Shader object doesn't really have mirror object. + * But it's using the updateMirrorObject interface to propagate + * the changes to the users + */ + synchronized void updateMirrorObject(int component, Object value) { + System.err.println("Shader.updateMirrorObject not implemented yet!"); + } + + void handleFrequencyChange(int bit) { + System.err.println("Shader.handleFrequencyChange not implemented yet!"); + } + + void createShaderData(int cvRdrIndex, long ctxTimeStamp) { + // Create shaderProgram resources if it has not been done. + synchronized(resourceLock) { + if (shaderData == null) { + shaderData = new ShaderData[cvRdrIndex+1]; + } else if (shaderData.length <= cvRdrIndex) { + ShaderData[] tempSData = new ShaderData[cvRdrIndex+1]; + + System.arraycopy(shaderData, 0, + tempSData, 0, + shaderData.length); + shaderData = tempSData; + } + + if (shaderData[cvRdrIndex] == null) { + shaderData[cvRdrIndex] = new ShaderData(); + } else if (shaderData[cvRdrIndex].getCtxTimeStamp() != ctxTimeStamp) { + // Issue 378 - reset the shader data for this canvas / renderer + // if the context has been recreated + shaderData[cvRdrIndex].reset(); + } + shaderData[cvRdrIndex].setCtxTimeStamp(ctxTimeStamp); + } + } + + + // Per-context (canvas) data for this shader + class ShaderData extends Object { + + // Issue 378 - time stamp of context creation for this canvas + private long ctxTimeStamp; + + // shaderId use by native code + private ShaderId shaderId = null; + + // indicated that the shader has been compiled for this canvas + private boolean compiled = false; + + /** ShaderProgramData Constructor */ + ShaderData() { + } + + void reset() { + ctxTimeStamp = 0L; + shaderId = null; + compiled = false; + } + + long getCtxTimeStamp() { + return ctxTimeStamp; + } + + void setCtxTimeStamp(long ctxTimeStamp) { + this.ctxTimeStamp = ctxTimeStamp; + } + + ShaderId getShaderId() { + return shaderId; + } + + void setShaderId(ShaderId shaderId) { + this.shaderId = shaderId; + } + + boolean isCompiled() { + return compiled; + } + + void setCompiled(boolean compiled) { + this.compiled = compiled; + } + + } + +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/Shape3D.java b/j3d-core/src/classes/share/javax/media/j3d/Shape3D.java new file mode 100644 index 0000000..9baa4d5 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Shape3D.java @@ -0,0 +1,794 @@ +/* + * $RCSfile: Shape3D.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Enumeration; + + +/** + * The Shape3D leaf node specifies all geometric objects. It contains + * a list of one or more Geometry component objects and a single + * Appearance component object. The geometry objects define the shape + * node's geometric data. The appearance object specifies that + * object's appearance attributes, including color, material, texture, + * and so on. + *

+ * The list of geometry objects must all be of the same equivalence + * class, that is, the same basic type of primitive. For subclasses + * of GeometryArray, all point objects are equivalent, all line + * objects are equivalent, and all polygon objects are equivalent. + * For other subclasses of Geometry, only objects of the same + * subclass are equivalent. The equivalence classes are as follows: + *

    + *
  • GeometryArray (point): [Indexed]PointArray
  • + *
  • GeometryArray (line): [Indexed]{LineArray, LineStripArray}
  • + *
  • GeometryArray (polygon): [Indexed]{TriangleArray, TriangleStripArray, + * TriangleFanArray, QuadArray}
  • + *
  • CompressedGeometry
  • + *
  • Raster
  • + *
  • Text3D
  • + *
+ *

+ * When Shape3D is used with multiple geometry components, Java 3D may + * choose to use individual geometry bounds instead of the shape's + * bounds for region of influence operations, such as lighting. + * For example, the individual characters of a Text3D shape object + * may be rendered with a different light set. + */ + +public class Shape3D extends Leaf { + + /** + * Id used in the compile optimization to determine + * how to get to the geometry in the case of read + * or picking .. + */ + int id; + + /** + * Specifies that the node allows read access to its geometry information. + */ + public static final int + ALLOW_GEOMETRY_READ = CapabilityBits.SHAPE3D_ALLOW_GEOMETRY_READ; + + /** + * Specifies that the node allows write access to its geometry information. + */ + public static final int + ALLOW_GEOMETRY_WRITE = CapabilityBits.SHAPE3D_ALLOW_GEOMETRY_WRITE; + + /** + * Specifies that the node allows read access to its appearance + * information. + */ + public static final int + ALLOW_APPEARANCE_READ = CapabilityBits.SHAPE3D_ALLOW_APPEARANCE_READ; + + /** + * Specifies that the node allows write access to its appearance + * information. + */ + public static final int + ALLOW_APPEARANCE_WRITE = CapabilityBits.SHAPE3D_ALLOW_APPEARANCE_WRITE; + + /** + * Specifies that the node allows reading its collision Bounds + */ + public static final int + ALLOW_COLLISION_BOUNDS_READ = CapabilityBits.SHAPE3D_ALLOW_COLLISION_BOUNDS_READ; + + /** + * Specifies the node allows writing its collision Bounds + */ + public static final int + ALLOW_COLLISION_BOUNDS_WRITE = CapabilityBits.SHAPE3D_ALLOW_COLLISION_BOUNDS_WRITE; + + /** + * Specifies that this node allows reading its appearance override + * enable flag. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_APPEARANCE_OVERRIDE_READ = + CapabilityBits.SHAPE3D_ALLOW_APPEARANCE_OVERRIDE_READ; + + /** + * Specifies that this node allows writing its appearance override + * enable flag. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_APPEARANCE_OVERRIDE_WRITE = + CapabilityBits.SHAPE3D_ALLOW_APPEARANCE_OVERRIDE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_GEOMETRY_READ, + ALLOW_APPEARANCE_READ, + ALLOW_COLLISION_BOUNDS_READ, + ALLOW_APPEARANCE_OVERRIDE_READ + }; + + /** + * Constructs a Shape3D node with default parameters. The default + * values are as follows: + *

    + * appearance : null
    + * geometry : { null }
    + * collision bounds : null
    + * appearance override enable : false
    + *
+ * The list of geometry components is initialized with a null + * geometry component as the single element with an index of 0. + * A null geometry component specifies + * that no geometry is drawn. A null appearance component specifies + * that default values are used for all appearance attributes. + */ + public Shape3D() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a Shape3D node with the specified + * geometry component and a null appearance component. + * The list of geometry components is initialized with the + * specified geometry component as the single element with an + * index of 0. + * A null appearance component specifies that default values are + * used for all appearance attributes. + * @param geometry the geometry component with which to initialize + * this shape node. + */ + public Shape3D(Geometry geometry) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((Shape3DRetained)retained).setGeometry(geometry, 0); + } + + /** + * Constructs and initializes a Shape3D node with the specified + * geometry and appearance components. + * The list of geometry components is initialized with the + * specified geometry component as the single element with an + * index of 0. + * @param geometry the geometry component with which to initialize + * this shape node + * @param appearance the appearance component of the shape node + */ + public Shape3D(Geometry geometry, Appearance appearance) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((Shape3DRetained)retained).setGeometry(geometry, 0); + ((Shape3DRetained)retained).setAppearance(appearance); + } + + /** + * Creates the retained mode Shape3DRetained object that this + * Shape3D object will point to. + */ + void createRetained() { + retained = new Shape3DRetained(); + retained.setSource(this); + } + + /** + * Sets the collision bounds of a node. + * @param bounds the collision bounding object for a node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setCollisionBounds(Bounds bounds) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLLISION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D0")); + + ((Shape3DRetained)this.retained).setCollisionBounds(bounds); + } + + /** + * Returns the collision bounding object of this node. + * @return the node's collision bounding object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getCollisionBounds() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLLISION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D1")); + + return ((Shape3DRetained)this.retained).getCollisionBounds(id); + } + + + /** + * Replaces the geometry component at index 0 in this Shape3D node's + * list of geometry components with the specified geometry component. + * If there are existing geometry components in the list (besides + * the one being replaced), the new geometry component must be of + * the same equivalence class (point, line, polygon, CompressedGeometry, + * Raster, Text3D) as the others. + * @param geometry the geometry component to be stored at index 0. + * @exception IllegalArgumentException if the new geometry + * component is not of of the same equivalence class as the + * existing geometry components. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setGeometry(Geometry geometry) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D2")); + + ((Shape3DRetained)retained).setGeometry(geometry, 0); + } + + /** + * Retrieves the geometry component at index 0 from this Shape3D node's + * list of geometry components. + * @return the geometry component at index 0. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Geometry getGeometry() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D3")); + + return ((Shape3DRetained)retained).getGeometry(0, id); + } + + + /** + * Replaces the geometry component at the specified index in this + * Shape3D node's list of geometry components with the specified + * geometry component. + * If there are existing geometry components in the list (besides + * the one being replaced), the new geometry component must be of + * the same equivalence class (point, line, polygon, CompressedGeometry, + * Raster, Text3D) as the others. + * @param geometry the geometry component to be stored at the + * specified index. + * @param index the index of the geometry component to be replaced. + * @exception IllegalArgumentException if the new geometry + * component is not of of the same equivalence class as the + * existing geometry components. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public void setGeometry(Geometry geometry, int index) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D2")); + + ((Shape3DRetained)retained).setGeometry(geometry, index); + } + + + /** + * Retrieves the geometry component at the specified index from + * this Shape3D node's list of geometry components. + * @param index the index of the geometry component to be returned. + * @return the geometry component at the specified index. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public Geometry getGeometry(int index) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D3")); + + return ((Shape3DRetained)retained).getGeometry(index, id); + } + + + /** + * Inserts the specified geometry component into this Shape3D + * node's list of geometry components at the specified index. + * If there are existing geometry components in the list, the new + * geometry component must be of the same equivalence class + * (point, line, polygon, CompressedGeometry, Raster, Text3D) as + * the others. + * @param geometry the geometry component to be inserted at the + * specified index. + * @param index the index at which the geometry component is inserted. + * @exception IllegalArgumentException if the new geometry + * component is not of of the same equivalence class as the + * existing geometry components. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public void insertGeometry(Geometry geometry, int index) { + + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_GEOMETRY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D2")); + + ((Shape3DRetained)retained).insertGeometry(geometry, index); + } + + + /** + * Removes the geometry component at the specified index from + * this Shape3D node's list of geometry components. + * @param index the index of the geometry component to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public void removeGeometry(int index) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D2")); + + ((Shape3DRetained)retained).removeGeometry(index); + } + + + /** + * Returns an enumeration of this Shape3D node's list of geometry + * components. + * @return an Enumeration object containing all geometry components in + * this Shape3D node's list of geometry components. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public Enumeration getAllGeometries() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D3")); + + return ((Shape3DRetained)retained).getAllGeometries(id); + } + + + /** + * Appends the specified geometry component to this Shape3D + * node's list of geometry components. + * If there are existing geometry components in the list, the new + * geometry component must be of the same equivalence class + * (point, line, polygon, CompressedGeometry, Raster, Text3D) as + * the others. + * @param geometry the geometry component to be appended. + * @exception IllegalArgumentException if the new geometry + * component is not of of the same equivalence class as the + * existing geometry components. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public void addGeometry(Geometry geometry) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D2")); + + ((Shape3DRetained)retained).addGeometry(geometry); + } + + + /** + * Returns the number of geometry components in this Shape3D node's + * list of geometry components. + * @return the number of geometry components in this Shape3D node's + * list of geometry components. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int numGeometries() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D3")); + return ((Shape3DRetained)retained).numGeometries(id); + } + + + /** + * Retrieves the index of the specified geometry component in + * this Shape3D node's list of geometry components. + * + * @param geometry the geometry component to be looked up. + * @return the index of the specified geometry component; + * returns -1 if the object is not in the list. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int indexOfGeometry(Geometry geometry) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D3")); + return ((Shape3DRetained)retained).indexOfGeometry(geometry); + } + + + /** + * Removes the specified geometry component from this + * Shape3D node's list of geometry components. + * If the specified object is not in the list, the list is not modified. + * + * @param geometry the geometry component to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeGeometry(Geometry geometry) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D2")); + ((Shape3DRetained)retained).removeGeometry(geometry); + } + + + /** + * Removes all geometry components from this Shape3D node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeAllGeometries() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_GEOMETRY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D2")); + ((Shape3DRetained)retained).removeAllGeometries(); + } + + + /** + * Sets the appearance component of this Shape3D node. Setting it to null + * specifies that default values are used for all appearance attributes. + * @param appearance the new appearance component for this shape node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAppearance(Appearance appearance) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_APPEARANCE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D4")); + + ((Shape3DRetained)this.retained).setAppearance(appearance); + } + + /** + * Retrieves the appearance component of this shape node. + * @return the appearance component of this shape node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Appearance getAppearance() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_APPEARANCE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D5")); + + return ((Shape3DRetained)this.retained).getAppearance(); + } + + + /** + * Checks whether the geometry in this shape node intersects with + * the specified pickShape. + * + * @param path the SceneGraphPath to this shape node + * @param pickShape the PickShape to be intersected + * + * @return true if the pick shape intersects this node; false + * otherwise. + * + * @exception IllegalArgumentException if pickShape is a PickPoint. + * Java 3D doesn't have spatial information of the surface. + * Use PickBounds with BoundingSphere and a small radius, instead. + * + * @exception CapabilityNotSetException if the Geometry.ALLOW_INTERSECT + * capability bit is not set in all of the Geometry objects + * referred to by this shape node. + */ + public boolean intersect(SceneGraphPath path, PickShape pickShape) { + return intersect(path, pickShape, null); + } + + + /** + * Checks whether the geometry in this shape node intersects with + * the specified pickRay. + * + * @param path the SceneGraphPath to this shape node + * @param pickRay the PickRay to be intersected + * @param dist the closest distance of the intersection + * + * @return true if the pick shape intersects this node; false + * otherwise. If true, dist contains the closest distance of + * intersection. + * + * @exception CapabilityNotSetException if the Geometry.ALLOW_INTERSECT + * capability bit is not set in all of the Geometry objects + * referred to by this shape node. + */ + public boolean intersect(SceneGraphPath path, + PickRay pickRay, + double[] dist) { + + if (isLiveOrCompiled()) { + if (!((Shape3DRetained)retained).allowIntersect()) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D6")); + } + return ((Shape3DRetained)this.retained).intersect(path, pickRay, dist); + + } + + /** + * Checks whether the geometry in this shape node intersects with + * the specified pickShape. + * + * @param path the SceneGraphPath to this shape node + * @param pickShape the PickShape to be intersected + * @param dist the closest distance of the intersection + * + * @return true if the pick shape intersects this node; false + * otherwise. If true, dist contains the closest distance of + * intersection. + * + * @exception IllegalArgumentException if pickShape is a PickPoint. + * Java 3D doesn't have spatial information of the surface. + * Use PickBounds with BoundingSphere and a small radius, instead. + * + * @exception CapabilityNotSetException if the Geometry.ALLOW_INTERSECT + * capability bit is not set in all of the Geometry objects + * referred to by this shape node. + * + * @since Java 3D 1.3 + */ + public boolean intersect(SceneGraphPath path, + PickShape pickShape, + double[] dist) { + + if (isLiveOrCompiled()) { + if (!((Shape3DRetained)retained).allowIntersect()) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D6")); + } + + if (pickShape instanceof PickPoint) { + throw new IllegalArgumentException(J3dI18N.getString("Shape3D7")); + } + + return ((Shape3DRetained)this.retained).intersect(path, pickShape, dist); + } + + + /** + * Sets a flag that indicates whether this node's appearance can + * be overridden. If the flag is true, then this node's + * appearance may be overridden by an AlternateAppearance leaf + * node, regardless of the value of the ALLOW_APPEARANCE_WRITE + * capability bit. + * The default value is false. + * + * @param flag the apperance override enable flag. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see AlternateAppearance + * + * @since Java 3D 1.2 + */ + public void setAppearanceOverrideEnable(boolean flag) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_APPEARANCE_OVERRIDE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D8")); + + ((Shape3DRetained)this.retained).setAppearanceOverrideEnable(flag); + } + + /** + * Retrieves the appearanceOverrideEnable flag for this node. + * @return true if the appearance can be overridden; false + * otherwise. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public boolean getAppearanceOverrideEnable() { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_APPEARANCE_OVERRIDE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Shape3D9")); + + return ((Shape3DRetained)this.retained).getAppearanceOverrideEnable(); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * cloneNode should be overridden by any user subclassed + * objects. All subclasses must have their cloneNode + * method consist of the following lines: + *

+     *     public Node cloneNode(boolean forceDuplicate) {
+     *         UserSubClass usc = new UserSubClass();
+     *         usc.duplicateNode(this, forceDuplicate);
+     *         return usc;
+     *     }
+     * 
+ * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Shape3D s = new Shape3D(); + s.duplicateNode(this, forceDuplicate); + return s; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @exception ClassCastException if originalNode is not an instance of + * Shape3D + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + checkDuplicateNode(originalNode, forceDuplicate); + } + + + + /** + * Copies all Shape3D information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + + super.duplicateAttributes(originalNode, forceDuplicate); + + Shape3DRetained attr = (Shape3DRetained) originalNode.retained; + Shape3DRetained rt = (Shape3DRetained) retained; + + rt.setAppearance((Appearance) getNodeComponent( + attr.getAppearance(), + forceDuplicate, + originalNode.nodeHashtable)); + int num = attr.numGeometries(id); + if (num > 0) { + rt.setGeometry((Geometry) getNodeComponent( + attr.getGeometry(0, id), + forceDuplicate, + originalNode.nodeHashtable), 0); + for(int i=1; i< num; i++) { + rt.addGeometry((Geometry) getNodeComponent( + attr.getGeometry(i, id), + forceDuplicate, + originalNode.nodeHashtable)); + } + } + + rt.setCollisionBounds(attr.getCollisionBounds(id)); + } + + /** + * See parent class for the documentation on getBounds(). + */ + public Bounds getBounds() { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_BOUNDS_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("Node2")); + } + } else { + // this will throw a SceneGraphCycleException if there is + // a cycle + checkForCycle(); + } + + return ((Shape3DRetained)this.retained).getBounds(); + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Shape3DCompileRetained.java b/j3d-core/src/classes/share/javax/media/j3d/Shape3DCompileRetained.java new file mode 100644 index 0000000..81022f4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Shape3DCompileRetained.java @@ -0,0 +1,552 @@ +/* + * $RCSfile: Shape3DCompileRetained.java,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.*; + +/** + * A leaf node that holds a merged shapes in compile mode + */ +class Shape3DCompileRetained extends Shape3DRetained { + + + int numShapes = 0; + + // Each element in the arraylist is an array of geometries for a + // particular merged shape + ArrayList geometryInfo = null; + + + Object[] srcList = null; + + Shape3DCompileRetained(Shape3DRetained[] shapes, int nShapes, int compileFlags) { + int i, j; + Shape3DRetained shape; + GeometryArrayRetained geo; + Vector list; + // Merged list, only merged if geometry is mergeable + Object[] mergedList = new Object[GeometryRetained.GEO_TYPE_GEOMETRYARRAY+1]; + // Sorted list of separate geometry by geoType + Object[] separateList = new Object[GeometryRetained.GEO_TYPE_GEOMETRYARRAY+1]; + + // Assign the num of shapes + numShapes = nShapes; + + Bounds shapeBounds; + + srcList = new Object[nShapes]; + + if (nShapes > 0) { + boundsAutoCompute = shapes[0].boundsAutoCompute; + source = shapes[0].source; + } + + // Remove the null that was added by Shape3DRetained constructor + geometryList.remove(0); + int geoIndex = 0; + + + + // Assign the fields for this compile shape + boundsAutoCompute = shapes[0].boundsAutoCompute; + isPickable = shapes[0].isPickable; + isCollidable = shapes[0].isCollidable; + appearanceOverrideEnable = shapes[0].appearanceOverrideEnable; + appearance = shapes[0].appearance; + collisionBound = shapes[0].collisionBound; + localBounds = shapes[0].localBounds; + + + if ((compileFlags & CompileState.GEOMETRY_READ) != 0) + geometryInfo = new ArrayList(); + + for (i = 0; i < nShapes; i++) { + shape = shapes[i]; + ((Shape3D)shape.source).id = i; + shape.source.retained = this; + srcList[i] = shape.source; + // If the transform has been pushd down + // to the shape, don't merge its geometry with other shapes + // geometry + // Put it in a separate list sorted by geo_type + // Have to handle shape.isPickable + + for (j = 0; j < shape.geometryList.size(); j++) { + geo = (GeometryArrayRetained)shape.geometryList.get(j); + if (geo != null) { + if (shape.willRemainOpaque(geo.geoType) && geo.isMergeable()) { + if (mergedList[geo.geoType] == null) { + mergedList[geo.geoType] = new ArrayList(); + } + ((ArrayList)mergedList[geo.geoType]).add(geo); + } + else { + // Keep a sorted list based on geoType; + if (separateList[geo.geoType] == null) { + separateList[geo.geoType] = new ArrayList(); + } + // add it to the geometryList separately + ((ArrayList)separateList[geo.geoType]).add(geo); + } + } + + } + + // Point to the geometryList's source, so the + // retained side will be garbage collected + if ((compileFlags & CompileState.GEOMETRY_READ) != 0) { + ArrayList sList = new ArrayList(); + for (j = 0; j < shape.geometryList.size(); j++) { + GeometryRetained g = (GeometryRetained)shape.geometryList.get(j); + if (g != null) + sList.add(g.source); + else + sList.add(null); + } + geometryInfo.add(sList); + } + + } + // Now, merged the mergelist and separate list based on geoType, + // this enables dlist optmization + for (i = 1; i <= GeometryRetained.GEO_TYPE_GEOMETRYARRAY; i++) { + GeometryArrayRetained cgeo = null; + ArrayList curList; + switch (i) { + case GeometryArrayRetained.GEO_TYPE_QUAD_SET: + if (mergedList[i] != null) { + cgeo = new QuadArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_TRI_SET: + if (mergedList[i] != null) { + cgeo = new TriangleArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_POINT_SET: + if (mergedList[i] != null) { + cgeo = new PointArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_LINE_SET: + if (mergedList[i] != null) { + cgeo = new LineArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_TRI_STRIP_SET: + if (mergedList[i] != null) { + cgeo = new TriangleStripArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_TRI_FAN_SET: + if (mergedList[i] != null) { + cgeo = new TriangleFanArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_LINE_STRIP_SET: + if (mergedList[i] != null) { + cgeo = new LineStripArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_INDEXED_QUAD_SET: + if (mergedList[i] != null) { + cgeo = new IndexedQuadArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_INDEXED_TRI_SET: + if (mergedList[i] != null) { + cgeo = new IndexedTriangleArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_INDEXED_POINT_SET: + if (mergedList[i] != null) { + cgeo = new IndexedPointArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_INDEXED_LINE_SET: + if (mergedList[i] != null) { + cgeo = new IndexedLineArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET: + if (mergedList[i] != null) { + cgeo = new IndexedTriangleStripArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_INDEXED_TRI_FAN_SET: + if (mergedList[i] != null) { + cgeo = new IndexedTriangleFanArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + case GeometryArrayRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + if (mergedList[i] != null) { + cgeo = new IndexedLineStripArrayRetained(); + curList = (ArrayList)mergedList[i]; + cgeo.setCompiled(curList); + geometryList.add(cgeo); + cgeo.setSource(((SceneGraphObjectRetained)curList.get(0)).source); + } + if (separateList[i] != null) { + ArrayList glist = (ArrayList)separateList[i]; + for (int k = 0; k < glist.size(); k++) { + geometryList.add(glist.get(k)); + } + + } + break; + } + } + + + } + + + Bounds getCollisionBounds(int childIndex) { + return collisionBound; + } + + + int numGeometries(int childIndex) { + ArrayList geo = (ArrayList) geometryInfo.get(childIndex); + return geo.size(); + } + + + Geometry getGeometry(int i, int childIndex) { + ArrayList geoInfo = (ArrayList) geometryInfo.get(childIndex); + return (Geometry)geoInfo.get(i); + + + } + + Enumeration getAllGeometries(int childIndex) { + ArrayList geoInfo = (ArrayList) geometryInfo.get(childIndex); + Vector geomList = new Vector(); + + for(int i=0; ipath is + * invalid. + */ + boolean intersect(SceneGraphPath path, + PickShape pickShape, double[] dist) { + + int flags; + PickInfo pickInfo = new PickInfo(); + + Transform3D localToVworld = path.getTransform(); + if (localToVworld == null) { + throw new IllegalArgumentException(J3dI18N.getString("Shape3DRetained3")); + } + pickInfo.setLocalToVWorldRef( localToVworld); + + Shape3D shape = (Shape3D) path.getObject(); + // Get the geometries for this shape only, since the compiled + // geomtryList contains several shapes + ArrayList glist = (ArrayList) geometryInfo.get(shape.id); + + // System.err.println("Shape3DCompileRetained.intersect() : "); + if (dist == null) { + // System.err.println(" no dist request ...."); + return intersect(pickInfo, pickShape, 0, glist); + } + + flags = PickInfo.CLOSEST_DISTANCE; + if (intersect(pickInfo, pickShape, flags, glist)) { + dist[0] = pickInfo.getClosestDistance(); + return true; + } + + return false; + + } + + boolean intersect(PickInfo pickInfo, PickShape pickShape, int flags, + ArrayList geometryList) { + + Transform3D localToVworld = pickInfo.getLocalToVWorldRef(); + + Transform3D t3d = new Transform3D(); + t3d.invert(localToVworld); + PickShape newPS = pickShape.transform(t3d); + + int geomListSize = geometryList.size(); + GeometryRetained geometry; + + if (((flags & PickInfo.CLOSEST_INTERSECTION_POINT) == 0) && + ((flags & PickInfo.CLOSEST_DISTANCE) == 0) && + ((flags & PickInfo.CLOSEST_GEOM_INFO) == 0) && + ((flags & PickInfo.ALL_GEOM_INFO) == 0)) { + + for (int i=0; i < geomListSize; i++) { + geometry = (GeometryRetained) geometryList.get(i); + if (geometry != null) { + if (geometry.mirrorGeometry != null) { + geometry = geometry.mirrorGeometry; + } + // Need to modify this method + // if (geometry.intersect(newPS, null, null)) { + if (geometry.intersect(newPS, null, 0, null, null, 0)) { + return true; + } + } + } + } + else { + double distance; + double minDist = Double.POSITIVE_INFINITY; + Point3d closestIPnt = new Point3d(); + Point3d iPnt = new Point3d(); + Point3d iPntVW = new Point3d(); + + for (int i=0; i < geomListSize; i++) { + geometry = (GeometryRetained) geometryList.get(i); + if (geometry != null) { + if (geometry.mirrorGeometry != null) { + geometry = geometry.mirrorGeometry; + } + if (geometry.intersect(newPS, pickInfo, flags, iPnt, geometry, i)) { + + iPntVW.set(iPnt); + localToVworld.transform(iPntVW); + distance = pickShape.distance(iPntVW); + + if (minDist > distance) { + minDist = distance; + closestIPnt.set(iPnt); + } + } + } + } + + if (minDist < Double.POSITIVE_INFINITY) { + if ((flags & PickInfo.CLOSEST_DISTANCE) != 0) { + pickInfo.setClosestDistance(minDist); + } + if((flags & PickInfo.CLOSEST_INTERSECTION_POINT) != 0) { + pickInfo.setClosestIntersectionPoint(closestIPnt); + } + return true; + } + } + + return false; + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Shape3DRetained.java b/j3d-core/src/classes/share/javax/media/j3d/Shape3DRetained.java new file mode 100644 index 0000000..f00e8b0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Shape3DRetained.java @@ -0,0 +1,2846 @@ +/* + * $RCSfile: Shape3DRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.12 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Vector; + +/** + * A shape leaf node consisting of geometry and appearance properties. + */ + +class Shape3DRetained extends LeafRetained { + + static final int GEOMETRY_CHANGED = 0x00001; + static final int APPEARANCE_CHANGED = 0x00002; + static final int COLLISION_CHANGED = 0x00004; + static final int BOUNDS_CHANGED = 0x00008; + static final int APPEARANCEOVERRIDE_CHANGED = 0x00010; + static final int LAST_DEFINED_BIT = 0x00010; + + + // Target threads to be notified when light changes + static final int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | + J3dThread.UPDATE_RENDER; + + /** + * The appearance component of the shape node. + */ + AppearanceRetained appearance = null; + + /** + * The arraylist of geometry component of the shape node. + */ + ArrayList geometryList = null; + + /** + * A 2D storage of all geometry atoms associated with this shape node. + * There may be more than one geometry for a Shape3D node. + * Do not change the following private variables to public, its access need to synchronize + * via mirrorShape3DLock. + */ + + // geomAtomArr should always be a 1 element array, unless S3D contains multiple Text3Ds. + private GeometryAtom geomAtom = null; + + /** + * To sychronize access of the mirrorShape3D's geomAtomArray*. + * A multiple read single write Lock to sychronize access into mirrorShape3D. + * To prevent deadlock a call to read/write lock must end with a read/write unlock + * respectively. + */ + private MRSWLock mirrorShape3DLock = null; + + /** + * The mirror Shape3DRetained nodes for this object. There is one + * mirror for each instance of this Shape3D node. If it is not in + * a SharedGroup, only index 0 is valid. + * Do not change the following private variables to public, its access need to synchronize + * via mirrorShape3DLock. + */ + ArrayList mirrorShape3D = new ArrayList(1); + + /** + * This field is used for mirror Shape3D nodes accessing their + * original nodes. It is a NodeRetained because the original + * node may be a Shape3DRetained or a MorphRetained node. + */ + NodeRetained sourceNode = null; + + /** + * The hashkey for this Shape3DRetained mirror object + */ + HashKey key = null; + + // This is true when this geometry is referenced in an IMM mode context + boolean inImmCtx = false; + + // A bitmask to indicate when something has changed + int isDirty = 0xffff; + + // The list of lights that are scoped to this node + LightRetained[] lights =null; + + // The number of lights in the above array, may be less than lights.length + int numlights = 0; + + // The list of fogs that are scoped to this node + FogRetained[] fogs = null; + + // The number of fogs in the above array, may be less than fogs.length + int numfogs = 0; + + // The list of modelClips that are scoped to this node + ModelClipRetained[] modelClips = null; + + // The number of modelClips in the above array, may be less than modelClips.length + int numModelClips = 0; + + // The list of alt app that are scoped to this node + AlternateAppearanceRetained[] altApps = null; + + //The number of alt app in the above array, may be less than alt app.length + int numAltApps = 0; + + /** + * Reference to the BranchGroup path of this mirror shape + * This is used for picking and GeometryStructure only. + */ + BranchGroupRetained branchGroupPath[]; + + // cache value for picking in mirror shape. + // True if all the node of the path from this to root are all pickable + boolean isPickable = true; + + // cache value for collidable in mirror shape. + // True if all the node of the path from this to root are all collidable + boolean isCollidable = true; + + // closest switch parent + SwitchRetained closestSwitchParent = null; + + // the child index from the closest switch parent + int closestSwitchIndex = -1; + + // Is this S3D visible ? The default is true. + boolean visible = true; + + // Whether the normal appearance is overrided by the alternate app + boolean appearanceOverrideEnable = false; + + // AlternateAppearance retained that is applicable to this + // mirror shape when the override flag is true + AppearanceRetained otherAppearance = null; + + // geometry Bounds in local coordinate + Bounds bounds = null; + + // geometry Bounds in virtual world coordinate + BoundingBox vwcBounds = null; + + // collision Bounds in local coordinate + Bounds collisionBound = null; + + // collision Bounds in virtual world coordinate + Bounds collisionVwcBound = null; + + // a path of OrderedGroup, childrenId pairs which leads to this node + OrderedPath orderedPath = null; + + // List of views that a mirror object is scoped to + ArrayList viewList = null; + + int changedFrequent = 0; + + Shape3DRetained() { + super(); + this.nodeType = NodeRetained.SHAPE; + numlights = 0; + numfogs = 0; + numModelClips = 0; + numAltApps = 0; + localBounds = new BoundingBox((BoundingBox) null); + + mirrorShape3DLock = new MRSWLock(); + geometryList = new ArrayList(1); + geometryList.add(null); + } + + /** + * Sets the collision bounds of a node. + * @param bounds the bounding object for the node + */ + void setCollisionBounds(Bounds bounds) { + if (bounds == null) { + this.collisionBound = null; + } else { + this.collisionBound = (Bounds)bounds.clone(); + } + + if (source.isLive()) { + // Notify Geometry Structure to check for collision + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.COLLISION_BOUND_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM; + message.universe = universe; + message.args[0] = getGeomAtomsArray(mirrorShape3D); + // no need to clone collisionBound + message.args[1] = collisionBound; + VirtualUniverse.mc.processMessage(message); + } + } + + Bounds getLocalBounds(Bounds bounds) { + if(localBounds != null) { + localBounds.set(bounds); + } + else { + localBounds = new BoundingBox(bounds); + } + return localBounds; + } + + + /** + * Sets the geometric bounds of a node. + * @param bounds the bounding object for the node + */ + void setBounds(Bounds bounds) { + super.setBounds(bounds); + + if (source.isLive() && !boundsAutoCompute) { + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.REGION_BOUND_CHANGED; + message.threads = J3dThread.UPDATE_TRANSFORM | + J3dThread.UPDATE_GEOMETRY | + J3dThread.UPDATE_RENDER; + + message.universe = universe; + message.args[0] = getGeomAtomsArray(mirrorShape3D); + // no need to clone localBounds + message.args[1] = localBounds; + VirtualUniverse.mc.processMessage(message); + } + } + + /** + * Gets the collision bounds of a node. + * @return the node's bounding object + */ + Bounds getCollisionBounds(int id) { + return (collisionBound == null ? + null: (Bounds)collisionBound.clone()); + } + + /** + * Appends the specified geometry component to this Shape3D + * node's list of geometry components. + * If there are existing geometry components in the list, the new + * geometry component must be of the same equivalence class + * (point, line, polygon, CompressedGeometry, Raster, Text3D) as + * the others. + * @param geometry the geometry component to be appended. + * @exception IllegalArgumentException if the new geometry + * component is not of of the same equivalence class as the + * existing geometry components. + * + * @since Java 3D 1.2 + */ + void addGeometry(Geometry geometry) { + int i; + Shape3DRetained s; + GeometryRetained newGeom = null; + + checkEquivalenceClass(geometry, -1); + + if(((Shape3D)this.source).isLive()) { + if (geometry != null) { + + newGeom = ((GeometryRetained)geometry.retained); + newGeom.setLive(inBackgroundGroup, refCount); + + geometryList.add(newGeom); + + } else { + geometryList.add(null); + newGeom = null; + } + sendDataChangedMessage(newGeom); + + } else { + if (geometry != null) { + geometryList.add((GeometryRetained) geometry.retained); + } else { + geometryList.add(null); + } + } + dirtyBoundsCache(); + } + + /** + * Replaces the geometry component at the specified index in this + * Shape3D node's list of geometry components with the specified + * geometry component. + * If there are existing geometry components in the list (besides + * the one being replaced), the new geometry component must be of + * the same equivalence class (point, line, polygon, CompressedGeometry, + * Raster, Text3D) as the others. + * @param geometry the geometry component to be stored at the + * specified index. + * @param index the index of the geometry component to be replaced. + * @exception IllegalArgumentException if the new geometry + * component is not of of the same equivalence class as the + * existing geometry components. + * + * @since Java 3D 1.2 + */ + void setGeometry(Geometry geometry, int index) { + int i; + Shape3DRetained mShape; + GeometryRetained newGeom = null; + GeometryRetained oldGeom = null; + + checkEquivalenceClass(geometry, index); + + if (((Shape3D)this.source).isLive()) { + + oldGeom = (GeometryRetained) (geometryList.get(index)); + if (oldGeom != null) { + oldGeom.clearLive(refCount); + for (i=0; i distance) { + minDist = distance; + closestIPnt.set(iPnt); + } + } + } + } + + if (minDist < Double.POSITIVE_INFINITY) { + if ((flags & PickInfo.CLOSEST_DISTANCE) != 0) { + pickInfo.setClosestDistance(minDist); + } + if((flags & PickInfo.CLOSEST_INTERSECTION_POINT) != 0) { + pickInfo.setClosestIntersectionPoint(closestIPnt); + } + return true; + } + } + + return false; + + } + + + /** + * Check if the geometry component of this shape node under path + * intersects with the pickShape. + * This is an expensive method. It should only be called if and only + * if the path's bound intersects pickShape. + * @exception IllegalArgumentException if path is + * invalid. + */ + + boolean intersect(SceneGraphPath path, + PickShape pickShape, double[] dist) { + + int flags; + PickInfo pickInfo = new PickInfo(); + + Transform3D localToVworld = path.getTransform(); + if (localToVworld == null) { + throw new IllegalArgumentException(J3dI18N.getString("Shape3DRetained3")); + } + pickInfo.setLocalToVWorldRef( localToVworld); + //System.err.println("Shape3DRetained.intersect() : "); + if (dist == null) { + //System.err.println(" no dist request ...."); + return intersect(pickInfo, pickShape, 0); + } + + flags = PickInfo.CLOSEST_DISTANCE; + if (intersect(pickInfo, pickShape, flags)) { + dist[0] = pickInfo.getClosestDistance(); + return true; + } + + return false; + + } + + /** + * This sets the immedate mode context flag + */ + void setInImmCtx(boolean inCtx) { + inImmCtx = inCtx; + } + + /** + * This gets the immedate mode context flag + */ + boolean getInImmCtx() { + return (inImmCtx); + } + + /** + * This updates the mirror shape to reflect the state of the + * real shape3d. + */ + private void initMirrorShape3D(SetLiveState s, Shape3DRetained ms, int index) { + + // New 1.2.1 code + + ms.inBackgroundGroup = inBackgroundGroup; + ms.geometryBackground = geometryBackground; + ms.source = source; + ms.universe = universe; + // Has to be false. We have a instance of mirror for every link to the shape3d. + ms.inSharedGroup = false; + ms.locale = locale; + ms.parent = parent; + + // New 1.3.2 + // Used when user supplied their own bounds for transparency sorting + // GeometryAtom uses this to change how it computes the centroid + ms.boundsAutoCompute = boundsAutoCompute; + ms.localBounds = localBounds; + // End new 1.3.2 + + OrderedPath op = (OrderedPath)s.orderedPaths.get(index); + if (op.pathElements.size() == 0) { + ms.orderedPath = null; + } else { + ms.orderedPath = op; +/* + System.err.println("initMirrorShape3D ms.orderedPath "); + ms.orderedPath.printPath(); +*/ + } + + // all mirror shapes point to the same transformGroupRetained + // for the static transform + ms.staticTransform = staticTransform; + + + ms.appearanceOverrideEnable = appearanceOverrideEnable; + + ms.geometryList = geometryList; + + // Assign the parent of this mirror shape node + ms.sourceNode = this; + + if (this instanceof OrientedShape3DRetained) { + OrientedShape3DRetained os = (OrientedShape3DRetained)this; + OrientedShape3DRetained oms = (OrientedShape3DRetained)ms; + oms.initAlignmentMode(os.mode); + oms.initAlignmentAxis(os.axis); + oms.initRotationPoint(os.rotationPoint); + oms.initConstantScaleEnable(os.constantScale); + oms.initScale(os.scaleFactor); + } + + } + + void updateImmediateMirrorObject(Object[] objs) { + int component = ((Integer)objs[1]).intValue(); + GeometryArrayRetained ga; + + Shape3DRetained[] msArr = (Shape3DRetained[]) objs[2]; + int i, j; + if ((component & APPEARANCE_CHANGED) != 0) { + Object[] arg = (Object[])objs[3]; + int val = ((Integer)arg[1]).intValue(); + for ( i = msArr.length-1; i >=0; i--) { + msArr[i].appearance = (AppearanceRetained)arg[0]; + msArr[i].changedFrequent = val; + } + } + if ((component & APPEARANCEOVERRIDE_CHANGED) != 0) { + Object[] arg = (Object[])objs[3]; + int val = ((Integer)arg[1]).intValue(); + for ( i = msArr.length-1; i >=0; i--) { + msArr[i].appearanceOverrideEnable = ((Boolean)arg[0]).booleanValue(); + msArr[i].changedFrequent = val; + } + } + } + + /** + * Gets the bounding object of a node. + * @return the node's bounding object + */ + + Bounds getBounds() { + + if(boundsAutoCompute) { + // System.err.println("getBounds ---- localBounds is " + localBounds); + // Issue 514 : NPE in Wonderland : triggered in cached bounds computation + if (validCachedBounds) { + return (Bounds) cachedBounds.clone(); + } + + if(geometryList != null) { + BoundingBox bbox = new BoundingBox((Bounds) null); + GeometryRetained geometry; + for(int i=0; i 1) { + return false; + } + alphaEditable = isAlphaEditable(geo); + if (geo instanceof GeometryArrayRetained) { + geo.isEditable = !((GeometryArrayRetained)geo).isWriteStatic(); + + // TODO: for now if vertex data can be returned, then + // don't apply static transform + if (geo.source.getCapability( + GeometryArray.ALLOW_COORDINATE_READ) || + geo.source.getCapability( + GeometryArray.ALLOW_NORMAL_READ)) + return false; + + } + + if (!geo.canBeInDisplayList(alphaEditable)) { + return false; + } + } + } + return true; + } + + + void compile(CompileState compState) { + AppearanceRetained newApp; + + super.compile(compState); + + if (isStatic() && staticXformCanBeApplied()) { + mergeFlag = SceneGraphObjectRetained.MERGE; + if (J3dDebug.devPhase && J3dDebug.debug) { + compState.numShapesWStaticTG++; + } + } else + { + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + compState.keepTG = true; + } + + if (J3dDebug.devPhase && J3dDebug.debug) { + compState.numShapes++; + } + + if (appearance != null) { + appearance.compile(compState); + // Non-static apperanace can still be compiled, since in compile + // state we will be grouping all shapes that have same appearance + // so, when the appearance changes, all the shapes will be affected + // For non-static appearances, we don't get an equivalent appearance + // from the compile state + if (appearance.isStatic()) { + newApp = compState.getAppearance(appearance); + appearance = newApp; + } + } + + for (int i = 0; i < geometryList.size(); i++) { + GeometryRetained geo = (GeometryRetained)geometryList.get(i); + if (geo != null) + geo.compile(compState); + } + + } + + void merge(CompileState compState) { + + + if (mergeFlag == SceneGraphObjectRetained.DONT_MERGE) { + + // no need to save the staticTransform here + + TransformGroupRetained saveStaticTransform = + compState.staticTransform; + compState.staticTransform = null; + super.merge(compState); + compState.staticTransform = saveStaticTransform; + } else { + super.merge(compState); + } + + if (shapeIsMergeable(compState)) { + compState.addShape(this); + } + } + + + boolean shapeIsMergeable(CompileState compState) { + boolean mergeable = true; + AppearanceRetained newApp; + int i; + + GeometryRetained geometry = null; + int index = 0; + i = 0; + /* + if (isPickable) + return false; + */ + + // For now, don't merge if the shape has static transform + if (staticTransform != null) + return false; + + // If this shape's to be immediate parent is orderedGroup or a switchNode + // this shape is not mergerable + if (parent instanceof OrderedGroupRetained || + parent instanceof SwitchRetained) + return false; + + // Get the first geometry that is non-null + while (geometry == null && index < geometryList.size()) { + geometry = (GeometryRetained) geometryList.get(index); + index++; + } + + if (!(geometry instanceof GeometryArrayRetained)) { + return false; + } + + GeometryArrayRetained firstGeo = (GeometryArrayRetained) geometry; + + for(i=index; (i CAN NEVER BE TRUE"); + return; + } + else { + ms = getMirrorShape(k); + } + } + else { + ms = (Shape3DRetained)mirrorShape3D.get(0); + } + + list.add(getGeomAtom(ms)); + + } + + + // Called on the mirror Object + void addLight(LightRetained light) { + LightRetained[] newlights; + int i, n; + Shape3DRetained ms; + + if (lights == null) { + lights = new LightRetained[10]; + } + else if (lights.length == numlights) { + newlights = new LightRetained[numlights*2]; + for (i=0; i=0) { + return (Shape3DRetained) mirrorShape3D.get(i); + } + } + // Not possible + throw new RuntimeException("Shape3DRetained: MirrorShape Not found!"); + } + + void setBoundsAutoCompute(boolean autoCompute) { + GeometryRetained geometry; + if (autoCompute != boundsAutoCompute) { + if (autoCompute) { + // localBounds may not have been set to bbox + localBounds = new BoundingBox((BoundingBox) null); + if (source.isLive() && geometryList != null) { + int size = geometryList.size()*mirrorShape3D.size(); + for (int i=0; i=0; i--) { + geom1 = (GeometryRetained) geometryList.get(i); + if (geom1 != null) { + for (int j=gaSize-1; j >=0; j--) { + geom2 = (GeometryRetained) gaList.get(j); + if ((geom2 != null) && + geom1.intersect(thisLocalToVworld, + otherLocalToVworld, geom2)) { + return true; + } + } + } + } + + return false; + } + + boolean intersectGeometryList(Transform3D thisLocalToVworld, Bounds targetBound) { + + GeometryRetained geometry; + + if (this instanceof OrientedShape3DRetained) { + Transform3D orientedTransform = + ((OrientedShape3DRetained)this). + getOrientedTransform(getPrimaryViewIdx()); + thisLocalToVworld.mul(orientedTransform); + } + + for (int i=geometryList.size() - 1; i >=0; i--) { + geometry = (GeometryRetained) geometryList.get(i); + if ((geometry != null) && + geometry.intersect(thisLocalToVworld, targetBound)) { + return true; + } + } + + return false; + + } + + + /** + * This initialize the mirror shape to reflect the state of the + * real Morph. + */ + void initMirrorShape3D(SetLiveState s, MorphRetained morph, int index) { + + GeometryRetained geometry; + + GeometryAtom[] newGeometryAtoms = null; + + universe = morph.universe; + inSharedGroup = morph.inSharedGroup; + inBackgroundGroup = morph.inBackgroundGroup; + geometryBackground = morph.geometryBackground; + parent = morph.parent; + locale = morph.locale; + + OrderedPath op = (OrderedPath)s.orderedPaths.get(index); + if (op.pathElements.size() == 0) { + orderedPath = null; + } else { + orderedPath = op; + } + + staticTransform = morph.staticTransform; + if (morph.boundsAutoCompute) { + localBounds.set(morph.localBounds); + } + bounds = localBounds; + vwcBounds = new BoundingBox((BoundingBox) null); + vwcBounds.transform(bounds, getCurrentLocalToVworld(0)); + + if (morph.collisionBound == null) { + collisionBound = null; + collisionVwcBound = vwcBounds; + } else { + collisionBound = morph.collisionBound; + collisionVwcBound = (Bounds)collisionBound.clone(); + collisionVwcBound.transform(getCurrentLocalToVworld(0)); + } + + appearanceOverrideEnable = morph.appearanceOverrideEnable; + + // mga is the final geometry we're interested. + geometryList = new ArrayList(1); + geometryList.add((GeometryArrayRetained)morph.morphedGeometryArray.retained); + + GeometryAtom gAtom = new GeometryAtom(); + gAtom.geometryArray = new GeometryRetained[1]; + + gAtom.locale = locale; + gAtom.visible = morph.visible; + gAtom.source = this; + + geometry = (GeometryRetained) geometryList.get(0); + + if(geometry ==null) { + gAtom.geometryArray[0] = null; + } else { + gAtom.geometryArray[0] = (GeometryArrayRetained)morph. + morphedGeometryArray.retained; + gAtom.geoType = gAtom.geometryArray[0].geoType; + } + geomAtom = gAtom; + + // Assign the parent of this mirror shape node + sourceNode = morph; + } + + // geometries in morph object is modified, update the geometry + // list in the mirror shapes and the geometry array in the geometry atom + + void setMorphGeometry(Geometry geometry, ArrayList mirrorShapes) { + GeometryAtom oldGA, newGA; + Shape3DRetained ms; + TransformGroupRetained tg; + int nMirrorShapes = mirrorShapes.size(); + int i; + + GeometryAtom oldGAArray[] = new GeometryAtom[nMirrorShapes]; + GeometryAtom newGAArray[] = new GeometryAtom[nMirrorShapes]; + + + for (i = 0; i < nMirrorShapes; i++) { + ms = (Shape3DRetained) mirrorShapes.get(i); + + oldGA = Shape3DRetained.getGeomAtom(ms); + + ms.geometryList = new ArrayList(1); + ms.geometryList.add((GeometryArrayRetained)geometry.retained); + + newGA = new GeometryAtom(); + newGA.geometryArray = new GeometryRetained[1]; + + if (geometry ==null) { + newGA.geometryArray[0] = null; + } else { + newGA.geometryArray[0] = + (GeometryArrayRetained)geometry.retained; + newGA.geoType = newGA.geometryArray[0].geoType; + } + + newGA.locale = locale; + newGA.visible = oldGA.visible; + newGA.source = this; + + oldGAArray[i] = oldGA; + newGAArray[i] = newGA; + + Shape3DRetained.setGeomAtom(ms, newGA); + } + + TargetsInterface ti = + ((GroupRetained)parent).getClosestTargetsInterface( + TargetsInterface.TRANSFORM_TARGETS); + CachedTargets[] newCtArr = null; + + if (ti != null) { + CachedTargets ct; + newCtArr = new CachedTargets[nMirrorShapes]; + + for (i=0; i=0; i--) { + ms = (Shape3DRetained) userList.get(i); + + if(moreThanOneUniv == false) { + if(firstFndUniv == null) { + firstFndUniv = ms.universe; + univList.add(ms.universe); + + gaList = new ArrayList(); + listPerUniverse.add(gaList); + } + else if(firstFndUniv != ms.universe) { + moreThanOneUniv = true; + univList.add(ms.universe); + gaList = new ArrayList(); + listPerUniverse.add(gaList); + } + } + else { + index = univList.indexOf(ms.universe); + if (index < 0) { + univList.add(ms.universe); + gaList = new ArrayList(); + listPerUniverse.add(gaList); + } + else { + gaList = (ArrayList) listPerUniverse.get(index); + } + } + + + ms.mirrorShape3DLock.readLock(); + + if(ms.geomAtom != null) { + gaList.add(ms.geomAtom); + } + ms.mirrorShape3DLock.readUnlock(); + + } + } + return listPerUniverse; + } + + final static GeometryAtom getGeomAtom(Shape3DRetained shape) { + GeometryAtom ga; + + shape.mirrorShape3DLock.readLock(); + ga = shape.geomAtom; + shape.mirrorShape3DLock.readUnlock(); + + return ga; + } + + final static void setGeomAtom(Shape3DRetained shape, GeometryAtom ga) { + shape.mirrorShape3DLock.writeLock(); + shape.geomAtom = ga; + shape.mirrorShape3DLock.writeUnlock(); + } + + + // Alpha is editable due to the appearance + boolean isAlphaEditable(GeometryRetained geo) { + + boolean alphaEditable = false; + + if (appearanceOverrideEnable) { + alphaEditable = true; + } else if (geo != null && + appearance != null) { + + AppearanceRetained app = appearance; + + if (source.getCapability( + Shape3D.ALLOW_APPEARANCE_WRITE) || + source.getCapability( + Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE) || + + app.source.getCapability( + Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE) || + + app.source.getCapability( + Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE) || + + (app.renderingAttributes != null && + (app.renderingAttributes.source.getCapability( + RenderingAttributes.ALLOW_ALPHA_TEST_FUNCTION_WRITE) || + app.renderingAttributes.source.getCapability( + RenderingAttributes.ALLOW_IGNORE_VERTEX_COLORS_WRITE))) || + + (app.transparencyAttributes != null && + (app.transparencyAttributes.source.getCapability( + TransparencyAttributes.ALLOW_MODE_WRITE) || + app.transparencyAttributes.source.getCapability( + TransparencyAttributes.ALLOW_VALUE_WRITE)))) { + + alphaEditable = true; + + } else if (geo instanceof GeometryArrayRetained && + (app.source.getCapability( + Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE) || + + (app.textureAttributes != null && + app.textureAttributes.source.getCapability( + TextureAttributes.ALLOW_MODE_WRITE)))) { + + alphaEditable = true; + + } else if (geo instanceof RasterRetained) { + if ((((RasterRetained)geo).type & Raster.RASTER_COLOR) != +0 + && ((RasterRetained)geo).source.getCapability( + Raster.ALLOW_IMAGE_WRITE)) { + + alphaEditable = true; + } + } + } + return alphaEditable; + } + + // getCombineBounds is faster than computeCombineBounds since it + // does not recompute the geometry.geoBounds + void getCombineBounds(BoundingBox bounds) { + + if(geometryList != null) { + BoundingBox bbox = null; + GeometryRetained geometry; + + if (staticTransform != null) { + bbox = new BoundingBox((BoundingBox) null); + } + + synchronized(bounds) { + bounds.setLower( 1.0, 1.0, 1.0); + bounds.setUpper(-1.0,-1.0,-1.0); + for(int i=0; i maxVal) + maxVal = tempVal; + tempVal = Math.abs(bounds.lower.y); + if(tempVal > maxVal) + maxVal = tempVal; + tempVal = Math.abs(bounds.upper.y); + if(tempVal > maxVal) + maxVal = tempVal; + tempVal = Math.abs(bounds.lower.z); + if(tempVal > maxVal) + maxVal = tempVal; + tempVal = Math.abs(bounds.upper.z); + if(tempVal > maxVal) + maxVal = tempVal; + + // System.err.println("Shape3DRetained - bounds (Before) " + bounds); + bounds.setLower(-maxVal, -maxVal, -maxVal); + bounds.setUpper(maxVal, maxVal, maxVal); + // System.err.println("Shape3DRetained - bounds (After) " + bounds); + } + + } + } + + + boolean isEquivalent(Shape3DRetained shape) { + if (this.appearance != shape.appearance || + // Scoping info should be same since they are under same group + this.appearanceOverrideEnable != shape.appearanceOverrideEnable || + this.isPickable != shape.isPickable || + this.isCollidable != shape.isCollidable) { + + return false; + } + if (this.boundsAutoCompute) { + if (!shape.boundsAutoCompute) + return false; + } + else { + // If bounds autoCompute is false + // Then check if both bounds are equal + if (this.localBounds != null) { + if (shape.localBounds != null) { + return this.localBounds.equals(shape.localBounds); + } + } + else if (shape.localBounds != null) { + return false; + } + } + if (collisionBound != null) { + if (shape.collisionBound == null) + return false; + else + return collisionBound.equals(shape.collisionBound); + } + else if (shape.collisionBound != null) + return false; + + return true; + } + + // Bounds can only be set after the geometry is setLived, so has to be done + // here, if we are not using switchVwcBounds + void initializeGAtom(Shape3DRetained ms) { + int i, gaCnt; + int geometryCnt = 0; + int gSize = geometryList.size(); + GeometryRetained geometry = null; + + ms.bounds = localBounds; + ms.vwcBounds = new BoundingBox((BoundingBox) null); + ms.vwcBounds.transform(ms.bounds, ms.getCurrentLocalToVworld(0)); + + if (collisionBound == null) { + ms.collisionBound = null; + ms.collisionVwcBound = ms.vwcBounds; + } else { + ms.collisionBound = collisionBound; + ms.collisionVwcBound = (Bounds)ms.collisionBound.clone(); + ms.collisionVwcBound.transform(ms.getCurrentLocalToVworld(0)); + } + GeometryAtom gAtom = new GeometryAtom(); + for(gaCnt=0; gaCnt= 0; i--) { + GeometryRetained geomRetained = (GeometryRetained) geometryList.get(i); + if ((geomRetained != null) && + (index != i)) { // this geometry will replace + // current one so there is no need to check + if (!geomRetained.isEquivalenceClass((GeometryRetained)geometry.retained)) { + throw new IllegalArgumentException(J3dI18N.getString("Shape3DRetained5")); + } + break; + } + } + } + } + + int indexOfGeometry(Geometry geometry) { + if(geometry != null) + return geometryList.indexOf(geometry.retained); + else + return geometryList.indexOf(null); + } + + + // Removes the specified geometry from this Shape3DRetained's list of geometries + void removeGeometry(Geometry geometry) { + int ind = indexOfGeometry(geometry); + if(ind >= 0) + removeGeometry(ind); + } + + // Removes all the geometries from this node + void removeAllGeometries() { + int n = geometryList.size(); + + int i; + Shape3DRetained mShape; + GeometryRetained oldGeom = null; + + if (((Shape3D)this.source).isLive()) { + for(int index = n-1; index >= 0; index--) { + oldGeom = (GeometryRetained) (geometryList.get(index)); + if (oldGeom != null) { + oldGeom.clearLive(refCount); + oldGeom.decRefCnt(); + for (i=0; i= 0; index--) { + oldGeom = (GeometryRetained) (geometryList.get(index)); + if (oldGeom != null) { + oldGeom.decRefCnt(); + } + geometryList.remove(index); + } + } + dirtyBoundsCache(); + } + + boolean willRemainOpaque(int geoType) { + if (appearance == null || + (appearance.isStatic() && + appearance.isOpaque(geoType))) { + return true; + } + else { + return false; + } + + } + + void handleFrequencyChange(int bit) { + int mask = 0; + if (bit == Shape3D.ALLOW_GEOMETRY_WRITE) { + mask = GEOMETRY_CHANGED; + } + else if (bit == Shape3D.ALLOW_APPEARANCE_WRITE) { + mask = APPEARANCE_CHANGED; + } + else if (bit == Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE) { + mask = APPEARANCEOVERRIDE_CHANGED; + } + if (mask != 0) { + if (source.getCapabilityIsFrequent(bit)) + changedFrequent |= mask; + else if (!source.isLive()) { + changedFrequent &= ~mask; + } + } + } + + + // Alpha is editable due to the appearance(Called on the MirrorShape3D) + boolean isAlphaFrequentlyEditable(GeometryRetained geo) { + + boolean alphaFrequentlyEditable = false; + if (appearanceOverrideEnable) { + alphaFrequentlyEditable = true; + } else if (geo != null && + appearance != null) { + AppearanceRetained app = appearance; + + if (((changedFrequent &(APPEARANCE_CHANGED|APPEARANCEOVERRIDE_CHANGED)) != 0)|| + ((app.changedFrequent &(AppearanceRetained.RENDERING|AppearanceRetained.TRANSPARENCY)) != 0) || + (app.renderingAttributes != null && + (((app.renderingAttributes.changedFrequent & (RenderingAttributesRetained.IGNORE_VCOLOR |RenderingAttributesRetained.ALPHA_TEST_FUNC)) != 0))) || + + (app.transparencyAttributes != null && + ((app.transparencyAttributes.changedFrequent != 0)))) { + + alphaFrequentlyEditable = true; + + } else if (geo instanceof GeometryArrayRetained && + ((app.changedFrequent & AppearanceRetained.TEXTURE_ATTR) != 0) || + (app.textureAttributes != null && + ((app.textureAttributes.changedFrequent & TextureAttributes.ALLOW_MODE_WRITE) != 0))) { + alphaFrequentlyEditable = true; + + } else if (geo instanceof RasterRetained) { + if (((((RasterRetained)geo).type & Raster.RASTER_COLOR) != +0) + && (((RasterRetained)geo).cachedChangedFrequent != 0)) { + + alphaFrequentlyEditable = true; + } + } + } + // System.err.println("changedFrequent="+changedFrequent+" sourceNode = "+sourceNode+" isAlphaFrequentlyEditable, = "+alphaFrequentlyEditable); + return alphaFrequentlyEditable; + } + + + int getPrimaryViewIdx() { + // To avoid MT-safe issues when using View, just clone it. + UnorderList viewList = VirtualUniverse.mc.cloneView(); + View views[] = (View []) viewList.toArray(false); + int size = viewList.arraySize(); + + for (int i=0; i < size; i++) { + if (views[i].primaryView) { + return views[i].viewIndex; + } + } + return 0; + } + + void searchGeometryAtoms(UnorderList list) { + list.add(getGeomAtom(getMirrorShape(key))); + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/SharedGroup.java b/j3d-core/src/classes/share/javax/media/j3d/SharedGroup.java new file mode 100644 index 0000000..749b470 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SharedGroup.java @@ -0,0 +1,171 @@ +/* + * $RCSfile: SharedGroup.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The SharedGroup provides the ability to manipulate an + * instanced scene graph. + * A SharedGroup node allows multiple Link leaf nodes to share its + * subgraph according to the following semantics: + *

    + *
  • A SharedGroup may be referenced by one or more Link leaf + * nodes. Any runtime changes to a node or component object in this + * shared subgraph affect all graphs that refer to this subgraph.
  • + * + *

  • A SharedGroup may be compiled by calling its compile method + * prior to being referenced by any Link leaf nodes.
  • + * + *

  • Only Link leaf nodes may refer to SharedGroup nodes. A + * SharedGroup node cannot have parents or be attached to a Locale.
  • + *

+ * + * A shared subgraph may contain any group node, except an embedded + * SharedGroup node (SharedGroup nodes cannot have parents). However, + * only the following leaf nodes may appear in a shared subgraph: + *

    + *
  • Light
  • + *
  • Link
  • + *
  • Morph
  • + *
  • Shape
  • + *
  • Sound

+ * + * An IllegalSharingException is thrown if any of the following leaf nodes + * appear in a shared subgraph:

+ *

    + *
  • AlternateAppearance
  • + *
  • Background
  • + *
  • Behavior
  • + *
  • BoundingLeaf
  • + *
  • Clip
  • + *
  • Fog
  • + *
  • ModelClip
  • + *
  • Soundscape
  • + *
  • ViewPlatform
+ *

+ * + * @see IllegalSharingException + */ + +public class SharedGroup extends Group { + + /** + * Specifies that this SharedGroup node allows reading the + * list of links that refer to this node. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_LINK_READ = CapabilityBits.SHARED_GROUP_ALLOW_LINK_READ; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_LINK_READ + }; + + /** + * Constructs and initializes a new SharedGroup node object. + */ + public SharedGroup() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + + /** + * Returns the list of Link nodes that refer to this SharedGroup node. + * @return An array of Link nodes that refer to this SharedGroup node. + * + * @since Java 3D 1.3 + */ + public Link[] getLinks() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LINK_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("SharedGroup1")); + } + } + return ((SharedGroupRetained)retained).getLinks(); + } + + + /** + * Creates the retained mode SharedGroupRetained object that this + * SharedGroup component object will point to. + */ + void createRetained() { + this.retained = new SharedGroupRetained(); + this.retained.setSource(this); + } + + + /** + * Compiles the source SharedGroup associated with this object and + * creates and caches a compiled scene graph. + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @exception RestrictedAccessException if the method is called + * when this object is part of a live scene graph. + */ + public void compile() { + if (isLive()) { + throw new RestrictedAccessException(J3dI18N.getString("SharedGroup0")); + } + + if (isCompiled() == false) { + // will throw SceneGraphCycleException if there is a cycle + // in the scene graph + checkForCycle(); + + ((SharedGroupRetained)this.retained).compile(); + } + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + SharedGroup sg = new SharedGroup(); + sg.duplicateNode(this, forceDuplicate); + return sg; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SharedGroupRetained.java b/j3d-core/src/classes/share/javax/media/j3d/SharedGroupRetained.java new file mode 100644 index 0000000..4802a6a --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SharedGroupRetained.java @@ -0,0 +1,917 @@ +/* + * $RCSfile: SharedGroupRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * The SharedGroup node provides the ability to share a scene graph from + * multiple other scene graphs through the use of a Link node. + */ + +class SharedGroupRetained extends GroupRetained implements TargetsInterface { + + /* + static final int ILLEGAL_LEAF_MASK = + 1 << NodeRetained.BACKGROUND | + 1 << NodeRetained.BEHAVIOR | + 1 << NodeRetained.CLIP | + 1 << NodeRetained.LINEARFOG | + 1 << NodeRetained.EXPONENTIALFOG | + 1 << NodeRetained.SOUNDSCAPE | + 1 << NodeRetained.VIEWPLATFORM | + 1 << NodeRetained.BOUNDINGLEAF; + */ + + // The current list of child transform group nodes or link nodes + // under a transform group + ArrayList childTransformLinks = new ArrayList(1); + + // key which identifies a unique path from a + // locale to this transform group + HashKey currentKey = new HashKey(); + + // key which identifies a unique path from a locale to this switch link + HashKey switchKey = new HashKey(); + + /** + * The Shared Group Node's parent vector. + */ + Vector parents = new Vector(1); + + // J3d copy. + CachedTargets[] j3dCTs = null; + + // User copy. + CachedTargets[] cachedTargets = null; + + // A bitmask of the types in targets for transform targets + int localTargetThreads = 0; + // combined localTargetThreads and decendants' localTargetThreads + int targetThreads = 0; + + ArrayList switchStates = null; + + SharedGroupRetained() { + this.nodeType = NodeRetained.SHAREDGROUP; + } + + // SharedGroup specific data at SetLive. + void setAuxData(SetLiveState s, int index, int hkIndex) { + int i, size; + + // Group's setAuxData() + super.setAuxData(s, index, hkIndex); + + branchGroupPaths.add(hkIndex, s.branchGroupPaths.get(index)); + + if (orderedPaths == null) { + orderedPaths = new ArrayList(1); + } + orderedPaths.add(hkIndex, s.orderedPaths.get(index)); + + if (switchStates == null) { + switchStates = new ArrayList(1); + } + switchStates.add(hkIndex, s.switchStates.get(index)); + + if (viewLists == null) { + viewLists = new ArrayList(1); + } + // If there are some ViewSpecificGroups in the path above this SharedGroup + // System.err.println("====> hkIndex = "+hkIndex+" s.viewLists = "+s.viewLists); + if (s.viewLists != null) { + viewLists.add(hkIndex, s.viewLists.get(index)); + } + else { + viewLists.add(hkIndex, null); + } + + if (lights == null) { + lights = new ArrayList(1); + } + if (s.lights != null) { + lights.add(hkIndex, s.lights.get(index)); + } + else { + lights.add(hkIndex, null); + } + + if (fogs == null) { + fogs = new ArrayList(1); + } + if (s.fogs != null) { + fogs.add(hkIndex, s.fogs.get(index)); + } + else { + fogs.add(hkIndex, null); + } + + + if (modelClips == null) { + modelClips = new ArrayList(1); + } + if (s.modelClips != null) { + modelClips.add(hkIndex, s.modelClips.get(index)); + } + else { + modelClips.add(hkIndex, null); + } + + + if (altAppearances == null) { + altAppearances = new ArrayList(1); + } + if (s.altAppearances != null) { + altAppearances.add(hkIndex, s.altAppearances.get(index)); + } + else { + altAppearances.add(hkIndex, null); + } + } + + + void setNodeData(SetLiveState s) { + + // For inSharedGroup case. + int i, j, len; + + if (localToVworld == null) { + localToVworld = new Transform3D[s.keys.length][]; + localToVworldIndex = new int[s.keys.length][]; + localToVworldKeys = new HashKey[s.keys.length]; + cachedTargets = new CachedTargets[s.keys.length]; + len=0; + } + else { + + int newLen = localToVworld.length + s.keys.length; + + Transform3D newTList[][] = new Transform3D[newLen][]; + HashKey newHList[] = new HashKey[newLen]; + int newIndexList[][] = new int[newLen][]; + CachedTargets newTargets[] = new CachedTargets[newLen]; + + len = localToVworld.length; + + // Copy the existing data into the newly created data objects. + System.arraycopy(localToVworld, 0, newTList, 0, localToVworld.length); + System.arraycopy(localToVworldIndex, 0, newIndexList, 0, + localToVworldIndex.length); + System.arraycopy(localToVworldKeys, 0, newHList, 0, + localToVworldKeys.length); + System.arraycopy(cachedTargets, 0, newTargets, 0, + cachedTargets.length); + + localToVworld = newTList; + localToVworldIndex = newIndexList; + localToVworldKeys = newHList; + cachedTargets = newTargets; + } + + int[] hkIndex = new int[1]; + int hkIndexPlus1, blkSize; + + s.hashkeyIndex = new int[s.keys.length]; + + // This should appear before super.setNodeData() if it exists + s.parentBranchGroupPaths = branchGroupPaths; + + for(i=len, j=0; i= 0) { + found = true; + if(index == curStart) { + curStart++; + } + else { + len = index - curStart; + System.arraycopy(localToVworld, curStart, newTList, newStart, len); + System.arraycopy(localToVworldIndex, curStart, newIndexList, + newStart, len); + System.arraycopy(localToVworldKeys, curStart, newHList, newStart, len); + System.arraycopy(cachedTargets, curStart, newTargets, + newStart, len); + + curStart = index+1; + newStart = newStart + len; + } + } + else { + found = false; + MasterControl.getCoreLogger().severe("Can't Find matching hashKey in SG.removeNodeData."); + } + } + + if((found == true) && (curStart < localToVworld.length)) { + len = localToVworld.length - curStart; + System.arraycopy(localToVworld, curStart, newTList, newStart, len); + System.arraycopy(localToVworldIndex, curStart, newIndexList, + newStart, len); + System.arraycopy(localToVworldKeys, curStart, newHList, newStart, len); + System.arraycopy(cachedTargets, curStart, newTargets, + newStart, len); + } + + // Must be in reverse, to preserve right indexing. + for (i = tempIndex.length-1; i >= 0 ; i--) { + if(tempIndex[i] >= 0) { + branchGroupPaths.remove(tempIndex[i]); + orderedPaths.remove(tempIndex[i]); + switchStates.remove(tempIndex[i]); + lights.remove(tempIndex[i]); + fogs.remove(tempIndex[i]); + modelClips.remove(tempIndex[i]); + altAppearances.remove(tempIndex[i]); + } + } + + localToVworld = newTList; + localToVworldIndex = newIndexList; + localToVworldKeys = newHList; + cachedTargets = newTargets; + } + s.localToVworld = localToVworld; + s.localToVworldIndex = localToVworldIndex; + s.localToVworldKeys = localToVworldKeys; + s.orderedPaths = orderedPaths; + s.switchStates = switchStates; + s.viewLists = viewLists; + s.lights = lights; + s.fogs = fogs; + s.modelClips = modelClips; + s.altAppearances = altAppearances; + } + + void clearLive(SetLiveState s) { + + int i,j,k, index; + + Transform3D savedLocalToVworld[][] = s.localToVworld; + int savedLocalToVworldIndex[][] = s.localToVworldIndex; + HashKey savedLocalToVworldKeys[] = s.localToVworldKeys; + ArrayList savedOrderedPaths = s.orderedPaths; + ArrayList savedViewLists = s.viewLists; + + ArrayList savedLights = s.lights; + ArrayList savedFogs = s.fogs; + ArrayList savedMclips = s.modelClips; + ArrayList savedAltApps = s.altAppearances; + + Targets[] savedSwitchTargets = s.switchTargets; + Targets[] savedTransformTargets = s.transformTargets; + // no need to gather targets from sg in clear live + s.transformTargets = null; + s.switchTargets = null; + + + // XXXX: This is a hack since removeNodeData is called before + // children are clearLives + int[] tempIndex = null; + // Don't keep the indices if everything will be cleared + if (s.keys.length != localToVworld.length) { + tempIndex = new int[s.keys.length]; + for (i = s.keys.length-1; i >= 0; i--) { + tempIndex[i] = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length); + } + } + + super.clearLive(s); + // Do this after children clearlive since part of the viewLists may get cleared + // during removeNodeData + if(refCount <= 0) { + viewLists.clear(); + } + else { + // Must be in reverse, to preserve right indexing. + for (i = tempIndex.length-1; i >= 0 ; i--) { + if(tempIndex[i] >= 0) { + viewLists.remove(tempIndex[i]); + } + } + } + + // restore setLiveState from it's local variables. + // removeNodeData has altered these variables. + s.localToVworld = savedLocalToVworld; + s.localToVworldIndex = savedLocalToVworldIndex; + s.localToVworldKeys = savedLocalToVworldKeys; + s.orderedPaths = savedOrderedPaths; + s.viewLists = savedViewLists; + s.lights = savedLights; + s.fogs = savedFogs; + s.modelClips = savedMclips; + s.altAppearances = savedAltApps; + s.transformTargets = savedTransformTargets; + s.switchTargets = savedSwitchTargets; + } + + void updateChildLocalToVworld(HashKey key, int index, + ArrayList dirtyTransformGroups, + ArrayList keySet, + UpdateTargets targets, + ArrayList blUsers) { + + LinkRetained ln; + TransformGroupRetained tg; + int i,j; + Object obj; + + CachedTargets ct = j3dCTs[index]; + if (ct != null) { + targets.addCachedTargets(ct); + if (ct.targetArr[Targets.BLN_TARGETS] != null) { + gatherBlUsers(blUsers, ct.targetArr[Targets.BLN_TARGETS]); + } + } + + synchronized(childTransformLinks) { + for (i=0; i + * Sound Data + * + *

    Associated with each Sound node is a MediaContainer + * which includes audio data and information about this data. + * This data can be cached (buffered) or non-cached (unbuffered or streaming). + * If an AudioDevice has been attached to the PhysicalEnvironment, the sound + * data is made ready to begin playing. + * Certain functionality can not be applied to true streaming sound data:

    + * 1) querying the sound's duration (Sound.DURATION_UNKNOWN will be returned),
    + * 2) looping over a range of the streaming data; and
    + * 3) restart a previously played portion of the data.

    + * Depending on the implementation of the AudioDevice used, streamed, non- + * cached data may not be fully spatialized.

+ *

+ * Initial Gain + * + *

    This gain is a scale factor applied to the sound data associated + * with this sound source to increase or decrease its overall amplitude.
+ *

+ * Loop + * + *

    Data for non-streaming sound (such as a sound sample) can contain two + * loop points marking a section of the data that is to be looped a specific + * number of times. Thus sound data can be divided into three segments: + * the attack (before the begin loop point), the sustain (between the begin + * and end loop points), and the release (after the end loop point). If + * there are no loop begin and end points defined as part of the sound data, + * the begin loop point is set at the beginning of the sound data, + * and the end loop point at the end of the sound data. + * If this is the case, looping the sound would mean repeating the whole + * sound. However, these allow a portion in the middle of the sound to + * be looped. + *

    + * A sound can be looped a specified number of times after it is activated + * before it is completed. The loop count value explicitly sets the number + * of times the sound is looped. Any non-negative number is a valid value. + * A value of zero denotes that the looped section is not repeated, but is + * played only once. A value of -1 denotes that the loop is repeated + * indefinitely. + *

    + * Changing loop count of a sound after the sound has been started will not + * dynamically affect the loop count currently used by the sound playing. + * The new loop count will be used the next time the sound is enabled.

+ *

+ * Release Flag + * + *

    When a sound is disabled, its playback would normally stop immediately + * no matter what part of the sound data was currently being played. By + * setting the Release Flag to true for nodes with non-streaming sound data, + * the sound is allowed to play from its current position in the sound data + * to the end of the data (without repeats), thus playing the release portion + * of the sound before stopping.
+ *

+ * Continuous Flag + * + *

    For some applications, it's useful to turn a sound source "off" but to + * continue "silently" playing the sound so that when it is turned back "on" + * the sound picks up playing in the same location (over time) as it would + * have been if the sound had never been disabled (turned off). Setting the + * Continuous flag true causes the sound renderer to keep track of where + * (over time) the sound would be playing even when the sound is disabled.
+ *

+ * Enable Sound + * + *

    When enabled, the sound source is started + * playing and thus can potentially be heard, depending on its activation + * state, gain control parameters, continuation state, and spatialization + * parameters. If the continuous state is true, even if the sound is not + * active, enabling the sound starts the sound silently "playing," so that + * when the sound is activated, the sound is (potentially) heard from + * somewhere in the middle of the sound data. Activation state can change + * from active to inactive any number of times without stopping or starting + * the sound. To re-start a sound at the beginning of its data, re-enable + * the sound by calling setEnable with true. + *

    + * Setting the enable flag to true during construction acts as a request + * to start the sound playing "as soon as it can" be started. + * This could be close to immediately in limited cases, but several conditions, + * detailed below, must be met for a sound to be ready to be played.

+ *

+ * Mute Sound + * + *

    When the mute state is set true, a playing sound is made to play silently. + *

+ * Pause Sound + * + *

    When the pause state is set true, a playing sound is paused. + *

    + * Setting the enable flag to true during construction acts as a request + * to start the sound playing "as soon as it can" be started. + * This could be close to immediately in limited cases, but several conditions, + * detailed below, must be met for a sound to be ready to be played.

+ *

+ * Scheduling Bounds + * + *

    + * A Sound is scheduled for activation when its scheduling region intersects + * the ViewPlatform's activation volume. This is used when the scheduling + * bounding leaf is set to null.
+ *

+ * Scheduling Bounding Leaf + * + *

    When set to a value other than null, the scheduling bounding leaf + * region overrides the scheduling bounds + * object.
+ *

+ * Prioritize Sound + * + *

    Sound Priority is used + * to rank concurrently playing sounds in order of importance during playback. + * When more sounds are started than the AudioDevice + * can handle, the sound node with the lowest priority ranking is + * deactivated (but continues playing silently). If a sound is deactivated + * (due to a sound with a higher + * priority being started), it is automatically re-activated when + * resources become available (e.g., when a sound with a higher priority + * finishes playing), or when the ordering of sound nodes are changed due to + * a change in a sound node's priority. + *

    + * Sounds with a lower priority than sound that can + * not be played due to lack of channels will be played. + * For example, assume we have eight channels available for playing sounds. + * After ordering four sounds, we begin playing them in order, checking if + * the number of channels required to play a given sound are actually available + * before the sound is played. Furthermore, say the first sound needs three + * channels + * to play, the second sound needs four channels, the third sound needs three + * channels + * and the fourth sound needs only one channel. The first and second sounds + * can be started because they require seven of the eight available channels. The + * third sound can not be audibly started because it requires three channels and + * only one is still available. Consequently, the third sound starts playing + * 'silently.' The fourth sound can and will be started since it only requires + * one channel. The third sound will be made audible when three channels become + * available (i.e., when the first or second sound finishes playing). + *

    + * Sounds given the same priority are ordered randomly. If the application + * wants a specific ordering, it must assign unique priorities to each sound. + *

    + * Methods to determine what audio output resources are required for playing + * a Sound node on a particular AudioDevice and to determine the currently + * available audio output resources are described in the AudioDevice class.

+ *

+ * Duration + * + *

    Each sound has a length of time in milliseconds that it + * can run (including repeating loop section) + * if it plays to completion. If the sound + * media type is streaming, or if the sound is looped indefinitely, then a + * value of -1 (implying infinite length) is returned.
+ *

+ * Number of Channels used on Audio Device to Play Sound + * + *

    When a sound is started, it could use more than one channel on the + * selected AudioDevice it is to be played on. The number of Audio Device + * channels currently used for a sound can be queried using + * getNumberOfChannelsUsed().
+ *

+ * Preparing a Sound to be Played + * + *

    Sound data associated with a Sound node, either during construction + * (when the MediaContainer is passed into the constructor as a parameter) + * or by calling setSoundData(), it can be prepared to begin playing + * only after the following conditions are satisfied:

    + * 1) the Sound node has non-null sound data associated with it
    + * 2) the Sound node is live
    + * 3) there is an active View in the Universe and
    + * 4) there is an initialized AudioDevice associated with the + * PhysicalEnvironment.

    + * Depending on the type of MediaContainer the sound data is and on the + * implementation of the AudioDevice used, sound data preparation could consist + * of opening, attaching, loading, or copying into memory the associated sound data. + * The query method, isReady() returns true when the sound is fully preprocessed + * so that it is playable (audibly if active, silently if not active).

+ *

+ * Playing Status + * + *

    A sound source will not be heard unless it is:

    + * 1) enabled/started
    + * 2) activated
    + * 3) not muted
    + * 4) not paused

    + * While these conditions are meet, the sound is potentially audible + * and the method isPlaying() will return a status of true. + *

    + * isPlaying returns false but isPlayingSilently returns true if a sound:

    + * 1) is enabled before it is activated; it is begun playing silently.
    + * 2) is enabled then deactivated while playing; it continues playing silently
    + * 3) is enabled while it mute state is true + *

    + * When the sound finishes playing it's sound data (including all loops), it + * is implicitly disabled.

+ *

+ * @see AudioDevice + */ + +public abstract class Sound extends Leaf { + // Constants for Sound object. + // + // These flags, when enabled using the setCapability method, allow an + // application to invoke methods that respectively read and write the + // sound fields. + // These capability flags are enforced only when the node is part of + // a live or compiled scene graph. + + /** + * Specifies that this node allows access to its object's sound data + * information. + */ + public static final int + ALLOW_SOUND_DATA_READ = CapabilityBits.SOUND_ALLOW_SOUND_DATA_READ; + + /** + * Specifies that this node allows writing to its object's sound data + * information. + */ + public static final int + ALLOW_SOUND_DATA_WRITE = CapabilityBits.SOUND_ALLOW_SOUND_DATA_WRITE; + + /** + * Specifies that this node allows access to its object's initial gain + * information. + */ + public static final int + ALLOW_INITIAL_GAIN_READ = CapabilityBits.SOUND_ALLOW_INITIAL_GAIN_READ; + + /** + * Specifies that this node allows writing to its object's initial gain + * information. + */ + public static final int + ALLOW_INITIAL_GAIN_WRITE = CapabilityBits.SOUND_ALLOW_INITIAL_GAIN_WRITE; + + /** + * Specifies that this node allows access to its object's loop + * information. + */ + public static final int + ALLOW_LOOP_READ = CapabilityBits.SOUND_ALLOW_LOOP_READ; + + /** + * Specifies that this node allows writing to its object's loop + * information. + */ + public static final int + ALLOW_LOOP_WRITE = CapabilityBits.SOUND_ALLOW_LOOP_WRITE; + + /** + * Specifies that this node allows access to its object's release flag + * information. + */ + public static final int + ALLOW_RELEASE_READ = CapabilityBits.SOUND_ALLOW_RELEASE_READ; + + /** + * Specifies that this node allows writing to its object's release flag + * information. + */ + public static final int + ALLOW_RELEASE_WRITE = CapabilityBits.SOUND_ALLOW_RELEASE_WRITE; + + /** + * Specifies that this node allows access to its object's continuous + * play information. + */ + public static final int + ALLOW_CONT_PLAY_READ = CapabilityBits.SOUND_ALLOW_CONT_PLAY_READ; + + /** + * Specifies that this node allows writing to its object's continuous + * play information. + */ + public static final int + ALLOW_CONT_PLAY_WRITE = CapabilityBits.SOUND_ALLOW_CONT_PLAY_WRITE; + + /** + * Specifies that this node allows access to its object's sound on + * information. + */ + public static final int + ALLOW_ENABLE_READ = CapabilityBits.SOUND_ALLOW_ENABLE_READ; + + /** + * Specifies that this node allows writing to its object's sound on + * information. + */ + public static final int + ALLOW_ENABLE_WRITE = CapabilityBits.SOUND_ALLOW_ENABLE_WRITE; + + /** + * Specifies that this node allows read access to its scheduling bounds + * information. + */ + public static final int + ALLOW_SCHEDULING_BOUNDS_READ = CapabilityBits.SOUND_ALLOW_SCHEDULING_BOUNDS_READ; + + /** + * Specifies that this node allows write access to its scheduling bounds + * information. + */ + public static final int + ALLOW_SCHEDULING_BOUNDS_WRITE = CapabilityBits.SOUND_ALLOW_SCHEDULING_BOUNDS_WRITE; + + /** + * Specifies that this node allows read access to its priority order + * value. + */ + public static final int + ALLOW_PRIORITY_READ = CapabilityBits.SOUND_ALLOW_PRIORITY_READ; + + /** + * Specifies that this node allows write access to its priority order + * value. + */ + public static final int + ALLOW_PRIORITY_WRITE = CapabilityBits.SOUND_ALLOW_PRIORITY_WRITE; + + /** + * Specifies that this node allows access to its object's sound duration + * information. + */ + public static final int + ALLOW_DURATION_READ = CapabilityBits.SOUND_ALLOW_DURATION_READ; + + /** + * Specifies that this node allows access to its object's sound status + * denoting if it is ready to be played 'immediately'. + */ + public static final int + ALLOW_IS_READY_READ = CapabilityBits.SOUND_ALLOW_IS_READY_READ; + + /** + * Specifies that this node allows access to its object's sound audibly + * playing or playing silently status. + */ + public static final int + ALLOW_IS_PLAYING_READ = CapabilityBits.SOUND_ALLOW_IS_PLAYING_READ; + + /** + * Specifies that this node allows access to its number of channels + * used by this sound. + */ + public static final int + ALLOW_CHANNELS_USED_READ = CapabilityBits.SOUND_ALLOW_CHANNELS_USED_READ; + + /** + * Specifies that this node allows access to its object's mute flag + * information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_MUTE_READ = CapabilityBits.SOUND_ALLOW_MUTE_READ; + + /** + * Specifies that this node allows writing to its object's mute flag + * information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_MUTE_WRITE = CapabilityBits.SOUND_ALLOW_MUTE_WRITE; + + /** + * Specifies that this node allows access to its object's pause flag + * information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_PAUSE_READ = CapabilityBits.SOUND_ALLOW_PAUSE_READ; + + /** + * Specifies that this node allows writing to its object's pause flag + * information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_PAUSE_WRITE = CapabilityBits.SOUND_ALLOW_PAUSE_WRITE; + + /** + * Specifies that this node allows access to its object's sample rate scale + * factor information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_RATE_SCALE_FACTOR_READ = CapabilityBits.SOUND_ALLOW_RATE_SCALE_FACTOR_READ; + + /** + * Specifies that this node allows writing to its object's sample rate scale + * factor information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_RATE_SCALE_FACTOR_WRITE = CapabilityBits.SOUND_ALLOW_RATE_SCALE_FACTOR_WRITE; + + /** + * Denotes that there is no filter value associated with object's distance + * or angular attenuation array. + */ + public static final float NO_FILTER = -1.0f; + + /** + * Denotes that the sound's duration could not be calculated. + * A fall back for getDuration of a non-cached sound. + */ + public static final int DURATION_UNKNOWN = -1; + + /** + * When used as a loop count sound will loop an infinite number of time + * until explicitly stopped (setEnabled(false)). + */ + public static final int INFINITE_LOOPS = -1; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_CHANNELS_USED_READ, + ALLOW_CONT_PLAY_READ, + ALLOW_DURATION_READ, + ALLOW_ENABLE_READ, + ALLOW_INITIAL_GAIN_READ, + ALLOW_IS_PLAYING_READ, + ALLOW_IS_READY_READ, + ALLOW_LOOP_READ, + ALLOW_MUTE_READ, + ALLOW_PAUSE_READ, + ALLOW_PRIORITY_READ, + ALLOW_RATE_SCALE_FACTOR_READ, + ALLOW_RELEASE_READ, + ALLOW_SCHEDULING_BOUNDS_READ, + ALLOW_SOUND_DATA_READ + }; + + + /** + * Constructs and initializes a new Sound node using default + * parameters. The following defaults values are used: + *

    + * sound data: null
    + * initial gain: 1.0
    + * loop: 0
    + * release flag: false
    + * continuous flag: false
    + * enable flag: false
    + * scheduling bounds : null
    + * scheduling bounding leaf : null
    + * priority: 1.0
    + * rate scale factor: 1.0
    + * mute state: false
    + * pause state: false
    + *
+ */ + public Sound() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a new Sound node object using the provided + * data and gain parameter values, and defaults for all other fields. This + * constructor implicitly loads the sound data associated with this node if + * the implementation uses sound caching. + * @param soundData description of JMF source data used by this sound source + * @param initialGain overall amplitude scale factor applied to sound source + */ + public Sound(MediaContainer soundData, float initialGain) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((SoundRetained)this.retained).setSoundData(soundData); + ((SoundRetained)this.retained).setInitialGain(initialGain); + } + + + /** + * Constructs and initializes a new Sound node using provided parameter + * values. + * @param soundData description of JMF source data used by this sound source + * @param initialGain overall amplitude scale factor applied to sound source + * @param loopCount number of times sound is looped when played + * @param release flag specifying whether the sound is to be played + * to end when stopped + * @param continuous flag specifying whether the sound silently plays + * when disabled + * @param enable flag specifying whether the sound is enabled + * @param region scheduling bounds + * @param priority defines playback priority if too many sounds started + */ + public Sound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority ) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((SoundRetained)this.retained).setSoundData(soundData); + ((SoundRetained)this.retained).setInitialGain(initialGain); + ((SoundRetained)this.retained).setLoop(loopCount); + ((SoundRetained)this.retained).setReleaseEnable(release); + ((SoundRetained)this.retained).setContinuousEnable(continuous); + ((SoundRetained)this.retained).setEnable(enable); + ((SoundRetained)this.retained).setSchedulingBounds(region); + ((SoundRetained)this.retained).setPriority(priority); + } + + /** + * Constructs and initializes a new Sound node using provided parameter + * values. + * @param soundData description of JMF source data used by this sound source + * @param initialGain overall amplitude scale factor applied to sound source + * @param loopCount number of times sound is looped when played + * @param release flag specifying whether the sound is to be played + * to end when stopped + * @param continuous flag specifying whether the sound silently plays + * when disabled + * @param enable flag specifying whether the sound is enabled + * @param region scheduling bounds + * @param priority defines playback priority if too many sounds started + * @param rateFactor defines playback sample rate scale factor + * @since Java 3D 1.3 + */ + public Sound(MediaContainer soundData, + float initialGain, + int loopCount, + boolean release, + boolean continuous, + boolean enable, + Bounds region, + float priority, + float rateFactor ) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((SoundRetained)this.retained).setSoundData(soundData); + ((SoundRetained)this.retained).setInitialGain(initialGain); + ((SoundRetained)this.retained).setLoop(loopCount); + ((SoundRetained)this.retained).setReleaseEnable(release); + ((SoundRetained)this.retained).setContinuousEnable(continuous); + ((SoundRetained)this.retained).setEnable(enable); + ((SoundRetained)this.retained).setSchedulingBounds(region); + ((SoundRetained)this.retained).setPriority(priority); + ((SoundRetained)this.retained).setRateScaleFactor(rateFactor); + } + + /** + * Sets fields that define the sound source data of this node. + * @param soundData description of JMF source data used by this sound source + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setSoundData(MediaContainer soundData) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SOUND_DATA_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound0")); + + if (this instanceof BackgroundSound) + ((SoundRetained)this.retained).setSoundData(soundData); + else // instanceof PointSound or ConeSound + ((PointSoundRetained)this.retained).setSoundData(soundData); + } + + /** + * Retrieves description/data associated with this sound source. + * @return soundData description of JMF source data used by this sound source + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public MediaContainer getSoundData() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SOUND_DATA_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound1")); + + return ((SoundRetained)this.retained).getSoundData(); + } + + /** + * Set the overall gain scale factor applied to data associated with this + * source to increase or decrease its overall amplitude. + * @param amplitude (gain) scale factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setInitialGain(float amplitude) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INITIAL_GAIN_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound2")); + + ((SoundRetained)this.retained).setInitialGain(amplitude); + } + + /** + * Get the overall gain applied to the sound data associated with source. + * @return overall gain scale factor applied to sound source data. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getInitialGain() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_INITIAL_GAIN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound3")); + + return ((SoundRetained)this.retained).getInitialGain(); + } + + /** + * Sets a sound's loop count. + * @param loopCount number of times sound is looped during play + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setLoop(int loopCount) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_LOOP_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound4")); + + ((SoundRetained)this.retained).setLoop(loopCount); + } + + /** + * Retrieves loop count for this sound + * @return loop count + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getLoop() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_LOOP_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound5")); + + return ((SoundRetained)this.retained).getLoop(); + } + + /** + * Enables or disables the release flag for the sound associated with + * this sound. + * @param state release flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setReleaseEnable(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_RELEASE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound6")); + + ((SoundRetained)this.retained).setReleaseEnable(state); + } + + /** + * Retrieves the release flag for sound associated with sound. + * @return sound's release flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getReleaseEnable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_RELEASE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound7")); + + return ((SoundRetained)this.retained).getReleaseEnable(); + } + + /** + * Enables or disables continuous play flag. + * @param state denotes if deactivated sound silently continues playing + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setContinuousEnable(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CONT_PLAY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound8")); + + ((SoundRetained)this.retained).setContinuousEnable(state); + } + + /** + * Retrieves sound's continuous play flag. + * @return flag denoting if deactivated sound silently continues playing + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getContinuousEnable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CONT_PLAY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound9")); + + return ((SoundRetained)this.retained).getContinuousEnable(); + } + + /** + * Enable or disable sound. + * @param state enable (on/off) flag denotes if active sound is heard + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setEnable(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ENABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound10")); + + if (this instanceof BackgroundSound) + ((SoundRetained)this.retained).setEnable(state); + else // instanceof PointSound or ConeSound + ((PointSoundRetained)this.retained).setEnable(state); + } + + /** + * Retrieves sound's enabled flag. + * @return sound enabled flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getEnable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ENABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound21")); + + return ((SoundRetained)this.retained).getEnable(); + } + + + /** + * Set the Sound's scheduling region to the specified bounds. + * This is used when the scheduling bounding leaf is set to null. + * @param region the bounds that contains the Sound's new scheduling + * region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setSchedulingBounds(Bounds region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCHEDULING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound11")); + + ((SoundRetained)this.retained).setSchedulingBounds(region); + } + + /** + * Retrieves the Sound node's scheduling bounds. + * @return this Sound's scheduling bounds information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getSchedulingBounds() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCHEDULING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound12")); + + return ((SoundRetained)this.retained).getSchedulingBounds(); + } + + + /** + * Set the Sound's scheduling region to the specified bounding leaf. + * When set to a value other than null, this overrides the scheduling + * bounds object. + * @param region the bounding leaf node used to specify the Sound + * node's new scheduling region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setSchedulingBoundingLeaf(BoundingLeaf region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCHEDULING_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound11")); + + ((SoundRetained)this.retained).setSchedulingBoundingLeaf(region); + } + + /** + * Retrieves the Sound node's scheduling bounding leaf. + * @return this Sound's scheduling bounding leaf information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BoundingLeaf getSchedulingBoundingLeaf() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SCHEDULING_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound12")); + + return ((SoundRetained)this.retained).getSchedulingBoundingLeaf(); + } + + + /** + * Set sound's priority value. + * @param priority value used to order sound's importance for playback. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPriority(float priority) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PRIORITY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound15")); + + ((SoundRetained)this.retained).setPriority(priority); + } + + /** + * Retrieves sound's priority value. + * @return sound priority value + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getPriority() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PRIORITY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound16")); + + return ((SoundRetained)this.retained).getPriority(); + } + + + /** + * Get the Sound's duration + * @return this Sound's duration in milliseconds including repeated + * loops + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public long getDuration() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_DURATION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound17")); + + return ((SoundRetained)this.retained).getDuration(); + } + + + /** + * Retrieves sound's 'ready' status. If this sound is fully + * prepared to begin playing (audibly or silently) on all + * initialized audio devices, this method returns true. + * @return flag denoting if sound is immediate playable or not + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean isReady() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_IS_READY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound22")); + + return ((SoundRetained)this.retained).isReady(); + } + + /** + * Retrieves sound's 'ready' status. If this sound is fully + * prepared to begin playing (audibly or silently) on the audio + * device associated with this view, this method returns true. + * @param view the view on which to query the ready status. + * @return flag denoting if sound is immediate playable or not + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public boolean isReady(View view) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_IS_READY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound22")); + + return ((SoundRetained)this.retained).isReady(view); + } + + + /** + * Retrieves sound's play status. If this sound is audibly playing on any + * initialized audio device, this method returns true. + * @return flag denoting if sound is playing (potentially audible) or not + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean isPlaying() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_IS_PLAYING_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound18")); + + return ((SoundRetained)this.retained).isPlaying(); + } + + /** + * Retrieves sound's play status. If this sound is audibly playing on the + * audio device associated with the given view, this method returns + * true. + * @param view the view on which to query the isPlaying status. + * @return flag denoting if sound is playing (potentially audible) or not + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public boolean isPlaying(View view) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_IS_PLAYING_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound18")); + + return ((SoundRetained)this.retained).isPlaying(view); + } + + /** + * Retrieves sound's silent status. If this sound is silently playing on + * any initialized audio device, this method returns true. + * @return flag denoting if sound is silently playing (enabled but not active) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean isPlayingSilently() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_IS_PLAYING_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound18")); + + return ((SoundRetained)this.retained).isPlayingSilently(); + } + + /** + * Retrieves sound's silent status. If this sound is silently playing on + * the audio device associated with the given view, this method returns + * true. + * The isPlayingSilently state is affected by enable, mute, and continuous + * states as well as active status of sound. + * @param view the view on which to query the isPlayingSilently status. + * @return flag denoting if sound is silently playing (enabled but not active) + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public boolean isPlayingSilently(View view) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_IS_PLAYING_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound18")); + + return ((SoundRetained)this.retained).isPlayingSilently(view); + } + + + /** + * Retrieves number of channels that are being used to render this sound + * on the audio device associated with the Virtual Universe's primary view. + * @return number of channels used by sound; returns 0 if not playing + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getNumberOfChannelsUsed() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHANNELS_USED_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound20")); + + return ((SoundRetained)this.retained).getNumberOfChannelsUsed(); + } + + /** + * Retrieves number of channels that are being used to render this sound + * on the audio device associated with given view. + * @param view the view on which to query the number of channels used. + * @return number of channels used by sound; returns 0 if not playing + * @exception CapabilityNotSetException if appropriate capability is + * @since Java 3D 1.3 + * not set and this object is part of live or compiled scene graph + */ + public int getNumberOfChannelsUsed(View view) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHANNELS_USED_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound20")); + + return ((SoundRetained)this.retained).getNumberOfChannelsUsed(view); + } + + /** + * Set mute state flag. If the sound is playing it will be set to + * play silently + * @param state flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setMute(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_MUTE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound23")); + + ((SoundRetained)this.retained).setMute(state); + } + + /** + * Retrieves sound Mute state. + * A return value of true does not imply that the sound has + * been started playing or is still playing silently. + * @return mute state flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public boolean getMute() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_MUTE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound24")); + + return ((SoundRetained)this.retained).getMute(); + } + + /** + * Pauses or resumes (paused) playing sound. + * @param state pause flag + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setPause(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PAUSE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound25")); + + ((SoundRetained)this.retained).setPause(state); + } + + /** + * Retrieves the value of the Pause state flag. + * A return value of true does not imply that the sound was + * started playing and then paused. + * @return pause state + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public boolean getPause() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PAUSE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound26")); + + return ((SoundRetained)this.retained).getPause(); + } + + /** + * Sets Sample Rate. + * Changes (scales) the playback rate of a sound independent of + * Doppler rate changes - applied to ALL sound types. + * Affects device sample rate playback and thus affects both pitch and speed + * @param scaleFactor %%% describe this. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public void setRateScaleFactor(float scaleFactor) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_RATE_SCALE_FACTOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound27")); + + ((SoundRetained)this.retained).setRateScaleFactor(scaleFactor); + } + + /** + * Retrieves Sample Rate. + * @return sample rate scale factor + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @since Java 3D 1.3 + */ + public float getRateScaleFactor() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_RATE_SCALE_FACTOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Sound28")); + + return ((SoundRetained)this.retained).getRateScaleFactor(); + } + + /** + * Copies all Sound information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + SoundRetained orgRetained = (SoundRetained)originalNode.retained; + + SoundRetained thisRetained = (SoundRetained)this.retained; + + thisRetained.setSoundData((MediaContainer) getNodeComponent( + orgRetained.getSoundData(), + forceDuplicate, + originalNode.nodeHashtable)); + thisRetained.setInitialGain(orgRetained.getInitialGain()); + thisRetained.setLoop(orgRetained.getLoop()); + thisRetained.setReleaseEnable(orgRetained.getReleaseEnable()); + thisRetained.setContinuousEnable(orgRetained.getContinuousEnable()); + thisRetained.setSchedulingBounds(orgRetained.getSchedulingBounds()); + thisRetained.setPriority(orgRetained.getPriority()); + thisRetained.setEnable(orgRetained.getEnable()); + + // updateNodeReferences will set the following correctly + thisRetained.setSchedulingBoundingLeaf(orgRetained.getSchedulingBoundingLeaf()); + } + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + super.updateNodeReferences(referenceTable); + + SoundRetained rt = (SoundRetained) retained; + BoundingLeaf bl = rt.getSchedulingBoundingLeaf(); + + if (bl != null) { + Object o = referenceTable.getNewObjectReference(bl); + rt.setSchedulingBoundingLeaf((BoundingLeaf)o); + } + MediaContainer sd = rt.getSoundData(); + if (sd != null) { + rt.setSoundData(sd); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SoundException.java b/j3d-core/src/classes/share/javax/media/j3d/SoundException.java new file mode 100644 index 0000000..d9f788f --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SoundException.java @@ -0,0 +1,54 @@ +/* + * $RCSfile: SoundException.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Indicates a problem in loading or playing a sound sample. + */ +public class SoundException extends RuntimeException{ + +/** + * Create the exception object with default values. + */ + public SoundException(){ + } + +/** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public SoundException(String str){ + + super(str); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SoundRenderer.java b/j3d-core/src/classes/share/javax/media/j3d/SoundRenderer.java new file mode 100644 index 0000000..f9ff277 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SoundRenderer.java @@ -0,0 +1,94 @@ +/* + * $RCSfile: SoundRenderer.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.Vector; + +class SoundRenderer extends Object { + + SoundRenderer() { + } + + void activate(SoundRetained sound, SoundscapeRetained ss) { + AuralAttributesRetained aa = ss.attributes.mirrorAa; + + if (sound instanceof BackgroundSoundRetained) { + System.err.println("Activating BackgroundSoundRetained"); + } else if (sound instanceof ConeSoundRetained) { + System.err.println("Activating ConeSoundRetained"); + } else if (sound instanceof PointSoundRetained) { + System.err.println("Activating PointSoundRetained"); + } + if (ss != null) + System.err.println("Soundscape is " + ss); + else + System.err.println("Soundscape is null"); + + if (aa != null) + System.err.println("AuralAttributes is " + aa); + else + System.err.println("AuralAttributes is null"); + } + + void update(SoundRetained sound, SoundscapeRetained ss) { + AuralAttributesRetained aa = ss.attributes.mirrorAa; + + if (false) { + if (sound instanceof BackgroundSoundRetained) { + System.err.println("Updating BackgroundSoundRetained"); + } else if (sound instanceof ConeSoundRetained) { + System.err.println("Updating ConeSoundRetained"); + } else if (sound instanceof PointSoundRetained) { + System.err.println("Updating PointSoundRetained"); + } + System.err.println("Soundscape is " + ss); + } + } + + void deactivate(SoundRetained sound) { + if (false) { + if (sound instanceof BackgroundSoundRetained) { + System.err.println("Deactivating BackgroundSoundRetained"); + } else if (sound instanceof ConeSoundRetained) { + System.err.println("Deactivating ConeSoundRetained"); + } else if (sound instanceof PointSoundRetained) { + System.err.println("Deactivating PointSoundRetained"); + } + } + } + + public String toString() { + return ""; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SoundRetained.java b/j3d-core/src/classes/share/javax/media/j3d/SoundRetained.java new file mode 100644 index 0000000..a92f208 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SoundRetained.java @@ -0,0 +1,1316 @@ +/* + * $RCSfile: SoundRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; +import java.util.ArrayList; + + + +/** + * SoundRetained is an abstract class that contains instance varables common + * to all retained sounds. + */ + +abstract class SoundRetained extends LeafRetained +{ + + /** + * Null Sound identifier denotes sound is not created or initialized + */ + static final int NULL_SOUND = -1; + + /** + * sound data associated with sound source + */ + MediaContainer soundData = null; + + /** + * Overall Scale Factor applied to sound. + */ + float initialGain = 1.0f; // Valid values are >= 0.0. + + /** + * Number of times sound is looped/repeated during play + */ + int loopCount = 0; // Range from 0 to POSITIVE_INFINITY(-1) + + /** + * Switch for turning sound on or off while the sound is "active" + */ + boolean enable = false; + + /** + * Type of release when sound is disabled. + * If true, sound plays thru to end of sample before disabled + * Otherwise, sound is disabled immediately. + */ + boolean release = false; + + /** + * Flag denoting if sound silently continues playing when it's deactivated. + */ + boolean continuous = false; + + /** + * Flag denoting if sound is explicitly muted, so that if begins playing + * it will be played silently. + */ + boolean mute = false; + + /** + * Flag denoting if sound is paused from playing - waiting to be resumed + */ + boolean pause = false; + + /** + * Sound priority ranking value. + * Valid values are 0.0 to 1.0 + */ + float priority = 1.0f; + + /** + * Rate Scale Factor applied to sounds playback sample rate in Hertz. + * Valid values are 0.0 to 1.0 + */ + float rate = 1.0f; + + /** + * The Boundary object defining the sound's scheduling region. + */ + Bounds schedulingRegion = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * The transformed bounds from either schedulingRegion or boundingLeaf + */ + Bounds transformedRegion = null; + + // Dirty bit flags used to pass change as part of message, and are + // acclummuated/stored in SoundSchedulerAtoms. + // These flags are grouped into two catagories: + // attribsDirty for sound node fields + // stateDirty for changes to sound state not reflected by sound fields. + + // Attributes Dirty bit flags + // This bitmask is set when sound node attribute is changed by the user. + static final int SOUND_DATA_DIRTY_BIT = 0x0001; + static final int INITIAL_GAIN_DIRTY_BIT = 0x0002; + static final int LOOP_COUNT_DIRTY_BIT = 0x0004; + static final int BOUNDS_DIRTY_BIT = 0x0008; + static final int BOUNDING_LEAF_DIRTY_BIT = 0x0010; + static final int PRIORITY_DIRTY_BIT = 0x0020; + static final int POSITION_DIRTY_BIT = 0x0040; + static final int DISTANCE_GAIN_DIRTY_BIT = 0x0080; + static final int BACK_DISTANCE_GAIN_DIRTY_BIT = 0x0100; + static final int DIRECTION_DIRTY_BIT = 0x0200; + static final int ANGULAR_ATTENUATION_DIRTY_BIT = 0x0400; + static final int RATE_DIRTY_BIT = 0x0800; + + static final int BOUNDS_CHANGED = + BOUNDS_DIRTY_BIT | BOUNDING_LEAF_DIRTY_BIT; + + static final int ATTRIBUTE_DIRTY_BITS = + SOUND_DATA_DIRTY_BIT | INITIAL_GAIN_DIRTY_BIT | + LOOP_COUNT_DIRTY_BIT | PRIORITY_DIRTY_BIT | + RATE_DIRTY_BIT; + + static final int POSITIONAL_DIRTY_BITS = + ATTRIBUTE_DIRTY_BITS | + POSITION_DIRTY_BIT | DISTANCE_GAIN_DIRTY_BIT; + + static final int DIRECTIONAL_DIRTY_BITS = + POSITIONAL_DIRTY_BITS | BACK_DISTANCE_GAIN_DIRTY_BIT | + DIRECTION_DIRTY_BIT | ANGULAR_ATTENUATION_DIRTY_BIT; + + // All attribute bits that are specifically set or cleared for any node */ + static final int ALL_ATTIBS_DIRTY_BITS = 0x0FFF; + + // State Dirty bit flags + // This bitmask is set when scene graph state is changed. + static final int LIVE_DIRTY_BIT = 0x0001; + static final int IMMEDIATE_MODE_DIRTY_BIT = 0x0002; + static final int LOAD_SOUND_DIRTY_BIT = 0x0004; + static final int RELEASE_DIRTY_BIT = 0x0008; + static final int CONTINUOUS_DIRTY_BIT = 0x0010; + static final int ENABLE_DIRTY_BIT = 0x0020; + static final int MUTE_DIRTY_BIT = 0x0040; + static final int PAUSE_DIRTY_BIT = 0x0080; + static final int XFORM_DIRTY_BIT = 0x8000; + + // All attribute bits that are specifically set or cleared for any node */ + static final int ALL_STATE_DIRTY_BITS = 0x80FF; + + // The type of sound node: Background, Point, Cone + int soundType = NULL_SOUND; + + // A back reference to the scene graph sound, when this is a mirror sound + SoundRetained sgSound = null; + + // A HashKey for sounds in a shared group + HashKey key = null; + + // An array of mirror sounds, one for each instance of this sound in a + // shared group. Entry 0 is the only one valid if we are not in a shared + // group. + SoundRetained[] mirrorSounds = new SoundRetained[1]; + + // The number of valid sounds in mirrorSounds + int numMirrorSounds = 0; + + /** + * Array of references to sound scheduler atoms associated with this node. + * For each view that a sound node is associated with a sound scheduler + * atom is created and maintained + */ + // for a particular view that are playing either audibly or silently. + private SoundSchedulerAtom[] loadedAtoms = new SoundSchedulerAtom[1]; + private int atomCount = 0; + + /** + * This is true when this sound is referenced in an immediate mode context + */ + boolean inImmCtx = false; + + /** + * Load Sound Data Status + */ + static final int LOAD_COMPLETE = 2; + // load requested but could not be performed due because sound not live + static final int LOAD_PENDING = 1; + static final int LOAD_NULL = 0; + static final int LOAD_FAILED = -1; + int loadStatus = LOAD_NULL; + long duration = Sound.DURATION_UNKNOWN; + + // Static initializer for SoundRetained class + static { + VirtualUniverse.loadLibraries(); + } + + // Target threads to be notified when sound changes + static final int targetThreads = J3dThread.UPDATE_SOUND | + J3dThread.SOUND_SCHEDULER; + + // Is true, if the mirror light is viewScoped + boolean isViewScoped = false; + + + /** + * Dispatch a message about a sound attribute change + */ + void dispatchAttribChange(int dirtyBit, Object argument) { + // Send message including a integer argument + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_SOUND | + J3dThread.SOUND_SCHEDULER; + createMessage.type = J3dMessage.SOUND_ATTRIB_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(dirtyBit); + if (inSharedGroup) + createMessage.args[2] = new Integer(numMirrorSounds); + else + createMessage.args[2] = new Integer(1); + createMessage.args[3] = mirrorSounds.clone(); + createMessage.args[4] = argument; + if (debugFlag) + debugPrint("dispatchAttribChange with " + dirtyBit); + VirtualUniverse.mc.processMessage(createMessage); + } + + /** + * Dispatch a message about a sound state change + */ + void dispatchStateChange(int dirtyBit, Object argument) { + // Send message including a integer argument + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_SOUND | + J3dThread.SOUND_SCHEDULER; + createMessage.type = J3dMessage.SOUND_STATE_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(dirtyBit); + if (inSharedGroup) + createMessage.args[2] = new Integer(numMirrorSounds); + else + createMessage.args[2] = new Integer(1); + createMessage.args[3] = mirrorSounds.clone(); + createMessage.args[4] = argument; + if (debugFlag) + debugPrint("dispatchStateChange with " + dirtyBit); + VirtualUniverse.mc.processMessage(createMessage); + } + + /** + * Assign value into sound data field + * @param soundData description of sound source data + */ + void setSoundDataState(MediaContainer soundData) { + this.soundData = soundData; + } + + /** + * Associates sound data with this sound source node + * Attempt to load sound + * @param soundData descrition of sound source data + */ + void setSoundData(MediaContainer soundData) { + // if resetting soundData to the same value don't bother doing anything + if (this.soundData == soundData) { + return; + } + + if (this.soundData != null) { + // this sound node had older sound data; clear it out + ((MediaContainerRetained)this.soundData.retained).removeUser(this); + } + + if (source != null && source.isLive()) { + if (this.soundData != null) { + ((MediaContainerRetained)this.soundData.retained).clearLive(refCount); + } + + if (soundData != null) { + ((MediaContainerRetained)soundData.retained).setLive(inBackgroundGroup, refCount); + ((MediaContainerRetained)soundData.retained).addUser(this); + } + } + + this.soundData = soundData; + dispatchAttribChange(SOUND_DATA_DIRTY_BIT, soundData); + + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Retrieves sound data associated with this sound source node + * @return sound source data container + */ + MediaContainer getSoundData() { + return ( this.soundData ); + } + + + /** + * Set the gain scale factor applied to this sound + * @param amplitude gain scale factor + */ + void setInitialGain(float scaleFactor) { + if (scaleFactor < 0.0f) + this.initialGain = 0.0f; + else + this.initialGain = scaleFactor; + + dispatchAttribChange(INITIAL_GAIN_DIRTY_BIT, (new Float(scaleFactor))); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + /** + * Get the overall gain (applied to the sound data associated with source). + * @return overall gain of sound source + */ + float getInitialGain() { + return (float) this.initialGain; + } + + + /** + * Sets the sound's loop count + * @param loopCount number of times sound is looped during play + */ + void setLoop(int loopCount) { + if (loopCount < -1) + this.loopCount = -1; + else + this.loopCount = (int) loopCount; + if (debugFlag) + debugPrint("setLoopCount called with " + this.loopCount); + + dispatchAttribChange(LOOP_COUNT_DIRTY_BIT, (new Integer(loopCount))); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Retrieves the loop count + * @return loop count for data associated with sound + */ + int getLoop() { + return (int) this.loopCount; + } + + /** + * Enable or disable the release flag for this sound source + * @param state flag denoting release sound before stopping + */ + void setReleaseEnable(boolean state) { + this.release = state; + dispatchAttribChange(RELEASE_DIRTY_BIT, (state ? Boolean.TRUE: Boolean.FALSE)); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Retrieves release flag for sound associated with this source node + * @return sound's release flag + */ + boolean getReleaseEnable() { + return (boolean) this.release; + } + + /** + * Enable or disable continuous play flag + * @param state denotes if sound continues playing silently when deactivated + */ + void setContinuousEnable(boolean state) { + this.continuous = state; + dispatchAttribChange(CONTINUOUS_DIRTY_BIT, (state ? Boolean.TRUE: Boolean.FALSE)); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Retrieves sound's continuous play flag + * @return flag denoting if deactivated sound silently continues playing + */ + boolean getContinuousEnable() { + return (boolean) this.continuous; + } + + /** + * Sets the flag denotine sound enabled/disabled and sends a message + * for the following to be done: + * If state is true: + * if sound is not playing, sound is started. + * if sound is playing, sound is stopped, then re-started. + * If state is false: + * if sound is playing, sound is stopped + * @param state true or false to enable or disable the sound + */ + void setEnable(boolean state) { + enable = state; + // QUESTION: Is this still valid code? + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + dispatchStateChange(ENABLE_DIRTY_BIT, (new Boolean(enable))); + } + + /** + * Retrieves sound's enabled flag + * @return sound enabled flag + */ + boolean getEnable() { + return enable; + } + + /** + * Set the Sound's scheduling region. + * @param region a region that contains the Sound's new scheduling region + */ + void setSchedulingBounds(Bounds region) { + if (region != null) { + schedulingRegion = (Bounds) region.clone(); + if (staticTransform != null) { + schedulingRegion.transform(staticTransform.transform); + } + // QUESTION: Clone into transformedRegion IS required. Why? + transformedRegion = (Bounds) schedulingRegion.clone(); + if (debugFlag) + debugPrint("setSchedulingBounds for a non-null region"); + } + else { + schedulingRegion = null; + // QUESTION: Is transformedRegion of node (not mirror node) + // even looked at??? + transformedRegion = null; + if (debugFlag) + debugPrint("setSchedulingBounds for a NULL region"); + } + // XXXX: test that this works - could not new Bounds() since + // Bounds is an abstract class and can't be instantiated + dispatchAttribChange(BOUNDS_DIRTY_BIT, region); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Get the Sound's scheduling region. + * @return this Sound's scheduling region information + */ + Bounds getSchedulingBounds() { + Bounds b = null; + + if (this.schedulingRegion != null) { + b = (Bounds) schedulingRegion.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + } + return b; + } + + /** + * Set the Sound's scheduling region to the specified Leaf node. + */ + void setSchedulingBoundingLeaf(BoundingLeaf region) { + int i; + int numSnds = numMirrorSounds; + if (numMirrorSounds == 0) + numSnds = 1; + + if ((boundingLeaf != null) && + (source != null && source.isLive())) { + // Remove the mirror lights as users of the original bounding leaf + for (i = 0; i < numSnds; i++) { + boundingLeaf.mirrorBoundingLeaf.removeUser(mirrorSounds[i]); + } + } + + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + // Add all mirror sounds as user of this bounding leaf + if (source != null && source.isLive()) { + for (i = 0; i < numSnds; i++) { + boundingLeaf.mirrorBoundingLeaf.addUser(mirrorSounds[i]); + } + } + } else { + boundingLeaf = null; + } + // XXXX: since BoundingLeaf constructor only takes Bounds + // test if region passed into dispatchAttribChange correctly. + dispatchAttribChange(BOUNDING_LEAF_DIRTY_BIT, region); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Get the Sound's scheduling region + */ + BoundingLeaf getSchedulingBoundingLeaf() { + if (boundingLeaf != null) { + return((BoundingLeaf)boundingLeaf.source); + } else { + return null; + } + } + + // The update Object function. + synchronized void updateMirrorObject(Object[] objs) { + Transform3D trans = null; + int component = ((Integer)objs[1]).intValue(); + if (component == -1) { // update everything + // object 2 contains the mirror object that needs to be + // updated + initMirrorObject(((SoundRetained)objs[2])); + } + + // call the parent's mirror object update routine + super.updateMirrorObject(objs); + + } + + void updateBoundingLeaf(long refTime) { + // This is necessary, if for example, the region + // changes from sphere to box. + if (boundingLeaf != null && boundingLeaf.switchState.currentSwitchOn) { + transformedRegion = boundingLeaf.transformedRegion; + } else { // evaluate schedulingRegion if not null + if (schedulingRegion != null) { + transformedRegion = schedulingRegion.copy(transformedRegion); + transformedRegion.transform(schedulingRegion, + getLastLocalToVworld()); + } else { + transformedRegion = null; + } + } + } + + + /** + * Set sound's proirity value. + * @param priority value used to order sound's importance for playback. + */ + void setPriority(float rank) { + if (rank == this.priority) + // changing priority is expensive in the sound scheduler(s) + // so only dispatch a message if 'new' priority value is really + // different + return; + + this.priority = rank; + dispatchAttribChange(PRIORITY_DIRTY_BIT, (new Float(rank))); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Retrieves sound's priority value. + * @return sound priority value + */ + float getPriority() { + return (this.priority); + } + + + /** + * Retrieves sound's duration in milliseconds + * @return sound's duration, returns DURATION_UNKNOWN if duration could + * not be queried from the audio device + */ + long getDuration() { + return (duration); + } + + + /** + * Set scale factor + * @param scaleFactor applied to sound playback rate + */ + void setRateScaleFactor(float scaleFactor) { + this.rate = scaleFactor; + dispatchAttribChange(RATE_DIRTY_BIT, (new Float(scaleFactor))); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Retrieves sound's rate scale factor + * @return sound rate scale factor + */ + float getRateScaleFactor() { + return (this.rate); + } + + void changeAtomList(SoundSchedulerAtom atom, int loadStatus) { + if (atom == null) + return; + if (loadStatus == SoundRetained.LOAD_COMPLETE) { + // atom is successfully loaded, so add this atom to array of atoms + // associated with this sound, if not already in list + for (int i=0; i currentArrayLength) { + // expand array - replace with a larger array + loadedAtoms = new SoundSchedulerAtom[2*currentArrayLength]; + } + loadedAtoms[atomCount-1] = atom; // store reference to new atom + // all atoms sample durations SHOULD be the same so store it in node + this.duration = atom.sampleLength; // XXXX: refine later? in ms + } + else { // atom is NOT loaded or has been unloaded; remove from list + if (atomCount == 0) + return; + + // remove atom from array of playing atoms if it is in list + boolean atomFound = false; + int i; + for (i=0; i + * 1) the Sound node has a non-null sound data and this data has + * sucessfully been loaded/opened/copied/attached;
+ * 2) the Sound node is live;
+ * 3) there is at least one active View in the Universe; and
+ * 4) an instance of an AudioDevice is attached to the current + * PhysicalEnvironment. + * + * + * @return true if potentially playable (audibly or silently); false otherwise + */ + boolean isReady() { + // all the atoms in the atom list must be are ready for this + // method to return true + // if any non-null atoms are found NOT ready, return false. + boolean atomFoundReady = true; + for (int i=0; i + * 1) the Sound node has a non-null sound data and this data has + * sucessfully been loaded/opened/copied/attached;
+ * 2) the Sound node is live;
+ * 3) the given View is active in the Universe; and
+ * 4) an instance of an AudioDevice is attached to the current + * PhysicalEnvironment. + * + * + * @param viewRef view to test sound readiness for + * @return true if potentially playable (audibly or silently); false otherwise + */ + boolean isReady(View viewRef) { + // if an atom in the atom list that is associated with the + // given view is found and has been loaded than return true, + // otherwise return false. + if (viewRef == null) + return false; + for (int i=0; i 0) { + for (int i=0; i < nMsg; i++) { + m = messages[i]; + + switch (m.type) { + case J3dMessage.INSERT_NODES: + insertNodes(m); + break; + case J3dMessage.REMOVE_NODES: + removeNodes(m); + break; + case J3dMessage.SOUND_ATTRIB_CHANGED: + changeNodeAttrib(m); + break; + case J3dMessage.SOUND_STATE_CHANGED: + changeNodeState(m); + break; + case J3dMessage.BOUNDINGLEAF_CHANGED: + processBoundingLeafChanged(m); + break; + case J3dMessage.SOUNDSCAPE_CHANGED: + SoundscapeRetained ss = (SoundscapeRetained)m.args[0]; + if (universe.soundStructure.isSoundscapeScopedToView(ss, view)) { + auralAttribsChanged = true; + changeNodeAttrib(m); + } + break; + case J3dMessage.AURALATTRIBUTES_CHANGED: + auralAttribsChanged = true; + changeNodeAttrib(m); + break; + case J3dMessage.MEDIA_CONTAINER_CHANGED: + changeNodeAttrib(m); + break; + case J3dMessage.TRANSFORM_CHANGED: + transformMsg = true; + auralAttribsChanged = true; + break; + case J3dMessage.RENDER_IMMEDIATE: + processImmediateNodes(m.args, referenceTime); + break; + case J3dMessage.VIEWSPECIFICGROUP_CHANGED: + processViewSpecificGroupChanged(m); + break; + case J3dMessage.UPDATE_VIEW: + if (debugFlag) + debugPrint(".processMessage() UPDATE_VIEW"); + // NOTE: can only rely on seeing UPDATE_VIEW when canvas [re]Created + // AND when view deactivated... + // NOTE: + // temp work-around + // calling prioritizeSounds() wipes out old atom fields + // QUESTION: prioritizedSound is NEVER empty - why if size is 0 can + // .isEmpty return anything but TRUE??? + // + if (prioritizedSounds.isEmpty()) { + nSounds = prioritizeSounds(); + } + break; + case J3dMessage.SWITCH_CHANGED: + if (debugFlag) + debugPrint(".processMessage() " + + "SWITCH_CHANGED ignored"); + break; + } // switch + m.decRefcount(); + } // for + if (transformMsg) { + targets = universe.transformStructure.getTargetList(); + updateTransformChange(targets, referenceTime); + transformMsg = false; + targets = null; + } + Arrays.fill(messages, 0, nMsg, null); + } + + // Call renderChanges within try/catch so errors won't kill + // the SoundScheduler. + try { + renderChanges(); + } + catch (RuntimeException e) { + System.err.println("Exception occurred " + + "during Sound rendering:"); + e.printStackTrace(); + } + catch (Error e) { + // Issue 264 - catch Error + System.err.println("Error occurred " + + "during Sound rendering:"); + e.printStackTrace(); + } + + // what if the user/app makes no change to scenegraph? + // must still re-render after retest for sound complete + // calculate which sound will finished first and set a + // wait time to this shortest time so that scheduler is + // re-entered to process sound complete. + + long waitTime = shortestTimeToFinish(); + + if (waitTime == 0L) { + // come right back + if (debugFlag) + debugPrint(".processMessage calls sendRunMessage " + + "for immediate processing"); + VirtualUniverse.mc.sendRunMessage(universe, + J3dThread.SOUND_SCHEDULER); + } + else if (waitTime > 0L) { + // Use TimerThread to send message with sounds complete. + // This uses waitForElapse time to sleep for at least the duration + // returned by shortestTimeToFinish method. + if (debugFlag) + debugPrint(".processMessage calls sendRunMessage " + + "with wait time = " + waitTime ); + // QUESTION (ISSUE): even when this is set to a large time + // processMessage is reentered immediately. + // Why is timer thread not waiting?? + VirtualUniverse.mc.sendRunMessage(waitTime, view, + J3dThread.SOUND_SCHEDULER); + } + } + + void insertNodes(J3dMessage m) { + Object[] nodes = (Object[])m.args[0]; + ArrayList viewScopedNodes = (ArrayList)m.args[3]; + ArrayList scopedNodesViewList = (ArrayList)m.args[4]; + Object node; + + for (int i=0; i 0) { + if (debugFlag) + debugPrint(" MuteDirtyBit is on"); + muteSound((SoundRetained) node); + } + if ((attribDirty & SoundRetained.PAUSE_DIRTY_BIT) > 0) { + if (debugFlag) + debugPrint(" PauseDirtyBit is on"); + pauseSound((SoundRetained) node); + } + } + else if (node instanceof SoundscapeRetained && + universe.soundStructure.isSoundscapeScopedToView(node, view)) { + auralAttribsChanged = true; + } + else if (node instanceof AuralAttributesRetained) { + auralAttribsChanged = true; + } + else if (node instanceof MediaContainerRetained) { + int listSize = ((Integer)m.args[2]).intValue(); + ArrayList userList = (ArrayList)m.args[3]; + for (int i = 0; i < listSize; i++) { + SoundRetained sound = (SoundRetained)userList.get(i); + if (sound != null) { + loadSound(sound, true); + if (debugFlag) + debugPrint(".changeNodeAttrib " + + "MEDIA_CONTAINER_CHANGE calls loadSound"); + } + } + } + } + + + void changeNodeState(J3dMessage m) { + Object node = m.args[0]; + Object value = m.args[1]; + if (debugFlag) + debugPrint(".changeNodeState:"); + if (node instanceof SoundRetained && universe.soundStructure.isSoundScopedToView(node, view)) { + int stateDirty = ((Integer)value).intValue(); + setStateDirtyFlag((SoundRetained)node, stateDirty); + if (debugFlag) + debugPrint(" Sound node dirty bit = "+stateDirty); + if ((stateDirty & SoundRetained.LIVE_DIRTY_BIT) > 0) { + if (debugFlag) + debugPrint(".changeNodeState LIVE_DIRTY_BIT " + + "calls loadSound"); + loadSound((SoundRetained) node, false); + } + if ((stateDirty & SoundRetained.ENABLE_DIRTY_BIT) > 0) { + if (debugFlag) + debugPrint(" EnableDirtyBit is on"); + if (((Boolean) m.args[4]).booleanValue()) { + enableSound((SoundRetained) node); + } else { + SoundSchedulerAtom soundAtom; + SoundRetained soundRetained = (SoundRetained) node; + for (int i=prioritizedSounds.size()-1; i >=0; i--) { + soundAtom = ((SoundSchedulerAtom)prioritizedSounds.get(i)); + if (soundAtom.sound.sgSound == soundRetained) { + // ignore soundRetained.release + // flag which is not implement + turnOff(soundAtom); + // Fix to Issue 431. + soundAtom.enable(soundRetained.enable); + } + } + } + } + } + } + + void shuffleSound(SoundRetained sound) { + // Find sound atom that references this sound node and + // reinsert it into prioritized sound list by removing atom for + // this sound from priority list, then re-add it. + // Assumes priority has really changed since a message is not sent + // to the scheduler if the 'new' priority value isn't different. + deleteSound(sound); // remove atom for this sound + addSound(sound); // then re-insert it back into list in new position + } + + + void loadSound(SoundRetained sound, boolean forceReload) { + // find sound atom that references this sound node + // QUESTION: "node" probably not mirror node? + SoundSchedulerAtom soundAtom = null; + for (int i=1; ;i++) { + soundAtom = findSoundAtom(sound, i); + if (soundAtom == null) + break; + MediaContainer mediaContainer = sound.getSoundData(); + if (forceReload || + soundAtom.loadStatus != SoundRetained.LOAD_COMPLETE) { + if (debugFlag) + debugPrint(": not LOAD_COMPLETE - try attaching"); + attachSoundData(soundAtom, mediaContainer, forceReload); + } + } + } + + + void enableSound(SoundRetained sound) { + if (debugFlag) + debugPrint(".enableSound " + sound ); + // find sound atom that references this sound node + SoundSchedulerAtom soundAtom = null; + for (int i=1; ;i++) { + soundAtom = findSoundAtom(sound, i); + if (soundAtom == null) + break; + // Set atom enabled field based on current Sound node + // enable boolean flag + soundAtom.enable(sound.enable); + } + } + + + void muteSound(SoundRetained sound) { + // make mute pending + // mute -> MAKE-SILENT + // unmute -> MAKE-AUDIBLE + if (debugFlag) + debugPrint(".muteSound " + sound ); + // find sound atom that references this sound node + SoundSchedulerAtom soundAtom = null; + for (int i=1; ;i++) { + soundAtom = findSoundAtom(sound, i); + if (soundAtom == null) + break; + // Set atom mute field based on node current + // mute boolean flag + soundAtom.mute(sound.mute); + } + } + + void pauseSound(SoundRetained sound) { + // make pause pending + // Pause is a separate action + // When resumed it has to reset its state + // PAUSE_AUDIBLE + // PAUSE_SILENT + // RESUME_AUDIBLE + // RESUME_SILENT + // to whatever it was before + if (debugFlag) + debugPrint(".pauseSound " + sound ); + // find sound atom that references this sound node + SoundSchedulerAtom soundAtom = null; + for (int i=1; ;i++) { + soundAtom = findSoundAtom(sound, i); + if (soundAtom == null) + break; + // Set atom pause field based on node's current + // pause boolean flag + soundAtom.pause(sound.pause); + } + } + + void processImmediateNodes(Object[] args, long referenceTime) { + Object command = args[0]; + Object newNode = args[1]; + Object oldNode = args[2]; + Sound oldSound = (Sound)oldNode; + Sound newSound = (Sound)newNode; + int action = ((Integer)command).intValue(); + if (debugFlag) + debugPrint(".processImmediateNodes() - action = " + + action); + switch (action) { + case GraphicsContext3D.ADD_SOUND : + case GraphicsContext3D.INSERT_SOUND : + addSound((SoundRetained)newSound.retained); + nImmedSounds++; + break; + case GraphicsContext3D.REMOVE_SOUND : + deleteSound((SoundRetained)oldSound.retained); + nImmedSounds--; + break; + case GraphicsContext3D.SET_SOUND : + deleteSound((SoundRetained)oldSound.retained); + addSound((SoundRetained)newSound.retained); + break; + } + } + + + void updateTransformChange(UpdateTargets targets, long referenceTime) { + // node.updateTransformChange() called immediately rather than + // waiting for updateObject to be called and process xformChangeList + // which apprears to only happen when sound started... + + UnorderList arrList = targets.targetList[Targets.SND_TARGETS]; + if (arrList != null) { + int j,i; + Object nodes[], nodesArr[]; + int size = arrList.size(); + nodesArr = arrList.toArray(false); + + for (j = 0; j 0) { + calcSchedulingAction(); + muteSilentSounds(); + + // short term flag set within performActions->update() + positionalSoundUpdated = false; + + // if listener parameters changed re-set View parameters + if (testListenerFlag()) { + if (debugFlag) + debugPrint(" audioDevice3D.setView"); + audioDevice3D.setView(view); + } + + numActiveSounds = performActions(); + + if (positionalSoundUpdated) { + // if performActions updated at least one positional sound + // was processed so the listener/view changes were processed, + // thus we can clear the SoundScheduler dirtyFlag, otherwise + // leave the flag dirty until a positional sound is updated + clearListenerFlag(); // clears listenerUpdated flag + } + } + /* + } + */ + } + + + /** + * Prioritize all sounds associated with SoundScheduler (view) + * This only need be done once when scheduler is initialized since + * the priority list is updated when: + * a) PRIORITY_DIRTY_BIT in soundDirty field set; or + * b) sound added or removed from live array list + */ + int prioritizeSounds() { + int size; + synchronized (prioritizedSounds) { + if (!prioritizedSounds.isEmpty()) { + prioritizedSounds.clear(); + } + // XXXX: sync soundStructure sound list + UnorderList retainedSounds = universe.soundStructure.getSoundList(view); + // QUESTION: what is in this sound list?? + // mirror node or actual node??? + nRetainedSounds = 0; + nImmedSounds = 0; + if (debugFlag) + debugPrint(" prioritizeSound , num retained sounds" + + retainedSounds.size()); + for (int i=0; i=0; j--) { + jAtom = (SoundSchedulerAtom)prioritizedSounds.get(j); + jSound = jAtom.sound; + if (debugFlag) + debugPrint(": priority of sound " + jSound.sgSound + + " element " + (j+1) + " of prioritized list"); + if (soundPriority <= jSound.sgSound.priority) { + if (j==jsounds) { + // last element's priority is larger than + // current sound's priority, so add this + // sound to the end of the list + prioritizedSounds.add(atom); + if (debugFlag) + debugPrint(": insert sound at list bottom"); + break; + } + else { + if (debugFlag) + debugPrint( + ": insert sound as list element " + + (j+1)); + prioritizedSounds.add(j+1, atom); + break; + } + } + } // for loop + if (j < 0) { // insert at the top of the list + if (debugFlag) + debugPrint(": insert sound at top of priority list"); + prioritizedSounds.add(0, atom); + } + } // else list not empty + } + + + /** + * Process active Soundscapes (if there are any) and intersect these + * soundscapes with the viewPlatform. + * + * Returns the number of soundscapes that intesect with + * view volume. + */ + int findActiveSoundscapes() { + int nSscapes = 0; + int nSelectedSScapes = 0; + SoundscapeRetained ss = null; + SoundscapeRetained lss = null; + boolean intersected = false; + int nUnivSscapes = 0; + UnorderList soundScapes = null; + + // Make a copy of references to the soundscapes in the universe + // that are both switch on and have non-null (transformed) regions, + // don't bother testing for intersection with view. + if (universe == null) { + if (debugFlag) + debugPrint(".findActiveSoundscapes() univ=null"); + return 0; + } + soundScapes = universe.soundStructure.getSoundscapeList(view); + if (soundScapes == null) { + if (debugFlag) + debugPrint(".findActiveSoundscapes() soundScapes null"); + return 0; + } + + synchronized (soundScapes) { + nUnivSscapes = soundScapes.size; + if (nUnivSscapes == 0) { + if (debugFlag) + debugPrint( + ".findActiveSoundscapes() soundScapes size=0"); + return 0; + } + + // increase arrays lengths by increments of 32 elements + if (intersectedRegions.length < nSscapes) { + intersectedRegions = new Bounds[nSscapes + 32]; + } + if (intersectedSoundscapes.length < nSscapes) { + intersectedSoundscapes = new SoundscapeRetained[nSscapes + 32]; + } + + // nSscapes is incremented for every Soundscape found + if (debugFlag) + debugPrint(".findActiveSoundscapes() nUnivSscapes="+ + nUnivSscapes); + nSelectedSScapes = 0; + for (int k=0; k 1) { + Bounds closestRegions; + closestRegions = viewPlatform.schedSphere.closestIntersection( + intersectedRegions); + for (int j=0; j < intersectedRegions.length; j++) { + if (debugFlag) + debugPrint(" element " + j + + " in intersectedSoundsscapes is " + intersectedRegions[j]); + if (intersectedRegions[j] == closestRegions) { + ss = intersectedSoundscapes[j]; + if (debugFlag) + debugPrint(" element " + j + " is closest"); + break; + } + } + } + + if (ss != null) { + if (debugFlag) + debugPrint(" closest SoundScape found is " + ss); + aa = ss.getAuralAttributes(); + if (aa != null) { + if (debugFlag) + debugPrint(": AuralAttribute for " + + "soundscape is NOT null"); + } else { + if (debugFlag) + debugPrint(": AuralAttribute for " + + "soundscape " + ss + " is NULL"); + } + } + else { + if (debugFlag) + debugPrint(": AuralAttribute is null " + + "since soundscape is NULL"); + } + + if (debugFlag) + debugPrint( + " auralAttrib for closest SoundScape found is " + aa); + return ((AuralAttributesRetained)aa.retained); + } + + /** + * Send current aural attributes to audio device + * + * Note that a AA's dirtyFlag is clear only after parameters are sent to + * audio device. + */ + void updateAuralAttribs(AuralAttributesRetained attribs) { + if (auralAttribsChanged) { + if (attribs != null) { + synchronized (attribs) { +/* + // XXXX: remove use of aaDirty from AuralAttrib node + if ((attribs != lastAA) || attribs.aaDirty) +*/ + if (debugFlag) { + debugPrint(" set real updateAuralAttribs because"); + } + + // Send current aural attributes to audio device + // Assumes that aural attribute parameter is NOT null. + audioDevice3D.setRolloff(attribs.rolloff); + if (debugFlag) + debugPrint(" rolloff " + attribs.rolloff); + + // Distance filter parameters + int arraySize = attribs.getDistanceFilterLength(); + if ((attribs.filterType == + AuralAttributesRetained.NO_FILTERING) || + arraySize == 0 ) { + audioDevice3D.setDistanceFilter( + attribs.NO_FILTERING, null, null); + if (debugFlag) + debugPrint(" no filtering"); + } + else { + Point2f[] attenuation = new Point2f[arraySize]; + for (int i=0; i< arraySize; i++) + attenuation[i] = new Point2f(); + attribs.getDistanceFilter(attenuation); + double[] distance = new double[arraySize]; + float[] cutoff = new float[arraySize]; + for (int i=0; i< arraySize; i++) { + distance[i] = attenuation[i].x; + cutoff[i] = attenuation[i].y; + } + audioDevice3D.setDistanceFilter(attribs.filterType, + distance, cutoff); + if (debugFlag) { + debugPrint(" filtering parameters: " + + " distance, cutoff arrays"); + for (int jj=0; jj0 && soundAtom.endTime<=currentTime) { + // sound's completed playing, force action + soundAtom.schedulingAction = SoundSchedulerAtom.COMPLETE; + if (debugFlag) + debugPrint(": sample complete;"+ + " endTime = " + soundAtom.endTime + + ", currentTime = " + currentTime + + " so turned off"); + soundAtom.status = SoundSchedulerAtom.SOUND_COMPLETE; + turnOff(soundAtom); // Stop sound in device that are complete + if (debugFlag) + debugPrint(": sound "+soundAtom.sampleId+ + " action COMPLETE results in call to stop"); + } + break; + + case SoundSchedulerAtom.RESTART_AUDIBLE: + case SoundSchedulerAtom.START_AUDIBLE: + case SoundSchedulerAtom.RESTART_SILENT: + case SoundSchedulerAtom.START_SILENT: + break; + + default: // includes COMPLETE, DO_NOTHING + soundAtom.schedulingAction = SoundSchedulerAtom.DO_NOTHING; + break; + } // switch + + if (debugFlag) + debugPrint(": final scheduling action " + + "set to " + soundAtom.schedulingAction); + } + + + /** + * Determine scheduling action for each live sound + */ + int calcSchedulingAction() { + // Temp variables + SoundRetained sound; + SoundRetained mirSound; + SoundSchedulerAtom soundAtom; + SoundRetained jSound; + int nSounds = 0; + boolean processSound; + // number of sounds to process including scene graph and immediate nodes + int numSoundsToProcess = 0; + + if (universe == null) { + if (debugFlag) + debugPrint( + ": calcSchedulingAction: univ NULL"); + return 0; + } + if (universe.soundStructure == null) { + if (debugFlag) + debugPrint( + ": calcSchedulingAction: soundStructure NULL"); + return 0; + } + + // List of prioritized "live" sounds taken from universe list of sounds. + // Maintained as an expandable array - start out with a small number of + // elements for this array then grow the list larger if necessary... + synchronized (prioritizedSounds) { + nSounds = prioritizedSounds.size(); + if (debugFlag) + debugPrint( + ": calcSchedulingAction: soundsList size = " + + nSounds); + + // (Large) Loop over all switched on sounds and conditionally put + // these into a order prioritized list of sound. + // Try throw out as many sounds as we can: + // Sounds finished playing (reached end before stopped) + // Sounds still yet to be loaded + // Positional sounds whose regions don't intersect view + // Sound to be stopped + // Those sounds remaining are inserted into a prioritized list + + for (int i=0; i>>>>>sound using sgSound at " + sound); + printAtomState(soundAtom); + } + processSoundAtom(soundAtom); + } // end of process sound + else { + soundAtom.schedulingAction = SoundSchedulerAtom.DO_NOTHING; + } // end of not process sound + + } // end loop over all sound in soundList + } // sync + + if (debugFlag) { + if (numSoundsToProcess > 0) + debugPrint(": number of liveSounds = " + numSoundsToProcess); + else + debugPrint(": number of liveSounds <= 0"); + } + + return numSoundsToProcess; + } + + + /** + * Mute sounds that are to be played silently. + * + * Not all the sound in the prioritized enabled sound list + * may be able to be played. Due to low priority, some sounds + * must be muted/silenced (if such an action frees up channel + * resources) to make way for sounds with higher priority. + * For each sound in priority list: + * For sounds whose actions are X_SILENT: + * Mute sounds to be silenced + * Add the number of channels used by this muted sound to + * current total number of channels used + * For all remaining sounds (with actions other than above) + * The number of channels that 'would be used' to play + * potentially audible sounds is compared with + * the number left on the device: + * If this sound would use more channels than available + * Change it's X_AUDIBLE action to X_SILENT + * Mute sounds to be silenced + * Add the number of channels used by this sound, muted + * or not, to current total number of channels used + * + * NOTE: requests for sounds to play beyond channel capability of + * the audio device do NOT throw an exception when more sounds are + * started than can be played. Rather the unplayable sounds are + * muted. It is up to the AudioDevice3D implementation to determine + * how muted/silent sounds are implememted (playing with gain zero + * and thus using up channel resources, or stop and restarted with + * correct offset when inactivated then re-actived. + */ + void muteSilentSounds() { + // Temp variables + SoundRetained sound; + SoundRetained mirSound; + int totalChannelsUsed = 0; + SoundSchedulerAtom soundAtom; + int nAtoms; + synchronized (prioritizedSounds) { + nAtoms = prioritizedSounds.size(); + if (debugFlag) + debugPrint(".muteSilentSounds(): Loop over prioritizedSounds list, " + + "size = " + nAtoms); + for (int i=0; itotalChannels) { + if ((soundAtom.schedulingAction == SoundSchedulerAtom.MAKE_AUDIBLE) || + (soundAtom.schedulingAction == SoundSchedulerAtom.LEAVE_AUDIBLE)) { + soundAtom.schedulingAction = SoundSchedulerAtom.MAKE_SILENT; + } + else if (soundAtom.schedulingAction == SoundSchedulerAtom.RESTART_AUDIBLE) + soundAtom.schedulingAction = SoundSchedulerAtom.RESTART_SILENT; + else if (soundAtom.schedulingAction == SoundSchedulerAtom.START_AUDIBLE) + soundAtom.schedulingAction = SoundSchedulerAtom.START_SILENT; + else if (soundAtom.schedulingAction == SoundSchedulerAtom.PAUSE_AUDIBLE) + soundAtom.schedulingAction = SoundSchedulerAtom.PAUSE_SILENT; + else if (soundAtom.schedulingAction == SoundSchedulerAtom.RESUME_AUDIBLE) + soundAtom.schedulingAction = SoundSchedulerAtom.RESUME_SILENT; + audioDevice3D.muteSample(sampleId); + if (debugFlag) { + debugPrint(": sound " + sampleId + + "number of channels needed is " + + numberChannels); + debugPrint(": sound " + sampleId + + " action is x_AUDIBLE but " + + "not enough channels free (" + + (totalChannels - totalChannelsUsed) + + ") so, sound muted"); + } + } + // sound has enough channels to play + else if (status != SoundSchedulerAtom.SOUND_AUDIBLE) { + // old status is not already unmuted/audible + audioDevice3D.unmuteSample(sampleId); + if (debugFlag) + debugPrint(": sound " + sampleId + + " action is x_AUDIBLE and channels free so, " + + "sound unmuted"); + } + // now that the exact muting state is known (re-)get actual + // number of channels used by this sound and add to total + numberChannels = + audioDevice3D.getNumberOfChannelsUsed(sampleId); + soundAtom.numberChannels = numberChannels; // used in audio device + totalChannelsUsed += numberChannels; + } // otherwise, scheduling is for potentally audible sound + // No sound in list should have action TURN_ or LEAVE_OFF + } // of for loop over sounds in list + } + } + + + void muteSilentSound(SoundSchedulerAtom soundAtom) { + // Temp variables + SoundRetained sound; + SoundRetained mirSound; + mirSound = (SoundRetained)soundAtom.sound; + sound = mirSound.sgSound; + int sampleId = soundAtom.sampleId; + int status = soundAtom.status; + + if (status == SoundSchedulerAtom.SOUND_COMPLETE) { + return; + } + if (sampleId == SoundRetained.NULL_SOUND) { + return; + } + if (debugFlag) { + debugPrint(": contents of current sound " + + soundAtom.sampleId + " before switch on sAction" ); + printAtomState(soundAtom); + } + + if ( (soundAtom.schedulingAction == SoundSchedulerAtom.MAKE_SILENT) || + (soundAtom.schedulingAction == SoundSchedulerAtom.RESTART_SILENT) || + (soundAtom.schedulingAction == SoundSchedulerAtom.LEAVE_SILENT) || + (soundAtom.schedulingAction == SoundSchedulerAtom.START_SILENT) ) { + // Mute sounds that are not already silent + if (status != SoundSchedulerAtom.SOUND_SILENT) { + // old status is not already muted/silent + audioDevice3D.muteSample(sampleId); + if (debugFlag) + debugPrint(": sound " + sampleId + + " action is x_SILENT, sound muted"); + } + } // scheduling is for silent sound + } + + /** + * Determine amount of time before next playing sound will be + * is complete. + * + * find the atom that has the least amount of time before is + * finished playing and return this time + * @return length of time in millisecond until the next active sound + * will be complete. Returns -1 if no sounds are playing (or all are + * complete). + */ + long shortestTimeToFinish() { + long currentTime = J3dClock.currentTimeMillis(); + long shortestTime = -1L; + SoundSchedulerAtom soundAtom; + synchronized (prioritizedSounds) { + int nAtoms = prioritizedSounds.size(); + for (int i=0; i= 0) { + if (debugFlag) + debugPrint(".start: " + index ); + soundAtom.playing = true; + soundAtom.startTime = audioDevice3D.getStartTime(index); + soundAtom.calculateEndTime(); + if (debugFlag) + debugPrint(".start: begintime = " + + soundAtom.startTime + ", endtime " + soundAtom.endTime); + } + else { // error returned by audio device when trying to start + soundAtom.startTime = 0; + soundAtom.endTime = 0; + soundAtom.playing = false; + if (debugFlag) { + debugPrint(".start: error " + startStatus + + " returned by audioDevice3D.startSample(" + index + + ")" ); + debugPrint( + " start/endTime set to zero"); + } + } + } + + + /** + * Exlicitly update the sound parameters associated with a sample + */ + void update(SoundSchedulerAtom soundAtom) { + int index = soundAtom.sampleId; + + if (index == SoundRetained.NULL_SOUND) { + return; + } + SoundRetained sound = soundAtom.sound; + audioDevice3D.updateSample(index); + if (debugFlag) { + debugPrint(".update: " + index ); + } + soundAtom.calculateEndTime(); + if (sound instanceof PointSoundRetained || + sound instanceof ConeSoundRetained) { + positionalSoundUpdated = true; + } + } + + + /** + * stop playing one specific sound node + * + * If setPending flag true, sound is stopped but enable state + * is set to pending-on so that it is restarted. + */ + void stopSound(SoundSchedulerAtom soundAtom, boolean setPending) { + if (audioDevice3D == null) + return; + + if (debugFlag) + debugPrint(":stopSound(" + soundAtom + + "), enabled = " + soundAtom.enabled); + switch (soundAtom.enabled) { + case SoundSchedulerAtom.ON: + if (setPending) + soundAtom.setEnableState(SoundSchedulerAtom.PENDING_ON); + else + soundAtom.setEnableState(SoundSchedulerAtom.SOUND_OFF); + break; + case SoundSchedulerAtom.PENDING_OFF: + soundAtom.setEnableState(SoundSchedulerAtom.SOUND_OFF); + break; + case SoundSchedulerAtom.PENDING_ON: + if (!setPending) + // Pending sounds to be stop from playing later + soundAtom.setEnableState(SoundSchedulerAtom.SOUND_OFF); + break; + default: + break; + } + soundAtom.status = SoundSchedulerAtom.SOUND_OFF; + turnOff(soundAtom); + } + + /** + * Deactive all playing sounds + * If the sound is continuous thendSilence it but leave it playing + * otherwise stop sound + */ + synchronized void deactivateAllSounds() { + SoundRetained sound; + SoundRetained mirSound; + SoundSchedulerAtom soundAtom; + + if (audioDevice3D == null) + return; + + if (debugFlag) + debugPrint(".deactivateAllSounds"); + + // sync this method from interrupting run() while loop + synchronized (prioritizedSounds) { + if (prioritizedSounds != null) { + int nAtoms = prioritizedSounds.size(); + if (debugFlag) + debugPrint("silenceAll " + nAtoms + " Sounds"); + for (int i=0; i ~/Current/MoveAppBoundingLeaf.outted, + // instead transformed position and direction + // points/vectors will be passed to AudioDevice directly. + + // vvvvvvvvvvvvvvvvvvvvvvvvvvv + if (updateAll || soundAtom.testDirtyFlag(SoundRetained.XFORM_DIRTY_BIT){ + Transform3D xform = new Transform3D(); + ps.trans.getWithLock(xform); + if (debugFlag) { + debugPrint(".updateXformedParams " + + "setVworldXfrm for ps @ " + ps + ":"); + debugPrint(" xformPosition " + + ps.xformPosition.x + ", " + + ps.xformPosition.y + ", " + + ps.xformPosition.z ); + debugPrint(" column-major transform "); + debugPrint(" " + + xform.mat[0]+", " + xform.mat[1]+", "+ + xform.mat[2]+", " + xform.mat[3]); + debugPrint(" " + + xform.mat[4]+", " + xform.mat[5]+", "+ + xform.mat[6]+", " + xform.mat[7]); + debugPrint(" " + + xform.mat[8]+", " + xform.mat[9]+", "+ + xform.mat[10]+", " + xform.mat[11]); + debugPrint(" " + + xform.mat[12]+", " + xform.mat[13]+", "+ + xform.mat[14]+", " + xform.mat[15]); + } + audioDevice3D.setVworldXfrm(index, xform); + soundAtom.clearStateDirtyFlag( SoundRetained.XFORM_DIRTY_BIT); + // XXXX: make sure position and direction are already transformed and stored + // into xformXxxxxxx fields. + } + // ^^^^^^^^^^^^^^^^^^^^^ + */ + + // Set Position + if (updateAll || testListenerFlag() || + soundAtom.testDirtyFlag(soundAtom.attribsDirty, + SoundRetained.POSITION_DIRTY_BIT) || + soundAtom.testDirtyFlag(soundAtom.stateDirty, + SoundRetained.XFORM_DIRTY_BIT) ) + { + Point3f xformLocation = new Point3f(); + mirrorPtSound.getXformPosition(xformLocation); + Point3d positionD = new Point3d(xformLocation); + if (debugFlag) + debugPrint("xform'd Position: ("+positionD.x+", "+ + positionD.y+", "+ positionD.z+")" ); + audioDevice3D.setPosition(index, positionD); + } + + // Set Direction + if (mirrorPtSound instanceof ConeSoundRetained) { + ConeSoundRetained cn = (ConeSoundRetained)mirrorPtSound; + ConeSoundRetained cnSound = (ConeSoundRetained)mirrorPtSound.sgSound; + if (updateAll || + // XXXX: test for XFORM_DIRTY only in for 1.2 + soundAtom.testDirtyFlag(soundAtom.attribsDirty, + (SoundRetained.DIRECTION_DIRTY_BIT | + SoundRetained.XFORM_DIRTY_BIT) ) ) { + + Vector3f xformDirection = new Vector3f(); + cn.getXformDirection(xformDirection); + Vector3d directionD = new Vector3d(xformDirection); + audioDevice3D.setDirection(index, directionD); + } + } + } + + + void updateSoundParams(boolean updateAll, SoundSchedulerAtom soundAtom, + AuralAttributesRetained attribs) { + + SoundRetained mirrorSound = soundAtom.sound; + SoundRetained sound = mirrorSound.sgSound; + int index = soundAtom.sampleId; + int arraySize; + + if (index == SoundRetained.NULL_SOUND) + return; + if (debugFlag) + debugPrint(".updateSoundParams(dirytFlags=" + + soundAtom.attribsDirty + ", " + soundAtom.stateDirty + ")"); + + // since the sound is audible, make sure that the parameter for + // this sound are up-to-date. + if (updateAll || soundAtom.testDirtyFlag( + soundAtom.attribsDirty, SoundRetained.INITIAL_GAIN_DIRTY_BIT)) { + + if (attribs != null) { + audioDevice3D.setSampleGain(index, + (sound.initialGain * attribs.attributeGain)); + } + else { + audioDevice3D.setSampleGain(index, sound.initialGain); + } + } + + if (updateAll || soundAtom.testDirtyFlag( + soundAtom.attribsDirty, SoundRetained.LOOP_COUNT_DIRTY_BIT)) { + if (debugFlag) + debugPrint(" audioDevice.setLoop(" + sound.loopCount + + ") called"); + audioDevice3D.setLoop(index, sound.loopCount); + } + + if (updateAll || soundAtom.testDirtyFlag( + soundAtom.attribsDirty, SoundRetained.RATE_DIRTY_BIT)) { + if (audioDevice3DL2 != null) { + if (debugFlag) + debugPrint(" audioDevice.setRateScaleFactor(" + + sound.rate + ") called"); + audioDevice3DL2.setRateScaleFactor(index, sound.rate); + } + } + + if (updateAll || soundAtom.testDirtyFlag( + soundAtom.attribsDirty, SoundRetained.DISTANCE_GAIN_DIRTY_BIT)){ + if (sound instanceof ConeSoundRetained) { + ConeSoundRetained cnSound = (ConeSoundRetained)sound; + + // set distance attenuation + arraySize = cnSound.getDistanceGainLength(); + if (arraySize == 0) { + // send default + audioDevice3D.setDistanceGain(index, null, null, null, null); + } + else { + Point2f[] attenuation = new Point2f[arraySize]; + Point2f[] backAttenuation = new Point2f[arraySize]; + for (int i=0; i< arraySize; i++) { + attenuation[i] = new Point2f(); + backAttenuation[i] = new Point2f(); + } + cnSound.getDistanceGain(attenuation, backAttenuation); + double[] frontDistance = new double[arraySize]; + float[] frontGain = new float[arraySize]; + double[] backDistance = new double[arraySize]; + float[] backGain = new float[arraySize]; + for (int i=0; i< arraySize; i++) { + frontDistance[i] = attenuation[i].x; + frontGain[i] = attenuation[i].y; + backDistance[i] = backAttenuation[i].x; + backGain[i] = backAttenuation[i].y; + } + audioDevice3D.setDistanceGain(index, + frontDistance, frontGain, backDistance, backGain); + } + } // ConeSound distanceGain + else if (sound instanceof PointSoundRetained) { + PointSoundRetained ptSound = (PointSoundRetained)sound; + + // set distance attenuation + arraySize = ptSound.getDistanceGainLength(); + if (arraySize == 0) { + // send default + audioDevice3D.setDistanceGain(index, null, null, null, null); + } + else { + Point2f[] attenuation = new Point2f[arraySize]; + for (int i=0; i< arraySize; i++) + attenuation[i] = new Point2f(); + ptSound.getDistanceGain(attenuation); + double[] frontDistance = new double[arraySize]; + float[] frontGain = new float[arraySize]; + for (int i=0; i< arraySize; i++) { + frontDistance[i] = attenuation[i].x; + frontGain[i] = attenuation[i].y; + } + audioDevice3D.setDistanceGain(index, frontDistance, + frontGain, null, null); + } + } // PointSound distanceGain + } + + if ((sound instanceof ConeSoundRetained) && + (updateAll || soundAtom.testDirtyFlag(soundAtom.attribsDirty, + SoundRetained.ANGULAR_ATTENUATION_DIRTY_BIT)) ) { + + // set angular attenuation + ConeSoundRetained cnSound = (ConeSoundRetained)sound; + arraySize = cnSound.getAngularAttenuationLength(); + if (arraySize == 0) { + // send default + double[] angle = new double[2]; + float[] scaleFactor = new float[2]; + angle[0] = 0.0; + angle[1] = (Math.PI)/2.0; + scaleFactor[0] = 1.0f; + scaleFactor[1] = 0.0f; + audioDevice3D.setAngularAttenuation(index, + cnSound.NO_FILTERING, + angle, scaleFactor, null); + } + else { + Point3f[] attenuation = new Point3f[arraySize]; + for (int i=0; i< arraySize; i++) { + attenuation[i] = new Point3f(); + } + cnSound.getAngularAttenuation(attenuation); + double[] angle = new double[arraySize]; + float[] scaleFactor = new float[arraySize]; + float[] cutoff = new float[arraySize]; + for (int i=0; i< arraySize; i++) { + angle[i] = attenuation[i].x; + scaleFactor[i] = attenuation[i].y; + cutoff[i] = attenuation[i].z; + } + audioDevice3D.setAngularAttenuation(index, + cnSound.filterType, + angle, scaleFactor, cutoff); + } + } + } + + + /** + * Check (and set if necessary) AudioDevice3D field + */ + boolean checkAudioDevice3D() { + if (universe != null) { + if (universe.currentView != null) + if (universe.currentView.physicalEnvironment != null) { + audioDevice = universe.currentView.physicalEnvironment.audioDevice; + if (audioDevice != null) { + if (audioDevice instanceof AudioDevice3DL2) { + audioDevice3DL2 = (AudioDevice3DL2)audioDevice; + } + if (audioDevice instanceof AudioDevice3D) { + audioDevice3D = (AudioDevice3D)audioDevice; + } + else { // audioDevice is only an instance of AudioDevice + if (internalErrors) + debugPrint("AudioDevice implementation not supported"); + // audioDevice3D should already be null + } + } + else { + // if audioDevice is null, clear extended class fields + audioDevice3DL2 = null; + audioDevice3D = null; + } + } + } + if (audioDevice3D == null) + return false; + + if (audioDevice3D.getTotalChannels() == 0) + return false; // can not render sounds on AudioEngine that has no channels + + return true; + } + + + /** + * Clears the fields associated with sample data for this sound. + * Assumes soundAtom is non-null, and that non-null atom + * would have non-null sound field. + */ + void clearSoundData(SoundSchedulerAtom soundAtom) { + if (checkAudioDevice3D() && + soundAtom.sampleId != SoundRetained.NULL_SOUND) { + stopSound(soundAtom, false); // force stop of playing sound + // Unload sound data from AudioDevice + audioDevice3D.clearSound(soundAtom.sampleId); + } + + soundAtom.sampleId = SoundRetained.NULL_SOUND; + // set load state into atom + soundAtom.loadStatus = SoundRetained.LOAD_NULL; + // NOTE: setting node load status not 1-to-1 w/actual load; + // this is incorrect + SoundRetained sound = soundAtom.sound; + soundAtom.loadStatus = SoundRetained.LOAD_NULL; + soundAtom.soundData = null; + sound.changeAtomList(soundAtom, SoundRetained.LOAD_NULL); + } + + + /** + * Attempts to load sound data for a particular sound source onto + * the chosen/initialized audio device + * If this called, it is assumed that SoundRetained.audioDevice is + * NOT null. + * If an error in loading occurs (an exception is caught,...) + * an error is printed out to stderr - an exception is not thrown. + * @param soundData descrition of sound source data + */ + // QUESTION: should this method be synchronized? + void attachSoundData(SoundSchedulerAtom soundAtom, + MediaContainer soundData, boolean forceReload) { + + if (!forceReload && (soundAtom.soundData == soundData)) { + return; + } + SoundRetained sound = soundAtom.sound.sgSound; + if (!checkAudioDevice3D()) { + if (debugFlag) + debugPrint(".attachSoundData audioDevice3D null"); + soundAtom.loadStatus = SoundRetained.LOAD_PENDING; + sound.changeAtomList(soundAtom, SoundRetained.LOAD_PENDING); + return; + } + if (soundAtom.soundData != null) { + // clear sound data field for view specific atom NOT sound node + clearSoundData(soundAtom); + if (soundData == null) { + if (debugFlag) + debugPrint(".attachSoundData with null soundData"); + return; + } + } + + URL url = ((MediaContainerRetained)sound.soundData.retained).url; + String path = ((MediaContainerRetained)sound.soundData.retained).urlString; + InputStream stream = ((MediaContainerRetained)sound.soundData.retained).inputStream; + if (url == null && path == null && stream == null) { + if (debugFlag) + debugPrint(".attachSoundData with null soundData"); + // clear non-null sample associated with this soundData + if (soundAtom.sampleId != SoundRetained.NULL_SOUND) { + clearSoundData(soundAtom); + } + return; + } + + int id; + if (sound instanceof ConeSoundRetained) + sound.soundType = AudioDevice3D.CONE_SOUND; + else if (sound instanceof PointSoundRetained) + sound.soundType = AudioDevice3D.POINT_SOUND; + else + sound.soundType = AudioDevice3D.BACKGROUND_SOUND; + if (debugFlag) { + debugPrint(".attachSoundData soundType = " + sound.soundType); + debugPrint(".attachSoundData this is = " + sound); + } + + // Clone the MediaContainer associated with this node and + // set the capability bits for this clone to allow access to + // all fields; this copy is passed to the audioDevice. + // As the fields of the MediaContainer expands, this code must + // be appended. + MediaContainer cloneMediaContainer = new MediaContainer(); + cloneMediaContainer.duplicateAttributes(soundData, true); + cloneMediaContainer.setCapability(MediaContainer.ALLOW_CACHE_READ); + cloneMediaContainer.setCapability(MediaContainer.ALLOW_URL_READ); + + id = audioDevice3D.prepareSound(sound.soundType, cloneMediaContainer); + if (debugFlag) + debugPrint(".attachSoundData prepareSound returned " + id); + + if (id == SoundRetained.NULL_SOUND) { + soundAtom.loadStatus = SoundRetained.LOAD_FAILED; + // NOTE: setting node load status not 1-to-1 with actual load; + // this is incorrect + sound.changeAtomList(soundAtom, SoundRetained.LOAD_FAILED); + //System.err.println(path + ": "+ J3dI18N.getString("SoundRetained1")); + } + else { + if (debugFlag) + debugPrint(".attachSoundData - sampleId set"); + soundAtom.sampleId = id; + + // For now loopLength=sampleLength, loop points not supported + long duration = audioDevice3D.getSampleDuration(id); + soundAtom.sampleLength = duration; + soundAtom.loopLength = soundAtom.sampleLength; + + // XXXX: for most this will be 0 but not all + soundAtom.loopStartOffset = 0; + soundAtom.attackLength = 0; // portion of sample before loop section + soundAtom.releaseLength = 0; // portion of sample after loop section + soundAtom.loadStatus = SoundRetained.LOAD_COMPLETE; + soundAtom.soundData = soundData; + sound.changeAtomList(soundAtom, SoundRetained.LOAD_COMPLETE); + if (debugFlag) + debugPrint(" attachSoundData; index = "+soundAtom.sampleId); + } + } + + + SoundSchedulerAtom findSoundAtom(SoundRetained node, int nthInstance) { + // find nth sound atom in the list of prioritized sounds that + // references this sound node + // nthInstance=1 would look for first instance + if (node == null) + return null; + SoundSchedulerAtom returnAtom = null; + synchronized (prioritizedSounds) { + if (!prioritizedSounds.isEmpty()) { + SoundSchedulerAtom soundAtom = null; + int atomFound = 0; + // find sound in list and remove it + int arrSize = prioritizedSounds.size(); + for (int index=0; index 0) + return true; + else + return false; + } + + /** + * set dirty flags associated with SoundSchedulerAtom + */ + void setAttribsDirtyFlag(SoundRetained node, int dirtyFlag) { + if (debugFlag) + debugPrint(".setAttribsDirtyFlag " + node ); + // find sound atom that references this sound node + SoundSchedulerAtom soundAtom = null; + for (int i=1; ;i++) { + soundAtom = findSoundAtom(node, i); + if (soundAtom == null) + break; + soundAtom.setAttribsDirtyFlag(dirtyFlag); + } + } + + void setStateDirtyFlag(SoundRetained node, int dirtyFlag) { + if (debugFlag) + debugPrint(".setStateDirtyFlag " + node ); + // find sound atom that references this sound node + SoundSchedulerAtom soundAtom = null; + for (int i=1; ;i++) { + soundAtom = findSoundAtom(node, i); + if (soundAtom == null) + break; + soundAtom.setStateDirtyFlag(dirtyFlag); + } + } + + + void printAtomState(SoundSchedulerAtom atom) { + SoundRetained sound = atom.sound.sgSound; + debugPrint(" this atom = " + atom + " "); + debugPrint(" references sound = " + sound + " "); + debugPrint(" enabled " + atom.enabled); + debugPrint(" status " + atom.status); + debugPrint(" activated " + atom.activated); + debugPrint(" released " + sound.release); + debugPrint(" continuous " + sound.continuous); + debugPrint(" scheduling " + atom.schedulingAction); + } + + // Debug print mechanism for Sound nodes + + static final boolean debugFlag = false; + static final boolean internalErrors = false; + + void debugPrint(String message) { + if (debugFlag) + System.err.println("SS."+message); + } + + void processViewSpecificGroupChanged(J3dMessage m) { + int component = ((Integer)m.args[0]).intValue(); + Object[] objAry = (Object[])m.args[1]; + if (((component & ViewSpecificGroupRetained.ADD_VIEW) != 0) || + ((component & ViewSpecificGroupRetained.SET_VIEW) != 0)) { + int i; + Object obj; + View v = (View)objAry[0]; + ArrayList leafList = (ArrayList)objAry[2]; + // View being added is this view + if (v == view) { + int size = leafList.size(); + for (i = 0; i < size; i++) { + obj = leafList.get(i); + if (obj instanceof SoundRetained) { + nRetainedSounds++; + addSound((SoundRetained) obj); + } + else if (obj instanceof SoundscapeRetained) { + auralAttribsChanged = true; + } + } + + } + + } + if (((component & ViewSpecificGroupRetained.REMOVE_VIEW) != 0)|| + ((component & ViewSpecificGroupRetained.SET_VIEW) != 0)) { + int i; + Object obj; + ArrayList leafList; + View v; + + if ((component & ViewSpecificGroupRetained.REMOVE_VIEW) != 0) { + v = (View)objAry[0]; + leafList = (ArrayList)objAry[2]; + } + else { + v = (View)objAry[4]; + leafList = (ArrayList)objAry[6]; + } + if (v == view) { + int size = leafList.size(); + for (i = 0; i < size; i++) { + obj = leafList.get(i); + if (obj instanceof SoundRetained) { + SoundSchedulerAtom soundAtom = null; + for (int arrIndx=1; ;arrIndx++) { + soundAtom = findSoundAtom((SoundRetained)obj, + arrIndx); + if (soundAtom == null) + break; + stopSound(soundAtom, false); + } + } + else if (obj instanceof SoundscapeRetained) { + auralAttribsChanged = true; + } + } + } + } + + } + + void processBoundingLeafChanged(J3dMessage m) { + // Notify all users of this bounding leaf, it may + // result in the re-evaluation of the lights/fogs/backgrounds + Object[] users = (Object[])(m.args[3]); + int i; + + for (i = 0; i < users.length; i++) { + LeafRetained leaf = (LeafRetained)users[i]; + if (leaf instanceof SoundRetained && universe.soundStructure.isSoundScopedToView(leaf, view)) { + auralAttribsChanged = true; + } + else if (leaf instanceof SoundscapeRetained && universe.soundStructure.isSoundscapeScopedToView(leaf, view)){ + auralAttribsChanged = true; + } + } + } + + void cleanup() { + // clean up any messages that are queued up, since they are + // irrelevant + // clearMessages(); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SoundSchedulerAtom.java b/j3d-core/src/classes/share/javax/media/j3d/SoundSchedulerAtom.java new file mode 100644 index 0000000..29d4bf6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SoundSchedulerAtom.java @@ -0,0 +1,713 @@ +/* + * $RCSfile: SoundSchedulerAtom.java,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * A SoundSchedulerAtom is the smallest object representing a Sound within + * SoundScheduler. This class contains View-Depedent fields. Some of these + * fields may appear to over lap fields in the Sound Node classes, but + * remember that the Sound Node fields are universal, user-defined fields + * and do not take into account specific Audio Device view-dependent + * conditions. + */ + +class SoundSchedulerAtom extends Object { + + /** + * The mirror sound node component of this sound scheduler atom + */ + SoundRetained sound = null; + + /** + * MediaContainer currently loaded for this atom + */ + MediaContainer soundData = null; + + // Maintain continuously playing silent sound sources. + long startTime = 0; + long endTime = 0; + + long sampleLength = 0; + long loopStartOffset = 0; // for most this will be 0 + long loopLength = 0; // for most this is end sample - sampleLength + long attackLength = 0; // portion of sample before loop section + long releaseLength = 0; // portion of sample after loop section + + int loadStatus = SoundRetained.LOAD_NULL; + boolean playing = false; + int numberChannels = 0; + + /** + * Is this sound in an active scheduling region + */ + boolean activated = false; + + /** + * Switch for turning sound on or off while the sound is "active" + */ + static final int OFF = 0; + static final int ON = 1; + static final int PENDING_ON = 2; + static final int PENDING_OFF = 3; + int enabled = OFF; + + /** + * Switch for muting and unmuting sound while it is playing + */ + static final int UNMUTED = 0; + static final int MUTED = 1; + static final int PENDING_UNMUTE = 2; + static final int PENDING_MUTE = 3; + int muted = UNMUTED; + + /** + * Switch for pausing and unpausing sound while it is playing + */ + static final int UNPAUSED = 0; // or resumed + static final int PAUSED = 1; + static final int PENDING_UNPAUSE = 2; // or pending resume + static final int PENDING_PAUSE = 3; + int paused = UNPAUSED; + + + /** + * Pending action for this sound determined by the SoundScheduler + */ + static final int DO_NOTHING = 0; + static final int LEAVE_OFF = 1; + static final int LEAVE_SILENT = 2; + static final int LEAVE_AUDIBLE = 3; + static final int LEAVE_PAUSED = 4; + + static final int RESTART_AUDIBLE = 5; + static final int START_AUDIBLE = 6; + static final int RESTART_SILENT = 7; + static final int START_SILENT = 8; + + static final int MAKE_AUDIBLE = 11; + static final int MAKE_SILENT = 12; + static final int PAUSE_AUDIBLE = 13; + static final int PAUSE_SILENT = 14; + static final int RESUME_AUDIBLE = 15; + static final int RESUME_SILENT = 16; + static final int TURN_OFF = 17; + static final int UPDATE = 18; + static final int COMPLETE = 19; + int schedulingAction = DO_NOTHING; + + /** + * This status flag is used for sound scheduling + */ + static final int SOUND_OFF = 0; // The sound is not playing + static final int SOUND_AUDIBLE = 1; // The sound is potentially audible + static final int SOUND_SILENT = 2; // The sound is playing silently + static final int SOUND_PAUSED = 3; // The sound is playing silently + static final int SOUND_COMPLETE = 4; // The sound is finished playing + int status = SOUND_OFF; + + // Sound atoms have two dirty flags: attribsDirty for sound node fields + // and stateDirty for changes to sound state not reflected by sound fields. + // When the field/parameter associated with the dirty bit has been: + // passed to all SoundSchedulers to update sound rendering or 'run' state + // the bit for that field is cleared by the SoundStructure thread. + + /** + * attribsDirty bit field + * This bitmask is set when sound node attribute is changed by the user. + */ + int attribsDirty = 0x0000; + + /** + * stateDirty bit field + * This bitmask is set when scene graph state is changed. + */ + int stateDirty = 0x0000; + + // Load Sound Data Status maintained in SoundRetained class + + /** + * Identifiers of sample associated with sound source + */ + int sampleId = SoundRetained.NULL_SOUND; + + /** + * reference to Sound Scheduler this atom is associated with + */ + SoundScheduler soundScheduler = null; + + + /** + * Calculate absolute time at which sample completes + * Checks playing flag denoting if sound is started already or not: + * false - calcalutes endTime in relation to startTime + * true - re-calculates endTime based on current position in + * loop portion of sample plus release length + */ + synchronized void calculateEndTime() { + SoundRetained sgSound = sound.sgSound; + int loops = sgSound.loopCount; + if (debugFlag) + debugPrint("calculateEndTime: loop count = " + loops); + // test lengths for <= 0; this includes DURATION_UNKNOWN + if ( (sampleLength <= 0 || loopLength <= 0 || loops < 0 ) +// QUESTION: removed? but what was this trying to avoid +// changing endTime when that is already set? +// but what happens when user changes LoopCount AFTER +// sound is started - should be able to do this +// && (enabled == OFF || enabled == PENDING_OFF) + ) { + endTime = -1; + if (debugFlag) + debugPrint("calculateEndTime: set to -1"); + } + else { +// QUESTION: if "&& playing" is in above test; won't we have to test for +// length unknown and loop = -1?? + if (playing && (startTime > 0)) { + endTime = startTime + attackLength + + (loopLength * (loops+1)) + releaseLength; if (debugFlag) + debugPrint("calculateEndTime: isPlaying so = " + endTime); } + else { + // Called when release flag is true + // Determine where within the loop portion sample the + // sound is currently playing, then set endTime to + // play remaining portion of loop portion plus the + // release portion. + long currentTime = J3dClock.currentTimeMillis(); + endTime = currentTime + ( (loopLength - + ((currentTime - startTime - attackLength) % loopLength)) + + releaseLength ); + if (debugFlag) + debugPrint("calculateEndTime: NOT Playing so = " + endTime); + } + } + } + + + void enable(boolean enabled) { + if (enabled) { + setEnableState(PENDING_ON); + if (debugFlag) + debugPrint(" enableSound calls soundAtom " + + this + " setEnableState PENDING_ON"); + } + else { + setEnableState(PENDING_OFF); + if (debugFlag) + debugPrint(" enableSound calls soundAtom " + + this + " setEnableState PENDING_OFF"); + } + } + + + void mute(boolean muted) { + if (muted) { + setMuteState(PENDING_MUTE); + if (debugFlag) + debugPrint(" muteSound() calls soundAtom " + + this + " setMuteState PENDING_ON"); + } + else { + setMuteState(PENDING_UNMUTE); + if (debugFlag) + debugPrint(" muteSound() calls soundAtom " + + this + " setMuteState PENDING_UNMUTE"); + } + } + + void pause(boolean paused) { + if (paused) { + setPauseState(PENDING_PAUSE); + if (debugFlag) + debugPrint(this + ".pause calls setPauseState(PENDING_PAUSE)"); + } + else { + setPauseState(PENDING_UNPAUSE); + if (debugFlag) + debugPrint(this +".pause calls setPauseState(PENDING_UNPAUSE)"); + } + } + + +// XXXX: remove this +// just set the state after debug no longer needed + void setEnableState(int state) { + enabled = state; + switch (state) { + case PENDING_ON: + if (debugFlag) + debugPrint("set enabled to PENDING_ON"); + break; + case ON: + if (debugFlag) + debugPrint("set enabled to ON"); + break; + case PENDING_OFF: + if (debugFlag) + debugPrint("set enabled to PENDING_OFF"); + break; + case OFF: + if (debugFlag) + debugPrint("set enabled to OFF"); + break; + default: + if (debugFlag) + debugPrint("state = " + state); + break; + } + } + +// XXXX: remove this +// just set the state after debug no longer needed + void setMuteState(int state) { + muted = state; + switch (state) { + case PENDING_MUTE: + if (debugFlag) + debugPrint("set mute to PENDING_MUTE"); + break; + case MUTED: + if (debugFlag) + debugPrint("set mute to MUTE"); + break; + case PENDING_UNMUTE: + if (debugFlag) + debugPrint("set mute to PENDING_UNMUTE"); + break; + case UNMUTED: + if (debugFlag) + debugPrint("set mute to UNMUTE"); + break; + default: + if (debugFlag) + debugPrint("state = " + state); + break; + } + } + +// XXXX: remove this +// just set the state after debug no longer needed + void setPauseState(int state) { + paused = state; + switch (state) { + case PENDING_PAUSE: + if (debugFlag) + debugPrint("set pause to PENDING_PAUSE"); + break; + case PAUSED: + if (debugFlag) + debugPrint("set pause to PAUSE"); + break; + case PENDING_UNPAUSE: + if (debugFlag) + debugPrint("set pause to PENDING_UNPAUSE"); + break; + case UNPAUSED: + if (debugFlag) + debugPrint("set pause to UNPAUSE"); + break; + default: + if (debugFlag) + debugPrint("state = " + state); + break; + } + } + + + /** + * calcActiveSchedAction() + * Calculate Sound Scheduler Action for Active sound (it's region + * intersects the viewPlatform). + * + * A big switch testing various SoundRetained fields to determine + * what SoundScheduler action to perform when sound is Active + * set sound active flag true + * switch on enable value, to set pending scheduling action + * depending on continuous and release flags and sound status + */ + synchronized int calcActiveSchedAction() { + SoundRetained sgSound = sound.sgSound; + int action = DO_NOTHING; + activated = true; + switch (enabled) { + case PENDING_ON: + setEnableState(ON); + if (debugFlag) + debugPrint(" calcActiveSchedAction: PENDING_ON"); + if (status == SOUND_OFF || + status == SOUND_PAUSED) + action = START_AUDIBLE; + else + action = RESTART_AUDIBLE; + break; + case ON: + if (debugFlag) + debugPrint(" calcActiveSchedAction: ON"); + if (status == SOUND_OFF) + // should NOT see this, but if we do... + action = START_AUDIBLE; + else if (status == SOUND_SILENT) + action = MAKE_AUDIBLE; + else // status == SOUND_AUDIBLE + action = LEAVE_AUDIBLE; + break; + case PENDING_OFF: + setEnableState(OFF); + if (debugFlag) + debugPrint("enable = " + enabled + + "enabled set to OFF"); + // fail thru + case OFF: + // QUESTION: Why would enable status ever be OFF yet + // status SOUND_AUDIBLE or _SILENT? + if (status == SOUND_AUDIBLE) { + if (sgSound.release) { + if (debugFlag) + debugPrint("enable = " + enabled + + ", AUDIBLE, released, " + + "action <- LEAVE_AUDIBLE"); + if (enabled == PENDING_OFF) { + // re-calculate EndTime + calculateEndTime(); + } + action = LEAVE_AUDIBLE; + } + else { + if (debugFlag) + debugPrint("enable = " + enabled + + ", AUDIBLE, not released, "+ + "action <- TURN_OFF"); + action = TURN_OFF; + } + } + else if (status == SOUND_SILENT) { + if (sgSound.release) { + if (debugFlag) + debugPrint("enable = " + enabled + + ", SILENT, released, " + + "action <- MAKE_AUDIBLE"); + // re-calculate EndTime + calculateEndTime(); + action = MAKE_AUDIBLE; + } + else { + if (debugFlag) + debugPrint("enable = " + enabled + + ", SILENT, not released, " + + "action <- TURN_OFF"); + action = TURN_OFF; + } + } + else { // status == SOUND_OFF + action = LEAVE_OFF; + } + break; + } // switch on enabled flag + + // if sounds pause state is PENDING_PAUSE modify action to perform. + if (paused == PENDING_PAUSE) { + // if this pause state is set to PAUSE then assume the sound is + // already paused, so any incoming action that leave the state + // as it already is, leaves the sound paused. + if (debugFlag) + debugPrint(" PENDING_PAUSE"); + switch (action) { + case MAKE_AUDIBLE: + case LEAVE_AUDIBLE: + case RESUME_AUDIBLE: + action = PAUSE_AUDIBLE; + break; + case MAKE_SILENT: + case LEAVE_SILENT: + case RESUME_SILENT: + action = PAUSE_SILENT; + break; + default: + // don't change action for any other cases + break; + } + } + // if sounds pause state is PENDING_UNPAUSE modify action + else if (paused == PENDING_UNPAUSE) { + debugPrint(" PENDING_UNPAUSE"); + switch (action) { + // When restart (audible or silent) pause flag is checked and + // explicitly set in SoundScheduler + case MAKE_AUDIBLE: + case LEAVE_AUDIBLE: + case PAUSE_AUDIBLE: + action = RESUME_AUDIBLE; + break; + case MAKE_SILENT: + case LEAVE_SILENT: + case PAUSE_SILENT: + action = RESUME_SILENT; + break; + default: + // don't change action for any other cases + break; + } + } + return(action); + } // end of calcActiveSchedAction + + + /** + * calcInactiveSchedAction() + * Calculate Sound Scheduler action for Inactive sound + * + * A big switch testing various SoundRetained fields to determine + * what SoundScheduler action to perform when sound is inactive. + * set sound active flag false + * switch on enable value, to set pending scheduling action + * depending on continuous and release flags and sound status + */ + synchronized int calcInactiveSchedAction() { + int action = DO_NOTHING; + SoundRetained sgSound = sound.sgSound; + + // Sound is Inactive + // Generally, sound is OFF unless continuous flag true + // then sound is silently playing if on. + activated = false; + + switch (enabled) { + case PENDING_ON: + if (debugFlag) + debugPrint(" calcInactiveSchedAction: PENDING_ON "); + setEnableState(ON); + if (sgSound.continuous) { + if (status == SOUND_OFF) + action = START_SILENT; + else // status == SOUND_AUDIBLE or SOUND_SILENT + action = RESTART_SILENT; + } + else { // sound is not continuous + if (status == SOUND_OFF) + action = LEAVE_OFF; + else // status == SOUND_SILENT || SOUND_AUDIBLE + action = TURN_OFF; + } + break; + case ON: + if (debugFlag) + debugPrint(" calcInactiveSchedActio: ON "); + if (sgSound.continuous) { + if (status == SOUND_AUDIBLE) + action = MAKE_SILENT; + else if (status == SOUND_OFF) + action = START_SILENT; + else // status == SOUND_SILENT + action = LEAVE_SILENT; + } + else { // sound is not continuous + // nothing to do if already off + if (status == SOUND_OFF) + action = LEAVE_OFF; + else // status == SOUND_SILENT or SOUND_AUDIBLE + action = TURN_OFF; + } + break; + case PENDING_OFF: + setEnableState(OFF); + if (debugFlag) + debugPrint("Enable = " + enabled + + "enabled set to OFF"); + // fall thru + + case OFF: + if (sgSound.release && sgSound.continuous) { + if (enabled == PENDING_OFF) { + // re-calculate EndTime + calculateEndTime(); + } + if (status == SOUND_AUDIBLE) { + if (debugFlag) + debugPrint("Enable = " + enabled + + ", AUDIBLE, released & continuous - " + + "action <- MAKE_SILENT"); + action = MAKE_SILENT; + } + else if (status == SOUND_SILENT) { + if (debugFlag) + debugPrint("Enable = " + enabled + + ", SILENT, released & continuous - " + + "action <- TURN_OFF"); + action = LEAVE_SILENT; + } + else { + if (debugFlag) + debugPrint("Enable = " + enabled + + ", already OFF, action <- LEAVE_OFF"); + action = LEAVE_OFF; + } + } + else { // continuous and release flag not both true + if (status == SOUND_OFF) { + if (debugFlag) + debugPrint("Enable = " + enabled + + ", already OFF, action <- LEAVE_OFF"); + action = LEAVE_OFF; + } + else { + if (debugFlag) + debugPrint("Enable = " + enabled + + ", not already OFF, action <- TURN_OFF"); + action = TURN_OFF; + } + } + break; + default: + break; + } // switch + + // if sounds pause state is PENDING_PAUSE modify action to perform. + if (paused == PENDING_PAUSE) { + // if this pause state is set to PAUSE then assume the sound is + // already paused, so any incoming action that leave the state + // as it already is, leaves the sound paused. + switch (action) { + case MAKE_SILENT: + case LEAVE_SILENT: + case RESUME_SILENT: + action = PAUSE_SILENT; + break; + default: + // don't change action for any other cases + break; + } + } + // if sounds pause state is PENDING_UNPAUSE modify action + else if (paused == PENDING_UNPAUSE) { + switch (action) { + case LEAVE_SILENT: + action = RESUME_SILENT; + break; + default: + // don't change action for any other cases + break; + } + } + return (action); + } // end of calcInactiveSchedAction + +// XXXX: isPLaying +// XXXX: setLoadingState + + // Debug print mechanism for Sound nodes + static final boolean debugFlag = false; + static final boolean internalErrors = false; + + void debugPrint(String message) { + if (debugFlag) { + System.err.println(message); + } + } + + + /** + * Set bit(s) in soundDirty field + * @param binary flag denotes bits to set ON + */ + void setAttribsDirtyFlag(int bitFlag) { + attribsDirty |= bitFlag; + if (debugFlag) + debugPrint("setAttribsDirtyFlag = " + bitFlag); + return ; + } + void setStateDirtyFlag(int bitFlag) { + stateDirty |= bitFlag; + if (debugFlag) + debugPrint("setStateDirtyFlag = " + bitFlag); + return ; + } + + /** + * Clear sound's dirty flag bit value. + * @param binary flag denotes bits to set OFF + */ + void clearAttribsDirtyFlag(int bitFlag) { + if (debugFlag) + debugPrint("clearAttribsDirtyFlag = " + bitFlag); + attribsDirty &= ~bitFlag; + return ; + } + void clearAttribsDirtyFlag() { + // clear all bits + if (debugFlag) + debugPrint("clearAttribsDirtyFlag = ALL"); + attribsDirty = 0x0; + return ; + } + void clearStateDirtyFlag(int bitFlag) { + if (debugFlag) + debugPrint("clearStateDirtyFlag = " + bitFlag); + stateDirty &= ~bitFlag; + return ; + } + void clearStateDirtyFlag() { + if (debugFlag) + debugPrint("clearStateDirtyFlag = ALL"); + stateDirty = 0x0; + return ; + } + + + /** + * Test sound's dirty flag bit(s) + * @param field denotes which bitmask to set into + * @param binary flag denotes bits to set Test + * @return true if bit(s) in bitFlag are set dirty (on) + */ + boolean testDirtyFlag(int field, int bitFlag) { + if ((field & bitFlag) > 0) + return true; + else + return false; + } + + /** + * Test sound's dirty flags for ANY bits on + * @return true if any bit in bitFlag is flipped on + */ + boolean testDirtyFlags() { + if ((attribsDirty & 0xFFFF) > 0) + return true; + else if ((stateDirty & 0xFFFF) > 0) + return true; + else + return false; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SoundStructure.java b/j3d-core/src/classes/share/javax/media/j3d/SoundStructure.java new file mode 100644 index 0000000..8164421 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SoundStructure.java @@ -0,0 +1,745 @@ +/* + * $RCSfile: SoundStructure.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * A sound structure is a object that organizes Sounds and + * soundscapes. + * This structure parallels the RenderingEnv structure and + * is used for sounds + */ + +class SoundStructure extends J3dStructure { + /** + * The list of Sound nodes + */ + UnorderList nonViewScopedSounds = new UnorderList(SoundRetained.class); + HashMap viewScopedSounds = new HashMap(); + + /** + * The list of Soundscapes + */ + UnorderList nonViewScopedSoundscapes = new UnorderList(SoundscapeRetained.class); + HashMap viewScopedSoundscapes = new HashMap(); + + /** + * The list of view platforms + */ + UnorderList viewPlatforms = new UnorderList(ViewPlatformRetained.class); + + /** + * A bounds used for getting a view platform scheduling BoundingSphere + */ + BoundingSphere tempSphere = new BoundingSphere(); + BoundingSphere vpsphere = new BoundingSphere(); + + // ArrayList of leafRetained object whose mirrorObjects + // should be updated + ArrayList objList = new ArrayList(); + + // ArrayList of leafRetained object whose boundingleaf xform + // should be updated + ArrayList xformChangeList = new ArrayList(); + + // ArrayList of switches that have changed + ArrayList switchChangeLeafNodes = new ArrayList(); + ArrayList switchChangeLeafMasks = new ArrayList(); + + // variables for processing transform messages + boolean transformMsg = false; + UpdateTargets targets = null; + + /** + * This constructor does nothing + */ + SoundStructure(VirtualUniverse u) { + super(u, J3dThread.UPDATE_SOUND); + if (debugFlag) + debugPrint("SoundStructure constructed"); + } + + void processMessages(long referenceTime) { + J3dMessage messages[] = getMessages(referenceTime); + int nMsg = getNumMessage(); + J3dMessage m; + + if (nMsg <= 0) { + return; + } + + + for (int i=0; i < nMsg; i++) { + m = messages[i]; + + switch (m.type) { + case J3dMessage.INSERT_NODES : + // Prioritize retained and non-retained sounds for this view + insertNodes(m); + break; + case J3dMessage.REMOVE_NODES: + removeNodes(m); + break; + case J3dMessage.SOUND_ATTRIB_CHANGED: + changeNodeAttrib(m); + break; + case J3dMessage.SOUND_STATE_CHANGED: + changeNodeState(m); + break; + case J3dMessage.SOUNDSCAPE_CHANGED: + case J3dMessage.AURALATTRIBUTES_CHANGED: + // XXXX: this needs to be changed + changeNodeAttrib(m); + break; + case J3dMessage.TRANSFORM_CHANGED: + transformMsg = true; + break; + case J3dMessage.SWITCH_CHANGED: + // This method isn't implemented yet. + // processSwitchChanged(m); + // may need to process dirty switched-on transform + if (universe.transformStructure.getLazyUpdate()) { + transformMsg = true; + } + break; + case J3dMessage.VIEWSPECIFICGROUP_CHANGED: + updateViewSpecificGroupChanged(m); + break; + // XXXX: case J3dMessage.BOUNDINGLEAF_CHANGED + } + + /* + // NOTE: this should already be handled by including/ORing + // SOUND_SCHEDULER in targetThread for these message types!! + // Dispatch a message about a sound change + ViewPlatformRetained vpLists[] = (ViewPlatformRetained []) + viewPlatforms.toArray(false); + + // QUESTION: can I just use this message to pass to all the Sound Bins + for (int k=viewPlatforms.arraySize()- 1; k>=0; k--) { + View[] views = vpLists[k].getViewList(); + for (int j=(views.length-1); j>=0; j--) { + View v = (View)(views[j]); + m.view = v; + VirtualUniverse.mc.processMessage(m); + } + } + */ + m.decRefcount(); + } + if (transformMsg) { + targets = universe.transformStructure.getTargetList(); + updateTransformChange(targets, referenceTime); + transformMsg = false; + targets = null; + } + + Arrays.fill(messages, 0, nMsg, null); + } + + void insertNodes(J3dMessage m) { + Object[] nodes = (Object[])m.args[0]; + ArrayList viewScopedNodes = (ArrayList)m.args[3]; + ArrayList scopedNodesViewList = (ArrayList)m.args[4]; + Object node; + + for (int i=0; i + * The Soundscape application region, different from a Sound node's scheduling + * region, is used to select which Soundscape (and thus which aural attribute + * object) is to be applied to the sounds being rendered. This selection is + * based on the position of the ViewPlatform (i.e., the listener), not the + * position of the sound. + *

+ * It will be common that multiple Soundscape regions are contained within a + * scene graph. For example, two Soundscape regions within a single space the + * listener can move about: a region with a large open area on the right, and + * a smaller more constricted, less reverberant area on the left. The rever- + * beration attributes for these two regions could be set to approximate their + * physical differences so that active sounds are rendered differently depending + * on which region the listener is in. + */ +public class Soundscape extends Leaf { + + // Constants + // + // These flags, when enabled using the setCapability method, allow an + // application to invoke methods that respectively read and write the + // application region and the aural attributes. These capability flags + // are enforced only when the node is part of a live or compiled scene + // graph. + + /** + * For Soundscape component objects, specifies that this object + * allows read access to its application bounds + */ + public static final int + ALLOW_APPLICATION_BOUNDS_READ = CapabilityBits.SOUNDSCAPE_ALLOW_APPLICATION_BOUNDS_READ; + + /** + * For Soundscape component objects, specifies that this object + * allows write access to its application bounds + */ + public static final int + ALLOW_APPLICATION_BOUNDS_WRITE = CapabilityBits.SOUNDSCAPE_ALLOW_APPLICATION_BOUNDS_WRITE; + + /** + * For Soundscape component objects, specifies that this object + * allows the reading of it's aural attributes information + */ + public static final int + ALLOW_ATTRIBUTES_READ = CapabilityBits.SOUNDSCAPE_ALLOW_ATTRIBUTES_READ; + + /** + * For Soundscape component objects, specifies that this object + * allows the writing of it's aural attribute information + */ + public static final int + ALLOW_ATTRIBUTES_WRITE = CapabilityBits.SOUNDSCAPE_ALLOW_ATTRIBUTES_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_APPLICATION_BOUNDS_READ, + ALLOW_ATTRIBUTES_READ + }; + /** + * Constructs and initializes a new Sound node using following + * defaults: + *

    application region: null (no active region)
+ *
    aural attributes: null (uses default aural attributes)
+ */ + public Soundscape() { + // Just use default values + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a new Sound node using specified + * parameters + * @param region application region + * @param attributes array of aural attribute component objects + */ + public Soundscape(Bounds region, + AuralAttributes attributes) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((SoundscapeRetained)this.retained).setApplicationBounds(region); + ((SoundscapeRetained)this.retained).setAuralAttributes(attributes); + } + + /** + * Creates the retained mode SoundscapeRetained object that this + * component object will point to. + */ + void createRetained() { + this.retained = new SoundscapeRetained(); + this.retained.setSource(this); + } + + /** + * Set the Soundscape's application region to the specified bounds + * specified in local coordinates of this leaf node. The aural + * attributes associated with this Soundscape are used to render + * the active sounds when this application region intersects the + * ViewPlatform's activation volume. The getApplicationBounds method + * returns a new Bounds object. + * This region is used when the application bounding leaf is null. + * @param region the bounds that contains the Soundscape's new application + * region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setApplicationBounds(Bounds region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Soundscape0")); + + ((SoundscapeRetained)this.retained).setApplicationBounds(region); + } + + /** + * Retrieves the Soundscape node's application bounds. + * @return this Soundscape's application bounds information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Bounds getApplicationBounds() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Soundscape1")); + + return ((SoundscapeRetained)this.retained).getApplicationBounds(); + } + + /** + * Set the Soundscape's application region to the specified bounding leaf. + * When set to a value other than null, this overrides the application + * bounds object. + * @param region the bounding leaf node used to specify the Soundscape + * node's new application region. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setApplicationBoundingLeaf(BoundingLeaf region) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Soundscape0")); + + ((SoundscapeRetained)this.retained).setApplicationBoundingLeaf(region); + } + + /** + * Retrieves the Soundscape node's application bounding leaf. + * @return this Soundscape's application bounding leaf information + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BoundingLeaf getApplicationBoundingLeaf() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Soundscape1")); + + return ((SoundscapeRetained)this.retained).getApplicationBoundingLeaf(); + } + + /** + * Set a set of aural attributes for this Soundscape + * @param attributes aural attributes + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setAuralAttributes(AuralAttributes attributes) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ATTRIBUTES_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Soundscape4")); + + ((SoundscapeRetained)this.retained).setAuralAttributes(attributes); + } + + /** + * Retrieve reference of Aural Attributes + * @return reference to aural attributes + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public AuralAttributes getAuralAttributes() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ATTRIBUTES_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Soundscape5")); + + return ((SoundscapeRetained)this.retained).getAuralAttributes(); + } + + + /** + * Creates a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Soundscape s = new Soundscape(); + s.duplicateNode(this, forceDuplicate); + return s; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + *
+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @exception ClassCastException if originalNode is not an instance of + * Soundscape + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + checkDuplicateNode(originalNode, forceDuplicate); + } + + /** + * Copies all Soundscape information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + SoundscapeRetained attr = (SoundscapeRetained) originalNode.retained; + SoundscapeRetained rt = (SoundscapeRetained) retained; + + rt.setApplicationBounds(attr.getApplicationBounds()); + + rt.setAuralAttributes((AuralAttributes) getNodeComponent( + attr.getAuralAttributes(), + forceDuplicate, + originalNode.nodeHashtable)); + + // the following reference will set correctly in updateNodeReferences + rt.setApplicationBoundingLeaf(attr.getApplicationBoundingLeaf()); + } + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + + SoundscapeRetained rt = (SoundscapeRetained) retained; + + BoundingLeaf bl = rt.getApplicationBoundingLeaf(); + + if (bl != null) { + Object o = referenceTable.getNewObjectReference(bl); + rt.setApplicationBoundingLeaf((BoundingLeaf) o); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SoundscapeRetained.java b/j3d-core/src/classes/share/javax/media/j3d/SoundscapeRetained.java new file mode 100644 index 0000000..0eefd98 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SoundscapeRetained.java @@ -0,0 +1,459 @@ +/* + * $RCSfile: SoundscapeRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.ArrayList; + +/** + * The SoundscapeRetained object defines all soundscape rendering state + * as a subclass of a Leaf node. + */ +class SoundscapeRetained extends LeafRetained +{ + static final int ATTRIBUTES_CHANGED = 0x00001; + static final int BOUNDING_LEAF_CHANGED = 0x00002; + static final int APPLICATION_BOUNDS_CHANGED = 0x00004; + + /** + * Soundscape nodes application region + */ + Bounds applicationRegion = null; + + /** + * The bounding leaf reference + */ + BoundingLeafRetained boundingLeaf = null; + + /** + * The transformed Application Region + */ + Bounds transformedRegion = null; + + /** + * Aural attributes associated with this Soundscape + */ + AuralAttributesRetained attributes = null; + + // A bitmask that indicates that the something has changed. + int isDirty = 0xffff; + + // Target threads to be notified when sound changes + int targetThreads = J3dThread.UPDATE_SOUND | + J3dThread.SOUND_SCHEDULER; + + + // Is true, if the mirror light is viewScoped + boolean isViewScoped = false; + + void dispatchMessage(int dirtyBit, Object argument) { + // Send message including a integer argument + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.type = J3dMessage.SOUNDSCAPE_CHANGED; + createMessage.universe = universe; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(dirtyBit); + createMessage.args[2] = new Integer(0); + createMessage.args[3] = null; + createMessage.args[4] = argument; + VirtualUniverse.mc.processMessage(createMessage); + } + + + SoundscapeRetained() { + super(); + this.nodeType = NodeRetained.SOUNDSCAPE; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + } + + + /** + * Set the Soundscape's application region. + * @param region a region that contains the Soundscape's new application region + */ + void setApplicationBounds(Bounds region) + { + if (region != null) { + applicationRegion = (Bounds) region.clone(); + if (staticTransform != null) { + applicationRegion.transform(staticTransform.transform); + } + } + else { + applicationRegion = null; + } + updateTransformChange(); + this.isDirty |= APPLICATION_BOUNDS_CHANGED; + dispatchMessage(APPLICATION_BOUNDS_CHANGED, region); + + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Get the Soundscape's application region. + * @return this Soundscape's application region information + */ + Bounds getApplicationBounds() + { + Bounds b = null; + + if (this.applicationRegion == null) + return (Bounds)null; + else { + b = (Bounds) applicationRegion.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + return b; + } + } + + /** + * Set the Soundscape's application region to the specified Leaf node. + */ + void setApplicationBoundingLeaf(BoundingLeaf region) { + if (boundingLeaf != null) { + // Remove the soundscape as users of the original bounding leaf + boundingLeaf.mirrorBoundingLeaf.removeUser(this); + } + if (region != null) { + boundingLeaf = (BoundingLeafRetained)region.retained; + boundingLeaf.mirrorBoundingLeaf.addUser(this); + } else { + boundingLeaf = null; + } + updateTransformChange(); + this.isDirty |= BOUNDING_LEAF_CHANGED; + dispatchMessage(BOUNDING_LEAF_CHANGED, region); +// QUESTION needed?? + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Get the Soundscape's application region + */ + BoundingLeaf getApplicationBoundingLeaf() { + if (boundingLeaf != null) { + return (BoundingLeaf)boundingLeaf.source; + } else { + return (BoundingLeaf)null; + } + } + + /** + * Set a set of aural attributes for this Soundscape + * @param attributes aural attributes to be set + */ + void setAuralAttributes(AuralAttributes attributes) + { + if (this.source.isLive()) { + if (this.attributes != null) { + this.attributes.clearLive(refCount); + } + + if (attributes != null) { + ((AuralAttributesRetained)attributes.retained).setLive(inBackgroundGroup, refCount); + } + } + + if (this.attributes != null) { + this.attributes.removeUser(this); + } + + if (attributes != null) { + this.attributes = (AuralAttributesRetained)attributes.retained; + this.attributes.addUser(this); + } else { + this.attributes = null; + } + + // copy all fields out of attributes and put into our copy of attributes + this.isDirty |= ATTRIBUTES_CHANGED; + dispatchMessage(ATTRIBUTES_CHANGED, attributes); + if (source != null && source.isLive()) { + notifySceneGraphChanged(false); + } + } + + /** + * Retrieve a reference to Aural Attributes + * @return attributes aural attributes to be returned + */ + AuralAttributes getAuralAttributes() + { + if (attributes != null) { + return ((AuralAttributes) attributes.source); + } + else + return ((AuralAttributes) null); + } + +/* +// NOTE: OLD CODE + // The update Object function. + public synchronized void updateObject() { + if ((attributes != null) && (attributes.aaDirty)) { + if (attributes.mirrorAa == null) { + attributes.mirrorAa = new AuralAttributesRetained(); + } + attributes.mirrorAa.update(attributes); + } + } +*/ + + // The update Object function. + synchronized void updateMirrorObject(Object[] objs) { + // NOTE: There doesn't seem to be a use for mirror objects since + // Soundscapes can't be shared. + // This method updates the transformed region from either bounding + // leaf or application bounds. Bounding leaf takes precidence. + Transform3D trans = null; + int component = ((Integer)objs[1]).intValue(); + if ((component & BOUNDING_LEAF_CHANGED) != 0) { + if (this.boundingLeaf != null) { + transformedRegion = boundingLeaf.transformedRegion; + } + else { // evaluate Application Region if not null + if (applicationRegion != null) { + transformedRegion = (Bounds)applicationRegion.clone(); + transformedRegion.transform(applicationRegion, + getLastLocalToVworld()); + } + else { + transformedRegion = null; + } + } + } + else if ((component & APPLICATION_BOUNDS_CHANGED) != 0) { + // application bounds only used when bounding leaf null + if (boundingLeaf == null) { + transformedRegion = (Bounds)applicationRegion.clone(); + transformedRegion.transform(applicationRegion, + getLastLocalToVworld()); + } + else { + transformedRegion = null; + } + } + } + + // The update tranform fields + synchronized void updateTransformChange() { + if (boundingLeaf != null) { + transformedRegion = boundingLeaf.transformedRegion; + } + else { // evaluate Application Region if not null + if (applicationRegion != null) { + transformedRegion = applicationRegion.copy(transformedRegion); + transformedRegion.transform(applicationRegion, + getLastLocalToVworld()); + } + else { + transformedRegion = null; + } + } + } + + void updateBoundingLeaf(long refTime) { + // This is necessary, if for example, the region + // changes from sphere to box. + if (boundingLeaf != null && boundingLeaf.switchState.currentSwitchOn) { + transformedRegion = boundingLeaf.transformedRegion; + } else { // evaluate Application Region if not null + if (applicationRegion != null) { + transformedRegion = applicationRegion.copy(transformedRegion); + transformedRegion.transform(applicationRegion, + getLastLocalToVworld()); + } else { + transformedRegion = null; + } + } + } + +// QUESTION: not needed? +/* + synchronized void initMirrorObject(SoundscapeRetained ms) { + GroupRetained group; + Transform3D trans; + Bounds region = null; + + if (ms == null) + return; +} + ms.isDirty = isDirty; + ms.setApplicationBounds(getApplicationBounds()); + ms.setApplicationBoundingLeaf(getApplicationBoundingLeaf()); + ms.setAuralAttributes(getAuralAttributes()); + +// QUESTION: no lineage of mirror node kept?? + ms.sgSound = sgSound; + ms.key = null; + ms.mirrorSounds = new SoundscapeRetained[1]; + ms.numMirrorSounds = 0; + ms.parent = parent; + ms.transformedRegion = null; + if (boundingLeaf != null) { + if (ms.boundingLeaf != null) + ms.boundingLeaf.removeUser(ms); + ms.boundingLeaf = boundingLeaf.mirrorBoundingLeaf; + // Add this mirror object as user + ms.boundingLeaf.addUser(ms); + ms.transformedRegion = ms.boundingLeaf.transformedRegion; + } + else { + ms.boundingLeaf = null; + } + + if (applicationRegion != null) { + ms.applicationRegion = (Bounds) applicationRegion.clone(); + // Assign region only if bounding leaf is null + if (ms.transformedRegion == null) { + ms.transformedRegion = (Bounds) ms.applicationRegion.clone(); + ms.transformedRegion.transform(ms.applicationRegion, + ms.getLastLocalToVworld()); + } + + } + else { + ms.applicationRegion = null; + } + } +*/ + + /** + * This setLive routine first calls the superclass's method, then + * it adds itself to the list of soundscapes + */ + void setLive(SetLiveState s) { + super.doSetLive(s); + + if (attributes != null) { + attributes.setLive(inBackgroundGroup, s.refCount); + } + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(this, Targets.SND_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + // If its view Scoped, then add this list + // to be sent to Sound Structure + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(this); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(this); + } + + if (inBackgroundGroup) { + throw new + IllegalSceneGraphException(J3dI18N.getString("SoundscapeRetained1")); + } + + if (inSharedGroup) { + throw new + IllegalSharingException(J3dI18N.getString("SoundscapeRetained0")); + } + + // process switch leaf + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(this, Targets.SND_TARGETS); + } + switchState = (SwitchState)s.switchStates.get(0); + s.notifyThreads |= (J3dThread.UPDATE_SOUND | + J3dThread.SOUND_SCHEDULER); + + super.markAsLive(); + } + + /** + * This clearLive routine first calls the superclass's method, then + * it removes itself to the list of lights + */ + void clearLive(SetLiveState s) { + super.clearLive(s); + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(this, Targets.SND_TARGETS); + } + + if (attributes != null) { + attributes.clearLive(s.refCount); + } + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(this, Targets.SND_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + // If its view Scoped, then add this list + // to be sent to Sound Structure + if ((s.viewScopedNodeList != null) && (s.viewLists != null)) { + s.viewScopedNodeList.add(this); + s.scopedNodesViewList.add(s.viewLists.get(0)); + } else { + s.nodeList.add(this); + } + s.notifyThreads |= (J3dThread.UPDATE_SOUND | + J3dThread.SOUND_SCHEDULER); + } + + // Simply pass along to the NodeComponents + /* + void compile(CompileState compState) { + setCompiled(); + + if (attributes != null) + attributes.compile(compState); + } + */ + + // This makes this sound look just like the one passed in + void update(SoundscapeRetained ss) { + applicationRegion = (Bounds)ss.applicationRegion.clone(); + attributes = ss.attributes; + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + if (applicationRegion != null) { + applicationRegion.transform(xform.transform); + } + } + + void getMirrorObjects(ArrayList leafList, HashKey key) { + leafList.add(this); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SourceCodeShader.java b/j3d-core/src/classes/share/javax/media/j3d/SourceCodeShader.java new file mode 100644 index 0000000..b26d11c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SourceCodeShader.java @@ -0,0 +1,140 @@ +/* + * $RCSfile: SourceCodeShader.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:30 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The SourceCodeShader object is a shader that is defined using + * text-based source code. It is used to define the source code for + * both vertex and fragment shaders. The currently supported shading + * languages are Cg and GLSL. + * + * @see ShaderProgram + * + * @since Java 3D 1.4 + */ + +public class SourceCodeShader extends Shader { + + /** + * Not a public constructor, for internal use + */ + SourceCodeShader() { + } + + /** + * Constructs a new shader object of the specified shading + * language and shader type from the specified source string. + * + * @param shadingLanguage the specified shading language, one of: + * SHADING_LANGUAGE_GLSL or + * SHADING_LANGUAGE_CG. + * + * @param shaderType the shader type, one of: + * SHADER_TYPE_VERTEX or + * SHADER_TYPE_FRAGMENT. + * + * @param shaderSource the shader source code + * + * @exception NullPointerException if shaderSource is null. + */ + + public SourceCodeShader(int shadingLanguage, int shaderType, String shaderSource) { + super(shadingLanguage, shaderType); + if (shaderSource == null) { + throw new NullPointerException(); + } + ((SourceCodeShaderRetained)this.retained).initShaderSource(shaderSource); + } + + /** + * Retrieves the shader source string from this shader object. + * + * @return the shader source string. + */ + public String getShaderSource() { + return ((SourceCodeShaderRetained)this.retained).getShaderSource(); + } + + + /** + * Creates a retained mode SourceCodeShaderRetained object that this + * SourceCodeShader component object will point to. + */ + void createRetained() { + this.retained = new SourceCodeShaderRetained(); + this.retained.setSource(this); + // System.err.println("SourceCodeShader.createRetained()"); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + SourceCodeShaderRetained scsRetained = (SourceCodeShaderRetained) retained; + + SourceCodeShader scs = new SourceCodeShader(scsRetained.getShadingLanguage(), + scsRetained.getShaderType(), + scsRetained.getShaderSource()); + scs.duplicateNodeComponent(this); + return scs; + } + + + /** + * Copies all node information from originalNodeComponent + * into the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + String sc = ((SourceCodeShaderRetained) originalNodeComponent.retained).getShaderSource(); + + if (sc != null) { + ((SourceCodeShaderRetained) retained).setShaderSource(sc); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SourceCodeShaderRetained.java b/j3d-core/src/classes/share/javax/media/j3d/SourceCodeShaderRetained.java new file mode 100644 index 0000000..8cf934d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SourceCodeShaderRetained.java @@ -0,0 +1,104 @@ +/* + * $RCSfile: SourceCodeShaderRetained.java,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The SourceCodeShaderRetained object is a shader that is defined using + * text-based source code. It is used to define the source code for + * both vertex and fragment shaders. The currently supported shading + * languages are Cg and GLSL. + */ + +class SourceCodeShaderRetained extends ShaderRetained { + + private String shaderSource = null; + + /** + * Constructs a new shader retained object of the specified shading + * language and shader type from the specified source string. + */ + + SourceCodeShaderRetained() { + } + + // This method is similar to setShaderSource(). + // To conform to j3d frame in retained creation, we will stick with method + // with init name. + final void initShaderSource(String shaderSource) { + this.shaderSource = shaderSource; + } + + final void set(int shadingLanguage, int shaderType, String shaderSource) { + this.shadingLanguage = shadingLanguage; + this.shaderType = shaderType; + this.shaderSource = shaderSource; + } + + /** + * Retrieves the shader source string from this shader object. + * + * @return the shader source string. + */ + final String getShaderSource() { + return shaderSource; + } + + final void setShaderSource(String shaderSource) { + this.shaderSource = shaderSource; + } + + synchronized void createMirrorObject() { + // System.err.println("SourceCodeShaderRetained : createMirrorObject"); + + if (mirror == null) { + SourceCodeShaderRetained mirrorSCS = new SourceCodeShaderRetained(); + mirror = mirrorSCS; + } + + initMirrorObject(); + } + + /** + * Initializes a mirror object. + */ + synchronized void initMirrorObject() { + mirror.source = source; + + ((SourceCodeShaderRetained) mirror).set(shadingLanguage, shaderType, shaderSource); + ((SourceCodeShaderRetained) mirror).shaderData = null; + } + + synchronized void updateMirrorObject(int component, Object value) { + System.err.println("SourceCodeShader.updateMirrorObject not implemented yet!"); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SpotLight.java b/j3d-core/src/classes/share/javax/media/j3d/SpotLight.java new file mode 100644 index 0000000..7236f58 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SpotLight.java @@ -0,0 +1,377 @@ +/* + * $RCSfile: SpotLight.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color3f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +/** + * The SpotLight object specifies an attenuated light source at a + * fixed point in space that radiates light in a specified direction + * from the light source. A SpotLight has the same attributes as a + * PointLight node, with the addition of the following:

+ *

    + *
  • Direction - The axis of the cone of light. The default + * direction is (0.0, 0.0, -1.0). The spot light direction is + * significant only when the spread angle is not PI radians + * (which it is by default).
  • + *

    + *

  • Spread angle - The angle in radians between the direction axis + * and a ray along the edge of the cone. Note that the angle of the + * cone at the apex is then twice this value. The range of values + * is [0.0,PI/2] radians, with a special value of PI radians. Values + * lower than 0 are clamped to 0 and values over PI/2 are clamped + * to PI. The default spread angle is PI radians.
  • + *

    + *

  • Concentration - Specifies how quickly the light intensity + * attenuates as a function of the angle of radiation as measured from + * the direction of radiation. The light's intensity is highest at the + * center of the cone and is attenuated toward the edges of the cone + * by the cosine of the angle between the direction of the light + * and the direction from the light to the object being lit, raised + * to the power of the spot concentration exponent. + * The higher the concentration value, the more focused the light + * source. The range of values is [0.0,128.0]. The default + * concentration is 0.0, which provides uniform light + * distribution.
  • + *

+ * A spot light contributes to diffuse and specular reflections, which + * depend on the orientation and position of an object's surface. + * A spot light does not contribute to ambient reflections. + */ + +public class SpotLight extends PointLight { + /** + * Specifies that the Node allows writing to its spot lights spread angle + * information. + */ + public static final int + ALLOW_SPREAD_ANGLE_WRITE = CapabilityBits.SPOT_LIGHT_ALLOW_SPREAD_ANGLE_WRITE; + + /** + * Specifies that the Node allows reading its spot lights spread angle + * information. + */ + public static final int + ALLOW_SPREAD_ANGLE_READ = CapabilityBits.SPOT_LIGHT_ALLOW_SPREAD_ANGLE_READ; + + /** + * Specifies that the Node allows writing to its spot lights concentration + * information. + */ + public static final int + ALLOW_CONCENTRATION_WRITE = CapabilityBits.SPOT_LIGHT_ALLOW_CONCENTRATION_WRITE; + + /** + * Specifies that the Node allows reading its spot lights concentration + * information. + */ + public static final int + ALLOW_CONCENTRATION_READ = CapabilityBits.SPOT_LIGHT_ALLOW_CONCENTRATION_READ; + + /** + * Specifies that the Node allows writing to its spot lights direction + * information. + */ + public static final int + ALLOW_DIRECTION_WRITE = CapabilityBits.SPOT_LIGHT_ALLOW_DIRECTION_WRITE; + + /** + * Specifies that the Node allows reading its spot lights direction + * information. + */ + public static final int + ALLOW_DIRECTION_READ = CapabilityBits.SPOT_LIGHT_ALLOW_DIRECTION_READ; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SPREAD_ANGLE_READ, + ALLOW_CONCENTRATION_READ, + ALLOW_DIRECTION_READ + }; + + /** + * Constructs a SpotLight node with default parameters. + * The default values are as follows: + *
    + * direction : (0,0,-1)
    + * spread angle : PI radians
    + * concentration : 0.0
    + *
+ */ + public SpotLight() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a SpotLight node using the + * specified parameters. + * @param color the color of the light source + * @param position the position of the light in three-space + * @param attenuation the attenuation (constant, linear, quadratic) + * of the light + * @param direction the direction of the light + * @param spreadAngle the spread angle of the light + * @param concentration the concentration of the light + */ + public SpotLight(Color3f color, + Point3f position, + Point3f attenuation, + Vector3f direction, + float spreadAngle, + float concentration) { + super(color, position, attenuation); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((SpotLightRetained)this.retained).initDirection(direction); + ((SpotLightRetained)this.retained).initSpreadAngle(spreadAngle); + ((SpotLightRetained)this.retained).initConcentration(concentration); + } + + /** + * Constructs and initializes a SpotLight node using the + * specified parameters. + * @param lightOn flag indicating whether this light is on or off + * @param color the color of the light source + * @param position the position of the light in three-space + * @param attenuation the attenuation (constant, linear, quadratic) of the light + * @param direction the direction of the light + * @param spreadAngle the spread angle of the light + * @param concentration the concentration of the light + */ + public SpotLight(boolean lightOn, + Color3f color, + Point3f position, + Point3f attenuation, + Vector3f direction, + float spreadAngle, + float concentration) { + super(lightOn, color, position, attenuation); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((SpotLightRetained)this.retained).initDirection(direction); + ((SpotLightRetained)this.retained).initSpreadAngle(spreadAngle); + ((SpotLightRetained)this.retained).initConcentration(concentration); + } + + /** + * Creates the retained mode SpotLightRetained object that this + * SpotLight component object will point to. + */ + void createRetained() { + this.retained = new SpotLightRetained(); + this.retained.setSource(this); + } + + + /** + * Sets spot light spread angle. + * @param spreadAngle the new spread angle for spot light + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph. + */ + public void setSpreadAngle(float spreadAngle) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SPREAD_ANGLE_WRITE)) + throw new + CapabilityNotSetException(J3dI18N.getString("SpotLight0")); + + if (isLive()) + ((SpotLightRetained)this.retained).setSpreadAngle(spreadAngle); + else + ((SpotLightRetained)this.retained).initSpreadAngle(spreadAngle); + } + + /** + * Gets spot light spread angle. + * @return the new spread angle for spot light. The value returned + * is the clamped value. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getSpreadAngle() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SPREAD_ANGLE_READ)) + throw new + CapabilityNotSetException(J3dI18N.getString("SpotLight1")); + + return ((SpotLightRetained)this.retained).getSpreadAngle(); + } + + /** + * Sets spot light concentration. + * @param concentration the new concentration for spot light + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setConcentration(float concentration) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CONCENTRATION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("SpotLight2")); + + if (isLive()) + ((SpotLightRetained)this.retained).setConcentration(concentration); + else + ((SpotLightRetained)this.retained).initConcentration(concentration); + } + + /** + * Gets spot light concentration. + * @return the new concentration for spot light + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getConcentration() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CONCENTRATION_READ)) + throw new + CapabilityNotSetException(J3dI18N.getString("SpotLight3")); + return ((SpotLightRetained)this.retained).getConcentration(); + } + + /** + * Sets light direction. + * @param x the new X direction + * @param y the new Y direction + * @param z the new Z direction + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDirection(float x, float y, float z) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_WRITE)) + throw new + CapabilityNotSetException(J3dI18N.getString("SpotLight4")); + + if (isLive()) + ((SpotLightRetained)this.retained).setDirection(x,y,z); + else + ((SpotLightRetained)this.retained).initDirection(x,y,z); + } + + /** + * Sets this Light's current direction and places it in the parameter specified. + * @param direction the vector that will receive this node's direction + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setDirection(Vector3f direction) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_WRITE)) + throw new + CapabilityNotSetException(J3dI18N.getString("SpotLight4")); + + if (isLive()) + ((SpotLightRetained)this.retained).setDirection(direction); + else + ((SpotLightRetained)this.retained).initDirection(direction); + } + + /** + * Gets this Light's current direction and places it in the + * parameter specified. + * @param direction the vector that will receive this node's direction + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getDirection(Vector3f direction) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_DIRECTION_READ)) + throw new + CapabilityNotSetException(J3dI18N.getString("SpotLight6")); + ((SpotLightRetained)this.retained).getDirection(direction); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + SpotLight s = new SpotLight(); + s.duplicateNode(this, forceDuplicate); + return s; + } + + + /** + * Copies all SpotLight information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean + forceDuplicate) { + + super.duplicateAttributes(originalNode, forceDuplicate); + + SpotLightRetained attr = (SpotLightRetained) originalNode.retained; + SpotLightRetained rt = (SpotLightRetained) retained; + + rt.initSpreadAngle(attr.getSpreadAngle()); + rt.initConcentration(attr.getConcentration()); + Vector3f v = new Vector3f(); + attr.getDirection(v); + rt.initDirection(v); + + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SpotLightRetained.java b/j3d-core/src/classes/share/javax/media/j3d/SpotLightRetained.java new file mode 100644 index 0000000..76fb12a --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SpotLightRetained.java @@ -0,0 +1,320 @@ +/* + * $RCSfile: SpotLightRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * A local spot light source object. + */ + +class SpotLightRetained extends PointLightRetained { + static final int DIRECTION_CHANGED = LAST_POINTLIGHT_DEFINED_BIT << 1; + static final int ANGLE_CHANGED = LAST_POINTLIGHT_DEFINED_BIT << 2; + static final int CONCENTRATION_CHANGED = LAST_POINTLIGHT_DEFINED_BIT << 3; + + /** + * The spot light's direction. + */ + Vector3f direction = new Vector3f(0.0f, 0.0f, -1.0f); + + // The transformed direction of this light + Vector3f xformDirection = new Vector3f(0.0f, 0.0f, -1.0f); + + /** + * The spot light's spread angle. + */ + float spreadAngle = (float)Math.PI; + + /** + * The spot light's concentration. + */ + float concentration = 0.0f; + + + SpotLightRetained() { + this.nodeType = NodeRetained.SPOTLIGHT; + lightType = 4; + } + + /** + * Initializes the spot light's spread angle. + * @param spreadAngle the light's spread angle + */ + void initSpreadAngle(float spreadAngle) { + if (spreadAngle < 0.0) { + this.spreadAngle = 0.0f; + } + else if (spreadAngle > (float) Math.PI * 0.5f) { + this.spreadAngle = (float)Math.PI; + } + else { + this.spreadAngle = spreadAngle; + } + } + + + void setLive(SetLiveState s) { + super.doSetLive(s); + J3dMessage createMessage = super.initMessage(12); + Object[] objs = (Object[])createMessage.args[4]; + objs[9] = new Float(spreadAngle); + objs[10] = new Float(concentration) ; + objs[11] = new Vector3f(direction); + VirtualUniverse.mc.processMessage(createMessage); + } + + /** + * Sets the spot light's spread angle. + * @param spreadAngle the light's spread angle + */ + void setSpreadAngle(float spreadAngle) { + initSpreadAngle(spreadAngle); + sendMessage(ANGLE_CHANGED, new Float(this.spreadAngle)); + } + + /** + * Returns the spot light's spread angle. + * @return the spread angle of the light + */ + float getSpreadAngle() { + return this.spreadAngle; + } + + /** + * Initializes the spot light's concentration. + * @param concentration the concentration of the light + */ + void initConcentration(float concentration) { + this.concentration = concentration; + } + + /** + * Sets the spot light's concentration. + * @param concentration the concentration of the light + */ + void setConcentration(float concentration) { + initConcentration(concentration); + sendMessage(CONCENTRATION_CHANGED, new Float(concentration)); + } + + /** + * Retrieves the spot light's concentration. + * @return the concentration of the light + */ + float getConcentration() { + return this.concentration; + } + + /** + * Initializes the spot light's direction from the vector provided. + * @param direction the new direction of the light + */ + void initDirection(Vector3f direction) { + this.direction.set(direction); + + if (staticTransform != null) { + staticTransform.transform.transform(this.direction, this.direction); + } + } + + /** + * Sets the spot light's direction from the vector provided. + * @param direction the new direction of the light + */ + void setDirection(Vector3f direction) { + initDirection(direction); + sendMessage(DIRECTION_CHANGED, new Vector3f(direction)); + } + + + /** + * Initializes this light's direction from the three values provided. + * @param x the new x direction + * @param y the new y direction + * @param z the new z direction + */ + void initDirection(float x, float y, float z) { + this.direction.x = x; + this.direction.y = y; + this.direction.z = z; + if (staticTransform != null) { + staticTransform.transform.transform(this.direction, this.direction); + } + } + + /** + * Sets this light's direction from the three values provided. + * @param x the new x direction + * @param y the new y direction + * @param z the new z direction + */ + void setDirection(float x, float y, float z) { + setDirection(new Vector3f(x, y, z)); + } + + + /** + * Retrieves this light's direction and places it in the + * vector provided. + * @param direction the variable to receive the direction vector + */ + void getDirection(Vector3f direction) { + direction.set(this.direction); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + invTransform.transform(direction, direction); + } + } + + /** + * This update function, and its native counterpart, + * updates a spot light. This includes its color, attenuation, + * transformed position, spread angle, concentration, + * and its transformed position. + */ + void update(Context ctx, int lightSlot, double scale) { + validateAttenuationInEc(scale); + Pipeline.getPipeline().updateSpotLight(ctx, + lightSlot, color.x, color.y, color.z, + attenuation.x, linearAttenuationInEc, + quadraticAttenuationInEc, + xformPosition.x, xformPosition.y, + xformPosition.z, spreadAngle, concentration, + xformDirection.x, xformDirection.y, + xformDirection.z); + } + + + /** + * This update function, and its native counterpart, + * updates a directional light. This includes its + * color and its transformed direction. + */ + // Note : if you add any more fields here , you need to update + // updateLight() in RenderingEnvironmentStructure + void updateMirrorObject(Object[] objs) { + + int component = ((Integer)objs[1]).intValue(); + Transform3D trans; + int i; + int numLgts = ((Integer)objs[2]).intValue(); + LightRetained[] mLgts = (LightRetained[]) objs[3]; + if ((component & DIRECTION_CHANGED) != 0) { + for (i = 0; i < numLgts; i++) { + if (mLgts[i].nodeType == NodeRetained.SPOTLIGHT) { + SpotLightRetained ml = (SpotLightRetained)mLgts[i]; + ml.direction = (Vector3f)objs[4]; + ml.getLastLocalToVworld().transform(ml.direction, + ml.xformDirection); + ml.xformDirection.normalize(); + } + } + } + else if ((component & ANGLE_CHANGED) != 0) { + for (i = 0; i < numLgts; i++) { + if (mLgts[i].nodeType == NodeRetained.SPOTLIGHT) { + SpotLightRetained ml = (SpotLightRetained)mLgts[i]; + ml.spreadAngle = ((Float)objs[4]).floatValue(); + } + } + + } + else if ((component & CONCENTRATION_CHANGED) != 0) { + + for (i = 0; i < numLgts; i++) { + if (mLgts[i].nodeType == NodeRetained.SPOTLIGHT) { + SpotLightRetained ml = (SpotLightRetained)mLgts[i]; + ml.concentration = ((Float)objs[4]).floatValue(); + } + } + } + else if ((component & INIT_MIRROR) != 0) { + for (i = 0; i < numLgts; i++) { + if (mLgts[i].nodeType == NodeRetained.SPOTLIGHT) { + SpotLightRetained ml = (SpotLightRetained)mLgts[i]; + ml.spreadAngle = ((Float)((Object[])objs[4])[9]).floatValue(); + ml.concentration = ((Float)((Object[])objs[4])[10]).floatValue(); + ml.direction = (Vector3f)((Object[])objs[4])[11]; + ml.getLastLocalToVworld().transform(ml.direction, + ml.xformDirection); + ml.xformDirection.normalize(); + } + } + } + + // call the parent's mirror object update routine + super.updateMirrorObject(objs); + } + + + // Clones only the retained side, internal use only + protected Object clone() { + SpotLightRetained sr = (SpotLightRetained)super.clone(); + sr.direction = new Vector3f(direction); + sr.xformDirection = new Vector3f(); + return sr; + } + + + + // Called on the mirror object + void updateTransformChange() { + super.updateTransformChange(); + + getLastLocalToVworld().transform(direction, xformDirection); + xformDirection.normalize(); + + } + + final void sendMessage(int attrMask, Object attr) { + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = targetThreads; + createMessage.universe = universe; + createMessage.type = J3dMessage.LIGHT_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + if (inSharedGroup) + createMessage.args[2] = new Integer(numMirrorLights); + else + createMessage.args[2] = new Integer(1); + createMessage.args[3] = mirrorLights.clone(); + createMessage.args[4] = attr; + VirtualUniverse.mc.processMessage(createMessage); + } + + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + xform.transform.transform(direction, direction); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/StructureUpdateThread.java b/j3d-core/src/classes/share/javax/media/j3d/StructureUpdateThread.java new file mode 100644 index 0000000..1e28f35 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/StructureUpdateThread.java @@ -0,0 +1,104 @@ +/* + * $RCSfile: StructureUpdateThread.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The StructureUpdateThread is thread that passes messages to its structure + */ + +class StructureUpdateThread extends J3dThread { + /** + * The structure that this thread works for + */ + J3dStructure structure; + + /** + * Some variables used to name threads correctly + */ + private static int numInstances[] = new int[7]; + private int instanceNum[] = new int[7]; + + private synchronized int newInstanceNum(int idx) { + return (++numInstances[idx]); + } + + int getInstanceNum(int idx) { + if (instanceNum[idx] == 0) + instanceNum[idx] = newInstanceNum(idx); + return instanceNum[idx]; + } + + /** + * Just saves the structure + */ + StructureUpdateThread(ThreadGroup t, J3dStructure s, int threadType) { + super(t); + structure = s; + type = threadType; + classification = J3dThread.UPDATE_THREAD; + + switch (type) { + case J3dThread.UPDATE_GEOMETRY: + setName("J3D-GeometryStructureUpdateThread-" + getInstanceNum(0)); + break; + case J3dThread.UPDATE_RENDER: + setName("J3D-RenderStructureUpdateThread-" + getInstanceNum(1)); + break; + case J3dThread.UPDATE_BEHAVIOR: + setName("J3D-BehaviorStructureUpdateThread-" + getInstanceNum(2)); + break; + case J3dThread.UPDATE_SOUND: + setName("J3D-SoundStructureUpdateThread-" + getInstanceNum(3)); + break; + case J3dThread.UPDATE_RENDERING_ATTRIBUTES: + // Only one exists in Java3D system + setName("J3D-RenderingAttributesStructureUpdateThread"); + break; + case J3dThread.UPDATE_RENDERING_ENVIRONMENT: + setName("J3D-RenderingEnvironmentStructureUpdateThread-"+ + getInstanceNum(4)); + break; + case J3dThread.UPDATE_TRANSFORM: + setName("J3D-TransformStructureUpdateThread-"+ getInstanceNum(5)); + break; + case J3dThread.SOUND_SCHEDULER: + setName("J3D-SoundSchedulerUpdateThread-"+ getInstanceNum(6)); + break; + + } + + } + + void doWork(long referenceTime) { + structure.processMessages(referenceTime); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Switch.java b/j3d-core/src/classes/share/javax/media/j3d/Switch.java new file mode 100644 index 0000000..df64653 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Switch.java @@ -0,0 +1,279 @@ +/* + * $RCSfile: Switch.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.BitSet; + +/** + * The Switch node controls which of its children will be rendered. + * It defines a child selection value (a switch value) that can either + * select a single child, or it can select 0 or more children using a + * mask to indicate which children are selected for rendering. + * The Switch node contains an ordered list of children, but the + * index order of the children in the list is only used for selecting + * the appropriate child or children and does not specify rendering + * order. + */ + +public class Switch extends Group { + + /** + * Specifies that this node allows reading its child selection + * and mask values and its current child. + */ + public static final int + ALLOW_SWITCH_READ = CapabilityBits.SWITCH_ALLOW_SWITCH_READ; + + /** + * Specifies that this node allows writing its child selection + * and mask values. + */ + public static final int + ALLOW_SWITCH_WRITE = CapabilityBits.SWITCH_ALLOW_SWITCH_WRITE; + + /** + * Specifies that no children are rendered. + * This value may be used in place of a non-negative child + * selection index. + */ + public static final int CHILD_NONE = -1; + + /** + * Specifies that all children are rendered. This setting causes + * the switch node to function as an ordinary group node. + * This value may be used in place of a non-negative child + * selection index. + */ + public static final int CHILD_ALL = -2; + + /** + * Specifies that the childMask BitSet is + * used to select which children are rendered. + * This value may be used in place of a non-negative child + * selection index. + */ + public static final int CHILD_MASK = -3; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_SWITCH_READ + }; + + /** + * Constructs a Switch node with default parameters. + * The default values are as follows: + *

    + * child selection index : CHILD_NONE
    + * child selection mask : false (for all children)
    + *
+ */ + public Switch() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a Switch node using the specified + * child selection index. + * @param whichChild the initial child selection index + */ + public Switch(int whichChild) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((SwitchRetained)this.retained).setWhichChild(whichChild, true); + } + + /** + * Constructs and initializes a Switch node using the specified + * child selection index and mask. + * @param whichChild the initial child selection index + * @param childMask the initial child selection mask + */ + public Switch(int whichChild, BitSet childMask){ + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((SwitchRetained)this.retained).setWhichChild(whichChild, true); + ((SwitchRetained)this.retained).setChildMask(childMask); + } + + /** + * Creates the retained mode SwitchRetained object that this + * Switch object will point to. + */ + void createRetained() { + this.retained = new SwitchRetained(); + this.retained.setSource(this); + } + + /** + * Sets the child selection index that specifies which child is rendered. + * If the value is out of range, then no children are drawn. + * @param child a non-negative integer index value, indicating a + * specific child, or one of the following constants: CHILD_NONE, + * CHILD_ALL, or CHILD_MASK. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #CHILD_NONE + * @see #CHILD_ALL + * @see #CHILD_MASK + */ + public void setWhichChild(int child) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SWITCH_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Switch0")); + + ((SwitchRetained)this.retained).setWhichChild(child, false); + } + + /** + * Retrieves the current child selection index that specifies which + * child is rendered. + * @return a non-negative integer index value, indicating a + * specific child, or one of the following constants: CHILD_NONE, + * CHILD_ALL, or CHILD_MASK + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #CHILD_NONE + * @see #CHILD_ALL + * @see #CHILD_MASK + */ + public int getWhichChild() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SWITCH_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Switch1")); + + return ((SwitchRetained)this.retained).getWhichChild(); + } + + /** + * Sets the child selection mask. This mask is used when + * the child selection index is set to CHILD_MASK. + * @param childMask a BitSet that specifies which children are rendered + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setChildMask(BitSet childMask) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SWITCH_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Switch2")); + + ((SwitchRetained)this.retained).setChildMask(childMask); + } + + /** + * Retrieves the current child selection mask. This mask is used when + * the child selection index is set to CHILD_MASK. + * @return the child selection mask + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public BitSet getChildMask() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SWITCH_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Switch3")); + + return ((SwitchRetained)this.retained).getChildMask(); + } + + /** + * Retrieves the currently selected child. If the child selection index + * is out of range or is set to CHILD_NONE, CHILD_ALL, or CHILD_MASK, + * then this method returns null. + * @return a reference to the current child chosen for rendering + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Node currentChild() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHILDREN_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Switch4")); + + return ((SwitchRetained)this.retained).currentChild(); + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Switch s = new Switch(); + s.duplicateNode(this, forceDuplicate); + return s; + } + + /** + * Copies all Switch information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Group#cloneNode + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + SwitchRetained attr = (SwitchRetained) originalNode.retained; + SwitchRetained rt = (SwitchRetained) retained; + + rt.setChildMask(attr.getChildMask()); + rt.setWhichChild(attr.getWhichChild(), true); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/SwitchRetained.java b/j3d-core/src/classes/share/javax/media/j3d/SwitchRetained.java new file mode 100644 index 0000000..d1d7835 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/SwitchRetained.java @@ -0,0 +1,956 @@ +/* + * $RCSfile: SwitchRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.11 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.BitSet; +import java.util.ArrayList; + +/** + * The switch node controls which one of its children will be rendered. + */ + +class SwitchRetained extends GroupRetained implements TargetsInterface +{ + static final int GEO_NODES = 0x0001; + static final int ENV_NODES = 0x0002; + static final int BEHAVIOR_NODES = 0x0004; + static final int SOUND_NODES = 0x0008; + static final int BOUNDINGLEAF_NODES = 0x0010; + + /** + * The value specifing which child to render. + */ + int whichChild = Switch.CHILD_NONE; + + /** + * The BitSet specifying which children are to be selected for + * rendering. This is used ONLY if whichChild is set to CHILD_MASK. + */ + BitSet childMask = new BitSet(); + + /** + * The childmask bitset used for rendering + */ + BitSet renderChildMask = new BitSet(); + + // A boolean indication that something changed + boolean isDirty = true; + + // switchLevel per key, used in traversing switch children + ArrayList switchLevels = new ArrayList(1); + + // key which identifies a unique path from a locale to this switch link + HashKey switchKey = new HashKey(); + + // switch index counter to identify specific children + int switchIndexCount = 0; + + // for message processing + UpdateTargets updateTargets = null; + + ArrayList childrenSwitchStates = null; + + SwitchRetained() { + this.nodeType = NodeRetained.SWITCH; + } + + /** + * Sets which child should be drawn. + * @param whichChild the child to choose during a render operation + */ + // synchronized with clearLive + synchronized void setWhichChild(int whichChild, boolean updateAlways) { + + int i, nchildren; + + this.whichChild = whichChild; + isDirty = true; + + if (source != null && source.isLive()) { + updateTargets = new UpdateTargets(); + ArrayList updateList = new ArrayList(1); + nchildren = children.size(); + switch (whichChild) { + case Switch.CHILD_ALL: + for (i=0; i this.childMask.size()) { + nbits = childMask.size(); + } else { + nbits = this.childMask.size(); + } + + for (i=0; i 0) { + + m = new J3dMessage(); + m.type = J3dMessage.SWITCH_CHANGED; + m.universe = universe; + m.threads = threads; + m.args[0] = updateTargets; + m.args[2] = updateList; + UnorderList blnList = + updateTargets.targetList[Targets.BLN_TARGETS]; + + if (blnList != null) { + BoundingLeafRetained mbleaf; + size = blnList.size(); + + Object[] boundingLeafUsersArr = new Object[size]; + nodesArr = blnList.toArray(false); + for (j=0; j= children.size())) + return null; + else + return getChild(whichChild); + } + + void updateSwitchChild(int child, boolean switchOn, ArrayList updateList) { + int i; + int switchLevel; + + if (inSharedGroup) { + for (i=0; i= 0) { + setAuxData(s, j, hkIndex); + } else { + MasterControl.getCoreLogger().severe("Can't Find matching hashKey in setNodeData."); + } + s.hashkeyIndex[j] = hkIndex; + } + } + } + + void setLive(SetLiveState s) { + int i,j,k; + boolean switchOn; + SwitchRetained switchRoot; + int size; + + // save setLiveState + Targets[] savedSwitchTargets = s.switchTargets; + ArrayList savedSwitchStates = s.switchStates; + SwitchRetained[] savedClosestSwitchParents = s.closestSwitchParents; + int[] savedClosestSwitchIndices = s.closestSwitchIndices; + ArrayList savedChildSwitchLinks = s.childSwitchLinks; + GroupRetained savedParentSwitchLink = s.parentSwitchLink; + int[] savedHashkeyIndex = s.hashkeyIndex; + + // update setLiveState for this node + s.closestSwitchParents = (SwitchRetained[]) + savedClosestSwitchParents.clone(); + s.closestSwitchIndices = (int[])savedClosestSwitchIndices.clone(); + + // Note that s.containsNodesList is updated in super.setLive + // Note that s.closestSwitchIndices is updated in super.setLive + for (i=0; i< s.switchLevels.length; i++) { + s.switchLevels[i]++; + s.closestSwitchParents[i] = this; + } + + super.doSetLive(s); + + initRenderChildMask(); + + // update switch leaves' compositeSwitchMask + // and update switch leaves' switchOn flag if this is top level switch + if (inSharedGroup) { + for (i=0; i= 0; i--) { + hkIndex = s.keys[i].equals(localToVworldKeys, 0, + localToVworldKeys.length); + if(hkIndex >= 0) { + for (j=0; j= 0 && + whichChild < children.size()) { + + child = (NodeRetained) children.get(whichChild); + if (child != null) { + child.computeCombineBounds((Bounds) boundingObject); + } + } + + return (Bounds) boundingObject; + } else { + return super.getBounds(); + } + } + + + /* + void compile(CompileState compState) { + setCompiled(); + compState.startGroup(null); // don't merge at this level + compileChildren(compState); + compState.endGroup(); + } + */ + + /** + * Compiles the children of the switch, preventing shape merging at + * this level or above + */ + void compile(CompileState compState) { + + + super.compile(compState); + + // don't remove this group node + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + + if (J3dDebug.devPhase && J3dDebug.debug) { + compState.numSwitches++; + } + } + + void insertChildrenData(int index) { + if (childrenSwitchStates == null) { + childrenSwitchStates = new ArrayList(1); + childrenSwitchLinks = new ArrayList(1); + } + + childrenSwitchLinks.add(index, new ArrayList(1)); + + ArrayList switchStates = new ArrayList(1); + childrenSwitchStates.add(index, switchStates); + if (source != null && source.isLive()) { + for (int i=0; i compositeSwitchMask.length) { + long newCompositeSwitchMask[] = new long[index+1]; + System.arraycopy(compositeSwitchMask, 0, + newCompositeSwitchMask, 0, index); + compositeSwitchMask = newCompositeSwitchMask; + } + if (switchOn) { + compositeSwitchMask[index] &= ~(1 << offset); + } else { + compositeSwitchMask[index] |= (1 << offset); + } + } + } + + void initSwitchOn() { + boolean switchOn = evalCompositeSwitchOn(); + currentSwitchOn = lastSwitchOn = cachedSwitchOn = switchOn; + //currentSwitchOn = cachedSwitchOn = switchOn; + initialized = true; + } + + void updateCurrentSwitchOn() { + currentSwitchOn = !currentSwitchOn; + } + + void updateLastSwitchOn() { + lastSwitchOn = currentSwitchOn; + } + + void updateCachedSwitchOn() { + cachedSwitchOn = !cachedSwitchOn; + } + + boolean evalCompositeSwitchOn() { + boolean switchOn; + if (compositeSwitchMask.length == 1) { + switchOn = (compositeSwitchMask[0] == 0); + } else { + switchOn = true; + for (int i=0; in-1, where n + * is the number of children in the target Switch node. + * @param alpha the alpha object for this interpolator + * @param target the Switch node affected by this interpolator + */ + public SwitchValueInterpolator(Alpha alpha, + Switch target) { + + super(alpha); + + this.target = target; + firstSwitchIndex = 0; + childCount = target.numChildren(); + lastSwitchIndex = childCount - 1; + + } + + /** + * Constructs a SwitchValueInterpolator behavior that varies its target + * Switch node's child index between the two values provided. + * @param alpha the alpha object for this interpolator + * @param target the Switch node affected by this interpolator + * @param firstChildIndex the index of first child in the Switch node to + * select + * @param lastChildIndex the index of last child in the Switch node to + * select + */ + public SwitchValueInterpolator(Alpha alpha, + Switch target, + int firstChildIndex, + int lastChildIndex) { + + super(alpha); + + this.target = target; + firstSwitchIndex = firstChildIndex; + lastSwitchIndex = lastChildIndex; + computeChildCount(); + } + + /** + * This method sets the firstChildIndex for this interpolator. + * @param firstIndex the new index for the first child + */ + public void setFirstChildIndex(int firstIndex) { + firstSwitchIndex = firstIndex; + computeChildCount(); + } + + /** + * This method retrieves this interpolator's firstChildIndex. + * @return the interpolator's firstChildIndex + */ + public int getFirstChildIndex() { + return this.firstSwitchIndex; + } + + /** + * This method sets the lastChildIndex for this interpolator. + * @param lastIndex the new index for the last child + */ + public void setLastChildIndex(int lastIndex) { + lastSwitchIndex = lastIndex; + computeChildCount(); + } + + /** + * This method retrieves this interpolator's lastSwitchIndex. + * @return the interpolator's maximum scale value + */ + public int getLastChildIndex() { + return this.lastSwitchIndex; + } + + /** + * This method sets the target for this interpolator. + * @param target the target Switch node + */ + public void setTarget(Switch target) { + this.target = target; + } + + /** + * This method retrieves this interpolator's target Switch node + * reference. + * @return the interpolator's target Switch node + */ + public Switch getTarget() { + return target; + } + + // The SwitchValueInterpolator's initialize routine uses the default + // initialization routine. + + /** + * This method is invoked by the behavior scheduler every frame. + * It maps the alpha value that corresponds to the current time + * into a child index value and updates the specified Switch node + * with this new child index value. + * @param criteria an enumeration of the criteria that triggered + * this stimulus + */ + public void processStimulus(Enumeration criteria) { + // Handle stimulus + WakeupCriterion criterion = passiveWakeupCriterion; + + if (alpha != null) { + float value = alpha.value(); + + if (value != prevAlphaValue) { + int child; + + if (lastSwitchIndex > firstSwitchIndex) { + child = (int)(firstSwitchIndex + + (int)(value * (childCount-1) + 0.49999999999f)); + } else { + child = (int)(firstSwitchIndex - + (int)(value * (childCount-1) + 0.49999999999f)); + } + target.setWhichChild(child); + prevAlphaValue = value; + } + if (!alpha.finished() && !alpha.isPaused()) { + criterion = defaultWakeupCriterion; + } + } + wakeupOn(criterion); + } + + + /** + * calculate the number of the child to manage for this switch node + */ + final private void computeChildCount() { + if (lastSwitchIndex >= firstSwitchIndex) { + childCount = lastSwitchIndex - firstSwitchIndex + 1; + } else { + childCount = firstSwitchIndex - lastSwitchIndex + 1; + } + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + SwitchValueInterpolator svi = new SwitchValueInterpolator(); + svi.duplicateNode(this, forceDuplicate); + return svi; + } + + + /** + * Copies all SwitchValueInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + SwitchValueInterpolator si = + (SwitchValueInterpolator) originalNode; + + setFirstChildIndex(si.getFirstChildIndex()); + setLastChildIndex(si.getLastChildIndex()); + // this reference will be updated in updateNodeReferences() + setTarget(si.getTarget()); + } + + /** + * Callback used to allow a node to check if any nodes referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any node references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding Node in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * node is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + super.updateNodeReferences(referenceTable); + + // check Switch + Node n = getTarget(); + + if (n != null) { + setTarget((Switch) referenceTable.getNewObjectReference(n)); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Table.java b/j3d-core/src/classes/share/javax/media/j3d/Table.java new file mode 100644 index 0000000..94eed13 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Table.java @@ -0,0 +1,103 @@ +/* + * $RCSfile: Table.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Used by ImageComponent for data conversions + */ + +class Table extends Object { + + // 2 to 8 bit data conversion + static final int[] table2To8Bit = {0,85,170,255}; + + // 3 to 8 bit data conversion + static final int[] table3To8Bit = {0,36,73,109,146,182,219,255}; + + // 4 to 8 bit data conversion + static final int[] table4To8Bit = { + 0,17,34,51,68,85,102,119,136,153,170,187,204,221,238,255}; + + // 5 to 8 bit data conversion + static final int[] table5To8Bit = { + 0,8,16,25,33,41,49,58,66,74,82,90,99,107,115,123,132,140,148,156, + 165,173,181,189,197,206,214,222,230,239,247,255}; + + // 8 to 4 bit data conversion + static final int[] table8To4Bit = { + 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15, + 15,15}; + + // 8 to 5 bit data conversion + static int[] table8To5Bit = { + 0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3, + 3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7, + 7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11, + 11,11,11,11,11,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,14, + 14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16, + 17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19, + 19,19,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22, + 22,22,22,22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25, + 25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,28, + 28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30, + 31,31,31,31,31}; + + // 8 to 3 bit data conversion + static int[] table8To3Bit = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7}; + + // 8 to 2 bit data conversion + static int[] table8To2Bit = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3}; +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Targets.java b/j3d-core/src/classes/share/javax/media/j3d/Targets.java new file mode 100644 index 0000000..6a5d0f5 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Targets.java @@ -0,0 +1,217 @@ +/* + * $RCSfile: Targets.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +class Targets { + + static final int MAX_NODELIST = 7; + + static final int GEO_TARGETS = 0; // For geometryAtoms. + static final int ENV_TARGETS = 1; // For enviroment nodes. + static final int BEH_TARGETS = 2; // For behavior nodes. + static final int SND_TARGETS = 3; // For sound nodes. + static final int VPF_TARGETS = 4; // For viewPlatform nodes. + static final int BLN_TARGETS = 5; // For boundingLeaf nodes. + static final int GRP_TARGETS = 6; // For group nodes. + + ArrayList[] targetList = new ArrayList[MAX_NODELIST]; + + void addNode(NnuId node, int targetType) { + if(targetList[targetType] == null) + targetList[targetType] = new ArrayList(1); + + targetList[targetType].add(node); + } + + void addNodeArray(NnuId[] nodeArr, int targetType) { + if(targetList[targetType] == null) + targetList[targetType] = new ArrayList(1); + + targetList[targetType].add(nodeArr); + } + + + void removeNode(int index, int targetType) { + if(targetList[targetType] != null) { + targetList[targetType].remove(index); + } + } + + + void addNodes(ArrayList nodeList, int targetType) { + if(targetList[targetType] == null) + targetList[targetType] = new ArrayList(1); + + targetList[targetType].addAll(nodeList); + } + + + void clearNodes() { + for(int i=0; i + * Texture coordinates determine which texel in the texture map is + * assigned to a given vertex. Texture coordinates are interpolated + * between vertices, similarly to how colors are interpolated between + * two vertices of lines and polygons. + *

+ * Texture coordinates consist of two, three or four coordinates. + * These coordinates + * are referred to as the S, T, R, and Q + * coordinates. + * 2D textures use the S and T coordinates. 3D textures + * use the S, T and R coordinates. The Q + * coordinate, similar to the w coordinate of the (x, y, z, w) + * object coordinates, is used to create homogeneous coordinates. + *

+ * Rather than the programmer having to explicitly assign texture + * coordinates, Java 3D can automatically generate the texture + * coordinates to achieve texture mapping onto contours. + * The TexCoordGeneration attributes specify the functions for automatically + * generating texture coordinates. The texture attributes that can be + * defined are: + *

    + *
  • Texture format - defines whether the generated texture + * coordinates are 2D, 3D, or 4D:

    + *

      + *
    • TEXTURE_COORDINATE_2 - generates 2D texture coordinates + * (S and T).

      + *

    • TEXTURE_COORDINATE_3 - generates 3D texture coordinates + * (S, T, and R).

      + *

    • TEXTURE_COORDINATE_4 - generates 4D texture coordinates + * (S, T, R, and Q).

      + *

    + *
  • Texture generation mode - defines how the texture coordinates + * are generated:

    + *

      + *
    • OBJECT_LINEAR - texture coordinates are generated as a linear + * function in object coordinates. The function used is:

      + *

        + * g = p1xo + p2yo + p3zo + p4wo + *

        + * where
        + *

          g is the value computed for the coordinate.
          + * p1, p2, + * p3, and p4 + * are the plane equation coefficients (described below).
          + * xo, yo, zo, and wo are + * the object coordinates of the vertex.

          + *

      + *
    • EYE_LINEAR - texture coordinates are generated as a linear + * function in eye coordinates. The function used is:

      + *

        + * g = p1'xe + p2'ye + p3'ze + p4'we + *

        + * where
        + *

          xe, ye, + * ze, and we are the eye + * coordinates of the vertex.
          + * p1', p2', + * p3', and p4' + * are the plane equation coefficients transformed into eye + * coordinates.

          + *

      + * + *
    • SPHERE_MAP - texture coordinates are generated using + * spherical reflection mapping in eye coordinates. Used to simulate + * the reflected image of a spherical environment onto a polygon.

      + * + *

    • NORMAL_MAP - texture coordinates are generated to match + * vertices' normals in eye coordinates. This is only available if + * TextureCubeMap is available. + *
    • + * + *

    • REFLECTION_MAP - texture coordinates are generated to match + * vertices' reflection vectors in eye coordinates. This is only available + * if TextureCubeMap is available. + *
    • + *

    + *
  • Plane equation coefficients - defines the coefficients for the + * plane equations used to generate the coordinates in the + * OBJECT_LINEAR and EYE_LINEAR texture generation modes. + * The coefficients define a reference plane in either object coordinates + * or in eye coordinates, depending on the texture generation mode. + *

    + * The equation coefficients are set by the setPlaneS, + * setPlaneT, setPlaneR, and setPlaneQ + * methods for each of the S, T, R, and Q coordinate functions, respectively. + * By default the equation coefficients are set as follows:

    + *

      + * plane S = (1.0, 0.0, 0.0, 0.0)
      + * plane T = (0.0, 1.0, 0.0, 0.0)
      + * plane R = (0.0, 0.0, 0.0, 0.0)
      + * plane Q = (0.0, 0.0, 0.0, 0.0)

      + *

+ * Texture coordinate generation is enabled or disabled by the + * setEnable method. When enabled, the specified + * texture coordinate is computed according to the generating function + * associated with the coordinate. When disabled, subsequent vertices + * take the specified texture coordinate from the current set of + * texture coordinates.

+ * + * @see Canvas3D#queryProperties + */ +public class TexCoordGeneration extends NodeComponent { + + /** + * Specifies that this TexCoordGeneration object allows reading its + * enable flag. + */ + public static final int + ALLOW_ENABLE_READ = CapabilityBits.TEX_COORD_GENERATION_ALLOW_ENABLE_READ; + + /** + * Specifies that this TexCoordGeneration object allows writing its + * enable flag. + */ + public static final int + ALLOW_ENABLE_WRITE = CapabilityBits.TEX_COORD_GENERATION_ALLOW_ENABLE_WRITE; + + /** + * Specifies that this TexCoordGeneration object allows reading its + * format information. + */ + public static final int + ALLOW_FORMAT_READ = CapabilityBits.TEX_COORD_GENERATION_ALLOW_FORMAT_READ; + + /** + * Specifies that this TexCoordGeneration object allows reading its + * mode information. + */ + public static final int + ALLOW_MODE_READ = CapabilityBits.TEX_COORD_GENERATION_ALLOW_MODE_READ; + + /** + * Specifies that this TexCoordGeneration object allows reading its + * planeS, planeR, and planeT component information. + */ + public static final int + ALLOW_PLANE_READ = CapabilityBits.TEX_COORD_GENERATION_ALLOW_PLANE_READ; + + /** + * Specifies that this TexCoordGeneration object allows writing its + * planeS, planeR, and planeT component information. + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_PLANE_WRITE = + CapabilityBits.TEX_COORD_GENERATION_ALLOW_PLANE_WRITE; + + /** + * Generates texture coordinates as a linear function in + * object coordinates. + * + * @see #setGenMode + */ + public static final int OBJECT_LINEAR = 0; + /** + * Generates texture coordinates as a linear function in + * eye coordinates. + * + * @see #setGenMode + */ + public static final int EYE_LINEAR = 1; + /** + * Generates texture coordinates using a spherical reflection + * mapping in eye coordinates. + * + * @see #setGenMode + */ + public static final int SPHERE_MAP = 2; + /** + * Generates texture coordinates that match vertices' normals in + * eye coordinates. + * + * @see #setGenMode + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public static final int NORMAL_MAP = 3; + /** + * Generates texture coordinates that match vertices' reflection + * vectors in eye coordinates. + * + * @see #setGenMode + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public static final int REFLECTION_MAP = 4; + + // Definitions for format + /** + * Generates 2D texture coordinates (S and T). + * + * @see #setFormat + */ + public static final int TEXTURE_COORDINATE_2 = 0; + /** + * Generates 3D texture coordinates (S, T, and R). + * + * @see #setFormat + */ + public static final int TEXTURE_COORDINATE_3 = 1; + /** + * Generates 4D texture coordinates (S, T, R, and Q). + * + * @see #setFormat + * + * @since Java 3D 1.3 + */ + public static final int TEXTURE_COORDINATE_4 = 2; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_ENABLE_READ, + ALLOW_FORMAT_READ, + ALLOW_MODE_READ, + ALLOW_PLANE_READ + }; + + /** + * Constructs a TexCoordGeneration object with default parameters. + * The default values are as follows: + *

    + * enable flag : true
    + * texture generation mode : OBJECT_LINEAR
    + * format : TEXTURE_COORDINATE_2
    + * plane S : (1,0,0,0)
    + * plane T : (0,1,0,0)
    + * plane R : (0,0,0,0)
    + * plane Q : (0,0,0,0)
    + *
+ */ + public TexCoordGeneration() { + // Just use the defaults + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a TexCoordGeneration object with the specified genMode and + * format. + * Defaults will be used for the rest of the state variables. + * @param genMode texture generation mode, one of: OBJECT_LINEAR, + * EYE_LINEAR, SPHERE_MAP, NORMAL_MAP, or REFLECTION_MAP + * @param format texture format, one of: TEXTURE_COORDINATE_2, + * TEXTURE_COORDINATE_3, or TEXTURE_COORDINATE_4 + * + * @see Canvas3D#queryProperties + */ + public TexCoordGeneration(int genMode, int format) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TexCoordGenerationRetained)this.retained).initGenMode(genMode); + ((TexCoordGenerationRetained)this.retained).initFormat(format); + } + + /** + * Constructs a TexCoordGeneration object with the specified genMode, + * format, and the S coordinate plane equation. + * Defaults will be used for the rest of the state variables. + * @param genMode texture generation mode, one of: OBJECT_LINEAR, + * EYE_LINEAR, SPHERE_MAP, NORMAL_MAP, or REFLECTION_MAP + * @param format texture format, one of: TEXTURE_COORDINATE_2, + * TEXTURE_COORDINATE_3 or TEXTURE_COORDINATE_4 + * @param planeS plane equation for the S coordinate + * + * @see Canvas3D#queryProperties + */ + public TexCoordGeneration(int genMode, int format, Vector4f planeS) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TexCoordGenerationRetained)this.retained).initGenMode(genMode); + ((TexCoordGenerationRetained)this.retained).initFormat(format); + ((TexCoordGenerationRetained)this.retained).initPlaneS(planeS); + } + + /** + * Constructs a TexCoordGeneration object with the specified genMode, + * format, and the S and T coordinate plane equations. + * Defaults will be used for the rest of the state variables. + * @param genMode texture generation mode, one of: OBJECT_LINEAR, + * EYE_LINEAR, SPHERE_MAP, NORMAL_MAP, or REFLECTION_MAP + * @param format texture format, one of: TEXTURE_COORDINATE_2, + * TEXTURE_COORDINATE_3 or TEXTURE_COORDINATE_4 + * @param planeS plane equation for the S coordinate + * @param planeT plane equation for the T coordinate + * + * @see Canvas3D#queryProperties + */ + public TexCoordGeneration(int genMode, int format, Vector4f planeS, + Vector4f planeT) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TexCoordGenerationRetained)this.retained).initGenMode(genMode); + ((TexCoordGenerationRetained)this.retained).initFormat(format); + ((TexCoordGenerationRetained)this.retained).initPlaneS(planeS); + ((TexCoordGenerationRetained)this.retained).initPlaneT(planeT); + } + + /** + * Constructs a TexCoordGeneration object with the specified genMode, + * format, and the S, T, and R coordinate plane equations. + * @param genMode texture generation mode, one of: OBJECT_LINEAR, + * EYE_LINEAR, SPHERE_MAP, NORMAL_MAP, or REFLECTION_MAP + * @param format texture format, one of: TEXTURE_COORDINATE_2, + * TEXTURE_COORDINATE_3 or TEXTURE_COORDINATE_4 + * @param planeS plane equation for the S coordinate + * @param planeT plane equation for the T coordinate + * @param planeR plane equation for the R coordinate + * + * @see Canvas3D#queryProperties + */ + public TexCoordGeneration(int genMode, int format, Vector4f planeS, + Vector4f planeT, Vector4f planeR) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TexCoordGenerationRetained)this.retained).initGenMode(genMode); + ((TexCoordGenerationRetained)this.retained).initFormat(format); + ((TexCoordGenerationRetained)this.retained).initPlaneS(planeS); + ((TexCoordGenerationRetained)this.retained).initPlaneT(planeT); + ((TexCoordGenerationRetained)this.retained).initPlaneR(planeR); + } + + /** + * Constructs a TexCoordGeneration object with the specified genMode, + * format, and the S, T, R, and Q coordinate plane equations. + * @param genMode texture generation mode, one of: OBJECT_LINEAR, + * EYE_LINEAR, SPHERE_MAP, NORMAL_MAP, or REFLECTION_MAP + * @param format texture format, one of: TEXTURE_COORDINATE_2, + * TEXTURE_COORDINATE_3 or TEXTURE_COORDINATE_4 + * @param planeS plane equation for the S coordinate + * @param planeT plane equation for the T coordinate + * @param planeR plane equation for the R coordinate + * @param planeQ plane equation for the Q coordinate + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public TexCoordGeneration(int genMode, int format, Vector4f planeS, + Vector4f planeT, Vector4f planeR, + Vector4f planeQ) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TexCoordGenerationRetained)this.retained).initGenMode(genMode); + ((TexCoordGenerationRetained)this.retained).initFormat(format); + ((TexCoordGenerationRetained)this.retained).initPlaneS(planeS); + ((TexCoordGenerationRetained)this.retained).initPlaneT(planeT); + ((TexCoordGenerationRetained)this.retained).initPlaneR(planeR); + ((TexCoordGenerationRetained)this.retained).initPlaneQ(planeQ); + } + + /** + * Enables or disables texture coordinate generation for this + * appearance component object. + * @param state true or false to enable or disable texture coordinate + * generation + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setEnable(boolean state) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ENABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration0")); + if (isLive()) + ((TexCoordGenerationRetained)this.retained).setEnable(state); + else + ((TexCoordGenerationRetained)this.retained).initEnable(state); + } + + /** + * Retrieves the state of the texCoordGeneration enable flag. + * @return true if texture coordinate generation is enabled, + * false if texture coordinate generation is disabled + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getEnable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ENABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration1")); + return ((TexCoordGenerationRetained)this.retained).getEnable(); + } + /** + * Sets the TexCoordGeneration format to the specified value. + * @param format texture format, one of: TEXTURE_COORDINATE_2, + * TEXTURE_COORDINATE_3 or TEXTURE_COORDINATE_4 + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + public void setFormat(int format) { + checkForLiveOrCompiled(); + ((TexCoordGenerationRetained)this.retained).initFormat(format); + + } + + /** + * Retrieves the current TexCoordGeneration format. + * @return the texture format + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getFormat() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_FORMAT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration2")); + return ((TexCoordGenerationRetained)this.retained).getFormat(); + } + + /** + * Sets the TexCoordGeneration generation mode to the specified value. + * @param genMode texture generation mode, one of: OBJECT_LINEAR, + * EYE_LINEAR, SPHERE_MAP, NORMAL_MAP, or REFLECTION_MAP. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @exception IllegalArgumentException if genMode is + * a value other than OBJECT_LINEAR, EYE_LINEAR, + * SPHERE_MAP, NORMAL_MAP, or + * REFLECTION_MAP. + * + * @see Canvas3D#queryProperties + */ + public void setGenMode(int genMode) { + checkForLiveOrCompiled(); + + if ((genMode < OBJECT_LINEAR) || (genMode > REFLECTION_MAP)) { + throw new IllegalArgumentException( + J3dI18N.getString("TexCoordGeneration5")); + } + ((TexCoordGenerationRetained)this.retained).initGenMode(genMode); + } + + /** + * Retrieves the current TexCoordGeneration generation mode. + * @return the texture generation mode + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getGenMode() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration3")); + return ((TexCoordGenerationRetained)this.retained).getGenMode(); + } + + /** + * Sets the S coordinate plane equation. This plane equation + * is used to generate the S coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeS plane equation for the S coordinate + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPlaneS(Vector4f planeS) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PLANE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration6")); + + if (isLive()) + ((TexCoordGenerationRetained)this.retained).setPlaneS(planeS); + else + ((TexCoordGenerationRetained)this.retained).initPlaneS(planeS); + } + + /** + * Retrieves a copy of the plane equation used to + * generate the S coordinate. + * @param planeS the S coordinate plane equation + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getPlaneS(Vector4f planeS) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PLANE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration4")); + ((TexCoordGenerationRetained)this.retained).getPlaneS(planeS); + } + + /** + * Sets the T coordinate plane equation. This plane equation + * is used to generate the T coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeT plane equation for the T coordinate + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPlaneT(Vector4f planeT) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PLANE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration6")); + + if (isLive()) + ((TexCoordGenerationRetained)this.retained).setPlaneT(planeT); + else + ((TexCoordGenerationRetained)this.retained).initPlaneT(planeT); + } + + /** + * Retrieves a copy of the plane equation used to + * generate the T coordinate. + * @param planeT the T coordinate plane equation + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getPlaneT(Vector4f planeT) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PLANE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration4")); + ((TexCoordGenerationRetained)this.retained).getPlaneT(planeT); + } + + /** + * Sets the R coordinate plane equation. This plane equation + * is used to generate the R coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeR plane equation for the R coordinate + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPlaneR(Vector4f planeR) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PLANE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration6")); + + if (isLive()) + ((TexCoordGenerationRetained)this.retained).setPlaneR(planeR); + else + ((TexCoordGenerationRetained)this.retained).initPlaneR(planeR); + } + + /** + * Retrieves a copy of the plane equation used to + * generate the R coordinate. + * @param planeR the R coordinate plane equation + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getPlaneR(Vector4f planeR) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PLANE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration4")); + ((TexCoordGenerationRetained)this.retained).getPlaneR(planeR); + } + + /** + * Sets the Q coordinate plane equation. This plane equation + * is used to generate the Q coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeQ plane equation for the Q coordinate + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void setPlaneQ(Vector4f planeQ) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PLANE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration6")); + + if (isLive()) + ((TexCoordGenerationRetained)this.retained).setPlaneQ(planeQ); + else + ((TexCoordGenerationRetained)this.retained).initPlaneQ(planeQ); + } + + /** + * Retrieves a copy of the plane equation used to + * generate the Q coordinate. + * @param planeQ the Q coordinate plane equation + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getPlaneQ(Vector4f planeQ) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PLANE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TexCoordGeneration4")); + ((TexCoordGenerationRetained)this.retained).getPlaneQ(planeQ); + } + + /** + * Creates a retained mode TexCoordGenerationRetained object that this + * TexCoordGeneration component object will point to. + */ + void createRetained() { + this.retained = new TexCoordGenerationRetained(); + this.retained.setSource(this); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + TexCoordGeneration tga = new TexCoordGeneration(); + tga.duplicateNodeComponent(this); + return tga; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + TexCoordGenerationRetained tex = (TexCoordGenerationRetained) + originalNodeComponent.retained; + TexCoordGenerationRetained rt = (TexCoordGenerationRetained) retained; + + Vector4f v = new Vector4f(); + + rt.initGenMode(tex.getGenMode()); + tex.getPlaneS(v); + rt.initPlaneS(v); + tex.getPlaneT(v); + rt.initPlaneT(v); + tex.getPlaneR(v); + rt.initPlaneR(v); + tex.getPlaneQ(v); + rt.initPlaneQ(v); + rt.initFormat(tex.getFormat()); + rt.initEnable(tex.getEnable()); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TexCoordGenerationRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TexCoordGenerationRetained.java new file mode 100644 index 0000000..c18e140 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TexCoordGenerationRetained.java @@ -0,0 +1,423 @@ +/* + * $RCSfile: TexCoordGenerationRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Vector4f; +import java.util.ArrayList; + +/** + * The TexCoordGeneration object contains all parameters needed for texture + * coordinate generation. It is included as part of an Appearance + * component object. + */ +class TexCoordGenerationRetained extends NodeComponentRetained { + + // A list of pre-defined bits to indicate which component + // in this TexCoordGeneration object changed. + private static final int ENABLE_CHANGED = 0x01; + private static final int PLANE_S_CHANGED = 0x02; + private static final int PLANE_T_CHANGED = 0x04; + private static final int PLANE_R_CHANGED = 0x08; + private static final int PLANE_Q_CHANGED = 0x10; + + // + // State variables + // + int genMode = TexCoordGeneration.OBJECT_LINEAR; + int format = TexCoordGeneration.TEXTURE_COORDINATE_2; + + Vector4f planeS = new Vector4f(1.0f, 0.0f, 0.0f, 0.0f); + Vector4f planeT = new Vector4f(0.0f, 1.0f, 0.0f, 0.0f); + Vector4f planeR = new Vector4f(0.0f, 0.0f, 0.0f, 0.0f); + Vector4f planeQ = new Vector4f(0.0f, 0.0f, 0.0f, 0.0f); + + /** + * Flag to enable/disable Texture coordinate generation. + */ + boolean enable = true; + + // true when mirror texCoord component set + boolean mirrorCompDirty = false; + + /** + * Enables or disables texture coordinate generation for this + * appearance component object. + * @param state true or false to enable or disable texture coordinate + * generation + */ + final void initEnable(boolean state) { + enable = state; + } + /** + * Enables or disables texture coordinate generation for this + * appearance component object and sends a message notifying + * the interested structures of the change. + * @param state true or false to enable or disable texture coordinate + * generation + */ + final void setEnable(boolean state) { + initEnable(state); + sendMessage(ENABLE_CHANGED, (state ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Retrieves the state of the texCoordGeneration enable flag. + * @return true if texture coordinate generation is enabled, + * false if texture coordinate generation is disabled + */ + final boolean getEnable() { + return enable; + } + /** + * Sets the TexCoordGeneration format to the specified value. + * @param format texture format, one of: TEXTURE_COORDINATE_2 + * or TEXTURE_COORDINATE_3 + */ + final void initFormat(int format) { + this.format = format; + } + + /** + * Retrieves the current TexCoordGeneration format. + * @return the texture format + */ + final int getFormat() { + return format; + } + + /** + * Sets the TexCoordGeneration generation mode to the specified value. + * @param genMode texture generation mode, one of: OBJECT_LINEAR, + * EYE_LINEAR, or SPHERE_MAP + */ + final void initGenMode(int genMode) { + this.genMode = genMode; + } + + /** + * Retrieves the current TexCoordGeneration generation mode. + * @return the texture generation mode + */ + final int getGenMode() { + return genMode; + } + + /** + * Sets the S coordinate plane equation. This plane equation + * is used to generate the S coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeS plane equation for the S coordinate + */ + final void setPlaneS(Vector4f planeS) { + initPlaneS(planeS); + sendMessage(PLANE_S_CHANGED, new Vector4f(planeS)); + } + + /** + * Sets the S coordinate plane equation. This plane equation + * is used to generate the S coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeS plane equation for the S coordinate + */ + final void initPlaneS(Vector4f planeS) { + this.planeS.set(planeS); + } + + /** + * Retrieves a copy of the plane equation used to + * generate the S coordinate. + * @param planeS the S coordinate plane equation + */ + final void getPlaneS(Vector4f planeS) { + planeS.set(this.planeS); + } + + /** + * Sets the T coordinate plane equation. This plane equation + * is used to generate the T coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeT plane equation for the T coordinate + */ + final void setPlaneT(Vector4f planeT) { + initPlaneT(planeT); + sendMessage(PLANE_T_CHANGED, new Vector4f(planeT)); + } + + /** + * Sets the T coordinate plane equation. This plane equation + * is used to generate the T coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeT plane equation for the T coordinate + */ + final void initPlaneT(Vector4f planeT) { + this.planeT.set(planeT); + } + + /** + * Retrieves a copy of the plane equation used to + * generate the T coordinate. + * @param planeT the T coordinate plane equation + */ + final void getPlaneT(Vector4f planeT) { + planeT.set(this.planeT); + } + + /** + * Sets the R coordinate plane equation. This plane equation + * is used to generate the R coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeR plane equation for the R coordinate + */ + final void setPlaneR(Vector4f planeR) { + initPlaneR(planeR); + sendMessage(PLANE_R_CHANGED, new Vector4f(planeR)); + } + + /** + * Sets the R coordinate plane equation. This plane equation + * is used to generate the R coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeR plane equation for the R coordinate + */ + final void initPlaneR(Vector4f planeR) { + this.planeR.set(planeR); + } + + /** + * Retrieves a copy of the plane equation used to + * generate the R coordinate. + * @param planeR the R coordinate plane equation + */ + final void getPlaneR(Vector4f planeR) { + planeR.set(this.planeR); + } + + /** + * Sets the Q coordinate plane equation. This plane equation + * is used to generate the Q coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeQ plane equation for the Q coordinate + */ + final void setPlaneQ(Vector4f planeQ) { + initPlaneQ(planeQ); + sendMessage(PLANE_Q_CHANGED, new Vector4f(planeQ)); + } + + /** + * Sets the Q coordinate plane equation. This plane equation + * is used to generate the Q coordinate in OBJECT_LINEAR and EYE_LINEAR + * texture generation modes. + * @param planeQ plane equation for the Q coordinate + */ + final void initPlaneQ(Vector4f planeQ) { + this.planeQ.set(planeQ); + } + + /** + * Retrieves a copy of the plane equation used to + * generate the Q coordinate. + * @param planeQ the Q coordinate plane equation + */ + final void getPlaneQ(Vector4f planeQ) { + planeQ.set(this.planeQ); + } + + + + /** + * Creates a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void createMirrorObject() { + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror= this; + } else { + TexCoordGenerationRetained mirrorTg = new TexCoordGenerationRetained(); + mirrorTg.set(this); + mirrorTg.source = source; + mirror = mirrorTg; + } + } else { + ((TexCoordGenerationRetained) mirror).set(this); + } + } + + void updateNative(Canvas3D cv) { + int gMode = genMode; + Transform3D trans = null; + Transform3D m = cv.vworldToEc; + + if (((cv.textureExtendedFeatures & Canvas3D.TEXTURE_CUBE_MAP) == 0) && + ((genMode == TexCoordGeneration.NORMAL_MAP) || + (genMode == TexCoordGeneration.REFLECTION_MAP))) { + gMode = TexCoordGeneration.SPHERE_MAP; + } + + if (VirtualUniverse.mc.isD3D() && + (gMode == TexCoordGeneration.EYE_LINEAR)) { + trans = new Transform3D(cv.vworldToEc); + trans.invert(); + m = trans; + } + + Pipeline.getPipeline().updateTexCoordGeneration(cv.ctx, + enable, gMode, format, planeS.x, planeS.y, planeS.z, + planeS.w, planeT.x, planeT.y, planeT.z, planeT.w, + planeR.x, planeR.y, planeR.z, planeR.w, + planeQ.x, planeQ.y, planeQ.z, planeQ.w, + m.mat); + } + + /** + * Initializes a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + ((TexCoordGenerationRetained)mirror).set(this); + } + + /** Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + TexCoordGenerationRetained mirrorTc = (TexCoordGenerationRetained) mirror; + + mirrorTc.mirrorCompDirty = true; + + if ((component & ENABLE_CHANGED) != 0) { + mirrorTc.enable = ((Boolean)value).booleanValue(); + } + else if ((component & PLANE_S_CHANGED) != 0) { + mirrorTc.planeS = (Vector4f)value; + } + else if ((component & PLANE_T_CHANGED) != 0) { + mirrorTc.planeT = (Vector4f)value; + } + else if ((component & PLANE_R_CHANGED) != 0) { + mirrorTc.planeR = (Vector4f)value; + } + else if ((component & PLANE_Q_CHANGED) != 0) { + mirrorTc.planeQ = (Vector4f)value; + } + } + + + boolean equivalent(TexCoordGenerationRetained tr) { + + if (tr == null) { + return (false); + + } else if ((this.changedFrequent != 0) || (tr.changedFrequent != 0)) { + return (this == tr); + } + + return ((tr.genMode == genMode) && + (tr.format == format) && + (tr.enable == enable) && + tr.planeS.equals(planeS) && + tr.planeT.equals(planeT) && + tr.planeR.equals(planeR)); + } + + protected Object clone() { + TexCoordGenerationRetained tr = (TexCoordGenerationRetained)super.clone(); + tr.planeS = new Vector4f(planeS); + tr.planeT = new Vector4f(planeT); + tr.planeR = new Vector4f(planeR); + // other attributes is copied in super.clone() + return tr; + + } + + protected void set(TexCoordGenerationRetained tr) { + super.set(tr); + genMode = tr.genMode; + format = tr.format; + enable = tr.enable; + planeS.set(tr.planeS); + planeT.set(tr.planeT); + planeR.set(tr.planeR); + } + + final void sendMessage(int attrMask, Object attr) { + + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.TEXCOORDGENERATION_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i + *
    + *
  • Font3D object - describes the font style of the text string, + * such as the font family (Helvetica, Courier, etc.), style (Italic, + * bold, etc.), and point size. The size of the resulting characters will + * be equal to the point size. For example, a 12 point font will result in + * a Font3D with characters 12 meters tall.
  • + *

  • Text string - the text string to be written.
  • + *

  • Position - determines the initial placement of the Text3D string + * in three-space.
  • + *

  • Alignment - specifies how glyphs in the string are placed in + * relation to the position parameter. Valid values are: + *
      + *
    • ALIGN_CENTER - the center of the string is placed on the + * position point.
    • + *
    • ALIGN_FIRST - the first character of the string is placed on + * the position point.
    • + *
    • ALIGN_LAST - the last character of the string is placed on the + * position point.
    • + *

    + *

  • Path - specifies how succeeding glyphs in the string are placed + * in relation to the previous glyph. Valid values are:
  • + *

      + *
    • PATH_LEFT - succeeding glyphs are placed to the left of the + * current glyph.
    • + *
    • PATH_RIGHT - succeeding glyphs are placed to the right of the + * current glyph.
    • + *
    • PATH_UP - succeeding glyphs are placed above the current glyph.
    • + *
    • PATH_DOWN - succeeding glyphs are placed below the current glyph.
    • + *

    + *

  • Character spacing - the space between characters. This spacing is + * in addition to the regular spacing between glyphs as defined in the + * Font object.

+ * + * @see Font3D + */ +public class Text3D extends Geometry { + + /** + * Specifies that this Text3D object allows + * reading the Font3D component information. + * + * @see Font3D + */ + public static final int + ALLOW_FONT3D_READ = CapabilityBits.TEXT3D_ALLOW_FONT3D_READ; + + /** + * Specifies that this Text3D object allows + * writing the Font3D component information. + * + * @see Font3D + */ + public static final int + ALLOW_FONT3D_WRITE = CapabilityBits.TEXT3D_ALLOW_FONT3D_WRITE; + + /** + * Specifies that this Text3D object allows + * reading the String object. + */ + public static final int + ALLOW_STRING_READ = CapabilityBits.TEXT3D_ALLOW_STRING_READ; + + /** + * Specifies that this Text3D object allows + * writing the String object. + */ + public static final int + ALLOW_STRING_WRITE = CapabilityBits.TEXT3D_ALLOW_STRING_WRITE; + + /** + * Specifies that this Text3D object allows + * reading the text position value. + */ + public static final int + ALLOW_POSITION_READ = CapabilityBits.TEXT3D_ALLOW_POSITION_READ; + + /** + * Specifies that this Text3D object allows + * writing the text position value. + */ + public static final int + ALLOW_POSITION_WRITE = CapabilityBits.TEXT3D_ALLOW_POSITION_WRITE; + + /** + * Specifies that this Text3D object allows + * reading the text alignment value. + */ + public static final int + ALLOW_ALIGNMENT_READ = CapabilityBits.TEXT3D_ALLOW_ALIGNMENT_READ; + + /** + * Specifies that this Text3D object allows + * writing the text alignment value. + */ + public static final int + ALLOW_ALIGNMENT_WRITE = CapabilityBits.TEXT3D_ALLOW_ALIGNMENT_WRITE; + + /** + * Specifies that this Text3D object allows + * reading the text path value. + */ + public static final int + ALLOW_PATH_READ = CapabilityBits.TEXT3D_ALLOW_PATH_READ; + + /** + * Specifies that this Text3D object allows + * writing the text path value. + */ + public static final int + ALLOW_PATH_WRITE = CapabilityBits.TEXT3D_ALLOW_PATH_WRITE; + + /** + * Specifies that this Text3D object allows + * reading the text character spacing value. + */ + public static final int + ALLOW_CHARACTER_SPACING_READ = CapabilityBits.TEXT3D_ALLOW_CHARACTER_SPACING_READ; + + /** + * Specifies that this Text3D object allows + * writing the text character spacing value. + */ + public static final int + ALLOW_CHARACTER_SPACING_WRITE = CapabilityBits.TEXT3D_ALLOW_CHARACTER_SPACING_WRITE; + + /** + * Specifies that this Text3D object allows + * reading the text string bounding box value + */ + public static final int + ALLOW_BOUNDING_BOX_READ = CapabilityBits.TEXT3D_ALLOW_BOUNDING_BOX_READ; + + /** + * alignment: the center of the string is placed on the + * position point. + * + * @see #getAlignment + */ + public static final int ALIGN_CENTER = 0; + + /** + * alignment: the first character of the string is placed + * on the position point. + * + * @see #getAlignment + */ + public static final int ALIGN_FIRST = 1; + + /** + * alignment: the last character of the string is placed + * on the position point. + * + * @see #getAlignment + */ + public static final int ALIGN_LAST = 2; + + /** + * path: succeeding glyphs are placed to the left of + * the current glyph. + * + * @see #getPath + */ + public static final int PATH_LEFT = 0; + /** + * path: succeeding glyphs are placed to the left of + * the current glyph. + * + * @see #getPath + */ + public static final int PATH_RIGHT = 1; + + /** + * path: succeeding glyphs are placed above the + * current glyph. + * + * @see #getPath + */ + public static final int PATH_UP = 2; + + /** + * path: succeeding glyphs are placed below the + * current glyph. + * + * @see #getPath + */ + public static final int PATH_DOWN = 3; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_FONT3D_READ, + ALLOW_STRING_READ, + ALLOW_POSITION_READ, + ALLOW_ALIGNMENT_READ, + ALLOW_PATH_READ, + ALLOW_CHARACTER_SPACING_READ, + ALLOW_BOUNDING_BOX_READ + }; + + /** + * Constructs a Text3D object with default parameters. + * The default values are as follows: + *

    + * font 3D : null
    + * string : null
    + * position : (0,0,0)
    + * alignment : ALIGN_FIRST
    + * path : PATH_RIGHT
    + * character spacing : 0.0
    + *
+ */ + public Text3D() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Creates a Text3D object with the given Font3D object. + * + * @see Font3D + */ + public Text3D(Font3D font3D) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((Text3DRetained)this.retained).setFont3D(font3D); + } + + /** + * Creates a Text3D object given a Font3D object and a string. The + * string is converted into 3D glyphs. The first glyph from the + * string is placed at (0.0, 0.0, 0.0) and succeeding glyphs are + * placed to the right of the initial glyph. + * + * @see Font3D + */ + public Text3D(Font3D font3D, String string) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((Text3DRetained)this.retained).setFont3D(font3D); + ((Text3DRetained)this.retained).setString(string); + } + + /** + * Creates a Text3D object given a Font3D, a string and position. The + * string is converted into 3D glyphs. The first glyph from the + * string is placed at position position and succeeding + * glyphs are placed to the right of the initial glyph. + * + * @see Font3D + */ + public Text3D(Font3D font3D, String string, Point3f position) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((Text3DRetained)this.retained).setFont3D(font3D); + ((Text3DRetained)this.retained).setString(string); + ((Text3DRetained)this.retained).setPosition(position); + } + + /** + * Creates a Text3D object given a Font3D, string, position, alignment + * and path along which string is to be placed. The + * string is converted into 3D glyphs. The placement of the glyphs + * with respect to the position position depends on + * the alignment parameter and the path parameter. + * + * @see Font3D + */ + public Text3D(Font3D font3D, String string, Point3f position, + int alignment, int path) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((Text3DRetained)this.retained).setFont3D(font3D); + ((Text3DRetained)this.retained).setString(string); + ((Text3DRetained)this.retained).setPosition(position); + ((Text3DRetained)this.retained).setAlignment(alignment); + ((Text3DRetained)this.retained).setPath(path); + } + + /** + * Creates the retained mode Text3DRetained object that this + * Text3D component object will point to. + */ + void createRetained() { + this.retained = new Text3DRetained(); + this.retained.setSource(this); + } + + + /** + * Returns the Font3D objects used by this Text3D NodeComponent object. + * + * @return the Font3D object of this Text3D node - null if no Font3D + * has been associated with this node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Font3D getFont3D() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_FONT3D_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D0")); + return ((Text3DRetained)this.retained).getFont3D(); + + } + + /** + * Sets the Font3D object used by this Text3D NodeComponent object. + * + * @param font3d the Font3D object to associate with this Text3D node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setFont3D(Font3D font3d) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_FONT3D_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D1")); + ((Text3DRetained)this.retained).setFont3D(font3d); + + } + + /** + * Copies the character string used in the construction of the + * Text3D node into the supplied parameter. + * + * @return a copy of the String object in this Text3D node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public String getString() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_STRING_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D2")); + return ((Text3DRetained)this.retained).getString(); + } + + /** + * Copies the character string from the supplied parameter into the + * Text3D node. + * + * @param string the String object to recieve the Text3D node's string. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setString(String string) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_STRING_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D3")); + ((Text3DRetained)this.retained).setString(string); + } + + /** + * Copies the node's position field into the supplied + * parameter. The position is used to determine the + * initial placement of the Text3D string. The position, combined with + * the path and alignment control how the text is displayed. + * + * @param position the point to position the text. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #getAlignment + * @see #getPath + */ + public void getPosition(Point3f position) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D4")); + ((Text3DRetained)this.retained).getPosition(position); + } + + /** + * Sets the node's position field to the supplied + * parameter. The position is used to determine the + * initial placement of the Text3D string. The position, combined with + * the path and alignment control how the text is displayed. + * + * @param position the point to position the text. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #getAlignment + * @see #getPath + */ + public void setPosition(Point3f position) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POSITION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D5")); + ((Text3DRetained)this.retained).setPosition(position); + } + + /** + * Retrieves the text alignment policy for this Text3D NodeComponent + * object. The alignment is used to specify how + * glyphs in the string are placed in relation to the + * position field. Valid values for this field + * are: + *
    + *
  • ALIGN_CENTER - the center of the string is placed on the + * position point. + *
  • ALIGN_FIRST - the first character of the string is placed on + * the position point. + *
  • ALIGN_LAST - the last character of the string is placed on the + * position point. + *
+ * The default value of this field is ALIGN_FIRST. + * + * @return the current alingment policy for this node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #getPosition + */ + public int getAlignment() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ALIGNMENT_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D6")); + return ((Text3DRetained)this.retained).getAlignment(); + } + + /** + * Sets the text alignment policy for this Text3D NodeComponent + * object. The alignment is used to specify how + * glyphs in the string are placed in relation to the + * position field. Valid values for this field + * are: + *
    + *
  • ALIGN_CENTER - the center of the string is placed on the + * position point. + *
  • ALIGN_FIRST - the first character of the string is placed on + * the position point. + *
  • ALIGN_LAST - the last character of the string is placed on the + * position point. + *
+ * The default value of this field is ALIGN_FIRST. + * + * @param alignment specifies how glyphs in the string are placed + * in relation to the position field + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #getPosition + */ + public void setAlignment(int alignment) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_ALIGNMENT_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D7")); + ((Text3DRetained)this.retained).setAlignment(alignment); + } + + /** + * Retrieves the node's path field. This field + * is used to specify how succeeding + * glyphs in the string are placed in relation to the previous glyph. + * Valid values for this field are: + *
    + *
  • PATH_LEFT: - succeeding glyphs are placed to the left of the + * current glyph. + *
  • PATH_RIGHT: - succeeding glyphs are placed to the right of the + * current glyph. + *
  • PATH_UP: - succeeding glyphs are placed above the current glyph. + *
  • PATH_DOWN: - succeeding glyphs are placed below the current glyph. + *
+ * The default value of this field is PATH_RIGHT. + * + * @return the current alingment policy for this node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getPath() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PATH_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D8")); + return ((Text3DRetained)this.retained).getPath(); + } + + /** + * Sets the node's path field. This field + * is used to specify how succeeding + * glyphs in the string are placed in relation to the previous glyph. + * Valid values for this field are: + *
    + *
  • PATH_LEFT - succeeding glyphs are placed to the left of the + * current glyph. + *
  • PATH_RIGHT - succeeding glyphs are placed to the right of the + * current glyph. + *
  • PATH_UP - succeeding glyphs are placed above the current glyph. + *
  • PATH_DOWN - succeeding glyphs are placed below the current glyph. + *
+ * The default value of this field is PATH_RIGHT. + * + * @param path the value to set the path to + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setPath(int path) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PATH_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D9")); + ((Text3DRetained)this.retained).setPath(path); + } + + /** + * Retrieves the 3D bounding box that encloses this Text3D object. + * + * @param bounds the object to copy the bounding information to. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see BoundingBox + */ + public void getBoundingBox(BoundingBox bounds) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_BOUNDING_BOX_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D10")); + ((Text3DRetained)this.retained).getBoundingBox(bounds); + } + + /** + * Retrieves the character spacing used to construct the Text3D string. + * This spacing is in addition to the regular spacing between glyphs as + * defined in the Font object. 1.0 in this space is measured as the + * width of the largest glyph in the 2D Font. The default value is + * 0.0. + * + * @return the current character spacing value + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getCharacterSpacing() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHARACTER_SPACING_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D11")); + return ((Text3DRetained)this.retained).getCharacterSpacing(); + } + + /** + * Sets the character spacing used when constructing the Text3D string. + * This spacing is in addition to the regular spacing between glyphs as + * defined in the Font object. 1.0 in this space is measured as the + * width of the largest glyph in the 2D Font. The default value is + * 0.0. + * + * @param characterSpacing the new character spacing value + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setCharacterSpacing(float characterSpacing) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_CHARACTER_SPACING_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Text3D12")); + ((Text3DRetained)this.retained).setCharacterSpacing(characterSpacing); + } + + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + Text3D t = new Text3D(); + t.duplicateNodeComponent(this); + return t; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + Text3DRetained text = (Text3DRetained) originalNodeComponent.retained; + Text3DRetained rt = (Text3DRetained) retained; + + Font3D font3D = text.getFont3D(); + if (font3D != null) { + rt.setFont3D(font3D); + } + + String s = text.getString(); + if (s != null) { + rt.setString(s); + } + + Point3f p = new Point3f(); + text.getPosition(p); + rt.setPosition(p); + rt.setAlignment(text.getAlignment()); + rt.setPath(text.getPath()); + rt.setCharacterSpacing(text.getCharacterSpacing()); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Text3DRenderMethod.java b/j3d-core/src/classes/share/javax/media/j3d/Text3DRenderMethod.java new file mode 100644 index 0000000..d604f8b --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Text3DRenderMethod.java @@ -0,0 +1,124 @@ +/* + * $RCSfile: Text3DRenderMethod.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The RenderMethod interface is used to create various ways to render + * different geometries. + */ + +class Text3DRenderMethod implements RenderMethod { + + /** + * The actual rendering code for this RenderMethod + */ + public boolean render(RenderMolecule rm, Canvas3D cv, + RenderAtomListInfo ra, int dirtyBits) { + + boolean isNonUniformScale; + Transform3D trans = null; + + GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry(); + geo.setVertexFormat((rm.useAlpha && ((geo.vertexFormat & + GeometryArray.COLOR) != 0)), + rm.textureBin.attributeBin.ignoreVertexColors, cv.ctx); + + if (rm.doInfinite) { + cv.updateState(dirtyBits); + while (ra != null) { + trans = ra.infLocalToVworld; + isNonUniformScale = !trans.isCongruent(); + cv.setModelViewMatrix(cv.ctx, cv.vworldToEc.mat, trans); + + ra.geometry().execute(cv, ra.renderAtom, isNonUniformScale, + (rm.useAlpha && ra.geometry().noAlpha), + rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin.ignoreVertexColors); + ra = ra.next; + } + return true; + } + + boolean isVisible = false; // True if any of the RAs is visible. + while (ra != null) { + if (cv.ra == ra.renderAtom) { + if (cv.raIsVisible) { + cv.updateState(dirtyBits); + trans = ra.localToVworld; + isNonUniformScale = !trans.isCongruent(); + + cv.setModelViewMatrix(cv.ctx, cv.vworldToEc.mat, trans); + ra.geometry().execute(cv, ra.renderAtom, isNonUniformScale, + (rm.useAlpha && ra.geometry().noAlpha), + rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin. + ignoreVertexColors); + isVisible = true; + } + } + else { + if (!VirtualUniverse.mc.viewFrustumCulling || + ra.renderAtom.localeVwcBounds.intersect(cv.viewFrustum)) { + cv.updateState(dirtyBits); + cv.raIsVisible = true; + trans = ra.localToVworld; + isNonUniformScale = !trans.isCongruent(); + + cv.setModelViewMatrix(cv.ctx, cv.vworldToEc.mat, trans); + ra.geometry().execute(cv, ra.renderAtom, isNonUniformScale, + (rm.useAlpha && ra.geometry().noAlpha), + rm.alpha, + cv.screen.screen, + rm.textureBin.attributeBin. + ignoreVertexColors); + isVisible = true; + } + else { + cv.raIsVisible = false; + } + cv.ra = ra.renderAtom; + } + + ra = ra.next; + + } + + geo.disableGlobalAlpha(cv.ctx, + (rm.useAlpha && ((geo.vertexFormat & + GeometryArray.COLOR) != 0)), + rm.textureBin.attributeBin.ignoreVertexColors); + + return isVisible; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Text3DRetained.java b/j3d-core/src/classes/share/javax/media/j3d/Text3DRetained.java new file mode 100644 index 0000000..13a5b8e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Text3DRetained.java @@ -0,0 +1,997 @@ +/* + * $RCSfile: Text3DRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.awt.font.*; +import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; + +/** + * Implements Text3D class. + */ +class Text3DRetained extends GeometryRetained { + /** + * Packaged scope variables needed for implementation + */ + Font3D font3D = null; + String string = null; + Point3f position = new Point3f(0.0f, 0.0f, 0.0f); + int alignment = Text3D.ALIGN_FIRST, path = Text3D.PATH_RIGHT; + float charSpacing = 0.0f; + int numChars = 0; + static final int targetThreads = (J3dThread.UPDATE_TRANSFORM | + J3dThread.UPDATE_GEOMETRY | + J3dThread.UPDATE_RENDER); + /** + * The temporary transforms for this Text3D + */ + Transform3D[] charTransforms = new Transform3D[0]; + + /** + * A cached list of geometry arrays for the current settings + */ + GeometryArrayRetained[] geometryList = new GeometryArrayRetained[0]; + GlyphVector[] glyphVecs = new GlyphVector[0]; + + /** + * Bounding box data for this text string. + */ + Point3d lower = new Point3d(); + Point3d upper = new Point3d(); + + + /** + * An Array list used for messages + */ + ArrayList newGeometryAtomList = new ArrayList(); + ArrayList oldGeometryAtomList = new ArrayList(); + + + /** + * temporary model view matrix for immediate mode only + */ + Transform3D vpcToEc; + Transform3D drawTransform; + + + Text3DRetained(){ + this.geoType = GEO_TYPE_TEXT3D; + } + + + synchronized void computeBoundingBox() { + Point3d l = new Point3d(); + Point3d u = new Point3d(); + Vector3f location = new Vector3f(this.position); + int i, k=0, numTotal=0; + double width = 0, height = 0; + Rectangle2D bounds; + + //Reset bounds data + l.set(location); + u.set(location); + + if (numChars != 0) { + // Set loop counters based on path type + if (path == Text3D.PATH_RIGHT || path == Text3D.PATH_UP) { + k = 0; + numTotal = numChars + 1; + } else if (path == Text3D.PATH_LEFT || path == Text3D.PATH_DOWN) { + k = 1; + numTotal = numChars; + // Reset bounds to bounding box if first character + bounds = glyphVecs[0].getVisualBounds(); + u.x += bounds.getWidth(); + u.y += bounds.getHeight(); + } + + for (i=1; iposition field into the supplied + * parameter. The position is used to determine the + * initial placement of the Text3D string. The position, combined with + * the path and alignment control how the text is displayed. + * + * @param position the point to position the text. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #getAlignment + * @see #getPath + */ + final void getPosition(Point3f position) { + position.set(this.position); + } + + /** + * Sets the node's position field to the supplied + * parameter. The position is used to determine the + * initial placement of the Text3D string. The position, combined with + * the path and alignment control how the text is displayed. + * + * @param position the point to position the text. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #getAlignment + * @see #getPath + */ + final void setPosition(Point3f position) { + geomLock.getLock(); + this.position.set(position); + updateTransformData(); + geomLock.unLock(); + sendTransformChangedMessage(); + } + + /** + * Retrieves the text alignment policy for this Text3D NodeComponent + * object. The alignment is used to specify how + * glyphs in the string are placed in relation to the + * position field. Valid values for this field + * are: + *
    + *
  • ALIGN_CENTER - the center of the string is placed on the + * position point. + *
  • ALIGN_FIRST - the first character of the string is placed on + * the position point. + *
  • ALIGN_LAST - the last character of the string is placed on the + * position point. + *
+ * The default value of this field is ALIGN_FIRST. + * + * @return the current alingment policy for this node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #getPosition + */ + final int getAlignment() { + return alignment; + } + + /** + * Sets the text alignment policy for this Text3D NodeComponent + * object. The alignment is used to specify how + * glyphs in the string are placed in relation to the + * position field. Valid values for this field + * are: + *
    + *
  • ALIGN_CENTER - the center of the string is placed on the + * position point. + *
  • ALIGN_FIRST - the first character of the string is placed on + * the position point. + *
  • ALIGN_LAST - the last character of the string is placed on the + * position point. + *
+ * The default value of this field is ALIGN_FIRST. + * + * @return the current alingment policy for this node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see #getPosition + */ + final void setAlignment(int alignment) { + geomLock.getLock(); + this.alignment = alignment; + updateTransformData(); + geomLock.unLock(); + sendTransformChangedMessage(); + } + + /** + * Retrieves the node's path field. This field + * is used to specify how succeeding + * glyphs in the string are placed in relation to the previous glyph. + * Valid values for this field are: + *
    + *
  • PATH_LEFT: - succeeding glyphs are placed to the left of the + * current glyph. + *
  • PATH_RIGHT: - succeeding glyphs are placed to the right of the + * current glyph. + *
  • PATH_UP: - succeeding glyphs are placed above the current glyph. + *
  • PATH_DOWN: - succeeding glyphs are placed below the current glyph. + *
+ * The default value of this field is PATH_RIGHT. + * + * @return the current alingment policy for this node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + final int getPath() { + return this.path; + } + + /** + * Sets the node's path field. This field + * is used to specify how succeeding + * glyphs in the string are placed in relation to the previous glyph. + * Valid values for this field are: + *
    + *
  • PATH_LEFT - succeeding glyphs are placed to the left of the + * current glyph. + *
  • PATH_RIGHT - succeeding glyphs are placed to the right of the + * current glyph. + *
  • PATH_UP - succeeding glyphs are placed above the current glyph. + *
  • PATH_DOWN - succeeding glyphs are placed below the current glyph. + *
+ * The default value of this field is PATH_RIGHT. + * + * @param path the value to set the path to. + * + * @return the current alingment policy for this node. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + final void setPath(int path) { + this.path = path; + updateTransformData(); + sendTransformChangedMessage(); + } + + /** + * Retrieves the 3D bounding box that encloses this Text3D object. + * + * @param bounds the object to copy the bounding information to. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see BoundingBox + */ + final void getBoundingBox(BoundingBox bounds) { + synchronized (this) { + bounds.setLower(lower); + bounds.setUpper(upper); + } + } + + /** + * Retrieves the character spacing used to construct the Text3D string. + * This spacing is in addition to the regular spacing between glyphs as + * defined in the Font object. 1.0 in this space is measured as the + * width of the largest glyph in the 2D Font. The default value is + * 0.0. + * + * @return the current character spacing value + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + final float getCharacterSpacing() { + return charSpacing; + } + + /** + * Sets the character spacing used hwne constructing the Text3D string. + * This spacing is in addition to the regular spacing between glyphs as + * defined in the Font object. 1.0 in this space is measured as the + * width of the largest glyph in the 2D Font. The default value is + * 0.0. + * + * @param characterSpacing the new character spacing value + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + final void setCharacterSpacing(float characterSpacing) { + geomLock.getLock(); + this.charSpacing = characterSpacing; + updateTransformData(); + geomLock.unLock(); + sendTransformChangedMessage(); + } + + + final void sendDataChangedMessage() { + J3dMessage[] m; + int i, j, k, kk, numMessages; + int gSize; + ArrayList shapeList, gaList; + Shape3DRetained s; + GeometryAtom[] newGeometryAtoms; + ArrayList tiArrList = new ArrayList(); + ArrayList newCtArrArrList = new ArrayList(); + + synchronized(liveStateLock) { + if (source.isLive()) { + synchronized (universeList) { + numMessages = universeList.size(); + m = new J3dMessage[numMessages]; + for (i=0; i 0) { + m[i].args[2] = tiArrList.toArray(); + m[i].args[3] = newCtArrArrList.toArray(); + } + + tiArrList.clear(); + newCtArrArrList.clear(); + + } + VirtualUniverse.mc.processMessage(m); + } + + } + } + } + + + final void sendTransformChangedMessage() { + J3dMessage[] m; + int i, j, numMessages, sCnt; + ArrayList shapeList; + ArrayList gaList = new ArrayList(); + Shape3DRetained s; + GeometryRetained geomR; + synchronized(liveStateLock) { + if (source.isLive()) { + synchronized (universeList) { + numMessages = universeList.size(); + m = new J3dMessage[numMessages]; + for (i=0; i= 0) { + // We need to transform iPnt to the vworld to compute the actual distance. + // In this method we'll transform iPnt by its char. offset. Shape3D will + // do the localToVworld transform. + iPnt.set(closestIPnt); + charTransforms[sIndex].transform(iPnt); + return true; + } + return false; + } + + boolean intersect(Point3d[] pnts) { + Transform3D tempT3D = new Transform3D(); + GeometryArrayRetained ga; + boolean isIntersect = false; + Point3d transPnts[] = new Point3d[pnts.length]; + for (int j=pnts.length-1; j >= 0; j--) { + transPnts[j] = new Point3d(); + } + + for (int i=numChars-1; i >= 0; i--) { + ga = geometryList[i]; + if ( ga != null) { + tempT3D.invert(charTransforms[i]); + for (int j=pnts.length-1; j >= 0; j--) { + tempT3D.transform(pnts[j], transPnts[j]); + } + if (ga.intersect(transPnts)) { + isIntersect = true; + break; + } + } + } + return isIntersect; + } + + + boolean intersect(Transform3D thisToOtherVworld, GeometryRetained geom) { + GeometryArrayRetained ga; + + for (int i=numChars-1; i >=0; i--) { + ga = geometryList[i]; + if ((ga != null) && ga.intersect(thisToOtherVworld, geom)) { + return true; + } + } + + return false; + } + + boolean intersect(Bounds targetBound) { + GeometryArrayRetained ga; + + for (int i=numChars-1; i >=0; i--) { + ga = geometryList[i]; + if ((ga != null) && ga.intersect(targetBound)) { + return true; + } + } + + return false; + + } + + void setModelViewMatrix(Transform3D vpcToEc, Transform3D drawTransform) { + this.vpcToEc = vpcToEc; + this.drawTransform = drawTransform; + } + + + void execute(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale, + boolean updateAlpha, float alpha, + int screen, + boolean ignoreVertexColors) { + + Transform3D trans = new Transform3D(); + + for (int i = 0; i < geometryList.length; i++) { + trans.set(drawTransform); + trans.mul(charTransforms[i]); + cv.setModelViewMatrix(cv.ctx, vpcToEc.mat, trans); + geometryList[i].execute(cv, ra, isNonUniformScale, updateAlpha, alpha, + screen, ignoreVertexColors); + } + } + + int getClassType() { + return TEXT3D_TYPE; + } + + + ArrayList getUniqueSource(ArrayList shapeList) { + ArrayList uniqueList = new ArrayList(); + int size = shapeList.size(); + Object src; + int i, index; + + for (i=0; i + * Each Texture object has the following properties:

+ *

    + *
  • Boundary color - the texture boundary color. The texture + * boundary color is used when the boundaryModeS and boundaryModeT + * parameters are set to CLAMP or CLAMP_TO_BOUNDARY and if the texture + * boundary is not specified.
  • + *

  • Boundary Width - the texture boundary width, which must be 0 or 1. + * If the texture boundary + * width is 1, then all images for all mipmap levels will include a border. + * The actual texture image for level 0, for example, will be of + * dimension (width + 2*boundaryWidth) * (height + 2*boundaryWidth). + * The boundary texels will be used when linear filtering is to be applied. + *
  • + *

  • Boundary ModeS and Boundary ModeT - the boundary mode for the + * S and T coordinates, respectively. The boundary modes are as + * follows:
  • + *

      + *
    • CLAMP - clamps texture coordinates to be in the range [0,1]. + * Texture boundary texels or the constant boundary color if boundary width + * is 0 will be used for U,V values that fall outside this range.
    • + *

    • WRAP - repeats the texture by wrapping texture coordinates + * that are outside the range [0,1]. Only the fractional portion + * of the texture coordinates is used. The integer portion is + * discarded
    • + *

    • CLAMP_TO_EDGE - clamps texture coordinates such that filtering + * will not sample a texture boundary texel. Texels at the edge of the + * texture will be used instead.
    • + *

    • CLAMP_TO_BOUNDARY - clamps texture coordinates such that filtering + * will sample only texture boundary texels, that is, it will never + * get some samples from the boundary and some from the edge. This + * will ensure clean unfiltered boundaries. If the texture does not + * have a boundary, that is the boundary width is equal to 0, then the + * constant boundary color will be used.
    • + *
    + *
  • Image - an image or an array of images for all the mipmap + * levels. If only one image is provided, the MIPmap mode must be + * set to BASE_LEVEL.
  • + *

  • Magnification filter - the magnification filter function. + * Used when the pixel being rendered maps to an area less than or + * equal to one texel. The magnification filter functions are as + * follows:
  • + *

      + *
    • FASTEST - uses the fastest available method for processing + * geometry.
    • + *

    • NICEST - uses the nicest available method for processing + * geometry.
    • + *

    • BASE_LEVEL_POINT - selects the nearest texel in the base level + * texture image.
    • + *

    • BASE_LEVEL_LINEAR - performs a bilinear interpolation on the four + * nearest texels in the base level texture image. The texture value T' is + * computed as follows:
    • + *

        + * i0 = trunc(u - 0.5)

        + * j0 = trunc(v - 0.5)

        + * i1 = i0 + 1

        + * j1 = j0 + 1

        + * a = frac(u - 0.5)

        + * b = frac(v - 0.5)

        + * T' = (1-a)*(1-b)*Ti0j0 + + * a*(1-b)*Ti1j0 + + * (1-a)*b*Ti0j1 + + * a*b*Ti1j1

        + *

      + *
    • LINEAR_SHARPEN - sharpens the resulting image by extrapolating + * from the base level plus one image to the base level image of this + * texture object.
    • + *

    • LINEAR_SHARPEN_RGB - performs linear sharpen filter for the rgb + * components only. The alpha component is computed using BASE_LEVEL_LINEAR + * filter.
    • + *

    • LINEAR_SHARPEN_ALPHA - performs linear sharpen filter for the alpha + * component only. The rgb components are computed using BASE_LEVEL_LINEAR + * filter.
    • + *

    • FILTER4 - applies an application-supplied weight function + * on the nearest 4x4 texels in the base level texture image. The + * texture value T' is computed as follows:
    • + *

        + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
        i1 = trunc(u - 0.5)i2 = i1 + 1i3 = i2 + 1i0 = i1 - 1
        j1 = trunc(v - 0.5)j3 = j2 + 1j2 = j1 + 1j0 = j1 - 1
        a = frac(u - 0.5)
        b = frac(v - 0.5)
        + * f(x) : filter4 function where 0<=x<=2

        + * T' = f(1+a) * f(1+b) * Ti0j0 + + * f(a) * f(1+b) * Ti1j0 + + * f(1-a) * f(1+b) * Ti2j0 + + * f(2-a) * f(1+b) * Ti3j0 +
        + * f(1+a) * f(b) * Ti0j1 + + * f(a) * f(b) * Ti1j1 + + * f(1-a) * f(b) * Ti2j1 + + * f(2-a) * f(b) * Ti3j1 +
        + * f(1+a) * f(1-b) * Ti0j2 + + * f(a) * f(1-b) * Ti1j2 + + * f(1-a) * f(1-b) * Ti2j2 + + * f(2-a) * f(1-b) * Ti3j2 +
        + * f(1+a) * f(2-b) * Ti0j3 + + * f(a) * f(2-b) * Ti1j3 + + * f(1-a) * f(2-b) * Ti2j3 + + * f(2-a) * f(2-b) * Ti3j3

        + *

      + *
    + *
  • Minification filter - the minification filter function. Used + * when the pixel being rendered maps to an area greater than one + * texel. The minifaction filter functions are as follows:
  • + *

      + *
    • FASTEST - uses the fastest available method for processing + * geometry.
    • + *

    • NICEST - uses the nicest available method for processing + * geometry.
    • + *

    • BASE_LEVEL_POINT - selects the nearest level in the base level + * texture map.
    • + *

    • BASE_LEVEL_LINEAR - performs a bilinear interpolation on the four + * nearest texels in the base level texture map.
    • + *

    • MULTI_LEVEL_POINT - selects the nearest texel in the nearest + * mipmap.
    • + *

    • MULTI_LEVEL_LINEAR - performs trilinear interpolation of texels + * between four texels each from the two nearest mipmap levels.
    • + *

    • FILTER4 - applies an application-supplied weight function + * on the nearest 4x4 texels in the base level texture image.
    • + *

    + *
  • MIPmap mode - the mode used for texture mapping for this + * object. The mode is one of the following:
  • + *

      + *
    • BASE_LEVEL - indicates that this Texture object only has a + * base-level image. If multiple levels are needed, they will be + * implicitly computed.
    • + *

    • MULTI_LEVEL_MIPMAP - indicates that this Texture object has + * multiple images. If MIPmap mode is set + * to MULTI_LEVEL_MIPMAP, images for Base Level through Max Level + * must be set.
    • + *

    + *
  • Format - the data format. The format is one of the + * following:
  • + *

      + *
    • INTENSITY - the texture image contains only texture + * values.
    • + *

    • LUMINANCE - the texture image contains only + * luminance values.
    • + *

    • ALPHA - the texture image contains only alpha + * values.
    • + *

    • LUMINANCE_ALPHA - the texture image contains + * both luminance and alpha values.
    • + *

    • RGB - the texture image contains red, green, + * and blue values.
    • + *

    • RGBA - the texture image contains red, green, blue, and alpha + * values.
    + *
  • Base Level - specifies the mipmap level to be used when filter + * specifies BASE_LEVEL_POINT or BASE_LEVEL_LINEAR.
  • + *

  • Maximum Level - specifies the maximum level of image that needs to be + * defined for this texture to be valid. Note, for this texture to be valid, + * images for Base Level through Maximum Level have to be defined.
  • + *

  • Minimum LOD - specifies the minimum of the LOD range. LOD smaller + * than this value will be clamped to this value.
  • + *

  • Maximum LOD - specifies the maximum of the LOD range. LOD larger + * than this value will be clamped to this value.
  • + *

  • LOD offset - specifies the offset to be used in the LOD calculation + * to compensate for under or over sampled texture images.
  • + *
  • Anisotropic Mode - defines how anisotropic filter is applied for + * this texture object. The anisotropic modes are as follows:
  • + *

      + *
    • ANISOTROPIC_NONE - no anisotropic filtering.
    • + *

    • ANISOTROPIC_SINGLE_VALUE - applies the degree of anisotropic filter + * in both the minification and magnification filters.
    • + *

    + *
  • Anisotropic Filter Degree - controls the degree of anisotropy. This + * property applies to both minification and magnification filtering. + * If it is equal to 1.0, then an isotropic filtering as specified in the + * minification or magnification filter will be used. If it is greater + * than 1.0, and the anisotropic mode is equal to ANISOTROPIC_SINGLE_VALUE, + * then + * the degree of anisotropy will also be applied in the filtering.
  • + *

  • Sharpen Texture Function - specifies the function of level-of-detail + * used in combining the texture value computed from the base level image + * and the texture value computed from the base level plus one image. The + * final texture value is computed as follows:
  • + *

      + * T' = ((1 + SharpenFunc(LOD)) * TBaseLevel) - (SharpenFunc(LOD) * TBaseLevel+1)

      + *

    + *
  • Filter4 Function - specifies the function to be applied to the + * nearest 4x4 texels. This property includes samples of the filter + * function f(x), 0<=x<=2. The number of function values supplied + * has to be equal to 2m + 1 for some integer value of m + * greater than or equal to 4.
  • + *

+ * + *

+ * Note that as of Java 3D 1.5, the texture width and height are no longer + * required to be an exact power of two. However, not all graphics devices + * supports non-power-of-two textures. If non-power-of-two texture mapping is + * unsupported on a particular Canvas3D, textures with a width or height that + * are not an exact power of two are ignored for that canvas. + * + * @see Canvas3D#queryProperties + */ +public abstract class Texture extends NodeComponent { + /** + * Specifies that this Texture object allows reading its + * enable flag. + */ + public static final int + ALLOW_ENABLE_READ = CapabilityBits.TEXTURE_ALLOW_ENABLE_READ; + + /** + * Specifies that this Texture object allows writing its + * enable flag. + */ + public static final int + ALLOW_ENABLE_WRITE = CapabilityBits.TEXTURE_ALLOW_ENABLE_WRITE; + + /** + * Specifies that this Texture object allows reading its + * boundary mode information. + */ + public static final int + ALLOW_BOUNDARY_MODE_READ = CapabilityBits.TEXTURE_ALLOW_BOUNDARY_MODE_READ; + + /** + * Specifies that this Texture object allows reading its + * filter information. + */ + public static final int + ALLOW_FILTER_READ = CapabilityBits.TEXTURE_ALLOW_FILTER_READ; + + /** + * Specifies that this Texture object allows reading its + * image component information. + */ + public static final int + ALLOW_IMAGE_READ = CapabilityBits.TEXTURE_ALLOW_IMAGE_READ; + + /** + * Specifies that this Texture object allows writing its + * image component information. + * + * @since Java 3D 1.2 + */ + public static final int + ALLOW_IMAGE_WRITE = CapabilityBits.TEXTURE_ALLOW_IMAGE_WRITE; + + /** + * Specifies that this Texture object allows reading its + * format information. + * + * @since Java 3D 1.2 + */ + public static final int + ALLOW_FORMAT_READ = CapabilityBits.TEXTURE_ALLOW_FORMAT_READ; + + /** + * Specifies that this Texture object allows reading its + * size information (e.g., width, height, number of mipmap levels, + * boundary width). + * + * @since Java 3D 1.2 + */ + public static final int + ALLOW_SIZE_READ = CapabilityBits.TEXTURE_ALLOW_SIZE_READ; + + /** + * Specifies that this Texture object allows reading its + * mipmap mode information. + */ + public static final int + ALLOW_MIPMAP_MODE_READ = CapabilityBits.TEXTURE_ALLOW_MIPMAP_MODE_READ; + + /** + * Specifies that this Texture object allows reading its + * boundary color information. + */ + public static final int + ALLOW_BOUNDARY_COLOR_READ = CapabilityBits.TEXTURE_ALLOW_BOUNDARY_COLOR_READ; + + /** + * Specifies that this Texture object allows reading its LOD range + * information (e.g., base level, maximum level, minimum lod, + * maximum lod, lod offset) + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_LOD_RANGE_READ = CapabilityBits.TEXTURE_ALLOW_LOD_RANGE_READ; + + /** + * Specifies that this Texture object allows writing its LOD range + * information (e.g., base level, maximum level, minimum lod, + * maximum lod, lod offset) + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_LOD_RANGE_WRITE = CapabilityBits.TEXTURE_ALLOW_LOD_RANGE_WRITE; + + + /** + * Specifies that this Texture object allows reading its anistropic + * filter information (e.g., anisotropic mode, anisotropic filter) + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_ANISOTROPIC_FILTER_READ = CapabilityBits.TEXTURE_ALLOW_ANISOTROPIC_FILTER_READ; + + /** + * Specifies that this Texture object allows reading its sharpen + * texture function information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_SHARPEN_TEXTURE_READ = CapabilityBits.TEXTURE_ALLOW_SHARPEN_TEXTURE_READ; + + /** + * Specifies that this Texture object allows reading its filter4 + * function information. + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_FILTER4_READ = CapabilityBits.TEXTURE_ALLOW_FILTER4_READ; + + + /** + * Uses the fastest available method for processing geometry. + * This value can be used as a parameter to setMinFilter and + * setMagFilter. + * @see #setMinFilter + * @see #setMagFilter + */ + public static final int FASTEST = 0; + /** + * Uses the nicest available method for processing geometry. + * This value can be used as a parameter to setMinFilter and + * setMagFilter. + * @see #setMinFilter + * @see #setMagFilter + */ + public static final int NICEST = 1; + + /** + * Select the nearest texel in level 0 texture map. + * Maps to NEAREST. + * @see #setMinFilter + * @see #setMagFilter + */ + public static final int BASE_LEVEL_POINT = 2; + + /** + * Performs bilinear interpolation on the four nearest texels + * in level 0 texture map. + * Maps to LINEAR. + * @see #setMinFilter + * @see #setMagFilter + */ + public static final int BASE_LEVEL_LINEAR = 3; + + /** + * Selects the nearest texel in the nearest mipmap. + * Maps to NEAREST_MIPMAP_NEAREST. + * @see #setMinFilter + */ + public static final int MULTI_LEVEL_POINT = 4; + + /** + * Performs tri-linear interpolation of texels between four + * texels each from two nearest mipmap levels. + * Maps to LINEAR_MIPMAP_LINEAR, but an implementation can + * fall back to LINEAR_MIPMAP_NEAREST or NEAREST_MIPMAP_LINEAR. + * @see #setMinFilter + */ + public static final int MULTI_LEVEL_LINEAR = 5; + + // NOTE: values 6, 7, and 8 are reserved for the LINEAR_DETAIL* + // filter modes in Texture2D + + /** + * Sharpens the resulting image by extrapolating + * from the base level plus one image to the base level image of this + * texture object. + * + * @since Java 3D 1.3 + * @see #setMagFilter + */ + public static final int LINEAR_SHARPEN = 9; + + /** + * Performs linear sharpen filter for the rgb + * components only. The alpha component is computed using + * BASE_LEVEL_LINEAR filter. + * + * @since Java 3D 1.3 + * @see #setMagFilter + */ + public static final int LINEAR_SHARPEN_RGB = 10; + + /** + * Performs linear sharpen filter for the alpha + * component only. The rgb components are computed using + * BASE_LEVEL_LINEAR filter. + * + * @since Java 3D 1.3 + * @see #setMagFilter + */ + public static final int LINEAR_SHARPEN_ALPHA = 11; + + /** + * Applies an application-supplied weight function + * on the nearest 4x4 texels in the base level texture image. + * + * @since Java 3D 1.3 + * @see #setMinFilter + * @see #setMagFilter + */ + public static final int FILTER4 = 12; + + // Texture boundary mode parameter values + /** + * Clamps texture coordinates to be in the range [0, 1]. + * Texture boundary texels or the constant boundary color if boundary + * width is 0 will be used for U,V values that fall + * outside this range. + */ + public static final int CLAMP = 2; + /** + * Repeats the texture by wrapping texture coordinates that are outside + * the range [0,1]. Only the fractional portion of the texture + * coordinates is used; the integer portion is discarded. + */ + public static final int WRAP = 3; + /** + * Clamps texture coordinates such that filtering + * will not sample a texture boundary texel. Texels at the edge of the + * texture will be used instead. + * + * @since Java 3D 1.3 + */ + public static final int CLAMP_TO_EDGE = 4; + /** + * Clamps texture coordinates such that filtering + * will sample only texture boundary texels. If the texture does not + * have a boundary, that is the boundary width is equal to 0, then the + * constant boundary color will be used.

+ * + * @since Java 3D 1.3 + */ + public static final int CLAMP_TO_BOUNDARY = 5; + + + /** + * Indicates that Texture object only has one level. If multiple + * levels are needed, they will be implicitly computed. + */ + public static final int BASE_LEVEL = 1; + + /** + * Indicates that this Texture object has multiple images, one for + * each mipmap level. In this mode, there are + * log2(max(width,height))+1 + * separate images. + */ + public static final int MULTI_LEVEL_MIPMAP = 2; + + // Texture format parameter values + + /** + * Specifies Texture contains only Intensity values. + */ + public static final int INTENSITY = 1; + + /** + * Specifies Texture contains only luminance values. + */ + public static final int LUMINANCE = 2; + + /** + * Specifies Texture contains only Alpha values. + */ + public static final int ALPHA = 3; + + /** + * Specifies Texture contains Luminance and Alpha values. + */ + public static final int LUMINANCE_ALPHA = 4; + + /** + * Specifies Texture contains Red, Green and Blue color values. + */ + public static final int RGB = 5; + + /** + * Specifies Texture contains Red, Green, Blue color values + * and Alpha value. + */ + public static final int RGBA = 6; + + /** + * No anisotropic filter. + * + * @since Java 3D 1.3 + * @see #setAnisotropicFilterMode + */ + public static final int ANISOTROPIC_NONE = 0; + + /** + * Uses the degree of anisotropy in both the minification and + * magnification filters. + * + * @since Java 3D 1.3 + * @see #setAnisotropicFilterMode + */ + public static final int ANISOTROPIC_SINGLE_VALUE = 1; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_ANISOTROPIC_FILTER_READ, + ALLOW_BOUNDARY_COLOR_READ, + ALLOW_BOUNDARY_MODE_READ, + ALLOW_ENABLE_READ, + ALLOW_FILTER4_READ, + ALLOW_FILTER_READ, + ALLOW_FORMAT_READ, + ALLOW_IMAGE_READ, + ALLOW_LOD_RANGE_READ, + ALLOW_MIPMAP_MODE_READ, + ALLOW_SHARPEN_TEXTURE_READ, + ALLOW_SIZE_READ + }; + + /** + * Constructs a Texture object with default parameters. + * The default values are as follows: + *
    + * enable flag : true
    + * width : 0
    + * height : 0
    + * mipmap mode : BASE_LEVEL
    + * format : RGB
    + * boundary mode S : WRAP
    + * boundary mode T : WRAP
    + * min filter : BASE_LEVEL_POINT
    + * mag filter : BASE_LEVEL_POINT
    + * boundary color : black (0,0,0,0)
    + * boundary width : 0
    + * array of images : null
    + * baseLevel : 0
    + * maximumLevel : log2(max(width,height))
    + * minimumLOD : -1000.0
    + * maximumLOD : 1000.0
    + * lod offset : (0, 0, 0)
    + * anisotropic mode : ANISOTROPIC_NONE
    + * anisotropic filter : 1.0
    + * sharpen texture func: null
    + * filter4 func: null
    + *
+ *

+ * Note that the default constructor creates a texture object with + * a width and height of 0 and is, therefore, not useful. + */ + public Texture() { + // Just use default values + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs an empty Texture object with specified mipMapMode, + * format, width and height. Defaults are used for all other + * parameters. If mipMapMode is set to + * BASE_LEVEL, then the image at level 0 must be set + * by the application (using either the setImage or + * setImages method). If mipMapMode is + * set to MULTI_LEVEL_MIPMAP, then images for levels + * Base Level through Maximum Level must be set. + * Note that a texture with a non-power-of-two width or height will + * only be rendered on a graphics device that supports non-power-of-two + * textures. + * + * @param mipMapMode type of mipmap for this Texture: one of + * BASE_LEVEL, MULTI_LEVEL_MIPMAP + * @param format data format of Textures saved in this object. + * One of INTENSITY, LUMINANCE, ALPHA, LUMINANCE_ALPHA, RGB, RGBA + * @param width width of image at level 0. + * @param height height of image at level 0. + * @exception IllegalArgumentException if width or height are not greater + * than 0, or if an invalid format or mipMapMode is specified. + */ + public Texture(int mipMapMode, + int format, + int width, + int height) { + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + if ((mipMapMode != BASE_LEVEL) && (mipMapMode != MULTI_LEVEL_MIPMAP)) + throw new IllegalArgumentException(J3dI18N.getString("Texture0")); + + if ((format != INTENSITY) && (format != LUMINANCE) && + (format != ALPHA) && (format != LUMINANCE_ALPHA) && + (format != RGB) && (format != RGBA)) { + throw new IllegalArgumentException(J3dI18N.getString("Texture1")); + } + + if (width < 1) { + throw new IllegalArgumentException(J3dI18N.getString("Texture46")); + } + + if (height < 1) { + throw new IllegalArgumentException(J3dI18N.getString("Texture47")); + } + + int widthLevels; + int heightLevels; + + widthLevels = getLevelsNPOT(width); + heightLevels = getLevelsNPOT(height); + + ((TextureRetained)this.retained).initialize(format, width, widthLevels, + height, heightLevels, mipMapMode, 0); + } + + /** + * Constructs an empty Texture object with specified mipMapMode, + * format, width, height, and boundaryWidth. + * Defaults are used for all other + * parameters. If mipMapMode is set to + * BASE_LEVEL, then the image at level 0 must be set + * by the application (using either the setImage or + * setImages method). If mipMapMode is + * set to MULTI_LEVEL_MIPMAP, then images for levels + * Base Level through Maximum Level must be set. + * Note that a texture with a non-power-of-two width or height will + * only be rendered on a graphics device that supports non-power-of-two + * textures. + * + * @param mipMapMode type of mipmap for this Texture: one of + * BASE_LEVEL, MULTI_LEVEL_MIPMAP + * @param format data format of Textures saved in this object. + * One of INTENSITY, LUMINANCE, ALPHA, LUMINANCE_ALPHA, RGB, RGBA + * @param width width of image at level 0. This + * does not include the width of the boundary. + * @param height height of image at level 0. This + * does not include the width of the boundary. + * @param boundaryWidth width of the boundary, which must be 0 or 1. + * @exception IllegalArgumentException if width or height are not greater + * than 0, if an invalid format or mipMapMode is specified, or + * if the boundaryWidth is < 0 or > 1 + * + * @since Java 3D 1.3 + */ + public Texture(int mipMapMode, + int format, + int width, + int height, + int boundaryWidth) { + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + if ((mipMapMode != BASE_LEVEL) && (mipMapMode != MULTI_LEVEL_MIPMAP)) + throw new IllegalArgumentException(J3dI18N.getString("Texture0")); + + if ((format != INTENSITY) && (format != LUMINANCE) && + (format != ALPHA) && (format != LUMINANCE_ALPHA) && + (format != RGB) && (format != RGBA)) { + throw new IllegalArgumentException(J3dI18N.getString("Texture1")); + } + + if (width < 1) { + throw new IllegalArgumentException(J3dI18N.getString("Texture46")); + } + + if (height < 1) { + throw new IllegalArgumentException(J3dI18N.getString("Texture47")); + } + + int widthLevels; + int heightLevels; + + widthLevels = getLevelsNPOT(width); + heightLevels = getLevelsNPOT(height); + + if (boundaryWidth < 0 || boundaryWidth > 1) + throw new IllegalArgumentException(J3dI18N.getString("Texture30")); + + ((TextureRetained)this.retained).initialize(format, width, widthLevels, + height, heightLevels, mipMapMode, boundaryWidth); + } + + /** + * Sets the boundary mode for the S coordinate in this texture object. + * @param boundaryModeS the boundary mode for the S coordinate. + * One of: CLAMP, WRAP, CLAMP_TO_EDGE, or CLAMP_TO_BOUNDARY. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if boundaryModeS + * is a value other than CLAMP, WRAP, + * CLAMP_TO_EDGE, or CLAMP_TO_BOUNDARY. + */ + public void setBoundaryModeS(int boundaryModeS) { + checkForLiveOrCompiled(); + switch (boundaryModeS) { + case Texture.CLAMP: + case Texture.WRAP: + case Texture.CLAMP_TO_EDGE: + case Texture.CLAMP_TO_BOUNDARY: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("Texture31")); + } + ((TextureRetained)this.retained).initBoundaryModeS(boundaryModeS); + } + + /** + * Retrieves the boundary mode for the S coordinate. + * @return the current boundary mode for the S coordinate. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getBoundaryModeS() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_BOUNDARY_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture4")); + return ((TextureRetained)this.retained).getBoundaryModeS(); + } + + /** + * Sets the boundary mode for the T coordinate in this texture object. + * @param boundaryModeT the boundary mode for the T coordinate. + * One of: CLAMP, WRAP, CLAMP_TO_EDGE, or CLAMP_TO_BOUNDARY. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if boundaryModeT + * is a value other than CLAMP, WRAP, + * CLAMP_TO_EDGE, or CLAMP_TO_BOUNDARY. + */ + public void setBoundaryModeT(int boundaryModeT) { + checkForLiveOrCompiled(); + switch (boundaryModeT) { + case Texture.CLAMP: + case Texture.WRAP: + case Texture.CLAMP_TO_EDGE: + case Texture.CLAMP_TO_BOUNDARY: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("Texture31")); + } + ((TextureRetained)this.retained).initBoundaryModeT(boundaryModeT); + } + + /** + * Retrieves the boundary mode for the T coordinate. + * @return the current boundary mode for the T coordinate. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getBoundaryModeT() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_BOUNDARY_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture4")); + return ((TextureRetained)this.retained).getBoundaryModeT(); + } + + /** + * Sets the minification filter function. This + * function is used when the pixel being rendered maps to an area + * greater than one texel. + * @param minFilter the minification filter. One of: + * FASTEST, NICEST, BASE_LEVEL_POINT, BASE_LEVEL_LINEAR, + * MULTI_LEVEL_POINT, MULTI_LEVEL_LINEAR, or FILTER4 + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if minFilter + * is a value other than FASTEST, NICEST, + * BASE_LEVEL_POINT, BASE_LEVEL_LINEAR, + * MULTI_LEVEL_POINT, MULTI_LEVEL_LINEAR, or + * FILTER4. + * + * @see Canvas3D#queryProperties + */ + public void setMinFilter(int minFilter) { + checkForLiveOrCompiled(); + + switch (minFilter) { + case FASTEST: + case NICEST: + case BASE_LEVEL_POINT: + case BASE_LEVEL_LINEAR: + case MULTI_LEVEL_POINT: + case MULTI_LEVEL_LINEAR: + case FILTER4: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("Texture28")); + } + + ((TextureRetained)this.retained).initMinFilter(minFilter); + } + + /** + * Retrieves the minification filter. + * @return the current minification filter function. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getMinFilter() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_FILTER_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture6")); + return ((TextureRetained)this.retained).getMinFilter(); + } + + /** + * Sets the magnification filter function. This + * function is used when the pixel being rendered maps to an area + * less than or equal to one texel. + * @param magFilter the magnification filter, one of: + * FASTEST, NICEST, BASE_LEVEL_POINT, BASE_LEVEL_LINEAR, + * LINEAR_SHARPEN, LINEAR_SHARPEN_RGB, LINEAR_SHARPEN_ALPHA, or FILTER4. + * + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if magFilter + * is a value other than FASTEST, NICEST, + * BASE_LEVEL_POINT, BASE_LEVEL_LINEAR, + * LINEAR_SHARPEN, LINEAR_SHARPEN_RGB, + * LINEAR_SHARPEN_ALPHA, or + * FILTER4. + * + * @see Canvas3D#queryProperties + */ + public void setMagFilter(int magFilter) { + checkForLiveOrCompiled(); + + switch (magFilter) { + case FASTEST: + case NICEST: + case BASE_LEVEL_POINT: + case BASE_LEVEL_LINEAR: + case LINEAR_SHARPEN: + case LINEAR_SHARPEN_RGB: + case LINEAR_SHARPEN_ALPHA: + case FILTER4: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("Texture29")); + } + + ((TextureRetained)this.retained).initMagFilter(magFilter); + } + + /** + * Retrieves the magnification filter. + * @return the current magnification filter function. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getMagFilter() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_FILTER_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture6")); + return ((TextureRetained)this.retained).getMagFilter(); + } + + /** + * Sets the image for a specified mipmap level. Note that the image size + * must be the correct size for the specified mipmap level. The image size + * of the base level image, that is level 0, must be the same size + * in each dimension (width, height, depth) as this + * texture, excluding the border, if any. + * Each successive mipmap level must be 1/2 the size of the previous level, + * such that size[n] = floor(size[n-1]/2), exluding + * the border. + * + * @param level mipmap level to set: 0 is the base level + * @param image ImageComponent object containing the texture image + * for the specified mipmap level + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if an ImageComponent3D is + * used in a Texture2D object or if an ImageComponent2D is used in a + * Texture3D object. + * + * @exception IllegalArgumentException if the image being set at this + * level is not the correct size for this level. + * + * @exception IllegalSharingException if this Texture is live and + * the specified image is being used by a Canvas3D as an off-screen buffer. + * + * @exception IllegalSharingException if this Texture is + * being used by an immediate mode context and + * the specified image is being used by a Canvas3D as an off-screen buffer. + */ + public void setImage(int level, ImageComponent image) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture15")); + } + + // Do illegal sharing check + validateImageIllegalSharing(image); + + if (isLive()) + ((TextureRetained)this.retained).setImage(level, image); + else + ((TextureRetained)this.retained).initImage(level, image); + } + + /** + * Retrieves the image for a specified mipmap level. + * @param level mipmap level to get: 0 is the base level + * @return the ImageComponent object containing the texture image at + * the specified mipmap level. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ImageComponent getImage(int level) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture9")); + } + + return ((TextureRetained)this.retained).getImage(level); + } + + /** + * Sets the array of images for all mipmap levels. Note that the image size + * of the base level image, images[0], must be the same size + * in each dimension (width, height, depth) as this + * texture, excluding the border, if any. + * Each successive mipmap level must be 1/2 the size of the previous level, + * such that size[n] = floor(size[n-1]/2), exluding + * the border. + * + * @param images array of ImageComponent objects + * containing the texture images for all mipmap levels + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalArgumentException if an ImageComponent3D is + * used in a Texture2D object or if an ImageComponent2D is used in a + * Texture3D object. + * + * @exception IllegalArgumentException if images.length is + * not equal to the total number of mipmap levels. + * + * @exception IllegalArgumentException if the size of each dimension + * of the image at a given level in the + * images array is not the correct size. + * + * @exception IllegalSharingException if this Texture is live and + * any of the specified images are being used by a Canvas3D as an + * off-screen buffer. + * + * @exception IllegalSharingException if this Texture is + * being used by an immediate mode context and + * any of the specified images are being used by a Canvas3D as an + * off-screen buffer. + * + * @since Java 3D 1.2 + */ + public void setImages(ImageComponent[] images) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture15")); + } + + // Do illegal sharing check + for(int i=0; imipMapMode is + * MULTI_LEVEL_MIPMAP; otherwise it returns 1. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int numMipMapLevels() { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_SIZE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture18")); + } + return ((TextureRetained)this.retained).numMipMapLevels(); + } + + /** + * Sets mipmap mode for texture mapping for this texture object. + * @param mipMapMode the new mipmap mode for this object. One of: + * BASE_LEVEL or MULTI_LEVEL_MIPMAP. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if mipMapMode + * is a value other than BASE_LEVEL or + * MULTI_LEVEL_MIPMAP. + */ + public void setMipMapMode(int mipMapMode) { + checkForLiveOrCompiled(); + ((TextureRetained)this.retained).initMipMapMode(mipMapMode); + } + + /** + * Retrieves current mipmap mode. + * @return current mipmap mode of this texture object. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getMipMapMode() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_MIPMAP_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture10")); + return ((TextureRetained)this.retained).getMipMapMode(); + } + + /** + * Enables or disables texture mapping for this + * appearance component object. + * @param state true or false to enable or disable texture mapping + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setEnable(boolean state) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_ENABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture11")); + } + if (isLive()) + ((TextureRetained)this.retained).setEnable(state); + else + ((TextureRetained)this.retained).initEnable(state); + + } + + /** + * Retrieves the state of the texture enable flag. + * @return true if texture mapping is enabled, + * false if texture mapping is disabled + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getEnable() { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_ENABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture12")); + } + return ((TextureRetained)this.retained).getEnable(); + } + + // Internal j3d usage method + // Returns n if num is 2**n + // Returns -1 if num is 0 or negative or if + // num is NOT power of 2. + // NOTE: ********** Assumes 32 bit integer****************** + static int getPowerOf2(int num) { + + int i, tmp; + // Can only handle positive numbers, return error. + if (num < 1) return -1; + + for (i=0, tmp = num; i < 32;i++) { + // Check if leftmost bit is 1 + if ((tmp & 0x80000000) != 0) { + //Check if any other bit is 1 + if ((tmp & 0x7fffffff) == 0) + return 31-i;//valid power of 2 integer + else + return -1;//invalid non-power-of-2 integer + } + tmp <<= 1; + } + //Can't reach here because we have already checked for 0 + return -1; + } + + // returns number of levels using NPOT rules for mipmap generation + // which say that each level should be floor(size/2) of previous level + static int getLevelsNPOT(int num) { + int tmp, levels = 0; + tmp = num; + while (tmp > 1) { + tmp = tmp / 2; + levels++; + } + return levels; + } + + /** + * Sets the texture boundary color for this texture object. The + * texture boundary color is used when boundaryModeS or boundaryModeT + * is set to CLAMP or CLAMP_TO_BOUNDARY and if texture boundary is not + * specified. + * @param boundaryColor the new texture boundary color. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + public void setBoundaryColor(Color4f boundaryColor) { + checkForLiveOrCompiled(); + ((TextureRetained)this.retained).initBoundaryColor(boundaryColor); + } + + /** + * Sets the texture boundary color for this texture object. The + * texture boundary color is used when boundaryModeS or boundaryModeT + * is set to CLAMP or CLAMP_TO_BOUNDARY and if texture boundary is not + * specified. + * @param r the red component of the color. + * @param g the green component of the color. + * @param b the blue component of the color. + * @param a the alpha component of the color. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + public void setBoundaryColor(float r, float g, float b, float a) { + checkForLiveOrCompiled(); + ((TextureRetained)this.retained).initBoundaryColor(r, g, b, a); + } + + /** + * Retrieves the texture boundary color for this texture object. + * @param boundaryColor the vector that will receive the + * current texture boundary color. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getBoundaryColor(Color4f boundaryColor) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_BOUNDARY_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture13")); + } + ((TextureRetained)this.retained).getBoundaryColor(boundaryColor); + } + + /** + * Specifies the base level for this texture object. + * @param baseLevel index of the lowest defined mipmap level. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if specified baseLevel < 0, or + * if baseLevel > maximumLevel + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setBaseLevel(int baseLevel) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture32")); + } + } + + if (isLive()) { + ((TextureRetained)this.retained).setBaseLevel(baseLevel); + } else { + ((TextureRetained)this.retained).initBaseLevel(baseLevel); + } + } + + /** + * Retrieves the base level for this texture object. + * @return base level for this texture object. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getBaseLevel() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture34")); + } + } + return ((TextureRetained)this.retained).getBaseLevel(); + } + + /** + * Specifies the maximum level for this texture object. + * @param maximumLevel index of the highest defined mipmap level. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if specified + * maximumLevel < baseLevel, or + * if maximumLevel > log2(max(width,height)) + * @exception IllegalArgumentException if mipMipMapMode is equal to BASE_LEVEL + * and maximumLevel is not equal to zero. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setMaximumLevel(int maximumLevel) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture33")); + } + } + + if (isLive()) { + ((TextureRetained)this.retained).setMaximumLevel(maximumLevel); + } else { + ((TextureRetained)this.retained).initMaximumLevel(maximumLevel); + } + } + + /** + * Retrieves the maximum level for this texture object. + * @return maximum level for this texture object. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getMaximumLevel() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture35")); + } + } + return ((TextureRetained)this.retained).getMaximumLevel(); + } + + /** + * Specifies the minimum level-of-detail for this texture object. + * @param minimumLod the minimum level-of-detail. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if specified lod > maximum lod + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setMinimumLOD(float minimumLod) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture38")); + } + } + + if (isLive()) { + ((TextureRetained)this.retained).setMinimumLOD(minimumLod); + } else { + ((TextureRetained)this.retained).initMinimumLOD(minimumLod); + } + } + + /** + * Retrieves the minimum level-of-detail for this texture object. + * @return the minimum level-of-detail + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public float getMinimumLOD() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture40")); + } + } + return ((TextureRetained)this.retained).getMinimumLOD(); + } + + /** + * Specifies the maximum level-of-detail for this texture object. + * @param maximumLod the maximum level-of-detail. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if specified lod < minimum lod + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setMaximumLOD(float maximumLod) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture39")); + } + } + + if (isLive()) { + ((TextureRetained)this.retained).setMaximumLOD(maximumLod); + } else { + ((TextureRetained)this.retained).initMaximumLOD(maximumLod); + } + } + + /** + * Retrieves the maximum level-of-detail for this texture object. + * @return the maximum level-of-detail + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public float getMaximumLOD() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture41")); + } + } + return ((TextureRetained)this.retained).getMaximumLOD(); + } + + /** + * Specifies the LOD offset for this texture object. + * @param s the s component of the LOD offset + * @param t the t component of the LOD offset + * @param r the r component of the LOD offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setLodOffset(float s, float t, float r) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture44")); + } + } + + if (isLive()) { + ((TextureRetained)this.retained).setLodOffset(s, t, r); + } else { + ((TextureRetained)this.retained).initLodOffset(s, t, r); + } + } + + /** + * Specifies the LOD offset for this texture object. + * @param offset the LOD offset + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setLodOffset(Tuple3f offset) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture44")); + } + } + + if (isLive()) { + ((TextureRetained)this.retained).setLodOffset( + offset.x, offset.y, offset.z); + } else { + ((TextureRetained)this.retained).initLodOffset( + offset.x, offset.y, offset.z); + } + } + + /** + * Retrieves the LOD offset for this texture object. + * @param offset the vector that will receive the + * current LOD offset. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getLodOffset(Tuple3f offset) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_LOD_RANGE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture45")); + } + } + ((TextureRetained)this.retained).getLodOffset(offset); + } + + /** + * Specifies the anisotropic filter mode for this texture object. + * @param mode the anisotropic filter mode. One of + * ANISOTROPIC_NONE or ANISOTROPIC_SINGLE_VALUE. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if + * mode is a value other than + * ANISOTROPIC_NONE or ANISOTROPIC_SINGLE_VALUE + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setAnisotropicFilterMode(int mode) { + checkForLiveOrCompiled(); + if ((mode != ANISOTROPIC_NONE) && + (mode != ANISOTROPIC_SINGLE_VALUE)) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture25")); + } + ((TextureRetained)this.retained).initAnisotropicFilterMode(mode); + } + + /** + * Retrieves the anisotropic filter mode for this texture object. + * @return the currrent anisotropic filter mode of this texture object. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getAnisotropicFilterMode() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_ANISOTROPIC_FILTER_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture26")); + } + } + return ((TextureRetained)this.retained).getAnisotropicFilterMode(); + } + + /** + * Specifies the degree of anisotropy to be + * used when the anisotropic filter mode specifies + * ANISOTROPIC_SINGLE_VALUE. + * @param degree degree of anisotropy + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if + * degree < 1.0 or + * degree > the maximum degree of anisotropy. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setAnisotropicFilterDegree(float degree) { + checkForLiveOrCompiled(); + if (degree < 1.0) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture27")); + } + ((TextureRetained)this.retained).initAnisotropicFilterDegree(degree); + } + + /** + * Retrieves the anisotropic filter degree for this texture object. + * @return the current degree of anisotropy of this texture object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public float getAnisotropicFilterDegree() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_ANISOTROPIC_FILTER_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture26")); + } + } + return ((TextureRetained)this.retained).getAnisotropicFilterDegree(); + } + + /** + * sets the sharpen texture LOD function for this texture object. + * @param lod array containing the level-of-detail values. + * @param pts array containing the function values for the corresponding + * level-of-detail values. + * + * @exception IllegalStateException if the length of lod + * does not match the length of pts + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setSharpenTextureFunc(float[] lod, float[] pts) { + checkForLiveOrCompiled(); + if (((lod != null) && (pts != null) && (lod.length == pts.length)) || + ((lod == null) && (pts == null))) { + ((TextureRetained)this.retained).initSharpenTextureFunc(lod, pts); + } else { + throw new IllegalStateException( + J3dI18N.getString("Texture22")); + } + } + + /** + * sets the sharpen texture LOD function for this texture object. + * The Point2f x,y values are defined as follows: x is the lod value, + * y is the corresponding function value. + * + * @param pts array of Point2f containing the lod as well as the + * corresponding function value. + * + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setSharpenTextureFunc(Point2f[] pts) { + checkForLiveOrCompiled(); + ((TextureRetained)this.retained).initSharpenTextureFunc(pts); + } + + /** + * Gets the number of points in the sharpen texture LOD function for this + * texture object. + * + * @return the number of points in the sharpen texture LOD function. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getSharpenTextureFuncPointsCount() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_SHARPEN_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture21")); + } + } + return ((TextureRetained)this.retained).getSharpenTextureFuncPointsCount(); + } + + /** + * Copies the array of sharpen texture LOD function points into the + * specified arrays. The arrays must be large enough to hold all the + * points. + * + * @param lod the array to receive the level-of-detail values. + * @param pts the array to receive the function values for the + * corresponding level-of-detail values. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getSharpenTextureFunc(float[] lod, float[] pts) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_SHARPEN_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture21")); + } + } + ((TextureRetained)this.retained).getSharpenTextureFunc( + lod, pts); + } + + /** + * Copies the array of sharpen texture LOD function points including + * the lod values and the corresponding function values into the + * specified array. The array must be large enough to hold all the points. + * The individual array elements must be allocated by the caller as well. + * + * @param pts the array to receive the sharpen texture LOD function points + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getSharpenTextureFunc(Point2f[] pts) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_SHARPEN_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture21")); + } + } + ((TextureRetained)this.retained).getSharpenTextureFunc(pts); + } + + /** + * sets the filter4 function for this texture object. + * @param weights array containing samples of the filter4 function. + * + * @exception IllegalArgumentException if the length of + * weight < 4 + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setFilter4Func(float[] weights) { + checkForLiveOrCompiled(); + if ((weights == null) || (weights.length < 4)) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture24")); + } else { + ((TextureRetained)this.retained).initFilter4Func(weights); + } + } + + /** + * Retrieves the number of filter4 function values for this + * texture object. + * + * @return the number of filter4 function values + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getFilter4FuncPointsCount() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_FILTER4_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture23")); + } + } + return (((TextureRetained)this.retained).getFilter4FuncPointsCount()); + } + + /** + * Copies the array of filter4 function values into the specified + * array. The array must be large enough to hold all the values. + * + * @param weights the array to receive the function values. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getFilter4Func(float[] weights) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_FILTER4_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture23")); + } + } + ((TextureRetained)this.retained).getFilter4Func(weights); + } + + + /** + * Copies all node information from originalNodeComponent + * into the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + Hashtable hashtable = originalNodeComponent.nodeHashtable; + + TextureRetained tex = (TextureRetained) originalNodeComponent.retained; + TextureRetained rt = (TextureRetained) retained; + + rt.initBoundaryModeS(tex.getBoundaryModeS()); + rt.initBoundaryModeT(tex.getBoundaryModeT()); + rt.initMinFilter(tex.getMinFilter()); + rt.initMagFilter(tex.getMagFilter()); + rt.initMipMapMode(tex.getMipMapMode()); + rt.initEnable(tex.getEnable()); + rt.initAnisotropicFilterMode(tex.getAnisotropicFilterMode()); + rt.initAnisotropicFilterDegree(tex.getAnisotropicFilterDegree()); + rt.initSharpenTextureFunc(tex.getSharpenTextureFunc()); + rt.initFilter4Func(tex.getFilter4Func()); + + rt.initBaseLevel(tex.getBaseLevel()); + rt.initMaximumLevel(tex.getMaximumLevel()); + rt.initMinimumLOD(tex.getMinimumLOD()); + rt.initMaximumLOD(tex.getMaximumLOD()); + + Point3f offset = new Point3f(); + tex.getLodOffset(offset); + rt.initLodOffset(offset.x, offset.y, offset.z); + + Color4f c = new Color4f(); + tex.getBoundaryColor(c); + rt.initBoundaryColor(c); + + // No API available to get the current level + for (int i=tex.maxLevels-1; i>=0; i-- ) { + ImageComponent image = (ImageComponent) + getNodeComponent(tex.getImage(i), + forceDuplicate, + hashtable); + if (image != null) { + rt.initImage(i, image); + } + } + // XXXX: clone new v1.2 attributes? + // NOTE: This sppears to have already been done + } + + /** + * This function is called from getNodeComponent() to see if any of + * the sub-NodeComponents duplicateOnCloneTree flag is true. + * If it is the case, current NodeComponent needs to + * duplicate also even though current duplicateOnCloneTree flag is false. + * This should be overwrite by NodeComponent which contains sub-NodeComponent. + */ + boolean duplicateChild() { + if (getDuplicateOnCloneTree()) + return true; + + int level = ((TextureRetained) this.retained).maxLevels; + TextureRetained rt = (TextureRetained) retained; + + for (int i=0; i < level; i++) { + ImageComponent img = rt.getImage(i); + if ((img != null) && img.getDuplicateOnCloneTree()) + return true; + } + return false; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Texture2D.java b/j3d-core/src/classes/share/javax/media/j3d/Texture2D.java new file mode 100644 index 0000000..6cf0994 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Texture2D.java @@ -0,0 +1,572 @@ +/* + * $RCSfile: Texture2D.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + + +/** + * Texture2D is a subclass of Texture class. It extends Texture + * class by adding a constructor and a mutator method for + * setting a 2D texture image. + *

+ * Note that as of Java 3D 1.5, the texture width and height are no longer + * required to be an exact power of two. However, not all graphics devices + * supports non-power-of-two textures. If non-power-of-two texture mapping is + * unsupported on a particular Canvas3D, textures with a width or height that + * are not an exact power of two are ignored for that canvas. + * + * @see Canvas3D#queryProperties + */ +public class Texture2D extends Texture { + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * Specifies that this Texture object allows reading its detail + * texture information (e.g., detail texture image, detail texture mode, + * detail texture function, detail texture function points count, + * detail texture level) + * + * @since Java 3D 1.3 + */ + public static final int + ALLOW_DETAIL_TEXTURE_READ = CapabilityBits.TEXTURE2D_ALLOW_DETAIL_TEXTURE_READ; + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * Performs linear sampling in both the base level + * texture image and the detail texture image, and combines the two + * texture values according to the detail texture mode. + * + * @since Java 3D 1.3 + * @see #setMagFilter + */ + public static final int LINEAR_DETAIL = 6; + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * Performs linear detail for the rgb + * components only. The alpha component is computed using + * BASE_LEVEL_LINEAR filter. + * + * @since Java 3D 1.3 + * @see #setMagFilter + */ + public static final int LINEAR_DETAIL_RGB = 7; + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * Performs linear detail for the alpha + * component only. The rgb components are computed using + * BASE_LEVEL_LINEAR filter. + * + * @since Java 3D 1.3 + * @see #setMagFilter + */ + public static final int LINEAR_DETAIL_ALPHA = 8; + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * Adds the detail texture image to the level 0 image of this texture + * object + * + * @since Java 3D 1.3 + * @see #setDetailTextureMode + */ + public static final int DETAIL_ADD = 0; + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * Modulates the detail texture image with the level 0 image of this + * texture object + * + * @since Java 3D 1.3 + * @see #setDetailTextureMode + */ + public static final int DETAIL_MODULATE = 1; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_DETAIL_TEXTURE_READ + }; + + /** + * Constructs a texture object using default values. + * + * The default values are as follows: + *

    + * detail texture image: null
    + * detail texture mode: DETAIL_MODULATE
    + * detail texture func: null
    + * detail texture level: 2
    + *
+ *

+ * Note that the default constructor creates a texture object with + * a width and height of 0 and is, therefore, not useful. + */ + public Texture2D() { + super(); + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + } + + /** + * Constructs an empty Texture2D object with specified mipmapMode + * format, width and height. Image at base level must be set by + * the application using 'setImage' method. If mipmapMode is + * set to MULTI_LEVEL_MIPMAP, images for base level through maximum level + * must be set. + * Note that a texture with a non-power-of-two width or height will + * only be rendered on a graphics device that supports non-power-of-two + * textures. + * + * @param mipMapMode type of mipmap for this Texture: One of + * BASE_LEVEL, MULTI_LEVEL_MIPMAP. + * @param format data format of Textures saved in this object. + * One of INTENSITY, LUMINANCE, ALPHA, LUMINANCE_ALPHA, RGB, RGBA. + * @param width width of image at level 0. + * @param height height of image at level 0. + * @exception IllegalArgumentException if width or height are NOT + * greater than 0 OR invalid format/mipmapMode is specified. + */ + public Texture2D( + int mipMapMode, + int format, + int width, + int height) { + + super(mipMapMode, format, width, height); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + + /** + * Constructs an empty Texture2D object with specified mipMapMode, + * format, width, height, and boundaryWidth. + * Defaults are used for all other + * parameters. If mipMapMode is set to + * BASE_LEVEL, then the image at level 0 must be set + * by the application (using either the setImage or + * setImages method). If mipMapMode is + * set to MULTI_LEVEL_MIPMAP, then images for levels + * Base Level through Maximum Level must be set. + * Note that a texture with a non-power-of-two width or height will + * only be rendered on a graphics device that supports non-power-of-two + * textures. + * + * @param mipMapMode type of mipmap for this Texture: one of + * BASE_LEVEL, MULTI_LEVEL_MIPMAP + * @param format data format of Textures saved in this object. + * One of INTENSITY, LUMINANCE, ALPHA, LUMINANCE_ALPHA, RGB, RGBA + * @param width width of image at level 0. This + * does not include the width of the boundary. + * @param height height of image at level 0. This + * does not include the width of the boundary. + * @param boundaryWidth width of the boundary, which must be 0 or 1. + * @exception IllegalArgumentException if width or height are not greater + * than 0, if an invalid format or mipMapMode is specified, or + * if the boundaryWidth is < 0 or > 1 + * + * @since Java 3D 1.3 + */ + public Texture2D(int mipMapMode, + int format, + int width, + int height, + int boundaryWidth) { + + super(mipMapMode, format, width, height, boundaryWidth); + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Sets the magnification filter function. This + * function is used when the pixel being rendered maps to an area + * less than or equal to one texel. + * @param magFilter the magnification filter, one of: + * FASTEST, NICEST, BASE_LEVEL_POINT, BASE_LEVEL_LINEAR, + * LINEAR_DETAIL, LINEAR_DETAIL_RGB, LINEAR_DETAIL_ALPHA, + * LINEAR_SHARPEN, LINEAR_SHARPEN_RGB, LINEAR_SHARPEN_ALPHA, or FILTER4. + * + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if minFilter + * is a value other than FASTEST, NICEST, + * BASE_LEVEL_POINT, BASE_LEVEL_LINEAR, + * LINEAR_DETAIL, LINEAR_DETAIL_RGB, + * LINEAR_DETAIL_ALPHA, + * LINEAR_SHARPEN, LINEAR_SHARPEN_RGB, + * LINEAR_SHARPEN_ALPHA, or + * FILTER4. + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setMagFilter(int magFilter) { + checkForLiveOrCompiled(); + + switch (magFilter) { + case FASTEST: + case NICEST: + case BASE_LEVEL_POINT: + case BASE_LEVEL_LINEAR: + case LINEAR_DETAIL: + case LINEAR_DETAIL_RGB: + case LINEAR_DETAIL_ALPHA: + case LINEAR_SHARPEN: + case LINEAR_SHARPEN_RGB: + case LINEAR_SHARPEN_ALPHA: + case FILTER4: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("Texture29")); + } + + ((Texture2DRetained)this.retained).initMagFilter(magFilter); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @param detailTexture ImageComponent2D object containing the + * detail texture image. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setDetailImage(ImageComponent2D detailTexture) { + checkForLiveOrCompiled(); + ((Texture2DRetained)this.retained).initDetailImage(detailTexture); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @return ImageComponent2D object containing the detail texture image. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public ImageComponent2D getDetailImage() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_DETAIL_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture2D0")); + } + } + return ((Texture2DRetained)this.retained).getDetailImage(); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @param mode detail texture mode. One of: DETAIL_ADD or DETAIL_MODULATE + * + * @exception IllegalArgumentException if + * mode is a value other than + * DETAIL_ADD, or DETAIL_MODULATE + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setDetailTextureMode(int mode) { + checkForLiveOrCompiled(); + if ((mode != DETAIL_ADD) && (mode != DETAIL_MODULATE)) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture2D1")); + } + ((Texture2DRetained)this.retained).initDetailTextureMode(mode); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @return the detail texture mode. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getDetailTextureMode() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_DETAIL_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture2D0")); + } + } + return ((Texture2DRetained)this.retained).getDetailTextureMode(); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @param level the detail texture level. + * + * @exception IllegalArgumentException if level < 0 + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setDetailTextureLevel(int level) { + checkForLiveOrCompiled(); + if (level < 0) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture2D2")); + } + ((Texture2DRetained)this.retained).initDetailTextureLevel(level); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @return the detail texture level. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getDetailTextureLevel() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_DETAIL_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture2D0")); + } + } + return ((Texture2DRetained)this.retained).getDetailTextureLevel(); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @param lod array containing the level-of-detail values. + * @param pts array containing the function values for the corresponding + * level-of-detail values. + * + * @exception IllegalStateException if the length of lod + * does not match the length of pts + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setDetailTextureFunc(float[] lod, float[] pts) { + checkForLiveOrCompiled(); + if (((lod != null) && (pts != null) && (lod.length == pts.length)) || + ((lod == null) && (pts == null))) { + ((Texture2DRetained)this.retained).initDetailTextureFunc(lod, pts); + } else { + throw new IllegalStateException(J3dI18N.getString("Texture2D3")); + } + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @param pts array of Point2f containing the lod as well as the + * corresponding function value. + * + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * + * @since Java 3D 1.3 + * @see Canvas3D#queryProperties + */ + public void setDetailTextureFunc(Point2f[] pts) { + checkForLiveOrCompiled(); + ((Texture2DRetained)this.retained).initDetailTextureFunc(pts); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @return the number of points in the detail texture LOD function. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getDetailTextureFuncPointsCount() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_DETAIL_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture2D0")); + } + } + return ((Texture2DRetained)this.retained).getDetailTextureFuncPointsCount(); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @param lod the array to receive the level-of-detail values. + * @param pts the array to receive the function values for the + * corresponding level-of-detail values. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getDetailTextureFunc(float[] lod, float[] pts) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_DETAIL_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture2D0")); + } + } + ((Texture2DRetained)this.retained).getDetailTextureFunc(lod, pts); + } + + /** + * @deprecated As of Java 3D 1.5 the optional detail texture feature is no + * longer supported. + * + * @param pts the array to receive the detail texture LOD function points + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void getDetailTextureFunc(Point2f[] pts) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_DETAIL_TEXTURE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("Texture2D0")); + } + } + ((Texture2DRetained)this.retained).getDetailTextureFunc(pts); + } + + + /** + * Creates a retained mode Texture2DRetained object that this + * Texture2D component object will point to. + */ + void createRetained() { + this.retained = new Texture2DRetained(); + this.retained.setSource(this); + } + + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + Texture2DRetained t2d = (Texture2DRetained) retained; + + Texture2D t = new Texture2D(t2d.getMipMapMode(), t2d.format, + t2d.width, t2d.height); + t.duplicateNodeComponent(this); + return t; + } + + /** + * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @deprecated replaced with duplicateNodeComponent( + * NodeComponent originalNodeComponent, boolean forceDuplicate) + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent) { + checkDuplicateNodeComponent(originalNodeComponent); + } + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + Texture2DRetained tex = (Texture2DRetained) + originalNodeComponent.retained; + Texture2DRetained rt = (Texture2DRetained) retained; + + + rt.initDetailImage(tex.getDetailImage()); + rt.initDetailTextureMode(tex.getDetailTextureMode()); + rt.initDetailTextureLevel(tex.getDetailTextureLevel()); + rt.initDetailTextureFunc(tex.getDetailTextureFunc()); + } +} + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/Texture2DRetained.java b/j3d-core/src/classes/share/javax/media/j3d/Texture2DRetained.java new file mode 100644 index 0000000..0c45373 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Texture2DRetained.java @@ -0,0 +1,208 @@ +/* + * $RCSfile: Texture2DRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; +import javax.vecmath.*; + +/** + * Texture2D is a subclass of Texture class. It extends Texture + * class by adding a constructor and a mutator method for + * setting a 2D texture image. + */ +class Texture2DRetained extends TextureRetained { + + // Note : There is hardly any HW vendor supports detail Image. + // Detail Image operation is simply no-op in 1.5. + + // currently detail image is only applicable to 2D texture + // detail texture info + + // These members are unused except for public set and get methods. + private ImageComponent2DRetained detailImage = null; + private int detailTextureMode = Texture2D.DETAIL_MODULATE; + private int detailTextureLevel = 2; + private int numDetailTextureFuncPts = 0; + private float detailTextureFuncPts[] = null; // array of pairs of floats + // first value for LOD + // second value for the fcn value + + /** + * Set detail texture image + */ + final void initDetailImage(ImageComponent2D image) { + if (image == null) { + detailImage = null; + } else { + detailImage = (ImageComponent2DRetained)image.retained; + } + } + + + /** + * Get detail texture image + */ + final ImageComponent2D getDetailImage() { + if (detailImage != null) { + return (ImageComponent2D)detailImage.source; + } else { + return null; + } + } + + + /** + * Set detail texture mode + */ + final void initDetailTextureMode(int mode) { + detailTextureMode = mode; + } + + + /** + * Get detail texture mode + */ + final int getDetailTextureMode() { + return detailTextureMode; + } + + + /** + * Set detail texture level + */ + final void initDetailTextureLevel(int level) { + detailTextureLevel = level; + } + + + /** + * Get detail texture level + */ + final int getDetailTextureLevel() { + return detailTextureLevel; + } + + + /** + * Set detail texture function + */ + final void initDetailTextureFunc(float[] lod, float[] pts) { + if (lod == null) { // pts will be null too. + detailTextureFuncPts = null; + numDetailTextureFuncPts = 0; + } else { + numDetailTextureFuncPts = lod.length; + if ((detailTextureFuncPts == null) || + (detailTextureFuncPts.length != lod.length * 2)) { + detailTextureFuncPts = new float[lod.length * 2]; + } + for (int i = 0, j = 0; i < lod.length; i++) { + detailTextureFuncPts[j++] = lod[i]; + detailTextureFuncPts[j++] = pts[i]; + } + } + } + + final void initDetailTextureFunc(Point2f[] pts) { + if (pts == null) { + detailTextureFuncPts = null; + numDetailTextureFuncPts = 0; + } else { + numDetailTextureFuncPts = pts.length; + if ((detailTextureFuncPts == null) || + (detailTextureFuncPts.length != pts.length * 2)) { + detailTextureFuncPts = new float[pts.length * 2]; + } + for (int i = 0, j = 0; i < pts.length; i++) { + detailTextureFuncPts[j++] = pts[i].x; + detailTextureFuncPts[j++] = pts[i].y; + } + } + } + + final void initDetailTextureFunc(float[] pts) { + if (pts == null) { + detailTextureFuncPts = null; + numDetailTextureFuncPts = 0; + } else { + numDetailTextureFuncPts = pts.length / 2; + if ((detailTextureFuncPts == null) || + (detailTextureFuncPts.length != pts.length)) { + detailTextureFuncPts = new float[pts.length]; + } + for (int i = 0; i < pts.length; i++) { + detailTextureFuncPts[i] = pts[i]; + } + } + } + + /** + * Get number of points in the detail texture LOD function + */ + final int getDetailTextureFuncPointsCount() { + return numDetailTextureFuncPts; + } + + + /** + * Copies the array of detail texture LOD function points into the + * specified arrays + */ + final void getDetailTextureFunc(float[] lod, float[] pts) { + if (detailTextureFuncPts != null) { + for (int i = 0, j = 0; i < numDetailTextureFuncPts; i++) { + lod[i] = detailTextureFuncPts[j++]; + pts[i] = detailTextureFuncPts[j++]; + } + } + } + + final void getDetailTextureFunc(Point2f[] pts) { + if (detailTextureFuncPts != null) { + for (int i = 0, j = 0; i < numDetailTextureFuncPts; i++) { + pts[i].x = detailTextureFuncPts[j++]; + pts[i].y = detailTextureFuncPts[j++]; + } + } + } + + + /** + * internal method only -- returns the detail texture LOD function + */ + final float[] getDetailTextureFunc() { + return detailTextureFuncPts; + } + + +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/Texture3D.java b/j3d-core/src/classes/share/javax/media/j3d/Texture3D.java new file mode 100644 index 0000000..d800efe --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Texture3D.java @@ -0,0 +1,267 @@ +/* + * $RCSfile: Texture3D.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Texture3D is a subclass of Texture class. It extends Texture + * class by adding a third coordinate, constructor and a mutator + * method for setting a 3D texture image. + * If 3D texture mapping is not supported on a particular Canvas3D, + * 3D texture mapping is ignored for that canvas. + * + *

+ * Note that as of Java 3D 1.5, the texture width, height, and depth + * are no longer + * required to be an exact power of two. However, not all graphics devices + * supports non-power-of-two textures. If non-power-of-two texture mapping is + * unsupported on a particular Canvas3D, textures with a width, height, + * or depth that are not an exact power of two are ignored for that canvas. + * + * @see Canvas3D#queryProperties + */ + +public class Texture3D extends Texture { + + // TODO KCR : NPOT + + /** + * Constructs a Texture3D object with default parameters. + * The default values are as follows: + *

    + * depth : 0
    + * boundary mode R : WRAP
    + *
+ *

+ * Note that the default constructor creates a texture object with + * a width, height, and depth of 0 and is, therefore, not useful. + */ + public Texture3D() { + super(); + } + + /** + * Constructs an empty Texture3D object with specified mipmapMode + * format, width, height, and depth. Image at base level must be set by + * the application using 'setImage' method. If mipmapMode is + * set to MULTI_LEVEL_MIPMAP, images for base level through + * maximum level must be set. + * Note that a texture with a non-power-of-two width, height, or depth will + * only be rendered on a graphics device that supports non-power-of-two + * textures. + * + * @param mipmapMode type of mipmap for this Texture: One of + * BASE_LEVEL, MULTI_LEVEL_MIPMAP. + * @param format data format of Textures saved in this object. + * One of INTENSITY, LUMINANCE, ALPHA, LUMINANCE_ALPHA, RGB, RGBA. + * @param width width of image at level 0. + * @param height height of image at level 0. + * @param depth depth of image at level 0. + * @exception IllegalArgumentException if width, height, or depth are not + * greater than 0 OR invalid format/mipmapMode is specified. + */ + public Texture3D(int mipmapMode, + int format, + int width, + int height, + int depth) { + + super(mipmapMode, format, width, height); + + int depthLevels = -1; + + depthLevels = getLevelsNPOT(depth); + + // TODO : Need to verify whether this is a bug. Why depthLevels isn't + // use to determine maxMipMapLevels ? See also Texture.java + + ((Texture3DRetained)this.retained).setDepth(depth); + } + + /** + * Constructs an empty Texture3D object with specified mipmapMode + * format, width, height, depth, and boundaryWidth. + * Image at base level must be set by + * the application using 'setImage' method. If mipmapMode is + * set to MULTI_LEVEL_MIPMAP, images for base level through + * maximum level must be set. + * Note that a texture with a non-power-of-two width, height, or depth will + * only be rendered on a graphics device that supports non-power-of-two + * textures. + * + * @param mipmapMode type of mipmap for this Texture: One of + * BASE_LEVEL, MULTI_LEVEL_MIPMAP. + * @param format data format of Textures saved in this object. + * One of INTENSITY, LUMINANCE, ALPHA, LUMINANCE_ALPHA, RGB, RGBA. + * @param width width of image at level 0. This + * does not include the width of the boundary. + * @param height height of image at level 0. This + * does not include the width of the boundary. + * @param depth depth of image at level 0. This + * does not include the width of the boundary. + * @param boundaryWidth width of the boundary, which must be 0 or 1. + * @exception IllegalArgumentException if width, height, or depth are not + * greater than 0 OR invalid format/mipmapMode is specified, or + * if the boundaryWidth is < 0 or > 1 + * + * @since Java 3D 1.3 + */ + public Texture3D(int mipmapMode, + int format, + int width, + int height, + int depth, + int boundaryWidth) { + + super(mipmapMode, format, width, height, boundaryWidth); + int depthLevels = -1; + + depthLevels = getLevelsNPOT(depth); + + // TODO : Need to verify whether this is a bug. Why depthLevels isn't + // use to determine maxMipMapLevels ? See also Texture.java + + ((Texture3DRetained)this.retained).setDepth(depth); + } + + /** + * Sets the boundary mode for the R coordinate in this texture object. + * @param boundaryModeR the boundary mode for the R coordinate, + * one of: CLAMP, WRAP, CLAMP_TO_EDGE, or CLAMP_TO_BOUNDARY + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if boundaryModeR + * is a value other than CLAMP, WRAP, + * CLAMP_TO_EDGE, or CLAMP_TO_BOUNDARY. + */ + public void setBoundaryModeR(int boundaryModeR) { + checkForLiveOrCompiled(); + switch (boundaryModeR) { + case Texture.CLAMP: + case Texture.WRAP: + case Texture.CLAMP_TO_EDGE: + case Texture.CLAMP_TO_BOUNDARY: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("Texture31")); + } + ((Texture3DRetained)this.retained).initBoundaryModeR(boundaryModeR); + } + + /** + * Retrieves the boundary mode for the R coordinate. + * @return the current boundary mode for the R coordinate. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + public int getBoundaryModeR() { + if (isLiveOrCompiled()) + if(!this.getCapability(Texture.ALLOW_BOUNDARY_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture3D0")); + return ((Texture3DRetained)this.retained).getBoundaryModeR(); + } + + /** + * Retrieves the depth of this Texture3D object. + * @return the depth of this Texture3D object. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getDepth() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_SIZE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Texture3D2")); + + return ((Texture3DRetained)this.retained).getDepth(); + } + + /** + * Creates a retained mode Texture3DRetained object that this + * Texture3D component object will point to. + */ + void createRetained() { + this.retained = new Texture3DRetained(); + this.retained.setSource(this); + } + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + Texture3DRetained t3d = (Texture3DRetained) retained; + Texture3D t = new Texture3D(t3d.getMipMapMode(), t3d.format, + t3d.width, t3d.height, t3d.depth); + t.duplicateNodeComponent(this); + return t; + } + + + /** + * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @deprecated replaced with duplicateNodeComponent( + * NodeComponent originalNodeComponent, boolean forceDuplicate) + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent) { + checkDuplicateNodeComponent(originalNodeComponent); + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + ((Texture3DRetained) retained).initBoundaryModeR(((Texture3DRetained) + originalNodeComponent.retained).getBoundaryModeR()); + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/Texture3DRetained.java b/j3d-core/src/classes/share/javax/media/j3d/Texture3DRetained.java new file mode 100644 index 0000000..67064d0 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/Texture3DRetained.java @@ -0,0 +1,256 @@ +/* + * $RCSfile: Texture3DRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.Enumeration; +import java.util.BitSet; + +/** + * Texture3D is a subclass of Texture class. It extends Texture + * class by adding a third co-ordinate, constructor and a mutator + * method for setting a 3D texture image. + */ + +class Texture3DRetained extends TextureRetained { + // Boundary mode for R coordinate (wrap, clamp) + int boundaryModeR = Texture.WRAP; + int depth = 1; // Depth (num slices) of texture map (2**p) + + final void setDepth(int depth) { + this.depth = depth; + } + + final int getDepth() { + return this.depth; + } + + /** + * Sets the boundary mode for the R coordinate in this texture object. + * @param boundaryModeR the boundary mode for the R coordinate, + * one of: CLAMP or WRAP. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final void initBoundaryModeR(int boundaryModeR) { + this.boundaryModeR = boundaryModeR; + } + + /** + * Retrieves the boundary mode for the R coordinate. + * @return the current boundary mode for the R coordinate. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final int getBoundaryModeR() { + return boundaryModeR; + } + + /** + * This method updates the native context. + */ + void bindTexture(Context ctx, int objectId, boolean enable) { + Pipeline.getPipeline().bindTexture3D(ctx, objectId, enable); + } + + void updateTextureBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + int boundaryModeR, float boundaryRed, + float boundaryGreen, float boundaryBlue, + float boundaryAlpha) { + + Pipeline.getPipeline().updateTexture3DBoundary(ctx, + boundaryModeS, boundaryModeT, boundaryModeR, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTextureFilterModes(Context ctx, + int minFilter, int magFilter) { + + Pipeline.getPipeline().updateTexture3DFilterModes(ctx, + minFilter, magFilter); + } + + void updateTextureSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + + Pipeline.getPipeline().updateTexture3DSharpenFunc(ctx, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTextureFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + + Pipeline.getPipeline().updateTexture3DFilter4Func(ctx, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTextureAnisotropicFilter(Context ctx, float degree) { + Pipeline.getPipeline().updateTexture3DAnisotropicFilter(ctx, degree); + } + + + + // Wrapper around the native call for 3D textures + void updateTextureImage(Canvas3D cv, + int face, int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, int depth, + int boundaryWidth, int imageDataType, + Object imageData) { + + Pipeline.getPipeline().updateTexture3DImage(cv.ctx, + numLevels, level, + textureFormat, imageFormat, + width, height, depth, + boundaryWidth, imageDataType, imageData, useAutoMipMapGeneration(cv)); + } + + // Wrapper around the native call for 3D textures + void updateTextureSubImage(Canvas3D cv, + int face, int level, + int xoffset, int yoffset, int zoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, int imgZOffset, + int tilew, int tileh, int width, int height, int depth, + int imageDataType, Object imageData) { + + Pipeline.getPipeline().updateTexture3DSubImage(cv.ctx, + level, xoffset, yoffset, zoffset, + textureFormat, imageFormat, + imgXOffset, imgYOffset, imgZOffset, + tilew, tileh, width, height, depth, + imageDataType, imageData, useAutoMipMapGeneration(cv)); + } + + + // get an ID for Texture3D + + int getTextureId() { + return (VirtualUniverse.mc.getTexture3DId()); + } + + + // get a Texture3D Id + + void freeTextureId(int id) { + synchronized (resourceLock) { + if (objectId == id) { + objectId = -1; + VirtualUniverse.mc.freeTexture3DId(id); + } + } + } + + + // load level 0 image with null data pointer, just to enable + // mipmapping when level 0 is not the base level + + void updateTextureDimensions(Canvas3D cv) { + if(images[0][0] != null) { + updateTextureImage(cv, maxLevels, 0, 0, + format, images[0][0].getImageFormatTypeIntValue(false), + width, height, depth, boundaryWidth, + images[0][0].getImageDataTypeIntValue(), null); + } + } + + + void updateTextureBoundary(Canvas3D cv) { + updateTextureBoundary(cv.ctx, + boundaryModeS, boundaryModeT, boundaryModeR, + boundaryColor.x, boundaryColor.y, + boundaryColor.z, boundaryColor.w); + } + + void updateTextureLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + + Pipeline.getPipeline().updateTexture3DLodRange(ctx, baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + void updateTextureLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + + Pipeline.getPipeline().updateTexture3DLodOffset(ctx, + lodOffsetX, lodOffsetY, lodOffsetZ); + } + + void reloadTextureImage(Canvas3D cv, int face, int level, + ImageComponentRetained image, int numLevels) { + +/* + System.err.println("Texture3D.reloadTextureImage: level= " + level + + " image.imageYup= " + image.imageYup + " w= " + image.width + + " h= " + image.height + " d= " + depth + + " numLevels= " + numLevels); +*/ + + // Texture3D does not need to support Raster + ImageComponentRetained.ImageData imageData = image.getImageData(false); + + updateTextureImage(cv, + 0, numLevels, level, format, + image.getImageFormatTypeIntValue(false), + image.width, image.height, depth, + boundaryWidth, image.getImageDataTypeIntValue(), + imageData.get()); + } + + void reloadTextureSubImage(Canvas3D cv, int level, int face, + ImageComponentUpdateInfo info, + ImageComponentRetained image) { + int x = info.x, + y = info.y, + z = info.z, + width = info.width, + height = info.height; + + int xoffset = x; + int yoffset = y; + // Texture3D does not need to support Raster + ImageComponentRetained.ImageData imageData = image.getImageData(false); + + updateTextureSubImage(cv, + 0, level, xoffset, yoffset, z, + format, image.getImageFormatTypeIntValue(false), + xoffset, yoffset, z, + image.width, image.height, + width, height, 1, image.getImageDataTypeIntValue(), + imageData.get()); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TextureAttributes.java b/j3d-core/src/classes/share/javax/media/j3d/TextureAttributes.java new file mode 100644 index 0000000..8918f6e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TextureAttributes.java @@ -0,0 +1,1436 @@ +/* + * $RCSfile: TextureAttributes.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color4f; + +/** + * The TextureAttributes object defines attributes that apply to + * texture mapping. + * The texture attributes include the following:

+ *

    + *
  • Texture mode - defines how the object and texture colors + * are blended. The mode may be one of the following:
  • + *

      + *
    • MODULATE - modulates the incoming color with the texture + * color.

      + *

        + * C' = C Ct + *
    • + *

    • DECAL - applies the texture color to the incoming color as a decal.

      + *

        + * C'rgb = Crgb (1 - Cta) + Ctrgb Cta

        + * C'a = Ca + *

    • + *

    • BLEND - blends the texture blend color with the incoming color.

      + *

        + * C'rgb = Crgb (1 - Ctrgb) + Cbrgb Ctrgb

        + * C'a = Ca Cta

        + *

      + * Note that if the texture format is INTENSITY, alpha is computed identically + * to red, green, and blue:

      + *

        + * C'a = Ca (1 - Cta) + Cba Cta + *
    • + *

    • REPLACE - replaces the incoming color with the texture color.

      + *

        + * C' = Ct

        + *

    • + *

    • COMBINE - combines the object color with the texture color or texture + * blend color according to the combine operation as specified in the + * texture combine mode.
    • + *

      + *

    + * C = Incoming color to the texture unit state. For texture unit state 0, C is the object color + * Ct = Texture color
    + * Cb = Texture blend color
    + *

    + *

  • Combine Mode - defines the combine operation when texture mode + * specifies COMBINE. The combine mode includes the following:

    + *

      + *
    • COMBINE_REPLACE

      + *

        + * C' = C0

        + *

    • + *

    • COMBINE_MODULATE

      + *

        + * C' = C0 C1 + *
    • + *

    • COMBINE_ADD

      + *

        + * C' = C0 + C1

        + *

    • + *

    • COMBINE_ADD_SIGNED

      + *

        + * C' = C0 + C1 - 0.5

        + *

    • + *

    • COMBINE_SUBTRACT

      + *

        + * C' = C0 - C1

        + *

    • + *

    • COMBINE_INTERPOLATE

      + *

        + * C' = C0 C2 + C1 (1 - C2)

        + *

    • + *

    • COMBINE_DOT3

      + *

        + * C' = 4 * ( + * (C0r - 0.5) * (C1r - 0.5) + + * (C0g - 0.5) * (C1g - 0.5) + + * (C0b - 0.5) * (C1b - 0.5))

        + * where CNx is the x component of the Nth color operand + * in the combine operation.

        + * The value C' will be placed to the all three r,g,b components or the + * a component of the output. + *

    • + *

  • + * where C0, C1 and C2 are determined by + * the color source, and the color operand. + *

+ *

    + *
  • Combine Color Source - defines the source for a color operand in the + * combine operation. The color source includes the following:

    + *

      + *
    • COMBINE_OBJECT_COLOR - object color

      + *

    • COMBINE_TEXTURE_COLOR - texture color

      + *

    • COMBINE_CONSTANT_COLOR - texture blend color

      + *

    • COMBINE_PREVIOUS_TEXTURE_UNIT_STATE - color from the previous texture + * unit state. For texture unit state 0, this is equivalent to + * COMBINE_OBJECT_COLOR.

      + *

  • + *

  • Combine Color Function - specifies the function for a color operand + * in the combine operation. The valid values are:

    + *

      + *
    • COMBINE_SRC_COLOR - the color function is f = Crgb

      + *

    • COMBINE_ONE_MINUS_SRC_COLOR - the color function is f = (1 - Crgb)

      + *

    • COMBINE_SRC_ALPHA - the color function is f = Ca

      + *

    • COMBINE_ONE_MINUS_SRC_ALPHA - the color function is f = (1 - Ca)

      + *

  • + *

  • Combine scale factor - specifies the scale factor to be applied to + * the output color of the combine operation. The valid values include: + * 1, 2, or 4.
  • + *

  • Transform - the texture transform object used to transform + * texture coordinates. The texture transform can translate, scale, + * or rotate the texture coordinates before the texture is applied + * to the object.
  • + *

  • Blend color - the constant texture blend color
  • + *

  • Perspective correction - the perspective correction mode + * used for color and texture coordinate interpolation. One of + * the following:
  • + *

      + *
    • NICEST - uses the nicest (highest quality) available + * method for texture mapping perspective correction.
    • + *

    • FASTEST - uses the fastest available method for texture + * mapping perspective correction.
    • + *

    + *
  • Texture color table - defines a table that is used to look up + * texture colors before applying the texture mode.
  • + *
+ * + * @see Appearance + * @see Canvas3D#queryProperties + */ +public class TextureAttributes extends NodeComponent { + /** + * Specifies that this TextureAttributes object allows + * reading its texture mode component + * information and perspective correction mode. + */ + public static final int + ALLOW_MODE_READ = CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_MODE_READ; + + /** + * Specifies that this TextureAttributes object allows + * writing its texture mode component + * information and perspective correction mode. + */ + public static final int + ALLOW_MODE_WRITE = CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_MODE_WRITE; + + /** + * Specifies that this TextureAttributes object allows + * reading its texture blend color component + * information. + */ + public static final int + ALLOW_BLEND_COLOR_READ = CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_BLEND_COLOR_READ; + + /** + * Specifies that this TextureAttributes object allows + * writing its texture blend color component + * information. + */ + public static final int + ALLOW_BLEND_COLOR_WRITE = CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_BLEND_COLOR_WRITE; + + /** + * Specifies that this TextureAttributes object allows + * reading its texture transform component + * information. + */ + public static final int + ALLOW_TRANSFORM_READ = CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_TRANSFORM_READ; + + /** + * Specifies that this TextureAttributes object allows + * writing its texture transform component + * information. + */ + public static final int + ALLOW_TRANSFORM_WRITE = CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_TRANSFORM_WRITE; + + /** + * Specifies that this TextureAttributes object allows + * reading its texture color table component + * information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_COLOR_TABLE_READ = + CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_COLOR_TABLE_READ; + + /** + * Specifies that this TextureAttributes object allows + * writing its texture color table component + * information. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_COLOR_TABLE_WRITE = + CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_COLOR_TABLE_WRITE; + + /** + * Specifies that this TextureAttributes object allows + * reading its texture combine mode information. (e.g. combine mode, + * combine color source, combine color function, combine scale factor) + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_COMBINE_READ = + CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_COMBINE_READ; + + /** + * Specifies that this TextureAttributes object allows + * writing its texture combine mode information. (e.g. combine mode, + * combine color source, combine color function, combine scale factor) + * + * @since Java 3D 1.3 + */ + public static final int ALLOW_COMBINE_WRITE = + CapabilityBits.TEXTURE_ATTRIBUTES_ALLOW_COMBINE_WRITE; + + + /** + * Use the fastest available method for perspective correction. + * @see #setPerspectiveCorrectionMode + */ + public static final int FASTEST = 0; + + /** + * Use the nicest (highest quality) available method for texture + * mapping perspective correction. + * @see #setPerspectiveCorrectionMode + */ + public static final int NICEST = 1; + + /** + * Modulate the object color with the texture color. + * @see #setTextureMode + */ + public static final int MODULATE = 2; + + /** + * Apply the texture color to the object as a decal. + * @see #setTextureMode + */ + public static final int DECAL = 3; + + /** + * Blend the texture blend color with the object color. + * @see #setTextureMode + */ + public static final int BLEND = 4; + + /** + * Replace the object color with the texture color. + * @see #setTextureMode + */ + public static final int REPLACE = 5; + + /** + * Combine the object color with texture color as specified in + * the combine mode. + * + * @see #setTextureMode + * @since Java 3D 1.3 + */ + public static final int COMBINE = 6; + + + /** + * Replace the input color with the specified color. + * + * @since Java 3D 1.3 + * @see #setCombineRgbMode + * @see #setCombineAlphaMode + */ + public static final int COMBINE_REPLACE = 0; + + /** + * Modulates one color with another color. + * + * @since Java 3D 1.3 + * @see #setCombineRgbMode + * @see #setCombineAlphaMode + */ + public static final int COMBINE_MODULATE = 1; + + /** + * Add two colors. + * + * @since Java 3D 1.3 + * @see #setCombineRgbMode + * @see #setCombineAlphaMode + */ + public static final int COMBINE_ADD = 2; + + /** + * Add two colors plus an implicit offset. + * + * @since Java 3D 1.3 + * @see #setCombineRgbMode + * @see #setCombineAlphaMode + */ + public static final int COMBINE_ADD_SIGNED = 3; + + /** + * Subtract one color from another color. + * + * @since Java 3D 1.3 + * @see #setCombineRgbMode + * @see #setCombineAlphaMode + */ + public static final int COMBINE_SUBTRACT = 4; + + /** + * Interpolate two colors with a factor. + * + * @since Java 3D 1.3 + * @see #setCombineRgbMode + * @see #setCombineAlphaMode + */ + public static final int COMBINE_INTERPOLATE = 5; + + /** + * Dot product of two colors. + * + * @since Java 3D 1.3 + * @see #setCombineRgbMode + * @see #setCombineAlphaMode + */ + public static final int COMBINE_DOT3 = 6; + + + /** + * Object color coming into the texturing state. + * + * @since Java 3D 1.3 + * @see #setCombineRgbSource + * @see #setCombineAlphaSource + */ + public static final int COMBINE_OBJECT_COLOR = 0; + + /** + * Texture color of the corresponding texture unit state. + * + * @since Java 3D 1.3 + * @see #setCombineRgbSource + * @see #setCombineAlphaSource + */ + public static final int COMBINE_TEXTURE_COLOR = 1; + + /** + * Texture blend color. + * + * @since Java 3D 1.3 + * @see #setCombineRgbSource + * @see #setCombineAlphaSource + */ + public static final int COMBINE_CONSTANT_COLOR = 2; + + /** + * Color from the previous texture unit state. + * + * @since Java 3D 1.3 + * @see #setCombineRgbSource + * @see #setCombineAlphaSource + */ + public static final int COMBINE_PREVIOUS_TEXTURE_UNIT_STATE = 3; + + /** + * Color function is f = Crgb + * + * @since Java 3D 1.3 + * @see #setCombineRgbFunction + */ + public static final int COMBINE_SRC_COLOR = 0; + + /** + * Color function is f = (1 - Crgb) + * + * @since Java 3D 1.3 + * @see #setCombineRgbFunction + */ + public static final int COMBINE_ONE_MINUS_SRC_COLOR = 1; + + /** + * Color function is f = Ca + * + * @since Java 3D 1.3 + * @see #setCombineRgbFunction + * @see #setCombineAlphaFunction + */ + public static final int COMBINE_SRC_ALPHA = 2; + + /** + * Color function is f = (1 - Ca) + * + * @since Java 3D 1.3 + * @see #setCombineRgbFunction + * @see #setCombineAlphaFunction + */ + public static final int COMBINE_ONE_MINUS_SRC_ALPHA = 3; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_BLEND_COLOR_READ, + ALLOW_COLOR_TABLE_READ, + ALLOW_COMBINE_READ, + ALLOW_MODE_READ, + ALLOW_TRANSFORM_READ + }; + + /** + * Constructs a TextureAttributes object with default parameters. + * The default values are as follows: + *
    + * texture mode : REPLACE
    + * blend color : black (0,0,0,0)
    + * transform : identity
    + * perspective correction mode : NICEST
    + * texture color table : null
    + * combine rgb mode : COMBINE_MODULATE
    + * combine alpha mode : COMBINE_MODULATE
    + * combine rgb source : + *
      + * C0=COMBINE_TEXTURE_COLOR
      + * C1=COMBINE_PREVIOUS_TEXTURE_UNIT_STATE
      + * C2=COMBINE_CONSTANT_COLOR
      + *
    + * combine alpha source : + *
      + * C0=COMBINE_TEXTURE_COLOR
      + * C1=COMBINE_PREVIOUS_TEXTURE_UNIT_STATE
      + * C2=COMBINE_CONSTANT_COLOR
      + *
    + * combine rgb function : COMBINE_SRC_COLOR
    + * combine alpha function : COMBINE_SRC_ALPHA
    + * combine rgb scale : 1
    + * combine alpha scale : 1
    + *
+ */ + public TextureAttributes() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a TextureAttributes object with the specified values. + * @param textureMode the texture mode; one of MODULATE, + * DECAL, BLEND, REPLACE, or + * COMBINE + * @param transform the transform object, used to transform texture + * coordinates + * @param textureBlendColor the texture constant color + * @param perspCorrectionMode the perspective correction mode to + * be used for color and/or texture coordinate interpolation; + * one of NICEST or FASTEST + * @exception IllegalArgumentException if textureMode + * is a value other than MODULATE, + * DECAL, BLEND, REPLACE, or + * COMBINE + * @exception IllegalArgumentException if mode value is other + * than FASTEST or NICEST. + */ + public TextureAttributes(int textureMode, Transform3D transform, + Color4f textureBlendColor, + int perspCorrectionMode) { + + if ((textureMode < MODULATE) || (textureMode > COMBINE)) { + throw new IllegalArgumentException(J3dI18N.getString("TextureAttributes10")); + } + + if ((perspCorrectionMode != FASTEST) && + (perspCorrectionMode!= NICEST)) { + throw new IllegalArgumentException(J3dI18N.getString("TextureAttributes9")); + } + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TextureAttributesRetained)this.retained).initTextureMode(textureMode); + ((TextureAttributesRetained)this.retained).initTextureBlendColor(textureBlendColor); + ((TextureAttributesRetained)this.retained).initTextureTransform(transform); + ((TextureAttributesRetained)this.retained).initPerspectiveCorrectionMode(perspCorrectionMode); + } + + /** + * Sets the texture mode parameter for this + * appearance component object. + * @param textureMode the texture mode, one of: MODULATE, + * DECAL, BLEND, REPLACE, or + * COMBINE + * @exception IllegalArgumentException if textureMode + * is a value other than MODULATE, + * DECAL, BLEND, REPLACE, or + * COMBINE + * + * @see Canvas3D#queryProperties + */ + public void setTextureMode(int textureMode) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MODE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes0")); + + if ((textureMode < MODULATE) || (textureMode > COMBINE)) { + throw new IllegalArgumentException(J3dI18N.getString("TextureAttributes10")); + } + + if (isLive()) + ((TextureAttributesRetained)this.retained).setTextureMode(textureMode); + else + ((TextureAttributesRetained)this.retained).initTextureMode(textureMode); + } + + /** + * Gets the texture mode parameter for this + * texture attributes object. + * @return textureMode the texture mode + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getTextureMode() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes1")); + + return ((TextureAttributesRetained)this.retained).getTextureMode(); + } + + /** + * Sets the texture constant color for this + * texture attributes object. + * @param textureBlendColor the texture constant color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setTextureBlendColor(Color4f textureBlendColor) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_BLEND_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes2")); + + if (isLive()) + ((TextureAttributesRetained)this.retained).setTextureBlendColor(textureBlendColor); + else + ((TextureAttributesRetained)this.retained).initTextureBlendColor(textureBlendColor); + } + + /** + * Sets the texture blend color for this + * appearance component object. + * @param r the red component of the color + * @param g the green component of the color + * @param b the blue component of the color + * @param a the alpha component of the color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setTextureBlendColor(float r, float g, float b, float a) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_BLEND_COLOR_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes3")); + + if (isLive()) + ((TextureAttributesRetained)this.retained).setTextureBlendColor(r, g, b, a); + else + ((TextureAttributesRetained)this.retained).initTextureBlendColor(r, g, b, a); + } + + /** + * Gets the texture blend color for this + * appearance component object. + * @param textureBlendColor the vector that will receive the texture + * constant color + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getTextureBlendColor(Color4f textureBlendColor) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_BLEND_COLOR_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes4")); + + ((TextureAttributesRetained)this.retained).getTextureBlendColor(textureBlendColor); + } + + /** + * Sets the texture transform object used to transform texture + * coordinates. A copy of the specified Transform3D object is + * stored in this TextureAttributes object. + * @param transform the new transform object + * @exception CapabilityNotSetException if the method is called + * when this object is part of live or compiled scene graph. + */ + public void setTextureTransform(Transform3D transform) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TRANSFORM_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes5")); + + if (isLive()) + ((TextureAttributesRetained)this.retained).setTextureTransform(transform); + else + ((TextureAttributesRetained)this.retained).initTextureTransform(transform); + } + + /** + * Retrieves a copy of the texture transform object. + * @param transform the transform object that will receive the + * current texture transform + * @exception CapabilityNotSetException if the method is called + * when this object is part of live or compiled scene graph. + */ + public void getTextureTransform(Transform3D transform) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_TRANSFORM_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes6")); + + ((TextureAttributesRetained)this.retained).getTextureTransform(transform); + } + + /** + * Sets perspective correction mode to be used for color + * and/or texture coordinate interpolation. + * A value of NICEST indicates that perspective correction should be + * performed and that the highest quality method should be used. + * A value of FASTEST indicates that the most efficient perspective + * correction method should be used. + * @param mode one of NICEST or FASTEST + * The default value is NICEST. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if mode value is other + * than FASTEST or NICEST. + */ + public void setPerspectiveCorrectionMode(int mode) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MODE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes7")); + + if ((mode != FASTEST) && (mode!= NICEST)) + throw new IllegalArgumentException(J3dI18N.getString("TextureAttributes9")); + + if (isLive()) + ((TextureAttributesRetained)this.retained).setPerspectiveCorrectionMode(mode); + else + ((TextureAttributesRetained)this.retained).initPerspectiveCorrectionMode(mode); + } + + /** + * Gets perspective correction mode value. + * @return mode the value of perspective correction mode + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getPerspectiveCorrectionMode() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes8")); + return ((TextureAttributesRetained)this.retained).getPerspectiveCorrectionMode(); + } + + /** + * Sets the texture color table from the specified table. The + * individual integer array elements are copied. The array is + * indexed first by color component (r, g, b, + * and a, respectively) and then by color value; + * table.length defines the number of color + * components and table[0].length defines the texture + * color table size. If the table is non-null, the number of + * color components must either be 3, for rgb data, or 4, + * for rgba data. The size of each array for each color + * component must be the same and must be a power of 2. If table + * is null or if the texture color table size is 0, the texture + * color table is disabled. If the texture color table size is + * greater than the device-dependent maximum texture color table + * size for a particular Canvas3D, the texture color table is + * ignored for that canvas. + * + *

+ * When enabled, the texture color table is applied after the + * texture filtering operation and before texture application. + * Each of the r, g, b, and a + * components are clamped to the range [0,1], multiplied by + * textureColorTableSize-1, and rounded to the + * nearest integer. The resulting value for each component is + * then used as an index into the respective table for that + * component. If the texture color table contains 3 components, + * alpha is passed through unmodified. + * + * @param table the new texture color table + * + * @exception IllegalArgumentException if table.length + * is not 3 or 4, or if the arrays for each component are not all + * the same length, or if the texture color table size + * is not a power of 2 + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.2 + */ + public void setTextureColorTable(int[][] table) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLOR_TABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes11")); + + if (isLive()) + ((TextureAttributesRetained)this.retained).setTextureColorTable(table); + else + ((TextureAttributesRetained)this.retained).initTextureColorTable(table); + } + + /** + * Retrieves the texture color table and copies it into the + * specified array. If the current texture color table is null, + * no values are copied. + * + * @param table the array that will receive a copy of the + * texture color table from this TextureAttributes object. + * The array must be allocated by the caller and must be large + * enough to hold the entire table (that is, + * int[numTextureColorTableComponents][textureColorTableSize]). + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public void getTextureColorTable(int[][] table) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_COLOR_TABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureAttributes12")); + ((TextureAttributesRetained)this.retained).getTextureColorTable(table); + return; + } + + /** + * Retrieves the number of color components in the current texture + * color table. A value of 0 is returned if the texture color + * table is null. + * + * @return the number of color components in the texture color + * table, or 0 if the table is null + * + * @since Java 3D 1.2 + */ + public int getNumTextureColorTableComponents() { + return (((TextureAttributesRetained)this.retained).getNumTextureColorTableComponents()); + } + + /** + * Retrieves the size of the current texture color table. A value + * of 0 is returned if the texture color table is null. + * + * @return the size of the texture color table, or 0 if the table + * is null + * + * @since Java 3D 1.2 + */ + public int getTextureColorTableSize() { + return (((TextureAttributesRetained)this.retained).getTextureColorTableSize()); + } + + + /** + * Sets the combine mode for the rgb components of the output color + * for this object. + * + * @param combineMode the combine mode, one of: + * COMBINE_REPLACE, + * COMBINE_MODULATE, COMBINE_ADD, + * COMBINE_ADD_SIGNED, COMBINE_SUBTRACT, + * COMBINE_INTERPOLATE, or COMBINE_DOT3 + * + * @exception IllegalArgumentException if combineMode + * is a value other than COMBINE_REPLACE, + * COMBINE_MODULATE, COMBINE_ADD, + * COMBINE_ADD_SIGNED, COMBINE_SUBTRACT, + * COMBINE_INTERPOLATE, or COMBINE_DOT3 + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setCombineRgbMode(int combineMode) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes16")); + } + } + + if ((combineMode < COMBINE_REPLACE) || (combineMode > COMBINE_DOT3)) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureAttributes20")); + } + + if (isLive()) { + ((TextureAttributesRetained)this.retained).setCombineRgbMode(combineMode); + } else { + ((TextureAttributesRetained)this.retained).initCombineRgbMode(combineMode); + } + } + + /** + * Sets the combine mode for the alpha component of the output color + * for this object. + * + * @param combineMode the combine mode, one of: + * COMBINE_REPLACE, + * COMBINE_MODULATE, COMBINE_ADD, + * COMBINE_ADD_SIGNED, COMBINE_SUBTRACT, + * COMBINE_INTERPOLATE, or COMBINE_DOT3 + * + * @exception IllegalArgumentException if combineMode + * is a value other than COMBINE_REPLACE, + * COMBINE_MODULATE, COMBINE_ADD, + * COMBINE_ADD_SIGNED, COMBINE_SUBTRACT, + * COMBINE_INTERPOLATE, or COMBINE_DOT3 + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setCombineAlphaMode(int combineMode) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes18")); + } + } + + if ((combineMode < COMBINE_REPLACE) || (combineMode > COMBINE_DOT3)) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureAttributes20")); + } + + if (isLive()) { + ((TextureAttributesRetained)this.retained).setCombineAlphaMode(combineMode); + } else { + ((TextureAttributesRetained)this.retained).initCombineAlphaMode(combineMode); + } + } + + /** + * Retrieves the combine mode for the rgb components of the output color + * for this object. + * @return the combine mode for the rgb components. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getCombineRgbMode() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes17")); + } + } + + return ((TextureAttributesRetained)this.retained).getCombineRgbMode(); + } + + /** + * Retrieves the combine mode for the alpha component of the output color + * for this object. + * @return the combine mode for the alpha component. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getCombineAlphaMode() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes19")); + } + } + + return ((TextureAttributesRetained)this.retained).getCombineAlphaMode(); + } + + /** + * Sets the source for the rgb components of the specified color operand + * for this object. + * + * @param index color operand in the combine operation + * @param src the color source, one of: COMBINE_OBJECT_COLOR, + * COMBINE_TEXTURE_COLOR, + * COMBINE_CONSTANT_COLOR, or + * COMBINE_PREVIOUS_TEXTURE_UNIT_STATE + * + * @exception IndexOutOfBoundsException if index < 0 or + * index > 2 + * @exception IllegalArgumentException if src + * is a value other than COMBINE_OBJECT_COLOR, + * COMBINE_TEXTURE_COLOR, + * COMBINE_CONSTANT_COLOR, or + * COMBINE_PREVIOUS_TEXTURE_UNIT_STATE + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setCombineRgbSource(int index, int src) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes21")); + } + } + + if ((index < 0) || (index > 2)) { + throw new IndexOutOfBoundsException( + J3dI18N.getString("TextureAttributes25")); + } + + if ((src < COMBINE_OBJECT_COLOR) || + (src > COMBINE_PREVIOUS_TEXTURE_UNIT_STATE)) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureAttributes26")); + } + + if (isLive()) { + ((TextureAttributesRetained)this.retained).setCombineRgbSource( + index, src); + } else { + ((TextureAttributesRetained)this.retained).initCombineRgbSource( + index, src); + } + } + + /** + * Sets the source for the alpha component of the specified color operand + * for this object. + * + * @param index color operand in the combine operation + * @param src the color source, one of: COMBINE_OBJECT_COLOR, + * COMBINE_TEXTURE_COLOR, + * COMBINE_CONSTANT_COLOR, or + * COMBINE_PREVIOUS_TEXTURE_UNIT_STATE + * + * @exception IndexOutOfBoundsException if index < 0 or + * index > 2 + * @exception IllegalArgumentException if src + * is a value other than COMBINE_OBJECT_COLOR, + * COMBINE_TEXTURE_COLOR, + * COMBINE_CONSTANT_COLOR, or + * COMBINE_PREVIOUS_TEXTURE_UNIT_STATE + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setCombineAlphaSource(int index, int src) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes23")); + } + } + + if ((index < 0) || (index > 2)) { + throw new IndexOutOfBoundsException( + J3dI18N.getString("TextureAttributes25")); + } + + if ((src < COMBINE_OBJECT_COLOR) || + (src > COMBINE_PREVIOUS_TEXTURE_UNIT_STATE)) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureAttributes26")); + } + + if (isLive()) { + ((TextureAttributesRetained)this.retained).setCombineAlphaSource( + index, src); + } else { + ((TextureAttributesRetained)this.retained).initCombineAlphaSource( + index, src); + } + } + + /** + * Retrieves the source for the rgb components of the specified + * color operand for this object. + * + * @param index color operand in the combine operation + * + * @return the source for the rgb components of the specified color + * operand for this object + * + * @exception IndexOutOfBoundsException if index < 0 or + * index > 2 + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getCombineRgbSource(int index) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes22")); + } + } + + if ((index < 0) || (index > 2)) { + throw new IndexOutOfBoundsException( + J3dI18N.getString("TextureAttributes25")); + } + + return ((TextureAttributesRetained)this.retained).getCombineRgbSource(index); + } + + /** + * Retrieves the source for the alpha component of the specified + * color operand for this object. + * + * @param index color operand in the combine operation + * + * @return the source for the alpha component of the specified color + * operand for this object + * + * @exception IndexOutOfBoundsException if index < 0 or + * index > 2 + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getCombineAlphaSource(int index) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes24")); + } + } + + if ((index < 0) || (index > 2)) { + throw new IndexOutOfBoundsException( + J3dI18N.getString("TextureAttributes25")); + } + + return ((TextureAttributesRetained)this.retained).getCombineAlphaSource(index); + } + + /** + * Sets the function for the rgb components of the specified color operand + * for this object. + * + * @param index color operand in the combine operation + * @param function the color function, one of: + * COMBINE_SRC_COLOR, + * COMBINE_ONE_MINUS_SRC_COLOR, + * COMBINE_SRC_ALPHA, or + * COMBINE_ONE_MINUS_SRC_ALPHA + * + * @exception IndexOutOfBoundsException if index < 0 or + * index > 2 + * @exception IllegalArgumentException if function + * is a value other than COMBINE_SRC_COLOR, + * COMBINE_ONE_MINUS_SRC_COLOR, + * COMBINE_SRC_ALPHA, or + * COMBINE_ONE_MINUS_SRC_ALPHA + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setCombineRgbFunction(int index, int function) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes27")); + } + } + + if ((index < 0) || (index > 2)) { + throw new IndexOutOfBoundsException( + J3dI18N.getString("TextureAttributes25")); + } + + if ((function < COMBINE_SRC_COLOR) || + (function > COMBINE_ONE_MINUS_SRC_ALPHA)) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureAttributes31")); + } + + if (isLive()) { + ((TextureAttributesRetained)this.retained).setCombineRgbFunction( + index, function); + } else { + ((TextureAttributesRetained)this.retained).initCombineRgbFunction( + index, function); + } + } + + /** + * Sets the function for the alpha component of the specified color operand + * for this object. + * + * @param index color operand in the combine operation + * @param function the color function, one of: + * COMBINE_SRC_ALPHA, or + * COMBINE_ONE_MINUS_SRC_ALPHA + * + * @exception IndexOutOfBoundsException if index < 0 or + * index > 2 + * @exception IllegalArgumentException if function + * is a value other than + * COMBINE_SRC_ALPHA or + * COMBINE_ONE_MINUS_SRC_ALPHA + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setCombineAlphaFunction(int index, int function) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes29")); + } + } + + if ((index < 0) || (index > 2)) { + throw new IndexOutOfBoundsException( + J3dI18N.getString("TextureAttributes25")); + } + + if ((function < COMBINE_SRC_ALPHA) || + (function > COMBINE_ONE_MINUS_SRC_ALPHA)) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureAttributes31")); + } + + if (isLive()) { + ((TextureAttributesRetained)this.retained).setCombineAlphaFunction( + index, function); + } else { + ((TextureAttributesRetained)this.retained).initCombineAlphaFunction( + index, function); + } + } + + /** + * Retrieves the function for the rgb components of the specified color + * operand for this object. + * + * @param index color operand in the combine operation + * + * @return the function for the rgb components of the specified color + * operand for this object. + * + * @exception IndexOutOfBoundsException if index < 0 or + * index > 2 + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getCombineRgbFunction(int index) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes28")); + } + } + + if ((index < 0) || (index > 2)) { + throw new IndexOutOfBoundsException( + J3dI18N.getString("TextureAttributes25")); + } + + return ((TextureAttributesRetained)this.retained).getCombineRgbFunction(index); + } + + /** + * Retrieves the function for the alpha component of the specified color + * operand for this object. + * + * @param index color operand in the combine operation + * + * @return the function for the alpha component of the specified color + * operand for this object. + * + * @exception IndexOutOfBoundsException if index < 0 or + * index > 2 + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getCombineAlphaFunction(int index) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes30")); + } + } + + if ((index < 0) || (index > 2)) { + throw new IndexOutOfBoundsException( + J3dI18N.getString("TextureAttributes25")); + } + + return ((TextureAttributesRetained)this.retained).getCombineAlphaFunction(index); + } + + /** + * Sets the scale factor for the rgb components of the output color + * for this object. + * + * @param scale the scale factor for the rgb components of the output + * color. It must be one of the following: 1, 2, or 4. + * + * @exception IllegalArgumentException if scale is a + * value other than 1, 2, or 4. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setCombineRgbScale(int scale) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes32")); + } + } + + + if ((scale != 1) && (scale != 2) && (scale != 4)) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureAttributes36")); + } + + if (isLive()) { + ((TextureAttributesRetained)this.retained).setCombineRgbScale(scale); + } else { + ((TextureAttributesRetained)this.retained).initCombineRgbScale(scale); + } + } + + /** + * Sets the scale factor for the alpha component of the output color + * for this object. + * + * @param scale the scale factor for the alpha component of the output + * color. It must be one of the following: 1, 2, or 4. + * + * @exception IllegalArgumentException if scale is a + * value other than 1, 2, or 4. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ + public void setCombineAlphaScale(int scale) { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_WRITE)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes34")); + } + } + + if ((scale != 1) && (scale != 2) && (scale != 4)) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureAttributes36")); + } + + if (isLive()) { + ((TextureAttributesRetained)this.retained).setCombineAlphaScale(scale); + } else { + ((TextureAttributesRetained)this.retained).initCombineAlphaScale(scale); + } + } + + /** + * Retrieves the scale factor for the rgb components of the output color + * for this object. + * + * @return the scale factor for the rgb components of the output color + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getCombineRgbScale() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes33")); + } + } + + return ((TextureAttributesRetained)this.retained).getCombineRgbScale(); + } + + /** + * Retrieves the scale factor for the alpha component of the output color + * for this object. + * + * @return the scale factor for the alpha component of the output color + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int getCombineAlphaScale() { + if (isLiveOrCompiled()) { + if (!this.getCapability(ALLOW_COMBINE_READ)) { + throw new CapabilityNotSetException( + J3dI18N.getString("TextureAttributes35")); + } + } + + return ((TextureAttributesRetained)this.retained).getCombineAlphaScale(); + } + + + /** + * Creates a retained mode TextureAttributesRetained object that this + * TextureAttributes component object will point to. + */ + void createRetained() { + this.retained = new TextureAttributesRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + TextureAttributes ta = new TextureAttributes(); + ta.duplicateNodeComponent(this); + return ta; + } + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + TextureAttributesRetained attr = + (TextureAttributesRetained) originalNodeComponent.retained; + TextureAttributesRetained rt = (TextureAttributesRetained) retained; + + Color4f c = new Color4f(); + attr.getTextureBlendColor(c); + Transform3D t = new Transform3D(); + attr.getTextureTransform(t); + + rt.initTextureMode(attr.getTextureMode()); + rt.initPerspectiveCorrectionMode(attr.getPerspectiveCorrectionMode()); + rt.initTextureBlendColor(c); + rt.initTextureTransform(t); + + if ((attr.getNumTextureColorTableComponents() != 0) && + (attr.getTextureColorTableSize() != 0)) { + int table[][] = new + int[attr.getNumTextureColorTableComponents()][attr.getTextureColorTableSize()]; + attr.getTextureColorTable(table); + rt.initTextureColorTable(table); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TextureAttributesRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TextureAttributesRetained.java new file mode 100644 index 0000000..d7a4c79 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TextureAttributesRetained.java @@ -0,0 +1,1004 @@ +/* + * $RCSfile: TextureAttributesRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:31 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color4f; +import java.util.ArrayList; + +/** + * The TextureAttributes object defines attributes that apply to + * to texture mapping. + */ +class TextureAttributesRetained extends NodeComponentRetained { + + // A list of pre-defined bits to indicate which component + // in this TextureAttributes object changed. + static final int TRANSFORM_CHANGED = 0x0001; + static final int MODE_CHANGED = 0x0002; + static final int COLOR_CHANGED = 0x0004; + static final int CORRECTION_CHANGED = 0x0008; + static final int TEXTURE_COLOR_TABLE_CHANGED = 0x0010; + static final int COMBINE_RGB_MODE_CHANGED = 0x0020; + static final int COMBINE_ALPHA_MODE_CHANGED = 0x0040; + static final int COMBINE_RGB_SRC_CHANGED = 0x0080; + static final int COMBINE_ALPHA_SRC_CHANGED = 0x0100; + static final int COMBINE_RGB_FCN_CHANGED = 0x0200; + static final int COMBINE_ALPHA_FCN_CHANGED = 0x0400; + static final int COMBINE_RGB_SCALE_CHANGED = 0x0800; + static final int COMBINE_ALPHA_SCALE_CHANGED = 0x1000; + + // static class variable for commands used in messages + static Integer commandInt[] = null; + + // static class variable for enums. Currently only supports 0 - 9. + static Integer enums[] = null; + + // Texture transform + Transform3D transform = new Transform3D(); + + // Texture mode + int textureMode = TextureAttributes.REPLACE; + + // Texture blend color + Color4f textureBlendColor = new Color4f(0.0f, 0.0f, 0.0f, 0.0f); + + // Texture color table + int textureColorTable[] = null; + int numTextureColorTableComponents = 0; + int textureColorTableSize = 0; + + // Texture Combine Mode + + int combineRgbMode = TextureAttributes.COMBINE_MODULATE; + int combineAlphaMode = TextureAttributes.COMBINE_MODULATE; + + // the following fields are only applicable if textureMode specifies + // COMBINE. If COMBINE mode is specified, then each of the following + // fields will be referencing an array of 3 integers, each representing + // an operand in the combine equation. + int [] combineRgbSrc = null; + int [] combineAlphaSrc = null; + int [] combineRgbFcn = null; + int [] combineAlphaFcn = null; + + int combineRgbScale = 1; + int combineAlphaScale = 1; + + //Perspective correction mode, used for color/texCoord interpolation + int perspCorrectionMode = TextureAttributes.NICEST; + + // true when mirror texCoord component set + boolean mirrorCompDirty = false; + + static final void initTextureEnums() { + // create some of the enums Integer to be used in the messages + // this can be eliminated if the message is modified to take + // integer itself + // + // NOTE: check with the actual enum value before using this + // list. This list only supports 0 - 9 + if (enums == null) { + enums = new Integer[10]; + for (int i = 0; i < 10; i++) { + enums[i] = new Integer(i); + } + } + } + + + TextureAttributesRetained() { + initTextureEnums(); + } + + // initCombineMode -- initializes the combine mode related fields + // delay the allocation of memory to minimize + // memory footprint + + final void initCombineMode(TextureAttributesRetained tr) { + tr.combineRgbSrc = new int[3]; + tr.combineAlphaSrc = new int[3]; + tr.combineRgbFcn = new int[3]; + tr.combineAlphaFcn = new int[3]; + + //default values + + tr.combineRgbSrc[0] = TextureAttributes.COMBINE_TEXTURE_COLOR; + tr.combineRgbSrc[1] = TextureAttributes.COMBINE_PREVIOUS_TEXTURE_UNIT_STATE; + tr.combineRgbSrc[2] = TextureAttributes.COMBINE_CONSTANT_COLOR; + + tr.combineAlphaSrc[0] = TextureAttributes.COMBINE_TEXTURE_COLOR; + tr.combineAlphaSrc[1] = TextureAttributes.COMBINE_PREVIOUS_TEXTURE_UNIT_STATE; + tr.combineAlphaSrc[2] = TextureAttributes.COMBINE_CONSTANT_COLOR; + + tr.combineRgbFcn[0] = TextureAttributes.COMBINE_SRC_COLOR; + tr.combineRgbFcn[1] = TextureAttributes.COMBINE_SRC_COLOR; + tr.combineRgbFcn[2] = TextureAttributes.COMBINE_SRC_COLOR; + + tr.combineAlphaFcn[0] = TextureAttributes.COMBINE_SRC_ALPHA; + tr.combineAlphaFcn[1] = TextureAttributes.COMBINE_SRC_ALPHA; + tr.combineAlphaFcn[2] = TextureAttributes.COMBINE_SRC_ALPHA; + } + + final void initTextureMode(int textureMode) { + this.textureMode = textureMode; + + if (textureMode == TextureAttributes.COMBINE) { + if (combineRgbSrc == null) { + initCombineMode(this); + } + } + } + + /** + * Sets the texture mode parameter for this + * appearance component object. + * @param textureMode the texture mode, one of: MODULATE, + * DECAL, BLEND, or REPLACE + */ + final void setTextureMode(int textureMode) { + initTextureMode(textureMode); + sendMessage(MODE_CHANGED, enums[textureMode], null); + } + + /** + * Gets the texture mode parameter for this + * texture attributes object. + * @return textureMode the texture mode + */ + final int getTextureMode() { + return textureMode; + } + + final void initTextureBlendColor(Color4f textureBlendColor) { + this.textureBlendColor.set(textureBlendColor); + + } + + /** + * Sets the texture blend color for this + * texture attributes object. + * @param textureBlendColor the texture blend color used when + * the mode is BLEND + */ + final void setTextureBlendColor(Color4f textureBlendColor) { + this.textureBlendColor.set(textureBlendColor); + sendMessage(COLOR_CHANGED, new Color4f(textureBlendColor), null); + } + + + final void initTextureBlendColor(float r, float g, float b, float a) { + this.textureBlendColor.set(r, g, b, a); + } + + + /** + * Sets the texture blend color for this + * appearance component object. This color is used when + * the mode is BLEND. + * @param r the red component of the color + * @param g the green component of the color + * @param b the blue component of the color + * @param a the alpha component of the color + */ + final void setTextureBlendColor(float r, float g, float b, float a) { + this.textureBlendColor.set(r, g, b, a); + sendMessage(COLOR_CHANGED, new Color4f(r, g, b, a), null); + } + + + /** + * Gets the texture blend color for this + * appearance component object. + * @param textureBlendColor the vector that will receive the texture + * blend color used when the mode is BLEND + */ + final void getTextureBlendColor(Color4f textureBlendColor) { + textureBlendColor.set(this.textureBlendColor); + } + + + final void initTextureTransform(Transform3D transform) { + this.transform.set(transform); + } + + + /** + * Sets the texture transform object used to transform texture + * coordinates. A copy of the specified Transform3D object is + * stored in this TextureAttributes object. + * @param transform the new transform object + */ + final void setTextureTransform(Transform3D transform) { + this.transform.set(transform); + sendMessage(TRANSFORM_CHANGED, new Transform3D(transform), null); + } + + + /** + * Retrieves a copy of the texture transform object. + * @param transform the transform object that will receive the + * current texture transform. + */ + final void getTextureTransform(Transform3D transform) { + transform.set(this.transform); + } + + + final void initPerspectiveCorrectionMode(int mode) { + this.perspCorrectionMode = mode; + } + + /** + * Sets perspective correction mode to be used for color + * and/or texture coordinate interpolation. + * A value of NICEST indicates that perspective correction should be + * performed and that the highest quality method should be used. + * A value of FASTEST indicates that the most efficient perspective + * correction method should be used. + * @param mode one of NICEST or FASTEST. + * The default value is NICEST. + */ + final void setPerspectiveCorrectionMode(int mode) { + this.perspCorrectionMode = mode; + sendMessage(CORRECTION_CHANGED, enums[mode], null); + } + + /** + * Gets perspective correction mode value. + * @return mode the value of perspective correction mode. + */ + final int getPerspectiveCorrectionMode() { + return perspCorrectionMode; + } + + final void setTextureColorTable(int[][] table) { + initTextureColorTable(table); + + //clone a copy of the texture for the mirror object + if (table == null) { + sendMessage(TEXTURE_COLOR_TABLE_CHANGED, null, null); + } else { + int ctable[] = new int[textureColorTableSize * + numTextureColorTableComponents]; + System.arraycopy(textureColorTable, 0, ctable, 0, + textureColorTable.length); + Object args[] = new Object[3]; + + args[0] = new Integer(numTextureColorTableComponents); + args[1] = new Integer(textureColorTableSize); + args[2] = ctable; + sendMessage(TEXTURE_COLOR_TABLE_CHANGED, args, null); + } + } + + final void initTextureColorTable(int[][] table) { + + numTextureColorTableComponents = 0; + textureColorTableSize = 0; + + if (table == null) { + textureColorTable = null; + return; + } + + if (table.length < 3 || table.length > 4) { + throw new IllegalArgumentException(J3dI18N.getString("TextureAttributes13")); + } + + if (Texture.getPowerOf2(table[0].length) == -1) { + throw new IllegalArgumentException(J3dI18N.getString("TextureAttributes14")); + } + + for (int i = 1; i < table.length; i++) { + if (table[i].length != table[0].length) + throw new IllegalArgumentException(J3dI18N.getString("TextureAttributes15")); + } + + numTextureColorTableComponents = table.length; + textureColorTableSize = table[0].length; + + if (textureColorTable == null || + textureColorTable.length != numTextureColorTableComponents * + textureColorTableSize) { + textureColorTable = new int[numTextureColorTableComponents * + textureColorTableSize]; + } + + int k = 0; + for (int i = 0; i < textureColorTableSize; i++) { + for (int j = 0; j < numTextureColorTableComponents; j++) { + textureColorTable[k++] = table[j][i]; + } + } + } + + + final void getTextureColorTable(int[][] table) { + + if (textureColorTable == null) + return; + + int k = 0; + for (int i = 0; i < textureColorTableSize; i++) { + for (int j = 0; j < numTextureColorTableComponents; j++) { + table[j][i] = textureColorTable[k++]; + } + } + } + + final int getNumTextureColorTableComponents() { + return numTextureColorTableComponents; + } + + final int getTextureColorTableSize() { + return textureColorTableSize; + } + + + final void initCombineRgbMode(int mode) { + combineRgbMode = mode; + } + + final void setCombineRgbMode(int mode) { + initCombineRgbMode(mode); + sendMessage(COMBINE_RGB_MODE_CHANGED, enums[mode], null); + } + + final int getCombineRgbMode() { + return combineRgbMode; + } + + final void initCombineAlphaMode(int mode) { + combineAlphaMode = mode; + } + + final void setCombineAlphaMode(int mode) { + initCombineAlphaMode(mode); + sendMessage(COMBINE_ALPHA_MODE_CHANGED, enums[mode], null); + } + + final int getCombineAlphaMode() { + return combineAlphaMode; + } + + final void initCombineRgbSource(int index, int src) { + if (combineRgbSrc == null) { + // it is possible to set the combineRgbSource before + // setting the texture mode to COMBINE, so need to initialize + // the combine mode related fields here + initCombineMode(this); + } + combineRgbSrc[index] = src; + } + + final void setCombineRgbSource(int index, int src) { + initCombineRgbSource(index, src); + sendMessage(COMBINE_RGB_SRC_CHANGED, enums[index], enums[src]); + } + + final int getCombineRgbSource(int index) { + if (combineRgbSrc == null) { + // it is possible to do a get before + // setting the texture mode to COMBINE, so need to initialize + // the combine mode related fields here + initCombineMode(this); + } + return combineRgbSrc[index]; + } + + final void initCombineAlphaSource(int index, int src) { + if (combineRgbSrc == null) { + // it is possible to set the combineAlphaSource before + // setting the texture mode to COMBINE, so need to initialize + // the combine mode related fields here + initCombineMode(this); + } + combineAlphaSrc[index] = src; + } + + final void setCombineAlphaSource(int index, int src) { + initCombineAlphaSource(index, src); + sendMessage(COMBINE_ALPHA_SRC_CHANGED, enums[index], enums[src]); + } + + final int getCombineAlphaSource(int index) { + if (combineRgbSrc == null) { + // it is possible to do a get before + // setting the texture mode to COMBINE, so need to initialize + // the combine mode related fields here + initCombineMode(this); + } + return combineAlphaSrc[index]; + } + + final void initCombineRgbFunction(int index, int fcn) { + if (combineRgbSrc == null) { + // it is possible to set the combineRgbFcn before + // setting the texture mode to COMBINE, so need to initialize + // the combine mode related fields here + initCombineMode(this); + } + combineRgbFcn[index] = fcn; + } + + final void setCombineRgbFunction(int index, int fcn) { + initCombineRgbFunction(index, fcn); + sendMessage(COMBINE_RGB_FCN_CHANGED, enums[index], enums[fcn]); + } + + final int getCombineRgbFunction(int index) { + if (combineRgbSrc == null) { + // it is possible to do a get before + // setting the texture mode to COMBINE, so need to initialize + // the combine mode related fields here + initCombineMode(this); + } + return combineRgbFcn[index]; + } + + final void initCombineAlphaFunction(int index, int fcn) { + if (combineRgbSrc == null) { + // it is possible to set the combineAlphaFcn before + // setting the texture mode to COMBINE, so need to initialize + // the combine mode related fields here + initCombineMode(this); + } + combineAlphaFcn[index] = fcn; + } + + final void setCombineAlphaFunction(int index, int fcn) { + initCombineAlphaFunction(index, fcn); + sendMessage(COMBINE_ALPHA_FCN_CHANGED, enums[index], enums[fcn]); + } + + final int getCombineAlphaFunction(int index) { + if (combineRgbSrc == null) { + // it is possible to do a get before + // setting the texture mode to COMBINE, so need to initialize + // the combine mode related fields here + initCombineMode(this); + } + return combineAlphaFcn[index]; + } + + final void initCombineRgbScale(int scale) { + combineRgbScale = scale; + } + + final void setCombineRgbScale(int scale) { + initCombineRgbScale(scale); + sendMessage(COMBINE_RGB_SCALE_CHANGED, enums[scale], null); + } + + final int getCombineRgbScale() { + return combineRgbScale; + } + + final void initCombineAlphaScale(int scale) { + combineAlphaScale = scale; + } + + final void setCombineAlphaScale(int scale) { + initCombineAlphaScale(scale); + sendMessage(COMBINE_ALPHA_SCALE_CHANGED, enums[scale], null); + } + + final int getCombineAlphaScale() { + return combineAlphaScale; + } + + void updateNative(Canvas3D cv, boolean simulate, int textureFormat) { + + //System.err.println("TextureAttributes/updateNative: simulate= " + simulate + " " + this); + + //if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_COLOR_TABLE) + // == 0) && textureColorTable != null) { + // System.err.println("TextureColorTable Not supported"); + //} + + //System.err.println("textureMode= " + textureMode); + boolean isIdentity = + ((transform.getType() & Transform3D.IDENTITY) != 0); + + if (simulate == false) { + if (VirtualUniverse.mc.useCombiners && + (cv.textureExtendedFeatures & + Canvas3D.TEXTURE_REGISTER_COMBINERS) != 0) { + Pipeline.getPipeline().updateRegisterCombiners(cv.ctx, + transform.mat, isIdentity, textureMode, perspCorrectionMode, + textureBlendColor.x, textureBlendColor.y, + textureBlendColor.z, textureBlendColor.w, + textureFormat, combineRgbMode, combineAlphaMode, + combineRgbSrc, combineAlphaSrc, + combineRgbFcn, combineAlphaFcn, + combineRgbScale, combineAlphaScale); + } else { + if (textureMode == TextureAttributes.COMBINE) { + + if ((cv.textureExtendedFeatures & + Canvas3D.TEXTURE_COMBINE) != 0) { + + // Texture COMBINE is supported by the underlying layer + + int _combineRgbMode = combineRgbMode; + int _combineAlphaMode = combineAlphaMode; + + Pipeline.getPipeline().updateTextureAttributes(cv.ctx, + transform.mat, isIdentity, textureMode, + perspCorrectionMode, + textureBlendColor.x, textureBlendColor.y, + textureBlendColor.z, textureBlendColor.w, + textureFormat); + + + if (((combineRgbMode == TextureAttributes.COMBINE_DOT3) && + ((cv.textureExtendedFeatures & + Canvas3D.TEXTURE_COMBINE_DOT3) == 0)) || + ((combineRgbMode == TextureAttributes.COMBINE_SUBTRACT) && + ((cv.textureExtendedFeatures & + Canvas3D.TEXTURE_COMBINE_SUBTRACT) == 0))) { + + // Combine DOT3/SUBTRACT is not supported by the + // underlying layer, fallback to COMBINE_REPLACE + + _combineRgbMode = TextureAttributes.COMBINE_REPLACE; + } + + if (((combineAlphaMode == TextureAttributes.COMBINE_DOT3) && + ((cv.textureExtendedFeatures & + Canvas3D.TEXTURE_COMBINE_DOT3) == 0)) || + ((combineAlphaMode == TextureAttributes.COMBINE_SUBTRACT) && + ((cv.textureExtendedFeatures & + Canvas3D.TEXTURE_COMBINE_SUBTRACT) == 0))) { + + // Combine DOT3/SUBTRACT is not supported by the + // underlying layer, fallback to COMBINE_REPLACE + + _combineAlphaMode = TextureAttributes.COMBINE_REPLACE; + } + + Pipeline.getPipeline().updateCombiner(cv.ctx, + _combineRgbMode, _combineAlphaMode, + combineRgbSrc, combineAlphaSrc, + combineRgbFcn, combineAlphaFcn, + combineRgbScale, combineAlphaScale); + + } else { + + // Texture COMBINE is not supported by the underlying + // layer, fallback to REPLACE + + Pipeline.getPipeline().updateTextureAttributes(cv.ctx, + transform.mat, isIdentity, + TextureAttributes.REPLACE, + perspCorrectionMode, + textureBlendColor.x, textureBlendColor.y, + textureBlendColor.z, textureBlendColor.w, + textureFormat); + } + } else { + Pipeline.getPipeline().updateTextureAttributes(cv.ctx, + transform.mat, isIdentity, textureMode, + perspCorrectionMode, + textureBlendColor.x, textureBlendColor.y, + textureBlendColor.z, textureBlendColor.w, + textureFormat); + } + } + + + if (((cv.textureExtendedFeatures & Canvas3D.TEXTURE_COLOR_TABLE) + != 0) && textureColorTable != null) { + + Pipeline.getPipeline().updateTextureColorTable(cv.ctx, + numTextureColorTableComponents, + textureColorTableSize, textureColorTable); + } + } else { + // we are in the multi-pass mode, + // in this case, set the texture Mode to replace and use + // blending to simulate the original textureMode + Pipeline.getPipeline().updateTextureAttributes(cv.ctx, + transform.mat, isIdentity, TextureAttributes.REPLACE, + perspCorrectionMode, + textureBlendColor.x, textureBlendColor.y, + textureBlendColor.z, textureBlendColor.w, textureFormat); + + if (((cv.textureExtendedFeatures & Canvas3D.TEXTURE_COLOR_TABLE) + != 0) && textureColorTable != null) { + + Pipeline.getPipeline().updateTextureColorTable(cv.ctx, numTextureColorTableComponents, + textureColorTableSize, textureColorTable); + } + + switch (textureMode) { + case TextureAttributes.COMBINE: + case TextureAttributes.REPLACE: + cv.setBlendFunc(cv.ctx, + TransparencyAttributes.BLEND_ONE, + TransparencyAttributes.BLEND_ZERO); + break; + case TextureAttributes.MODULATE: + cv.setBlendFunc(cv.ctx, + TransparencyAttributes.BLEND_DST_COLOR, + TransparencyAttributes.BLEND_ZERO); + break; + case TextureAttributes.DECAL: + if (textureFormat == Texture.RGBA) { + cv.setBlendFunc(cv.ctx, + TransparencyAttributes.BLEND_SRC_ALPHA, + TransparencyAttributes.BLEND_ONE_MINUS_SRC_ALPHA); + } else { + cv.setBlendFunc(cv.ctx, + TransparencyAttributes.BLEND_ONE, + TransparencyAttributes.BLEND_ZERO); + } + break; + case TextureAttributes.BLEND: + cv.setBlendColor(cv.ctx, textureBlendColor.x, textureBlendColor.y, + textureBlendColor.z, textureBlendColor.w); + cv.setBlendFunc(cv.ctx, + TransparencyAttributes.BLEND_CONSTANT_COLOR, + TransparencyAttributes.BLEND_ONE_MINUS_SRC_COLOR); + break; + } + } + } + + + /** + * Creates and initializes a mirror object, point the mirror object + * to the retained object if the object is not editable + */ + synchronized void createMirrorObject() { + + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror = this; + } else { + TextureAttributesRetained mirrorTa = new TextureAttributesRetained(); + mirrorTa.source = source; + mirrorTa.set(this); + mirror = mirrorTa; + } + } else { + ((TextureAttributesRetained)mirror).set(this); + } + } + + /** + * Initializes a mirror object + */ + synchronized void initMirrorObject() { + ((TextureAttributesRetained)mirror).set(this); + } + + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value, + Object value2) { + TextureAttributesRetained mirrorTa = (TextureAttributesRetained)mirror; + mirrorTa.mirrorCompDirty = true; + + if ((component & TRANSFORM_CHANGED) != 0) { + mirrorTa.transform.set((Transform3D)value); + } + else if ((component & MODE_CHANGED) != 0) { + mirrorTa.textureMode = ((Integer)value).intValue(); + + if ((mirrorTa.textureMode == TextureAttributes.COMBINE) && + (mirrorTa.combineRgbSrc == null)) { + initCombineMode(mirrorTa); + } + } + else if ((component & COLOR_CHANGED) != 0) { + mirrorTa.textureBlendColor.set((Color4f)value); + } + else if ((component & CORRECTION_CHANGED) != 0) { + mirrorTa.perspCorrectionMode = ((Integer)value).intValue(); + } + else if ((component & TEXTURE_COLOR_TABLE_CHANGED) != 0) { + if (value == null) { + mirrorTa.textureColorTable = null; + mirrorTa.numTextureColorTableComponents = 0; + mirrorTa.textureColorTableSize = 0; + } else { + Object args[] = (Object[])value; + mirrorTa.textureColorTable = (int[])args[2]; + mirrorTa.numTextureColorTableComponents = + ((Integer)args[0]).intValue(); + mirrorTa.textureColorTableSize = + ((Integer)args[1]).intValue(); + } + } + else if ((component & COMBINE_RGB_MODE_CHANGED) != 0) { + mirrorTa.combineRgbMode = ((Integer)value).intValue(); + } + else if ((component & COMBINE_ALPHA_MODE_CHANGED) != 0) { + mirrorTa.combineAlphaMode = ((Integer)value).intValue(); + } + else if ((component & COMBINE_RGB_SRC_CHANGED) != 0) { + if (mirrorTa.combineRgbSrc == null) { + //initialize the memory for combine mode + initCombineMode(mirrorTa); + } + int index = ((Integer)value).intValue(); + mirrorTa.combineRgbSrc[index] = ((Integer)value2).intValue(); + } + else if ((component & COMBINE_ALPHA_SRC_CHANGED) != 0) { + if (mirrorTa.combineRgbSrc == null) { + //initialize the memory for combine mode + initCombineMode(mirrorTa); + } + int index = ((Integer)value).intValue(); + mirrorTa.combineAlphaSrc[index] = ((Integer)value2).intValue(); + } + else if ((component & COMBINE_RGB_FCN_CHANGED) != 0) { + if (mirrorTa.combineRgbSrc == null) { + //initialize the memory for combine mode + initCombineMode(mirrorTa); + } + int index = ((Integer)value).intValue(); + mirrorTa.combineRgbFcn[index] = ((Integer)value2).intValue(); + } + else if ((component & COMBINE_ALPHA_FCN_CHANGED) != 0) { + if (mirrorTa.combineRgbSrc == null) { + //initialize the memory for combine mode + initCombineMode(mirrorTa); + } + int index = ((Integer)value).intValue(); + mirrorTa.combineAlphaFcn[index] = ((Integer)value2).intValue(); + } + else if ((component & COMBINE_RGB_SCALE_CHANGED) != 0) { + mirrorTa.combineRgbScale = ((Integer)value).intValue(); + } + else if ((component & COMBINE_ALPHA_SCALE_CHANGED) != 0) { + mirrorTa.combineAlphaScale = ((Integer)value).intValue(); + } + } + + + boolean equivalent(TextureAttributesRetained tr) { + + if (tr == null) { + return (false); + + } else if ((this.changedFrequent != 0) || (tr.changedFrequent != 0)) { + return (this == tr); + } + + if (!(tr.transform.equals(transform) && + tr.textureBlendColor.equals(textureBlendColor) && + (tr.textureMode == textureMode) && + (tr.perspCorrectionMode == perspCorrectionMode))) { + return false; + } + + + // now check for combine mode attributes if textureMode specifies + // COMBINE + + if (textureMode == TextureAttributes.COMBINE) { + + if ((tr.combineRgbMode != combineRgbMode) || + (tr.combineAlphaMode != combineAlphaMode) || + (tr.combineRgbScale != combineRgbScale) || + (tr.combineAlphaScale != combineAlphaScale)) { + return false; + } + + // now check if the operands for the combine equations are + // equivalent + + int nOpNeeded = 0; + + if (combineRgbMode == TextureAttributes.COMBINE_REPLACE) { + nOpNeeded = 1; + } else if (combineRgbMode == TextureAttributes.COMBINE_INTERPOLATE) { + nOpNeeded = 3; + } else { + nOpNeeded = 2; + } + + for (int i = 0; i < nOpNeeded; i++) { + if ((tr.combineRgbSrc[i] != combineRgbSrc[i]) || + (tr.combineAlphaSrc[i] != combineAlphaSrc[i]) || + (tr.combineRgbFcn[i] != combineRgbFcn[i]) || + (tr.combineAlphaFcn[i] != combineAlphaFcn[i])) { + return false; + } + } + } + + // now check for texture color table + + if (tr.textureColorTable == null) { + if (this.textureColorTable == null) + return true; + else + return false; + } else if (this.textureColorTable == null) { + // tr.textureColorTable != null + return false; + } else { + if (tr.textureColorTable.length != this.textureColorTable.length) + return false; + + for (int i = 0; i < this.textureColorTable.length; i++) { + if (this.textureColorTable[i] != tr.textureColorTable[i]) + return false; + } + + return true; + } + + } + + + protected Object clone() { + TextureAttributesRetained tr = (TextureAttributesRetained)super.clone(); + tr.transform = new Transform3D(transform); + tr.textureBlendColor = new Color4f(textureBlendColor); + if (textureColorTable != null) { + tr.textureColorTable = new int[textureColorTable.length]; + System.arraycopy(textureColorTable, 0, tr.textureColorTable, 0, + textureColorTable.length); + } else { + tr.textureColorTable = null; + } + + // clone the combine mode attributes + if (combineRgbSrc != null) { + tr.combineRgbSrc = new int[3]; + tr.combineAlphaSrc = new int[3]; + tr.combineRgbFcn = new int[3]; + tr.combineAlphaFcn = new int[3]; + + for (int i = 0; i < 3; i++) { + tr.combineRgbSrc[i] = combineRgbSrc[i]; + tr.combineAlphaSrc[i] = combineAlphaSrc[i]; + tr.combineRgbFcn[i] = combineRgbFcn[i]; + tr.combineAlphaFcn[i] = combineAlphaFcn[i]; + } + } + + // other attributes are copied in super.clone() + return tr; + } + + protected void set(TextureAttributesRetained tr) { + super.set(tr); + transform.set(tr.transform); + textureBlendColor.set(tr.textureBlendColor); + textureMode = tr.textureMode; + perspCorrectionMode = tr.perspCorrectionMode; + + // set texture color table + + if (tr.textureColorTable != null) { + if (textureColorTable == null || + textureColorTable.length != tr.textureColorTable.length) { + textureColorTable = new int[tr.textureColorTable.length]; + } + System.arraycopy(tr.textureColorTable, 0, textureColorTable, 0, + tr.textureColorTable.length); + } else { + textureColorTable = null; + } + numTextureColorTableComponents = tr.numTextureColorTableComponents; + textureColorTableSize = tr.textureColorTableSize; + + + // set the combine mode attributes + + combineRgbMode = tr.combineRgbMode; + combineAlphaMode = tr.combineAlphaMode; + combineRgbScale = tr.combineRgbScale; + combineAlphaScale = tr.combineAlphaScale; + + if (tr.combineRgbSrc != null) { + if (combineRgbSrc == null) { + combineRgbSrc = new int[3]; + combineAlphaSrc = new int[3]; + combineRgbFcn = new int[3]; + combineAlphaFcn = new int[3]; + } + + for (int i = 0; i < 3; i++) { + combineRgbSrc[i] = tr.combineRgbSrc[i]; + combineAlphaSrc[i] = tr.combineAlphaSrc[i]; + combineRgbFcn[i] = tr.combineRgbFcn[i]; + combineAlphaFcn[i] = tr.combineAlphaFcn[i]; + } + } + } + + + final void sendMessage(int attrMask, Object attr1, Object attr2) { + + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.TEXTUREATTRIBUTES_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1] = new Integer(attrMask); + createMessage.args[2] = attr1; + createMessage.args[3] = attr2; + createMessage.args[4] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i 0 && texUnitState[0] != null) { + prevFirstTexture = texUnitState[0].texture; + } + + for (i = 0; i < state.length; i++) { + if (state[i] == null) { + texUnitState[i] = null; + foundDisableUnit = true; + } else { + + // create a clone texture unit state + if (texUnitState[i] == null) { + texUnitState[i] = new TextureUnitStateRetained(); + } + + // for sole user TextureUnitState, save + // the node component reference in the mirror reference + // of the cloned copy for equal test, and + // for native download optimization + if (soleUser || state[i].changedFrequent != 0) { + texUnitState[i].mirror = state[i]; + } + + // for the lowest level of node component in + // TextureBin, clone it only if it is not + // changedFrequent; in other words, if the + // lowest level of texture related node components + // such as TextureAttributes & TexCoordGen is + // changedFrequent, have the cloned texUnitState + // reference the mirror of those node components + // directly. For Texture, we'll always reference + // the mirror. + + // decrement the TextureBin ref count of the previous + // texture + tex = texUnitState[i].texture; + if (tex != null) { + tex.decTextureBinRefCount(this); + if (soleUser && + (tex.getTextureBinRefCount(this) == 0) && + (tex != state[i].texture)) { + // In this case texture change but + // TextureBin will not invoke clear() to reset. + // So we need to free the texture resource here. + renderBin.addTextureResourceFreeList(tex); + } + } + + texUnitState[i].texture = state[i].texture; + + // increment the TextureBin ref count of the new + // texture + + if (texUnitState[i].texture != null) { + texUnitState[i].texture.incTextureBinRefCount(this); + } + + if (state[i].texAttrs != null) { + + if (state[i].texAttrs.changedFrequent != 0) { + texUnitState[i].texAttrs = state[i].texAttrs; + + } else { + + // need to check for texAttrs.source because + // texAttrs could be pointing to the mirror + // in the last frame, so don't want to + // overwrite the mirror + + if (texUnitState[i].texAttrs == null || + texUnitState[i].texAttrs.source != null) { + texUnitState[i].texAttrs = + new TextureAttributesRetained(); + } + texUnitState[i].texAttrs.set( + state[i].texAttrs); + texUnitState[i].texAttrs.mirrorCompDirty = true; + + // for sole user TextureBin, we are saving + // the mirror node component in the mirror + // reference in the clone object. This + // will be used in state download to + // avoid redundant download + + if (soleUser) { + texUnitState[i].texAttrs.mirror = + state[i].texAttrs; + } else { + texUnitState[i].texAttrs.mirror = null; + } + + } + } else { + texUnitState[i].texAttrs = null; + } + + + if (state[i].texGen != null) { + if (state[i].texGen.changedFrequent != 0) { + texUnitState[i].texGen = state[i].texGen; + } else { + + // need to check for texGen.source because + // texGen could be pointing to the mirror + // in the last frame, so don't want to + // overwrite the mirror + + if (texUnitState[i].texGen == null || + texUnitState[i].texGen.source != null) { + texUnitState[i].texGen = + new TexCoordGenerationRetained(); + } + + texUnitState[i].texGen.set(state[i].texGen); + texUnitState[i].texGen.mirrorCompDirty = true; + + + // for sole user TextureBin, we are saving + // the mirror node component in the mirror + // reference in the clone object. This + // will be used in state download to + // avoid redundant download + + if (soleUser) { + texUnitState[i].texGen.mirror = state[i].texGen; + } else { + texUnitState[i].texGen.mirror = null; + } + } + } else { + texUnitState[i].texGen = null; + } + + + // Track the last active texture unit and the total number + // of active texture units. Note that this total number + // now includes disabled units so that there is always + // a one-to-one mapping. We no longer remap texture units. + if (texUnitState[i].isTextureEnabled()) { + lastActiveTexUnitIndex = i; + numActiveTexUnit = i + 1; + + if (foundDisableUnit) { + + // mark that active texture units are not + // contiguous + tbFlag &= ~TextureBin.CONTIGUOUS_ACTIVE_UNITS; + } + } else { + foundDisableUnit = true; + } + } + } + + // check to see if the TextureBin sorting criteria is + // modified for this textureBin; if yes, mark that + // resorting is needed + + if ((texUnitState[0] == null && prevFirstTexture != null) || + (texUnitState[0] != null && + texUnitState[0].texture != prevFirstTexture)) { + tbFlag |= TextureBin.RESORT; + } + + } else { + + // check to see if the TextureBin sorting criteria is + // modified for this textureBin; if yes, mark that + // resorting is needed + + if (texUnitState != null && texUnitState[0].texture != null) { + tbFlag |= TextureBin.RESORT; + } + texUnitState = null; + } + + soleUserCompDirty = 0; + } + + + /** + * The TextureBin is to be removed from RenderBin, + * do the proper unsetting of any references + */ + void clear() { + + // make sure there is no reference to the scenegraph + app = null; + + // for each texture referenced in the texture units, decrement + // the reference count. If the reference count == 0, tell + // the renderer to free up the resource + if (texUnitState != null) { + + TextureRetained tex; + + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null) { + if (texUnitState[i].texture != null) { + tex = texUnitState[i].texture; + tex.decTextureBinRefCount(this); + + if (tex.getTextureBinRefCount(this) == 0) { + renderBin.addTextureResourceFreeList(tex); + } + + texUnitState[i].texture = null; + } + + // make sure there is no more reference to the scenegraph + + texUnitState[i].mirror = null; + texUnitState[i].texture = null; + if (texUnitState[i].texAttrs != null && + texUnitState[i].texAttrs.source != null) { + texUnitState[i].texAttrs = null; + } + if (texUnitState[i].texGen != null && + texUnitState[i].texGen.source != null) { + texUnitState[i].texGen = null; + } + } + } + } + } + + + + /** + * This tests if the qiven textureUnitState matches this TextureBin + */ + boolean equals(TextureUnitStateRetained state[], RenderAtom ra) { + + int i, j, k = 0; + TextureRetained texture; + + // if this TextureBin is a soleUser case or the incoming + // app has changedFrequent bit set for any of the texture + // related component, then either the current TextureBin + // or the incoming app requires the same app match + if (((tbFlag & TextureBin.SOLE_USER) != 0) || + ((ra.app != null) && + (ra.app.changedFrequent & + (AppearanceRetained.TEXTURE | + AppearanceRetained.TEXCOORD_GEN | + AppearanceRetained.TEXTURE_ATTR | + AppearanceRetained.TEXTURE_UNIT_STATE)) != 0)) { + + if (app == ra.app) { + + // if this textureBin is currently on a zombie state, + // we'll need to put it on the update list to reevaluate + // the state, because while it is on a zombie state, + // texture state could have been changed. Example, + // application could have detached an appearance, + // made changes to the texture references, and then + // reattached the appearance. In this case, the texture + // changes would not have reflected to the textureBin + + if (numEditingRenderMolecules == 0) { + + //System.err.println("===> TB in zombie state " + this); + + if (soleUserCompDirty == 0) { + this.renderBin.tbUpdateList.add(this); + } + soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_REF; + } + return true; + + } else { + return false; + } + } + + if (texUnitState == null && state == null) + return (true); + + if (texUnitState == null || state == null) + return (false); + + if (state.length != texUnitState.length) + return (false); + + for (i = 0; i < texUnitState.length; i++) { + // If texture Unit State is null + if (texUnitState[i] == null) { + if (state[i] != null) + return (false); + } + else { + if (!texUnitState[i].equivalent(state[i])) { + return (false); + } + } + } + + // Check if the image component has changed(may be a clearLive texture + // change img component. setLive case) + // + if ((tbFlag & TextureBin.ON_RENDER_BIN_LIST) == 0) { + renderBin.addTextureBin(this); + tbFlag |= TextureBin.ON_RENDER_BIN_LIST; + } + + return (true); + + } + + + /* + // updateNodeComponentCheck is called for each soleUser TextureBin + // into which new renderAtom has been added. This method is called before + // updateNodeComponent() to allow TextureBin to catch any node + // component changes that have been missed because the changes + // come when there is no active renderAtom associated with the + // TextureBin. See bug# 4503926 for details. + public void updateNodeComponentCheck() { + + //System.err.println("TextureBin.updateNodeComponentCheck()"); + + tbFlag &= ~TextureBin.ON_UPDATE_CHECK_LIST; + + if ((soleUserCompDirty & SOLE_USER_DIRTY_REF) != 0) { + return ; + } + + if ((app.compChanged & (AppearanceRetained.TEXTURE | + AppearanceRetained.TEXCOORD_GEN | + AppearanceRetained.TEXTURE_ATTR | + AppearanceRetained.TEXTURE_UNIT_STATE)) != 0) { + if (soleUserCompDirty == 0) { + this.renderBin.tbUpdateList.add(this); + } + soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_REF; + + } else if (app.texUnitState != null) { + + // if one texture unit state has to be reevaluated, then + // it's enough update checking because reevaluating texture unit + // state will automatically take care of its node component + // updates. + + boolean done = false; + + for (int i = 0; i < app.texUnitState.length && !done; i++) { + if (app.texUnitState[i] != null) { + if (app.texUnitState[i].compChanged != 0) { + if (soleUserCompDirty == 0) { + this.renderBin.tbUpdateList.add(this); + } + soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TUS; + done = true; + } else { + if (app.texUnitState[i].texAttrs != null && + app.texUnitState[i].texAttrs.compChanged != 0) { + if (soleUserCompDirty == 0) { + this.renderBin.tbUpdateList.add(this); + } + soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TA; + } + if (app.texUnitState[i].texGen != null && + app.texUnitState[i].texGen.compChanged != 0) { + if (soleUserCompDirty == 0) { + this.renderBin.tbUpdateList.add(this); + } + soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TC; + } + if (app.texUnitState[i].texture != null && + ((app.texUnitState[i].texture.compChanged & + TextureRetained.ENABLE_CHANGED) != 0)) { + if (soleUserCompDirty == 0) { + this.renderBin.tbUpdateList.add(this); + } + soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TEXTURE; + } + } + } + } + } + } + */ + + + + + /** + * updateNodeComponent is called from RenderBin to update the + * clone copy of the sole user node component in TextureBin when the + * corresponding node component is being modified + */ + public void updateNodeComponent() { + + // don't bother to update if the TextureBin is already + // removed from RenderBin + + if ((tbFlag & TextureBin.ON_RENDER_BIN_LIST) == 0) + return; + + // if any of the texture reference in the appearance referenced + // by a sole user TextureBin is being modified, just do a reset + + if (((tbFlag & TextureBin.SOLE_USER) != 0) && + ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_REF) != 0)) { + + resetTextureState(app.texUnitState); + return; + } + + if (texUnitState == null) { + soleUserCompDirty = 0; + return; + } + + if ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_TUS) != 0) { + + // Now take care of the Texture Unit State changes + TextureUnitStateRetained tus, mirrorTUS = null; + boolean soleUser = ((tbFlag & TextureBin.SOLE_USER) != 0); + + for (int i = 0; i < texUnitState.length; i++) { + tus = texUnitState[i]; + if (tus != null) { + if (tus.mirror != null) { + + mirrorTUS = (TextureUnitStateRetained)tus.mirror; + + if (tus.texture != mirrorTUS.texture) { + if (tus.texture != null) { + tus.texture.decTextureBinRefCount(this); + } + tus.texture = mirrorTUS.texture; + if (tus.texture != null) { + tus.texture.incTextureBinRefCount(this); + } + + // the first texture (TextureBin sorting + // criteria) is modified, so needs to resort + + if (i == 0) { + tbFlag |= TextureBin.RESORT; + } + } + + + if (mirrorTUS.texAttrs != null) { + if (mirrorTUS.texAttrs.changedFrequent != 0) { + tus.texAttrs = mirrorTUS.texAttrs; + } else { + if (tus.texAttrs == null || + tus.texAttrs.source != null) { + tus.texAttrs = + new TextureAttributesRetained(); + } + tus.texAttrs.set(mirrorTUS.texAttrs); + tus.texAttrs.mirrorCompDirty = true; + + if (soleUser) { + tus.texAttrs.mirror = mirrorTUS.texAttrs; + } else { + tus.texAttrs.mirror = null; + } + } + } else { + tus.texAttrs = null; + } + + if (mirrorTUS.texGen != null) { + if (mirrorTUS.texGen.changedFrequent != 0) { + tus.texGen = mirrorTUS.texGen; + } else { + if (tus.texGen == null || + tus.texGen.source != null) { + tus.texGen = + new TexCoordGenerationRetained(); + } + tus.texGen.set(mirrorTUS.texGen); + tus.texGen.mirrorCompDirty = true; + + if (soleUser) { + tus.texGen.mirror = mirrorTUS.texGen; + } else { + tus.texGen.mirror = null; + } + } + } else { + tus.texGen = null; + } + } + } + } + + // need to reEvaluate # of active textures after the update + soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TEXTURE; + + // TextureUnitState update automatically taken care of + // TextureAttributes & TexCoordGeneration update + + soleUserCompDirty &= ~(TextureBin.SOLE_USER_DIRTY_TA | + TextureBin.SOLE_USER_DIRTY_TC); + } + + if ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_TEXTURE) != 0) { + + + + boolean foundDisableUnit = false; + + numActiveTexUnit = 0; + lastActiveTexUnitIndex = 0; + tbFlag |= TextureBin.CONTIGUOUS_ACTIVE_UNITS; + for (int i = 0; i < texUnitState.length; i++) { + + // Track the last active texture unit and the total number + // of active texture units. Note that this total number + // now includes disabled units so that there is always + // a one-to-one mapping. We no longer remap texture units. + if (texUnitState[i] != null && + texUnitState[i].isTextureEnabled()) { + lastActiveTexUnitIndex = i; + numActiveTexUnit = i + 1; + + if (foundDisableUnit) { + + // mark that active texture units are not + // contiguous + tbFlag &= ~TextureBin.CONTIGUOUS_ACTIVE_UNITS; + } + } else { + foundDisableUnit = true; + } + } + } + + if ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_TA) != 0) { + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null && + texUnitState[i].texAttrs != null && + texUnitState[i].texAttrs.mirror != null && + texUnitState[i].texAttrs.mirror.changedFrequent != 0) { + texUnitState[i].texAttrs = (TextureAttributesRetained) + texUnitState[i].texAttrs.mirror; + } + } + } + + if ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_TC) != 0) { + for (int i = 0; i < texUnitState.length; i++) { + if (texUnitState[i] != null && + texUnitState[i].texGen != null && + texUnitState[i].texGen.mirror != null && + texUnitState[i].texGen.mirror.changedFrequent != 0) { + texUnitState[i].texGen = (TexCoordGenerationRetained) + texUnitState[i].texGen.mirror; + } + } + } + + soleUserCompDirty = 0; + } + + public void updateObject() { + if (!addOpaqueRMs.isEmpty()) { + opaqueRMList = addAll(opaqueRenderMoleculeMap, addOpaqueRMs, + opaqueRMList, true); + } + if (!addTransparentRMs.isEmpty()) { + // If transparent and not in bg geometry and inodepth + // sorted transparency + if (transparentRMList == null && + (renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE || + environmentSet.lightBin.geometryBackground != null)) { + // System.err.println("========> addTransparentTextureBin "+this); + transparentRMList = addAll(transparentRenderMoleculeMap, + addTransparentRMs, transparentRMList, false); + // Eventhough we are adding to transparentList , if all the RMS + // have been switched already due to changeLists, then there is + // nothing to add, and TBIN does not have any transparentRMList + if (transparentRMList != null) { + renderBin.addTransparentObject(this); + } + + } + else { + transparentRMList = addAll(transparentRenderMoleculeMap, + addTransparentRMs, transparentRMList, false); + } + } + tbFlag &= ~TextureBin.ON_UPDATE_LIST; + + } + + + /** + * Each list of renderMoledule with the same localToVworld + * is connect by rm.next and rm.prev. + * At the end of the list (i.e. rm.next = null) the field + * rm.nextMap is link to another list (with the same + * localToVworld). So during rendering it will traverse + * rm.next until this is null, then follow the .nextMap + * to access another list and use rm.next to continue + * until both rm.next and rm.nextMap are null. + * + * renderMoleculeMap is use to assist faster location of + * renderMolecule List with the same localToVWorld. The + * start of renderMolecule in the list with same + * localToVworld is insert in renderMoleculeMap. This + * map is clean up at removeRenderMolecule(). TextureBin + * also use the map for quick location of renderMolecule + * with the same localToVworld and attributes in + * findRenderMolecule(). + */ + RenderMolecule addAll(HashMap renderMoleculeMap, HashMap addRMs, + RenderMolecule startList, + boolean opaqueList) { + int i; + RenderMolecule r; + Collection c = addRMs.values(); + Iterator listIterator = c.iterator(); + RenderMolecule renderMoleculeList, head; + + while (listIterator.hasNext()) { + boolean changed = false; + ArrayList curList = (ArrayList)listIterator.next(); + r = (RenderMolecule)curList.get(0); + // If this is a opaque one , but has been switched to a transparentList or + // vice-versa (dur to changeLists function called before this), then + // do nothing! + // For changedFrequent case: Consider the case when a RM is added + // (so is in the addRM list) and then + // a change in transparent value occurs that make it from opaque to + // transparent (the switch is handled before this function is called) + if (r.isOpaqueOrInOG != opaqueList) { + continue; + } + // Get the list of renderMolecules for this transform + renderMoleculeList = (RenderMolecule)renderMoleculeMap.get( + r.localToVworld); + if (renderMoleculeList == null) { + renderMoleculeList = r; + renderMoleculeMap.put(r.localToVworld, renderMoleculeList); + // Add this renderMolecule at the beginning of RM list + if (startList == null) { + startList = r; + r.nextMap = null; + r.prevMap = null; + startList.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS; + } + else { + r.nextMap = startList; + startList.prevMap = r; + startList = r; + startList.nextMap.checkEquivalenceWithLeftNeighbor(r, + RenderMolecule.ALL_DIRTY_BITS); + } + + } + else { + // Insert the renderMolecule next to a RM that has equivalent + // texture unit state + if ((head = insertRenderMolecule(r, renderMoleculeList)) != null) { + if (renderMoleculeList.prevMap != null) { + renderMoleculeList.prevMap.nextMap = head; + } + head.prevMap = renderMoleculeList.prevMap; + renderMoleculeList.prevMap = null; + renderMoleculeList = head; + changed = true; + } + } + for (i = 1; i < curList.size(); i++) { + r = (RenderMolecule)curList.get(i); + // If this is a opaque one , but has been switched to a transparentList or + // vice-versa (dur to changeLists function called before this), then + // do nothing! + // For changedFrequent case: Consider the case when a RM is added + // (so is in the addRM list) and then + // a change in transparent value occurs that make it from opaque to + // transparent (the switch is handled before this function is called) + if (r.isOpaqueOrInOG != opaqueList) + continue; + if ((head = insertRenderMolecule(r, renderMoleculeList)) != null) { + if (renderMoleculeList.prevMap != null) { + renderMoleculeList.prevMap.nextMap = head; + } + head.prevMap = renderMoleculeList.prevMap; + renderMoleculeList.prevMap = null; + renderMoleculeList = head; + changed = true; + } + + } + if (changed) { + renderMoleculeMap.put(r.localToVworld, renderMoleculeList); + if (renderMoleculeList.prevMap != null) { + renderMoleculeList.checkEquivalenceWithLeftNeighbor( + renderMoleculeList.prevMap, + RenderMolecule.ALL_DIRTY_BITS); + } + else { + startList = renderMoleculeList; + startList.dirtyAttrsAcrossRms = + RenderMolecule.ALL_DIRTY_BITS; + } + } + } + + addRMs.clear(); + return startList; + } + + + // XXXX: Could the analysis be done during insertRenderMolecule? + // Return the head of the list, + // if the insertion occurred at beginning of the list + RenderMolecule insertRenderMolecule(RenderMolecule r, + RenderMolecule renderMoleculeList) { + RenderMolecule rm, retval; + + // Look for a RM that has an equivalent material + rm = renderMoleculeList; + while (rm != null) { + if (rm.material == r.material || + (rm.definingMaterial != null && + rm.definingMaterial.equivalent(r.definingMaterial))) { + // Put it here + r.next = rm; + r.prev = rm.prev; + if (rm.prev == null) { + renderMoleculeList = r; + retval = renderMoleculeList; + } else { + rm.prev.next = r; + retval = null; + } + rm.prev = r; + r.checkEquivalenceWithBothNeighbors(RenderMolecule.ALL_DIRTY_BITS); + return retval; + } + // If they are not equivalent, then skip to the first one + // that has a different material using the dirty bits + else { + rm = rm.next; + while (rm != null && + ((rm.dirtyAttrsAcrossRms & RenderMolecule.MATERIAL_DIRTY) == 0)) { + rm = rm.next; + } + } + } + // Just put it up front + r.next = renderMoleculeList; + renderMoleculeList.prev = r; + renderMoleculeList = r; + r.checkEquivalenceWithBothNeighbors(RenderMolecule.ALL_DIRTY_BITS); + return renderMoleculeList; + } + + + /** + * Adds the given RenderMolecule to this TextureBin + */ + void addRenderMolecule(RenderMolecule r, RenderBin rb) { + RenderMolecule rm; + ArrayList list; + HashMap map; + r.textureBin = this; + + if (r.isOpaqueOrInOG) + map = addOpaqueRMs; + else + map = addTransparentRMs; + + if ((list = (ArrayList)map.get(r.localToVworld)) == null) { + list = new ArrayList(); + map.put(r.localToVworld, list); + } + list.add(r); + + if ((tbFlag & TextureBin.ON_UPDATE_LIST) == 0) { + tbFlag |= TextureBin.ON_UPDATE_LIST; + rb.objUpdateList.add(this); + } + } + + /** + * Removes the given RenderMolecule from this TextureBin + */ + void removeRenderMolecule(RenderMolecule r) { + ArrayList list; + int index; + boolean found = false; + RenderMolecule renderMoleculeList, rmlist; + HashMap addMap; + HashMap allMap; + r.textureBin = null; + + if (r.isOpaqueOrInOG) { + rmlist = opaqueRMList; + allMap = opaqueRenderMoleculeMap; + addMap = addOpaqueRMs; + } + else { + rmlist = transparentRMList; + allMap = transparentRenderMoleculeMap; + addMap = addTransparentRMs; + } + // If the renderMolecule being remove is contained in addRMs, then + // remove the renderMolecule from the addList + if ((list = (ArrayList) addMap.get(r.localToVworld)) != null) { + if ((index = list.indexOf(r)) != -1) { + list.remove(index); + // If this was the last element for this localToVworld, then remove + // the entry from the addRMs list + if (list.isEmpty()) { + addMap.remove(r.localToVworld); + } + + r.prev = null; + r.next = null; + found = true; + } + } + if (!found) { + RenderMolecule head = removeOneRM(r, allMap, rmlist); + + r.soleUserCompDirty = 0; + r.onUpdateList = 0; + if (r.definingPolygonAttributes != null && + (r.definingPolygonAttributes.changedFrequent != 0)) + r.definingPolygonAttributes = null; + + if (r.definingLineAttributes != null && + (r.definingLineAttributes.changedFrequent != 0)) + r.definingLineAttributes = null; + + if (r.definingPointAttributes != null && + (r.definingPointAttributes.changedFrequent != 0)) + r.definingPointAttributes = null; + + if (r.definingMaterial != null && + (r.definingMaterial.changedFrequent != 0)) + r.definingMaterial = null; + + if (r.definingColoringAttributes != null && + (r.definingColoringAttributes.changedFrequent != 0)) + r.definingColoringAttributes = null; + + if (r.definingTransparency != null && + (r.definingTransparency.changedFrequent != 0)) + r.definingTransparency = null; + + renderBin.removeRenderMolecule(r); + if (r.isOpaqueOrInOG) { + opaqueRMList = head; + } + else { + transparentRMList = head; + } + + } + // If the renderMolecule removed is not opaque then .. + if (!r.isOpaqueOrInOG && transparentRMList == null && (renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE || + environmentSet.lightBin.geometryBackground != null)) { + renderBin.removeTransparentObject(this); + } + // If the rm removed is the one that is referenced in the tinfo + // then change this reference + else if (parentTInfo != null && parentTInfo.rm == r) { + parentTInfo.rm = transparentRMList; + } + // Removal of this texture setting from the texCoordGenartion + // is done during the removeRenderAtom routine in RenderMolecule.java + // Only remove this texture bin if there are no more renderMolcules + // waiting to be added + if (opaqueRenderMoleculeMap.isEmpty() && addOpaqueRMs.isEmpty() && + transparentRenderMoleculeMap.isEmpty() && addTransparentRMs.isEmpty()) { + if ((tbFlag & TextureBin.ON_RENDER_BIN_LIST) != 0) { + tbFlag &= ~TextureBin.ON_RENDER_BIN_LIST; + renderBin.removeTextureBin(this); + } + + shaderBin.removeTextureBin(this); + texUnitState = null; + } + } + + /** + * This method is called to update the state for this + * TextureBin. This is only applicable in the single-pass case. + * Multi-pass render will have to take care of its own + * state update. + */ + void updateAttributes(Canvas3D cv) { + + boolean dirty = ((cv.canvasDirty & (Canvas3D.TEXTUREBIN_DIRTY| + Canvas3D.TEXTUREATTRIBUTES_DIRTY)) != 0); + + if (cv.textureBin == this && !dirty) { + return; + } + + cv.textureBin = this; + + // save the current number of active texture unit so as + // to be able to reset the one that is not enabled in this bin + + int lastActiveTexUnitIdx = -1; + + // Get the number of available texture units; this depends on + // whether or not shaders are being used. + boolean useShaders = (shaderBin.shaderProgram != null); + int availableTextureUnits = + useShaders ? cv.maxTextureImageUnits : cv.maxTextureUnits; + + // If the number of active texture units is greater than the number of + // supported units, then we + // need to set a flag indicating that the texture units are invalid. + boolean disableTexture = false; + + if (numActiveTexUnit > availableTextureUnits) { + disableTexture = true; +// System.err.println("*** TextureBin : number of texture units exceeded"); + } + + // set the number active texture unit in Canvas3D + if (disableTexture) { + cv.setNumActiveTexUnit(0); + } + else { + cv.setNumActiveTexUnit(numActiveTexUnit); + } + + // state update + if (numActiveTexUnit <= 0 || disableTexture) { + if (cv.getLastActiveTexUnit() >= 0) { + // no texture units enabled + + // when the canvas supports multi texture units, + // we'll need to reset texture for all texture units + if (cv.multiTexAccelerated) { + for (int i = 0; i <= cv.getLastActiveTexUnit(); i++) { + cv.resetTexture(cv.ctx, i); + } + // set the active texture unit back to 0 + cv.setNumActiveTexUnit(0); + cv.activeTextureUnit(cv.ctx, 0); + } else { + cv.resetTexture(cv.ctx, -1); + } + cv.setLastActiveTexUnit(-1); + } + } else { + + int j = 0; + + for (int i = 0; i < texUnitState.length; i++) { + + if (j >= cv.texUnitState.length) { + // We finish enabling the texture state. + // Note that it is possible + // texUnitState.length > cv.texUnitState.length + + break; + } + + if ((texUnitState[i] != null) && + texUnitState[i].isTextureEnabled()) { + if (dirty || + cv.texUnitState[j].mirror == null || + cv.texUnitState[j].mirror != texUnitState[i].mirror) { + // update the texture unit state + texUnitState[i].updateNative(j, cv, false, false); + cv.texUnitState[j].mirror = texUnitState[i].mirror; + } + + // create a mapping that maps an active texture + // unit to a texture unit state + + lastActiveTexUnitIdx = j; + } else { + if (j <= cv.getLastActiveTexUnit()) { + cv.resetTexture(cv.ctx, j); + } + } + + j++; + } + + // make sure to disable the remaining texture units + // since they could have been enabled from the previous + // texture bin + + for (int i = j; i <= cv.getLastActiveTexUnit(); i++) { + cv.resetTexture(cv.ctx, i); + } + + cv.setLastActiveTexUnit(lastActiveTexUnitIdx); + + // set the active texture unit back to 0 + cv.activeTextureUnit(cv.ctx, 0); + + } + cv.canvasDirty &= ~Canvas3D.TEXTUREBIN_DIRTY; + } + + + /** + * Renders this TextureBin + */ + void render(Canvas3D cv) { + render(cv, (Object) opaqueRMList); + } + + void render(Canvas3D cv, Object rlist) { + + cv.texLinearMode = false; + + /* + System.err.println("TextureBin/render " + this + + " numActiveTexUnit= " + numActiveTexUnit + + " maxTextureUnits= " + cv.maxTextureUnits); + */ + + // include this TextureBin to the to-be-updated state set in canvas + cv.setStateToUpdate(Canvas3D.TEXTUREBIN_BIT, this); + + // For D3D - set the texLinearMode flag in the canvas if texcoord + // generation is enabled in object_linear mode for any texture unit. + if ((texUnitState != null) && VirtualUniverse.mc.isD3D()) { + TextureUnitStateRetained tus; + for (int i = 0; i < texUnitState.length; i++) { + tus = texUnitState[i]; + if ((tus != null) && tus.isTextureEnabled()) { + if ((tus.texGen != null) && + (tus.texGen.genMode == TexCoordGeneration.OBJECT_LINEAR)) { + cv.texLinearMode = true; + } + } + } + } + + renderList(cv, USE_DISPLAYLIST, rlist); + } + + + /** + * render a render list + */ + void renderList(Canvas3D cv, int pass, Object rlist) { + assert pass < 0; + + if (rlist instanceof RenderMolecule) { + renderList(cv, pass, (RenderMolecule) rlist); + } else if (rlist instanceof TransparentRenderingInfo) { + renderList(cv, pass, (TransparentRenderingInfo) rlist); + } + } + + + /** + * render list of RenderMolecule + */ + void renderList(Canvas3D cv, int pass, RenderMolecule rlist) { + assert pass < 0; + + // bit mask of all attr fields that are equivalent across + // renderMolecules thro. ORing of invisible RMs. + int combinedDirtyBits = 0; + boolean rmVisible = true; + RenderMolecule rm = rlist; + + while (rm != null) { + if(rmVisible) { + combinedDirtyBits = rm.dirtyAttrsAcrossRms; + } + else { + combinedDirtyBits |= rm.dirtyAttrsAcrossRms; + } + + rmVisible = rm.render(cv, pass, combinedDirtyBits); + + + // next render molecule or the nextmap + if (rm.next == null) { + rm = rm.nextMap; + } + else { + rm = rm.next; + } + } + } + + + /** + * render sorted transparent list + */ + void renderList(Canvas3D cv, int pass, TransparentRenderingInfo tinfo) { + assert pass < 0; + + RenderMolecule rm = tinfo.rm; + if (rm.isSwitchOn()) { + rm.transparentSortRender(cv, pass, tinfo); + } + } + + + void changeLists(RenderMolecule r) { + RenderMolecule renderMoleculeList, rmlist = null, head; + HashMap allMap = null; + ArrayList list; + int index; + boolean newRM = false; + // System.err.println("changeLists r = "+r+" tBin = "+this); + // If its a new RM then do nothing, otherwise move lists + if (r.isOpaqueOrInOG) { + if (opaqueRMList == null && + (r.prev == null && r.prevMap == null && r.next == null && + r.nextMap == null)) { + newRM = true; + } + else { + rmlist = opaqueRMList; + allMap = opaqueRenderMoleculeMap; + } + + } + else { + if (transparentRMList == null && + (r.prev == null && r.prevMap == null && r.next == null && + r.nextMap == null) ){ + newRM = true; + } + else { + rmlist = transparentRMList; + allMap = transparentRenderMoleculeMap; + } + } + if (!newRM) { + head = removeOneRM(r, allMap, rmlist); + + if (r.isOpaqueOrInOG) { + opaqueRMList = head; + } + else { + transparentRMList = head; + if (transparentRMList == null && + (renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE || + environmentSet.lightBin.geometryBackground != null)) { + renderBin.removeTransparentObject(this); + } + // Issue 129: remove the RM's render atoms from the + // list of transparent render atoms + if ((renderBin.transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY) && + (environmentSet.lightBin.geometryBackground == null)) { + r.addRemoveTransparentObject(renderBin, false); + } + } + } + HashMap renderMoleculeMap; + RenderMolecule startList; + + // Now insert in the other bin + r.evalAlphaUsage(shaderBin.attributeBin.definingRenderingAttributes, texUnitState); + r.isOpaqueOrInOG = r.isOpaque() ||r.inOrderedGroup; + if (r.isOpaqueOrInOG) { + startList = opaqueRMList; + renderMoleculeMap = opaqueRenderMoleculeMap; + markDlistAsDirty(r); + } + else { + startList = transparentRMList; + renderMoleculeMap = transparentRenderMoleculeMap; + if ((r.primaryMoleculeType &RenderMolecule.DLIST_MOLECULE) != 0 && + renderBin.transpSortMode != View.TRANSPARENCY_SORT_NONE) { + renderBin.addDisplayListResourceFreeList(r); + renderBin.removeDirtyRenderMolecule(r); + + r.vwcBounds.set(null); + r.displayListId = 0; + r.displayListIdObj = null; + // Change the group type for all the rlistInfo in the primaryList + RenderAtomListInfo rinfo = r.primaryRenderAtomList; + while (rinfo != null) { + rinfo.groupType = RenderAtom.SEPARATE_DLIST_PER_RINFO; + if (rinfo.renderAtom.dlistIds == null) { + rinfo.renderAtom.dlistIds = new int[rinfo.renderAtom.rListInfo.length]; + + for (int k = 0; k < rinfo.renderAtom.dlistIds.length; k++) { + rinfo.renderAtom.dlistIds[k] = -1; + } + } + if (rinfo.renderAtom.dlistIds[rinfo.index] == -1) { + rinfo.renderAtom.dlistIds[rinfo.index] = VirtualUniverse.mc.getDisplayListId().intValue(); + renderBin.addDlistPerRinfo.add(rinfo); + } + rinfo = rinfo.next; + } + r.primaryMoleculeType = RenderMolecule.SEPARATE_DLIST_PER_RINFO_MOLECULE; + } + else { + markDlistAsDirty(r); + } + + } + renderMoleculeList = (RenderMolecule)renderMoleculeMap.get(r.localToVworld); + + if (renderMoleculeList == null) { + renderMoleculeList = r; + renderMoleculeMap.put(r.localToVworld, renderMoleculeList); + // Add this renderMolecule at the beginning of RM list + if (startList == null) { + startList = r; + r.nextMap = null; + r.prevMap = null; + } + else { + r.nextMap = startList; + startList.prevMap = r; + startList = r; + startList.nextMap.checkEquivalenceWithLeftNeighbor(r,RenderMolecule.ALL_DIRTY_BITS); + } + // Issue 67 : since we are adding the new RM at the head, we must + // set all dirty bits unconditionally + startList.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS; + } + else { + // Insert the renderMolecule next to a RM that has equivalent + // texture unit state + if ((head = insertRenderMolecule(r, renderMoleculeList)) != null) { + if (renderMoleculeList.prevMap != null) { + renderMoleculeList.prevMap.nextMap = head; + } + head.prevMap = renderMoleculeList.prevMap; + renderMoleculeList.prevMap = null; + renderMoleculeList = head; + renderMoleculeMap.put(r.localToVworld, renderMoleculeList); + if (renderMoleculeList.prevMap != null) { + renderMoleculeList.checkEquivalenceWithLeftNeighbor(renderMoleculeList.prevMap, + RenderMolecule.ALL_DIRTY_BITS); + } + else { + startList.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS; + startList = renderMoleculeList; + } + } + + } + if (r.isOpaqueOrInOG) { + opaqueRMList = startList; + } + else { + // If transparent and not in bg geometry and inodepth sorted transparency + if (transparentRMList == null&& + (renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE || + environmentSet.lightBin.geometryBackground != null)) { + transparentRMList = startList; + renderBin.addTransparentObject(this); + } + else { + transparentRMList = startList; + } + // Issue 129: add the RM's render atoms to the list of + // transparent render atoms + // XXXX: do we need to resort the list after the add??? + if ((renderBin.transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY) && + (environmentSet.lightBin.geometryBackground == null)) { + r.addRemoveTransparentObject(renderBin, true); + } + } + } + + RenderMolecule removeOneRM(RenderMolecule r, HashMap allMap, RenderMolecule list) { + RenderMolecule rmlist = list; + // In the middle, just remove and update + if (r.prev != null && r.next != null) { + r.prev.next = r.next; + r.next.prev = r.prev; + r.next.checkEquivalenceWithLeftNeighbor(r.prev,RenderMolecule.ALL_DIRTY_BITS); + } + // If whats is removed is at the end of an entry + else if (r.prev != null && r.next == null) { + r.prev.next = r.next; + r.prev.nextMap = r.nextMap; + if (r.nextMap != null) { + r.nextMap.prevMap = r.prev; + r.nextMap.checkEquivalenceWithLeftNeighbor(r.prev,RenderMolecule.ALL_DIRTY_BITS); + } + } + else if (r.prev == null && r.next != null) { + r.next.prev = null; + r.next.prevMap = r.prevMap; + if (r.prevMap != null) { + r.prevMap.nextMap = r.next; + r.next.checkEquivalenceWithLeftNeighbor(r.prevMap,RenderMolecule.ALL_DIRTY_BITS); + } + // Head of the rmList + else { + rmlist = r.next; + rmlist.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS; + } + allMap.put(r.localToVworld, r.next); + } + // Update the maps and remove this entry from the map list + else if (r.prev == null && r.next == null) { + if (r.prevMap != null) { + r.prevMap.nextMap = r.nextMap; + + } + else { + rmlist = r.nextMap; + if (r.nextMap != null) { + rmlist.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS; + } + } + if (r.nextMap != null) { + r.nextMap.prevMap = r.prevMap; + if (r.prevMap != null) { + r.nextMap.checkEquivalenceWithLeftNeighbor(r.prevMap,RenderMolecule.ALL_DIRTY_BITS); + } + + } + + allMap.remove(r.localToVworld); + + + } + r.prev = null; + r.next = null; + r.prevMap = null; + r.nextMap = null; + return rmlist; + } + + void markDlistAsDirty(RenderMolecule r) { + + if (r.primaryMoleculeType == RenderMolecule.DLIST_MOLECULE) { + renderBin.addDirtyRenderMolecule(r); + } + else if (r.primaryMoleculeType == RenderMolecule.SEPARATE_DLIST_PER_RINFO_MOLECULE) { + RenderAtomListInfo ra = r.primaryRenderAtomList; + while (ra != null) { + renderBin.addDlistPerRinfo.add(ra); + ra = ra.next; + } + } + } + + + void decrActiveRenderMolecule() { + numEditingRenderMolecules--; + + if (numEditingRenderMolecules == 0) { + + // if number of editing renderMolecules goes to 0, + // inform the shaderBin that this textureBin goes to + // zombie state + + shaderBin.decrActiveTextureBin(); + } + } + + void incrActiveRenderMolecule() { + + if (numEditingRenderMolecules == 0) { + + // if this textureBin is in zombie state, inform + // the shaderBin that this textureBin is activated again. + + shaderBin.incrActiveTextureBin(); + } + + numEditingRenderMolecules++; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TextureCubeMap.java b/j3d-core/src/classes/share/javax/media/j3d/TextureCubeMap.java new file mode 100644 index 0000000..d1f45c4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TextureCubeMap.java @@ -0,0 +1,403 @@ +/* + * $RCSfile: TextureCubeMap.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * TextureCubeMap is a subclass of Texture class. It defines + * a special kind of texture mapping which is composed of a set of six + * 2D images representating the six faces of a cube. The texture coordinate + * (s,t,r) is used as a 3D direction vector emanating from the center + * of a cube to select a particular face of the cube based on the + * largest magnitude coordinate (the major axis). A new 2D texture coordinate + * (s,t) is then determined by dividing the other two coordinates (the minor + * axes) by the major axis value. The new coordinate is then used for + * texel lookup from the selected texture image of this cube map. + * + * The TextureCubeMap image is defined by specifying the images for each + * face of the cube. The cube map texture can be thought of as centered at + * the orgin of and aligned to an XYZ coordinate system. The names + * of the cube faces are: + * + *

    + *
  • POSITIVE_X
  • + *
  • NEGATIVE_X
  • + *
  • POSITIVE_Y
  • + *
  • NEGATIVE_Y
  • + *
  • POSITIVE_Z
  • + *
  • NEGATIVE_Z
  • + *
+ * + *

+ * Note that as of Java 3D 1.5, the texture width and height are no longer + * required to be an exact power of two. However, not all graphics devices + * supports non-power-of-two textures. If non-power-of-two texture mapping is + * unsupported on a particular Canvas3D, textures with a width or height that + * are not an exact power of two are ignored for that canvas. + * + * @see Canvas3D#queryProperties + * + * @since Java 3D 1.3 + */ +public class TextureCubeMap extends Texture { + + // TODO KCR : NPOT + + /** + * Specifies the face of the cube that is pierced by the positive x axis + */ + public static final int POSITIVE_X = 0; + + /** + * Specifies the face of the cube that is pierced by the negative x axis + */ + public static final int NEGATIVE_X = 1; + + /** + * Specifies the face of the cube that is pierced by the positive y axis + */ + public static final int POSITIVE_Y = 2; + + /** + * Specifies the face of the cube that is pierced by the negative y axis + */ + public static final int NEGATIVE_Y = 3; + + /** + * Specifies the face of the cube that is pierced by the positive z axis + */ + public static final int POSITIVE_Z = 4; + + /** + * Specifies the face of the cube that is pierced by the negative z axis + */ + public static final int NEGATIVE_Z = 5; + + + /** + * Constructs a texture object using default values. + * Note that the default constructor creates a texture object with + * a width of 0 and is, therefore, not useful. + */ + public TextureCubeMap() { + super(); + } + + /** + * Constructs an empty TextureCubeMap object with specified mipmapMode + * format, and width. Image at base level + * must be set by + * the application using 'setImage' method. If mipmapMode is + * set to MULTI_LEVEL_MIPMAP, images for base level through maximum level + * must be set. + * Note that cube map is square in dimensions, hence specifying width + * is sufficient. + * Note also that a texture with a non-power-of-two width will + * only be rendered on a graphics device that supports non-power-of-two + * textures. + * + * @param mipmapMode type of mipmap for this Texture: One of + * BASE_LEVEL, MULTI_LEVEL_MIPMAP. + * @param format data format of Textures saved in this object. + * One of INTENSITY, LUMINANCE, ALPHA, LUMINANCE_ALPHA, RGB, RGBA. + * @param width width (and height) of image at level 0. + * @exception IllegalArgumentException if width is not greater + * than 0 OR invalid format/mipmapMode is specified. + */ + public TextureCubeMap( + int mipmapMode, + int format, + int width){ + + super(mipmapMode, format, width, width); + } + + /** + * Constructs an empty TextureCubeMap object with specified mipmapMode + * format, width, and boundary width. Image at base level + * must be set by + * the application using 'setImage' method. If mipmapMode is + * set to MULTI_LEVEL_MIPMAP, images for base level through maximum level + * must be set. + * Note that cube map is square in dimensions, hence specifying width + * is sufficient. + * Note also that a texture with a non-power-of-two width will + * only be rendered on a graphics device that supports non-power-of-two + * textures. + * + * @param mipmapMode type of mipmap for this Texture: One of + * BASE_LEVEL, MULTI_LEVEL_MIPMAP. + * @param format data format of Textures saved in this object. + * One of INTENSITY, LUMINANCE, ALPHA, LUMINANCE_ALPHA, RGB, RGBA. + * @param width width (and height) of image at level 0. This + * does not include the width of the boundary. + * @param boundaryWidth width of the boundary, which must be 0 or 1. + * + * @exception IllegalArgumentException if width is not + * greater than 0 OR invalid format/mipmapMode is specified. + */ + public TextureCubeMap( + int mipmapMode, + int format, + int width, + int boundaryWidth){ + + super(mipmapMode, format, width, width, boundaryWidth); + } + + /** + * Sets the image for a specified mipmap level of a specified face + * of the cube map + * + * @param level mipmap level + * @param face face of the cube map. One of: + * POSITIVE_X, NEGATIVE_X, + * POSITIVE_Y, NEGATIVE_Y, + * POSITIVE_Z or NEGATIVE_Z. + * @param image ImageComponent2D object containing the image + * + * @exception IllegalArgumentException if + * face has a value other + * than POSITIVE_X, NEGATIVE_X, + * POSITIVE_Y, NEGATIVE_Y, + * POSITIVE_Z or NEGATIVE_Z. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalSharingException if this TextureCubeMap is live and + * the specified image is being used by a Canvas3D as an off-screen buffer. + * + * @exception IllegalSharingException if this TextureCubeMap is + * being used by an immediate mode context and + * the specified image is being used by a Canvas3D as an off-screen buffer. + */ + public void setImage(int level, int face, ImageComponent2D image) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_WRITE)) + throw new CapabilityNotSetException( + J3dI18N.getString("TextureCubeMap1")); + } + + validateImageIllegalSharing(image); + + if (isLive()) + ((TextureCubeMapRetained)this.retained).setImage(level, face, image); + else + ((TextureCubeMapRetained)this.retained).initImage(level, face, image); + } + + /** + * Sets the array of images for mipmap levels from base level through + * max level for a specified face of the cube map + * + * @param face face of the cube map. One of: + * POSITIVE_X, NEGATIVE_X, + * POSITIVE_Y, NEGATIVE_Y, + * POSITIVE_Z or NEGATIVE_Z. + * @param images array of ImageComponent2D objects containing the images + * + * @exception IllegalArgumentException if + * face has a value other + * than POSITIVE_X, NEGATIVE_X, + * POSITIVE_Y, NEGATIVE_Y, + * POSITIVE_Z or NEGATIVE_Z. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @exception IllegalSharingException if this TextureCubeMap is live and + * any of the specified images are being used by a Canvas3D as an + * off-screen buffer. + * + * @exception IllegalSharingException if this TextureCubeMap is + * being used by an immediate mode context and + * any of the specified images are being used by a Canvas3D as an + * off-screen buffer. + */ + public void setImages(int face, ImageComponent2D[] images) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_WRITE)) + throw new CapabilityNotSetException( + J3dI18N.getString("TextureCubeMap1")); + } + + // Do illegal sharing check + for(int i=0; iPOSITIVE_X, NEGATIVE_X, + * POSITIVE_Y, NEGATIVE_Y, + * POSITIVE_Z or NEGATIVE_Z. + * @return the ImageComponent object containing the texture image at + * the specified mipmap level. + * + * @exception IllegalArgumentException if + * face has a value other + * than POSITIVE_X, NEGATIVE_X, + * POSITIVE_Y, NEGATIVE_Y, + * POSITIVE_Z or NEGATIVE_Z. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ImageComponent getImage(int level, int face) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_READ)) + throw new CapabilityNotSetException( + J3dI18N.getString("TextureCubeMap2")); + } + + return ((TextureCubeMapRetained)this.retained).getImage(level, face); + } + + /** + * Retrieves the array of images for all mipmap level of a particular + * face of the cube map. + * @param face face of the cube map. One of: + * POSITIVE_X, NEGATIVE_X, + * POSITIVE_Y, NEGATIVE_Y, + * POSITIVE_Z or NEGATIVE_Z. + * @return an array of ImageComponent object for the particular face of + * of the cube map. + * + * @exception IllegalArgumentException if + * face has a value other + * than POSITIVE_X, NEGATIVE_X, + * POSITIVE_Y, NEGATIVE_Y, + * POSITIVE_Z or NEGATIVE_Z. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public ImageComponent[] getImages(int face) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_IMAGE_READ)) + throw new CapabilityNotSetException( + J3dI18N.getString("TextureCubeMap2")); + } + + return ((TextureCubeMapRetained)this.retained).getImages(face); + } + + + /** + * This method is not supported for TextureCubeMap. + * A face of the cube map has to be specified when setting an image + * for a particular level of the cube map. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setImage(int level, ImageComponent image) { + throw new UnsupportedOperationException(); + } + + + /** + * This method is not supported for TextureCubeMap. + * A face of the cube map has to be specified when setting images + * for the cube map. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public void setImages(ImageComponent[] images) { + throw new UnsupportedOperationException(); + } + + /** + * This method is not supported for TextureCubeMap. + * A face of the cube map has to be specified when retrieving an image + * for a particular level of the cube map. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public ImageComponent getImage(int level) { + throw new UnsupportedOperationException(); + } + + + /** + * This method is not supported for TextureCubeMap. + * A face of the cube map has to be specified when retrieving images + * for the cube map. + * + * @exception UnsupportedOperationException this method is not supported + * + * @since Java 3D 1.3 + */ + public ImageComponent[] getImages() { + throw new UnsupportedOperationException(); + } + + + /** + * Creates a retained mode TextureCubeMapRetained object that this + * TextureCubeMap component object will point to. + */ + void createRetained() { + this.retained = new TextureCubeMapRetained(); + this.retained.setSource(this); + } + + /** + * NOTE: Applications should not call this method directly. + * It should only be called by the cloneNode method. + * + * @deprecated replaced with duplicateNodeComponent( + * NodeComponent originalNodeComponent, boolean forceDuplicate) + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent) { + checkDuplicateNodeComponent(originalNodeComponent); + } +} + diff --git a/j3d-core/src/classes/share/javax/media/j3d/TextureCubeMapRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TextureCubeMapRetained.java new file mode 100644 index 0000000..2e70682 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TextureCubeMapRetained.java @@ -0,0 +1,352 @@ +/* + * $RCSfile: TextureCubeMapRetained.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; +import javax.vecmath.Color4f; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; + +/** + * TextureCubeMap is a subclass of Texture class. + */ +class TextureCubeMapRetained extends TextureRetained { + + + static final int NUMFACES = 6; + + + void initialize(int format, int width, int widPower, + int height, int heiPower, int mipmapMode, + int boundaryWidth) { + + this.numFaces = 6; + + super.initialize(format, width, widPower, height, heiPower, + mipmapMode, boundaryWidth); + } + + + /** + * Sets a specified mipmap level for a particular face of the cubemap. + */ + void initImage(int level, int face, ImageComponent image) { + + // Issue 172 : call checkImageSize even for non-live setImage calls + checkImageSize(level, image); + + if (this.images == null) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureRetained0")); + } + + if (image instanceof ImageComponent3D) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureCubeMap3")); + } + + + if (face < TextureCubeMap.POSITIVE_X || + face > TextureCubeMap.NEGATIVE_Z) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureCubeMap4")); + } + + if (this.source.isLive()) { + if (this.images[face][level] != null) { + this.images[face][level].clearLive(refCount); + } + + + if (image != null) { + ((ImageComponentRetained)image.retained).setLive( + inBackgroundGroup, refCount); + } + } + + /* Don't think this is needed. --- Chien. + ((ImageComponent2DRetained)image.retained).setTextureRef(); + */ + + if (image != null) { + this.images[face][level] = (ImageComponentRetained)image.retained; + } else { + this.images[face][level] = null; + } + } + + final void setImage(int level, int face, ImageComponent image) { + + initImage(level, face, image); + + Object arg[] = new Object[3]; + arg[0] = new Integer(level); + arg[1] = image; + arg[2] = new Integer(face); + sendMessage(IMAGE_CHANGED, arg); + + // If the user has set enable to true, then if the image is null + // turn off texture enable + if (userSpecifiedEnable) { + enable = userSpecifiedEnable; + if (image != null && level < maxLevels) { + ImageComponentRetained img= (ImageComponentRetained)image.retained; + if (img.isByReference()) { + if (img.getRefImage(0) == null) { + enable = false; + } + } + else { + if (img.getImageData(isUseAsRaster()).get() == null) { + enable = false; + } + } + if (!enable) + sendMessage(ENABLE_CHANGED, Boolean.FALSE); + } + } + } + + void initImages(int face, ImageComponent[] images) { + + if (images.length != maxLevels) + throw new IllegalArgumentException(J3dI18N.getString("Texture20")); + + for (int i = 0; i < images.length; i++) { + initImage(i, face, images[i]); + } + } + + final void setImages(int face, ImageComponent[] images) { + + int i; + + initImages(face, images); + + ImageComponent [] imgs = new ImageComponent[images.length]; + for (i = 0; i < images.length; i++) { + imgs[i] = images[i]; + } + + Object args[] = new Object[2]; + args[0] = imgs; + args[1] = new Integer(face); + + sendMessage(IMAGES_CHANGED, args); + // If the user has set enable to true, then if the image is null + // turn off texture enable + if (userSpecifiedEnable) { + enable = userSpecifiedEnable; + i = 0; + while (enable && i < maxLevels) { + if (images[i] != null) { + ImageComponentRetained img= (ImageComponentRetained)images[i].retained; + if (img.isByReference()) { + if (img.getRefImage(0) == null) { + enable = false; + } + } + else { + if (img.getImageData(isUseAsRaster()).get() == null) { + enable = false; + } + } + } + i++; + } + if (!enable) { + sendMessage(ENABLE_CHANGED, Boolean.FALSE); + } + } + } + + + + + /** + * Gets a specified mipmap level of a particular face of the cube map. + * @param level mipmap level to get + * @param face face of the cube map + * @return the pixel array object containing the texture image + */ + final ImageComponent getImage(int level, int face) { + + if (face < TextureCubeMap.POSITIVE_X || + face > TextureCubeMap.NEGATIVE_Z) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureCubeMap4")); + } + + return (((images != null) && (images[face][level] != null)) ? + (ImageComponent)images[face][level].source : null); + } + + + /** + * Gets an array of image for a particular face of the cube map. + * @param face face of the cube map + * @return the pixel array object containing the texture image + */ + final ImageComponent[] getImages(int face) { + + if (images == null) + return null; + + if (face < TextureCubeMap.POSITIVE_X || + face > TextureCubeMap.NEGATIVE_Z) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureCubeMap4")); + } + + ImageComponent [] rImages = new ImageComponent[images[face].length]; + for (int i = 0; i < images[face].length; i++) { + if (images[face][i] != null) + rImages[i] = (ImageComponent)images[face][i].source; + else + rImages[i] = null; + } + return rImages; + } + + + void bindTexture(Context ctx, int objectId, boolean enable) { + Pipeline.getPipeline().bindTextureCubeMap(ctx, objectId, enable); + } + + void updateTextureBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + + Pipeline.getPipeline().updateTextureCubeMapBoundary(ctx, + boundaryModeS, boundaryModeT, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTextureFilterModes(Context ctx, + int minFilter, int magFilter) { + + Pipeline.getPipeline().updateTextureCubeMapFilterModes(ctx, + minFilter, magFilter); + } + + void updateTextureSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + + Pipeline.getPipeline().updateTextureCubeMapSharpenFunc(ctx, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTextureFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + + Pipeline.getPipeline().updateTextureCubeMapFilter4Func(ctx, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTextureAnisotropicFilter(Context ctx, float degree) { + Pipeline.getPipeline().updateTextureCubeMapAnisotropicFilter(ctx, degree); + } + + + void updateTextureLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + + Pipeline.getPipeline().updateTextureCubeMapLodRange(ctx, baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + void updateTextureLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + + Pipeline.getPipeline().updateTextureCubeMapLodOffset(ctx, + lodOffsetX, lodOffsetY, lodOffsetZ); + } + + + /** + * Load level 0 explicitly with null data pointer to allow + * mipmapping when level 0 is not the base level + */ + void updateTextureDimensions(Canvas3D cv) { + if(images[0][0] != null) { + // All faces should have the same image format and type. + int imageFormat = images[0][0].getImageFormatTypeIntValue(false); + int imageType = images[0][0].getImageDataTypeIntValue(); + + for (int i = 0; i < 6; i++) { + updateTextureImage(cv, i, maxLevels, 0, + format, imageFormat, + width, height, boundaryWidth, + imageType, null); + } + } + } + + // This is just a wrapper of the native method. + void updateTextureImage(Canvas3D cv, + int face, int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, int imageDataType, + Object imageData) { + + Pipeline.getPipeline().updateTextureCubeMapImage(cv.ctx, + face, numLevels, level, + textureFormat, imageFormat, + width, height, + boundaryWidth, imageDataType, imageData, useAutoMipMapGeneration(cv)); + } + + // This is just a wrapper of the native method. + void updateTextureSubImage(Canvas3D cv, + int face, int level, + int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int imageDataType, Object imageData) { + + Pipeline.getPipeline().updateTextureCubeMapSubImage(cv.ctx, + face, level, xoffset, yoffset, + textureFormat, imageFormat, + imgXOffset, imgYOffset, + tilew, width, height, + imageDataType, imageData, useAutoMipMapGeneration(cv)); + + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TextureRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TextureRetained.java new file mode 100644 index 0000000..53cc922 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TextureRetained.java @@ -0,0 +1,2537 @@ +/* + * $RCSfile: TextureRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.17 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; +import javax.vecmath.*; +import java.awt.image.DataBufferByte; +import java.awt.image.RenderedImage; + +/** + * The Texture object is a component object of an Appearance object + * that defines the texture properties used when texture mapping is + * enabled. Texture object is an abstract class and all texture + * objects must be created as either a Texture2D object or a + * Texture3D object. + */ +abstract class TextureRetained extends NodeComponentRetained { + // A list of pre-defined bits to indicate which component + // in this Texture object changed. + static final int ENABLE_CHANGED = 0x001; + static final int COLOR_CHANGED = 0x002; + static final int IMAGE_CHANGED = 0x004; + static final int STATE_CHANGED = 0x008; + static final int UPDATE_IMAGE = 0x010; + static final int IMAGES_CHANGED = 0x020; + static final int BASE_LEVEL_CHANGED = 0x040; + static final int MAX_LEVEL_CHANGED = 0x080; + static final int MIN_LOD_CHANGED = 0x100; + static final int MAX_LOD_CHANGED = 0x200; + static final int LOD_OFFSET_CHANGED = 0x400; + + // constants for min and mag filter + static final int MIN_FILTER = 0; + static final int MAG_FILTER = 1; + + // Boundary width + int boundaryWidth = 0; + + // Boundary modes (wrap, clamp, clamp_to_edge, clamp_to_boundary) + int boundaryModeS = Texture.WRAP; + int boundaryModeT = Texture.WRAP; + + // Filter modes + int minFilter = Texture.BASE_LEVEL_POINT; + int magFilter = Texture.BASE_LEVEL_POINT; + + // Integer flag that contains bitset to indicate + // which field changed. + int isDirty = 0xffff; + + // Texture boundary color + Color4f boundaryColor = new Color4f(0.0f, 0.0f, 0.0f, 0.0f); + + // Texture Object Id used by native code. + int objectId = -1; + + int mipmapMode = Texture.BASE_LEVEL; // Type of mip-mapping + int format = Texture.RGB; // Texture format + int width = 1; // Width in pixels (2**n) + int height = 1; // Height in pixels (2**m) + + // true if width or height is non power of two + private boolean widthOrHeightIsNPOT = false; + // Array of images (one for each mipmap level) + ImageComponentRetained images[][]; + // maximum number of levels needed for the mipmapMode of this texture + int maxLevels = 0; + // maximum number of mipmap levels that can be defined for this texture + private int maxMipMapLevels = 0; + + int numFaces = 1; // For CubeMap, it is 6 + int baseLevel = 0; + int maximumLevel = 0; + float minimumLod = -1000.0f; + float maximumLod = 1000.0f; + Point3f lodOffset = null; + + private boolean useAsRaster = false; // true if used by Raster or Background. + + // Texture mapping enable switch + // This enable is derived from the user specified enable + // and whether the buf image in the imagecomp is null + boolean enable = true; + + // User specified enable + boolean userSpecifiedEnable = true; + + + // true if alpha channel need update during rendering + boolean isAlphaNeedUpdate = false; + + // sharpen texture info + int numSharpenTextureFuncPts = 0; + float sharpenTextureFuncPts[] = null; // array of pairs of floats + // first value for LOD + // second value for the fcn value + + // filter4 info + float filter4FuncPts[] = null; + + // anisotropic filter info + int anisotropicFilterMode = Texture.ANISOTROPIC_NONE; + float anisotropicFilterDegree = 1.0f; + + + // Each bit corresponds to a unique renderer if shared context + // or a unique canvas otherwise. + // This mask specifies which renderer/canvas has loaded the + // texture images. 0 means no renderer/canvas has loaded the texture. + // 1 at the particular bit means that renderer/canvas has loaded the + // texture. 0 means otherwise. + int resourceCreationMask = 0x0; + + // Each bit corresponds to a unique renderer if shared context + // or a unique canvas otherwise + // This mask specifies if texture images are up-to-date. + // 0 at a particular bit means texture images are not up-to-date. + // 1 means otherwise. If it specifies 0, then it needs to go + // through the imageUpdateInfo to update the images accordingly. + // + int resourceUpdatedMask = 0x0; + + // Each bit corresponds to a unique renderer if shared context + // or a unique canvas otherwise + // This mask specifies if texture lod info is up-to-date. + // 0 at a particular bit means texture lod info is not up-to-date. + // 1 means otherwise. + // + int resourceLodUpdatedMask = 0x0; + + // Each bit corresponds to a unique renderer if shared context + // or a unique canvas otherwise + // This mask specifies if texture is in the resource reload list + // 0 at a particular bit means texture is not in reload list + // 1 means otherwise. + // + int resourceInReloadList = 0x0; + + // image update info + ArrayList imageUpdateInfo[][]; + + + int imageUpdatePruneMask[]; + + // Issue 357 - we need a separate reference counter per RenderBin, since + // each RenderBin keeps an independent list of Texture objects to be freed. + // Since this is accessed infrequently, we will use a HashMap for the + // textureBin reference counter + private HashMap textureBinRefCount = + new HashMap(); + + // This is used for D3D only to check whether texture need to + // resend down + private int texTimestamp = 0; + + // need to synchronize access from multiple rendering threads + Object resourceLock = new Object(); + + private static boolean isPowerOfTwo(int val) { + return ((val & (val - 1)) == 0); + } + + void initialize(int format, int width, int widLevels, + int height, int heiLevels, int mipmapMode, + int boundaryWidth) { + + this.mipmapMode = mipmapMode; + this.format = format; + this.width = width; + this.height = height; + this.boundaryWidth = boundaryWidth; + + if(!isPowerOfTwo(width) || !isPowerOfTwo(height)) { + this.widthOrHeightIsNPOT = true; + } + + // determine the maximum number of mipmap levels that can be + // defined from the specified dimension + + if (widLevels > heiLevels) { + maxMipMapLevels = widLevels + 1; + } else { + maxMipMapLevels = heiLevels + 1; + } + + + // determine the maximum number of mipmap levels that will be + // needed with the current mipmapMode + + if (mipmapMode != Texture.BASE_LEVEL) { + baseLevel = 0; + maximumLevel = maxMipMapLevels - 1; + maxLevels = maxMipMapLevels; + } else { + baseLevel = 0; + maximumLevel = 0; + maxLevels = 1; + } + + images = new ImageComponentRetained[numFaces][maxLevels]; + + for (int j = 0; j < numFaces; j++) { + for (int i = 0; i < maxLevels; i++) { + images[j][i] = null; + } + } + } + + final int getFormat() { + return this.format; + } + + final int getWidth() { + return this.width; + } + + final int getHeight() { + return this.height; + } + + final int numMipMapLevels() { + return (maximumLevel - baseLevel + 1); + } + + /** + * Sets the boundary mode for the S coordinate in this texture object. + * @param boundaryModeS the boundary mode for the S coordinate, + * one of: CLAMP or WRAP. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final void initBoundaryModeS(int boundaryModeS) { + this.boundaryModeS = boundaryModeS; + } + + /** + * Retrieves the boundary mode for the S coordinate. + * @return the current boundary mode for the S coordinate. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final int getBoundaryModeS() { + return boundaryModeS; + } + + /** + * Sets the boundary mode for the T coordinate in this texture object. + * @param boundaryModeT the boundary mode for the T coordinate, + * one of: CLAMP or WRAP. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final void initBoundaryModeT(int boundaryModeT) { + this.boundaryModeT = boundaryModeT; + } + + /** + * Retrieves the boundary mode for the T coordinate. + * @return the current boundary mode for the T coordinate. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final int getBoundaryModeT() { + return boundaryModeT; + } + + /** + * Retrieves the boundary width. + * @return the boundary width of this texture. + */ + final int getBoundaryWidth() { + return boundaryWidth; + } + + /** + * Sets the minification filter function. This + * function is used when the pixel being rendered maps to an area + * greater than one texel. + * @param minFilter the minification filter, one of: + * FASTEST, NICEST, BASE_LEVEL_POINT, BASE_LEVEL_LINEAR, + * MULTI_LEVEL_POINT, MULTI_LEVEL_LINEAR. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final void initMinFilter(int minFilter) { + this.minFilter = minFilter; + } + + /** + * Retrieves the minification filter. + * @return the current minification filter function. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final int getMinFilter() { + return minFilter; + } + + /** + * Sets the magnification filter function. This + * function is used when the pixel being rendered maps to an area + * less than or equal to one texel. + * @param magFilter the magnification filter, one of: + * FASTEST, NICEST, BASE_LEVEL_POINT, or BASE_LEVEL_LINEAR. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final void initMagFilter(int magFilter) { + this.magFilter = magFilter; + } + + /** + * Retrieves the magnification filter. + * @return the current magnification filter function. + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final int getMagFilter() { + return magFilter; + } + + /** + * Sets a specified mipmap level. + * @param level mipmap level to set: 0 is the base level + * @param image pixel array object containing the texture image + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + * @exception IllegalArgumentException if an ImageComponent3D + * is used in a Texture2D or ImageComponent2D in Texture3D + * power of 2 OR invalid format/mipmapMode is specified. + */ + void initImage(int level, ImageComponent image) { + + // Issue 172 : call checkImageSize even for non-live setImage calls + checkImageSize(level, image); + + if (this.images == null) { + throw new IllegalArgumentException(J3dI18N.getString("TextureRetained0")); + } + + if (this.source instanceof Texture2D) { + if (image instanceof ImageComponent3D) + throw new IllegalArgumentException(J3dI18N.getString("Texture8")) +; + } else { + + if (image instanceof ImageComponent2D) + throw new IllegalArgumentException(J3dI18N.getString("Texture14") +); + } + + + if (this.source.isLive()) { + + if (this.images[0][level] != null) { + this.images[0][level].clearLive(refCount); + } + + + if (image != null) { + ((ImageComponentRetained)image.retained).setLive(inBackgroundGroup, refCount); + } + } + + if (image != null) { + this.images[0][level] = (ImageComponentRetained)image.retained; + + } else { + this.images[0][level] = null; + } + } + + final void checkImageSize(int level, ImageComponent image) { + if (image != null) { + int imgWidth = ((ImageComponentRetained)image.retained).width; + int imgHeight = ((ImageComponentRetained)image.retained).height; + + int wdh = width; + int hgt = height; + for (int i = 0; i < level; i++) { + wdh >>= 1; + hgt >>= 1; + } + + if (wdh < 1) wdh = 1; + if (hgt < 1) hgt = 1; + + if ((wdh != (imgWidth - 2*boundaryWidth)) || + (hgt != (imgHeight - 2*boundaryWidth))) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureRetained1")); + } + } + } + + final void checkSizes(ImageComponentRetained images[]) { + // Issue 172 : this method is now redundant + + // Assertion check that the image at each level is the correct size + // This shouldn't be needed since we already should have checked the + // size at each level, and verified that all levels are set. + if (images != null) { + int hgt = height; + int wdh = width; + for (int level = 0; level < images.length; level++) { + int imgWidth = images[level].width; + int imgHeight = images[level].height; + + assert (wdh == (imgWidth - 2*boundaryWidth)) && + (hgt == (imgHeight - 2*boundaryWidth)); + + wdh /= 2; + hgt /= 2; + if (wdh < 1) wdh = 1; + if (hgt < 1) hgt = 1; + } + } + } + + final void setImage(int level, ImageComponent image) { + initImage(level, image); + + Object arg[] = new Object[3]; + arg[0] = new Integer(level); + arg[1] = image; + arg[2] = new Integer(0); + sendMessage(IMAGE_CHANGED, arg); + + // If the user has set enable to true, then if the image is null + // turn off texture enable + + if (userSpecifiedEnable) { + enable = userSpecifiedEnable; + if (image != null && level >= baseLevel && level <= maximumLevel) { + ImageComponentRetained img= (ImageComponentRetained)image.retained; + if (img.isByReference()) { + if (img.getRefImage(0) == null) { + enable = false; + } + } + else { + if (img.getImageData(isUseAsRaster()).get() == null) { + enable = false; + } + } + if (!enable) + sendMessage(ENABLE_CHANGED, Boolean.FALSE); + } + } + } + + void initImages(ImageComponent[] images) { + + if (images.length != maxLevels) + throw new IllegalArgumentException(J3dI18N.getString("Texture20")); + + for (int i = 0; i < images.length; i++) { + initImage(i, images[i]); + } + } + + final void setImages(ImageComponent[] images) { + + int i; + + initImages(images); + + ImageComponent [] imgs = new ImageComponent[images.length]; + for (i = 0; i < images.length; i++) { + imgs[i] = images[i]; + } + + Object arg[] = new Object[2]; + arg[0] = imgs; + arg[1] = new Integer(0); + + sendMessage(IMAGES_CHANGED, arg); + + // If the user has set enable to true, then if the image is null + // turn off texture enable + + if (userSpecifiedEnable) { + enable = userSpecifiedEnable; + for (i = baseLevel; i <= maximumLevel && enable; i++) { + if (images[i] != null) { + ImageComponentRetained img= + (ImageComponentRetained)images[i].retained; + if (img.isByReference()) { + if (img.getRefImage(0) == null) { + enable = false; + } + } + else { + if (img.getImageData(isUseAsRaster()).get() == null) { + enable = false; + } + } + } + } + if (!enable) { + sendMessage(ENABLE_CHANGED, Boolean.FALSE); + } + } + } + + + + + /** + * Gets a specified mipmap level. + * @param level mipmap level to get: 0 is the base level + * @return the pixel array object containing the texture image + * @exception RestrictedAccessException if the method is called + * when this object is part of live or compiled scene graph. + */ + final ImageComponent getImage(int level) { + return (((images != null) && (images[0][level] != null)) ? + (ImageComponent)images[0][level].source : null); + } + + final ImageComponent[] getImages() { + if (images == null) + return null; + + ImageComponent [] rImages = new ImageComponent[images[0].length]; + for (int i = 0; i < images[0].length; i++) { + if (images[0][i] != null) + rImages[i] = (ImageComponent)images[0][i].source; + else + rImages[i] = null; + } + return rImages; + } + + /** + * Sets mipmap mode for texture mapping for this texture object. + * @param mipMapMode the new mipmap mode for this object. One of: + * BASE_LEVEL or MULTI_LEVEL_MIPMAP. + * @exception RestrictedAccessException if the method is called + */ + final void initMipMapMode(int mipmapMode) { + + if (this.mipmapMode == mipmapMode) + return; + + + int prevMaxLevels = maxLevels; // previous maxLevels + + this.mipmapMode = mipmapMode; + + if (mipmapMode != Texture.BASE_LEVEL) { + maxLevels = maxMipMapLevels; + } else { + baseLevel = 0; + maximumLevel = 0; + maxLevels = 1; + } + + + ImageComponentRetained[][] newImages = + new ImageComponentRetained[numFaces][maxLevels]; + + if (prevMaxLevels < maxLevels) { + for (int f = 0; f < numFaces; f++) { + for (int i = 0; i < prevMaxLevels; i++) { + newImages[f][i] = images[f][i]; + } + + for (int j = prevMaxLevels; j < maxLevels; j++) { + newImages[f][j] = null; + } + } + } else { + for (int f = 0; f < numFaces; f++) { + for (int i = 0; i < maxLevels; i++) + newImages[f][i] = images[f][i]; + } + } + images = newImages; + } + + /** + * Retrieves current mipmap mode. + * @return current mipmap mode of this texture object. + * @exception RestrictedAccessException if the method is called + */ + final int getMipMapMode() { + return this.mipmapMode; + } + + /** + * Enables or disables texture mapping for this + * appearance component object. + * @param state true or false to enable or disable texture mapping + */ + final void initEnable(boolean state) { + userSpecifiedEnable = state; + } + + /** + * Enables or disables texture mapping for this + * appearance component object and sends a + * message notifying the interested structures of the change. + * @param state true or false to enable or disable texture mapping + */ + final void setEnable(boolean state) { + + initEnable(state); + + if (state == enable) { + // if enable flag is same as user specified one + // this is only possible when enable is false + // because one of the images is null and user specifies false + return; + } + + enable = state; + + for (int j = 0; j < numFaces && enable; j++) { + for (int i = baseLevel; i <= maximumLevel && enable; i++) { + if (images[j][i].isByReference()) { + if (images[j][i].getRefImage(0) == null) { + enable = false; + } + } else { + if (images[j][i].getImageData(isUseAsRaster()).get() == null) { + enable = false; + } + } + } + } + sendMessage(ENABLE_CHANGED, (enable ? Boolean.TRUE: Boolean.FALSE)); + } + + /** + * Retrieves the state of the texture enable flag. + * @return true if texture mapping is enabled, + * false if texture mapping is disabled + */ + final boolean getEnable() { + return userSpecifiedEnable; + } + + + final void initBaseLevel(int level) { + if ((level < 0) || (level > maximumLevel)) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture36")); + } + baseLevel = level; + } + + + final void setBaseLevel(int level) { + + if (level == baseLevel) + return; + + initBaseLevel(level); + sendMessage(BASE_LEVEL_CHANGED, new Integer(level)); + } + + final int getBaseLevel() { + return baseLevel; + } + + + final void initMaximumLevel(int level) { + if ((level < baseLevel) || (level >= maxMipMapLevels)) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture37")); + } + if((mipmapMode == Texture.BASE_LEVEL) && (level != 0)) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture48")); + } + + maximumLevel = level; + } + + final void setMaximumLevel(int level) { + + if (level == maximumLevel) + return; + + initMaximumLevel(level); + sendMessage(MAX_LEVEL_CHANGED, new Integer(level)); + } + + final int getMaximumLevel() { + return maximumLevel; + } + + final void initMinimumLOD(float lod) { + if (lod > maximumLod) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture42")); + } + minimumLod = lod; + } + + final void setMinimumLOD(float lod) { + initMinimumLOD(lod); + sendMessage(MIN_LOD_CHANGED, new Float(lod)); + } + + final float getMinimumLOD() { + return minimumLod; + } + + + final void initMaximumLOD(float lod) { + if (lod < minimumLod) { + throw new IllegalArgumentException( + J3dI18N.getString("Texture42")); + } + maximumLod = lod; + } + + final void setMaximumLOD(float lod) { + initMaximumLOD(lod); + sendMessage(MAX_LOD_CHANGED, new Float(lod)); + } + + final float getMaximumLOD() { + return maximumLod; + } + + + final void initLodOffset(float s, float t, float r) { + if (lodOffset == null) { + lodOffset = new Point3f(s, t, r); + } else { + lodOffset.set(s, t, r); + } + } + + final void setLodOffset(float s, float t, float r) { + initLodOffset(s, t, r); + sendMessage(LOD_OFFSET_CHANGED, new Point3f(s, t, r)); + } + + final void getLodOffset(Tuple3f offset) { + if (lodOffset == null) { + offset.set(0.0f, 0.0f, 0.0f); + } else { + offset.set(lodOffset); + } + } + + + /** + * Sets the texture boundary color for this texture object. The + * texture boundary color is used when boundaryModeS or boundaryModeT + * is set to CLAMP. + * @param boundaryColor the new texture boundary color. + */ + final void initBoundaryColor(Color4f boundaryColor) { + this.boundaryColor.set(boundaryColor); + } + + /** + * Sets the texture boundary color for this texture object. The + * texture boundary color is used when boundaryModeS or boundaryModeT + * is set to CLAMP. + * @param r the red component of the color. + * @param g the green component of the color. + * @param b the blue component of the color. + * @param a the alpha component of the color. + */ + final void initBoundaryColor(float r, float g, float b, float a) { + this.boundaryColor.set(r, g, b, a); + } + + /** + * Retrieves the texture boundary color for this texture object. + * @param boundaryColor the vector that will receive the + * current texture boundary color. + */ + final void getBoundaryColor(Color4f boundaryColor) { + boundaryColor.set(this.boundaryColor); + } + + + /** + * Set Anisotropic Filter + */ + final void initAnisotropicFilterMode(int mode) { + anisotropicFilterMode = mode; + } + + final int getAnisotropicFilterMode() { + return anisotropicFilterMode; + } + + final void initAnisotropicFilterDegree(float degree) { + anisotropicFilterDegree = degree; + } + + final float getAnisotropicFilterDegree() { + return anisotropicFilterDegree; + } + + /** + * Set Sharpen Texture function + */ + final void initSharpenTextureFunc(float[] lod, float[] pts) { + if (lod == null) { // pts will be null too. + sharpenTextureFuncPts = null; + numSharpenTextureFuncPts = 0; + } else { + numSharpenTextureFuncPts = lod.length; + if ((sharpenTextureFuncPts == null) || + (sharpenTextureFuncPts.length != lod.length * 2)) { + sharpenTextureFuncPts = new float[lod.length * 2]; + } + for (int i = 0, j = 0; i < lod.length; i++) { + sharpenTextureFuncPts[j++] = lod[i]; + sharpenTextureFuncPts[j++] = pts[i]; + } + } + } + + final void initSharpenTextureFunc(Point2f[] pts) { + if (pts == null) { + sharpenTextureFuncPts = null; + numSharpenTextureFuncPts = 0; + } else { + numSharpenTextureFuncPts = pts.length; + if ((sharpenTextureFuncPts == null) || + (sharpenTextureFuncPts.length != pts.length * 2)) { + sharpenTextureFuncPts = new float[pts.length * 2]; + } + for (int i = 0, j = 0; i < pts.length; i++) { + sharpenTextureFuncPts[j++] = pts[i].x; + sharpenTextureFuncPts[j++] = pts[i].y; + } + } + } + + final void initSharpenTextureFunc(float[] pts) { + if (pts == null) { + sharpenTextureFuncPts = null; + numSharpenTextureFuncPts = 0; + } else { + numSharpenTextureFuncPts = pts.length / 2; + if ((sharpenTextureFuncPts == null) || + (sharpenTextureFuncPts.length != pts.length)) { + sharpenTextureFuncPts = new float[pts.length]; + } + for (int i = 0; i < pts.length; i++) { + sharpenTextureFuncPts[i] = pts[i]; + } + } + } + + /** + * Get number of points in the sharpen texture LOD function + */ + final int getSharpenTextureFuncPointsCount() { + return numSharpenTextureFuncPts; + } + + + /** + * Copies the array of sharpen texture LOD function points into the + * specified arrays + */ + final void getSharpenTextureFunc(float[] lod, float[] pts) { + if (sharpenTextureFuncPts != null) { + for (int i = 0, j = 0; i < numSharpenTextureFuncPts; i++) { + lod[i] = sharpenTextureFuncPts[j++]; + pts[i] = sharpenTextureFuncPts[j++]; + } + } + } + + final void getSharpenTextureFunc(Point2f[] pts) { + if (sharpenTextureFuncPts != null) { + for (int i = 0, j = 0; i < numSharpenTextureFuncPts; i++) { + pts[i].x = sharpenTextureFuncPts[j++]; + pts[i].y = sharpenTextureFuncPts[j++]; } } + } + + + final void initFilter4Func(float[] weights) { + if (weights == null) { + filter4FuncPts = null; + } else { + if ((filter4FuncPts == null) || + (filter4FuncPts.length != weights.length)) { + filter4FuncPts = new float[weights.length]; + } + for (int i = 0; i < weights.length; i++) { + filter4FuncPts[i] = weights[i]; + } + } + } + + + final int getFilter4FuncPointsCount() { + if (filter4FuncPts == null) { + return 0; + } else { + return filter4FuncPts.length; + } + } + + final void getFilter4Func(float[] weights) { + if (filter4FuncPts != null) { + for (int i = 0; i < filter4FuncPts.length; i++) { + weights[i] = filter4FuncPts[i]; + } + } + } + + + /** + * internal method only -- returns internal function points + */ + final float[] getSharpenTextureFunc() { + return sharpenTextureFuncPts; + } + + final float[] getFilter4Func(){ + return filter4FuncPts; + } + + + + + void setLive(boolean backgroundGroup, int refCount) { + + // This line should be assigned before calling doSetLive, so that + // the mirror object's enable is assigned correctly! + enable = userSpecifiedEnable; + + super.doSetLive(backgroundGroup, refCount); + + // XXXX: for now, do setLive for all the defined images. + // But in theory, we only need to setLive those within the + // baseLevel and maximumLevel range. But then we'll need + // setLive and clearLive image when the range changes. + + if (images != null) { + + for (int j = 0; j < numFaces; j++) { + for (int i = 0; i < maxLevels; i++){ + if (images[j][i] == null) { + throw new IllegalArgumentException( + J3dI18N.getString("TextureRetained3") + i); + } + images[j][i].setLive(backgroundGroup, refCount); + } + } + } + + // Issue 172 : assertion check the sizes of the images after we have + // checked for all mipmap levels being set + if (images != null) { + for (int j = 0; j < numFaces; j++) { + checkSizes(images[j]); + } + } + + // Send a message to Rendering Attr stucture to update the resourceMask + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.TEXTURE_CHANGED; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(UPDATE_IMAGE); + createMessage.args[2] = null; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + // If the user has set enable to true, then if the image is null + // turn off texture enable + if (userSpecifiedEnable) { + if (images != null) { + for (int j = 0; j < numFaces && enable; j++) { + for (int i = baseLevel; i <= maximumLevel && enable; i++){ + if (images[j][i].isByReference()) { + if (images[j][i].getRefImage(0) == null) { + enable = false; + } + } else { + if (images[j][i].getImageData(isUseAsRaster()).get() == null) { + enable = false; + } + } + } + } + } else { + enable = false; + } + if (!enable) + sendMessage(ENABLE_CHANGED, Boolean.FALSE); + } + + super.markAsLive(); + } + + void clearLive(int refCount) { + super.clearLive(refCount); + + if (images != null) { + for (int j = 0; j < numFaces; j++) { + for (int i = 0; i < maxLevels; i++) { + images[j][i].clearLive(refCount); + images[j][i].removeUser(mirror); + } + } + } + } + + /* + * The following methods update the native context. + * The implementation for Texture2D happens here. + * Texture3D and TextureCubeMap implement their own versions. + */ + + void bindTexture(Context ctx, int objectId, boolean enable) { + Pipeline.getPipeline().bindTexture2D(ctx, objectId, enable); + } + + void updateTextureBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + + Pipeline.getPipeline().updateTexture2DBoundary(ctx, + boundaryModeS, boundaryModeT, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTextureFilterModes(Context ctx, + int minFilter, int magFilter) { + + Pipeline.getPipeline().updateTexture2DFilterModes(ctx, + minFilter, magFilter); + } + + void updateTextureSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + + Pipeline.getPipeline().updateTexture2DSharpenFunc(ctx, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTextureFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + + Pipeline.getPipeline().updateTexture2DFilter4Func(ctx, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTextureAnisotropicFilter(Context ctx, float degree) { + Pipeline.getPipeline().updateTexture2DAnisotropicFilter(ctx, degree); + } + + void updateTextureLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + + Pipeline.getPipeline().updateTexture2DLodRange(ctx, baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + void updateTextureLodOffset(Context ctx, + float lodOffsetX, float lodOffsetY, + float lodOffsetZ) { + + Pipeline.getPipeline().updateTexture2DLodOffset(ctx, + lodOffsetX, lodOffsetY, lodOffsetZ); + } + + + // get an ID for Texture 2D + int getTextureId() { + return (VirtualUniverse.mc.getTexture2DId()); + } + + + // free a Texture2D id + void freeTextureId(int id) { + synchronized (resourceLock) { + if (objectId == id) { + objectId = -1; + VirtualUniverse.mc.freeTexture2DId(id); + } + } + } + + private boolean isEnabled(Canvas3D cv) { + if(widthOrHeightIsNPOT && !isUseAsRaster() && + ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_NON_POWER_OF_TWO ) == 0)) { + return false; + } + return enable; + } + + + // bind a named texture to a texturing target + void bindTexture(Canvas3D cv) { + + synchronized(resourceLock) { + if (objectId == -1) { + objectId = getTextureId(); + } + cv.addTextureResource(objectId, this); + } + bindTexture(cv.ctx, objectId, isEnabled(cv)); + } + + + /** + * load level 0 explicitly with null pointer to enable + * mipmapping when level 0 is not the base level + */ + void updateTextureDimensions(Canvas3D cv) { + if(images[0][0] != null) { + updateTextureImage(cv, 0, maxLevels, 0, + format, images[0][0].getImageFormatTypeIntValue(false), + width, height, boundaryWidth, + images[0][0].getImageDataTypeIntValue(), null); + } + } + + + void updateTextureLOD(Canvas3D cv) { + + if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_LOD_RANGE) != 0 ) { + + int max = 0; + if( mipmapMode == Texture.BASE_LEVEL ) { + max = maxMipMapLevels; + } + else { + max = maximumLevel; + } + + updateTextureLodRange(cv.ctx, baseLevel, max, + minimumLod, maximumLod); + } + + if ((lodOffset != null) && + ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_LOD_OFFSET) != 0)) { + updateTextureLodOffset(cv.ctx, + lodOffset.x, lodOffset.y, lodOffset.z); + } + } + + + void updateTextureBoundary(Canvas3D cv) { + updateTextureBoundary(cv.ctx, boundaryModeS, boundaryModeT, + boundaryColor.x, boundaryColor.y, + boundaryColor.z, boundaryColor.w); + } + + + void updateTextureFields(Canvas3D cv) { + + int magnificationFilter = magFilter; + int minificationFilter = minFilter; + + // update sharpen texture function if applicable + + if ((magnificationFilter >= Texture.LINEAR_SHARPEN) && + (magnificationFilter <= Texture.LINEAR_SHARPEN_ALPHA)) { + + if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_SHARPEN) != 0 ) { + + // send down sharpen texture LOD function + // + updateTextureSharpenFunc(cv.ctx, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + + } else { + + // sharpen texture is not supported by the underlying + // library, fallback to BASE_LEVEL_LINEAR + + magnificationFilter = Texture.BASE_LEVEL_LINEAR; + } + } else if ((magnificationFilter >= Texture2D.LINEAR_DETAIL) && + (magnificationFilter <= Texture2D.LINEAR_DETAIL_ALPHA)) { + if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_DETAIL) == 0) { + + // detail texture is not supported by the underlying + // library, fallback to BASE_LEVEL_LINEAR + + magnificationFilter = Texture.BASE_LEVEL_LINEAR; + } + } + + if (minificationFilter == Texture.FILTER4 || magnificationFilter == Texture.FILTER4) { + + boolean noFilter4 = false; + + if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_FILTER4) != 0) { + + if (filter4FuncPts == null) { + + // filter4 function is not defined, + // fallback to BASE_LEVEL_LINEAR + + noFilter4 = true; + } else { + updateTextureFilter4Func(cv.ctx, filter4FuncPts.length, + filter4FuncPts); + } + } else { + + // filter4 is not supported by the underlying + // library, fallback to BASE_LEVEL_LINEAR + + noFilter4 = true; + } + + if (noFilter4) { + if (minificationFilter == Texture.FILTER4) { + minificationFilter = Texture.BASE_LEVEL_LINEAR; + } + if (magnificationFilter == Texture.FILTER4) { + magnificationFilter = Texture.BASE_LEVEL_LINEAR; + } + } + } + + // Fallback to BASE mode if hardware mipmap generation is not supported. + if ((mipmapMode == Texture.BASE_LEVEL) && ((cv.textureExtendedFeatures & + Canvas3D.TEXTURE_AUTO_MIPMAP_GENERATION) == 0)) { + + if (minificationFilter == Texture.NICEST || + minificationFilter == Texture.MULTI_LEVEL_LINEAR) { + minificationFilter = Texture.BASE_LEVEL_LINEAR; + } else if (minificationFilter == Texture.MULTI_LEVEL_POINT) { + minificationFilter = Texture.BASE_LEVEL_POINT; + } + } + + // update texture filtering modes + updateTextureFilterModes(cv.ctx, minificationFilter, + magnificationFilter); + + if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_ANISOTROPIC_FILTER) + != 0) { + if (anisotropicFilterMode == Texture.ANISOTROPIC_NONE) { + updateTextureAnisotropicFilter(cv.ctx, 1.0f); + } else { + updateTextureAnisotropicFilter(cv.ctx, anisotropicFilterDegree); + } + } + + // update texture boundary modes, boundary color + + updateTextureBoundary(cv); + + } + + + // Wrapper around the native call for 2D textures; overridden for + // TextureCureMap + void updateTextureImage(Canvas3D cv, + int face, int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int imageDataType, Object data) { + + Pipeline.getPipeline().updateTexture2DImage(cv.ctx, + numLevels, level, + textureFormat, imageFormat, + width, height, boundaryWidth, + imageDataType, data, useAutoMipMapGeneration(cv)); + } + + // Wrapper around the native call for 2D textures; overridden for + // TextureCureMap + void updateTextureSubImage(Canvas3D cv, + int face, int level, + int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int imageDataType, Object data) { + + Pipeline.getPipeline().updateTexture2DSubImage(cv.ctx, + level, xoffset, yoffset, + textureFormat, imageFormat, + imgXOffset, imgYOffset, + tilew, width, height, + imageDataType, data, useAutoMipMapGeneration(cv)); + } + + + /** + * reloadTextureImage is used to load a particular level of image + * This method needs to take care of RenderedImage as well as + * BufferedImage + */ + void reloadTextureImage(Canvas3D cv, int face, int level, + ImageComponentRetained image, int numLevels) { + + boolean useAsRaster = isUseAsRaster(); + ImageComponentRetained.ImageData imageData = image.getImageData(useAsRaster); + + assert imageData != null; + + updateTextureImage(cv, + face, numLevels, level, + format, image.getImageFormatTypeIntValue(useAsRaster), + imageData.getWidth(), imageData.getHeight(), + boundaryWidth, image.getImageDataTypeIntValue(), + imageData.get()); + + + // TODO : Dead code - need to clean up for 1.6 + // Now take care of the RenderedImage (byRef and yUp) case. Note, if image + // is a RenderedImage ( byRef and yUp), then imageData will be null + + if (imageData == null) { + // System.err.println("==========. subImage"); + // Download all the tiles for this texture + int xoffset = 0, yoffset = 0; + int tmpw = image.width; + int tmph = image.height; + int endXTile = image.tilew; + int endYTile = image.tileh; + int curw = endXTile; + int curh = endYTile; + + if (tmpw < curw) { + curw = tmpw; + } + + if (tmph < curh) { + curh = tmph; + } + + int startw = curw; + int imageXOffset = image.tilew - curw; + int imageYOffset = image.tileh - curh; + for (int m = 0; m < image.numYTiles; m++) { + xoffset = 0; + tmpw = width; + curw = startw; + imageXOffset = image.tilew - curw; + for (int n = 0; n < image.numXTiles; n++) { + java.awt.image.Raster ras; + ras = ((RenderedImage)image.getRefImage(0)).getTile(n,m); + byte[] data = ((DataBufferByte)ras.getDataBuffer()).getData(); + updateTextureSubImage(cv, face, + level, xoffset, yoffset, format, + image.getImageFormatTypeIntValue(false), + imageXOffset, imageYOffset, + image.tilew, + curw, curh, + ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY, + (Object) data); + xoffset += curw; + imageXOffset = 0; + tmpw -= curw; + if (tmpw < image.tilew) + curw = tmpw; + else + curw = image.tilew; + } + yoffset += curh; + imageYOffset = 0; + tmph -= curh; + if (tmph < image.tileh) + curh = tmph; + else + curh = image.tileh; + } + } + } + + + /** + * update a subregion of the texture image + * This method needs to take care of RenderedImage as well as + * BufferedImage + */ + void reloadTextureSubImage(Canvas3D cv, int face, int level, + ImageComponentUpdateInfo info, + ImageComponentRetained image) { + + int x = info.x, + y = info.y, + width = info.width, + height = info.height; + + //The x and y here specifies the subregion of the imageData of + //the associated RenderedImage. + + //System.err.println("\nupdateTextureSubImage: x= " + x + " y= " + y + + // " width= " + width + " height= " + height + + // " format= " + format); + + ImageComponentRetained.ImageData imageData = image.getImageData(isUseAsRaster()); + if(imageData != null) { + int xoffset = x; + int yoffset = y; + + // TODO Check this logic : If !yUp adjust yoffset + if (!image.yUp) { + yoffset = image.height - yoffset - height; + } + + updateTextureSubImage(cv, face, level, + xoffset, yoffset, + format, image.getImageFormatTypeIntValue(false), + xoffset, yoffset, + image.width, width, height, + image.getImageDataTypeIntValue(), + imageData.get()); + + } else { + + assert false; + + // TODO : Dead code - need to clean up for 1.6 + // System.err.println("RenderedImage subImage update"); + // determine the first tile of the image + + float mt; + int minTileX, minTileY; + + int rx = x; + int ry = y; + + mt = (float)(rx) / (float)image.tilew; + if (mt < 0) { + minTileX = (int)(mt - 1); + } else { + minTileX = (int)mt; + } + + mt = (float)(ry) / (float)image.tileh; + if (mt < 0) { + minTileY = (int)(mt - 1); + } else { + minTileY = (int)mt; + } + + // determine the pixel offset of the upper-left corner of the + // first tile + int startXTile = minTileX * image.tilew; + int startYTile = minTileY * image.tilew; + + + // image dimension in the first tile + + int curw = (startXTile + image.tilew - rx); + int curh = (startYTile + image.tileh - ry); + + // check if the to-be-copied region is less than the tile image + // if so, update the to-be-copied dimension of this tile + + if (curw > width) { + curw = width; + } + + if (curh > height) { + curh = height; + } + + // save the to-be-copied width of the left most tile + + int startw = curw; + + + // temporary variable for dimension of the to-be-copied region + + int tmpw = width; + int tmph = height; + + + // offset of the first pixel of the tile to be copied; offset is + // relative to the upper left corner of the title + + int imgX = rx - startXTile; + int imgY = ry - startYTile; + + + // determine the number of tiles in each direction that the + // image spans + + int numXTiles = (width + imgX) / image.tilew; + int numYTiles = (height + imgY) / image.tileh; + + if (((float)(width + imgX ) % (float)image.tilew) > 0) { + numXTiles += 1; + } + + if (((float)(height + imgY ) % (float)image.tileh) > 0) { + numYTiles += 1; + } + + java.awt.image.Raster ras; + + int textureX = x; // x offset in the texture + int textureY = y; // y offset in the texture + + for (int yTile = minTileY; yTile < minTileY + numYTiles; + yTile++) { + + tmpw = width; + curw = startw; + imgX = rx - startXTile; + + for (int xTile = minTileX; xTile < minTileX + numXTiles; + xTile++) { + ras = ((RenderedImage)image.getRefImage(0)).getTile(xTile, yTile); + byte[] data = ((DataBufferByte)ras.getDataBuffer()).getData(); + + updateTextureSubImage(cv, face, level, + textureX, textureY, + format, image.getImageFormatTypeIntValue(false), + imgX, imgY, + image.tilew, curw, curh, + ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY, + (Object)data); + + // move to the next tile in x direction + + textureX += curw; + imgX = 0; + + // determine the width of copy region of the next tile + + tmpw -= curw; + if (tmpw < image.tilew) { + curw = tmpw; + } else { + curw = image.tilew; + } + } + + // move to the next set of tiles in y direction + textureY += curh; + imgY = 0; + + // determine the height of copy region for the next set + // of tiles + tmph -= curh; + if (tmph < image.tileh) { + curh = tmph; + } else { + curh = image.tileh; + } + } + } + } + + + // reload texture mipmap + + void reloadTexture(Canvas3D cv) { + + + int blevel, mlevel; + + //System.err.println("reloadTexture: baseLevel= " + baseLevel + + // " maximumLevel= " + maximumLevel); + + if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_LOD_RANGE) == 0 ) { + blevel = 0; + mlevel = maxLevels - 1; + } else { + blevel = baseLevel; + mlevel = maximumLevel; + } + + if (blevel != 0) { + // level 0 is not the base level, hence, need + // to load level 0 explicitly with a null pointer in order + // for mipmapping to be active. + + updateTextureDimensions(cv); + } + + for (int j = 0; j < numFaces; j++) { + for (int i = blevel; i <= mlevel; i++) { + + // it is possible to have null pointer if only a subset + // of mipmap levels is defined but the canvas does not + // support lod_range extension + + ImageComponentRetained image = images[j][i]; + if (image != null) { + // Issue 366: call evaluateExtensions, since it may not + // have been called yet in all cases + image.evaluateExtensions(cv); + reloadTextureImage(cv, j, i, image, maxLevels); + } + } + } + } + + + // update texture mipmap based on the imageUpdateInfo + + void updateTexture(Canvas3D cv, int resourceBit) { + + //System.err.println("updateTexture\n"); + + ImageComponentUpdateInfo info; + + for (int k = 0; k < numFaces; k++) { + for (int i = baseLevel; i <= maximumLevel; i++) { + if (imageUpdateInfo[k][i] != null) { + for (int j = 0; j < imageUpdateInfo[k][i].size(); j++) { + + info = (ImageComponentUpdateInfo) + imageUpdateInfo[k][i].get(j); + + + synchronized(resourceLock) { + + // if this info is updated, move on to the next one + + if ((info.updateMask & resourceBit) == 0) + continue; + + + // check if all canvases have processed this update + info.updateMask &= ~resourceBit; + + // all the current resources have updated this + // info, so this info can be removed from the + // update list + if ((info.updateMask & resourceCreationMask) + == 0) { + info.updateMask = 0; // mark this update as + // done + + // mark the prune flag so as to prune the + // update list next time when the update + // list is to be modified. + // Don't want to clean up the list at + // rendering time because (1) MT issue, + // other renderer could be processing + // the update list now; + // (2) takes up rendering time. + if (imageUpdatePruneMask == null) { + imageUpdatePruneMask = new int[numFaces]; + } + imageUpdatePruneMask[k] = 1 << i; + } + } + + if (info.entireImage == true) { + reloadTextureImage(cv, k, i, + images[k][i], maxLevels); + } else { + reloadTextureSubImage(cv, k, i, info, images[k][i]); + } + + } + } + } + } + } + + + /** + * reloadTextureSharedContext is called to reload texture + * on a shared context. It is invoked from the Renderer + * before traversing the RenderBin. The idea is to reload + * all necessary textures up front for all shared contexts + * in order to minimize the context switching overhead. + */ + void reloadTextureSharedContext(Canvas3D cv) { + + // if texture is not enabled, don't bother downloading the + // the texture state + + if (!isEnabled(cv)) { + return; + } + + bindTexture(cv); + + // reload all levels of texture image + + // update texture parameters such as boundary modes, filtering + + updateTextureFields(cv); + + + // update texture Lod parameters + + updateTextureLOD(cv); + + + // update all texture images + + reloadTexture(cv); + + synchronized(resourceLock) { + resourceCreationMask |= cv.screen.renderer.rendererBit; + resourceUpdatedMask |= cv.screen.renderer.rendererBit; + resourceLodUpdatedMask |= cv.screen.renderer.rendererBit; + resourceInReloadList &= ~cv.screen.renderer.rendererBit; + } + } + + + /** + * updateNative is called while traversing the RenderBin to + * update the texture state + */ + void updateNative(Canvas3D cv) { + boolean reloadTexture = false; // true - reload all levels of texture + boolean updateTexture = false; // true - update a portion of texture + boolean updateTextureLod = false; // true - update texture Lod info + + //System.err.println("Texture/updateNative: " + this + "object= " + objectId + " enable= " + enable); + + bindTexture(cv); + + // if texture is not enabled, don't bother downloading the + // the texture state + + if (!isEnabled(cv)) { + return; + } + + if (cv.useSharedCtx && cv.screen.renderer.sharedCtx != null) { + + if ((resourceCreationMask & cv.screen.renderer.rendererBit) == 0) { + reloadTexture = true; + } else { + if (((resourceUpdatedMask & + cv.screen.renderer.rendererBit) == 0) && + (imageUpdateInfo != null)) { + updateTexture = true; + } + + if ((resourceLodUpdatedMask & + cv.screen.renderer.rendererBit) == 0) { + updateTextureLod = true; + } + } + if (reloadTexture || updateTexture || updateTextureLod) { + cv.makeCtxCurrent(cv.screen.renderer.sharedCtx); + bindTexture(cv); + } + } else { + if ((resourceCreationMask & cv.canvasBit) == 0) { + reloadTexture = true; + } else { + if (((resourceUpdatedMask & cv.canvasBit) == 0) && + (imageUpdateInfo != null)) { + updateTexture = true; + } + + if ((resourceLodUpdatedMask & cv.canvasBit) == 0) { + updateTextureLod = true; + } + } + } + + + if (VirtualUniverse.mc.isD3D()) { + if (texTimestamp != VirtualUniverse.mc.resendTexTimestamp) { + texTimestamp = VirtualUniverse.mc.resendTexTimestamp; + reloadTexture = true; + } + + if (!reloadTexture) { + // D3D didn't store texture properties during Texture binding + updateTextureFields(cv); + } + } + + +//System.err.println("......... reloadTexture= " + reloadTexture + +// " updateTexture= " + updateTexture + +// " updateTextureLod= " + updateTextureLod); + +//System.err.println("......... resourceCreationMask= " + resourceCreationMask + +// " resourceUpdatedMask= " + resourceUpdatedMask); + + if (reloadTexture) { + + // reload all levels of texture image + + // update texture parameters such as boundary modes, filtering + + updateTextureFields(cv); + + + // update texture Lod parameters + + updateTextureLOD(cv); + + + // update all texture images + + reloadTexture(cv); + + + if (cv.useSharedCtx) { + cv.makeCtxCurrent(cv.ctx); + synchronized(resourceLock) { + resourceCreationMask |= cv.screen.renderer.rendererBit; + resourceUpdatedMask |= cv.screen.renderer.rendererBit; + resourceLodUpdatedMask |= cv.screen.renderer.rendererBit; + } + } + else { + synchronized(resourceLock) { + resourceCreationMask |= cv.canvasBit; + resourceUpdatedMask |= cv.canvasBit; + resourceLodUpdatedMask |= cv.canvasBit; + } + } + } else if (updateTextureLod || updateTexture) { + + if (updateTextureLod) { + updateTextureLOD(cv); + } + + if (updateTexture) { + + // update texture image + + int resourceBit = 0; + + if (cv.useSharedCtx) { + resourceBit = cv.screen.renderer.rendererBit; + } else { + resourceBit = cv.canvasBit; + } + + // update texture based on the imageComponent update info + + updateTexture(cv, resourceBit); + } + + // set the appropriate bit in the resource update masks showing + // that the resource is up-to-date + + if (cv.useSharedCtx) { + cv.makeCtxCurrent(cv.ctx); + synchronized(resourceLock) { + resourceUpdatedMask |= cv.screen.renderer.rendererBit; + resourceLodUpdatedMask |= cv.screen.renderer.rendererBit; + } + } else { + synchronized(resourceLock) { + resourceUpdatedMask |= cv.canvasBit; + resourceLodUpdatedMask |= cv.canvasBit; + } + } + } + } + + synchronized void createMirrorObject() { + if (mirror == null) { + if (this instanceof Texture3DRetained) { + Texture3DRetained t3d = (Texture3DRetained)this; + Texture3D tex = new Texture3D(t3d.mipmapMode, + t3d.format, + t3d.width, + t3d.height, + t3d.depth, + t3d.boundaryWidth); + mirror = (Texture3DRetained)tex.retained;; + + } else if (this instanceof TextureCubeMapRetained) { + TextureCubeMap tex = new TextureCubeMap(mipmapMode, + format, width, + boundaryWidth); + mirror = (TextureCubeMapRetained)tex.retained; + + } else { + Texture2D tex = new Texture2D(mipmapMode, + format, + width, + height, + boundaryWidth); + mirror = (Texture2DRetained)tex.retained; + } + + ((TextureRetained)mirror).objectId = -1; + } + initMirrorObject(); + } + + + /** + * Initializes a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + mirror.source = source; + if (this instanceof Texture3DRetained) { + Texture3DRetained t3d = (Texture3DRetained)this; + + ((Texture3DRetained)mirror).boundaryModeR = t3d.boundaryModeR; + ((Texture3DRetained)mirror).depth = t3d.depth; + } + TextureRetained mirrorTexture = (TextureRetained)mirror; + + mirrorTexture.boundaryModeS = boundaryModeS; + mirrorTexture.boundaryModeT = boundaryModeT; + mirrorTexture.minFilter = minFilter; + mirrorTexture.magFilter = magFilter; + mirrorTexture.boundaryColor.set(boundaryColor); + mirrorTexture.enable = enable; + mirrorTexture.userSpecifiedEnable = enable; + mirrorTexture.enable = enable; + mirrorTexture.numFaces = numFaces; + mirrorTexture.resourceCreationMask = 0x0; + mirrorTexture.resourceUpdatedMask = 0x0; + mirrorTexture.resourceLodUpdatedMask = 0x0; + mirrorTexture.resourceInReloadList = 0x0; + + // LOD information + mirrorTexture.baseLevel = baseLevel; + mirrorTexture.maximumLevel = maximumLevel; + mirrorTexture.minimumLod = minimumLod; + mirrorTexture.maximumLod = maximumLod; + mirrorTexture.lodOffset = lodOffset; + + // sharpen texture LOD function + + mirrorTexture.numSharpenTextureFuncPts = numSharpenTextureFuncPts; + if (sharpenTextureFuncPts == null) { + mirrorTexture.sharpenTextureFuncPts = null; + } else { + if ((mirrorTexture.sharpenTextureFuncPts == null) || + (mirrorTexture.sharpenTextureFuncPts.length != + sharpenTextureFuncPts.length)) { + mirrorTexture.sharpenTextureFuncPts = + new float[sharpenTextureFuncPts.length]; + } + for (int i = 0; i < sharpenTextureFuncPts.length; i++) { + mirrorTexture.sharpenTextureFuncPts[i] = + sharpenTextureFuncPts[i]; + } + } + + // filter4 function + if (filter4FuncPts == null) { + mirrorTexture.filter4FuncPts = null; + } else { + if ((mirrorTexture.filter4FuncPts == null) || + (mirrorTexture.filter4FuncPts.length != + filter4FuncPts.length)) { + mirrorTexture.filter4FuncPts = + new float[filter4FuncPts.length]; + } + for (int i = 0; i < filter4FuncPts.length; i++) { + mirrorTexture.filter4FuncPts[i] = + filter4FuncPts[i]; + } + } + + // Anisotropic Filter + mirrorTexture.anisotropicFilterMode = anisotropicFilterMode; + mirrorTexture.anisotropicFilterDegree = anisotropicFilterDegree; + + mirrorTexture.maxLevels = maxLevels; + if (images != null) { + + for (int j = 0; j < numFaces; j++) { + for (int i = 0; i < maxLevels; i++) { + mirrorTexture.images[j][i] = images[j][i]; + + // add texture to the userList of the images + if (images[j][i] != null) { + images[j][i].addUser(mirrorTexture); + } + } + } + } + } + + boolean useAutoMipMapGeneration(Canvas3D cv) { + if (mipmapMode == Texture.BASE_LEVEL && + (minFilter == Texture.NICEST || + minFilter == Texture.MULTI_LEVEL_POINT || + minFilter == Texture.MULTI_LEVEL_LINEAR) && + ((cv.textureExtendedFeatures & + Canvas3D.TEXTURE_AUTO_MIPMAP_GENERATION) != 0)) { + return true; + } + + return false; + } + + /** + * Go through the image update info list + * and remove those that are already done + * by all the resources + */ + void pruneImageUpdateInfo() { + ImageComponentUpdateInfo info; + + //System.err.println("Texture.pruneImageUpdateInfo"); + + for (int k = 0; k < numFaces; k++) { + for (int i = baseLevel; i <= maximumLevel; i++) { + if ((imageUpdatePruneMask[k] & (1<= width/2) && (arg.height >= height/2)) { +// +// // if the subimage dimension is close to the complete dimension, +// // use the full update (it's more efficient) +// info.entireImage = true; + } else { + info.entireImage = false; + } + + if (info.entireImage) { + // the entire image update supercedes all the subimage update; + // hence, remove all the existing updates from the list + imageUpdateInfo[face][level].clear(); + + // reset the update prune mask for this level + if (imageUpdatePruneMask != null) { + imageUpdatePruneMask[face] &= ~(1 << level); + } + + } else { + // subimage update, needs to save the subimage info + info.x = arg.x; + info.y = arg.y; + info.z = arg.z; + info.width = arg.width; + info.height = arg.height; + } + + // save the mask which shows the canvases that have created resources + // for this image, aka, these are the resources that need to be + // updated. + info.updateMask = resourceCreationMask; + + // add the image update to the list + imageUpdateInfo[face][level].add(info); + + // check if the update list stills need to be pruned + if (imageUpdatePruneMask != null) { + pruneImageUpdateInfo(); + } + } + + void validate() { + enable = true; + for (int j = 0; j < numFaces && enable; j++) { + for (int i = baseLevel; i <= maximumLevel && enable; i++) { + if (images[j][i] == null) { + enable = false; + } + } + } + } + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + TextureRetained mirrorTexture = (TextureRetained)mirror; + + if ((component & ENABLE_CHANGED) != 0) { + mirrorTexture.enable = ((Boolean)value).booleanValue(); + + } else if ((component & IMAGE_CHANGED) != 0) { + + Object [] arg = (Object []) value; + int level = ((Integer)arg[0]).intValue(); + ImageComponent image = (ImageComponent)arg[1]; + int face = ((Integer)arg[2]).intValue(); + + // first remove texture from the userList of the current + // referencing image and + + if (mirrorTexture.images[face][level] != null) { + mirrorTexture.images[face][level].removeUser(mirror); + } + + // assign the new image and add texture to the userList + if (image == null) { + mirrorTexture.images[face][level] = null; + + } else { + mirrorTexture.images[face][level] = + (ImageComponentRetained)image.retained; + mirrorTexture.images[face][level].addUser(mirror); + + } + + // NOTE: the old image has to be removed from the + // renderBins' NodeComponentList and new image has to be + // added to the lists. This will be taken care of + // in the RenderBin itself in response to the + // IMAGE_CHANGED message + + + // mark that texture images need to be updated + mirrorTexture.resourceUpdatedMask = 0; + + // add update info to the update list + mirrorTexture.addImageUpdateInfo(level, face, null); + + } else if ((component & IMAGES_CHANGED) != 0) { + + Object [] arg = (Object []) value; + ImageComponent [] images = (ImageComponent[])arg[0]; + int face = ((Integer)arg[1]).intValue(); + + for (int i = 0; i < images.length; i++) { + + // first remove texture from the userList of the current + // referencing image + if (mirrorTexture.images[face][i] != null) { + mirrorTexture.images[face][i].removeUser(mirror); + } + + // assign the new image and add texture to the userList + if (images[i] == null) { + mirrorTexture.images[face][i] = null; + } else { + mirrorTexture.images[face][i] = + (ImageComponentRetained)images[i].retained; + mirrorTexture.images[face][i].addUser(mirror); + } + } + mirrorTexture.updateResourceCreationMask(); + + // NOTE: the old images have to be removed from the + // renderBins' NodeComponentList and new image have to be + // added to the lists. This will be taken care of + // in the RenderBin itself in response to the + // IMAGES_CHANGED message + + } else if ((component & BASE_LEVEL_CHANGED) != 0) { + int level = ((Integer)value).intValue(); + + if (level < mirrorTexture.baseLevel) { + + // add texture to the userList of those new levels of + // enabling images + + for (int j = 0; j < numFaces; j++) { + for (int i = level; i < mirrorTexture.baseLevel; i++) { + + if (mirrorTexture.images[j][i] == null) { + mirrorTexture.enable = false; + } else { + mirrorTexture.addImageUpdateInfo(i, j, null); + } + } + } + + mirrorTexture.baseLevel = level; + + // mark that texture images need to be updated + mirrorTexture.resourceUpdatedMask = 0; + + + } else { + + mirrorTexture.baseLevel = level; + + if (userSpecifiedEnable && (mirrorTexture.enable == false)) { + + // if texture is to be enabled but is currently + // disabled, it's probably disabled because + // some of the images are missing. Now that + // the baseLevel is modified, validate the + // texture images again + + mirrorTexture.validate(); + } + } + + // mark that texture lod info needs to be updated + mirrorTexture.resourceLodUpdatedMask = 0; + + } else if ((component & MAX_LEVEL_CHANGED) != 0) { + int level = ((Integer)value).intValue(); + + if (level > mirrorTexture.maximumLevel) { + + // add texture to the userList of those new levels of + // enabling images + + for (int j = 0; j < numFaces; j++) { + for (int i = mirrorTexture.maximumLevel; i < level; i++) { + + if (mirrorTexture.images[j][i] == null) { + mirrorTexture.enable = false; + } else { + mirrorTexture.addImageUpdateInfo(i, j, null); + } + } + } + + mirrorTexture.maximumLevel = level; + + // mark that texture images need to be updated + mirrorTexture.resourceUpdatedMask = 0; + + } else { + + mirrorTexture.maximumLevel = level; + + if (userSpecifiedEnable && (mirrorTexture.enable == false)) { + + // if texture is to be enabled but is currently + // disabled, it's probably disabled because + // some of the images are missing. Now that + // the baseLevel is modified, validate the + // texture images again + + mirrorTexture.validate(); + } + } + + // mark that texture lod info needs to be updated + mirrorTexture.resourceLodUpdatedMask = 0; + + } else if ((component & MIN_LOD_CHANGED) != 0) { + mirrorTexture.minimumLod = ((Float)value).floatValue(); + + // mark that texture lod info needs to be updated + mirrorTexture.resourceLodUpdatedMask = 0; + + } else if ((component & MAX_LOD_CHANGED) != 0) { + mirrorTexture.maximumLod = ((Float)value).floatValue(); + + // mark that texture lod info needs to be updated + mirrorTexture.resourceLodUpdatedMask = 0; + + } else if ((component & LOD_OFFSET_CHANGED) != 0) { + if ((mirrorTexture.lodOffset) == null) { + mirrorTexture.lodOffset = + new Point3f((Point3f)value); + } else { + mirrorTexture.lodOffset.set((Point3f)value); + } + + // mark that texture lod info needs to be updated + mirrorTexture.resourceLodUpdatedMask = 0; + + } else if ((component & UPDATE_IMAGE) != 0) { + mirrorTexture.updateResourceCreationMask(); + } + + } + + + // notifies the Texture mirror object that the image data in a referenced + // ImageComponent object is changed. Need to update the texture image + // accordingly. + // Note: this is called from mirror object only + + void notifyImageComponentImageChanged(ImageComponentRetained image, + ImageComponentUpdateInfo value) { + + //System.err.println("Texture.notifyImageComponentImageChanged"); + + + // if this texture is to be reloaded, don't bother to keep + // the update info + + if (resourceCreationMask == 0) { + + if (imageUpdateInfo != null) { + + //remove all the existing updates from the list + + for (int face = 0; face < numFaces; face++) { + for (int level = 0; level < maxLevels; level++) { + if (imageUpdateInfo[face][level] != null) { + imageUpdateInfo[face][level].clear(); + } + } + + // reset the update prune mask for this level + if (imageUpdatePruneMask != null) { + imageUpdatePruneMask[face] = 0; + } + } + } + + return; + } + + + // first find which texture image is being affected + + boolean done; + + for (int j = 0; j < numFaces; j++) { + + done = false; + for (int i = baseLevel; i <= maximumLevel && !done; i++) { + if (images[j][i] == image) { + + // reset the resourceUpdatedMask to tell the + // rendering method to update the resource + resourceUpdatedMask = 0; + + // add update info to the update list + addImageUpdateInfo(i, j, value); + + // set done to true for this face because no two levels + // can reference the same ImageComponent object + done = true; + } + } + } + } + + + // reset the resourceCreationMask + // Note: called from the mirror object only + + void updateResourceCreationMask() { + resourceCreationMask = 0x0; + } + + void incTextureBinRefCount(TextureBin tb) { + + ImageComponentRetained image; + + setTextureBinRefCount(tb, getTextureBinRefCount(tb) + 1); + + // check to see if there is any modifiable images, + // if yes, add those images to nodeComponentList in RenderBin + // so that RenderBin can acquire a lock before rendering + // to prevent updating of image data while rendering + + for (int j = 0; j < numFaces; j++) { + for (int i = 0; i < maxLevels; i++) { + image = images[j][i]; + + // it is possible that image.source == null because + // the mipmap could have been created by the library, and + // hence don't have source and therefore they are + // guaranteed not modifiable + + if (image != null && + (image.isByReference() || + (image.source != null && + image.source.getCapability( + ImageComponent.ALLOW_IMAGE_WRITE)))) { + tb.renderBin.addNodeComponent(image); + } + } + } + } + + void decTextureBinRefCount(TextureBin tb) { + + ImageComponentRetained image; + + setTextureBinRefCount(tb, getTextureBinRefCount(tb) - 1); + + // remove any modifiable images from RenderBin nodeComponentList + + for (int j = 0; j < numFaces; j++) { + for (int i = 0; i < maxLevels; i++) { + image = images[j][i]; + if (image != null && + (image.isByReference() || + (image.source != null && + image.source.getCapability( + ImageComponent.ALLOW_IMAGE_WRITE)))) { + tb.renderBin.removeNodeComponent(image); + } + } + } + } + + + final void sendMessage(int attrMask, Object attr) { + + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.TEXTURE_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1] = new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i + *

    + *
  • Texture - defines the texture image and filtering + * parameters used when texture mapping is enabled. These attributes + * are defined in a Texture object.
  • + * + *

  • Texture attributes - defines the attributes that apply to + * texture mapping, such as the texture mode, texture transform, + * blend color, and perspective correction mode. These attributes + * are defined in a TextureAttributes object.
  • + * + *

  • Texture coordinate generation - defines the attributes + * that apply to texture coordinate generation, such as whether + * texture coordinate generation is enabled, coordinate format + * (2D or 3D coordinates), coordinate generation mode (object + * linear, eye linear, or spherical reflection mapping), and the + * R, S, and T coordinate plane equations. These attributes + * are defined in a TexCoordGeneration object.
  • + *

+ * + * @see Appearance + * @see Texture + * @see TextureAttributes + * @see TexCoordGeneration + * + * @since Java 3D 1.2 + */ +public class TextureUnitState extends NodeComponent { + + /** + * Specifies that this TextureUnitState object allows reading its + * texture, texture attribute, or texture coordinate generation + * component information. + */ + public static final int ALLOW_STATE_READ = + CapabilityBits.TEXTURE_UNIT_STATE_ALLOW_STATE_READ; + + /** + * Specifies that this TextureUnitState object allows writing its + * texture, texture attribute, or texture coordinate generation + * component information. + */ + public static final int ALLOW_STATE_WRITE = + CapabilityBits.TEXTURE_UNIT_STATE_ALLOW_STATE_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_STATE_READ + }; + + /** + * Constructs a TextureUnitState component object using defaults for all + * state variables. All component object references are initialized + * to null. + */ + public TextureUnitState() { + // Just use default values + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs a TextureUnitState component object using the specified + * component objects. + * + * @param texture object that specifies the desired texture + * map and texture parameters + * @param textureAttributes object that specifies the desired + * texture attributes + * @param texCoordGeneration object that specifies the texture coordinate + * generation parameters + */ + public TextureUnitState(Texture texture, + TextureAttributes textureAttributes, + TexCoordGeneration texCoordGeneration) { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TextureUnitStateRetained)this.retained).initTexture(texture); + ((TextureUnitStateRetained)this.retained).initTextureAttributes( + textureAttributes); + ((TextureUnitStateRetained)this.retained).initTexCoordGeneration( + texCoordGeneration); + } + + /** + * Creates the retained mode TextureUnitStateRetained object that this + * TextureUnitState component object will point to. + */ + void createRetained() { + this.retained = new TextureUnitStateRetained(); + this.retained.setSource(this); + } + + /** + * Sets the texture, texture attributes, and texture coordinate + * generation components in this TextureUnitState object to the + * specified component objects. + * + * @param texture object that specifies the desired texture + * map and texture parameters + * @param textureAttributes object that specifies the desired + * texture attributes + * @param texCoordGeneration object that specifies the texture coordinate + * generation parameters + * + * @exception IllegalSharingException if this TextureUnitState is live and + * the specified texture refers to an ImageComponent2D that is being used + * by a Canvas3D as an off-screen buffer. + * + * @exception IllegalSharingException if this TextureUnitState is + * being used by an immediate mode context and + * the specified texture refers to an ImageComponent2D that is being used + * by a Canvas3D as an off-screen buffer. + */ + public void set(Texture texture, + TextureAttributes textureAttributes, + TexCoordGeneration texCoordGeneration) { + + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_STATE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TextureUnitState0")); + + // Do illegal sharing check + if(texture != null) { + TextureRetained texRetained = (TextureRetained)texture.retained; + ImageComponent[] images = texRetained.getImages(); + if(images != null) { + for(int i=0; inot call this method directly. + * It should only be called by the cloneNode method. + * + * @deprecated replaced with duplicateNodeComponent( + * NodeComponent originalNodeComponent, boolean forceDuplicate) + */ + public void duplicateNodeComponent(NodeComponent originalNodeComponent) { + checkDuplicateNodeComponent(originalNodeComponent); + } + + /** + * Copies all TextureUnitState information from + * originalNodeComponent into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + Hashtable hashtable = originalNodeComponent.nodeHashtable; + + TextureUnitStateRetained app = (TextureUnitStateRetained) originalNodeComponent.retained; + + TextureUnitStateRetained rt = (TextureUnitStateRetained) retained; + + rt.setTexture((Texture) getNodeComponent(app.getTexture(), + forceDuplicate, + hashtable)); + + rt.setTextureAttributes((TextureAttributes) getNodeComponent( + app.getTextureAttributes(), + forceDuplicate, + hashtable)); + + rt.setTexCoordGeneration((TexCoordGeneration) getNodeComponent( + app.getTexCoordGeneration(), + forceDuplicate, + hashtable)); + } + + /** + * This function is called from getNodeComponent() to see if any of + * the sub-NodeComponents duplicateOnCloneTree flag is true. + * If it is the case, current NodeComponent needs to + * duplicate also even though current duplicateOnCloneTree flag is false. + * This should be overwrite by NodeComponent which contains sub-NodeComponent. + */ + boolean duplicateChild() { + if (getDuplicateOnCloneTree()) + return true; + + TextureUnitStateRetained rt = (TextureUnitStateRetained) retained; + + NodeComponent nc = rt.getTexture(); + if ((nc != null) && nc.duplicateChild()) + return true; + + nc = rt.getTextureAttributes(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + nc = rt.getTexCoordGeneration(); + if ((nc != null) && nc.getDuplicateOnCloneTree()) + return true; + + return false; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TextureUnitStateRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TextureUnitStateRetained.java new file mode 100644 index 0000000..ca3eb83 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TextureUnitStateRetained.java @@ -0,0 +1,620 @@ +/* + * $RCSfile: TextureUnitStateRetained.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.Color4f; +import java.util.ArrayList; + +class TextureUnitStateRetained extends NodeComponentRetained { + + static final int TEXTURE_CHANGED = 0x0001; + static final int TEXTURE_ATTRS_CHANGED = 0x0002; + static final int TEXCOORD_GEN_CHANGED = 0x0004; + static final int ALL_STATE_CHANGED = 0x0008; + + TextureRetained texture = null; + TextureAttributesRetained texAttrs = null; + TexCoordGenerationRetained texGen = null; + + /** + * An abstract method to validate the texture unit state component + */ + final void setTextureUnitStateComponent(NodeComponent comp, + NodeComponentRetained thisComp, + int messageOp) { + if (source.isLive()) { + + if ((comp == null && thisComp == null) || + (comp != null && comp.retained == thisComp)) + return; + + if (thisComp != null) { + thisComp.clearLive(refCount); + thisComp.removeMirrorUsers(this); + } + + if (comp != null) { + ((NodeComponentRetained)comp.retained).setLive(inBackgroundGroup, refCount); + // If texture unit is live, then copy all the users of this + // texture unit state as users of this texture component + ((NodeComponentRetained)comp.retained).copyMirrorUsers(this); + } + + if (messageOp != -1) { + sendMessage(messageOp, + (comp == null ? null : + ((NodeComponentRetained)comp.retained).mirror)); + } + + } + } + + final void initTextureUnitState(Texture texture, + TextureAttributes texAttrs, + TexCoordGeneration texGen) { + + initTexture(texture); + initTextureAttributes(texAttrs); + initTexCoordGeneration(texGen); + } + + final void setTextureUnitState(Texture texture, + TextureAttributes texAttrs, + TexCoordGeneration texGen) { + + setTextureUnitStateComponent(texture, this.texture, -1); + setTextureUnitStateComponent(texAttrs, this.texAttrs, -1); + setTextureUnitStateComponent(texGen, this.texGen, -1); + + + // send all changes to the target threads in one + // message to avoid modifying the renderBin repeatedly + + Object args[] = new Object[3]; + args[0] = (texture == null ? null : + ((TextureRetained)texture.retained).mirror); + args[1] = (texAttrs == null ? null : + ((TextureAttributesRetained)texAttrs.retained).mirror); + args[2] = (texGen == null ? null : + ((TexCoordGenerationRetained)texGen.retained).mirror); + + sendMessage(ALL_STATE_CHANGED, args); + + initTextureUnitState(texture, texAttrs, texGen); + } + + final void initTexture(Texture texture) { + if (texture == null) + this.texture = null; + else + this.texture = (TextureRetained)texture.retained; + } + + final void setTexture(Texture texture) { + setTextureUnitStateComponent(texture, this.texture, TEXTURE_CHANGED); + initTexture(texture); + } + + final void initTextureAttributes(TextureAttributes texAttrs) { + if (texAttrs == null) + this.texAttrs = null; + else + this.texAttrs = (TextureAttributesRetained)texAttrs.retained; + } + + final void setTextureAttributes(TextureAttributes texAttrs) { + setTextureUnitStateComponent(texAttrs, this.texAttrs, + TEXTURE_ATTRS_CHANGED); + initTextureAttributes(texAttrs); + } + + final void initTexCoordGeneration(TexCoordGeneration texGen) { + if (texGen == null) + this.texGen = null; + else + this.texGen = (TexCoordGenerationRetained)texGen.retained; + } + + final void setTexCoordGeneration(TexCoordGeneration texGen) { + setTextureUnitStateComponent(texGen, this.texGen, TEXCOORD_GEN_CHANGED); + initTexCoordGeneration(texGen); + } + + Texture getTexture() { + return (texture == null ? null : (Texture)texture.source); + } + + TextureAttributes getTextureAttributes() { + return (texAttrs == null ? null : (TextureAttributes)texAttrs.source); + } + + TexCoordGeneration getTexCoordGeneration() { + return (texGen == null ? null : (TexCoordGeneration)texGen.source); + } + + void updateNative(int unitIndex, Canvas3D cv, + boolean reload, boolean simulate) { + + //System.err.println("TextureUnitState/updateNative: unitIndex= " + unitIndex + " reload= " + reload + " simulate= " + simulate); + + // unitIndex can be -1 for the single texture case, so + // can't use unitIndex to index into the cv.texUnitState; + // in this case, use index 0 + + int index = unitIndex; + + if (index < 0) + index = 0; + + + boolean dirty = ((cv.canvasDirty & (Canvas3D.TEXTUREATTRIBUTES_DIRTY|Canvas3D.TEXTUREBIN_DIRTY)) != 0); + + if (this.texture == null) { + // if texture is null, then texture mapped is + // disabled for this texture unit; and no more + // state update is needed + + //System.err.println("texture is null"); + + if (cv.texUnitState[index].texture != null) { + cv.resetTexture(cv.ctx, unitIndex); + cv.texUnitState[index].texture = null; + } + cv.canvasDirty &= ~Canvas3D.TEXTUREATTRIBUTES_DIRTY; + return; + } else { + + Pipeline.getPipeline().updateTextureUnitState(cv.ctx, unitIndex, true); + } + + // reload is needed in a multi-texture case to bind the + // texture parameters to the texture unit state + + if (reload || dirty || cv.texUnitState[index].texture != this.texture) { + + // texture cannot be null at this point because it is + // already checked above + this.texture.updateNative(cv); + + cv.texUnitState[index].texture = this.texture; + + } + + if (this.texAttrs == null) { + if (reload || dirty || cv.texUnitState[index].texAttrs != null) { + cv.resetTextureAttributes(cv.ctx); + if (VirtualUniverse.mc.isD3D() && + (texGen != null) && + ((texGen.genMode == TexCoordGeneration.EYE_LINEAR) || + ((texGen.genMode == TexCoordGeneration.SPHERE_MAP)))) { + // We need to reload tex since eye linear + // and sphere map in D3D will change the + // texture transform matrix also. + dirty = true; + } + cv.setBlendFunc(cv.ctx, TransparencyAttributes.BLEND_ONE, + TransparencyAttributes.BLEND_ZERO); + cv.texUnitState[index].texAttrs = null; + } + } else { + + TextureAttributesRetained mTexAttrs; + if (this.texAttrs.mirror == null) { + mTexAttrs = this.texAttrs; + } else { + mTexAttrs = (TextureAttributesRetained) this.texAttrs.mirror; + } + + + if (mTexAttrs.mirrorCompDirty) { + // This happen when canvas reference is same as + // texUnitState.texAttrs and we update the later without + // notify cache. + cv.texUnitState[index].texAttrs = null; + mTexAttrs.mirrorCompDirty = false; + } + + if (reload || dirty || cv.texUnitState[index].texAttrs != mTexAttrs) { + this.texAttrs.updateNative(cv, simulate, texture.format); + if (VirtualUniverse.mc.isD3D() && + (texGen != null) && + ((texGen.genMode == TexCoordGeneration.EYE_LINEAR) || + ((texGen.genMode == TexCoordGeneration.SPHERE_MAP)))) { + dirty = true; + } + cv.texUnitState[index].texAttrs = mTexAttrs; + } + } + + if (this.texGen == null) { + if (reload || dirty || cv.texUnitState[index].texGen != null) { + cv.resetTexCoordGeneration(cv.ctx); + cv.texUnitState[index].texGen = null; + } + } else { + TexCoordGenerationRetained mTexGen; + + if (this.texGen.mirror == null) { + mTexGen = this.texGen; + } else { + mTexGen = (TexCoordGenerationRetained)this.texGen.mirror; + } + + if (mTexGen.mirrorCompDirty) { + // This happen when canvas reference is same as + // texUnitState.texGen and we update the later without + // notify cache. + cv.texUnitState[index].texGen = null; + mTexGen.mirrorCompDirty = false; + } + + if (reload || dirty || cv.texUnitState[index].texGen != mTexGen) { + this.texGen.updateNative(cv); + cv.texUnitState[index].texGen = mTexGen; + } + } + cv.canvasDirty &= ~Canvas3D.TEXTUREATTRIBUTES_DIRTY; + } + + + /** + * Creates and initializes a mirror object, point the mirror object + * to the retained object if the object is not editable + */ + synchronized void createMirrorObject() { + + if (mirror == null) { + TextureUnitStateRetained mirrorTus = + new TextureUnitStateRetained(); + mirror = mirrorTus; + } + mirror.source = source; + initMirrorObject(); + + } + + synchronized void initMirrorObject() { + + TextureUnitStateRetained mirrorTus = + (TextureUnitStateRetained)mirror; + + if (this.texture != null) + mirrorTus.texture = (TextureRetained)this.texture.mirror; + else + mirrorTus.texture = null; + + if (this.texAttrs != null) + mirrorTus.texAttrs = + (TextureAttributesRetained)this.texAttrs.mirror; + else + mirrorTus.texAttrs = null; + + if (this.texGen != null) + mirrorTus.texGen = (TexCoordGenerationRetained)this.texGen.mirror; + else + mirrorTus.texGen = null; + } + + + /** Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + TextureUnitStateRetained mirrorTus = (TextureUnitStateRetained)mirror; + + if ((component & TEXTURE_CHANGED) != 0) { + mirrorTus.texture = (TextureRetained)value; + } + else if ((component & TEXTURE_ATTRS_CHANGED) != 0) { + mirrorTus.texAttrs = (TextureAttributesRetained)value; + } + else if ((component & TEXCOORD_GEN_CHANGED) != 0) { + mirrorTus.texGen = (TexCoordGenerationRetained)value; + } + else if ((component & ALL_STATE_CHANGED) != 0) { + Object [] args = (Object []) value; + mirrorTus.texture = (TextureRetained)args[0]; + mirrorTus.texAttrs = (TextureAttributesRetained)args[1]; + mirrorTus.texGen = (TexCoordGenerationRetained)args[2]; + } + } + + + boolean equivalent(TextureUnitStateRetained tr) { + + if (tr == null) { + return (false); + + } else if ((this.changedFrequent != 0) || (tr.changedFrequent != 0)) { + return (this.mirror == tr); + + } else { + + if (this.texture != tr.texture) { + return false; + } + + if (this.texAttrs != null && + !this.texAttrs.equivalent(tr.texAttrs)) { + return false; + } + + if (this.texGen != null && + !this.texGen.equivalent(tr.texGen)) { + return false; + } + } + + return true; + } + + protected Object clone() { + TextureUnitStateRetained tr = (TextureUnitStateRetained)super.clone(); + + // the cloned object is used for RenderBin only. + // In most cases, it will duplicate all attributes in the RenderBin + // so that updating a mirror object in one level will not affect the + // entire structure of the RenderBin, but will affect only those bins + // that got affected by the modified mirror object + if (this.texAttrs != null) + tr.texAttrs = (TextureAttributesRetained)this.texAttrs.clone(); + + if (this.texGen != null) + tr.texGen = (TexCoordGenerationRetained)this.texGen.clone(); + + return tr; + } + + + /** + * set the texture unit state according to the specified texture + * unit state + */ + protected void set(TextureUnitStateRetained tr) { + super.set(tr); + this.texture = tr.texture; + + if (tr.texAttrs == null) { + this.texAttrs = null; + } else { + if (this.texAttrs == null) { + this.texAttrs = (TextureAttributesRetained)tr.texAttrs.clone(); + } else { + this.texAttrs.set(tr.texAttrs); + } + } + + if (tr.texGen == null) { + this.texGen = null; + } else { + if (this.texGen == null) { + this.texGen = (TexCoordGenerationRetained)tr.texGen.clone(); + } else { + this.texGen.set(tr.texGen); + } + } + } + + protected void set(TextureRetained texture, + TextureAttributesRetained texAttrs, + TexCoordGenerationRetained texGen) { + this.texture = texture; + this.texAttrs = texAttrs; + this.texGen = texGen; + } + + synchronized void addAMirrorUser(Shape3DRetained shape) { + + super.addAMirrorUser(shape); + + if (texture != null) + texture.addAMirrorUser(shape); + if (texAttrs != null) + texAttrs.addAMirrorUser(shape); + if (texGen != null) + texGen.addAMirrorUser(shape); + } + + synchronized void removeAMirrorUser(Shape3DRetained shape) { + super.removeAMirrorUser(shape); + + if (texture != null) + texture.removeAMirrorUser(shape); + if (texAttrs != null) + texAttrs.removeAMirrorUser(shape); + if (texGen != null) + texGen.removeAMirrorUser(shape); + } + + synchronized void removeMirrorUsers(NodeComponentRetained node) { + super.removeMirrorUsers(node); + + if (texture != null) + texture.removeMirrorUsers(node); + if (texAttrs != null) + texAttrs.removeMirrorUsers(node); + if (texGen != null) + texGen.removeMirrorUsers(node); + } + + synchronized void copyMirrorUsers(NodeComponentRetained node) { + super.copyMirrorUsers(node); + + if (texture != null) + texture.copyMirrorUsers(node); + if (texAttrs != null) + texAttrs.copyMirrorUsers(node); + if (texGen != null) + texGen.copyMirrorUsers(node); + } + + + void setLive(boolean backgroundGroup, int refCount) { + if (texture != null) + texture.setLive(backgroundGroup, refCount); + + if (texAttrs != null) + texAttrs.setLive(backgroundGroup, refCount); + + if (texGen != null) + texGen.setLive(backgroundGroup, refCount); + + // Increment the reference count and initialize the textureUnitState + // mirror object + super.doSetLive(backgroundGroup, refCount); + super.markAsLive(); + + } + + + void clearLive(int refCount) { + super.clearLive(refCount); + + if (texture != null) + texture.clearLive(refCount); + if (texAttrs != null) + texAttrs.clearLive(refCount); + if (texGen != null) + texGen.clearLive(refCount); + } + + boolean isStatic() { + + return (source.capabilityBitsEmpty() && + ((texture == null) || (texture.isStatic())) && + ((texAttrs == null) || (texAttrs.isStatic())) && + ((texGen == null) || (texGen.isStatic()))); + } + + // Issue 209 - enable this method (was previously commented out) + // Simply pass along to the NodeComponent + void compile (CompileState compState) { + setCompiled(); + + if (texture != null) + texture.compile(compState); + if (texAttrs != null) + texAttrs.compile(compState); + if (texGen != null) + texGen.compile(compState); + } + + boolean equals(TextureUnitStateRetained ts) { + return ((ts == this) || + (ts != null) && + ((texture == ts.texture) || + ((texture != null) && (texture.equals(ts.texture)))) && + ((texAttrs == ts.texAttrs) || + ((texAttrs != null) && (texAttrs.equals(ts.texAttrs)))) && + ((texGen == ts.texGen) || + ((texGen != null) && (texGen.equals(ts.texGen))))); + } + + + void setInImmCtx(boolean flag) { + super.setInImmCtx(flag); + if (texture != null) + texture.setInImmCtx(flag); + if (texAttrs != null) + texAttrs.setInImmCtx(flag); + if (texGen != null) + texGen.setInImmCtx(flag); + } + + boolean getInImmCtx() { + return (super.getInImmCtx() || + ((texture != null) && (texture.getInImmCtx())) || + ((texAttrs != null) && (texAttrs.getInImmCtx())) || + ((texGen != null) && (texGen.getInImmCtx()))); + } + + + boolean isLive() { + return (source.isLive() || + ((texture != null) && (texture.source.isLive())) || + ((texAttrs != null) && (texAttrs.source.isLive())) || + ((texGen != null) && (texGen.source.isLive()))); + } + + final void sendMessage(int attrMask, Object attr) { + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.TEXTURE_UNIT_STATE_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i + * + * A transform has an associated type, and + * all type classification is left to the Transform3D object. + * A transform will typically have multiple types, unless it is a + * general, unclassifiable matrix, in which case it won't be assigned + * a type.

+ * + * The Transform3D type is internally computed when the transform + * object is constructed and updated any time it is modified. A + * matrix will typically have multiple types. For example, the type + * associated with an identity matrix is the result of ORing all of + * the types, except for ZERO and NEGATIVE_DETERMINANT, together. + * There are public methods available to get the ORed type of the + * transformation, the sign of the determinant, and the least + * general matrix type. The matrix type flags are defined as + * follows:

+ *

    + *
  • ZERO - zero matrix. All of the elements in the matrix + * have the value 0.
  • + *

  • IDENTITY - identity matrix. A matrix with ones on its + * main diagonal and zeros every where else.
  • + *

  • SCALE - the matrix is a uniform scale matrix - there are + * no rotational or translation components.
  • + *

  • ORTHOGONAL - the four row vectors that make up an orthogonal + * matrix form a basis, meaning that they are mutually orthogonal. + * The scale is unity and there are no translation components.
  • + *

  • RIGID - the upper 3 X 3 of the matrix is orthogonal, and + * there is a translation component-the scale is unity.
  • + *

  • CONGRUENT - this is an angle- and length-preserving matrix, + * meaning that it can translate, rotate, and reflect about an axis, + * and scale by an amount that is uniform in all directions. These + * operations preserve the distance between any two points, and the + * angle between any two intersecting lines.
  • + *

  • AFFINE - an affine matrix can translate, rotate, reflect, + * scale anisotropically, and shear. Lines remain straight, and parallel + * lines remain parallel, but the angle between intersecting lines can + * change.
  • + *

+ * A matrix is also classified by the sign of its determinant:

+ *

    + * NEGATIVE_DETERMINANT - this matrix has a negative determinant. + * An orthogonal matrix with a positive determinant is a rotation + * matrix. An orthogonal matrix with a negative determinant is a + * reflection and rotation matrix.

+ * The Java 3D model for 4 X 4 transformations is:

+ *

    + * [ m00 m01 m02 m03 ]   [ x ]   [ x' ]
    + * [ m10 m11 m12 m13 ] . [ y ] = [ y' ]
    + * [ m20 m21 m22 m23 ]   [ z ]   [ z' ]
    + * [ m30 m31 m32 m33 ]   [ w ]   [ w' ]
    + *
    + * x' = m00 . x+m01 . y+m02 . z+m03 . w
    + * y' = m10 . x+m11 . y+m12 . z+m13 . w
    + * z' = m20 . x+m21 . y+m22 . z+m23 . w
    + * w' = m30 . x+m31 . y+m32 . z+m33 . w
    + * 

+ * Note: When transforming a Point3f or a Point3d, the input w is set to + * 1. When transforming a Vector3f or Vector3d, the input w is set to 0. + */ + +public class Transform3D { + + double[] mat = new double[16]; + //double[] rot = new double[9]; + //double[] scales = new double[3]; + // allocate the memory only when it is needed. Following three places will allocate the memory, + // void setScaleTranslation(), void computeScales() and void computeScaleRotation() + double[] rot = null; + double[] scales = null; + + // Unknown until lazy classification is done + private int type = 0; + + // Dirty bit for classification, this is used + // for classify() + private static final int AFFINE_BIT = 0x01; + private static final int ORTHO_BIT = 0x02; + private static final int CONGRUENT_BIT = 0x04; + private static final int RIGID_BIT = 0x08; + private static final int CLASSIFY_BIT = 0x10; + + // this is used for scales[], rot[] + private static final int SCALE_BIT = 0x20; + private static final int ROTATION_BIT = 0x40; + // set when SVD renormalization is necessary + private static final int SVD_BIT = 0x80; + + private static final int CLASSIFY_ALL_DIRTY = AFFINE_BIT | + ORTHO_BIT | + CONGRUENT_BIT | + RIGID_BIT | + CLASSIFY_BIT; + private static final int ROTSCALESVD_DIRTY = SCALE_BIT | + ROTATION_BIT | + SVD_BIT; + private static final int ALL_DIRTY = CLASSIFY_ALL_DIRTY | ROTSCALESVD_DIRTY; + + private int dirtyBits; + + boolean autoNormalize = false; // Don't auto normalize by default + /* + // reused temporaries for compute_svd + private boolean svdAllocd =false; + private double[] u1 = null; + private double[] v1 = null; + private double[] t1 = null; // used by both compute_svd and compute_qr + private double[] t2 = null; // used by both compute_svd and compute_qr + private double[] ts = null; + private double[] svdTmp = null; + private double[] svdRot = null; + private double[] single_values = null; + private double[] e = null; + private double[] svdScales = null; + // from svrReorder + private int[] svdOut = null; + private double[] svdMag = null; + + // from compute_qr + private double[] cosl = null; + private double[] cosr = null; + private double[] sinl = null; + private double[] sinr = null; + private double[] qr_m = null; + */ + + private static final double EPS = 1.110223024E-16; + + static final double EPSILON = 1.0e-10; + static final double EPSILON_ABSOLUTE = 1.0e-5; + static final double EPSILON_RELATIVE = 1.0e-4; + /** + * A zero matrix. + */ + public static final int ZERO = 0x01; + + /** + * An identity matrix. + */ + public static final int IDENTITY = 0x02; + + + /** + * A Uniform scale matrix with no translation or other + * off-diagonal components. + */ + public static final int SCALE = 0x04; + + /** + * A translation-only matrix with ones on the diagonal. + * + */ + public static final int TRANSLATION = 0x08; + + /** + * The four row vectors that make up an orthogonal matrix form a basis, + * meaning that they are mutually orthogonal; an orthogonal matrix with + * positive determinant is a pure rotation matrix; a negative + * determinant indicates a rotation and a reflection. + */ + public static final int ORTHOGONAL = 0x10; + + /** + * This matrix is a rotation and a translation with unity scale; + * The upper 3x3 of the matrix is orthogonal, and there is a + * translation component. + */ + public static final int RIGID = 0x20; + + /** + * This is an angle and length preserving matrix, meaning that it + * can translate, rotate, and reflect + * about an axis, and scale by an amount that is uniform in all directions. + * These operations preserve the distance between any two points and the + * angle between any two intersecting lines. + */ + public static final int CONGRUENT = 0x40; + + /** + * An affine matrix can translate, rotate, reflect, scale anisotropically, + * and shear. Lines remain straight, and parallel lines remain parallel, + * but the angle between intersecting lines can change. In order for a + * transform to be classified as affine, the 4th row must be: [0, 0, 0, 1]. + */ + public static final int AFFINE = 0x80; + + /** + * This matrix has a negative determinant; an orthogonal matrix with + * a positive determinant is a rotation matrix; an orthogonal matrix + * with a negative determinant is a reflection and rotation matrix. + */ + public static final int NEGATIVE_DETERMINANT = 0x100; + + /** + * The upper 3x3 column vectors that make up an orthogonal + * matrix form a basis meaning that they are mutually orthogonal. + * It can have non-uniform or zero x/y/z scale as long as + * the dot product of any two column is zero. + * This one is used by Java3D internal only and should not + * expose to the user. + */ + private static final int ORTHO = 0x40000000; + + /** + * Constructs and initializes a transform from the 4 x 4 matrix. The + * type of the constructed transform will be classified automatically. + * @param m1 the 4 x 4 transformation matrix + */ + public Transform3D(Matrix4f m1) { + set(m1); + } + + /** + * Constructs and initializes a transform from the 4 x 4 matrix. The + * type of the constructed transform will be classified automatically. + * @param m1 the 4 x 4 transformation matrix + */ + public Transform3D(Matrix4d m1) { + set(m1); + } + + /** + * Constructs and initializes a transform from the Transform3D object. + * @param t1 the transformation object to be copied + */ + public Transform3D(Transform3D t1) { + set(t1); + } + + /** + * Constructs and initializes a transform to the identity matrix. + */ + public Transform3D() { + setIdentity(); // this will also classify the matrix + } + + /** + * Constructs and initializes a transform from the float array of + * length 16; the top row of the matrix is initialized to the first + * four elements of the array, and so on. The type of the transform + * object is classified internally. + * @param matrix a float array of 16 + */ + public Transform3D(float[] matrix) { + set(matrix); + } + + /** + * Constructs and initializes a transform from the double precision array + * of length 16; the top row of the matrix is initialized to the first + * four elements of the array, and so on. The type of the transform is + * classified internally. + * @param matrix a float array of 16 + */ + public Transform3D(double[] matrix) { + set(matrix); + } + + /** + * Constructs and initializes a transform from the quaternion, + * translation, and scale values. The scale is applied only to the + * rotational components of the matrix (upper 3 x 3) and not to the + * translational components of the matrix. + * @param q1 the quaternion value representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Transform3D(Quat4d q1, Vector3d t1, double s) { + set(q1, t1, s); + } + + /** + * Constructs and initializes a transform from the quaternion, + * translation, and scale values. The scale is applied only to the + * rotational components of the matrix (upper 3 x 3) and not to the + * translational components of the matrix. + * @param q1 the quaternion value representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Transform3D(Quat4f q1, Vector3d t1, double s) { + set(q1, t1, s); + } + + /** + * Constructs and initializes a transform from the quaternion, + * translation, and scale values. The scale is applied only to the + * rotational components of the matrix (upper 3 x 3) and not to the + * translational components of the matrix. + * @param q1 the quaternion value representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Transform3D(Quat4f q1, Vector3f t1, float s) { + set(q1, t1, s); + } + + /** + * Constructs a transform and initializes it to the upper 4 x 4 + * of the GMatrix argument. If the parameter matrix is + * smaller than 4 x 4, the remaining elements in the transform matrix are + * assigned to zero. + * @param m1 the GMatrix + */ + public Transform3D(GMatrix m1) { + set(m1); + } + + /** + * Constructs and initializes a transform from the rotation matrix, + * translation, and scale values. The scale is applied only to the + * rotational component of the matrix (upper 3x3) and not to the + * translational component of the matrix. + * @param m1 the rotation matrix representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Transform3D(Matrix3f m1, Vector3d t1, double s) { + set(m1, t1, s); + } + + /** + * Constructs and initializes a transform from the rotation matrix, + * translation, and scale values. The scale is applied only to the + * rotational components of the matrix (upper 3x3) and not to the + * translational components of the matrix. + * @param m1 the rotation matrix representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Transform3D(Matrix3d m1, Vector3d t1, double s) { + set(m1, t1, s); + } + + + /** + * Constructs and initializes a transform from the rotation matrix, + * translation, and scale values. The scale is applied only to the + * rotational components of the matrix (upper 3x3) and not to the + * translational components of the matrix. + * @param m1 the rotation matrix representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Transform3D(Matrix3f m1, Vector3f t1, float s) { + set(m1, t1, s); + } + + /** + * Returns the type of this matrix as an or'ed bitmask of + * of all of the type classifications to which it belongs. + * @return or'ed bitmask of all of the type classifications + * of this transform + */ + public final int getType() { + if ((dirtyBits & CLASSIFY_BIT) != 0) { + classify(); + } + // clear ORTHO bit which only use internally + return (type & ~ORTHO); + } + + // True if type is ORTHO + // Since ORTHO didn't take into account the last row. + final boolean isOrtho() { + if ((dirtyBits & ORTHO_BIT) != 0) { + if ((almostZero(mat[0]*mat[2] + mat[4]*mat[6] + + mat[8]*mat[10]) && + almostZero(mat[0]*mat[1] + mat[4]*mat[5] + + mat[8]*mat[9]) && + almostZero(mat[1]*mat[2] + mat[5]*mat[6] + + mat[9]*mat[10]))) { + type |= ORTHO; + dirtyBits &= ~ORTHO_BIT; + return true; + } else { + type &= ~ORTHO; + dirtyBits &= ~ORTHO_BIT; + return false; + } + } + return ((type & ORTHO) != 0); + } + + final boolean isCongruent() { + if ((dirtyBits & CONGRUENT_BIT) != 0) { + // This will also classify AFFINE + classifyRigid(); + } + return ((type & CONGRUENT) != 0); + } + + final boolean isAffine() { + if ((dirtyBits & AFFINE_BIT) != 0) { + classifyAffine(); + } + return ((type & AFFINE) != 0); + } + + final boolean isRigid() { + if ((dirtyBits & RIGID_BIT) != 0) { + + + // This will also classify AFFINE & CONGRUENT + if ((dirtyBits & CONGRUENT_BIT) != 0) { + classifyRigid(); + } else { + + if ((type & CONGRUENT) != 0) { + // Matrix is Congruent, need only + // to check scale + double s; + if ((dirtyBits & SCALE_BIT) != 0){ + s = mat[0]*mat[0] + mat[4]*mat[4] + + mat[8]*mat[8]; + // Note that + // scales[0] = sqrt(s); + // but since sqrt(1) = 1, + // we don't need to do s = sqrt(s) here. + } else { + if(scales == null) + scales = new double[3]; + s = scales[0]; + } + if (almostOne(s)) { + type |= RIGID; + } else { + type &= ~RIGID; + } + } else { + // Not even congruent, so isRigid must be false + type &= ~RIGID; + } + dirtyBits &= ~RIGID_BIT; + } + } + return ((type & RIGID) != 0); + } + + + /** + * Returns the least general type of this matrix; the order of + * generality from least to most is: ZERO, IDENTITY, + * SCALE/TRANSLATION, ORTHOGONAL, RIGID, CONGRUENT, AFFINE. + * If the matrix is ORTHOGONAL, calling the method + * getDeterminantSign() will yield more information. + * @return the least general matrix type + */ + public final int getBestType() { + getType(); // force classify if necessary + + if ((type & ZERO) != 0 ) return ZERO; + if ((type & IDENTITY) != 0 ) return IDENTITY; + if ((type & SCALE) != 0 ) return SCALE; + if ((type & TRANSLATION) != 0 ) return TRANSLATION; + if ((type & ORTHOGONAL) != 0 ) return ORTHOGONAL; + if ((type & RIGID) != 0 ) return RIGID; + if ((type & CONGRUENT) != 0 ) return CONGRUENT; + if ((type & AFFINE) != 0 ) return AFFINE; + if ((type & NEGATIVE_DETERMINANT) != 0 ) return NEGATIVE_DETERMINANT; + return 0; + } + + /* + private void print_type() { + if ((type & ZERO) > 0 ) System.err.print(" ZERO"); + if ((type & IDENTITY) > 0 ) System.err.print(" IDENTITY"); + if ((type & SCALE) > 0 ) System.err.print(" SCALE"); + if ((type & TRANSLATION) > 0 ) System.err.print(" TRANSLATION"); + if ((type & ORTHOGONAL) > 0 ) System.err.print(" ORTHOGONAL"); + if ((type & RIGID) > 0 ) System.err.print(" RIGID"); + if ((type & CONGRUENT) > 0 ) System.err.print(" CONGRUENT"); + if ((type & AFFINE) > 0 ) System.err.print(" AFFINE"); + if ((type & NEGATIVE_DETERMINANT) > 0 ) System.err.print(" NEGATIVE_DETERMINANT"); + } + */ + + /** + * Returns the sign of the determinant of this matrix; a return value + * of true indicates a non-negative determinant; a return value of false + * indicates a negative determinant. A value of true will be returned if + * the determinant is NaN. In general, an orthogonal matrix + * with a positive determinant is a pure rotation matrix; an orthogonal + * matrix with a negative determinant is a both a rotation and a + * reflection matrix. + * @return determinant sign : true means non-negative, false means negative + */ + public final boolean getDeterminantSign() { + double det = determinant(); + if (Double.isNaN(det)) { + return true; + } + return det >= 0; + } + + /** + * Sets a flag that enables or disables automatic SVD + * normalization. If this flag is enabled, an automatic SVD + * normalization of the rotational components (upper 3x3) of this + * matrix is done after every subsequent matrix operation that + * modifies this matrix. This is functionally equivalent to + * calling normalize() after every subsequent call, but may be + * less computationally expensive. + * The default value for this parameter is false. + * @param autoNormalize the boolean state of auto normalization + */ + public final void setAutoNormalize(boolean autoNormalize) { + this.autoNormalize = autoNormalize; + + if (autoNormalize) { + normalize(); + } + } + + /** + * Returns the state of auto-normalization. + * @return boolean state of auto-normalization + */ + public final boolean getAutoNormalize() { + return this.autoNormalize; + } + + /** + * Transforms the point parameter with this transform and + * places the result into pointOut. The fourth element of the + * point input paramter is assumed to be one. + * @param point the input point to be transformed + * @param pointOut the transformed point + */ + void transform(Point3d point, Point4d pointOut) { + + pointOut.x = mat[0]*point.x + mat[1]*point.y + + mat[2]*point.z + mat[3]; + pointOut.y = mat[4]*point.x + mat[5]*point.y + + mat[6]*point.z + mat[7]; + pointOut.z = mat[8]*point.x + mat[9]*point.y + + mat[10]*point.z + mat[11]; + pointOut.w = mat[12]*point.x + mat[13]*point.y + + mat[14]*point.z + mat[15]; + } + + + + private static final boolean almostZero(double a) { + return ((a < EPSILON_ABSOLUTE) && (a > -EPSILON_ABSOLUTE)); + } + + private static final boolean almostOne(double a) { + return ((a < 1+EPSILON_ABSOLUTE) && (a > 1-EPSILON_ABSOLUTE)); + } + + private static final boolean almostEqual(double a, double b) { + double diff = a-b; + + if (diff >= 0) { + if (diff < EPSILON) { + return true; + } + // a > b + if ((b > 0) || (a > -b)) { + return (diff < EPSILON_RELATIVE*a); + } else { + return (diff < -EPSILON_RELATIVE*b); + } + + } else { + if (diff > -EPSILON) { + return true; + } + // a < b + if ((b < 0) || (-a > b)) { + return (diff > EPSILON_RELATIVE*a); + } else { + return (diff > -EPSILON_RELATIVE*b); + } + } + } + + private final void classifyAffine() { + if (!isInfOrNaN() && + almostZero(mat[12]) && + almostZero(mat[13]) && + almostZero(mat[14]) && + almostOne(mat[15])) { + type |= AFFINE; + } else { + type &= ~AFFINE; + } + dirtyBits &= ~AFFINE_BIT; + } + + // same amount of work to classify rigid and congruent + private final void classifyRigid() { + + if ((dirtyBits & AFFINE_BIT) != 0) { + // should not touch ORTHO bit + type &= ORTHO; + classifyAffine(); + } else { + // keep the affine bit if there is one + // and clear the others (CONGRUENT/RIGID) bit + type &= (ORTHO | AFFINE); + } + + if ((type & AFFINE) != 0) { + // checking orthogonal condition + if (isOrtho()) { + if ((dirtyBits & SCALE_BIT) != 0) { + double s0 = mat[0]*mat[0] + mat[4]*mat[4] + + mat[8]*mat[8]; + double s1 = mat[1]*mat[1] + mat[5]*mat[5] + + mat[9]*mat[9]; + if (almostEqual(s0, s1)) { + double s2 = mat[2]*mat[2] + mat[6]*mat[6] + + mat[10]*mat[10]; + if (almostEqual(s2, s0)) { + type |= CONGRUENT; + // Note that scales[0] = sqrt(s0); + if (almostOne(s0)) { + type |= RIGID; + } + } + } + } else { + if(scales == null) + scales = new double[3]; + + double s = scales[0]; + if (almostEqual(s, scales[1]) && + almostEqual(s, scales[2])) { + type |= CONGRUENT; + if (almostOne(s)) { + type |= RIGID; + } + } + } + } + } + dirtyBits &= (~RIGID_BIT | ~CONGRUENT_BIT); + } + + /** + * Classifies a matrix. + */ + private final void classify() { + + if ((dirtyBits & (RIGID_BIT|AFFINE_BIT|CONGRUENT_BIT)) != 0) { + // Test for RIGID, CONGRUENT, AFFINE. + classifyRigid(); + } + + // Test for ZERO, IDENTITY, SCALE, TRANSLATION, + // ORTHOGONAL, NEGATIVE_DETERMINANT + if ((type & AFFINE) != 0) { + if ((type & CONGRUENT) != 0) { + if ((type & RIGID) != 0) { + if (zeroTranslation()) { + type |= ORTHOGONAL; + if (rotateZero()) { + // mat[0], mat[5], mat[10] can be only be + // 1 or -1 when reach here + if ((mat[0] > 0) && + (mat[5] > 0) && + (mat[10] > 0)) { + type |= IDENTITY|SCALE|TRANSLATION; + } + } + } else { + if (rotateZero()) { + type |= TRANSLATION; + } + } + } else { + // uniform scale + if (zeroTranslation() && rotateZero()) { + type |= SCALE; + } + } + + } + } else { + // last row is not (0, 0, 0, 1) + if (almostZero(mat[12]) && + almostZero(mat[13]) && + almostZero(mat[14]) && + almostZero(mat[15]) && + zeroTranslation() && + rotateZero() && + almostZero(mat[0]) && + almostZero(mat[5]) && + almostZero(mat[10])) { + type |= ZERO; + } + } + + if (!getDeterminantSign()) { + type |= NEGATIVE_DETERMINANT; + } + dirtyBits &= ~CLASSIFY_BIT; + } + + final boolean zeroTranslation() { + return (almostZero(mat[3]) && + almostZero(mat[7]) && + almostZero(mat[11])); + } + + final boolean rotateZero() { + return (almostZero(mat[1]) && almostZero(mat[2]) && + almostZero(mat[4]) && almostZero(mat[6]) && + almostZero(mat[8]) && almostZero(mat[9])); + } + + /** + * Returns the matrix elements of this transform as a string. + * @return the matrix elements of this transform + */ + public String toString() { + // also, print classification? + return + mat[0] + ", " + mat[1] + ", " + mat[2] + ", " + mat[3] + "\n" + + mat[4] + ", " + mat[5] + ", " + mat[6] + ", " + mat[7] + "\n" + + mat[8] + ", " + mat[9] + ", " + mat[10] + ", " + mat[11] + "\n" + + mat[12] + ", " + mat[13] + ", " + mat[14] + ", " + mat[15] + + "\n"; + } + + /** + * Sets this transform to the identity matrix. + */ + public final void setIdentity() { + mat[0] = 1.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = 0.0; + mat[4] = 0.0; mat[5] = 1.0; mat[6] = 0.0; mat[7] = 0.0; + mat[8] = 0.0; mat[9] = 0.0; mat[10] = 1.0; mat[11] = 0.0; + mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 1.0; + type = IDENTITY | SCALE | ORTHOGONAL | RIGID | CONGRUENT | + AFFINE | TRANSLATION | ORTHO; + dirtyBits = SCALE_BIT | ROTATION_BIT; + // No need to set SVD_BIT + } + + /** + * Sets this transform to all zeros. + */ + public final void setZero() { + mat[0] = 0.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = 0.0; + mat[4] = 0.0; mat[5] = 0.0; mat[6] = 0.0; mat[7] = 0.0; + mat[8] = 0.0; mat[9] = 0.0; mat[10] = 0.0; mat[11] = 0.0; + mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 0.0; + + type = ZERO | ORTHO; + dirtyBits = SCALE_BIT | ROTATION_BIT; + } + + + /** + * Adds this transform to transform t1 and places the result into + * this: this = this + t1. + * @param t1 the transform to be added to this transform + */ + public final void add(Transform3D t1) { + for (int i=0 ; i<16 ; i++) { + mat[i] += t1.mat[i]; + } + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + + } + + /** + * Adds transforms t1 and t2 and places the result into this transform. + * @param t1 the transform to be added + * @param t2 the transform to be added + */ + public final void add(Transform3D t1, Transform3D t2) { + for (int i=0 ; i<16 ; i++) { + mat[i] = t1.mat[i] + t2.mat[i]; + } + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + + } + + /** + * Subtracts transform t1 from this transform and places the result + * into this: this = this - t1. + * @param t1 the transform to be subtracted from this transform + */ + public final void sub(Transform3D t1) { + for (int i=0 ; i<16 ; i++) { + mat[i] -= t1.mat[i]; + } + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + + /** + * Subtracts transform t2 from transform t1 and places the result into + * this: this = t1 - t2. + * @param t1 the left transform + * @param t2 the right transform + */ + public final void sub(Transform3D t1, Transform3D t2) { + for (int i=0 ; i<16 ; i++) { + mat[i] = t1.mat[i] - t2.mat[i]; + } + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + + } + + + /** + * Transposes this matrix in place. + */ + public final void transpose() { + double temp; + + temp = mat[4]; + mat[4] = mat[1]; + mat[1] = temp; + + temp = mat[8]; + mat[8] = mat[2]; + mat[2] = temp; + + temp = mat[12]; + mat[12] = mat[3]; + mat[3] = temp; + + temp = mat[9]; + mat[9] = mat[6]; + mat[6] = temp; + + temp = mat[13]; + mat[13] = mat[7]; + mat[7] = temp; + + temp = mat[14]; + mat[14] = mat[11]; + mat[11] = temp; + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + /** + * Transposes transform t1 and places the value into this transform. + * The transform t1 is not modified. + * @param t1 the transform whose transpose is placed into this transform + */ + public final void transpose(Transform3D t1) { + + if (this != t1) { + mat[0] = t1.mat[0]; + mat[1] = t1.mat[4]; + mat[2] = t1.mat[8]; + mat[3] = t1.mat[12]; + mat[4] = t1.mat[1]; + mat[5] = t1.mat[5]; + mat[6] = t1.mat[9]; + mat[7] = t1.mat[13]; + mat[8] = t1.mat[2]; + mat[9] = t1.mat[6]; + mat[10] = t1.mat[10]; + mat[11] = t1.mat[14]; + mat[12] = t1.mat[3]; + mat[13] = t1.mat[7]; + mat[14] = t1.mat[11]; + mat[15] = t1.mat[15]; + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } else { + this.transpose(); + } + + } + + /** + * Sets the value of this transform to the matrix conversion of the + * single precision quaternion argument; the non-rotational + * components are set as if this were an identity matrix. + * @param q1 the quaternion to be converted + */ + public final void set(Quat4f q1) { + + mat[0] = (1.0f - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z); + mat[4] = (2.0f*(q1.x*q1.y + q1.w*q1.z)); + mat[8] = (2.0f*(q1.x*q1.z - q1.w*q1.y)); + + mat[1] = (2.0f*(q1.x*q1.y - q1.w*q1.z)); + mat[5] = (1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z); + mat[9] = (2.0f*(q1.y*q1.z + q1.w*q1.x)); + + mat[2] = (2.0f*(q1.x*q1.z + q1.w*q1.y)); + mat[6] = (2.0f*(q1.y*q1.z - q1.w*q1.x)); + mat[10] = (1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y); + + mat[3] = 0.0; + mat[7] = 0.0; + mat[11] = 0.0; + + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(q1)) { + dirtyBits = ALL_DIRTY; + return; + } + + dirtyBits = CLASSIFY_BIT | SCALE_BIT | ROTATION_BIT; + type = RIGID | CONGRUENT | AFFINE | ORTHO; + } + + /** + * Sets the value of this transform to the matrix conversion of the + * double precision quaternion argument; the non-rotational + * components are set as if this were an identity matrix. + * @param q1 the quaternion to be converted + */ + public final void set(Quat4d q1) { + + mat[0] = (1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z); + mat[4] = (2.0*(q1.x*q1.y + q1.w*q1.z)); + mat[8] = (2.0*(q1.x*q1.z - q1.w*q1.y)); + + mat[1] = (2.0*(q1.x*q1.y - q1.w*q1.z)); + mat[5] = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z); + mat[9] = (2.0*(q1.y*q1.z + q1.w*q1.x)); + + mat[2] = (2.0*(q1.x*q1.z + q1.w*q1.y)); + mat[6] = (2.0*(q1.y*q1.z - q1.w*q1.x)); + mat[10] = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y); + + mat[3] = 0.0; + mat[7] = 0.0; + mat[11] = 0.0; + + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(q1)) { + dirtyBits = ALL_DIRTY; + return; + } + + dirtyBits = CLASSIFY_BIT | SCALE_BIT | ROTATION_BIT; + type = RIGID | CONGRUENT | AFFINE | ORTHO; + } + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * matrix values in the double precision Matrix3d argument; the other + * elements of this transform are unchanged; any pre-existing scale + * will be preserved; the argument matrix m1 will be checked for proper + * normalization when this transform is internally classified. + * @param m1 the double precision 3x3 matrix + */ + public final void setRotation(Matrix3d m1) { + + if ((dirtyBits & SCALE_BIT)!= 0) { + computeScales(false); + } + + mat[0] = m1.m00*scales[0]; + mat[1] = m1.m01*scales[1]; + mat[2] = m1.m02*scales[2]; + mat[4] = m1.m10*scales[0]; + mat[5] = m1.m11*scales[1]; + mat[6] = m1.m12*scales[2]; + mat[8] = m1.m20*scales[0]; + mat[9] = m1.m21*scales[1]; + mat[10]= m1.m22*scales[2]; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + // the matrix pass in may not normalize + normalize(); + } + } + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * matrix values in the single precision Matrix3f argument; the other + * elements of this transform are unchanged; any pre-existing scale + * will be preserved; the argument matrix m1 will be checked for proper + * normalization when this transform is internally classified. + * @param m1 the single precision 3x3 matrix + */ + public final void setRotation(Matrix3f m1) { + + if ((dirtyBits & SCALE_BIT)!= 0) { + computeScales(false); + } + + mat[0] = m1.m00*scales[0]; + mat[1] = m1.m01*scales[1]; + mat[2] = m1.m02*scales[2]; + mat[4] = m1.m10*scales[0]; + mat[5] = m1.m11*scales[1]; + mat[6] = m1.m12*scales[2]; + mat[8] = m1.m20*scales[0]; + mat[9] = m1.m21*scales[1]; + mat[10]= m1.m22*scales[2]; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * matrix equivalent values of the quaternion argument; the other + * elements of this transform are unchanged; any pre-existing scale + * in the transform is preserved. + * @param q1 the quaternion that specifies the rotation + */ + public final void setRotation(Quat4f q1) { + + if ((dirtyBits & SCALE_BIT)!= 0) { + computeScales(false); + } + + mat[0] = (1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z)*scales[0]; + mat[4] = (2.0*(q1.x*q1.y + q1.w*q1.z))*scales[0]; + mat[8] = (2.0*(q1.x*q1.z - q1.w*q1.y))*scales[0]; + + mat[1] = (2.0*(q1.x*q1.y - q1.w*q1.z))*scales[1]; + mat[5] = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z)*scales[1]; + mat[9] = (2.0*(q1.y * q1.z + q1.w * q1.x))*scales[1]; + + mat[2] = (2.0*(q1.x*q1.z + q1.w*q1.y))*scales[2]; + mat[6] = (2.0*(q1.y*q1.z - q1.w*q1.x))*scales[2]; + mat[10] = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y)*scales[2]; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(q1)) { + dirtyBits = ALL_DIRTY; + return; + } + + dirtyBits |= CLASSIFY_BIT | ROTATION_BIT; + dirtyBits &= ~ORTHO_BIT; + type |= ORTHO; + type &= ~(ORTHOGONAL|IDENTITY|SCALE|TRANSLATION|SCALE|ZERO); + } + + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * matrix equivalent values of the quaternion argument; the other + * elements of this transform are unchanged; any pre-existing scale + * in the transform is preserved. + * @param q1 the quaternion that specifies the rotation + */ + public final void setRotation(Quat4d q1) { + + if ((dirtyBits & SCALE_BIT)!= 0) { + computeScales(false); + } + + mat[0] = (1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z)*scales[0]; + mat[4] = (2.0*(q1.x*q1.y + q1.w*q1.z))*scales[0]; + mat[8] = (2.0*(q1.x*q1.z - q1.w*q1.y))*scales[0]; + + mat[1] = (2.0*(q1.x*q1.y - q1.w*q1.z))*scales[1]; + mat[5] = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z)*scales[1]; + mat[9] = (2.0*(q1.y * q1.z + q1.w * q1.x))*scales[1]; + + mat[2] = (2.0*(q1.x*q1.z + q1.w*q1.y))*scales[2]; + mat[6] = (2.0*(q1.y*q1.z - q1.w*q1.x))*scales[2]; + mat[10] = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y)*scales[2]; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(q1)) { + dirtyBits = ALL_DIRTY; + return; + } + + dirtyBits |= CLASSIFY_BIT | ROTATION_BIT; + dirtyBits &= ~ORTHO_BIT; + type |= ORTHO; + type &= ~(ORTHOGONAL|IDENTITY|SCALE|TRANSLATION|SCALE|ZERO); + } + + + /** + * Sets the value of this transform to the matrix conversion + * of the single precision axis-angle argument; all of the matrix + * values are modified. + * @param a1 the axis-angle to be converted (x, y, z, angle) + */ + public final void set(AxisAngle4f a1) { + + double mag = Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z); + + if (almostZero(mag)) { + setIdentity(); + } else { + mag = 1.0/mag; + double ax = a1.x*mag; + double ay = a1.y*mag; + double az = a1.z*mag; + + double sinTheta = Math.sin((double)a1.angle); + double cosTheta = Math.cos((double)a1.angle); + double t = 1.0 - cosTheta; + + double xz = ax * az; + double xy = ax * ay; + double yz = ay * az; + + mat[0] = t * ax * ax + cosTheta; + mat[1] = t * xy - sinTheta * az; + mat[2] = t * xz + sinTheta * ay; + mat[3] = 0.0; + + mat[4] = t * xy + sinTheta * az; + mat[5] = t * ay * ay + cosTheta; + mat[6] = t * yz - sinTheta * ax; + mat[7] = 0.0; + + mat[8] = t * xz - sinTheta * ay; + mat[9] = t * yz + sinTheta * ax; + mat[10] = t * az * az + cosTheta; + mat[11] = 0.0; + + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(a1)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = CONGRUENT | AFFINE | RIGID | ORTHO; + dirtyBits = CLASSIFY_BIT | ROTATION_BIT | SCALE_BIT; + } + } + + + /** + * Sets the value of this transform to the matrix conversion + * of the double precision axis-angle argument; all of the matrix + * values are modified. + * @param a1 the axis-angle to be converted (x, y, z, angle) + */ + public final void set(AxisAngle4d a1) { + + double mag = Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z); + + if (almostZero(mag)) { + setIdentity(); + } else { + mag = 1.0/mag; + double ax = a1.x*mag; + double ay = a1.y*mag; + double az = a1.z*mag; + + double sinTheta = Math.sin(a1.angle); + double cosTheta = Math.cos(a1.angle); + double t = 1.0 - cosTheta; + + double xz = ax * az; + double xy = ax * ay; + double yz = ay * az; + + mat[0] = t * ax * ax + cosTheta; + mat[1] = t * xy - sinTheta * az; + mat[2] = t * xz + sinTheta * ay; + mat[3] = 0.0; + + mat[4] = t * xy + sinTheta * az; + mat[5] = t * ay * ay + cosTheta; + mat[6] = t * yz - sinTheta * ax; + mat[7] = 0.0; + + mat[8] = t * xz - sinTheta * ay; + mat[9] = t * yz + sinTheta * ax; + mat[10] = t * az * az + cosTheta; + mat[11] = 0.0; + + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(a1)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = CONGRUENT | AFFINE | RIGID | ORTHO; + dirtyBits = CLASSIFY_BIT | ROTATION_BIT | SCALE_BIT; + } + } + + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * matrix equivalent values of the axis-angle argument; the other + * elements of this transform are unchanged; any pre-existing scale + * in the transform is preserved. + * @param a1 the axis-angle to be converted (x, y, z, angle) + */ + public final void setRotation(AxisAngle4d a1) { + + if ((dirtyBits & SCALE_BIT)!= 0) { + computeScales(false); + } + + double mag = Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z); + + if (almostZero(mag)) { + mat[0] = scales[0]; + mat[1] = 0.0; + mat[2] = 0.0; + mat[4] = 0.0; + mat[5] = scales[1]; + mat[6] = 0.0; + mat[8] = 0.0; + mat[9] = 0.0; + mat[10] = scales[2]; + } else { + mag = 1.0/mag; + double ax = a1.x*mag; + double ay = a1.y*mag; + double az = a1.z*mag; + + double sinTheta = Math.sin(a1.angle); + double cosTheta = Math.cos(a1.angle); + double t = 1.0 - cosTheta; + + double xz = ax * az; + double xy = ax * ay; + double yz = ay * az; + + mat[0] = (t * ax * ax + cosTheta)*scales[0]; + mat[1] = (t * xy - sinTheta * az)*scales[1]; + mat[2] = (t * xz + sinTheta * ay)*scales[2]; + + mat[4] = (t * xy + sinTheta * az)*scales[0]; + mat[5] = (t * ay * ay + cosTheta)*scales[1]; + mat[6] = (t * yz - sinTheta * ax)*scales[2]; + + mat[8] = (t * xz - sinTheta * ay)*scales[0]; + mat[9] = (t * yz + sinTheta * ax)*scales[1]; + mat[10] = (t * az * az + cosTheta)*scales[2]; + } + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(a1)) { + dirtyBits = ALL_DIRTY; + return; + } + + // Rigid remain rigid, congruent remain congruent after + // set rotation + dirtyBits |= CLASSIFY_BIT | ROTATION_BIT; + dirtyBits &= ~ORTHO_BIT; + type |= ORTHO; + type &= ~(ORTHOGONAL|IDENTITY|SCALE|TRANSLATION|SCALE|ZERO); + } + + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * matrix equivalent values of the axis-angle argument; the other + * elements of this transform are unchanged; any pre-existing scale + * in the transform is preserved. + * @param a1 the axis-angle to be converted (x, y, z, angle) + */ + public final void setRotation(AxisAngle4f a1) { + + if ((dirtyBits & SCALE_BIT)!= 0) { + computeScales(false); + } + + double mag = Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z); + + if (almostZero(mag)) { + mat[0] = scales[0]; + mat[1] = 0.0; + mat[2] = 0.0; + mat[4] = 0.0; + mat[5] = scales[1]; + mat[6] = 0.0; + mat[8] = 0.0; + mat[9] = 0.0; + mat[10] = scales[2]; + } else { + mag = 1.0/mag; + double ax = a1.x*mag; + double ay = a1.y*mag; + double az = a1.z*mag; + + double sinTheta = Math.sin(a1.angle); + double cosTheta = Math.cos(a1.angle); + double t = 1.0 - cosTheta; + + double xz = ax * az; + double xy = ax * ay; + double yz = ay * az; + + mat[0] = (t * ax * ax + cosTheta)*scales[0]; + mat[1] = (t * xy - sinTheta * az)*scales[1]; + mat[2] = (t * xz + sinTheta * ay)*scales[2]; + + mat[4] = (t * xy + sinTheta * az)*scales[0]; + mat[5] = (t * ay * ay + cosTheta)*scales[1]; + mat[6] = (t * yz - sinTheta * ax)*scales[2]; + + mat[8] = (t * xz - sinTheta * ay)*scales[0]; + mat[9] = (t * yz + sinTheta * ax)*scales[1]; + mat[10] = (t * az * az + cosTheta)*scales[2]; + } + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(a1)) { + dirtyBits = ALL_DIRTY; + return; + } + + // Rigid remain rigid, congruent remain congruent after + // set rotation + dirtyBits |= CLASSIFY_BIT | ROTATION_BIT; + dirtyBits &= (~ORTHO_BIT | ~SVD_BIT); + type |= ORTHO; + type &= ~(ORTHOGONAL|IDENTITY|SCALE|TRANSLATION|SCALE|ZERO); + } + + + /** + * Sets the value of this transform to a counter clockwise rotation + * about the x axis. All of the non-rotational components are set as + * if this were an identity matrix. + * @param angle the angle to rotate about the X axis in radians + */ + public void rotX(double angle) { + double sinAngle = Math.sin(angle); + double cosAngle = Math.cos(angle); + + mat[0] = 1.0; + mat[1] = 0.0; + mat[2] = 0.0; + mat[3] = 0.0; + + mat[4] = 0.0; + mat[5] = cosAngle; + mat[6] = -sinAngle; + mat[7] = 0.0; + + mat[8] = 0.0; + mat[9] = sinAngle; + mat[10] = cosAngle; + mat[11] = 0.0; + + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(angle)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = CONGRUENT | AFFINE | RIGID | ORTHO; + dirtyBits = CLASSIFY_BIT | ROTATION_BIT | SCALE_BIT; + } + + /** + * Sets the value of this transform to a counter clockwise rotation about + * the y axis. All of the non-rotational components are set as if this + * were an identity matrix. + * @param angle the angle to rotate about the Y axis in radians + */ + public void rotY(double angle) { + double sinAngle = Math.sin(angle); + double cosAngle = Math.cos(angle); + + mat[0] = cosAngle; + mat[1] = 0.0; + mat[2] = sinAngle; + mat[3] = 0.0; + + mat[4] = 0.0; + mat[5] = 1.0; + mat[6] = 0.0; + mat[7] = 0.0; + + mat[8] = -sinAngle; + mat[9] = 0.0; + mat[10] = cosAngle; + mat[11] = 0.0; + + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(angle)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = CONGRUENT | AFFINE | RIGID | ORTHO; + dirtyBits = CLASSIFY_BIT | ROTATION_BIT | SCALE_BIT; + } + + + /** + * Sets the value of this transform to a counter clockwise rotation + * about the z axis. All of the non-rotational components are set + * as if this were an identity matrix. + * @param angle the angle to rotate about the Z axis in radians + */ + public void rotZ(double angle) { + double sinAngle = Math.sin(angle); + double cosAngle = Math.cos(angle); + + mat[0] = cosAngle; + mat[1] = -sinAngle; + mat[2] = 0.0; + mat[3] = 0.0; + + mat[4] = sinAngle; + mat[5] = cosAngle; + mat[6] = 0.0; + mat[7] = 0.0; + + mat[8] = 0.0; + mat[9] = 0.0; + mat[10] = 1.0; + mat[11] = 0.0; + + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(angle)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = CONGRUENT | AFFINE | RIGID | ORTHO; + dirtyBits = CLASSIFY_BIT | ROTATION_BIT | SCALE_BIT; + } + + + /** + * Sets the translational value of this matrix to the Vector3f parameter + * values, and sets the other components of the matrix as if this + * transform were an identity matrix. + * @param trans the translational component + */ + public final void set(Vector3f trans) { + mat[0] = 1.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = trans.x; + mat[4] = 0.0; mat[5] = 1.0; mat[6] = 0.0; mat[7] = trans.y; + mat[8] = 0.0; mat[9] = 0.0; mat[10] = 1.0; mat[11] = trans.z; + mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(trans)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = CONGRUENT | AFFINE | RIGID | ORTHO; + dirtyBits = CLASSIFY_BIT | ROTATION_BIT | SCALE_BIT; + } + + /** + * Sets the translational value of this matrix to the Vector3d paramter + * values, and sets the other components of the matrix as if this + * transform were an identity matrix. + * @param trans the translational component + */ + public final void set(Vector3d trans) { + mat[0] = 1.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = trans.x; + mat[4] = 0.0; mat[5] = 1.0; mat[6] = 0.0; mat[7] = trans.y; + mat[8] = 0.0; mat[9] = 0.0; mat[10] = 1.0; mat[11] = trans.z; + mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(trans)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = CONGRUENT | AFFINE | RIGID | ORTHO; + dirtyBits = CLASSIFY_BIT | ROTATION_BIT | SCALE_BIT; + } + + /** + * Sets the scale component of the current transform; any existing + * scale is first factored out of the existing transform before + * the new scale is applied. + * @param scale the new scale amount + */ + public final void setScale(double scale) { + if ((dirtyBits & ROTATION_BIT)!= 0) { + computeScaleRotation(false); + } + + scales[0] = scales[1] = scales[2] = scale; + mat[0] = rot[0]*scale; + mat[1] = rot[1]*scale; + mat[2] = rot[2]*scale; + mat[4] = rot[3]*scale; + mat[5] = rot[4]*scale; + mat[6] = rot[5]*scale; + mat[8] = rot[6]*scale; + mat[9] = rot[7]*scale; + mat[10] = rot[8]*scale; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(scale)) { + dirtyBits = ALL_DIRTY; + return; + } + + dirtyBits |= (CLASSIFY_BIT | RIGID_BIT | CONGRUENT_BIT | SVD_BIT); + dirtyBits &= ~SCALE_BIT; + } + + + /** + * Sets the possibly non-uniform scale component of the current + * transform; any existing scale is first factored out of the + * existing transform before the new scale is applied. + * @param scale the new x,y,z scale values + */ + public final void setScale(Vector3d scale) { + + if ((dirtyBits & ROTATION_BIT)!= 0) { + computeScaleRotation(false); + } + + scales[0] = scale.x; + scales[1] = scale.y; + scales[2] = scale.z; + + mat[0] = rot[0]*scale.x; + mat[1] = rot[1]*scale.y; + mat[2] = rot[2]*scale.z; + mat[4] = rot[3]*scale.x; + mat[5] = rot[4]*scale.y; + mat[6] = rot[5]*scale.z; + mat[8] = rot[6]*scale.x; + mat[9] = rot[7]*scale.y; + mat[10] = rot[8]*scale.z; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(scale)) { + dirtyBits = ALL_DIRTY; + return; + } + + dirtyBits |= (CLASSIFY_BIT | RIGID_BIT | CONGRUENT_BIT | SVD_BIT); + dirtyBits &= ~SCALE_BIT; + } + + + /** + * Replaces the current transform with a non-uniform scale transform. + * All values of the existing transform are replaced. + * @param xScale the new X scale amount + * @param yScale the new Y scale amount + * @param zScale the new Z scale amount + * @deprecated Use setScale(Vector3d) instead of setNonUniformScale; + * note that the setScale only modifies the scale component + */ + public final void setNonUniformScale(double xScale, + double yScale, + double zScale) { + if(scales == null) + scales = new double[3]; + + scales[0] = xScale; + scales[1] = yScale; + scales[2] = zScale; + mat[0] = xScale; + mat[1] = 0.0; + mat[2] = 0.0; + mat[3] = 0.0; + mat[4] = 0.0; + mat[5] = yScale; + mat[6] = 0.0; + mat[7] = 0.0; + mat[8] = 0.0; + mat[9] = 0.0; + mat[10] = zScale; + mat[11] = 0.0; + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + } + + /** + * Replaces the translational components of this transform to the values + * in the Vector3f argument; the other values of this transform are not + * modified. + * @param trans the translational component + */ + public final void setTranslation(Vector3f trans) { + mat[3] = trans.x; + mat[7] = trans.y; + mat[11] = trans.z; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(trans)) { + dirtyBits = ALL_DIRTY; + return; + } + + // Only preserve CONGRUENT, RIGID, ORTHO + type &= ~(ORTHOGONAL|IDENTITY|SCALE|TRANSLATION|SCALE|ZERO); + dirtyBits |= CLASSIFY_BIT; + } + + + /** + * Replaces the translational components of this transform to the values + * in the Vector3d argument; the other values of this transform are not + * modified. + * @param trans the translational component + */ + public final void setTranslation(Vector3d trans) { + mat[3] = trans.x; + mat[7] = trans.y; + mat[11] = trans.z; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(trans)) { + dirtyBits = ALL_DIRTY; + return; + } + + type &= ~(ORTHOGONAL|IDENTITY|SCALE|TRANSLATION|SCALE|ZERO); + dirtyBits |= CLASSIFY_BIT; + } + + + /** + * Sets the value of this matrix from the rotation expressed + * by the quaternion q1, the translation t1, and the scale s. + * @param q1 the rotation expressed as a quaternion + * @param t1 the translation + * @param s the scale value + */ + public final void set(Quat4d q1, Vector3d t1, double s) { + if(scales == null) + scales = new double[3]; + + scales[0] = scales[1] = scales[2] = s; + + mat[0] = (1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z)*s; + mat[4] = (2.0*(q1.x*q1.y + q1.w*q1.z))*s; + mat[8] = (2.0*(q1.x*q1.z - q1.w*q1.y))*s; + + mat[1] = (2.0*(q1.x*q1.y - q1.w*q1.z))*s; + mat[5] = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z)*s; + mat[9] = (2.0*(q1.y*q1.z + q1.w*q1.x))*s; + + mat[2] = (2.0*(q1.x*q1.z + q1.w*q1.y))*s; + mat[6] = (2.0*(q1.y*q1.z - q1.w*q1.x))*s; + mat[10] = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y)*s; + + mat[3] = t1.x; + mat[7] = t1.y; + mat[11] = t1.z; + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the quaternion q1, the translation t1, and the scale s. + * @param q1 the rotation expressed as a quaternion + * @param t1 the translation + * @param s the scale value + */ + public final void set(Quat4f q1, Vector3d t1, double s) { + if(scales == null) + scales = new double[3]; + + scales[0] = scales[1] = scales[2] = s; + + mat[0] = (1.0f - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z)*s; + mat[4] = (2.0f*(q1.x*q1.y + q1.w*q1.z))*s; + mat[8] = (2.0f*(q1.x*q1.z - q1.w*q1.y))*s; + + mat[1] = (2.0f*(q1.x*q1.y - q1.w*q1.z))*s; + mat[5] = (1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z)*s; + mat[9] = (2.0f*(q1.y*q1.z + q1.w*q1.x))*s; + + mat[2] = (2.0f*(q1.x*q1.z + q1.w*q1.y))*s; + mat[6] = (2.0f*(q1.y*q1.z - q1.w*q1.x))*s; + mat[10] = (1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y)*s; + + mat[3] = t1.x; + mat[7] = t1.y; + mat[11] = t1.z; + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the quaternion q1, the translation t1, and the scale s. + * @param q1 the rotation expressed as a quaternion + * @param t1 the translation + * @param s the scale value + */ + public final void set(Quat4f q1, Vector3f t1, float s) { + if(scales == null) + scales = new double[3]; + + scales[0] = scales[1] = scales[2] = s; + + mat[0] = (1.0f - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z)*s; + mat[4] = (2.0f*(q1.x*q1.y + q1.w*q1.z))*s; + mat[8] = (2.0f*(q1.x*q1.z - q1.w*q1.y))*s; + + mat[1] = (2.0f*(q1.x*q1.y - q1.w*q1.z))*s; + mat[5] = (1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z)*s; + mat[9] = (2.0f*(q1.y*q1.z + q1.w*q1.x))*s; + + mat[2] = (2.0f*(q1.x*q1.z + q1.w*q1.y))*s; + mat[6] = (2.0f*(q1.y*q1.z - q1.w*q1.x))*s; + mat[10] = (1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y)*s; + + mat[3] = t1.x; + mat[7] = t1.y; + mat[11] = t1.z; + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the rotation matrix m1, the translation t1, and the scale s. + * The scale is only applied to the + * rotational component of the matrix (upper 3x3) and not to the + * translational component of the matrix. + * @param m1 the rotation matrix + * @param t1 the translation + * @param s the scale value + */ + public final void set(Matrix3f m1, Vector3f t1, float s) { + mat[0]=m1.m00*s; + mat[1]=m1.m01*s; + mat[2]=m1.m02*s; + mat[3]=t1.x; + mat[4]=m1.m10*s; + mat[5]=m1.m11*s; + mat[6]=m1.m12*s; + mat[7]=t1.y; + mat[8]=m1.m20*s; + mat[9]=m1.m21*s; + mat[10]=m1.m22*s; + mat[11]=t1.z; + mat[12]=0.0; + mat[13]=0.0; + mat[14]=0.0; + mat[15]=1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + // input matrix may not normalize + normalize(); + } + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the rotation matrix m1, the translation t1, and the scale s. + * The scale is only applied to the + * rotational component of the matrix (upper 3x3) and not to the + * translational component of the matrix. + * @param m1 the rotation matrix + * @param t1 the translation + * @param s the scale value + */ + public final void set(Matrix3f m1, Vector3d t1, double s) { + mat[0]=m1.m00*s; + mat[1]=m1.m01*s; + mat[2]=m1.m02*s; + mat[3]=t1.x; + mat[4]=m1.m10*s; + mat[5]=m1.m11*s; + mat[6]=m1.m12*s; + mat[7]=t1.y; + mat[8]=m1.m20*s; + mat[9]=m1.m21*s; + mat[10]=m1.m22*s; + mat[11]=t1.z; + mat[12]=0.0; + mat[13]=0.0; + mat[14]=0.0; + mat[15]=1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the rotation matrix m1, the translation t1, and the scale s. + * The scale is only applied to the + * rotational component of the matrix (upper 3x3) and not to the + * translational component of the matrix. + * @param m1 the rotation matrix + * @param t1 the translation + * @param s the scale value + */ + public final void set(Matrix3d m1, Vector3d t1, double s) { + mat[0]=m1.m00*s; + mat[1]=m1.m01*s; + mat[2]=m1.m02*s; + mat[3]=t1.x; + mat[4]=m1.m10*s; + mat[5]=m1.m11*s; + mat[6]=m1.m12*s; + mat[7]=t1.y; + mat[8]=m1.m20*s; + mat[9]=m1.m21*s; + mat[10]=m1.m22*s; + mat[11]=t1.z; + mat[12]=0.0; + mat[13]=0.0; + mat[14]=0.0; + mat[15]=1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + /** + * Sets the matrix values of this transform to the matrix values in the + * upper 4x4 corner of the GMatrix parameter. If the parameter matrix is + * smaller than 4x4, the remaining elements in the transform matrix are + * assigned to zero. The transform matrix type is classified + * internally by the Transform3D class. + * @param matrix the general matrix from which the Transform3D matrix is derived + */ + public final void set(GMatrix matrix) { + int i,j, k; + int numRows = matrix.getNumRow(); + int numCol = matrix.getNumCol(); + + for(i=0 ; i<4 ; i++) { + k = i*4; + for(j=0 ; j<4 ; j++) { + if(i>=numRows || j>=numCol) + mat[k+j] = 0.0; + else + mat[k+j] = matrix.getElement(i,j); + } + } + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + + } + + /** + * Sets the matrix, type, and state of this transform to the matrix, + * type, and state of transform t1. + * @param t1 the transform to be copied + */ + public final void set(Transform3D t1){ + mat[0] = t1.mat[0]; + mat[1] = t1.mat[1]; + mat[2] = t1.mat[2]; + mat[3] = t1.mat[3]; + mat[4] = t1.mat[4]; + mat[5] = t1.mat[5]; + mat[6] = t1.mat[6]; + mat[7] = t1.mat[7]; + mat[8] = t1.mat[8]; + mat[9] = t1.mat[9]; + mat[10] = t1.mat[10]; + mat[11] = t1.mat[11]; + mat[12] = t1.mat[12]; + mat[13] = t1.mat[13]; + mat[14] = t1.mat[14]; + mat[15] = t1.mat[15]; + type = t1.type; + + // don't copy rot[] and scales[] + dirtyBits = t1.dirtyBits | ROTATION_BIT | SCALE_BIT; + autoNormalize = t1.autoNormalize; + } + + // This version gets a lock before doing the set. It is used internally + synchronized void setWithLock(Transform3D t1) { + this.set(t1); + } + + // This version gets a lock before doing the get. It is used internally + synchronized void getWithLock(Transform3D t1) { + t1.set(this); + } + + /** + * Sets the matrix values of this transform to the matrix values in the + * double precision array parameter. The matrix type is classified + * internally by the Transform3D class. + * @param matrix the double precision array of length 16 in row major format + */ + public final void set(double[] matrix) { + mat[0] = matrix[0]; + mat[1] = matrix[1]; + mat[2] = matrix[2]; + mat[3] = matrix[3]; + mat[4] = matrix[4]; + mat[5] = matrix[5]; + mat[6] = matrix[6]; + mat[7] = matrix[7]; + mat[8] = matrix[8]; + mat[9] = matrix[9]; + mat[10] = matrix[10]; + mat[11] = matrix[11]; + mat[12] = matrix[12]; + mat[13] = matrix[13]; + mat[14] = matrix[14]; + mat[15] = matrix[15]; + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + + } + + /** + * Sets the matrix values of this transform to the matrix values in the + * single precision array parameter. The matrix type is classified + * internally by the Transform3D class. + * @param matrix the single precision array of length 16 in row major format + */ + public final void set(float[] matrix) { + mat[0] = matrix[0]; + mat[1] = matrix[1]; + mat[2] = matrix[2]; + mat[3] = matrix[3]; + mat[4] = matrix[4]; + mat[5] = matrix[5]; + mat[6] = matrix[6]; + mat[7] = matrix[7]; + mat[8] = matrix[8]; + mat[9] = matrix[9]; + mat[10] = matrix[10]; + mat[11] = matrix[11]; + mat[12] = matrix[12]; + mat[13] = matrix[13]; + mat[14] = matrix[14]; + mat[15] = matrix[15]; + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + + } + + /** + * Sets the matrix values of this transform to the matrix values in the + * double precision Matrix4d argument. The transform type is classified + * internally by the Transform3D class. + * @param m1 the double precision 4x4 matrix + */ + public final void set(Matrix4d m1) { + mat[0] = m1.m00; + mat[1] = m1.m01; + mat[2] = m1.m02; + mat[3] = m1.m03; + mat[4] = m1.m10; + mat[5] = m1.m11; + mat[6] = m1.m12; + mat[7] = m1.m13; + mat[8] = m1.m20; + mat[9] = m1.m21; + mat[10] = m1.m22; + mat[11] = m1.m23; + mat[12] = m1.m30; + mat[13] = m1.m31; + mat[14] = m1.m32; + mat[15] = m1.m33; + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + + /** + * Sets the matrix values of this transform to the matrix values in the + * single precision Matrix4f argument. The transform type is classified + * internally by the Transform3D class. + * @param m1 the single precision 4x4 matrix + */ + public final void set(Matrix4f m1) { + mat[0] = m1.m00; + mat[1] = m1.m01; + mat[2] = m1.m02; + mat[3] = m1.m03; + mat[4] = m1.m10; + mat[5] = m1.m11; + mat[6] = m1.m12; + mat[7] = m1.m13; + mat[8] = m1.m20; + mat[9] = m1.m21; + mat[10] = m1.m22; + mat[11] = m1.m23; + mat[12] = m1.m30; + mat[13] = m1.m31; + mat[14] = m1.m32; + mat[15] = m1.m33; + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * matrix values in the single precision Matrix3f argument; the other + * elements of this transform are initialized as if this were an identity + * matrix (i.e., affine matrix with no translational component). + * @param m1 the single precision 3x3 matrix + */ + public final void set(Matrix3f m1) { + mat[0] = m1.m00; + mat[1] = m1.m01; + mat[2] = m1.m02; + mat[3] = 0.0; + mat[4] = m1.m10; + mat[5] = m1.m11; + mat[6] = m1.m12; + mat[7] = 0.0; + mat[8] = m1.m20; + mat[9] = m1.m21; + mat[10] = m1.m22; + mat[11] = 0.0; + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * matrix values in the double precision Matrix3d argument; the other + * elements of this transform are initialized as if this were an identity + * matrix (ie, affine matrix with no translational component). + * @param m1 the double precision 3x3 matrix + */ + public final void set(Matrix3d m1) { + mat[0] = m1.m00; + mat[1] = m1.m01; + mat[2] = m1.m02; + mat[3] = 0.0; + mat[4] = m1.m10; + mat[5] = m1.m11; + mat[6] = m1.m12; + mat[7] = 0.0; + mat[8] = m1.m20; + mat[9] = m1.m21; + mat[10] = m1.m22; + mat[11] = 0.0; + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + + } + + + /** + * Sets the rotational component (upper 3x3) of this transform to the + * rotation matrix converted from the Euler angles provided; the other + * non-rotational elements are set as if this were an identity matrix. + * The euler parameter is a Vector3d consisting of three rotation angles + * applied first about the X, then Y then Z axis. + * These rotations are applied using a static frame of reference. In + * other words, the orientation of the Y rotation axis is not affected + * by the X rotation and the orientation of the Z rotation axis is not + * affected by the X or Y rotation. + * @param euler the Vector3d consisting of three rotation angles about X,Y,Z + * + */ + public final void setEuler(Vector3d euler) { + double sina, sinb, sinc; + double cosa, cosb, cosc; + + sina = Math.sin(euler.x); + sinb = Math.sin(euler.y); + sinc = Math.sin(euler.z); + cosa = Math.cos(euler.x); + cosb = Math.cos(euler.y); + cosc = Math.cos(euler.z); + + mat[0] = cosb * cosc; + mat[1] = -(cosa * sinc) + (sina * sinb * cosc); + mat[2] = (sina * sinc) + (cosa * sinb *cosc); + mat[3] = 0.0; + + mat[4] = cosb * sinc; + mat[5] = (cosa * cosc) + (sina * sinb * sinc); + mat[6] = -(sina * cosc) + (cosa * sinb *sinc); + mat[7] = 0.0; + + mat[8] = -sinb; + mat[9] = sina * cosb; + mat[10] = cosa * cosb; + mat[11] = 0.0; + + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(euler)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = AFFINE | CONGRUENT | RIGID | ORTHO; + dirtyBits = CLASSIFY_BIT | SCALE_BIT | ROTATION_BIT; + } + + + /** + * Places the values of this transform into the double precision array + * of length 16. The first four elements of the array will contain + * the top row of the transform matrix, etc. + * @param matrix the double precision array of length 16 + */ + public final void get(double[] matrix) { + matrix[0] = mat[0]; + matrix[1] = mat[1]; + matrix[2] = mat[2]; + matrix[3] = mat[3]; + matrix[4] = mat[4]; + matrix[5] = mat[5]; + matrix[6] = mat[6]; + matrix[7] = mat[7]; + matrix[8] = mat[8]; + matrix[9] = mat[9]; + matrix[10] = mat[10]; + matrix[11] = mat[11]; + matrix[12] = mat[12]; + matrix[13] = mat[13]; + matrix[14] = mat[14]; + matrix[15] = mat[15]; + } + + + /** + * Places the values of this transform into the single precision array + * of length 16. The first four elements of the array will contain + * the top row of the transform matrix, etc. + * @param matrix the single precision array of length 16 + */ + public final void get(float[] matrix) { + matrix[0] = (float) mat[0]; + matrix[1] = (float) mat[1]; + matrix[2] = (float) mat[2]; + matrix[3] = (float) mat[3]; + matrix[4] = (float) mat[4]; + matrix[5] = (float) mat[5]; + matrix[6] = (float) mat[6]; + matrix[7] = (float) mat[7]; + matrix[8] = (float) mat[8]; + matrix[9] = (float) mat[9]; + matrix[10] = (float) mat[10]; + matrix[11] = (float) mat[11]; + matrix[12] = (float) mat[12]; + matrix[13] = (float) mat[13]; + matrix[14] = (float) mat[14]; + matrix[15] = (float) mat[15]; + } + + + /** + * Places the normalized rotational component of this transform + * into the 3x3 matrix argument. + * @param m1 the matrix into which the rotational component is placed + */ + public final void get(Matrix3d m1) { + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } + m1.m00 = rot[0]; + m1.m01 = rot[1]; + m1.m02 = rot[2]; + m1.m10 = rot[3]; + m1.m11 = rot[4]; + m1.m12 = rot[5]; + m1.m20 = rot[6]; + m1.m21 = rot[7]; + m1.m22 = rot[8]; + } + + /** + * Places the normalized rotational component of this transform + * into the 3x3 matrix argument. + * @param m1 the matrix into which the rotational component is placed + */ + public final void get(Matrix3f m1) { + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } + m1.m00 = (float)rot[0]; + m1.m01 = (float)rot[1]; + m1.m02 = (float)rot[2]; + m1.m10 = (float)rot[3]; + m1.m11 = (float)rot[4]; + m1.m12 = (float)rot[5]; + m1.m20 = (float)rot[6]; + m1.m21 = (float)rot[7]; + m1.m22 = (float)rot[8]; + } + + /** + * Places the quaternion equivalent of the normalized rotational + * component of this transform into the quaternion parameter. + * @param q1 the quaternion into which the rotation component is placed + */ + public final void get(Quat4f q1) { + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } + + double ww = 0.25*(1.0 + rot[0] + rot[4] + rot[8]); + if (!((ww < 0 ? -ww : ww) < 1.0e-10)) { + q1.w = (float)Math.sqrt(ww); + ww = 0.25/q1.w; + q1.x = (float)((rot[7] - rot[5])*ww); + q1.y = (float)((rot[2] - rot[6])*ww); + q1.z = (float)((rot[3] - rot[1])*ww); + return; + } + + q1.w = 0.0f; + ww = -0.5*(rot[4] + rot[8]); + if (!((ww < 0 ? -ww : ww) < 1.0e-10)) { + q1.x = (float)Math.sqrt(ww); + ww = 0.5/q1.x; + q1.y = (float)(rot[3]*ww); + q1.z = (float)(rot[6]*ww); + return; + } + + q1.x = 0.0f; + ww = 0.5*(1.0 - rot[8]); + if (!((ww < 0 ? -ww : ww) < 1.0e-10)) { + q1.y = (float)Math.sqrt(ww); + q1.z = (float)(rot[7]/(2.0*q1.y)); + return; + } + + q1.y = 0.0f; + q1.z = 1.0f; + } + + /** + * Places the quaternion equivalent of the normalized rotational + * component of this transform into the quaternion parameter. + * @param q1 the quaternion into which the rotation component is placed + */ + public final void get(Quat4d q1) { + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } + + double ww = 0.25*(1.0 + rot[0] + rot[4] + rot[8]); + if (!((ww < 0 ? -ww : ww) < 1.0e-10)) { + q1.w = Math.sqrt(ww); + ww = 0.25/q1.w; + q1.x = (rot[7] - rot[5])*ww; + q1.y = (rot[2] - rot[6])*ww; + q1.z = (rot[3] - rot[1])*ww; + return; + } + + q1.w = 0.0; + ww = -0.5*(rot[4] + rot[8]); + if (!((ww < 0 ? -ww : ww) < 1.0e-10)) { + q1.x = Math.sqrt(ww); + ww = 0.5/q1.x; + q1.y = rot[3]*ww; + q1.z = rot[6]*ww; + return; + } + + q1.x = 0.0; + ww = 0.5*(1.0 - rot[8]); + if (!((ww < 0 ? -ww : ww) < 1.0e-10)) { + q1.y = Math.sqrt(ww); + q1.z = rot[7]/(2.0*q1.y); + return; + } + + q1.y = 0.0; + q1.z = 1.0; + } + + /** + * Places the values of this transform into the double precision + * matrix argument. + * @param matrix the double precision matrix + */ + public final void get(Matrix4d matrix) { + matrix.m00 = mat[0]; + matrix.m01 = mat[1]; + matrix.m02 = mat[2]; + matrix.m03 = mat[3]; + matrix.m10 = mat[4]; + matrix.m11 = mat[5]; + matrix.m12 = mat[6]; + matrix.m13 = mat[7]; + matrix.m20 = mat[8]; + matrix.m21 = mat[9]; + matrix.m22 = mat[10]; + matrix.m23 = mat[11]; + matrix.m30 = mat[12]; + matrix.m31 = mat[13]; + matrix.m32 = mat[14]; + matrix.m33 = mat[15]; + } + + /** + * Places the values of this transform into the single precision matrix + * argument. + * @param matrix the single precision matrix + */ + public final void get(Matrix4f matrix) { + matrix.m00 = (float) mat[0]; + matrix.m01 = (float) mat[1]; + matrix.m02 = (float) mat[2]; + matrix.m03 = (float) mat[3]; + matrix.m10 = (float) mat[4]; + matrix.m11 = (float) mat[5]; + matrix.m12 = (float) mat[6]; + matrix.m13 = (float) mat[7]; + matrix.m20 = (float) mat[8]; + matrix.m21 = (float) mat[9]; + matrix.m22 = (float) mat[10]; + matrix.m23 = (float) mat[11]; + matrix.m30 = (float) mat[12]; + matrix.m31 = (float) mat[13]; + matrix.m32 = (float) mat[14]; + matrix.m33 = (float) mat[15]; + } + + /** + * Places the quaternion equivalent of the normalized rotational + * component of this transform into the quaternion parameter; + * places the translational component into the Vector parameter. + * @param q1 the quaternion representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final double get(Quat4d q1, Vector3d t1) { + + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } else if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + + t1.x = mat[3]; + t1.y = mat[7]; + t1.z = mat[11]; + + double maxScale = max3(scales); + + double ww = 0.25*(1.0 + rot[0] + rot[4] + rot[8]); + if (!((ww < 0 ? -ww : ww) < EPSILON)) { + q1.w = Math.sqrt(ww); + ww = 0.25/q1.w; + q1.x = (rot[7] - rot[5])*ww; + q1.y = (rot[2] - rot[6])*ww; + q1.z = (rot[3] - rot[1])*ww; + return maxScale; + } + + q1.w = 0.0; + ww = -0.5*(rot[4] + rot[8]); + if (!((ww < 0 ? -ww : ww) < EPSILON)) { + q1.x = Math.sqrt(ww); + ww = 0.5/q1.x; + q1.y = rot[3]*ww; + q1.z = rot[6]*ww; + return maxScale; + } + + q1.x = 0.0; + ww = 0.5*(1.0 - rot[8]); + if (!((ww < 0 ? -ww : ww) < EPSILON)) { + q1.y = Math.sqrt(ww); + q1.z = rot[7]/(2.0*q1.y); + return maxScale; + } + + q1.y = 0.0; + q1.z = 1.0; + return maxScale; + } + + + /** + * Places the quaternion equivalent of the normalized rotational + * component of this transform into the quaternion parameter; + * places the translational component into the Vector parameter. + * @param q1 the quaternion representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final float get(Quat4f q1, Vector3f t1) { + + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } else if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + + double maxScale = max3(scales); + t1.x = (float)mat[3]; + t1.y = (float)mat[7]; + t1.z = (float)mat[11]; + + double ww = 0.25*(1.0 + rot[0] + rot[4] + rot[8]); + if (!((ww < 0 ? -ww : ww) < EPSILON)) { + q1.w = (float)Math.sqrt(ww); + ww = 0.25/q1.w; + q1.x = (float)((rot[7] - rot[5])*ww); + q1.y = (float)((rot[2] - rot[6])*ww); + q1.z = (float)((rot[3] - rot[1])*ww); + return (float) maxScale; + } + + q1.w = 0.0f; + ww = -0.5*(rot[4] + rot[8]); + if (!((ww < 0 ? -ww : ww) < EPSILON)) { + q1.x = (float)Math.sqrt(ww); + ww = 0.5/q1.x; + q1.y = (float)(rot[3]*ww); + q1.z = (float)(rot[6]*ww); + return (float) maxScale; + } + + q1.x = 0.0f; + ww = 0.5*(1.0 - rot[8]); + if (!((ww < 0? -ww : ww) < EPSILON)) { + q1.y = (float)Math.sqrt(ww); + q1.z = (float)(rot[7]/(2.0*q1.y)); + return (float) maxScale; + } + + q1.y = 0.0f; + q1.z = 1.0f; + return (float) maxScale; + } + + /** + * Places the quaternion equivalent of the normalized rotational + * component of this transform into the quaternion parameter; + * places the translational component into the Vector parameter. + * @param q1 the quaternion representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final double get(Quat4f q1, Vector3d t1) { + + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } else if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + + double maxScale = max3(scales); + + t1.x = mat[3]; + t1.y = mat[7]; + t1.z = mat[11]; + + double ww = 0.25*(1.0 + rot[0] + rot[4] + rot[8]); + if (!(( ww < 0 ? -ww : ww) < EPSILON)) { + q1.w = (float)Math.sqrt(ww); + ww = 0.25/q1.w; + q1.x = (float)((rot[7] - rot[5])*ww); + q1.y = (float)((rot[2] - rot[6])*ww); + q1.z = (float)((rot[3] - rot[1])*ww); + return maxScale; + } + + q1.w = 0.0f; + ww = -0.5*(rot[4] + rot[8]); + if (!(( ww < 0 ? -ww : ww) < EPSILON)) { + q1.x = (float)Math.sqrt(ww); + ww = 0.5/q1.x; + q1.y = (float)(rot[3]*ww); + q1.z = (float)(rot[6]*ww); + return maxScale; + } + + q1.x = 0.0f; + ww = 0.5*(1.0 - rot[8]); + if (!(( ww < 0 ? -ww : ww) < EPSILON)) { + q1.y = (float)Math.sqrt(ww); + q1.z = (float)(rot[7]/(2.0*q1.y)); + return maxScale; + } + + q1.y = 0.0f; + q1.z = 1.0f; + return maxScale; + } + + /** + * Places the normalized rotational component of this transform + * into the matrix parameter; place the translational component + * into the vector parameter. + * @param m1 the normalized matrix representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final double get(Matrix3d m1, Vector3d t1) { + + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } else if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + + t1.x = mat[3]; + t1.y = mat[7]; + t1.z = mat[11]; + + m1.m00 = rot[0]; + m1.m01 = rot[1]; + m1.m02 = rot[2]; + + m1.m10 = rot[3]; + m1.m11 = rot[4]; + m1.m12 = rot[5]; + + m1.m20 = rot[6]; + m1.m21 = rot[7]; + m1.m22 = rot[8]; + + return max3(scales); + } + + + /** + * Places the normalized rotational component of this transform + * into the matrix parameter; place the translational component + * into the vector parameter. + * @param m1 the normalized matrix representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final float get(Matrix3f m1, Vector3f t1) { + + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } else if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + + t1.x = (float)mat[3]; + t1.y = (float)mat[7]; + t1.z = (float)mat[11]; + + m1.m00 = (float)rot[0]; + m1.m01 = (float)rot[1]; + m1.m02 = (float)rot[2]; + + m1.m10 = (float)rot[3]; + m1.m11 = (float)rot[4]; + m1.m12 = (float)rot[5]; + + m1.m20 = (float)rot[6]; + m1.m21 = (float)rot[7]; + m1.m22 = (float)rot[8]; + + return (float) max3(scales); + } + + + /** + * Places the normalized rotational component of this transform + * into the matrix parameter; place the translational component + * into the vector parameter. + * @param m1 the normalized matrix representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final double get(Matrix3f m1, Vector3d t1) { + if ((dirtyBits & ROTATION_BIT) != 0) { + computeScaleRotation(false); + } else if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + + t1.x = mat[3]; + t1.y = mat[7]; + t1.z = mat[11]; + + m1.m00 = (float)rot[0]; + m1.m01 = (float)rot[1]; + m1.m02 = (float)rot[2]; + + m1.m10 = (float)rot[3]; + m1.m11 = (float)rot[4]; + m1.m12 = (float)rot[5]; + + m1.m20 = (float)rot[6]; + m1.m21 = (float)rot[7]; + m1.m22 = (float)rot[8]; + + return max3(scales); + } + + + /** + * Returns the uniform scale factor of this matrix. + * If the matrix has non-uniform scale factors, the largest of the + * x, y, and z scale factors will be returned. + * @return the scale factor of this matrix + */ + public final double getScale() { + if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + return max3(scales); + } + + + /** + * Gets the possibly non-uniform scale components of the current + * transform and places them into the scale vector. + * @param scale the vector into which the x,y,z scale values will be placed + */ + public final void getScale(Vector3d scale) { + if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + scale.x = scales[0]; + scale.y = scales[1]; + scale.z = scales[2]; + } + + + /** + * Retrieves the translational components of this transform. + * @param trans the vector that will receive the translational component + */ + public final void get(Vector3f trans) { + trans.x = (float)mat[3]; + trans.y = (float)mat[7]; + trans.z = (float)mat[11]; + } + + + /** + * Retrieves the translational components of this transform. + * @param trans the vector that will receive the translational component + */ + public final void get(Vector3d trans) { + trans.x = mat[3]; + trans.y = mat[7]; + trans.z = mat[11]; + } + + /** + * Sets the value of this transform to the inverse of the passed + * Transform3D parameter. This method uses the transform type + * to determine the optimal algorithm for inverting transform t1. + * @param t1 the transform to be inverted + * @exception SingularMatrixException thrown if transform t1 is + * not invertible + */ + public final void invert(Transform3D t1) { + if (t1 == this) { + invert(); + } else if (t1.isAffine()) { + // We can't use invertOrtho() because of numerical + // instability unless we set tolerance of ortho test to 0 + invertAffine(t1); + } else { + invertGeneral(t1); + } + } + + /** + * Inverts this transform in place. This method uses the transform + * type to determine the optimal algorithm for inverting this transform. + * @exception SingularMatrixException thrown if this transform is + * not invertible + */ + public final void invert() { + if (isAffine()) { + invertAffine(); + } else { + invertGeneral(this); + } + } + + /** + * Congruent invert routine. + * + * if uniform scale s + * + * [R | t] => [R^T/s*s | -R^T * t/s*s] + * + */ + + /* + final void invertOrtho() { + double tmp, s1, s2, s3; + + // do not force classifyRigid() + if (((dirtyBits & CONGRUENT_BIT) == 0) && + ((type & CONGRUENT) != 0)) { + s1 = mat[0]*mat[0] + mat[4]*mat[4] + mat[8]*mat[8]; + if (s1 == 0) { + throw new SingularMatrixException(J3dI18N.getString("Transform3D1")); + } + s1 = s2 = s3 = 1/s1; + dirtyBits |= ROTSCALESVD_DIRTY; + } else { + // non-uniform scale matrix + s1 = mat[0]*mat[0] + mat[4]*mat[4] + mat[8]*mat[8]; + s2 = mat[1]*mat[1] + mat[5]*mat[5] + mat[9]*mat[9]; + s3 = mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10]; + if ((s1 == 0) || (s2 == 0) || (s3 == 0)) { + throw new SingularMatrixException(J3dI18N.getString("Transform3D1")); + } + s1 = 1/s1; + s2 = 1/s2; + s3 = 1/s3; + dirtyBits |= ROTSCALESVD_DIRTY | ORTHO_BIT | CONGRUENT_BIT + | RIGID_BIT | CLASSIFY_BIT; + } + // multiple by 1/s will cause loss in numerical value + tmp = mat[1]; + mat[1] = mat[4]*s1; + mat[4] = tmp*s2; + tmp = mat[2]; + mat[2] = mat[8]*s1; + mat[8] = tmp*s3; + tmp = mat[6]; + mat[6] = mat[9]*s2; + mat[9] = tmp*s3; + mat[0] *= s1; + mat[5] *= s2; + mat[10] *= s3; + + tmp = mat[3]; + s1 = mat[7]; + mat[3] = -(tmp * mat[0] + s1 * mat[1] + mat[11] * mat[2]); + mat[7] = -(tmp * mat[4] + s1 * mat[5] + mat[11] * mat[6]); + mat[11]= -(tmp * mat[8] + s1 * mat[9] + mat[11] * mat[10]); + mat[12] = mat[13] = mat[14] = 0.0; + mat[15] = 1.0; + } + */ + + /** + * Orthogonal matrix invert routine. + * Inverts t1 and places the result in "this". + */ + /* + final void invertOrtho(Transform3D t1) { + double s1, s2, s3; + + // do not force classifyRigid() + if (((t1.dirtyBits & CONGRUENT_BIT) == 0) && + ((t1.type & CONGRUENT) != 0)) { + s1 = t1.mat[0]*t1.mat[0] + t1.mat[4]*t1.mat[4] + + t1.mat[8]*t1.mat[8]; + if (s1 == 0) { + throw new SingularMatrixException(J3dI18N.getString("Transform3D1")); + } + s1 = s2 = s3 = 1/s1; + dirtyBits = t1.dirtyBits | ROTSCALESVD_DIRTY; + } else { + // non-uniform scale matrix + s1 = t1.mat[0]*t1.mat[0] + t1.mat[4]*t1.mat[4] + + t1.mat[8]*t1.mat[8]; + s2 = t1.mat[1]*t1.mat[1] + t1.mat[5]*t1.mat[5] + + t1.mat[9]*t1.mat[9]; + s3 = t1.mat[2]*t1.mat[2] + t1.mat[6]*t1.mat[6] + + t1.mat[10]*t1.mat[10]; + + if ((s1 == 0) || (s2 == 0) || (s3 == 0)) { + throw new SingularMatrixException(J3dI18N.getString("Transform3D1")); + } + s1 = 1/s1; + s2 = 1/s2; + s3 = 1/s3; + dirtyBits = t1.dirtyBits | ROTSCALESVD_DIRTY | ORTHO_BIT | + CONGRUENT_BIT | RIGID_BIT; + } + + mat[0] = t1.mat[0]*s1; + mat[1] = t1.mat[4]*s1; + mat[2] = t1.mat[8]*s1; + mat[4] = t1.mat[1]*s2; + mat[5] = t1.mat[5]*s2; + mat[6] = t1.mat[9]*s2; + mat[8] = t1.mat[2]*s3; + mat[9] = t1.mat[6]*s3; + mat[10] = t1.mat[10]*s3; + + mat[3] = -(t1.mat[3] * mat[0] + t1.mat[7] * mat[1] + + t1.mat[11] * mat[2]); + mat[7] = -(t1.mat[3] * mat[4] + t1.mat[7] * mat[5] + + t1.mat[11] * mat[6]); + mat[11]= -(t1.mat[3] * mat[8] + t1.mat[7] * mat[9] + + t1.mat[11] * mat[10]); + mat[12] = mat[13] = mat[14] = 0.0; + mat[15] = 1.0; + type = t1.type; + } + */ + + /** + * Affine invert routine. Inverts t1 and places the result in "this". + */ + final void invertAffine(Transform3D t1) { + double determinant = t1.affineDeterminant(); + + if (determinant == 0.0) + throw new SingularMatrixException(J3dI18N.getString("Transform3D1")); + + + double s = (t1.mat[0]*t1.mat[0] + t1.mat[1]*t1.mat[1] + + t1.mat[2]*t1.mat[2] + t1.mat[3]*t1.mat[3])* + (t1.mat[4]*t1.mat[4] + t1.mat[5]*t1.mat[5] + + t1.mat[6]*t1.mat[6] + t1.mat[7]*t1.mat[7])* + (t1.mat[8]*t1.mat[8] + t1.mat[9]*t1.mat[9] + + t1.mat[10]*t1.mat[10] + t1.mat[11]*t1.mat[11]); + + if ((determinant*determinant) < (EPS * s)) { + // using invertGeneral is numerically more stable for + //this case see bug 4227733 + invertGeneral(t1); + return; + } + s = 1.0 / determinant; + + mat[0] = (t1.mat[5]*t1.mat[10] - t1.mat[9]*t1.mat[6]) * s; + mat[1] = -(t1.mat[1]*t1.mat[10] - t1.mat[9]*t1.mat[2]) * s; + mat[2] = (t1.mat[1]*t1.mat[6] - t1.mat[5]*t1.mat[2]) * s; + mat[4] = -(t1.mat[4]*t1.mat[10] - t1.mat[8]*t1.mat[6]) * s; + mat[5] = (t1.mat[0]*t1.mat[10] - t1.mat[8]*t1.mat[2]) * s; + mat[6] = -(t1.mat[0]*t1.mat[6] - t1.mat[4]*t1.mat[2]) * s; + mat[8] = (t1.mat[4]*t1.mat[9] - t1.mat[8]*t1.mat[5]) * s; + mat[9] = -(t1.mat[0]*t1.mat[9] - t1.mat[8]*t1.mat[1]) * s; + mat[10]= (t1.mat[0]*t1.mat[5] - t1.mat[4]*t1.mat[1]) * s; + mat[3] = -(t1.mat[3] * mat[0] + t1.mat[7] * mat[1] + + t1.mat[11] * mat[2]); + mat[7] = -(t1.mat[3] * mat[4] + t1.mat[7] * mat[5] + + t1.mat[11] * mat[6]); + mat[11]= -(t1.mat[3] * mat[8] + t1.mat[7] * mat[9] + + t1.mat[11] * mat[10]); + + mat[12] = mat[13] = mat[14] = 0.0; + mat[15] = 1.0; + + dirtyBits = t1.dirtyBits | ROTSCALESVD_DIRTY | CLASSIFY_BIT | ORTHO_BIT; + type = t1.type; + } + + /** + * Affine invert routine. Inverts "this" matrix in place. + */ + final void invertAffine() { + double determinant = affineDeterminant(); + + if (determinant == 0.0) + throw new SingularMatrixException(J3dI18N.getString("Transform3D1")); + + double s = (mat[0]*mat[0] + mat[1]*mat[1] + + mat[2]*mat[2] + mat[3]*mat[3])* + (mat[4]*mat[4] + mat[5]*mat[5] + + mat[6]*mat[6] + mat[7]*mat[7])* + (mat[8]*mat[8] + mat[9]*mat[9] + + mat[10]*mat[10] + mat[11]*mat[11]); + + if ((determinant*determinant) < (EPS * s)) { + invertGeneral(this); + return; + } + s = 1.0 / determinant; + double tmp0 = (mat[5]*mat[10] - mat[9]*mat[6]) * s; + double tmp1 = -(mat[1]*mat[10] - mat[9]*mat[2]) * s; + double tmp2 = (mat[1]*mat[6] - mat[5]*mat[2]) * s; + double tmp4 = -(mat[4]*mat[10] - mat[8]*mat[6]) * s; + double tmp5 = (mat[0]*mat[10] - mat[8]*mat[2]) * s; + double tmp6 = -(mat[0]*mat[6] - mat[4]*mat[2]) * s; + double tmp8 = (mat[4]*mat[9] - mat[8]*mat[5]) * s; + double tmp9 = -(mat[0]*mat[9] - mat[8]*mat[1]) * s; + double tmp10= (mat[0]*mat[5] - mat[4]*mat[1]) * s; + double tmp3 = -(mat[3] * tmp0 + mat[7] * tmp1 + mat[11] * tmp2); + double tmp7 = -(mat[3] * tmp4 + mat[7] * tmp5 + mat[11] * tmp6); + mat[11]= -(mat[3] * tmp8 + mat[7] * tmp9 + mat[11] * tmp10); + + mat[0]=tmp0; mat[1]=tmp1; mat[2]=tmp2; mat[3]=tmp3; + mat[4]=tmp4; mat[5]=tmp5; mat[6]=tmp6; mat[7]=tmp7; + mat[8]=tmp8; mat[9]=tmp9; mat[10]=tmp10; + mat[12] = mat[13] = mat[14] = 0.0; + mat[15] = 1.0; + dirtyBits |= ROTSCALESVD_DIRTY | CLASSIFY_BIT | ORTHO_BIT; + } + + /** + * General invert routine. Inverts t1 and places the result in "this". + * Note that this routine handles both the "this" version and the + * non-"this" version. + * + * Also note that since this routine is slow anyway, we won't worry + * about allocating a little bit of garbage. + */ + final void invertGeneral(Transform3D t1) { + double tmp[] = new double[16]; + int row_perm[] = new int[4]; + int i, r, c; + + // Use LU decomposition and backsubstitution code specifically + // for floating-point 4x4 matrices. + + // Copy source matrix to tmp + System.arraycopy(t1.mat, 0, tmp, 0, tmp.length); + + // Calculate LU decomposition: Is the matrix singular? + if (!luDecomposition(tmp, row_perm)) { + // Matrix has no inverse + throw new SingularMatrixException(J3dI18N.getString("Transform3D1")); + } + + // Perform back substitution on the identity matrix + // luDecomposition will set rot[] & scales[] for use + // in luBacksubstituation + mat[0] = 1.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = 0.0; + mat[4] = 0.0; mat[5] = 1.0; mat[6] = 0.0; mat[7] = 0.0; + mat[8] = 0.0; mat[9] = 0.0; mat[10] = 1.0; mat[11] = 0.0; + mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 1.0; + luBacksubstitution(tmp, row_perm, this.mat); + + type = 0; + dirtyBits = ALL_DIRTY; + } + + + /** + * Given a 4x4 array "matrix0", this function replaces it with the + * LU decomposition of a row-wise permutation of itself. The input + * parameters are "matrix0" and "dimen". The array "matrix0" is also + * an output parameter. The vector "row_perm[4]" is an output + * parameter that contains the row permutations resulting from partial + * pivoting. The output parameter "even_row_xchg" is 1 when the + * number of row exchanges is even, or -1 otherwise. Assumes data + * type is always double. + * + * This function is similar to luDecomposition, except that it + * is tuned specifically for 4x4 matrices. + * + * @return true if the matrix is nonsingular, or false otherwise. + */ + // + // Reference: Press, Flannery, Teukolsky, Vetterling, + // _Numerical_Recipes_in_C_, Cambridge University Press, + // 1988, pp 40-45. + // + static boolean luDecomposition(double[] matrix0, + int[] row_perm) { + + // Can't re-use this temporary since the method is static. + double row_scale[] = new double[4]; + + // Determine implicit scaling information by looping over rows + { + int i, j; + int ptr, rs; + double big, temp; + + ptr = 0; + rs = 0; + + // For each row ... + i = 4; + while (i-- != 0) { + big = 0.0; + + // For each column, find the largest element in the row + j = 4; + while (j-- != 0) { + temp = matrix0[ptr++]; + temp = Math.abs(temp); + if (temp > big) { + big = temp; + } + } + + // Is the matrix singular? + if (big == 0.0) { + return false; + } + row_scale[rs++] = 1.0 / big; + } + } + + { + int j; + int mtx; + + mtx = 0; + + // For all columns, execute Crout's method + for (j = 0; j < 4; j++) { + int i, imax, k; + int target, p1, p2; + double sum, big, temp; + + // Determine elements of upper diagonal matrix U + for (i = 0; i < j; i++) { + target = mtx + (4*i) + j; + sum = matrix0[target]; + k = i; + p1 = mtx + (4*i); + p2 = mtx + j; + while (k-- != 0) { + sum -= matrix0[p1] * matrix0[p2]; + p1++; + p2 += 4; + } + matrix0[target] = sum; + } + + // Search for largest pivot element and calculate + // intermediate elements of lower diagonal matrix L. + big = 0.0; + imax = -1; + for (i = j; i < 4; i++) { + target = mtx + (4*i) + j; + sum = matrix0[target]; + k = j; + p1 = mtx + (4*i); + p2 = mtx + j; + while (k-- != 0) { + sum -= matrix0[p1] * matrix0[p2]; + p1++; + p2 += 4; + } + matrix0[target] = sum; + + // Is this the best pivot so far? + if ((temp = row_scale[i] * Math.abs(sum)) >= big) { + big = temp; + imax = i; + } + } + + if (imax < 0) { + return false; + } + + // Is a row exchange necessary? + if (j != imax) { + // Yes: exchange rows + k = 4; + p1 = mtx + (4*imax); + p2 = mtx + (4*j); + while (k-- != 0) { + temp = matrix0[p1]; + matrix0[p1++] = matrix0[p2]; + matrix0[p2++] = temp; + } + + // Record change in scale factor + row_scale[imax] = row_scale[j]; + } + + // Record row permutation + row_perm[j] = imax; + + // Is the matrix singular + if (matrix0[(mtx + (4*j) + j)] == 0.0) { + return false; + } + + // Divide elements of lower diagonal matrix L by pivot + if (j != (4-1)) { + temp = 1.0 / (matrix0[(mtx + (4*j) + j)]); + target = mtx + (4*(j+1)) + j; + i = 3 - j; + while (i-- != 0) { + matrix0[target] *= temp; + target += 4; + } + } + } + } + + return true; + } + + + /** + * Solves a set of linear equations. The input parameters "matrix1", + * and "row_perm" come from luDecompostionD4x4 and do not change + * here. The parameter "matrix2" is a set of column vectors assembled + * into a 4x4 matrix of floating-point values. The procedure takes each + * column of "matrix2" in turn and treats it as the right-hand side of the + * matrix equation Ax = LUx = b. The solution vector replaces the + * original column of the matrix. + * + * If "matrix2" is the identity matrix, the procedure replaces its contents + * with the inverse of the matrix from which "matrix1" was originally + * derived. + */ + // + // Reference: Press, Flannery, Teukolsky, Vetterling, + // _Numerical_Recipes_in_C_, Cambridge University Press, + // 1988, pp 44-45. + // + static void luBacksubstitution(double[] matrix1, + int[] row_perm, + double[] matrix2) { + + int i, ii, ip, j, k; + int rp; + int cv, rv; + + // rp = row_perm; + rp = 0; + + // For each column vector of matrix2 ... + for (k = 0; k < 4; k++) { + // cv = &(matrix2[0][k]); + cv = k; + ii = -1; + + // Forward substitution + for (i = 0; i < 4; i++) { + double sum; + + ip = row_perm[rp+i]; + sum = matrix2[cv+4*ip]; + matrix2[cv+4*ip] = matrix2[cv+4*i]; + if (ii >= 0) { + // rv = &(matrix1[i][0]); + rv = i*4; + for (j = ii; j <= i-1; j++) { + sum -= matrix1[rv+j] * matrix2[cv+4*j]; + } + } + else if (sum != 0.0) { + ii = i; + } + matrix2[cv+4*i] = sum; + } + + // Backsubstitution + // rv = &(matrix1[3][0]); + rv = 3*4; + matrix2[cv+4*3] /= matrix1[rv+3]; + + rv -= 4; + matrix2[cv+4*2] = (matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+2]; + + rv -= 4; + matrix2[cv+4*1] = (matrix2[cv+4*1] - + matrix1[rv+2] * matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+1]; + + rv -= 4; + matrix2[cv+4*0] = (matrix2[cv+4*0] - + matrix1[rv+1] * matrix2[cv+4*1] - + matrix1[rv+2] * matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+0]; + } + } + + // given that this matrix is affine + final double affineDeterminant() { + return mat[0]*(mat[5]*mat[10] - mat[6]*mat[9]) - + mat[1]*(mat[4]*mat[10] - mat[6]*mat[8]) + + mat[2]*(mat[4]*mat[ 9] - mat[5]*mat[8]); + } + + /** + * Calculates and returns the determinant of this transform. + * @return the double precision determinant + */ + public final double determinant() { + + if (isAffine()) { + return mat[0]*(mat[5]*mat[10] - mat[6]*mat[9]) - + mat[1]*(mat[4]*mat[10] - mat[6]*mat[8]) + + mat[2]*(mat[4]*mat[ 9] - mat[5]*mat[8]); + } + // cofactor exapainsion along first row + return mat[0]*(mat[5]*(mat[10]*mat[15] - mat[11]*mat[14]) - + mat[6]*(mat[ 9]*mat[15] - mat[11]*mat[13]) + + mat[7]*(mat[ 9]*mat[14] - mat[10]*mat[13])) - + mat[1]*(mat[4]*(mat[10]*mat[15] - mat[11]*mat[14]) - + mat[6]*(mat[ 8]*mat[15] - mat[11]*mat[12]) + + mat[7]*(mat[ 8]*mat[14] - mat[10]*mat[12])) + + mat[2]*(mat[4]*(mat[ 9]*mat[15] - mat[11]*mat[13]) - + mat[5]*(mat[ 8]*mat[15] - mat[11]*mat[12]) + + mat[7]*(mat[ 8]*mat[13] - mat[ 9]*mat[12])) - + mat[3]*(mat[4]*(mat[ 9]*mat[14] - mat[10]*mat[13]) - + mat[5]*(mat[ 8]*mat[14] - mat[10]*mat[12]) + + mat[6]*(mat[ 8]*mat[13] - mat[ 9]*mat[12])); + } + + /** + * Sets the value of this transform to a uniform scale; all of + * the matrix values are modified. + * @param scale the scale factor for the transform + */ + public final void set(double scale) { + setScaleTranslation(0, 0, 0, scale); + } + + + /** + * Sets the value of this transform to a scale and translation + * matrix; the scale is not applied to the translation and all + * of the matrix values are modified. + * @param scale the scale factor for the transform + * @param v1 the translation amount + */ + public final void set(double scale, Vector3d v1) { + setScaleTranslation(v1.x, v1.y, v1.z, scale); + } + + + /** + * Sets the value of this transform to a scale and translation + * matrix; the scale is not applied to the translation and all + * of the matrix values are modified. + * @param scale the scale factor for the transform + * @param v1 the translation amount + */ + public final void set(float scale, Vector3f v1) { + setScaleTranslation(v1.x, v1.y, v1.z, scale); + } + + /** + * Sets the value of this transform to a scale and translation matrix; + * the translation is scaled by the scale factor and all of the + * matrix values are modified. + * @param v1 the translation amount + * @param scale the scale factor for the transform AND the translation + */ + public final void set(Vector3d v1, double scale) { + setScaleTranslation(v1.x*scale, v1.y*scale, v1.z*scale, scale); + } + + /** + * Sets the value of this transform to a scale and translation matrix; + * the translation is scaled by the scale factor and all of the + * matrix values are modified. + * @param v1 the translation amount + * @param scale the scale factor for the transform AND the translation + */ + public final void set(Vector3f v1, float scale) { + setScaleTranslation(v1.x*scale, v1.y*scale, v1.z*scale, scale); + } + + private final void setScaleTranslation(double x, double y, + double z, double scale) { + mat[0] = scale; + mat[1] = 0.0; + mat[2] = 0.0; + mat[3] = x; + mat[4] = 0.0; + mat[5] = scale; + mat[6] = 0.0; + mat[7] = y; + mat[8] = 0.0; + mat[9] = 0.0; + mat[10] = scale; + mat[11] = z; + mat[12] = 0.0; + mat[13] = 0.0; + mat[14] = 0.0; + mat[15] = 1.0; + + if(scales == null) + scales = new double[3]; + + scales[0] = scales[1] = scales[2] = scale; + + // Issue 253: set all dirty bits if input is infinity or NaN + if (isInfOrNaN(x) || isInfOrNaN(y) || isInfOrNaN(z) || isInfOrNaN(scale)) { + dirtyBits = ALL_DIRTY; + return; + } + + type = AFFINE | CONGRUENT | ORTHO; + dirtyBits = CLASSIFY_BIT | ROTATION_BIT | RIGID_BIT; + } + + + + /** + * Multiplies each element of this transform by a scalar. + * @param scalar the scalar multiplier + */ + public final void mul(double scalar) { + for (int i=0 ; i<16 ; i++) { + mat[i] *= scalar; + } + dirtyBits = ALL_DIRTY; + } + + /** + * Multiplies each element of transform t1 by a scalar and places + * the result into this. Transform t1 is not modified. + * @param scalar the scalar multiplier + * @param t1 the original transform + */ + public final void mul(double scalar, Transform3D t1) { + for (int i=0 ; i<16 ; i++) { + mat[i] = t1.mat[i] * scalar; + } + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + + } + + + /** + * Sets the value of this transform to the result of multiplying itself + * with transform t1 (this = this * t1). + * @param t1 the other transform + */ + public final void mul(Transform3D t1) { + double tmp0, tmp1, tmp2, tmp3; + double tmp4, tmp5, tmp6, tmp7; + double tmp8, tmp9, tmp10, tmp11; + boolean aff = false; + + if (t1.isAffine()) { + tmp0 = mat[0]*t1.mat[0] + mat[1]*t1.mat[4] + mat[2]*t1.mat[8]; + tmp1 = mat[0]*t1.mat[1] + mat[1]*t1.mat[5] + mat[2]*t1.mat[9]; + tmp2 = mat[0]*t1.mat[2] + mat[1]*t1.mat[6] + mat[2]*t1.mat[10]; + tmp3 = mat[0]*t1.mat[3] + mat[1]*t1.mat[7] + mat[2]*t1.mat[11] + mat[3]; + tmp4 = mat[4]*t1.mat[0] + mat[5]*t1.mat[4] + mat[6]*t1.mat[8]; + tmp5 = mat[4]*t1.mat[1] + mat[5]*t1.mat[5] + mat[6]*t1.mat[9]; + tmp6 = mat[4]*t1.mat[2] + mat[5]*t1.mat[6] + mat[6]*t1.mat[10]; + tmp7 = mat[4]*t1.mat[3] + mat[5]*t1.mat[7] + mat[6]*t1.mat[11] + mat[7]; + tmp8 = mat[8]*t1.mat[0] + mat[9]*t1.mat[4] + mat[10]*t1.mat[8]; + tmp9 = mat[8]*t1.mat[1] + mat[9]*t1.mat[5] + mat[10]*t1.mat[9]; + tmp10 = mat[8]*t1.mat[2] + mat[9]*t1.mat[6] + mat[10]*t1.mat[10]; + tmp11 = mat[8]*t1.mat[3] + mat[9]*t1.mat[7] + mat[10]*t1.mat[11] + mat[11]; + if (isAffine()) { + mat[12] = mat[13] = mat[14] = 0; + mat[15] = 1; + aff = true; + } else { + double tmp12 = mat[12]*t1.mat[0] + mat[13]*t1.mat[4] + + mat[14]*t1.mat[8]; + double tmp13 = mat[12]*t1.mat[1] + mat[13]*t1.mat[5] + + mat[14]*t1.mat[9]; + double tmp14 = mat[12]*t1.mat[2] + mat[13]*t1.mat[6] + + mat[14]*t1.mat[10]; + double tmp15 = mat[12]*t1.mat[3] + mat[13]*t1.mat[7] + + mat[14]*t1.mat[11] + mat[15]; + mat[12] = tmp12; + mat[13] = tmp13; + mat[14] = tmp14; + mat[15] = tmp15; + } + } else { + tmp0 = mat[0]*t1.mat[0] + mat[1]*t1.mat[4] + mat[2]*t1.mat[8] + + mat[3]*t1.mat[12]; + tmp1 = mat[0]*t1.mat[1] + mat[1]*t1.mat[5] + mat[2]*t1.mat[9] + + mat[3]*t1.mat[13]; + tmp2 = mat[0]*t1.mat[2] + mat[1]*t1.mat[6] + mat[2]*t1.mat[10] + + mat[3]*t1.mat[14]; + tmp3 = mat[0]*t1.mat[3] + mat[1]*t1.mat[7] + mat[2]*t1.mat[11] + + mat[3]*t1.mat[15]; + tmp4 = mat[4]*t1.mat[0] + mat[5]*t1.mat[4] + mat[6]*t1.mat[8] + + mat[7]*t1.mat[12]; + tmp5 = mat[4]*t1.mat[1] + mat[5]*t1.mat[5] + mat[6]*t1.mat[9] + + mat[7]*t1.mat[13]; + tmp6 = mat[4]*t1.mat[2] + mat[5]*t1.mat[6] + mat[6]*t1.mat[10] + + mat[7]*t1.mat[14]; + tmp7 = mat[4]*t1.mat[3] + mat[5]*t1.mat[7] + mat[6]*t1.mat[11] + + mat[7]*t1.mat[15]; + tmp8 = mat[8]*t1.mat[0] + mat[9]*t1.mat[4] + mat[10]*t1.mat[8] + + mat[11]*t1.mat[12]; + tmp9 = mat[8]*t1.mat[1] + mat[9]*t1.mat[5] + mat[10]*t1.mat[9] + + mat[11]*t1.mat[13]; + tmp10 = mat[8]*t1.mat[2] + mat[9]*t1.mat[6] + + mat[10]*t1.mat[10]+ mat[11]*t1.mat[14]; + tmp11 = mat[8]*t1.mat[3] + mat[9]*t1.mat[7] + + mat[10]*t1.mat[11] + mat[11]*t1.mat[15]; + + if (isAffine()) { + mat[12] = t1.mat[12]; + mat[13] = t1.mat[13]; + mat[14] = t1.mat[14]; + mat[15] = t1.mat[15]; + } else { + double tmp12 = mat[12]*t1.mat[0] + mat[13]*t1.mat[4] + + mat[14]*t1.mat[8] + mat[15]*t1.mat[12]; + double tmp13 = mat[12]*t1.mat[1] + mat[13]*t1.mat[5] + + mat[14]*t1.mat[9] + mat[15]*t1.mat[13]; + double tmp14 = mat[12]*t1.mat[2] + mat[13]*t1.mat[6] + + mat[14]*t1.mat[10] + mat[15]*t1.mat[14]; + double tmp15 = mat[12]*t1.mat[3] + mat[13]*t1.mat[7] + + mat[14]*t1.mat[11] + mat[15]*t1.mat[15]; + mat[12] = tmp12; + mat[13] = tmp13; + mat[14] = tmp14; + mat[15] = tmp15; + } + } + + mat[0] = tmp0; + mat[1] = tmp1; + mat[2] = tmp2; + mat[3] = tmp3; + mat[4] = tmp4; + mat[5] = tmp5; + mat[6] = tmp6; + mat[7] = tmp7; + mat[8] = tmp8; + mat[9] = tmp9; + mat[10] = tmp10; + mat[11] = tmp11; + + if (((dirtyBits & CONGRUENT_BIT) == 0) && + ((type & CONGRUENT) != 0) && + ((t1.dirtyBits & CONGRUENT_BIT) == 0) && + ((t1.type & CONGRUENT) != 0)) { + type &= t1.type; + dirtyBits |= t1.dirtyBits | CLASSIFY_BIT | + ROTSCALESVD_DIRTY | RIGID_BIT; + } else { + if (aff) { + dirtyBits = ORTHO_BIT | CONGRUENT_BIT | RIGID_BIT | + CLASSIFY_BIT | ROTSCALESVD_DIRTY; + } else { + dirtyBits = ALL_DIRTY; + } + } + + if (autoNormalize) { + normalize(); + } + + } + + /** + * Sets the value of this transform to the result of multiplying transform + * t1 by transform t2 (this = t1*t2). + * @param t1 the left transform + * @param t2 the right transform + */ + public final void mul(Transform3D t1, Transform3D t2) { + boolean aff = false; + if ((this != t1) && (this != t2)) { + if (t2.isAffine()) { + + mat[0] = t1.mat[0]*t2.mat[0] + t1.mat[1]*t2.mat[4] + t1.mat[2]*t2.mat[8]; + mat[1] = t1.mat[0]*t2.mat[1] + t1.mat[1]*t2.mat[5] + t1.mat[2]*t2.mat[9]; + mat[2] = t1.mat[0]*t2.mat[2] + t1.mat[1]*t2.mat[6] + t1.mat[2]*t2.mat[10]; + mat[3] = t1.mat[0]*t2.mat[3] + t1.mat[1]*t2.mat[7] + + t1.mat[2]*t2.mat[11] + t1.mat[3]; + mat[4] = t1.mat[4]*t2.mat[0] + t1.mat[5]*t2.mat[4] + t1.mat[6]*t2.mat[8]; + mat[5] = t1.mat[4]*t2.mat[1] + t1.mat[5]*t2.mat[5] + t1.mat[6]*t2.mat[9]; + mat[6] = t1.mat[4]*t2.mat[2] + t1.mat[5]*t2.mat[6] + t1.mat[6]*t2.mat[10]; + mat[7] = t1.mat[4]*t2.mat[3] + t1.mat[5]*t2.mat[7] + + t1.mat[6]*t2.mat[11] + t1.mat[7]; + mat[8] = t1.mat[8]*t2.mat[0] + t1.mat[9]*t2.mat[4] + t1.mat[10]*t2.mat[8]; + mat[9] = t1.mat[8]*t2.mat[1] + t1.mat[9]*t2.mat[5] + t1.mat[10]*t2.mat[9]; + mat[10] = t1.mat[8]*t2.mat[2] + t1.mat[9]*t2.mat[6] + t1.mat[10]*t2.mat[10]; + mat[11] = t1.mat[8]*t2.mat[3] + t1.mat[9]*t2.mat[7] + + t1.mat[10]*t2.mat[11] + t1.mat[11]; + if (t1.isAffine()) { + aff = true; + mat[12] = mat[13] = mat[14] = 0; + mat[15] = 1; + } else { + mat[12] = t1.mat[12]*t2.mat[0] + t1.mat[13]*t2.mat[4] + + t1.mat[14]*t2.mat[8]; + mat[13] = t1.mat[12]*t2.mat[1] + t1.mat[13]*t2.mat[5] + + t1.mat[14]*t2.mat[9]; + mat[14] = t1.mat[12]*t2.mat[2] + t1.mat[13]*t2.mat[6] + + t1.mat[14]*t2.mat[10]; + mat[15] = t1.mat[12]*t2.mat[3] + t1.mat[13]*t2.mat[7] + + t1.mat[14]*t2.mat[11] + t1.mat[15]; + } + } else { + mat[0] = t1.mat[0]*t2.mat[0] + t1.mat[1]*t2.mat[4] + + t1.mat[2]*t2.mat[8] + t1.mat[3]*t2.mat[12]; + mat[1] = t1.mat[0]*t2.mat[1] + t1.mat[1]*t2.mat[5] + + t1.mat[2]*t2.mat[9] + t1.mat[3]*t2.mat[13]; + mat[2] = t1.mat[0]*t2.mat[2] + t1.mat[1]*t2.mat[6] + + t1.mat[2]*t2.mat[10] + t1.mat[3]*t2.mat[14]; + mat[3] = t1.mat[0]*t2.mat[3] + t1.mat[1]*t2.mat[7] + + t1.mat[2]*t2.mat[11] + t1.mat[3]*t2.mat[15]; + mat[4] = t1.mat[4]*t2.mat[0] + t1.mat[5]*t2.mat[4] + + t1.mat[6]*t2.mat[8] + t1.mat[7]*t2.mat[12]; + mat[5] = t1.mat[4]*t2.mat[1] + t1.mat[5]*t2.mat[5] + + t1.mat[6]*t2.mat[9] + t1.mat[7]*t2.mat[13]; + mat[6] = t1.mat[4]*t2.mat[2] + t1.mat[5]*t2.mat[6] + + t1.mat[6]*t2.mat[10] + t1.mat[7]*t2.mat[14]; + mat[7] = t1.mat[4]*t2.mat[3] + t1.mat[5]*t2.mat[7] + + t1.mat[6]*t2.mat[11] + t1.mat[7]*t2.mat[15]; + mat[8] = t1.mat[8]*t2.mat[0] + t1.mat[9]*t2.mat[4] + + t1.mat[10]*t2.mat[8] + t1.mat[11]*t2.mat[12]; + mat[9] = t1.mat[8]*t2.mat[1] + t1.mat[9]*t2.mat[5] + + t1.mat[10]*t2.mat[9] + t1.mat[11]*t2.mat[13]; + mat[10] = t1.mat[8]*t2.mat[2] + t1.mat[9]*t2.mat[6] + + t1.mat[10]*t2.mat[10] + t1.mat[11]*t2.mat[14]; + mat[11] = t1.mat[8]*t2.mat[3] + t1.mat[9]*t2.mat[7] + + t1.mat[10]*t2.mat[11] + t1.mat[11]*t2.mat[15]; + if (t1.isAffine()) { + mat[12] = t2.mat[12]; + mat[13] = t2.mat[13]; + mat[14] = t2.mat[14]; + mat[15] = t2.mat[15]; + } else { + mat[12] = t1.mat[12]*t2.mat[0] + t1.mat[13]*t2.mat[4] + + t1.mat[14]*t2.mat[8] + t1.mat[15]*t2.mat[12]; + mat[13] = t1.mat[12]*t2.mat[1] + t1.mat[13]*t2.mat[5] + + t1.mat[14]*t2.mat[9] + t1.mat[15]*t2.mat[13]; + mat[14] = t1.mat[12]*t2.mat[2] + t1.mat[13]*t2.mat[6] + + t1.mat[14]*t2.mat[10] + t1.mat[15]*t2.mat[14]; + mat[15] = t1.mat[12]*t2.mat[3] + t1.mat[13]*t2.mat[7] + + t1.mat[14]*t2.mat[11] + t1.mat[15]*t2.mat[15]; + } + } + } else { + double tmp0, tmp1, tmp2, tmp3; + double tmp4, tmp5, tmp6, tmp7; + double tmp8, tmp9, tmp10, tmp11; + + if (t2.isAffine()) { + tmp0 = t1.mat[0]*t2.mat[0] + t1.mat[1]*t2.mat[4] + t1.mat[2]*t2.mat[8]; + tmp1 = t1.mat[0]*t2.mat[1] + t1.mat[1]*t2.mat[5] + t1.mat[2]*t2.mat[9]; + tmp2 = t1.mat[0]*t2.mat[2] + t1.mat[1]*t2.mat[6] + t1.mat[2]*t2.mat[10]; + tmp3 = t1.mat[0]*t2.mat[3] + t1.mat[1]*t2.mat[7] + + t1.mat[2]*t2.mat[11] + t1.mat[3]; + tmp4 = t1.mat[4]*t2.mat[0] + t1.mat[5]*t2.mat[4] + t1.mat[6]*t2.mat[8]; + tmp5 = t1.mat[4]*t2.mat[1] + t1.mat[5]*t2.mat[5] + t1.mat[6]*t2.mat[9]; + tmp6 = t1.mat[4]*t2.mat[2] + t1.mat[5]*t2.mat[6] + t1.mat[6]*t2.mat[10]; + tmp7 = t1.mat[4]*t2.mat[3] + t1.mat[5]*t2.mat[7] + + t1.mat[6]*t2.mat[11] + t1.mat[7]; + tmp8 = t1.mat[8]*t2.mat[0] + t1.mat[9]*t2.mat[4] + t1.mat[10]*t2.mat[8]; + tmp9 = t1.mat[8]*t2.mat[1] + t1.mat[9]*t2.mat[5] + t1.mat[10]*t2.mat[9]; + tmp10 = t1.mat[8]*t2.mat[2] + t1.mat[9]*t2.mat[6] + t1.mat[10]*t2.mat[10]; + tmp11 = t1.mat[8]*t2.mat[3] + t1.mat[9]*t2.mat[7] + + t1.mat[10]*t2.mat[11] + t1.mat[11]; + if (t1.isAffine()) { + aff = true; + mat[12] = mat[13] = mat[14] = 0; + mat[15] = 1; + } else { + double tmp12 = t1.mat[12]*t2.mat[0] + t1.mat[13]*t2.mat[4] + + t1.mat[14]*t2.mat[8]; + double tmp13 = t1.mat[12]*t2.mat[1] + t1.mat[13]*t2.mat[5] + + t1.mat[14]*t2.mat[9]; + double tmp14 = t1.mat[12]*t2.mat[2] + t1.mat[13]*t2.mat[6] + + t1.mat[14]*t2.mat[10]; + double tmp15 = t1.mat[12]*t2.mat[3] + t1.mat[13]*t2.mat[7] + + t1.mat[14]*t2.mat[11] + t1.mat[15]; + mat[12] = tmp12; + mat[13] = tmp13; + mat[14] = tmp14; + mat[15] = tmp15; + } + } else { + tmp0 = t1.mat[0]*t2.mat[0] + t1.mat[1]*t2.mat[4] + + t1.mat[2]*t2.mat[8] + t1.mat[3]*t2.mat[12]; + tmp1 = t1.mat[0]*t2.mat[1] + t1.mat[1]*t2.mat[5] + + t1.mat[2]*t2.mat[9] + t1.mat[3]*t2.mat[13]; + tmp2 = t1.mat[0]*t2.mat[2] + t1.mat[1]*t2.mat[6] + + t1.mat[2]*t2.mat[10] + t1.mat[3]*t2.mat[14]; + tmp3 = t1.mat[0]*t2.mat[3] + t1.mat[1]*t2.mat[7] + + t1.mat[2]*t2.mat[11] + t1.mat[3]*t2.mat[15]; + tmp4 = t1.mat[4]*t2.mat[0] + t1.mat[5]*t2.mat[4] + + t1.mat[6]*t2.mat[8] + t1.mat[7]*t2.mat[12]; + tmp5 = t1.mat[4]*t2.mat[1] + t1.mat[5]*t2.mat[5] + + t1.mat[6]*t2.mat[9] + t1.mat[7]*t2.mat[13]; + tmp6 = t1.mat[4]*t2.mat[2] + t1.mat[5]*t2.mat[6] + + t1.mat[6]*t2.mat[10] + t1.mat[7]*t2.mat[14]; + tmp7 = t1.mat[4]*t2.mat[3] + t1.mat[5]*t2.mat[7] + + t1.mat[6]*t2.mat[11] + t1.mat[7]*t2.mat[15]; + tmp8 = t1.mat[8]*t2.mat[0] + t1.mat[9]*t2.mat[4] + + t1.mat[10]*t2.mat[8] + t1.mat[11]*t2.mat[12]; + tmp9 = t1.mat[8]*t2.mat[1] + t1.mat[9]*t2.mat[5] + + t1.mat[10]*t2.mat[9] + t1.mat[11]*t2.mat[13]; + tmp10 = t1.mat[8]*t2.mat[2] + t1.mat[9]*t2.mat[6] + + t1.mat[10]*t2.mat[10] + t1.mat[11]*t2.mat[14]; + tmp11 = t1.mat[8]*t2.mat[3] + t1.mat[9]*t2.mat[7] + + t1.mat[10]*t2.mat[11] + t1.mat[11]*t2.mat[15]; + + if (t1.isAffine()) { + mat[12] = t2.mat[12]; + mat[13] = t2.mat[13]; + mat[14] = t2.mat[14]; + mat[15] = t2.mat[15]; + } else { + double tmp12 = t1.mat[12]*t2.mat[0] + t1.mat[13]*t2.mat[4] + + t1.mat[14]*t2.mat[8] + t1.mat[15]*t2.mat[12]; + double tmp13 = t1.mat[12]*t2.mat[1] + t1.mat[13]*t2.mat[5] + + t1.mat[14]*t2.mat[9] + t1.mat[15]*t2.mat[13]; + double tmp14 = t1.mat[12]*t2.mat[2] + t1.mat[13]*t2.mat[6] + + t1.mat[14]*t2.mat[10] + t1.mat[15]*t2.mat[14]; + double tmp15 = t1.mat[12]*t2.mat[3] + t1.mat[13]*t2.mat[7] + + t1.mat[14]*t2.mat[11] + t1.mat[15]*t2.mat[15]; + mat[12] = tmp12; + mat[13] = tmp13; + mat[14] = tmp14; + mat[15] = tmp15; + } + } + mat[0] = tmp0; + mat[1] = tmp1; + mat[2] = tmp2; + mat[3] = tmp3; + mat[4] = tmp4; + mat[5] = tmp5; + mat[6] = tmp6; + mat[7] = tmp7; + mat[8] = tmp8; + mat[9] = tmp9; + mat[10] = tmp10; + mat[11] = tmp11; + } + + + if (((t1.dirtyBits & CONGRUENT_BIT) == 0) && + ((t1.type & CONGRUENT) != 0) && + ((t2.dirtyBits & CONGRUENT_BIT) == 0) && + ((t2.type & CONGRUENT) != 0)) { + type = t1.type & t2.type; + dirtyBits = t1.dirtyBits | t2.dirtyBits | CLASSIFY_BIT | + ROTSCALESVD_DIRTY | RIGID_BIT; + } else { + if (aff) { + dirtyBits = ORTHO_BIT | CONGRUENT_BIT | RIGID_BIT | + CLASSIFY_BIT | ROTSCALESVD_DIRTY; + } else { + dirtyBits = ALL_DIRTY; + } + } + + if (autoNormalize) { + normalize(); + } + } + + /** + * Multiplies this transform by the inverse of transform t1. The final + * value is placed into this matrix (this = this*t1^-1). + * @param t1 the matrix whose inverse is computed. + */ + public final void mulInverse(Transform3D t1) { + Transform3D t2 = new Transform3D(); + t2.autoNormalize = false; + t2.invert(t1); + this.mul(t2); + } + + + /** + * Multiplies transform t1 by the inverse of transform t2. The final + * value is placed into this matrix (this = t1*t2^-1). + * @param t1 the left transform in the multiplication + * @param t2 the transform whose inverse is computed. + */ + public final void mulInverse(Transform3D t1, Transform3D t2) { + Transform3D t3 = new Transform3D(); + t3.autoNormalize = false; + t3.invert(t2); + this.mul(t1,t3); + } + + /** + * Multiplies transform t1 by the transpose of transform t2 and places + * the result into this transform (this = t1 * transpose(t2)). + * @param t1 the transform on the left hand side of the multiplication + * @param t2 the transform whose transpose is computed + */ + public final void mulTransposeRight(Transform3D t1, Transform3D t2) { + Transform3D t3 = new Transform3D(); + t3.autoNormalize = false; + t3.transpose(t2); + mul(t1, t3); + } + + + /** + * Multiplies the transpose of transform t1 by transform t2 and places + * the result into this matrix (this = transpose(t1) * t2). + * @param t1 the transform whose transpose is computed + * @param t2 the transform on the right hand side of the multiplication + */ + public final void mulTransposeLeft(Transform3D t1, Transform3D t2){ + Transform3D t3 = new Transform3D(); + t3.autoNormalize = false; + t3.transpose(t1); + mul(t3, t2); + } + + + /** + * Multiplies the transpose of transform t1 by the transpose of + * transform t2 and places the result into this transform + * (this = transpose(t1) * transpose(t2)). + * @param t1 the transform on the left hand side of the multiplication + * @param t2 the transform on the right hand side of the multiplication + */ + public final void mulTransposeBoth(Transform3D t1, Transform3D t2) { + Transform3D t3 = new Transform3D(); + Transform3D t4 = new Transform3D(); + t3.autoNormalize = false; + t4.autoNormalize = false; + t3.transpose(t1); + t4.transpose(t2); + mul(t3, t4); + } + + + /** + * Normalizes the rotational components (upper 3x3) of this matrix + * in place using a Singular Value Decomposition (SVD). + * This operation ensures that the column vectors of this matrix + * are orthogonal to each other. The primary use of this method + * is to correct for floating point errors that accumulate over + * time when concatenating a large number of rotation matrices. + * Note that the scale of the matrix is not altered by this method. + */ + public final void normalize() { + // Issue 253: Unable to normalize matrices with infinity or NaN + if (!isAffine() && isInfOrNaN()) { + return; + } + + if ((dirtyBits & (ROTATION_BIT|SVD_BIT)) != 0) { + computeScaleRotation(true); + } else if ((dirtyBits & (SCALE_BIT|SVD_BIT)) != 0) { + computeScales(true); + } + + mat[0] = rot[0]*scales[0]; + mat[1] = rot[1]*scales[1]; + mat[2] = rot[2]*scales[2]; + mat[4] = rot[3]*scales[0]; + mat[5] = rot[4]*scales[1]; + mat[6] = rot[5]*scales[2]; + mat[8] = rot[6]*scales[0]; + mat[9] = rot[7]*scales[1]; + mat[10] = rot[8]*scales[2]; + dirtyBits |= CLASSIFY_BIT; + dirtyBits &= ~ORTHO_BIT; + type |= ORTHO; + } + + /** + * Normalizes the rotational components (upper 3x3) of transform t1 + * using a Singular Value Decomposition (SVD), and places the result + * into this transform. + * This operation ensures that the column vectors of this matrix + * are orthogonal to each other. The primary use of this method + * is to correct for floating point errors that accumulate over + * time when concatenating a large number of rotation matrices. + * Note that the scale of the matrix is not altered by this method. + * + * @param t1 the source transform, which is not modified + */ + public final void normalize(Transform3D t1){ + set(t1); + normalize(); + } + + /** + * Normalizes the rotational components (upper 3x3) of this transform + * in place using a Cross Product (CP) normalization. + * This operation ensures that the column vectors of this matrix + * are orthogonal to each other. The primary use of this method + * is to correct for floating point errors that accumulate over + * time when concatenating a large number of rotation matrices. + * Note that the scale of the matrix is not altered by this method. + */ + public final void normalizeCP() { + // Issue 253: Unable to normalize matrices with infinity or NaN + if (!isAffine() && isInfOrNaN()) { + return; + } + + if ((dirtyBits & SCALE_BIT) != 0) { + computeScales(false); + } + + double mag = mat[0]*mat[0] + mat[4]*mat[4] + + mat[8]*mat[8]; + + if (mag != 0) { + mag = 1.0/Math.sqrt(mag); + mat[0] = mat[0]*mag; + mat[4] = mat[4]*mag; + mat[8] = mat[8]*mag; + } + + mag = mat[1]*mat[1] + mat[5]*mat[5] + + mat[9]*mat[9]; + + if (mag != 0) { + mag = 1.0/Math.sqrt(mag); + mat[1] = mat[1]*mag; + mat[5] = mat[5]*mag; + mat[9] = mat[9]*mag; + } + mat[2] = (mat[4]*mat[9] - mat[5]*mat[8])*scales[0]; + mat[6] = (mat[1]*mat[8] - mat[0]*mat[9])*scales[1]; + mat[10] = (mat[0]*mat[5] - mat[1]*mat[4])*scales[2]; + + mat[0] *= scales[0]; + mat[1] *= scales[0]; + mat[4] *= scales[1]; + mat[5] *= scales[1]; + mat[8] *= scales[2]; + mat[9] *= scales[2]; + + // leave the AFFINE bit + dirtyBits |= CONGRUENT_BIT | RIGID_BIT | CLASSIFY_BIT | ROTATION_BIT | SVD_BIT; + dirtyBits &= ~ORTHO_BIT; + type |= ORTHO; + } + + + /** + * Normalizes the rotational components (upper 3x3) of transform t1 + * using a Cross Product (CP) normalization, and + * places the result into this transform. + * This operation ensures that the column vectors of this matrix + * are orthogonal to each other. The primary use of this method + * is to correct for floating point errors that accumulate over + * time when concatenating a large number of rotation matrices. + * Note that the scale of the matrix is not altered by this method. + * + * @param t1 the transform to be normalized + */ + public final void normalizeCP(Transform3D t1) { + set(t1); + normalizeCP(); + } + + + /** + * Returns true if all of the data members of transform t1 are + * equal to the corresponding data members in this Transform3D. + * @param t1 the transform with which the comparison is made + * @return true or false + */ + public boolean equals(Transform3D t1) { + return (t1 != null) && + (mat[0] == t1.mat[0]) && (mat[1] == t1.mat[1]) && + (mat[2] == t1.mat[2]) && (mat[3] == t1.mat[3]) && + (mat[4] == t1.mat[4]) && (mat[5] == t1.mat[5]) && + (mat[6] == t1.mat[6]) && (mat[7] == t1.mat[7]) && + (mat[8] == t1.mat[8]) && (mat[9] == t1.mat[9]) && + (mat[10] == t1.mat[10]) && (mat[11] == t1.mat[11]) && + (mat[12] == t1.mat[12]) && (mat[13] == t1.mat[13]) && + (mat[14] == t1.mat[14]) && ( mat[15] == t1.mat[15]); + } + + + /** + * Returns true if the Object o1 is of type Transform3D and all of the + * data members of o1 are equal to the corresponding data members in + * this Transform3D. + * @param o1 the object with which the comparison is made. + * @return true or false + */ + public boolean equals(Object o1) { + return (o1 instanceof Transform3D) && equals((Transform3D) o1); + } + + + /** + * Returns true if the L-infinite distance between this matrix + * and matrix m1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to + * MAX[i=0,1,2,3 ; j=0,1,2,3 ; abs[(this.m(i,j) - m1.m(i,j)] + * @param t1 the transform to be compared to this transform + * @param epsilon the threshold value + */ + public boolean epsilonEquals(Transform3D t1, double epsilon) { + double diff; + + for (int i=0 ; i<16 ; i++) { + diff = mat[i] - t1.mat[i]; + if ((diff < 0 ? -diff : diff) > epsilon) { + return false; + } + } + return true; + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Transform3D objects with identical data + * values (i.e., Transform3D.equals returns true) will return the + * same hash number. Two Transform3D objects with different data + * members may return the same hash value, although this is not + * likely. + * @return the integer hash code value + */ + public int hashCode() { + long bits = 1L; + + for (int i = 0; i < 16; i++) { + bits = 31L * bits + HashCodeUtil.doubleToLongBits(mat[i]); + } + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Transform the vector vec using this transform and place the + * result into vecOut. + * @param vec the double precision vector to be transformed + * @param vecOut the vector into which the transformed values are placed + */ + public final void transform(Vector4d vec, Vector4d vecOut) { + + if (vec != vecOut) { + vecOut.x = (mat[0]*vec.x + mat[1]*vec.y + + mat[2]*vec.z + mat[3]*vec.w); + vecOut.y = (mat[4]*vec.x + mat[5]*vec.y + + mat[6]*vec.z + mat[7]*vec.w); + vecOut.z = (mat[8]*vec.x + mat[9]*vec.y + + mat[10]*vec.z + mat[11]*vec.w); + vecOut.w = (mat[12]*vec.x + mat[13]*vec.y + + mat[14]*vec.z + mat[15]*vec.w); + } else { + transform(vec); + } + } + + + /** + * Transform the vector vec using this Transform and place the + * result back into vec. + * @param vec the double precision vector to be transformed + */ + public final void transform(Vector4d vec) { + double x = (mat[0]*vec.x + mat[1]*vec.y + + mat[2]*vec.z + mat[3]*vec.w); + double y = (mat[4]*vec.x + mat[5]*vec.y + + mat[6]*vec.z + mat[7]*vec.w); + double z = (mat[8]*vec.x + mat[9]*vec.y + + mat[10]*vec.z + mat[11]*vec.w); + vec.w = (mat[12]*vec.x + mat[13]*vec.y + + mat[14]*vec.z + mat[15]*vec.w); + vec.x = x; + vec.y = y; + vec.z = z; + } + + + /** + * Transform the vector vec using this Transform and place the + * result into vecOut. + * @param vec the single precision vector to be transformed + * @param vecOut the vector into which the transformed values are placed + */ + public final void transform(Vector4f vec, Vector4f vecOut) { + if (vecOut != vec) { + vecOut.x = (float) (mat[0]*vec.x + mat[1]*vec.y + + mat[2]*vec.z + mat[3]*vec.w); + vecOut.y = (float) (mat[4]*vec.x + mat[5]*vec.y + + mat[6]*vec.z + mat[7]*vec.w); + vecOut.z = (float) (mat[8]*vec.x + mat[9]*vec.y + + mat[10]*vec.z + mat[11]*vec.w); + vecOut.w = (float) (mat[12]*vec.x + mat[13]*vec.y + + mat[14]*vec.z + mat[15]*vec.w); + } else { + transform(vec); + } + } + + + /** + * Transform the vector vec using this Transform and place the + * result back into vec. + * @param vec the single precision vector to be transformed + */ + public final void transform(Vector4f vec) { + float x = (float) (mat[0]*vec.x + mat[1]*vec.y + + mat[2]*vec.z + mat[3]*vec.w); + float y = (float) (mat[4]*vec.x + mat[5]*vec.y + + mat[6]*vec.z + mat[7]*vec.w); + float z = (float) (mat[8]*vec.x + mat[9]*vec.y + + mat[10]*vec.z + mat[11]*vec.w); + vec.w = (float) (mat[12]*vec.x + mat[13]*vec.y + + mat[14]*vec.z + mat[15]*vec.w); + vec.x = x; + vec.y = y; + vec.z = z; + } + + + /** + * Transforms the point parameter with this transform and + * places the result into pointOut. The fourth element of the + * point input paramter is assumed to be one. + * @param point the input point to be transformed + * @param pointOut the transformed point + */ + public final void transform(Point3d point, Point3d pointOut) { + if (point != pointOut) { + pointOut.x = mat[0]*point.x + mat[1]*point.y + + mat[2]*point.z + mat[3]; + pointOut.y = mat[4]*point.x + mat[5]*point.y + + mat[6]*point.z + mat[7]; + pointOut.z = mat[8]*point.x + mat[9]*point.y + + mat[10]*point.z + mat[11]; + } else { + transform(point); + } + } + + + /** + * Transforms the point parameter with this transform and + * places the result back into point. The fourth element of the + * point input paramter is assumed to be one. + * @param point the input point to be transformed + */ + public final void transform(Point3d point) { + double x = mat[0]*point.x + mat[1]*point.y + mat[2]*point.z + mat[3]; + double y = mat[4]*point.x + mat[5]*point.y + mat[6]*point.z + mat[7]; + point.z = mat[8]*point.x + mat[9]*point.y + mat[10]*point.z + mat[11]; + point.x = x; + point.y = y; + } + + + /** + * Transforms the normal parameter by this transform and places the value + * into normalOut. The fourth element of the normal is assumed to be zero. + * @param normal the input normal to be transformed + * @param normalOut the transformed normal + */ + public final void transform(Vector3d normal, Vector3d normalOut) { + if (normalOut != normal) { + normalOut.x = mat[0]*normal.x + mat[1]*normal.y + mat[2]*normal.z; + normalOut.y = mat[4]*normal.x + mat[5]*normal.y + mat[6]*normal.z; + normalOut.z = mat[8]*normal.x + mat[9]*normal.y + mat[10]*normal.z; + } else { + transform(normal); + } + } + + + /** + * Transforms the normal parameter by this transform and places the value + * back into normal. The fourth element of the normal is assumed to be zero. + * @param normal the input normal to be transformed + */ + public final void transform(Vector3d normal) { + double x = mat[0]*normal.x + mat[1]*normal.y + mat[2]*normal.z; + double y = mat[4]*normal.x + mat[5]*normal.y + mat[6]*normal.z; + normal.z = mat[8]*normal.x + mat[9]*normal.y + mat[10]*normal.z; + normal.x = x; + normal.y = y; + } + + + /** + * Transforms the point parameter with this transform and + * places the result into pointOut. The fourth element of the + * point input paramter is assumed to be one. + * @param point the input point to be transformed + * @param pointOut the transformed point + */ + public final void transform(Point3f point, Point3f pointOut) { + if (point != pointOut) { + pointOut.x = (float)(mat[0]*point.x + mat[1]*point.y + + mat[2]*point.z + mat[3]); + pointOut.y = (float)(mat[4]*point.x + mat[5]*point.y + + mat[6]*point.z + mat[7]); + pointOut.z = (float)(mat[8]*point.x + mat[9]*point.y + + mat[10]*point.z + mat[11]); + } else { + transform(point); + } + } + + + /** + * Transforms the point parameter with this transform and + * places the result back into point. The fourth element of the + * point input paramter is assumed to be one. + * @param point the input point to be transformed + */ + public final void transform(Point3f point) { + float x = (float) (mat[0]*point.x + mat[1]*point.y + + mat[2]*point.z + mat[3]); + float y = (float) (mat[4]*point.x + mat[5]*point.y + + mat[6]*point.z + mat[7]); + point.z = (float) (mat[8]*point.x + mat[9]*point.y + + mat[10]*point.z + mat[11]); + point.x = x; + point.y = y; + } + + + /** + * Transforms the normal parameter by this transform and places the value + * into normalOut. The fourth element of the normal is assumed to be zero. + * Note: For correct lighting results, if a transform has uneven scaling + * surface normals should transformed by the inverse transpose of + * the transform. This the responsibility of the application and is not + * done automatically by this method. + * @param normal the input normal to be transformed + * @param normalOut the transformed normal + */ + public final void transform(Vector3f normal, Vector3f normalOut) { + if (normal != normalOut) { + normalOut.x = (float) (mat[0]*normal.x + mat[1]*normal.y + + mat[2]*normal.z); + normalOut.y = (float) (mat[4]*normal.x + mat[5]*normal.y + + mat[6]*normal.z); + normalOut.z = (float) (mat[8]*normal.x + mat[9]*normal.y + + mat[10]*normal.z); + } else { + transform(normal); + } + } + + /** + * Transforms the normal parameter by this transform and places the value + * back into normal. The fourth element of the normal is assumed to be zero. + * Note: For correct lighting results, if a transform has uneven scaling + * surface normals should transformed by the inverse transpose of + * the transform. This the responsibility of the application and is not + * done automatically by this method. + * @param normal the input normal to be transformed + */ + public final void transform(Vector3f normal) { + float x = (float) (mat[0]*normal.x + mat[1]*normal.y + + mat[2]*normal.z); + float y = (float) (mat[4]*normal.x + mat[5]*normal.y + + mat[6]*normal.z); + normal.z = (float) (mat[8]*normal.x + mat[9]*normal.y + + mat[10]*normal.z); + normal.x = x; + normal.y = y; + } + + + /** + * Replaces the upper 3x3 matrix values of this transform with the + * values in the matrix m1. + * @param m1 the matrix that will be the new upper 3x3 + */ + public final void setRotationScale(Matrix3f m1) { + mat[0] = m1.m00; mat[1] = m1.m01; mat[2] = m1.m02; + mat[4] = m1.m10; mat[5] = m1.m11; mat[6] = m1.m12; + mat[8] = m1.m20; mat[9] = m1.m21; mat[10] = m1.m22; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + + /** + * Replaces the upper 3x3 matrix values of this transform with the + * values in the matrix m1. + * @param m1 the matrix that will be the new upper 3x3 + */ + public final void setRotationScale(Matrix3d m1) { + mat[0] = m1.m00; mat[1] = m1.m01; mat[2] = m1.m02; + mat[4] = m1.m10; mat[5] = m1.m11; mat[6] = m1.m12; + mat[8] = m1.m20; mat[9] = m1.m21; mat[10] = m1.m22; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + /** + * Scales transform t1 by a Uniform scale matrix with scale + * factor s and then adds transform t2 (this = S*t1 + t2). + * @param s the scale factor + * @param t1 the transform to be scaled + * @param t2 the transform to be added + */ + public final void scaleAdd(double s, Transform3D t1, Transform3D t2) { + for (int i=0 ; i<16 ; i++) { + mat[i] = s*t1.mat[i] + t2.mat[i]; + } + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + + /** + * Scales this transform by a Uniform scale matrix with scale factor + * s and then adds transform t1 (this = S*this + t1). + * @param s the scale factor + * @param t1 the transform to be added + */ + public final void scaleAdd(double s, Transform3D t1) { + for (int i=0 ; i<16 ; i++) { + mat[i] = s*mat[i] + t1.mat[i]; + } + + dirtyBits = ALL_DIRTY; + + if (autoNormalize) { + normalize(); + } + } + + + /** + * Gets the upper 3x3 values of this matrix and places them into + * the matrix m1. + * @param m1 the matrix that will hold the values + */ + public final void getRotationScale(Matrix3f m1) { + m1.m00 = (float) mat[0]; + m1.m01 = (float) mat[1]; + m1.m02 = (float) mat[2]; + m1.m10 = (float) mat[4]; + m1.m11 = (float) mat[5]; + m1.m12 = (float) mat[6]; + m1.m20 = (float) mat[8]; + m1.m21 = (float) mat[9]; + m1.m22 = (float) mat[10]; + } + + + /** + * Gets the upper 3x3 values of this matrix and places them into + * the matrix m1. + * @param m1 the matrix that will hold the values + */ + public final void getRotationScale(Matrix3d m1) { + m1.m00 = mat[0]; + m1.m01 = mat[1]; + m1.m02 = mat[2]; + m1.m10 = mat[4]; + m1.m11 = mat[5]; + m1.m12 = mat[6]; + m1.m20 = mat[8]; + m1.m21 = mat[9]; + m1.m22 = mat[10]; + } + + + /** + * Helping function that specifies the position and orientation of a + * view matrix. The inverse of this transform can be used to control + * the ViewPlatform object within the scene graph. + * @param eye the location of the eye + * @param center a point in the virtual world where the eye is looking + * @param up an up vector specifying the frustum's up direction + */ + public void lookAt(Point3d eye, Point3d center, Vector3d up) { + double forwardx,forwardy,forwardz,invMag; + double upx,upy,upz; + double sidex,sidey,sidez; + + forwardx = eye.x - center.x; + forwardy = eye.y - center.y; + forwardz = eye.z - center.z; + + invMag = 1.0/Math.sqrt( forwardx*forwardx + forwardy*forwardy + forwardz*forwardz); + forwardx = forwardx*invMag; + forwardy = forwardy*invMag; + forwardz = forwardz*invMag; + + + invMag = 1.0/Math.sqrt( up.x*up.x + up.y*up.y + up.z*up.z); + upx = up.x*invMag; + upy = up.y*invMag; + upz = up.z*invMag; + + // side = Up cross forward + sidex = upy*forwardz-forwardy*upz; + sidey = upz*forwardx-upx*forwardz; + sidez = upx*forwardy-upy*forwardx; + + invMag = 1.0/Math.sqrt( sidex*sidex + sidey*sidey + sidez*sidez); + sidex *= invMag; + sidey *= invMag; + sidez *= invMag; + + // recompute up = forward cross side + + upx = forwardy*sidez-sidey*forwardz; + upy = forwardz*sidex-forwardx*sidez; + upz = forwardx*sidey-forwardy*sidex; + + // transpose because we calculated the inverse of what we want + mat[0] = sidex; + mat[1] = sidey; + mat[2] = sidez; + + mat[4] = upx; + mat[5] = upy; + mat[6] = upz; + + mat[8] = forwardx; + mat[9] = forwardy; + mat[10] = forwardz; + + mat[3] = -eye.x*mat[0] + -eye.y*mat[1] + -eye.z*mat[2]; + mat[7] = -eye.x*mat[4] + -eye.y*mat[5] + -eye.z*mat[6]; + mat[11] = -eye.x*mat[8] + -eye.y*mat[9] + -eye.z*mat[10]; + + mat[12] = mat[13] = mat[14] = 0; + mat[15] = 1; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + } + + + /** + * Creates a perspective projection transform that mimics a standard, + * camera-based, + * view-model. This transform maps coordinates from Eye Coordinates (EC) + * to Clipping Coordinates (CC). Note that unlike the similar function + * in OpenGL, the clipping coordinates generated by the resulting + * transform are in a right-handed coordinate system + * (as are all other coordinate systems in Java 3D). + *

+ * The frustum function-call establishes a view model with the eye + * at the apex of a symmetric view frustum. The arguments + * define the frustum and its associated perspective projection: + * (left, bottom, -near) and (right, top, -near) specify the + * point on the near clipping plane that maps onto the + * lower-left and upper-right corners of the window respectively, + * assuming the eye is located at (0, 0, 0). + * @param left the vertical line on the left edge of the near + * clipping plane mapped to the left edge of the graphics window + * @param right the vertical line on the right edge of the near + * clipping plane mapped to the right edge of the graphics window + * @param bottom the horizontal line on the bottom edge of the near + * clipping plane mapped to the bottom edge of the graphics window + * @param top the horizontal line on the top edge of the near + * @param near the distance to the frustum's near clipping plane. + * This value must be positive, (the value -near is the location of the + * near clip plane). + * @param far the distance to the frustum's far clipping plane. + * This value must be positive, and must be greater than near. + */ + public void frustum(double left, double right, + double bottom, double top, + double near, double far) { + double dx = 1/(right - left); + double dy = 1/(top - bottom); + double dz = 1/(far - near); + + mat[0] = (2.0*near)*dx; + mat[5] = (2.0*near)*dy; + mat[10] = (far+near)*dz; + mat[2] = (right+left)*dx; + mat[6] = (top+bottom)*dy; + mat[11] = (2.0*far*near)*dz; + mat[14] = -1.0; + mat[1] = mat[3] = mat[4] = mat[7] = mat[8] = mat[9] = mat[12] + = mat[13] = mat[15] = 0; + + // Matrix is a projection transform + type = 0; + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + } + + + /** + * Creates a perspective projection transform that mimics a standard, + * camera-based, + * view-model. This transform maps coordinates from Eye Coordinates (EC) + * to Clipping Coordinates (CC). Note that unlike the similar function + * in OpenGL, the clipping coordinates generated by the resulting + * transform are in a right-handed coordinate system + * (as are all other coordinate systems in Java 3D). Also note that the + * field of view is specified in radians. + * @param fovx specifies the field of view in the x direction, in radians + * @param aspect specifies the aspect ratio and thus the field of + * view in the x direction. The aspect ratio is the ratio of x to y, + * or width to height. + * @param zNear the distance to the frustum's near clipping plane. + * This value must be positive, (the value -zNear is the location of the + * near clip plane). + * @param zFar the distance to the frustum's far clipping plane + */ + public void perspective(double fovx, double aspect, + double zNear, double zFar) { + double sine, cotangent, deltaZ; + double half_fov = fovx * 0.5; + double x, y; + Vector3d v1, v2, v3, v4; + Vector3d norm = new Vector3d(); + + deltaZ = zFar - zNear; + sine = Math.sin(half_fov); +// if ((deltaZ == 0.0) || (sine == 0.0) || (aspect == 0.0)) { +// return; +// } + cotangent = Math.cos(half_fov) / sine; + + mat[0] = cotangent; + mat[5] = cotangent * aspect; + mat[10] = (zFar + zNear) / deltaZ; + mat[11] = 2.0 * zNear * zFar / deltaZ; + mat[14] = -1.0; + mat[1] = mat[2] = mat[3] = mat[4] = mat[6] = mat[7] = mat[8] = + mat[9] = mat[12] = mat[13] = mat[15] = 0; + + // Matrix is a projection transform + type = 0; + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + } + + + /** + * Creates an orthographic projection transform that mimics a standard, + * camera-based, + * view-model. This transform maps coordinates from Eye Coordinates (EC) + * to Clipping Coordinates (CC). Note that unlike the similar function + * in OpenGL, the clipping coordinates generated by the resulting + * transform are in a right-handed coordinate system + * (as are all other coordinate systems in Java 3D). + * @param left the vertical line on the left edge of the near + * clipping plane mapped to the left edge of the graphics window + * @param right the vertical line on the right edge of the near + * clipping plane mapped to the right edge of the graphics window + * @param bottom the horizontal line on the bottom edge of the near + * clipping plane mapped to the bottom edge of the graphics window + * @param top the horizontal line on the top edge of the near + * clipping plane mapped to the top edge of the graphics window + * @param near the distance to the frustum's near clipping plane + * (the value -near is the location of the near clip plane) + * @param far the distance to the frustum's far clipping plane + */ + public void ortho(double left, double right, double bottom, + double top, double near, double far) { + double deltax = 1/(right - left); + double deltay = 1/(top - bottom); + double deltaz = 1/(far - near); + +// if ((deltax == 0.0) || (deltay == 0.0) || (deltaz == 0.0)) { +// return; +// } + + mat[0] = 2.0 * deltax; + mat[3] = -(right + left) * deltax; + mat[5] = 2.0 * deltay; + mat[7] = -(top + bottom) * deltay; + mat[10] = 2.0 * deltaz; + mat[11] = (far + near) * deltaz; + mat[1] = mat[2] = mat[4] = mat[6] = mat[8] = + mat[9] = mat[12] = mat[13] = mat[14] = 0; + mat[15] = 1; + + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + } + + /** + * get the scaling factor of matrix in this transform, + * use for distance scaling + */ + double getDistanceScale() { + // The caller know that this matrix is affine + // orthogonal before invoke this procedure + + if ((dirtyBits & SCALE_BIT) != 0) { + double max = mat[0]*mat[0] + mat[4]*mat[4] + + mat[8]*mat[8]; + if (((dirtyBits & CONGRUENT_BIT) == 0) && + ((type & CONGRUENT) != 0)) { + // in most case it is congruent + return Math.sqrt(max); + } + double tmp = mat[1]*mat[1] + mat[5]*mat[5] + + mat[9]*mat[9]; + if (tmp > max) { + max = tmp; + } + tmp = mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10]; + return Math.sqrt((tmp > max) ? tmp : max); + } + return max3(scales); + } + + + static private void mat_mul(double[] m1, double[] m2, double[] m3) { + + double[] result = m3; + if ((m1 == m3) || (m2 == m3)) { + result = new double[9]; + } + + result[0] = m1[0]*m2[0] + m1[1]*m2[3] + m1[2]*m2[6]; + result[1] = m1[0]*m2[1] + m1[1]*m2[4] + m1[2]*m2[7]; + result[2] = m1[0]*m2[2] + m1[1]*m2[5] + m1[2]*m2[8]; + + result[3] = m1[3]*m2[0] + m1[4]*m2[3] + m1[5]*m2[6]; + result[4] = m1[3]*m2[1] + m1[4]*m2[4] + m1[5]*m2[7]; + result[5] = m1[3]*m2[2] + m1[4]*m2[5] + m1[5]*m2[8]; + + result[6] = m1[6]*m2[0] + m1[7]*m2[3] + m1[8]*m2[6]; + result[7] = m1[6]*m2[1] + m1[7]*m2[4] + m1[8]*m2[7]; + result[8] = m1[6]*m2[2] + m1[7]*m2[5] + m1[8]*m2[8]; + + if (result != m3) { + for(int i=0;i<9;i++) { + m3[i] = result[i]; + } + } + } + + static private void transpose_mat(double[] in, double[] out) { + out[0] = in[0]; + out[1] = in[3]; + out[2] = in[6]; + + out[3] = in[1]; + out[4] = in[4]; + out[5] = in[7]; + + out[6] = in[2]; + out[7] = in[5]; + out[8] = in[8]; + } + + + final static private void multipleScale(double m[] , double s[]) { + m[0] *= s[0]; + m[1] *= s[0]; + m[2] *= s[0]; + m[4] *= s[1]; + m[5] *= s[1]; + m[6] *= s[1]; + m[8] *= s[2]; + m[9] *= s[2]; + m[10] *= s[2]; + } + + private void compute_svd(Transform3D matrix, double[] outScale, + double[] outRot) { + + int i,j; + double g,scale; + double m[] = new double[9]; + + // if (!svdAllocd) { + double[] u1 = new double[9]; + double[] v1 = new double[9]; + double[] t1 = new double[9]; + double[] t2 = new double[9]; + // double[] ts = new double[9]; + // double[] svdTmp = new double[9]; It is replaced by t1 + double[] svdRot = new double[9]; + // double[] single_values = new double[3]; replaced by t2 + + double[] e = new double[3]; + double[] svdScales = new double[3]; + + + // XXXX: initialize to 0's if alread allocd? Should not have to, since + // no operations depend on these being init'd to zero. + + int converged, negCnt=0; + double cs,sn; + double c1,c2,c3,c4; + double s1,s2,s3,s4; + double cl1,cl2,cl3; + + + svdRot[0] = m[0] = matrix.mat[0]; + svdRot[1] = m[1] = matrix.mat[1]; + svdRot[2] = m[2] = matrix.mat[2]; + svdRot[3] = m[3] = matrix.mat[4]; + svdRot[4] = m[4] = matrix.mat[5]; + svdRot[5] = m[5] = matrix.mat[6]; + svdRot[6] = m[6] = matrix.mat[8]; + svdRot[7] = m[7] = matrix.mat[9]; + svdRot[8] = m[8] = matrix.mat[10]; + + // u1 + + if( m[3]*m[3] < EPS ) { + u1[0] = 1.0; u1[1] = 0.0; u1[2] = 0.0; + u1[3] = 0.0; u1[4] = 1.0; u1[5] = 0.0; + u1[6] = 0.0; u1[7] = 0.0; u1[8] = 1.0; + } else if( m[0]*m[0] < EPS ) { + t1[0] = m[0]; + t1[1] = m[1]; + t1[2] = m[2]; + m[0] = m[3]; + m[1] = m[4]; + m[2] = m[5]; + + m[3] = -t1[0]; // zero + m[4] = -t1[1]; + m[5] = -t1[2]; + + u1[0] = 0.0; u1[1] = 1.0; u1[2] = 0.0; + u1[3] = -1.0; u1[4] = 0.0; u1[5] = 0.0; + u1[6] = 0.0; u1[7] = 0.0; u1[8] = 1.0; + } else { + g = 1.0/Math.sqrt(m[0]*m[0] + m[3]*m[3]); + c1 = m[0]*g; + s1 = m[3]*g; + t1[0] = c1*m[0] + s1*m[3]; + t1[1] = c1*m[1] + s1*m[4]; + t1[2] = c1*m[2] + s1*m[5]; + + m[3] = -s1*m[0] + c1*m[3]; // zero + m[4] = -s1*m[1] + c1*m[4]; + m[5] = -s1*m[2] + c1*m[5]; + + m[0] = t1[0]; + m[1] = t1[1]; + m[2] = t1[2]; + u1[0] = c1; u1[1] = s1; u1[2] = 0.0; + u1[3] = -s1; u1[4] = c1; u1[5] = 0.0; + u1[6] = 0.0; u1[7] = 0.0; u1[8] = 1.0; + } + + // u2 + + if( m[6]*m[6] < EPS ) { + } else if( m[0]*m[0] < EPS ){ + t1[0] = m[0]; + t1[1] = m[1]; + t1[2] = m[2]; + m[0] = m[6]; + m[1] = m[7]; + m[2] = m[8]; + + m[6] = -t1[0]; // zero + m[7] = -t1[1]; + m[8] = -t1[2]; + + t1[0] = u1[0]; + t1[1] = u1[1]; + t1[2] = u1[2]; + u1[0] = u1[6]; + u1[1] = u1[7]; + u1[2] = u1[8]; + + u1[6] = -t1[0]; // zero + u1[7] = -t1[1]; + u1[8] = -t1[2]; + } else { + g = 1.0/Math.sqrt(m[0]*m[0] + m[6]*m[6]); + c2 = m[0]*g; + s2 = m[6]*g; + t1[0] = c2*m[0] + s2*m[6]; + t1[1] = c2*m[1] + s2*m[7]; + t1[2] = c2*m[2] + s2*m[8]; + + m[6] = -s2*m[0] + c2*m[6]; + m[7] = -s2*m[1] + c2*m[7]; + m[8] = -s2*m[2] + c2*m[8]; + m[0] = t1[0]; + m[1] = t1[1]; + m[2] = t1[2]; + + t1[0] = c2*u1[0]; + t1[1] = c2*u1[1]; + u1[2] = s2; + + t1[6] = -u1[0]*s2; + t1[7] = -u1[1]*s2; + u1[8] = c2; + u1[0] = t1[0]; + u1[1] = t1[1]; + u1[6] = t1[6]; + u1[7] = t1[7]; + } + + // v1 + + if( m[2]*m[2] < EPS ) { + v1[0] = 1.0; v1[1] = 0.0; v1[2] = 0.0; + v1[3] = 0.0; v1[4] = 1.0; v1[5] = 0.0; + v1[6] = 0.0; v1[7] = 0.0; v1[8] = 1.0; + } else if( m[1]*m[1] < EPS ) { + t1[2] = m[2]; + t1[5] = m[5]; + t1[8] = m[8]; + m[2] = -m[1]; + m[5] = -m[4]; + m[8] = -m[7]; + + m[1] = t1[2]; // zero + m[4] = t1[5]; + m[7] = t1[8]; + + v1[0] = 1.0; v1[1] = 0.0; v1[2] = 0.0; + v1[3] = 0.0; v1[4] = 0.0; v1[5] =-1.0; + v1[6] = 0.0; v1[7] = 1.0; v1[8] = 0.0; + } else { + g = 1.0/Math.sqrt(m[1]*m[1] + m[2]*m[2]); + c3 = m[1]*g; + s3 = m[2]*g; + t1[1] = c3*m[1] + s3*m[2]; // can assign to m[1]? + m[2] =-s3*m[1] + c3*m[2]; // zero + m[1] = t1[1]; + + t1[4] = c3*m[4] + s3*m[5]; + m[5] =-s3*m[4] + c3*m[5]; + m[4] = t1[4]; + + t1[7] = c3*m[7] + s3*m[8]; + m[8] =-s3*m[7] + c3*m[8]; + m[7] = t1[7]; + + v1[0] = 1.0; v1[1] = 0.0; v1[2] = 0.0; + v1[3] = 0.0; v1[4] = c3; v1[5] = -s3; + v1[6] = 0.0; v1[7] = s3; v1[8] = c3; + } + + // u3 + + if( m[7]*m[7] < EPS ) { + } else if( m[4]*m[4] < EPS ) { + t1[3] = m[3]; + t1[4] = m[4]; + t1[5] = m[5]; + m[3] = m[6]; // zero + m[4] = m[7]; + m[5] = m[8]; + + m[6] = -t1[3]; // zero + m[7] = -t1[4]; // zero + m[8] = -t1[5]; + + t1[3] = u1[3]; + t1[4] = u1[4]; + t1[5] = u1[5]; + u1[3] = u1[6]; + u1[4] = u1[7]; + u1[5] = u1[8]; + + u1[6] = -t1[3]; // zero + u1[7] = -t1[4]; + u1[8] = -t1[5]; + + } else { + g = 1.0/Math.sqrt(m[4]*m[4] + m[7]*m[7]); + c4 = m[4]*g; + s4 = m[7]*g; + t1[3] = c4*m[3] + s4*m[6]; + m[6] =-s4*m[3] + c4*m[6]; // zero + m[3] = t1[3]; + + t1[4] = c4*m[4] + s4*m[7]; + m[7] =-s4*m[4] + c4*m[7]; + m[4] = t1[4]; + + t1[5] = c4*m[5] + s4*m[8]; + m[8] =-s4*m[5] + c4*m[8]; + m[5] = t1[5]; + + t1[3] = c4*u1[3] + s4*u1[6]; + u1[6] =-s4*u1[3] + c4*u1[6]; + u1[3] = t1[3]; + + t1[4] = c4*u1[4] + s4*u1[7]; + u1[7] =-s4*u1[4] + c4*u1[7]; + u1[4] = t1[4]; + + t1[5] = c4*u1[5] + s4*u1[8]; + u1[8] =-s4*u1[5] + c4*u1[8]; + u1[5] = t1[5]; + } + + t2[0] = m[0]; + t2[1] = m[4]; + t2[2] = m[8]; + e[0] = m[1]; + e[1] = m[5]; + + if( e[0]*e[0]>EPS || e[1]*e[1]>EPS ) { + compute_qr( t2, e, u1, v1); + } + + svdScales[0] = t2[0]; + svdScales[1] = t2[1]; + svdScales[2] = t2[2]; + + + // Do some optimization here. If scale is unity, simply return the rotation matric. + if(almostOne(Math.abs(svdScales[0])) && + almostOne(Math.abs(svdScales[1])) && + almostOne(Math.abs(svdScales[2]))) { + + for(i=0;i<3;i++) + if(svdScales[i]<0.0) + negCnt++; + + if((negCnt==0)||(negCnt==2)) { + //System.err.println("Optimize!!"); + outScale[0] = outScale[1] = outScale[2] = 1.0; + for(i=0;i<9;i++) + outRot[i] = svdRot[i]; + + return; + } + } + + // XXXX: could eliminate use of t1 and t1 by making a new method which + // transposes and multiplies two matricies + transpose_mat(u1, t1); + transpose_mat(v1, t2); + + + svdReorder( m, t1, t2, svdRot, svdScales, outRot, outScale); + } + + + private void svdReorder( double[] m, double[] t1, double[] t2, double[] rot, + double[] scales, double[] outRot, double[] outScale) { + + int in0, in1, in2, index,i; + int[] svdOut = new int[3]; + double[] svdMag = new double[3]; + + + // check for rotation information in the scales + if(scales[0] < 0.0 ) { // move the rotation info to rotation matrix + scales[0] = -scales[0]; + t2[0] = -t2[0]; + t2[1] = -t2[1]; + t2[2] = -t2[2]; + } + if(scales[1] < 0.0 ) { // move the rotation info to rotation matrix + scales[1] = -scales[1]; + t2[3] = -t2[3]; + t2[4] = -t2[4]; + t2[5] = -t2[5]; + } + if(scales[2] < 0.0 ) { // move the rotation info to rotation matrix + scales[2] = -scales[2]; + t2[6] = -t2[6]; + t2[7] = -t2[7]; + t2[8] = -t2[8]; + } + + + mat_mul(t1,t2,rot); + + // check for equal scales case and do not reorder + if(almostEqual(Math.abs(scales[0]), Math.abs(scales[1])) && + almostEqual(Math.abs(scales[1]), Math.abs(scales[2])) ){ + for(i=0;i<9;i++){ + outRot[i] = rot[i]; + } + for(i=0;i<3;i++){ + outScale[i] = scales[i]; + } + + }else { + + // sort the order of the results of SVD + if( scales[0] > scales[1]) { + if( scales[0] > scales[2] ) { + if( scales[2] > scales[1] ) { + svdOut[0] = 0; svdOut[1] = 2; svdOut[2] = 1; // xzy + } else { + svdOut[0] = 0; svdOut[1] = 1; svdOut[2] = 2; // xyz + } + } else { + svdOut[0] = 2; svdOut[1] = 0; svdOut[2] = 1; // zxy + } + } else { // y > x + if( scales[1] > scales[2] ) { + if( scales[2] > scales[0] ) { + svdOut[0] = 1; svdOut[1] = 2; svdOut[2] = 0; // yzx + } else { + svdOut[0] = 1; svdOut[1] = 0; svdOut[2] = 2; // yxz + } + } else { + svdOut[0] = 2; svdOut[1] = 1; svdOut[2] = 0; // zyx + } + } + + + // sort the order of the input matrix + svdMag[0] = (m[0]*m[0] + m[1]*m[1] + m[2]*m[2]); + svdMag[1] = (m[3]*m[3] + m[4]*m[4] + m[5]*m[5]); + svdMag[2] = (m[6]*m[6] + m[7]*m[7] + m[8]*m[8]); + + + if( svdMag[0] > svdMag[1]) { + if( svdMag[0] > svdMag[2] ) { + if( svdMag[2] > svdMag[1] ) { + // 0 - 2 - 1 + in0 = 0; in2 = 1; in1 = 2;// xzy + } else { + // 0 - 1 - 2 + in0 = 0; in1 = 1; in2 = 2; // xyz + } + } else { + // 2 - 0 - 1 + in2 = 0; in0 = 1; in1 = 2; // zxy + } + } else { // y > x 1>0 + if( svdMag[1] > svdMag[2] ) { // 1>2 + if( svdMag[2] > svdMag[0] ) { // 2>0 + // 1 - 2 - 0 + in1 = 0; in2 = 1; in0 = 2; // yzx + } else { + // 1 - 0 - 2 + in1 = 0; in0 = 1; in2 = 2; // yxz + } + } else { + // 2 - 1 - 0 + in2 = 0; in1 = 1; in0 = 2; // zyx + } + } + + + index = svdOut[in0]; + outScale[0] = scales[index]; + + index = svdOut[in1]; + outScale[1] = scales[index]; + + index = svdOut[in2]; + outScale[2] = scales[index]; + + index = svdOut[in0]; + if (outRot == null) { + MasterControl.getCoreLogger().severe("outRot == null"); + } + if (rot == null) { + MasterControl.getCoreLogger().severe("rot == null"); + } + + outRot[0] = rot[index]; + + index = svdOut[in0]+3; + outRot[0+3] = rot[index]; + + index = svdOut[in0]+6; + outRot[0+6] = rot[index]; + + index = svdOut[in1]; + outRot[1] = rot[index]; + + index = svdOut[in1]+3; + outRot[1+3] = rot[index]; + + index = svdOut[in1]+6; + outRot[1+6] = rot[index]; + + index = svdOut[in2]; + outRot[2] = rot[index]; + + index = svdOut[in2]+3; + outRot[2+3] = rot[index]; + + index = svdOut[in2]+6; + outRot[2+6] = rot[index]; + } + + } + + private int compute_qr( double[] s, double[] e, double[] u, double[] v) { + int i,j,k; + boolean converged; + double shift,ssmin,ssmax,r; + + double utemp,vtemp; + double f,g; + + final int MAX_INTERATIONS = 10; + final double CONVERGE_TOL = 4.89E-15; + + double[] cosl = new double[2]; + double[] cosr = new double[2]; + double[] sinl = new double[2]; + double[] sinr = new double[2]; + double[] qr_m = new double[9]; + + + double c_b48 = 1.; + double c_b71 = -1.; + int first; + converged = false; + + first = 1; + + if( Math.abs(e[1]) < CONVERGE_TOL || Math.abs(e[0]) < CONVERGE_TOL) converged = true; + + for(k=0;k b ? a : b); + } + + static final double min( double a, double b) { + return ( a < b ? a : b); + } + + static final double d_sign(double a, double b) { + double x = (a >= 0 ? a : - a); + return( b >= 0 ? x : -x); + } + + static final double compute_shift( double f, double g, double h) { + double d__1, d__2; + double fhmn, fhmx, c, fa, ga, ha, as, at, au; + double ssmin; + + fa = Math.abs(f); + ga = Math.abs(g); + ha = Math.abs(h); + fhmn = min(fa,ha); + fhmx = max(fa,ha); + if (fhmn == 0.) { + ssmin = 0.; + if (fhmx == 0.) { + } else { + d__1 = min(fhmx,ga) / max(fhmx,ga); + } + } else { + if (ga < fhmx) { + as = fhmn / fhmx + 1.; + at = (fhmx - fhmn) / fhmx; + d__1 = ga / fhmx; + au = d__1 * d__1; + c = 2. / (Math.sqrt(as * as + au) + Math.sqrt(at * at + au)); + ssmin = fhmn * c; + } else { + au = fhmx / ga; + if (au == 0.) { + + + ssmin = fhmn * fhmx / ga; + } else { + as = fhmn / fhmx + 1.; + at = (fhmx - fhmn) / fhmx; + d__1 = as * au; + d__2 = at * au; + c = 1. / (Math.sqrt(d__1 * d__1 + 1.) + Math.sqrt(d__2 * d__2 + 1.)); + ssmin = fhmn * c * au; + ssmin += ssmin; + } + } + } + + return(ssmin); + } + + static int compute_2X2( double f, double g, double h, double[] single_values, + double[] snl, double[] csl, double[] snr, double[] csr, int index) { + + double c_b3 = 2.; + double c_b4 = 1.; + + double d__1; + int pmax; + double temp; + boolean swap; + double a, d, l, m, r, s, t, tsign, fa, ga, ha; + double ft, gt, ht, mm; + boolean gasmal; + double tt, clt, crt, slt, srt; + double ssmin,ssmax; + + ssmax = single_values[0]; + ssmin = single_values[1]; + clt = 0.0; + crt = 0.0; + slt = 0.0; + srt = 0.0; + tsign = 0.0; + + ft = f; + fa = Math.abs(ft); + ht = h; + ha = Math.abs(h); + + pmax = 1; + if( ha > fa) + swap = true; + else + swap = false; + + if (swap) { + pmax = 3; + temp = ft; + ft = ht; + ht = temp; + temp = fa; + fa = ha; + ha = temp; + + } + gt = g; + ga = Math.abs(gt); + if (ga == 0.) { + + single_values[1] = ha; + single_values[0] = fa; + clt = 1.; + crt = 1.; + slt = 0.; + srt = 0.; + } else { + gasmal = true; + + if (ga > fa) { + pmax = 2; + if (fa / ga < EPS) { + + gasmal = false; + ssmax = ga; + if (ha > 1.) { + ssmin = fa / (ga / ha); + } else { + ssmin = fa / ga * ha; + } + clt = 1.; + slt = ht / gt; + srt = 1.; + crt = ft / gt; + } + } + if (gasmal) { + + d = fa - ha; + if (d == fa) { + + l = 1.; + } else { + l = d / fa; + } + + m = gt / ft; + + t = 2. - l; + + mm = m * m; + tt = t * t; + s = Math.sqrt(tt + mm); + + if (l == 0.) { + r = Math.abs(m); + } else { + r = Math.sqrt(l * l + mm); + } + + a = (s + r) * .5; + + if (ga > fa) { + pmax = 2; + if (fa / ga < EPS) { + + gasmal = false; + ssmax = ga; + if (ha > 1.) { + ssmin = fa / (ga / ha); + } else { + ssmin = fa / ga * ha; + } + clt = 1.; + slt = ht / gt; + srt = 1.; + crt = ft / gt; + } + } + if (gasmal) { + + d = fa - ha; + if (d == fa) { + + l = 1.; + } else { + l = d / fa; + } + + m = gt / ft; + + t = 2. - l; + + mm = m * m; + tt = t * t; + s = Math.sqrt(tt + mm); + + if (l == 0.) { + r = Math.abs(m); + } else { + r = Math.sqrt(l * l + mm); + } + + a = (s + r) * .5; + + + ssmin = ha / a; + ssmax = fa * a; + if (mm == 0.) { + + if (l == 0.) { + t = d_sign(c_b3, ft) * d_sign(c_b4, gt); + } else { + t = gt / d_sign(d, ft) + m / t; + } + } else { + t = (m / (s + t) + m / (r + l)) * (a + 1.); + } + l = Math.sqrt(t * t + 4.); + crt = 2. / l; + srt = t / l; + clt = (crt + srt * m) / a; + slt = ht / ft * srt / a; + } + } + if (swap) { + csl[0] = srt; + snl[0] = crt; + csr[0] = slt; + snr[0] = clt; + } else { + csl[0] = clt; + snl[0] = slt; + csr[0] = crt; + snr[0] = srt; + } + + if (pmax == 1) { + tsign = d_sign(c_b4, csr[0]) * d_sign(c_b4, csl[0]) * d_sign(c_b4, f); + } + if (pmax == 2) { + tsign = d_sign(c_b4, snr[0]) * d_sign(c_b4, csl[0]) * d_sign(c_b4, g); + } + if (pmax == 3) { + tsign = d_sign(c_b4, snr[0]) * d_sign(c_b4, snl[0]) * d_sign(c_b4, h); + } + single_values[index] = d_sign(ssmax, tsign); + d__1 = tsign * d_sign(c_b4, f) * d_sign(c_b4, h); + single_values[index+1] = d_sign(ssmin, d__1); + + + } + return 0; + } + + static double compute_rot( double f, double g, double[] sin, double[] cos, int index, int first) { + int i__1; + double d__1, d__2; + double cs,sn; + int i; + double scale; + int count; + double f1, g1; + double r; + final double safmn2 = 2.002083095183101E-146; + final double safmx2 = 4.994797680505588E+145; + + if (g == 0.) { + cs = 1.; + sn = 0.; + r = f; + } else if (f == 0.) { + cs = 0.; + sn = 1.; + r = g; + } else { + f1 = f; + g1 = g; + scale = max(Math.abs(f1),Math.abs(g1)); + if (scale >= safmx2) { + count = 0; + while(scale >= safmx2) { + ++count; + f1 *= safmn2; + g1 *= safmn2; + scale = max(Math.abs(f1),Math.abs(g1)); + } + r = Math.sqrt(f1*f1 + g1*g1); + cs = f1 / r; + sn = g1 / r; + i__1 = count; + for (i = 1; i <= count; ++i) { + r *= safmx2; + } + } else if (scale <= safmn2) { + count = 0; + while(scale <= safmn2) { + ++count; + f1 *= safmx2; + g1 *= safmx2; + scale = max(Math.abs(f1),Math.abs(g1)); + } + r = Math.sqrt(f1*f1 + g1*g1); + cs = f1 / r; + sn = g1 / r; + i__1 = count; + for (i = 1; i <= count; ++i) { + r *= safmn2; + } + } else { + r = Math.sqrt(f1*f1 + g1*g1); + cs = f1 / r; + sn = g1 / r; + } + if (Math.abs(f) > Math.abs(g) && cs < 0.) { + cs = -cs; + sn = -sn; + r = -r; + } + } + sin[index] = sn; + cos[index] = cs; + return r; + + } + + static final private double max3( double[] values) { + if( values[0] > values[1] ) { + if( values[0] > values[2] ) + return(values[0]); + else + return(values[2]); + } else { + if( values[1] > values[2] ) + return(values[1]); + else + return(values[2]); + } + } + + + final private void computeScales(boolean forceSVD) { + + if(scales == null) + scales = new double[3]; + + if ((!forceSVD || ((dirtyBits & SVD_BIT) == 0)) && isAffine()) { + if (isCongruent()) { + if (((dirtyBits & RIGID_BIT) == 0) && + ((type & RIGID) != 0)) { + scales[0] = scales[1] = scales[2] = 1; + dirtyBits &= ~SCALE_BIT; + return; + } + scales[0] = scales[1] = scales[2] = + Math.sqrt(mat[0]*mat[0] + mat[4]*mat[4] + + mat[8]*mat[8]); + dirtyBits &= ~SCALE_BIT; + return; + } + if (isOrtho()) { + scales[0] = Math.sqrt(mat[0]*mat[0] + mat[4]*mat[4] + + mat[8]*mat[8]); + scales[1] = Math.sqrt(mat[1]*mat[1] + mat[5]*mat[5] + + mat[9]*mat[9]); + scales[2] = Math.sqrt(mat[2]*mat[2] + mat[6]*mat[6] + + mat[10]*mat[10]); + dirtyBits &= ~SCALE_BIT; + return; + } + } + // fall back to use SVD decomposition + if (rot == null) + rot = new double[9]; + + compute_svd(this, scales, rot); + dirtyBits &= ~ROTSCALESVD_DIRTY; + } + + final private void computeScaleRotation(boolean forceSVD) { + + if(rot == null) + rot = new double[9]; + + if(scales == null) + scales = new double[3]; + + if ((!forceSVD || ((dirtyBits & SVD_BIT) == 0)) && isAffine()) { + if (isCongruent()) { + if (((dirtyBits & RIGID_BIT) == 0) && + ((type & RIGID) != 0)) { + rot[0] = mat[0]; + rot[1] = mat[1]; + rot[2] = mat[2]; + rot[3] = mat[4]; + rot[4] = mat[5]; + rot[5] = mat[6]; + rot[6] = mat[8]; + rot[7] = mat[9]; + rot[8] = mat[10]; + scales[0] = scales[1] = scales[2] = 1; + dirtyBits &= (~ROTATION_BIT | ~SCALE_BIT); + return; + } + double s = Math.sqrt(mat[0]*mat[0] + mat[4]*mat[4] + mat[8]*mat[8]); + if (s == 0) { + compute_svd(this, scales, rot); + return; + } + scales[0] = scales[1] = scales[2] = s; + s = 1/s; + rot[0] = mat[0]*s; + rot[1] = mat[1]*s; + rot[2] = mat[2]*s; + rot[3] = mat[4]*s; + rot[4] = mat[5]*s; + rot[5] = mat[6]*s; + rot[6] = mat[8]*s; + rot[7] = mat[9]*s; + rot[8] = mat[10]*s; + dirtyBits &= (~ROTATION_BIT | ~SCALE_BIT); + return; + } + if (isOrtho()) { + double s; + + scales[0] = Math.sqrt(mat[0]*mat[0] + mat[4]*mat[4] + mat[8]*mat[8]); + scales[1] = Math.sqrt(mat[1]*mat[1] + mat[5]*mat[5] + mat[9]*mat[9]); + scales[2] = Math.sqrt(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10]); + + if ((scales[0] == 0) || (scales[1] == 0) || (scales[2] == 0)) { + compute_svd(this, scales, rot); + return; + } + s = 1/scales[0]; + rot[0] = mat[0]*s; + rot[3] = mat[4]*s; + rot[6] = mat[8]*s; + s = 1/scales[1]; + rot[1] = mat[1]*s; + rot[4] = mat[5]*s; + rot[7] = mat[9]*s; + s = 1/scales[2]; + rot[2] = mat[2]*s; + rot[5] = mat[6]*s; + rot[8] = mat[10]*s; + dirtyBits &= (~ROTATION_BIT | ~SCALE_BIT); + return; + } + } + // fall back to use SVD decomposition + compute_svd(this, scales, rot); + dirtyBits &= ~ROTSCALESVD_DIRTY; + } + + + final void getRotation(Transform3D t) { + if ((dirtyBits & ROTATION_BIT)!= 0) { + computeScaleRotation(false); + } + + t.mat[3] = t.mat[7] = t.mat[11] = t.mat[12] = t.mat[13] = + t.mat[14] = 0; + t.mat[15] = 1; + t.mat[0] = rot[0]; + t.mat[1] = rot[1]; + t.mat[2] = rot[2]; + t.mat[4] = rot[3]; + t.mat[5] = rot[4]; + t.mat[6] = rot[5]; + t.mat[8] = rot[6]; + t.mat[9] = rot[7]; + t.mat[10] = rot[8]; + + // Issue 253: set all dirty bits + t.dirtyBits = ALL_DIRTY; + } + + // somehow CanvasViewCache will directly modify mat[] + // instead of calling ortho(). So we need to reset dirty bit + final void setOrthoDirtyBit() { + // Issue 253: set all dirty bits + dirtyBits = ALL_DIRTY; + type = 0; + } + + // Fix for Issue 167 -- don't classify matrices with Infinity or NaN values + // as affine + private final boolean isInfOrNaN() { + // The following is a faster version of the check. + // Instead of 3 tests per array element (Double.isInfinite is 2 tests), + // for a total of 48 tests, we will do 16 multiplies and 1 test. + double d = 0.0; + for (int i = 0; i < 16; i++) { + d *= mat[i]; + } + + return d != 0.0; + } + + // Fix for Issue 253 + // Methods to check input parameters for Infinity or NaN values + private final boolean isInfOrNaN(Quat4f q) { + return (Float.isNaN(q.x) || Float.isInfinite(q.x) || + Float.isNaN(q.y) || Float.isInfinite(q.y) || + Float.isNaN(q.z) || Float.isInfinite(q.z) || + Float.isNaN(q.w) || Float.isInfinite(q.w)); + } + + private boolean isInfOrNaN(Quat4d q) { + return (Double.isNaN(q.x) || Double.isInfinite(q.x) || + Double.isNaN(q.y) || Double.isInfinite(q.y) || + Double.isNaN(q.z) || Double.isInfinite(q.z) || + Double.isNaN(q.w) || Double.isInfinite(q.w)); + } + + private boolean isInfOrNaN(AxisAngle4f a) { + return (Float.isNaN(a.x) || Float.isInfinite(a.x) || + Float.isNaN(a.y) || Float.isInfinite(a.y) || + Float.isNaN(a.z) || Float.isInfinite(a.z) || + Float.isNaN(a.angle) || Float.isInfinite(a.angle)); + } + + private boolean isInfOrNaN(AxisAngle4d a) { + return (Double.isNaN(a.x) || Double.isInfinite(a.x) || + Double.isNaN(a.y) || Double.isInfinite(a.y) || + Double.isNaN(a.z) || Double.isInfinite(a.z) || + Double.isNaN(a.angle) || Double.isInfinite(a.angle)); + } + + private boolean isInfOrNaN(double val) { + return Double.isNaN(val) || Double.isInfinite(val); + } + + private boolean isInfOrNaN(Vector3f v) { + return (Float.isNaN(v.x) || Float.isInfinite(v.x) || + Float.isNaN(v.y) || Float.isInfinite(v.y) || + Float.isNaN(v.z) || Float.isInfinite(v.z)); + } + + private boolean isInfOrNaN(Vector3d v) { + return (Double.isNaN(v.x) || Double.isInfinite(v.x) || + Double.isNaN(v.y) || Double.isInfinite(v.y) || + Double.isNaN(v.z) || Double.isInfinite(v.z)); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TransformGroup.java b/j3d-core/src/classes/share/javax/media/j3d/TransformGroup.java new file mode 100644 index 0000000..f460f2a --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TransformGroup.java @@ -0,0 +1,208 @@ +/* + * $RCSfile: TransformGroup.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Group node that contains a transform. The TransformGroup node + * specifies a single spatial transformation, via a Transform3D + * object, that can position, orient, and scale all of its children. + *

+ * The specified transformation must be affine. Further, if the + * TransformGroup node is used as an ancestor of a ViewPlatform node + * in the scene graph, the transformation must be congruent-only + * rotations, translations, and uniform scales are allowed in + * a direct path from a Locale to a ViewPlatform node. + *

+ * Note: Even though arbitrary affine transformations are + * allowed, better performance will result if all matrices + * within a branch graph are congruent, containing only rotations + * translation, and uniform scale. + *

+ * The effects of transformations in the scene graph are cumulative. + * The concatenation of the transformations of each TransformGroup in + * a direct path from the Locale to a Leaf node defines a composite + * model transformation (CMT) that takes points in that Leaf node's + * local coordinates and transforms them into Virtual World (Vworld) + * coordinates. This composite transformation is used to + * transform points, normals, and distances into Vworld coordinates. + * Points are transformed by the CMT. Normals are transformed by the + * inverse-transpose of the CMT. Distances are transformed by the scale + * of the CMT. In the case of a transformation containing a nonuniform + * scale or shear, the maximum scale value in + * any direction is used. This ensures, for example, that a transformed + * bounding sphere, which is specified as a point and a radius, + * continues to enclose all objects that are also transformed using + * a nonuniform scale. + *

+ */ + +public class TransformGroup extends Group { + /** + * Specifies that the node allows access to + * its object's transform information. + */ + public static final int + ALLOW_TRANSFORM_READ = CapabilityBits.TRANSFORM_GROUP_ALLOW_TRANSFORM_READ; + + /** + * Specifies that the node allows writing + * its object's transform information. + */ + public static final int + ALLOW_TRANSFORM_WRITE = CapabilityBits.TRANSFORM_GROUP_ALLOW_TRANSFORM_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_TRANSFORM_READ + }; + + /** + * Constructs and initializes a TransformGroup using an + * identity transform. + */ + public TransformGroup() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Constructs and initializes a TransformGroup from + * the Transform passed. + * @param t1 the transform3D object + * @exception BadTransformException if the transform is not affine. + */ + public TransformGroup(Transform3D t1) { + if (!t1.isAffine()) { + throw new BadTransformException(J3dI18N.getString("TransformGroup0")); + } + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TransformGroupRetained)this.retained).setTransform(t1); + } + + /** + * Creates the retained mode TransformGroupRetained object that this + * TransformGroup object will point to. + */ + void createRetained() { + this.retained = new TransformGroupRetained(); + this.retained.setSource(this); + } + + /** + * Sets the transform component of this TransformGroup to the value of + * the passed transform. + * @param t1 the transform to be copied + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception BadTransformException if the transform is not affine. + */ + public void setTransform(Transform3D t1) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TRANSFORM_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TransformGroup1")); + + if (!t1.isAffine()) { + throw new BadTransformException(J3dI18N.getString("TransformGroup0")); + } + + ((TransformGroupRetained)this.retained).setTransform(t1); + } + + /** + * Copies the transform component of this TransformGroup into + * the passed transform object. + * @param t1 the transform object to be copied into + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void getTransform(Transform3D t1) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_TRANSFORM_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TransformGroup2")); + + ((TransformGroupRetained)this.retained).getTransform(t1); + } + + + /** + * Creates a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + TransformGroup tg = new TransformGroup(); + tg.duplicateNode(this, forceDuplicate); + return tg; + } + + + /** + * Copies all TransformGroup information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + Transform3D t = new Transform3D(); + ((TransformGroupRetained) originalNode.retained).getTransform(t); + ((TransformGroupRetained) retained).setTransform(t); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TransformGroupData.java b/j3d-core/src/classes/share/javax/media/j3d/TransformGroupData.java new file mode 100644 index 0000000..8a43499 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TransformGroupData.java @@ -0,0 +1,42 @@ +/* + * $RCSfile: TransformGroupData.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +class TransformGroupData extends NodeData { + // per path node data + // XXXX: replace per path mirror objects with node data + // XXXX: move other TransfromGroup related data here + boolean switchDirty = false; + + // use for eliminate multiple updates and generate unique targets + boolean markedDirty = false; +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TransformGroupRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TransformGroupRetained.java new file mode 100644 index 0000000..98c5fa9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TransformGroupRetained.java @@ -0,0 +1,1259 @@ +/* + * $RCSfile: TransformGroupRetained.java,v $ + * + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.13 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * Group node that contains a transform. + */ + +class TransformGroupRetained extends GroupRetained implements TargetsInterface +{ + + /** + * The Transform value for the TransformGroup. + */ + Transform3D transform = new Transform3D(); + + /** + * The inverse of the transform + */ + Transform3D invTransform = null; + + /** + * The transpose of the inverse of the transform + */ + Transform3D normalTransform = null; + + /** + * The Transform value currently being used internally + */ + Transform3D currentTransform = new Transform3D(); + + /** + * localVworld values for children of this TG + */ + Transform3D[][] childLocalToVworld = null; + int[][] childLocalToVworldIndex = null; + + // working variable for children transforms + Transform3D[][] childTrans = null; + int[][] childTransIndex = null; + + + /** + * A bitmask of the types in targets + */ + int localTargetThreads = 0; + + // combined localTargetThreads and decendants' localTargetThreads + int targetThreads = 0; + + /** + * A list of WakeupOnTransformChange conditions for this Transform + */ + WakeupIndexedList transformChange = null; + + // The current list of child transform group nodes or link nodes + // under a transform group + ArrayList childTransformLinks = new ArrayList(1); + + // working area while compile + boolean needNormalsTransform = false; // true if normals transformation + // is needed to push this + // transform down to geometry + + // key which identifies a unique path from a + // locale to this transform group + HashKey currentKey = new HashKey(); + + boolean aboveAViewPlatform = false; + + // maximum transform level of all shared path + int maxTransformLevel = -1; + + // List of transform level, one per shared path + int transformLevels[] = null; + + // J3d copy. + CachedTargets[] j3dCTs = null; + + // User copy. + CachedTargets[] cachedTargets = null; + + // Contains per path data, XXXX: move to NodeRetained + TransformGroupData[] perPathData = null; + + + /** + * The constructor + */ + TransformGroupRetained() { + this.nodeType = NodeRetained.TRANSFORMGROUP; + } + + /** + * Sets the transform component of this TransformGroup to the value of + * the passed transform. + * @param t1 the transform to be copied + */ + void setTransform(Transform3D t1) { + J3dMessage tchangeMessage = null; + int i, j; + Transform3D trans = null; + + if (staticTransform != null) { + // this writeable transformGroup has a static transform + // merged into this node + + trans = new Transform3D(staticTransform.transform); + trans.mul(t1); + + transform.setWithLock(trans); + + } else { + trans = new Transform3D(t1); + transform.setWithLock(t1); + } + + if (transformChange != null) { + notifyConditions(); + } + + if (source.isLive()) { + + if (aboveAViewPlatform && !t1.isCongruent()) { + throw new BadTransformException(J3dI18N.getString("ViewPlatformRetained0")); + } + + tchangeMessage = new J3dMessage(); + tchangeMessage.type = J3dMessage.TRANSFORM_CHANGED; + tchangeMessage.threads = targetThreads; + tchangeMessage.args[1] = this; + tchangeMessage.args[2] = trans; + + tchangeMessage.universe = universe; + //System.err.println("TransformGroupRetained --- TRANSFORM_CHANGED " + this); + VirtualUniverse.mc.processMessage(tchangeMessage); + } + dirtyBoundsCache(); + } + + /** + * Copies the transform component of this TransformGroup into + * the passed transform object. + * @param t1 the transform object to be copied into + */ + void getTransform(Transform3D t1) { + transform.getWithLock(t1); + + // if staticTransform exists for this node, need to + // redetermine the original user specified transform + + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + t1.mul(invTransform, t1); + } + } + + + // get the inverse of the transform -- note: this method only + // supports static transform + + Transform3D getInvTransform() { + if (invTransform == null) { + invTransform = new Transform3D(transform); + invTransform.invert(); + } + return invTransform; + } + + + // get the inverse of the transpose -- note: this method only + // supports static transform, the translation component will + // not transform + Transform3D getNormalTransform() { + if (normalTransform == null) { + normalTransform = new Transform3D(transform); + normalTransform.invert(); + normalTransform.transpose(); + } + return normalTransform; + } + + // synchronized with TransformStructure + synchronized void setNodeData(SetLiveState s) { + int i; + + super.setNodeData(s); + + childTrans = new Transform3D[s.currentTransforms.length][2]; + childTransIndex = new int[s.currentTransforms.length][2]; + + for (i=0; i< s.currentTransforms.length; i++) { + childTrans[i][0] = new Transform3D(); + + childTrans[i][0].mul(s.currentTransforms[i] + [s.currentTransformsIndex[i] + [CURRENT_LOCAL_TO_VWORLD]], currentTransform); + childTrans[i][1] = new Transform3D(childTrans[i][0]); + childTransIndex[i][0] = 0; + childTransIndex[i][1] = 0; + + } + + if (!s.inSharedGroup) { + s.transformLevels[0] += 1; + maxTransformLevel = s.transformLevels[0]; + } else { + for (i=0; i maxTransformLevel) { + maxTransformLevel = s.transformLevels[i]; + } + } + } + + if (!inSharedGroup) { + if (childLocalToVworld == null) { + // If the node is a transformGroup then need to keep + // the child transforms as well + childLocalToVworld = new Transform3D[1][]; + childLocalToVworldIndex = new int[1][]; + transformLevels = new int[1]; + // Use by TransformStructure + cachedTargets = new CachedTargets[1]; + perPathData = new TransformGroupData[1]; + } + childLocalToVworld[0] = childTrans[0]; + childLocalToVworldIndex[0] = childTransIndex[0]; + transformLevels[0] = s.transformLevels[0]; + + setAuxData(s, 0, 0); + } else { + + // For inSharedGroup case. + int j, len; + + if (childLocalToVworld == null) { + childLocalToVworld = new Transform3D[s.keys.length][]; + childLocalToVworldIndex = new int[s.keys.length][]; + transformLevels = new int[s.keys.length]; + cachedTargets = new CachedTargets[s.keys.length]; + perPathData = new TransformGroupData[s.keys.length]; + len=0; + } else { + + len = localToVworld.length - s.keys.length; + + int newLen = localToVworld.length; + + Transform3D newChildTList[][] = new Transform3D[newLen][]; + int newChildIndexList[][] = new int[newLen][]; + int newTransformLevels[] = new int[newLen]; + CachedTargets newTargets[] = new CachedTargets[newLen]; + TransformGroupData newPerPathData[] = new TransformGroupData[newLen]; + + System.arraycopy(childLocalToVworld, 0, + newChildTList, 0, childLocalToVworld.length); + System.arraycopy(childLocalToVworldIndex, 0, + newChildIndexList, 0, childLocalToVworldIndex.length); + System.arraycopy(transformLevels, 0, + newTransformLevels, 0, transformLevels.length); + + System.arraycopy(cachedTargets, 0, + newTargets, 0, cachedTargets.length); + + System.arraycopy(perPathData, 0, + newPerPathData, 0, perPathData.length); + + childLocalToVworld = newChildTList; + childLocalToVworldIndex = newChildIndexList; + transformLevels = newTransformLevels; + cachedTargets = newTargets; + perPathData = newPerPathData; + } + + int hkIndex; + int hkIndexPlus1, blkSize; + + for(i=len, j=0; i= i) { // Append to last. + childLocalToVworld[i] = childTrans[j]; + childLocalToVworldIndex[i] = childTransIndex[j]; + transformLevels[i] = s.transformLevels[j]; + } else { + hkIndexPlus1 = hkIndex + 1; + blkSize = i - hkIndex; + + System.arraycopy(childLocalToVworld, hkIndex, + childLocalToVworld, hkIndexPlus1, blkSize); + + System.arraycopy(childLocalToVworldIndex, hkIndex, + childLocalToVworldIndex, hkIndexPlus1, blkSize); + + System.arraycopy(transformLevels, hkIndex, + transformLevels, hkIndexPlus1, blkSize); + + System.arraycopy(cachedTargets, hkIndex, + cachedTargets, hkIndexPlus1, blkSize); + + System.arraycopy(perPathData, hkIndex, + perPathData, hkIndexPlus1, blkSize); + + childLocalToVworld[hkIndex] = childTrans[j]; + childLocalToVworldIndex[hkIndex] = childTransIndex[j]; + transformLevels[hkIndex] = s.transformLevels[j]; + } + + setAuxData(s, j, hkIndex); + } + } + if (s.childTransformLinks != null) { + // do not duplicate shared nodes + synchronized(s.childTransformLinks) { + if(!inSharedGroup || !s.childTransformLinks.contains(this)) { + s.childTransformLinks.add(this); + } + } + } + + s.localToVworld = childLocalToVworld; + s.localToVworldIndex = childLocalToVworldIndex; + s.currentTransforms = childTrans; + s.currentTransformsIndex = childTransIndex; + + s.childTransformLinks = childTransformLinks; + s.parentTransformLink = this; + } + + void setAuxData(SetLiveState s, int index, int hkIndex) { + super.setAuxData(s, index, hkIndex); + perPathData[hkIndex] = new TransformGroupData(); + perPathData[hkIndex].switchState = + (SwitchState)s.switchStates.get(hkIndex); + } + + + // Add a WakeupOnTransformChange to the list + void removeCondition(WakeupOnTransformChange wakeup) { + synchronized (transformChange) { + transformChange.remove(wakeup); + } + } + + // Add a WakeupOnTransformChange to the list + void addCondition(WakeupOnTransformChange wakeup) { + synchronized (transformChange) { + transformChange.add(wakeup); + } + } + + void notifyConditions() { + synchronized (transformChange) { + WakeupOnTransformChange list[] = (WakeupOnTransformChange []) + transformChange.toArray(false); + for (int i=transformChange.size()-1; i >=0; i--) { + list[i].setTriggered(); + } + } + } + + boolean isStatic() { + if (!super.isStatic() || + source.getCapability(TransformGroup.ALLOW_TRANSFORM_READ) || + source.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)) { + return false; + } else { + return true; + } + } + + void mergeTransform(TransformGroupRetained xform) { + super.mergeTransform(xform); + transform.mul(xform.transform, transform); + } + + void traverse(boolean sameLevel, int level) { + + System.err.println(); + for (int i = 0; i < level; i++) { + System.err.print("."); + } + System.err.print(this); + + if (isStatic()) { + System.err.print(" (s)"); + } else { + System.err.print(" (w)"); + } + System.err.println(); + System.err.println(transform.toString()); + super.traverse(true, level); + } + + void compile(CompileState compState) { + + // save and reset the keepTG and needNormalsTransform flags + + boolean saveKeepTG = compState.keepTG; + compState.keepTG = false; + + boolean saveNeedNormalsTransform = compState.needNormalsTransform; + compState.needNormalsTransform = false; + + super.compile(compState); + + if (compState.keepTG) { + // keep this transform group, don't merge it + + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + } + + if (J3dDebug.devPhase && J3dDebug.debug) { + compState.numTransformGroups++; + if (isStatic()) + compState.numStaticTransformGroups++; + if (mergeFlag == SceneGraphObjectRetained.MERGE) + compState.numMergedTransformGroups++; + } + + if (mergeFlag == SceneGraphObjectRetained.DONT_MERGE) { + // a non-mergeable TG will trigger a merge of its subtree + + compState.staticTransform = null; + compState.parentGroup = null; + super.merge(compState); + + } else { + // flag this TG as to be merged later on + mergeFlag = SceneGraphObjectRetained.MERGE; + } + + // restore compile state + compState.keepTG = saveKeepTG; + this.needNormalsTransform = compState.needNormalsTransform; + compState.needNormalsTransform = saveNeedNormalsTransform; + } + + void merge(CompileState compState) { + + TransformGroupRetained saveStaticTransform; + + // merge the transforms + if (compState.staticTransform != null) { + staticTransform = compState.staticTransform; + mergeTransform(compState.staticTransform); + } + + if (mergeFlag == SceneGraphObjectRetained.MERGE) { + + // before we push down the static transform, check + // to see if the transform will be pushed down to shapes + // with geometry_with_normals and if so, check if + // the normal transform has uniform scale or not. If + // it doesn't, don't push it down. + + if (this.needNormalsTransform) { + Transform3D normalXform = this.getNormalTransform(); + if (!normalXform.isCongruent()) { + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + } + } + } + + if (mergeFlag == SceneGraphObjectRetained.MERGE) { + saveStaticTransform = compState.staticTransform; + compState.staticTransform = this; + + // go to the merge method of the group node to start + // pushing down the static transform until it hits + // a leaf or a subtree which is already merged. + super.merge(compState); + + // reset the compile state + compState.staticTransform = saveStaticTransform; + + } else { + compState.parentGroup.compiledChildrenList.add(this); + parent = compState.parentGroup; + } + + mergeFlag = SceneGraphObjectRetained.MERGE_DONE; + } + + /** + * This setlive simply concatinates it's transform onto all the ones + * passed in. + */ + void setLive(SetLiveState s) { + int i,j; + Transform3D trans = null; + Targets[] newTargets = null; + Targets[] savedTransformTargets = null; + int oldTraverseFlags = 0; + int len; + Object obj; + + // XXXX - optimization for targetThreads computation, require + // cleanup in GroupRetained.doSetLive() + //int savedTargetThreads = 0; + //savedTargetThreads = s.transformTargetThreads; + //s.transformTargetThreads = 0; + + oldTraverseFlags = s.traverseFlags; + + savedTransformTargets = s.transformTargets; + + int numPaths = (s.inSharedGroup)? s.keys.length : 1; + newTargets = new Targets[numPaths]; + for(i=0; i= 0) { + found = true; + + if(index == curStart) { + curStart++; + } + else { + len = index - curStart; + System.arraycopy(childLocalToVworld, curStart, newChildTList, + newStart, len); + System.arraycopy(childLocalToVworldIndex, curStart, newChildIndexList, + newStart, len); + System.arraycopy(transformLevels, curStart, newTransformLevels, + newStart, len); + System.arraycopy(cachedTargets, curStart, newTargets, newStart, len); + System.arraycopy(perPathData, curStart, + newPerPathData, newStart, len); + + curStart = index+1; + newStart = newStart + len; + } + } + else { + found = false; + MasterControl.getCoreLogger().severe("TG.removeNodeData-Can't find matching hashKey."); + } + } + + if((found == true) && (curStart < localToVworld.length)) { + len = localToVworld.length - curStart; + System.arraycopy(childLocalToVworld, curStart, newChildTList, + newStart, len); + System.arraycopy(childLocalToVworldIndex, curStart, newChildIndexList, + newStart, len); + System.arraycopy(transformLevels, curStart, newTransformLevels, + newStart, len); + System.arraycopy(cachedTargets, curStart, newTargets, newStart, len); + System.arraycopy(perPathData, curStart, + newPerPathData, newStart, len); + } + + childLocalToVworld = newChildTList; + childLocalToVworldIndex = newChildIndexList; + transformLevels = newTransformLevels; + cachedTargets = newTargets; + perPathData = newPerPathData; + } + super.removeNodeData(s); + // Set it back to its parent localToVworld data. + // This is b/c the parent has changed it localToVworld data arrays. + s.localToVworld = childLocalToVworld; + s.localToVworldIndex = childLocalToVworldIndex; + } + } + + void clearLive(SetLiveState s) { + + Targets[] savedTransformTargets = null; + + savedTransformTargets = s.transformTargets; + // no need to gather targets from tg in clear live + s.transformTargets = null; + + super.clearLive(s); + + // restore setLiveState from it's local variables. + // removeNodeData has altered these variables. + s.localToVworld = localToVworld; + s.localToVworldIndex = localToVworldIndex; + s.transformTargets = savedTransformTargets; + + synchronized (this) { // synchronized with TransformStructure + if (inSharedGroup) { + if (transformLevels != null) { + maxTransformLevel = transformLevels[0]; + for (int i=1; i maxTransformLevel) { + maxTransformLevel = transformLevels[i]; + } + } + } else { + maxTransformLevel = -1; + } + + if (s.switchTargets != null) { + for (int i=0; i=0; i--) { + child = (NodeRetained)children.get(i); + if(child != null) + child.computeCombineBounds(boundingObject); + } + + if (VirtualUniverse.mc.cacheAutoComputedBounds) { + cachedBounds = (Bounds) boundingObject.clone(); + } + } + else { + // Should this be lock too ? ( MT safe ? ) + synchronized(localBounds) { + boundingObject.set(localBounds); + } + } + + // Should this be lock too ? ( MT safe ? ) + // Thoughts : + // Make a temp copy with lock : transform.getWithLock(trans);, but this will cause gc ... + synchronized(transform) { + boundingObject.transform(transform); + } + bounds.combine(boundingObject); + + } + + void processChildLocalToVworld(ArrayList dirtyTransformGroups, + ArrayList keySet, + UpdateTargets targets, + ArrayList blUsers) { + + synchronized(this) { // sync with setLive/clearLive + + if (inSharedGroup) { + if (localToVworldKeys != null) { + for(int j=0; j= 0) { + return childLocalToVworld[i] + [childLocalToVworldIndex[i][NodeRetained.CURRENT_LOCAL_TO_VWORLD]]; + } + } + return new Transform3D(); + } + + + /** + * Get the last child localToVworld transform for a node + */ + Transform3D getLastChildLocalToVworld(HashKey key) { + + if (!inSharedGroup) { + return childLocalToVworld[0][childLocalToVworldIndex[0][NodeRetained.LAST_LOCAL_TO_VWORLD]]; + } else { + int i = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + if(i>= 0) { + return childLocalToVworld[i] + [childLocalToVworldIndex[i][NodeRetained.LAST_LOCAL_TO_VWORLD]]; + } + } + return new Transform3D(); + } + + // **************************** + // TargetsInterface methods + // **************************** + + public int getTargetThreads(int type) { + // type is ignored here, only need for SharedGroup + if (type == TargetsInterface.TRANSFORM_TARGETS) { + return targetThreads; + } else { + System.err.println("getTargetsThreads: wrong arguments"); + return -1; + } + } + + public CachedTargets getCachedTargets(int type, int index, int child) { + // type is ignored here, only need for SharedGroup + // child is ignored here + if (type == TargetsInterface.TRANSFORM_TARGETS) { + return cachedTargets[index]; + } else { + System.err.println("getCachedTargets: wrong arguments"); + return null; + } + } + + TargetsInterface getClosestTargetsInterface(int type) { + return (type == TargetsInterface.TRANSFORM_TARGETS)? + (TargetsInterface)this: + (TargetsInterface)parentSwitchLink; + } + + // re-evalute localTargetThreads using newCachedTargets and + // re-evaluate targetThreads + public void computeTargetThreads(int type, + CachedTargets[] newCachedTargets) { + + // type is ignored here, only need for SharedGroup + if (type == TargetsInterface.TRANSFORM_TARGETS) { + localTargetThreads = J3dThread.UPDATE_TRANSFORM; + + for(int i=0; ioriginalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + TransformInterpolator ti = (TransformInterpolator) originalNode; + + setTransformAxis(ti.getTransformAxis()); + + // this reference will be updated in updateNodeReferences() + setTarget(ti.getTarget()); + } + + /** + * Callback used to allow a node to check if any scene graph objects + * referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any object references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding object in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * object is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + super.updateNodeReferences(referenceTable); + + // check TransformGroup + Node n = getTarget(); + + if (n != null) { + setTarget((TransformGroup) referenceTable.getNewObjectReference(n)); + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TransformStructure.java b/j3d-core/src/classes/share/javax/media/j3d/TransformStructure.java new file mode 100644 index 0000000..5b7dbd4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TransformStructure.java @@ -0,0 +1,759 @@ +/* + * $RCSfile: TransformStructure.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/05/28 15:49:49 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * A transform update is a object that manages TransformGroups + */ + +class TransformStructure extends J3dStructure implements ObjectUpdate { + + /** + * A set of TransformGroups and associated Transform3Ds to traverse + */ + private HashSet transformSet = new HashSet(); + + private ArrayList objectList = new ArrayList(); + + /** + * arraylist of the bounding leaf users affected by the transform + */ + private ArrayList blUsers = new ArrayList(); + + // to gather transform targets + private UpdateTargets targets = new UpdateTargets(); + + /** + * An arrayList of nodes that need collisionBounds updates + */ + private ArrayList collisionObjectList = new ArrayList(); + + // List of dirty TransformGroups + private ArrayList dirtyTransformGroups = new ArrayList(); + + // Associated Keys with the dirtyNodeGroup + private ArrayList keySet = new ArrayList(); + + // the active list contains changed TransformGroup minus those that + // have been switched-off, plus those that have been changed but + // just switched-on + private ArrayList activeTraverseList = + new ArrayList(); + + // contains TG that have been previously changed but just switched-on + private ArrayList switchDirtyTgList = new ArrayList(1); + + private boolean lazyUpdate = false; + + // ArrayList of switches that have changed, use for lastSwitchOn updates + private ArrayList switchChangedList = new ArrayList(); + + // true if already in MasterControl's update object list + private boolean inUpdateObjectList = false; + + /** + * This constructor does nothing + */ + TransformStructure(VirtualUniverse u) { + super(u, J3dThread.UPDATE_TRANSFORM); + } + + void processMessages(long referenceTime) { + J3dMessage[] messages = getMessages(referenceTime); + int nMsg = getNumMessage(); + J3dMessage m; + int i; + + if (nMsg <= 0) { + return; + } + + targets.clearNodes(); + objectList.clear(); + blUsers.clear(); + inUpdateObjectList = false; + + synchronized (universe.sceneGraphLock) { + // first compact the TRANSFORM_CHANGED messages by going + // backwards through the messages + for (i = (nMsg-1); i >= 0; i--) { + m = messages[i]; + if (m.type == J3dMessage.TRANSFORM_CHANGED) { + // Add the TG and associated transform. Since this is a + // set, duplicates will be culled. + transformSet.add(new TransformData((TransformGroupRetained)m.args[1], (Transform3D)m.args[2])); + } + } + + for (i=0; i 0) { + processGeometryAtomVwcBounds(); + } + processVwcBounds(); + } + + // Issue 434: clear references to objects that have been processed + objectList.clear(); + + Arrays.fill(messages, 0, nMsg, null); + } + + void processCurrentLocalToVworld() { + int i, j, tSize, sSize; + TransformGroupRetained tg; + BranchGroupRetained bgr; + Transform3D t; + TransformGroupData data; + + lazyUpdate = false; + + tSize = transformSet.size(); + sSize = switchDirtyTgList.size(); + if (tSize <= 0 && sSize <= 0) { + return; + } + + // process TG with setTransform changes + // update Transform3D, switchDirty and lToVwDrity flags + if (tSize > 0) { + Iterator it = transformSet.iterator(); + while(it.hasNext()) { + TransformData lData = it.next(); + tg = lData.getTransformGroupRetained(); + tg.currentTransform.set(lData.getTransform3D()); + + synchronized(tg) { // synchronized with tg.set/clearLive + if(tg.perPathData != null) { + if (! tg.inSharedGroup) { + data = tg.perPathData[0]; + if (! data.switchState.inSwitch) { + // always add to activetraverseList if not in switch + activeTraverseList.add(tg); + data.markedDirty = true; + data.switchDirty = false; + } else { + // if in switch, add to activetraverseList only if it is + // currently switched on, otherwise, mark it as + // switchDirty + if (data.switchState.currentSwitchOn) { + activeTraverseList.add(tg); + data.switchDirty = false; + data.markedDirty = true; + } else { + data.switchDirty = true; + data.markedDirty = false; + } + } + } else { + int npaths = tg.perPathData.length; + boolean added = false; + + for (int k=0; k 0) { + activeTraverseList.addAll(switchDirtyTgList); + switchDirtyTgList.clear(); + lazyUpdate = true; + } + + // activeTraverseList contains switched-on tg as well + tSize = activeTraverseList.size(); + TransformGroupRetained[] tgs = + (TransformGroupRetained[])activeTraverseList.toArray(new TransformGroupRetained[tSize]); + + // process active TGs + if (tSize > 0) { + + sortTransformGroups(tSize, tgs); + + // update lToVw and gather targets + for (i=0; i0 && + (tgs[j-1].maxTransformLevel > tgs[j].maxTransformLevel); j--) { + TransformGroupRetained tmptg = tgs[j]; + tgs[j] = tgs[j-1]; + tgs[j-1] = tmptg; + } + } + } + + private void quicksort( int l, int r, TransformGroupRetained[] tgs ) { + int i = l; + int j = r; + double k = tgs[(l+r) / 2].maxTransformLevel; + do { + while (tgs[i].maxTransformLevel 0) { + SwitchState switchState; + + for (int i = 0; i < size; i++) { + switchState = (SwitchState)switchChangedList.get(i); + switchState.updateLastSwitchOn(); + } + switchChangedList.clear(); + } + } + + + void processLastLocalToVworld() { + int i, j, k; + TransformGroupRetained tg; + HashKey key; + + + int dTGSize = dirtyTransformGroups.size(); + if (J3dDebug.devPhase && J3dDebug.debug) { + J3dDebug.doDebug(J3dDebug.transformStructure, J3dDebug.LEVEL_5, + "processLastLocalToVworld(): dTGSize= " + dTGSize + "\n"); + } + + for (i=0, k=0; i < dTGSize; i++) { + tg = (TransformGroupRetained)dirtyTransformGroups.get(i); + // Check if the transformGroup is still alive + + // XXXX: This is a hack, should be fixed after EA + // Null pointer checking should be removed! + // should call trans = tg.getCurrentChildLocalToVworld(key); + synchronized(tg) { + if (tg.childLocalToVworld != null) { + if (tg.inSharedGroup) { + key = (HashKey) keySet.get(k++); + for (j=0; j 0) { + // update SwitchState's CurrentSwitchOn flag + SwitchState switchState; + for (int j=0; j + *

    + *
  • Transparency mode - defines how transparency is applied to + * this Appearance component object:
  • + *

      + *
    • FASTEST - uses the fastest available method for transparency.
    • + *

    • NICEST - uses the nicest available method for transparency.
    • + *

    • SCREEN_DOOR - uses screen-door transparency. This is done using + * an on/off stipple pattern in which the percentage of transparent pixels + * is approximately equal to the value specified by the transparency + * parameter.
    • + *

    • BLENDED - uses alpha blended transparency. The blend equation is + * specified by the srcBlendFunction and dstBlendFunction attributes. + * The default equation is: + *
        + * alphasrc*src + + * (1-alphasrc)*dst + *
      + * where alphasrc is + * 1-transparency. + * When this mode is used with a Raster object or with a Geometry + * that contains per-vertex colors with alpha, the alpha values in + * the Raster's image or in the Geometry's per-vertex colors are + * combined with the transparency value in this TransparencyAttributes + * object to perform blending. In this case, the alpha value used for + * blending at each pixel is: + *
        + * alphasrc = + * alphapix * + * (1-transparency). + *
      + *
    • + *

    • NONE - no transparency; opaque object.
    • + *

    + *
  • Transparency value - the amount of transparency to be applied to this + * Appearance component object. The transparency values are in the + * range [0.0, 1.0], with 0.0 being fully opaque and 1.0 being + * fully transparent.
  • + *

  • Blend function - used in blended transparency and antialiasing + * operations. The source function specifies the factor that is + * multiplied by the source color. This value is added to the product + * of the destination factor and the destination color. The default + * source blend function is BLEND_SRC_ALPHA. The source blend function + * is one of the following:
  • + *

      + *
    • BLEND_ZERO - the blend function is f = 0
    • + *
    • BLEND_ONE - the blend function is f = 1
    • + *
    • BLEND_SRC_ALPHA - the blend function is f = + * alphasrc
    • + *
    • BLEND_ONE_MINUS_SRC_ALPHA - the blend function is f = + * 1 - alphasrc
    • + *
    • BLEND_DST_COLOR - the blend function is f = + * colordst
    • + *
    • BLEND_ONE_MINUS_DST_COLOR - the blend function is f = + * 1 - colordst
    • + *
    • BLEND_SRC_COLOR - the blend function is f = + * colorsrc
    • + *
    • BLEND_ONE_MINUS_SRC_COLOR - the blend function is f = + * 1 - colorsrc
    • + *
    + *
+ */ +public class TransparencyAttributes extends NodeComponent { + /** + * Specifies that this TransparencyAttributes object + * allows reading its transparency mode component information. + */ + public static final int + ALLOW_MODE_READ = CapabilityBits.TRANSPARENCY_ATTRIBUTES_ALLOW_MODE_READ; + + /** + * Specifies that this TransparencyAttributes object + * allows writing its transparency mode component information. + */ + public static final int + ALLOW_MODE_WRITE = CapabilityBits.TRANSPARENCY_ATTRIBUTES_ALLOW_MODE_WRITE; + + /** + * Specifies that this TransparencyAttributes object + * allows reading its transparency value. + */ + public static final int + ALLOW_VALUE_READ = CapabilityBits.TRANSPARENCY_ATTRIBUTES_ALLOW_VALUE_READ; + + /** + * Specifies that this TransparencyAttributes object + * allows writing its transparency value. + */ + public static final int + ALLOW_VALUE_WRITE = CapabilityBits.TRANSPARENCY_ATTRIBUTES_ALLOW_VALUE_WRITE; + + /** + * Specifies that this TransparencyAttributes object + * allows reading its blend function. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_BLEND_FUNCTION_READ = + CapabilityBits.TRANSPARENCY_ATTRIBUTES_ALLOW_BLEND_FUNCTION_READ; + + /** + * Specifies that this TransparencyAttributes object + * allows writing its blend function. + * + * @since Java 3D 1.2 + */ + public static final int ALLOW_BLEND_FUNCTION_WRITE = + CapabilityBits.TRANSPARENCY_ATTRIBUTES_ALLOW_BLEND_FUNCTION_WRITE; + + /** + * Use the fastest available method for transparency. + * @see #setTransparencyMode + */ + public static final int FASTEST = 0; + + /** + * Use the nicest available method for transparency. + * @see #setTransparencyMode + */ + public static final int NICEST = 1; + + /** + * Use alpha blended transparency. The blend equation is + * specified by the srcBlendFunction and dstBlendFunction attributes. + * The default equation is: + *
    + * alphasrc*src + + * (1-alphasrc)*dst + *
+ * where alphasrc is + * 1-transparency. + * When this mode is used with a Raster object or with a Geometry + * that contains per-vertex colors with alpha, the alpha values in + * the Raster's image or in the Geometry's per-vertex colors are + * combined with the transparency value in this TransparencyAttributes + * object to perform blending. In this case, the alpha value used for + * blending at each pixel is: + *
    + * alphasrc = + * alphapix * + * (1-transparency). + *
+ * + * @see #setTransparencyMode + * @see #setSrcBlendFunction + * @see #setDstBlendFunction + */ + public static final int BLENDED = 2; + + /** + * Use screen-door transparency. This is done using an on/off stipple + * pattern where the percentage of pixels that are transparent is + * approximately equal to the value specified by the transparency + * parameter. + * @see #setTransparencyMode + */ + public static final int SCREEN_DOOR = 3; + + /** + * No transparency, opaque object. + * @see #setTransparencyMode + */ + public static final int NONE = 4; + + /** + * Blend function: f = 0. + * @see #setSrcBlendFunction + * @see #setDstBlendFunction + * + * @since Java 3D 1.2 + */ + public static final int BLEND_ZERO = 0; + + /** + * Blend function: f = 1. + * @see #setSrcBlendFunction + * @see #setDstBlendFunction + * + * @since Java 3D 1.2 + */ + public static final int BLEND_ONE = 1; + + /** + * Blend function: + * f = alphasrc. + * @see #setSrcBlendFunction + * @see #setDstBlendFunction + * + * @since Java 3D 1.2 + */ + public static final int BLEND_SRC_ALPHA = 2; + + /** + * Blend function: + * f = 1-alphasrc. + * @see #setSrcBlendFunction + * @see #setDstBlendFunction + * + * @since Java 3D 1.2 + */ + public static final int BLEND_ONE_MINUS_SRC_ALPHA = 3; + + /** + * Blend function: + * f = colordst. + *

Note that this function may only be used as a source + * blend function.

+ * @see #setSrcBlendFunction + * + * @since Java 3D 1.4 + */ + public static final int BLEND_DST_COLOR = 4; + + /** + * Blend function: + * f = 1-colordst. + *

Note that this function may only be used as a source + * blend function.

+ * @see #setSrcBlendFunction + * + * @since Java 3D 1.4 + */ + public static final int BLEND_ONE_MINUS_DST_COLOR = 5; + + /** + * Blend function: + * f = colorsrc. + *

Note that this function may only be used as a destination + * blend function.

+ * @see #setDstBlendFunction + * + * @since Java 3D 1.4 + */ + public static final int BLEND_SRC_COLOR = 6; + + /** + * Blend function: + * f = 1-colorsrc. + *

Note that this function may only be used as a destination + * blend function.

+ * @see #setDstBlendFunction + * + * @since Java 3D 1.4 + */ + public static final int BLEND_ONE_MINUS_SRC_COLOR = 7; + + static final int BLEND_CONSTANT_COLOR = 8; + + static final int MAX_BLEND_FUNC_TABLE_SIZE = 9; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_BLEND_FUNCTION_READ, + ALLOW_MODE_READ, + ALLOW_VALUE_READ + }; + + /** + * Constructs a TransparencyAttributes object with default parameters. + * The default values are as follows: + *
    + * transparency mode : NONE
    + * transparency value : 0.0
    + * source blend function : BLEND_SRC_ALPHA
    + * destination blend function : BLEND_ONE_MINUS_SRC_ALPHA
    + *
+ */ + public TransparencyAttributes() { + // Just use the default for all attributes + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Construct TransparencyAttributes object with specified values. + * @param tMode the transparency mode + * @param tVal the transparency value + * @exception IllegalArgumentException if + * tMode is a value other than + * NONE, FASTEST, NICEST, + * SCREEN_DOOR, or BLENDED + * + */ + public TransparencyAttributes(int tMode, float tVal){ + this(tMode, tVal, BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); + } + + /** + * Construct TransparencyAttributes object with specified values. + * @param tMode the transparency mode + * @param tVal the transparency value + * @param srcBlendFunction the blend function to be used for the source + * color, one of BLEND_ZERO, BLEND_ONE, + * BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, + * BLEND_DST_COLOR, or BLEND_ONE_MINUS_DST_COLOR. + * @param dstBlendFunction the blend function to be used for the + * destination + * color, one of BLEND_ZERO, BLEND_ONE, + * BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, + * BLEND_SRC_COLOR, or BLEND_ONE_MINUS_SRC_COLOR. + * @exception IllegalArgumentException if + * tMode is a value other than + * NONE, FASTEST, NICEST, + * SCREEN_DOOR, or BLENDED + * @exception IllegalArgumentException if + * srcBlendFunction or dstBlendFunction + * is a value other than one of the supported functions listed above. + * + * @since Java 3D 1.2 + */ + public TransparencyAttributes(int tMode, + float tVal, + int srcBlendFunction, + int dstBlendFunction) { + if ((tMode < FASTEST) ||(tMode > NONE)) { + throw new IllegalArgumentException(J3dI18N.getString("TransparencyAttributes6")); + } + + switch (srcBlendFunction) { + case BLEND_ZERO: + case BLEND_ONE: + case BLEND_SRC_ALPHA: + case BLEND_ONE_MINUS_SRC_ALPHA: + case BLEND_DST_COLOR: + case BLEND_ONE_MINUS_DST_COLOR: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("TransparencyAttributes7")); + } + + switch (dstBlendFunction) { + case BLEND_ZERO: + case BLEND_ONE: + case BLEND_SRC_ALPHA: + case BLEND_ONE_MINUS_SRC_ALPHA: + case BLEND_SRC_COLOR: + case BLEND_ONE_MINUS_SRC_COLOR: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("TransparencyAttributes8")); + } + + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + + ((TransparencyAttributesRetained)this.retained).initTransparencyMode(tMode); + ((TransparencyAttributesRetained)this.retained).initTransparency(tVal); + ((TransparencyAttributesRetained)this.retained).initSrcBlendFunction(srcBlendFunction); + ((TransparencyAttributesRetained)this.retained).initDstBlendFunction(dstBlendFunction); + } + + /** + * Sets the transparency mode for this + * appearance component object. + * @param transparencyMode the transparency mode to be used, one of + * NONE, FASTEST, NICEST, + * SCREEN_DOOR, or BLENDED + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if + * transparencyMode is a value other than + * NONE, FASTEST, NICEST, + * SCREEN_DOOR, or BLENDED + */ + public void setTransparencyMode(int transparencyMode) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MODE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TransparencyAttributes0")); + + if ((transparencyMode < FASTEST) || (transparencyMode > NONE)) { + throw new IllegalArgumentException(J3dI18N.getString("TransparencyAttributes6")); + } + + if (isLive()) + ((TransparencyAttributesRetained)this.retained).setTransparencyMode(transparencyMode); + else + ((TransparencyAttributesRetained)this.retained).initTransparencyMode(transparencyMode); + } + + + + /** + * Gets the transparency mode for this + * appearance component object. + * @return transparencyMode the transparency mode + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getTransparencyMode() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_MODE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TransparencyAttributes1")); + + return ((TransparencyAttributesRetained)this.retained).getTransparencyMode(); + } + + /** + * Sets this appearance's transparency. + * @param transparency the appearance's transparency + * in the range [0.0, 1.0] with 0.0 being + * fully opaque and 1.0 being fully transparent + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setTransparency(float transparency) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VALUE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TransparencyAttributes2")); + + + if (isLive()) + ((TransparencyAttributesRetained)this.retained).setTransparency(transparency); + else + ((TransparencyAttributesRetained)this.retained).initTransparency(transparency); + + } + + + /** + * Retrieves this appearance's transparency. + * @return the appearance's transparency + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public float getTransparency() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_VALUE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TransparencyAttributes3")); + + return ((TransparencyAttributesRetained)this.retained).getTransparency(); + } + + /** + * Sets the source blend function used in blended transparency + * and antialiasing operations. The source function specifies the + * factor that is multiplied by the source color; this value is + * added to the product of the destination factor and the + * destination color. The default source blend function is + * BLEND_SRC_ALPHA. + * + * @param blendFunction the blend function to be used for the source + * color, one of BLEND_ZERO, BLEND_ONE, + * BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, + * BLEND_DST_COLOR, or BLEND_ONE_MINUS_DST_COLOR. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if blendFunction + * is a value other than one of the supported functions listed above. + * + * @since Java 3D 1.2 + */ + public void setSrcBlendFunction(int blendFunction) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_BLEND_FUNCTION_WRITE)) + throw new + CapabilityNotSetException(J3dI18N.getString("TransparencyAttributes4")); + + switch (blendFunction) { + case BLEND_ZERO: + case BLEND_ONE: + case BLEND_SRC_ALPHA: + case BLEND_ONE_MINUS_SRC_ALPHA: + case BLEND_DST_COLOR: + case BLEND_ONE_MINUS_DST_COLOR: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("TransparencyAttributes7")); + } + + if (isLive()) + ((TransparencyAttributesRetained)this.retained).setSrcBlendFunction(blendFunction); + else + ((TransparencyAttributesRetained)this.retained).initSrcBlendFunction(blendFunction); + } + + + + /** + * Gets the source blend function for this + * TransparencyAttributes object. + * @return the source blend function. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getSrcBlendFunction() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_BLEND_FUNCTION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TransparencyAttributes5")); + return ((TransparencyAttributesRetained)this.retained).getSrcBlendFunction(); + } + + /** + * Sets the destination blend function used in blended transparency + * and antialiasing operations. The destination function specifies the + * factor that is multiplied by the destination color; this value is + * added to the product of the source factor and the + * source color. The default destination blend function is + * BLEND_ONE_MINUS_SRC_ALPHA. + * + * @param blendFunction the blend function to be used for the destination + * color, one of BLEND_ZERO, BLEND_ONE, + * BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, + * BLEND_SRC_COLOR, or BLEND_ONE_MINUS_SRC_COLOR. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception IllegalArgumentException if blendFunction + * is a value other than one of the supported functions listed above. + * + * @since Java 3D 1.2 + */ + public void setDstBlendFunction(int blendFunction) { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_BLEND_FUNCTION_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("TransparencyAttributes4")); + + switch (blendFunction) { + case BLEND_ZERO: + case BLEND_ONE: + case BLEND_SRC_ALPHA: + case BLEND_ONE_MINUS_SRC_ALPHA: + case BLEND_SRC_COLOR: + case BLEND_ONE_MINUS_SRC_COLOR: + break; + default: + throw new IllegalArgumentException(J3dI18N.getString("TransparencyAttributes8")); + } + + if (isLive()) + ((TransparencyAttributesRetained)this.retained).setDstBlendFunction(blendFunction); + else + ((TransparencyAttributesRetained)this.retained).initDstBlendFunction(blendFunction); + } + + + + /** + * Gets the destination blend function for this + * TransparencyAttributes object. + * @return the destination blend function. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.2 + */ + public int getDstBlendFunction() { + if (isLiveOrCompiled()) + if (!this.getCapability(ALLOW_BLEND_FUNCTION_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("TransparencyAttributes5")); + + return ((TransparencyAttributesRetained)this.retained).getDstBlendFunction(); + } + + /** + * Creates a retained mode TransparencyAttributesRetained object that this + * TransparencyAttributes component object will point to. + */ + void createRetained() { + this.retained = new TransparencyAttributesRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + TransparencyAttributes transa = new TransparencyAttributes(); + transa.duplicateNodeComponent(this); + return transa; + } + + + + /** + * Copies all node information from originalNodeComponent into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). + * + * @param originalNodeComponent the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(NodeComponent originalNodeComponent, + boolean forceDuplicate) { + super.duplicateAttributes(originalNodeComponent, forceDuplicate); + + TransparencyAttributesRetained attr = + (TransparencyAttributesRetained) originalNodeComponent.retained; + TransparencyAttributesRetained rt = + (TransparencyAttributesRetained) retained; + + rt.initTransparencyMode(attr.getTransparencyMode()); + rt.initTransparency(attr.getTransparency()); + rt.initSrcBlendFunction(attr.getSrcBlendFunction()); + rt.initDstBlendFunction(attr.getDstBlendFunction()); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TransparencyAttributesRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TransparencyAttributesRetained.java new file mode 100644 index 0000000..6f15b28 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TransparencyAttributesRetained.java @@ -0,0 +1,345 @@ +/* + * $RCSfile: TransparencyAttributesRetained.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.ArrayList; + +/** + * The TransparencyAttributes object defines all attributes affecting + * transparency of the object. + */ +class TransparencyAttributesRetained extends NodeComponentRetained { + // A list of pre-defined bits to indicate which component + // in this TransparencyAttributes object changed. + static final int MODE_CHANGED = 0x01; + static final int VALUE_CHANGED = 0x02; + static final int SRC_BLEND_FUNCTION_CHANGED = 0x04; + static final int DST_BLEND_FUNCTION_CHANGED = 0x08; + + // Integer flag that contains bitset to indicate + // which field changed. + int isDirty = 0xffff; + + // Transparency mode (alpha, screen_door) + int transparencyMode = TransparencyAttributes.NONE; + float transparency = 0.0f; + + // Transparency blend functions + int srcBlendFunction = TransparencyAttributes.BLEND_SRC_ALPHA; + int dstBlendFunction = TransparencyAttributes.BLEND_ONE_MINUS_SRC_ALPHA; + + /** + * Sets the transparency mode for this + * appearance component object. + * @param transparencyMode the transparency mode to be used, one of + * NONE, FASTEST, NICEST, + * SCREEN_DOOR, or BLENDED + */ + final void initTransparencyMode(int transparencyMode) { + this.transparencyMode = transparencyMode; + } + + /** + * Sets the transparency mode for this + * appearance component object and sends a message notifying + * the interested structures of the change. + * @param transparencyMode the transparency mode to be used, one of + * FASTEST, NICEST, + * SCREEN_DOOR, or BLENDED + */ + final void setTransparencyMode(int transparencyMode) { + initTransparencyMode(transparencyMode); + sendMessage(MODE_CHANGED, new Integer(transparencyMode)); + } + + /** + * Gets the transparency mode for this + * appearance component object. + * @return transparencyMode the transparency mode + */ + final int getTransparencyMode() { + return transparencyMode; + } + + /** + * Sets this appearance's transparency. + * @param transparency the appearance's transparency + * in the range [0.0, 1.0] with 0.0 being + * fully opaque and 1.0 being fully transparent + */ + final void initTransparency(float transparency) { + this.transparency = transparency; + } + + /** + * Sets this appearance's transparency and sends a message notifying + * the interested structures of the change. + * @param transparency the appearance's transparency + * in the range [0.0, 1.0] with 0.0 being + * fully opaque and 1.0 being fully transparent + */ + final void setTransparency(float transparency) { + initTransparency(transparency); + sendMessage(VALUE_CHANGED, new Float(transparency)); + } + + /** + * Retrieves this appearance's transparency. + * @return the appearance's transparency + */ + final float getTransparency() { + return this.transparency; + } + + /** + * Sets the source blend function used in blended transparency + * and antialiasing operations. The source function specifies the + * factor that is multiplied by the source color; this value is + * added to the product of the destination factor and the + * destination color. The default source blend function is + * BLEND_SRC_ALPHA. + * + * @param blendFunction the blend function to be used for the source + * color, one of BLEND_ZERO, BLEND_ONE, + * BLEND_SRC_ALPHA, or BLEND_ONE_MINUS_SRC_ALPHA. + */ + final void initSrcBlendFunction(int blendFunction) { + this.srcBlendFunction = blendFunction; + } + + + /** + * Sets the source blend function used in blended transparency + * and antialiasing operations and sends a message notifying the + * interested structures of the change. The source function specifies the + * factor that is multiplied by the source color; this value is + * added to the product of the destination factor and the + * destination color. The default source blend function is + * BLEND_SRC_ALPHA. + * + * @param blendFunction the blend function to be used for the source + * color, one of BLEND_ZERO, BLEND_ONE, + * BLEND_SRC_ALPHA, or BLEND_ONE_MINUS_SRC_ALPHA. + */ + final void setSrcBlendFunction(int blendFunction) { + initSrcBlendFunction(blendFunction); + sendMessage(SRC_BLEND_FUNCTION_CHANGED, new Integer(blendFunction)); + } + + + /** + * Retrieves this appearance's source blend function. + * @return the appearance's source blend function + */ + final int getSrcBlendFunction() { + return srcBlendFunction; + } + + + /** + * Sets the destination blend function used in blended transparency + * and antialiasing operations. The destination function specifies the + * factor that is multiplied by the destination color; this value is + * added to the product of the source factor and the + * source color. The default destination blend function is + * BLEND_ONE_MINUS_SRC_ALPHA. + * + * @param blendFunction the blend function to be used for the destination + * color, one of BLEND_ZERO, BLEND_ONE, + * BLEND_SRC_ALPHA, or BLEND_ONE_MINUS_SRC_ALPHA. + * + */ + final void initDstBlendFunction(int blendFunction) { + this.dstBlendFunction = blendFunction; + } + + + /** + * Sets the destination blend function used in blended transparency + * and antialiasing operations and sends a message notifying the + * interested structures of the change. The destination function + * specifies the factor that is multiplied by the destination + * color; this value is added to the product of the source factor + * and the source color. The default destination blend function is + * BLEND_ONE_MINUS_SRC_ALPHA. + * + * @param blendFunction the blend function to be used for the destination + * color, one of BLEND_ZERO, BLEND_ONE, + * BLEND_SRC_ALPHA, or BLEND_ONE_MINUS_SRC_ALPHA. + */ + final void setDstBlendFunction(int blendFunction) { + initDstBlendFunction(blendFunction); + sendMessage(DST_BLEND_FUNCTION_CHANGED, new Integer(blendFunction)); + } + + + /** + * Retrieves this appearance's destination blend function. + * @return the appearance's destination blend function + */ + final int getDstBlendFunction() { + return dstBlendFunction; + } + + + /** + * Creates and initializes a mirror object, point the mirror object + * to the retained object if the object is not editable + */ + synchronized void createMirrorObject() { + if (mirror == null) { + // Check the capability bits and let the mirror object + // point to itself if is not editable + if (isStatic()) { + mirror = this; + } else { + TransparencyAttributesRetained mirrorTa + = new TransparencyAttributesRetained(); + mirrorTa.source = source; + mirrorTa.set(this); + mirror = mirrorTa; + + } + } else { + ((TransparencyAttributesRetained) mirror).set(this); + } + } + + void updateNative(Context ctx, + float alpha, int geometryType, int polygonMode, + boolean lineAA, + boolean pointAA) { + Pipeline.getPipeline().updateTransparencyAttributes(ctx, alpha, geometryType, polygonMode, + lineAA, pointAA, transparencyMode, + srcBlendFunction, dstBlendFunction); + } + + /** + * Initializes a mirror object, point the mirror object to the retained + * object if the object is not editable + */ + synchronized void initMirrorObject() { + ((TransparencyAttributesRetained)mirror).set(this); + } + + /** + * Update the "component" field of the mirror object with the + * given "value" + */ + synchronized void updateMirrorObject(int component, Object value) { + + TransparencyAttributesRetained mirrorTa = + (TransparencyAttributesRetained) mirror; + + if ((component & MODE_CHANGED) != 0) { + mirrorTa.transparencyMode = ((Integer)value).intValue(); + } + else if ((component & VALUE_CHANGED) != 0) { + mirrorTa.transparency = ((Float)value).floatValue(); + } + else if ((component & SRC_BLEND_FUNCTION_CHANGED) != 0) { + mirrorTa.srcBlendFunction = ((Integer) value).intValue(); + } + else if ((component & DST_BLEND_FUNCTION_CHANGED) != 0) { + mirrorTa.dstBlendFunction = ((Integer) value).intValue(); + } + } + + + boolean equivalent(TransparencyAttributesRetained tr) { + return ((tr != null) && + (tr.transparencyMode == transparencyMode) && + (tr.transparency == transparency) && + (tr.srcBlendFunction == srcBlendFunction) && + (tr.dstBlendFunction == dstBlendFunction)); + } + + protected void set(TransparencyAttributesRetained transp) { + super.set(transp); + transparencyMode = transp.transparencyMode; + transparency = transp.transparency; + srcBlendFunction = transp.srcBlendFunction; + dstBlendFunction = transp.dstBlendFunction; + } + + + + final void sendMessage(int attrMask, Object attr) { + + ArrayList univList = new ArrayList(); + ArrayList gaList = Shape3DRetained.getGeomAtomsList(mirror.users, univList); + + // Send to rendering attribute structure, regardless of + // whether there are users or not (alternate appearance case ..) + J3dMessage createMessage = new J3dMessage(); + createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES; + createMessage.type = J3dMessage.TRANSPARENCYATTRIBUTES_CHANGED; + createMessage.universe = null; + createMessage.args[0] = this; + createMessage.args[1]= new Integer(attrMask); + createMessage.args[2] = attr; + createMessage.args[3] = new Integer(changedFrequent); + VirtualUniverse.mc.processMessage(createMessage); + + + // System.err.println("univList.size is " + univList.size()); + for(int i=0; i + * There are two forms of constructor to specify the + * type of transparency interpolation. The first constructor takes + * an Alpha and a TransparencyAttributes object and creates a transparency + * interpolator that maps an Alpha value of 1.0 to a transparency + * value of 1.0, and an Alpha value of 0.0 and maps it to a + * transparency value of 0.0. The second constructor takes an Alpha, + * a TransparencyAttributes object, a minimum transparency value and a + * maximum transparency value. This constructor provides more + * flexibility by specifying how the Alpha values are mapped + * to the transparency values - an Alpha of 1.0 maps to the + * maximum transparency value and an Alpha of 0.0 maps to the + * minimum transparency value.

+ * + * @see Alpha + * @see TransparencyAttributes + */ + + +public class TransparencyInterpolator extends Interpolator { + + TransparencyAttributes target; + float minimumTransparency; + float maximumTransparency; + + // We can't use a boolean flag since it is possible + // that after alpha change, this procedure only run + // once at alpha.finish(). So the best way is to + // detect alpha value change. + private float prevAlphaValue = Float.NaN; + private WakeupCriterion passiveWakeupCriterion = + (WakeupCriterion) new WakeupOnElapsedFrames(0, true); + + // non-public, default constructor used by cloneNode + TransparencyInterpolator() { + } + + /** + * Constructs a trivial transparency interpolator with a specified target, + * a minimum transparency of 0.0f and a maximum transparency of 1.0f. + * @param alpha the alpha object for this interpolator + * @param target the TransparencyAttributes component object affected + * by this interpolator + */ + public TransparencyInterpolator(Alpha alpha, + TransparencyAttributes target) { + + super(alpha); + + this.target = target; + this.minimumTransparency = 0.0f; + this.maximumTransparency = 1.0f; + } + + /** + * Constructs a new transparency interpolator that varies the target + * material's transparency between the two transparency values. + * @param alpha the alpha object for this Interpolator + * @param target the TransparencyAttributes component object affected + * by this interpolator + * @param minimumTransparency the starting transparency + * @param maximumTransparency the ending transparency + */ + public TransparencyInterpolator(Alpha alpha, + TransparencyAttributes target, + float minimumTransparency, + float maximumTransparency) { + + super(alpha); + + this.target = target; + this.minimumTransparency = minimumTransparency; + this.maximumTransparency = maximumTransparency; + } + + /** + * This method sets the minimumTransparency for this interpolator. + * @param transparency the new minimum transparency + */ + public void setMinimumTransparency(float transparency) { + this.minimumTransparency = transparency; + } + + /** + * This method retrieves this interpolator's minimumTransparency. + * @return the interpolator's minimum transparency value + */ + public float getMinimumTransparency() { + return this.minimumTransparency; + } + + /** + * This method sets the maximumTransparency for this interpolator. + * @param transparency the new maximum transparency + */ + public void setMaximumTransparency(float transparency) { + this.maximumTransparency = transparency; + } + + /** + * This method retrieves this interpolator's maximumTransparency. + * @return the interpolator's maximal transparency vslue + */ + public float getMaximumTransparency() { + return this.maximumTransparency; + } + + /** + * This method sets the target TransparencyAttributes object + * for this interpolator. + * @param target the target TransparencyAttributes object + */ + public void setTarget(TransparencyAttributes target) { + this.target = target; + } + + /** + * This method retrieves this interpolator's target reference. + * @return the interpolator's target TransparencyAttributes object + */ + public TransparencyAttributes getTarget() { + return target; + } + + // The TransparencyInterpolator's initialize routine uses the default + // initialization routine. + + /** + * This method is invoked by the behavior scheduler every frame. It + * maps the alpha value that corresponds to the current time into a + * transparency value and updates the specified TransparencyAttributes + * object with this new transparency value. + * @param criteria an enumeration of the criteria that caused the + * stimulus + */ + public void processStimulus(Enumeration criteria) { + // Handle stimulus + WakeupCriterion criterion = passiveWakeupCriterion; + + if (alpha != null) { + float value = alpha.value(); + + if (value != prevAlphaValue) { + float val = (float)((1.0-value)*minimumTransparency + + value*maximumTransparency); + + target.setTransparency(val); + prevAlphaValue = value; + } + if (!alpha.finished() && !alpha.isPaused()) { + criterion = defaultWakeupCriterion; + } + } + wakeupOn(criterion); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + TransparencyInterpolator ti = new TransparencyInterpolator(); + ti.duplicateNode(this, forceDuplicate); + return ti; + } + + + /** + * Copies all TransparencyInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + TransparencyInterpolator ti = + (TransparencyInterpolator) originalNode; + + setMinimumTransparency(ti.getMinimumTransparency()); + setMaximumTransparency(ti.getMaximumTransparency()); + + // this reference will be updated in updateNodeReferences() + setTarget(ti.getTarget()); + } + + /** + * Callback used to allow a node to check if any nodes referenced + * by that node have been duplicated via a call to cloneTree. + * This method is called by cloneTree after all nodes in + * the sub-graph have been duplicated. The cloned Leaf node's method + * will be called and the Leaf node can then look up any node references + * by using the getNewObjectReference method found in the + * NodeReferenceTable object. If a match is found, a + * reference to the corresponding Node in the newly cloned sub-graph + * is returned. If no corresponding reference is found, either a + * DanglingReferenceException is thrown or a reference to the original + * node is returned depending on the value of the + * allowDanglingReferences parameter passed in the + * cloneTree call. + *

+ * NOTE: Applications should not call this method directly. + * It should only be called by the cloneTree method. + * + * @param referenceTable a NodeReferenceTableObject that contains the + * getNewObjectReference method needed to search for + * new object instances. + * @see NodeReferenceTable + * @see Node#cloneTree + * @see DanglingReferenceException + */ + public void updateNodeReferences(NodeReferenceTable referenceTable) { + super.updateNodeReferences(referenceTable); + + // check TransparencyAttributes + NodeComponent nc = getTarget(); + + if (nc != null) { + setTarget((TransparencyAttributes) referenceTable.getNewObjectReference(nc)); + } + } + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TransparentRenderingInfo.java b/j3d-core/src/classes/share/javax/media/j3d/TransparentRenderingInfo.java new file mode 100644 index 0000000..f3bd8ae --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TransparentRenderingInfo.java @@ -0,0 +1,164 @@ +/* + * $RCSfile: TransparentRenderingInfo.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +class TransparentRenderingInfo extends Object implements com.sun.j3d.utils.scenegraph.transparency.TransparencySortGeom { + // For DepthSortedTransparency, rm is the rendermolecule + // that this rInfo is part of + // For non depth sorted transparency, rm is one of the rendermolecules + // in the textureBin that is rendered, all renderMolecules under + // rm.textureBin's will be rendered + RenderMolecule rm; + RenderAtomListInfo rInfo; + TransparentRenderingInfo prev; + TransparentRenderingInfo next; + GeometryAtom geometryAtom; + double zVal; // Used in DepthSorted Transparency + // XXXX: Add Dirty info + + /** + * update state before rendering transparent objects + */ + boolean updateState(Canvas3D cv) { + + TextureBin textureBin = rm.textureBin; + AttributeBin attributeBin = textureBin.attributeBin; + ShaderBin shaderBin = textureBin.shaderBin; + + // Get a collection to check if switch is on + + RenderMolecule rm = textureBin.transparentRMList ; + + // Optimization to skip updating Attributes if + // all switch are off. Note that switch condition + // is check again in rm.render(). + while (rm != null) { + if (rm.isSwitchOn()) { + break; + } + if (rm.next != null) { + rm = rm.next; + } else { + rm = rm.nextMap; + } + } + + if (rm == null) { + return false; + } + + // XXXX : Code cleanup needed : The following code segment should simply test + // each bin independently and update it if necessary. + if (cv.environmentSet != attributeBin.environmentSet) { + + boolean visible = (attributeBin.definingRenderingAttributes == null || + attributeBin.definingRenderingAttributes.visible); + + if ( (attributeBin.environmentSet.renderBin.view.viewCache.visibilityPolicy + == View.VISIBILITY_DRAW_VISIBLE && !visible) || + (attributeBin.environmentSet.renderBin.view.viewCache.visibilityPolicy + == View.VISIBILITY_DRAW_INVISIBLE && visible)) { + return false; + } + + // Fix to issue 314. Set the appropriate bits for the dirty bins + // and call the update state method. + cv.setStateToUpdate(Canvas3D.LIGHTBIN_BIT, attributeBin.environmentSet.lightBin); + cv.setStateToUpdate(Canvas3D.ENVIRONMENTSET_BIT, attributeBin.environmentSet); + cv.setStateToUpdate(Canvas3D.ATTRIBUTEBIN_BIT, attributeBin); + cv.setStateToUpdate(Canvas3D.SHADERBIN_BIT, shaderBin); + cv.updateEnvState(); + + } else if (cv.attributeBin != attributeBin) { + boolean visible = (attributeBin.definingRenderingAttributes == null || + attributeBin.definingRenderingAttributes.visible); + + if ( (attributeBin.environmentSet.renderBin.view.viewCache.visibilityPolicy + == View.VISIBILITY_DRAW_VISIBLE && !visible) || + (attributeBin.environmentSet.renderBin.view.viewCache.visibilityPolicy + == View.VISIBILITY_DRAW_INVISIBLE && visible)) { + return false; + } + + // Fix to issue 314. Set the appropriate bits for the dirty bins + // and call the update state method. + cv.setStateToUpdate(Canvas3D.ATTRIBUTEBIN_BIT, attributeBin); + cv.setStateToUpdate(Canvas3D.SHADERBIN_BIT, shaderBin); + cv.updateEnvState(); + + } else if (cv.shaderBin != shaderBin) { + + // Fix to issue 314. Set the appropriate bits for the dirty bins + // and call the update state method. + cv.setStateToUpdate(Canvas3D.SHADERBIN_BIT, shaderBin); + cv.updateEnvState(); + + } + + return true; + } + + void render(Canvas3D cv) { + if (updateState(cv)) { + rm.textureBin.render(cv, rm.textureBin.transparentRMList); + } + } + + + void sortRender(Canvas3D cv) { + if (updateState(cv)) { + rm.textureBin.render(cv, this); + } + } + + public double getDistanceSquared() { + return zVal; + } + + public Geometry getGeometry() { + // XXXX: verify 0 is always the correct index. Assumption is that for + // Shape3D with multiple geometry each geometry is put in it's + // own geometryAtom. + if (geometryAtom.geometryArray[0]==null) + return null; + return (Geometry)geometryAtom.geometryArray[0].source; + } + + public void getLocalToVWorld(Transform3D localToVW) { + localToVW.set(rm.localToVworld[NodeRetained.LAST_LOCAL_TO_VWORLD]); + } + + public Shape3D getShape3D() { + return (Shape3D)geometryAtom.source.source; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TriangleArray.java b/j3d-core/src/classes/share/javax/media/j3d/TriangleArray.java new file mode 100644 index 0000000..d682195 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TriangleArray.java @@ -0,0 +1,194 @@ +/* + * $RCSfile: TriangleArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * The TriangleArray object draws the array of vertices as individual + * triangles. Each group + * of three vertices defines a triangle to be drawn. + */ + +public class TriangleArray extends GeometryArray { + + // non-public, no parameter constructor + TriangleArray() {} + + /** + * Constructs an empty TriangleArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 3 + * or vertexCount is not a multiple of 3 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int)} + * for more exceptions that can be thrown + */ + public TriangleArray(int vertexCount, int vertexFormat) { + super(vertexCount,vertexFormat); + + if (vertexCount < 3 || ((vertexCount%3) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("TriangleArray0")); + } + + /** + * Constructs an empty TriangleArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 3 + * or vertexCount is not a multiple of 3 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public TriangleArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap); + + if (vertexCount < 3 || ((vertexCount%3) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("TriangleArray0")); + } + + /** + * Constructs an empty TriangleArray object using the specified + * parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 3 + * or vertexCount is not a multiple of 3 + * ;
+ * See {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public TriangleArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes); + + if (vertexCount < 3 || ((vertexCount%3) != 0)) + throw new IllegalArgumentException(J3dI18N.getString("TriangleArray0")); + } + + + /** + * Creates the retained mode TriangleArrayRetained object that this + * TriangleArray object will point to. + */ + void createRetained() { + this.retained = new TriangleArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + TriangleArrayRetained rt = (TriangleArrayRetained) retained; + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + TriangleArray t = new TriangleArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes); + t.duplicateNodeComponent(this); + return t; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TriangleArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TriangleArrayRetained.java new file mode 100644 index 0000000..2716d5d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TriangleArrayRetained.java @@ -0,0 +1,490 @@ +/* + * $RCSfile: TriangleArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The TriangleArray object draws the array of vertices as individual + * triangles. Each group + * of three vertices defines a triangle to be drawn. + */ + +class TriangleArrayRetained extends GeometryArrayRetained { + + TriangleArrayRetained() { + this.geoType = GEO_TYPE_TRI_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[3]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int[] vtxIndexArr = new int[3]; + + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectRay(pnts, pickRay, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectSegment(pnts, pickSegment.start, + pickSegment.end, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < validVertexCount) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectBoundingPolytope(pnts, bpolytope, + sdist,iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + while (i < validVertexCount) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectCylinder(pnts, pickCylinder, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < validVertexCount) { + for(int j=0; j<3; j++) { + vtxIndexArr[j] = i; + getVertexData(i++, pnts[j]); + } + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("TriangleArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + + boolean intersect(Point3d[] pnts) { + Point3d[] points = new Point3d[3]; + double dist[] = new double[1]; + int i = ((vertexFormat & GeometryArray.BY_REFERENCE) == 0 ? + initialVertexIndex : initialCoordIndex); + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle + while (i + * See {@link GeometryStripArray#GeometryStripArray(int,int,int[])} + * for more exceptions that can be thrown + */ + public TriangleFanArray(int vertexCount, + int vertexFormat, + int stripVertexCounts[]) { + + super(vertexCount, vertexFormat, stripVertexCounts); + + if (vertexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("TriangleFanArray0")); + } + + /** + * Constructs an empty TriangleFanArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param stripVertexCounts + * see {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 3 + * or any element in the stripVertexCounts array is less than 3 + * ;
+ * See {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public TriangleFanArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int stripVertexCounts[]) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + stripVertexCounts); + + if (vertexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("TriangleFanArray0")); + } + + /** + * Constructs an empty TriangleFanArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param stripVertexCounts + * see {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int,int[],int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 3 + * or any element in the stripVertexCounts array is less than 3 + * ;
+ * See {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int,int[],int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public TriangleFanArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int[] stripVertexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + stripVertexCounts); + + if (vertexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("TriangleFanArray0")); + } + + /** + * Creates the retained mode TriangleFanArrayRetained object that this + * TriangleFanArray object will point to. + */ + void createRetained() { + this.retained = new TriangleFanArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + TriangleFanArrayRetained rt = (TriangleFanArrayRetained) retained; + int stripcounts[] = new int[rt.getNumStrips()]; + rt.getStripVertexCounts(stripcounts); + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + TriangleFanArray t = new TriangleFanArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + stripcounts); + t.duplicateNodeComponent(this); + return t; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TriangleFanArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TriangleFanArrayRetained.java new file mode 100644 index 0000000..8006eb9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TriangleFanArrayRetained.java @@ -0,0 +1,596 @@ +/* + * $RCSfile: TriangleFanArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The TriangleFanArray object draws an array of vertices as a set of + * connected triangle fans. An array of per-strip + * vertex counts specifies where the separate strips (fans) appear + * in the vertex array. For every strip in the set, + * each vertex, beginning with the third vertex in the array, + * defines a triangle to be drawn using the current vertex, + * the previous vertex and the first vertex. This can be thought of + * as a collection of convex polygons. + */ + +class TriangleFanArrayRetained extends GeometryStripArrayRetained { + + TriangleFanArrayRetained() { + this.geoType = GEO_TYPE_TRI_FAN_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[3]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int i = 0; + int j, end; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + int[] vtxIndexArr = new int[3]; + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectRay(pnts, pickRay, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectSegment(pnts, pickSegment.start, + pickSegment.end, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectBoundingSphere(pnts, bsphere, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectBoundingPolytope(pnts, bpolytope, + sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("TriangleFanArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + // intersect pnts[] with every triangle in this object + boolean intersect(Point3d[] pnts) { + int j, end; + Point3d[] points = new Point3d[3]; + double dist[] = new double[1]; + int i = 0; + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + + + + switch (pnts.length) { + case 3: // Triangle + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + getVertexData(j++, points[1]); + while (j < end) { + getVertexData(j++, points[2]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2])) { + return true; + } + points[1].set(points[2]); + } + } + break; + case 4: // Quad + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + getVertexData(j++, points[1]); + while (j < end) { + getVertexData(j++, points[2]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[2], pnts[3])) { + return true; + } + points[1].set(points[2]); + } + } + break; + case 2: // Line + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + getVertexData(j++, points[1]); + while (j < end) { + getVertexData(j++, points[2]); + if (intersectSegment(points, pnts[0], pnts[1], + dist, null)) { + return true; + } + points[1].set(points[2]); + } + } + break; + case 1: // Point + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + getVertexData(j++, points[1]); + while (j < end) { + getVertexData(j++, points[2]); + if (intersectTriPnt(points[0], points[1], points[2], + pnts[0])) { + return true; + } + points[1].set(points[2]); + } + } + break; + } + return false; + } + + boolean intersect(Transform3D thisToOtherVworld, GeometryRetained geom) { + int i = 0, j, end; + Point3d[] pnts = new Point3d[3]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + getVertexData(j++, pnts[1]); + thisToOtherVworld.transform(pnts[0]); + thisToOtherVworld.transform(pnts[1]); + while (j < end) { + getVertexData(j++, pnts[2]); + thisToOtherVworld.transform(pnts[2]); + if (geom.intersect(pnts)) { + return true; + } + pnts[1].set(pnts[2]); + } + } + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + int i = 0; + int j, end; + Point3d[] pnts = new Point3d[3]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + getVertexData(j++, pnts[0]); + getVertexData(j++, pnts[1]); + end = j + stripVertexCounts[i++]; + while ( j < end) { + getVertexData(j++, pnts[2]); + if (intersectBoundingBox(pnts, box, null, null)) { + return true; + } + pnts[1].set(pnts[2]); + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + getVertexData(j++, pnts[1]); + while ( j < end) { + getVertexData(j++, pnts[2]); + if (intersectBoundingSphere(pnts, bsphere, null, null)) { + return true; + } + pnts[1].set(pnts[2]); + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + getVertexData(j++, pnts[1]); + while ( j < end) { + getVertexData(j++, pnts[2]); + if (intersectBoundingPolytope(pnts, bpolytope, null, null)) { + return true; + } + pnts[1].set(pnts[2]); + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + return false; + } + + // From Graphics Gems IV (pg5) and Graphics Gems II, Pg170 + void computeCentroid() { + Vector3d vec = new Vector3d(); + Vector3d normal = new Vector3d(); + Vector3d tmpvec = new Vector3d(); + Point3d pnt0 = new Point3d(); + Point3d pnt1 = new Point3d(); + Point3d pnt2 = new Point3d(); + double area, totalarea = 0; + int end, replaceIndex, j, i = 0; + centroid.x = 0; + centroid.y = 0; + centroid.z = 0; + + while( i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnt0); + getVertexData(j++, pnt1); + replaceIndex = 2; + while (j < end) { + area = 0; + if (replaceIndex == 2) { + getVertexData(j++, pnt2); + replaceIndex = 1; + } else { + getVertexData(j++, pnt1); + replaceIndex = 2; + } + + // Determine the normal + vec.sub(pnt0, pnt1); + tmpvec.sub(pnt1, pnt2); + + // Do the cross product + normal.cross(vec, tmpvec); + normal.normalize(); + // If a degenerate triangle, don't include + if (Double.isNaN(normal.x + normal.y + normal.z)) + continue; + + tmpvec.set(0,0,0); + + // compute the area + getCrossValue(pnt0, pnt1, tmpvec); + getCrossValue(pnt1, pnt2, tmpvec); + getCrossValue(pnt2, pnt0, tmpvec); + area = normal.dot(tmpvec); + totalarea += area; + centroid.x += (pnt0.x + pnt1.x + pnt2.x) * area; + centroid.y += (pnt0.y + pnt1.y + pnt2.y) * area; + centroid.z += (pnt0.z + pnt1.z + pnt2.z) * area; + + } + } + + if (totalarea != 0.0) { + area = 1.0/(3.0 * totalarea); + centroid.x *= area; + centroid.y *= area; + centroid.z *= area; + } + } + + int getClassType() { + return TRIANGLE_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TriangleStripArray.java b/j3d-core/src/classes/share/javax/media/j3d/TriangleStripArray.java new file mode 100644 index 0000000..46c6344 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TriangleStripArray.java @@ -0,0 +1,220 @@ +/* + * $RCSfile: TriangleStripArray.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * The TriangleStripArray object draws an array of vertices as a set of + * connected triangle strips. An array of per-strip vertex counts specifies + * where the separate strips appear in the vertex array. + * For every strip in the set, + * each vertex, beginning with the third vertex in the array, + * defines a triangle to be drawn using the current vertex and + * the two previous vertices. + */ + +public class TriangleStripArray extends GeometryStripArray { + + // non-public, no parameter constructor + TriangleStripArray() {} + + /** + * Constructs an empty TriangleStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int)} + * for a description of this parameter. + * + * @param stripVertexCounts + * see {@link GeometryStripArray#GeometryStripArray(int,int,int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 3 + * or any element in the stripVertexCounts array is less than 3 + * ;
+ * See {@link GeometryStripArray#GeometryStripArray(int,int,int[])} + * for more exceptions that can be thrown + */ + public TriangleStripArray(int vertexCount, + int vertexFormat, + int stripVertexCounts[]) { + + super(vertexCount, vertexFormat, stripVertexCounts); + + if (vertexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("TriangleStripArray0")); + } + + /** + * Constructs an empty TriangleStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[])} + * for a description of this parameter. + * + * @param stripVertexCounts + * see {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 3 + * or any element in the stripVertexCounts array is less than 3 + * ;
+ * See {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.2 + */ + public TriangleStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int stripVertexCounts[]) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + stripVertexCounts); + + if (vertexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("TriangleStripArray0")); + } + + /** + * Constructs an empty TriangleStripArray object using the + * specified parameters. + * + * @param vertexCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexFormat + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param texCoordSetMap + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrCount + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param vertexAttrSizes + * see {@link GeometryArray#GeometryArray(int,int,int,int[],int,int[])} + * for a description of this parameter. + * + * @param stripVertexCounts + * see {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int,int[],int[])} + * for a description of this parameter. + * + * @exception IllegalArgumentException if vertexCount is less than 3 + * or any element in the stripVertexCounts array is less than 3 + * ;
+ * See {@link GeometryStripArray#GeometryStripArray(int,int,int,int[],int,int[],int[])} + * for more exceptions that can be thrown + * + * @since Java 3D 1.4 + */ + public TriangleStripArray(int vertexCount, + int vertexFormat, + int texCoordSetCount, + int[] texCoordSetMap, + int vertexAttrCount, + int[] vertexAttrSizes, + int[] stripVertexCounts) { + + super(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap, + vertexAttrCount, vertexAttrSizes, + stripVertexCounts); + + if (vertexCount < 3 ) + throw new IllegalArgumentException(J3dI18N.getString("TriangleStripArray0")); + } + + /** + * Creates the retained mode TriangleStripArrayRetained object that this + * TriangleStripArray object will point to. + */ + void createRetained() { + this.retained = new TriangleStripArrayRetained(); + this.retained.setSource(this); + } + + + /** + * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) + */ + public NodeComponent cloneNodeComponent() { + TriangleStripArrayRetained rt = (TriangleStripArrayRetained) retained; + int stripcounts[] = new int[rt.getNumStrips()]; + rt.getStripVertexCounts(stripcounts); + int texSetCount = rt.getTexCoordSetCount(); + int[] texMap = null; + int vertexAttrCount = rt.getVertexAttrCount(); + int[] vertexAttrSizes = null; + if (texSetCount > 0) { + texMap = new int[rt.getTexCoordSetMapLength()]; + rt.getTexCoordSetMap(texMap); + } + if (vertexAttrCount > 0) { + vertexAttrSizes = new int[vertexAttrCount]; + rt.getVertexAttrSizes(vertexAttrSizes); + } + TriangleStripArray t = new TriangleStripArray(rt.getVertexCount(), + rt.getVertexFormat(), + texSetCount, + texMap, + vertexAttrCount, + vertexAttrSizes, + stripcounts); + t.duplicateNodeComponent(this); + return t; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/TriangleStripArrayRetained.java b/j3d-core/src/classes/share/javax/media/j3d/TriangleStripArrayRetained.java new file mode 100644 index 0000000..925b93d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/TriangleStripArrayRetained.java @@ -0,0 +1,622 @@ +/* + * $RCSfile: TriangleStripArrayRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.lang.Math; + +/** + * The TriangleStripArray object draws an array of vertices as a set of + * connected triangle strips. An array of per-strip vertex counts specifies + * where the separate strips appear in the vertex array. + * For every strip in the set, + * each vertex, beginning with the third vertex in the array, + * defines a triangle to be drawn using the current vertex and + * the two previous vertices. + */ + +class TriangleStripArrayRetained extends GeometryStripArrayRetained { + + TriangleStripArrayRetained() { + this.geoType = GEO_TYPE_TRI_STRIP_SET; + } + + boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, + GeometryRetained geom, int geomIndex) { + Point3d pnts[] = new Point3d[3]; + double sdist[] = new double[1]; + double minDist = Double.MAX_VALUE; + double x = 0, y = 0, z = 0; + int i = 0; + int j, end; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + int[] vtxIndexArr = new int[3]; + + switch (pickShape.getPickType()) { + case PickShape.PICKRAY: + PickRay pickRay= (PickRay) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectRay(pnts, pickRay, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKSEGMENT: + PickSegment pickSegment = (PickSegment) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectSegment(pnts, pickSegment.start, + pickSegment.end, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGBOX: + BoundingBox bbox = (BoundingBox) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectBoundingSphere(pnts, bsphere, sdist, + iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) + ((PickBounds) pickShape).bounds; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectBoundingPolytope(pnts, bpolytope, + sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKCYLINDER: + PickCylinder pickCylinder= (PickCylinder) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKCONE: + PickCone pickCone= (PickCone) pickShape; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + for(int k=0; k<2; k++) { + vtxIndexArr[k] = j; + getVertexData(j++, pnts[k]); + } + while (j < end) { + vtxIndexArr[2] = j; + getVertexData(j++, pnts[2]); + if (intersectCone(pnts, pickCone, sdist, iPnt)) { + if (flags == 0) { + return true; + } + if (sdist[0] < minDist) { + minDist = sdist[0]; + x = iPnt.x; + y = iPnt.y; + z = iPnt.z; + if((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + if((flags & PickInfo.ALL_GEOM_INFO) != 0) { + storeInterestData(pickInfo, flags, geom, geomIndex, + vtxIndexArr, iPnt, sdist[0]); + } + } + pnts[0].set(pnts[1]); + vtxIndexArr[0] = vtxIndexArr[1]; + pnts[1].set(pnts[2]); + vtxIndexArr[1] = vtxIndexArr[2]; + } + } + break; + case PickShape.PICKPOINT: + // Should not happen since API already check for this + throw new IllegalArgumentException(J3dI18N.getString("TriangleStripArrayRetained0")); + default: + throw new RuntimeException ("PickShape not supported for intersection"); + } + + if (minDist < Double.MAX_VALUE) { + iPnt.x = x; + iPnt.y = y; + iPnt.z = z; + return true; + } + return false; + } + + // intersect pnts[] with every triangle in this object + boolean intersect(Point3d[] pnts) { + int j, end; + Point3d[] points = new Point3d[3]; + double dist[] = new double[1]; + int i = 0; + + points[0] = new Point3d(); + points[1] = new Point3d(); + points[2] = new Point3d(); + + switch (pnts.length) { + case 3: // Triangle + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + getVertexData(j++, points[1]); + while (j < end) { + getVertexData(j++, points[2]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2])) { + return true; + } + points[0].set(points[1]); + points[1].set(points[2]); + } + } + break; + case 4: // Quad + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + getVertexData(j++, points[1]); + while (j < end) { + getVertexData(j++, points[2]); + if (intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[1], pnts[2]) || + intersectTriTri(points[0], points[1], points[2], + pnts[0], pnts[2], pnts[3])) { + return true; + } + points[0].set(points[1]); + points[1].set(points[2]); + } + } + break; + case 2: // Line + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + getVertexData(j++, points[1]); + while (j < end) { + getVertexData(j++, points[2]); + if (intersectSegment(points, pnts[0], pnts[1], + dist, null)) { + return true; + } + points[0].set(points[1]); + points[1].set(points[2]); + } + } + break; + case 1: // Point + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, points[0]); + getVertexData(j++, points[1]); + while (j < end) { + getVertexData(j++, points[2]); + if (intersectTriPnt(points[0], points[1], points[2], + pnts[0])) { + return true; + } + points[0].set(points[1]); + points[1].set(points[2]); + } + } + break; + } + return false; + } + + boolean intersect(Transform3D thisToOtherVworld, GeometryRetained geom) { + int i = 0, j, end; + Point3d[] pnts = new Point3d[3]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + getVertexData(j++, pnts[1]); + thisToOtherVworld.transform(pnts[0]); + thisToOtherVworld.transform(pnts[1]); + while (j < end) { + getVertexData(j++, pnts[2]); + thisToOtherVworld.transform(pnts[2]); + if (geom.intersect(pnts)) { + return true; + } + pnts[0].set(pnts[1]); + pnts[1].set(pnts[2]); + } + } + return false; + } + + // the bounds argument is already transformed + boolean intersect(Bounds targetBound) { + int i = 0; + int j, end; + Point3d[] pnts = new Point3d[3]; + pnts[0] = new Point3d(); + pnts[1] = new Point3d(); + pnts[2] = new Point3d(); + + + switch(targetBound.getPickType()) { + case PickShape.PICKBOUNDINGBOX: + BoundingBox box = (BoundingBox) targetBound; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + getVertexData(j++, pnts[1]); + while ( j < end) { + getVertexData(j++, pnts[2]); + if (intersectBoundingBox(pnts, box, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + pnts[1].set(pnts[2]); + } + } + break; + case PickShape.PICKBOUNDINGSPHERE: + BoundingSphere bsphere = (BoundingSphere) targetBound; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + getVertexData(j++, pnts[1]); + while ( j < end) { + getVertexData(j++, pnts[2]); + if (intersectBoundingSphere(pnts, bsphere, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + pnts[1].set(pnts[2]); + } + } + break; + case PickShape.PICKBOUNDINGPOLYTOPE: + BoundingPolytope bpolytope = (BoundingPolytope) targetBound; + + while (i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnts[0]); + getVertexData(j++, pnts[1]); + while ( j < end) { + getVertexData(j++, pnts[2]); + if (intersectBoundingPolytope(pnts, bpolytope, null, null)) { + return true; + } + pnts[0].set(pnts[1]); + pnts[1].set(pnts[2]); + } + } + break; + default: + throw new RuntimeException("Bounds not supported for intersection " + + targetBound); + } + return false; + } + + // From Graphics Gems IV (pg5) and Graphics Gems II, Pg170 + void computeCentroid() { + Point3d pnt0 = new Point3d(); + Point3d pnt1 = new Point3d(); + Point3d pnt2 = new Point3d(); + Vector3d vec = new Vector3d(); + Vector3d normal = new Vector3d(); + Vector3d tmpvec = new Vector3d(); + + double area, totalarea = 0; + int end, replaceIndex, j, i = 0; + centroid.x = 0; + centroid.y = 0; + centroid.z = 0; + + while( i < stripVertexCounts.length) { + j = stripStartVertexIndices[i]; + end = j + stripVertexCounts[i++]; + getVertexData(j++, pnt0); + getVertexData(j++, pnt1); + replaceIndex = 2; + while (j < end) { + area = 0; + switch (replaceIndex) { + case 0: + getVertexData(j++, pnt0); + replaceIndex = 1; + break; + case 1: + getVertexData(j++, pnt1); + replaceIndex = 2; + break; + default: + getVertexData(j++, pnt2); + replaceIndex = 0; + } + + // Determine the normal + vec.sub(pnt0, pnt1); + tmpvec.sub(pnt1, pnt2); + + // Do the cross product + normal.cross(vec, tmpvec); + normal.normalize(); + // If a degenerate triangle, don't include + if (Double.isNaN(normal.x + normal.y + normal.z)) + continue; + + tmpvec.set(0,0,0); + + // compute the area + getCrossValue(pnt0, pnt1, tmpvec); + getCrossValue(pnt1, pnt2, tmpvec); + getCrossValue(pnt2, pnt0, tmpvec); + area = normal.dot(tmpvec); + totalarea += area; + centroid.x += (pnt0.x + pnt1.x + pnt2.x) * area; + centroid.y += (pnt0.y + pnt1.y + pnt2.y) * area; + centroid.z += (pnt0.z + pnt1.z + pnt2.z) * area; + + } + } + + if (totalarea != 0.0) { + area = 1.0/(3.0 * totalarea); + centroid.x *= area; + centroid.y *= area; + centroid.z *= area; + } + } + + + int getClassType() { + return TRIANGLE_TYPE; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/UnorderList.java b/j3d-core/src/classes/share/javax/media/j3d/UnorderList.java new file mode 100644 index 0000000..ef27078 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/UnorderList.java @@ -0,0 +1,593 @@ +/* + * $RCSfile: UnorderList.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.Arrays; + +/** + * A strongly type unorder array list. + * The operation add(Object o) & remove(int i) take O(1) time. + * The class is designed to optimize speed. So many reductance + * procedures call and range check as found in ArrayList are + * removed. + * + *

+ * Use the following code to iterate through an array. + * + *

+ *  UnorderList  list = new UnorderList(YourClass.class);
+ *  // add element here
+ *
+ *  YourClass[] arr = (YourClass []) list.toArray();
+ *  int size = list.arraySize();
+ *  for (int i=0; i < size; i++) {
+ *      YourClass obj = arr[i];
+ *      ....
+ *  }
+ * 
+ * + *

+ * Note: + *

    + * 1) The array return is a copied of internal array.
    + * 2) Don't use arr.length , use list.arraySize();
    + * 3) No need to do casting for individual element as in + * ArrayList.
    + * 4) UnorderList is thread safe. + *
+ */ + +class UnorderList implements Cloneable, java.io.Serializable { + + /** + * The array buffer into which the elements of the ArrayList are stored. + * The capacity of the ArrayList is the length of this array buffer. + * + * It is non-private to enable compiler do inlining for get(), + * set(), remove() when -O flag turn on. + */ + transient Object elementData[]; + + /** + * Clone copy of elementData return by toArray(true); + */ + transient Object cloneData[]; + // size of the above clone objec. + transient int cloneSize; + + transient boolean isDirty = true; + + /** + * Component Type of individual array element entry + */ + + Class componentType; + + /** + * The size of the ArrayList (the number of elements it contains). + * + * We make it non-private to enable compiler do inlining for + * getSize() when -O flag turn on. + */ + int size; + + + /** + * Constructs an empty list with the specified initial capacity. + * and the class data Type + * + * @param initialCapacity the initial capacity of the list. + * @param componentType class type of element in the list. + */ + UnorderList(int initialCapacity, Class componentType) { + this.componentType = componentType; + this.elementData = (Object[])java.lang.reflect.Array.newInstance( + componentType, initialCapacity); + } + + /** + * Constructs an empty list. + * @param componentType class type of element in the list. + */ + UnorderList(Class componentType) { + this(10, componentType); + } + + + /** + * Constructs an empty list with the specified initial capacity. + * + * @param initialCapacity the initial capacity of the list. + */ + UnorderList(int initialCapacity) { + this(initialCapacity, Object.class); + } + + + /** + * Constructs an empty list. + * componentType default to Object. + */ + UnorderList() { + this(10, Object.class); + } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list. + */ + final int size() { + return size; + } + + + /** + * Returns the size of entry use in toArray() number of elements + * in this list. + * + * @return the number of elements in this list. + */ + final int arraySize() { + return cloneSize; + } + + /** + * Tests if this list has no elements. + * + * @return true if this list has no elements; + * false otherwise. + */ + final boolean isEmpty() { + return size == 0; + } + + /** + * Returns true if this list contains the specified element. + * + * @param o element whose presence in this List is to be tested. + */ + synchronized final boolean contains(Object o) { + if (o != null) { // common case first + for (int i=size-1; i >= 0; i--) + if (o.equals(elementData[i])) + return true; + } else { + for (int i=size-1; i >= 0; i--) + if (elementData[i]==null) + return true; + } + return false; + + } + + + /** + * Add Object into the list if it is not already exists. + * + * @param o an object to add into the list + * @return true if object successfully add, false if duplicate found + */ + synchronized final boolean addUnique(Object o) { + if (!contains(o)) { + add(o); + return true; + } + return false; + } + + /** + * Searches for the last occurence of the given argument, testing + * for equality using the equals method. + * + * @param o an object. + * @return the index of the first occurrence of the argument in this + * list; returns -1 if the object is not found. + * @see Object#equals(Object) + */ + synchronized final int indexOf(Object o) { + if (o != null) { // common case first + for (int i=size-1; i >= 0; i--) + if (o.equals(elementData[i])) + return i; + } else { + for (int i=size-1; i >= 0; i--) + if (elementData[i]==null) + return i; + } + return -1; + } + + /** + * Returns a shallow copy of this ArrayList instance. (The + * elements themselves are not copied.) + * + * @return a clone of this ArrayList instance. + */ + synchronized protected final Object clone() { + try { + UnorderList v = (UnorderList)super.clone(); + v.elementData = (Object[])java.lang.reflect.Array.newInstance( + componentType, size); + System.arraycopy(elementData, 0, v.elementData, 0, size); + isDirty = true; // can't use the old cloneData reference + return v; + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + + + /** + * Returns an array containing all of the elements in this list. + * The size of the array may longer than the actual size. Use + * arraySize() to retrieve the size. + * The array return is a copied of internal array. if copy + * is true. + * + * @return an array containing all of the elements in this list + */ + synchronized final Object[] toArray(boolean copy) { + if (copy) { + if (isDirty) { + if ((cloneData == null) || cloneData.length < size) { + cloneData = (Object[])java.lang.reflect.Array.newInstance( + componentType, size); + } + System.arraycopy(elementData, 0, cloneData, 0, size); + cloneSize = size; + isDirty = false; + } + return cloneData; + } else { + cloneSize = size; + return elementData; + } + + } + + /** + * Returns an array containing all of the elements in this list. + * The size of the array may longer than the actual size. Use + * arraySize() to retrieve the size. + * The array return is a copied of internal array. So another + * thread can continue add/delete the current list. However, + * it should be noticed that two call to toArray() may return + * the same copy. + * + * @return an array containing all of the elements in this list + */ + synchronized final Object[] toArray() { + return toArray(true); + } + + + /** + * Returns an array containing elements starting from startElement + * all of the elements in this list. A new array of exact size + * is always allocated. + * + * @param startElement starting element to copy + * + * @return an array containing elements starting from + * startElement, null if element not found. + * + */ + synchronized final Object[] toArray(Object startElement) { + int idx = indexOf(startElement); + if (idx < 0) { + return (Object[])java.lang.reflect.Array.newInstance(componentType, 0); + } + + int s = size - idx; + Object data[] = (Object[])java.lang.reflect.Array.newInstance(componentType, s); + System.arraycopy(elementData, idx, data, 0, s); + return data; + } + + // copy element to objs and clear the array + synchronized final void toArrayAndClear(Object[] objs) { + System.arraycopy(elementData, 0, objs, 0, size); + Arrays.fill(elementData, 0, size, null); + size = 0; + isDirty = true; + } + + + /** + * Trims the capacity of this ArrayList instance to be the + * list's current size. An application can use this operation to minimize + * the storage of an ArrayList instance. + */ + synchronized final void trimToSize() { + if (elementData.length > size) { + Object oldData[] = elementData; + elementData = (Object[])java.lang.reflect.Array.newInstance( + componentType, + size); + System.arraycopy(oldData, 0, elementData, 0, size); + } + } + + + // Positional Access Operations + + /** + * Returns the element at the specified position in this list. + * + * @param index index of element to return. + * @return the element at the specified position in this list. + * @throws IndexOutOfBoundsException if index is out of range (index + * < 0 || index >= size()). + */ + synchronized final Object get(int index) { + return elementData[index]; + } + + /** + * Replaces the element at the specified position in this list with + * the specified element. + * + * @param index index of element to replace. + * @param element element to be stored at the specified position. + * @return the element previously at the specified position. + * @throws IndexOutOfBoundsException if index out of range + * (index < 0 || index >= size()). + */ + synchronized final void set(int index, Object element) { + elementData[index] = element; + isDirty = true; + } + + /** + * Appends the specified element to the end of this list. + * It is the user responsible to ensure that the element add is of + * the same type as array componentType. + * + * @param o element to be appended to this list. + */ + synchronized final void add(Object o) { + if (elementData.length == size) { + Object oldData[] = elementData; + elementData = (Object[])java.lang.reflect.Array.newInstance( + componentType, + (size << 1)); + System.arraycopy(oldData, 0, elementData, 0, size); + + } + elementData[size++] = o; + isDirty = true; + } + + + /** + * Removes the element at the specified position in this list. + * Replace the removed element by the last one. + * + * @param index the index of the element to removed. + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index >= size()). + */ + synchronized final void remove(int index) { + elementData[index] = elementData[--size]; + elementData[size] = null; + isDirty = true; + /* + if ((cloneData != null) && (index < cloneData.length)) { + cloneData[index] = null; // for gc + } + */ + } + + + /** + * Removes the element at the specified position in this list. + * The order is keep. + * + * @param index the index of the element to removed. + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index >= size()). + */ + synchronized final void removeOrdered(int index) { + size--; + if (index < size) { + System.arraycopy(elementData, index+1, + elementData, index, size-index); + + } + // gc for last element + elementData[size] = null; + isDirty = true; + } + + + /** + * Removes the element at the last position in this list. + * @return The element remove + * @throws IndexOutOfBoundsException if array is empty + */ + synchronized final Object removeLastElement() { + Object elm = elementData[--size]; + elementData[size] = null; + isDirty = true; + /* + if ((cloneData != null) && (size < cloneData.length)) { + cloneData[size] = null; // for gc + } + */ + return elm; + } + + + // Shift element of array from positin idx to position 0 + // Note that idx < size, otherwise ArrayIndexOutOfBoundsException + // throws. The element remove are copy to objs. + synchronized final void shift(Object objs[], int idx) { + int oldsize = size; + + System.arraycopy(elementData, 0, objs, 0, idx); + size -= idx; + if (size > 0) { + System.arraycopy(elementData, idx, elementData, 0, size); + } + Arrays.fill(elementData, size, oldsize, null); + } + + /** + * Removes the specified element in this list. + * Replace the removed element by the last one. + * + * @param o the element to removed. + * @return true if object remove + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index >= size()). + */ + synchronized final boolean remove(Object o) { + size--; + if (o != null) { + for (int i=size; i >= 0; i--) { + if (o.equals(elementData[i])) { + elementData[i] = elementData[size]; + elementData[size] = null; + /* + if ((cloneData != null) && (i < cloneData.length)) { + cloneData[i] = null; // for gc + } + */ + isDirty = true; + return true; + } + } + } else { + for (int i=size; i >= 0; i--) + if (elementData[i]==null) { + elementData[i] = elementData[size]; + elementData[size] = null; + /* + if ((cloneData != null) && (i < cloneData.length)) { + cloneData[i] = null; // for gc + } + */ + isDirty = true; + return true; + } + } + size++; // fail to remove + return false; + } + + + /** + * Removes all of the elements from this list. The list will + * be empty after this call returns. + */ + synchronized final void clear() { + if (size > 0) { + Arrays.fill(elementData, 0, size, null); + size = 0; + isDirty = true; + } + } + + synchronized final void clearMirror() { + if (cloneData != null) { + Arrays.fill(cloneData, 0, cloneData.length, null); + } + cloneSize = 0; + isDirty = true; + } + + final Class getComponentType() { + return componentType; + } + + synchronized public String toString() { + StringBuffer sb = new StringBuffer("Size = " + size + "\n["); + int len = size-1; + Object obj; + + for (int i=0; i < size; i++) { + obj = elementData[i]; + if (obj != null) { + sb.append(elementData[i].toString()); + } else { + sb.append("NULL"); + } + if (i != len) { + sb.append(", "); + } + } + sb.append("]\n"); + return sb.toString(); + } + + /** + * Save the state of the ArrayList instance to a stream (that + * is, serialize it). + * + * @serialData The length of the array backing the ArrayList + * instance is emitted (int), followed by all of its elements + * (each an Object) in the proper order. + */ + private synchronized void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException{ + // Write out element count, and any hidden stuff + s.defaultWriteObject(); + + // Write out array length + s.writeInt(elementData.length); + + // Write out all elements in the proper order. + for (int i=0; iArrayList instance from a stream (that is, + * deserialize it). + */ + private synchronized void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in array length and allocate array + int arrayLength = s.readInt(); + elementData = (Object[])java.lang.reflect.Array.newInstance( + componentType, arrayLength); + + // Read in all elements in the proper order. + for (int i=0; i + * The View object is the main Java 3D object for controlling the + * Java 3D viewing model. All of the components that specify the + * view transform used to render to the 3D canvases are either contained + * in the View object or in objects that are referenced by the View + * object. + *

+ * Java 3D allows applications to specify multiple simultaneously active + * View objects, each controlling its own set of canvases. + *

+ * The Java 3D View object has several instance variables and methods, + * but most are calibration variables or user-helping functions. The + * viewing policies defined by the View object are described below. + *

+ * Policies

+ * + * The View object defines the following policies:

+ *

    + *
  • View policy - informs Java 3D whether it should generate + * the view using the head-tracked system of transformations or the + * head-mounted system of transformations. These policies are attached + * to the Java 3D View object. There are two view policies:
  • + *

      + *
    • SCREEN_VIEW - specifies that Java 3D should compute a new + * viewpoint using the sequence of transforms appropriate to screen-based + * head-tracked display environments (fish-tank VR/portals/VR-desks). + * This is the default setting.
    • + *

    • HMD_VIEW - specifies that Java 3D should compute a new viewpoint + * using the sequence of transforms appropriate to head mounted display + * environments. This policy is not available in compatibility mode + * (see the setCompatibilityModeEnable method description).
    • + *

    + *
  • Projection policy - specifies whether Java 3D should generate + * a parallel projection or a perspective projection. This policy + * is attached to the Java 3D View object. There are two projection + * policies:
  • + *

      + *
    • PARALLEL_PROJECTION - specifies that a parallel projection + * transform is computed.
    • + *

    • PERSPECTIVE_PROJECTION - specifies that a perspective projection + * transform is computed. This is the default policy.
    • + *

    + *
  • Screen scale policy - specifies where the screen scale comes from. + * There are two screen scale policies:
  • + *

      + *
    • SCALE_SCREEN_SIZE - specifies that the scale is derived from the + * physical screen according to the following formula (this is the + * default mode):
    • + *
        + * screenScale = physicalScreenWidth / 2.0

        + *

      + *
    • SCALE_EXPLICIT - pecifies that the scale is taken directly from + * the user-provided screenScale attribute (see the + * setScreenScale method description).
    • + *

    + *
  • Window resize policy - specifies how Java 3D modifies the view + * when users resize windows. When users resize or move windows, + * Java 3D can choose to think of the window as attached either to + * the physical world or to the virtual world. The window resize + * policy allows an application to specify how the + * view model will handle resizing requests. + * There are two window resize policies:
  • + *

      + *
    • VIRTUAL_WORLD - implies that the original image remains the + * same size on the screen but the user sees more or less of the + * virtual world depending on whether the window grew or shrank + * in size.
    • + *

    • PHYSICAL_WORLD - implies that the original image continues + * to fill the window in the same way using more or less pixels + * depending on whether the window grew or shrank in size.
    • + *

    + *
  • Window movement policy - specifies what part of the virtual + * world Java 3D draws as a function of window placement on the screen. + * There are two window movement policies:
  • + *

      + *
    • VIRTUAL_WORLD - implies that the image seen in the window + * changes as the position of the window shifts on the screen. + * (This mode acts as if the window were a window into the virtual + * world.)
    • + *

    • PHYSICAL_WORLD - implies that the image seen in the window + * remains the same no matter where the user positions the window + * on the screen.
    • + *

    + *
  • Window eyepoint policy - comes into effect in a non-head-tracked + * environment. The policy tells Java 3D how to construct a new view + * frustum based on changes in the field of view and in the Canvas3D's + * location on the screen. The policy only comes into effect when the + * application changes a parameter that can change the placement of the + * eyepoint relative to the view frustum. + * There are three window eyepoint policies:
  • + *

      + *
    • RELATIVE_TO_SCREEN - tells Java 3D to interpret the eye's position + * relative to the entire screen. No matter where an end user moves a + * window (a Canvas3D), Java 3D continues to interpret the eye's position + * relative to the screen. This implies that the view frustum changes shape + * whenever an end user moves the location of a window on the screen. + * In this mode, the field of view is read-only.
    • + *

    • RELATIVE_TO_WINDOW - specifies that Java 3D should interpret the + * eye's position information relative to the window (Canvas3D). No matter + * where an end user moves a window (a Canvas3D), Java 3D continues to + * interpret the eye's position relative to that window. This implies + * that the frustum remains the same no matter where the end user + * moves the window on the screen. In this mode, the field of view + * is read-only.
    • + *

    • RELATIVE_TO_FIELD_OF_VIEW - tells Java 3D that it should + * modify the eyepoint position so it is located at the appropriate + * place relative to the window to match the specified field of view. + * This implies that the view frustum will change whenever the + * application changes the field of view. In this mode, the eye + * position is read-only. This is the default setting.
    • + *

    • RELATIVE_TO_COEXISTENCE - tells Java 3D to interpret the eye's + * position in coexistence coordinates. In this mode, the eye position + * is taken from the view (rather than the Canvas3D) and transformed from + * coexistence coordinates to image plate coordinates for each + * Canvas3D. The resulting eye position is relative to the screen. As + * in RELATIVE_TO_SCREEN mode, this implies that the view frustum + * changes shape whenever an end user moves the location of a window + * on the screen. In this mode, the field of view is + * read-only.
    • + *

    + *
  • Front and back clip policies - specifies how Java 3D + * interprets clipping distances to both the near and far clip + * planes. The policies can contain one of four values specifying + * whether a distance measurement should be interpreted in + * the physical or the virtual world and whether that distance + * measurement should be interpreted relative to the physical + * eyepoint or the physical screen. + * The front and back clip policies + * are specified separately. The front clip policy determines + * where Java 3D places the front clipping plane. The back clip + * policy determines where Java 3D places the back clipping plane. + * The values for both front and back clipping planes are:
  • + *

      + *
    • VIRTUAL_EYE - specifies that the associated distance is from + * the eye and in units of virtual distance.
    • + *

    • PHYSICAL_EYE - specifies that the associated distance is from + * the eye and in units of physical distance (in meters). + * This is the default policy for both front and back clipping.
    • + *

    • VIRTUAL_SCREEN - specifies that the associated distance is + * from the screen and in units of virtual distance.
    • + *

    • PHYSICAL_SCREEN - specifies that the associated distance is + * from the screen and in units of physical distance (in meters). + *
    • + *

    + *
  • Visibility policy - specifies how visible and invisible objects + * are drawn. There are three visibility policies:
  • + *

      + *
    • VISIBILITY_DRAW_VISIBLE - only visible objects are drawn + * (this is the default).
    • + *

    • VISIBILITY_DRAW_INVISIBLE - only invisible objects are drawn.
    • + *

    • VISIBILITY_DRAW_ALL - both visible and invisible + * objects are drawn.
    • + *

    + *
  • Transparency sorting policy - specifies whether and how + * transparent objects are sorted. Sorting multiple transparent + * objects is necessary to avoid artifacts caused by overlapping + * transparent objects. There are two transparency sorting + * policies:
  • + *

      + *
    • TRANSPARENCY_SORT_NONE - no depth sorting of transparent + * objects is performed (this is the default). Transparent objects + * are drawn after opaque objects, but are not sorted from back to + * front.
    • + *

    • TRANSPARENCY_SORT_GEOMETRY - transparent objects are + * depth-sorted on a per-geometry basis. Each geometry object of each + * transparent Shape3D node is drawn from back to front. Note that + * this policy will not split geometry into smaller pieces, so + * intersecting or intertwined objects may not be sorted + * correctly. The method used for determining which geometry is closer + * is implementation dependent.
    • + *

    + *
+ * Projection and Clip Parameters

+ * The projection and clip parameters determine the view model's + * field of view and the front and back clipping distances.

+ *

    + *
  • Field of view - specifies the view model's horizontal + * field of view in radians, when in the default non-head-tracked + * mode. This value is ignored when the view model is operating + * in head-tracked mode, or when the Canvas3D's window eyepoint + * policy is set to a value other than the default setting of + * RELATIVE_TO_FIELD_OF_VIEW.
  • + *

  • Front clip distance - specifies the distance away from the + * clip origin, specified by the front clip policy variable, in + * the direction of gaze where objects stop disappearing. Objects + * closer than the clip origin (eye or screen) + * plus the front clip distance are not drawn. Measurements are + * done in the space (physical or virtual) that is specified by + * the associated front clip policy parameter.
  • + *

  • Back clip distance - specifies the distance away from the + * clip origin (specified by the back clip policy variable) in the + * direction of gaze where objects begin disappearing. Objects + * farther away from the clip origin (eye or + * screen) plus the back clip distance are not drawn. + * Measurements are done in the space (physical or virtual) that + * is specified by the associated back clip policy + * parameter. The View object's back clip distance is ignored + * if the scene graph contains an active Clip leaf node.
  • + * There are several considerations to take into account when + * choosing values for the front and back clip distances.

    + *

      + *
    • The front clip distance must be greater than 0.0 in physical + * eye coordinates.
    • + *

    • The front clipping plane must be in front of the back clipping + * plane, that is, the front clip distance must be less than the + * back clip distance in physical eye coordinates.
    • + *

    • The front and back clip distances, in physical eye coordinates, + * must be less than the largest positive single-precision floating + * point value, Float.MAX_VALUE. In practice, since these physical + * eye coordinate distances are in meters, the values + * should be much less than that.
    • + *

    • The ratio of the back distance divided by the front distance, + * in physical eye coordinates, affects Z-buffer precision. This ratio + * should be less than about 3000 to accommodate 16-bit Z-buffers. + * Values of 100 to less than 1000 will produce better results.
    • + *

    + * Violating any of the above rules will result in undefined behavior. + * In many cases, no picture will be drawn.

    + *

+ * Frame Start Time, Duration, and Number

+ * + * There are five methods used to get information about system + * execution and performance:

+ *

    + * getCurrentFrameStartTime returns the time at which + * the most recent rendering frame started.

    + * getLastFrameDuration returns the duration, in milliseconds, of + * the most recently completed rendering frame.

    + * getFrameNumber returns the frame number for this view.

    + * getMaxFrameStartTimes retrieves the implementation-dependent + * maximum number of frames whose start times will be recorded by + * the system.

    + * getFrameStartTimes copies the last k frame start time values + * into the user-specified array.

    + *

+ * View Traversal and Behavior Scheduling

+ * The following methods control the traversal, the rendering, and + * the execution of the behavior scheduler for this view:

+ *

    + * startBehaviorScheduler starts the behavior scheduler + * running after it has been stopped.

    + * stopBehaviorScheduler stops the behavior scheduler after all + * currently-scheduled behaviors are executed.

    + * isBehaviorSchedulerRunning retrieves a flag that indicates + * whether the behavior scheduler is currently running.

    + * startView starts traversing this view and starts the renderers + * associated with all canvases attached to this view.

    + * stopView stops traversing this view after the current state of + * the scene graph is reflected on all canvases attached to this + * view.

    + * isViewRunning returns a flag indicating whether the traverser + * is currently running on this view.

    + *

+ * Note: The above six methods are heavy-weight methods intended + * for verification and image capture (recording). They are not + * intended to be used for flow control.

+ * + * Scene Antialiasing

+ * + * The following methods set and retrieve the scene antialiasing + * flag. Scene antialiasing is either enabled or disabled for this + * view. If enabled, the entire scene will be antialiased on each + * canvas in which scene antialiasing is available. Scene + * antialiasing is disabled by default.

+ *

    + * setSceneAntialiasingEnable sets the scene antialiasing flag.

    + * getSceneAntialiasingEnable returns the scene antialiasing + * flag.

    + *

+ * Note that line and point antialiasing are independent of scene + * antialiasing. If antialiasing is enabled for lines and points, + * the lines and points will be antialiased prior to scene antialiasing. + * If scene antialiasing is disabled, antialiased lines and points will + * still be antialiased. + *

+ * Note: Scene antialiasing is ignored in pure immediate mode, + * but is supported in mixed-immediate mode. + *

+ * Depth Buffer

+ * + * The following two methods enable and disable automatic freezing + * of the depth buffer for objects rendered during the transparent + * rendering pass (that is, objects rendered using alpha blending) + * for this view. If enabled, depth buffer writes are disabled + * during the transparent rendering pass regardless of the value + * of the depth-buffer-write-enable flag in the RenderingAttributes + * object for a particular node. This flag is enabled by default.

+ *

    + * setDepthBufferFreezeTransparent enables depth buffer freezing.

    + * getDepthBufferFreezeTransparent retrieves the depth buffer + * flag.

    + *

+ * Transparent objects include BLENDED transparent primitives + * and antialiased lines + * and points. Transparent objects do not include opaque objects + * or primitives rendered with SCREEN_DOOR transparency.

+ * + * Sensors

+ * + * The following methods retrieve the sensor's location in the + * virtual world:

+ *

    + * getSensorToVworld takes the sensor's last reading and + * generates a sensor-to-vworld coordinate system transform. This + * Transform3D object takes points in that sensor's local coordinate + * system and transforms them into virtual world coordinates.

    + * + * getSensorHotSpotInVworld retrieves the specified sensor's + * last hotspot location in virtual world coordinates.

    + *

+ * + * Compatibility Mode

+ * + * A camera-based view model allows application programmers to think + * about the images displayed on the computer screen as if a virtual + * camera took those images. Such a view model allows application + * programmers to position and orient a virtual camera within a + * virtual scene, to manipulate some parameters of the virtual + * camera's lens (specify its field of view), and to specify the + * locations of the near and far clipping planes.

+ * Java 3D allows applications to enable compatibility mode for + * room-mounted, non-head-tracked display environments, or to disable + * compatibility mode using the following methods. Camera-based + * viewing functions are only available in compatibility mode.

+ *

    + * setCompatibilityModeEnable turns compatibility mode on or off. + * Compatibility mode is disabled by default.

    + * getCompatabilityModeEnable returns the compatibility mode + * enable flag.

    + *

+ * Use of these view-compatibility functions will disable some of + * Java 3D's view model features and limit the portability of Java + * 3D programs. These methods are primarily intended to help + * jump-start porting of existing applications.

+ * + * Setting the Viewing Transform

+ * + * The View object provides the following compatibility-mode + * methods that operate on the viewing transform.

+ *

    + * setVpcToEc a compatibility mode method that + * specifies the ViewPlatform + * coordinates (VPC) to eye coordinates viewing transform.

    + * getVpcToEc returns the VPC.

    + *

+ * Setting the Projection Transform + *

+ * The View object provides the following compatibility-mode + * methods that operate on the projection transform:

+ *

    + * The setLeftProjection and setRightProjection + * methods specify + * a viewing frustum for the left and right eye that transforms + * points in eye coordinates to clipping coordinates.

    + * + * The getLeftProjection and getRightProjection + * methods return + * the viewing frustum for the left and right eye.

    + *

+ * + *

+ * Additional Information + *

+ * For more information, see the + * Introduction to the Java 3D API and + * View Model + * documents. + * + * @see Canvas3D + * @see PhysicalBody + * @see PhysicalEnvironment + * @see ViewPlatform + * @see TransparencyAttributes + */ + +public class View extends Object { + /** + * Specifies a policy whereby the origin of physical or virtual + * coordinates is relative to the position of the nominal head. + * When used as a view attach policy, this sets the origin of view + * platform coordinates to be at the eyepoint. + * @see ViewPlatform#setViewAttachPolicy + * @see PhysicalEnvironment#setCoexistenceCenterInPworldPolicy + */ + public static final int NOMINAL_HEAD = 0; + + /** + * Specifies a policy whereby the origin of physical or virtual + * coordinates is relative to the position of the nominal feet. + * When used as a view attach policy, this sets the origin of view + * platform coordinates to be at the ground plane. + * @see ViewPlatform#setViewAttachPolicy + * @see PhysicalEnvironment#setCoexistenceCenterInPworldPolicy + */ + public static final int NOMINAL_FEET = 1; + + /** + * Specifies a policy whereby the origin of physical or virtual + * coordinates is relative to the screen. + * When used as a view attach policy, this sets the origin of view + * platform coordinates to be at the center of the window or screen, + * in effect, allowing the user to view objects from an optimal viewpoint. + * @see ViewPlatform#setViewAttachPolicy + * @see PhysicalEnvironment#setCoexistenceCenterInPworldPolicy + */ + public static final int NOMINAL_SCREEN = 2; + + /** + * Specifies that the screen scale for this view is derived from + * the physical screen size. This scale factor is computed as follows: + *

    + * physical_screen_width / 2.0 + *
+ * This allows an application to define a world in a normalized + * [-1,1] space and view it on a screen of any size. + * @see #setScreenScalePolicy + */ + public static final int SCALE_SCREEN_SIZE = 0; + + /** + * Specifies that the screen scale for this view is taken directly + * from the user-provided screenScale parameter. + * @see #setScreenScalePolicy + * @see #setScreenScale + */ + public static final int SCALE_EXPLICIT = 1; + + /** + * Specifies that the associated distance is measured + * from the screen in virtual world coordinates. + * Policy for interpreting clip plane distances. + * Used in specifying the policy in frontClipPolicy and backClipPolicy. + * @see #setFrontClipPolicy + * @see #setBackClipPolicy + */ + public static final int VIRTUAL_SCREEN = 0; + + /** + * Specifies that the associated distance is measured + * from the screen in meters. + * Policy for interpreting clip plane distances. + * Used in specifying the policy in frontClipPolicy and backClipPolicy. + * @see #setFrontClipPolicy + * @see #setBackClipPolicy + */ + public static final int PHYSICAL_SCREEN = 1; + + /** + * Specifies that the associated distance is measured + * from the eye in virtual world coordinates. + * Policy for interpreting clip plane distances. + * Used in specifying the policy in frontClipPolicy and backClipPolicy. + * @see #setFrontClipPolicy + * @see #setBackClipPolicy + */ + public static final int VIRTUAL_EYE = 2; + + /** + * Specifies that the associated distance is measured + * from the eye in meters. + * Policy for interpreting clip plane distances. + * Used in specifying the policy in frontClipPolicy and backClipPolicy. + * This is the default policy for both front and back clipping. + * @see #setFrontClipPolicy + * @see #setBackClipPolicy + */ + public static final int PHYSICAL_EYE = 3; + + /** + * Policy for resizing and moving windows. + * Used in specifying windowResizePolicy and windowMovementPolicy. + * VIRTUAL_WORLD specifies that the associated action takes place + * in the virtual world as well as in the physical world. + * @see #setWindowResizePolicy + * @see #setWindowMovementPolicy + */ + public static final int VIRTUAL_WORLD = 0; + + /** + * Policy for resizing and moving windows. + * Used in specifying windowResizePolicy and windowMovementPolicy. + * PHYSICAL_WORLD specifies that the specified action takes place + * only in the physical world. + * @see #setWindowResizePolicy + * @see #setWindowMovementPolicy + */ + public static final int PHYSICAL_WORLD = 1; + + /** + * Policy for placing the eyepoint in non-head-tracked modes. + * Specifies that Java 3D should interpret the + * given fixed eyepoint position as relative to the entire screen. + * This implies + * that the view frustum shape will change whenever a + * user moves the location of a window on the screen. + * @see #setWindowEyepointPolicy + */ + public static final int RELATIVE_TO_SCREEN = 0; + + /** + * Policy for placing the eyepoint in non-head-tracked modes. + * Specifies that Java 3D should interpret the + * given fixed-eyepoint position as relative to the window. + * @see #setWindowEyepointPolicy + */ + public static final int RELATIVE_TO_WINDOW = 1; + + /** + * Policy for placing the eyepoint in non-head-tracked modes. + * Specifies that Java 3D should + * modify the position of the eyepoint to match any changes in field + * of view; the view frustum will change whenever the application + * program changes the field of view. + *

+ * NOTE: when this policy is specified, the Z coordinate of + * the derived eyepoint is used in place of + * nominalEyeOffsetFromNominalScreen. + * @see #setWindowEyepointPolicy + */ + public static final int RELATIVE_TO_FIELD_OF_VIEW = 2; + + /** + * Policy for placing the eyepoint in non-head-tracked modes. + * Specifies that Java 3D should interpret the fixed eyepoint + * position in the view as relative to the origin + * of coexistence coordinates. This eyepoint is transformed from + * coexistence coordinates to image plate coordinates for each + * Canvas3D. + * As in RELATIVE_TO_SCREEN mode, this implies + * that the view frustum shape will change whenever a + * user moves the location of a window on the screen. + * @see #setWindowEyepointPolicy + * + * @since Java 3D 1.2 + */ + public static final int RELATIVE_TO_COEXISTENCE = 3; + + /** + * Specifies that monoscopic view generated should be the view as seen + * from the left eye. + * @see Canvas3D#setMonoscopicViewPolicy + */ + public static final int LEFT_EYE_VIEW = 0; + + /** + * Specifies that monoscopic view generated should be the view as seen + * from the right eye. + * @see Canvas3D#setMonoscopicViewPolicy + */ + public static final int RIGHT_EYE_VIEW = 1; + + /** + * Specifies that monoscopic view generated should be the view as seen + * from the 'center eye', the fictional eye half-way between the left and + * right eye. + * @see Canvas3D#setMonoscopicViewPolicy + */ + public static final int CYCLOPEAN_EYE_VIEW = 2; + + /** + * Specifies that the viewing environment for this view is a + * standard screen-based display environment. + * In this mode, Java 3D will compute new viewpoints + * using that sequence of transforms appropriate to screen-based, + * display environments, that may or may not include head tracking + * (e.g., a monoscopic screen, fish-tank VR, portals, VR-desks). + * This is the default mode. + * @see #setViewPolicy + */ + public static final int SCREEN_VIEW = 0; + + /** + * Specifies that the viewing environment for this view is a + * head-mounted display environment. + * In this mode, Java 3D will compute new viewpoints + * using that sequence of transforms appropriate to head-mounted display + * environments. These environments are generally head-tracked. + * @see #setViewPolicy + */ + public static final int HMD_VIEW = 1; + + /** + * Specifies that Java 3D should generate a parallel projection matrix + * for this View. + * @see #setProjectionPolicy + */ + public static final int PARALLEL_PROJECTION = 0; + + /** + * Specifies that Java 3D should generate a perspective projection matrix + * for this View. + * This is the default mode. + * @see #setProjectionPolicy + */ + public static final int PERSPECTIVE_PROJECTION = 1; + + /** + * Policy that specifies that only visible objects should be drawn. + * This is the default mode. + * @see #setVisibilityPolicy + * + * @since Java 3D 1.2 + */ + public static final int VISIBILITY_DRAW_VISIBLE = 0; + + /** + * Policy that specifies that only invisible objects should be drawn. + * @see #setVisibilityPolicy + * + * @since Java 3D 1.2 + */ + public static final int VISIBILITY_DRAW_INVISIBLE = 1; + + /** + * Policy that specifies that both visible and invisible objects + * should be drawn. + * @see #setVisibilityPolicy + * + * @since Java 3D 1.2 + */ + public static final int VISIBILITY_DRAW_ALL = 2; + + /** + * Policy that specifies that no sorting of transparent objects + * is done. + * This is the default mode. + * @see #setTransparencySortingPolicy + * + * @since Java 3D 1.3 + */ + public static final int TRANSPARENCY_SORT_NONE = 0; + + /** + * Policy that specifies that transparent objects + * are sorted from back to front on a per-geometry basis. + * @see #setTransparencySortingPolicy + * + * @since Java 3D 1.3 + */ + public static final int TRANSPARENCY_SORT_GEOMETRY = 1; + + + // + // The AWT window for display. + // + // This object can be queried to obtain: + // screen width in pixels + // screen height in pixels + // window width in pixels + // window height in pixels + // window upper left corner location in pixels relative to screen + // + // Use getCanvases() to access this + private Vector canvases = new Vector(3); + + // + // The current universe associated with this view + // + VirtualUniverse universe = null; + + // + // The RenderBin associated with this view. + // + RenderBin renderBin = null; + + // This is the SoundScheduler associated with this view. + SoundScheduler soundScheduler = null; + + // This is the thread associated with this view. + SoundRenderer soundRenderer = new SoundRenderer(); + + // AudioDevice enumerator current position + // AudioDeviceEnumerator allAudioEnumerator = null; + + // These are used for tracking the frame times + static final int NUMBER_FRAME_START_TIMES = 10; + + long[] frameStartTimes = new long[NUMBER_FRAME_START_TIMES]; + long[] frameNumbers = new long[NUMBER_FRAME_START_TIMES]; + int currentFrameIndex = 0; + + // These are the values that are set at the end of each frame + long currentFrameStartTime = 0; + long currentFrameDuration = 0; + long currentFrameNumber = 0; + + // These are the ones that get updated directly by MC + long frameNumber = 0; + long startTime = 0; + long stopTime = 0; + + // Support dynamic video resize -- DVR. + Viewer viewer = null; // Cached the associate viewer of this view. + boolean firstTime = true; +// float dvrFactor = 1.0f; +// boolean dvrResizeCompensation = true; + + // User adjustable minimum frame cycle time + long minFrameCycleTime; + + // True when stopBehaviorScheduler invoke + boolean stopBehavior; + + // + // View cache for this view. + // + ViewCache viewCache = null; + + // Compatibility mode related field has changed. + // { compatibilityModeEnable, compatVpcToEc, compatLeftProjection, + // compatRightProjection } + static final int COMPATIBILITY_MODE_DIRTY = 0x01; + // ScreenScalePolicy field has changed. + static final int SCREEN_SCALE_POLICY_DIRTY = 0x02; + // Screen scale field has changed. + static final int SCREEN_SCALE_DIRTY = 0x04; + // Window Resize Policy field has changed. + static final int WINDOW_RESIZE_POLICY_DIRTY = 0x08; + // View Policy eye in image plate field has changed. + static final int VIEW_POLICY_DIRTY = 0x10; + // Clip related field has changed. + // { frontClipDistance, backClipDistance, frontClipPolicy, backClipPolicy } + static final int CLIP_DIRTY = 0x20; + // Projection Policy field has changed. + static final int PROJECTION_POLICY_DIRTY = 0x40; + // Window Movement Policy field has changed. + static final int WINDOW_MOVEMENT_POLICY_DIRTY = 0x80; + // Window Eye Point Policy field has changed. + static final int WINDOW_EYE_POINT_POLICY_DIRTY = 0x100; + // Monoscopic View Policy field has changed. + static final int MONOSCOPIC_VIEW_POLICY_DIRTY = 0x200; + // Field Of View field has changed. + static final int FIELD_OF_VIEW_DIRTY = 0x400; + // Tracking Enable field has changed. + static final int TRACKING_ENABLE_DIRTY = 0x800; + // User Head To Vworld Enable field has changed. + static final int USER_HEAD_TO_VWORLD_ENABLE_DIRTY = 0x1000; + // coexistenceCenteringEnable flag has changed. + static final int COEXISTENCE_CENTERING_ENABLE_DIRTY = 0x2000; + // leftManualEyeInCoexistence has changed. + static final int LEFT_MANUAL_EYE_IN_COEXISTENCE_DIRTY = 0x4000; + // rightManualEyeInCoexistence has changed. + static final int RIGHT_MANUAL_EYE_IN_COEXISTENCE_DIRTY = 0x8000; + // visibilityPolicy has changed. + static final int VISIBILITY_POLICY_DIRTY = 0x10000; + + // This is not from View object. It is here for the purpose + // keeping all ViewCache's dirty mask bit declaration in one place. + // ViewPlatformRetained viewAttach Policy field has changed. + static final int VPR_VIEW_ATTACH_POLICY_DIRTY = 0x10000; + static final int VPR_VIEWPLATFORM_DIRTY = 0x20000; + + // PhysicalEnvironment fields has changed. + static final int PE_COE_TO_TRACKER_BASE_DIRTY = 0x100000; + static final int PE_TRACKING_AVAILABLE_DIRTY = 0x200000; + static final int PE_COE_CENTER_IN_PWORLD_POLICY_DIRTY = 0x400000; + + // PhysicalBody fields has changed. + static final int PB_EYE_POSITION_DIRTY = 0x1000000; + static final int PB_EAR_POSITION_DIRTY = 0x2000000; + static final int PB_NOMINAL_EYE_HEIGHT_FROM_GROUND_DIRTY = 0x4000000; + static final int PB_NOMINAL_EYE_OFFSET_FROM_NOMINAL_SCREEN_DIRTY = 0x8000000; + + + // Mask that indicates this View's view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + int vDirtyMask = (COMPATIBILITY_MODE_DIRTY | SCREEN_SCALE_POLICY_DIRTY + | SCREEN_SCALE_DIRTY | WINDOW_RESIZE_POLICY_DIRTY + | VIEW_POLICY_DIRTY | CLIP_DIRTY + | PROJECTION_POLICY_DIRTY | WINDOW_MOVEMENT_POLICY_DIRTY + | WINDOW_EYE_POINT_POLICY_DIRTY | MONOSCOPIC_VIEW_POLICY_DIRTY + | FIELD_OF_VIEW_DIRTY | TRACKING_ENABLE_DIRTY + | USER_HEAD_TO_VWORLD_ENABLE_DIRTY + | COEXISTENCE_CENTERING_ENABLE_DIRTY + | LEFT_MANUAL_EYE_IN_COEXISTENCE_DIRTY + | RIGHT_MANUAL_EYE_IN_COEXISTENCE_DIRTY + | VISIBILITY_POLICY_DIRTY); + + + // + // This object contains a specification of the user's physical body. + // + // Attributes of this object are defined in head coordinates and + // include information such as the location of the user's eyes and + // ears. + // The origin is defined to be halfway between the left and right eye + // in the plane of the face. + // The x-axis extends to the right (of the head looking out from the head). + // The y-axis extends up. The z-axis extends to the rear of the head. + // + PhysicalBody physicalBody; + + // This object contains a specification of the physical environment. + PhysicalEnvironment physicalEnvironment; + + // View model compatibility mode flag + boolean compatibilityModeEnable = false; + + // View model coexistenceCenteringEnable flag + boolean coexistenceCenteringEnable = true; + + Point3d leftManualEyeInCoexistence = new Point3d(); + Point3d rightManualEyeInCoexistence = new Point3d(); + + // + // Indicates which major mode of view computation to use: + // HMD mode or screen/fish-tank-VR mode. + // + int viewPolicy = SCREEN_VIEW; + + // The current projection policy (parallel versus perspective) + int projectionPolicy = PERSPECTIVE_PROJECTION; + + // + // The view model's field of view. + // + double fieldOfView = 45.0 * Math.PI / 180.0; + + // + // The distance away from the clip origin + // in the direction of gaze for the front and back clip planes. + // The default values are in meters. + // + double frontClipDistance = 0.1; + double backClipDistance = 10.0; + + // This variable specifies where the screen scale comes from + int screenScalePolicy = SCALE_SCREEN_SIZE; + + // The screen scale value used when the screen scale policy is + // SCALE_EXPLICIT + double screenScale = 1.0; + + // + // This variable specifies how Java 3D modifies the view when + // the window is resized (VIRTUAL_WORLD or PHYSICAL_WORLD). + // + int windowResizePolicy = PHYSICAL_WORLD; + + // + // This variable specifies how Java 3D modifies the view when + // the window is moved (VIRTUAL_WORLD or PHYSICAL_WORLD). + // + int windowMovementPolicy = PHYSICAL_WORLD; + + // + // Specifies how Java 3D handles the predefined eyepoint in + // non-head-tracked environment (RELATIVE_TO_SCREEN, + // RELATIVE_TO_WINDOW, RELATIVE_TO_FIELD_OF_VIEW, or + // RELATIVE_TO_COEXISTENCE) + // + int windowEyepointPolicy = RELATIVE_TO_FIELD_OF_VIEW; + + // + // Specifies how Java 3D generates monoscopic view + // (LEFT_EYE_VIEW, RIGHT_EYE_VIEW, or CYCLOPEAN_EYE_VIEW). + // + int monoscopicViewPolicy = CYCLOPEAN_EYE_VIEW; + + /** + * Defines the policy for placing the front clipping plane. + * Legal values include PHYSICAL_EYE, PHYSICAL_SCREEN, + * VIRTUAL_EYE, and VIRTUAL_SCREEN. + */ + int frontClipPolicy = PHYSICAL_EYE; + + /** + * Defines the policy for placing the back clipping plane. + */ + int backClipPolicy = PHYSICAL_EYE; + + /** + * Defines the visibility policy. + */ + int visibilityPolicy = VISIBILITY_DRAW_VISIBLE; + + /** + * Defines the transparency sorting policy. + */ + int transparencySortingPolicy = TRANSPARENCY_SORT_NONE; + + /** + * Flag to enable tracking, if so allowed by the trackingAvailable flag. + */ + boolean trackingEnable = false; + + /** + * This setting enables the continuous updating by Java 3D of the + * userHeadToVworld transform. + */ + boolean userHeadToVworldEnable = false; + + /** + * The view platform currently associated with this view. + */ + private ViewPlatform viewPlatform = null; + + // The current compatibility mode view transform + Transform3D compatVpcToEc = new Transform3D(); + + // The current compatibility mode projection transforms + Transform3D compatLeftProjection = new Transform3D(); + Transform3D compatRightProjection = new Transform3D(); + + // The long id of this view - used for dirty bit evaluation in the scene graph + Integer viewId = null; + int viewIndex = -1; + + // A boolean that indicates whether or not this is the primary view + boolean primaryView = false; + + // A boolean that indicates whether or not this view is active as + // seen by MasterControl + boolean active = false; + + // A boolean that indicates whether or not this view is active as + // seen by this view. There is a delay before MasterControl set + // active flag, so a local activeStatus is used. Otherwise + // activate event may lost if it proceed by deactivate event + // but MC not yet set active to false. This happens in + // viewplatform detach and attach. + boolean activeStatus = false; + + // This boolean indicates whether or not the view is running. It + // is used for startView/stopView + volatile boolean isRunning = true; + + // A flag to indicate that we are in a canvas callback routine + boolean inCanvasCallback = false; + + // + // Flag to enable depth buffer freeze during trasparent rendering pass + // + boolean depthBufferFreezeTransparent = true; + + // + // Flag to enable scene antialiasing + // + boolean sceneAntialiasingEnable = false; + + // + // Flag to enable local eye lighting + // + boolean localEyeLightingEnable = false; + + // Array Lists to track the screens and canvases associated with this View. + // use getScreens() to access this + private ArrayList screenList = new ArrayList(); + + // use getCanvasList() to access this + private ArrayList canvasList = new ArrayList(); + + private Canvas3D[][] cachedCanvasList; + private Canvas3D[] cachedCanvases; + private Screen3D[] cachedScreens; + private int longestScreenList = 0; + private boolean canvasesDirty = true; + + // Flag to notify user thread when renderOnce is finished + volatile boolean renderOnceFinish = true; + + // Lock to synchronize start/stop/renderOnce call + private Object startStopViewLock = new Object(); + + // Lock for evaluateActive() only. This is used to prevent + // using lock this which will cause deadlock when MC call + // snapshot which waitForMC() in user thread. + private Object evaluateLock = new Object(); + + /** + * use for stop view, when stopview, set to count -1, + * when reach 1, call stopView() in MC and reset to -1. + */ + int stopViewCount = -1; + + /** + * False if current frame cycle time less than minimum frame cycle time + */ + boolean isMinCycleTimeAchieve = true; + + // Time to sleep if minimum frame cycle time not achieve + long sleepTime = 0; + + // use in pure immediate mode to tell whether this view rendering + // thread is added in MC renderThreadData + volatile boolean inRenderThreadData = false; + + // use to notify MC that render bin has run once, and is ready for + // renderer to render + boolean renderBinReady = false; + + // No of time setUniverse() is invoke + long universeCount = 0; + + // The universe count when UNREGISTER_VIEW request is post, + // this is used to distingish whether new setUniverse() is + // invoked after UNREGISTER_VIEW request post to avoid + // resetting the newly set universe. + long resetUnivCount = 0; + + // This notify user thread waitForMC() to continue when + // MC finish unregisterView + volatile boolean doneUnregister = false; + + static final int TRANSP_SORT_POLICY_CHANGED = 0x0001; + static final int OTHER_ATTRS_CHANGED = 0x0002; + + /** + * Constructs a View object with default parameters. The default + * values are as follows: + *

    + * view policy : SCREEN_VIEW
    + * projection policy : PERSPECTIVE_PROJECTION
    + * screen scale policy : SCALE_SCREEN_SIZE
    + * window resize policy : PHYSICAL_WORLD
    + * window movement policy : PHYSICAL_WORLD
    + * window eyepoint policy : RELATIVE_TO_FIELD_OF_VIEW
    + * monoscopic view policy : CYCLOPEAN_EYE_VIEW
    + * front clip policy : PHYSICAL_EYE
    + * back clip policy : PHYSICAL_EYE
    + * visibility policy : VISIBILITY_DRAW_VISIBLE
    + * transparency sorting policy : TRANSPARENCY_SORT_NONE
    + * coexistenceCentering flag : true
    + * compatibility mode : false
    + * left projection : identity
    + * right projection : identity
    + * vpc to ec transform : identity
    + * physical body : null
    + * physical environment : null
    + * screen scale : 1.0
    + * field of view : PI/4
    + * left manual eye in coexistence : (-0.033, 0.0, 0.4572)
    + * right manual eye in coexistence : (0.033, 0.0, 0.4572)
    + * front clip distance : 0.1
    + * back clip distance : 10.0
    + * tracking enable : false
    + * user head to vworld enable : false
    + * list of Canvas3D objects : empty
    + * depth buffer freeze transparent : true
    + * scene antialiasing : false
    + * local eye lighting : false
    + * view platform : null
    + * behavior scheduler running : true
    + * view running : true
    + * minimum frame cycle time : 0
    + *
+ */ + public View() { + viewCache = new ViewCache(this); + } + + /** + * Sets the policy for view computation. + * This variable specifies how Java 3D uses its transforms in + * computing new viewpoints. + *
    + *
  • SCREEN_VIEW specifies that Java 3D should compute a new viewpoint + * using the sequence of transforms appropriate to screen-based + * head-tracked display environments (fish-tank VR/portals/VR-desks). + *
  • + *
  • HMD_VIEW specifies that Java 3D should compute a new viewpoint + * using the sequence of transforms appropriate to head mounted + * display environments. + *
  • + *
+ * The default view policy is SCREEN_VIEW. + * @param policy the new policy, one of SCREEN_VIEW or HMD_VIEW + * @exception IllegalArgumentException if policy is a value other than + * SCREEN_VIEW or HMD_VIEW + * @exception IllegalStateException if the specified policy + * is HMD_VIEW and if any canvas associated with this view is + * a stereo canvas with a monoscopicEyePolicy of CYCLOPEAN_EYE_VIEW + */ + public void setViewPolicy(int policy) { + if (policy != HMD_VIEW && + policy != SCREEN_VIEW) { + + throw new IllegalArgumentException(J3dI18N.getString("View0")); + } + if(policy == HMD_VIEW) { + // Check the following : + // 1) If the view is in HMD mode and there exists a canvas in + // CYCLOPEAN_EYE_VIEW mode then throw exception. + synchronized (canvasList) { + for (int i=canvases.size()-1; i>=0; i--) { + Canvas3D c3d = (Canvas3D)canvases.elementAt(i); + + if ((c3d.monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) && + (!c3d.useStereo)){ + throw new + IllegalStateException(J3dI18N.getString("View31")); + } + } + } + } + synchronized(this) { + this.viewPolicy = policy; + vDirtyMask |= View.VIEW_POLICY_DIRTY; + } + repaint(); + } + + /** + * Retrieves the current view computation policy for this View. + * @return one of: SCREEN_VIEW or HMD_VIEW. + */ + public int getViewPolicy() { + return this.viewPolicy; + } + + /** + * Sets the projection policy for this View. + * This variable specifies the type of projection transform that + * will be generated. A value of PARALLEL_PROJECTION specifies that + * a parallel projection transform is generated. A value of + * PERSPECTIVE_PROJECTION specifies that + * a perspective projection transform is generated. + * The default projection policy is PERSPECTIVE. + * @param policy the new policy, one of PARALLEL_PROJECTION or + * PERSPECTIVE_PROJECTION + * @exception IllegalArgumentException if policy is a value other than + * PARALLEL_PROJECTION or PERSPECTIVE_PROJECTION + */ + public void setProjectionPolicy(int policy) { + if (policy != PERSPECTIVE_PROJECTION && + policy != PARALLEL_PROJECTION) { + + throw new IllegalArgumentException(J3dI18N.getString("View1")); + } + synchronized(this) { + this.projectionPolicy = policy; + vDirtyMask |= View.PROJECTION_POLICY_DIRTY; + } + + repaint(); + } + + /** + * Retrieves the current projection policy for this View. + * @return one of: PARALLEL_PROJECTION or PERSPECTIVE_PROJECTION. + */ + public int getProjectionPolicy() { + return this.projectionPolicy; + } + + /** + * Sets the screen scale policy for this view. + * This policy specifies how the screen scale is derived. + * The value is either SCALE_SCREEN_SIZE or SCALE_EXPLICIT. + * A value of SCALE_SCREEN_SIZE specifies that the scale is derived + * from the size of the physical screen. A value of SCALE_EXPLICIT + * specifies that the scale is taken directly from the screenScale + * parameter. + * The default screen scale policy is SCALE_SCREEN_SIZE. + * @param policy the new policy, one of SCALE_SCREEN_SIZE or + * SCALE_EXPLICIT. + */ + public void setScreenScalePolicy(int policy) { + + synchronized(this) { + this.screenScalePolicy = policy; + vDirtyMask |= View.SCREEN_SCALE_POLICY_DIRTY; + } + + repaint(); + } + + /** + * Returns the current screen scale policy, one of: + * SCALE_SCREEN_SIZE or SCALE_EXPLICIT. + * @return the current screen scale policy + */ + public int getScreenScalePolicy() { + return this.screenScalePolicy; + } + + /** + * Sets the window resize policy. + * This variable specifies how Java 3D modifies the view when + * users resize windows. The variable can contain one of + * VIRTUAL_WORLD or PHYSICAL_WORLD. + * A value of VIRTUAL_WORLD implies that the original image + * remains the same size on the screen but the user sees more + * or less of the virtual world depending on whether the window + * grew or shrank in size. + * A value of PHYSICAL_WORLD implies that the original image + * continues to fill the window in the same way using more or + * less pixels depending on whether the window grew or shrank + * in size. + * The default window resize policy is PHYSICAL_WORLD. + * @param policy the new policy, one of VIRTUAL_WORLD or PHYSICAL_WORLD + */ + public void setWindowResizePolicy(int policy) { + + synchronized(this) { + this.windowResizePolicy = policy; + vDirtyMask |= View.WINDOW_RESIZE_POLICY_DIRTY; + } + repaint(); + } + + /** + * Returns the current window resize policy, one of: + * VIRTUAL_WORLD or PHYSICAL_WORLD. + * @return the current window resize policy + */ + public int getWindowResizePolicy() { + return this.windowResizePolicy; + } + + /** + * Sets the window movement policy. + * This variable specifies what part of the virtual world Java 3D + * draws as a function of window placement on the screen. The + * variable can contain one of VIRTUAL_WORLD or PHYSICAL_WORLD. + * A value of VIRTUAL_WORLD implies that the image seen in the + * window changes as the position of the window shifts on the + * screen. (This mode acts as if the window were a window into + * the virtual world.) + * A value of PHYSICAL_WORLD implies that the image seen in the + * window remains the same no matter where the user positions + * the window on the screen. + * The default window movement policy is PHYSICAL_WORLD. + * @param policy the new policy, one of VIRTUAL_WORLD or PHYSICAL_WORLD + */ + public void setWindowMovementPolicy(int policy) { + + synchronized(this) { + this.windowMovementPolicy = policy; + vDirtyMask |= View.WINDOW_MOVEMENT_POLICY_DIRTY; + } + repaint(); + } + + /** + * Returns the current window movement policy, + * one of: VIRTUAL_WORLD or PHYSICAL_WORLD. + * @return the current window movement policy + */ + public int getWindowMovementPolicy() { + return this.windowMovementPolicy; + } + + /** + * Sets the view model's window eyepoint policy. + * This variable specifies how Java 3D handles the predefined eye + * point in a non-head-tracked environment. The variable can contain + * one of: + *
    + *
  • RELATIVE_TO_SCREEN, Java 3D should interpret the + * given fixed-eyepoint position as relative to the screen (this + * implies that the view frustum shape will change whenever a + * user moves the location of a window on the screen). + *
  • + *
  • RELATIVE_TO_WINDOW, Java 3D should interpret the + * given fixed-eyepoint position as relative to the window. In this + * mode, the X and Y values are taken as the center of the window and + * the Z value is taken from the canvas eyepoint position. + *
  • + *
  • RELATIVE_TO_FIELD_OF_VIEW, Java 3D should + * modify the position of the eyepoint to match any changes in field + * of view (the view frustum will change whenever the application + * program changes the field of view). + *
  • + *
  • RELATIVE_TO_COEXISTENCE, Java 3D should interpret the eye's + * position in coexistence coordinates. In this mode, the eye position + * is taken from the view (rather than the Canvas3D) and transformed from + * coexistence coordinates to image plate coordinates for each + * Canvas3D. The resulting eye position is relative to the screen (this + * implies that the view frustum shape will change whenever a + * user moves the location of a window on the screen). + *
  • + *
+ * The default window eyepoint policy is RELATIVE_TO_FIELD_OF_VIEW. + * @param policy the new policy, one of RELATIVE_TO_SCREEN, + * RELATIVE_TO_WINDOW, RELATIVE_TO_FIELD_OF_VIEW, or + * RELATIVE_TO_COEXISTENCE + */ + public void setWindowEyepointPolicy(int policy) { + synchronized(this) { + this.windowEyepointPolicy = policy; + vDirtyMask |= View.WINDOW_EYE_POINT_POLICY_DIRTY; + } + + repaint(); + } + + /** + * Returns the current window eyepoint policy, one of: + * RELATIVE_TO_SCREEN, RELATIVE_TO_WINDOW, RELATIVE_TO_FIELD_OF_VIEW or + * RELATIVE_TO_COEXISTENCE. + * @return the current window eyepoint policy + */ + public int getWindowEyepointPolicy() { + return this.windowEyepointPolicy; + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * Canvas3D.setMonoscopicViewPolicy + */ + public void setMonoscopicViewPolicy(int policy) { + synchronized(this) { + this.monoscopicViewPolicy = policy; + vDirtyMask |= View.MONOSCOPIC_VIEW_POLICY_DIRTY; + } + repaint(); + } + + /** + * @deprecated As of Java 3D version 1.2, replaced by + * Canvas3D.getMonoscopicViewPolicy + */ + public int getMonoscopicViewPolicy() { + return this.monoscopicViewPolicy; + } + + /** + * Sets the coexistenceCentering enable flag to true or false. + * If the coexistenceCentering flag is true, the center of + * coexistence in image plate coordinates, as specified by the + * trackerBaseToImagePlate transform, is translated to the center + * of either the window or the screen in image plate coordinates, + * according to the value of windowMovementPolicy. + * + *

+ * By default, coexistenceCentering is enabled. It should be + * disabled if the trackerBaseToImagePlate calibration transform + * is set to a value other than the identity (for example, when + * rendering to multiple screens or when head tracking is + * enabled). This flag is ignored for HMD mode, or when the + * coexistenceCenterInPworldPolicy is not + * NOMINAL_SCREEN. + * + * @param flag the new coexistenceCentering enable flag + * + * @since Java 3D 1.2 + */ + public void setCoexistenceCenteringEnable(boolean flag) { + synchronized(this) { + this.coexistenceCenteringEnable = flag; + vDirtyMask |= View.COEXISTENCE_CENTERING_ENABLE_DIRTY; + } + repaint(); + } + + /** + * Retrieves the coexistenceCentering enable flag. + * + * @return the current coexistenceCentering enable flag + * + * @since Java 3D 1.2 + */ + public boolean getCoexistenceCenteringEnable() { + return this.coexistenceCenteringEnable; + } + + /** + * Sets the compatibility mode enable flag to true or false. + * Compatibility mode is disabled by default. + * @param flag the new compatibility mode enable flag + */ + public void setCompatibilityModeEnable(boolean flag) { + synchronized(this) { + this.compatibilityModeEnable = flag; + vDirtyMask |= View.COMPATIBILITY_MODE_DIRTY; + } + repaint(); + } + + /** + * Retrieves the compatibility mode enable flag. + * @return the current compatibility mode enable flag + */ + public boolean getCompatibilityModeEnable() { + return this.compatibilityModeEnable; + } + + /** + * Compatibility mode method that specifies a viewing frustum for + * the left eye that transforms points in Eye Coordinates (EC) to + * Clipping Coordinates (CC). + * If compatibility mode is disabled, then this transform is not used; + * the actual projection is derived from other values. + * In monoscopic mode, only the left eye projection matrix is used. + * @param projection the new left eye projection transform + * @exception RestrictedAccessException if compatibility mode is disabled. + */ + public void setLeftProjection(Transform3D projection) { + if (!compatibilityModeEnable) { + throw new RestrictedAccessException(J3dI18N.getString("View2")); + } + + synchronized(this) { + compatLeftProjection.setWithLock(projection); + vDirtyMask |= View.COMPATIBILITY_MODE_DIRTY; + } + repaint(); + } + + /** + * Compatibility mode method that specifies a viewing frustum for + * the right eye that transforms points in Eye Coordinates (EC) to + * Clipping Coordinates (CC). + * If compatibility mode is disabled, then this transform is not used; + * the actual projection is derived from other values. + * In monoscopic mode, the right eye projection matrix is ignored. + * @param projection the new right eye projection transform + * @exception RestrictedAccessException if compatibility mode is disabled. + */ + public void setRightProjection(Transform3D projection) { + if (!compatibilityModeEnable) { + throw new RestrictedAccessException(J3dI18N.getString("View2")); + } + + synchronized(this) { + compatRightProjection.setWithLock(projection); + vDirtyMask |= View.COMPATIBILITY_MODE_DIRTY; + } + + repaint(); + } + + /** + * Compatibility mode method that retrieves the current + * compatibility mode projection transform for the left eye and + * places it into the specified object. + * @param projection the Transform3D object that will receive the + * projection + * @exception RestrictedAccessException if compatibility mode is disabled. + */ + public void getLeftProjection(Transform3D projection) { + if (!compatibilityModeEnable) { + throw new RestrictedAccessException(J3dI18N.getString("View4")); + } + + projection.set(compatLeftProjection); + } + + /** + * Compatibility mode method that retrieves the current + * compatibility mode projection transform for the right eye and + * places it into the specified object. + * @param projection the Transform3D object that will receive the + * projection + * @exception RestrictedAccessException if compatibility mode is disabled. + */ + public void getRightProjection(Transform3D projection) { + if (!compatibilityModeEnable) { + throw new RestrictedAccessException(J3dI18N.getString("View4")); + } + + projection.set(compatRightProjection); + } + + /** + * Compatibility mode method that specifies the ViewPlatform + * Coordinates (VPC) to Eye Coordinates (EC) transform. + * If compatibility mode is disabled, then this transform + * is derived from other values and is read-only. + * @param vpcToEc the new VPC to EC transform + * @exception RestrictedAccessException if compatibility mode is disabled. + * @exception BadTransformException if the transform is not affine. + */ + public void setVpcToEc(Transform3D vpcToEc) { + if (!compatibilityModeEnable) { + throw new RestrictedAccessException(J3dI18N.getString("View6")); + } + + if (!vpcToEc.isAffine()) { + throw new BadTransformException(J3dI18N.getString("View7")); + } + + synchronized(this) { + compatVpcToEc.setWithLock(vpcToEc); + vDirtyMask |= View.COMPATIBILITY_MODE_DIRTY; + } + + repaint(); + } + + /** + * Compatibility mode method that retrieves the current + * ViewPlatform Coordinates (VPC) system to + * Eye Coordinates (EC) transform and copies it into the specified + * object. + * @param vpcToEc the object that will receive the vpcToEc transform. + * @exception RestrictedAccessException if compatibility mode is disabled. + */ + public void getVpcToEc(Transform3D vpcToEc) { + if (!compatibilityModeEnable) { + throw new RestrictedAccessException(J3dI18N.getString("View8")); + } + + vpcToEc.set(compatVpcToEc); + } + + /** + * Sets the view model's physical body to the PhysicalBody object provided. + * Java 3D uses the parameters in the PhysicalBody to ensure accurate + * image and sound generation when in head-tracked mode. + * @param physicalBody the new PhysicalBody object + */ + public void setPhysicalBody(PhysicalBody physicalBody) { + // need to synchronize variable activateStatus + synchronized (canvasList) { + if (activeStatus) { + if (this.physicalBody != null) { + this.physicalBody.removeUser(this); + } + physicalBody.addUser(this); + } + } + this.physicalBody = physicalBody; + repaint(); + } + + /** + * Returns a reference to the view model's PhysicalBody object. + * @return the view object's PhysicalBody object + */ + public PhysicalBody getPhysicalBody() { + return this.physicalBody; + } + + /** + * Sets the view model's physical environment to the PhysicalEnvironment + * object provided. + * @param physicalEnvironment the new PhysicalEnvironment object + */ + public void setPhysicalEnvironment(PhysicalEnvironment physicalEnvironment) { + synchronized (canvasList) { + if (activeStatus) { + if (this.physicalEnvironment != null) { + this.physicalEnvironment.removeUser(this); + } + physicalEnvironment.addUser(this); + } + } + this.physicalEnvironment = physicalEnvironment; + + + if ((viewPlatform != null) && viewPlatform.isLive()) { + VirtualUniverse.mc.postRequest(MasterControl.PHYSICAL_ENV_CHANGE, this); + } + repaint(); + } + + /** + * Returns a reference to the view model's PhysicalEnvironment object. + * @return the view object's PhysicalEnvironment object + */ + public PhysicalEnvironment getPhysicalEnvironment() { + return this.physicalEnvironment; + } + + /** + * Sets the screen scale value for this view. + * This is used when the screen scale policy is SCALE_EXPLICIT. + * The default value is 1.0 (i.e., unscaled). + * @param scale the new screen scale + */ + public void setScreenScale(double scale) { + synchronized(this) { + this.screenScale = scale; + vDirtyMask |= View.SCREEN_SCALE_DIRTY; + } + repaint(); + } + + /** + * Returns the current screen scale value + * @return the current screen scale value + */ + public double getScreenScale() { + return this.screenScale; + } + + /** + * Sets the field of view used to compute the projection transform. + * This is used when head tracking is disabled and when the Canvas3D's + * windowEyepointPolicy is RELATIVE_TO_FIELD_OF_VIEW. + * @param fieldOfView the new field of view in radians + */ + public void setFieldOfView(double fieldOfView) { + synchronized(this) { + this.fieldOfView = fieldOfView; + vDirtyMask |= View.FIELD_OF_VIEW_DIRTY; + } + repaint(); + + } + + /** + * Returns the current field of view. + * @return the current field of view in radians + */ + public double getFieldOfView() { + return this.fieldOfView; + } + + + /** + * Sets the position of the manual left eye in coexistence + * coordinates. This value determines eye placement when a head + * tracker is not in use and the application is directly controlling + * the eye position in coexistence coordinates. This value is + * ignored when in head-tracked mode or when the + * windowEyePointPolicy is not RELATIVE_TO_COEXISTENCE. + * + * @param position the new manual left eye position + * + * @since Java 3D 1.2 + */ + public void setLeftManualEyeInCoexistence(Point3d position) { + synchronized(this) { + leftManualEyeInCoexistence.set(position); + vDirtyMask |= View.LEFT_MANUAL_EYE_IN_COEXISTENCE_DIRTY; + } + repaint(); + } + + /** + * Sets the position of the manual right eye in coexistence + * coordinates. This value determines eye placement when a head + * tracker is not in use and the application is directly controlling + * the eye position in coexistence coordinates. This value is + * ignored when in head-tracked mode or when the + * windowEyePointPolicy is not RELATIVE_TO_COEXISTENCE. + * + * @param position the new manual right eye position + * + * @since Java 3D 1.2 + */ + public void setRightManualEyeInCoexistence(Point3d position) { + synchronized(this) { + rightManualEyeInCoexistence.set(position); + vDirtyMask |= View.RIGHT_MANUAL_EYE_IN_COEXISTENCE_DIRTY; + } + repaint(); + } + + /** + * Retrieves the position of the user-specified, manual left eye + * in coexistence + * coordinates and copies that value into the object provided. + * @param position the object that will receive the position + * + * @since Java 3D 1.2 + */ + public void getLeftManualEyeInCoexistence(Point3d position) { + position.set(leftManualEyeInCoexistence); + } + + /** + * Retrieves the position of the user-specified, manual right eye + * in coexistence + * coordinates and copies that value into the object provided. + * @param position the object that will receive the position + * + * @since Java 3D 1.2 + */ + public void getRightManualEyeInCoexistence(Point3d position) { + position.set(rightManualEyeInCoexistence); + } + + + /** + * Sets the view model's front clip distance. + * This value specifies the distance away from the eyepoint + * in the direction of gaze where objects stop disappearing. + * Objects closer to the eye than the front clip + * distance are not drawn. The default value is 0.1 meters. + *

+ * There are several considerations that need to be taken into + * account when choosing values for the front and back clip + * distances. + *

    + *
  • The front clip distance must be greater than + * 0.0 in physical eye coordinates.
  • + *
  • The front clipping plane must be in front of the + * back clipping plane, that is, the front clip distance + * must be less than the back clip distance in physical eye + * coordinates.
  • + *
  • The front and back clip distances, in physical + * eye coordinates, must be less than the largest positive + * single-precision floating point value, Float.MAX_VALUE. + * In practice, since these physical eye coordinate distances are in + * meters, the values should be much less than that. + *
  • The ratio of the back distance divided by the front distance, + * in physical eye coordinates, affects Z-buffer precision. This + * ratio should be less than about 3000 in order to accommodate 16-bit + * Z-buffers. Values of 100 to less than 1000 will produce better + * results.
  • + *
+ * Violating any of the above rules will result in undefined + * behavior. In many cases, no picture will be drawn. + * + * @param distance the new front clip distance + * @see #setBackClipDistance + */ + public void setFrontClipDistance(double distance) { + synchronized(this) { + this.frontClipDistance = distance; + vDirtyMask |= View.CLIP_DIRTY; + } + repaint(); + } + + /** + * Returns the view model's front clip distance. + * @return the current front clip distance + */ + public double getFrontClipDistance() { + return this.frontClipDistance; + } + + /** + * Sets the view model's back clip distance. + * The parameter specifies the distance from the eyepoint + * in the direction of gaze to where objects begin disappearing. + * Objects farther away from the eye than the + * back clip distance are not drawn. + * The default value is 10.0 meters. + *

+ * There are several considerations that need to be taken into + * account when choosing values for the front and back clip + * distances. These are enumerated in the description of + * setFrontClipDistance. + *

+ * Note that this attribute is only used if there is no Clip node + * that is in scope of the view platform associated with this view. + * @param distance the new back clip distance + * @see #setFrontClipDistance + * @see Clip#setBackDistance + */ + public void setBackClipDistance(double distance) { + synchronized(this) { + this.backClipDistance = distance; + vDirtyMask |= View.CLIP_DIRTY; + } + repaint(); + } + + /** + * Returns the view model's back clip distance. + * @return the current back clip distance + */ + public double getBackClipDistance() { + return this.backClipDistance; + } + + /** + * Retrieves the user-head to virtual-world transform + * and copies that value into the transform provided. + * @param t the Transform3D object that will receive the transform + */ + public void getUserHeadToVworld(Transform3D t) { + + if( userHeadToVworldEnable ) { + + // get the calculated userHeadToVworld transform + // from the view cache. + // grab the first canvas -- not sure for multiple canvases + Canvas3D canvas = (Canvas3D) this.canvases.firstElement(); + synchronized(canvas.canvasViewCache) { + t.set(canvas.canvasViewCache.getHeadToVworld()); + } + }else { + throw new RestrictedAccessException(J3dI18N.getString("View9")); + } + } + + /** + * Sets the view model's front clip policy, the policy Java 3D uses + * in computing where to place the front clip plane. The variable + * can contain one of: + *

    + *
  • VIRTUAL_EYE, to specify that the associated distance is + * from the eye and in units of virtual distance + *
  • + *
  • PHYSICAL_EYE, to specify that the associated distance is + * from the eye and in units of physical distance (meters) + *
  • + *
  • VIRTUAL_SCREEN, to specify that the associated distance is + * from the screen and in units of virtual distance + *
  • + *
  • PHYSICAL_SCREEN, to specify that the associated distance is + * from the screen and in units of physical distance (meters) + *
  • + *
+ * The default front clip policy is PHYSICAL_EYE. + * @param policy the new policy, one of PHYSICAL_EYE, PHYSICAL_SCREEN, + * VIRTUAL_EYE, or VIRTUAL_SCREEN + */ + public void setFrontClipPolicy(int policy) { + synchronized(this) { + this.frontClipPolicy = policy; + vDirtyMask |= View.CLIP_DIRTY; + } + repaint(); + } + + /** + * Returns the view model's current front clip policy. + * @return one of: + * VIRTUAL_EYE, PHYSICAL_EYE, VIRTUAL_SCREEN, or PHYSICAL_SCREEN + */ + public int getFrontClipPolicy() { + return this.frontClipPolicy; + } + + /** + * Sets the view model's back clip policy, the policy Java 3D uses + * in computing where to place the back clip plane. The variable + * can contain one of: + *
    + *
  • VIRTUAL_EYE, to specify that the associated distance is + * from the eye and in units of virtual distance + *
  • + *
  • PHYSICAL_EYE, to specify that the associated distance is + * from the eye and in units of physical distance (meters) + *
  • + *
  • VIRTUAL_SCREEN, to specify that the associated distance is + * from the screen and in units of virtual distance + *
  • + *
  • PHYSICAL_SCREEN, to specify that the associated distance is + * from the screen and in units of physical distance (meters) + *
  • + *
+ * The default back clip policy is PHYSICAL_EYE. + * @param policy the new policy, one of PHYSICAL_EYE, PHYSICAL_SCREEN, + * VIRTUAL_EYE, or VIRTUAL_SCREEN + */ + public void setBackClipPolicy(int policy) { + synchronized(this) { + this.backClipPolicy = policy; + vDirtyMask |= View.CLIP_DIRTY; + } + repaint(); + } + + /** + * Returns the view model's current back clip policy. + * @return one of: + * VIRTUAL_EYE, PHYSICAL_EYE, VIRTUAL_SCREEN, or PHYSICAL_SCREEN + */ + public int getBackClipPolicy() { + return this.backClipPolicy; + } + + /** + * Sets the visibility policy for this view. This attribute + * is one of: + *
    + *
  • VISIBILITY_DRAW_VISIBLE, to specify that only visible objects + * are drawn. + *
  • + *
  • VISIBILITY_DRAW_INVISIBLE, to specify that only invisible objects + * are drawn. + *
  • + *
  • VISIBILITY_DRAW_ALL, to specify that both visible and + * invisible objects are drawn. + *
  • + *
+ * The default visibility policy is VISIBILITY_DRAW_VISIBLE. + * + * @param policy the new policy, one of VISIBILITY_DRAW_VISIBLE, + * VISIBILITY_DRAW_INVISIBLE, or VISIBILITY_DRAW_ALL. + * + * @see RenderingAttributes#setVisible + * + * @since Java 3D 1.2 + */ + public void setVisibilityPolicy(int policy) { + + synchronized(this) { + this.visibilityPolicy = policy; + vDirtyMask |= View.VISIBILITY_POLICY_DIRTY; + } + + if (activeStatus && isRunning) { + + J3dMessage vpMessage = new J3dMessage(); + vpMessage.universe = universe; + vpMessage.view = this; + vpMessage.type = J3dMessage.UPDATE_VIEW; + vpMessage.threads = J3dThread.UPDATE_RENDER; + vpMessage.args[0] = this; + synchronized(((ViewPlatformRetained)viewPlatform.retained).sphere) { + vpMessage.args[1] = new Float(((ViewPlatformRetained)viewPlatform. + retained).sphere.radius); + } + vpMessage.args[2] = new Integer(OTHER_ATTRS_CHANGED); + vpMessage.args[3] = new Integer(transparencySortingPolicy); + VirtualUniverse.mc.processMessage(vpMessage); + } + } + + /** + * Retrieves the current visibility policy. + * @return one of: + * VISIBILITY_DRAW_VISIBLE, + * VISIBILITY_DRAW_INVISIBLE, or VISIBILITY_DRAW_ALL. + * + * @since Java 3D 1.2 + */ + public int getVisibilityPolicy() { + return this.visibilityPolicy; + } + + /** + * Sets the transparency sorting policy for this view. This attribute + * is one of: + * + *
    + *
  • TRANSPARENCY_SORT_NONE, to specify that no depth sorting of + * transparent objects is performed. Transparent objects are + * drawn after opaque objects, but are not sorted from back to + * front.
  • + * + *
  • TRANSPARENCY_SORT_GEOMETRY, to specify that transparent + * objects are depth-sorted on a per-geometry basis. Each + * geometry object of each transparent Shape3D node is drawn from + * back to front. Note that this policy will not split geometry + * into smaller pieces, so intersecting or intertwined objects may + * not be sorted correctly.
  • + *
+ * + * The default policy is TRANSPARENCY_SORT_NONE. + * + * @param policy the new policy, one of TRANSPARENCY_SORT_NONE + * or TRANSPARENCY_SORT_GEOMETRY. + * + * @since Java 3D 1.3 + */ + public void setTransparencySortingPolicy(int policy) { + if (policy == transparencySortingPolicy) { + return; + } + + transparencySortingPolicy = policy; + if (activeStatus && isRunning) { + + J3dMessage vpMessage = new J3dMessage(); + vpMessage.universe = universe; + vpMessage.view = this; + vpMessage.type = J3dMessage.UPDATE_VIEW; + vpMessage.threads = J3dThread.UPDATE_RENDER; + vpMessage.args[0] = this; + vpMessage.args[1] = null; + vpMessage.args[2] = new Integer(TRANSP_SORT_POLICY_CHANGED); + vpMessage.args[3] = new Integer(policy); + VirtualUniverse.mc.processMessage(vpMessage); + } + } + + /** + * Retrieves the current transparency sorting policy. + * @return one of: + * TRANSPARENCY_SORT_NONE or TRANSPARENCY_SORT_GEOMETRY. + * + * @since Java 3D 1.3 + */ + public int getTransparencySortingPolicy() { + return this.transparencySortingPolicy; + } + + /** + * Turns head tracking on or off for this view. + * @param flag specifies whether head tracking is enabled or + * disabled for this view + */ + public void setTrackingEnable(boolean flag) { + + synchronized(this) { + this.trackingEnable = flag; + vDirtyMask |= View.TRACKING_ENABLE_DIRTY; + } + + repaint(); + } + + /** + * Returns a status flag indicating whether or not head tracking + * is enabled. + * @return a flag telling whether head tracking is enabled + */ + public boolean getTrackingEnable() { + return this.trackingEnable; + } + + /** + * Turns on or off the continuous + * updating of the userHeadToVworld transform. + * @param flag enables or disables continuous updating + */ + public void setUserHeadToVworldEnable(boolean flag) { + + synchronized(this) { + userHeadToVworldEnable = flag; + vDirtyMask |= View.USER_HEAD_TO_VWORLD_ENABLE_DIRTY; + } + repaint(); + } + + /** + * Returns a status flag indicating whether or not + * Java 3D is continuously updating the userHeadToVworldEnable transform. + * @return a flag indicating if continuously updating userHeadToVworld + */ + public boolean getUserHeadToVworldEnable() { + return userHeadToVworldEnable; + } + + /** + * Computes the sensor to virtual-world transform + * and copies that value into the transform provided. + * The computed transforms takes points in the sensor's coordinate + * system and produces the point's corresponding value in + * virtual-world coordinates. + * @param sensor the sensor in question + * @param t the object that will receive the transform + */ + public void getSensorToVworld(Sensor sensor, Transform3D t) { + // grab the first canvas -- not sure for multiple canvases + Canvas3D canvas = (Canvas3D) this.canvases.firstElement(); + Transform3D localTrans = new Transform3D(); + synchronized(canvas.canvasViewCache) { + t.set(canvas.canvasViewCache.getVworldToTrackerBase()); + } + t.invert(); + sensor.getRead(localTrans); + t.mul(localTrans); + } + + /** + * Retrieves the position of the specified Sensor's + * hotspot in virtual-world coordinates + * and copies that value into the position provided. + * This value is derived from other values and is read-only. + * @param sensor the sensor in question + * @param position the variable that will receive the position + */ + public void getSensorHotspotInVworld(Sensor sensor, + Point3f position) { + + Canvas3D canvas = (Canvas3D) this.canvases.firstElement(); + Transform3D sensorToVworld = new Transform3D(); + Point3d hotspot3d = new Point3d(); + + getSensorToVworld(sensor, sensorToVworld); + sensor.getHotspot(hotspot3d); + position.set(hotspot3d); + sensorToVworld.transform(position); + } + + /** + * Retrieves the position of the specified Sensor's + * hotspot in virtual-world coordinates + * and copies that value into the position provided. + * This value is derived from other values and is read-only. + * @param sensor the sensor in question + * @param position the variable that will receive the position + */ + public void getSensorHotspotInVworld(Sensor sensor, + Point3d position) { + + Canvas3D canvas = (Canvas3D) this.canvases.firstElement(); + Transform3D sensorToVworld = new Transform3D(); + + getSensorToVworld(sensor, sensorToVworld); + sensor.getHotspot(position); + sensorToVworld.transform(position); + } + + /** + * Sets given Canvas3D at the given index position. + * @param canvas3D the given Canvas3D to be set + * @param index the position to be set + * @exception IllegalStateException if the specified canvas is + * a stereo canvas with a monoscopicEyePolicy of CYCLOPEAN_EYE_VIEW, + * and the viewPolicy for this view is HMD_VIEW + * @exception IllegalSharingException if the specified canvas is + * associated with another view + */ + public void setCanvas3D(Canvas3D canvas3D, int index) { + + if((viewPolicy == HMD_VIEW) && + (canvas3D.monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) && + (!canvas3D.useStereo)){ + + throw new + IllegalStateException(J3dI18N.getString("View31")); + } + + Canvas3D cv; + + synchronized(canvasList) { + if (canvas3D.getView() != null) + throw new IllegalSharingException(J3dI18N.getString("View10")); + cv = (Canvas3D) canvases.elementAt(index); + canvases.setElementAt(canvas3D, index); + removeFromCanvasList(cv); + addToCanvasList(canvas3D); + canvasesDirty = true; + } + + canvas3D.setView(this); + cv.setView(null); + + if (canvas3D.added) { + evaluateActive(); + } + if (cv.added) { + evaluateActive(); + } + + } + + /** + * Gets the Canvas3D at the specified index position. + * @param index the position from which to get Canvas3D object + * @return the Canvas3D at the sprcified index position + */ + public Canvas3D getCanvas3D(int index){ + return (Canvas3D) this.canvases.elementAt(index); + } + + /** + * Gets the enumeration object of all the Canvas3Ds. + * @return the enumeration object of all the Canvas3Ds. + */ + public Enumeration getAllCanvas3Ds(){ + return canvases.elements(); + } + + /** + * Returns the number of Canvas3Ds in this View. + * @return the number of Canvas3Ds in this View + * + * @since Java 3D 1.2 + */ + public int numCanvas3Ds() { + return canvases.size(); + } + + /** + * Adds the given Canvas3D at the end of the list. + * @param canvas3D the Canvas3D to be added + * @exception IllegalStateException if the specified canvas is + * a stereo canvas with a monoscopicEyePolicy of CYCLOPEAN_EYE_VIEW, + * and the viewPolicy for this view is HMD_VIEW + * @exception IllegalSharingException if the specified canvas is + * associated with another view + */ + public void addCanvas3D(Canvas3D canvas3D){ + + if((viewPolicy == HMD_VIEW) && + (canvas3D.monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) && + (!canvas3D.useStereo)) { + throw new + IllegalStateException(J3dI18N.getString("View31")); + } + + synchronized(canvasList) { + if (canvas3D.getView() != null) + throw new IllegalSharingException(J3dI18N.getString("View10")); + canvases.addElement(canvas3D); + addToCanvasList(canvas3D); + canvasesDirty = true; + } + + canvas3D.setView(this); + + if (canvas3D.added) { + if ((canvas3D.visible || canvas3D.offScreen) && + canvas3D.firstPaintCalled) { + canvas3D.active = true; + } + evaluateActive(); + } + } + + /** + * Inserts the Canvas3D at the given index position. + * @param canvas3D the Canvas3D to be inserted + * @param index the position to be inserted at + * @exception IllegalStateException if the specified canvas is + * a stereo canvas with a monoscopicEyePolicy of CYCLOPEAN_EYE_VIEW, + * and the viewPolicy for this view is HMD_VIEW + * @exception IllegalSharingException if the specified canvas is + * associated with another view + */ + public void insertCanvas3D(Canvas3D canvas3D, int index){ + + if((viewPolicy == HMD_VIEW) && + (canvas3D.monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) && + (!canvas3D.useStereo)) { + throw new + IllegalStateException(J3dI18N.getString("View31")); + } + + synchronized(canvasList) { + if (canvas3D.getView() != null) + throw new IllegalSharingException(J3dI18N.getString("View10")); + this.canvases.insertElementAt(canvas3D, index); + addToCanvasList(canvas3D); + canvasesDirty = true; + } + + canvas3D.setView(this); + + if (canvas3D.added) { + if ((canvas3D.visible || canvas3D.offScreen) && + canvas3D.firstPaintCalled) { + canvas3D.active = true; + } + evaluateActive(); + } + } + + /** + * Removes the Canvas3D from the given index position. + * @param index the position of Canvas3D object to be removed + */ + public void removeCanvas3D(int index) { + // index -1 is possible if the view is unregistered first + // because viewPlatform is clearLived, + // and then removeCanvas from the view + if (index == -1) + return; + + Canvas3D cv; + + synchronized(canvasList) { + cv = (Canvas3D) canvases.elementAt(index); + + canvases.removeElementAt(index); + removeFromCanvasList(cv); + canvasesDirty = true; + } + + // reset canvas will set view to null also + VirtualUniverse.mc.postRequest(MasterControl.RESET_CANVAS, + cv); + cv.pendingView = null; + + computeCanvasesCached(); + + if (cv.added) { + cv.active = false; + evaluateActive(); + } + if (universe != null) { + universe.waitForMC(); + } + } + + + /** + * Retrieves the index of the specified Canvas3D in + * this View's list of Canvas3Ds + * + * @param canvas3D the Canvas3D to be looked up. + * @return the index of the specified Canvas3D; + * returns -1 if the object is not in the list. + * + * @since Java 3D 1.3 + */ + public int indexOfCanvas3D(Canvas3D canvas3D) { + return canvases.indexOf(canvas3D); + } + + + /** + * Removes the specified Canvas3D from this View's + * list of Canvas3Ds. + * If the specified object is not in the list, the list is not modified. + * + * @param canvas3D the Canvas3D to be removed. + */ + public void removeCanvas3D(Canvas3D canvas3D) { + removeCanvas3D(canvases.indexOf(canvas3D)); + } + + + /** + * Removes all Canvas3Ds from this View. + * + * @since Java 3D 1.3 + */ + public void removeAllCanvas3Ds() { + LinkedList tmpCanvases = new LinkedList(); + + synchronized(canvasList) { + int numCanvases = canvases.size(); + + // Remove in reverse order to ensure valid indices + for (int index = numCanvases - 1; index >= 0; index--) { + Canvas3D cv; + + cv = (Canvas3D) canvases.elementAt(index); + + // Record list of canvases to be deleted; + tmpCanvases.add(cv); + + canvases.removeElementAt(index); + removeFromCanvasList(cv); + canvasesDirty = true; + } + } + + // ISSUE 83: postRequest must *not* be called while holding + // canvasList lock. Holding the lock can cause a deadlock. + + Iterator iterator = tmpCanvases.iterator(); + while (iterator.hasNext()) { + Canvas3D cv = (Canvas3D)iterator.next(); + + // reset canvas will set view to null also + VirtualUniverse.mc.postRequest(MasterControl.RESET_CANVAS, + cv); + cv.pendingView = null; + + if (cv.added) { + cv.active = false; + } + } + + computeCanvasesCached(); + + evaluateActive(); + + if (universe != null) { + universe.waitForMC(); + } + } + + + // This adds this canvas and its screen to the screen list. + // Locks are already acquired before this is called. + private void addToCanvasList(Canvas3D c) { + + for (int i=screenList.size()-1; i>=0; i--) { + if ((Screen3D)screenList.get(i) == c.screen) { + // This is the right screen slot + ((ArrayList)canvasList.get(i)).add(c); + canvasesDirty = true; + return; + } + } + + // Add a screen slot + screenList.add(c.screen); + ArrayList clist = new ArrayList(); + canvasList.add(clist); + clist.add(c); + canvasesDirty = true; + } + + // This removes this canvas and its screen from the screen list + // Locks are already acquired before this is called. + private void removeFromCanvasList(Canvas3D c) { + + for (int i=screenList.size()-1; i>=0; i--) { + if ((Screen3D) screenList.get(i) == c.screen) { + // This is the right screen slot + ArrayList clist = (ArrayList)canvasList.get(i); + clist.remove(clist.indexOf(c)); + + if (clist.size() == 0) { + canvasList.remove(i); + screenList.remove(i); + canvasesDirty = true; + } + return; + } + } + } + + // Locks are not acquired before this is called. + void computeCanvasesCached() { + + synchronized (canvasList) { + ArrayList cv; + int len = canvases.size(); + + Canvas3D newCachedCanvases[] = new Canvas3D[len]; + for (int i=0; i < len; i++) { + newCachedCanvases[i] = (Canvas3D) canvases.get(i); + } + // Do this in one instruction so there is no need to + // synchronized getCanvases() + + cachedCanvases = newCachedCanvases; + len = 0; + longestScreenList = 0; + cachedCanvasList = new Canvas3D[canvasList.size()][0]; + for (int i=0; i < cachedCanvasList.length; i++) { + cv = (ArrayList) canvasList.get(i); + len = cv.size(); + cachedCanvasList[i] = new Canvas3D[len]; + for (int j=0; j < len; j++) { + cachedCanvasList[i][j] = (Canvas3D) cv.get(j); + } + + if (len > longestScreenList) { + longestScreenList = len; + } + } + len = screenList.size(); + Screen3D newCachedScreens[] = new Screen3D[len]; + + for (int i=0; i < len; i++) { + newCachedScreens[i] = (Screen3D) screenList.get(i); + } + // Do this in one instruction so there is no need to + // synchronized getScreens() + cachedScreens = newCachedScreens; + canvasesDirty = false; + } + } + + // This creates a 2 dimentional list of canvases + // ONLY MC can call this procedure with canCompute=true, + // since MC want the result return by + // evaluateCanvases and updateWorkThreads agree to each other, + // so only evaluateCanvases can compute a new list. + // Other threads should use getCanvasList(false). + Canvas3D[][] getCanvasList(boolean canCompute) { + if (canvasesDirty && canCompute) { + computeCanvasesCached(); + } + return cachedCanvasList; + } + + // assume getCanvasList is called before + int getLongestScreenList() { + return longestScreenList; + } + + // assume getCanvasList is called before + Canvas3D[] getCanvases() { + return cachedCanvases; + } + + // assume getCanvasList is called before + Screen3D[] getScreens() { + return cachedScreens; + } + + Canvas3D getFirstCanvas() { + synchronized (canvasList) { + if (canvases.size() > 0) { + return (Canvas3D) canvases.elementAt(0); + } + return null; + } + } + + /** + * This method returns the time at which the most recent rendering + * frame started. It is defined as the number of milliseconds + * since January 1, 1970 00:00:00 GMT. + * Since multiple canvases might be attached to this View, + * the start of a frame is defined as the point in time just prior + * to clearing any canvas attached to this view. + * @return the time at which the most recent rendering frame started + */ + public long getCurrentFrameStartTime() { + synchronized (frameStartTimes) { + return currentFrameStartTime; + } + } + + /** + * This method returns the duration, in milliseconds, of the most + * recently completed rendering frame. The time taken to render + * all canvases attached to this view is measured. This duration + * is computed as the difference between the start of the most recently + * completed frame and the end of that frame. + * Since multiple canvases might be attached to this View, + * the start of a frame is defined as the point in time just prior + * to clearing any canvas attached to this view--before preRender + * is called for any canvas. Similarly, the end of a frame is + * defined as the point in time just after swapping the buffer for + * all canvases--after postSwap is called for all canvases. + * Note that since the frame duration is measured from start to stop + * for this view only, the value returned is not the same as + * frame rate; it measures only the rendering time for this view. + * + * @return the duration, in milliseconds, of the most recently + * completed rendering frame + */ + public long getLastFrameDuration() { + synchronized (frameStartTimes) { + return currentFrameDuration; + } + } + + /** + * This method returns the frame number for this view. The frame + * number starts at 0 and is incremented at the start of each + * frame--prior to clearing all the canvases attached to this + * view. + * + * @return the current frame number for this view + */ + public long getFrameNumber() { + synchronized (frameStartTimes) { + return currentFrameNumber; + } + } + + /** + * Retrieves the implementation-dependent maximum number of + * frames whose start times will be recorded by the system. This + * value is guaranteed to be at least 10 for all implementations + * of the Java 3D API. + * @return the maximum number of frame start times recorded + */ + public static int getMaxFrameStartTimes() { + return (NUMBER_FRAME_START_TIMES); + } + + /** + * Copies the last k frame start time values into + * the user-specified array. The most recent frame start time is + * copied to location 0 of the array, the next most recent frame + * start time is copied into location 1 of the array, and so forth. + * If times.length is smaller than + * maxFrameStartTimes, then only the last times.length values are + * copied. If times.length is greater than maxFrameStartTimes, + * then all array elements after index maxFrameStartTimes-1 are + * set to 0. + * + * @return the frame number of the most recent frame in the array + * + * @see #setMinimumFrameCycleTime + */ + public long getFrameStartTimes(long[] times) { + int index, i, loopCount; + long lastFrameNumber; + + synchronized (frameStartTimes) { + index = currentFrameIndex - 1; + if (index < 0) { + index = NUMBER_FRAME_START_TIMES - 1; + } + lastFrameNumber = frameNumbers[index]; + + if (times.length <= NUMBER_FRAME_START_TIMES) { + loopCount = times.length; + } else { + loopCount = NUMBER_FRAME_START_TIMES; + } + + for (i=0; i NUMBER_FRAME_START_TIMES) { + for (; iminimumTime < 0 + * + * @see #getFrameStartTimes + * + * @since Java 3D 1.2 + */ + public void setMinimumFrameCycleTime(long minimumTime) { + if (minimumTime < 0L) + throw new IllegalArgumentException(J3dI18N.getString("View27")); + + minFrameCycleTime = minimumTime; + VirtualUniverse.mc.setWork(); + } + + /** + * Retrieves the minimum frame cycle time, in milliseconds, for this view. + * @return the minimum frame cycle time for this view. + * + * @see #getFrameStartTimes + * + * @since Java 3D 1.2 + */ + public long getMinimumFrameCycleTime() { + return minFrameCycleTime; + } + + + /** + * This adds a frame time to the this of frame times + */ + void setFrameTimingValues() { + + synchronized (frameStartTimes) { + if (currentFrameIndex == NUMBER_FRAME_START_TIMES) { + currentFrameIndex = 0; + } + + frameNumbers[currentFrameIndex] = frameNumber; + + frameStartTimes[currentFrameIndex++] = startTime; + currentFrameStartTime = startTime; + currentFrameDuration = stopTime - startTime; + currentFrameNumber = frameNumber; + } + } + + /** + * Return true if maximum fps impose by user reach + */ + void computeCycleTime() { + if (minFrameCycleTime == 0) { + isMinCycleTimeAchieve = true; + sleepTime = 0; + } else { + sleepTime = minFrameCycleTime - + (J3dClock.currentTimeMillis() - startTime); + isMinCycleTimeAchieve = (sleepTime <= 0); + } + } + + + /** + * Enables or disables automatic freezing of the depth buffer for + * objects rendered + * during the transparent rendering pass (i.e., objects rendered + * using alpha blending) for this view. + * If enabled, depth buffer writes will be disabled during the + * transparent rendering pass regardless of the value of + * the depth buffer write enable flag in the RenderingAttributes + * object for a particular node. + * This flag is enabled by default. + * @param flag indicates whether automatic freezing of the depth buffer + * for transparent/antialiased objects is enabled. + * @see RenderingAttributes#setDepthBufferWriteEnable + */ + public void setDepthBufferFreezeTransparent(boolean flag) { + depthBufferFreezeTransparent = flag; + repaint(); + } + + /** + * Retrieves the current value of the depth buffer freeze transparent + * flag for this view. + * @return a flag that indicates whether or not the depth + * buffer is automatically frozen during the transparent rendering pass. + */ + public boolean getDepthBufferFreezeTransparent() { + return depthBufferFreezeTransparent; + } + + /** + * Enables or disables scene antialiasing for this view. + * If enabled, the entire scene will be antialiased on + * each canvas in which scene antialiasing is available. + * Scene antialiasing is disabled by default. + *

+ * NOTE: Scene antialiasing is ignored in pure immediate mode, + * but is supported in mixed-immediate mode. + * @param flag indicates whether scene antialiasing is enabled + * + * @see Canvas3D#queryProperties + */ + public void setSceneAntialiasingEnable(boolean flag) { + sceneAntialiasingEnable = flag; + repaint(); + } + + /** + * Returns a flag that indicates whether or not scene antialiasing + * is enabled for this view. + * @return a flag that indicates whether scene antialiasing is enabled + */ + public boolean getSceneAntialiasingEnable() { + return sceneAntialiasingEnable; + } + + /** + * Sets a flag that indicates whether the local eyepoint is used in + * lighting calculations for perspective projections. + * If this flag is set to true, the view vector is calculated per-vertex + * based on the direction from the actual eyepoint to the vertex. + * If this flag is set to false, a single view vector is computed from + * the eyepoint to the center of the view frustum. This is + * called infinite eye lighting. + * Local eye lighting is disabled by default, and is ignored for + * parallel projections. + * @param flag indicates whether local eye lighting is enabled + */ + public void setLocalEyeLightingEnable(boolean flag) { + localEyeLightingEnable = flag; + repaint(); + } + + /** + * Retrieves a flag that indicates whether or not local eye lighting + * is enabled for this view. + * @return a flag that indicates whether local eye lighting is enabled + */ + public boolean getLocalEyeLightingEnable() { + return localEyeLightingEnable; + } + + /** + * Attach viewPlatform structure to this view. + * @param vp the viewPlatform to be attached + */ + public void attachViewPlatform(ViewPlatform vp) { + + if ((vp != null) && (vp == viewPlatform)) { + return; + } + + if (viewPlatform != null) { + ((ViewPlatformRetained)viewPlatform.retained).removeView(this); + if (viewPlatform.isLive()) { + synchronized (evaluateLock) { + viewPlatform = null; + // cleanup View stuff for the old platform + evaluateActive(); + viewPlatform = vp; + } + if (universe != null) { + universe.waitForMC(); + } + } else { + viewPlatform = vp; + } + } else { + viewPlatform = vp; + } + if (vp != null) { + if (vp.isLive()) { + checkView(); + setUniverse(((ViewPlatformRetained)vp.retained).universe); + } + ((ViewPlatformRetained)vp.retained).setView(this); + } + + evaluateActive(); + if ((vp == null) && (universe != null)) { + universe.waitForMC(); + } + } + + /** + * Retrieves the currently attached ViewPlatform object + * @return the currently attached ViewPlatform + */ + public ViewPlatform getViewPlatform() { + return viewPlatform; + } + + /** + * Checks view parameters for consistency + */ + void checkView() { + if (physicalBody == null) + throw new IllegalStateException(J3dI18N.getString("View13")); + + if (physicalEnvironment == null) + throw new IllegalStateException(J3dI18N.getString("View14")); + } + + + /** + * Stops the behavior scheduler after all + * currently scheduled behaviors are executed. Any frame-based + * behaviors scheduled to wake up on the next frame will be + * executed at least once before the behavior scheduler is + * stopped. + *

+ * NOTE: This is a heavy-weight method + * intended for verification and image capture (recording); it + * is not intended to be used for flow control. + * @return a pair of integers that specify the beginning and ending + * time (in milliseconds since January 1, 1970 00:00:00 GMT) + * of the behavior scheduler's last pass + * @exception IllegalStateException if this method is called + * from a Behavior method or from any Canvas3D render callback + * method + */ + public final long[] stopBehaviorScheduler() { + long[] intervalTime = new long[2]; + + if (checkBehaviorSchedulerState("View15", "View16")) { + if (activeStatus && isRunning && + (universe.behaviorScheduler != null)) { + // view is active + universe.behaviorScheduler.stopBehaviorScheduler(intervalTime); + } else { + if ((universe != null) && + (universe.behaviorScheduler != null)) { + universe.behaviorScheduler.userStop = true; + } + } + } + stopBehavior = true; + return intervalTime; + } + + /** + * Starts the behavior scheduler running after it has been stopped. + * @exception IllegalStateException if this method is called + * from a Behavior method or from any Canvas3D render callback + * method + */ + public final void startBehaviorScheduler() { + if (checkBehaviorSchedulerState("View17", "View18")) { + if (activeStatus && isRunning && + (universe.behaviorScheduler != null)) { + universe.behaviorScheduler.startBehaviorScheduler(); + + } else { + if ((universe != null) && + (universe.behaviorScheduler != null)) { + universe.behaviorScheduler.userStop = false; + } + } + } + + stopBehavior = false; + } + + /** + * Check if BehaviorScheduler is in valid state to start/stop + * itself. + * @param s1 Exception String if method is called from a Canvas3D + * @param s2 Exception String if method is called from a Behavior method + * @return true if viewPlatform is live + * @exception IllegalStateException if this method is called + * from a Behavior method or from any Canvas3D render callback + * method + * + */ + boolean checkBehaviorSchedulerState(String s1, String s2) { + Thread me = Thread.currentThread(); + + if (inCanvasCallback) { + synchronized (canvasList) { + for (int i=canvases.size()-1; i>=0; i--) { + if (((Canvas3D)canvases.elementAt(i)).screen.renderer == me) { + throw new IllegalStateException(J3dI18N.getString(s1)); + } + } + } + } + + if ((viewPlatform != null) && viewPlatform.isLive()) { + if (universe.inBehavior && (universe.behaviorScheduler == me)) { + throw new IllegalStateException(J3dI18N.getString(s2)); + } + return true; + } + return false; + } + + /** + * Retrieves a flag that indicates whether the behavior scheduler is + * currently running. + * @return true if the behavior scheduler is running, false otherwise + * @exception IllegalStateException if this method is called + * from a Behavior method or from any Canvas3D render callback + * method + */ + public final boolean isBehaviorSchedulerRunning() { + return (((universe != null) && !stopBehavior && + (universe.behaviorScheduler != null)) ? + !universe.behaviorScheduler.userStop : false); + } + + /** + * Stops traversing the scene graph for this + * view after the current state of the scene graph is reflected on + * all canvases attached to this view. The renderers associated + * with these canvases are also stopped. + *

+ * NOTE: This is a heavy-weight method + * intended for verification and image capture (recording); it + * is not intended to be used for flow control. + * @exception IllegalStateException if this method is called + * from a Behavior method or from any Canvas3D render callback + * method + */ + public final void stopView() { + checkViewState("View19", "View20"); + synchronized (startStopViewLock) { + if (activeStatus && isRunning) { + VirtualUniverse.mc.postRequest(MasterControl.STOP_VIEW, this); + while (isRunning) { + MasterControl.threadYield(); + } + } else { + isRunning = false; + } + } + } + + /** + * Starts + * traversing this view, and starts the renderers associated + * with all canvases attached to this view. + * @exception IllegalStateException if this method is called + * from a Behavior method or from any Canvas3D render callback + * method + */ + public final void startView() { + + checkViewState("View21", "View22"); + synchronized (startStopViewLock) { + if (activeStatus && !isRunning) { + VirtualUniverse.mc.postRequest(MasterControl.START_VIEW, this); + while (!isRunning) { + MasterControl.threadYield(); + } + VirtualUniverse.mc.sendRunMessage(this, + J3dThread.RENDER_THREAD); + } else { + isRunning = true; + } + } + + } + + /** + * This will throw IllegalStateException if not in valid state + * for start/stop request. + */ + void checkViewState(String s1, String s2) throws IllegalStateException { + if (inCanvasCallback) { + Thread me = Thread.currentThread(); + synchronized (canvasList) { + for (int i= canvases.size()-1; i>=0; i--) { + Canvas3D cv = (Canvas3D)canvases.elementAt(i); + if (cv.screen.renderer == me) { + throw new + IllegalStateException(J3dI18N.getString(s1)); + } + } + } + } + + if ((viewPlatform != null) && viewPlatform.isLive()) { + if (universe.inBehavior && + (Thread.currentThread() == universe.behaviorScheduler)) { + throw new IllegalStateException(J3dI18N.getString(s2)); + } + } + } + + /** + * Retrieves a flag that indicates whether the traverser is + * currently running on this view. + * @return true if the traverser is running, false otherwise + * @exception IllegalStateException if this method is called + * from a Behavior method or from any Canvas3D render callback + * method + */ + public final boolean isViewRunning() { + return isRunning; + } + + /** + * Renders one frame for a stopped View. Functionally, this + * method is equivalent to startView() followed by + * stopview(), except that it is atomic, which + * guarantees that only one frame is rendered. + * + * @exception IllegalStateException if this method is called from + * a Behavior method or from any Canvas3D render callback, or if + * the view is currently running. + * + * @since Java 3D 1.2 + */ + public void renderOnce() { + checkViewState("View28", "View29"); + synchronized (startStopViewLock) { + if (isRunning) { + throw new IllegalStateException(J3dI18N.getString("View30")); + } + renderOnceFinish = false; + VirtualUniverse.mc.postRequest(MasterControl.RENDER_ONCE, this); + while (!renderOnceFinish) { + MasterControl.threadYield(); + } + renderOnceFinish = true; + } + } + + /** + * Requests that this View be scheduled for rendering as soon as + * possible. The repaint method may return before the frame has + * been rendered. If the view is stopped, or if the view is + * continuously running (for example, due to a free-running + * interpolator), this method will have no effect. Most + * applications will not need to call this method, since any + * update to the scene graph or to viewing parameters will + * automatically cause all affected views to be rendered. + * + * @since Java 3D 1.2 + */ + public void repaint() { + if (activeStatus && isRunning) { + VirtualUniverse.mc.sendRunMessage(this, + J3dThread.RENDER_THREAD); + } + } + + + /** + * Update the view cache associated with this view. Also, shapshot + * the per-screen parameters associated with all screens attached + * to this view. + */ + final void updateViewCache() { + + + // TODO KCR : remove obsolete DVR code (but make sure we don't end + // up with a leak in the Viewer Map object). + + // DVR support + // This is a back door in j3d to provide DVR support. + // A better place to put this code segment is in + // ViewCache.snapshot(). Since it consists of some + // back door code, I've decided to put it here to isolate + // it from the rest of view snapshot code. + if(firstTime) { + // System.err.println("View : First Time is " + firstTime); + // viewer = Viewer.getViewer(this); + // Since we've the handler to the viewer, we can remove the entry + // now to avoid confusion and prevent memory leak problem. + viewer = Viewer.removeViewerMapEntry(this); + firstTime = false; + } + +// if(viewer != null) { +// if(viewer.isDvrEnabled()) { +// dvrFactor = viewer.getDvrFactor(); +// dvrResizeCompensation = +// viewer.getDvrResizeCompensationEnable(); +// /* +// System.err.println("View : dvrFactor is " + dvrFactor); +// System.err.println("View : dvrResizeCompensation is " + +// dvrResizeCompensation); +// */ +// } +// else { +// // Reset back to default. +// dvrFactor = 1.0f; +// dvrResizeCompensation = true; +// +// } +// } + // End of back door -- DVR. + + synchronized(this) { + viewCache.snapshot(); + viewCache.computeDerivedData(); + } + + // Just take the brute force approach and snapshot the + // parameters for each screen attached to each canvas. We won't + // worry about whether a screen is cached more than once. + // Eventually, dirty bits will take care of this. + + synchronized (canvasList) { + int i = canvases.size()-1; + while (i>=0) { + Screen3D scr = + ((Canvas3D)canvases.elementAt(i--)).getScreen3D(); + if (scr != null) + scr.updateViewCache(); + } + } + } + + + /** + * This routine activates or deactivates a view based on various information + */ + void evaluateActive() { + + synchronized (evaluateLock) { + if (universe == null) { + return; + } + + if ((viewPlatform == null) || + !viewPlatform.isLive() || + !((ViewPlatformRetained)viewPlatform.retained).switchState.currentSwitchOn) { + if (activeStatus) { + deactivate(); + activeStatus = false; + } + // Destroy threads from MC + if (VirtualUniverse.mc.isRegistered(this) && + (universe.isEmpty() || + (canvases.isEmpty() && + ((viewPlatform == null) || + !viewPlatform.isLive())))) { + // We can't wait until MC finish unregister view + // here because user thread may + // holds the universe.sceneGraphLock if branch + // or locale remove in clearLive(). In this way + // There is deadlock since MC also need need + // sceneGraphLock in some threads + // (e.g. TransformStructure update thread) + universe.unRegViewWaiting = this; + resetUnivCount = universeCount; + VirtualUniverse.mc.postRequest( + MasterControl.UNREGISTER_VIEW, this); + } + } else { + + // We're on a live view platform. See what the canvases say + // If view not register, MC will register it automatically + + int i; + VirtualUniverse u = null; + synchronized (canvasList) { + + for (i=canvases.size()-1; i>=0; i--) { + Canvas3D cv = (Canvas3D)canvases.elementAt(i); + if (cv.active) { + + if (!activeStatus && (universeCount > resetUnivCount)) { + u = universe; + } + break; + } + } + } + + // We should do this outside canvasList lock, + // otherwise it may cause deadlock with MC + if (u != null) { + activate(u); + activeStatus = true; + return; + } + + + if ((i < 0) && activeStatus) { + deactivate(); + activeStatus = false; + return; + } + + if (VirtualUniverse.mc.isRegistered(this)) { + // notify MC that canvases state for this view changed + VirtualUniverse.mc.postRequest( + MasterControl.REEVALUATE_CANVAS, this); + } + } + } + } + + void setUniverse(VirtualUniverse universe) { + + synchronized (VirtualUniverse.mc.requestObjList) { + if ((renderBin == null) || + (renderBin.universe != universe)) { + if (renderBin != null) { + renderBin.cleanup(); + } + renderBin = new RenderBin(universe, this); + renderBin.universe = universe; + } + + + if ((soundScheduler == null) || + (soundScheduler.universe != universe)) { + // create a sound scheduler for this view, with this universe + if (soundScheduler != null) { + soundScheduler.cleanup(); + } + soundScheduler = new SoundScheduler(universe, this); + } + + + // This has to be the last call before + // RenderBin and SoundScheduler construct. Since it is + // possible that canvas receive paint call and invoked + // evaluateActive in another thread - which check for + // universe == null and may let it pass before soundScheduler + // and renderBin initialize. + universeCount++; + this.universe = universe; + } + evaluateActive(); + } + + /** + * This activates all traversers and renderers associated with this view. + */ + void activate(VirtualUniverse universe) { + + universe.checkForEnableEvents(); + + if (physicalBody != null) { + physicalBody.addUser(this); + } + + if (!VirtualUniverse.mc.isRegistered(this)) { + universe.regViewWaiting = this; + } + + VirtualUniverse.mc.postRequest(MasterControl.ACTIVATE_VIEW, + this); + + if (!universe.isSceneGraphLock) { + universe.waitForMC(); + } + if (soundScheduler != null) { + soundScheduler.reset(); + } + + J3dMessage vpMessage = new J3dMessage(); + vpMessage.universe = universe; + vpMessage.view = this; + vpMessage.type = J3dMessage.UPDATE_VIEW; + vpMessage.threads = + J3dThread.SOUND_SCHEDULER | + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_BEHAVIOR; + vpMessage.args[0] = this; + synchronized(((ViewPlatformRetained)viewPlatform.retained).sphere) { + vpMessage.args[1] = new Float(((ViewPlatformRetained)viewPlatform.retained).sphere.radius); + } + vpMessage.args[2] = new Integer(OTHER_ATTRS_CHANGED); + vpMessage.args[3] = new Integer(transparencySortingPolicy); + VirtualUniverse.mc.processMessage(vpMessage); + } + + /** + * This deactivates all traversers and renderers associated with this view. + */ + void deactivate() { + VirtualUniverse.mc.postRequest(MasterControl.DEACTIVATE_VIEW, this); + if (physicalBody != null) { + physicalBody.removeUser(this); + } + + // This is a temporary fix for bug 4267395 + // XXXX:cleanup in RenderBin after View detach + // universe.addViewIdToFreeList(viewId); + + // using new property -Dj3d.forceReleaseView to disable bug fix 4267395 + // this bug fix can produce memory leaks in *some* applications which creates + // and destroy Canvas3D from time to time. This just add the view in the + // FreeList earlier. + if (VirtualUniverse.mc.forceReleaseView) { + universe.addViewIdToFreeList(viewId); + } + + + J3dMessage vpMessage = new J3dMessage(); + vpMessage.universe = universe; + vpMessage.view = this; + vpMessage.type = J3dMessage.UPDATE_VIEW; + vpMessage.threads = + J3dThread.SOUND_SCHEDULER | + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_BEHAVIOR; + vpMessage.args[0] = this; + if (viewPlatform != null) { + synchronized(((ViewPlatformRetained)viewPlatform.retained).sphere) { + vpMessage.args[1] = new Float(((ViewPlatformRetained)viewPlatform.retained).sphere.radius); + } + } else { + vpMessage.args[1] = new Float(0); + } + vpMessage.args[2] = new Integer(OTHER_ATTRS_CHANGED); + vpMessage.args[3] = new Integer(transparencySortingPolicy); + VirtualUniverse.mc.processMessage(vpMessage); + + } + + void cleanupViewId() { + universe.addViewIdToFreeList(viewId); + viewId = null; + } + + + void assignViewId () { + if (viewId == null) { + viewId = universe.getViewId(); + viewIndex = viewId.intValue(); + } + } + + /** + * This method passes window event to SoundScheduler + */ + void sendEventToSoundScheduler(AWTEvent evt) { + if (soundScheduler != null) { + soundScheduler.receiveAWTEvent(evt); + } + } + + void reset() { + + for (int i=0; i < canvases.size(); i++) { + ((Canvas3D) canvases.get(i)).reset(); + } + + // reset the renderBinReady flag + renderBinReady = false; + + soundScheduler.cleanup(); + soundScheduler = null; + soundRenderer = new SoundRenderer(); + + viewCache = new ViewCache(this); + getCanvasList(true); + cleanupViewId(); + renderBin.cleanup(); + renderBin = null; + universe = null; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ViewCache.java b/j3d-core/src/classes/share/javax/media/j3d/ViewCache.java new file mode 100644 index 0000000..3f0b285 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ViewCache.java @@ -0,0 +1,361 @@ +/* + * $RCSfile: ViewCache.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:32 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; + +/** + * The ViewCache class is used to cache all data, both API data and derived + * data, that is independent of the Canvas3D and Screen3D. + */ +class ViewCache extends Object { + // The view associated with this view cache + View view; + + // + // API/INPUT DATA + // + + // ********************* + // * From ViewPlatform * + // ********************* + int viewAttachPolicy; + + // ********************* + // * From PhysicalBody * + // ********************* + + /** + * The user's left eye's position in head coordinates. + */ + Point3d leftEyePosInHead = new Point3d(); + + /** + * The user's right eye's position in head coordinates. + */ + Point3d rightEyePosInHead = new Point3d(); + + /** + * The user's left ear's position in head coordinates. + */ + Point3d leftEarPosInHead = new Point3d(); + + /** + * The user's right ear's position in head coordinates. + */ + Point3d rightEarPosInHead = new Point3d(); + + /** + * The user's nominal eye height as measured + * from the ground plane. + */ + double nominalEyeHeightFromGround; + + /** + * The amount to offset the system's + * viewpoint from the user's current eye-point. This offset + * distance allows an "Over the shoulder" view of the scene + * as seen by the user. + */ + double nominalEyeOffsetFromNominalScreen; + + // Head to head-tracker coordinate system transform. + // If head tracking is enabled, this transform is a calibration + // constant. If head tracking is not enabled, this transform is + // not used. + // This is only used in SCREEN_VIEW mode. + Transform3D headToHeadTracker = new Transform3D(); + + // **************************** + // * From PhysicalEnvironment * + // **************************** + + // Coexistence coordinate system to tracker-base coordinate + // system transform. If head tracking is enabled, this transform + // is a calibration constant. If head tracking is not enabled, + // this transform is not used. + // This is used in both SCREEN_VIEW and HMD_VIEW modes. + Transform3D coexistenceToTrackerBase = new Transform3D(); + + // Transform generated by the head tracker to transform + // from tracker base to head tracker coordinates (and the inverse). + Transform3D headTrackerToTrackerBase = new Transform3D(); + Transform3D trackerBaseToHeadTracker = new Transform3D(); + + // + // Indicates whether the underlying hardware implementation + // supports tracking. + // + boolean trackingAvailable; + + // Sensor index for head tracker + int headIndex; + + // + // This variable specifies the policy Java 3D will use in placing + // the user's eye position relative to the user's head position + // (NOMINAL_SCREEN, NOMINAL_HEAD, or NOMINAL_FEET). + // It is used in the calibration process. + // + int coexistenceCenterInPworldPolicy; + + + // ************* + // * From View * + // ************* + + // View model compatibility mode flag + boolean compatibilityModeEnable; + + // coexistenceCenteringEnable flag + boolean coexistenceCenteringEnable; + + Point3d leftManualEyeInCoexistence = new Point3d(); + Point3d rightManualEyeInCoexistence = new Point3d(); + + // Indicates which major mode of view computation to use: + // HMD mode or screen/fish-tank-VR mode. + int viewPolicy; + + // The current projection policy (parallel versus perspective) + int projectionPolicy; + + // The current screen scale policy and scale value + int screenScalePolicy; + double screenScale; + + // The current window resize, movement and eyepoint policies + int windowResizePolicy; + int windowMovementPolicy; + int windowEyepointPolicy; + + // The current monoscopic view policy + int monoscopicViewPolicy; + + // The view model's field of view. + double fieldOfView; + + // The distance away from the clip origin + // in the direction of gaze for the front and back clip planes. + double frontClipDistance; + double backClipDistance; + + // Front and back clip policies + int frontClipPolicy; + int backClipPolicy; + + // ViewPlatform of this view + ViewPlatformRetained vpRetained; + + /** + * Defines the visibility policy. + */ + int visibilityPolicy; + + // Flag to enable tracking, if so allowed by the trackingAvailable flag. + boolean trackingEnable; + + // This setting enables the continuous updating by Java 3D of the + // userHeadToVworld transform. + boolean userHeadToVworldEnable; + + // The current compatibility mode view transform + Transform3D compatVpcToEc = new Transform3D(); + + // The current compatibility mode projection transforms + Transform3D compatLeftProjection = new Transform3D(); + Transform3D compatRightProjection = new Transform3D(); + + // Mask that indicates ViewCache's view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + int vcDirtyMask = 0; + + // + // DERIVED DATA + // + + // Flag indicating that head tracking will be used + private boolean doHeadTracking; + + // + // Matrix to transform from user-head to + // virtual-world coordinates. This matrix is a read-only + // value that Java 3D generates continuously, but only if enabled + // by userHeadToVworldEnableFlag. + // + Transform3D userHeadToVworld = new Transform3D(); + + + /** + * Take snapshot of all per-view API parameters and input values. + */ + synchronized void snapshot() { + + // View parameters + vcDirtyMask = view.vDirtyMask; + view.vDirtyMask = 0; + compatibilityModeEnable = view.compatibilityModeEnable; + coexistenceCenteringEnable = view.coexistenceCenteringEnable; + leftManualEyeInCoexistence.set(view.leftManualEyeInCoexistence); + rightManualEyeInCoexistence.set(view.rightManualEyeInCoexistence); + viewPolicy = view.viewPolicy; + projectionPolicy = view.projectionPolicy; + screenScalePolicy = view.screenScalePolicy; + windowResizePolicy = view.windowResizePolicy; + windowMovementPolicy = view.windowMovementPolicy; + windowEyepointPolicy = view.windowEyepointPolicy; + monoscopicViewPolicy = view.monoscopicViewPolicy; + + fieldOfView = view.fieldOfView; + screenScale = view.screenScale; + + frontClipDistance = view.frontClipDistance; + backClipDistance = view.backClipDistance; + frontClipPolicy = view.frontClipPolicy; + backClipPolicy = view.backClipPolicy; + + visibilityPolicy = view.visibilityPolicy; + + trackingEnable = view.trackingEnable; + userHeadToVworldEnable = view.userHeadToVworldEnable; + + view.compatVpcToEc.getWithLock(compatVpcToEc); + view.compatLeftProjection.getWithLock(compatLeftProjection); + view.compatRightProjection.getWithLock(compatRightProjection); + + // ViewPlatform parameters + ViewPlatform vpp = view.getViewPlatform(); + + if (vpp == null) { + // This happens when user attach a null viewplatform + // and MC still call updateViewCache() in run before + // the viewDeactivate request get. + return; + } + + vpRetained = (ViewPlatformRetained) vpp.retained; + + synchronized(vpRetained) { + vcDirtyMask |= vpRetained.vprDirtyMask; + vpRetained.vprDirtyMask = 0; + viewAttachPolicy = vpRetained.viewAttachPolicy; + // System.err.println("ViewCache snapshot vcDirtyMask " + vcDirtyMask ); + } + + // PhysicalEnvironment parameters + PhysicalEnvironment env = view.getPhysicalEnvironment(); + + synchronized(env) { + vcDirtyMask |= env.peDirtyMask; + env.peDirtyMask = 0; + + env.coexistenceToTrackerBase.getWithLock(coexistenceToTrackerBase); + trackingAvailable = env.trackingAvailable; + coexistenceCenterInPworldPolicy = env.coexistenceCenterInPworldPolicy; + + // NOTE: this is really derived data, but we need it here in order + // to avoid reading head tracked data when no tracker is available + // and enabled. + doHeadTracking = trackingEnable && trackingAvailable; + + if (doHeadTracking) { + headIndex = env.getHeadIndex(); + env.getSensor(headIndex).getRead(headTrackerToTrackerBase); + vcDirtyMask |= View.TRACKING_ENABLE_DIRTY; + } + else { + headTrackerToTrackerBase.setIdentity(); + } + } + + // PhysicalBody parameters + PhysicalBody body = view.getPhysicalBody(); + + synchronized(body) { + vcDirtyMask |= body.pbDirtyMask; + body.pbDirtyMask = 0; + + leftEyePosInHead.set(body.leftEyePosition); + rightEyePosInHead.set(body.rightEyePosition); + leftEarPosInHead.set(body.leftEarPosition); + rightEarPosInHead.set(body.rightEarPosition); + + nominalEyeHeightFromGround = body.nominalEyeHeightFromGround; + nominalEyeOffsetFromNominalScreen = + body.nominalEyeOffsetFromNominalScreen; + } + + body.headToHeadTracker.getWithLock(headToHeadTracker); + } + + + /** + * Compute derived data using the snapshot of the per-view data. + */ + synchronized void computeDerivedData() { + if (doHeadTracking) { + trackerBaseToHeadTracker.invert(headTrackerToTrackerBase); + //System.err.println("trackerBaseToHeadTracker: "); + //System.err.println(trackerBaseToHeadTracker); + } + else { + trackerBaseToHeadTracker.setIdentity(); + } + + // XXXX: implement head to vworld tracking if userHeadToVworldEnable is set + userHeadToVworld.setIdentity(); + } + + + // Get methods for returning derived data values. + // Eventually, these get functions will cause some of the parameters + // to be lazily evaluated. + // + // NOTE that in the case of Transform3D, and Tuple objects, a reference + // to the actual derived data is returned. In these cases, the caller + // must ensure that the returned data is not modified. + + boolean getDoHeadTracking() { + return doHeadTracking; + } + + /** + * Constructs and initializes a ViewCache object. + */ + ViewCache(View view) { + this.view = view; + + if (false) + System.err.println("Constructed a ViewCache"); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ViewPlatform.java b/j3d-core/src/classes/share/javax/media/j3d/ViewPlatform.java new file mode 100644 index 0000000..e17aedc --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ViewPlatform.java @@ -0,0 +1,291 @@ +/* + * $RCSfile: ViewPlatform.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + + +/** + * The ViewPlatform leaf node object controls the position, orientation + * and scale of the viewer. It is the node in the scene graph that a + * View object connects to. A viewer navigates through the virtual + * universe by changing the transform in the scene graph hierarchy above + * the ViewPlatform. + *

+ * The View Attach Policy + *

+ * The actual view that Java 3D's renderer draws depends on the view + * attach policy specified within the currently attached ViewPlatform. + * The view attach policy, set by the setViewAttachPolicy + * method, is one of the following: + *

+ *

    + *
  • View.NOMINAL_HEAD - ensures that the end-user's nominal eye + * position in the physical world corresponds to the virtual eye's + * nominal eye position in the virtual world (the ViewPlatform's origin). + * In essence, this policy tells Java 3D to position the virtual eyepoint + * relative to the ViewPlatform origin in the same way as the physical + * eyepoint is positioned relative to its nominal physical-world + * origin. Deviations in the physical eye's position and orientation from + * nominal in the physical world generate corresponding deviations of the + * virtual eye's position and orientation in the virtual world. This + * is the default view attach policy.
  • + *

    + *

  • View.NOMINAL_FEET - ensures that the end-user's virtual feet + * always touch the virtual ground. This policy tells Java 3D to compute + * the physical-to-virtual-world correspondence in a way that enforces + * this constraint. Java 3D does so by appropriately offsetting the + * physical eye's position by the end-user's physical height. Java 3D + * uses the nominalEyeHeightFromGround parameter found in the + * PhysicalBody object to perform this computation.
  • + *

    + *

  • View.NOMINAL_SCREEN - allows an application to always have + * the virtual eyepoint appear at some "viewable" distance from a point + * of interest. This policy tells Java 3D to compute the + * physical-to-virtual-world correspondence in a way + * that ensures that the renderer moves the nominal virtual eyepoint + * away from the point of interest by the amount specified by the + * nominalEyeOffsetFromNominalScreen parameter found in the + * PhysicalBody object.
+ *

+ * Activation Radius + *

+ * The ViewPlatform's activation radius defines an activation + * volume surrounding the center of the ViewPlatform. This activation + * volume is a spherical region that intersects with the scheduling regions + * and application regions + * of other leaf node objects to determine which of those objects may + * affect rendering. Only active view platforms--that is, view platforms + * attached to a View--will be used to schedule or select other leaf nodes. + *

+ * Different leaf objects interact with the ViewPlatform's activation + * volume differently. The Background, Clip, and Soundscape leaf objects + * each define a set of attributes and an application region in which + * those attributes are applied. If more than one node of a given type + * (Background, Clip, or Soundscape) intersects an active ViewPlatform's + * activation volume, the "most appropriate" node is selected for that View. + * Sound leaf objects and Behavior objects become active when + * their scheduling region intersects an active ViewPlatform's activation + * volume. + *

+ * The activation radius is in view platform coordinates. For the + * default screen scale policy of SCALE_SCREEN_SIZE, the + * activationRadius parameter value is multiplied by half the + * monitor screen size to derive the actual activation radius. For example, + * for the default screen size of 0.35 meters, and the default activation + * radius value of 62, the actual activation radius would be 10.85 + * meters. + *

+ *

    + * 62 * 0.35 / 2 = 10.85 + *
+ *

+ * + * @see View + */ + +public class ViewPlatform extends Leaf { + + /** + * Specifies that the ViewPlatform allows read access to its view + * attach policy information at runtime. + */ + public static final int + ALLOW_POLICY_READ = CapabilityBits.VIEW_PLATFORM_ALLOW_POLICY_READ; + + /** + * Specifies that the ViewPlatform allows write access to its view + * attach policy information at runtime. + */ + public static final int + ALLOW_POLICY_WRITE = CapabilityBits.VIEW_PLATFORM_ALLOW_POLICY_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_POLICY_READ + }; + + /** + * Constructs a ViewPlatform object with default parameters. + * The default values are as follows: + *

    + * view attach policy : View.NOMINAL_HEAD
    + * activation radius : 62
    + *
+ */ + public ViewPlatform() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + * Creates the retained mode ViewPlatformRetained object that this + * ViewPlatform component object will point to. + */ + void createRetained() { + this.retained = new ViewPlatformRetained(); + this.retained.setSource(this); + } + + + /** + * Sets the view attach policy that determines the coexistence center + * in the virtual world. This policy determines how Java 3D places the + * view platform relative to the position of the user's head, one of + * View.NOMINAL_SCREEN, View.NOMINAL_HEAD, or View.NOMINAL_FEET. + * The default policy is View.NOMINAL_HEAD. + * @param policy the new policy + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @see View#NOMINAL_SCREEN + * @see View#NOMINAL_HEAD + * @see View#NOMINAL_FEET + */ + public void setViewAttachPolicy(int policy) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POLICY_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewPlatform0")); + + switch (policy) { + case View.NOMINAL_SCREEN: + case View.NOMINAL_HEAD: + case View.NOMINAL_FEET: + break; + + default: + throw new IllegalArgumentException(J3dI18N.getString("ViewPlatform1")); + } + + ((ViewPlatformRetained)this.retained).setViewAttachPolicy(policy); + } + + /** + * Returns the current coexistence center in virtual-world policy. + * @return one of: View.NOMINAL_SCREEN, View.NOMINAL_HEAD, or + * View.NOMINAL_FEET + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int getViewAttachPolicy() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_POLICY_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewPlatform2")); + + return ((ViewPlatformRetained)this.retained).getViewAttachPolicy(); + } + + /** + * Set the ViewPlatform's activation radius which defines an activation + * volume around the view platform. + * @param activationRadius the new activation radius + */ + public void setActivationRadius(float activationRadius) { + ((ViewPlatformRetained)this.retained).setActivationRadius(activationRadius); + } + + /** + * Get the ViewPlatform's activation radius. + * @return the ViewPlatform activation radius + */ + public float getActivationRadius() { + return ((ViewPlatformRetained)this.retained).getActivationRadius(); + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * cloneNode should be overridden by any user subclassed + * objects. All subclasses must have their cloneNode + * method consist of the following lines: + *

+     *     public Node cloneNode(boolean forceDuplicate) {
+     *         UserSubClass usc = new UserSubClass();
+     *         usc.duplicateNode(this, forceDuplicate);
+     *         return usc;
+     *     }
+     * 
+ * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + ViewPlatform v = new ViewPlatform(); + v.duplicateNode(this, forceDuplicate); + return v; + } + + + /** + * Copies all ViewPlatform information from originalNode into + * the current node. This method is called from the + * duplicateNode method. This routine does + * the actual duplication of all "local data" (any data defined in + * this object). It then will duplicate the retained side of the + * tree if this method was called from its own 2 parameter + * duplicateNode method. This is designate by setting the + * duplicateRetained flag to true. + * Without this flag a duplicateNode method would not + * whether or not to duplicate the retained side of the object. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * @param duplicateRetained set to true when this + * method is should initiate the duplicateRetained call. This + * call walks up a nodes superclasses so it should only be called + * once from the class of the original node. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + super.duplicateAttributes(originalNode, forceDuplicate); + + ViewPlatformRetained attr = + (ViewPlatformRetained) originalNode.retained; + ViewPlatformRetained rt = (ViewPlatformRetained) retained; + + rt.setActivationRadius(attr.getActivationRadius()); + rt.setViewAttachPolicy(attr.getViewAttachPolicy()); + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ViewPlatformRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ViewPlatformRetained.java new file mode 100644 index 0000000..023690e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ViewPlatformRetained.java @@ -0,0 +1,424 @@ +/* + * $RCSfile: ViewPlatformRetained.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import javax.vecmath.*; +import java.util.ArrayList; + +/** + * ViewPlatform object (retained side) + */ + +class ViewPlatformRetained extends LeafRetained { + + // different types of IndexedUnorderedSet that use in BehaviorStructure + static final int VP_IN_BS_LIST = 0; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 1; + + /** + * This variable specifies the policy Java 3D will use in placing the + * user's eye point as a function of head position. The variable can + * contain one of NOMINAL_SCREEN, NOMINAL_HEAD, or NOMINAL_FEET. + */ + int viewAttachPolicy = View.NOMINAL_HEAD; + + /** + * The list of views associated with this view platform. + * Use getViewList() to access this variable. + */ + private ArrayList viewList = new ArrayList(); + + /** + * Cached list of viewList for synchronization + */ + private View views[] = null; + + // The locale that this node is decended from + Locale locale = null; + + // dirty flag for viewList + boolean viewListDirty = true; + + /** + * The current cached view platform transform (vworldToVpc) and + * its inverse (vpcToVworld). + */ + Transform3D vworldToVpc = null; + Transform3D vpcToVworld = new Transform3D(); + + + /** + * The activation radius. The value is chosen so that when using a + * default screen scale and field of view, the entire view frustum + * is enclosed. + */ + + /** + * Position used for placing this view platform. + */ + BoundingSphere sphere = + new BoundingSphere(new Point3d(0.0,0.0,0.0), 62.0f); + + /** + * This is the cached bounding sphere used for the activation volume. + */ + BoundingSphere schedSphere; + Point3d center = new Point3d(); + final static Point3d zeroPoint = new Point3d(); + + // Mask that indicates this ViewPlatformRetained's view dependence info. has changed, + // and CanvasViewCache may need to recompute the final view matries. + int vprDirtyMask = (View.VPR_VIEW_ATTACH_POLICY_DIRTY + | View.VPR_VIEWPLATFORM_DIRTY); + + static final Object emptyObj[] = new Object[0]; + static final Transform3D identity = new Transform3D(); + + ViewPlatformRetained() { + this.nodeType = NodeRetained.VIEWPLATFORM; + localBounds = new BoundingBox(); + ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); + ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); + IndexedUnorderSet.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + schedSphere = (BoundingSphere) sphere.clone(); + } + + /** + * Sets the coexistence center in virtual world policy. + * This setting determines how Java 3D places the + * user's eye point as a function of head position. The variable can + * contain one of NOMINAL_SCREEN, NOMINAL_HEAD, or NOMINAL_FEET. + * @param policy the new policy, one of NOMINAL_SCREEN, NOMINAL_HEAD, + * or NOMINAL_FEET + */ + void setViewAttachPolicy(int policy) { + synchronized(this) { + this.viewAttachPolicy = policy; + vprDirtyMask |= View.VPR_VIEW_ATTACH_POLICY_DIRTY; + } + + if (source != null && source.isLive()) { + repaint(); + } + } + + + void repaint() { + View views[] = getViewList(); + for (int i=views.length-1; i >=0; i--) { + views[i].repaint(); + } + } + + /** + * Returns the current coexistence center in virtual-world policy. + * @return one of: NOMINAL_SCREEN, NOMINAL_HEAD, or NOMINAL_FEET + */ + int getViewAttachPolicy() { + return this.viewAttachPolicy; + } + + /** + * Set the ViewPlatform's activation radius + */ + void setActivationRadius(float activationRadius) { + sphere.setRadius(activationRadius); + + if (source != null && source.isLive()) { + repaint(); + } + // Notify behavior scheduler & RenderBin + if (source.isLive()) { + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.UPDATE_VIEWPLATFORM; + message.threads = J3dThread.UPDATE_RENDER|J3dThread.UPDATE_BEHAVIOR; + message.universe = universe; + message.args[0] = this; + message.args[1] = new Float(activationRadius); + VirtualUniverse.mc.processMessage(message); + } else { + schedSphere.setRadius(activationRadius); + } + + } + + /** + * Get the ViewPlatform's activation radius + */ + float getActivationRadius() { + return (float) sphere.getRadius(); + } + + /** + * This sets the view that is associated with this view platform. + */ + void setView(View v) { + synchronized (viewList) { + if (!viewList.contains(v)) { + viewList.add(v); + } + viewListDirty = true; + } + } + + void removeView(View v) { + synchronized (viewList) { + if (viewList.contains(v)) { + viewList.remove(viewList.indexOf(v)); + } + viewListDirty = true; + } + } + + Transform3D getVworldToVpc() { + if (vworldToVpc == null) + vworldToVpc = new Transform3D(); + vworldToVpc.set(getCurrentLocalToVworld(null)); + vworldToVpc.invert(); + return vworldToVpc; + } + + Transform3D getVpcToVworld() { + vpcToVworld .set(getCurrentLocalToVworld(null)); + return vpcToVworld; + } + + + void evaluateViewPlatformTransform() { + // clear cache so that next time getVworldToVpc() can recompute + vworldToVpc = null; + } + + /** + * Evaluate the view platform transform by traversing *up* the tree from + * this ViewPlatform node, computing the composite model transform + * along the way. Because we are traversing bottom to top, we must + * multiply each TransformGroup's matrix on the left by the + * composite transform on the right (rather than the other way + * around as is usually done). Once we have the composite model + * transform for this ViewPlatform--the vpcToVworld transform--we + * simply invert it to get the vworldToVpc transform. + */ + void evaluateInitViewPlatformTransform(NodeRetained node, Transform3D trans) { + if (node instanceof TransformGroupRetained) { + Transform3D tmpTrans = new Transform3D(); + TransformGroupRetained tgr = (TransformGroupRetained)node; + tgr.transform.getWithLock(tmpTrans); + trans.mul(tmpTrans, trans); + } + + NodeRetained parent = node.getParent(); + if (parent != null) { + // Not at the top yet. + evaluateInitViewPlatformTransform(parent, trans); + } + } + + void evaluateInitViewPlatformTransform() { + + Transform3D lastLocalToVworld; + + synchronized (this) { + lastLocalToVworld = getLastLocalToVworld(); + + if (lastLocalToVworld.equals(identity)) { + // lastLocalToVworld not yet updated + // for Renderer viewCache when startup + evaluateInitViewPlatformTransform((NodeRetained)this, + lastLocalToVworld); + } + } + } + + + // This is invoke from BehaviorStructure + void updateActivationRadius(float radius) { + schedSphere.setCenter(zeroPoint); + schedSphere.setRadius(radius); + schedSphere.transform(getCurrentLocalToVworld(null)); + } + + // This is invoke from BehaviorStructure when TransformGroup + // above this viewplatform changed + void updateTransformRegion() { + Transform3D tr = getCurrentLocalToVworld(null); + schedSphere.setCenter(zeroPoint); + schedSphere.transform(tr); + tr.transform(zeroPoint, center); + } + + /** + * This setLive routine first calls the superclass's method, then + * it evaluates the view platform transform, and then it activates + * all canvases that are associated with the attached view. + */ + void setLive(SetLiveState s) { + View views[] = getViewList(); + + for (int i = views.length-1; i>=0; i--) { + views[i].checkView(); + } + + super.doSetLive(s); + + if (inBackgroundGroup) { + throw new + IllegalSceneGraphException(J3dI18N.getString("ViewPlatformRetained1")); + } + + if (inSharedGroup) { + throw new + IllegalSharingException(J3dI18N.getString("ViewPlatformRetained2")); + } + + if (s.viewLists != null) { + throw new + IllegalSceneGraphException(J3dI18N.getString("ViewPlatformRetained3")); + } + /* + if (false) { + System.err.println("setLive: vworldToVpc = "); + System.err.println(this.vworldToVpc); + System.err.println("setLive: vpcToVworld = "); + System.err.println(this.vpcToVworld); + } + */ + this.locale = s.locale; + + + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(this, Targets.VPF_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + } + // process switch leaf + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(this, Targets.VPF_TARGETS); + } + switchState = (SwitchState)s.switchStates.get(0); + s.nodeList.add(this); + s.notifyThreads |= (J3dThread.UPDATE_BEHAVIOR); + super.markAsLive(); + for (int i = views.length-1; i>=0; i--) { + views[i].setUniverse(s.universe); + views[i].evaluateActive(); + } + + universe.addViewPlatform(this); + s.traverseFlags |= NodeRetained.CONTAINS_VIEWPLATFORM; + } + + /** + * This clearLive routine first calls the superclass's method, then + * it deactivates all canvases that are associated with the attached + * view. + */ + void clearLive(SetLiveState s) { + super.clearLive(s); + if (s.switchTargets != null && + s.switchTargets[0] != null) { + s.switchTargets[0].addNode(this, Targets.VPF_TARGETS); + } + + View views[] = getViewList(); + for (int i = views.length-1; i>=0; i--) { + views[i].evaluateActive(); + } + s.nodeList.add(this); + if (s.transformTargets != null && s.transformTargets[0] != null) { + s.transformTargets[0].addNode(this, Targets.VPF_TARGETS); + s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; + + } + s.notifyThreads |= (J3dThread.UPDATE_BEHAVIOR | + J3dThread.SOUND_SCHEDULER); + universe.removeViewPlatform(this); + } + + /** + * Re-evaluate all View active status reference to this view + * platform. This procedure is called from RenderBin when switch + * above a view platform changed. + */ + void reEvaluateView() { + View views[] = getViewList(); + + for (int i=views.length-1; i >=0; i--) { + views[i].evaluateActive(); + } + } + + /** + * Get a copy of cached view list + */ + View[] getViewList() { + synchronized (viewList) { + if (viewListDirty) { + views = (View []) viewList.toArray(new View[viewList.size()]); + viewListDirty = false; + } + return views; + } + } + + /** + * Use by BehaviorStructure to determine whether current + * ViewPlatform is active or not. + */ + boolean isActiveViewPlatform() { + View v[] = getViewList(); + if (v != null) { + for (int i=0; i < v.length; i++) { + if (v[i].active) { + return true; + } + } + } + return false; + } + + void processSwitchChanged() { + reEvaluateView(); + } + + + void compile(CompileState compState) { + + super.compile(compState); + + // keep the parent transform group. It's not worth + // to push the static transform here. + compState.keepTG = true; + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ViewSpecificGroup.java b/j3d-core/src/classes/share/javax/media/j3d/ViewSpecificGroup.java new file mode 100644 index 0000000..eb1446d --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ViewSpecificGroup.java @@ -0,0 +1,363 @@ +/* + * $RCSfile: ViewSpecificGroup.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Enumeration; + +/** + * The ViewSpecificGroup node is a Group whose descendants are + * rendered only on a specified set of views. It + * contains a list of views on which its descendants are + * rendered. Methods are provided to add, remove, and enumerate the + * list of views. The list of views is initially empty, meaning that + * the descendants of this group will not be rendered on any view. At + * least one view must be added to the list of views for rendering to + * occur. + * + *

+ * All nodes except ViewPlatform may appear as a descendant of + * ViewSpecificGroup, including another ViewSpecificGroup. If a + * ViewSpecificGroup is a descendant of a ViewSpecificGroup, the + * effect is to intersect the view sets of the ViewSpecificGroup nodes + * in the hierarchy; each ViewSpecificGroup encountered when + * traversing the scene graph further restricts the set of views on + * which its descendants are rendered. More formally, descendant + * nodes of ViewSpecificGroups are rendered in (or apply to) only + * those views that are contained in the set of views of every + * ViewSpecificGroup in the scene graph path from the Locale to the + * Node. + * + *

+ * Behavior + * nodes may appear under a ViewSpecificGroup, but are not affected by + * it--the Behavior scheduler is per-universe rather than per-View. + * BoundingLeaf nodes are similarly unaffected by being under a + * ViewSpecificGroup. A BoundingLeaf under a ViewSpecificGroup + * provides a valid bounds for any node that refers to it, + * irrespective of the view. + * + *

+ * The rest of the leaf nodes either: A) are only rendered within the + * specified view(s), for example, Shape3D, Morph, and Sound; or B) + * only affect other objects when they are rendered in the specified + * view(s), for example, AlternateAppearance, Clip, ModelClip, Fog, + * Light, Soundscape, Background. + * + * @since Java 3D 1.3 + */ + +public class ViewSpecificGroup extends Group { + /** + * Specifies that this ViewSpecificGroup node allows reading its + * view information at runtime. + */ + public static final int + ALLOW_VIEW_READ = CapabilityBits.VIEW_SPECIFIC_GROUP_ALLOW_VIEW_READ; + + /** + * Specifies that this ViewSpecificGroup node allows writing its + * view information at runtime. + */ + public static final int + ALLOW_VIEW_WRITE = CapabilityBits.VIEW_SPECIFIC_GROUP_ALLOW_VIEW_WRITE; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_VIEW_READ + }; + + /** + * Constructs and initializes a new ViewSpecificGroup node object. + */ + public ViewSpecificGroup() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + + /** + * Creates the retained mode ViewSpecificGroupRetained object that this + * ViewSpecificGroup component object will point to. + */ + void createRetained() { + this.retained = new ViewSpecificGroupRetained(); + this.retained.setSource(this); + } + + + /** + * Replaces the view at the specified index in this node's + * list of views with the specified View object. + * + * @param view the View object to be stored at the specified index. + * @param index the index of the View object to be replaced. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setView(View view, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup1")); + + ((ViewSpecificGroupRetained)this.retained).setView(view, index); + } + + + /** + * Retrieves the View object at the specified index from this node's + * list of views. + * + * @param index the index of the View object to be returned. + * @return the View object at the specified index. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public View getView(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup2")); + + return ((ViewSpecificGroupRetained)this.retained).getView(index); + } + + + /** + * Inserts the specified View object into this node's + * list of views at the specified index. + * + * @param view the View object to be inserted at the specified index. + * @param index the index at which the View object is inserted. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void insertView(View view, int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup1")); + + ((ViewSpecificGroupRetained)this.retained).insertView(view, index); + } + + + /** + * Removes the View object at the specified index from this node's + * list of views. + * If this operation causes the list of views to become empty, + * then the descendants of this ViewSpecificGroup node will not be + * rendered. + * + * @param index the index of the View object to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void removeView(int index) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup1")); + ((ViewSpecificGroupRetained)this.retained).removeView(index); + + } + + + /** + * Returns an enumeration of this ViewSpecificGroup node's list + * of views. + * + * @return an Enumeration object containing all the views. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Enumeration getAllViews() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup2")); + + return ((ViewSpecificGroupRetained)this.retained).getAllViews(); + } + + + /** + * Appends the specified View object to this node's list of views. + * + * @param view the View object to be appended. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void addView(View view) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup1")); + + ((ViewSpecificGroupRetained)this.retained).addView(view); + } + + + /** + * Returns the number of View objects in this node's list of views. + * If this number is 0, then the list of views is empty and + * the descendants of this ViewSpecificGroup node will not be + * rendered. + * + * @return the number of views in this node's list of views. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public int numViews() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup2")); + + return ((ViewSpecificGroupRetained)this.retained).numViews(); + } + + + /** + * Retrieves the index of the specified View object in this + * node's list of views. + * + * @param view the View object to be looked up. + * @return the index of the specified View object; + * returns -1 if the object is not in the list. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public int indexOfView(View view) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup2")); + + return ((ViewSpecificGroupRetained)this.retained).indexOfView(view); + } + + + /** + * Removes the specified View object from this + * node's list of views. If the specified object is not in the + * list, the list is not modified. + * If this operation causes the list of views to become empty, + * then the descendants of this ViewSpecificGroup node will not be + * rendered. + * + * @param view the View object to be removed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeView(View view) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup1")); + + ((ViewSpecificGroupRetained)this.retained).removeView(view); + } + + + /** + * Removes all View objects from this node's + * list of views. + * Since this method clears the list of views, the descendants of + * this ViewSpecificGroup node will not be rendered. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * + * @since Java 3D 1.3 + */ + public void removeAllViews() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_VIEW_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("ViewSpecificGroup1")); + + ((ViewSpecificGroupRetained)this.retained).removeAllViews(); + } + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + ViewSpecificGroup vsg = new ViewSpecificGroup(); + vsg.duplicateNode(this, forceDuplicate); + return vsg; + } + + + /** + * Copies all ViewSpecificGroup information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Group#cloneNode + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + + // XXXX: implement this? + super.duplicateAttributes(originalNode, forceDuplicate); + + ViewSpecificGroupRetained attr = (ViewSpecificGroupRetained) originalNode.retained; + ViewSpecificGroupRetained rt = (ViewSpecificGroupRetained) retained; + + for (Enumeration e = attr.getAllViews(); e.hasMoreElements(); ) { + rt.addView((View)e.nextElement()); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/ViewSpecificGroupRetained.java b/j3d-core/src/classes/share/javax/media/j3d/ViewSpecificGroupRetained.java new file mode 100644 index 0000000..f696e27 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/ViewSpecificGroupRetained.java @@ -0,0 +1,765 @@ +/* + * $RCSfile: ViewSpecificGroupRetained.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * The ViewSpecificGroup node retained object. + */ + +class ViewSpecificGroupRetained extends GroupRetained { + + ArrayList apiViewList = new ArrayList(); + + // Used by leaf objects particularly GAs + // Updated in a MT Safe manner and also used by RenderBin + ArrayList cachedViewList = new ArrayList(); + + // The object that contains the dynamic HashKey - a string type object + // Used in scoping + HashKey tempKey = new HashKey(250); + + // ArrayList of Integer indices + ArrayList parentLists = new ArrayList(); + + + static final int SET_VIEW = 0x1; + static final int ADD_VIEW = 0x2; + static final int REMOVE_VIEW = 0x4; + + // Construct retained object + ViewSpecificGroupRetained() { + this.nodeType = NodeRetained.VIEWSPECIFICGROUP; + viewLists = new ArrayList(); + } + + void addView(View view) { + int i; + Integer mtype = new Integer(ADD_VIEW); + + apiViewList.add(view); + if (source.isLive() && view != null) { + // Gather all affected leaf nodes and send a message to + // RenderingEnv and RenderBin + if (inSharedGroup) { + ArrayList parentList; + for (int k = 0; k < localToVworldKeys.length; k++) { + parentList = (ArrayList)parentLists.get(k); + // If the parentList contains this view or if this is the + // first VSG then .. + if (parentList == null || parentList.contains(view)) { + Object[] objAry = new Object[4]; + ArrayList addVsgList = new ArrayList(); + ArrayList addLeafList = new ArrayList(); + int[] addKeyList = new int[10]; + + HashKey key = localToVworldKeys[k]; + addVsgList.add(this); + addKeyList[0] = k; + objAry[0] = view; + objAry[1] = addVsgList; + objAry[2] = addLeafList; + /* + for (int n = 0; n < addLeafList.size(); n++) { + System.err.println("Shared:n = "+n+" addLeafList = "+addLeafList.get(n)); + } + */ + objAry[3] = super.processViewSpecificInfo(ADD_VIEW, + (HashKey)key, view, + addVsgList, addKeyList, addLeafList); + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.VIEWSPECIFICGROUP_CHANGED; + message.threads = (J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_SOUND| + J3dThread.SOUND_SCHEDULER); + message.universe = universe; + message.args[0] = mtype; + message.args[1] = objAry; + VirtualUniverse.mc.processMessage(message); + } + } + + } + else { + ArrayList parentList = (ArrayList)parentLists.get(0); + + // If the parentList contains this view or if this is the + // first VSG then .. + if (parentList == null || parentList.contains(view)) { + Object[] objAry = new Object[4]; + ArrayList addVsgList = new ArrayList(); + ArrayList addLeafList = new ArrayList(); + int[] addKeyList = new int[10]; + + objAry[0] = view; + objAry[1] = addVsgList; + objAry[2] = addLeafList; + + addVsgList.add(this); + addKeyList[0] = 0; + tempKey.reset(); + objAry[3] = super.processViewSpecificInfo(ADD_VIEW, + tempKey, view, + addVsgList, addKeyList, addLeafList); + + /* + for (int n = 0; n < addLeafList.size(); n++) { + System.err.println("n = "+n+" addLeafList = "+addLeafList.get(n)); + } + */ + + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.VIEWSPECIFICGROUP_CHANGED; + message.threads = (J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_SOUND| + J3dThread.SOUND_SCHEDULER); + message.universe = universe; + message.args[0] = mtype; + message.args[1] = objAry; + VirtualUniverse.mc.processMessage(message); + } + } + + + } + } + + + void setView(View view, int index) { + int i; + + View oldView = (View)apiViewList.get(index); + Integer mtype = new Integer(SET_VIEW); + + if (oldView == view) + return; + + apiViewList.set(index, view); + if (source.isLive()) { + // Gather all affected leaf nodes and send a message to + // RenderingEnv and RenderBin + if (inSharedGroup) { + ArrayList parentList; + for (int k = 0; k < localToVworldKeys.length; k++) { + parentList = (ArrayList)parentLists.get(k); + Object[] objAry = new Object[8]; + ArrayList addVsgList = new ArrayList(); + ArrayList removeVsgList = new ArrayList(); + ArrayList addLeafList = new ArrayList(); + ArrayList removeLeafList = new ArrayList(); + int[] addKeyList = new int[10]; + int[] removeKeyList = new int[10]; + + objAry[0] = view; + objAry[1] = addVsgList ; + objAry[2] = addLeafList; + objAry[4] = oldView; + objAry[5] = removeVsgList; + objAry[6] = removeLeafList; + + HashKey key = localToVworldKeys[k]; + if (oldView != null && (parentList == null || parentList.contains(oldView))) { + removeVsgList.add(this); + removeKeyList[0] = k; + objAry[7] = super.processViewSpecificInfo(REMOVE_VIEW, (HashKey)key, + oldView, removeVsgList, removeKeyList, removeLeafList); + } + + if (view != null && (parentList == null || parentList.contains(view))) { + addVsgList.add(this); + addKeyList[0] = k; + objAry[3] = super.processViewSpecificInfo(ADD_VIEW, (HashKey)key, + view, addVsgList, addKeyList, addLeafList); + } + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.VIEWSPECIFICGROUP_CHANGED; + message.threads = (J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_SOUND| + J3dThread.SOUND_SCHEDULER); + message.universe = universe; + message.args[0] = mtype; + message.args[1] = objAry; + VirtualUniverse.mc.processMessage(message); + } + + } + else { + ArrayList parentList = (ArrayList)parentLists.get(0); + Object[] objAry = new Object[8]; + ArrayList addVsgList = new ArrayList(); + ArrayList removeVsgList = new ArrayList(); + ArrayList addLeafList = new ArrayList(); + ArrayList removeLeafList = new ArrayList(); + int[] addKeyList = new int[10]; + int[] removeKeyList = new int[10]; + + objAry[0] = view; + objAry[1] = addVsgList ; + objAry[2] = addLeafList; + objAry[4] = oldView; + objAry[5] = removeVsgList; + objAry[6] = removeLeafList; + + + + tempKey.reset(); + if (oldView != null && (parentList == null || parentList.contains(oldView))) { + removeVsgList.add(this); + removeKeyList[0] = 0; + objAry[7] = super.processViewSpecificInfo(REMOVE_VIEW, (HashKey)tempKey, + oldView, removeVsgList, removeKeyList, removeLeafList); + } + if (view != null && (parentList == null || parentList.contains(view))) { + tempKey.reset(); + addVsgList.add(this); + addKeyList[0] = 0; + objAry[3] = super.processViewSpecificInfo(ADD_VIEW, (HashKey)tempKey, + view, addVsgList, addKeyList, addLeafList); + } + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.VIEWSPECIFICGROUP_CHANGED; + message.threads = (J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_SOUND| + J3dThread.SOUND_SCHEDULER); + + message.universe = universe; + message.args[0] = mtype; + message.args[1] = objAry; + VirtualUniverse.mc.processMessage(message); + } + + + } + + } + + int[] processViewSpecificInfo(int mode, HashKey key, View v, ArrayList vsgList, int[] keyList, ArrayList leaflist) { + int hkIndex = 0; + Integer hashInt = null; + int[] newKeyList = null; + // Get the intersection of the viewList with this view, + + if (source.isLive()) { + if (inSharedGroup) { + hkIndex = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + } + + if (mode == ADD_VIEW) { + ArrayList parentList = (ArrayList)parentLists.get(hkIndex); + parentList.add(v); + } + else if (mode == REMOVE_VIEW) { + ArrayList parentList = (ArrayList)parentLists.get(hkIndex); + parentList.remove(v); + } + if(apiViewList.contains(v)) { + // System.err.println("processViewSpecificInfo, this = "+this+" key = "+key); + vsgList.add(this); + if (keyList.length< vsgList.size()) { + // System.err.println("====> allocating new array"); + newKeyList = new int[keyList.length+20]; + System.arraycopy(keyList, 0, newKeyList, 0, keyList.length); + keyList = newKeyList; + } + if (mode == ADD_VIEW) { + if (inSharedGroup) { + keyList[vsgList.size()-1] = hkIndex; + + } + else { + keyList[vsgList.size()-1] = 0; + } + } + else if (mode == REMOVE_VIEW) { + if (inSharedGroup) { + keyList[vsgList.size()-1] = hkIndex; + } + else { + keyList[vsgList.size()-1] = 0; + } + } + return super.processViewSpecificInfo(mode, key, v, vsgList, keyList, leaflist); + } + } + return keyList; + } + + View getView(int index) { + return (View)apiViewList.get(index); + } + + void insertView(View view, int index) { + int i; + Integer mtype = new Integer(ADD_VIEW); + + apiViewList.add(index, view); + if (source.isLive() && view != null) { + // Gather all affected leaf nodes and send a message to + // RenderingEnv and RenderBin + if (inSharedGroup) { + ArrayList parentList; + for (int k = 0; k < localToVworldKeys.length; k++) { + parentList = (ArrayList)parentLists.get(k); + // If the parentList contains this view or if this is the + // first VSG then .. + if (parentList == null || parentList.contains(view)) { + Object[] objAry = new Object[4]; + ArrayList addVsgList = new ArrayList(); + ArrayList addLeafList = new ArrayList(); + int[] addKeyList = new int[10]; + + HashKey key = localToVworldKeys[k]; + addVsgList.add(this); + addKeyList[0] = k; + objAry[0] = view; + objAry[1] = addVsgList; + objAry[2] = addLeafList; + /* + for (int n = 0; n < addLeafList.size(); n++) { + System.err.println("Shared:n = "+n+" addLeafList = "+addLeafList.get(n)); + } + */ + objAry[3] = super.processViewSpecificInfo(ADD_VIEW, + (HashKey)key, view, + addVsgList, addKeyList, addLeafList); + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.VIEWSPECIFICGROUP_CHANGED; + message.threads = (J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_SOUND| + J3dThread.SOUND_SCHEDULER); + message.universe = universe; + message.args[0] = mtype; + message.args[1] = objAry; + VirtualUniverse.mc.processMessage(message); + } + } + + } + else { + ArrayList parentList = (ArrayList)parentLists.get(0); + + // If the parentList contains this view or if this is the + // first VSG then .. + if (parentList == null || parentList.contains(view)) { + Object[] objAry = new Object[4]; + ArrayList addVsgList = new ArrayList(); + ArrayList addLeafList = new ArrayList(); + int[] addKeyList = new int[10]; + + objAry[0] = view; + objAry[1] = addVsgList; + objAry[2] = addLeafList; + + addVsgList.add(this); + addKeyList[0] = 0; + tempKey.reset(); + objAry[3] = super.processViewSpecificInfo(ADD_VIEW, + tempKey, view, + addVsgList, addKeyList, addLeafList); + + /* + for (int n = 0; n < addLeafList.size(); n++) { + System.err.println("n = "+n+" addLeafList = "+addLeafList.get(n)); + } + */ + + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.VIEWSPECIFICGROUP_CHANGED; + message.threads = (J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_SOUND| + J3dThread.SOUND_SCHEDULER); + message.universe = universe; + message.args[0] = mtype; + message.args[1] = objAry; + VirtualUniverse.mc.processMessage(message); + } + } + + + } + } + + void removeView(int index) { + int i; + View v = (View) apiViewList.remove(index); + if (source.isLive() && v != null) { + // Gather all affected leaf nodes and send a message to + // RenderingEnv and RenderBin + if (inSharedGroup) { + ArrayList parentList; + for (int k = 0; k < localToVworldKeys.length; k++) { + parentList = (ArrayList)parentLists.get(k); + // If the parentList contains this view or if this is the + // first VSG then .. + if (parentList == null || parentList.contains(v)) { + Object[] objAry = new Object[4]; + ArrayList removeVsgList = new ArrayList(); + ArrayList removeLeafList = new ArrayList(); + int[] removeKeyList = new int[10]; + + objAry[0] = v; + objAry[1] = removeVsgList; + objAry[2] = removeLeafList; + HashKey key = localToVworldKeys[k]; + + removeVsgList.add(this); + removeKeyList[0] = k; + + objAry[3] = super.processViewSpecificInfo(REMOVE_VIEW, + (HashKey)key,v, + removeVsgList, removeKeyList, removeLeafList); + + + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.VIEWSPECIFICGROUP_CHANGED; + message.threads = (J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_SOUND| + J3dThread.SOUND_SCHEDULER); + message.universe = universe; + message.args[0] = new Integer(REMOVE_VIEW); + message.args[1] = objAry; + VirtualUniverse.mc.processMessage(message); + } + } + + } + else { + ArrayList parentList = (ArrayList)parentLists.get(0); + + // If the parentList contains this view or if this is the + // first VSG then .. + if (parentList == null || parentList.contains(v)) { + Object[] objAry = new Object[4]; + ArrayList removeVsgList = new ArrayList(); + ArrayList removeLeafList = new ArrayList(); + int[] removeKeyList = new int[10]; + + objAry[0] = v; + objAry[1] = removeVsgList; + objAry[2] = removeLeafList; + removeVsgList.add(this); + removeKeyList[0] = 0; + + tempKey.reset(); + objAry[3] = super.processViewSpecificInfo(REMOVE_VIEW, + (HashKey)tempKey, v, + removeVsgList, removeKeyList, removeLeafList); + + /* + for (int n = 0; n < removeKeyList.size(); n++) { + System.err.println("n = "+n+" keyValue = "+removeKeyList.get(n)); + } + */ + J3dMessage message = new J3dMessage(); + message.type = J3dMessage.VIEWSPECIFICGROUP_CHANGED; + message.threads = (J3dThread.UPDATE_RENDERING_ENVIRONMENT| + J3dThread.UPDATE_RENDER | + J3dThread.UPDATE_SOUND| + J3dThread.SOUND_SCHEDULER); + message.universe = universe; + message.args[0] = new Integer(REMOVE_VIEW); + message.args[1] = objAry; + VirtualUniverse.mc.processMessage(message); + } + } + + } + } + + Enumeration getAllViews() { + Vector viewList = new Vector(); + for (int i = 0; i < apiViewList.size(); i++) { + viewList.add(apiViewList.get(i)); + } + return viewList.elements(); + } + + int numViews() { + return apiViewList.size(); + } + + int indexOfView(View view) { + return apiViewList.indexOf(view); + } + + void removeView(View view) { + removeView(apiViewList.indexOf(view)); + } + + void removeAllViews() { + int size = apiViewList.size(); + for (int i = 0; i < size; i++) { + removeView(0); + } + } + + void compile(CompileState compState) { + super.compile(compState); + + // don't remove this group node + mergeFlag = SceneGraphObjectRetained.DONT_MERGE; + + // XXXX: complete this + } + + void setLive(SetLiveState s) { + if (inBackgroundGroup) { + throw new + IllegalSceneGraphException(J3dI18N.getString("ViewSpecificGroup3")); + } + + s.inViewSpecificGroup = true; + ArrayList savedViewList = s.viewLists; + if (s.changedViewGroup == null) { + s.changedViewGroup = new ArrayList(); + s.changedViewList = new ArrayList(); + s.keyList = new int[10]; + s.viewScopedNodeList = new ArrayList(); + s.scopedNodesViewList = new ArrayList(); + } + super.setLive(s); + s.viewLists = savedViewList; + + } + + void clearLive(SetLiveState s) { + ArrayList savedViewList = s.viewLists; + if (s.changedViewGroup == null) { + s.changedViewGroup = new ArrayList(); + s.changedViewList = new ArrayList(); + s.keyList = new int[10]; + s.viewScopedNodeList = new ArrayList(); + s.scopedNodesViewList = new ArrayList(); + } + // XXXX: This is a hack since removeNodeData is called before + // children are clearLives + int[] tempIndex = null; + // Don't keep the indices if everything will be cleared + if (inSharedGroup && (s.keys.length != localToVworld.length)) { + tempIndex = new int[s.keys.length]; + for (int i = 0; i < s.keys.length; i++) { + tempIndex[i] = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length); + } + } + super.clearLive(s); + // Do this after children clearlive since part of the viewLists may get cleared + // during removeNodeData + + // If the last SharedGroup is being cleared + if((!inSharedGroup) || (localToVworld == null)) { + viewLists.clear(); + } + else { + // Must be in reverse, to preserve right indexing. + for (int i = tempIndex.length-1; i >= 0 ; i--) { + if(tempIndex[i] >= 0) { + viewLists.remove(tempIndex[i]); + } + } + } + s.viewLists = savedViewList; + } + + + void removeNodeData(SetLiveState s) { + if((!inSharedGroup) || (s.keys.length == localToVworld.length)) { + s.changedViewGroup.add(this); + // Remove everything .. + int size = s.changedViewGroup.size(); + if (s.keyList.length < size) { + int[] newKeyList = new int[s.keyList.length+20]; + System.arraycopy(s.keyList, 0, newKeyList, 0, s.keyList.length); + s.keyList = newKeyList; + // System.err.println("====> RemovedNodeData: Allocating Non-shared"); + } + s.keyList[size -1] = -1; + parentLists.clear(); + } + // A path of the shared group is removed + else { + int i, index; + int size = s.changedViewGroup.size(); + if (s.keyList.length < size+1+s.keys.length) { + int[] newKeyList = new int[s.keyList.length+s.keys.length+20]; + System.arraycopy(s.keyList, 0, newKeyList, 0, s.keyList.length); + s.keyList = newKeyList; + // System.err.println("====> RemovedNodeData: Allocating Shared"); + } + // Must be in reverse, to preserve right indexing. + for (i = s.keys.length-1; i >= 0; i--) { + index = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length); + if(index >= 0) { + s.changedViewGroup.add(this); + s.keyList[s.changedViewGroup.size() -1] = index; + parentLists.remove(index); + } + } + } + s.viewLists =viewLists; + super.removeNodeData(s); + } + + void updateCachedInformation(int component, View view, int index ) { + ArrayList list = (ArrayList) cachedViewList.get(index); + + /* + System.err.println("updateCachedInformation v = "+this+" index = "+index+" list = "+list+" cachedViewList.size() = "+cachedViewList.size()); + for (int k = 0; k < cachedViewList.size(); k++) { + System.err.println("v = "+this+" k = "+k+" v.cachedViewList.get(k) = "+cachedViewList.get(k)); + } + */ + if ((component & ADD_VIEW) != 0) { + list.add(view); + } + else if ((component & REMOVE_VIEW) != 0) { + list.remove(view); + } + /* + System.err.println("After updateCachedInformation v = "+this+" index = "+index+" list = "+list+" cachedViewList.size() = "+cachedViewList.size()); + for (int k = 0; k < cachedViewList.size(); k++) { + System.err.println("v = "+this+" k = "+k+" v.cachedViewList.get(k) = "+cachedViewList.get(k)); + } + */ + + } + + void setNodeData(SetLiveState s) { + super.setNodeData(s); + if (!inSharedGroup) { + int size = s.changedViewGroup.size(); + if (s.keyList.length < size+1) { + int[] newKeyList = new int[s.keyList.length+20]; + System.arraycopy(s.keyList, 0, newKeyList, 0, s.keyList.length); + s.keyList = newKeyList; + // System.err.println("====> setNodeData: Allocating Non-shared"); + } + setAuxData(s, 0, 0); + } else { + // For inSharedGroup case. + int j, hkIndex; + + int size = s.changedViewGroup.size(); + if (s.keyList.length < size+1+s.keys.length) { + int[] newKeyList = new int[s.keyList.length+s.keys.length+20]; + System.arraycopy(s.keyList, 0, newKeyList, 0, s.keyList.length); + s.keyList = newKeyList; + // System.err.println("====> setNodeData: Allocating Shared"); + } + + for(j=0; j= 0) { + setAuxData(s, j, hkIndex); + + } else { + MasterControl.getCoreLogger().severe("Can't Find matching hashKey in setNodeData."); + } + } + } + // Make the VSG's viewLists as the relavant one for its children + s.viewLists = viewLists; + + } + + void setAuxData(SetLiveState s, int index, int hkIndex) { + ArrayList vl; + ArrayList parentList = null; + int size = apiViewList.size(); + if (s.viewLists != null) { + // System.err.println("=====> VSG: = "+this+" hkIndex = "+hkIndex+" s.viewLists = "+s.viewLists); + parentList = (ArrayList) s.viewLists.get(hkIndex); + if (parentList != null) { + vl = new ArrayList(); + for (int i = 0; i < size; i++) { + Object obj1 = apiViewList.get(i); + // Get the intersection of the parentlist and this vsg's api list + for (int j = 0; j < parentList.size(); j++) { + if (obj1 == parentList.get(j)) { + vl.add(obj1); + break; + } + } + } + } + else { + vl = new ArrayList(); + // Only include the non null ones in the apiViewList + for (int i = 0; i < size; i++) { + Object obj = apiViewList.get(i); + if (obj != null) { + vl.add(obj); + } + } + } + } + else { + vl = new ArrayList(); + // Only include the non null ones in the apiViewList + for (int i = 0; i < size; i++) { + Object obj = apiViewList.get(i); + if (obj != null) { + vl.add(obj); + } + } + } + if (parentList != null) { + parentLists.add(hkIndex, parentList.clone()); + } + else { + parentLists.add(hkIndex, null); + } + + viewLists.add(hkIndex,vl); + s.changedViewGroup.add(this); + s.changedViewList.add(vl); + if (localToVworldKeys != null) { + s.keyList[s.changedViewGroup.size() -1] = hkIndex; + } + else { + s.keyList[s.changedViewGroup.size() -1] = 0; + } + + + + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/VirtualUniverse.java b/j3d-core/src/classes/share/javax/media/j3d/VirtualUniverse.java new file mode 100644 index 0000000..a7cacf9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/VirtualUniverse.java @@ -0,0 +1,1351 @@ +/* + * $RCSfile: VirtualUniverse.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.17 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A VirtualUniverse object is the top-level container for all scene + * graphs. A virtual universe consists of a set of Locale objects, + * each of which has a high-resolution position within the virtual + * universe. An application or applet may have more than one + * VirtualUniverse objects, but many applications will need only one. + * Virtual universes are separate entities in that no node object may + * exist in more than one virtual universe at any one time. Likewise, + * the objects in one virtual universe are not visible in, nor do they + * interact with objects in, any other virtual universe. + *

+ * A VirtualUniverse object defines methods to enumerate its Locale + * objects and to remove them from the virtual universe. + * + *

+ * For more information, see the + * Introduction to the Java 3D API and + * Scene Graph Superstructure + * documents. + * + * @see Locale + */ + +public class VirtualUniverse extends Object { + // NOTE TO DEVELOPERS: + // + // Developers who modify Java 3D in any way should modify + // the auxiliary implementation vendor string in VersionInfo.java. + // See that file for instructions. + + // The global MasterControl object. There is only one of these + // for all of Java 3D. + static MasterControl mc = null; + + // The lock to acquire before traversing the scene graph + Object sceneGraphLock = new Object(); + Object behaviorLock = new Object(); + + // A list of locales that are contained within this universe + Vector listOfLocales = new Vector(); + + // The list of view platforms. + ArrayList viewPlatforms = new ArrayList(); + + + // The cached list of vp's + Object[] viewPlatformList = null; + + // A flag that indicates that the list of view platforms has changed + boolean vpChanged = false; + + // The list of backgrounds + Vector backgrounds = new Vector(); + + // The list of clips + Vector clips = new Vector(); + + // The list of sounds + Vector sounds = new Vector(); + + // The list of soundscapes + Vector soundscapes = new Vector(); + + // The Behavior Scheduler Thread for this Virtual Universe. + BehaviorScheduler behaviorScheduler = null; + + + // The geometry structure for this Universe + GeometryStructure geometryStructure = null; + + // The transform structure for this Universe + TransformStructure transformStructure = null; + + // The behavior structure for this Universe + BehaviorStructure behaviorStructure = null; + + // The sound structure for this Universe + SoundStructure soundStructure = null; + + // The rendering attributes structure for this Universe + RenderingEnvironmentStructure renderingEnvironmentStructure = null; + + // Reference count of users of the RenderingEnvironmentStructure + int renderingEnvironmentStructureRefCount = 0; + + // This is a global counter for node id's. + long nodeIdCount = 0; + + // This is a global counter for view id's. + int viewIdCount = 0; + + // This is a vector of free nodeid's + Vector nodeIdFreeList = new Vector(); + + // This is a vector of free viewid's + ArrayList viewIdFreeList = new ArrayList(); + + // The number of nodes in this universe + int numNodes = 0; + + // The State object used when branch graphs are added + SetLiveState setLiveState; + + // This is an array of references to objects that need their mirror + // copies updated. It is updated by the traverser and emptied by + // the view thread. + ObjectUpdate[] updateObjects = new ObjectUpdate[16]; + + // The number of valid entries in updateObjects + int updateObjectsLen = 0; + + // A list of all mirror geometry object that are dirty + ArrayList dirtyGeomList = new ArrayList(); + + // The current primary view for this universe + View currentView; + + // A flag to indicate that we are in a behavior routine + boolean inBehavior = false; + + // Flags to indicate if events need to be delivered + boolean enableComponent = false; + boolean enableFocus = false; + boolean enableKey = false; + boolean enableMouse = false; + boolean enableMouseMotion = false; + boolean enableMouseWheel = false; + + // Keep track of how many active View use this universe + int activeViewCount = 0; + + // Root ThreadGroup for creating Java 3D threads + static ThreadGroup rootThreadGroup; + + // Properties object for getProperties + private static J3dQueryProps properties = null; + + // Flag to indicate that user thread has to + // stop until MC completely register/unregister View. + View regViewWaiting = null; + View unRegViewWaiting = null; + boolean isSceneGraphLock = false; + + private Object waitLock = new Object(); + + // Set of scene graph structure change listeners + private HashSet structureChangeListenerSet = null; + + // Set of shader error listeners + private HashSet shaderErrorListenerSet = null; + private ShaderErrorListener defaultShaderErrorListener = + ShaderProgram.getDefaultErrorListener(); + + // Set of rendering error listeners + private static HashSet renderingErrorListenerSet = null; + private static RenderingErrorListener defaultRenderingErrorListener = + Renderer.getDefaultErrorListener(); + + /** + * Constructs a new VirtualUniverse. + */ + public VirtualUniverse() { + setLiveState = new SetLiveState(this); + initMCStructure(); + } + + + void initMCStructure() { + if (geometryStructure != null) { + geometryStructure.cleanup(); + } + geometryStructure = new GeometryStructure(this); + if (transformStructure != null) { + transformStructure.cleanup(); + } + transformStructure = new TransformStructure(this); + if (behaviorStructure != null) { + behaviorStructure.cleanup(); + } + behaviorStructure = new BehaviorStructure(this); + if (soundStructure != null) { + soundStructure.cleanup(); + } + soundStructure = new SoundStructure(this); + if (renderingEnvironmentStructure != null) { + renderingEnvironmentStructure.cleanup(); + } + renderingEnvironmentStructure = new + RenderingEnvironmentStructure(this); + + } + + /** + * Initialize the native interface and anything else that needs + * to be initialized. + */ + static void loadLibraries() { + // No need to do anything. The act of calling any method in this + // class is sufficient to cause the static MasterControl object + // to be created which, in turn, loads the native libraries. + } + + static { + boolean isLoggableConfig = MasterControl.isCoreLoggable(Level.CONFIG); + Logger logger = MasterControl.getCoreLogger(); + + // Print out version information unless this is a + // non-debuggable, release (fcs) build + if (isLoggableConfig || J3dDebug.devPhase || VersionInfo.isDebug) { + StringBuffer strBuf = new StringBuffer("3D "); + if (J3dDebug.devPhase) { + strBuf.append("[dev] "); + } + strBuf.append(VersionInfo.getVersion()); + String str = strBuf.toString(); + if (isLoggableConfig) { + logger.config(str); + } else { + System.err.println(str); + System.err.println(); + } + } + + // Print out debugging information for debug builds + if (isLoggableConfig || VersionInfo.isDebug) { + StringBuffer strBuf = new StringBuffer(); + strBuf.append("Initializing 3D runtime system:\n"). + append(" version = "). + append(VersionInfo.getVersion()). + append("\n"). + append(" vendor = "). + append(VersionInfo.getVendor()). + append("\n"). + append(" specification.version = "). + append(VersionInfo.getSpecificationVersion()). + append("\n"). + append(" specification.vendor = "). + append(VersionInfo.getSpecificationVendor()); + String str = strBuf.toString(); + if (isLoggableConfig) { + logger.config(str); + } else { + System.err.println(str); + System.err.println(); + } + } + + // Java 3D cannot run in headless mode, so we will throw a + // HeadlessException if isHeadless() is true. This avoids a + // cryptic error message from MasterControl.loadLibraries(). + if (java.awt.GraphicsEnvironment.isHeadless()) { + throw new java.awt.HeadlessException(); + } + + // Load the native libraries and create the static + // MasterControl object + MasterControl.loadLibraries(); + mc = new MasterControl(); + + // Print out debugging information for debug builds + if (isLoggableConfig || VersionInfo.isDebug) { + StringBuffer strBuf = new StringBuffer(); + strBuf.append("3D system initialized\n"). + append(" rendering pipeline = "). + append(Pipeline.getPipeline().getPipelineName()); + String str = strBuf.toString(); + if (isLoggableConfig) { + logger.config(str); + } else { + System.err.println(str); + System.err.println(); + } + } + } + + /** + * Adds a locale at the end of list of locales + * @param locale the locale to be added + */ + void addLocale(Locale locale) { + listOfLocales.addElement(locale); + } + + /** + * Removes a Locale and its associates branch graphs from this + * universe. All branch graphs within the specified Locale are + * detached, regardless of whether their ALLOW_DETACH capability + * bits are set. The Locale is then marked as being dead: no + * branch graphs may subsequently be attached. + * + * @param locale the Locale to be removed. + * + * @exception IllegalArgumentException if the specified Locale is not + * attached to this VirtualUniverse. + * + * @since Java 3D 1.2 + */ + public void removeLocale(Locale locale) { + if (locale.getVirtualUniverse() != this) { + throw new IllegalArgumentException(J3dI18N.getString("VirtualUniverse0")); + } + + listOfLocales.removeElement(locale); + locale.removeFromUniverse(); + if (isEmpty()) { + VirtualUniverse.mc.postRequest(MasterControl.EMPTY_UNIVERSE, + this); + } + setLiveState.reset(null); + } + + + /** + * Removes all Locales and their associates branch graphs from + * this universe. All branch graphs within each Locale are + * detached, regardless of whether their ALLOW_DETACH capability + * bits are set. Each Locale is then marked as being dead: no + * branch graphs may subsequently be attached. This method + * should be called by applications and applets to allow + * Java 3D to cleanup its resources. + * + * @since Java 3D 1.2 + */ + public void removeAllLocales() { + // NOTE: this is safe because Locale.removeFromUniverse does not + // remove the Locale from the listOfLocales + int i; + + + for (i = listOfLocales.size()-1; i > 0; i--) { + ((Locale)listOfLocales.get(i)).removeFromUniverse(); + } + + if (i >= 0) { + // We have to clear() the listOfLocales first before + // invoke the last removeFromUniverse() so that isEmpty() + // (call from View.deactivate() ) will return true and + // threads can destroy from MC. + Locale loc = (Locale) listOfLocales.get(0); + listOfLocales.clear(); + loc.removeFromUniverse(); + } + VirtualUniverse.mc.postRequest(MasterControl.EMPTY_UNIVERSE, + this); + + setLiveState.reset(null); + } + + + /** + * Returns the enumeration object of all locales in this virtual universe. + * @return the enumeration object + */ + public Enumeration getAllLocales() { + return this.listOfLocales.elements(); + } + + /** + * Returns the number of locales. + * @return the count of locales + */ + public int numLocales() { + return this.listOfLocales.size(); + } + + + /** + * Sets the priority of all Java 3D threads to the specified + * value. The default value is the priority of the thread that + * started Java 3D. + * + * @param priority the new thread priority + * + * @exception IllegalArgumentException if the priority is not in + * the range MIN_PRIORITY to MAX_PRIORITY + * + * @exception SecurityException if the priority is greater than + * that of the calling thread + * + * @since Java 3D 1.2 + */ + public static void setJ3DThreadPriority(int priority) { + if (priority > Thread.MAX_PRIORITY) { + priority = Thread.MAX_PRIORITY; + } else if (priority < Thread.MIN_PRIORITY) { + priority = Thread.MIN_PRIORITY; + } + VirtualUniverse.mc.setThreadPriority(priority); + } + + + /** + * Retrieves that priority of Java 3D's threads. + * + * @return the current priority of Java 3D's threads + * + * @since Java 3D 1.2 + */ + public static int getJ3DThreadPriority() { + return VirtualUniverse.mc.getThreadPriority(); + } + + + /** + * Returns a read-only Map object containing key-value pairs that + * define various global properties for Java 3D. All of the keys + * are String objects. The values are key-specific, but most will + * be String objects. + * + *

+ * The set of global Java 3D properties always includes values for + * the following keys: + * + *

+ *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Key (String)Value Type
    j3d.versionString
    j3d.vendorString
    j3d.specification.versionString
    j3d.specification.vendorString
    j3d.pipelineString
    j3d.rendererString
    + *
+ * + *

+ * The descriptions of the values returned for each key are as follows: + * + *

+ *

    + * + *
  • + * j3d.version + *
      + * A String that defines the Java 3D implementation version. + * The portion of the implementation version string before the first + * space must adhere to one of the the following three formats + * (anything after the first space is an optional free-form addendum + * to the version): + *
        + * x.y.z
        + * x.y.z_p
        + * x.y.z-ssss
        + *
      + * where: + *
        + * x is the major version number
        + * y is the minor version number
        + * z is the sub-minor version number
        + * p is the patch revision number
        + * ssss is a string, identifying a non-release build + * (e.g., beta1, build47, rc1, etc.). It may only + * contain letters, numbers, periods, dashes, or + * underscores. + *
      + *
    + *
  • + *

    + * + *

  • + * j3d.vendor + *
      + * String that specifies the Java 3D implementation vendor. + *
    + *
  • + *

    + * + *

  • + * j3d.specification.version + *
      + * A String that defines the Java 3D specification version. + * This string must be of the following form: + *
        + * x.y + *
      + * where: + *
        + * x is the major version number
        + * y is the minor version number
        + *
      + * No other characters are allowed in the specification version string. + *
    + *
  • + *

    + * + *

  • + * j3d.specification.vendor + *
      + * String that specifies the Java 3D specification vendor. + *
    + *
  • + *

    + * + *

  • + * j3d.pipeline + *
      + * String that specifies the Java 3D rendering pipeline. This could + * be one of: "NATIVE_OGL", "NATIVE_D3D", or "JOGL". Others could be + * added in the future. + *
    + *
  • + *

    + * + *

  • + * j3d.renderer + *
      + * String that specifies the underlying rendering library. This could + * be one of: "OpenGL" or "DirectX". Others could be added in the future. + *
    + *
  • + *

    + * + *

+ * + * @return the global Java 3D properties + * + * @since Java 3D 1.3 + */ + public static final Map getProperties() { + if (properties == null) { + // Create lists of keys and values + ArrayList keys = new ArrayList(); + ArrayList values = new ArrayList(); + + // Implementation version string is obtained from the + // ImplementationVersion class. + keys.add("j3d.version"); + values.add(VersionInfo.getVersion()); + + keys.add("j3d.vendor"); + values.add(VersionInfo.getVendor()); + + keys.add("j3d.specification.version"); + values.add(VersionInfo.getSpecificationVersion()); + + keys.add("j3d.specification.vendor"); + values.add(VersionInfo.getSpecificationVendor()); + + keys.add("j3d.renderer"); + values.add(Pipeline.getPipeline().getRendererName()); + + keys.add("j3d.pipeline"); + values.add(Pipeline.getPipeline().getPipelineName()); + + // Now Create read-only properties object + properties = + new J3dQueryProps((String[]) keys.toArray(new String[0]), + values.toArray()); + } + return properties; + } + + + /** + * This returns the next available nodeId as a string. + */ + // XXXX: reuse of id's imply a slight collision problem in the + // render queue's. + // BUG 4181362 + String getNodeId() { + String str; + + if (nodeIdFreeList.size() == 0) { + str = Long.toString(nodeIdCount); + nodeIdCount++; + } else { + // Issue 496: Remove last object using index to avoid performance + // hit of a needless linear search. + int idx = nodeIdFreeList.size() - 1; + str = (String) nodeIdFreeList.remove(idx); + } + return(str); + } + + /** + * This returns the next available viewId + */ + Integer getViewId() { + Integer id; + int size; + + synchronized (viewIdFreeList) { + size = viewIdFreeList.size(); + if (size == 0) { + id = new Integer(viewIdCount++); + } else { + id = (Integer) viewIdFreeList.remove(size-1); + } + } + return(id); + } + + /** + * This returns a viewId to the freelist + */ + void addViewIdToFreeList(Integer viewId) { + synchronized (viewIdFreeList) { + viewIdFreeList.add(viewId); + } + } + + void addViewPlatform(ViewPlatformRetained vp) { + vpChanged = true; + viewPlatforms.add(vp); + } + + void removeViewPlatform(ViewPlatformRetained vp) { + vpChanged = true; + viewPlatforms.remove(viewPlatforms.indexOf(vp)); + } + + synchronized Object[] getViewPlatformList() { + if (vpChanged) { + viewPlatformList = viewPlatforms.toArray(); + vpChanged = false; + } + return viewPlatformList; + } + + void checkForEnableEvents() { + enableComponentEvents(); + if (enableFocus) { + enableFocusEvents(); + } + if (enableKey) { + enableKeyEvents(); + } + if (enableMouse) { + enableMouseEvents(); + } + if (enableMouseMotion) { + enableMouseMotionEvents(); + } + if (enableMouseWheel) { + enableMouseWheelEvents(); + } + + } + + void enableComponentEvents() { + // Issue 458 - This method is now a noop + /* + Enumeration cvs; + Canvas3D cv; + ViewPlatformRetained vp; + View views[]; + Object[] vps = getViewPlatformList(); + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) { + cv.eventCatcher.enableComponentEvents(); + } + } + } + } + } + */ + } + + void disableFocusEvents() { + Enumeration cvs; + Canvas3D cv; + ViewPlatformRetained vp; + View views[]; + Object[] vps = getViewPlatformList(); + enableFocus = false; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.disableFocusEvents(); + } + } + } + } + + } + + void enableFocusEvents() { + Enumeration cvs; + Canvas3D cv; + ViewPlatformRetained vp; + View views[]; + Object[] vps = getViewPlatformList(); + enableFocus = true; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.enableFocusEvents(); + } + } + } + } + } + + + void disableKeyEvents() { + Enumeration cvs; + Canvas3D cv; + ViewPlatformRetained vp; + Object[] vps = getViewPlatformList(); + View views[]; + + enableKey = false; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.disableKeyEvents(); + } + } + } + } + } + + + void enableKeyEvents() { + Enumeration cvs; + Canvas3D cv; + ViewPlatformRetained vp; + Object[] vps = getViewPlatformList(); + View views[]; + + enableKey = true; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.enableKeyEvents(); + } + } + } + } + } + + + void disableMouseEvents() { + Enumeration cvs; + Canvas3D cv; + View views[]; + ViewPlatformRetained vp; + Object[] vps = getViewPlatformList(); + + enableMouse = false; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.disableMouseEvents(); + } + } + } + } + } + + void enableMouseEvents() { + Enumeration cvs; + Canvas3D cv; + View views[]; + ViewPlatformRetained vp; + Object[] vps = getViewPlatformList(); + + enableMouse = true; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.enableMouseEvents(); + } + } + } + } + } + + + void disableMouseMotionEvents() { + Enumeration cvs; + Canvas3D cv; + View views[]; + ViewPlatformRetained vp; + Object[] vps = getViewPlatformList(); + + enableMouseMotion = false; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.disableMouseMotionEvents(); + } + } + } + } + } + + void enableMouseMotionEvents() { + Enumeration cvs; + Canvas3D cv; + View views[]; + ViewPlatformRetained vp; + Object[] vps = getViewPlatformList(); + + enableMouseMotion = true; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.enableMouseMotionEvents(); + } + } + } + } + } + + void disableMouseWheelEvents() { + Enumeration cvs; + Canvas3D cv; + View views[]; + ViewPlatformRetained vp; + Object[] vps = getViewPlatformList(); + + enableMouseWheel = false; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.disableMouseWheelEvents(); + } + } + } + } + } + + void enableMouseWheelEvents() { + Enumeration cvs; + Canvas3D cv; + View views[]; + ViewPlatformRetained vp; + Object[] vps = getViewPlatformList(); + + enableMouseWheel = true; + + if (vps != null) { + for (int i=0; i=0; j--) { + cvs = views[j].getAllCanvas3Ds(); + while(cvs.hasMoreElements()) { + cv = (Canvas3D) cvs.nextElement(); + // offscreen canvas does not have event catcher + if (cv.eventCatcher != null) + cv.eventCatcher.enableMouseWheelEvents(); + } + } + } + } + } + + /** + * Sets the "current" view (during view activation) for this virtual + * universe. + * @param last activated view + */ + final void setCurrentView(View view) { + this.currentView = view; + } + + /** + * Returns the "current" view (the last view activated for this virtual + * universe. + * @return last activated view + */ + final View getCurrentView() { + return this.currentView; + } + + + /** + * Method to return the root thread group. This must be called from + * within a doPrivileged block. + */ + static ThreadGroup getRootThreadGroup() { + return rootThreadGroup; + } + + /** + * return true if all Locales under it don't have branchGroup + * attach to it. + */ + boolean isEmpty() { + Enumeration elm = listOfLocales.elements(); + + while (elm.hasMoreElements()) { + Locale loc = (Locale) elm.nextElement(); + if (!loc.branchGroups.isEmpty()) { + return false; + } + } + return true; + } + + void resetWaitMCFlag() { + synchronized (waitLock) { + regViewWaiting = null; + unRegViewWaiting = null; + isSceneGraphLock = true; + } + } + + void waitForMC() { + synchronized (waitLock) { + if (unRegViewWaiting != null) { + if ((regViewWaiting == null) || + (regViewWaiting != unRegViewWaiting)) { + while (!unRegViewWaiting.doneUnregister) { + MasterControl.threadYield(); + } + unRegViewWaiting.doneUnregister = false; + unRegViewWaiting = null; + } + } + + if (regViewWaiting != null) { + while (!VirtualUniverse.mc.isRegistered(regViewWaiting)) { + MasterControl.threadYield(); + } + regViewWaiting = null; + } + isSceneGraphLock = false; + } + } + + /** + * Adds the specified GraphStructureChangeListener to the set of listeners + * that will be notified when the graph structure is changed on a live + * scene graph. If the specifed listener is null no action is taken and no + * exception is thrown. + * + * @param listener the listener to add to the set. + * + * @since Java 3D 1.4 + */ + public void addGraphStructureChangeListener(GraphStructureChangeListener listener) { + if (listener == null) { + return; + } + + if (structureChangeListenerSet == null) { + structureChangeListenerSet = new HashSet(); + } + + synchronized(structureChangeListenerSet) { + structureChangeListenerSet.add(listener); + } + } + + /** + * Removes the specified GraphStructureChangeListener from the set of listeners. This + * method performs no function, nor does it throw an exception if the specified listener + * is not currently in the set or is null. + * + * @param listener the listener to remove from the set. + * + * @since Java 3D 1.4 + */ + public void removeGraphStructureChangeListener(GraphStructureChangeListener listener) { + if (structureChangeListenerSet == null) { + return; + } + + synchronized(structureChangeListenerSet) { + structureChangeListenerSet.remove(listener); + } + } + + /** + * Processes all live BranchGroup add and removes and notifies + * any registered listeners. Used for add and remove + */ + void notifyStructureChangeListeners(boolean add, Object parent, BranchGroup child) { + if (structureChangeListenerSet == null) { + return; + } + + synchronized(structureChangeListenerSet) { + Iterator it = structureChangeListenerSet.iterator(); + while(it.hasNext()) { + GraphStructureChangeListener listener = it.next(); + try { + if (add) { + listener.branchGroupAdded(parent, child); + } else { + listener.branchGroupRemoved(parent, child); + } + } + catch (RuntimeException e) { + System.err.println("Exception occurred in GraphStructureChangeListener:"); + e.printStackTrace(); + } + catch (Error e) { + // Issue 264 - catch Error + System.err.println("Error occurred in GraphStructureChangeListener:"); + e.printStackTrace(); + } + } + } + } + + /** + * Processes all live BranchGroup moves and notifies + * any registered listeners. Used for moveTo + */ + void notifyStructureChangeListeners(Object oldParent, Object newParent, BranchGroup child) { + if (structureChangeListenerSet == null) { + return; + } + + synchronized(structureChangeListenerSet) { + Iterator it = structureChangeListenerSet.iterator(); + while(it.hasNext()) { + GraphStructureChangeListener listener = it.next(); + try { + listener.branchGroupMoved(oldParent, newParent, child); + } + catch (RuntimeException e) { + System.err.println("Exception occurred in GraphStructureChangeListener:"); + e.printStackTrace(); + } + catch (Error e) { + // Issue 264 - catch Error + System.err.println("Error occurred in GraphStructureChangeListener:"); + e.printStackTrace(); + } + } + } + } + + + /** + * Adds the specified ShaderErrorListener to the set of listeners + * that will be notified when a programmable shader error is + * detected on a live scene graph. If the specifed listener is + * null no action is taken and no exception is thrown. + * If a shader error occurs, the listeners will be called + * asynchronously from a separate notification thread. The Java 3D + * renderer and behavior scheduler will continue to run as if the + * error had not occurred, except that shading will be disabled + * for the objects in error. If applications desire to detach or + * modify the scene graph as a result of the error, they should + * use a behavior post if they want that change to be + * synchronous with the renderer. + * + * @param listener the listener to add to the set. + * + * @since Java 3D 1.4 + */ + public void addShaderErrorListener(ShaderErrorListener listener) { + if (listener == null) { + return; + } + + if (shaderErrorListenerSet == null) { + shaderErrorListenerSet = new HashSet(); + } + + synchronized(shaderErrorListenerSet) { + shaderErrorListenerSet.add(listener); + } + } + + /** + * Removes the specified ShaderErrorListener from the set of + * listeners. This method performs no function, nor does it throw + * an exception if the specified listener is not currently in the + * set or is null. + * + * @param listener the listener to remove from the set. + * + * @since Java 3D 1.4 + */ + public void removeShaderErrorListener(ShaderErrorListener listener) { + if (shaderErrorListenerSet == null) { + return; + } + + synchronized(shaderErrorListenerSet) { + shaderErrorListenerSet.remove(listener); + } + } + + /** + * Notifies all listeners of a shader error. If no listeners exist, a default + * listener is notified. + */ + void notifyShaderErrorListeners(ShaderError error) { + boolean errorReported = false; + + // Notify all error listeners in the set + if (shaderErrorListenerSet != null) { + synchronized(shaderErrorListenerSet) { + Iterator it = shaderErrorListenerSet.iterator(); + while(it.hasNext()) { + ShaderErrorListener listener = it.next(); + try { + listener.errorOccurred(error); + } + catch (RuntimeException e) { + System.err.println("Exception occurred in ShaderErrorListener:"); + e.printStackTrace(); + } + catch (Error e) { + // Issue 264 - catch Error + System.err.println("Error occurred in ShaderErrorListener:"); + e.printStackTrace(); + } + errorReported = true; + } + } + } + + // Notify the default error listener if the set is null or empty + if (!errorReported) { + defaultShaderErrorListener.errorOccurred(error); + } + } + + + // Issue 260 : rendering error listeners. + + /** + * Adds the specified RenderingErrorListener to the set of listeners + * that will be notified when a rendering error is detected. + * If the specifed listener is null no action is taken and no exception + * is thrown. + * If a rendering error occurs, the listeners will be called + * asynchronously from a separate notification thread. If the set + * of listeners is empty, a default listener is notified. The + * default listener prints the error information to System.err and + * then calls System.exit(). + * + * @param listener the listener to add to the set. + * + * @since Java 3D 1.5 + */ + public static void addRenderingErrorListener(RenderingErrorListener listener) { + if (listener == null) { + return; + } + + if (renderingErrorListenerSet == null) { + renderingErrorListenerSet = new HashSet(); + } + + synchronized(renderingErrorListenerSet) { + renderingErrorListenerSet.add(listener); + } + } + + /** + * Removes the specified RenderingErrorListener from the set of + * listeners. This method performs no function, nor does it throw + * an exception if the specified listener is not currently in the + * set or is null. + * + * @param listener the listener to remove from the set. + * + * @since Java 3D 1.5 + */ + public static void removeRenderingErrorListener(RenderingErrorListener listener) { + if (renderingErrorListenerSet == null) { + return; + } + + synchronized(renderingErrorListenerSet) { + renderingErrorListenerSet.remove(listener); + } + } + + /** + * Notifies all listeners of a rendering error. If no listeners exist, + * a default listener is notified. + */ + static void notifyRenderingErrorListeners(RenderingError error) { + boolean errorReported = false; + + // Notify all error listeners in the set + if (renderingErrorListenerSet != null) { + synchronized(renderingErrorListenerSet) { + Iterator it = renderingErrorListenerSet.iterator(); + while(it.hasNext()) { + RenderingErrorListener listener = it.next(); + try { + listener.errorOccurred(error); + } + catch (RuntimeException e) { + System.err.println("Exception occurred in RenderingErrorListener:"); + e.printStackTrace(); + } + catch (Error e) { + // Issue 264 - catch Error + System.err.println("Error occurred in RenderingErrorListener:"); + e.printStackTrace(); + } + errorReported = true; + } + } + } + + // Notify the default error listener if the set is null or empty + if (!errorReported) { + defaultRenderingErrorListener.errorOccurred(error); + } + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupAnd.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupAnd.java new file mode 100644 index 0000000..f7c7729 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupAnd.java @@ -0,0 +1,134 @@ +/* + * $RCSfile: WakeupAnd.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; + +/** + * Class specifying any number of wakeup conditions ANDed together. + * This WakeupCondition object specifies that Java 3D should awaken + * this Behavior when all of the WakeupCondition's constituent wakeup + * criteria become valid. + *

+ * Note that a unique WakeupCriterion object must be used + * for each individual element in the array of wakeup criteria. + */ + +public final class WakeupAnd extends WakeupCondition { + + WakeupCriterion conditions[]; + boolean conditionsMet[]; + + /** + * Constructs a new WakeupAnd criterion. + * @param conditions a vector of individual Wakeup conditions + */ + public WakeupAnd(WakeupCriterion conditions[]) { + this.conditions = new WakeupCriterion[conditions.length]; + this.conditionsMet = new boolean[conditions.length]; + + for(int i = 0; i < conditions.length; i++){ + this.conditions[i] = conditions[i]; + // It is false by default when array is initialized. + // this.conditionsMet[i] = false; + } + } + + + /** + * This sets the bit for the given child, then checks if the full condition is met + */ + void setConditionMet(int id, Boolean checkSchedulingRegion) { + conditionsMet[id] = true; + + for (int i=0; i + * Note that a unique WakeupCriterion object must be used for each + * individual element in the set of arrays specified by the array of + * WakeupOr objects. + */ + +public final class WakeupAndOfOrs extends WakeupCondition { + + WakeupOr conditions[]; + boolean conditionsMet[]; + + /** + * Constructs a new WakeupAndOfOrs criterion. + * @param conditions a vector of individual Wakeup conditions + */ + public WakeupAndOfOrs(WakeupOr conditions[]) { + this.conditions = new WakeupOr[conditions.length]; + this.conditionsMet = new boolean[conditions.length]; + + for(int i = 0; i < conditions.length; i++){ + this.conditions[i] = conditions[i]; + // conditionsMet is false by default when it is initilized + // this.conditionsMet[i] = false; + } + } + + + /** + * This sets the bit for the given child, then checks if the full condition is met + */ + void setConditionMet(int id, Boolean checkSchedulingRegion) { + conditionsMet[id] = true; + + for (int i=0; i + * Note that a unique WakeupCriterion object must be used with each instance + * of a Behavior. Sharing wakeup criteria among different instances of + * a Behavior is illegal. Similarly, a unique WakeupCriterion object + * must be used for each individual element in the set of arrays used + * to construct WakeupOr, WakeupAnd, WakeupOrOfAnds, and + * WakeupAndOfOrs objects. + */ + +public abstract class WakeupCriterion extends WakeupCondition { + + /** + * Flag specifying whether this criterion triggered a wakeup + */ + boolean triggered; + + /** + * Returns true if this criterion triggered the wakeup. + * @return true if this criterion triggered the wakeup. + */ + public boolean hasTriggered(){ + return this.triggered; + } + + /** + * Set the Criterion's trigger flag to true. + */ + void setTriggered(){ + this.triggered = true; + if (this.parent == null) { + super.setConditionMet(id, Boolean.TRUE); + } else { + parent.setConditionMet(id, Boolean.TRUE); + } + } + + /** + * Initialize And/Or tree and add criterion to the BehaviourStructure. + * + */ + void buildTree(WakeupCondition parent, int id, BehaviorRetained b) { + super.buildTree(parent, id, b); + triggered = false; + addBehaviorCondition(b.universe.behaviorStructure); + } + + + /** + * This goes through the AndOr tree to remove the various criterion from the + * BehaviorStructure. + * We can't use behav.universe.behaviorStructure since behav + * may reassign to another universe at this time. + * + */ + void cleanTree(BehaviorStructure bs){ + conditionMet = false; + removeBehaviorCondition(bs); + }; + + + /** + * This goes through the AndOr tree to reset various criterion. + */ + void resetTree() { + conditionMet = false; + triggered = false; + resetBehaviorCondition(behav.universe.behaviorStructure); + } + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + abstract void addBehaviorCondition(BehaviorStructure bs); + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + abstract void removeBehaviorCondition(BehaviorStructure bs); + + /** + * It is used reset wakeupCondition when it is reused. + */ + abstract void resetBehaviorCondition(BehaviorStructure bs); +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupIndexedList.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupIndexedList.java new file mode 100644 index 0000000..3bf7df6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupIndexedList.java @@ -0,0 +1,603 @@ +/* + * $RCSfile: WakeupIndexedList.java,v $ + * + * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A strongly type unorder indexed array list. + * All operations remove(WakeupCondition), add(WakeupCondition), + * contains(WakeupCondition) etc. take O(1) time. + * The class is designed to optimize speed. So many reductance + * procedures call and range check as found in ArrayList are + * removed. + * + *

+ * Use the following code to iterate through an array. + * + *

+ *  WakeupIndexedList  list = new WakeupIndexedList(YourClass.class);
+ *  // add element here
+ *
+ *  YourClass[] arr = (YourClass []) list.toArray();
+ *  int size = list.arraySize();
+ *  for (int i=0; i < size; i++) {
+ *      YourClass obj = arr[i];
+ *      ....
+ *  }
+ * 
+ * + *

+ * Note: + *

    + * 1) The array return is a copied of internal array.
    + * 2) Don't use arr.length , use list.arraySize();
    + * 3) No need to do casting for individual element as in + * ArrayList.
    + * 4) WakeupIndexedList is thread safe.
    + * 5) Object implement this interface MUST initialize the index + * to -1.
    + *
+ * + *

+ * Limitation: + *

    + * - Same element can't add in two different WakeupIndexedList
    + * - Order of WakeupCondition is not important
    + * - Can't modify the clone() copy.
    + * - Object can't be null
    + *
+ */ + +class WakeupIndexedList implements Cloneable, java.io.Serializable { + + // XXXX: set to false when release + final static boolean debug = false; + + /** + * The array buffer into which the elements of the ArrayList are stored. + * The capacity of the ArrayList is the length of this array buffer. + * + * It is non-private to enable compiler do inlining for get(), + * set(), remove() when -O flag turn on. + */ + transient WakeupCondition elementData[]; + + /** + * Clone copy of elementData return by toArray(true); + */ + transient Object cloneData[]; + // size of the above clone objec. + transient int cloneSize; + + transient boolean isDirty = true; + + /** + * Component Type of individual array element entry + */ + Class componentType; + + /** + * The size of the ArrayList (the number of elements it contains). + * + * We make it non-private to enable compiler do inlining for + * getSize() when -O flag turn on. + */ + int size; + + int listType; + + // Current VirtualUniverse using this structure + VirtualUniverse univ; + + /** + * Constructs an empty list with the specified initial capacity. + * and the class data Type + * + * @param initialCapacity the initial capacity of the list. + * @param componentType class type of element in the list. + */ + WakeupIndexedList(int initialCapacity, Class componentType, + int listType, VirtualUniverse univ) { + this.componentType = componentType; + this.elementData = (WakeupCondition[])java.lang.reflect.Array.newInstance( + componentType, initialCapacity); + this.listType = listType; + this.univ = univ; + } + + /** + * Constructs an empty list. + * @param componentType class type of element in the list. + */ + WakeupIndexedList(Class componentType, int listType, + VirtualUniverse univ) { + this(10, componentType, listType, univ); + } + + + /** + * Constructs an empty list with the specified initial capacity. + * + * @param initialCapacity the initial capacity of the list. + */ + WakeupIndexedList(int initialCapacity, int listType, + VirtualUniverse univ) { + this(initialCapacity, WakeupCondition.class, listType, univ); + } + + + /** + * Constructs an empty list. + * componentType default to Object. + */ + WakeupIndexedList(int listType, VirtualUniverse univ) { + this(10, WakeupCondition.class, listType, univ); + } + + + /** + * Initialize all indexes to -1 + */ + final static void init(WakeupCondition obj, int len) { + obj.listIdx = new int[2][len]; + + for (int i=0; i < len; i++) { + obj.listIdx[0][i] = -1; + obj.listIdx[1][i] = -1; + } + } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list. + */ + final int size() { + return size; + } + + /** + * Returns the size of entry use in toArray() number of elements + * in this list. + * + * @return the number of elements in this list. + */ + final int arraySize() { + return cloneSize; + } + + /** + * Tests if this list has no elements. + * + * @return true if this list has no elements; + * false otherwise. + */ + final boolean isEmpty() { + return size == 0; + } + + /** + * Returns true if this list contains the specified element. + * + * @param o element whose presence in this List is to be tested. + */ + synchronized final boolean contains(WakeupCondition o) { + return (o.listIdx[o.behav.getIdxUsed(univ)][listType] >= 0); + } + + + /** + * Searches for the last occurence of the given argument, testing + * for equality using the equals method. + * + * @param o an object. + * @return the index of the first occurrence of the argument in this + * list; returns -1 if the object is not found. + * @see Object#equals(Object) + */ + synchronized final int indexOf(WakeupCondition o) { + return o.listIdx[o.behav.getIdxUsed(univ)][listType]; + } + + /** + * Returns a shallow copy of this ArrayList instance. (The + * elements themselves are not copied.) + * + * @return a clone of this ArrayList instance. + */ + synchronized protected final Object clone() { + try { + WakeupIndexedList v = (WakeupIndexedList)super.clone(); + v.elementData = (WakeupCondition[])java.lang.reflect.Array.newInstance( + componentType, size); + System.arraycopy(elementData, 0, v.elementData, 0, size); + isDirty = true; // can't use the old cloneData reference + return v; + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + + + /** + * Returns an array containing all of the elements in this list. + * The size of the array may longer than the actual size. Use + * arraySize() to retrieve the size. + * The array return is a copied of internal array. if copy + * is true. + * + * @return an array containing all of the elements in this list + */ + synchronized final Object[] toArray(boolean copy) { + if (copy) { + if (isDirty) { + if ((cloneData == null) || cloneData.length < size) { + cloneData = (Object[])java.lang.reflect.Array.newInstance( + componentType, size); + } + System.arraycopy(elementData, 0, cloneData, 0, size); + cloneSize = size; + isDirty = false; + } + return cloneData; + } else { + cloneSize = size; + return elementData; + } + + } + + /** + * Returns an array containing all of the elements in this list. + * The size of the array may longer than the actual size. Use + * arraySize() to retrieve the size. + * The array return is a copied of internal array. So another + * thread can continue add/delete the current list. However, + * it should be noticed that two call to toArray() may return + * the same copy. + * + * @return an array containing all of the elements in this list + */ + synchronized final Object[] toArray() { + return toArray(true); + } + + + /** + * Returns an array containing elements starting from startElement + * all of the elements in this list. A new array of exact size + * is always allocated. + * + * @param startElement starting element to copy + * + * @return an array containing elements starting from + * startElement, null if element not found. + * + */ + synchronized final Object[] toArray(WakeupCondition startElement) { + int idx = indexOf(startElement); + if (idx < 0) { + return (Object[])java.lang.reflect.Array.newInstance(componentType, 0); + } + + int s = size - idx; + Object data[] = (Object[])java.lang.reflect.Array.newInstance(componentType, s); + System.arraycopy(elementData, idx, data, 0, s); + return data; + } + + /** + * Trims the capacity of this ArrayList instance to be the + * list's current size. An application can use this operation to minimize + * the storage of an ArrayList instance. + */ + synchronized final void trimToSize() { + if (elementData.length > size) { + Object oldData[] = elementData; + elementData = (WakeupCondition[])java.lang.reflect.Array.newInstance( + componentType, + size); + System.arraycopy(oldData, 0, elementData, 0, size); + } + } + + + // Positional Access Operations + + /** + * Returns the element at the specified position in this list. + * + * @param index index of element to return. + * @return the element at the specified position in this list. + * @throws IndexOutOfBoundsException if index is out of range (index + * < 0 || index >= size()). + */ + synchronized final Object get(int index) { + return elementData[index]; + } + + /** + * Replaces the element at the specified position in this list with + * the specified element. + * + * @param index index of element to replace. + * @param o element to be stored at the specified position. + * @return the element previously at the specified position. + * @throws IndexOutOfBoundsException if index out of range + * (index < 0 || index >= size()). + */ + synchronized final void set(int index, WakeupCondition o) { + + WakeupCondition oldElm = elementData[index]; + if (oldElm != null) { + oldElm.listIdx[oldElm.behav.getIdxUsed(univ)][listType] = -1; + } + elementData[index] = o; + + int univIdx = o.behav.getIdxUsed(univ); + + if (debug) { + if (o.listIdx[univIdx][listType] != -1) { + System.err.println("Illegal use of UnorderIndexedList idx in set " + + o.listIdx[univIdx][listType]); + Thread.dumpStack(); + } + } + + o.listIdx[univIdx][listType] = index; + isDirty = true; + } + + /** + * Appends the specified element to the end of this list. + * It is the user responsible to ensure that the element add is of + * the same type as array componentType. + * + * @param o element to be appended to this list. + */ + synchronized final void add(WakeupCondition o) { + if (elementData.length == size) { + WakeupCondition oldData[] = elementData; + elementData = (WakeupCondition[])java.lang.reflect.Array.newInstance( + componentType, + (size << 1)); + System.arraycopy(oldData, 0, elementData, 0, size); + + } + + int univIdx = o.behav.getIdxUsed(univ); + // System.err.println(this + " add " + o + " univ " + univIdx); + if (debug) { + int idx = o.listIdx[univIdx][listType]; + if (idx >= 0) { + if (elementData[idx] != o) { + System.err.println("Illegal use of UnorderIndexedList idx in add " + idx); + Thread.dumpStack(); + } + } + } + + int idx = size++; + elementData[idx] = o; + o.listIdx[univIdx][listType] = idx; + isDirty = true; + } + + + /** + * Removes the element at the specified position in this list. + * Replace the removed element by the last one. + * + * @param index the index of the element to removed. + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index >= size()). + */ + synchronized final void remove(int index) { + WakeupCondition elm = elementData[index]; + int univIdx = elm.behav.getIdxUsed(univ); + + if (debug) { + if (elm.listIdx[univIdx][listType] != index) { + System.err.println("Inconsistent idx in remove, expect " + index + + " actual " + elm.listIdx[univIdx][listType]); + Thread.dumpStack(); + } + } + + elm.listIdx[univIdx][listType] = -1; + size--; + if (index != size) { + elm = elementData[size]; + elm.listIdx[univIdx][listType] = index; + elementData[index] = elm; + } + elementData[size] = null; + isDirty = true; + /* + if ((cloneData != null) && (index < cloneData.length)) { + cloneData[index] = null; // for gc + } + */ + } + + + /** + * Removes the element at the last position in this list. + * @return The element remove + * @throws IndexOutOfBoundsException if array is empty + */ + synchronized final Object removeLastElement() { + WakeupCondition elm = elementData[--size]; + elementData[size] = null; + elm.listIdx[elm.behav.getIdxUsed(univ)][listType] = -1; + isDirty = true; + /* + if ((cloneData != null) && (size < cloneData.length)) { + cloneData[size] = null; // for gc + } + */ + return elm; + } + + + /** + * Removes the specified element in this list. + * Replace the removed element by the last one. + * + * @param o the element to removed. + * @return true if object remove + * @throws IndexOutOfBoundsException if index out of range (index + * < 0 || index >= size()). + */ + synchronized final boolean remove(WakeupCondition o) { + int univIdx = o.behav.getIdxUsed(univ); + int idx = o.listIdx[univIdx][listType]; + + // System.err.println(this + " remove " + o + " univ " + univIdx); + + if (idx >= 0) { + // Object in the container + if (debug) { + if (o != elementData[idx]) { + System.err.println(" Illegal use of UnorderIndexedList in remove expect " + o + " actual " + elementData[idx] + " idx = " + idx); + Thread.dumpStack(); + } + } + size--; + if (idx != size) { + WakeupCondition elm = elementData[size]; + elementData[idx] = elm; + elm.listIdx[elm.behav.getIdxUsed(univ)][listType] = idx; + } + elementData[size] = null; + o.listIdx[univIdx][listType] = -1; + isDirty = true; + return true; + } + return false; + } + + + /** + * Removes all of the elements from this list. The list will + * be empty after this call returns. + */ + synchronized final void clear() { + WakeupCondition o; + + for (int i = size-1; i >= 0; i--) { + o = elementData[i]; + o.listIdx[o.behav.getIdxUsed(univ)][listType] = -1; + elementData[i] = null; // Let gc do its work + } + + size = 0; + isDirty = true; + } + + synchronized final void clearMirror() { + if (cloneData != null) { + for (int i = cloneData.length-1; i >= 0; i--) { + // don't set index to -1 since the original + // copy is using this. + cloneData[i] = null; // Let gc do its work + } + } + cloneSize = 0; + isDirty = true; + } + + final Class getComponentType() { + return componentType; + } + + synchronized public String toString() { + StringBuffer sb = new StringBuffer(hashCode() + " Size = " + size + "["); + int len = size-1; + Object obj; + + for (int i=0; i < size; i++) { + obj = elementData[i]; + if (obj != null) { + sb.append(elementData[i].toString()); + } else { + sb.append("NULL"); + } + if (i != len) { + sb.append(", "); + } + } + sb.append("]"); + return sb.toString(); + } + + /** + * Save the state of the ArrayList instance to a stream (that + * is, serialize it). + * + * @serialData The length of the array backing the ArrayList + * instance is emitted (int), followed by all of its elements + * (each an Object) in the proper order. + */ + private synchronized void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException{ + // Write out element count, and any hidden stuff + s.defaultWriteObject(); + + // Write out array length + s.writeInt(elementData.length); + + // Write out all elements in the proper order. + for (int i=0; iArrayList instance from a stream (that is, + * deserialize it). + */ + private synchronized void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in array length and allocate array + int arrayLength = s.readInt(); + elementData = (WakeupCondition[])java.lang.reflect.Array.newInstance( + componentType, arrayLength); + + // Read in all elements in the proper order. + for (int i=0; i= ComponentEvent.COMPONENT_FIRST && + AwtId <= ComponentEvent.COMPONENT_LAST) || + (EventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) { + behav.universe.enableComponentEvents(); + } + if ((AwtId >= FocusEvent.FOCUS_FIRST && AwtId <= FocusEvent.FOCUS_LAST) || + (EventMask & AWTEvent.FOCUS_EVENT_MASK) != 0) { + behav.universe.enableFocusEvents(); + } + if ((AwtId >= KeyEvent.KEY_FIRST && AwtId <= KeyEvent.KEY_LAST) || + (EventMask & AWTEvent.KEY_EVENT_MASK) != 0) { + behav.universe.enableKeyEvents(); + } + if ((AwtId >= MouseEvent.MOUSE_FIRST) && + (AwtId <= MouseEvent.MOUSE_LAST)) { + if ((AwtId == MouseEvent.MOUSE_DRAGGED) || + (AwtId == MouseEvent.MOUSE_MOVED)) { + behav.universe.enableMouseMotionEvents(); + } + else if (AwtId == MouseEvent.MOUSE_WHEEL) { + behav.universe.enableMouseWheelEvents(); + } + else if (AwtId == MouseEvent.MOUSE_CLICKED || + AwtId == MouseEvent.MOUSE_ENTERED || + AwtId == MouseEvent.MOUSE_EXITED || + AwtId == MouseEvent.MOUSE_PRESSED || + AwtId == MouseEvent.MOUSE_RELEASED) { + behav.universe.enableMouseEvents(); + } + } else { + if ((EventMask & AWTEvent.MOUSE_EVENT_MASK) != 0) { + behav.universe.enableMouseEvents(); + } + if ((EventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0) { + behav.universe.enableMouseMotionEvents(); + } + if ((EventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0) { + behav.universe.enableMouseWheelEvents(); + } + } + enableAWTEventTS = bs.awtEventTimestamp; + } + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnActivation.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnActivation.java new file mode 100644 index 0000000..b7d5663 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnActivation.java @@ -0,0 +1,84 @@ +/* + * $RCSfile: WakeupOnActivation.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class specifying a wakeup the first time an active Viewplatform's + * activation + * volume intersects with this object's scheduling region. + * This gives the behavior an explicit means of executing code when + * it is activated. + */ +public final class WakeupOnActivation extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 1; + + /** + * Constructs a new WakeupOnActivation criterion. + */ + public WakeupOnActivation() { + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + behav.wakeupArray[BehaviorRetained.WAKEUP_ACTIVATE_INDEX]++; + behav.wakeupMask |= BehaviorRetained.WAKEUP_ACTIVATE; + bs.wakeupOnActivation.add(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + behav.wakeupArray[BehaviorRetained.WAKEUP_ACTIVATE_INDEX]--; + if (behav.wakeupArray[BehaviorRetained.WAKEUP_ACTIVATE_INDEX] == 0) { + behav.wakeupMask &= ~BehaviorRetained.WAKEUP_ACTIVATE; + } + bs.wakeupOnActivation.remove(this); + } + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) {} +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnBehaviorPost.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnBehaviorPost.java new file mode 100644 index 0000000..e33c47e --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnBehaviorPost.java @@ -0,0 +1,132 @@ +/* + * $RCSfile: WakeupOnBehaviorPost.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class that specifies a Behavior wakeup when a specific behavior object + * posts a specific event + */ +public final class WakeupOnBehaviorPost extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 1; + + Behavior armingBehavior, triggeringBehavior; + int post, triggeringPost; + + + /** + * Constructs a new WakeupOnBehaviorPost criterion. A behavior of null + * specifies a wakeup from any behavior on the specified postId. A postId + * of 0 specifies a wakeup on any postId from the specified behavior. + * A behavior of null AND a postId of 0 specify a wakeup on any postId + * from any behavior. + * @param behavior the behavior that must be the source of the post, + * if behavior == null, then any behavior posting the postId will cause + * the wakeup. + * @param postId the postId that will trigger a wakeup if posted by the + * specified behavior, if postId == 0, then any post by the specified + * behavior will cause the wakeup. + */ + public WakeupOnBehaviorPost(Behavior behavior, int postId) { + this.armingBehavior = behavior; + this.post = postId; + triggeringPost = -1; + triggeringBehavior = null; + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Retrieve the WakeupCriterion's specified postId + * @return the post id specified in this object's construction. + */ + public int getPostId(){ + return post; + } + + + /** + * Returns the behavior specified in this object's constructor. + * @return the arming behavior + */ + public Behavior getBehavior () { + return armingBehavior; + } + + + /** + * Returns the postId that caused the behavior to wakeup. If the postId + * used to construct this wakeup criterion was not zero, then the + * triggering postId will always be equal to the postId used in the + * constructor. + */ + public int getTriggeringPostId() { + return triggeringPost; + } + + + /** + * Returns the behavior that triggered this wakeup. If the arming + * behavior used to construct this object was not null, then the + * triggering behavior will be the same as the arming behavior. + */ + public Behavior getTriggeringBehavior() { + return triggeringBehavior; + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + bs.wakeupOnBehaviorPost.add(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + bs.wakeupOnBehaviorPost.remove(this); + } + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) {} +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionEntry.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionEntry.java new file mode 100644 index 0000000..1bc2095 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionEntry.java @@ -0,0 +1,598 @@ +/* + * $RCSfile: WakeupOnCollisionEntry.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.*; + +/** + * Class specifying a wakeup when the specified object + * collides with any other object in the scene graph. + * + */ +public final class WakeupOnCollisionEntry extends WakeupCriterion { + + // different types of WakeupIndexedList that use in GeometryStructure + static final int COND_IN_GS_LIST = 0; + static final int COLLIDEENTRY_IN_BS_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + /** + * Use geometry in computing collisions. + */ + public static final int USE_GEOMETRY = 10; + + /** + * Use geometric bounds as an approximation in computing collisions. + */ + public static final int USE_BOUNDS = 11; + + static final int GROUP = NodeRetained.GROUP; + static final int BOUNDINGLEAF = NodeRetained.BOUNDINGLEAF; + static final int SHAPE = NodeRetained.SHAPE; + static final int MORPH = NodeRetained.MORPH; + static final int ORIENTEDSHAPE3D = NodeRetained.ORIENTEDSHAPE3D; + static final int BOUND = 0; + + /** + * Accuracy mode one of USE_GEOMETRY or USE_BOUNDS + */ + int accuracyMode; + + // Cached the arming Node being used when it is not BOUND + NodeRetained armingNode; + + // A transformed Bounds of Group/Bounds, use by + // BOUND, GROUP + Bounds vwcBounds = null; + + // Use by BoundingLeaf, point to mirror BoundingLeaf + // transformedRegion under this leaf is used. + BoundingLeafRetained boundingLeaf = null; + + /** + * Geometry atoms that this wakeup condition refer to. + * Only use by SHAPE, MORPH, GROUP, ORIENTEDSHAPE + */ + UnorderList geometryAtoms = null; + + // one of GROUP, BOUNDINGLEAF, SHAPE, MORPH, BOUND + int nodeType; + + SceneGraphPath armingPath = null; + Bounds armingBounds = null; + + // the following two references are set only after a collision + // has occurred + Bounds collidingBounds = null; + SceneGraphPath collidingPath = null; + + /** + * Constructs a new WakeupOnCollisionEntry criterion with + * USE_BOUNDS for a speed hint. + * @param armingPath the path used to arm collision + * detection + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or + * BoundingLeaf node. + */ + public WakeupOnCollisionEntry(SceneGraphPath armingPath) { + this(armingPath, USE_BOUNDS); + } + + /** + * Constructs a new WakeupOnCollisionEntry criterion. + * @param armingPath the path used to arm collision + * detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or + * BoundingLeaf node. + */ + public WakeupOnCollisionEntry(SceneGraphPath armingPath, + int speedHint) { + this(new SceneGraphPath(armingPath), speedHint, null); + } + + /** + * Constructs a new WakeupOnCollisionEntry criterion. + * @param armingNode the Group, Shape, or Morph node used to + * arm collision detection + * @exception IllegalArgumentException if object is under a + * SharedGroup node or object is other than a Group, Shape3D, + * Morph or BoundingLeaf node. + */ + public WakeupOnCollisionEntry(Node armingNode) { + this(armingNode, USE_BOUNDS); + } + + /** + * Constructs a new WakeupOnCollisionEntry criterion. + * @param armingNode the Group, Shape, or Morph node used to + * arm collision detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object is under a + * SharedGroup node or object is other than a Group, Shape3D, + * Morph or BoundingLeaf node. + */ + public WakeupOnCollisionEntry(Node armingNode, int speedHint) { + this(new SceneGraphPath(null, armingNode), speedHint, null); + } + + + /** + * Constructs a new WakeupOnCollisionEntry criterion. + * @param armingBounds the bounds object used to arm collision + * detection + */ + public WakeupOnCollisionEntry(Bounds armingBounds) { + this(null, USE_BOUNDS, (Bounds) armingBounds.clone()); + } + + /** + * Constructs a new WakeupOnCollisionEntry criterion. + * @param armingPath the path used to arm collision + * detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @param armingBounds the bounds object used to arm collision + * detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or + * BoundingLeaf node. + */ + WakeupOnCollisionEntry(SceneGraphPath armingPath, + int speedHint, Bounds armingBounds) { + if (armingPath != null) { + this.armingNode = (NodeRetained) armingPath.getObject().retained; + nodeType = getNodeType(armingNode, armingPath, + "WakeupOnCollisionEntry"); + this.armingPath = armingPath; + validateSpeedHint(speedHint, "WakeupOnCollisionEntry4"); + } else { + this.armingBounds = armingBounds; + nodeType = BOUND; + } + accuracyMode = speedHint; + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Returns the path used in specifying the collision condition. + * @return the SceneGraphPath object generated when arming this + * criterion---null implies that a bounds object armed this criteria + */ + public SceneGraphPath getArmingPath() { + return (armingPath != null ? + new SceneGraphPath(armingPath) : null); + } + + /** + * Returns the bounds object used in specifying the collision condition. + * @return the Bounds object generated when arming this + * criterion---null implies that a SceneGraphPath armed this criteria + */ + public Bounds getArmingBounds() { + return (armingBounds != null ? + (Bounds)armingBounds.clone() : null); + } + + /** + * Retrieves the path describing the object causing the collision. + * @return the SceneGraphPath that describes the triggering object. + * @exception IllegalStateException if not called from within the + * a behavior's processStimulus method which was awoken by a collision. + */ + public SceneGraphPath getTriggeringPath() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnCollisionEntry5")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new IllegalStateException + (J3dI18N.getString("WakeupOnCollisionEntry5")); + } + } + return (collidingPath != null ? + new SceneGraphPath(collidingPath): null); + } + + /** + * Retrieves the Bounds object that caused the collision + * @return the colliding Bounds object. + * @exception IllegalStateException if not called from within the + * a behavior's processStimulus method which was awoken by a collision. + */ + public Bounds getTriggeringBounds() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnCollisionEntry6")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new IllegalStateException + (J3dI18N.getString("WakeupOnCollisionEntry6")); + } + } + return (collidingBounds != null ? + (Bounds)(collidingBounds.clone()): null); + } + + + /** + * Node legality checker + * throw Exception if node is not legal. + * @return nodeType + */ + static int getNodeType(NodeRetained armingNode, + SceneGraphPath armingPath, String s) + throws IllegalArgumentException { + + // check if SceneGraphPath is unique + // Note that graph may not live at this point so we + // can't use node.inSharedGroup. + if (!armingPath.validate()) { + throw new IllegalArgumentException(J3dI18N.getString(s + "7")); + } + + if (armingNode.inBackgroundGroup) { + throw new IllegalArgumentException(J3dI18N.getString(s + "1")); + } + + // This should come before Shape3DRetained check + if (armingNode instanceof OrientedShape3DRetained) { + return ORIENTEDSHAPE3D; + } + + if (armingNode instanceof Shape3DRetained) { + return SHAPE; + } + + if (armingNode instanceof MorphRetained) { + return MORPH; + } + + if (armingNode instanceof GroupRetained) { + return GROUP; + } + + if (armingNode instanceof BoundingLeafRetained) { + return BOUNDINGLEAF; + } + + throw new IllegalArgumentException(J3dI18N.getString(s + "0")); + } + + /** + * speedHint legality checker + * throw Exception if speedHint is not legal + */ + static void validateSpeedHint(int speedHint, String s) + throws IllegalArgumentException { + if ((speedHint != USE_GEOMETRY) && (speedHint != USE_BOUNDS)) { + throw new IllegalArgumentException(J3dI18N.getString(s)); + } + + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + + switch (nodeType) { + case SHAPE: // Use geometryAtoms[].collisionBounds + case ORIENTEDSHAPE3D: + if (!armingNode.source.isLive()) { + return; + } + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + Shape3DRetained shape = (Shape3DRetained) armingNode; + geometryAtoms.add(Shape3DRetained.getGeomAtom(shape.getMirrorShape(armingPath))); + break; + case MORPH: // Use geometryAtoms[].collisionBounds + if (!armingNode.source.isLive()) { + return; + } + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + MorphRetained morph = (MorphRetained) armingNode; + geometryAtoms.add(Shape3DRetained.getGeomAtom(morph.getMirrorShape(armingPath))); + break; + case BOUNDINGLEAF: // use BoundingLeaf.transformedRegion + if (!armingNode.source.isLive()) { + return; + } + this.boundingLeaf = ((BoundingLeafRetained) armingNode).mirrorBoundingLeaf; + break; + case BOUND: // use this.vwcBounds + vwcBounds = (Bounds) armingBounds.clone(); + this.armingNode = behav; + break; + case GROUP: + if (!armingNode.source.isLive()) { + return; + } + if (accuracyMode == USE_GEOMETRY) { + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + ((GroupRetained) armingNode).searchGeometryAtoms(geometryAtoms); + } + // else use this.vwcBounds + default: + } + + behav.universe.geometryStructure.addWakeupOnCollision(this); + } + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + vwcBounds = null; + if (geometryAtoms != null) { + geometryAtoms.clear(); + } + boundingLeaf = null; + behav.universe.geometryStructure.removeWakeupOnCollision(this); + } + + + // Set collidingPath & collidingBounds + void setTarget(BHLeafInterface leaf) { + SceneGraphPath path; + Bounds bound; + + if (leaf instanceof GeometryAtom) { + // Find the triggered Path & Bounds for this geometry Atom + GeometryAtom geomAtom = (GeometryAtom) leaf; + Shape3DRetained shape = geomAtom.source; + + path = getSceneGraphPath(shape.sourceNode, + shape.key, + shape.getCurrentLocalToVworld(0)); + bound = getTriggeringBounds(shape); + + } else { + // Find the triggered Path & Bounds for this alternative + // collision target + GroupRetained group = (GroupRetained) leaf; + path = getSceneGraphPath(group); + bound = getTriggeringBounds(group); + } + + if (path != null) { + // colliding path may be null when branch detach before + // user behavior retrieve the previous colliding path + collidingPath = path; + collidingBounds = bound; + } + } + + + // Invoke from GeometryStructure to update vwcBounds of GROUP + void updateCollisionBounds(boolean reEvaluateGAs){ + if (nodeType == GROUP) { + GroupRetained group = (GroupRetained) armingNode; + if (group.collisionBound != null) { + vwcBounds = (Bounds) group.collisionBound.clone(); + } else { + // this may involve recursive tree traverse if + // BoundsAutoCompute is true, we can't avoid + // since the bound under it may change by transform + vwcBounds = group.getEffectiveBounds(); + } + group.transformBounds(armingPath, vwcBounds); + } else if (nodeType == BOUND) { + vwcBounds.transform(armingBounds, behav.getCurrentLocalToVworld()); + } + + if (reEvaluateGAs && + (nodeType == GROUP) && + (accuracyMode == USE_GEOMETRY)) { + geometryAtoms.clear(); + ((GroupRetained) armingNode).searchGeometryAtoms(geometryAtoms); + } + } + + + /** + * Return the TriggeringBounds for node + */ + static Bounds getTriggeringBounds(Shape3DRetained mirrorShape) { + NodeRetained node = mirrorShape.sourceNode; + + if (node instanceof Shape3DRetained) { + Shape3DRetained shape = (Shape3DRetained) node; + if (shape.collisionBound == null) { + // TODO: get bounds by copy + return shape.getEffectiveBounds(); + } + return shape.collisionBound; + } + + + MorphRetained morph = (MorphRetained) node; + if (morph.collisionBound == null) { + // TODO: get bounds by copy + return morph.getEffectiveBounds(); + } + return morph.collisionBound; + } + + + /** + * Return the TriggeringBounds for node + */ + static Bounds getTriggeringBounds(GroupRetained group) { + if (group.collisionBound == null) { + // TODO: get bounds by copy + return group.getEffectiveBounds(); + } + return group.collisionBound; + } + + static SceneGraphPath getSceneGraphPath(GroupRetained group) { + // Find the transform base on the key + Transform3D transform = null; + GroupRetained srcGroup = group.sourceNode; + + synchronized (srcGroup.universe.sceneGraphLock) { + if (group.key == null) { + transform = srcGroup.getCurrentLocalToVworld(); + } else { + HashKey keys[] = srcGroup.localToVworldKeys; + if (keys == null) { + // the branch is already detach when + // Collision got this message + return null; + } + transform = srcGroup.getCurrentLocalToVworld(group.key); + } + return getSceneGraphPath(srcGroup, group.key, transform); + } + + } + + /** + * return the SceneGraphPath of the geomAtom. + * Find the alternative Collision target closest to the locale. + */ + static SceneGraphPath getSceneGraphPath(NodeRetained startNode, + HashKey key, + Transform3D transform) { + synchronized (startNode.universe.sceneGraphLock) { + NodeRetained target = startNode; + + UnorderList path = new UnorderList(5, Node.class); + NodeRetained nodeR = target; + Locale locale = nodeR.locale; + String nodeId; + Vector parents; + NodeRetained linkR; + + if (nodeR.inSharedGroup) { + // getlastNodeId() will destroy this key + if (key != null) { + key = new HashKey(key); + } else { + key = new HashKey(startNode.localToVworldKeys[0]); + } + } + + do { + if (nodeR.source.getCapability(Node.ENABLE_COLLISION_REPORTING)){ + path.add(nodeR.source); + } + + if (nodeR instanceof SharedGroupRetained) { + + // retrieve the last node ID + nodeId = key.getLastNodeId(); + parents = ((SharedGroupRetained) nodeR).parents; + NodeRetained prevNodeR = nodeR; + for(int i=parents.size()-1; i >=0; i--) { + linkR = (NodeRetained) parents.elementAt(i); + if (linkR.nodeId.equals(nodeId)) { + nodeR = linkR; + break; + } + } + if (nodeR == prevNodeR) { + // the branch is already detach when + // Collision got this message + return null; + } + } else if ((nodeR instanceof GroupRetained) && + ((GroupRetained) nodeR).collisionTarget) { + // we need to find the collision target closest to the + // root of tree + target = nodeR; + + if (key == null) { + transform = nodeR.getCurrentLocalToVworld(null); + } else { + transform = nodeR.getCurrentLocalToVworld(key); + } + } + nodeR = nodeR.parent; + } while (nodeR != null); // reach Locale + + Node nodes[]; + if (target == startNode) { // in most case + nodes = (Node []) path.toArray(false); + } else { // alternativeCollisionTarget is set + nodes = (Node []) path.toArray(target); + } + SceneGraphPath sgpath = new SceneGraphPath(locale, + nodes, + (Node) target.source); + sgpath.setTransform(transform); + return sgpath; + } + } + + + void setTriggered(){ + // if path not set, probably the branch is just detach. + if (collidingPath != null) { + super.setTriggered(); + } + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) { + // The reference geometryAtom will not change once + // Shape3D create so there is no need to set this. + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionExit.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionExit.java new file mode 100644 index 0000000..1577a15 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionExit.java @@ -0,0 +1,396 @@ +/* + * $RCSfile: WakeupOnCollisionExit.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.*; + +/** + * Class specifying a wakeup when the specified object + * no longer collides with any other object in the scene graph. + */ +public final class WakeupOnCollisionExit extends WakeupCriterion { + + // different types of WakeupIndexedList that use in GeometryStructure + static final int COND_IN_GS_LIST = 0; + static final int COLLIDEEXIT_IN_BS_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + /** + * Use geometry in computing collisions. + */ + public static final int USE_GEOMETRY = WakeupOnCollisionEntry.USE_GEOMETRY; + + /** + * Use geometric bounds as an approximation in computing collisions. + */ + public static final int USE_BOUNDS = WakeupOnCollisionEntry.USE_BOUNDS; + + /** + * Accuracy mode one of USE_GEOMETRY or USE_BOUNDS + */ + int accuracyMode; + + // Cached the arming Node being used when it is not BOUND + NodeRetained armingNode; + + // A transformed Bounds of Group/Bounds + // use by BOUND, GROUP + Bounds vwcBounds; + + + // use by GROUP to cache local bounds + Bounds localBounds = null; + + // Use by BoundingLeaf, point to mirror BoundingLeaf + // transformedRegion under this leaf is used. + BoundingLeafRetained boundingLeaf = null; + + /** + * Geometry atoms that this wakeup condition refer to. + * Only use by SHAPE, MORPH, GROUP, ORIENTEDSHAPE + */ + UnorderList geometryAtoms = null; + + // one of GROUP, BOUNDINGLEAF, SHAPE, MORPH, BOUND + int nodeType; + + SceneGraphPath armingPath = null; + Bounds armingBounds = null; + + // the following two references are set only after a collision + // has occurred + SceneGraphPath collidingPath = null; + Bounds collidingBounds = null; + + /** + * Constructs a new WakeupOnCollisionExit criterion. + * @param armingPath the path used to arm collision + * detection + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node. + */ + public WakeupOnCollisionExit(SceneGraphPath armingPath) { + this(armingPath, USE_BOUNDS); + } + + /** + * Constructs a new WakeupOnCollisionExit criterion. + * @param armingPath the path used to arm collision + * detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node. + */ + public WakeupOnCollisionExit(SceneGraphPath armingPath, int speedHint) { + this(new SceneGraphPath(armingPath), speedHint, null); + } + + /** + * Constructs a new WakeupOnCollisionExit criterion. + * @param armingNode the Group, Shape, or Morph node used to + * arm collision detection + * @exception IllegalArgumentException if object is under a + * SharedGroup node or object is other than a Group, Shape3D, + * Morph or BoundingLeaf node. + */ + public WakeupOnCollisionExit(Node armingNode) { + this(armingNode, USE_BOUNDS); + } + + /** + * Constructs a new WakeupOnCollisionExit criterion. + * @param armingNode the Group, Shape, or Morph node used to + * arm collision detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object is under a + * SharedGroup node or object is other than a Group, Shape3D, + * Morph or BoundingLeaf node. + */ + public WakeupOnCollisionExit(Node armingNode, int speedHint) { + this(new SceneGraphPath(null, armingNode), speedHint, null); + } + + + /** + * Constructs a new WakeupOnCollisionExit criterion. + * @param armingBounds the bounds object used to arm collision + * detection + */ + public WakeupOnCollisionExit(Bounds armingBounds) { + this(null, USE_BOUNDS, (Bounds) armingBounds.clone()); + } + + /** + * Constructs a new WakeupOnCollisionExit criterion. + * @param armingPath the path used to arm collision + * detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @param armingBounds the bounds object used to arm collision + * detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node. + */ + WakeupOnCollisionExit(SceneGraphPath armingPath, + int speedHint, Bounds armingBounds) { + if (armingPath != null) { + this.armingNode = (NodeRetained) armingPath.getObject().retained; + nodeType = WakeupOnCollisionEntry.getNodeType(armingNode, armingPath, + "WakeupOnCollisionExit"); + this.armingPath = armingPath; + WakeupOnCollisionEntry.validateSpeedHint(speedHint, + "WakeupOnCollisionExit4"); + } else { + this.armingBounds = armingBounds; + nodeType = WakeupOnCollisionEntry.BOUND; + } + accuracyMode = speedHint; + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Returns the path used in specifying the collision condition. + * @return the SceneGraphPath object generated when arming this + * criterion---null implies that a bounds object armed this criteria + */ + public SceneGraphPath getArmingPath() { + return (armingPath != null ? + new SceneGraphPath(armingPath) : null); + } + + /** + * Returns the bounds object used in specifying the collision condition. + * @return the Bounds object generated when arming this + * criterion---null implies that a SceneGraphPath armed this criteria + */ + public Bounds getArmingBounds() { + return (armingBounds != null ? + (Bounds)armingBounds.clone() : null); + } + + /** + * Retrieves the path describing the object causing the collision. + * @return the SceneGraphPath that describes the triggering object. + * @exception IllegalStateException if not called from within the + * a behavior's processStimulus method which was awoken by a collision. + */ + public SceneGraphPath getTriggeringPath() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnCollisionExit5")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new IllegalStateException + (J3dI18N.getString("WakeupOnCollisionExit5")); + } + } + return (collidingPath != null ? + new SceneGraphPath(collidingPath): null); + } + + /** + * Retrieves the Bounds object that caused the collision + * @return the colliding Bounds object. + * @exception IllegalStateException if not called from within the + * a behavior's processStimulus method which was awoken by a collision. + */ + public Bounds getTriggeringBounds() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnCollisionExit6")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new IllegalStateException + (J3dI18N.getString("WakeupOnCollisionExit6")); + } + } + return (collidingBounds != null ? + (Bounds)(collidingBounds.clone()): null); + } + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + + switch (nodeType) { + case WakeupOnCollisionEntry.SHAPE: // Use geometryAtoms[].collisionBounds + case WakeupOnCollisionEntry.ORIENTEDSHAPE3D: + if (!armingNode.source.isLive()) { + return; + } + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + Shape3DRetained shape = (Shape3DRetained) armingNode; + geometryAtoms.add(Shape3DRetained.getGeomAtom(shape.getMirrorShape(armingPath))); + break; + case WakeupOnCollisionEntry.MORPH: // Use geometryAtoms[].collisionBounds + if (!armingNode.source.isLive()) { + return; + } + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + MorphRetained morph = (MorphRetained) armingNode; + geometryAtoms.add(Shape3DRetained.getGeomAtom(morph.getMirrorShape(armingPath))); + break; + case WakeupOnCollisionEntry.BOUNDINGLEAF: // use BoundingLeaf.transformedRegion + if (!armingNode.source.isLive()) { + return; + } + this.boundingLeaf = ((BoundingLeafRetained) armingNode).mirrorBoundingLeaf; + break; + case WakeupOnCollisionEntry.BOUND: // use this.vwcBounds + vwcBounds = (Bounds) armingBounds.clone(); + this.armingNode = behav; + break; + case WakeupOnCollisionEntry.GROUP: + if (!armingNode.source.isLive()) { + return; + } + if (accuracyMode == USE_GEOMETRY) { + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + ((GroupRetained) armingNode).searchGeometryAtoms(geometryAtoms); + } + // else use this.vwcBounds + default: + } + + behav.universe.geometryStructure.addWakeupOnCollision(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + vwcBounds = null; + if (geometryAtoms != null) { + geometryAtoms.clear(); + } + boundingLeaf = null; + behav.universe.geometryStructure.removeWakeupOnCollision(this); + } + + + + // Set collidingPath & collidingBounds + void setTarget(BHLeafInterface leaf) { + SceneGraphPath path; + Bounds bound; + + if (leaf instanceof GeometryAtom) { + // Find the triggered Path & Bounds for this geometry Atom + GeometryAtom geomAtom = (GeometryAtom) leaf; + Shape3DRetained shape = geomAtom.source; + path = WakeupOnCollisionEntry.getSceneGraphPath( + shape.sourceNode, + shape.key, + shape.getCurrentLocalToVworld(0)); + bound = WakeupOnCollisionEntry.getTriggeringBounds(shape); + + + } else { + // Find the triggered Path & Bounds for this alternative + // collision target + GroupRetained group = (GroupRetained) leaf; + path = WakeupOnCollisionEntry.getSceneGraphPath(group); + bound = WakeupOnCollisionEntry.getTriggeringBounds(group); + } + + if (path != null) { + // colliding path may be null when branch detach before + // user behavior retrieve the previous colliding path + collidingPath = path; + collidingBounds = bound; + } + + } + + // Invoke from GeometryStructure to update vwcBounds of GROUP + void updateCollisionBounds(boolean reEvaluateGAs){ + if (nodeType == WakeupOnCollisionEntry.GROUP) { + GroupRetained group = (GroupRetained) armingNode; + if (group.collisionBound != null) { + vwcBounds = (Bounds) group.collisionBound.clone(); + } else { + // this may involve recursive tree traverse if + // BoundsAutoCompute is true, we can't avoid + // since the bound under it may change by transform + vwcBounds = group.getEffectiveBounds(); + } + group.transformBounds(armingPath, vwcBounds); + } else if (nodeType == WakeupOnCollisionEntry.BOUND) { + vwcBounds.transform(armingBounds, behav.getCurrentLocalToVworld()); + } + + if (reEvaluateGAs && + (nodeType == WakeupOnCollisionEntry.GROUP) && + (accuracyMode == USE_GEOMETRY)) { + geometryAtoms.clear(); + ((GroupRetained) armingNode).searchGeometryAtoms(geometryAtoms); + } + } + + void setTriggered(){ + // if path not set, probably the branch is just detach. + if (collidingPath != null) { + super.setTriggered(); + } + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) { + // The reference geometryAtom will not change once + // Shape3D create so there is no need to set this. + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionMovement.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionMovement.java new file mode 100644 index 0000000..ce89717 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnCollisionMovement.java @@ -0,0 +1,404 @@ +/* + * $RCSfile: WakeupOnCollisionMovement.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.*; + +/** + * Class specifying a wakeup when the specified object + * moves while in collision with any other object in the scene graph. + */ +public final class WakeupOnCollisionMovement extends WakeupCriterion { + + // different types of WakeupIndexedList that use in GeometryStructure + static final int COND_IN_GS_LIST = 0; + static final int COLLIDEMOVE_IN_BS_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + /** + * Use geometry in computing collisions. + */ + public static final int USE_GEOMETRY = WakeupOnCollisionEntry.USE_GEOMETRY; + + /** + * Use geometric bounds as an approximation in computing collisions. + */ + public static final int USE_BOUNDS = WakeupOnCollisionEntry.USE_BOUNDS; + + /** + * Accuracy mode one of USE_GEOMETRY or USE_BOUNDS + */ + int accuracyMode; + + // Cached the arming Node being used when it is not BOUND + NodeRetained armingNode; + + // transformed Bounds of Group/Bounds, use by + // BOUND, BOUNDINGLEAF, GROUP + Bounds vwcBounds; + + + // use by GROUP to cache local bounds + Bounds localBounds = null; + + // source bound when collision occur last time + // These three variables are used to keep track of duplicate + // wakupOnMovement event + Bounds lastSrcBounds = null; + Bounds lastDstBounds = null; + boolean duplicateEvent = false; + + // Use by BoundingLeaf, point to mirror BoundingLeaf + // transformedRegion under this leaf is used. + BoundingLeafRetained boundingLeaf = null; + + /** + * Geometry atoms that this wakeup condition refer to. + * Only use by SHAPE, MORPH, GROUP, ORIENTEDSHAPE + */ + UnorderList geometryAtoms = null; + + // one of GROUP, BOUNDINGLEAF, SHAPE, MORPH, BOUND + int nodeType; + + SceneGraphPath armingPath = null; + Bounds armingBounds = null; + + // the following two references are set only after a collision + // has occurred + SceneGraphPath collidingPath = null; + Bounds collidingBounds = null; + + /** + * Constructs a new WakeupOnCollisionMovement criterion. + * @param armingPath the path used to arm collision + * detection + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node. + */ + public WakeupOnCollisionMovement(SceneGraphPath armingPath) { + this(armingPath, USE_BOUNDS); + } + + /** + * Constructs a new WakeupOnCollisionMovement criterion. + * @param armingPath the path used to arm collision + * detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node. + */ + public WakeupOnCollisionMovement(SceneGraphPath armingPath, + int speedHint) { + this(new SceneGraphPath(armingPath), speedHint, null); + } + + /** + * Constructs a new WakeupOnCollisionMovement criterion. + * @param armingNode the Group, Shape, or Morph node used to + * arm collision detection + * @exception IllegalArgumentException if object is under a + * SharedGroup node or object is other than a Group, Shape3D, + * Morph or BoundingLeaf node. + */ + public WakeupOnCollisionMovement(Node armingNode) { + this(armingNode, USE_BOUNDS); + } + + /** + * Constructs a new WakeupOnCollisionMovement criterion. + * @param armingNode the Group, Shape, or Morph node used to + * arm collision detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object is under a + * SharedGroup node or object is other than a Group, Shape3D, + * Morph or BoundingLeaf node. + */ + public WakeupOnCollisionMovement(Node armingNode, int speedHint) { + this(new SceneGraphPath(null, armingNode), speedHint, null); + } + + + /** + * Constructs a new WakeupOnCollisionMovement criterion. + * @param armingBounds the bounds object used to arm collision + * detection + */ + public WakeupOnCollisionMovement(Bounds armingBounds) { + this(null, USE_BOUNDS, (Bounds)armingBounds.clone()); + } + + /** + * Constructs a new WakeupOnCollisionMovement criterion. + * @param armingPath the path used to arm collision + * detection + * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how + * accurately Java 3D will perform collision detection + * @param armingBounds the bounds object used to arm collision + * detection + * @exception IllegalArgumentException if hint is not one of + * USE_GEOMETRY or USE_BOUNDS. + * @exception IllegalArgumentException if object associated with the + * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node. + */ + WakeupOnCollisionMovement(SceneGraphPath armingPath, + int speedHint, Bounds armingBounds) { + if (armingPath != null) { + this.armingNode = (NodeRetained) armingPath.getObject().retained; + nodeType = WakeupOnCollisionEntry.getNodeType(armingNode, armingPath, + "WakeupOnCollisionMovement"); + this.armingPath = armingPath; + WakeupOnCollisionEntry.validateSpeedHint(speedHint, + "WakeupOnCollisionMovement4"); + } else { + this.armingBounds = armingBounds; + nodeType = WakeupOnCollisionEntry.BOUND; + } + accuracyMode = speedHint; + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Returns the path used in specifying the collision condition. + * @return the SceneGraphPath object generated when arming this + * criterion---null implies that a bounds object armed this criteria + */ + public SceneGraphPath getArmingPath() { + return (armingPath != null ? + new SceneGraphPath(armingPath) : null); + } + + /** + * Returns the bounds object used in specifying the collision condition. + * @return the Bounds object generated when arming this + * criterion---null implies that a SceneGraphPath armed this criteria + */ + public Bounds getArmingBounds() { + return (armingBounds != null ? + (Bounds)armingBounds.clone() : null); + } + + /** + * Retrieves the path describing the object causing the collision. + * @return the SceneGraphPath that describes the triggering object. + * @exception IllegalStateException if not called from within the + * a behavior's processStimulus method which was awoken by a collision. + */ + public SceneGraphPath getTriggeringPath() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnCollisionMovement5")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new IllegalStateException + (J3dI18N.getString("WakeupOnCollisionMovement5")); + } + } + return (collidingPath != null ? + new SceneGraphPath(collidingPath): null); + } + + /** + * Retrieves the Bounds object that caused the collision + * @return the colliding Bounds object. + * @exception IllegalStateException if not called from within the + * a behavior's processStimulus method which was awoken by a collision. + */ + public Bounds getTriggeringBounds() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnCollisionMovement6")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new IllegalStateException + (J3dI18N.getString("WakeupOnCollisionMovement6")); + } + } + return (collidingBounds != null ? + (Bounds)(collidingBounds.clone()): null); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + + switch (nodeType) { + case WakeupOnCollisionEntry.SHAPE: // Use geometryAtoms[].collisionBounds + case WakeupOnCollisionEntry.ORIENTEDSHAPE3D: + if (!armingNode.source.isLive()) { + return; + } + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + Shape3DRetained shape = (Shape3DRetained) armingNode; + geometryAtoms.add(Shape3DRetained.getGeomAtom(shape.getMirrorShape(armingPath))); + break; + case WakeupOnCollisionEntry.MORPH: // Use geometryAtoms[].collisionBounds + if (!armingNode.source.isLive()) { + return; + } + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + MorphRetained morph = (MorphRetained) armingNode; + geometryAtoms.add(Shape3DRetained.getGeomAtom(morph.getMirrorShape(armingPath))); + break; + case WakeupOnCollisionEntry.BOUNDINGLEAF: // use BoundingLeaf.transformedRegion + if (!armingNode.source.isLive()) { + return; + } + this.boundingLeaf = ((BoundingLeafRetained) armingNode).mirrorBoundingLeaf; + break; + case WakeupOnCollisionEntry.BOUND: // use this.vwcBounds + vwcBounds = (Bounds) armingBounds.clone(); + this.armingNode = behav; + break; + case WakeupOnCollisionEntry.GROUP: + if (!armingNode.source.isLive()) { + return; + } + if (accuracyMode == USE_GEOMETRY) { + if (geometryAtoms == null) { + geometryAtoms = new UnorderList(1, GeometryAtom.class); + } + ((GroupRetained) armingNode).searchGeometryAtoms(geometryAtoms); + } + // else use this.vwcBounds + default: + } + + behav.universe.geometryStructure.addWakeupOnCollision(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + vwcBounds = null; + if (geometryAtoms != null) { + geometryAtoms.clear(); + } + boundingLeaf = null; + behav.universe.geometryStructure.removeWakeupOnCollision(this); + } + + + // Set collidingPath & collidingBounds + void setTarget(BHLeafInterface leaf) { + SceneGraphPath path; + Bounds bound; + + if (leaf instanceof GeometryAtom) { + // Find the triggered Path & Bounds for this geometry Atom + GeometryAtom geomAtom = (GeometryAtom) leaf; + Shape3DRetained shape = geomAtom.source; + path = WakeupOnCollisionEntry.getSceneGraphPath( + shape.sourceNode, + shape.key, + shape.getCurrentLocalToVworld(0)); + bound = WakeupOnCollisionEntry.getTriggeringBounds(shape); + + } else { + // Find the triggered Path & Bounds for this alternative + // collision target + GroupRetained group = (GroupRetained) leaf; + path = WakeupOnCollisionEntry.getSceneGraphPath(group); + bound = WakeupOnCollisionEntry.getTriggeringBounds(group); + } + + if (path != null) { + // colliding path may be null when branch detach before + // user behavior retrieve the previous colliding path + collidingPath = path; + collidingBounds = bound; + } + } + + // Invoke from GeometryStructure to update vwcBounds of GROUP + void updateCollisionBounds(boolean reEvaluateGAs) { + if (nodeType == WakeupOnCollisionEntry.GROUP) { + GroupRetained group = (GroupRetained) armingNode; + if (group.collisionBound != null) { + vwcBounds = (Bounds) group.collisionBound.clone(); + } else { + // this may involve recursive tree traverse if + // BoundsAutoCompute is true, we can't avoid + // since the bound under it may change by transform + vwcBounds = group.getEffectiveBounds(); + } + group.transformBounds(armingPath, vwcBounds); + } else if (nodeType == WakeupOnCollisionEntry.BOUND) { + vwcBounds.transform(armingBounds, behav.getCurrentLocalToVworld()); + } + + + if (reEvaluateGAs && + (nodeType == WakeupOnCollisionEntry.GROUP) && + (accuracyMode == USE_GEOMETRY)) { + geometryAtoms.clear(); + ((GroupRetained) armingNode).searchGeometryAtoms(geometryAtoms); + } + } + + void setTriggered(){ + // if path not set, probably the branch is just detach. + if (collidingPath != null) { + super.setTriggered(); + } + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) { + // The reference geometryAtom will not change once + // Shape3D create so there is no need to set this. + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnDeactivation.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnDeactivation.java new file mode 100644 index 0000000..5f7ee71 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnDeactivation.java @@ -0,0 +1,97 @@ +/* + * $RCSfile: WakeupOnDeactivation.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class specifying a wakeup on first detection of a Viewplatform's + * activation volume no longer intersecting with this object's scheduling + * region. This gives the behavior an explicit means of executing code + * when it is deactivated. + */ +public final class WakeupOnDeactivation extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 1; + + /** + * Constructs a new WakeupOnDeactivation criterion. + */ + public WakeupOnDeactivation() { + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + + /** + * Set the Criterion's trigger flag to true. + * No need to check for scheduling region in this case + */ + void setTriggered(){ + this.triggered = true; + if (this.parent == null) { + super.setConditionMet(id, Boolean.FALSE); + } else { + parent.setConditionMet(id, Boolean.FALSE); + } + } + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + behav.wakeupArray[BehaviorRetained.WAKEUP_DEACTIVATE_INDEX]++; + behav.wakeupMask |= BehaviorRetained.WAKEUP_DEACTIVATE; + bs.wakeupOnDeactivation.add(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + behav.wakeupArray[BehaviorRetained.WAKEUP_DEACTIVATE_INDEX]--; + if (behav.wakeupArray[BehaviorRetained.WAKEUP_DEACTIVATE_INDEX] == 0) { + behav.wakeupMask &= ~BehaviorRetained.WAKEUP_DEACTIVATE; + } + bs.wakeupOnDeactivation.remove(this); + } + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) {} +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedFrames.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedFrames.java new file mode 100644 index 0000000..23b7b01 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedFrames.java @@ -0,0 +1,183 @@ +/* + * $RCSfile: WakeupOnElapsedFrames.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class specifying a wakeup when a specific number of frames have + * elapsed. The wakeup criterion can either be passive or + * non-passive. If any behavior uses a non-passive + * WakeupOnElapsedFrames, the rendering system will run continuously. + * + *

+ * In general, applications cannot count on behavior execution being + * synchronized with rendering. Behaviors that use + * WakeupOnElapsedFrames with a frame count of 0 are an exception to + * this general rule. Such behaviors will be executed every frame. + * Further, all modifications to scene graph objects (not including + * geometry by-reference or texture by-reference) made from the + * processStimulus methods of such behaviors are + * guaranteed to take effect in the same rendering frame. + */ +public final class WakeupOnElapsedFrames extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 1; + + // Indicates whether the wakeup condition is passive or + // non-passive. Only behaviors using a non-passive + // WakeupOnElapsedFrames will force a continuous traversal. + boolean passive; + + // Number of frames before wakeup + int frameCount; + + // When this reaches 0, this criterion is met. + int countdown; + + /** + * Constructs a non-passive WakeupOnElapsedFrames criterion. + * + * @param frameCount the number of frames that Java 3D should draw + * before awakening this behavior object; a value of N means + * wakeup at the end of frame N, where the current frame is zero, + * a value of zero means wakeup at the end of the current frame. + * + * @exception IllegalArgumentException if frameCount is less than zero + */ + public WakeupOnElapsedFrames(int frameCount) { + this(frameCount, false); + } + + /** + * Constructs a WakeupOnElapsedFrames criterion. + * + * @param frameCount the number of frames that Java 3D should draw + * before awakening this behavior object; a value of N means + * wakeup at the end of frame N, where the current frame is zero, + * a value of zero means wakeup at the end of the current frame. + * + * @param passive flag indicating whether this behavior is + * passive; a non-passive behavior will cause the rendering system + * to run continuously, while a passive behavior will only run + * when some other event causes a frame to be run. + * + * @exception IllegalArgumentException if frameCount is less than zero + * + * @since Java 3D 1.2 + */ + public WakeupOnElapsedFrames(int frameCount, boolean passive) { + if (frameCount < 0) + throw new IllegalArgumentException(J3dI18N.getString("WakeupOnElapsedFrames0")); + + this.frameCount = frameCount; + this.passive = passive; + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Retrieves the elapsed frame count that was used when + * constructing this object. + * + * @return the elapsed frame count specified when constructing + * this object + */ + public int getElapsedFrameCount() { + return frameCount; + } + + /** + * Retrieves the state of the passive flag that was used when + * constructing this object. + * + * @return true if this wakeup criterion is passive, false otherwise + * + * @since Java 3D 1.2 + */ + public boolean isPassive() { + return passive; + } + + /** + * decrement the frame count, and set trigger if 0 + */ + void newFrame() { + if (this.countdown == 0) { + this.setTriggered(); + } else { + this.countdown--; + } + } + + + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + this.countdown = this.frameCount; + bs.wakeupOnElapsedFrames.add(this); + if (!passive && (behav != null) && behav.enable) { + bs.activeWakeupOnFrameCount++; + } + + // This is necessary to invoke this condition next time + // Otherwise jftc won't work for static scene. + VirtualUniverse.mc.sendRunMessage(bs.universe, + J3dThread.UPDATE_BEHAVIOR); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + bs.wakeupOnElapsedFrames.remove(this); + if (!passive && (behav != null) && behav.enable) { + bs.activeWakeupOnFrameCount--; + } + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) { + this.countdown = this.frameCount; + } + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedTime.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedTime.java new file mode 100644 index 0000000..6f0bd5b --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedTime.java @@ -0,0 +1,113 @@ +/* + * $RCSfile: WakeupOnElapsedTime.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class specifying a wakeup when a specific number of milliseconds + * have elapsed. + * + */ +public final class WakeupOnElapsedTime extends WakeupCriterion { + + long wait; + + /** + * This represents the triggered time + */ + long triggeredTime; + + /** + * Constructs a new WakeupOnElapsedTime criterion. + * @param milliseconds the number of milliseconds to the wakeup. A value + * of zero or less will cause an IllegalArgumentException to be thrown. + */ + public WakeupOnElapsedTime(long milliseconds) { + if(milliseconds <= 0L) + throw new IllegalArgumentException(J3dI18N.getString("WakeupOnElapsedTime0")); + this.wait = milliseconds; + } + + /** + * Retrieve the WakeupCriterion's elapsed time value that was used when + * constructing this object. + * @return the elapsed time specified when constructing this object + */ + public long getElapsedFrameTime(){ + return wait; + } + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + this.triggeredTime = wait + J3dClock.currentTimeMillis(); + behav.wakeupArray[BehaviorRetained.WAKEUP_TIME_INDEX]++; + behav.wakeupMask |= BehaviorRetained.WAKEUP_TIME; + VirtualUniverse.mc.timerThread.add(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + behav.wakeupArray[BehaviorRetained.WAKEUP_TIME_INDEX]--; + if (behav.wakeupArray[BehaviorRetained.WAKEUP_TIME_INDEX] == 0) { + behav.wakeupMask &= ~BehaviorRetained.WAKEUP_TIME; + } + VirtualUniverse.mc.timerThread.remove(this); + } + + /** + * This is invoked when Behavior processStimulus can't schedule + * to run because behav.active = false. In this case we must + * reinsert the wakeupOnElapseTime condition back to the + * TimerThread wakeup heap + */ + void reInsertElapseTimeCond() { + super.reInsertElapseTimeCond(); + this.triggeredTime = wait + J3dClock.currentTimeMillis(); + VirtualUniverse.mc.timerThread.add(this); + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) { + this.triggeredTime = wait + J3dClock.currentTimeMillis(); + VirtualUniverse.mc.timerThread.add(this); + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedTimeHeap.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedTimeHeap.java new file mode 100644 index 0000000..67b14a3 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnElapsedTimeHeap.java @@ -0,0 +1,229 @@ +/* + * $RCSfile: WakeupOnElapsedTimeHeap.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * A Binary heap to store WakeupOnElapsedTime. It is arranged so that the + * smallest triggeredTime of the wakeup object is put at the top of the heap. + * Add/deletion takes O(log n) time. + * For better performance we can consider to use Fibonacci Heaps. + * + */ +class WakeupOnElapsedTimeHeap implements Cloneable { + + // entry 0 is not used so index can be calculated more efficiently + WakeupOnElapsedTime data[]; + int size = 0; + + /** + * Construct heap with user-defined capacity + */ + WakeupOnElapsedTimeHeap(int initCapacity) { + data = new WakeupOnElapsedTime[initCapacity+1]; + } + + /** + * Construct heap of default capacity 10 + */ + WakeupOnElapsedTimeHeap() { + this(10); + } + + /** + * Return size of heap + */ + final int size() { + return size; + } + + /** + * Return true if heap is empty + */ + final boolean isEmpty() { + return (size == 0); + } + + /** + * Get the minimum element from the heap. + * User has to make sure that size > 0 before it is called. + */ + final WakeupOnElapsedTime getMin() { + return data[1]; + } + + + /** + * Insert the key into the heap + */ + final void insert(WakeupOnElapsedTime key) { + if (data.length == size + 1) { + WakeupOnElapsedTime oldData[] = data; + data = new WakeupOnElapsedTime[oldData.length << 1]; + System.arraycopy(oldData, 0, data, 0, oldData.length); + } + + int i = ++size; + + int parentIdx = i >> 1; + WakeupOnElapsedTime parentKey = data[parentIdx]; + long time = key.triggeredTime; + + while ((i > 1) && (parentKey.triggeredTime > time)) { + data[i] = parentKey; + i = parentIdx; + parentIdx >>= 1; + parentKey = data[parentIdx]; + } + data[i] = key; + } + + /** + * Extract wakeup condition belongs to behav from the heap. + * Return true if wakeup is found. + */ + final void extract(BehaviorRetained behav) { + for (int i=1; i <= size; i++) { + if (data[i].behav == behav) { + extract(i); + } + } + } + + /** + * Extract wakeup from the heap. + * Return true if wakeup is found. + */ + final boolean extract(WakeupOnElapsedTime wakeup) { + for (int i=1; i <= size; i++) { + if (data[i] == wakeup) { + extract(i); + return true; + } + } + return false; + } + + /** + * Extract the minimum value from the heap. + * User has to make sure that size > 0 before it is called. + */ + final WakeupOnElapsedTime extractMin() { + return extract(1); + } + + /** + * Extract the ith value from the heap. + * User has to make sure that i <= size before it is called. + */ + final WakeupOnElapsedTime extract(int i) { + WakeupOnElapsedTime min = data[i]; + WakeupOnElapsedTime temp; + int l, r; + int smallest; + data[i] = data[size]; + data[size] = null; // for gc + size--; + + + do { + l = i << 1; + r = l+1; + + if ((l <= size) && + (data[l].triggeredTime < data[i].triggeredTime)) { + smallest = l; + } else { + smallest = i; + } + if ((r <= size) && + (data[r].triggeredTime < data[smallest].triggeredTime)) { + smallest = r; + } + if (smallest == i) { + break; + } + temp = data[smallest]; + data[smallest] = data[i]; + data[i] = temp; + i = smallest; + } while (true); + + return min; + } + + + /*** + * Trims the capacity of this instance to be the + * list's current size. + */ + final void trimToSize() { + if (data.length > size+1) { + WakeupOnElapsedTime oldData[] = data; + data = new WakeupOnElapsedTime[size+1]; + System.arraycopy(oldData, 0, data, 0, data.length); + } + } + + /** + * Clone this heap + */ + protected final Object clone() { + try { + WakeupOnElapsedTimeHeap heap = (WakeupOnElapsedTimeHeap)super.clone(); + heap.data = new WakeupOnElapsedTime[size+1]; + System.arraycopy(data, 0, heap.data, 0, size+1); + return heap; + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + + } + + + public String toString() { + StringBuffer sb = new StringBuffer("[ "); + + if (size > 0) { + sb.append(data[1]); + } + + for (int i=2; i <= size; i++) { + sb.append("," + data[i]); + } + sb.append(" ]"); + return sb.toString(); + } + + + +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnSensorEntry.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnSensorEntry.java new file mode 100644 index 0000000..fa280f7 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnSensorEntry.java @@ -0,0 +1,148 @@ +/* + * $RCSfile: WakeupOnSensorEntry.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class specifying a wakeup on first sensor intersection with the + * specified boundary. + */ +public final class WakeupOnSensorEntry extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + static final int SENSORENTRY_IN_BS_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + Bounds region; + + // Transformed region used by BehaviorStructure + Bounds transformedRegion; + + Sensor armingSensor; + + /** + * Constructs a new WakeupOnEntry criterion. + * @param region the region that will trigger a wakeup if a Sensor + * intersects. + */ + public WakeupOnSensorEntry(Bounds region) { + this.region = (Bounds)region.clone(); + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Returns this object's bounds specification + * @return the bounds used in constructing this WakeupCriterion. + */ + public Bounds getBounds() { + return (Bounds) region.clone(); + } + + /** + * Update the cached Transfrom Region, call from BehaviorStructure + */ + void updateTransformRegion() { + if (transformedRegion != null) { + transformedRegion.set(region); + } else { + // region is read only once initialize (since there is no + // set method for region). So no need to use cloneWithLock() + transformedRegion = (Bounds) region.clone(); + } + transformedRegion.transform(behav.getCurrentLocalToVworld(null)); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + bs.addSensorEntryCondition(this); + if ((behav != null) && behav.enable) { + bs.activeWakeupOnSensorCount++; + } + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + bs.removeSensorEntryCondition(this); + if ((behav != null) && behav.enable) { + bs.activeWakeupOnSensorCount--; + } + } + + /** + * Set the sensor that trigger this behavior + */ + void setTarget(Sensor sensor) { + this.armingSensor = sensor; + } + + /** + * Retrieves the Sensor object that caused the wakeup. + * + * @return the triggering Sensor object + * + * @exception IllegalStateException if not called from within + * a behavior's processStimulus method which was awoken by a sensor + * entry. + * + * @since Java 3D 1.2 + */ + public Sensor getTriggeringSensor() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnSensorEntry0")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new + IllegalStateException(J3dI18N.getString("WakeupOnSensorEntry0")); + } + } + return armingSensor; + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) {} +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnSensorExit.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnSensorExit.java new file mode 100644 index 0000000..349734c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnSensorExit.java @@ -0,0 +1,147 @@ +/* + * $RCSfile: WakeupOnSensorExit.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class specifying a wakeup on first detection of sensors no + * longer intersecting the specified boundary. + */ +public final class WakeupOnSensorExit extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + static final int SENSOREXIT_IN_BS_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + Bounds region; + // Transformed region used by BehaviorStructure + Bounds transformedRegion; + + Sensor armingSensor; + + /** + * Constructs a new WakeupOnExit criterion. + * @param region the region that will trigger a wakeup if a Sensor + * intersects. + */ + public WakeupOnSensorExit(Bounds region) { + this.region = (Bounds)region.clone(); + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Returns this object's bounds specification + * @return the bounds used in constructing this WakeupCriterion. + */ + public Bounds getBounds() { + return (Bounds)region.clone(); + } + + /** + * Update the cached Transfrom Region, call from BehaviorStructure + */ + void updateTransformRegion() { + if (transformedRegion != null) { + transformedRegion.set(region); + } else { + // region is read only once initialize (since there is no + // set method for region). So no need to use cloneWithLock() + transformedRegion = (Bounds) region.clone(); + } + transformedRegion.transform(behav.getCurrentLocalToVworld(null)); + } + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + bs.addSensorExitCondition(this); + if ((behav != null) && behav.enable) { + bs.activeWakeupOnSensorCount++; + } + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + bs.removeSensorExitCondition(this); + if ((behav != null) && behav.enable) { + bs.activeWakeupOnSensorCount--; + } + } + + + /** + * Set the sensor that trigger this behavior + */ + void setTarget(Sensor sensor) { + this.armingSensor = sensor; + } + + /** + * Retrieves the Sensor object that caused the wakeup. + * + * @return the triggering Sensor object + * + * @exception IllegalStateException if not called from within + * a behavior's processStimulus method which was awoken by a sensor + * exit. + * + * @since Java 3D 1.2 + */ + public Sensor getTriggeringSensor() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnSensorExit0")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new + IllegalStateException(J3dI18N.getString("WakeupOnSensorExit0")); + } + } + return armingSensor; + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) {} +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnTransformChange.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnTransformChange.java new file mode 100644 index 0000000..04427c9 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnTransformChange.java @@ -0,0 +1,99 @@ +/* + * $RCSfile: WakeupOnTransformChange.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; +import java.util.ArrayList; + +/** + * Class specifying a wakeup when the transform within a specified + * TransformGroup changes + */ +public final class WakeupOnTransformChange extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 1; + + TransformGroupRetained transform; + + /** + * Constructs a new WakeupOnTransformChange criterion. + * + * @param node the TransformGroup node that will trigger a wakeup if + * its transform is modified + */ + public WakeupOnTransformChange(TransformGroup node) { + this.transform = (TransformGroupRetained)node.retained; + synchronized (transform) { + if (transform.transformChange == null) { + transform.transformChange = new WakeupIndexedList(1, + WakeupOnTransformChange.class, + WakeupOnTransformChange.COND_IN_BS_LIST, + transform.universe); + } + } + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Returns the TransformGroup node used in creating this WakeupCriterion + * @return the TransformGroup used in this criterion's construction + */ + public TransformGroup getTransformGroup(){ + return (TransformGroup)this.transform.source; + } + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + transform.addCondition(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + transform.removeCondition(this); + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) {} +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnViewPlatformEntry.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnViewPlatformEntry.java new file mode 100644 index 0000000..45efafb --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnViewPlatformEntry.java @@ -0,0 +1,152 @@ +/* + * $RCSfile: WakeupOnViewPlatformEntry.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class specifying a wakeup when an active ViewPlatform intersects the + * specified boundary. + */ +public final class WakeupOnViewPlatformEntry extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + static final int BOUNDSENTRY_IN_BS_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + Bounds region; + + /** + * Transformed region + */ + Bounds transformedRegion; + + /** + * ViewPlatform that triggered this wakeup condition. + */ + ViewPlatformRetained triggeredVP; + + /** + * Constructs a new WakeupOnEntry criterion. + * @param region the region that will trigger a wakeup if a ViewPlatform + * intersects. + */ + public WakeupOnViewPlatformEntry(Bounds region) { + this.region = (Bounds)region.clone(); + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + /** + * Returns this object's bounds specification + * @return the bounds used in constructing this WakeupCriterion. + */ + public Bounds getBounds() { + return (Bounds)region.clone(); + } + + /** + * Retrieves the ViewPlatform node that caused the wakeup. + * + * @return the triggering ViewPlatform node + * + * @exception IllegalStateException if not called from within + * a behavior's processStimulus method that was awoken by a + * view platform entry. + * + * @since Java 3D 1.3 + */ + public ViewPlatform getTriggeringViewPlatform() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnViewPlatformEntry0")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnViewPlatformEntry0")); + } + } + + return (triggeredVP != null) ? (ViewPlatform)triggeredVP.source : null; + } + + /** + * Update the cached Transfrom Region, call from BehaviorStructure + * when TRANSFORM_CHANGED message get. Also call from buildTree. + */ + void updateTransformRegion(BehaviorRetained b) { + if (transformedRegion != null) { + transformedRegion.set(region); + } else { + // region is read only once initialize (since there is no + // set method for region). So no need to use cloneWithLock() + transformedRegion = (Bounds) region.clone(); + } + transformedRegion.transform(b.getCurrentLocalToVworld(null)); + } + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + updateTransformRegion(behav); + behav.wakeupArray[BehaviorRetained.WAKEUP_VP_ENTRY_INDEX]++; + behav.wakeupMask |= BehaviorRetained.WAKEUP_VP_ENTRY; + bs.addVPEntryCondition(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + behav.wakeupArray[BehaviorRetained.WAKEUP_VP_ENTRY_INDEX]--; + if (behav.wakeupArray[BehaviorRetained.WAKEUP_VP_ENTRY_INDEX] == 0) { + behav.wakeupMask &= ~BehaviorRetained.WAKEUP_VP_ENTRY; + } + bs.removeVPEntryCondition(this); + } + + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) { + // updateTransformRegion() is invoked in BehaviorStructure + // whenever Behavior transform change so there is + // no need to transform here every time. + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOnViewPlatformExit.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnViewPlatformExit.java new file mode 100644 index 0000000..995af0c --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOnViewPlatformExit.java @@ -0,0 +1,154 @@ +/* + * $RCSfile: WakeupOnViewPlatformExit.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +/** + * Class specifying a wakeup when an active ViewPlatform no longer + * intersects the specified boundary. + */ +public final class WakeupOnViewPlatformExit extends WakeupCriterion { + + // different types of WakeupIndexedList that use in BehaviorStructure + static final int COND_IN_BS_LIST = 0; + static final int BOUNDSEXIT_IN_BS_LIST = 1; + + // total number of different IndexedUnorderedSet types + static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; + + Bounds region; + + + /** + * Transformed region + */ + Bounds transformedRegion; + + /** + * ViewPlatform that triggered this wakeup condition. + */ + ViewPlatformRetained triggeredVP; + + /** + * Constructs a new WakeupOnExit criterion. + * @param region the region that will trigger a wakeup if a ViewPlatform + * no longer intersects. + */ + public WakeupOnViewPlatformExit(Bounds region) { + this.region = (Bounds)region.clone(); + WakeupIndexedList.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); + } + + + /** + * Returns this object's bounds specification + * @return the bounds used in constructing this WakeupCriterion. + */ + public Bounds getBounds() { + return (Bounds)region.clone(); + } + + /** + * Retrieves the ViewPlatform node that caused the wakeup. + * + * @return the triggering ViewPlatform node + * + * @exception IllegalStateException if not called from within + * a behavior's processStimulus method that was awoken by a + * view platform exit. + * + * @since Java 3D 1.3 + */ + public ViewPlatform getTriggeringViewPlatform() { + if (behav == null) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnViewPlatformExit0")); + } + + synchronized (behav) { + if (!behav.inCallback) { + throw new IllegalStateException(J3dI18N.getString("WakeupOnViewPlatformExit0")); + } + } + + return (triggeredVP != null) ? (ViewPlatform)triggeredVP.source : null; + } + + /** + * Update the cached Transfrom Region, call from BehaviorStructure + * when TRANSFORM_CHANGED message get. Also call from buildTree. + */ + void updateTransformRegion(BehaviorRetained b) { + if (transformedRegion != null) { + transformedRegion.set(region); + } else { + // region is read only once initialize (since there is no + // set method for region). So no need to use cloneWithLock() + transformedRegion = (Bounds) region.clone(); + } + transformedRegion.transform(b.getCurrentLocalToVworld(null)); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to add wakeupCondition to behavior structure. + */ + void addBehaviorCondition(BehaviorStructure bs) { + updateTransformRegion(behav); + behav.wakeupArray[BehaviorRetained.WAKEUP_VP_EXIT_INDEX]++; + behav.wakeupMask |= BehaviorRetained.WAKEUP_VP_EXIT; + bs.addVPExitCondition(this); + } + + + /** + * This is a callback from BehaviorStructure. It is + * used to remove wakeupCondition from behavior structure. + */ + void removeBehaviorCondition(BehaviorStructure bs) { + bs.removeVPExitCondition(this); + behav.wakeupArray[BehaviorRetained.WAKEUP_VP_EXIT_INDEX]--; + if (behav.wakeupArray[BehaviorRetained.WAKEUP_VP_EXIT_INDEX] == 0) { + behav.wakeupMask &= ~BehaviorRetained.WAKEUP_VP_EXIT; + } + } + + + /** + * Perform task in addBehaviorCondition() that has to be + * set every time the condition met. + */ + void resetBehaviorCondition(BehaviorStructure bs) { + // updateTransformRegion() is invoked in BehaviorStructure + // whenever Behavior transform change so there is + // no need to transform here every time. + } +} diff --git a/j3d-core/src/classes/share/javax/media/j3d/WakeupOr.java b/j3d-core/src/classes/share/javax/media/j3d/WakeupOr.java new file mode 100644 index 0000000..2e467c2 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/WakeupOr.java @@ -0,0 +1,119 @@ +/* + * $RCSfile: WakeupOr.java,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:33 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.util.Vector; + +/** + * Class specifying any number of wakeup conditions ORed together. + * This WakeupCondition object specifies that Java 3D should awaken + * this Behavior when any of the WakeupCondition's constituent wakeup + * criteria becomes valid. + *

+ * Note that a unique WakeupCriterion object must be used + * for each individual element in the array of wakeup criteria. + */ + +public final class WakeupOr extends WakeupCondition { + + WakeupCriterion conditions[]; + + /** + * Constructs a new WakeupOr criterion. + * @param conditions a vector of individual Wakeup conditions + */ + public WakeupOr(WakeupCriterion conditions[]) { + this.conditions = new WakeupCriterion[conditions.length]; + + for(int i = 0; i < conditions.length; i++){ + this.conditions[i] = conditions[i]; + } + } + + /** + * This sets the bit for the given child, then checks if the full condition is met + */ + void setConditionMet(int id, Boolean checkSchedulingRegion) { + if (parent == null) { + super.setConditionMet(this.id, checkSchedulingRegion); + } else { + parent.setConditionMet(this.id, checkSchedulingRegion); + } + } + + + /** + * This gets called when this condition is added to the AndOr tree. + */ + void buildTree(WakeupCondition parent, int id, BehaviorRetained b) { + super.buildTree(parent, id, b); + + for(int i = 0; i < conditions.length; i++) { + if (conditions[i] != null) { + conditions[i].buildTree(this, i, b); + } + } + } + + /** + * This goes through the AndOr tree to remove the various criterion from the + * BehaviorStructure lists + */ + void cleanTree(BehaviorStructure bs) { + for (int i=0; i + * Note that a unique WakeupCriterion object must be used for each + * individual element in the set of arrays specified by the array of + * WakeupAnd objects. + */ + +public final class WakeupOrOfAnds extends WakeupCondition { + + WakeupAnd conditions[]; + + /** + * Constructs a new WakeupOrOfAnds criterion. + * @param conditions a vector of individual Wakeup conditions + */ + public WakeupOrOfAnds(WakeupAnd conditions[]) { + this.conditions = new WakeupAnd[conditions.length]; + for(int i = 0; i < conditions.length; i++){ + this.conditions[i] = conditions[i]; + } + } + + + /** + * This sets the bit for the given child, then checks if the full condition is met + */ + void setConditionMet(int id, Boolean checkSchedulingRegion) { + if (parent == null) { + super.setConditionMet(this.id, checkSchedulingRegion); + } else { + parent.setConditionMet(this.id, checkSchedulingRegion); + } + } + + /** + * This gets called when this condition is added to the AndOr tree. + */ + void buildTree(WakeupCondition parent, int id, BehaviorRetained b) { + super.buildTree(parent, id, b); + + for(int i = 0; i < conditions.length; i++) { + if (conditions[i] != null) { + conditions[i].buildTree(this, i, b); + } + } + } + + /** + * This goes through the AndOr tree to remove the various criterion from the + * BehaviorStructure lists + */ + void cleanTree(BehaviorStructure bs) { + for (int i=0; i + + + + Java 3D API - Behaviors and Interpolators + + +

Behaviors and Interpolators

+

Behavior nodes provide the means for +animating objects, processing keyboard and mouse inputs, reacting to +movement, and enabling and processing pick events. Behavior nodes +contain Java code and state variables. A Behavior node's Java code can +interact with Java objects, change node values within a Java 3D +scene +graph, change the behavior's internal state-in general, perform any +computation it wishes. +

+

Simple behaviors can add surprisingly interesting effects to a scene +graph. For example, one can animate a rigid object by using a Behavior +node to repetitively modify the TransformGroup node that points to the +object one wishes to animate. Alternatively, a Behavior node can track +the current position of a mouse and modify portions of the scene graph +in response.

+

Behavior Object

+

A Behavior leaf node object contains a scheduling region and two +methods: an initialize method called once when the +behavior becomes "live" and a processStimulus +method called whenever appropriate by the Java 3D behavior +scheduler. +The Behavior object also contains the state information needed by its initialize +and processStimulus methods. +

+

The scheduling region defines a spatial volume that serves +to enable the scheduling of Behavior nodes. A Behavior node is active +(can receive stimuli) whenever an active ViewPlatform's activation +volume intersects a Behavior object's scheduling region. Only active +behaviors can receive stimuli. +

+

The scheduling interval defines a +partial order of execution for behaviors that wake up in response to +the same wakeup condition (that is, those behaviors that are processed +at the same "time"). Given a set of behaviors whose wakeup conditions +are satisfied at the same time, the behavior scheduler will execute all +behaviors in a lower scheduling interval before executing any behavior +in a higher scheduling interval. Within a scheduling interval, +behaviors can be executed in any order, or in parallel. Note that this +partial ordering is only guaranteed for those behaviors that wake up at +the same time in response to the same wakeup condition, for example, +the set of behaviors that wake up every frame in response to a +WakeupOnElapsedFrames(0) wakeup condition. +

+

The processStimulus method receives and processes a +behavior's ongoing messages. The Java 3D behavior scheduler +invokes a +Behavior node's processStimulus +method when an active ViewPlatform's activation volume intersects a +Behavior object's scheduling region and all of that behavior's wakeup +criteria are satisfied. The processStimulus method +performs its computations and actions (possibly including the +registration of state change information that could cause Java 3D +to +wake other Behavior objects), establishes its next wakeup condition, +and finally exits. +

+

A typical behavior will modify one or more nodes or node components +in +the scene graph. These modifications can happen in parallel with +rendering. In general, applications cannot count on behavior execution +being synchronized with rendering. There are two exceptions to this +general rule: +

+
    +
  • All modifications to scene graph objects (not including geometry +by-reference or texture by-reference) made from the processStimulus +method of a single behavior instance are guaranteed to take effect in +the same rendering frame
  • +
+
    +
  • All modifications to scene graph objects (not including geometry +by-reference or texture by-reference) made from the processStimulus +methods of the set of behaviors that wake up in response to a +WakeupOnElapsedFrames(0) wakeup condition are guaranteed to take effect +in the same rendering frame.
  • +
+

Note that modifications to geometry by-reference or texture +by-reference are not guaranteed to show up in the same frame as other +scene graph changes. +

+

Code Structure

+

When the Java 3D behavior scheduler invokes a Behavior object's +processStimulus +method, that method may perform any computation it wishes. Usually, it +will change its internal state and specify its new wakeup conditions. +Most probably, it will manipulate scene graph elements. However, the +behavior code can change only those aspects of a scene graph element +permitted by the capabilities associated with that scene graph element. +A scene graph's capabilities restrict behavioral manipulation to those +manipulations explicitly allowed. +

+

The application must provide the Behavior object with references to +those scene graph elements that the Behavior object will manipulate. +The application provides those references as arguments to the +behavior's constructor when it creates the Behavior object. +Alternatively, the Behavior object itself can obtain access to the +relevant scene graph elements either when Java 3D invokes its initialize +method or each time Java 3D invokes its processStimulus +method. +

+

Behavior methods have a very rigid structure. Java 3D assumes +that +they +always run to completion (if needed, they can spawn threads). Each +method's basic structure consists of the following: +

+
    +
  • Code to decode and extract references from the WakeupCondition +enumeration that caused the object's awakening.
  • +
+
    +
  • Code to perform the manipulations associated with the +WakeupCondition.
  • +
+
    +
  • Code to establish this behavior's new WakeupCondition.
  • +
+
    +
  • A path to Exit (so that execution returns to the Java 3D +behavior +scheduler).
  • +
+

WakeupCondition Object

+

A WakeupCondition object is +an +abstract class specialized to fourteen +different WakeupCriterion objects and to four combining objects +containing multiple WakeupCriterion objects. +

+

A Behavior node provides the Java 3D behavior scheduler with a +WakeupCondition object. When that object's WakeupCondition has been +satisfied, the behavior scheduler hands that same WakeupCondition back +to the Behavior via an enumeration. +

+

+

+

WakeupCriterion Object

+

Java 3D provides a rich set of wakeup criteria that Behavior +objects +can use in specifying a complex WakeupCondition. These wakeup criteria +can cause Java 3D's behavior scheduler to invoke a behavior's processStimulus +method whenever +

+
    +
  • The center of an active ViewPlatform enters a specified region.
  • +
+
    +
  • The center of an active ViewPlatform exits a specified region.
  • +
+
    +
  • A behavior is activated.
  • +
+
    +
  • A behavior is deactivated.
  • +
+
    +
  • A specified TransformGroup node's transform changes.
  • +
+
    +
  • Collision is detected between a specified Shape3D node's Geometry +object and any other object.
  • +
+
    +
  • Movement occurs between a specified Shape3D node's Geometry +object and any other object with which it collides.
  • +
+
    +
  • A specified Shape3D node's Geometry object no longer collides +with any other object.
  • +
+
    +
  • A specified Behavior object posts a specific event.
  • +
+
    +
  • A specified AWT event occurs.
  • +
+
    +
  • A specified time interval elapses.
  • +
+
    +
  • A specified number of frames have been drawn.
  • +
+
    +
  • The center of a specified Sensor enters a specified region.
  • +
+
    +
  • The center of a specified Sensor exits a specified region.
  • +
+

A Behavior object constructs a WakeupCriterion +by constructing the +appropriate criterion object. The Behavior object must provide the +appropriate arguments (usually a reference to some scene graph object +and possibly a region of interest). Thus, to specify a +WakeupOnViewPlatformEntry, a behavior would specify the region that +will cause the behavior to execute if an active ViewPlatform enters it. +

+

Composing WakeupCriterion +Objects

+

A Behavior object can combine multiple WakeupCriterion objects into +a +more powerful, composite WakeupCondition. Java 3D behaviors +construct a +composite WakeupCondition in one of the following ways: +

+
    +
  • WakeupAnd: An array of +WakeupCriterion objects ANDed together.
  • +
+
            WakeupCriterion && WakeupCriterion && ...
+
    +
  • WakeupOr: An array of +WakeupCriterion objects ORed together.
  • +
+
            WakeupCriterion || WakeupCriterion || ...
+
    +
  • WakeupAndOfOrs: An array of +WakeupOr WakeupCondition objects that +are then ANDed together.
  • +
+
            WakeupOr && WakeupOr && ...
+
    +
  • WakeupOrOfAnds: An array of +WakeupAnd WakeupCondition objects +that are then ORed together.
  • +
+
            WakeupAnd || WakeupAnd || ...
+

Composing Behaviors

+

Behavior objects can condition themselves to awaken only when +signaled +by another Behavior node. The WakeupOnBehaviorPost +WakeupCriterion +takes as arguments a reference to a Behavior node and an integer. These +two arguments allow a behavior to limit its wakeup criterion to a +specific post by a specific behavior. +

+

The WakeupOnBehaviorPost WakeupCriterion permits behaviors to chain +their computations, allowing parenthetical computations-one behavior +opens a door and the second closes the same door, or one behavior +highlights an object and the second unhighlights the same object. +

+

+

+

Scheduling

+

As a virtual universe grows large, Java 3D must carefully +husband +its +resources to ensure adequate performance. In a 10,000-object virtual +universe with 400 or so Behavior nodes, a naive implementation of Java +3D could easily end up consuming the majority of its compute cycles in +executing the behaviors associated with the 400 Behavior objects before +it draws a frame. In such a situation, the frame rate could easily drop +to unacceptable levels. +

+

Behavior objects are usually associated with geometric objects in +the +virtual universe. In our example of 400 Behavior objects scattered +throughout a 10,000-object virtual universe, only a few of these +associated geometric objects would be visible at a given time. A +sizable fraction of the Behavior nodes-those associated with nonvisible +objects-need not be executed. Only those relatively few Behavior +objects that are associated with visible objects must be executed. +

+

Java 3D mitigates the problem of a large number of Behavior +nodes in +a +high-population virtual universe through execution culling-choosing to +invoke only those behaviors that have high relevance. +

+

Java 3D requires each behavior to have a scheduling region +and to post a wakeup condition. Together a behavior's scheduling region +and wakeup condition provide Java 3D's behavior scheduler with +sufficient domain knowledge to selectively prune behavior invocations +and invoke only those behaviors that absolutely need to be executed. +

+

+

+

How Java 3D Performs +Execution Culling

+

Java 3D finds all scheduling regions associated with Behavior +nodes +and +constructs a scheduling/volume tree. It also creates an AND/OR tree +containing all the Behavior node wakeup criteria. These two data +structures provide the domain knowledge Java 3D needs to prune +unneeded +behavior execution (to perform "execution triage"). +

+

Java 3D must track a behavior's wakeup conditions only if an +active +ViewPlatform object's activation volume intersects with that Behavior +object's scheduling region. If the ViewPlatform object's activation +volume does not intersect with a behavior's scheduling region, +Java 3D +can safely ignore that behavior's wakeup criteria. +

+

In essence, the Java 3D scheduler performs the following +checks: +

+
    +
  • Find all Behavior objects with scheduling regions that intersect +the active ViewPlatform object's activation volume.
  • +
+
    +
  • For each Behavior object within the ViewPlatform's activation +volume, if that behavior's WakeupCondition is true, +schedule that Behavior object for execution.
  • +
+

Java 3D's behavior scheduler executes those Behavior objects +that +have +been scheduled by calling the behavior's processStimulus +method. +

+

Interpolator Behaviors

+

This section describes Java 3D's predefined Interpolator behaviors. +They are called interpolators +because they smoothly interpolate between the two extreme values that +an interpolator can produce. Interpolators perform simple behavioral +acts, yet they provide broad functionality. +

+

The Java 3D API provides interpolators for a number of +functions: +manipulating transforms within a TransformGroup, modifying the values +of a Switch node, and modifying Material attributes such as color and +transparency. +

+

These predefined Interpolator behaviors share the same mechanism for +specifying and later for converting a temporal value into an alpha +value. Interpolators consist of two portions: a generic portion that +all interpolators share and a domain-specific portion. +

+

The generic portion maps time in milliseconds onto a value in the +range +[0.0, 1.0] inclusive. The domain-specific portion maps an alpha value +in the range [0.0, 1.0] onto a value appropriate to the predefined +behavior's range of outputs. An alpha value of 0.0 generates an +interpolator's minimum value, an alpha value of 1.0 generates an +interpolator's maximum value, and an alpha value somewhere in between +generates a value proportionally in between the minimum and maximum +values. +

+

Mapping Time to Alpha

+

Several parameters control the mapping of time onto an alpha value +(see +the javadoc for the Alpha object for a +description of the API). +That mapping is deterministic as long as its parameters do not change. +Thus, two different interpolators with the same parameters will +generate the same alpha value given the same time value. This means +that two interpolators that do not communicate can still precisely +coordinate their activities, even if they reside in different threads +or even different processors-as long as those processors have +consistent clocks. +

+

Figure +1 +shows the components of an interpolator's time-to-alpha mapping. Time +is represented on the horizontal axis. Alpha is represented on the +vertical axis. As we move from left to right, we see the alpha value +start at 0.0, rise to 1.0, and then decline back to 0.0 on the +right-hand side. +

+

On the left-hand side, the trigger time defines +when this interpolator's waveform begins in milliseconds. The region +directly to the right of the trigger time, labeled Phase Delay, defines +a time period where the waveform does not change. During phase delays +alpha is either 0 or 1, depending on which region it precedes. +

+

Phase delays provide an important means for offsetting multiple +interpolators from one another, especially where the interpolators have +all the same parameters. The next four regions, labeled α +increasing, α at 1, α decreasing, and +α at 0, all specify durations for +the corresponding values +of alpha. +

+

Interpolators have a loop count that determines how many times to +repeat the sequence of alpha increasing, alpha at 1, alpha decreasing, +and alpha at 0; they also have associated mode flags that enable either +the increasing or decreasing portions, or both, of the waveform. +

+

Time-to-Alpha Mapping +

+

+

+
    + Figure 1 – An Interpolator's Generic +Time-to-Alpha Mapping Sequence +
+

+Developers can use the loop count in conjunction with the mode flags to +generate various kinds of actions. Specifying a loop count of 1 and +enabling the mode flag for only the alpha-increasing and alpha-at-1 +portion of the waveform, we would get the waveform shown in Figure +2. +

+

Alpha Increasing +

+

+

+
    + Figure 2 – An Interpolator Set to a Loop +Count of 1 with Mode Flags Set to Enable +Only the Alpha-Increasing and Alpha-at-1 Portion of the Waveform +
+

+In Figure +2, +the alpha value is 0 before the combination of trigger time plus the +phase delay duration. The alpha value changes from 0 to 1 over a +specified interval of time, and thereafter the alpha value remains 1 +(subject to the reprogramming of the interpolator's parameters). A +possible use of a single alpha-increasing value might be to combine it +with a rotation interpolator to program a door opening. +

+

Similarly, by specifying a loop count of 1 and +a mode flag that enables only the alpha-decreasing and alpha-at-0 +portion of the waveform, we would get the waveform shown in Figure +3. +

+

In Figure +3, +the alpha value is 1 before the combination of trigger time plus the +phase delay duration. The alpha value changes from 1 to 0 over a +specified interval; thereafter the alpha value remains 0 (subject to +the reprogramming of the interpolator's parameters). A possible use of +a single α-decreasing value might be to combine it with a +rotation +interpolator to program a door closing. +

+

Alpha Decreasing +

+

+

+
    + Figure 3 – An Interpolator Set to a Loop +Count of 1 with Mode Flags Set to Enable +Only the Alpha-Decreasing and Alpha-at-0 Portion of the Waveform +
+

+We can combine both of the above waveforms by specifying a loop count +of 1 and setting the mode flag to enable both the alpha-increasing and +alpha-at-1 portion of the waveform as well as the alpha-decreasing and +alpha-at-0 portion of the waveform. This combination would result in +the waveform shown in Figure +4. +

+

Alpha Increasing & Decreasing +

+

+

+
    + Figure 4 – An Interpolator Set to a Loop +Count of 1 with Mode Flags +Set to Enable All Portions of the Waveform +
+

+In Figure +4, +the alpha value is 0 before the combination of trigger time plus the +phase delay duration. The alpha value changes from 0 to 1 over a +specified period of time, remains at 1 for another specified period of +time, then changes from 1 to 0 over a third specified period of time; +thereafter the alpha value remains 0 (subject to the reprogramming of +the interpolator's parameters). A possible use of an alpha-increasing +value followed by an alpha-decreasing value might be to combine it with +a rotation interpolator to program a door swinging open and then +closing. +

+

By increasing the loop count, we can get +repetitive behavior, such as a door swinging open and closed some +number of times. At the extreme, we can specify a loop count of -1 +(representing infinity). +

+

We can construct looped versions of the waveforms shown in Figure +2, Figure +3, and Figure +4. Figure +5 shows a looping interpolator with mode flags set to enable +only the alpha-increasing and alpha-at-1 portion of the waveform. +

+

Alpha Increasing Infinite Loop +

+

+

+
    + Figure 5 – An Interpolator Set to Loop +Infinitely and Mode Flags Set to Enable +Only the Alpha-Increasing and Alpha-at-1 Portion of the Waveform +
+

+In Figure +5, alpha goes from 0 to 1 over a fixed duration of time, stays +at 1 for another fixed duration of time, and then repeats. +

+

Similarly, Figure +6 shows a looping interpolator with mode flags set to enable +only the alpha-decreasing and alpha-at-0 portion of the waveform. +

+

Alpha Decreasing Infinite Loop +

+

+

+
    + Figure 6 – An Interpolator Set to Loop +Infinitely and Mode Flags Set to Enable +Only the Alpha-Decreasing and Alpha-at-0 Portion of the Waveform +
+

+Finally, Figure +7 shows a looping interpolator with both the increasing and +decreasing portions of the waveform enabled. +

+

In all three cases shown by Figure +5, Figure +6, and Figure +7, we can compute the exact value of alpha at any point in time. +

+

Alpha Increasing & Decreasing  Infinite Loop +

+

+

+
    + Figure 7 – An Interpolator Set to Loop +Infinitely and Mode Flags Set +to Enable All Portions of the Waveform +
+

+Java 3D's preprogrammed behaviors permit other behaviors to change +their parameters. When such a change occurs, the alpha value changes to +match the state of the newly parameterized interpolator. +

+

Acceleration of Alpha

+

Commonly, developers want alpha to change slowly at first and then +to +speed up until the change in alpha reaches some appropriate rate. This +is analogous to accelerating your car up to the speed limit-it does not +start off immediately at the speed limit. Developers specify this +"ease-in, ease-out" behavior through two additional parameters, the increasingAlphaRampDuration +and the decreasing-AlphaRampDuration. +

+

Each of these parameters specifies a period within the increasing or +decreasing alpha duration region during which the "change in alpha" is +accelerated (until it reaches its maximum per-unit-of-time step size) +and then symmetrically decelerated. Figure +8 shows three general examples of how the increasingAlphaRampDuration +method can be used to modify the alpha waveform. A value of 0 for the +increasing ramp duration implies that α +is not accelerated; it changes at a constant rate. A value of 0.5 or +greater (clamped to 0.5) for this increasing ramp duration implies that +the change in α is accelerated during the first half of the +period and +then decelerated during the second half of the period. For a value of n +that is less than 0.5, alpha is accelerated for duration n, +held constant for duration (1.0 - 2n), then decelerated for +duration n of the period. +

+

Alpha acceleration +

+

+

+
    + Figure 8 – How an Alpha-Increasing Waveform +Changes with Various +Values of increasing-AlphaRampDuration +
+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors1.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors1.gif new file mode 100644 index 0000000..bb288ce Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors1.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors2.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors2.gif new file mode 100644 index 0000000..005564f Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors2.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors3.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors3.gif new file mode 100644 index 0000000..a8beb09 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors3.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors4.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors4.gif new file mode 100644 index 0000000..685bcb7 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors4.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors5.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors5.gif new file mode 100644 index 0000000..74783fb Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors5.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors6.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors6.gif new file mode 100644 index 0000000..8614a4e Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors6.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors7.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors7.gif new file mode 100644 index 0000000..0f2ce48 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors7.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors8.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors8.gif new file mode 100644 index 0000000..d048cfa Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Behaviors8.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts.html new file mode 100644 index 0000000..7b005af --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts.html @@ -0,0 +1,291 @@ + + + + + Java 3D API - Concepts + + +

Java 3D Concepts

+

The Java 3D API specification serves to define objects, methods, and +their actions precisely. Describing how to use an API belongs in a +tutorial or programmer's +reference manual, and is well beyond the scope of this specification. +However, a short introduction to the main concepts in Java 3D will +provide the context for understanding the detailed, but isolated, +specification found in the class and method descriptions. We introduce +some of the key Java 3D concepts and illustrate them with some simple +program fragments. +

+

+

+

Basic Scene Graph Concepts

+

A scene graph is a "tree" structure that contains data arranged in a +hierarchical manner. The scene graph consists of parent nodes, child +nodes, and data objects. The parent nodes, called Group nodes, organize +and, in some cases, control how Java 3D interprets their descendants. +Group nodes serve as the glue that holds a scene graph together. Child +nodes can be either Group nodes or Leaf nodes. Leaf nodes have no +children. They encode the core semantic elements of a scene graph- for +example, what to draw (geometry), what to play (audio), how to +illuminate objects (lights), or what code to execute (behaviors). Leaf +nodes refer to data objects, called NodeComponent objects. +NodeComponent objects are not scene graph nodes, but they contain the +data that Leaf nodes require, such as the geometry to draw or the sound +sample to play. +

+

A Java 3D application builds and manipulates a scene graph by +constructing Java 3D objects and then later modifying those objects by +using their methods. A Java 3D program first constructs a scene graph, +then, once built, hands that scene graph to Java 3D for processing. +

+

The structure of a scene graph determines the relationships among +the +objects in the graph and determines which objects a programmer can +manipulate as a single entity. Group nodes provide a single point for +handling or manipulating all the nodes beneath it. A programmer can +tune a scene graph appropriately by thinking about what manipulations +an application will need to perform. He or she can make a particular +manipulation easy or difficult by grouping or regrouping nodes in +various ways. +

+

+

+

Constructing a Simple Scene +Graph

+

The following code constructs a simple scene graph consisting of a +group node and two leaf +nodes.
+

+

+Listing 1 – Code for Constructing a Simple Scene Graph +

+
+
Shape3D myShape1 = new Shape3D(myGeometry1, myAppearance1);
Shape3D myShape2 = new Shape3D(myGeometry2);
myShape2.setAppearance(myAppearance2);

Group myGroup = new Group();
myGroup.addChild(myShape1);
myGroup.addChild(myShape2);
+
+

It first constructs one leaf node, the first of two Shape3D +nodes, using a constructor that takes both a Geometry and an Appearance +NodeComponent object. It then constructs the second Shape3D node, with +only a Geometry object. Next, since the second Shape3D node was created +without an Appearance object, it supplies the missing Appearance object +using the Shape3D node's setAppearance method. At this +point both leaf nodes have been fully constructed. The code next +constructs a group node to hold the two leaf nodes. It +uses the Group node's addChild method to add the two leaf +nodes as children to the group node, finishing the construction of the +scene graph. Figure +1 +shows the constructed scene graph, all the nodes, the node component +objects, and the variables used in constructing the scene graph. +

+

A Simple Scene Graph +

+
    + Figure 1 – A Simple Scene Graph +
+

A Place For Scene Graphs

+Once a scene graph has been constructed, the +question becomes what to do with it? Java 3D cannot start rendering a +scene graph until a program "gives" it the scene graph. The program +does this by inserting the scene graph into the virtual universe. +

Java 3D places restrictions on how a program can insert a scene +graph +into a universe. +

+

A Java 3D environment consists of two superstructure objects, +VirtualUniverse and Locale, and one or more graphs, rooted by a special +BranchGroup node. Figure 2 shows these objects +in context with other scene graph objects. +

+

The VirtualUniverse object defines a universe. A universe allows a +Java +3D program to create a separate and distinct arena for defining objects +and their relationships to one another. Typically, Java 3D programs +have only one VirtualUniverse object. Programs that have more than one +VirtualUniverse may share NodeComponent objects but not scene graph +node objects. +

+

The Locale object specifies a fixed position within the universe. +That +fixed position defines an origin for all scene graph nodes beneath it. +The Locale object allows a programmer to specify that origin very +precisely and with very high dynamic range. A Locale can accurately +specify a location anywhere in the known physical universe and at the +precision of Plank's distance. Typically, Java 3D programs have only +one Locale object with a default origin of (0, 0, 0). Programs that +have more than one Locale object will set the location of the +individual Locale objects so that they provide an appropriate local +origin for the nodes beneath them. For example, to model the Mars +landing, a programmer might create one Locale object with an origin at +Cape Canaveral and another with an origin located at the landing site +on Mars. +

+

Content Branch, View Branch, Superstructure +

+
    + Figure 2 – Content Branch, View Branch, and +Superstructure +
+

+The BranchGroup node serves as the root of a branch graph. +Collectively, the BranchGroup node and all of its children form the +branch graph. The two kinds of branch graphs are called content +branches and view branches. A content branch contains only +content-related leaf nodes, while a view branch +contains a ViewPlatform leaf node and may contain other content-related +leaf nodes. Typically, a universe contains more than one branch +graph-one view branch, and any number of content branches. +

+

Besides serving as the root of a branch graph, the BranchGroup node +has +two special properties: It alone may be inserted into a Locale object, +and it may be compiled. Java 3D treats uncompiled and compiled branch +graphs identically, though compiled branch graphs will typically render +more efficiently. +

+

We could not insert the scene graph created by our simple example (Listing +1) into a Locale because it does not have a BranchGoup node for +its root. Listing 2 +shows a modified version of our first code example that creates a +simple content branch graph and the minimum of superstructure objects. +Of special note, Locales do not have children, and they are not part of +the scene graph. The method for inserting a branch graph is addBranchGraph, +whereas addChild is the method for adding children to all +group nodes.

+

+Listing 2 – Code for Constructing a +Scene Graph and Some +Superstructure Objects +

+
+
Shape3D myShape1 = new Shape3D(myGeometry1, myAppearance1);
Shape3D myShape2 = new Shape3D(myGeometry2, myAppearance2);

BranchGroup myBranch = new BranchGroup();
myBranch.addChild(myShape1);
myBranch.addChild(myShape2);
myBranch.compile();

VirtualUniverse myUniverse = new VirtualUniverse();
Locale myLocale = new Locale(myUniverse);
myLocale.addBranchGraph(myBranch);
+
+

SimpleUniverse Utility

+Most Java 3D programs build an identical set of superstructure and view +branch objects, so the Java 3D utility packages provide a universe +package for constructing and manipulating the objects in a view branch. +The classes in the universe package provide a quick means +for building a single view (single window) application. Listing 3 +shows a code fragment for using the SimpleUniverse class. Note that the +SimpleUniverse constructor takes a Canvas3D as an argument, in this +case referred to by the variable myCanvas. +

Listing 3 – Code +for Constructing a Scene Graph Using the Universe +Package +

+
+
import com.sun.j3d.utils.universe.*;

Shape3D myShape1 = new Shape3D(myGeometry1, myAppearance1);
Shape3D myShape2 = new Shape3D(myGeometry2, myAppearance2);

BranchGroup myBranch = new BranchGroup();
myBranch.addChild(myShape1);
myBranch.addChild(myShape2);
myBranch.compile();

SimpleUniverse myUniv = new SimpleUniverse(myCanvas);
myUniv.addBranchGraph(myBranch);
+
+

Processing a Scene Graph

+When given a scene graph, Java 3D processes that scene graph as +efficiently as possible. How a Java 3D implementation processes a scene +graph can vary, as long as the implementation conforms to the semantics +of the API. In general, a Java 3D implementation will render all +visible objects, play all enabled sounds, execute all triggered +behaviors, process any identified input devices, and check for and +generate appropriate collision events. +

The order that a particular Java 3D implementation renders objects +onto +the display is carefully not defined. One implementation might render +the first Shape3D object and then the second. Another might first +render the second Shape3D node before it renders the first one. Yet +another implementation may render both Shape3D nodes in parallel. +

+

+

+

Features of Java 3D

+Java 3D allows a programmer to specify a broad range of information. It +allows control over the shape of objects, their color, and +transparency. It allows control over background effects, lighting, and +environmental effects such as fog. It allows control over the placement +of all objects (even nonvisible objects such as lights and behaviors) +in the scene graph and over their orientation and scale. It allows +control over how those objects move, rotate, stretch, shrink, or morph +over time. It allows control over what code should execute, what sounds +should play, and how they should sound and change over time. +

Java 3D provides different techniques for controlling the effect of +various features. Some techniques act fairly locally, such as getting +the color of a vertex. Other techniques have broader influence, such as +changing the color or appearance of an entire object. Still other +techniques apply to a broad number of objects. In the first two cases, +the programmer can modify a particular object or an object associated +with the affected object. In the latter case, Java 3D provides a means +for specifying more than one object spatially. +

+

+

+

Bounds

+Bounds objects allow a programmer to define a volume in space. There +are three ways to specify this volume: as a box, a sphere, or a set of +planes enclosing a space. +

Bounds objects specify a volume in which particular operations +apply. +Environmental effects such as lighting, fog, alternate appearance, and +model clipping planes use bounds objects to specify their region of +influence. Any object that falls within the space defined by the bounds +object has the particular environmental effect applied. The proper use +of bounds objects can ensure that these environmental effects are +applied only to those objects in a particular volume, such as a light +applying only to the objects within a single room. +

+

Bounds objects are also used to specify a region of action. +Behaviors +and sounds execute or play only if they are close enough to the viewer. +The use of behavior and sound bounds objects allows Java 3D to cull +away those behaviors and sounds that are too far away to affect the +viewer (listener). By using bounds properly, a programmer can ensure +that only the relevant behaviors and sounds execute or play. +

+

Finally, bounds objects are used to specify a region of application +for +per-view operations such as background, clip, and soundscape selection. +For example, the background node whose region of application is closest +to the viewer is selected for a given view. +

+

+

+

Nodes

+All scene graph nodes have an implicit location in space of (0, 0, 0). +For objects that exist in space, this implicit location provides a +local coordinate system for that object, a fixed reference point. Even +abstract objects that may not seem to have a well-defined location, +such as behaviors and ambient lights, have this implicit location. An +object's location provides an origin for its local coordinate system +and, just as importantly, an origin for any bounding volume information +associated with that object. +

Live and/or Compiled

+All scene graph objects, including nodes and node component objects, +are either part of an active universe or not. An object is said to be live +if it is part of an active universe. Additionally, branch graphs are +either compiled +or not. When a node is either live or compiled, Java 3D enforces access +restrictions to nodes and node component objects. Java 3D allows only +those operations that are enabled by the program before a node or node +component becomes live or is compiled. It is best to set capabilities +when you build your content. Listing 4 shows +an example where we create a TransformGroup node and +enable it for writing. +

Listing 4 – +Capabilities Example +

+
+
TransformGroup myTrans = new TransformGroup();
myTrans.setCapability(Transform.ALLOW_TRANSFORM_WRITE);
+
+

By setting the capability to write the transform, Java 3D will allow +the following code to execute: +

+
myTrans.setTransform3D(myT3D);
+

It is important to ensure that all needed capabilities are set and +that +unnecessary capabilities are not set. The process of compiling a branch +graph examines the capability bits and uses that information to reduce +the amount of computation needed to run a program. +

+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts1.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts1.gif new file mode 100644 index 0000000..8aa0dbc Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts1.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts2.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts2.gif new file mode 100644 index 0000000..f21e085 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Concepts2.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/DAG.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/DAG.gif new file mode 100644 index 0000000..8479136 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/DAG.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/HelloUniverse.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/HelloUniverse.html new file mode 100644 index 0000000..5e37bd6 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/HelloUniverse.html @@ -0,0 +1,21 @@ + + + + + HelloUniverse + + +

HelloUniverse: A Sample Java +3D Program

+

Here are code fragments from a simple program, HelloUniverse.java, +that creates a cube and a RotationInterpolator behavior object that +rotates the cube at a constant rate of pi/2 radians per second. The +HelloUniverse class creates the branch graph +that includes the cube and the RotationInterpolator behavior. It then +adds this branch graph to the Locale object generated by the +SimpleUniverse utility. +

+


public class HelloUniverse ... {
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();

// Create the TransformGroup node and initialize it to the
// identity. Enable the TRANSFORM_WRITE capability so that
// our behavior code can modify it at run time. Add it to
// the root of the subgraph.
TransformGroup objTrans = new TransformGroup();
objTrans.setCapability(
TransformGroup.ALLOW_TRANSFORM_WRITE);
objRoot.addChild(objTrans);

// Create a simple Shape3D node; add it to the scene graph.
objTrans.addChild(new ColorCube(0.4));

// Create a new Behavior object that will perform the
// desired operation on the specified transform and add
// it into the scene graph.
Transform3D yAxis = new Transform3D();
Alpha rotationAlpha = new Alpha(-1, 4000);
RotationInterpolator rotator = new RotationInterpolator(
rotationAlpha, objTrans, yAxis,
0.0f, (float) Math.PI*2.0f);
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
rotator.setSchedulingBounds(bounds);
objRoot.addChild(rotator);

// Have Java 3D perform optimizations on this scene graph.
objRoot.compile();

return objRoot;
}

public HelloUniverse() {
<set layout of container, construct canvas3d, add canvas3d>

// Create the scene; attach it to the virtual universe
BranchGroup scene = createSceneGraph();
SimpleUniverse u = new SimpleUniverse(canvas3d);
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
}
+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Immediate.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Immediate.html new file mode 100644 index 0000000..101fe22 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Immediate.html @@ -0,0 +1,114 @@ + + + + + Java 3D API - Immediate-Mode Rendering + + +

Immediate-Mode Rendering

+

Java 3D is fundamentally a scene graph-based API. Most of +the constructs in the API are biased toward retained mode and +compiled-retained mode rendering. However, there are some applications +that want both the control and the flexibility that immediate-mode +rendering offers. +

+

Immediate-mode applications can either use or ignore Java 3D's +scene +graph structure. By using immediate mode, end-user applications have +more freedom, but this freedom comes at the expense of performance. In +immediate mode, Java 3D has no high-level information concerning +graphical objects or their composition. Because it has minimal global +knowledge, Java 3D can perform only localized optimizations on +behalf +of the application programmer. +

+

+

+

Two Styles of Immediate-Mode +Rendering

+Use of Java 3D's immediate mode falls into one of two categories: +pure +immediate-mode rendering and mixed-mode rendering in which immediate +mode and retained or compiled-retained mode interoperate and render to +the same canvas. The Java 3D renderer is idle in pure immediate +mode, +distinguishing it from mixed-mode rendering. +

Pure Immediate-Mode +Rendering

+Pure immediate-mode rendering provides for those applications and +applets that do not want Java 3D to do any automatic rendering of +the +scene graph. Such applications may not even wish to build a scene graph +to represent their graphical data. However, they use Java 3D's +attribute objects to set graphics state and Java 3D's geometric +objects +to render geometry. +
Note: Scene antialiasing is not supported +in pure immediate mode. +
A pure immediate mode application must create a +minimal set of Java 3D +objects before rendering. In addition to a Canvas3D object, the +application must create a View object, with its associated PhysicalBody +and PhysicalEnvironment objects, and the following scene graph +elements: a VirtualUniverse object, a high-resolution Locale object, a +BranchGroup node object, a TransformGroup node object with associated +transform, and, finally, a ViewPlatform leaf node object that defines +the position and orientation within the virtual universe that generates +the view (see Figure +1). +

Minimal Immediate-Mode Structure

+

+

+
    + Figure 1 – Minimal Immediate-Mode Structure +
+

+Java 3D provides utility functions that create much of this +structure +on behalf of a pure immediate-mode application, making it less +noticeable from the application's perspective-but the structure must +exist. +

+

All rendering is done completely under user control. It is necessary +for the user to clear the 3D canvas, render all geometry, and swap the +buffers. Additionally, rendering the right and left eye for stereo +viewing becomes the sole responsibility of the application. +

+

In pure immediate mode, the user must stop the Java 3D +renderer, via +the Canvas3D object stopRenderer() +method, prior to adding the Canvas3D object to an active View object +(that is, one that is attached to a live ViewPlatform object). +

+

+

+

Mixed-Mode Rendering

+Mixing immediate mode and retained or compiled-retained mode requires +more structure than pure immediate mode. In mixed mode, the +Java 3D +renderer is running continuously, rendering the scene graph into the +canvas. +

The basic Java 3D stereo rendering loop, executed for +each +Canvas3D, is as follows: +

+


clear canvas (both eyes)
+
call preRender()                           // user-supplied method
set left eye view
render opaque scene graph objects
call renderField(FIELD_LEFT) // user-supplied method
render transparent scene graph objects
set right eye view
render opaque scene graph objects again
call renderField(FIELD_RIGHT) // user-supplied method
render transparent scene graph objects again
call postRender() // user-supplied method
synchronize and swap buffers
+
call postSwap()                            // user-supplied method


+The basic Java 3D monoscopic rendering loop is as +follows: +


clear canvas
+
call preRender()                            // user-supplied method
set view
render opaque scene graph objects
call renderField(FIELD_ALL) // user-supplied method
render transparent scene graph objects
call postRender() // user-supplied method
synchronize and swap buffers
+
call postSwap()                             // user-supplied method


+In both cases, the entire loop, beginning with clearing the canvas and +ending with swapping the buffers, defines a frame. The application is +given the opportunity to render immediate-mode geometry at any of the +clearly identified spots in the rendering loop. A user specifies his or +her own rendering methods by extending the Canvas3D class and +overriding the preRender, postRender, postSwap, +and/or renderField methods. + + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Immediate1.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Immediate1.gif new file mode 100644 index 0000000..2d549b1 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Immediate1.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/Rendering.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Rendering.html new file mode 100644 index 0000000..7415ce8 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/Rendering.html @@ -0,0 +1,148 @@ + + + + + Java 3D API - Execution and Rendering Model + + +

Execution and Rendering Model

+

Java 3D's execution and rendering model assumes the +existence of a VirtualUniverse +object and an attached scene graph. This +scene graph can be minimal and not noticeable from an application's +perspective when using immediate-mode rendering, but it must exist. +

+

Java 3D's execution model intertwines with its rendering modes +and +with +behaviors and their scheduling. This chapter first describes the three +rendering modes, then describes how an application starts up a +Java 3D +environment, and finally it discusses how the various rendering modes +work within this framework. +

+

+

+

Three Major Rendering Modes

+

Java 3D supports three different modes for rendering scenes: +immediate +mode, retained mode, and compiled-retained mode. These three levels of +API support represent a potentially large variation in graphics +processing speed and in on-the-fly restructuring. +

+

+

Immediate Mode

+

Immediate mode allows maximum flexibility at some cost in rendering +speed. The application programmer can either use or ignore the scene +graph structure inherent in Java 3D's design. The programmer can +choose +to draw geometry directly or to define a scene graph. Immediate mode +can be either used independently or mixed with retained and/or +compiled-retained mode rendering. The immediate-mode API is described +in the "Immediate-Mode Rendering" section.

+

+

+

Retained Mode

+

Retained mode allows a great deal of the flexibility provided by +immediate mode while also providing a substantial increase in rendering +speed. All objects defined in the scene graph are accessible and +manipulable. The scene graph itself is fully manipulable. The +application programmer can rapidly construct the scene graph, create +and delete nodes, and instantly "see" the effect of edits. Retained +mode also allows maximal access to objects through a general pick +capability. +

+

Java 3D's retained mode allows a programmer to construct +objects, +insert objects into a database, compose objects, and add behaviors to +objects. +

+

In retained mode, Java 3D knows that the programmer has defined +objects, knows how the programmer has combined those objects into +compound objects or scene graphs, and knows what behaviors or actions +the programmer has attached to objects in the database. This knowledge +allows Java 3D to perform many optimizations. It can construct +specialized data structures that hold an object's geometry in a manner +that enhances the speed at which the Java 3D system can render it. +It +can compile object behaviors so that they run at maximum speed when +invoked. It can flatten transformation manipulations and state changes +where possible in the scene graph. +

+

+

+

Compiled-Retained Mode

+

Compiled-retained mode allows the Java 3D API to perform an +arbitrarily +complex series of optimizations including, but not restricted to, +geometry compression, scene graph flattening, geometry grouping, and +state change clustering. +

+

Compiled-retained mode provides hooks for end-user manipulation and +picking. Pick operations return the closest object (in scene graph +space) associated with the picked geometry. +

+

Java 3D's compiled-retained mode ensures effective graphics +rendering +speed in yet one more way. A programmer can request that Java 3D +compile an object or a scene graph. Once it is compiled, the programmer +has minimal access to the internal structure of the object or scene +graph. Capability flags provide access to specified components that the +application program may need to modify on a continuing basis. +

+

A compiled object or scene graph consists of whatever internal +structures Java 3D wishes to create to ensure that objects or +scene +graphs render at maximal rates. Because Java 3D knows that the +majority +of the compiled object's or scene graph's components will not change, +it can perform an extraordinary number of optimizations, including the +fusing of multiple objects into one conceptual object, turning an +object into compressed geometry or even breaking an object up into +like-kind components and reassembling the like-kind components into new +"conceptual objects." +

+

+

+

Instantiating the Render Loop

+

From an application's perspective, Java 3D's render loop runs +continuously. Whenever an application adds a scene branch to the +virtual world, that scene branch is instantly visible. This high-level +view of the render loop permits concurrent implementations of +Java 3D +as well as serial implementations. The remainder of this section +describes the Java 3D render loop bootstrap process from a +serialized +perspective. Differences that would appear in concurrent +implementations are noted as well. +

+

+

An Application-Level +Perspective

+

First the application must construct its scene graphs. It does this +by +constructing scene graph nodes and component objects and linking them +into self-contained trees with a BranchGroup node as a root. The +application next must obtain a reference to any constituent nodes or +objects within that branch that it may wish to manipulate. It sets the +capabilities of all the objects to match their anticipated use and only +then compiles the branch using the BranchGroup's compile +method. Whether it compiles the branch, the application can add it to +the virtual universe by adding the BranchGroup to a Locale object. The +application repeats this process for each branch it wishes to create. +Note that for concurrent Java 3D implementations, whenever an +application adds a branch to the active virtual universe, that branch +becomes visible. +

+

+

Retained and +Compiled-Retained Rendering Modes

+

This initialization process is identical for retained and +compiled-retained modes. In both modes, the application builds a scene +graph. In compiled-retained mode, the application compiles the scene +graph. Then the application inserts the (possibly compiled) scene graph +into the virtual universe. +

+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphOverview.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphOverview.html new file mode 100644 index 0000000..f1616df --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphOverview.html @@ -0,0 +1,226 @@ + + + + + Java 3D API - Scene Graph Overview + + +

Scene Graph Basics

+

A scene graph consists of Java 3D +objects, called nodes, +arranged in a tree structure. The user creates one or more scene +subgraphs and attaches them to a virtual universe. The individual +connections between Java 3D nodes always represent a directed +relationship: parent to child. Java 3D restricts scene graphs in one +major way: Scene graphs may not contain cycles. Thus, a Java 3D scene +graph is a directed acyclic graph (DAG). See Figure +1. +

+

Java 3D refines the Node object class +into two subclasses: Group +and +Leaf node objects. Group node objects group +together one or more child +nodes. A group node can point to zero or more children but can have +only one parent. The SharedGroup node cannot have any parents (although +it allows sharing portions of a scene graph, as described in "Reusing Scene Graphs"). +Leaf node objects contain the actual definitions of shapes (geometry), +lights, fog, sounds, and so forth. A leaf node has no children and only +one parent. The semantics of the various group and leaf nodes are +described in subsequent chapters.

+

Scene Graph Structure

+

A scene graph organizes and controls the rendering +of its constituent objects. The Java 3D renderer draws a scene graph in +a consistent way that allows for concurrence. The Java 3D renderer can +draw one object independently of other objects. Java 3D can allow such +independence because its scene graphs have a particular form and cannot +share state among branches of a tree. +

+

Spatial Separation

+

The hierarchy of the scene graph encourages a natural spatial +grouping +on the geometric objects found at the leaves of the graph. Internal +nodes act to group their children together. A group node also defines a +spatial bound that contains all the geometry defined by its +descendants. Spatial grouping allows for efficient implementation of +operations such as proximity detection, collision detection, view +frustum culling, and occlusion culling. +

+

Directed Acyclic Graph

+

+
    + Figure 1 – A Java +3D Scene Graph Is a DAG +(Directed Acyclic Graph) +
+

+

State Inheritance

+

A leaf node's state is defined by the nodes in a direct path between +the scene graph's root and the leaf. Because a leaf's graphics context +relies only on a linear path between the root and that node, the Java +3D renderer can decide to traverse the scene graph in whatever order it +wishes. It can traverse the scene graph from left to right and top to +bottom, in level order from right to left, or even in parallel. The +only exceptions to this rule are spatially bounded attributes such as +lights and fog. +

+

This characteristic is in marked contrast to many older scene +graph-based APIs (including PHIGS and SGI's Inventor) where, if a node +above or to the left of a node changes the graphics state, the change +affects the graphics state of all nodes below it or to its right.

+

The most common node object, along the path from the root to the +leaf, +that changes the graphics state is the TransformGroup object. The +TransformGroup object can change the position, orientation, and scale +of the objects below it.

+

Most graphics state attributes are set by a Shape3D leaf node +through +its constituent Appearance object, thus allowing parallel rendering. +The Shape3D node also has a constituent Geometry object that specifies +its geometry-this permits different shape objects to share common +geometry without sharing material attributes (or vice versa).

+

+

Rendering

+

The Java 3D renderer incorporates all graphics state changes made in +a +direct path from a scene graph root to a leaf object in the drawing of +that leaf object. Java 3D provides this semantic for both retained and +compiled-retained modes. +

+

+

Scene Graph Objects

+

A Java 3D scene graph consists of a collection of Java 3D node +objects +connected in a tree structure. These node objects reference other scene +graph objects called node component objects. +All scene graph node and component objects are subclasses of a common +SceneGraphObject class. The +SceneGraphObject class is an abstract class +that defines methods that are common among nodes and component objects. +

+

Scene graph objects are constructed by creating a new instance of +the +desired class and are accessed and manipulated using the object's set +and get +methods. Once a scene graph object is created and connected to other +scene graph objects to form a subgraph, the entire subgraph can be +attached to a virtual universe---via a high-resolution Locale +object-making the object live. Prior to attaching a subgraph +to a virtual +universe, the entire subgraph can be compiled into an +optimized, internal format (see the +BranchGroup.compile() +method).

+

An important characteristic of all scene graph objects is that +they can +be accessed or modified only during the creation of a scene graph, +except where explicitly allowed. Access to most set and get +methods of objects that are part of a live or compiled scene graph is +restricted. Such restrictions provide the scene graph compiler with +usage information it can use in optimally compiling or rendering a +scene graph. Each object has a set of capability bits that enable +certain functionality when the object is live or compiled. By default, +all capability bits are disabled (cleared). Only those set +and get +methods corresponding to capability bits that are explicitly enabled +(set) prior to the object being compiled or made live are legal.
+

+

+

Scene Graph Superstructure +Objects

+Java 3D defines two scene graph superstructure objects, +VirtualUniverse +and Locale, which are used to contain +collections of subgraphs that +comprise the scene graph. These objects are described in more detail in +"Scene Graph Superstructure." +

+

VirtualUniverse Object

+A VirtualUniverse object +consists of a list of Locale objects that +contain a collection of scene graph nodes that exist in the universe. +Typically, an application will need only one VirtualUniverse, even for +very large virtual databases. Operations on a VirtualUniverse include +enumerating the Locale objects contained within the universe. +

+

Locale Object

+The Locale object acts as a container for +a collection of subgraphs of +the scene graph that are rooted by a BranchGroup node. A Locale also +defines a location within the virtual universe using high-resolution +coordinates (HiResCoord) to specify its position. The HiResCoord serves +as the origin for all scene graph objects contained within the Locale. +

A Locale has no parent in the scene graph but is implicitly +attached to +a virtual universe when it is constructed. A Locale may reference an +arbitrary number of BranchGroup nodes but has no explicit children.

+

The coordinates of all scene graph objects are relative to the +HiResCoord of the Locale in which they are contained. Operations on a +Locale include setting or getting the HiResCoord of the Locale, adding +a subgraph, and removing a subgraph.

+

+

Scene Graph Viewing Objects

+Java 3D defines five scene graph viewing objects that are not part of +the scene graph per se but serve to define the viewing parameters and +to provide hooks into the physical world. These objects are Canvas3D, +Screen3D, View, +PhysicalBody, and PhysicalEnvironment. They are +described in more detail in the "View Model" +document.
+

+

Canvas3D Object

+The Canvas3D object encapsulates all of +the parameters associated with +the window being rendered into. +When a Canvas3D object is attached to a View object, the Java 3D +traverser renders the specified view onto the canvas. Multiple Canvas3D +objects can point to the same View object. +

+

Screen3D Object

+The Screen3D object encapsulates all of +the +parameters associated with the physical screen containing the canvas, +such as the width and height of the screen in pixels, the physical +dimensions of the screen, and various physical calibration values. +

+

View Object

+The View object specifies information +needed to render the scene graph. +Figure +2 shows a View object attached to a simple scene graph for +viewing the scene. +

The View object is the central Java 3D object for coordinating all +aspects of viewing. +All viewing parameters in Java 3D are directly contained either within +the View object or within objects pointed to by a View object. Java 3D +supports multiple simultaneously active View objects, each of which can +render to one or more canvases.

+

+

PhysicalBody Object

+The PhysicalBody object encapsulates all of the +parameters associated with the physical body, such as head position, +right and left eye position, and so forth. +

+

PhysicalEnvironment Object

+

The PhysicalEnvironment object encapsulates all of the parameters +associated with the physical environment, such as calibration +information for the tracker base for the head or hand tracker.
+

+


+

+

Viewing a Scene Graph +

+

+
    + Figure 2 – Viewing a Scene Graph +
+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing.html new file mode 100644 index 0000000..ff80cb4 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing.html @@ -0,0 +1,250 @@ + + + + + Java 3D API - Reusing Scene Graphs + + +

Reusing Scene Graphs

+

+Java 3D provides application programmers +with two different means for reusing scene graphs. First, multiple +scene graphs can share a common subgraph. Second, the node hierarchy of +a common subgraph can be cloned, while still sharing large component +objects such as geometry and texture objects. In the first case, +changes in the shared subgraph affect all scene graphs that refer to +the shared subgraph. In the second case, each instance is unique-a +change in one instance does not affect any other instance. +

+

Sharing Subgraphs

+

An application that wishes to share a subgraph from multiple places +in +a scene graph must do so through the use of the Link +leaf node and an +associated SharedGroup node. The +SharedGroup node serves as the root of +the shared subgraph. The Link leaf node refers to the SharedGroup node. +It does not incorporate the shared scene graph directly into its scene +graph. +

+

A SharedGroup node allows multiple Link leaf nodes to share its +subgraph as shown in Figure +1 below.
+

+

Sharing a Subgraph +

+
    + Figure 1 – Sharing a Subgraph +
+

Cloning Subgraphs

+

An application developer may wish to reuse a common subgraph without +completely sharing that subgraph. For example, the developer may wish +to create a parking lot scene consisting of multiple cars, each with a +different color. The developer might define three basic types of cars, +such as convertible, truck, and sedan. To create the parking lot scene, +the application will instantiate each type of car several times. Then +the application can change the color of the various instances to create +more variety in the scene. Unlike shared subgraphs, each instance is a +separate copy of the scene graph definition: Changes to one instance do +not affect any other instance. +

+

Java 3D provides the cloneTree +method for this +purpose. The cloneTree +method allows the programmer to change some attributes (NodeComponent +objects) in a scene graph, while at the same time sharing the majority +of the scene graph data-the geometry. +

+

References to Node Component +Objects

+

When cloneTree reaches a leaf node, +there are two possible actions for handling the leaf node's +NodeComponent objects (such as Material, Texture, and so forth). First, +the cloned leaf node can reference the original leaf node's +NodeComponent object-the NodeComponent object itself is not duplicated. +Since the cloned leaf node shares the NodeComponent object with the +original leaf node, changing the data in the NodeComponent object will +effect a change in both nodes. This mode would also be used for objects +that are read-only at run time. +

+

Alternatively, the NodeComponent object can be duplicated, in which +case the new leaf node would reference the duplicated object. This mode +allows data referenced by the newly created leaf node to be modified +without that modification affecting the original leaf node. +

+

Figure +2 +shows two instances of NodeComponent objects that are shared and one +NodeComponent element that is duplicated for the cloned subgraph. +

+

Referenced and Duplicated NodeComponent Objects +

+

+

+
    + Figure 2 – Referenced and Duplicated +NodeComponent Objects +
+

References to Other Scene +Graph Nodes

+Leaf nodes that contain references to other nodes +(for example, Light nodes reference a Group node) can create a problem +for the cloneTree method. After the cloneTree +operation is performed, the reference in the cloned leaf node will +still refer to the node in the original subgraph-a situation that is +most likely incorrect (see Figure +3). +

To handle these ambiguities, a callback mechanism is provided. +

+

References to Other Scene Graph Nodes +

+
    + Figure 3 – References to Other Scene Graph +Nodes +
+

+A leaf node that needs to update referenced nodes upon being duplicated +by a call to cloneTree must implement the updateNodeReferences +method. By using this method, the cloned leaf node can determine if any +nodes referenced by it have been duplicated and, if so, update the +appropriate references to their cloned counterparts. +

+

Suppose, for instance, that the leaf node Lf1 in Figure +3 implemented the updateNodeReferences method. Once +all nodes had been duplicated, the clone-Tree method +would then call each cloned leaf's node updateNodeReferences +method. When cloned leaf node Lf2's method was called, Lf2 could ask if +the node N1 had been duplicated during the cloneTree +operation. If the node had been duplicated, leaf Lf2 could then update +its internal state with the cloned node, N2 (see Figure +4). +

+

Updated Subgraph after updateNodeReferences Call +

+

+

+
    + Figure 4 – Updated Subgraph after +updateNodeReferences Call +
+

+All predefined Java 3D nodes will automatically have their updateNodeReferences +method defined. Only subclassed nodes that reference other nodes need +to have this method overridden by the user. +

+

Dangling References

+Because cloneTree is able to start +the cloning operation from any node, there is a potential for creating +dangling references. A dangling reference can occur only when a leaf +node that contains a reference to another scene graph node is cloned. +If the referenced node is not cloned, a dangling reference situation +exists: There are now two leaf nodes that access the same node (Figure +5). A dangling reference is discovered when a leaf node's updateNodeReferences +method calls the getNewNodeReference method and the +cloned subgraph does not contain a counterpart to the node being looked +up. +

Dangling Reference

+

+

+
    + Figure 5 – Dangling Reference: Bold Nodes +Are Being Cloned +
+

+When a dangling reference is discovered, cloneTree can +handle it in one of two ways. If cloneTree is called +without the allowDanglingReferences parameter set to true, +a dangling reference will result in a DanglingReferenceException +being thrown. The user can catch this exception if desired. If cloneTree +is called with the allowDanglingReferences parameter set +to true, the update-NodeReferences method +will return a reference to the same object passed into the getNewNodeReference +method. This will result in the cloneTree operation +completing with dangling references, as in Figure +5. +

+

Subclassing Nodes

+All Java 3D predefined nodes (for example, Interpolators and LOD +nodes) +automatically handle all node reference and duplication operations. +When a user subclasses a Leaf object or a NodeComponent object, certain +methods must be provided in order to ensure the proper operation of cloneTree. +

Leaf node subclasses (for example, Behaviors) that contain any user +node-specific data that needs to be duplicated during a cloneTree +operation must define the following two methods: +

+
Node cloneNode(boolean forceDuplicate);
void duplicateNode(Node n, boolean forceDuplicate)
+The cloneNode method consists of three lines: +


UserSubClass usc = new UserSubClass();
usc.duplicateNode(this, forceDuplicate);

return usc;


+The duplicateNode method must first call super.duplicateNode +before duplicating any necessary user-specific data or setting any +user-specific state. +

NodeComponent subclasses that contain any user node-specific data +must define the following two methods: +

+
NodeComponent cloneNodeComponent();
void duplicateNodeComponent(NodeComponent nc, boolean forceDuplicate);
+The cloneNodeComponent method consists of three lines: +


UserNodeComponent unc = new UserNodeComponent();
unc.duplicateNodeComponent(this, forceDuplicate);

return un;


+The duplicateNodeComponent must first call super.duplicateNodeComponent +and then can duplicate any user-specific data or set any user-specific +state as necessary. +

NodeReferenceTable Object

+The NodeReferenceTable object is used by a leaf node's updateNodeReferences +method called by the cloneTree +operation. The NodeReferenceTable maps nodes from the original subgraph +to the new nodes in the cloned subgraph. This information can than be +used to update any cloned leaf node references to reference nodes in +the cloned subgraph. This object can be created only by Java 3D. +

Example: User Behavior Node

+The following is an example of a user-defined Behavior object to show +properly how to define a node to be compatible with the cloneTree +operation. +
+
class RotationBehavior extends Behavior {
TransformGroup objectTransform;
WakeupOnElapsedFrames w;
+
    Matrix4d rotMat = new Matrix4d();
Matrix4d objectMat = new Matrix4d();
Transform3D t = new Transform3D();
+
    // Override Behavior's initialize method to set up wakeup
// criteria
+
    public void initialize() {
+
        // Establish initial wakeup criteria
+
        wakeupOn(w);
}
+
    // Override Behavior's stimulus method to handle the event
+
    public void processStimulus(Enumeration criteria) {
+
        // Rotate by another PI/120.0 radians
+
        objectMat.mul(objectMat, rotMat);
t.set(objectMat);
objectTransform.setTransform(t);
+
        // Set wakeup criteria for next time
+
        wakeupOn(w);
}
+
    // Constructor for rotation behavior.
+
    public RotationBehavior(TransformGroup tg, int numFrames) {
w = new WakeupOnElapsedFrames(numFrames);
objectTransform = tg;
+
        objectMat.setIdentity();
+
        // Create a rotation matrix that rotates PI/120.0
// radians per frame
rotMat.rotX(Math.PI/120.0);
+
        // Note: When this object is duplicated via cloneTree,
// the cloned RotationBehavior node needs to point to
// the TransformGroup in the just-cloned tree.
}
+
    // Sets a new TransformGroup.
+
    public void setTransformGroup(TransformGroup tg) {
objectTransform = tg;
+
    }
+
    // The next two methods are needed for cloneTree to operate
// correctly.
// cloneNode is needed to provide a new instance of the user
// derived subclass.
+
    public Node cloneNode(boolean forceDuplicate) {
+
        // Get all data from current node needed for
// the constructor
int numFrames = w.getElapsedFrameCount();
+
        RotationBehavior r =
new RotationBehavior(objectTransform, numFrames);
r.duplicateNode(this, forceDuplicate);
return r;
}
+
    // duplicateNode is needed to duplicate all super class
// data as well as all user data.
+
    public void duplicateNode(Node originalNode, boolean 
forceDuplicate) {
super.duplicateNode(originalNode, forceDuplicate);
+
        // Nothing to do here - all unique data was handled
// in the constructor in the cloneNode routine.
}
+
    // Callback for when this leaf is cloned. For this object
// we want to find the cloned TransformGroup node that this
// clone Leaf node should reference.
+
    public void updateNodeReferences(NodeReferenceTable t) {
+
        super.updateNodeReferences(t);
+
        // Update node's TransformGroup to proper reference
+
        TransformGroup newTg =
(TransformGroup)t.getNewObjectReference(
objectTransform);
setTransformGroup(newTg);
}
}
+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing1.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing1.gif new file mode 100644 index 0000000..f6ca47c Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing1.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing2.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing2.gif new file mode 100644 index 0000000..c062c81 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing2.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing3.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing3.gif new file mode 100644 index 0000000..325cab1 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing3.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing4.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing4.gif new file mode 100644 index 0000000..78aeaab Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing4.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing5.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing5.gif new file mode 100644 index 0000000..2ff6547 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/SceneGraphSharing5.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewBranch.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewBranch.gif new file mode 100644 index 0000000..75cc40d Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewBranch.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel.html new file mode 100644 index 0000000..3cc9ece --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel.html @@ -0,0 +1,1064 @@ + + + + + Java 3D API - View Model + + +

View Model

+

Java 3D introduces a new view model that takes Java's +vision of "write once, run anywhere" and generalizes it to include +display devices and six-degrees-of-freedom input peripherals such as +head trackers. This "write once, view everywhere" nature of the new +view model means that an application or applet written using the Java +3D view model can render images to a broad range of display devices, +including standard computer displays, multiple-projection display +rooms, and head-mounted displays, without modification of the scene +graph. It also means that the same application, once again without +modification, can render stereoscopic views and can take advantage of +the input from a head tracker to control the rendered view. +

+

Java 3D's view model achieves this versatility by cleanly +separating +the virtual and the physical world. This model distinguishes between +how an application positions, orients, and scales a ViewPlatform object +(a viewpoint) within the virtual world and how the Java 3D +renderer +constructs the final view from that viewpoint's position and +orientation. The application controls the ViewPlatform's position and +orientation; the renderer computes what view to render using this +position and orientation, a description of the end-user's physical +environment, and the user's position and orientation within the +physical environment. +

+

This document first explains why Java 3D chose a different view +model +and some of the philosophy behind that choice. It next describes how +that model operates in the simple case of a standard computer screen +without head tracking—the most common case. Finally, it presents +advanced material that was originally published in Appendix C of the +API specification guide. +

+

+

+

Why a New Model?

+

Camera-based view models, as found in low-level APIs, give +developers +control over all rendering parameters. This makes sense when dealing +with custom applications, less sense when dealing with systems that +wish to have broader applicability: systems such as viewers or browsers +that load and display whole worlds as a single unit or systems where +the end users view, navigate, display, and even interact with the +virtual world. +

+

Camera-based view models emulate a camera in the virtual world, not +a +human in a virtual world. Developers must continuously reposition a +camera to emulate "a human in the virtual world." +

+

The Java 3D view model incorporates head tracking directly, if +present, +with no additional effort from the developer, thus providing end users +with the illusion that they actually exist inside a virtual world. +

+

The Java 3D view model, when operating in a non-head-tracked +environment and rendering to a single, standard display, acts very much +like a traditional camera-based view model, with the added +functionality of being able to generate stereo views transparently. +

+

+

+

The Physical Environment +Influences the View

+

Letting the application control all viewing parameters is not +reasonable in systems in which the physical environment dictates some +of the view parameters. +

+

One example of this is a head-mounted display (HMD), where the +optics +of the head-mounted display directly determine the field of view that +the application should use. Different HMDs have different optics, +making it unreasonable for application developers to hard-wire such +parameters or to allow end users to vary that parameter at will. +

+

Another example is a system that automatically computes view +parameters +as a function of the user's current head position. The specification of +a world and a predefined flight path through that world may not exactly +specify an end-user's view. HMD users would expect to look and thus see +to their left or right even when following a fixed path through the +environment-imagine an amusement park ride with vehicles that follow +fixed paths to present content to their visitors, but visitors can +continue to move their heads while on those rides. +

+

Depending on the physical details of the end-user's environment, the +values of the viewing parameters, particularly the viewing and +projection matrices, will vary widely. The factors that influence the +viewing and projection matrices include the size of the physical +display, how the display is mounted (on the user's head or on a table), +whether the computer knows the user's head location in three space, the +head mount's actual field of view, the display's pixels per inch, and +other such parameters. For more information, see "View Model Details." +

+

+

+

Separation of Physical and +Virtual

+

The Java 3D view model separates the virtual environment, where +the +application programmer has placed objects in relation to one another, +from the physical environment, where the user exists, sees computer +displays, and manipulates input devices. +

+

Java 3D also defines a fundamental correspondence between the +user's +physical world and the virtual world of the graphic application. This +physical-to-virtual-world correspondence defines a single common space, +a space where an action taken by an end user affects objects within the +virtual world and where any activity by objects in the virtual world +affects the end user's view. +

+

+

+

The Virtual World

+

The virtual world is a common space in which virtual objects exist. +The +virtual world coordinate system exists relative to a high-resolution +Locale-each Locale object defines the origin of virtual world +coordinates for all of the objects attached to that Locale. The Locale +that contains the currently active ViewPlatform object defines the +virtual world coordinates that are used for rendering. Java3D +eventually transforms all coordinates associated with scene graph +elements into this common virtual world space. +

+

The Physical World

+

The physical world is just that-the real, physical world. This is +the +space in which the physical user exists and within which he or she +moves his or her head and hands. This is the space in which any +physical trackers define their local coordinates and in which several +calibration coordinate systems are described. +

+

The physical world is a space, not a common coordinate system +between +different execution instances of Java 3D. So while two different +computers at two different physical locations on the globe may be +running at the same time, there is no mechanism directly within +Java 3D +to relate their local physical world coordinate systems with each +other. Because of calibration issues, the local tracker (if any) +defines the local physical world coordinate system known to a +particular instance of Java 3D. +

+

+

+

The Objects That Define the +View

+

Java 3D distributes its view model parameters across several +objects, +specifically, the View object and its associated component objects, the +PhysicalBody object, the PhysicalEnvironment object, the Canvas3D +object, and the Screen3D object. Figure +1 shows graphically the central role of the View object and the +subsidiary role of its component objects. +

+

View Object + Other Components

+

+

+
    + Figure 1 – View Object, Its Component +Objects, and Their +Interconnection +
+

+The view-related objects shown in Figure +1 +and their roles are as follows. For each of these objects, the portion +of the API that relates to modifying the virtual world and the portion +of the API that is relevant to non-head-tracked standard display +configurations are derived in this chapter. The remainder of the +details are described in "View Model +Details." +

+ +
    +
  • View: The main view object. +It contains many pieces of +view state.
  • +
+
    +
  • Canvas3D: The 3D version +of the Abstract Windowing +Toolkit +(AWT) Canvas object. It represents a window in which Java 3D will +draw +images. It contains a reference to a Screen3D object and information +describing the Canvas3D's size, shape, and location within the Screen3D +object.
  • +
+
    +
  • Screen3D: An object that +contains information describing +the display screen's physical properties. Java 3D places +display-screen +information in a separate object to prevent the duplication of screen +information within every Canvas3D object that shares a common screen.
  • +
+
    +
  • PhysicalBody: An object that +contains calibration information +describing the user's physical body.
  • +
+
    +
  • PhysicalEnvironment: An +object that contains calibration +information describing the physical world, mainly information that +describes the environment's six-degrees-of freedom tracking hardware, +if present.
  • +
+

Together, these objects describe the geometry of viewing rather than +explicitly providing a viewing or projection matrix. The Java 3D +renderer uses this information to construct the appropriate viewing and +projection matrices. The geometric focus of these view objects provides +more flexibility in generating views-a flexibility needed to support +alternative display configurations. +

+

ViewPlatform: A Place in the +Virtual World

+

A ViewPlatform leaf node defines a coordinate system, and thus a +reference frame with its associated origin or reference point, within +the virtual world. The ViewPlatform serves as a point of attachment for +View objects and as a base for determining a renderer's view. +

+

Figure +2 +shows a portion of a scene graph containing a ViewPlatform node. The +nodes directly above a ViewPlatform determine where that ViewPlatform +is located and how it is oriented within the virtual world. By +modifying the Transform3D object associated with a TransformGroup node +anywhere directly above a ViewPlatform, an application or behavior can +move that ViewPlatform anywhere within the virtual world. A simple +application might define one TransformGroup node directly above a +ViewPlatform, as shown in Figure +2. +

+

A VirtualUniverse may have many different ViewPlatforms, but a +particular View object can attach itself only to a single ViewPlatform. +Thus, each rendering onto a Canvas3D is done from the point of view of +a single ViewPlatform. +

+

View Platform Branch Graph +

+

+

+
    + Figure 2 – A Portion of a Scene Graph +Containing a ViewPlatform Object +
+

+

+

Moving through the Virtual +World

+

An application navigates within the virtual world by modifying a +ViewPlatform's parent TransformGroup. Examples of applications that +modify a ViewPlatform's location and orientation include browsers, +object viewers that provide navigational controls, applications that do +architectural walkthroughs, and even search-and-destroy games. +

+

Controlling the ViewPlatform object can produce very interesting and +useful results. Our first simple scene graph (see "Introduction," Figure 1) +defines a scene graph for a simple application that draws an object in +the center of a window and rotates that object about its center point. +In that figure, the Behavior object modifies the TransformGroup +directly above the Shape3D node. +

+

An alternative application scene graph, shown in Figure +3, +leaves the central object alone and moves the ViewPlatform around the +world. If the shape node contains a model of the earth, this +application could generate a view similar to that seen by astronauts as +they orbit the earth. +

+

Had we populated this world with more objects, this scene graph +would allow navigation through the world via the Behavior node. +

+

Simple Scene Graph with View Control +

+

+

+
    + Figure 3 – A Simple Scene Graph with View +Control +
+

+Applications and behaviors manipulate a TransformGroup through its +access methods. These methods allow an application to retrieve and +set the Group node's Transform3D object. Transform3D Node methods +include getTransform and setTransform. +

+

+

+

Dropping in on a Favorite +Place

+

A scene graph may contain multiple ViewPlatform +objects. If a user detaches a View object +from a ViewPlatform and then +reattaches that View to a different ViewPlatform, the image on the +display will now be rendered from the point of view of the new +ViewPlatform.

+

Associating Geometry with a +ViewPlatform

+

Java 3D does not have any built-in semantics for displaying a +visible +manifestation of a ViewPlatform within the virtual world (an avatar). +However, a developer can construct and manipulate an avatar using +standard Java 3D constructs. +

+

A developer can construct a small scene graph consisting of a +TransformGroup node, a behavior leaf node, and a shape node and insert +it directly under the BranchGroup node associated with the ViewPlatform +object. The shape node would contain a geometric model of the avatar's +head. The behavior node would change the TransformGroup's transform +periodically to the value stored in a View object's UserHeadToVworld +parameter (see "View Model +Details"). +The avatar's virtual head, represented by the shape node, will now move +around in lock-step with the ViewPlatform's TransformGroup and any +relative position and orientation changes of the user's actual physical +head (if a system has a head tracker). +

+

+

+

Generating a View

+

Java 3D generates viewing matrices in one of a few different +ways, +depending on whether the end user has a head-mounted or a room-mounted +display environment and whether head tracking is enabled. This section +describes the computation for a non-head-tracked, room-mounted +display-a standard computer display. Other environments are described +in "View Model Details." +

+

In the absence of head tracking, the ViewPlatform's origin specifies +the virtual eye's location and orientation within the virtual world. +However, the eye location provides only part of the information needed +to render an image. The renderer also needs a projection matrix. In the +default mode, Java 3D uses the projection policy, the specified +field-of-view information, and the front and back clipping distances to +construct a viewing frustum. +

+

+

+

Composing Model and Viewing +Transformations

+

Figure +4 +shows a simple scene graph. To draw the object labeled "S," +Java 3D +internally constructs the appropriate model, view platform, eye, and +projection matrices. Conceptually, the model transformation for a +particular object is computed by concatenating all the matrices in a +direct path between the object and the VirtualUniverse. The view matrix +is then computed-again, conceptually-by concatenating all the matrices +between the VirtualUniverse object and the ViewPlatform attached to the +current View object. The eye and projection matrices are constructed +from the View object and its associated component objects. +

+

Object and ViewPlatform Transform

+

+

+
    + Figure 4 – Object and ViewPlatform +Transformations +
+

In our scene graph, what we would normally consider the +model transformation would consist of the following three +transformations: LT1T2. By +multiplying LT1T2 +by a vertex in the shape object, we would transform that vertex into +the virtual universe's coordinate system. What we would normally +consider the view platform transformation would be (LTv1)-1 +or Tv1-1L-1. +This presents a problem since coordinates in the virtual universe are +256-bit fixed-point values, which cannot be used to represent +transformed points efficiently. +

+

Fortunately, however, there is a solution to this problem. Composing +the model and view platform transformations gives us +

+
+

+
+
Tv1-1L-1LT1T2 += Tv1-1IT1T2 += Tv1-1T1T2, +
+
+

the matrix that takes vertices in an object's local coordinate +system +and places them in the ViewPlatform's coordinate system. Note that the +high-resolution Locale transformations cancel each other out, which +removes the need to actually transform points into high-resolution +VirtualUniverse coordinates. The general formula of the matrix that +transforms object coordinates to ViewPlatform coordinates is Tvn-1...Tv2-1Tv1-1T1T2...Tm. +

+

As mentioned earlier, the View object contains the remainder of the +view information, specifically, the eye matrix, E, +that takes points in the View-Platform's local coordinate system and +translates them into the user's eye coordinate system, and the +projection matrix, P, that projects objects in the +eye's coordinate system into clipping coordinates. The final +concatenation of matrices for rendering our shape object "S" on the +specified Canvas3D is PETv1-1T1T2. +In general this is PETvn-1...Tv2-1Tv1-1T1T2...Tm. +

+

The details of how Java 3D constructs the matrices E +and P in different end-user configurations are +described in "View Model Details." +

+

+

+

Multiple Locales

+

Java 3D supports multiple high-resolution Locales. In some +cases, +these +Locales are close enough to each other that they can "see" each other, +meaning that objects can be rendered even though they are not in the +same Locale as the ViewPlatform object that is attached to the View. +Java 3D automatically handles this case without the application +having +to do anything. As in the previous example, where the ViewPlatform and +the object being rendered are attached to the same Locale, Java 3D +internally constructs the appropriate matrices for cases in which the +ViewPlatform and the object being rendered are not attached +to the same Locale. +

+

Let's take two Locales, L1 and L2, with the View attached to a +ViewPlatform in L1. According to our general formula, the modeling +transformation-the transformation that takes points in object +coordinates and transforms them into VirtualUniverse coordinates-is LT1T2...Tm. +In our specific example, a point in Locale L2 would be transformed into +VirtualUniverse coordinates by L2T1T2...Tm. +The view platform transformation would be (L1Tv1Tv1...Tvn)-1 +or Tvn-1...Tv2-1Tv1-1L1-1. +Composing these two matrices gives us +

+
+

+
+
Tvn-1...Tv2-1Tv1-1L1-1L2T1T2...Tm. +
+
+

Thus, to render objects in another Locale, it is sufficient to +compute L1-1L2 +and use that as the starting matrix when composing the model +transformations. Given that a Locale is represented by a single +high-resolution coordinate position, the transformation L1-1L2 +is a simple translation by L2 - L1. +Again, it is not actually necessary to transform points into +high-resolution VirtualUniverse coordinates. +

+

In general, Locales that are close enough that the difference in +their +high-resolution coordinates can be represented in double precision by a +noninfinite value are close enough to be rendered. In practice, more +sophisticated culling techniques can be used to render only those +Locales that really are "close enough." +

+

+

+

A Minimal Environment

+

An application must create a minimal set of Java 3D objects +before +Java +3D can render to a display device. In addition to a Canvas3D object, +the application must create a View object, with its associated +PhysicalBody and PhysicalEnvironment objects, and the following scene +graph elements: +

+
    +
  • A VirtualUniverse object
  • +
+
    +
  • A high-resolution Locale object
  • +
+
    +
  • A BranchGroup node object
  • +
+
    +
  • A TransformGroup node object with associated transform
  • +
+
    +
  • A ViewPlatform leaf node object that defines the position and +orientation within the virtual universe for generating views
  • +
+
+

View Model Details

+

An application programmer writing a 3D +graphics program that will deploy on a variety of platforms must +anticipate the likely end-user environments and must carefully +construct the view transformations to match those characteristics using +a low-level API. This appendix addresses many of the issues an +application must face and describes the sophisticated features that +Java 3D's advanced view model provides. +

+

+

+

An Overview of the +Java 3D +View Model

+Both camera-based and Java 3D-based view models allow a programmer +to +specify the shape of a view frustum and, under program control, to +place, move, and reorient that frustum within the virtual environment. +However, how they do this varies enormously. Unlike the camera-based +system, the Java 3D view model allows slaving the view frustum's +position and orientation to that of a six-degrees-of-freedom tracking +device. By slaving the frustum to the tracker, Java 3D can +automatically modify the view frustum so that the generated images +match the end-user's viewpoint exactly. +

Java 3D must handle two rather different head-tracking +situations. +In one case, we rigidly attach a tracker's base, +and thus its coordinate frame, to the display environment. This +corresponds to placing a tracker base in a fixed position and +orientation relative to a projection screen within a room, to a +computer display on a desk, or to the walls of a multiple-wall +projection display. In the second head-tracking situation, we rigidly +attach a tracker's sensor, not its base, to the display +device. This corresponds to rigidly attaching one of that tracker's +sensors to a head-mounted display and placing the tracker base +somewhere within the physical environment. +

+

+

+

Physical Environments and +Their Effects

+Imagine an application where the end user sits on a magic carpet. The +application flies the user through the virtual environment by +controlling the carpet's location and orientation within the virtual +world. At first glance, it might seem that the application also +controls what the end user will see-and it does, but only +superficially. +

The following two examples show how end-user environments can +significantly affect how an application must construct viewing +transformations. +

+

+

+

A Head-Mounted Example

+Imagine that the end user sees the magic carpet and the virtual world +with a head-mounted display and head tracker. As the application flies +the carpet through the virtual world, the user may turn to look to the +left, to the right, or even toward the rear of the carpet. Because the +head tracker keeps the renderer informed of the user's gaze direction, +it might not need to draw the scene directly in front of the magic +carpet. The view that the renderer draws on the head-mount's display +must match what the end user would see if the experience had occurred +in the real world. +

A Room-Mounted Example

+Imagine a slightly different scenario where the end user sits in a +darkened room in front of a large projection screen. The application +still controls the carpet's flight path; however, the position and +orientation of the user's head barely influences the image drawn on the +projection screen. If a user looks left or right, then he or she sees +only the darkened room. The screen does not move. It's as if the screen +represents the magic carpet's "front window" and the darkened room +represents the "dark interior" of the carpet. +

By adding a left and right screen, we give the magic carpet rider a +more complete view of the virtual world surrounding the carpet. Now our +end user sees the view to the left or right of the magic carpet by +turning left or right. +

+

+

+

Impact of Head Position and +Orientation on the Camera

+In the head-mounted example, the user's head position and orientation +significantly affects a camera model's camera position and orientation +but hardly has any effect on the projection matrix. In the room-mounted +example, the user's head position and orientation contributes little to +a camera model's camera position and orientation; however, it does +affect the projection matrix. +

From a camera-based perspective, the application developer must +construct the camera's position and orientation by combining the +virtual-world component (the position and orientation of the magic +carpet) and the physical-world component (the user's instantaneous head +position and orientation). +

+

Java 3D's view model incorporates the appropriate abstractions +to +compensate automatically for such variability in end-user hardware +environments. +

+

+

+

The Coordinate Systems

+The basic view model consists of eight or nine coordinate systems, +depending on whether the end-user environment consists of a +room-mounted display or a head-mounted display. First, we define the +coordinate systems used in a room-mounted display environment. Next, we +define the added coordinate system introduced when using a head-mounted +display system. +

Room-Mounted Coordinate +Systems

+The room-mounted coordinate system is divided into the virtual +coordinate system and the physical coordinate system. Figure +5 +shows these coordinate systems graphically. The coordinate systems +within the grayed area exist in the virtual world; those outside exist +in the physical world. Note that the coexistence coordinate system +exists in both worlds. +

The Virtual Coordinate +Systems

+
The Virtual World Coordinate System
+The virtual world coordinate system encapsulates +the unified coordinate system for all scene graph objects in the +virtual environment. For a given View, the virtual world coordinate +system is defined by the Locale object that contains the ViewPlatform +object attached to the View. It is a right-handed coordinate system +with +x to the right, +y up, and +z toward +the viewer. +
The ViewPlatform Coordinate System
+The ViewPlatform coordinate system is the local coordinate system of +the ViewPlatform leaf node to which the View is attached. +

Display Rigidly Attached to Tracker Base

+

+

+
    + Figure 5 – Display Rigidly Attached to the +Tracker Base +
+

+

+
The Coexistence Coordinate System
+A primary implicit goal of any view model is to map a specified local +portion of the physical world onto a specified portion of the virtual +world. Once established, one can legitimately ask where the user's head +or hand is located within the virtual world or where a virtual object +is located in the local physical world. In this way the physical user +can interact with objects inhabiting the virtual world, and vice versa. +To establish this mapping, Java 3D defines a special coordinate +system, +called coexistence coordinates, that is defined to exist in both the +physical world and the virtual world. +

The coexistence coordinate system exists half in the virtual world +and +half in the physical world. The two transforms that go from the +coexistence coordinate system to the virtual world coordinate system +and back again contain all the information needed to expand or shrink +the virtual world relative to the physical world. It also contains the +information needed to position and orient the virtual world relative to +the physical world. +

+

Modifying the transform that maps the coexistence coordinate system +into the virtual world coordinate system changes what the end user can +see. The Java 3D application programmer moves the end user within +the +virtual world by modifying this transform. +

+

+

+

The Physical Coordinate +Systems

+
The Head Coordinate System
+The head coordinate system allows an application to import its user's +head geometry. The coordinate system provides a simple consistent +coordinate frame for specifying such factors as the location of the +eyes and ears. +
The Image Plate Coordinate System
+The image plate coordinate system corresponds with the physical +coordinate system of the image generator. The image plate is defined as +having its origin at the lower left-hand corner of the display area and +as lying in the display area's XY +plane. Note that image plate is a different coordinate system than +either left image plate or right image plate. These last two coordinate +systems are defined in head-mounted environments only. +
The Head Tracker Coordinate System
+The head tracker coordinate system corresponds to the +six-degrees-of-freedom tracker's sensor attached to the user's head. +The head tracker's coordinate system describes the user's instantaneous +head position. +
The Tracker Base Coordinate System
+The tracker base coordinate system corresponds to the emitter +associated with absolute position/orientation trackers. For those +trackers that generate relative position/orientation information, this +coordinate system is that tracker's initial position and orientation. +In general, this coordinate system is rigidly attached to the physical +world. +

Head-Mounted Coordinate +Systems

+Head-mounted coordinate systems divide the same virtual coordinate +systems and the physical coordinate systems. Figure +6 +shows these coordinate systems graphically. As with the room-mounted +coordinate systems, the coordinate systems within the grayed area exist +in the virtual world; those outside exist in the physical world. Once +again, the coexistence coordinate system exists in both worlds. The +arrangement of the coordinate system differs from those for a +room-mounted display environment. The head-mounted version of +Java 3D's +coordinate system differs in another way. It includes two image plate +coordinate systems, one for each of an end-user's eyes. +
The Left Image Plate and Right Image Plate Coordinate Systems
+The left image plate and right image plate +coordinate systems correspond with the physical coordinate system of +the image generator associated with the left and right eye, +respectively. The image plate is defined as having its origin at the +lower left-hand corner of the display area and lying in the display +area's XY plane. Note that the left image plate's XY +plane does not necessarily lie parallel to the right image plate's XY +plane. Note that the left image plate and the right image plate are +different coordinate systems than the room-mounted display +environment's image plate coordinate system. +

Display Rigidly Attached to Head Tracker

+

+

+
    + Figure 6 – Display Rigidly Attached to the +Head Tracker (Sensor) +
+

+

+

The Screen3D Object

+A Screen3D object represents one independent display device. The most +common environment for a Java 3D application is a desktop computer +with +or without a head tracker. Figure +7 shows a scene graph fragment for a display environment designed +for such an end-user environment. Figure +8 shows a display environment that matches the scene graph +fragment in Figure +7. +

Environment with Single Screen3D Object

+

+

+
    + Figure 7 – A Portion of a Scene Graph +Containing a Single Screen3D +Object +
+

+Single-Screen Display Environment

+

+

+
    + Figure 8 – A Single-Screen Display +Environment +
+

+A multiple-projection wall display presents a more exotic environment. +Such environments have multiple screens, typically three or more. Figure +9 shows a scene graph fragment representing such a system, and Figure +10 shows the corresponding display environment. +

+

Environment with Three Screen3D Object +

+

+

+
    + Figure 9 – A Portion of a Scene Graph +Containing Three Screen3D +Objects +
+

+Three-Screen Display Environment

+

+

+
    + Figure 10 – A Three-Screen Display +Environment +
+

+A multiple-screen environment requires more care during the +initialization and calibration phase. Java 3D must know how the +Screen3Ds are placed with respect to one another, the tracking device, +and the physical portion of the coexistence coordinate system. +

+

+

+

Viewing in Head-Tracked Environments

+

The "Generating a View" section +describes how Java 3D generates a view for a standard flat-screen +display with no head tracking. In this section, we describe how +Java 3D +generates a view in a room-mounted, head-tracked display +environment-either a computer monitor with shutter glasses and head +tracking or a multiple-wall display with head-tracked shutter glasses. +Finally, we describe how Java 3D generates view matrices in a +head-mounted and head-tracked display environment. +

+

A Room-Mounted Display with +Head Tracking

+When head tracking combines with a room-mounted +display environment (for example, a standard flat-screen display), the +ViewPlatform's origin and orientation serve as a base for constructing +the view matrices. Additionally, Java 3D uses the end-user's head +position and orientation to compute where an end-user's eyes are +located in physical space. Each eye's position serves to offset the +corresponding virtual eye's position relative to the ViewPlatform's +origin. Each eye's position also serves to specify that eye's frustum +since the eye's position relative to a Screen3D uniquely specifies that +eye's view frustum. Note that Java 3D will access the PhysicalBody +object to obtain information describing the user's interpupilary +distance and tracking hardware, values it needs to compute the +end-user's eye positions from the head position information. +

A Head-Mounted Display with +Head Tracking

+In a head-mounted environment, the ViewPlatform's origin and +orientation also serves as a base for constructing view matrices. And, +as in the head-tracked, room-mounted environment, Java 3D also +uses the +end-user's head position and orientation to modify the ViewPlatform's +position and orientation further. In a head-tracked, head-mounted +display environment, an end-user's eyes do not move relative to their +respective display screens, rather, the display screens move relative +to the virtual environment. A rotation of the head by an end user can +radically affect the final view's orientation. In this situation, Java +3D combines the position and orientation from the ViewPlatform with the +position and orientation from the head tracker to form the view matrix. +The view frustum, however, does not change since the user's eyes do not +move relative to their respective display screen, so Java 3D can +compute the projection matrix once and cache the result. +

If any of the parameters of a View object are updated, this will +effect +a change in the implicit viewing transform (and thus image) of any +Canvas3D that references that View object. +

+

+

+

Compatibility Mode

+

A camera-based view model allows application programmers to think +about +the images displayed on the computer screen as if a virtual camera took +those images. Such a view model allows application programmers to +position and orient a virtual camera within a virtual scene, to +manipulate some parameters of the virtual camera's lens (specify its +field of view), and to specify the locations of the near and far +clipping planes. +

+

Java 3D allows applications to enable compatibility mode for +room-mounted, non-head-tracked display environments or to disable +compatibility mode using the following methods. Camera-based viewing +functions are available only in compatibility mode. The setCompatibilityModeEnable +method turns compatibility mode on or off. Compatibility mode is +disabled by default. +

+
+

Note: Use of these view-compatibility +functions will disable some of Java 3D's view model features and +limit +the portability of Java 3D programs. These methods are primarily +intended to help jump-start porting of existing applications. +

+
+

Overview of the +Camera-Based View Model

+The traditional camera-based view model, shown in Figure +11, +places a virtual camera inside a geometrically specified world. The +camera "captures" the view from its current location, orientation, and +perspective. The visualization system then draws that view on the +user's display device. The application controls the view by moving the +virtual camera to a new location, by changing its orientation, by +changing its field of view, or by controlling some other camera +parameter. +

The various parameters that users control in a +camera-based view model specify the shape of a viewing volume (known as +a frustum because of its truncated pyramidal shape) and locate that +frustum within the virtual environment. The rendering pipeline uses the +frustum to decide which objects to draw on the display screen. The +rendering pipeline does not draw objects outside the view frustum, and +it clips (partially draws) objects that intersect the frustum's +boundaries. +

+

Though a view frustum's specification may have many items in common +with those of a physical camera, such as placement, orientation, and +lens settings, some frustum parameters have no physical analog. Most +noticeably, a frustum has two parameters not found on a physical +camera: the near and far clipping planes. +

+

Camera-Based View Model +

+

+

+
    + Figure 11 – The Camera-Based View Model +
+

+The location of the near and far clipping planes allows the application +programmer to specify which objects Java 3D should not draw. +Objects +too far away from the current eyepoint usually do not result in +interesting images. Those too close to the eyepoint might obscure the +interesting objects. By carefully specifying near and far clipping +planes, an application programmer can control which objects the +renderer will not be drawing. +

+

From the perspective of the display device, the virtual camera's +image +plane corresponds to the display screen. The camera's placement, +orientation, and field of view determine the shape of the view frustum. +

+

+

+

Using the Camera-Based View +Model

+

The camera-based view model allows Java 3D to bridge the gap +between +existing 3D code and Java 3D's view model. By using the +camera-based +view model methods, a programmer retains the familiarity of the older +view model but gains some of the flexibility afforded by Java 3D's +new +view model. +

+

The traditional camera-based view model is supported in Java 3D +by +helping methods in the Transform3D object. These methods were +explicitly designed to resemble as closely as possible the view +functions of older packages and thus should be familiar to most 3D +programmers. The resulting Transform3D objects can be used to set +compatibility-mode transforms in the View object. +

+

+

+

Creating a Viewing Matrix

+

The Transform3D object provides a lookAt utility +method +to create a +viewing matrix. This method specifies the position and orientation of +a viewing transform. It works similarly to the equivalent function in +OpenGL. The inverse of this transform can be used to control the +ViewPlatform object within the scene graph. Alternatively, this +transform can be passed directly to the View's VpcToEc +transform via the compatibility-mode viewing functions. The setVpcToEc +method is used to set the viewing matrix when in compatibility mode. +

+

Creating a Projection +Matrix

+

The Transform3D object provides three methods for +creating a projection matrix: frustum, perspective, +and ortho. All three map points from eye coordinates +(EC) to clipping coordinates (CC). Eye coordinates are defined such +that (0, 0, 0) is at the eye and the projection plane is at z += -1.
+

+

The frustum method +establishes a perspective projection with the eye at the apex of a +symmetric view frustum. The transform maps points from eye coordinates +to clipping coordinates. The clipping coordinates generated by the +resulting transform are in a right-handed coordinate system (as are all +other coordinate systems in Java 3D). +

+

The arguments define the frustum and its associated perspective +projection: (left, bottom, -near) +and (right, top, -near) +specify the point on the near clipping plane that maps onto the +lower-left and upper-right corners of the window, respectively. The -far +parameter specifies the far clipping plane. See Figure +12. +

+

The perspective method establishes a perspective +projection with the eye at the apex of a symmetric view frustum, +centered about the Z-axis, +with a fixed field of view. The resulting perspective projection +transform mimics a standard camera-based view model. The transform maps +points from eye coordinates to clipping coordinates. The clipping +coordinates generated by the resulting transform are in a right-handed +coordinate system. +

+

The arguments define the frustum and its associated perspective +projection: -near and -far specify the near +and far clipping planes; fovx specifies the field of view +in the X dimension, in radians; and aspect +specifies the aspect ratio of the window. See Figure +13. +

+

Perspective Viewing Frustum +

+

+

+
    + Figure 12 – A Perspective Viewing Frustum +
+

+Perspective View Model Arguments

+

+

+
    + Figure 13 – Perspective View Model Arguments +
+

+The ortho method +establishes a parallel projection. The orthographic projection +transform mimics a standard camera-based video model. The transform +maps points from eye coordinates to clipping coordinates. The clipping +coordinates generated by the resulting transform are in a right-handed +coordinate system. +

+

The arguments define a rectangular box used for projection: (left, +bottom, -near) and (right, top, +-near) +specify the point on the near clipping plane that maps onto the +lower-left and upper-right corners of the window, respectively. The -far +parameter specifies the far clipping plane. See Figure +14. +

+

Orthographic View Model +

+

+

+
    + Figure 14 – Orthographic View Model +
+

+

+

The setLeftProjection +and setRightProjection methods are used to set the +projection matrices for the left eye and right eye, respectively, when +in compatibility mode.

+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel1.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel1.gif new file mode 100644 index 0000000..e94743e Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel1.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel10.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel10.gif new file mode 100644 index 0000000..aceb6e7 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel10.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel11.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel11.gif new file mode 100644 index 0000000..f943c15 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel11.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel12.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel12.gif new file mode 100644 index 0000000..787afe7 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel12.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel13.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel13.gif new file mode 100644 index 0000000..a8482ef Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel13.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel14.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel14.gif new file mode 100644 index 0000000..f201443 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel14.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel2.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel2.gif new file mode 100644 index 0000000..2d549b1 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel2.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel3.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel3.gif new file mode 100644 index 0000000..5285015 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel3.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel4.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel4.gif new file mode 100644 index 0000000..ab9db1d Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel4.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel5.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel5.gif new file mode 100644 index 0000000..859b456 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel5.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel6.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel6.gif new file mode 100644 index 0000000..2200595 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel6.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel7.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel7.gif new file mode 100644 index 0000000..ec84ac2 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel7.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel8.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel8.gif new file mode 100644 index 0000000..ee4b331 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel8.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel9.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel9.gif new file mode 100644 index 0000000..0cbf72c Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/ViewModel9.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/VirtualUniverse.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/VirtualUniverse.gif new file mode 100644 index 0000000..4d713a8 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/VirtualUniverse.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/VirtualUniverse.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/VirtualUniverse.html new file mode 100644 index 0000000..2f9dd14 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/VirtualUniverse.html @@ -0,0 +1,265 @@ + + + + + Java 3D API - Scene Graph Superstructure + + +

Scene Graph Superstructure

+

Java 3D's superstructure consists of one or more +VirtualUniverse objects, each of which contains a set of one or more +high-resolution Locale objects. The Locale objects, in turn, contain +collections of subgraphs that comprise the scene graph (see Figure +1). +

+

+

+

The Virtual Universe

+Java 3D defines the concept of a virtual universe +as a three-dimensional space with an associated set of objects. Virtual +universes serve as the largest unit of aggregate representation, and +can also be thought of as databases. Virtual universes can be very +large, both in physical space units and in content. Indeed, in most +cases a single virtual universe will serve an application's entire +needs. +

Virtual universes are separate entities in that no node object may +exist in more than one virtual universe at any one time. Likewise, the +objects in one virtual universe are not visible in, nor do they +interact with objects in, any other virtual universe. +

+

To support large virtual universes, Java 3D introduces the concept +of Locales that have high-resolution coordinates +as an origin. Think of high-resolution coordinates as "tie-downs" that +precisely anchor the locations of objects specified using less precise +floating-point coordinates that are within the range of influence of +the high-resolution coordinates. +

+

A Locale, with its associated high-resolution coordinates, serves as +the next level of representation down from a virtual universe. All +virtual universes contain one or more high-resolution-coordinate +Locales, and all other objects are attached to a Locale. +High-resolution coordinates act as an upper-level translation-only +transform node. For example, the coordinates of all objects that are +attached to a particular Locale are all relative to the location of +that Locale's high-resolution coordinates. +

+

The Virtual Universe +

+

+

+
    + Figure 1 – The Virtual Universe +
+

+While a virtual universe is similar to the traditional computer +graphics concept of a scene graph, a given virtual universe can become +so large that it is often better to think of a scene graph as the +descendant of a high-resolution-coordinate Locale. +

+

+

+

Establishing a Scene

+To construct a three-dimensional scene, the programmer must execute a +Java 3D program. The Java 3D application must first create a +VirtualUniverse object and attach at least one Locale to it. Then the +desired scene graph is constructed, starting with a BranchGroup node +and including at least one ViewPlatform object, and the scene graph is +attached to the Locale. Finally, a View object that references the +ViewPlatform object (see "Structuring +the Java 3D Program") +is constructed. As soon as a scene graph containing a ViewPlatform is +attached to the VirtualUniverse, Java 3D's rendering loop is engaged, +and the scene will appear on the drawing canvas(es) associated with the +View object. +

Loading a Virtual Universe

+Java 3D is a runtime application programming +interface (API), not a file format. As an API, Java 3D provides no +direct mechanism for loading or storing a virtual universe. +Constructing a scene graph involves the execution of a Java 3D program. +However, loaders to convert a number of standard 3D file formats to or +from Java 3D virtual universes are expected to be generally available. +

Coordinate Systems

+By default, Java 3D coordinate systems are right-handed, with the +orientation semantics being that +y is the local gravitational +up, +x is horizontal to the right, and +z is directly +toward the viewer. The default units are meters. +

High-Resolution Coordinates

+Double-precision floating-point, single-precision floating-point, or +even fixed-point representations of three-dimensional coordinates are +sufficient to represent and display rich 3D scenes. Unfortunately, +scenes are not worlds, let alone universes. If one ventures even a +hundred miles away from the (0.0, 0.0, 0.0) origin using only +single-precision floating-point coordinates, representable points +become quite quantized, to at very best a third of an inch (and much +more coarsely than that in practice). +

To "shrink" down to a small size (say the size of an IC transistor), +even very near (0.0, 0.0, 0.0), the same problem arises. +

+

If a large contiguous virtual universe is to be supported, some form +of +higher-resolution addressing is required. Thus the choice of 256-bit +positional components for "high-resolution" positions. +

+

+

+

Java 3D High-Resolution +Coordinates

+Java 3D high-resolution coordinates consist of three 256-bit +fixed-point numbers, one each for x, y, and z. +The fixed point is at bit 128, and the value 1.0 is defined to be +exactly 1 meter. This coordinate system is sufficient to describe a +universe in excess of several hundred billion light years across, yet +still define objects smaller than a proton (down to below the planck +length). Table +1 shows how many bits are needed above or below the fixed point +to represent the range of interesting physical dimensions. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1 – +Java 3D High-Resolution Coordinates
2n Meters Units
87.29Universe (20 billion light years) 
+
69.68Galaxy (100,000 light years)
53.07Light year
43.43Solar system diameter
23.60Earth diameter
10.65Mile
9.97Kilometer
0.00Meter
-19.93Micron
-33.22Angstrom
-115.57Planck length
+

+

A 256-bit fixed-point number also has the advantage of being able to +directly represent nearly any reasonable single-precision +floating-point value exactly. +

+

High-resolution coordinates in Java 3D are used only to embed more +traditional floating point coordinate systems within a much +higher-resolution substrate. In this way a visually seamless virtual +universe of any conceivable size or scale can be created, without worry +about numerical accuracy. +

+

+

+

Java 3D Virtual World +Coordinates

+Within a given virtual world coordinate system, positions are expressed +by three floating point numbers. The virtual world coordinate scale is +in meters, but this can be affected by scale changes in the object +hierarchy. +

Details of High-Resolution +Coordinates

+High-resolution coordinates are represented as signed, +two's-complement, fixed-point numbers consisting of 256 bits. Although +Java 3D keeps the internal representation of high-resolution +coordinates opaque, users specify such coordinates using 8-element +integer arrays. Java 3D treats the integer found at index 0 as +containing the most significant bits and the integer found at index 7 +as containing the least significant bits of the high-resolution +coordinate. The binary point is located at bit position 128, or between +the integers at index 3 and 4. A high-resolution coordinate of 1.0 is 1 +meter. +

The semantics of how file loaders deal with high-resolution +coordinates +is up to the individual file loader, as Java 3D does not directly +define any file-loading semantics. However, some general advice can be +given (note that this advice is not officially part of the +Java 3D specification). +

+

For "small" virtual universes (on the order of hundreds of meters +across in relative scale), a single Locale with high-resolution +coordinates at location (0.0, 0.0, 0.0) as the root node (below the +VirtualUniverse object) is sufficient; a loader can automatically +construct this node during the loading process, and the point in +high-resolution coordinates does not need any direct representation in +the external file. +

+

Larger virtual universes are expected to be constructed usually like +computer directory hierarchies, that is, as a "root" virtual universe +containing mostly external file references to embedded virtual +universes. In this case, the file reference object (user-specific data +hung off a Java 3D group or hi-res node) defines the location for the +data to be read into the current virtual universe. +

+

The data file's contents should be parented to the file object node +while being read, thus inheriting the high-resolution coordinates of +the file object as the new relative virtual universe origin of the +embedded scene graph. If this scene graph itself contains +high-resolution coordinates, it will need to be offset (translated) by +the amount in the file object's high-resolution coordinates and then +added to the larger virtual universe as new high-resolution +coordinates, with their contents hung off below them. Once again, this +procedure is not part of the official Java 3D specification, but some +more details on the care and use of high-resolution coordinates in +external file formats will probably be available as a Java 3D +application note. +

+

Authoring tools that directly support high-resolution coordinates +should create additional high-resolution coordinates as a user creates +new geometry "sufficiently" far away (or of different scale) from +existing high-resolution coordinates. +

+

Semantics of widely moving objects. Most fixed and +nearly-fixed objects stay attached to the same high-resolution Locale. +Objects that make wide changes in position or scale may periodically +need to be reparented to a more appropriate high-resolution Locale. If +no appropriate high-resolution Locale exists, the application may need +to create a new one. +

+

Semantics of viewing. The ViewPlatform object and +the +associated nodes in its hierarchy are very often widely moving objects. +Applications will typically attach the view platform to the most +appropriate high-resolution Locale. For display, all objects will first +have their positions translated by the difference between the location +of their high-resolution Locale and the view platform's high-resolution +Locale. (In the common case of the Locales being the same, no +translation is necessary.) +

+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/intro.gif b/j3d-core/src/classes/share/javax/media/j3d/doc-files/intro.gif new file mode 100644 index 0000000..503f818 Binary files /dev/null and b/j3d-core/src/classes/share/javax/media/j3d/doc-files/intro.gif differ diff --git a/j3d-core/src/classes/share/javax/media/j3d/doc-files/intro.html b/j3d-core/src/classes/share/javax/media/j3d/doc-files/intro.html new file mode 100644 index 0000000..f5ea134 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/doc-files/intro.html @@ -0,0 +1,337 @@ + + + + + The Java 3D API - Introduction + + +

Disclaimer

+

+This guide, which contains documentation formerly +published separately from the javadoc-generated API documentation, +is not an +official API specification. This documentation may contain references to +Java and Java 3D, both of which are trademarks of Sun Microsystems, Inc. +Any reference to these and other trademarks of Sun Microsystems are +for explanatory purposes only. Their use does impart any rights beyond +those listed in the source code license. In particular, Sun Microsystems +retains all intellectual property and trademark rights as described in +the proprietary rights notice in the COPYRIGHT.txt file. + +

+
+

Introduction to the Java 3D API

+

The Java 3D API is an application +programming interface used for writing three-dimensional graphics +applications and applets. It gives developers high-level constructs for +creating and manipulating 3D geometry and for constructing the +structures used in rendering that geometry. Application developers can +describe very large virtual worlds using these constructs, which +provide Java 3D with enough information to render these worlds +efficiently. +

+

Java 3D delivers Java's "write once, run anywhere" +benefit to +developers of 3D graphics applications. Java 3D is part of the +JavaMedia suite of APIs, making it available on a wide range of +platforms. It also integrates well with the Internet because +applications and applets written using the Java 3D API have access to +the entire set of Java classes. +

+

The Java 3D API draws its ideas from existing +graphics APIs and from +new technologies. Java 3D's low-level graphics constructs synthesize +the best ideas found in low-level APIs such as Direct3D, OpenGL, +QuickDraw3D, and XGL. Similarly, its higher-level constructs synthesize +the best ideas found in several scene graph-based systems. Java 3D +introduces some concepts not commonly considered part of the graphics +environment, such as 3D spatial sound. Java 3D's sound capabilities +help to provide a more immersive experience for the user.
+

+ +

+

+

Programming Paradigm

+Java 3D is an object-oriented API. Applications construct individual +graphics elements as separate objects and connect them together into a +treelike structure called a scene graph. The application +manipulates these objects using their predefined accessor, mutator, and +node-linking methods. +

The Scene Graph Programming +Model

+Java 3D's scene graph-based programming model provides a simple and +flexible mechanism for representing and rendering scenes. The scene +graph contains a complete description of the entire scene, or virtual +universe. This includes the geometric data, the attribute information, +and the viewing information needed to render the scene from a +particular point of view. The "Scene +Graph Basics" document provides more information on the Java 3D +scene graph programming model. +

The Java 3D API improves on previous graphics APIs +by eliminating many +of the bookkeeping and programming chores that those APIs impose. Java +3D allows the programmer to think about geometric objects rather than +about triangles-about the scene and its composition rather than about +how to write the rendering code for efficiently displaying the scene. +

+

+

+

Rendering Modes

+Java 3D includes three different rendering modes: immediate mode, +retained mode, and compiled-retained mode (see "Execution +and Rendering Model"). +Each successive rendering mode allows Java 3D more freedom in +optimizing an application's execution. Most Java 3D applications will +want to take advantage of the convenience and performance benefits that +the retained and compiled-retained modes provide. +

Immediate Mode

+Immediate mode leaves little room for global +optimization at the scene graph level. Even so, Java 3D has raised the +level of abstraction and accelerates immediate mode rendering on a +per-object basis. An application must provide a Java 3D draw method +with a complete set of points, lines, or triangles, which are then +rendered by the high-speed Java 3D renderer. Of course, the application +can build these lists of points, lines, or triangles in any manner it +chooses. +

Retained Mode

+Retained mode requires an application to construct a scene graph and +specify which elements of that scene graph may change during rendering. +The scene graph describes the objects in the virtual universe, the +arrangement of those objects, and how the application animates those +objects. +

Compiled-Retained Mode

+Compiled-retained mode, like retained mode, requires the application to +construct a scene graph and specify which elements of the scene graph +may change during rendering. Additionally, the application can compile +some or all of the subgraphs that make up a complete scene graph. Java +3D compiles these graphs into an internal format. The compiled +representation of the scene graph may bear little resemblance to the +original tree structure provided by the application, however, it is +functionally equivalent. Compiled-retained mode provides the highest +performance. +

Extensibility

+Most Java 3D classes expose only accessor and mutator methods. Those +methods operate only on that object's internal state, making it +meaningless for an application to override them. Therefore, Java 3D +does not provide the capability to override the behavior of Java 3D +attributes. To make Java 3D work correctly, applications must call "super.setXxxxx" +for any attribute state set method that is overridden. +

Applications can extend Java 3D's classes and add +their own methods. +However, they may not override Java 3D's scene graph traversal +semantics because the nodes do not contain explicit traversal and draw +methods. Java 3D's renderer retains those semantics internally. +

+

Java 3D does provide hooks for mixing +Java 3D-controlled scene graph rendering and user-controlled rendering +using Java 3D's immediate mode constructs (see "Mixed-Mode Rendering"). Alternatively, +the application can +stop Java 3D's renderer and do all its drawing in immediate mode (see "Pure Immediate-Mode Rendering"). +

+

Behaviors require applications to extend the +Behavior object and to +override its methods with user-written Java code. These extended +objects should contain references to those scene graph objects that +they will manipulate at run time. The "Behaviors +and Interpolators" document describes Java 3D's behavior +model. +

+

+

+

High Performance

+Java 3D's programming model allows the Java 3D API to do the mundane +tasks, such as scene graph traversal, managing attribute state changes, +and so forth, thereby simplifying the application's job. Java 3D does +this without sacrificing performance. At first glance, it might appear +that this approach would create more work for the API; however, it +actually has the opposite effect. Java 3D's higher level of abstraction +changes not only the amount but, more important, also the kind of work +the API must perform. Java 3D does not need to impose the same type of +constraints as do APIs with a lower level of abstraction, thus allowing +Java 3D to introduce optimizations not possible with these lower-level +APIs. +

Additionally, leaving the details of rendering to +Java 3D allows it to +tune the rendering to the underlying hardware. For example, relaxing +the strict rendering order imposed by other APIs allows parallel +traversal as well as parallel rendering. Knowing which portions of the +scene graph cannot be modified at run time allows Java 3D to flatten +the tree, pretransform geometry, or represent the geometry in a native +hardware format without the need to keep the original data. +

+

+

+

Layered Implementation

+Besides optimizations at the scene graph level, one of the more +important factors that determines the performance of Java 3D is the +time it takes to render the visible geometry. Java 3D implementations +are layered to take advantage of the native, low-level API that is +available on a given system. In particular, Java 3D implementations +that use Direct3D and OpenGL are available. This means that Java 3D +rendering will be accelerated across the same wide range of systems +that are supported by these lower-level APIs. +

Target Hardware Platforms

+Java 3D is aimed at a wide range of 3D-capable hardware and software +platforms, from low-cost PC game cards and software renderers at the +low end, through midrange workstations, all the way up to very +high-performance specialized 3D image generators. +

Java 3D implementations are expected to provide +useful rendering rates +on most modern PCs, especially those with 3D graphics accelerator +cards. On midrange workstations, Java 3D is expected to provide +applications with nearly full-speed hardware performance. +

+

Finally, Java 3D is designed to scale as the +underlying hardware +platforms increase in speed over time. Tomorrow's 3D PC game +accelerators will support more complex virtual worlds than high-priced +workstations of a few years ago. Java 3D is prepared to meet this +increase in hardware performance. +

+

+

+

Structuring the Java 3D Program

+

This section illustrates how a developer might +structure a Java 3D application. The simple application in this example +creates a scene graph that draws an object in the middle of a window +and rotates the object about its center point. +

+

Java 3D Application Scene +Graph

+

The scene graph for the sample application is shown below. +

+

The scene graph consists of superstructure +components—a VirtualUniverse +object and a Locale object—and a set of branch graphs. Each branch +graph is a subgraph that is rooted by a BranchGroup node that is +attached to the superstructure. For more information, see "Scene Graph Basics." +

+

Application
+scene graph

+

+

+
    + Figure 1 – Application Scene Graph +
+

+A VirtualUniverse object defines a named universe. Java 3D permits the +creation of more than one universe, though the vast majority of +applications will use just one. The VirtualUniverse object provides a +grounding for scene graphs. All Java 3D scene graphs must connect to a +VirtualUniverse object to be displayed. For more information, see "Scene Graph Superstructure." +

+

Below the VirtualUniverse object is a Locale object. +The Locale object +defines the origin, in high-resolution coordinates, of its attached +branch graphs. A virtual universe may contain as many Locales as +needed. In this example, a single Locale object is defined with its +origin at (0.0, 0.0, 0.0). +

+

The scene graph itself starts with the BranchGroup +nodes. +A BranchGroup serves as the root of a +subgraph, called a branch graph, of the scene graph. Only +BranchGroup objects can attach to Locale objects. +

+

In this example there are two branch graphs and, +thus, two BranchGroup +nodes. Attached to the left BranchGroup are two subgraphs. One subgraph +consists of a user-extended Behavior leaf node. The Behavior node +contains Java code for manipulating the transformation matrix +associated with the object's geometry. +

+

The other subgraph in this BranchGroup consists of a +TransformGroup +node that specifies the position (relative to the Locale), orientation, +and scale of the geometric objects in the virtual universe. A single +child, a Shape3D leaf node, refers to two component objects: a Geometry +object and an Appearance object. The Geometry object describes the +geometric shape of a 3D object (a cube in our simple example). The +Appearance object describes the appearance of the geometry (color, +texture, material reflection characteristics, and so forth). +

+

The right BranchGroup has a single subgraph that +consists of a +TransformGroup node and a ViewPlatform leaf node. The TransformGroup +specifies the position (relative to the Locale), orientation, and scale +of the ViewPlatform. This transformed ViewPlatform object defines the +end user's view within the virtual universe. +

+

Finally, the ViewPlatform is referenced by a View +object that specifies +all of the parameters needed to render the scene from the point of view +of the ViewPlatform. Also referenced by the View object are other +objects that contain information, such as the drawing canvas into which +Java 3D renders, the screen that contains the canvas, and information +about the physical environment. +

+

+

+

Recipe for a Java 3D Program

+

The following steps are taken by the example program to create the +scene graph elements and link them together. Java 3D will then render +the scene graph and display the graphics in a window on the screen:

+
    +1. Create a Canvas3D object and add it to the Applet panel. +

    2. Create a BranchGroup as the root of the scene branch graph.

    +

    3. Construct a Shape3D node with a TransformGroup node above it.

    +

    4. Attach a RotationInterpolator behavior to the TransformGroup.

    +

    5. Call the simple universe utility function to do the following:

    +
      +a. Establish a virtual universe with a single high-resolution Locale +(see "Scene Graph Basics"). +

      b. Create the PhysicalBody, PhysicalEnvironment, View, and +ViewPlat-form objects.

      +

      c. Create a BranchGroup as the root of the view platform branch +graph.

      +

      d. Insert the view platform branch graph into the Locale.

      +
    +6. Insert the scene branch graph into the simple universe's Locale. +
+

The Java 3D renderer then starts running in an infinite loop. The +renderer conceptually performs the following operations:

+
    while(true) {
Process input
If (request to exit) break
Perform Behaviors
Traverse the scene graph and render visible objects
}
Cleanup and exit
+

HelloUniverse: A Sample Java +3D Program

+

Click here to see code fragments +from a simple program, HelloUniverse.java, +that creates a cube and a RotationInterpolator behavior object that +rotates the cube at a constant rate of pi/2 radians per second.
+

+

Other Documents
+

+

Here are other documents that provide explanatory material, +previously included as part of +the Java 3D API Specification Guide.
+

+ +


+

+ + diff --git a/j3d-core/src/classes/share/javax/media/j3d/package.html b/j3d-core/src/classes/share/javax/media/j3d/package.html new file mode 100644 index 0000000..a9a3553 --- /dev/null +++ b/j3d-core/src/classes/share/javax/media/j3d/package.html @@ -0,0 +1,40 @@ + + + + + javax.media.j3d + + + +

Provides the core set of classes for the +3D graphics API for the Java platform; click here for more information, +including explanatory material that was formerly found in the guide. +

+ +

The 3D API is an application +programming interface used for writing three-dimensional graphics +applications and applets. It gives developers high-level constructs for +creating and manipulating 3D geometry and for constructing the +structures used in rendering that geometry. Application developers can +describe very large virtual worlds using these constructs, which +provide the runtime system with enough information to render these worlds +efficiently. +

+ + + + + diff --git a/j3d-core/src/classes/win32/javax/media/j3d/Win32NativeConfigTemplate3D.java b/j3d-core/src/classes/win32/javax/media/j3d/Win32NativeConfigTemplate3D.java new file mode 100644 index 0000000..d34b968 --- /dev/null +++ b/j3d-core/src/classes/win32/javax/media/j3d/Win32NativeConfigTemplate3D.java @@ -0,0 +1,246 @@ +/* + * $RCSfile: Win32NativeConfigTemplate3D.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.2 $ + * $Date: 2008/02/28 20:17:57 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsDevice; +import java.awt.GraphicsConfiguration; +import sun.awt.Win32GraphicsDevice; +import sun.awt.Win32GraphicsConfig; +import java.awt.GraphicsConfigTemplate; + +/** + * Native config template class. A singleton instance of this class is + * created by a factory method in the base class using reflection. + */ +class Win32NativeConfigTemplate3D extends NativeConfigTemplate3D { + private final static boolean debug = false; + + Win32NativeConfigTemplate3D() { + } + + /** + * selects the proper visual + */ + native int + choosePixelFormat(long ctx, int screen, int[] attrList, long[] pFormatInfo); + + // Native method to free an PixelFormatInfo struct. This is static since it + // may need to be called to clean up the Canvas3D graphicsConfigTable after the + // Win32NativeConfigTemplate3D has been disposed of. + static native void freePixelFormatInfo(long pFormatInfo); + + // Native methods to return whether a particular attribute is available + native boolean isStereoAvailable(long pFormatInfo, boolean offScreen); + native boolean isDoubleBufferAvailable(long pFormatInfo, boolean offScreen); + native boolean isSceneAntialiasingAccumAvailable(long pFormatInfo, boolean offScreen); + native boolean isSceneAntialiasingMultisampleAvailable(long pFormatInfo, boolean offScreen, int screen); + native int getStencilSize(long pFormatInfo, boolean offScreen); + + /** + * Chooses the best PixelFormat for Java 3D apps. + */ + @Override + GraphicsConfiguration + getBestConfiguration(GraphicsConfigTemplate3D template, + GraphicsConfiguration[] gc) { + + Win32GraphicsDevice gd = + (Win32GraphicsDevice)((Win32GraphicsConfig)gc[0]).getDevice(); + + /* Not ready to enforce ARB extension in J3D1.3.2, but will likely to + do so in J3D 1.4. + System.out.println("getBestConfiguration : Checking WGL ARB support\n"); + + if (!Win32NativeScreenInfo.isWglARB()) { + Thread.dumpStack(); + System.out.println("getBestConfiguration : WGL ARB support fail\n"); + return null; + } + */ + + // holds the list of attributes to be tramslated + // for glxChooseVisual call + int attrList[] = new int[NUM_ITEMS]; + // assign template values to array + attrList[RED_SIZE] = template.getRedSize(); + attrList[GREEN_SIZE] = template.getGreenSize(); + attrList[BLUE_SIZE] = template.getBlueSize(); + + attrList[DEPTH_SIZE] = template.getDepthSize(); + attrList[DOUBLEBUFFER] = template.getDoubleBuffer(); + attrList[STEREO] = template.getStereo(); + attrList[ANTIALIASING] = template.getSceneAntialiasing(); + attrList[STENCIL_SIZE] = template.getStencilSize(); + // System.out.println("Win32NativeConfigTemplate3D : getStencilSize " + + // attrList[STENCIL_SIZE]); + + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + + long[] pFormatInfo = new long[1]; + + /* Deliberately set this to -1. pFormatInfo is not use in + D3D, so this value will be unchange in the case of D3D. + In the case of OGL, the return value should be 0 or a + positive valid address. + */ + pFormatInfo[0] = -1; + + int pixelFormat = choosePixelFormat(0, screen, attrList, pFormatInfo); + if (debug) { + System.out.println(" choosePixelFormat() returns " + pixelFormat); + System.out.println(" pFormatInfo is " + pFormatInfo[0]); + System.out.println(); + } + + if (pixelFormat < 0) { + // current mode don't support the minimum config + return null; + } + + // Fix to issue 104 -- + // Pass in 0 for pixel format to the AWT. + // ATI driver will lockup pixelFormat, if it is passed to AWT. + GraphicsConfiguration gc1 = Win32GraphicsConfig.getConfig(gd, 0); + + // We need to cache the GraphicsTemplate3D and the private + // pixel format info. + synchronized (Canvas3D.graphicsConfigTable) { + if (Canvas3D.graphicsConfigTable.get(gc1) == null) { + GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(template); + gcInfo.setPrivateData(new Long(pFormatInfo[0])); + Canvas3D.graphicsConfigTable.put(gc1, gcInfo); + } else { + freePixelFormatInfo(pFormatInfo[0]); + } + } + + return gc1; + } + + /** + * Determine if a given GraphicsConfiguration object can be used + * by Java 3D. + */ + @Override + boolean isGraphicsConfigSupported(GraphicsConfigTemplate3D template, + GraphicsConfiguration gc) { + + Win32GraphicsDevice gd = + (Win32GraphicsDevice)((Win32GraphicsConfig) gc).getDevice(); + + /* Not ready to enforce ARB extension in J3D1.3.2, but will likely to + do so in J3D 1.4. + System.out.println("isGraphicsConfigSupported : Checking WGL ARB support\n"); + + if (!Win32NativeScreenInfo.isWglARB()) { + Thread.dumpStack(); + System.out.println("isGraphicsConfigSupported : WGL ARB support fail\n"); + return false; + } + */ + + // holds the list of attributes to be tramslated + // for glxChooseVisual call + int attrList[] = new int[NUM_ITEMS]; + // assign template values to array + attrList[RED_SIZE] = template.getRedSize(); + attrList[GREEN_SIZE] = template.getGreenSize(); + attrList[BLUE_SIZE] = template.getBlueSize(); + + attrList[DEPTH_SIZE] = template.getDepthSize(); + attrList[DOUBLEBUFFER] = template.getDoubleBuffer(); + attrList[STEREO] = template.getStereo(); + attrList[ANTIALIASING] = template.getSceneAntialiasing(); + attrList[STENCIL_SIZE] = template.getStencilSize(); + // System.out.println("Win32NativeConfigTemplate3D : getStencilSize " + + // attrList[STENCIL_SIZE]); + + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + + long[] pFormatInfo = new long[1]; + + int pixelFormat = choosePixelFormat(0, screen, attrList, pFormatInfo); + if (debug) { + System.out.println(" choosePixelFormat() returns " + pixelFormat); + System.out.println(" pFormatInfo is " + pFormatInfo[0]); + System.out.println(); + } + + if (pixelFormat < 0) { + // current mode don't support the minimum config + return false; + } else + return true; + } + + + // Return whether stereo is available. + @Override + boolean hasStereo(Canvas3D c3d) { + return isStereoAvailable(c3d.fbConfig, c3d.offScreen); + } + + // Return the stencil of this canvas. + @Override + int getStencilSize(Canvas3D c3d) { + return getStencilSize(c3d.fbConfig, c3d.offScreen); + } + + // Return whether a double buffer is available. + @Override + boolean hasDoubleBuffer(Canvas3D c3d) { + return isDoubleBufferAvailable(c3d.fbConfig, c3d.offScreen); + } + + // Return whether scene antialiasing is available. + @Override + boolean hasSceneAntialiasingAccum(Canvas3D c3d) { + return isSceneAntialiasingAccumAvailable(c3d.fbConfig, c3d.offScreen); + } + + // Return whether scene antialiasing is available. + @Override + boolean hasSceneAntialiasingMultisample(Canvas3D c3d) { + GraphicsConfiguration gc = c3d.graphicsConfiguration; + + Win32GraphicsDevice gd = + (Win32GraphicsDevice)((Win32GraphicsConfig)gc).getDevice(); + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + /* Fix to issue 77 */ + return isSceneAntialiasingMultisampleAvailable(c3d.fbConfig, c3d.offScreen, screen); + } + + // Ensure that the native libraries are loaded + static { + VirtualUniverse.loadLibraries(); + } +} diff --git a/j3d-core/src/classes/win32/javax/media/j3d/Win32NativeScreenInfo.java b/j3d-core/src/classes/win32/javax/media/j3d/Win32NativeScreenInfo.java new file mode 100644 index 0000000..7025ede --- /dev/null +++ b/j3d-core/src/classes/win32/javax/media/j3d/Win32NativeScreenInfo.java @@ -0,0 +1,78 @@ +/* + * $RCSfile: Win32NativeScreenInfo.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.2 $ + * $Date: 2008/02/28 20:17:57 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsDevice; +import sun.awt.Win32GraphicsDevice; + +/** + * Native screen info class. A singleton instance of this class is created by + * a factory method in the base class using reflection. + */ +class Win32NativeScreenInfo extends NativeScreenInfo { + private static final long display = 0; // unused for Win32 + + private static boolean wglARBChecked = false; + private static boolean isWglARB; + + private static native boolean queryWglARB(); + + Win32NativeScreenInfo() { + } + + // This method will return true if wglGetExtensionsStringARB is supported, + // else return false + static synchronized boolean isWglARB() { + + if (!wglARBChecked) { + // Query for wglGetExtensionsStringARB support. + isWglARB = queryWglARB(); + wglARBChecked = true; + } + return isWglARB; + } + + @Override + long getDisplay() { + return display; + } + + @Override + int getScreen(GraphicsDevice graphicsDevice) { + return ((Win32GraphicsDevice)graphicsDevice).getScreen(); + } + + // Ensure that the native libraries are loaded + static { + VirtualUniverse.loadLibraries(); + } +} diff --git a/j3d-core/src/classes/x11/javax/media/j3d/X11NativeConfigTemplate3D.java b/j3d-core/src/classes/x11/javax/media/j3d/X11NativeConfigTemplate3D.java new file mode 100644 index 0000000..720d3a1 --- /dev/null +++ b/j3d-core/src/classes/x11/javax/media/j3d/X11NativeConfigTemplate3D.java @@ -0,0 +1,298 @@ +/* + * $RCSfile: X11NativeConfigTemplate3D.java,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.2 $ + * $Date: 2008/02/28 20:17:57 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsDevice; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsConfigTemplate; +import java.awt.Rectangle; +import sun.awt.X11GraphicsDevice; +import sun.awt.X11GraphicsConfig; + +/** + * Native config template class. A singleton instance of this class is + * created by a factory method in the base class using reflection. + */ +class X11NativeConfigTemplate3D extends NativeConfigTemplate3D { + private final static boolean debug = false; + + X11NativeConfigTemplate3D() { + } + + // Native method to get an OpenGL visual id and a pointer to the + // GLXFBConfig structure list itself. + native int chooseOglVisual(long display, int screen, + int[] attrList, long[] fbConfig); + + // Native method to free an GLXFBConfig struct. This is static since it + // may need to be called to clean up the Canvas3D graphicsConfigTable + // after the X11NativeConfigTemplate3D has been disposed of. + static native void freeFBConfig(long fbConfig); + + // Native methods to return whether a particular attribute is available + native boolean isStereoAvailable(long display, int screen, int vid); + native boolean isDoubleBufferAvailable(long display, int screen, int vid); + native boolean isSceneAntialiasingAccumAvailable(long display, int screen, int vid); + native boolean isSceneAntialiasingMultisampleAvailable(long display, int screen, int vid); + native int getStencilSize(long display, int screen, int vid); + + /* + * Chooses the best FBConfig for Java 3D apps. + */ + @Override + GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate3D template, + GraphicsConfiguration[] gc) { + + X11GraphicsDevice gd = + (X11GraphicsDevice)((X11GraphicsConfig)gc[0]).getDevice(); + + if (!X11NativeScreenInfo.isGLX13()) { + return null; + } + + long display = NativeScreenInfo.getNativeScreenInfo().getDisplay(); + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + + if (debug) { + System.out.println(" X11NativeConfigTemplate3D: using device " + gd); + System.out.println(" display " + display + " screen " + screen); + System.out.println(" configuration count: " + gc.length); + for (int i = 0 ; i < gc.length ; i++) { + System.out.println(" visual id at index " + i + ": " + + ((X11GraphicsConfig)gc[i]).getVisual()); + } + } + + Rectangle bounds = gc[0].getBounds(); + if ((bounds.x != 0 || bounds.y != 0) && + (! VirtualUniverse.mc.xineramaDisabled)) { + // Xinerama is being used. The screen needs to be set to 0 since + // glxChooseFBConfig will not return a valid visual otherwise. + screen = 0; + if (debug) { + System.out.println(" Non-primary Xinerama screen:"); + System.out.println(" bounds = " + bounds); + System.out.println(" using screen 0 visual"); + } + } + + int[] attrList; // holds the list of attributes to be translated + // for glxChooseFBConfig call + + attrList = new int[NUM_ITEMS]; + + // assign template values to array + attrList[RED_SIZE] = template.getRedSize(); + attrList[GREEN_SIZE] = template.getGreenSize(); + attrList[BLUE_SIZE] = template.getBlueSize(); + + attrList[DEPTH_SIZE] = template.getDepthSize(); + attrList[DOUBLEBUFFER] = template.getDoubleBuffer(); + attrList[STEREO] = template.getStereo(); + attrList[ANTIALIASING] = template.getSceneAntialiasing(); + attrList[STENCIL_SIZE] = template.getStencilSize(); + // System.out.println("X11NativeConfigTemplate3D : getStencilSize " + + // attrList[STENCIL_SIZE]); + + long[] fbConfig = new long[1]; + int visID = chooseOglVisual(display, screen, attrList, fbConfig); + if (debug) { + System.out.println(" chooseOglVisual() returns " + visID); + System.out.println(" pointer to GLXFBConfig is " + fbConfig[0]); + System.out.println(); + } + + if (visID == 0 || fbConfig[0] == 0) { + return null; // no valid visual was found + } + + // search list of graphics configurations for config + // with matching visualId + X11GraphicsConfig gc0 = null; + for (int i = 0; i < gc.length; i++) { + if (((X11GraphicsConfig)gc[i]).getVisual() == visID) { + gc0 = (X11GraphicsConfig)gc[i]; + break; + } + } + + // Just return if we didn't find a match + if (gc0 == null) { + return null; + } + + // Create a new GraphicsConfig object based on the one we found + X11GraphicsConfig gc1 = + X11GraphicsConfig.getConfig(gd, gc0.getVisual(), + gc0.getDepth(), gc0.getColormap(), false); + + // We need to cache the GraphicsTemplate3D and the private + // fbconfig info. + synchronized (Canvas3D.graphicsConfigTable) { + if (Canvas3D.graphicsConfigTable.get(gc1) == null) { + GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(template); + gcInfo.setPrivateData(new Long(fbConfig[0])); + Canvas3D.graphicsConfigTable.put(gc1, gcInfo); + } else { + freeFBConfig(fbConfig[0]); + } + } + return gc1; + } + + /* + * Determine if a given GraphicsConfiguration object can be used + * by Java 3D. + */ + @Override + boolean isGraphicsConfigSupported(GraphicsConfigTemplate3D template, + GraphicsConfiguration gc) { + + X11GraphicsDevice gd = + (X11GraphicsDevice)((X11GraphicsConfig)gc).getDevice(); + + if (!X11NativeScreenInfo.isGLX13()) { + return false; + } + + long display = NativeScreenInfo.getNativeScreenInfo().getDisplay(); + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + + int[] attrList; // holds the list of attributes to be tramslated + // for glxChooseVisual call + + attrList = new int[NUM_ITEMS]; + + // assign template values to array + attrList[RED_SIZE] = template.getRedSize(); + attrList[GREEN_SIZE] = template.getGreenSize(); + attrList[BLUE_SIZE] = template.getBlueSize(); + + attrList[DEPTH_SIZE] = template.getDepthSize(); + attrList[DOUBLEBUFFER] = template.getDoubleBuffer(); + attrList[STEREO] = template.getStereo(); + attrList[ANTIALIASING] = template.getSceneAntialiasing(); + attrList[STENCIL_SIZE] = template.getStencilSize(); + // System.out.println("X11NativeConfigTemplate3D : getStencilSize " + + // attrList[STENCIL_SIZE]); + + long[] fbConfig = new long[1]; + int visID = chooseOglVisual(display, screen, attrList, fbConfig); + + if (visID == 0 || fbConfig[0] == 0) + return false; // no valid visual was found + else + return true; + } + + + // Return whether stereo is available. + @Override + boolean hasStereo(Canvas3D c3d) { + GraphicsConfiguration gc = c3d.graphicsConfiguration; + + X11GraphicsDevice gd = + (X11GraphicsDevice)((X11GraphicsConfig)gc).getDevice(); + + long display = NativeScreenInfo.getNativeScreenInfo().getDisplay(); + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + int vid = ((X11GraphicsConfig)gc).getVisual(); + + return isStereoAvailable(display, screen, vid); + } + + // Return the stencil of this canvas. + @Override + int getStencilSize(Canvas3D c3d) { + GraphicsConfiguration gc = c3d.graphicsConfiguration; + + X11GraphicsDevice gd = + (X11GraphicsDevice)((X11GraphicsConfig)gc).getDevice(); + + long display = NativeScreenInfo.getNativeScreenInfo().getDisplay(); + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + int vid = ((X11GraphicsConfig)gc).getVisual(); + + return getStencilSize(display, screen, vid); + } + + // Return whether a double buffer is available. + @Override + boolean hasDoubleBuffer(Canvas3D c3d) { + GraphicsConfiguration gc = c3d.graphicsConfiguration; + + X11GraphicsDevice gd = + (X11GraphicsDevice)((X11GraphicsConfig)gc).getDevice(); + + long display = NativeScreenInfo.getNativeScreenInfo().getDisplay(); + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + int vid = ((X11GraphicsConfig)gc).getVisual(); + + return isDoubleBufferAvailable(display, screen, vid); + } + + // Return whether scene antialiasing is available. + @Override + boolean hasSceneAntialiasingAccum(Canvas3D c3d) { + GraphicsConfiguration gc = c3d.graphicsConfiguration; + + X11GraphicsDevice gd = + (X11GraphicsDevice)((X11GraphicsConfig)gc).getDevice(); + + long display = NativeScreenInfo.getNativeScreenInfo().getDisplay(); + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + int vid = ((X11GraphicsConfig)gc).getVisual(); + + return isSceneAntialiasingAccumAvailable(display, screen, vid); + } + + + // Return whether scene antialiasing is available. + @Override + boolean hasSceneAntialiasingMultisample(Canvas3D c3d) { + GraphicsConfiguration gc = c3d.graphicsConfiguration; + + X11GraphicsDevice gd = + (X11GraphicsDevice)((X11GraphicsConfig)gc).getDevice(); + + long display = NativeScreenInfo.getNativeScreenInfo().getDisplay(); + int screen = NativeScreenInfo.getNativeScreenInfo().getScreen(gd); + int vid = ((X11GraphicsConfig)gc).getVisual(); + + return isSceneAntialiasingMultisampleAvailable(display, screen, vid); + } + + // Ensure that the native libraries are loaded + static { + VirtualUniverse.loadLibraries(); + } +} diff --git a/j3d-core/src/classes/x11/javax/media/j3d/X11NativeScreenInfo.java b/j3d-core/src/classes/x11/javax/media/j3d/X11NativeScreenInfo.java new file mode 100644 index 0000000..ac6cf62 --- /dev/null +++ b/j3d-core/src/classes/x11/javax/media/j3d/X11NativeScreenInfo.java @@ -0,0 +1,91 @@ +/* + * $RCSfile: X11NativeScreenInfo.java,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.2 $ + * $Date: 2008/02/28 20:17:57 $ + * $State: Exp $ + */ + +package javax.media.j3d; + +import java.awt.GraphicsDevice; +import sun.awt.X11GraphicsDevice; + +/** + * Native screen info class. A singleton instance of this class is created by + * a factory method in the base class using reflection. + */ +class X11NativeScreenInfo extends NativeScreenInfo { + private static long display = 0; + private static boolean glxChecked = false; + private static boolean isGLX13; + + private static native long openDisplay(); + private static native boolean queryGLX13(long display); + + X11NativeScreenInfo() { + } + + // Fix for issue 20. + // This method will return true if glx version is 1.3 or higher, + // else return false. + static synchronized boolean isGLX13() { + if (!glxChecked) { + // Open a new static display connection if one is not already opened. + getStaticDisplay(); + + // Query for glx1.3 support. + isGLX13 = queryGLX13(getStaticDisplay()); + glxChecked = true; + } + + return isGLX13; + } + + private static synchronized long getStaticDisplay() { + if (display == 0) { + display = openDisplay(); + } + return display; + } + + @Override + long getDisplay() { + // Open a new static display connection if one is not already opened + return getStaticDisplay(); + } + + @Override + int getScreen(GraphicsDevice graphicsDevice) { + // Get the screen number + return ((X11GraphicsDevice)graphicsDevice).getScreen(); + } + + // Ensure that the native libraries are loaded + static { + VirtualUniverse.loadLibraries(); + } +} diff --git a/j3d-core/src/native/build.xml b/j3d-core/src/native/build.xml new file mode 100644 index 0000000..89b6d86 --- /dev/null +++ b/j3d-core/src/native/build.xml @@ -0,0 +1,431 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/d3d/Attributes.cpp b/j3d-core/src/native/d3d/Attributes.cpp new file mode 100644 index 0000000..c7ed15c --- /dev/null +++ b/j3d-core/src/native/d3d/Attributes.cpp @@ -0,0 +1,3268 @@ +/* + * $RCSfile: Attributes.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.21 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#include "StdAfx.h" + + +const DWORD blendFunctionTable[] = +{ + D3DBLEND_ZERO, D3DBLEND_ONE, + D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, + D3DBLEND_DESTCOLOR, D3DBLEND_SRCCOLOR, + D3DBLEND_INVSRCCOLOR, D3DBLEND_SRCCOLOR +}; + +const DWORD combineFunctionTable[] = +{ + D3DTOP_SELECTARG1, D3DTOP_SELECTARG1, D3DTOP_SELECTARG1, D3DTOP_SELECTARG1, + D3DTOP_MODULATE, D3DTOP_MODULATE2X, D3DTOP_MODULATE2X, D3DTOP_MODULATE4X, + D3DTOP_ADD, D3DTOP_ADD, D3DTOP_ADD, D3DTOP_ADD, + D3DTOP_ADDSIGNED, D3DTOP_ADDSIGNED2X, D3DTOP_ADDSIGNED2X, D3DTOP_ADDSIGNED2X, + D3DTOP_SUBTRACT, D3DTOP_SUBTRACT, D3DTOP_SUBTRACT, D3DTOP_SUBTRACT, + D3DTOP_LERP, D3DTOP_LERP, D3DTOP_LERP, D3DTOP_LERP, + D3DTOP_DOTPRODUCT3, D3DTOP_DOTPRODUCT3, D3DTOP_DOTPRODUCT3, D3DTOP_DOTPRODUCT3 +}; + +// Assume COMBINE_OBJECT_COLOR = 0 +// COMBINE_TEXTURE_COLOR = 1 +// COMBINE_CONSTANT_COLOR = 2 +// COMBINE_PREVIOUS_TEXTURE_UNIT_STATE = 3 +// +// COMBINE_SRC_COLOR = 0 +// COMBINE_ONE_MINUS_SRC_COLOR = 1 +// COMBINE_SRC_ALPHA = 2 +// COMBINE_ONE_MINUS_SRC_ALPHA = 3 +// +const DWORD combineSourceTable[] = +{ + D3DTA_DIFFUSE, + D3DTA_DIFFUSE | D3DTA_COMPLEMENT, + D3DTA_DIFFUSE | D3DTA_ALPHAREPLICATE, + D3DTA_DIFFUSE | D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE, + D3DTA_TEXTURE, + D3DTA_TEXTURE | D3DTA_COMPLEMENT, + D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE, + D3DTA_TEXTURE | D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE, + D3DTA_TFACTOR, + D3DTA_TFACTOR | D3DTA_COMPLEMENT, + D3DTA_TFACTOR | D3DTA_ALPHAREPLICATE, + D3DTA_TFACTOR | D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE, + D3DTA_CURRENT, + D3DTA_CURRENT | D3DTA_COMPLEMENT, + D3DTA_CURRENT | D3DTA_ALPHAREPLICATE, + D3DTA_CURRENT | D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE +}; + +// Assume TEXTURE_COORDINATE_2 = 0 +// TEXTURE_COORDINATE_3 = 1; +// TEXTURE_COORDINATE_4 = 2; +const int coordFormatTable[] = {2, 3, 4}; + +BOOL isLineWidthMessOutput = false; +BOOL isBackFaceMessOutput = false; +BOOL isLinePatternMessOutput = false; +BOOL isTexBorderMessOutput = false; + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateLinearFog( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat red, + jfloat green, + jfloat blue, + jdouble fdist, + jdouble bdist) +{ + GetDevice(); + + float fstart = (float) fdist; + float fend = (float) bdist; + + device->SetRenderState(d3dCtx->deviceInfo->fogMode, + D3DFOG_LINEAR); + device->SetRenderState(D3DRS_FOGCOLOR, + D3DCOLOR_COLORVALUE(red, green, blue, 0)); + + device->SetRenderState(D3DRS_FOGSTART, + *((LPDWORD) (&fstart))); + device->SetRenderState(D3DRS_FOGEND, + *((LPDWORD) (&fend))); + device->SetRenderState(D3DRS_FOGENABLE, TRUE); + +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateExponentialFog( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat red, + jfloat green, + jfloat blue, + jfloat density) +{ + GetDevice(); + + float d = (float) density; + + device->SetRenderState(d3dCtx->deviceInfo->fogMode, + D3DFOG_EXP); + device->SetRenderState(D3DRS_FOGCOLOR, + D3DCOLOR_COLORVALUE(red, green, blue, 0)); + device->SetRenderState(D3DRS_FOGDENSITY, + *((LPDWORD) (&d))); + device->SetRenderState(D3DRS_FOGENABLE, TRUE); + +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateModelClip( + JNIEnv *env, + jobject obj, + jlong ctx, + jint planeNum, + jboolean enableFlag, + jdouble A, + jdouble B, + jdouble C, + jdouble D) +{ + DWORD status; + float clip[4]; + + GetDevice(); + + clip[0] = -A; + clip[1] = -B; + clip[2] = -C; + clip[3] = -D; + + device->GetRenderState(D3DRS_CLIPPLANEENABLE, &status); + + if (enableFlag) { + device->SetClipPlane(planeNum, clip); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, + status | (1 << planeNum)); + } else { + device->SetRenderState(D3DRS_CLIPPLANEENABLE, + status & ~(1 << planeNum)); + } +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setModelViewMatrix( + JNIEnv * env, + jobject obj, + jlong ctx, + jdoubleArray viewMatrix, + jdoubleArray modelMatrix) +{ + D3DXMATRIX d3dMatrix; + + GetDevice(); + + + jdouble *matrix = reinterpret_cast( + env->GetPrimitiveArrayCritical(modelMatrix, NULL)); + + CopyTranspose(d3dMatrix, matrix); + + env->ReleasePrimitiveArrayCritical(modelMatrix, matrix, 0); + + + device->SetTransform(D3DTS_WORLD,&d3dMatrix); + + matrix = reinterpret_cast( + env->GetPrimitiveArrayCritical(viewMatrix, NULL)); + CopyTranspose(d3dMatrix, matrix); + + env->ReleasePrimitiveArrayCritical(viewMatrix, matrix, 0); + + // Because we negate the third row in projection matrix to + // make ._34 = 1. Here we negate the third column of View + // matrix to compensate it. + d3dMatrix._13 = -d3dMatrix._13; + d3dMatrix._23 = -d3dMatrix._23; + d3dMatrix._33 = -d3dMatrix._33; + d3dMatrix._43 = -d3dMatrix._43; + + device->SetTransform(D3DTS_VIEW, &d3dMatrix); +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setProjectionMatrix( + JNIEnv * env, + jobject obj, + jlong ctx, + jdoubleArray projMatrix) +{ + + GetDevice(); + + jdouble *s = reinterpret_cast( + env->GetPrimitiveArrayCritical(projMatrix, NULL)); + + /* + * There are five steps we need to do in order that this + * matrix is useful by D3D + * + * (1) We need to transpose the matrix since in Java3D v' = M*v + * but in Direct3D v' = v*N where N is the transpose of M + * + * (2) Invert the Z value in clipping coordinates because OpenGL + * uses left-handed clipping coordinates, while Java3D defines + * right-handed coordinates everywhere. i.e. do the following + * after the transpose + * + * d3dMatrix._13 *= -1; + * d3dMatrix._23 *= -1; + * d3dMatrix._33 *= -1; + * d3dMatrix._43 *= -1; + * + * (3) In Direct3D, the z-depths range is [0,1] instead of + * OGL [-1, 1], so we need to multiple it by + * + * [1 0 0 0] + * R = [0 1 0 0] + * [0 0 0.5 0] + * [0 0 0.5 1] + * + * after the transpose and negate. i.e. N*R + * + * (4) We want w-friendly perspective matrix, i.e., d3dMatrix._34 = 1 + * We do this first by divide the whole matrix by + * 1/d3dMatrix._34 Since d3dMatrix._34 is always negative as + * input from Java3D. Now d3dMatrix._34 = -1 + * + * (5) To make d3dMatrix._34 = 1, we negate the third row of it. + * Because of this, we need to negate the third column in + * View matrix to compensate this. + * + * All of the above operation is combined together in this + * implementation for optimization. + */ + D3DXMATRIX m; + + if (s[14] != 0) { + // Perspective projection + // s[14] is always < 0 + float ratio = -1/s[14]; + m._12= m._13 = m._14 = m._21 = m._23 = + m._24 = m._41 = m._42 = m._44 = 0; + m._11 = s[0]*ratio; + m._22 = s[5]*ratio; + m._31 = -s[2]*ratio; + m._32 = -s[6]*ratio; + m._33 = -(s[14]-s[10])*ratio/2; + m._43 = -s[11]*ratio/2; + m._34 = 1; + } else { + // parallel projection + m._12 = m._13 = m._14 = m._21 = m._23 = + m._24 = m._31 = m._32 = m._34 = 0; + m._11 = s[0]; + m._22 = s[5]; + m._33 = s[10]/2; + m._41 = s[3]; + m._42 = s[7]; + m._43 = (s[15]-s[11])/2; + m._44 = s[15]; + } + + env->ReleasePrimitiveArrayCritical(projMatrix, s, 0); + device->SetTransform(D3DTS_PROJECTION, &m); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setViewport( + JNIEnv *env, + jobject obj, + jlong ctx, + jint x, + jint y, + jint width, + jint height) +{ + GetDevice(); + + if (d3dCtx->bFullScreen) { + width = d3dCtx->devmode.dmPelsWidth; + height = d3dCtx->devmode.dmPelsHeight; + } + D3DVIEWPORT9 vp = {x, y, width, height, 0.0f, 1.0f}; + + device->SetViewport(&vp); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setSceneAmbient( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat red, + jfloat green, + jfloat blue) +{ + GetDevice(); + /* + Clamp(red); + Clamp(green); + Clamp(blue); + */ + device->SetRenderState(D3DRS_AMBIENT, + D3DCOLOR_COLORVALUE(red, green, blue, 0)); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setLightEnables( + JNIEnv *env, + jobject obj, + jlong ctx, + jlong enable_mask, + jint nlights) +{ + GetDevice(); + +#pragma warning(disable:4244) // loss of data from __int64 to int + + for (int i=nlights-1; i>=0; i--) { + device->LightEnable(i, enable_mask & (long)(1L<isLightEnable = lightingOn; + device->SetRenderState(D3DRS_LIGHTING, lightingOn); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_disableFog( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + device->SetRenderState(D3DRS_FOGENABLE, false); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_disableModelClip( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); +} + +/** + * one of : + * STENCIL_KEEP - keeps the current value (no operation performed). This is the default setting. + * STENCIL_ZERO - Sets the stencil buffer value to 0. + * STENCIL_REPLACE - Sets the stencil buffer value to refValue, as specified by setStencilFunction. + * STENCIL_INCR - Increments the current stencil buffer value. + * STENCIL_DECR - Decrements the current stencil buffer value. + * STENCIL_INVERT - Bitwise inverts the current stencil buffer value. +*/ +DWORD getStencilOP(jint op) +{ + DWORD value = D3DSTENCILOP_KEEP; + switch(op) + { + case javax_media_j3d_RenderingAttributes_STENCIL_KEEP: + value = D3DSTENCILOP_KEEP; break; + case javax_media_j3d_RenderingAttributes_STENCIL_ZERO: + value = D3DSTENCILOP_ZERO; break; + case javax_media_j3d_RenderingAttributes_STENCIL_REPLACE: + value = D3DSTENCILOP_REPLACE; break; + case javax_media_j3d_RenderingAttributes_STENCIL_INCR: + value = D3DSTENCILOP_INCRSAT; break; + case javax_media_j3d_RenderingAttributes_STENCIL_DECR: + value = D3DSTENCILOP_DECRSAT; break; + case javax_media_j3d_RenderingAttributes_STENCIL_INVERT: + value = D3DSTENCILOP_INVERT; break; + default : + value = D3DSTENCILOP_KEEP; break; + } + + return value; +} + +/** + * ALWAYS - pixels are always drawn, irrespective of the stencil value. This effectively disables stencil testing. This is the default setting. + * NEVER - pixels are never drawn, irrespective of the stencil value. + * EQUAL - pixels are drawn if the stencil reference value is equal to the stored stencil value in the frame buffer. + * NOT_EQUAL - pixels are drawn if the stencil reference value is not equal to the stored stencil value in the frame buffer. + * LESS - pixels are drawn if the stencil reference value is less than the stored stencil value in the frame buffer. + * LESS_OR_EQUAL - pixels are drawn if the stencil reference value is less than or equal to the stored stencil value in the frame buffer. + * GREATER - pixels are drawn if the stencil reference value is greater than the stored stencil value in the frame buffer. + * GREATER_OR_EQUAL - pixels are drawn if the stencil reference value is greater than or equal to the stored stencil value in the frame buffer. +*/ +DWORD getStencilFunc(jint func) +{ + DWORD value = D3DCMP_ALWAYS; + switch(func) + { + case javax_media_j3d_RenderingAttributes_ALWAYS: + value = D3DCMP_ALWAYS; break; + case javax_media_j3d_RenderingAttributes_NEVER: + value = D3DCMP_NEVER; break; + case javax_media_j3d_RenderingAttributes_EQUAL: + value = D3DCMP_EQUAL; break; + case javax_media_j3d_RenderingAttributes_NOT_EQUAL: + value = D3DCMP_NOTEQUAL; break; + case javax_media_j3d_RenderingAttributes_LESS_OR_EQUAL: + value = D3DCMP_LESSEQUAL; break; + case javax_media_j3d_RenderingAttributes_GREATER: + value = D3DCMP_GREATER; break; + case javax_media_j3d_RenderingAttributes_GREATER_OR_EQUAL: + value = D3DCMP_GREATEREQUAL; break; + default : + value = D3DCMP_ALWAYS; break; + } + + return value; +} + +/** + * LESS_OR_EQUAL - DEFAULT pixels are drawn if the depth value is less than or equal to the stored depth value in the frame buffer. + * ALWAYS - pixels are always drawn, irrespective of the depth value. This effectively disables depth testing. + * NEVER - pixels are never drawn, irrespective of the depth value. + * EQUAL - pixels are drawn if the depth value is equal to the stored stencil value in the frame buffer. + * NOT_EQUAL - pixels are drawn if the depth value is not equal to the stored depth value in the frame buffer. + * LESS - pixels are drawn if the depth value is less than the stored stencil value in the frame buffer. + * GREATER - pixels are drawn if the depth value is greater than the stored stencil value in the frame buffer. + * GREATER_OR_EQUAL - pixels are drawn if the depth value is greater than or equal to the stored stencil value in the frame buffer. +*/ +DWORD getDepthFunc(jint func) +{ + DWORD value = D3DCMP_LESSEQUAL; + switch(func) + { + case javax_media_j3d_RenderingAttributes_ALWAYS: + value = D3DCMP_ALWAYS; break; + case javax_media_j3d_RenderingAttributes_NEVER: + value = D3DCMP_NEVER; break; + case javax_media_j3d_RenderingAttributes_EQUAL: + value = D3DCMP_EQUAL; break; + case javax_media_j3d_RenderingAttributes_NOT_EQUAL: + value = D3DCMP_NOTEQUAL; break; + case javax_media_j3d_RenderingAttributes_LESS_OR_EQUAL: + value = D3DCMP_LESSEQUAL; break; + case javax_media_j3d_RenderingAttributes_GREATER: + value = D3DCMP_GREATER; break; + case javax_media_j3d_RenderingAttributes_GREATER_OR_EQUAL: + value = D3DCMP_GREATEREQUAL; break; + default : + value = D3DCMP_LESSEQUAL; break; + } + + return value; +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetRenderingAttributes( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean db_write_enable_override, + jboolean db_enable_override) +{ + GetDevice(); + + if (!db_write_enable_override) { + d3dCtx->zWriteEnable = TRUE; + device->SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_TRUE); + device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + } + + if (!db_enable_override) { + d3dCtx->zEnable = TRUE; + device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + } + + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS); + device->SetRenderState(D3DRS_ALPHAREF, 0); + if(d3dCtx->stencilWriteEnable) { + device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + device->SetRenderState( D3DRS_STENCILREF, 0); + device->SetRenderState( D3DRS_STENCILMASK, 0xFFFFFFFF); + device->SetRenderState( D3DRS_STENCILWRITEMASK, 0xFFFFFFFF ); + + // Always increment the stencil value + device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); + device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + d3dCtx->stencilWriteEnable = false; + } + + /* setRasterOp(d3dCtx, R2_COPYPEN); */ + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateRenderingAttributes( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean db_write_enable_override, + jboolean db_enable_override, + jboolean db_enable, + jboolean db_write_enable, + jint db_func, + jfloat at_value, + jint at_func, + jboolean ignoreVertexColors, + jboolean rasterOpEnable, + jint rasterOp, + jboolean userStencilAvailable, + jboolean stencilEnable, + jint stencilFailOp, + jint stencilZFailOp, + jint stencilZPassOp, + jint stencilFunction, + jint stencilReferenceValue, + jint stencilCompareMask, + jint stencilWriteMask) +{ + + GetDevice(); + + DWORD alpha = (DWORD) (at_value * 255 + 0.5f); + + if (!db_enable_override) + { + if (db_enable) + { + d3dCtx->zEnable = TRUE; + device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + } + else + { + d3dCtx->zEnable = FALSE; + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } + } + + if (!db_write_enable_override) + { + d3dCtx->zWriteEnable = db_write_enable; + device->SetRenderState(D3DRS_ZWRITEENABLE, db_write_enable); + // disable ZFunc if ZBuffer is disabled ? no. + // ZFunc must work even when there is no z-buffer enable + device->SetRenderState(D3DRS_ZFUNC, getDepthFunc(db_func)); + } + + if (at_func == javax_media_j3d_RenderingAttributes_ALWAYS) + { + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + } + else + { + device->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + device->SetRenderState(D3DRS_ALPHAREF, alpha); + } + + switch (at_func) + { + case javax_media_j3d_RenderingAttributes_ALWAYS: + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS); + break; + case javax_media_j3d_RenderingAttributes_NEVER: + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_NEVER); + break; + case javax_media_j3d_RenderingAttributes_EQUAL: + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_EQUAL); + break; + case javax_media_j3d_RenderingAttributes_NOT_EQUAL: + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_NOTEQUAL); + break; + case javax_media_j3d_RenderingAttributes_LESS: + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS); + break; + case javax_media_j3d_RenderingAttributes_LESS_OR_EQUAL: + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); + break; + case javax_media_j3d_RenderingAttributes_GREATER: + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); + break; + case javax_media_j3d_RenderingAttributes_GREATER_OR_EQUAL: + device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + break; + } + +/* + stencilFailOp, * + stencilZFailOp, * + stencilZPassOp, * + stencilFunction, * + stencilReferenceValue, * + stencilCompareMask, * + stencilWriteMask * +*/ + if (userStencilAvailable == JNI_TRUE) + { + if (stencilEnable == JNI_TRUE) + { + // Turn on stenciling + device->SetRenderState( D3DRS_STENCILENABLE, TRUE ); + // printf("StencilEnable TRUE\n"); + // Set the function to always pass. + device->SetRenderState( D3DRS_STENCILFUNC, getStencilFunc(stencilFunction) ); + device->SetRenderState( D3DRS_STENCILREF, stencilReferenceValue ); + device->SetRenderState( D3DRS_STENCILMASK, stencilCompareMask ); + device->SetRenderState( D3DRS_STENCILWRITEMASK, stencilWriteMask ); + + // Always increment the stencil value + device->SetRenderState(D3DRS_STENCILFAIL, getStencilOP(stencilFailOp) ); + device->SetRenderState(D3DRS_STENCILZFAIL, getStencilOP(stencilZFailOp)); + device->SetRenderState(D3DRS_STENCILPASS, getStencilOP(stencilZPassOp) ); + } + else + { + device->SetRenderState( D3DRS_STENCILENABLE, FALSE ); + // printf("StencilEnable False\n"); + } + } + /* + else + { + printf("UserStencilEnable False\n"); + } + */ + +}// + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetPolygonAttributes( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + // D3D vertex order is reverse of OGL + d3dCtx->cullMode = D3DCULL_CW; + d3dCtx->fillMode = D3DFILL_SOLID; + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); + d3dCtx->twoSideLightingEnable = false; + device->SetRenderState(D3DRS_DEPTHBIAS, 0); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updatePolygonAttributes( + JNIEnv *env, + jobject obj, + jlong ctx, + jint polygonMode, + jint cullFace, + jboolean backFaceNormalFlip, + jfloat polygonOffset, + jfloat polygonOffsetFactor) +{ + + GetDevice(); + + jfloat zbias = polygonOffset + polygonOffsetFactor; + DWORD zbias_w = 0; + /* + * DirectX support Z-bias from 0 to 16 only and the + * direction is opposite to OGL. If we pass negative + * Z-bias the polygon will not render at all. + * So we map -ve polygon offset to positive value + * and +ve offset to 0. (i.e. we don't support positive + * polygon offset) + */ + if (zbias <= -1) { + zbias_w = max(-zbias/50, 1); + + if (zbias_w > 16) { + zbias_w = 16; + } + } + + device->SetRenderState(D3DRS_DEPTHBIAS, zbias_w); + + if (cullFace == javax_media_j3d_PolygonAttributes_CULL_NONE) { + d3dCtx->cullMode = D3DCULL_NONE; + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } else { + if (cullFace == javax_media_j3d_PolygonAttributes_CULL_BACK) { + d3dCtx->cullMode = D3DCULL_CW; + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); + } else { + d3dCtx->cullMode = D3DCULL_CCW; + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); + } + } + + if (polygonMode == javax_media_j3d_PolygonAttributes_POLYGON_POINT) { + d3dCtx->fillMode = D3DFILL_POINT; + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_POINT); + } else if (polygonMode == javax_media_j3d_PolygonAttributes_POLYGON_LINE) { + d3dCtx->fillMode = D3DFILL_WIREFRAME; + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + } else { + d3dCtx->fillMode = D3DFILL_SOLID; + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + } + + /* + if (debug && !isBackFaceMessOutput && + (backFaceNormalFlip) && (cullFace != javax_media_j3d_PolygonAttributes_CULL_BACK)) { + isBackFaceMessOutput = true; + printf("BackFaceNormalFlip is not support !\n"); + } + */ +} + +/* +void printDepthFunc(jint func) +{ + DWORD value = D3DCMP_LESSEQUAL; + printf("DepthFunc: "); + switch(func) + { + case javax_media_j3d_RenderingAttributes_ALWAYS: + printf(" D3DCMP_ALWAYS\n"); break; + case javax_media_j3d_RenderingAttributes_NEVER: + printf(" D3DCMP_NEVER\n"); break; + case javax_media_j3d_RenderingAttributes_EQUAL: + printf(" D3DCMP_EQUAL\n"); break; + case javax_media_j3d_RenderingAttributes_NOT_EQUAL: + printf(" D3DCMP_NOTEQUAL\n"); break; + case javax_media_j3d_RenderingAttributes_LESS_OR_EQUAL: + printf(" D3DCMP_LESSEQUAL\n"); break; + case javax_media_j3d_RenderingAttributes_GREATER: + printf(" D3DCMP_GREATER\n"); break; + case javax_media_j3d_RenderingAttributes_GREATER_OR_EQUAL: + printf(" D3DCMP_GREATEREQUAL\n"); break; + default : + printf(" D3DCMP_LESSEQUAL\n"); break; + } +} + +*/ + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetLineAttributes( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + // GetDevice(); + + // D3D don't support Line width + // glLineWidth(1); + // D3D9 doesnot support line Patterns + // @TODO must update this to use ID3DXLine Interface + /* + D3DLINEPATTERN pattern; + pattern.wRepeatFactor = 0; + pattern.wLinePattern = 0; + device->SetRenderState(D3DRS_LINEPATTERN, + *((LPDWORD) (&pattern))); + */ +} + + +// Note that some graphics card don't support it. +// In this case use RGB Emulation. +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateLineAttributes( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat lineWidth, + jint linePattern, + jint linePatternMask, + jint linePatternScaleFactor, + jboolean lineAntialiasing) +{ + // GetDevice(); + + //Alessandro + //D3DLINEPATTERN pattern; + + /* + if (lineWidth > 1) { + if (debug && !isLineWidthMessOutput) { + isLineWidthMessOutput = true; + printf("Line width > 1 not support !\n"); + } + } + */ + // glLineWidth(lineWidth); + /** Alessandro + if (linePattern == javax_media_j3d_LineAttributes_PATTERN_SOLID) { + pattern.wRepeatFactor = 0; + pattern.wLinePattern = 0; + + } else { + **/ + + /* + if (!d3dCtx->deviceInfo->linePatternSupport) { + if (debug && !isLinePatternMessOutput) { + printf("Device not support line pattern !\n"); + isLinePatternMessOutput = false; + } + } + */ + /** alessandro + if (linePattern == javax_media_j3d_LineAttributes_PATTERN_DASH) { // dashed lines + pattern.wRepeatFactor = 1; + pattern.wLinePattern = 0x00ff; + } else if (linePattern == javax_media_j3d_LineAttributes_PATTERN_DOT) { // dotted lines + pattern.wRepeatFactor = 1; + pattern.wLinePattern = 0x0101; + } else if (linePattern == javax_media_j3d_LineAttributes_PATTERN_DASH_DOT) { // dash-dotted lines + pattern.wRepeatFactor = 1; + pattern.wLinePattern = 0x087f; + } else if (linePattern == javax_media_j3d_LineAttributes_PATTERN_USER_DEFINED) { // user-defined mask + pattern.wRepeatFactor = linePatternScaleFactor; + pattern.wLinePattern = (WORD) linePatternMask; + } + } + + device->SetRenderState(D3DRS_LINEPATTERN, + *((LPDWORD) (&pattern))); + **/ + /* + if (lineAntialiasing == JNI_TRUE) { + glEnable (GL_LINE_SMOOTH); + } else { + glDisable (GL_LINE_SMOOTH); + } + */ +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetPointAttributes( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + + if (d3dCtx->pointSize != 1.0f) { + d3dCtx->pointSize = 1.0f; + device->SetRenderState(D3DRS_POINTSIZE, *((LPDWORD) &d3dCtx->pointSize)); + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updatePointAttributes( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat pointSize, + jboolean pointAntialiasing) +{ + // point Antialiasing not support by D3D + GetDevice(); + + if (pointSize < 1.0f) { + // We don't want to set pointSize unnecessary and + // trigger the software vertex processing mode in + // D3DVertexBuffer if possible. It is an error + // to set pointSize to zero under OGL. + pointSize = 1.0f; + } + + if (d3dCtx->pointSize != pointSize) { + device->SetRenderState(D3DRS_POINTSIZE, *((LPDWORD) + &pointSize)); + d3dCtx->pointSize = pointSize; + } +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetTexCoordGeneration( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + + int tus = d3dCtx->texUnitStage; + + if (tus >= d3dCtx->bindTextureIdLen) { + return; + } + + d3dCtx->texGenMode[tus] = TEX_GEN_NONE; + + if (d3dCtx->texTransformSet[tus]) { + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), + &(d3dCtx->texTransform[tus])); + } + + device->SetTextureStageState(tus, + D3DTSS_TEXCOORDINDEX, + D3DTSS_TCI_PASSTHRU); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexCoordGeneration( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean enable, + jint genMode, + jint format, + jfloat planeSx, + jfloat planeSy, + jfloat planeSz, + jfloat planeSw, + jfloat planeTx, + jfloat planeTy, + jfloat planeTz, + jfloat planeTw, + jfloat planeRx, + jfloat planeRy, + jfloat planeRz, + jfloat planeRw, + jfloat planeQx, + jfloat planeQy, + jfloat planeQz, + jfloat planeQw, + jdoubleArray eyeToVworld) +{ + + D3DXMATRIX m; + jdouble *mv; + GetDevice(); + + int tus = d3dCtx->texUnitStage; + + + if (tus >= d3dCtx->bindTextureIdLen) { + return; + } + + if (!enable) { + device->SetTextureStageState(tus, + D3DTSS_TEXCOORDINDEX, + D3DTSS_TCI_PASSTHRU); + d3dCtx->texGenMode[tus] = TEX_GEN_NONE; + return; + } + + d3dCtx->texCoordFormat[tus] = coordFormatTable[format]; + +// printf("TexCoordGenerationRetained_updateNative texStage %d set Mode %d, format %d, texTransformSet %d\n", tus, genMode, format, d3dCtx->texTransformSet[tus]); + + switch (genMode) { + case javax_media_j3d_TexCoordGeneration_EYE_LINEAR: + // Generated Coordinate = p1'*x + p2'*y + p3'*z + p4'*w; + // where (p1', p2', p3', p4') = (p1 p2 p3 p4)*eyeToVworld + mv = (jdouble * ) env->GetPrimitiveArrayCritical(eyeToVworld, 0); + m._11 = planeSx*mv[0] + planeSy*mv[4] + planeSz*mv[8] + planeSw*mv[12]; + m._21 = planeSx*mv[1] + planeSy*mv[5] + planeSz*mv[9] + planeSw*mv[13]; + m._31 = planeSx*mv[2] + planeSy*mv[6] + planeSz*mv[10] + planeSw*mv[14]; + m._41 = planeSx*mv[3] + planeSy*mv[7] + planeSz*mv[11] + planeSw*mv[15]; + m._12 = planeTx*mv[0] + planeTy*mv[4] + planeTz*mv[8] + planeTw*mv[12]; + m._22 = planeTx*mv[1] + planeTy*mv[5] + planeTz*mv[9] + planeTw*mv[13]; + m._32 = planeTx*mv[2] + planeTy*mv[6] + planeTz*mv[10] + planeTw*mv[14]; + m._42 = planeTx*mv[3] + planeTy*mv[7] + planeTz*mv[11] + planeTw*mv[15]; + + + if (format >= javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_3) { + m._13 = planeRx*mv[0] + planeRy*mv[4] + planeRz*mv[8] + planeRw*mv[12]; + m._23 = planeRx*mv[1] + planeRy*mv[5] + planeRz*mv[9] + planeRw*mv[13]; + m._33 = planeRx*mv[2] + planeRy*mv[6] + planeRz*mv[10] + planeRw*mv[14]; + m._43 = planeRx*mv[3] + planeRy*mv[7] + planeRz*mv[11] + planeRw*mv[15]; + + if (format >= javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_4) { + m._14 = planeQx*mv[0] + planeQy*mv[4] + planeQz*mv[8] + planeQw*mv[12]; + m._24 = planeQx*mv[1] + planeQy*mv[5] + planeQz*mv[9] + planeQw*mv[13]; + m._34 = planeQx*mv[2] + planeQy*mv[6] + planeQz*mv[10] + planeQw*mv[14]; + m._44 = planeQx*mv[3] + planeQy*mv[7] + planeQz*mv[11] + planeQw*mv[15]; + } else { + m._14 = 0; + m._24 = 0; + m._34 = 0; + m._44 = 0; + } + } else { + m._13 = 0; + m._23 = 0; + m._33 = 0; + m._43 = 0; + m._14 = 0; + m._24 = 0; + m._34 = 0; + m._44 = 0; + } + + env->ReleasePrimitiveArrayCritical(eyeToVworld, mv, 0); + + if (d3dCtx->texTransformSet[tus]) { + device->MultiplyTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus) , &m); + } else { + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), &m); + d3dCtx->texTransformSet[tus] = true; + } + d3dCtx->texGenMode[tus] = TEX_EYE_LINEAR; + + break; + + case javax_media_j3d_TexCoordGeneration_SPHERE_MAP: + /* + The matrix has to scale and translate the texture coordinates + Since in sphere map Tx = Nx/2 + 0.5, Ty = Ny/2 + 0.5 + */ + m._11 = 0.5f; m._12 = 0.0f; m._13 = 0.0f; m._14 = 0.0f; + m._21 = 0.0f; m._22 = 0.5f; m._23 = 0.0f; m._24 = 0.0f; + m._31 = 0.0f; m._32 = 0.0f; m._33 = 1.0f; m._34 = 0.0f; + m._41 = 0.5f; m._42 = 0.5f; m._43 = 0.0f; m._44 = 1.0f; + + if (d3dCtx->texTransformSet[tus]) { + // If texture transform already set, multiple by this + // matrix. + device->MultiplyTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus) , &m); + } else { + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), &m); + d3dCtx->texTransformSet[tus] = true; + } + + d3dCtx->texGenMode[tus] = TEX_SPHERE_MAP; + break; + case javax_media_j3d_TexCoordGeneration_OBJECT_LINEAR: + // OBJECT_LINEAR not support by D3D, we'll do it ourselve. + d3dCtx->planeS[tus][0] = planeSx; + d3dCtx->planeS[tus][1] = planeSy; + d3dCtx->planeS[tus][2] = planeSz; + d3dCtx->planeS[tus][3] = planeSw; + d3dCtx->planeT[tus][0] = planeTx; + d3dCtx->planeT[tus][1] = planeTy; + d3dCtx->planeT[tus][2] = planeTz; + d3dCtx->planeT[tus][3] = planeTw; + d3dCtx->planeR[tus][0] = planeRx; + d3dCtx->planeR[tus][1] = planeRy; + d3dCtx->planeR[tus][2] = planeRz; + d3dCtx->planeR[tus][3] = planeRw; + d3dCtx->planeQ[tus][0] = planeQx; + d3dCtx->planeQ[tus][1] = planeQy; + d3dCtx->planeQ[tus][2] = planeQz; + d3dCtx->planeQ[tus][3] = planeQw; + d3dCtx->texGenMode[tus] = TEX_OBJ_LINEAR; + break; + case javax_media_j3d_TexCoordGeneration_NORMAL_MAP: + d3dCtx->texGenMode[tus] = TEX_NORMAL_MAP; + break; + case javax_media_j3d_TexCoordGeneration_REFLECTION_MAP: + d3dCtx->texGenMode[tus] = TEX_REFLECT_MAP; + break; + default: + printf("Unknown TexCoordinate Generation mode %d\n", genMode); + } +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetTextureAttributes( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + + int tus = d3dCtx->texUnitStage; + + if (tus >= d3dCtx->bindTextureIdLen) { + return; + } + + if (d3dCtx->texTransformSet[tus]) { + d3dCtx->texTransformSet[tus] = false; + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), + &identityMatrix); + } + + // perspCorrectionMode always turn on in DX8.0 if device support + + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG1, D3DTA_TEXTURE); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureAttributes( + JNIEnv *env, + jobject obj, + jlong ctx, + jdoubleArray transform, jboolean isIdentityT, + jint textureMode, + jint perspCorrectionMode, + jfloat textureBlendColorRed, + jfloat textureBlendColorGreen, + jfloat textureBlendColorBlue, + jfloat textureBlendColorAlpha, + jint format) +{ + + D3DCOLOR textureBlendColor; + BOOL alphaDisable = FALSE; + + GetDevice(); + + int tus = d3dCtx->texUnitStage; + + if (tus >= d3dCtx->bindTextureIdLen) { + return; + } + + // perspCorrectionMode always turn on in DX8.0 if device support + + if (isIdentityT) { + d3dCtx->texTransformSet[tus] = false; + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), + &identityMatrix); + } else { + D3DXMATRIX *m = &(d3dCtx->texTransform[tus]); + jdouble *mx_ptr = reinterpret_cast( + env->GetPrimitiveArrayCritical(transform, NULL)); + CopyTranspose((*m), mx_ptr); + + env->ReleasePrimitiveArrayCritical(transform, mx_ptr, 0); + /* + printf("set Tex Transform \n"); + printf("%f, %f, %f, %f\n", (*m)._11, (*m)._12, (*m)._13, (*m)._14); + printf("%f, %f, %f, %f\n", (*m)._21, (*m)._22, (*m)._23, (*m)._24); + printf("%f, %f, %f, %f\n", (*m)._31, (*m)._23, (*m)._33, (*m)._34); + printf("%f, %f, %f, %f\n", (*m)._41, (*m)._42, (*m)._43, (*m)._44); + */ + d3dCtx->texTransformSet[tus] = true; + d3dCtx->texTranslateSet[tus] = false; + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), m); + } + + /* set texture environment mode */ + + switch (textureMode) { + case javax_media_j3d_TextureAttributes_MODULATE: + switch (format) { + case J3D_RGBA: + case INTENSITY: + case LUMINANCE_ALPHA: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_MODULATE); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_COLORARG2, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_MODULATE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG2, D3DTA_CURRENT); + break; + case J3D_RGB: + case LUMINANCE: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_MODULATE); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_COLORARG2, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_DISABLE); + break; + case ALPHA: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_MODULATE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG2, D3DTA_CURRENT); + break; + default: + printf("Format %d not support\n", format); + } + break; + case javax_media_j3d_TextureAttributes_DECAL: + switch (format) { + case J3D_RGBA: + case INTENSITY: + case LUMINANCE_ALPHA: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_COLORARG2, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_DISABLE); + break; + case J3D_RGB: + case LUMINANCE: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_DISABLE); + break; + case ALPHA: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + break; + default: + printf("Format %d not support\n", format); + } + break; + case javax_media_j3d_TextureAttributes_BLEND: + // Two pass is needed for this mode, the first pass + // will + + textureBlendColor = D3DCOLOR_COLORVALUE(textureBlendColorRed, + textureBlendColorGreen, + textureBlendColorBlue, + textureBlendColorAlpha); + + device->SetRenderState(D3DRS_TEXTUREFACTOR, + *((LPDWORD) &textureBlendColor)); + + switch (format) { + case ALPHA: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_MODULATE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG2, D3DTA_CURRENT); + break; + case INTENSITY: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_COLORARG2, D3DTA_TFACTOR); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_BLENDTEXTUREALPHA); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG1, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG2, D3DTA_TFACTOR); + break; + case J3D_RGB: + case LUMINANCE: + device->SetTextureStageState(0, + D3DTSS_ALPHAOP, + D3DTOP_DISABLE); + alphaDisable = TRUE; + // fallthrough + case J3D_RGBA: + case LUMINANCE_ALPHA: + + if (!d3dCtx->deviceInfo->texLerpSupport) { + // Use two pass, first pass will enable specular and + // compute Cf*(1 - Ct), second pass will disable specular and + // comptue Cc*Ct. Note that multi-texturing is disable + // in this case, so stage 0 is always use. + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + device->SetTextureStageState(0, D3DTSS_COLORARG1, + D3DTA_TEXTURE|D3DTA_COMPLEMENT); + device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + + if (!alphaDisable) { + device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + } + } else { + device->SetTextureStageState(tus, D3DTSS_COLOROP, D3DTOP_LERP); + device->SetTextureStageState(tus, D3DTSS_COLORARG0, D3DTA_TEXTURE); + device->SetTextureStageState(tus, D3DTSS_COLORARG1, D3DTA_TFACTOR); + device->SetTextureStageState(tus, D3DTSS_COLORARG2, D3DTA_CURRENT); + + if (!alphaDisable) { + device->SetTextureStageState(tus, D3DTSS_ALPHAOP, D3DTOP_LERP); + device->SetTextureStageState(tus, D3DTSS_ALPHAARG0, D3DTA_TEXTURE); + device->SetTextureStageState(tus, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + device->SetTextureStageState(tus, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + } + } + break; + default: + printf("Format %d not support\n", format); + } + + + break; + case javax_media_j3d_TextureAttributes_REPLACE: + switch (format) { + case J3D_RGBA: + case INTENSITY: + case LUMINANCE_ALPHA: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + break; + case J3D_RGB: + case LUMINANCE: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_DISABLE); + break; + case ALPHA: + device->SetTextureStageState(tus, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_COLORARG1, D3DTA_CURRENT); + device->SetTextureStageState(tus, + D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + device->SetTextureStageState(tus, + D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + break; + default: + printf("Format %d not support\n", format); + } + break; + default: + // TEXTURE COMBINER case + break; + } +} + + +// // This procedure is invoked after Blend2Pass to restore the original value +// extern "C" JNIEXPORT +// void JNICALL Java_javax_media_j3d_NativePipeline_restoreBlend1Pass( +// JNIEnv *env, +// jobject obj, +// jlong ctx) +// { +// GetDevice(); + +// device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); +// device->SetTextureStageState(0, D3DTSS_COLORARG1, +// D3DTA_TEXTURE|D3DTA_COMPLEMENT); +// device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + +// device->SetRenderState(D3DRS_SRCBLEND, +// d3dCtx->srcBlendFunc); +// device->SetRenderState(D3DRS_DESTBLEND, +// d3dCtx->dstBlendFunc); +// device->SetRenderState(D3DRS_ALPHABLENDENABLE, +// d3dCtx->blendEnable); +// } + + +// extern "C" JNIEXPORT +// void JNICALL Java_javax_media_j3d_NativePipeline_updateBlend2Pass( +// JNIEnv *env, +// jobject obj, +// jlong ctx) +// { +// GetDevice(); +// device->GetRenderState(D3DRS_SRCBLEND, +// &d3dCtx->srcBlendFunc); +// device->GetRenderState(D3DRS_DESTBLEND, +// &d3dCtx->dstBlendFunc); +// device->GetRenderState(D3DRS_ALPHABLENDENABLE, +// &d3dCtx->blendEnable); + +// device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); +// device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); +// device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); +// device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); +// device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); +// device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR); +// } + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateCombiner( + JNIEnv *env, + jobject obj, + jlong ctx, + jint combineRgbMode, + jint combineAlphaMode, + jintArray combineRgbSrc, + jintArray combineAlphaSrc, + jintArray combineRgbFcn, + jintArray combineAlphaFcn, + jint combineRgbScale, + jint combineAlphaScale) +{ + + GetDevice(); + + DWORD ts = d3dCtx->texUnitStage; + + jint *rgbSrc = (jint *) env->GetPrimitiveArrayCritical(combineRgbSrc, NULL); + jint *alphaSrc = (jint *) env->GetPrimitiveArrayCritical(combineAlphaSrc, NULL); + jint *rgbFcn = (jint *) env->GetPrimitiveArrayCritical(combineRgbFcn, NULL); + jint *alphaFcn = (jint *) env->GetPrimitiveArrayCritical(combineAlphaFcn, NULL); + + + device->SetTextureStageState(ts, D3DTSS_COLOROP, + combineFunctionTable[(combineRgbMode << 2) + combineRgbScale - 1]); + + if (combineRgbMode != javax_media_j3d_TextureAttributes_COMBINE_INTERPOLATE) { + device->SetTextureStageState(ts, D3DTSS_COLORARG1, + combineSourceTable[(rgbSrc[0] << 2) + rgbFcn[0]]); + if (combineRgbMode != javax_media_j3d_TextureAttributes_COMBINE_REPLACE) { + device->SetTextureStageState(ts, D3DTSS_COLORARG2, + combineSourceTable[(rgbSrc[1] << 2) + rgbFcn[1]]); + } + } else { + device->SetTextureStageState(ts, D3DTSS_COLORARG1, + combineSourceTable[(rgbSrc[2] << 2) + rgbFcn[2]]); + device->SetTextureStageState(ts, D3DTSS_COLORARG2, + combineSourceTable[(rgbSrc[0] << 2) + rgbFcn[0]]); + device->SetTextureStageState(ts, D3DTSS_COLORARG0, + combineSourceTable[(rgbSrc[1] << 2) + rgbFcn[1]]); + } + + device->SetTextureStageState(ts, D3DTSS_ALPHAOP, + combineFunctionTable[(combineAlphaMode << 2) + combineAlphaScale - 1]); + + if (combineAlphaMode != javax_media_j3d_TextureAttributes_COMBINE_INTERPOLATE) { + device->SetTextureStageState(ts, D3DTSS_ALPHAARG1, + combineSourceTable[(alphaSrc[0] << 2) + alphaFcn[0]]); + if (combineAlphaMode != javax_media_j3d_TextureAttributes_COMBINE_REPLACE) { + device->SetTextureStageState(ts, D3DTSS_ALPHAARG2, + combineSourceTable[(alphaSrc[1] << 2) + alphaFcn[1]]); + } + } else { + device->SetTextureStageState(ts, D3DTSS_ALPHAARG0, + combineSourceTable[(alphaSrc[2] << 2) + alphaFcn[2]]); + device->SetTextureStageState(ts, D3DTSS_ALPHAARG1, + combineSourceTable[(alphaSrc[0] << 2) + alphaFcn[0]]); + device->SetTextureStageState(ts, D3DTSS_ALPHAARG2, + combineSourceTable[(alphaSrc[1] << 2) + alphaFcn[1]]); + } + + env->ReleasePrimitiveArrayCritical(combineRgbSrc, rgbSrc, 0); + env->ReleasePrimitiveArrayCritical(combineAlphaSrc, alphaSrc, 0); + env->ReleasePrimitiveArrayCritical(combineRgbFcn, rgbFcn, 0); + env->ReleasePrimitiveArrayCritical(combineAlphaFcn, alphaFcn, 0); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureColorTable( + JNIEnv *env, + jobject obj, + jlong ctx, + jint numComponents, + jint colorTableSize, + jintArray textureColorTable) +{ + // Not support by D3D +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateMaterialColor( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat transparency) +{ + GetDevice(); + + d3dCtx->currentColor_r = colorRed; + d3dCtx->currentColor_g = colorGreen; + d3dCtx->currentColor_b = colorBlue; + d3dCtx->currentColor_a = transparency; + + d3dCtx->isLightEnable = false; + device->SetRenderState(D3DRS_LIGHTING, false); + if (d3dCtx->resetColorTarget) { + device->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, + D3DMCS_COLOR1); + device->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, + D3DMCS_MATERIAL); + device->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, + D3DMCS_MATERIAL); + device->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, + D3DMCS_MATERIAL); + d3dCtx->resetColorTarget = false; + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateMaterial( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat transparency, + jfloat aRed, + jfloat aGreen, + jfloat aBlue, + jfloat eRed, + jfloat eGreen, + jfloat eBlue, + jfloat dRed, + jfloat dGreen, + jfloat dBlue, + jfloat sRed, + jfloat sGreen, + jfloat sBlue, + jfloat shininess, + jint colorTarget, + jboolean lightEnable) +{ + D3DMATERIAL9 material; + + GetDevice(); + + switch (colorTarget) { + case javax_media_j3d_Material_DIFFUSE: + device->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, + D3DMCS_COLOR1); + break; + case javax_media_j3d_Material_SPECULAR: + device->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, + D3DMCS_COLOR1); + d3dCtx->resetColorTarget = true; + break; + case javax_media_j3d_Material_AMBIENT: + device->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, + D3DMCS_COLOR1); + d3dCtx->resetColorTarget = true; + break; + case javax_media_j3d_Material_AMBIENT_AND_DIFFUSE: + device->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, + D3DMCS_COLOR1); + device->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, + D3DMCS_COLOR1); + d3dCtx->resetColorTarget = true; + break; + case javax_media_j3d_Material_EMISSIVE: + device->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, + D3DMCS_COLOR1); + d3dCtx->resetColorTarget = true; + break; + default: + printf("Material updateNative: Uknown colorTarget %d\n", colorTarget); + } + + material.Power = shininess; + + CopyColor(material.Emissive, eRed, eGreen, eBlue, 1.0f); + CopyColor(material.Ambient, aRed, aGreen, aBlue, 1.0f); + CopyColor(material.Specular, sRed, sGreen, sBlue, 1.0f); + + d3dCtx->currentColor_a = transparency; + + if (lightEnable) { + d3dCtx->currentColor_r = dRed; + d3dCtx->currentColor_g = dGreen; + d3dCtx->currentColor_b = dBlue; + + CopyColor(material.Diffuse, dRed, dGreen, dBlue, + transparency); + + } else { + d3dCtx->currentColor_r = colorRed; + d3dCtx->currentColor_g = colorGreen; + d3dCtx->currentColor_b = colorBlue; + + CopyColor(material.Diffuse, colorRed, colorGreen, + colorBlue, transparency); + } + + + d3dCtx->isLightEnable = lightEnable; + device->SetRenderState(D3DRS_LIGHTING, lightEnable); + device->SetMaterial(&material); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetTransparency( + JNIEnv *env, + jobject obj, + jlong ctx, + jint geometryType, + jint polygonMode, + jboolean lineAA, + jboolean pointAA) +{ + GetDevice(); + + // Line/Point Antialiasing not support + + /* + if (((((geometryType & LINE) != 0) || polygonMode == POLYGON_LINE) + && lineAA == JNI_TRUE) || + ((((geometryType & _POINT) != 0) || polygonMode == POLYGON_POINT) + && pointAA == JNI_TRUE)) { + device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } else { + */ + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + // } +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTransparencyAttributes( + JNIEnv *env, + jobject tr, + jlong ctx, + jfloat transparency, + jint geometryType, + jint polygonMode, + jboolean lineAA, + jboolean pointAA, + jint transparencyMode, + jint srcBlendFunction, + jint dstBlendFunction) +{ + + GetDevice(); + + // No screen door transparency in D3D, use BLENDED + // Don't know how to use STIPPLEDALPHA either. + /* + if (transparencyMode != TRANS_SCREEN_DOOR) { + device->SetRenderState(D3DRS_STIPPLEDALPHA, FALSE); + } else { + device->SetRenderState(D3DRS_STIPPLEDALPHA, TRUE); + } + */ + + if (transparencyMode < javax_media_j3d_TransparencyAttributes_NONE) { + /* + ((((geometryType & LINE) != 0) || polygonMode == POLYGON_LINE) + && lineAA == JNI_TRUE) || + ((((geometryType & _POINT) != 0) || polygonMode == POLYGON_POINT) + && pointAA == JNI_TRUE)) { + */ + device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + device->SetRenderState(D3DRS_SRCBLEND, + blendFunctionTable[srcBlendFunction]); + device->SetRenderState(D3DRS_DESTBLEND, + blendFunctionTable[dstBlendFunction]); + } else { + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetColoringAttributes( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat transparency, + jboolean lightEnable) +{ + + GetDevice(); + + if (!lightEnable) { + d3dCtx->currentColor_r = colorRed; + d3dCtx->currentColor_g = colorGreen; + d3dCtx->currentColor_b = colorBlue; + d3dCtx->currentColor_a = transparency; + } + device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + // No line smooth in D3D +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateColoringAttributes( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat dRed, + jfloat dGreen, + jfloat dBlue, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat transparency, + jboolean lightEnable, + jint shadeModel) +{ + + GetDevice(); + + d3dCtx->currentColor_a = transparency; + if (lightEnable) { + d3dCtx->currentColor_r = dRed; + d3dCtx->currentColor_g = dGreen; + d3dCtx->currentColor_b = dBlue; + } else { + d3dCtx->currentColor_r = colorRed; + d3dCtx->currentColor_g = colorGreen; + d3dCtx->currentColor_b = colorBlue; + } + + + if (shadeModel == javax_media_j3d_ColoringAttributes_SHADE_FLAT) { + device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); + } else { + device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + } +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetTextureNative( + JNIEnv *env, + jobject obj, + jlong ctx, + jint texUnitIndex) +{ + GetDevice(); + + if (texUnitIndex < 0) { + texUnitIndex = 0; + } + + d3dCtx->texUnitStage = texUnitIndex; + + if (texUnitIndex >= d3dCtx->bindTextureIdLen) { + return; + } + device->SetTexture(texUnitIndex, NULL); + d3dCtx->bindTextureId[texUnitIndex] = -1; + + if (d3dCtx->texTransformSet[texUnitIndex]) { + d3dCtx->texTransformSet[texUnitIndex] = false; + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + texUnitIndex), + &identityMatrix); + } + d3dCtx->texGenMode[texUnitIndex] = TEX_GEN_NONE; + device->SetTextureStageState(texUnitIndex, + D3DTSS_TEXCOORDINDEX, + D3DTSS_TCI_PASSTHRU); + device->SetTextureStageState(texUnitIndex, + D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(texUnitIndex, + D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(texUnitIndex, + D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + device->SetTextureStageState(texUnitIndex, + D3DTSS_ALPHAARG1, D3DTA_TEXTURE); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_bindTexture2D( + JNIEnv *env, + jobject obj, + jlong ctx, + jint objectId, + jboolean enable) +{ + GetDevice(); + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + return; + } + + if (!enable) { + device->SetTexture(d3dCtx->texUnitStage, NULL); + d3dCtx->bindTextureId[d3dCtx->texUnitStage] = -1; + } else { + if (d3dCtx->bindTextureId[d3dCtx->texUnitStage] == objectId) { + return; + } + + if (objectId >= d3dCtx->textureTableLen) { + DWORD i; + DWORD len = max(objectId+1, d3dCtx->textureTableLen << 1); + LPDIRECT3DTEXTURE9 *newTable = (LPDIRECT3DTEXTURE9 *) + malloc(sizeof(LPDIRECT3DTEXTURE9) * len); + + if (newTable == NULL) { + printf("Not enough memory to alloc texture table of size %d.\n", len); + return; + } + for (i=0; i < d3dCtx->textureTableLen; i++) { + newTable[i] = d3dCtx->textureTable[i]; + } + for (i=d3dCtx->textureTableLen; i < len; i++) { + newTable[i] = NULL; + } + d3dCtx->textureTableLen = len; + SafeFree(d3dCtx->textureTable); + d3dCtx->textureTable = newTable; + } + + d3dCtx->bindTextureId[d3dCtx->texUnitStage] = objectId; + if (d3dCtx->textureTable[objectId] != NULL) { + device->SetTexture(d3dCtx->texUnitStage, + d3dCtx->textureTable[objectId]); + } + // else we will bind this in updateTextureImage + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DFilterModes( + JNIEnv *env, + jobject obj, + jlong ctx, + jint minFilter, + jint magFilter) +{ + GetDevice(); + + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + return; + } + + d3dCtx->texLinearMode = false; + + /* set texture min filter */ + switch (minFilter) { + case javax_media_j3d_Texture_FASTEST: + case javax_media_j3d_Texture_BASE_LEVEL_POINT: + device->SetSamplerState(d3dCtx->texUnitStage, + D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MIPFILTER, D3DTEXF_POINT); + break; + case javax_media_j3d_Texture_BASE_LEVEL_LINEAR: + d3dCtx->texLinearMode = true; + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MIPFILTER, D3DTEXF_POINT); + break; + case javax_media_j3d_Texture_MULTI_LEVEL_POINT: + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + break; + case javax_media_j3d_Texture_NICEST: + case javax_media_j3d_Texture_MULTI_LEVEL_LINEAR: + d3dCtx->texLinearMode = true; + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + break; + } + + /* set texture mag filter */ + switch (magFilter) { + case javax_media_j3d_Texture_FASTEST: + case javax_media_j3d_Texture_BASE_LEVEL_POINT: + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MAGFILTER, D3DTEXF_POINT); + break; + case javax_media_j3d_Texture_NICEST: + case javax_media_j3d_Texture_BASE_LEVEL_LINEAR: + d3dCtx->texLinearMode = true; + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + break; + } + + return; +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DLodRange( + JNIEnv *env, + jobject obj, + jlong ctx, + jint baseLevel, + jint maximumLevel, + jfloat minimumLod, + jfloat maximumLod) +{ +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DLodOffset( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat lodOffsetS, + jfloat lodOffsetT, + jfloat lodOffsetR) +{ + /* not supported */ +} + +void updateTextureBoundary(JNIEnv *env, + jobject obj, + jlong ctx, + jint boundaryModeS, + jint boundaryModeT, + jint boundaryModeR, + jfloat boundaryRed, + jfloat boundaryGreen, + jfloat boundaryBlue, + jfloat boundaryAlpha) +{ + GetDevice(); + + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + return; + } + + /* set texture wrap parameter */ + BOOL useBorderMode = FALSE; + + // D3D ignored border color in CLAMP mode. + // Instead D3D use Border color in D3DTADDRESS_BORDER only. + // So we approximate the effect by using D3DTADDRESS_BORDER + // mode if linear filtering mode is used. + + switch (boundaryModeS) { + case javax_media_j3d_Texture_WRAP: + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSU, + D3DTADDRESS_WRAP); + break; + case javax_media_j3d_Texture_CLAMP: + if (!d3dCtx->texLinearMode || !d3dCtx->deviceInfo->texBorderModeSupport) { + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSU, + D3DTADDRESS_CLAMP); + } else { + useBorderMode = TRUE; + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSU, + D3DTADDRESS_BORDER); + } + break; + } + + switch (boundaryModeT) { + case javax_media_j3d_Texture_WRAP: + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSV, + D3DTADDRESS_WRAP); + break; + case javax_media_j3d_Texture_CLAMP: + if (!d3dCtx->texLinearMode || !d3dCtx->deviceInfo->texBorderModeSupport) { + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSV, + D3DTADDRESS_CLAMP); + } else { + useBorderMode = TRUE; + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSV, + D3DTADDRESS_BORDER); + } + break; + } + + if (boundaryModeR >= 0) { + switch (boundaryModeR) { + case javax_media_j3d_Texture_WRAP: + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSW, + D3DTADDRESS_WRAP); + break; + case javax_media_j3d_Texture_CLAMP: + if (!d3dCtx->texLinearMode || !d3dCtx->deviceInfo->texBorderModeSupport) { + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSW, + D3DTADDRESS_CLAMP); + } else { + useBorderMode = TRUE; + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_ADDRESSW, + D3DTADDRESS_BORDER); + } + break; + } + } + + if (useBorderMode) { + D3DCOLOR color = D3DCOLOR_COLORVALUE(boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_BORDERCOLOR, + *((DWORD *) &color)); + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DBoundary( + JNIEnv *env, + jobject obj, + jlong ctx, + jint boundaryModeS, + jint boundaryModeT, + jfloat boundaryRed, + jfloat boundaryGreen, + jfloat boundaryBlue, + jfloat boundaryAlpha) +{ + updateTextureBoundary(env, obj, ctx, boundaryModeS, + boundaryModeT, -1, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DSharpenFunc( + JNIEnv *env, + jobject obj, + jlong ctx, + jint numPts, + jfloatArray pts) +{ +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DFilter4Func( + JNIEnv *env, + jobject obj, + jlong ctx, + jint numPts, + jfloatArray pts) +{ +} + + +void updateTextureAnisotropicFilter( + jlong ctx, + jfloat degree) +{ + GetDevice(); + + if (degree > 1) { + DWORD deg = degree + 0.5f; // round float to int + // This will overwrite the previous setting in + // updateTextureFilterModes() + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MINFILTER, + D3DTEXF_ANISOTROPIC); + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MAGFILTER, + D3DTEXF_ANISOTROPIC); + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MIPFILTER, + D3DTEXF_ANISOTROPIC); + + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MAXANISOTROPY, deg); + } else { + // updateTextureFilterModes() will always invoke before + // updateTextureAnisotropicFilter() to set Filter mode + // correctly. + device->SetSamplerState (d3dCtx->texUnitStage, + D3DSAMP_MAXANISOTROPY, 1); + } + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DAnisotropicFilter( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat degree) +{ + updateTextureAnisotropicFilter(ctx, degree); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DAnisotropicFilter( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat degree) +{ + GetCtx(); + + if (d3dCtx->deviceInfo->maxTextureDepth > 0) { + updateTextureAnisotropicFilter(ctx, degree); + } + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapAnisotropicFilter( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat degree) +{ + updateTextureAnisotropicFilter(ctx, degree); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DSubImage( + JNIEnv *env, + jobject obj, + jlong ctx, + jint level, + jint xoffset, + jint yoffset, + jint textureFormat, + jint imageFormat, + jint imgXOffset, + jint imgYOffset, + jint tilew, + jint width, + jint height, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + /* Note: useAutoMipMap is not use for SubImage in the d3d pipe */ + GetDevice(); + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + return; + } + + INT currBindTex = d3dCtx->bindTextureId[d3dCtx->texUnitStage]; + + if ((currBindTex < 1) || + (currBindTex >= d3dCtx->textureTableLen)) { + if (debug) { + printf("Internal Error : UpdateTextureSubImage bind texture ID %d, textureTableLen %d, texUnitStage = %d \n", currBindTex, d3dCtx->textureTableLen, d3dCtx->texUnitStage); + } + return; + } + + LPDIRECT3DTEXTURE9 surf = d3dCtx->textureTable[currBindTex]; + + if ((surf == NULL) || + ((level > 0) && (!d3dCtx->deviceInfo->supportMipmap))) { + return; + } + + void *imageObjPtr; + jbyte *dataBuffer; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)data, NULL); + } + else { + imageObjPtr = (void *)env->GetDirectBufferAddress(data); + } + + // update Image data + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_ABGR: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + dataBuffer = (jbyte *) imageObjPtr; + copyDataToSurface(imageFormat, textureFormat, xoffset, yoffset, + imgXOffset, imgYOffset, + width, height, tilew, dataBuffer, + surf, level); + break; + case IMAGE_FORMAT_USHORT_GRAY: + default: + throwAssert(env, "updateTexture2DSubImage : imageFormat illegal format"); + return; + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + env->ReleasePrimitiveArrayCritical((jarray)data, imageObjPtr, 0); + } + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DImage( + JNIEnv *env, + jobject obj, + jlong ctx, + jint numLevels, + jint level, + jint textureFormat, + jint imageFormat, + jint width, + jint height, + jint boundaryWidth, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + GetDevice(); + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + if (debug) { + printf("Internal Error: texUnitState %d, bindTextureIDLen %d\n", + d3dCtx->texUnitStage, d3dCtx->bindTextureIdLen); + } + return; + } + + INT currBindTex = d3dCtx->bindTextureId[d3dCtx->texUnitStage]; + + if ((currBindTex < 1) || + (currBindTex >= d3dCtx->textureTableLen)) { + if (debug) { + printf("Internal Error : UpdateTextureImage bind texture ID %d, textureTableLen %d, texUnitStage = %d \n", currBindTex, d3dCtx->textureTableLen, d3dCtx->texUnitStage); + } + return; + } + + LPDIRECT3DTEXTURE9 surf = d3dCtx->textureTable[currBindTex]; + + if (level == 0) { + if (surf != NULL) { + // see if no. of mipmap level change + + if (surf->GetLevelCount() != numLevels) { + d3dCtx->freeResource(surf); + d3dCtx->textureTable[currBindTex] = NULL; + surf = NULL; + } + } + + if (surf == NULL) { + // Need to create surface + surf = createTextureSurface(d3dCtx, numLevels, textureFormat, + width, height, useAutoMipMap); + + if (surf == NULL) { + return; + } + + d3dCtx->textureTable[currBindTex] = surf; + } + } else { + if (surf == NULL) { + return; + } + } + + if ((level > 0) && (!d3dCtx->deviceInfo->supportMipmap)) { + if (debug) { + printf("mipmap not support\n"); + } + return; + } + + // update Image data + if (data != NULL) { + void *imageObjPtr; + jbyte *dataBuffer; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)data, NULL); + } + else { + imageObjPtr = (void *)env->GetDirectBufferAddress(data); + } + + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_ABGR: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + dataBuffer = (jbyte *) imageObjPtr; + copyDataToSurface(imageFormat, textureFormat, 0, 0, 0, 0, + width, height, width, dataBuffer, + surf, level); + break; + case IMAGE_FORMAT_USHORT_GRAY: + default: + throwAssert(env, "updateTexture2DImage : imageFormat illegal format"); + return; + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + env->ReleasePrimitiveArrayCritical((jarray)data, imageObjPtr, 0); + } + } + device->SetTexture(d3dCtx->texUnitStage, surf); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_bindTexture3D( + JNIEnv *env, + jobject obj, + jlong ctx, + jint objectId, + jboolean enable) +{ + GetDevice(); + + if ((d3dCtx->deviceInfo->maxTextureDepth <= 0) || + (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen)) { + return; + } + + if (!enable) { + device->SetTexture(d3dCtx->texUnitStage, NULL); + d3dCtx->bindTextureId[d3dCtx->texUnitStage] = -1; + } else { + if (d3dCtx->bindTextureId[d3dCtx->texUnitStage] == objectId) { + return; + } + if (objectId >= d3dCtx->volumeTableLen) { + DWORD i; + DWORD len = max(objectId+1, d3dCtx->volumeTableLen << 1); + LPDIRECT3DVOLUMETEXTURE9 *newTable = (LPDIRECT3DVOLUMETEXTURE9 *) + malloc(sizeof(LPDIRECT3DVOLUMETEXTURE9) * len); + + if (newTable == NULL) { + printf("Not enough memory to alloc volume texture table of size %d.\n", len); + return; + } + for (i=0; i < d3dCtx->volumeTableLen; i++) { + newTable[i] = d3dCtx->volumeTable[i]; + } + for (i=d3dCtx->volumeTableLen; i < len; i++) { + newTable[i] = NULL; + } + d3dCtx->volumeTableLen = len; + SafeFree(d3dCtx->volumeTable); + d3dCtx->volumeTable = newTable; + } + + d3dCtx->bindTextureId[d3dCtx->texUnitStage] = objectId; + if (d3dCtx->volumeTable[objectId] != NULL) { + device->SetTexture(d3dCtx->texUnitStage, + d3dCtx->volumeTable[objectId]); + } + // else we will bind this in updateTextureImage + } + +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DFilterModes( + JNIEnv *env, + jobject obj, + jlong ctx, + jint minFilter, + jint magFilter) +{ + GetCtx(); + + if (d3dCtx->deviceInfo->maxTextureDepth > 0) { + Java_javax_media_j3d_NativePipeline_updateTexture2DFilterModes( + env, obj, ctx, minFilter, magFilter); + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DLodRange( + JNIEnv *env, + jobject obj, + jlong ctx, + jint baseLevel, + jint maximumLevel, + jfloat minimumLod, + jfloat maximumLod) +{ + // Not support +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DLodOffset( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat lodOffsetS, + jfloat lodOffsetT, + jfloat lodOffsetR) +{ + /* not supported */ +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DBoundary( + JNIEnv *env, + jobject obj, + jlong ctx, + jint boundaryModeS, + jint boundaryModeT, + jint boundaryModeR, + jfloat boundaryRed, + jfloat boundaryGreen, + jfloat boundaryBlue, + jfloat boundaryAlpha) +{ + + GetCtx(); + + if (d3dCtx->deviceInfo->maxTextureDepth > 0) { + + updateTextureBoundary( + env, obj, ctx, + boundaryModeS, + boundaryModeT, + boundaryModeR, + boundaryRed, + boundaryGreen, + boundaryBlue, + boundaryAlpha); + } +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DImage( + JNIEnv *env, + jobject obj, + jlong ctx, + jint numLevels, + jint level, + jint textureFormat, + jint imageFormat, + jint width, + jint height, + jint depth, + jint boundaryWidth, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + GetDevice(); + + if (d3dCtx->deviceInfo->maxTextureDepth <= 0) { + return; + } + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + if (debug) { + printf("Internal Error: texUnitState %d, bindTextureIDLen %d\n", + d3dCtx->texUnitStage, d3dCtx->bindTextureIdLen); + } + return; + } + + + INT currBindTex = d3dCtx->bindTextureId[d3dCtx->texUnitStage]; + + if ((currBindTex < 1) || + (currBindTex >= d3dCtx->volumeTableLen)) { + if (debug) { + printf("Internal Error : UpdateTexture3DImage bind texture ID %d, volumeTableLen %d, texUnitStage = %d \n", currBindTex, d3dCtx->volumeTableLen, d3dCtx->texUnitStage); + } + return; + } + + LPDIRECT3DVOLUMETEXTURE9 surf = d3dCtx->volumeTable[currBindTex]; + + if (level == 0) { + if (surf != NULL) { + // see if no. of mipmap level change + + if (surf->GetLevelCount() != numLevels) { + d3dCtx->freeResource(surf); + d3dCtx->volumeTable[currBindTex] = NULL; + surf = NULL; + } + } + + if (surf == NULL) { + surf = createVolumeTexture(d3dCtx, numLevels, textureFormat, + width, height, depth, useAutoMipMap); + if (surf == NULL) { + return; + } + + d3dCtx->volumeTable[currBindTex] = surf; + } + } else { + if (surf == NULL) { + return; + } + } + + if ((level > 0) && (!d3dCtx->deviceInfo->supportMipmap)) { + if (debug) { + printf("mipmap not support\n"); + } + return; + } + + // update Image data + if (data != NULL) { + void *imageObjPtr; + jbyte *dataBuffer; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)data, NULL); + } + else { + imageObjPtr = (void *)env->GetDirectBufferAddress(data); + } + + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_ABGR: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + dataBuffer = (jbyte *) imageObjPtr; + copyDataToVolume(imageFormat, textureFormat, 0, 0, 0, 0, 0, 0, + width, height, depth, width, height, dataBuffer, + surf, level); + break; + case IMAGE_FORMAT_USHORT_GRAY: + default: + throwAssert(env, "updateTexture3DImage : imageFormat illegal format"); + return; + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + env->ReleasePrimitiveArrayCritical((jarray)data, imageObjPtr, 0); + } + } + device->SetTexture(d3dCtx->texUnitStage, surf); + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DSubImage( + JNIEnv *env, + jobject obj, + jlong ctx, + jint level, + jint xoffset, + jint yoffset, + jint zoffset, + jint textureFormat, + jint imageFormat, + jint imgXOffset, + jint imgYOffset, + jint imgZOffset, + jint tilew, + jint tileh, + jint width, + jint height, + jint depth, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + /* Note: useAutoMipMap is not use for SubImage in the d3d pipe */ + + GetDevice(); + + if ((d3dCtx->deviceInfo->maxTextureDepth <= 0) || + (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen)) { + return; + } + + INT currBindTex = d3dCtx->bindTextureId[d3dCtx->texUnitStage]; + + if ((currBindTex < 1) || + (currBindTex >= d3dCtx->volumeTableLen)) { + if (debug) { + printf("Internal Error : UpdateTexture3DSubImage bind texture ID %d, volumeableLen %d, texUnitStage = %d \n", currBindTex, d3dCtx->volumeTableLen, d3dCtx->texUnitStage); + } + return; + } + + LPDIRECT3DVOLUMETEXTURE9 surf = d3dCtx->volumeTable[currBindTex]; + + if ((surf == NULL) || + ((level > 0) && (!d3dCtx->deviceInfo->supportMipmap))) { + return; + } + + void *imageObjPtr; + jbyte *dataBuffer; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)data, NULL); + } + else { + imageObjPtr = (void *)env->GetDirectBufferAddress(data); + } + + // update Image data + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_ABGR: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + dataBuffer = (jbyte *) imageObjPtr; + copyDataToVolume(imageFormat, textureFormat, xoffset, + yoffset, zoffset, imgXOffset, imgYOffset, + imgZOffset, width, height, depth, + tilew, tileh, dataBuffer, + surf, level); + break; + case IMAGE_FORMAT_USHORT_GRAY: + default: + throwAssert(env, "updateTexture3DSubImage : imageFormat illegal format"); + return; + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + env->ReleasePrimitiveArrayCritical((jarray)data, imageObjPtr, 0); + } + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_bindTextureCubeMap( + JNIEnv *env, + jobject obj, + jlong ctx, + jint objectId, + jboolean enable) +{ + GetDevice(); + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + return; + } + + if (!enable) { + device->SetTexture(d3dCtx->texUnitStage, NULL); + d3dCtx->bindTextureId[d3dCtx->texUnitStage] = -1; + } else { + + if (d3dCtx->bindTextureId[d3dCtx->texUnitStage] == objectId) { + return; + } + + if (objectId >= d3dCtx->cubeMapTableLen) { + DWORD i; + DWORD len = max(objectId+1, d3dCtx->cubeMapTableLen << 1); + LPDIRECT3DCUBETEXTURE9 *newTable = (LPDIRECT3DCUBETEXTURE9 *) + malloc(sizeof(LPDIRECT3DCUBETEXTURE9) * len); + + if (newTable == NULL) { + printf("Not enough memory to alloc cubeMap table of size %d.\n", len); + return; + } + for (i=0; i < d3dCtx->cubeMapTableLen; i++) { + newTable[i] = d3dCtx->cubeMapTable[i]; + } + for (i=d3dCtx->cubeMapTableLen; i < len; i++) { + newTable[i] = NULL; + } + d3dCtx->cubeMapTableLen = len; + SafeFree(d3dCtx->cubeMapTable); + d3dCtx->cubeMapTable = newTable; + } + + d3dCtx->bindTextureId[d3dCtx->texUnitStage] = objectId; + if (d3dCtx->cubeMapTable[objectId] != NULL) { + device->SetTexture(d3dCtx->texUnitStage, + d3dCtx->cubeMapTable[objectId]); + } + // else we will bind this in updateTextureImage + } +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapFilterModes( + JNIEnv *env, + jobject obj, + jlong ctx, + jint minFilter, + jint magFilter) +{ + Java_javax_media_j3d_NativePipeline_updateTexture2DFilterModes(env, + obj, ctx, minFilter, magFilter); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapLodRange( + JNIEnv *env, + jobject obj, + jlong ctx, + jint baseLevel, + jint maximumLevel, + jfloat minimumLod, + jfloat maximumLod) +{ + // not support +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapLodOffset( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat lodOffsetS, + jfloat lodOffsetT, + jfloat lodOffsetR) +{ + /* not supported */ +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapBoundary( + JNIEnv *env, + jobject obj, + jlong ctx, + jint boundaryModeS, + jint boundaryModeT, + jfloat boundaryRed, + jfloat boundaryGreen, + jfloat boundaryBlue, + jfloat boundaryAlpha) +{ + updateTextureBoundary(env, obj, ctx, boundaryModeS, + boundaryModeT, -1, boundaryRed, + boundaryGreen, boundaryBlue, + boundaryAlpha); + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapSubImage( + JNIEnv *env, + jobject obj, + jlong ctx, + jint face, + jint level, + jint xoffset, + jint yoffset, + jint textureFormat, + jint imageFormat, + jint imgXOffset, + jint imgYOffset, + jint tilew, + jint width, + jint height, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + /* Note: useAutoMipMap is not use for SubImage in the d3d pipe */ + + GetDevice(); + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + return; + } + + INT currBindTex = d3dCtx->bindTextureId[d3dCtx->texUnitStage]; + + if ((currBindTex < 1) || + (currBindTex >= d3dCtx->cubeMapTableLen)) { + if (debug) { + printf("Internal Error : UpdateCubeMapSubImage bind texture ID %d, cubeMapTableLen %d, texUnitStage = %d \n", currBindTex, d3dCtx->cubeMapTableLen, d3dCtx->texUnitStage); + } + return; + } + + LPDIRECT3DCUBETEXTURE9 surf = d3dCtx->cubeMapTable[currBindTex]; + + if ((surf == NULL) || + ((level > 0) && (!d3dCtx->deviceInfo->supportMipmap))) { + return; + } + + void *imageObjPtr; + jbyte *dataBuffer; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)data, NULL); + } + else { + imageObjPtr = (void *)env->GetDirectBufferAddress(data); + } + + // update Image data + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_ABGR: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + dataBuffer = (jbyte *) imageObjPtr; + copyDataToCubeMap(imageFormat, textureFormat, + xoffset, yoffset, + imgXOffset, imgYOffset, + width, height, + tilew, dataBuffer, + surf, level, face); + break; + case IMAGE_FORMAT_USHORT_GRAY: + default: + throwAssert(env, "updateTextureCubeMapSubImage : imageFormat illegal format"); + return; + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + env->ReleasePrimitiveArrayCritical((jarray)data, imageObjPtr, 0); + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapImage( + JNIEnv *env, + jobject obj, + jlong ctx, + jint face, + jint numLevels, + jint level, + jint textureFormat, + jint imageFormat, + jint width, + jint height, + jint boundaryWidth, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + GetDevice(); + + if (d3dCtx->texUnitStage >= d3dCtx->bindTextureIdLen) { + if (debug) { + printf("Internal Error: texUnitState %d, bindTextureIDLen %d\n", + d3dCtx->texUnitStage, d3dCtx->bindTextureIdLen); + } + return; + } + + + INT currBindTex = d3dCtx->bindTextureId[d3dCtx->texUnitStage]; + + if ((currBindTex < 1) || + (currBindTex >= d3dCtx->cubeMapTableLen)) { + if (debug) { + printf("Internal Error : UpdateCubeMapImage bind texture ID %d, cubeMapTableLen %d, texUnitStage = %d \n", currBindTex, d3dCtx->cubeMapTableLen, d3dCtx->texUnitStage); + } + return; + } + + LPDIRECT3DCUBETEXTURE9 surf = d3dCtx->cubeMapTable[currBindTex]; + + if (level == 0) { + if (surf != NULL) { + // see if no. of mipmap level change + + if (surf->GetLevelCount() != numLevels) { + d3dCtx->freeResource(surf); + d3dCtx->cubeMapTable[currBindTex] = NULL; + surf = NULL; + } + } + + if (surf == NULL) { + // Need to create surface + surf = createCubeMapTexture(d3dCtx, numLevels, textureFormat, + width, height, useAutoMipMap); + if (surf == NULL) { + return; + } + + d3dCtx->cubeMapTable[currBindTex] = surf; + } + } else { + if (surf == NULL) { + return; + } + } + + if ((level > 0) && (!d3dCtx->deviceInfo->supportMipmap)) { + if (debug) { + printf("mipmap not support\n"); + } + return; + } + + // update Image data + if (data != NULL) { + void *imageObjPtr; + jbyte *dataBuffer; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)data, NULL); + } + else { + imageObjPtr = (void *)env->GetDirectBufferAddress(data); + } + + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_ABGR: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + dataBuffer = (jbyte *) imageObjPtr; + copyDataToCubeMap(imageFormat, textureFormat, 0, 0, 0, 0, + width, height, width, dataBuffer, + surf, level, face); + break; + case IMAGE_FORMAT_USHORT_GRAY: + default: + throwAssert(env, "updateTextureCubeMapImage : imageFormat illegal format"); + return; + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + env->ReleasePrimitiveArrayCritical((jarray)data, imageObjPtr, 0); + } + + } + + device->SetTexture(d3dCtx->texUnitStage, surf); +} + + +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_decal1stChildSetup( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice2(); + + device->SetRenderState(D3DRS_STENCILENABLE, TRUE); + device->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1.0, 0); + device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + device->SetRenderState(D3DRS_STENCILREF, 0x1); + device->SetRenderState(D3DRS_STENCILMASK, 0x1); + device->SetRenderState(D3DRS_STENCILFAIL, + D3DSTENCILOP_KEEP); + device->SetRenderState(D3DRS_STENCILZFAIL, + D3DSTENCILOP_KEEP); + device->SetRenderState(D3DRS_STENCILPASS, + D3DSTENCILOP_REPLACE); + return d3dCtx->zEnable; +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_decalNthChildSetup( + JNIEnv *env, + jobject obj, + jlong ctx) + +{ + GetDevice(); + + d3dCtx->zEnable = FALSE; + device->SetRenderState(D3DRS_ZENABLE, FALSE); + device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + device->SetRenderState(D3DRS_STENCILREF, 0x1); + device->SetRenderState(D3DRS_STENCILMASK, 0x1); + device->SetRenderState(D3DRS_STENCILFAIL, + D3DSTENCILOP_KEEP); + device->SetRenderState(D3DRS_STENCILZFAIL, + D3DSTENCILOP_KEEP); + device->SetRenderState(D3DRS_STENCILPASS, + D3DSTENCILOP_KEEP); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_decalReset( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean depthBufferEnable) +{ + GetDevice(); + + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + + if (depthBufferEnable) { + d3dCtx->zEnable = TRUE; + device->SetRenderState(D3DRS_ZENABLE, TRUE); + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_ctxUpdateEyeLightingEnable( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean localEyeLightingEnable) +{ + GetDevice(); + device->SetRenderState(D3DRS_LOCALVIEWER, localEyeLightingEnable); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_activeTextureUnit( + JNIEnv *env, + jobject obj, + jlong ctx, + jint index) +{ + GetDevice(); + // If this index is greater than max support stage, + // then subsequence texture operation will ignore. + if (index < 0) { + index = 0; + } + + d3dCtx->texUnitStage = index; +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureUnitState( + JNIEnv *env, + jobject obj, + jlong ctx, + jint index, + jboolean enable) +{ + GetDevice(); + // If this index is greater than max support stage, + // then subsequence texture operation will ignore. + if (index <= 0) { + index = 0; + } + + d3dCtx->texUnitStage = index; + + if (!enable && (index < d3dCtx->bindTextureIdLen)) { + device->SetTexture(index, NULL); + d3dCtx->bindTextureId[index] = -1; + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setDepthFunc( + JNIEnv * env, + jobject obj, + jlong ctx, + jint func) +{ + GetDevice(); + + if (func == javax_media_j3d_RenderingAttributesRetained_LESS) { + device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS); + } else if (func == + javax_media_j3d_RenderingAttributesRetained_LEQUAL) { + device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + } + +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setBlendColor( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat colorAlpha) +{ + // Not support in D3D +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setBlendFunc( + JNIEnv * env, + jobject obj, + jlong ctx, + jint srcBlendFunction, + jint dstBlendFunction) +{ + GetDevice(); + + device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + device->SetRenderState(D3DRS_SRCBLEND, + blendFunctionTable[srcBlendFunction]); + device->SetRenderState(D3DRS_DESTBLEND, + blendFunctionTable[dstBlendFunction]); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setFogEnableFlag( + JNIEnv * env, + jobject obj, + jlong ctx, + jboolean enable) +{ + GetDevice(); + + device->SetRenderState(D3DRS_FOGENABLE, enable); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateSeparateSpecularColorEnable( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean enable) +{ +} + + +// Fix issue 221 : Temporary stub until Cg is implemented +/* + * Class: javax_media_j3d_NativePipeline + * Method: loadNativeCgLibrary + * Signature: ([Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL +Java_javax_media_j3d_NativePipeline_loadNativeCgLibrary( + JNIEnv *env, + jobject thiz, + jobjectArray libpath) +{ + return JNI_FALSE; +} diff --git a/j3d-core/src/native/d3d/Canvas3D.cpp b/j3d-core/src/native/d3d/Canvas3D.cpp new file mode 100644 index 0000000..d482274 --- /dev/null +++ b/j3d-core/src/native/d3d/Canvas3D.cpp @@ -0,0 +1,1325 @@ +/* + * $RCSfile: Canvas3D.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.22 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#include "StdAfx.h" + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setDrawActive( + JNIEnv *env, + jobject obj, + jint fd) +{ + // This function is only used for Solaris OpenGL +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_widSync( + JNIEnv *env, + jobject obj, + jint fd, + jint numWindows) +{ + // This function is only used for Solaris OpenGL +} + + + +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_useSharedCtx( + JNIEnv *env, + jobject obj) +{ + return JNI_FALSE; +} + + + +extern "C" JNIEXPORT +jlong JNICALL Java_javax_media_j3d_NativePipeline_createNewContext( + JNIEnv *env, + jobject obj, + jobject cv, + jlong display, + jlong window, + jlong fbConfigListPtr, + jlong sharedCtx, + jboolean isSharedCtx, + jboolean offScreen, + jboolean glslLibraryAvailable, + jboolean cgLibraryAvailable) +{ + HWND hwnd = WindowFromDC(reinterpret_cast(window)); + + lock(); + int vid = 0; // TODO: get needed info from fbConfigListPtr + D3dCtx* ctx = new D3dCtx(env, cv, hwnd, offScreen, vid); + if (ctx == NULL) { + printf("%s", getErrorMessage(OUTOFMEMORY)); + unlock(); + return 0; + } + + if (offScreen) + { + jclass cls = (jclass) env->GetObjectClass(cv); + jfieldID fieldId = env->GetFieldID(cls, + "offScreenCanvasSize", + "Ljava/awt/Dimension;"); + jobject dimObj = env->GetObjectField(cv, fieldId); + if (dimObj == NULL) + { + // user invoke queryProperties() + ctx->offScreenWidth = 1; + ctx->offScreenHeight = 1; + } + else + { + cls = (jclass) env->GetObjectClass(dimObj); + fieldId = env->GetFieldID(cls, "width", "I"); + ctx->offScreenWidth = env->GetIntField(dimObj, fieldId); + fieldId = env->GetFieldID(cls, "height", "I"); + ctx->offScreenHeight = env->GetIntField(dimObj, fieldId); + } + } + + if (!ctx->initialize(env, cv)) + { + delete ctx; + unlock(); + return 0; + } + d3dCtxList.push_back(ctx); + + unlock(); + return reinterpret_cast(ctx); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_createQueryContext( + JNIEnv *env, + jobject obj, + jobject cv, + jlong display, + jlong window, + jlong fbConfigListPtr, + jboolean offScreen, + jint width, + jint height, + jboolean glslLibraryAvailable, + jboolean cgLibraryAvailable) +{ + HWND hwnd = WindowFromDC(reinterpret_cast(window)); + + lock(); + // always use offscreen for property since it + // makes no difference in D3D and this will also + // instruct initialize() to use offScreenWidth/Height + // instead of current window width/height to create + // context. + + int vid = 0; // TODO: get needed info from fbConfigListPtr + D3dCtx* ctx = new D3dCtx(env, cv, hwnd, true, vid); + if (ctx == NULL) { + printf("%s", getErrorMessage(OUTOFMEMORY)); + unlock(); + return; + } + + ctx->offScreenWidth = width; + ctx->offScreenHeight = height; + + ctx->initialize(env, cv); + delete ctx; + unlock(); +} + +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_useCtx( + JNIEnv *env, + jobject obj, + jlong ctx, + jlong display, + jlong window) +{ + return JNI_TRUE; + // D3D doesn't have notation of current context +} + + +extern "C" JNIEXPORT +jint JNICALL Java_javax_media_j3d_NativePipeline_getNumCtxLights( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice2(); + + int nlight = d3dCtx->deviceInfo->maxActiveLights; + if (nlight <= 0) { + // In emulation & referene mode, D3D return -1 + // work around by setting 8. + nlight = 8; + } + return nlight; +} + +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_initTexturemapping( + JNIEnv *env, + jobject texture, + jlong ctx, + jint texWidth, + jint texHeight, + jint objectId) +{ + GetCtx2(); + + + if ((objectId >= 0) && + (objectId < d3dCtx->textureTableLen) && + (d3dCtx->textureTable[objectId] != NULL)) { + // delete the previous texture reference + // when canvas resize + Java_javax_media_j3d_NativePipeline_freeTexture(env, + NULL, + ctx, + objectId); + } + + Java_javax_media_j3d_NativePipeline_bindTexture2D(env, texture, ctx, objectId, TRUE); + + Java_javax_media_j3d_NativePipeline_updateTexture2DImage(env, texture, ctx, 1, 0, + J3D_RGBA, 0, texWidth, + texHeight, 0, 0, NULL, JNI_FALSE); + return (d3dCtx->textureTable[objectId] != NULL); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_texturemapping( + JNIEnv *env, + jobject texture, + jlong ctx, + jint px, + jint py, + jint minX, + jint minY, + jint maxX, + jint maxY, + jint texWidth, + jint texHeight, + jint rasWidth, + jint format, + jint objectId, + jbyteArray byteData, + jint winWidth, + jint winHeight) +{ + GetDevice(); + + Java_javax_media_j3d_NativePipeline_bindTexture2D( + env, texture, ctx, objectId, TRUE); + + Java_javax_media_j3d_NativePipeline_updateTexture2DSubImage( + env, texture, ctx, 0, minX, minY, J3D_RGBA, format, + minX, minY, rasWidth, maxX-minX, maxY-minY, IMAGE_DATA_TYPE_BYTE_ARRAY, + byteData, JNI_FALSE); + + LPDIRECT3DTEXTURE9 surf = d3dCtx->textureTable[objectId]; + + if (surf == NULL) { + if (debug) { + printf("[Java 3D] Fail to apply texture in J3DGraphics2D !\n"); + } + return; + } + + D3DTLVERTEX screenCoord; + DWORD zcmpfunc; + + screenCoord.sx = (px + minX) - 0.5f; + screenCoord.sy = (py + minY) - 0.5f; + + // sz can be any number since we will disable z buffer + // However rhw can't be 0, otherwise texture will not shown + screenCoord.sz = 0.999f; + screenCoord.rhw = 1; + + DWORD blendEnable; + DWORD srcBlend; + DWORD dstBlend; + + // disable z buffer + device->GetRenderState(D3DRS_ZFUNC, &zcmpfunc); + device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + + device->GetRenderState(D3DRS_ALPHABLENDENABLE, &blendEnable); + device->GetRenderState(D3DRS_SRCBLEND, &srcBlend); + device->GetRenderState(D3DRS_DESTBLEND, &dstBlend); + + device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + + drawTextureRect(d3dCtx, device, surf, screenCoord, + minX, minY, maxX, maxY, + maxX - minX, maxY - minY, false); + + Java_javax_media_j3d_NativePipeline_bindTexture2D( + env, texture, ctx, objectId, FALSE); + + device->SetRenderState(D3DRS_ALPHABLENDENABLE, blendEnable); + device->SetRenderState(D3DRS_SRCBLEND, srcBlend); + device->SetRenderState(D3DRS_DESTBLEND, dstBlend); + device->SetRenderState(D3DRS_ZFUNC, zcmpfunc); + device->SetRenderState(D3DRS_ZWRITEENABLE, + d3dCtx->zWriteEnable); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_clear( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat r, + jfloat g, + jfloat b, + jboolean clearStencil) +{ + + GetDevice(); + +// TODO ACES: The d3dCtx->stencilEnable and d3dCtx->stencilWriteEnable flags +// are not used in the rest of the code. They are never set to a value, and +// they are not looked at by most of the code. + + /* Java 3D always clears the Z-buffer */ + + if (!d3dCtx->zWriteEnable) { + device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + } + + // Issue 239 - clear stencil, if requested + if (clearStencil) { + device->SetRenderState(D3DRS_STENCILENABLE, TRUE); + device->SetRenderState(D3DRS_STENCILWRITEMASK, ~0); + + // clear stencil and ZBuffer + HRESULT hr = device->Clear(0, NULL, + D3DCLEAR_STENCIL | D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + D3DCOLOR_COLORVALUE(r, g, b, 1.0f), 1.0, 0); + if (hr == D3DERR_INVALIDCALL) { + printf("[Java3D] Error cleaning Canvas3D stencil & ZBuffer\n"); + } + // printf("canvas3D clear stencil & ZBuffer\n"); + + // TODO: DO WE NEED TO RESTORE THE STENCIL ENABLE AND WRITE MASK??? +// if (!d3dCtx->stencilEnable) { +// device->SetRenderState(D3DRS_STENCILENABLE, FALSE); +// } +// if (!d3dCtx->stencilWriteEnable) { +// device->SetRenderState(D3DRS_STENCILWRITEMASK, 0); +// } + + } + else { + // clear ZBuffer only + HRESULT hr = device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + D3DCOLOR_COLORVALUE(r, g, b, 1.0f), 1.0, 0); + if (hr == D3DERR_INVALIDCALL) { + printf("[Java3D] Error cleaning Canvas3D ZBuffer\n"); + } + // printf("canvas3D clear ZBuffer\n"); + } + + if (!d3dCtx->zWriteEnable) { + device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + } + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_textureFillBackground( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat texMinU, + jfloat texMaxU, + jfloat texMinV, + jfloat texMaxV, + jfloat mapMinX, + jfloat mapMaxX, + jfloat mapMinY, + jfloat mapMaxY, + jboolean useBilinearFilter) +{ + + DWORD alphaTest, alphaBlend, cull, zBuffer, + fog, lighting, stencil, specular; + + D3DXMATRIX Ortho2D; + D3DXMATRIX ptm, wtm, vtm; + COORDTEXVERTEX verts[4]; + D3DXMATRIX texMatrix; + int tus; + + GetDevice(); + + device->GetRenderState(D3DRS_ALPHATESTENABLE, &alphaTest); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + + device->GetRenderState(D3DRS_ALPHABLENDENABLE, &alphaBlend); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + device->GetRenderState(D3DRS_CULLMODE, &cull); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + device->GetRenderState(D3DRS_ZENABLE, &zBuffer); + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + + device->GetRenderState(D3DRS_FOGENABLE, &fog); + device->SetRenderState(D3DRS_FOGENABLE, FALSE); + + device->GetRenderState(D3DRS_LIGHTING, &lighting); + device->SetRenderState(D3DRS_LIGHTING, FALSE); + + device->GetRenderState(D3DRS_STENCILENABLE, &stencil); + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + + device->GetRenderState(D3DRS_SPECULARENABLE, &specular); + device->SetRenderState(D3DRS_SPECULARENABLE, FALSE); + + tus = d3dCtx->texUnitStage; + + if (tus >= d3dCtx->bindTextureIdLen) { + if (debug) { + printf("Internal Error: texUnitState %d, bindTextureIDLen %d\n", + d3dCtx->texUnitStage, d3dCtx->bindTextureIdLen); + } + return; + } + + if (d3dCtx->texTransformSet[tus]) { + device->GetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), + &texMatrix); + + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), + &identityMatrix); + } + + // TextureStage will be restore by caller. + device->SetTextureStageState(tus, + D3DTSS_TEXCOORDINDEX, + D3DTSS_TCI_PASSTHRU); + + /* Setup filter mode if needed */ + if(useBilinearFilter) { + /* fprintf(stderr, "Background : use bilinear filter\n"); */ + device->SetSamplerState (tus, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device->SetSamplerState (tus, D3DSAMP_MIPFILTER, D3DTEXF_POINT); + device->SetSamplerState (tus, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + /* For debugging only + else { + fprintf(stderr, "Background : Not use bilinear filter\n"); + } + */ + + device->GetTransform(D3DTS_PROJECTION, &ptm); + device->GetTransform(D3DTS_WORLD, &wtm); + device->GetTransform(D3DTS_VIEW, &vtm); + + Ortho2D._11 = 1.0; + Ortho2D._12 = 0.0; + Ortho2D._13 = 0.0; + Ortho2D._14 = 0.0; + + Ortho2D._21 = 0.0; + Ortho2D._22 = 1.0; + Ortho2D._23 = 0.0; + Ortho2D._24 = 0.0; + + Ortho2D._31 = 0.0; + Ortho2D._32 = 0.0; + Ortho2D._33 = 0.5; + Ortho2D._34 = 0.0; + + Ortho2D._41 = 0.0; + Ortho2D._42 = 0.0; + Ortho2D._43 = 0.5; + Ortho2D._44 = 1.0; + + /* + printf("Ortho2D matix : \n"); + printf("%f, %f, %f, %f\n", Ortho2D._11, Ortho2D._12, Ortho2D._13, Ortho2D._14); + printf("%f, %f, %f, %f\n", Ortho2D._21, Ortho2D._22, Ortho2D._23, Ortho2D._24); + printf("%f, %f, %f, %f\n", Ortho2D._31, Ortho2D._32, Ortho2D._33, Ortho2D._34); + printf("%f, %f, %f, %f\n", Ortho2D._41, Ortho2D._42, Ortho2D._43, Ortho2D._44); + */ + + device->SetTransform(D3DTS_PROJECTION, &Ortho2D); + device->SetTransform(D3DTS_WORLD, &identityMatrix); + device->SetTransform(D3DTS_VIEW, &identityMatrix); + + verts[0].tu = texMinU; /* tumin; */ + verts[0].tv = texMaxV; /* tvmax; */ + verts[1].tu = texMinU; /* tumin; */ + verts[1].tv = texMinV; /* tvmin; */ + verts[2].tu = texMaxU; /* tumax; */ + verts[2].tv = texMaxV; /* tvmax; */ + verts[3].tu = texMaxU; /* tumax; */ + verts[3].tv = texMinV; /* tvmin; */ + + verts[0].sx = mapMinX; + verts[0].sy = mapMaxY; + verts[0].sz = 0.999f; + + verts[1].sx = mapMinX; + verts[1].sy = mapMinY; + verts[1].sz = 0.999f; + + verts[2].sx = mapMaxX; + verts[2].sy = mapMaxY; + verts[2].sz = 0.999f; + + verts[3].sx = mapMaxX; + verts[3].sy = mapMinY; + verts[3].sz = 0.999f; + + /* + printf("(texMinU,texMinV,texMaxU,texMaxV) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + texMinU,texMinV,texMaxU,texMaxV); + printf("(mapMinX,mapMinY,mapMaxX,mapMaxY) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + mapMinX,mapMinY,mapMaxX,mapMaxY); + */ + + device->SetVertexShader(NULL); + + device->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); + + device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, + 2, verts, sizeof(COORDTEXVERTEX)); + + + /* Restore renderstates */ + device->SetRenderState(D3DRS_ALPHATESTENABLE, alphaTest); + device->SetRenderState(D3DRS_CULLMODE, cull); + device->SetRenderState(D3DRS_ZENABLE, zBuffer); + device->SetRenderState(D3DRS_FOGENABLE, fog); + device->SetRenderState(D3DRS_LIGHTING, lighting); + device->SetRenderState(D3DRS_STENCILENABLE, stencil); + device->SetRenderState(D3DRS_SPECULARENABLE, specular); + + /* Restore texture Matrix transform */ + if (d3dCtx->texTransformSet[tus]) { + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), + &texMatrix); + } + + device->SetTransform(D3DTS_PROJECTION, &ptm); + device->SetTransform(D3DTS_WORLD, &wtm); + device->SetTransform(D3DTS_VIEW, &vtm); + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_textureFillRaster(JNIEnv *env, + jobject obj, + jlong ctx, + jfloat texMinU, + jfloat texMaxU, + jfloat texMinV, + jfloat texMaxV, + jfloat mapMinX, + jfloat mapMaxX, + jfloat mapMinY, + jfloat mapMaxY, + jfloat mapZ, + jfloat alpha, + jboolean useBilinearFilter) +{ + + DWORD cull, lighting; + D3DXMATRIX Ortho2D; + D3DXMATRIX ptm, wtm, vtm; + COORDCLRTEXVERTEX verts[4]; + D3DXMATRIX texMatrix; + int tus; + + GetDevice(); + + device->GetRenderState(D3DRS_CULLMODE, &cull); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + device->GetRenderState(D3DRS_LIGHTING, &lighting); + device->SetRenderState(D3DRS_LIGHTING, FALSE); + + tus = d3dCtx->texUnitStage; + + if (tus >= d3dCtx->bindTextureIdLen) { + if (debug) { + printf("Internal Error: texUnitState %d, bindTextureIDLen %d\n", + d3dCtx->texUnitStage, d3dCtx->bindTextureIdLen); + } + return; + } + + // TextureStage will be restore by caller. + device->SetTextureStageState(tus, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + device->SetTextureStageState(tus, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + device->SetTextureStageState(tus, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + + /* Setup filter mode if needed */ + if(useBilinearFilter) { + /* fprintf(stderr, "Raster : use bilinear filter\n"); */ + device->SetSamplerState (tus, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device->SetSamplerState (tus, D3DSAMP_MIPFILTER, D3DTEXF_POINT); + device->SetSamplerState (tus, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + /* For debugging only + else { + fprintf(stderr, "Raster : Not use bilinear filter\n"); + } + */ + + device->GetTransform(D3DTS_PROJECTION, &ptm); + device->GetTransform(D3DTS_WORLD, &wtm); + device->GetTransform(D3DTS_VIEW, &vtm); + + Ortho2D._11 = 2.0; + Ortho2D._12 = 0.0; + Ortho2D._13 = 0.0; + Ortho2D._14 = 0.0; + + Ortho2D._21 = 0.0; + Ortho2D._22 = 2.0; + Ortho2D._23 = 0.0; + Ortho2D._24 = 0.0; + + Ortho2D._31 = 0.0; + Ortho2D._32 = 0.0; + Ortho2D._33 = -1.0; + Ortho2D._34 = 0.0; + + Ortho2D._41 = -1.0; + Ortho2D._42 = -1.0; + Ortho2D._43 = 0.0; + Ortho2D._44 = 1.0; + + /* + printf("Ortho2D matix : \n"); + printf("%f, %f, %f, %f\n", Ortho2D._11, Ortho2D._12, Ortho2D._13, Ortho2D._14); + printf("%f, %f, %f, %f\n", Ortho2D._21, Ortho2D._22, Ortho2D._23, Ortho2D._24); + printf("%f, %f, %f, %f\n", Ortho2D._31, Ortho2D._32, Ortho2D._33, Ortho2D._34); + printf("%f, %f, %f, %f\n", Ortho2D._41, Ortho2D._42, Ortho2D._43, Ortho2D._44); + */ + + device->SetTransform(D3DTS_WORLD, &identityMatrix); + device->SetTransform(D3DTS_VIEW, &identityMatrix); + device->SetTransform(D3DTS_PROJECTION, &Ortho2D); + + verts[0].tu = texMinU; /* tumin; */ + verts[0].tv = texMaxV; /* tvmax; */ + verts[1].tu = texMinU; /* tumin; */ + verts[1].tv = texMinV; /* tvmin; */ + verts[2].tu = texMaxU; /* tumax; */ + verts[2].tv = texMaxV; /* tvmax; */ + verts[3].tu = texMaxU; /* tumax; */ + verts[3].tv = texMinV; /* tvmin; */ + + D3DCOLOR alphaColor = 0xffffff | ((int)(alpha * 255.0f) << 24); + + verts[0].color = alphaColor; + verts[0].sx = mapMinX; + verts[0].sy = mapMaxY; + verts[0].sz = mapZ; + + verts[1].color = alphaColor; + verts[1].sx = mapMinX; + verts[1].sy = mapMinY; + verts[1].sz = mapZ; + + verts[2].color = alphaColor; + verts[2].sx = mapMaxX; + verts[2].sy = mapMaxY; + verts[2].sz = mapZ; + + verts[3].color = alphaColor; + verts[3].sx = mapMaxX; + verts[3].sy = mapMinY; + verts[3].sz = mapZ; + + /* + printf("(texMinU,texMinV,texMaxU,texMaxV) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + texMinU,texMinV,texMaxU,texMaxV); + printf("(mapMinX,mapMinY,mapMaxX,mapMaxY) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + mapMinX,mapMinY,mapMaxX,mapMaxY); + + printf("(mapZ) = (%3.2f)\n",mapZ); + */ + device->SetVertexShader(NULL); + + device->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1 | + D3DFVF_DIFFUSE | D3DFVF_TEXCOORDSIZE2(0)); + + device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, + 2, verts, sizeof(COORDCLRTEXVERTEX)); + + + /* Restore renderstates */ + device->SetRenderState(D3DRS_CULLMODE, cull); + device->SetRenderState(D3DRS_LIGHTING, lighting); + + /* Restore texture Matrix transform */ + device->SetTransform(D3DTS_PROJECTION, &ptm); + device->SetTransform(D3DTS_WORLD, &wtm); + device->SetTransform(D3DTS_VIEW, &vtm); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeRasterDepth(JNIEnv *env, + jobject obj, + jlong ctx, + jfloat posX, + jfloat posY, + jfloat posZ, + jint srcOffsetX, + jint srcOffsetY, + jint rasterWidth, + jint rasterHeight, + jint depthWidth, + jint depthHeight, + jint depthFormat, + jobject depthData) +{ + void *depthObjPtr; + D3DVERTEX worldCoord; + D3DTLVERTEX screenCoord; + int endx = srcOffsetX + rasterWidth; + int endy = srcOffsetY + rasterHeight; + + GetDevice(); + /* printf("*** Canvas3D.executeRasterDepth() ***\n"); */ + + // clipping + if (srcOffsetX > depthWidth) { + srcOffsetX = depthWidth; + } else if (srcOffsetX < 0) { + srcOffsetX = 0; + } + if (srcOffsetY > depthHeight) { + srcOffsetY = depthHeight; + } else if (srcOffsetY < 0) { + srcOffsetY = 0; + } + + if (endx > depthWidth) { + endx = depthWidth; + } else if (endx < 0) { + endx = 0; + } + if (endy > depthHeight) { + endy = depthHeight; + } else if (endy < 0) { + endy = 0; + } + + int h = endy - srcOffsetY; + int w = endx - srcOffsetX; + + // raster position is upper left corner, default for Java3D + // ImageComponent currently has the data reverse in Y + if ((h > 0) && (w > 0)) { + worldCoord.x = posX; + worldCoord.y = posY; + worldCoord.z = posZ; + + d3dCtx->transform(&worldCoord, &screenCoord); + + if (d3dCtx->depthStencilSurface == NULL) { + HRESULT hr = + device->GetDepthStencilSurface(&d3dCtx->depthStencilSurface); + if (FAILED(hr)) { + if (debug) { + printf("[Java3D] Fail to get depth stencil surface %s\n", + DXGetErrorString9(hr)); + } + return; + } + } + + depthObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)depthData, NULL); + + if (depthFormat == javax_media_j3d_DepthComponentRetained_DEPTH_COMPONENT_TYPE_INT) { + copyDepthToSurface(d3dCtx, + device, + (int)(screenCoord.sx), + (int)(screenCoord.sy), + srcOffsetX, srcOffsetY, + w, h, depthWidth, depthHeight, + (jint *)depthObjPtr, d3dCtx->depthStencilSurface); + + } else { // javax_media_j3d_DepthComponentRetained_DEPTH_COMPONENT_TYPE_FLOAT + + copyDepthToSurface(d3dCtx, + device, + (int)(screenCoord.sx), + (int)(screenCoord.sy), + srcOffsetX, srcOffsetY, + w, h, depthWidth, depthHeight, + (jfloat *)depthObjPtr, d3dCtx->depthStencilSurface); + } + env->ReleasePrimitiveArrayCritical((jarray)depthData, depthObjPtr, 0); + + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setRenderMode( + JNIEnv *env, + jobject obj, + jlong ctx, + jint mode, + jboolean dbEnable) +{ + // D3D v8.0 doesn't support stereo +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_clearAccum( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + // D3D use full-scene antialiasing capbilities in device + // instead of accumulation buffer (which it didn't support) +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_accum( + JNIEnv *env, + jobject obj, + jlong ctx, + jfloat value) +{ + // D3D use full-scene antialiasing capbilities in device + // instead of accumulation buffer (which didn't support) +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_accumReturn( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + // D3D use full-scene antialiasing capbilities in device + // instead of accumulation buffer (which it didn't support) +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setDepthBufferWriteEnable( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean mode) +{ + GetDevice(); + + d3dCtx->zWriteEnable = mode; + device->SetRenderState(D3DRS_ZWRITEENABLE, mode); +} + + +VOID freePointerList() +{ + if (useFreePointerList0) { + if (freePointerList1.size() > 0) { + lockSurfaceList(); + for (ITER_VOID p = freePointerList1.begin(); + p != freePointerList1.end(); ++p) { + delete (*p); + } + + freePointerList1.clear(); + unlockSurfaceList(); + } + useFreePointerList0 = false; + } else { + if (freePointerList0.size() > 0) { + lockSurfaceList(); + for (ITER_VOID p = freePointerList0.begin(); + p != freePointerList0.end(); ++p) { + delete (*p); + } + + freePointerList0.clear(); + unlockSurfaceList(); + } + useFreePointerList0 = true; + + } +} + + +extern "C" JNIEXPORT +jint JNICALL Java_javax_media_j3d_NativePipeline_swapBuffers( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctx, + jlong display, + jlong window) +{ + GetDevice2(); + + int retCode = NOCHANGE; + + HRESULT hr = device->Present(NULL, NULL, NULL, NULL); + + if (FAILED(hr)) { + hr = device->TestCooperativeLevel(); + if (D3DERR_DEVICELOST == hr) { + return NOCHANGE; + } + if (D3DERR_DEVICENOTRESET == hr) { + if (debug) { + printf("Buffer swap error %s, try Reset() the surface... \n", + DXGetErrorString9(hr)); + } + retCode = d3dCtx->resetSurface(env, cv); + GetDevice2(); + hr = device->Present(NULL, NULL, NULL, NULL); + if (FAILED(hr)) { + if (debug) { + printf("Buffer swap error %s \n", + DXGetErrorString9(hr)); + } + } + } + + } + + d3dCtx->freeList(); + freePointerList(); + return retCode; +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_syncRender( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean waitFlag) +{ + // do nothing since D3D always wait in Blt +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_newDisplayList( + JNIEnv *env, + jobject obj, + jlong ctx, + jint id) +{ + GetCtx(); + + if (id <= 0) { + if (debug) { + printf("In Canvas3D.newDisplayList id pass in = %d !\n", id); + } + return; + } + + if (id >= d3dCtx->dlTableSize) { + int newSize = d3dCtx->dlTableSize << 1; + if (id >= newSize) { + newSize = id+1; + } + int i=0; + LPD3DDISPLAYLIST *newTable = new LPD3DDISPLAYLIST[newSize]; + + if (newTable == NULL) { + printf("%s", getErrorMessage(OUTOFMEMORY)); + exit(1); + } + // entry 0 is not used + newTable[0] = NULL; + while (++i < d3dCtx->dlTableSize) { + newTable[i] = d3dCtx->displayListTable[i]; + } + while (i < newSize) { + newTable[i++] = NULL; + } + d3dCtx->dlTableSize = newSize; + SafeDelete(d3dCtx->displayListTable); + d3dCtx->displayListTable = newTable; + } + + if (d3dCtx->displayListTable[id] != NULL) { + SafeDelete(d3dCtx->displayListTable[id]); + } + d3dCtx->displayListTable[id] = new D3dDisplayList(); + if (d3dCtx->displayListTable[id] == NULL) { + printf("%s", getErrorMessage(OUTOFMEMORY)); + exit(1); + } + d3dCtx->currDisplayListID = id; +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_endDisplayList( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + d3dCtx->displayListTable[d3dCtx->currDisplayListID]->optimize(d3dCtx); + d3dCtx->currDisplayListID = 0; +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_callDisplayList( + JNIEnv *env, + jobject obj, + jlong ctx, + jint id, + jboolean isNonUniformScale) +{ + GetDevice(); + + // TODO: Remove this two safe checks when release + // d3dCtx->displayListTable[id]->render(d3dCtx); + + + if ((id <= 0) || (id >= d3dCtx->dlTableSize)) { + if (debug) { + if (id <= 0) { + printf("[Java 3D] Invalid Display List ID %d is invoked !\n", id); + } else { + printf("[Java 3D] Display List ID %d not yet initialize !\n", id); + } + } + return; + } + + LPD3DDISPLAYLIST dl = d3dCtx->displayListTable[id]; + + if (dl == NULL) { + if (debug) { + printf("[Java 3D] Display List ID %d not yet initialize !\n", id); + } + return; + } + dl->render(d3dCtx); + +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_freeDisplayList( + JNIEnv *env, + jobject obj, + jlong ctx, + jint id) +{ + GetCtx(); + + if ((id < 0) || (id >= d3dCtx->dlTableSize)) { + if (debug) { + printf("[Java 3D] FreeDisplayList, id %d not within table range %d!\n", id, + d3dCtx->dlTableSize); + } + return; + } + + SafeDelete(d3dCtx->displayListTable[id]); +} + + +/* + Native function to delete OGL texture object after j3d texture object + has been deleted by java garbage collector. + */ +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_freeTexture( + JNIEnv *env, + jobject obj, + jlong ctx, + jint id) +{ + GetDevice(); + + for (int i=0; i < d3dCtx->bindTextureIdLen; i++) { + if (d3dCtx->bindTextureId[i] == id) { + device->SetTexture(i, NULL); + d3dCtx->bindTextureId[i] = -1; + } + } + + if ((id >= d3dCtx->textureTableLen) || (id < 1)) { + if (debug) { + printf("Internal Error : freeTexture ID %d, textureTableLen %d \n", + id, d3dCtx->textureTableLen); + } + return; + } + + d3dCtx->freeResource(d3dCtx->textureTable[id]); + d3dCtx->textureTable[id] = NULL; +} + + +extern "C" JNIEXPORT +jint JNICALL Java_javax_media_j3d_NativePipeline_getTextureUnitCount( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetCtx2(); + return d3dCtx->deviceInfo->maxTextureUnitStageSupport; +} + + +extern "C" JNIEXPORT +jlong JNICALL Java_javax_media_j3d_NativePipeline_createOffScreenBuffer( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctx, + jlong display, + jlong fbConfigListPtr, + jint width, + jint height) + { + // Issue 396. + // createContext() will be invoked later in Renderer + return 1; +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_destroyContext( + JNIEnv *env, + jobject obj, + jlong display, + jlong window, + jlong ctx) +{ + GetDevice(); + + lock(); + d3dCtxList.erase(find(d3dCtxList.begin(), d3dCtxList.end(), d3dCtx)); + delete d3dCtx; + unlock(); + + Java_javax_media_j3d_NativePipeline_cleanupRenderer(env, obj); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_destroyOffScreenBuffer( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctx, + jlong display, + jlong fbConfigListPtr, + jlong window) +{ + // do nothing, since the old buffer will destory + // in createOffScreenBuffer + + // TODO : this means that we will hold onto the last off-screen buffer; + // we should clean this up at some point +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_readOffScreenBuffer( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctx, + jint format, + jint dataType, + jobject data, + jint width, + jint height) +{ + void *imageObjPtr; + + GetDevice(); + + if (format == IMAGE_FORMAT_USHORT_GRAY) { + printf("[Java 3D] readOffScreenBuffer not support IMAGE_FORMAT_USHORT_GRAY\n"); + return; + } + + if (d3dCtx->backSurface == NULL) { + HRESULT hr = device->GetBackBuffer(0,0, D3DBACKBUFFER_TYPE_MONO, //iSwapChain is 0 + &d3dCtx->backSurface); + if (FAILED(hr)) { + printf("[Java 3D] GetBackBuffer fail %s\n", + DXGetErrorString9(hr)); + return; + } + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *)env->GetPrimitiveArrayCritical((jarray)data, NULL); + } + else { + imageObjPtr = (void *)env->GetDirectBufferAddress(data); + } + + copyDataFromSurface(format, 0, 0, width, height, (jbyte *)imageObjPtr, + d3dCtx->backSurface); + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + env->ReleasePrimitiveArrayCritical((jarray)data, imageObjPtr, 0); + } + return; +} + + +extern "C" JNIEXPORT +jint JNICALL Java_javax_media_j3d_NativePipeline_resizeD3DCanvas( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctx) +{ + int status; + + GetCtx2(); + lock(); + status = d3dCtx->resize(env, cv); + unlock(); + + return status; +} + + +extern "C" JNIEXPORT +jint JNICALL Java_javax_media_j3d_NativePipeline_toggleFullScreenMode( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctx) +{ + int status; + + GetCtx2(); + lock(); + status = d3dCtx->toggleMode(!d3dCtx->bFullScreen, env, cv); + unlock(); + if (status == RECREATEDFAIL) { + return RECREATEDDRAW; + } + return status; +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setFullSceneAntialiasing( + JNIEnv *env, + jobject obj, + jlong ctx, + jboolean enable) +{ + GetDevice(); + + if (!implicitMultisample) { + device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, enable); + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_cleanupRenderer( + JNIEnv *env, + jobject obj) +{ + lock(); + if (d3dCtxList.empty()) { + D3dDriverInfo::release(); + } + unlock(); + + // Need to call it two times to free both list0 and list1 + freePointerList(); + freePointerList(); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_beginScene( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + device->BeginScene(); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_endScene( + JNIEnv *env, + jobject obj, + jlong ctx) +{ + GetDevice(); + device->EndScene(); +} + + +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_validGraphicsMode( + JNIEnv *env, + jobject obj) +{ + DEVMODE devMode; + + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode); + return (devMode.dmBitsPerPel > 8); +} diff --git a/j3d-core/src/native/d3d/D3dCtx.cpp b/j3d-core/src/native/d3d/D3dCtx.cpp new file mode 100644 index 0000000..fc94238 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dCtx.cpp @@ -0,0 +1,2200 @@ +/* + * $RCSfile: D3dCtx.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.20 $ + * $Date: 2008/04/04 14:46:08 $ + * $State: Exp $ + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include "Stdafx.h" + +D3dCtxVector d3dCtxList; + +/* + * Use the following code to initialize ctx property : + * + * D3dCtx ctx* = new D3dCtx(env, obj, hwnd, offScreen, vid); + * if (ctx->initialize(env, obj)) { + * delete ctx; + * } + * d3dCtxList.push_back(ctx); + * + * + * When ctx remove : + * + * d3dCtxList.erase(find(d3dCtxList.begin(), d3dCtxList.end(), ctx); + * delete ctx; + * + */ + +const D3DXMATRIX identityMatrix = D3DXMATRIX(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + +D3dCtx::D3dCtx(JNIEnv* env, jobject obj, HWND _hwnd, BOOL _offScreen, + jint vid) +{ + int i; + jniEnv = env; + monitor = NULL; + hwnd = _hwnd; + pD3D = NULL; + pDevice = NULL; + offScreen = _offScreen; + offScreenWidth = 0; + offScreenHeight = 0; + + driverInfo = NULL; + deviceInfo = NULL; + + depthStencilSurface = NULL; + frontSurface = NULL; + backSurface = NULL; + resetColorTarget = false; + forceResize = false; + inToggle = false; + useFreeList0 = true; + reIndexifyTable = NULL; + bFastDrawQuads = getSystemProperty(env,"j3d.d3dForceFastQuads","true"); + + // set default RenderingState variable + cullMode = D3DCULL_CW; + fillMode = D3DFILL_SOLID; + zWriteEnable = TRUE; + zEnable = TRUE; + + // TODO: THIS NEEDS TO BE REDONE WITH INFO FROM THE FBCONFIG PTR + // this is the pixelFormat return from NativeConfigTemplate. + minZDepth = vid & 0x3fffffff; + if (vid & 0x80000000) + { + antialiasing = REQUIRED; + } + else + if (vid & 0x40000000) + { + antialiasing = PREFERRED; + } + else + { + antialiasing = UNNECESSARY; + } + + setFullScreenFromProperty(env); + + if (offScreen) { + // disable fullscreen mode for offscreen + bFullScreen = false; + bFullScreenRequired = false; + } + + dlTableSize = DISPLAYLIST_INITSIZE; + displayListTable = new LPD3DDISPLAYLIST[dlTableSize]; + if (displayListTable == NULL) { + error(OUTOFMEMORY); + exit(1); + } + for (i=0; i < dlTableSize; i++) { + displayListTable[i] = NULL; + } + + currDisplayListID = 0; + quadIndexBuffer = NULL; + quadIndexBufferSize = 0; + lineModeIndexBuffer = NULL; + + srcVertexBuffer = NULL; + dstVertexBuffer = NULL; + + + multiTextureSupport = false; + texUnitStage = 0; + twoSideLightingEnable = false; + bindTextureId = NULL; + bindTextureIdLen = 0; + + textureTable = (LPDIRECT3DTEXTURE9 *) malloc( + sizeof(LPDIRECT3DTEXTURE9) * TEXTURETABLESIZE); + + if (textureTable == NULL) { + error(OUTOFMEMORY); + exit(1); + } + ZeroMemory(textureTable, sizeof(LPDIRECT3DTEXTURE9)*TEXTURETABLESIZE); + textureTableLen = TEXTURETABLESIZE; + + bindTextureId = NULL; + + volumeTable = (LPDIRECT3DVOLUMETEXTURE9 *) malloc( + sizeof(LPDIRECT3DVOLUMETEXTURE9) * TEXTURETABLESIZE); + + if (volumeTable == NULL) { + error(OUTOFMEMORY); + exit(1); + } + ZeroMemory(volumeTable, sizeof(LPDIRECT3DVOLUMETEXTURE9)*TEXTURETABLESIZE); + volumeTableLen = TEXTURETABLESIZE; + + + cubeMapTable = (LPDIRECT3DCUBETEXTURE9 *) malloc( + sizeof(LPDIRECT3DCUBETEXTURE9) * TEXTURETABLESIZE); + + if (cubeMapTable == NULL) { + error(OUTOFMEMORY); + exit(1); + } + ZeroMemory(cubeMapTable, sizeof(LPDIRECT3DCUBETEXTURE9)*TEXTURETABLESIZE); + cubeMapTableLen = TEXTURETABLESIZE; + + + if (hwnd == 0) { + // Offscreen rendering + hwnd = GetDesktopWindow(); + topHwnd = hwnd; + } else { + topHwnd = getTopWindow(hwnd); + } + + if (d3dDriverList == NULL) { + + // keep trying to initialize even though + // last time it fail. + D3dDriverInfo::initialize(env); + } + + if (d3dDriverList == NULL) { + /* + * This happen when either + * (1) D3D v9.0 not install or + * (2) Not enough memory or + * (3) No adapter found in the system. + */ + SafeRelease(pD3D); + error(D3DNOTFOUND); + return; + } + + pD3D = Direct3DCreate9( D3D_SDK_VERSION ); + + if (pD3D == NULL) { + error(D3DNOTFOUND); + return; + } + // find current monitor handle before + // get current display mode + monitor = findMonitor(); + + // check current display mode + enumDisplayMode(&devmode); + + if (devmode.dmBitsPerPel < 16) { + // tell user switch to at least 16 bit color next time + warning(NEEDSWITCHMODE); + } + + // find the adapter for this + setDriverInfo(); + + GetWindowRect(topHwnd, &savedTopRect); + winStyle = GetWindowLong(topHwnd, GWL_STYLE); + + for (i=0; i < 4; i++) { + rasterRect[i].sx = 0; + rasterRect[i].sy = 0; + rasterRect[i].sz = 0; + rasterRect[i].rhw = 0; + } + + rasterRect[0].tu = 0; + rasterRect[0].tv = 1; + rasterRect[1].tu = 0; + rasterRect[1].tv = 0; + rasterRect[2].tu = 1; + rasterRect[2].tv = 1; + rasterRect[3].tu = 1; + rasterRect[3].tv = 0; + + // initialize Ambient Material + ambientMaterial.Power = 0; + CopyColor(ambientMaterial.Emissive, 0, 0, 0, 1.0f); + CopyColor(ambientMaterial.Diffuse, 0, 0, 0, 1.0f); + CopyColor(ambientMaterial.Ambient, 1.0f, 1.0f, 1.0f, 1.0f); + CopyColor(ambientMaterial.Specular, 0, 0, 0, 1.0f); + GetWindowRect(hwnd, &windowRect); +} + +D3dCtx::~D3dCtx() +{ + release(); + SafeRelease(pD3D); +} + +VOID D3dCtx::releaseTexture() +{ + + for (int i=0; i < bindTextureIdLen; i++) { + if (bindTextureId[i] > 0) { + pDevice->SetTexture(i, NULL); + } + } + + lockSurfaceList(); + if (textureTable != NULL) { + // free all textures + for (int i=0; i < textureTableLen; i++) { + SafeRelease(textureTable[i]); + } + SafeFree(textureTable); + } + + if (volumeTable != NULL) { + for (int i=0; i < volumeTableLen; i++) { + SafeRelease(volumeTable[i]); + } + SafeFree(volumeTable); + + } + + + if (cubeMapTable != NULL) { + for (int i=0; i < cubeMapTableLen; i++) { + SafeRelease(cubeMapTable[i]); + } + SafeFree(cubeMapTable); + + } + + textureTableLen = 0; + volumeTableLen = 0; + cubeMapTableLen = 0; + unlockSurfaceList(); + + // free list0 + freeList(); + // free list1 + freeList(); +} + +VOID D3dCtx::setViewport() +{ + int renderWidth = getWidth(); + int renderHeight = getHeight(); + HRESULT hr; + D3DVIEWPORT9 vp = {0, 0, renderWidth, renderHeight, 0.0f, 1.0f}; + + hr = pDevice->SetViewport( &vp ); + + if (FAILED(hr)) { + // Use the previous Viewport if fail + error(VIEWPORTFAIL, hr); + } +} + +VOID D3dCtx::releaseVB() +{ + + if (displayListTable != NULL) { + // entry 0 is not used + for (int i=1; i < dlTableSize; i++) { + SafeDelete(displayListTable[i]); + } + SafeFree(displayListTable); + dlTableSize = 0; + } + + + lockGeometry(); + + D3dVertexBuffer *p = vertexBufferTable.next; + D3dVertexBuffer *q, **r; + D3dVertexBufferVector *vbVector; + boolean found = false; + + while (p != NULL) { + vbVector = p->vbVector; + if (vbVector != NULL) { + for (ITER_LPD3DVERTEXBUFFER r = vbVector->begin(); + r != vbVector->end(); ++r) { + if (*r == p) { + vbVector->erase(r); + found = true; + break; + } + } + } + q = p; + p = p->next; + delete q; + } + + vertexBufferTable.next = NULL; + + freeVBList0.clear(); + freeVBList1.clear(); + + unlockGeometry(); + +} + +VOID D3dCtx::release() +{ + + releaseTexture(); + SafeFree(bindTextureId); + bindTextureIdLen = 0; + + + SafeRelease(srcVertexBuffer); + SafeRelease(dstVertexBuffer); + SafeRelease(quadIndexBuffer); + SafeRelease(lineModeIndexBuffer); + quadIndexBufferSize = 0; + releaseVB(); + + // trying to free VertexBuffer + // This will crash the driver if Indices/StreamSource + // Not set before. + // pDevice->SetIndices(NULL, 0); + // pDevice->SetStreamSource(0, NULL, 0); + SafeRelease(depthStencilSurface); + SafeRelease(frontSurface); + SafeRelease(backSurface); + + SafeRelease(pDevice); + currDisplayListID = 0; + multiTextureSupport = false; + texUnitStage = 0; + twoSideLightingEnable = false; + freePointerList(); + freePointerList(); +} + + + +/* + * Application should delete ctx when this function return false. + */ +BOOL D3dCtx::initialize(JNIEnv *env, jobject obj) +{ + HRESULT hr; + // int oldWidth, oldHeight; + // BOOL needBiggerRenderSurface = false; + + // It is possible that last time Emulation mode is used. + // If this is the case we will try Hardware mode first. + deviceInfo = setDeviceInfo(driverInfo, &bFullScreen, minZDepth, minZDepthStencil); + + if ((pD3D == NULL) || (driverInfo == NULL)) { + return false; + } + /* + if (offScreenWidth > driverInfo->desktopMode.Width) { + if (debug) { + printf("OffScreen width cannot greater than %d\n", + driverInfo->desktopMode.Width); + } + oldWidth = offScreenWidth; + offScreenWidth = driverInfo->desktopMode.Width; + needBiggerRenderSurface = true; + + } + + if (offScreenHeight > driverInfo->desktopMode.Height) { + if (debug) { + printf("OffScreen Height cannot greater than %d\n", + driverInfo->desktopMode.Height); + } + oldHeight = offScreenHeight; + offScreenHeight = driverInfo->desktopMode.Height; + needBiggerRenderSurface = true; + } + */ + + if (!bFullScreen) { + getScreenRect(hwnd, &savedClientRect); + CopyMemory(&screenRect, &savedClientRect, sizeof (RECT)); + } + + dwBehavior = findBehavior(); + + + if (debug) { + printf("[Java3D]: Use %s, ", driverInfo->adapterIdentifier.Description); + + if (deviceInfo->isHardwareTnL && + (dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING)!=0) + { + // user select non-TnL device + printf("Hardware Rasterizer\n"); + } else { + printf("%s (TnL) \n", deviceInfo->deviceName); + } + } + + setPresentParams(env, obj); + + if (debug) { + printf("\n[Java3D]: Create device :\n"); + printInfo(&d3dPresent); + } + + + if ((d3dPresent.BackBufferWidth <= 0) || + (d3dPresent.BackBufferHeight <= 0)) { + if (debug) { + printf("[Java3D]: D3D: Can't create device of buffer size %dx%d\n", + d3dPresent.BackBufferWidth, + d3dPresent.BackBufferHeight); + } + //return false; + // Issue #578 fix on zero dimension window size + d3dPresent.BackBufferWidth = 1; + d3dPresent.BackBufferHeight = 1; + // end fix + } + + +if(bUseNvPerfHUD) +{ + // using NVIDIA NvPerfHUD profiler + printf("\n[Java3D]: running in NVIDIA NvPerfHUD mode:"); + UINT adapterToUse=driverInfo->iAdapter; + D3DDEVTYPE deviceType=deviceInfo->deviceType; + DWORD behaviorFlags = dwBehavior; + bool isHUDavail = false; + + // Look for 'NVIDIA NVPerfHUD' adapter + // If it is present, override default settings + for (UINT adapter=0;adapterGetAdapterCount(); adapter++) + { + D3DADAPTER_IDENTIFIER9 identifier; + HRESULT Res=pD3D->GetAdapterIdentifier(adapter,0,&identifier); + printf("\n Adapter identifier : %s",identifier.Description); + if (strcmp(identifier.Description,"NVIDIA NVPerfHUD")==0) + { + adapterToUse=adapter; + deviceType=D3DDEVTYPE_REF; + behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING ; + isHUDavail = true; + printf("\n[Java3D]: found a NVIDIA NvPerfHUD adapter"); + break; + } + } + hr = pD3D->CreateDevice( adapterToUse, + deviceType, + topHwnd, + behaviorFlags, + &d3dPresent, + &pDevice); + if(!FAILED(hr)&& isHUDavail) + { + printf("\n[Java3D]: Using NVIDIA NvPerfHUD ! \n"); + } + else + { + printf("\n[Java3D]: No suitable device found for NVIDIA NvPerfHUD ! \n"); + } +} +else +{ + // NORMAL Mode + + hr = pD3D->CreateDevice(driverInfo->iAdapter, + deviceInfo->deviceType, + topHwnd, + dwBehavior, + &d3dPresent, + &pDevice); + if(debug){ + char* ok = SUCCEEDED(hr) ? " Successful ! " : " Failed !"; + char* devTypeName = deviceInfo->deviceType==D3DDEVTYPE_HAL ? " HAL " : "REF"; + printf("\n[Java3D] CreateDevice using \"%s\" was %s (%s) \n", deviceInfo->deviceName, ok, devTypeName ); + } + + if(SUCCEEDED(hr) && deviceInfo->deviceType==D3DDEVTYPE_REF){ + // error(HALDEVICENOTFOUND); + error(NOHARDWAREACCEL); + } + +} + + + if (FAILED(hr) && (requiredDeviceID < 0)) + { + printf("\n[Java3D]: Using D3DDEVTYPE_REF mode.\n"); + if (deviceInfo->deviceType != D3DDEVTYPE_REF) { + // switch to reference mode + warning(CREATEDEVICEFAIL, hr); + deviceInfo = driverInfo->d3dDeviceList[DEVICE_REF]; + dwBehavior = findBehavior(); + deviceInfo->findDepthStencilFormat(minZDepth,minZDepthStencil); + d3dPresent.AutoDepthStencilFormat = + deviceInfo->depthStencilFormat; + if (deviceInfo->depthStencilFormat == D3DFMT_UNKNOWN) { + // should not happen since reference mode will + // support all depth stencil format + error(DEPTHSTENCILNOTFOUND); + return false; + } + if (debug) { + printf("[Java3D]: Fallback to create reference device :\n"); + printInfo(&d3dPresent); + } + + hr = pD3D->CreateDevice(driverInfo->iAdapter, + deviceInfo->deviceType, + topHwnd, + dwBehavior, + &d3dPresent, + &pDevice); + + if(SUCCEEDED(hr)){ + // error(HALDEVICENOTFOUND); + error(NOHARDWAREACCEL); + } + } + } + + /* + if (offScreen && needBiggerRenderSurface) { + IDirect3DSurface9 *pRenderTarget; + IDirect3DSurface9 *pStencilDepthTarget; + + hr = pDevice->CreateRenderTarget(oldWidth, + oldHeight, + driverInfo->desktopMode.Format, + D3DMULTISAMPLE_NONE, + true, + &pRenderTarget); + + if (FAILED(hr)) { + printf("Fail to CreateRenderTarget %s\n", DXGetErrorString9(hr)); + } else { + hr = pDevice->CreateDepthStencilSurface(oldWidth, + oldHeight, + deviceInfo->depthStencilFormat, + D3DMULTISAMPLE_NONE, + &pStencilDepthTarget); + if (FAILED(hr)) { + printf("Fail to CreateDepthStencilSurface %s\n", DXGetErrorString9(hr)); + pRenderTarget->Release(); + } else { + hr = pDevice->SetRenderTarget(pRenderTarget, + pStencilDepthTarget); + if (FAILED(hr)) { + printf("Fail to SetRenderTarget %s\n", DXGetErrorString9(hr)); + pRenderTarget->Release(); + pStencilDepthTarget->Release(); + } else { + printf("Successfully set bigger buffer\n"); + } + } + } + } + */ + + + setWindowMode(); + + if (FAILED(hr)) { + release(); + if (!inToggle) { + if(debug){ + error(PLEASEUPDATEDRIVERS, hr); + }else{ + error(PLEASEUPDATEDRIVERS); + } + } else { + warning(PLEASEUPDATEDRIVERS, hr); + } + return false; + } + + if (deviceInfo != NULL) { + bindTextureIdLen = deviceInfo->maxTextureUnitStageSupport; + } else { + bindTextureIdLen = 1; + } + + + jclass canvasCls = env->GetObjectClass(obj); + jfieldID id; + + // TODO check it !!!! + id = env->GetFieldID(canvasCls, "maxTexCoordSets", "I"); //was numtexCoordSupported + env->SetIntField(obj, id, TEXSTAGESUPPORT); + + if (bindTextureIdLen > 1) { + if (bindTextureIdLen > TEXSTAGESUPPORT) { + // D3D only support max. 8 stages. + bindTextureIdLen = TEXSTAGESUPPORT; + } + multiTextureSupport = true; + id = env->GetFieldID(canvasCls, "multiTexAccelerated", "Z"); + env->SetBooleanField(obj, id, JNI_TRUE); + + // TODO check it !!!! + id = env->GetFieldID(canvasCls, "maxTextureUnits", "I"); //was numTexUnitSupported + env->SetIntField(obj, id, bindTextureIdLen); + } else { + bindTextureIdLen = 1; + } + + bindTextureId = (INT *) malloc(sizeof(INT) * bindTextureIdLen); + if (bindTextureId == NULL) { + release(); + error(OUTOFMEMORY); + return false; + } + + setViewport(); + setDefaultAttributes(); + + // Issue 400: initialize local viewer (for lighting) to false + pDevice->SetRenderState(D3DRS_LOCALVIEWER, FALSE); + + createVertexBuffer(); + + if (debug && (deviceInfo != NULL)) { + if (multiTextureSupport) { + printf("Max Texture Unit Stage support : %d \n", + deviceInfo->maxTextureBlendStages); + + printf("Max Simultaneous Texture unit support : %d \n", + deviceInfo->maxSimultaneousTextures); + } else { + printf("MultiTexture support : false\n"); + } + } + return true; +} + +// canvas size change, get new back buffer +INT D3dCtx::resize(JNIEnv *env, jobject obj) +{ + int retValue; + + if ((pDevice == NULL) || bFullScreen) { + return false; // not yet ready when startup + } + + if (forceResize) { + // ignore first resize request after screen toggle + forceResize = false; + return NOCHANGE; + } + // we don't want resize to do twice but when window toggle + // between fullscreen and window mode, the move event will got + // first. Thus it will get size correctly without doing resize. + + BOOL moveRequest; + + + GetWindowRect(hwnd, &windowRect); + + if ((windowRect.right == screenRect.right) && + (windowRect.left == screenRect.left) && + (windowRect.bottom == screenRect.bottom) && + (windowRect.top == screenRect.top)) { + return NOCHANGE; + } + + if (((windowRect.left - windowRect.right) + == (screenRect.left - screenRect.right)) && + ((windowRect.bottom - windowRect.top) + == (screenRect.bottom - screenRect.top))) { + moveRequest = true; + } else { + moveRequest = false; + } + + + HMONITOR oldMonitor = monitor; + monitor = findMonitor(); + + getScreenRect(hwnd, &screenRect); + + if (monitor != oldMonitor) { + enumDisplayMode(&devmode); + setDriverInfo(); + release(); + initialize(env, obj); + return RECREATEDDRAW; + } + + if (!moveRequest) { + + retValue = resetSurface(env, obj); + if (retValue != RECREATEDFAIL) { + return retValue; + } else { + return RECREATEDDRAW; + } + } + return NOCHANGE; +} + + +INT D3dCtx::toggleMode(BOOL _bFullScreen, JNIEnv *env, jobject obj) +{ + INT retValue; + + if ((pDevice == NULL) || + (!_bFullScreen && + !deviceInfo->canRenderWindowed)) { + // driver did not support window mode + return NOCHANGE; + } + + int onScreenCount = 0; + + for (ITER_D3dCtxVector p = d3dCtxList.begin(); p != d3dCtxList.end(); p++) { + if (!(*p)->offScreen && + // (monitor == (*p)->monitor) && + (++onScreenCount > 1)) { + // don't toggle if there are more than one onScreen ctx exists + // in the same screen + return false; + } + } + + + inToggle = true; + bFullScreen = _bFullScreen; + + retValue = resetSurface(env, obj); + + if (retValue != RECREATEDFAIL) { + forceResize = true; + } else { + // Switch back to window mode if fall to toggle fullscreen + // and vice versa + bFullScreen = !bFullScreen; + release(); + if (initialize(env, obj)) { + retValue = RECREATEDDRAW; + forceResize = true; + } else { + retValue = RECREATEDFAIL; + } + } + if (retValue != RECREATEDFAIL) { + setViewport(); + } + + inToggle = false; + return retValue; +} + +VOID D3dCtx::setPresentParams(JNIEnv *env, jobject obj) +{ + setCanvasProperty(env, obj); + + d3dPresent.AutoDepthStencilFormat = deviceInfo->depthStencilFormat; + d3dPresent.EnableAutoDepthStencil = true; + + // Fix to Issue 226 : D3D - fail on stress test for the creation and destruction of Canvases + bool useMultisample = (antialiasing != UNNECESSARY) && deviceInfo->supportAntialiasing(); + + if (useMultisample) { + d3dPresent.MultiSampleType = deviceInfo->getBestMultiSampleType(); + d3dPresent.MultiSampleQuality = 0; + } else { + d3dPresent.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dPresent.MultiSampleQuality = 0; + } + d3dPresent.BackBufferCount = 1; + d3dPresent.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + + // We can't use Discard, otherwise readRaster will fail as + // content of backbuffer will discard after swap unless + // we always call readRaster() just before swap. + // However in this way we can't use multisample effect + + // FULLSCREEN + if (bFullScreen) { + GetWindowRect(topHwnd, &savedTopRect); + GetWindowRect(hwnd, &savedClientRect); + + d3dPresent.Windowed = false; + d3dPresent.hDeviceWindow = topHwnd; + + if (useMultisample) { + d3dPresent.SwapEffect = D3DSWAPEFFECT_DISCARD; + } else { + d3dPresent.SwapEffect = D3DSWAPEFFECT_FLIP; + } + d3dPresent.BackBufferWidth = driverInfo->desktopMode.Width; + d3dPresent.BackBufferHeight = driverInfo->desktopMode.Height; + d3dPresent.BackBufferFormat = driverInfo->desktopMode.Format; + d3dPresent.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + if (deviceInfo->supportRasterPresImmediate) + d3dPresent.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + else + d3dPresent.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + + } else { + // WINDOWED mode + d3dPresent.Windowed = true; + d3dPresent.hDeviceWindow = hwnd; + + if (useMultisample) { + d3dPresent.SwapEffect = D3DSWAPEFFECT_DISCARD; + } else { + d3dPresent.SwapEffect = D3DSWAPEFFECT_COPY; + } + d3dPresent.BackBufferWidth = getWidth(); + d3dPresent.BackBufferHeight = getHeight(); + d3dPresent.BackBufferFormat = driverInfo->desktopMode.Format; + d3dPresent.FullScreen_RefreshRateInHz = 0; + + if (deviceInfo->supportRasterPresImmediate) + d3dPresent.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + else + d3dPresent.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + + } + +} + +INT D3dCtx::resetSurface(JNIEnv *env, jobject obj) +{ + D3dDeviceInfo* oldDevice = deviceInfo; + HRESULT hr; + + + deviceInfo = setDeviceInfo(driverInfo, &bFullScreen, minZDepth, minZDepthStencil); + + if (deviceInfo == NULL) { + return NOCHANGE; + } + if (deviceInfo != oldDevice) { + // we fall back to Reference mode last time, + // try to see if we can run in hardware mode after + // the surface size change. + release(); + if (initialize(env, obj)) { + return RECREATEDDRAW; + } else { + return RECREATEDFAIL; + } + } else { + setPresentParams(env, obj); + if (debug) { + printf("\nReset Device :\n"); + printInfo(&d3dPresent); + } + + // Must release any non default pool surface, otherwise + // Reset() will fail + SafeRelease(depthStencilSurface); + SafeRelease(frontSurface); + SafeRelease(backSurface); + + releaseVB(); + SafeRelease(lineModeIndexBuffer); + quadIndexBufferSize = 0; + + hr = pDevice->Reset(&d3dPresent); + if (FAILED(hr)) { + warning(RESETFAIL, hr); + // try to recreate Surface, if still fail, try Reference mode + release(); + if (initialize(env, obj)) { + return RECREATEDDRAW; + } else { + return RECREATEDFAIL; + } + } else { + setWindowMode(); + setDefaultAttributes(); + return RESETSURFACE; + } + } + + return NOCHANGE; +} + + +VOID D3dCtx::error(int idx) +{ + error(getErrorMessage(idx)); +} + +VOID D3dCtx::error(int idx, HRESULT hr) +{ + error(getErrorMessage(idx), hr); +} + + +VOID D3dCtx::warning(int idx) +{ + printf("[Java3D] Warning : %s\n", getErrorMessage(idx)); +} + +VOID D3dCtx::warning(int idx, HRESULT hr) +{ + printf("[Java3D] Warning : %s - %s\n", getErrorMessage(idx), DXGetErrorString9(hr)); +} + + +VOID D3dCtx::error(char *s) +{ + showError(hwnd, s, bFullScreen); +} + +VOID D3dCtx::error(char *s, HRESULT hr) +{ + char message[400]; + sprintf(message, "%s - %s", s, DXGetErrorString9(hr)); + showError(hwnd, message, bFullScreen); +} + + +VOID D3dCtx::d3dWarning(int idx) +{ + printf("[Java3D] Warning: %s\n", getErrorMessage(idx)); +} + +VOID D3dCtx::d3dWarning(int idx, HRESULT hr) +{ + printf("[Java3D] Warning: %s - %s\n", + getErrorMessage(idx), DXGetErrorString9(hr)); + +} + +VOID D3dCtx::d3dError(char *s) +{ + showError(GetDesktopWindow(), s, false); +} + + +VOID D3dCtx::d3dError(int idx) +{ + d3dError(getErrorMessage(idx)); +} + + +// Only display message box for the first error, since +// Java3D will continue to invoke createContext() when it fail +VOID D3dCtx::showError(HWND hwnd, char *s, BOOL bFullScreen) +{ + if (firstError) { + firstError = false; + if (bFullScreen) { + // In full screen mode, we can't see message box + printf("[Java3D] Error: %s\n", s); + exit(1); + } else { + MessageBox(hwnd, s, "Java 3D", MB_OK|MB_ICONERROR); + } + } +} + + +DWORD D3dCtx::getWidth() +{ + if (!offScreen) { + return screenRect.right - screenRect.left; + } else { + return offScreenWidth; + } + +} + + +DWORD D3dCtx::getHeight() +{ + if (!offScreen) { + return screenRect.bottom - screenRect.top; + } else { + return offScreenHeight; + } + +} + +D3dDeviceInfo* D3dCtx::selectDevice(int deviceID, + D3dDriverInfo *driverInfo, + BOOL *bFullScreen, + int minZDepth, + int minZDepthStencil) +{ + D3dDeviceInfo *pDevice; + + for (int i=0; i < numDeviceTypes; i++) + { + pDevice = driverInfo->d3dDeviceList[i]; + if ((((deviceID == DEVICE_HAL) || (deviceID == DEVICE_HAL_TnL)) && + (pDevice->deviceType == D3DDEVTYPE_HAL)) || + (deviceID == DEVICE_REF) && + (pDevice->deviceType == D3DDEVTYPE_REF)) + { + if ((*bFullScreen && !pDevice->fullscreenCompatible) || + (!*bFullScreen && !pDevice->desktopCompatible)) + { + if (pDevice->deviceType == D3DDEVTYPE_HAL) + { + d3dError(HALDEVICENOTFOUND); + } + else + { + // should not happen, REF device always support + d3dError(DEVICENOTFOUND); + } + // exit is not allowed on applets + //exit(1); + return NULL; + } + if (pDevice->maxZBufferDepthSize == 0) + { + if (pDevice->deviceType == D3DDEVTYPE_HAL) + { + d3dError(HALNOTCOMPATIBLE); + } + else + { + // should not happen, REF device always support + d3dError(DEVICENOTFOUND); + } + // exit is not allowed on applets + //exit(1); + return NULL; + } + if (pDevice->deviceType == D3DDEVTYPE_HAL) + { + if ((deviceID == DEVICE_HAL_TnL) && + !pDevice->isHardwareTnL) + { + d3dError(TNLHALDEVICENOTFOUND); + // exit is not allowed on applets + //exit(1); + return NULL; + } + } + + pDevice->findDepthStencilFormat(minZDepth, minZDepthStencil); + if (pDevice->depthStencilFormat == D3DFMT_UNKNOWN) + { + d3dError(DEPTHSTENCILNOTFOUND); + // exit is not allowed on applets + //exit(1); + return NULL; + } + return pDevice; + } + } + + // should not happen + d3dError(DEVICENOTFOUND); + // exit is not allowed on applets + //exit(1); + return NULL; +} + + + +D3dDeviceInfo* D3dCtx::selectBestDevice(D3dDriverInfo *driverInfo, + BOOL *bFullScreen, + int minZDepth, + int minZDepthStencil) +{ + D3dDeviceInfo *pDevice; + D3dDeviceInfo *bestDevice = NULL; + int i; + + for (i=0; i < numDeviceTypes; i++) + { + pDevice = driverInfo->d3dDeviceList[i]; + if (pDevice->maxZBufferDepthSize > 0) + { + pDevice->findDepthStencilFormat(minZDepth, minZDepthStencil); + + if (pDevice->depthStencilFormat == D3DFMT_UNKNOWN) + { + if (pDevice->deviceType == D3DDEVTYPE_REF) + { + d3dError(DEPTHSTENCILNOTFOUND); + return NULL; + } else { + continue; + } + } + if (*bFullScreen) { + if (pDevice->fullscreenCompatible) { + bestDevice = pDevice; + break; + } + } else { + if (pDevice->canRenderWindowed) { + if (pDevice->desktopCompatible) { + bestDevice = pDevice; + break; + } + } else { + if (pDevice->fullscreenCompatible) { + // switch to fullscreen mode + *bFullScreen = true; + bestDevice = pDevice; + break; + } + } + } + } + } + + if (bestDevice == NULL) { + // should not happen + d3dError(DEVICENOTFOUND); + return NULL; + } + + // TODO: suggest another display mode for user + /* + if (bestDevice->deviceType == D3DDEVTYPE_REF) { + // Recomend other display mode that support + // hardware accerated rendering if any. + int numModes = pD3D->GetAdapterModeCount(driverInfo->iAdapter); + D3DDISPLAYMODE dmode; + + for (i=0; i < numModes; i++) { + pD3D->EnumAdapterModes(pDriverInfo->iAdapter, i, &dmode); + if ((dmode.Width < 640) || (dmode.Height < 400)) { + // filter out low resolution modes + continue; + } + } + .... + } + */ + return bestDevice; +} + + +VOID D3dCtx::setDeviceFromProperty(JNIEnv *env) +{ + + jclass systemClass = env->FindClass( "javax/media/j3d/MasterControl" ); + + if ( systemClass != NULL ) + { + jmethodID method = env->GetStaticMethodID( + systemClass, "getProperty", + "(Ljava/lang/String;)Ljava/lang/String;" ); + if ( method != NULL ) + { + jstring name = env->NewStringUTF( "j3d.d3ddevice" ); + jstring property = reinterpret_cast( + env->CallStaticObjectMethod( + systemClass, method, name )); + jboolean isCopy; + + if ( property != NULL ) + { + const char* chars = env->GetStringUTFChars( + property, &isCopy ); + if ( chars != 0 ) + { + if (stricmp(chars, "reference") == 0) { + // There is no emulation device anymore in v8.0 + requiredDeviceID = DEVICE_REF; + } else if (stricmp(chars, "hardware") == 0) { + requiredDeviceID = DEVICE_HAL; + } else if (stricmp(chars, "TnLhardware") == 0) { + requiredDeviceID = DEVICE_HAL_TnL; + } else { + d3dError(UNKNOWNDEVICE); + //switch to default + requiredDeviceID = 0; + //exit(1); + + } + env->ReleaseStringUTFChars( property, chars ); + } + } + name = env->NewStringUTF( "j3d.d3ddriver" ); + property = reinterpret_cast( + env->CallStaticObjectMethod( + systemClass, method, name )); + if ( property != NULL ) + { + const char* chars = env->GetStringUTFChars( + property, &isCopy); + if ( chars != 0 ) + { + // atoi() return 0, our default value, on error. + requiredDriverID = atoi(chars); + } + } + } + } +} + +VOID D3dCtx::setFullScreenFromProperty(JNIEnv *env) +{ + + jclass systemClass = env->FindClass( "javax/media/j3d/MasterControl" ); + + bFullScreenRequired = false; + bFullScreen = false; + + if ( systemClass != NULL ) + { + jmethodID method = env->GetStaticMethodID( + systemClass, "getProperty", + "(Ljava/lang/String;)Ljava/lang/String;" ); + if ( method != NULL ) + { + jstring name = env->NewStringUTF( "j3d.fullscreen" ); + jstring property = reinterpret_cast( + env->CallStaticObjectMethod( + systemClass, method, name )); + if ( property != NULL ) + { + jboolean isCopy; + const char * chars = env->GetStringUTFChars( + property, &isCopy ); + if ( chars != 0 ) + { + if ( stricmp( chars, "required" ) == 0 ) { + bFullScreenRequired = true; + bFullScreen = true; + } else if ( stricmp( chars, "preferred" ) == 0 ) { + bFullScreen = true; + } + // "UNNECESSARY" is the default + env->ReleaseStringUTFChars( property, chars ); + } + } + } + } + +} + +VOID D3dCtx::setVBLimitProperty(JNIEnv *env) +{ + jclass systemClass = env->FindClass( "javax/media/j3d/MasterControl" ); + + if ( systemClass != NULL ) + { + jmethodID method = env->GetStaticMethodID( + systemClass, "getProperty", + "(Ljava/lang/String;)Ljava/lang/String;" ); + if ( method != NULL ) + { + jstring name = env->NewStringUTF( "j3d.vertexbufferlimit" ); + jstring property = reinterpret_cast( + env->CallStaticObjectMethod( + systemClass, method, name )); + if ( property != NULL ) + { + jboolean isCopy; + const char * chars = env->GetStringUTFChars( + property, &isCopy ); + if ( chars != 0 ) + { + long vbLimit = atol(chars); + env->ReleaseStringUTFChars( property, chars ); + if (vbLimit >= 6) { + // Has to be at least 6 since for Quad the + // limit reset to 2*vbLimit/3 >= 4 + printf("Java 3D: VertexBuffer limit set to %ld\n", vbLimit); + vertexBufferMaxVertexLimit = vbLimit; + } else { + printf("Java 3D: VertexBuffer limit should be an integer >= 6 !\n"); + } + + } + } + } + } +} + +VOID D3dCtx::setDebugProperty(JNIEnv *env) +{ + jclass systemClass = env->FindClass( "javax/media/j3d/MasterControl" ); + + debug = false; + + if ( systemClass != NULL ) + { + jmethodID method = env->GetStaticMethodID( + systemClass, "getProperty", + "(Ljava/lang/String;)Ljava/lang/String;" ); + if ( method != NULL ) + { + jstring name = env->NewStringUTF( "j3d.debug" ); + jstring property = reinterpret_cast( + env->CallStaticObjectMethod( + systemClass, method, name )); + if ( property != NULL ) + { + jboolean isCopy; + const char * chars = env->GetStringUTFChars( + property, &isCopy ); + if ( chars != 0 ) + { + if ( stricmp( chars, "true" ) == 0 ) { + debug = true; + } else { + debug = false; + } + // "UNNECESSARY" is the default + env->ReleaseStringUTFChars( property, chars ); + } + } + } + } +} + +BOOL D3dCtx::getSystemProperty(JNIEnv *env, char *strName, char *strValue) +{ + jclass systemClass = env->FindClass( "javax/media/j3d/MasterControl" ); + + if ( systemClass != NULL ) + { + jmethodID method = env->GetStaticMethodID( + systemClass, "getProperty", + "(Ljava/lang/String;)Ljava/lang/String;" ); + if ( method != NULL ) + { + jstring name = env->NewStringUTF( strName ); + jstring property = reinterpret_cast( + env->CallStaticObjectMethod( + systemClass, method, name )); + if ( property != NULL ) + { + jboolean isCopy; + const char * chars = env->GetStringUTFChars(property, &isCopy ); + if ( chars != 0 && stricmp( chars, strValue ) == 0 ) + { + env->ReleaseStringUTFChars( property, chars ); + return true; + } + else + { + env->ReleaseStringUTFChars( property, chars ); + return false; + } + } + } + } + return false; +} + +VOID D3dCtx::setImplicitMultisamplingProperty(JNIEnv *env) +{ + jclass cls = env->FindClass("javax/media/j3d/VirtualUniverse"); + + if (cls == NULL) { + implicitMultisample = false; + return; + } + + jfieldID fieldID = env->GetStaticFieldID(cls, "mc", "Ljavax/media/j3d/MasterControl;"); + + if (fieldID == NULL) { + implicitMultisample = false; + return; + } + + jobject obj = env->GetStaticObjectField(cls, fieldID); + + if (obj == NULL) { + implicitMultisample = false; + return; + } + + cls = env->FindClass("javax/media/j3d/MasterControl"); + + if (cls == NULL) { + implicitMultisample = false; + return; + } + + fieldID = env->GetFieldID(cls, "implicitAntialiasing", "Z"); + + if (fieldID == NULL ) { + implicitMultisample = false; + return; + } + + implicitMultisample = env->GetBooleanField(obj, fieldID); + return; +} + + +// Callback to notify Canvas3D which mode it is currently running +VOID D3dCtx::setCanvasProperty(JNIEnv *env, jobject obj) +{ + int mask = javax_media_j3d_Canvas3D_EXT_ABGR | + javax_media_j3d_Canvas3D_EXT_BGR; + + if ((deviceInfo->depthStencilFormat == D3DFMT_D24S8) || + (deviceInfo->depthStencilFormat == D3DFMT_D24X4S4)) + { + // The other format D3DFMT_D15S1 with 1 bit + // stencil buffer has no use for Decal group so it + // is ignored. + mask |= javax_media_j3d_Canvas3D_STENCIL_BUFFER; + } + + + jclass canvasCls = env->GetObjectClass(obj); + jfieldID id = env->GetFieldID(canvasCls, "fullScreenMode", "Z"); + env->SetBooleanField(obj, id, bFullScreen); + + id = env->GetFieldID(canvasCls, "fullscreenWidth", "I"); + env->SetIntField(obj, id, driverInfo->desktopMode.Width); + + id = env->GetFieldID(canvasCls, "fullscreenHeight", "I"); + env->SetIntField(obj, id, driverInfo->desktopMode.Height); + + //id = env->GetFieldID(canvasCls, "userStencilAvailable", "Z"); + //env->SetBooleanField(obj, id, deviceInfo->supportStencil ); + + + id = env->GetFieldID(canvasCls, "textureExtendedFeatures", "I"); + int texMask = deviceInfo->getTextureFeaturesMask(); + jboolean enforcePowerOfTwo = getJavaBoolEnv(env, "enforcePowerOfTwo"); + if(enforcePowerOfTwo) { + // printf("DEBUG enforcePowerOfTwo is true"); + texMask &= ~javax_media_j3d_Canvas3D_TEXTURE_NON_POWER_OF_TWO; + } + env->SetIntField(obj, id, texMask); + + + + id = env->GetFieldID(canvasCls, "extensionsSupported", "I"); + env->SetIntField(obj, id, mask); + + + id = env->GetFieldID(canvasCls, "nativeGraphicsVersion", "Ljava/lang/String;"); + char *version = "DirectX 9.0 or above"; + env->SetObjectField(obj, id, env->NewStringUTF(version)); + + float degree = float(deviceInfo->maxAnisotropy); + id = env->GetFieldID(canvasCls, "anisotropicDegreeMax", "F"); + env->SetFloatField(obj, id, degree); + + id = env->GetFieldID(canvasCls, "textureWidthMax", "I"); + env->SetIntField(obj, id, deviceInfo->maxTextureWidth); + + id = env->GetFieldID(canvasCls, "textureHeightMax", "I"); + env->SetIntField(obj, id, deviceInfo->maxTextureHeight); + + if (deviceInfo->maxTextureDepth > 0) { + id = env->GetFieldID(canvasCls, "texture3DWidthMax", "I"); + env->SetIntField(obj, id, deviceInfo->maxTextureWidth); + + id = env->GetFieldID(canvasCls, "texture3DHeightMax", "I"); + env->SetIntField(obj, id, deviceInfo->maxTextureHeight); + + id = env->GetFieldID(canvasCls, "texture3DDepthMax", "I"); + env->SetIntField(obj, id, deviceInfo->maxTextureDepth); + + // issue 135 + // private String nativeGraphicsVendor = ""; + // private String nativeGraphicsRenderer = ""; + id = env->GetFieldID(canvasCls, "nativeGraphicsVendor", "Ljava/lang/String;"); + //char *nGVendor = driverInfo->adapterIdentifier.DeviceName ; + char *nGVendor = deviceInfo->deviceVendor ; + env->SetObjectField(obj, id, env->NewStringUTF(nGVendor)); + // printf("DEBUG vendor : %s ", nGVendor); + + id = env->GetFieldID(canvasCls, "nativeGraphicsRenderer", "Ljava/lang/String;"); + // char *nGRenderer = driverInfo->adapterIdentifier.Description; + char *nGRenderer = deviceInfo->deviceRenderer; + env->SetObjectField(obj, id, env->NewStringUTF(nGRenderer)); + + + } +} + + + + +VOID D3dCtx::createVertexBuffer() +{ + if (srcVertexBuffer != NULL) { + // Each pDevice has its own vertex buffer, + // so if different pDevice create vertex buffer has to + // recreate again. + srcVertexBuffer->Release(); + } + + if (dstVertexBuffer != NULL) { + dstVertexBuffer->Release(); + } + DWORD usage_D3DVERTEX = D3DUSAGE_DONOTCLIP| + D3DUSAGE_WRITEONLY| + D3DUSAGE_SOFTWAREPROCESSING; + + DWORD usage_D3DTLVERTEX= D3DUSAGE_DONOTCLIP| + D3DUSAGE_SOFTWAREPROCESSING; + +//# if NVIDIA_DEBUG + if(deviceInfo->isHardwareTnL) + { + // remove SoftwareProcessing + usage_D3DVERTEX = D3DUSAGE_DONOTCLIP| + D3DUSAGE_WRITEONLY; + + usage_D3DTLVERTEX = D3DUSAGE_DONOTCLIP; + } +// # endif + + HRESULT hr = + pDevice->CreateVertexBuffer(sizeof(D3DVERTEX), + usage_D3DVERTEX, + D3DFVF_XYZ, + D3DPOOL_MANAGED, + &srcVertexBuffer, + NULL); + + if (FAILED(hr)) { + printf("\n[Java3D] Failed to create VertexBuffer (D3DVERTEX)\n"); + error(CREATEVERTEXBUFFER, hr); + + } + + hr = pDevice->CreateVertexBuffer(sizeof(D3DTLVERTEX), + usage_D3DTLVERTEX, + D3DFVF_XYZRHW|D3DFVF_TEX1, + D3DPOOL_MANAGED, + &dstVertexBuffer,NULL); + if (FAILED(hr)) { + printf("\n[Java3D] Warning: Failed to create VertexBuffer (D3DTLVERTEX)\n"); + error(CREATEVERTEXBUFFER, hr); + } +} + + +VOID D3dCtx::transform(D3DVERTEX *worldCoord, D3DTLVERTEX *screenCoord) { + D3DVERTEX *pv; + D3DTLVERTEX *tlpv; + HRESULT hr; + + if (srcVertexBuffer != NULL) { + // Need to disable Texture state, otherwise + // ProcessVertices() will fail with debug message : + // + // "Number of output texture coordintes and their format should + // be the same in the destination vertex buffer and as + // computed for current D3D settings." + // + // when multiple texture is used. + DWORD texState; + // save original texture state + pDevice->GetTextureStageState(0, D3DTSS_COLOROP, &texState); + // disable texture processing + pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); + + if (!softwareVertexProcessing) { + // ProcessVertices() only work in software vertex + // processing mode + //pDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, TRUE); + pDevice->SetSoftwareVertexProcessing(TRUE); + } + + pDevice->SetRenderState(D3DRS_CLIPPING, FALSE); + hr = srcVertexBuffer->Lock(0, 0, (VOID **)&pv, 0); + if (FAILED(hr)) { + if (debug) { + printf("[Java3D] Fail to lock buffer %s\n", DXGetErrorString9(hr)); + } + } else { + pv[0].x = worldCoord->x; + pv[0].y = worldCoord->y; + pv[0].z = worldCoord->z; + + srcVertexBuffer->Unlock(); + pDevice->SetStreamSource(0, srcVertexBuffer,0, sizeof(D3DVERTEX)); + + //pDevice->SetVertexShader(D3DFVF_XYZ); + pDevice->SetVertexShader(NULL); + pDevice->SetFVF(D3DFVF_XYZ); + + hr = pDevice->ProcessVertices(0, 0, 1, + dstVertexBuffer, + NULL, + 0); + + if (FAILED(hr)) { + if (debug) { + printf("[Java3D] Fail to processVertices %s\n", DXGetErrorString9(hr)); + } + } else { + hr = dstVertexBuffer->Lock(0, 0, (VOID **)&tlpv, D3DLOCK_READONLY); + if (SUCCEEDED(hr)) { + screenCoord->sx = tlpv[0].sx; + screenCoord->sy = tlpv[0].sy; + screenCoord->sz = tlpv[0].sz; + screenCoord->rhw = tlpv[0].rhw; + dstVertexBuffer->Unlock(); + } else { + if (debug) { + error("Fail to lock surface in transform", hr); + } + } + } + } + pDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + if (!softwareVertexProcessing) { + //pDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE); + pDevice->SetSoftwareVertexProcessing(FALSE); + } + // restore original texture state + pDevice->SetTextureStageState(0, D3DTSS_COLOROP, texState); + } +} + + + +VOID D3dCtx::getScreenRect(HWND hwnd, RECT *rect) { + + GetWindowRect(hwnd, rect); + + if ((deviceInfo->isHardware) && + (numDriver > 1)) { + + MONITORINFO info; + HMONITOR hMonitor = driverInfo->hMonitor; + + info.cbSize = sizeof(MONITORINFO); + if (hMonitor == NULL) { + hMonitor = MonitorFromWindow(hwnd, + MONITOR_DEFAULTTONEAREST); + } + GetMonitorInfo(hMonitor, &info); + monitorLeft = info.rcMonitor.left; + monitorTop = info.rcMonitor.top; + rect->left -= monitorLeft; + rect->right -= monitorLeft; + rect->top -= monitorTop; + rect->bottom -= monitorTop; + } else { + monitorLeft = 0; + monitorTop = 0; + } +} + +/* + * Search the monitor that this window competely enclosed. + * Return NULL if this window intersect several monitor + */ + +HMONITOR D3dCtx::findMonitor() +{ + + if ((osvi.dwMajorVersion < 4) || + (numDriver < 2)) { + return NULL; + } + + RECT rect; + MONITORINFO info; + HMONITOR hmonitor = MonitorFromWindow(hwnd, + MONITOR_DEFAULTTONEAREST); + info.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(hmonitor, &info); + GetWindowRect(hwnd, &rect); + + if ((info.rcMonitor.left <= rect.left) && + (info.rcMonitor.right >= rect.right) && + (info.rcMonitor.top <= rect.top) && + (info.rcMonitor.bottom >= rect.bottom)) { + if (info.dwFlags & MONITORINFOF_PRIMARY) { + // Pass NULL is same as passing the guid of the + // first monitor. This can avoid recreate when + // window drag between screen borders from first + // screen. + return NULL; + } else { + return hmonitor; + } + } + return NULL; +} + + +D3dDeviceInfo* D3dCtx::setDeviceInfo(D3dDriverInfo *driverInfo, + BOOL *bFullScreen, + int minZDepth, + int minZDepthStencil) +{ + if (requiredDeviceID >= 0) + { + return selectDevice(requiredDeviceID, + driverInfo, + bFullScreen, + minZDepth, + minZDepthStencil); + } + else + { + return selectBestDevice(driverInfo, + bFullScreen, + minZDepth, + minZDepthStencil); + } +} + +// Find the adapter that this window belongs to +// and set driverInfo to this +VOID D3dCtx::setDriverInfo() +{ + D3dDriverInfo *newDriver = NULL; + + if (requiredDriverID <= 0) { + if ((numDriver < 2) || + (monitor == NULL) || + (osvi.dwMajorVersion < 4)) { + // windows 95 don't support multiple monitors + // Use Primary display driver + newDriver = d3dDriverList[0]; + } else { + for (int i=0; i < numDriver; i++) { + if (d3dDriverList[i]->hMonitor == monitor) { + newDriver = d3dDriverList[i]; + break; + } + } + } + } else { + if (requiredDriverID > numDriver) { + requiredDriverID = numDriver; + } + newDriver = d3dDriverList[requiredDriverID-1]; + } + + driverInfo = newDriver; +} + + +VOID D3dCtx::setDefaultAttributes() +{ + + /*pDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, + softwareVertexProcessing);*/ + pDevice->SetSoftwareVertexProcessing(softwareVertexProcessing); + + pDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, + D3DMCS_MATERIAL); + pDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, + D3DMCS_MATERIAL); + pDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE); + // Default specular is FALSE + pDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE); + // Texture & CULL mode default value for D3D is different from OGL + + pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); + + // Default in D3D is D3DCMP_LESSEQUAL, OGL is D3DCMP_LESS + + // Set Range based fog + pDevice->SetRenderState(D3DRS_RANGEFOGENABLE, + deviceInfo->rangeFogEnable); + + // disable antialiasing (default is true in D3D) + if (!implicitMultisample) { + pDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, FALSE); + } + + pointSize = 1; + cullMode = D3DCULL_CW; + fillMode = D3DFILL_SOLID; + zWriteEnable = TRUE; + zEnable = TRUE; + + if ((pDevice != NULL) && (bindTextureId != NULL)) { + for (int i=0; i < bindTextureIdLen; i++) { + pDevice->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + pDevice->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pDevice->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + pDevice->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + //pDevice->SetTextureStageState(i, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); + //pDevice->SetTextureStageState(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); + bindTextureId[i] = -1; + } + } + + + for (int i=0; i < TEXSTAGESUPPORT; i++) { + texGenMode[i] = TEX_GEN_NONE; + texTransformSet[i] = false; + texCoordFormat[i] = 2; + texTransform[i] = identityMatrix; + texStride[i] = 0; + texTranslateSet[i] = false; + } +} + +VOID D3dCtx::enumDisplayMode(DEVMODE* dmode) +{ + + MONITORINFOEX mi; + + if (monitor == NULL) { + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, dmode ); + } else { + mi.cbSize = sizeof(MONITORINFOEX); + GetMonitorInfo(monitor, (MONITORINFOEX *) &mi); + dmode->dmSize = sizeof(DEVMODE); + EnumDisplaySettings( mi.szDevice, ENUM_CURRENT_SETTINGS, dmode); + } +} +// check what kind of Vertex processing will be used +DWORD D3dCtx::findBehavior() +{ + bForceHwdVertexProcess = getSystemProperty(jniEnv,"j3d.d3dVertexProcess","hardware"); + bForceMixVertexProcess = getSystemProperty(jniEnv,"j3d.d3dVertexProcess","mixed"); + bForceSWVertexProcess = getSystemProperty(jniEnv,"j3d.d3dVertexProcess","software"); + + bUseNvPerfHUD = getSystemProperty(jniEnv,"j3d.useNvPerfHUD","true"); + + //Issue #560 - use D3DCREATE_FPU_PRESERV + //This is just way to disable it, as FPUPreserv is enabled by default + boolean useD3D_FPU_PRESERV = !(getSystemProperty(jniEnv,"j3d.d3dFPUPreserv","false")); + + int behavior = 0; + + if(useD3D_FPU_PRESERV){ + behavior = D3DCREATE_FPU_PRESERVE; + }else{ + printf("\n[Java3D]: Disabled D3DCREATE_FPU_PRESERVE \n"); + } + + + + if (bUseNvPerfHUD) // must have bForceHwdVertexProcess as true + { + printf("\n[Java3D]: using j3d.useNvPerfHUD=true and HARDWARE_VERTEXPROCESSING \n"); + bForceHwdVertexProcess = true; + bForceMixVertexProcess = false; + bForceSWVertexProcess = false; + } + + if (bForceHwdVertexProcess) + { + softwareVertexProcessing = FALSE; + printf("\n[Java3D]: using d3dVertexProcess=hardware\n"); + return D3DCREATE_HARDWARE_VERTEXPROCESSING | behavior; + } + + if (bForceMixVertexProcess) + { + printf("\n[Java3D]: using d3dVertexProcess=mixed\n"); + softwareVertexProcessing = FALSE; + return D3DCREATE_MIXED_VERTEXPROCESSING | behavior; + } + + if (bForceSWVertexProcess) + { + printf("\n[Java3D]: using d3dVertexProcess=software\n"); + softwareVertexProcessing = TRUE; + return D3DCREATE_SOFTWARE_VERTEXPROCESSING | behavior; + } + + // below is the default path. + // Rule : Shader capable videocards uses Hardware + // Low end devices (No shaders support) uses Software + // Middle end devices (TnL but no Shader) uses Mixed + + // high-end video cards: NV25 and above + if (deviceInfo->isHardwareTnL && deviceInfo->supportShaders11 && + ((requiredDeviceID < 0) || (requiredDeviceID == DEVICE_HAL_TnL))) + { + if (debug){printf("\n[Java3D]: using hardware Vertex Processing.\n");} + softwareVertexProcessing = FALSE; + return D3DCREATE_HARDWARE_VERTEXPROCESSING | behavior; + } + + // middle-end video cards + if (deviceInfo->isHardwareTnL && + ((requiredDeviceID < 0) || (requiredDeviceID == DEVICE_HAL_TnL))) + { + if (debug){printf("\n[Java3D]: using mixed Vertex Processing.\n");} + softwareVertexProcessing = FALSE; + return D3DCREATE_MIXED_VERTEXPROCESSING | behavior ; + } + else // low-end vcards use Software Vertex Processing + { + if (debug){printf("\n[Java3D]: using software Vertex Processing.\n");} + softwareVertexProcessing = TRUE; + return D3DCREATE_SOFTWARE_VERTEXPROCESSING | behavior; + } +} + +VOID D3dCtx::printInfo(D3DPRESENT_PARAMETERS *d3dPresent) +{ + + if (d3dPresent->Windowed) { + printf("Window "); + } else { + printf("FullScreen "); + } + + printf("%dx%d %s, handle=%p, MultiSampleType %s, SwapEffect %s, AutoDepthStencilFormat: %s\n", + d3dPresent->BackBufferWidth, + d3dPresent->BackBufferHeight, + getPixelFormatName(d3dPresent->BackBufferFormat), + d3dPresent->hDeviceWindow, + getMultiSampleName(d3dPresent->MultiSampleType), + getSwapEffectName(d3dPresent->SwapEffect), + getPixelFormatName(d3dPresent->AutoDepthStencilFormat)); +} + +VOID D3dCtx::setWindowMode() +{ + if (inToggle) { + if (!bFullScreen) { + SetWindowLong(topHwnd, GWL_STYLE, winStyle); + SetWindowPos(topHwnd, HWND_NOTOPMOST, savedTopRect.left, savedTopRect.top, + savedTopRect.right - savedTopRect.left, + savedTopRect.bottom - savedTopRect.top, + SWP_SHOWWINDOW); + } else { + SetWindowLong(topHwnd, GWL_STYLE, + WS_POPUP|WS_SYSMENU|WS_VISIBLE); + } + } + +} + +VOID D3dCtx::setAmbientLightMaterial() +{ + // We need to set a constant per vertex color + // There is no way in D3D to do this. It is workaround + // by adding Ambient light and set Ambient Material + // color temporary + pDevice->GetLight(0, &savedLight); + pDevice->GetMaterial(&savedMaterial); + pDevice->GetLightEnable(0, &savedLightEnable); + + CopyColor(ambientMaterial.Ambient, + currentColor_r, + currentColor_g, + currentColor_b, + currentColor_a); + + + // This is what the specification say it should set + ambientMaterial.Specular.a = currentColor_a; + + // This is what we found after testing - spec. is not correct + ambientMaterial.Diffuse.a = currentColor_a; + + pDevice->SetLight(0, &ambientLight); + pDevice->SetMaterial(&ambientMaterial); + pDevice->SetRenderState(D3DRS_LIGHTING, TRUE); + pDevice->LightEnable(0, TRUE); +} + +VOID D3dCtx::restoreDefaultLightMaterial() +{ + // restore original values after setAmbientLightMaterial() + pDevice->SetLight(0, &savedLight); + pDevice->SetMaterial(&savedMaterial); + pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + pDevice->LightEnable(0, savedLightEnable); +} + +VOID D3dCtx::freeVBList(D3dVertexBufferVector *v) +{ + //LPD3DVERTEXBUFFER *p; + LPD3DVERTEXBUFFER r; + + lockGeometry(); + + for (ITER_LPD3DVERTEXBUFFER p = v->begin(); p != v->end(); ++p) { + // Remove itself from current ctx vertexBufferTable list + r = (*p)->next; + if (r != NULL) { + r->previous = (*p)->previous; + } + (*p)->previous->next = r; + // Now we can free current VB + delete (*p); + } + v->clear(); + unlockGeometry(); +} + + +VOID D3dCtx::freeResourceList(LPDIRECT3DRESOURCE9Vector *v) +{ + ITER_LPDIRECT3DRESOURCE9 s; + + lockSurfaceList(); + for (s = v->begin(); s != v->end(); ++s) { + (*s)->Release(); + } + v->clear(); + unlockSurfaceList(); +} + +VOID D3dCtx::freeList() +{ + if (useFreeList0) { + if (freeResourceList1.size() > 0) { + freeResourceList(&freeResourceList1); + } + if (freeVBList1.size() > 0) { + freeVBList(&freeVBList1); + } + useFreeList0 = false; + } else { + if (freeResourceList0.size() > 0) { + freeResourceList(&freeResourceList0); + } + if (freeVBList0.size() > 0) { + freeVBList(&freeVBList0); + } + useFreeList0 = true; + } +} + +VOID D3dCtx::freeVB(LPD3DVERTEXBUFFER vb) +{ + if (vb != NULL) { + lockSurfaceList(); + if (useFreeList0) { + freeVBList0.push_back(vb); + } else { + freeVBList1.push_back(vb); + } + unlockSurfaceList(); + } +} + + +VOID D3dCtx::freeResource(LPDIRECT3DRESOURCE9 res) +{ + if (res != NULL) { + lockSurfaceList(); + if (useFreeList0) { + freeResourceList0.push_back(res); + } else { + freeResourceList1.push_back(res); + } + unlockSurfaceList(); + } +} + +BOOL D3dCtx::createFrontBuffer() +{ + HRESULT hr; + + /*CreateImageSurface*/ + hr = pDevice->CreateOffscreenPlainSurface( + driverInfo->desktopMode.Width, + driverInfo->desktopMode.Height, + D3DFMT_A8R8G8B8, + D3DPOOL_SCRATCH, + &frontSurface, + NULL); + if (FAILED(hr)) { + if (debug) { + printf("[Java3D] Fail to CreateOffscreenPlainSurface %s\n", + DXGetErrorString9(hr)); + } + frontSurface = NULL; + return false; + } + return true; +} + +jboolean D3dCtx::getJavaBoolEnv(JNIEnv *env, char* envStr) +{ + + jclass cls; + jfieldID fieldID; + jobject obj; + + cls = env->FindClass( "javax/media/j3d/VirtualUniverse" ); + + if (cls == NULL) { + return JNI_FALSE; + } + + fieldID = (jfieldID) env->GetStaticFieldID( cls, "mc", + "Ljavax/media/j3d/MasterControl;"); + if (fieldID == NULL) { + return JNI_FALSE; + } + + obj = env->GetStaticObjectField( cls, fieldID); + + if (obj == NULL) { + return JNI_FALSE; + } + + cls = (jclass) env->FindClass("javax/media/j3d/MasterControl"); + + if (cls == NULL) { + return JNI_FALSE; + } + + fieldID = (jfieldID) env->GetFieldID( cls, envStr, "Z"); + + if (fieldID == NULL ) { + return JNI_FALSE; + } + + return env->GetBooleanField( obj, fieldID); + +} + +/** +// this routine is not safe using current D3D routines +VOID D3dCtx::getDXVersion(CHAR* strResult) +{ + HRESULT hr; + // TCHAR strResult[128]; + + DWORD dwDirectXVersion = 0; + TCHAR strDirectXVersion[10]; + + hr = GetDXVersion( &dwDirectXVersion, strDirectXVersion, 10 ); + if( SUCCEEDED(hr) ) + { + strcpy( strResult, "DirectX "); + if( dwDirectXVersion > 0 ) + + strcpy( strResult, strDirectXVersion ); + else + strcpy( strResult, "not installed") ); + } + else + { + strcpy( strResult, "Unknown version of DirectX installed"); + } + +} + **/ + + diff --git a/j3d-core/src/native/d3d/D3dCtx.hpp b/j3d-core/src/native/d3d/D3dCtx.hpp new file mode 100644 index 0000000..61808e3 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dCtx.hpp @@ -0,0 +1,387 @@ +/* + * $RCSfile: D3dCtx.hpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#if !defined(D3DCTX_H) +#define D3DCTX_H + + +#include "StdAfx.h" +#include "D3dVertexBuffer.hpp" +#include "D3dDisplayList.hpp" + +#define TEXTURETABLESIZE 8 +#define TEXSTAGESUPPORT 8 +#define DISPLAYLIST_INITSIZE 8 +#define NOCHANGE 0 +#define RESETSURFACE 1 +#define RECREATEDDRAW 2 +#define RECREATEDFAIL -1 + +#undef javax_media_j3d_Canvas3D_STENCIL_BUFFER +#define javax_media_j3d_Canvas3D_STENCIL_BUFFER 4096L + + +// Use in texCoordPosition[] +// Must be negative number +#define TEX_GEN_NONE 0 +#define TEX_EYE_LINEAR -1 +#define TEX_SPHERE_MAP -2 +#define TEX_NORMAL_MAP -3 +#define TEX_REFLECT_MAP -4 +#define TEX_OBJ_LINEAR -5 +#define TEX_GEN_INVALID -6 +#define TEX_GEN_AUTO -7 + +typedef struct _D3DVERTEX { + float x, y, z; +} D3DVERTEX; + + +typedef struct _D3DTLVERTEX { + float sx, sy, sz, rhw; + float tu, tv; +} D3DTLVERTEX; + +typedef struct _COORDTEXVERTEX { + float sx, sy, sz; + float tu, tv; +} COORDTEXVERTEX; + +typedef struct _COORDCLRTEXVERTEX { + float sx, sy, sz; + D3DCOLOR color; + float tu, tv; +} COORDCLRTEXVERTEX; + + +typedef vector LPDIRECT3DRESOURCE9Vector; +typedef vector LPDIRECT3DVERTEXBUFFER9Vector; +//issue 135 iterator for vectors +typedef vector::iterator ITER_LPDIRECT3DRESOURCE9; +typedef vector::iterator ITER_LPDIRECT3DVERTEXBUFFER9; + +class D3dCtx { +public: + + HWND hwnd; // window handle + HWND topHwnd; // Top window handle + D3dDriverInfo *driverInfo; // Driver use + D3dDeviceInfo *deviceInfo; // Device use + + LPDIRECT3D9 pD3D; // Direct3D interface + LPDIRECT3DDEVICE9 pDevice; // Instance of D3D Device + + LPDIRECT3DSURFACE9 depthStencilSurface; + + // This is used for readRaster and offscreen rendering + // Only allocate the memory area if necessary + LPDIRECT3DSURFACE9 frontSurface; + + LPDIRECT3DSURFACE9 backSurface; + + // Parameters use for CreateDevice() + D3DPRESENT_PARAMETERS d3dPresent; + DWORD dwBehavior; + BOOL bForceHwdVertexProcess; // true if j3d.d3dVertexProcess is hardware + BOOL bForceMixVertexProcess; // true if j3d.d3dVertexProcess is mixed + BOOL bForceSWVertexProcess; // true if j3d.d3dVertexProcess is software + + BOOL bUseNvPerfHUD; // true if j3d.useNvPerfHUD is true + // it also makes bForceHwdVertexProcess true + + BOOL offScreen; // true if it is offScreen rendering + // in this case only backSurface is used + BOOL bFastDrawQuads; + DWORD offScreenWidth; + DWORD offScreenHeight; + + BOOL bFullScreen; // true if in full screen mode + BOOL bFullScreenRequired; // true if must run in full + // screen mode or die + BOOL inToggle; // in toggle fullscreen/window mode + RECT screenRect; // coordinate of window relative to + // the whole desktop in multiple monitor + RECT windowRect; // coordinate of window relative to + // the current monitor desktop only + INT minZDepth; // min Z depth set in NativeConfigTemplate + INT minZDepthStencil; // min Stencil depth set in NativeConfigTemplate + DEVMODE devmode; // current display mode + DWORD antialiasing; // PREFERRED, REQUIRED or UNNECESSARY + + + // Store current color as in OGL glColor() + float currentColor_r; + float currentColor_g; + float currentColor_b; + float currentColor_a; + + // Two side light is used. Note that D3D don't support two side + // lighting. + BOOL twoSideLightingEnable; + + // True if lighting is currently enable + // Save the current RenderingState to avoid GetRenderState() + // call during Rendering. + BOOL isLightEnable; + DWORD cullMode; + DWORD fillMode; + DWORD softwareVertexProcessing; + DWORD zWriteEnable; + DWORD zEnable; + +// TODO ACES: The following two stencil enable flags are not used +// consistently throughout the pipeline. They are never set to a value, +// and they are not looked at by most of the code. + DWORD stencilWriteEnable; // new on 1.4 + DWORD stencilEnable; // new on 1.4 + + // Ambient material used when coloring Attributes + D3DMATERIAL9 ambientMaterial; + + // temporary variables for ambient light setting + D3DLIGHT9 savedLight; + D3DMATERIAL9 savedMaterial; + BOOL savedLightEnable; + + // temporary variables used for building VertexBuffer + LPD3DVERTEXBUFFER pVB; // point to the current VB being update + DWORD texSetUsed; + DWORD texStride[TEXSTAGESUPPORT]; + + // true when in toggle mode + BOOL forceResize; + + // Texture related variables + INT *bindTextureId; + DWORD bindTextureIdLen; + + LPDIRECT3DTEXTURE9 *textureTable; + DWORD textureTableLen; + + // Volume Texture related variables + // Since 2d & 3d texture ID can't be the same from Java3D. + // We don't need bindVolumeId + LPDIRECT3DVOLUMETEXTURE9 *volumeTable; + DWORD volumeTableLen; + + // Texture Cube Mapping related variables + LPDIRECT3DCUBETEXTURE9 *cubeMapTable; + DWORD cubeMapTableLen; + + // true if hardware support MultiTexture + BOOL multiTextureSupport; + + // handle to monitor that this ctx belongs to. This is equal to + // NULL if this window is a primary display screen or it covers + // more than one screen. + HMONITOR monitor; + + // D3D don't have concept of current texture unit stage, + // instead, the texture unit stage is pass in as argument + // for all texture call. + INT texUnitStage; + + // true if linear filtering is to be used + BOOL texLinearMode; + + + // This is used temporary to store the blend function + // when two pass texture is used to simulate BLEND mode + DWORD srcBlendFunc; + DWORD dstBlendFunc; + DWORD blendEnable; + + + // This is used for to transform vertex + // from world to screen coordinate + LPDIRECT3DVERTEXBUFFER9 srcVertexBuffer; + LPDIRECT3DVERTEXBUFFER9 dstVertexBuffer; + + // For Rect of texture map in Raster write + D3DTLVERTEX rasterRect[4]; + + // Set automatic Texture coordinate generation type + // TEX_xxx_xxx as defined in GeometryArrayRetained.cpp + INT texGenMode[TEXSTAGESUPPORT]; + + // Whether TEXTURE_COORDINATE_2/3/4 is used in this state + INT texCoordFormat[TEXSTAGESUPPORT]; + + // Whether texture transform matrix is set in this state or not + BOOL texTransformSet[TEXSTAGESUPPORT]; + + // Remember the last Texture Transform pass down, since + // TexCoordGen may destroy it in some mode so we have to + // restore it later manually. + D3DXMATRIX texTransform[TEXSTAGESUPPORT]; + + // True if we copy m._41, m._42 elment to m._31, m._32 + // as a workaround that 2D texture translation did not work. + BOOL texTranslateSet[TEXSTAGESUPPORT]; + + float planeS[TEXSTAGESUPPORT][4]; + float planeT[TEXSTAGESUPPORT][4]; + float planeR[TEXSTAGESUPPORT][4]; + float planeQ[TEXSTAGESUPPORT][4]; + + // Display List ID (start from 1) => VertexBuffer pointer table + LPD3DDISPLAYLIST *displayListTable; + int dlTableSize; + + // For immediate mode rendering, we save the vertexBuffer pointer + // in variable pVertexBuffer of GeometryArrayRetained to reuse it. + D3dVertexBuffer vertexBufferTable; + + int currDisplayListID; + + // True if colorTarget need to reset + BOOL resetColorTarget; + + // Use for QuadArray + LPDIRECT3DINDEXBUFFER9 quadIndexBuffer; + DWORD quadIndexBufferSize; + + // Use for Quad Polygon Line mode + LPDIRECT3DINDEXBUFFER9 lineModeIndexBuffer; + + // Use temporary for reindexing + DWORD *reIndexifyTable; + + // True if Direcct Draw context is being destroy and recreate + // again during resize/toggle + BOOL recreateDDraw; + + // Screen coordinate of current monitor in use + // When hardware accleerated mode is used. For Emulation mode + // they are always zero; + INT monitorLeft; + INT monitorTop; + float pointSize; + + // Use to free resource surface in swap() + BOOL useFreeList0; + LPDIRECT3DRESOURCE9Vector freeResourceList0; + LPDIRECT3DRESOURCE9Vector freeResourceList1; + D3dVertexBufferVector freeVBList0; + D3dVertexBufferVector freeVBList1; + + D3dCtx(JNIEnv *env, jobject obj, HWND hwnd, BOOL offScreen, jint vid); + ~D3dCtx(); + + BOOL initialize(JNIEnv *env, jobject obj); + INT resize(JNIEnv *env, jobject obj); + VOID error(char *s, HRESULT hr); + VOID error(int idx, HRESULT hr); + VOID error(int idx); + VOID error(char *s); + VOID warning(int idx, HRESULT hr); + VOID warning(int idx); + + static VOID d3dError(int idx); + static VOID d3dError(char *s); + static VOID d3dWarning(int idx, HRESULT hr); + static VOID d3dWarning(int idx); + + INT toggleMode(BOOL fullScreen, JNIEnv *env, jobject obj); + DWORD getWidth(); + DWORD getHeight(); + + VOID release(); + VOID releaseTexture(); + VOID releaseVB(); + VOID setViewport(); + VOID transform(D3DVERTEX *worldCoord, D3DTLVERTEX *screenCoord); + VOID getScreenRect(HWND hwnd, RECT *rect); + HMONITOR findMonitor(); + VOID setDriverInfo(); + static D3dDeviceInfo* setDeviceInfo(D3dDriverInfo *driverInfo, + BOOL *bFullScreen, + int minZDepth, + int minZDepthStencil); + DWORD findBehavior(); + VOID setPresentParams(); + INT resetSurface(JNIEnv *env, jobject obj); + VOID setPresentParams(JNIEnv *env, jobject obj); + VOID setAmbientLightMaterial(); + VOID restoreDefaultLightMaterial(); + VOID freeResource(LPDIRECT3DRESOURCE9 surf); + VOID freeVB(LPD3DVERTEXBUFFER vb); + + VOID freeList(); + VOID freeResourceList(LPDIRECT3DRESOURCE9Vector *v); + VOID freeVBList(D3dVertexBufferVector *v); + BOOL createFrontBuffer(); + + static D3dDeviceInfo* selectDevice(int deviceID, + D3dDriverInfo *driverInfo, + BOOL *bFullScreen, + int minZDepth, + int minZDepthStencil); + static D3dDeviceInfo* selectBestDevice(D3dDriverInfo *driverInfo, + BOOL *bFullScreen, + int minZDepth, + int minZDepthStencil); + static VOID setDeviceFromProperty(JNIEnv *env); + static BOOL getSystemProperty(JNIEnv *env, char *strName, char *strValue); + static VOID setDebugProperty(JNIEnv *env); + static VOID setVBLimitProperty(JNIEnv *env); + static VOID setImplicitMultisamplingProperty(JNIEnv *env); + + + +private: + + RECT savedTopRect; // for toggle between fullscreen mode + RECT savedClientRect; + DWORD winStyle; + // a private reference for JNIEnv + JNIEnv* jniEnv; + + VOID createVertexBuffer(); + + VOID setCanvasProperty(JNIEnv *env, jobject obj); + VOID setFullScreenFromProperty(JNIEnv *env); + VOID enumDisplayMode(DEVMODE *devmode); + + static VOID printWarningMessage(D3dDeviceInfo *deviceInfo); + static VOID showError(HWND hwnd, char *s, BOOL bFullScreen); + VOID setDefaultAttributes(); + VOID printInfo(D3DPRESENT_PARAMETERS *d3dPresent); + VOID setWindowMode(); + jboolean getJavaBoolEnv(JNIEnv *env, char* envStr); +}; + +typedef vector D3dCtxVector; +//issue 135 added iterator for D3dCtxVector +typedef vector::iterator ITER_D3dCtxVector; +extern D3dCtxVector d3dCtxList; +const extern D3DXMATRIX identityMatrix; +#endif diff --git a/j3d-core/src/native/d3d/D3dDeviceInfo.cpp b/j3d-core/src/native/d3d/D3dDeviceInfo.cpp new file mode 100644 index 0000000..8d324d3 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dDeviceInfo.cpp @@ -0,0 +1,320 @@ +/* + * $RCSfile: D3dDeviceInfo.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.12 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#include "Stdafx.h" + +// return true if device is capable of hardware accelerated + +D3dDeviceInfo::D3dDeviceInfo() +{ +} + +D3dDeviceInfo::~D3dDeviceInfo() +{ +} + +VOID D3dDeviceInfo::setCaps(D3DCAPS9 *d3dCaps) { + + BOOL supportNPOT; + if (deviceType == D3DDEVTYPE_HAL ){ + isHardware = true; + isHardwareTnL = (d3dCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT); + } + else // D3DDEVTYPE_REF + { + isHardware = false; + isHardwareTnL = false; + } + + + // D3DTEXTURECAPS_NONPOW2CONDITIONAL caps-bit indicates "conditional" + // Non Power of Two (NPOT) + // textures that only support CLAMP addressing and don't + // support mipmaps or compressed textures. + // But some new vcards supports NP2 unconditional (GF6 and above). + // Correct test for any kind of NP2 support: + // If both unconditional and conditional support is + // unavailable then NP2 is not possible anyway. + // ------------------------------------------- + // POW2 | NP2_CONDITIONAL | result + // ------------------------------------------- + // true | true | CONDITIONAL NPOT(*) + // true | false | POW2 Only + // false| any | UNConditional NPOT (**) // + // --------------------------------------------- + // (**)OpenGL like, Java3D preferred. + // (*) below test: + /* + * if (((d3dCaps->TextureCaps & D3DPTEXTURECAPS_POW2) != 0) && // POW2 is true + * ((d3dCaps->TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) == 0)){ //NPOT_Cond is false + * //Pow2 Only + * supportNPOT = false; + * } + * else{ + * // both conditional and unconditional + * supportNPOT = true; + * } + */ + if(d3dCaps->TextureCaps & D3DPTEXTURECAPS_POW2){ + supportNPOT = false; + if(d3dCaps->TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL){ + // NPOT conditionl But, in certain cases textures can ignore the power of 2 limitation + // As OpenGL is UNCONDITIONAL, it is not used by Java3D + //supportNPOT = true; + } + } else { + //UNconditional: Textures do not need to be a power of 2 in size + supportNPOT = true; + } + + // check if it supports at least vertex shader 1.1 + if(d3dCaps->VertexShaderVersion < D3DVS_VERSION(1, 1)) { + supportShaders11 = false; + } + else { + supportShaders11 = true; + } + + DWORD vsVersion = d3dCaps->VertexShaderVersion; + if (debug) { + char* dt; + if (isHardware) + dt = "HAL"; + else + dt ="REL"; + + printf("Java3D: Supported Shaders = %d.%d in mode %s \n", + HIBYTE(LOWORD(vsVersion)), + LOBYTE(LOWORD(vsVersion)), + dt); + } + + //supportStreamOffset = + + supportDepthBias = (d3dCaps->RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0; + + maxTextureBlendStages = d3dCaps->MaxTextureBlendStages; + maxSimultaneousTextures = d3dCaps->MaxSimultaneousTextures; + + maxTextureUnitStageSupport = min(maxTextureBlendStages, maxSimultaneousTextures); + supportMipmap = ((d3dCaps->TextureCaps & D3DPTEXTURECAPS_MIPMAP) != 0); + + texturePow2Only = ((d3dCaps->TextureCaps & D3DPTEXTURECAPS_POW2) != 0); + + textureSquareOnly = ((d3dCaps->TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0); + + linePatternSupport = false; //((d3dCaps->PrimitiveMiscCaps & D3DPMISCCAPS_LINEPATTERNREP) != 0); + + texBorderModeSupport = ((d3dCaps->TextureAddressCaps & D3DPTADDRESSCAPS_BORDER) != 0); + + texLerpSupport = ((d3dCaps->TextureOpCaps & D3DTEXOPCAPS_LERP) != 0); + + canRenderWindowed = true;//((d3dCaps->Caps2 & D3DCAPS2_CANRENDERWINDOWED) != 0); + + + maxPrimitiveCount = d3dCaps->MaxPrimitiveCount; + maxVertexIndex = min(vertexBufferMaxVertexLimit, d3dCaps->MaxVertexIndex); + + maxTextureHeight = d3dCaps->MaxTextureHeight; + maxTextureWidth = d3dCaps->MaxTextureWidth; + maxTextureDepth = d3dCaps->MaxVolumeExtent; + + maxActiveLights = d3dCaps->MaxActiveLights; + maxPointSize = DWORD(d3dCaps->MaxPointSize); + maxAnisotropy = d3dCaps->MaxAnisotropy; + + maxVertexCount[GEO_TYPE_QUAD_SET] = min(vertexBufferMaxVertexLimit, maxPrimitiveCount << 1); + + // Since index is used, we need to make sure than index range + // is also support. + maxVertexCount[GEO_TYPE_QUAD_SET] = min(maxVertexCount[GEO_TYPE_QUAD_SET], maxVertexIndex); + + maxVertexCount[GEO_TYPE_TRI_SET] = min(vertexBufferMaxVertexLimit, maxPrimitiveCount*3); + + maxVertexCount[GEO_TYPE_POINT_SET] = min(vertexBufferMaxVertexLimit, maxPrimitiveCount); + + maxVertexCount[GEO_TYPE_LINE_SET] = min(vertexBufferMaxVertexLimit, maxPrimitiveCount << 1); + + maxVertexCount[GEO_TYPE_TRI_STRIP_SET] = min(vertexBufferMaxVertexLimit, maxPrimitiveCount + 2); + + maxVertexCount[GEO_TYPE_TRI_FAN_SET] = min(vertexBufferMaxVertexLimit, maxPrimitiveCount + 2); + + maxVertexCount[GEO_TYPE_LINE_STRIP_SET] = min(vertexBufferMaxVertexLimit, + maxPrimitiveCount +1); + maxVertexCount[GEO_TYPE_INDEXED_QUAD_SET] = maxVertexCount[GEO_TYPE_QUAD_SET]; + maxVertexCount[GEO_TYPE_INDEXED_TRI_SET] = maxVertexCount[GEO_TYPE_TRI_SET]; + maxVertexCount[GEO_TYPE_INDEXED_POINT_SET] = maxVertexCount[GEO_TYPE_POINT_SET]; + maxVertexCount[GEO_TYPE_INDEXED_LINE_SET] = maxVertexCount[GEO_TYPE_LINE_SET]; + maxVertexCount[GEO_TYPE_INDEXED_TRI_STRIP_SET] = maxVertexCount[GEO_TYPE_TRI_STRIP_SET]; + maxVertexCount[GEO_TYPE_INDEXED_TRI_FAN_SET] = maxVertexCount[GEO_TYPE_TRI_FAN_SET]; + maxVertexCount[GEO_TYPE_INDEXED_LINE_STRIP_SET] = maxVertexCount[GEO_TYPE_LINE_STRIP_SET]; + + + if ( (d3dCaps->PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) != 0) + supportRasterPresImmediate = true; + else + supportRasterPresImmediate = false; + + if (((d3dCaps->RasterCaps & D3DPRASTERCAPS_FOGTABLE) != 0) && + ((d3dCaps->RasterCaps & D3DPRASTERCAPS_WFOG) != 0)) { + // use pixel w-fog + fogMode = D3DRS_FOGTABLEMODE; + rangeFogEnable = false; + } + else if (((d3dCaps->RasterCaps & D3DPRASTERCAPS_FOGVERTEX) != 0) && + ((d3dCaps->RasterCaps & D3DPRASTERCAPS_FOGRANGE) != 0)) { + // use vertex range based fog + fogMode = D3DRS_FOGVERTEXMODE; + rangeFogEnable = true; + } + else if ((d3dCaps->RasterCaps & D3DPRASTERCAPS_FOGTABLE) != 0) { + // use pixel z-fog + fogMode = D3DRS_FOGTABLEMODE; + rangeFogEnable = false; + } + else if (D3DPRASTERCAPS_FOGVERTEX) { + // use vertex z-fog + fogMode = D3DRS_FOGVERTEXMODE; + rangeFogEnable = false; + } + else { + if (debug) { + printf("[Java 3D] Fog not support in this device !\n"); + } + } + + texMask = 0; + if(supportNPOT){ + texMask |= javax_media_j3d_Canvas3D_TEXTURE_NON_POWER_OF_TWO; + } + + if((d3dCaps->Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) != 0) { + texMask |= javax_media_j3d_Canvas3D_TEXTURE_AUTO_MIPMAP_GENERATION; + } + + if ((d3dCaps->TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) && + (maxTextureDepth > 0)) { + texMask |= javax_media_j3d_Canvas3D_TEXTURE_3D; + } + + if (d3dCaps->TextureCaps & D3DPTEXTURECAPS_CUBEMAP) { + texMask |= javax_media_j3d_Canvas3D_TEXTURE_CUBE_MAP; + } + + if (maxTextureUnitStageSupport > 1) { + texMask |= javax_media_j3d_Canvas3D_TEXTURE_MULTI_TEXTURE; + } + + + if (d3dCaps->TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3) { + texMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE_DOT3; + } + + if (d3dCaps->TextureOpCaps & D3DTEXOPCAPS_SUBTRACT) { + texMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE_SUBTRACT; + } + + if (d3dCaps->TextureOpCaps & D3DTEXOPCAPS_LERP) { + texMask |= (javax_media_j3d_Canvas3D_TEXTURE_LERP| + javax_media_j3d_Canvas3D_TEXTURE_COMBINE); + } else if (d3dCaps->TextureOpCaps & + (D3DTEXOPCAPS_DOTPRODUCT3|D3DTEXOPCAPS_SUBTRACT| + D3DTEXOPCAPS_MODULATE|D3DTEXOPCAPS_ADD| + D3DTEXOPCAPS_ADDSIGNED)) { + texMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE; + } + + + if (maxAnisotropy > 1) { + texMask |= javax_media_j3d_Canvas3D_TEXTURE_ANISOTROPIC_FILTER; + } + +} + +BOOL D3dDeviceInfo::supportAntialiasing() { + return (multiSampleSupport != 0); +} + + +void D3dDeviceInfo::findDepthStencilFormat(int minZDepth, int minZDepthStencil) +{ + // Fix to Issue 226 : D3D - fail on stress test for the creation and destruction of Canvases + //sanity check of stencil and depth + minZDepthStencil = min(minZDepthStencil, 8); + minZDepth = min(minZDepth, 32); + + depthStencilFormat = D3DFMT_UNKNOWN; + + for (int i=0; i < D3DDEPTHFORMATSIZE; i++) { + //printf("\ndepthFormatSupport %s, %b",getPixelFormatName(d3dDepthFormat[i]), depthFormatSupport[i]); + if (depthFormatSupport[i]){ + // prefer one with stencil buffer, follow by D3DFMT_D16_LOCKABLE, + // printf("\n ZDepth %d, Stencil %d ",d3dDepthTable[i],d3dStencilDepthTable[i]); + if (d3dDepthTable[i] >= minZDepth && d3dStencilDepthTable[i] >= minZDepthStencil ) { + depthStencilFormat = (D3DFORMAT) d3dDepthFormat[i]; + break; + } + }//if + }// for + // if none suitable found +} + + +D3DMULTISAMPLE_TYPE D3dDeviceInfo::getBestMultiSampleType() +{ + DWORD bitmask = 0; + UINT i; + + // Fix to Issue 226 : D3D - fail on stress test for the creation and destruction of Canvases + // start with 4 and up, if none found, try 3 and 2 + for (i=4; i <= 16; i++) { + bitmask = (1 << i); + if (multiSampleSupport & bitmask) { + return (D3DMULTISAMPLE_TYPE) i; + } + } + + // try 3 and 2 + for (i=3; i >= 2; i--) { + bitmask = (1 << i); + if (multiSampleSupport & bitmask) { + return (D3DMULTISAMPLE_TYPE) i; + } + } + + // Should not happen + return D3DMULTISAMPLE_NONE; +} + +int D3dDeviceInfo::getTextureFeaturesMask() +{ + return texMask; +} diff --git a/j3d-core/src/native/d3d/D3dDeviceInfo.hpp b/j3d-core/src/native/d3d/D3dDeviceInfo.hpp new file mode 100644 index 0000000..ea3c8a5 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dDeviceInfo.hpp @@ -0,0 +1,120 @@ +/* + * $RCSfile: D3dDeviceInfo.hpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#if !defined(D3DDEVICEINFO_H) +#define D3DDEVICEINFO_H + +#include "StdAfx.h" + +extern UINT vertexBufferMaxVertexLimit; + +// Fix to Issue 226 : D3D - fail on stress test for the creation and destruction of Canvases +#define D3DDEPTHFORMATSIZE 7 + +class D3dDeviceInfo { + public: + // Hardware Rasterizer + // Transform & Light Hardware Rasterizer + // Reference Rasterizer + char deviceName[40]; // One of above name + D3DDEVTYPE deviceType; // D3DDEVTYPE_HAL or D3DDEVTYPE_REF + BOOL desktopCompatible; // Can render in desktop mode + BOOL fullscreenCompatible; // Can render in fullscreen mode + // using current desktop mode setting + //issue 135 - adding device info + char* deviceVendor; + char* deviceRenderer; + char* deviceVersion; + + // each bitmask correspond to the support of + // D3DMULTISAMPLE_i_SAMPLES type, i = 2...16 + DWORD multiSampleSupport; + + // TRUE when d3dDepthFormat[i] support + BOOL depthFormatSupport[D3DDEPTHFORMATSIZE]; + + // depth format select + D3DFORMAT depthStencilFormat; + + // max z buffer depth support + UINT maxZBufferDepthSize; + + // max stencil buffer depth support + UINT maxStencilDepthSize; // new on 1.4 + + // Max vertex count support for each primitive + DWORD maxVertexCount[GEO_TYPE_INDEXED_LINE_STRIP_SET+1]; + + BOOL supportStencil; // new on 1.4 + BOOL supportShaders11; + BOOL isHardware; + BOOL isHardwareTnL; + BOOL supportDepthBias; + BOOL supportRasterPresImmediate; + BOOL canRenderWindowed; + BOOL supportMipmap; + BOOL texturePow2Only; + BOOL textureSquareOnly; + BOOL linePatternSupport; + BOOL texBorderModeSupport; + BOOL texLerpSupport; + DWORD maxTextureUnitStageSupport; + DWORD maxTextureBlendStages; + DWORD maxSimultaneousTextures; + DWORD maxTextureWidth; + DWORD maxTextureHeight; + DWORD maxTextureDepth; + DWORD maxPrimitiveCount; + DWORD maxVertexIndex; + DWORD maxActiveLights; + DWORD maxPointSize; + DWORD rangeFogEnable; + D3DRENDERSTATETYPE fogMode; + int texMask; + int maxAnisotropy; + + BOOL supportStreamOffset; + + D3dDeviceInfo(); + ~D3dDeviceInfo(); + + // set capabilities of this device + VOID setCaps(D3DCAPS9 *d3dCaps); + BOOL supportAntialiasing(); + D3DMULTISAMPLE_TYPE getBestMultiSampleType(); + int getTextureFeaturesMask(); + void findDepthStencilFormat(int minZDepth, int minZDepthStencil); + + +}; + +#endif + diff --git a/j3d-core/src/native/d3d/D3dDisplayList.cpp b/j3d-core/src/native/d3d/D3dDisplayList.cpp new file mode 100644 index 0000000..945544f --- /dev/null +++ b/j3d-core/src/native/d3d/D3dDisplayList.cpp @@ -0,0 +1,353 @@ +/* + * $RCSfile: D3dDisplayList.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#include "StdAfx.h" +#include "D3dDisplayList.hpp" + +D3dDisplayList::D3dDisplayList() +{ +} + +D3dDisplayList::~D3dDisplayList() +{ + for (ITER_LPD3DVERTEXBUFFER p = vBufferVec.begin(); + p != vBufferVec.end(); p++) { + SafeDelete(*p); + } + vBufferVec.empty(); +} + +VOID D3dDisplayList::render(D3dCtx *d3dCtx) +{ + for (ITER_LPD3DVERTEXBUFFER p = vBufferVec.begin(); + p != vBufferVec.end(); p++) { + (*p)->render(d3dCtx); + } +} + +VOID D3dDisplayList::add(LPD3DVERTEXBUFFER vbuffer) +{ + vBufferVec.push_back(vbuffer); +} + + +BOOL D3dDisplayList::isQuad(LPD3DVERTEXBUFFER p) +{ + return (!p->isIndexPrimitive && (p->indexBuffer != NULL)); +} + +VOID D3dDisplayList::optimize(D3dCtx *d3dCtx) +{ + + D3dVertexBufferVector vCloneBufferVec; + D3dVertexBuffer **r = &(*vBufferVec.begin()); + + for (; r != &(*vBufferVec.end()); r++) { + vCloneBufferVec.push_back(*r); + + } + + vBufferVec.erase(vBufferVec.begin(), vBufferVec.end()); + + D3dVertexBuffer **vbegin = &(*vCloneBufferVec.begin()); + D3dVertexBuffer **vend = &(*vCloneBufferVec.end()); + D3dVertexBuffer **q = vbegin; + D3dVertexBuffer **p; + int primitiveType, vcounts, climit; + int indexCounts = 0; + BOOL merge; + LPD3DVERTEXBUFFER mergedVB; + BOOL isPointFlagUsed; + DWORD vertexFormat; + BOOL isIndexPrimitive; + BOOL quadFlag; + + while (q != vend) { + primitiveType = (*q)->primitiveType; + climit = (*q)->maxVertexLimit; + vcounts = (*q)->vcount; + isPointFlagUsed = (*q)->isPointFlagUsed; + vertexFormat = (*q)->vertexFormat; + isIndexPrimitive = (*q)->isIndexPrimitive; + quadFlag = isQuad(*q); + + if ((*q)->indexBuffer != NULL) { + indexCounts = (*q)->indexCount; + } + merge = false; + p = q + 1; + + while (p != vend) { + if (((*p)->primitiveType == primitiveType) && + ((*p)->vertexFormat == vertexFormat) && + ((*p)->isIndexPrimitive == isIndexPrimitive) && + (isQuad(*p) == quadFlag) && + ((*p)->isPointFlagUsed == isPointFlagUsed) && + // This means Mutliple VBs already use + ((*p)->totalVertexCount == (*p)->vcount)) { + vcounts += (*p)->totalVertexCount; + if ((*p)->indexBuffer != NULL) { + indexCounts += (*p)->totalIndexCount; + } + if ((vcounts > climit) || (indexCounts > climit)) { + break; + } + p++; + merge = true; + } else { + break; + } + } + + if (merge) { + mergedVB = createMergedVB(d3dCtx, q, p, vcounts, indexCounts); + if (mergedVB != NULL) { + for (r = q; r != p; r++) { + SafeDelete(*r); + } + vBufferVec.push_back(mergedVB); + } else { + for (r = q; r != p; r++) { + vBufferVec.push_back(*r); + } + } + } else { + vBufferVec.push_back(*q); + } + q = p; + } + + vCloneBufferVec.erase(vCloneBufferVec.begin(), vCloneBufferVec.end()); +} + + + + +LPD3DVERTEXBUFFER D3dDisplayList::createMergedVB(D3dCtx *d3dCtx, + D3dVertexBuffer **vstart, + D3dVertexBuffer **vend, + DWORD vcount, + DWORD indexCount) +{ + LPDIRECT3DDEVICE9 device = d3dCtx->pDevice; + D3dVertexBuffer **r; + UINT i; + HRESULT hr; + LPD3DVERTEXBUFFER vb = new D3dVertexBuffer(); + + vb->primitiveType = (*vstart)->primitiveType; + vb->isIndexPrimitive = (*vstart)->isIndexPrimitive; + vb->isPointFlagUsed = (*vstart)->isPointFlagUsed; + vb->vertexFormat = (*vstart)->vertexFormat; + vb->stride = (*vstart)->stride; + vb->ctx = (*vstart)->ctx; + vb->vcount = vb->totalVertexCount = vcount; + vb->indexCount = vb->totalIndexCount = indexCount; + vb->maxVertexLimit = (*vstart)->maxVertexLimit; + + if (!vb->isPointFlagUsed) { + hr = device->CreateVertexBuffer(vb->stride*vcount, + D3DUSAGE_WRITEONLY, + vb->vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + } else { + hr = device->CreateVertexBuffer(vb->stride*vcount, + D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS, + vb->vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + } + + if (FAILED(hr)) { + return NULL; + } + BYTE *bdst = NULL; + WORD *wdst = NULL; + UINT *idst = NULL; + + hr = vb->buffer->Lock(0, 0,(VOID**) &bdst , 0); + if (FAILED(hr)) { + SafeRelease(vb->buffer); + return NULL; + } + + if (indexCount > 0) { + if (indexCount < 0xffff) { + hr = device->CreateIndexBuffer(indexCount*sizeof(WORD), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX16, + D3DPOOL_DEFAULT, + &vb->indexBuffer, + NULL); + + } else { + hr = device->CreateIndexBuffer(indexCount*sizeof(UINT), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX32, + D3DPOOL_DEFAULT, + &vb->indexBuffer, + NULL); + } + if (FAILED(hr)) { + vb->buffer->Unlock(); + SafeRelease(vb->buffer); + return NULL; + } + if (indexCount <= 0xffff) { + hr = vb->indexBuffer->Lock(0, 0,(VOID**) &wdst, 0); + } else { + hr = vb->indexBuffer->Lock(0, 0,(VOID**) &idst, 0); + } + if (FAILED(hr)) { + vb->buffer->Unlock(); + SafeRelease(vb->buffer); + SafeRelease(vb->indexBuffer); + return NULL; + } + } + + BYTE *bsrc = NULL; + WORD *wsrc = NULL; + UINT *isrc = NULL; + UINT offset = 0; + DWORD len; + BOOL stripType = true; + + if ((vb->primitiveType == D3DPT_POINTLIST) || + (vb->primitiveType == D3DPT_LINELIST) || + (vb->primitiveType == D3DPT_TRIANGLELIST)) { + vb->numVertices = new USHORT[1]; + if (indexCount <= 0) { + vb->numVertices[0] = vcount; + } else { + vb->numVertices[0] = indexCount; + } + vb->numVerticesLen = 1; + vb->stripLen = 1; + stripType = false; + } + + for (r = vstart; r != vend; r++) { + hr = (*r)->buffer->Lock(0, 0,(VOID**) &bsrc, 0); + + if (FAILED(hr)) { + vb->buffer->Unlock(); + if (indexCount > 0) { + vb->indexBuffer->Unlock(); + } + SafeRelease(vb->buffer); + SafeRelease(vb->indexBuffer); + return NULL; + } + + if (indexCount > 0) { + if (indexCount <= 0xffff) { + hr = (*r)->indexBuffer->Lock(0, 0, (VOID**)&wsrc, 0); + } else { + hr = (*r)->indexBuffer->Lock(0, 0,(VOID**) &isrc, 0); + } + if (FAILED(hr)) { + (*r)->buffer->Unlock(); + vb->buffer->Unlock(); + SafeRelease(vb->buffer); + SafeRelease(vb->indexBuffer); + return NULL; + } + } + len = (*r)->vcount*(*r)->stride; + CopyMemory(bdst, bsrc, len); + if (stripType) { + vb->appendStrides((*r)->stripLen, (*r)->numVertices); + } + if (indexCount > 0) { + if (wdst != NULL) { + if (wsrc != NULL) { + for (i=0; i < (*r)->indexCount; i++) { + *wdst++ = offset + *wsrc++; + } + } else { + // should not happen + printf("[Java3D] Error in merging index vertex buffer\n"); + } + + } else { + if (wsrc != NULL) { + for (i=0; i < (*r)->indexCount; i++) { + *idst++ = offset + *wsrc++; + } + } else { + for (i=0; i < (*r)->indexCount; i++) { + *idst++ = offset + *isrc++; + } + } + } + offset += (*r)->vcount; + } + bdst += len; + (*r)->buffer->Unlock(); + if (indexCount > 0) { + (*r)->indexBuffer->Unlock(); + wsrc = NULL; + isrc = NULL; + } + } + + + vb->buffer->Unlock(); + if (indexCount > 0) { + vb->indexBuffer->Unlock(); + } + + if (vb->isIndexPrimitive && (indexCount <= 0)) { + // QUAD is used, adjust size of index + createQuadIndices(d3dCtx, vcount); + } + + for (i=0; i < D3DDP_MAXTEXCOORD; i++) { + vb->texCoordPosition[i] = -9999; + } + + + if (debug) { + int n = 0; + for (r = vstart; r != vend; r++) { + n++; + } + printf("Merge %d VB with primitiveType %d, vcount %d, indexCount %d\n", + n, vb->primitiveType, vcount, indexCount); + } + return vb; + +} + diff --git a/j3d-core/src/native/d3d/D3dDisplayList.hpp b/j3d-core/src/native/d3d/D3dDisplayList.hpp new file mode 100644 index 0000000..01d5328 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dDisplayList.hpp @@ -0,0 +1,57 @@ +/* + * $RCSfile: D3dDisplayList.hpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.5 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#if !defined(D3DDISPLAYLIST_H) +#define D3DDISPLAYLIST_H + +#include "StdAfx.h" +#include "D3dVertexBuffer.hpp" + + +class D3dDisplayList { +public: + D3dDisplayList(); + ~D3dDisplayList(); + VOID add(LPD3DVERTEXBUFFER vBuffer); + VOID render(D3dCtx *d3dCtx); + VOID optimize(D3dCtx *d3dCtx); + BOOL isQuad(LPD3DVERTEXBUFFER p); + LPD3DVERTEXBUFFER createMergedVB(D3dCtx *d3dCtx, + D3dVertexBuffer **p, + D3dVertexBuffer **q, + DWORD vcount, + DWORD indexCount); + +private: + D3dVertexBufferVector vBufferVec; +}; +typedef D3dDisplayList* LPD3DDISPLAYLIST; +#endif diff --git a/j3d-core/src/native/d3d/D3dDriverInfo.cpp b/j3d-core/src/native/d3d/D3dDriverInfo.cpp new file mode 100644 index 0000000..087ceb7 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dDriverInfo.cpp @@ -0,0 +1,466 @@ +/* + * $RCSfile: D3dDriverInfo.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.15 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" +#include "Stdafx.h" + + +const DWORD numDeviceTypes = 2; +const D3DDEVTYPE deviceTypes[2] = { D3DDEVTYPE_HAL, D3DDEVTYPE_REF }; +D3dDriverInfo **d3dDriverList = NULL; +int numDriver = 0; // size of above array list + +int requiredDeviceID = -1; // must use this Device or die + +// If this number is greater than zero, J3D must use the +// adapter index in the order of GetAdapterIdentifier() starting from one. +// Otherwise, the first driver found with monitor matching the display +// driver is used. +int requiredDriverID = -1; +OSVERSIONINFO osvi; + +// There is bug in Nvidia driver which prevent VB too big +// in TnL hardware vertex processing mode. +// When the index is greater than 65535, the nvidia driver will +// consider it to be N % 65535. However it works fine in +// hardware vertex processing mode. +//@TODO check this with Cap Bits +UINT vertexBufferMaxVertexLimit = 65535; + +// True to disable setting D3DRS_MULTISAMPLEANTIALIAS +// Rendering state. +BOOL implicitMultisample; + +// Fix to Issue 226 : D3D - fail on stress test for the creation and destruction of Canvases +D3DFORMAT d3dDepthFormat[D3DDEPTHFORMATSIZE] = { D3DFMT_D24S8, // this is the best choice + D3DFMT_D24X4S4, + D3DFMT_D15S1, + D3DFMT_D24X8, + D3DFMT_D16_LOCKABLE, + D3DFMT_D16, + D3DFMT_D32 +}; + +// This should match the depth bit in the above array +int d3dDepthTable[D3DDEPTHFORMATSIZE] = {24, 24, 15, 24, 16, 16, 32}; +int d3dStencilDepthTable[D3DDEPTHFORMATSIZE] = { 8, 4, 1, 0, 0, 0, 0}; + +D3DLIGHT9 ambientLight; + +D3dDriverInfo::D3dDriverInfo() +{ + for (int i=0; i < numDeviceTypes; i++) { + d3dDeviceList[i] = new D3dDeviceInfo(); + } +} + +D3dDriverInfo::~D3dDriverInfo() +{ + for (int i=0; i < numDeviceTypes; i++) { + SafeDelete(d3dDeviceList[i]); + } +} + +VOID computeRGBDepth(D3dDriverInfo *pDriver) +{ + switch (pDriver->desktopMode.Format) { + case D3DFMT_R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + pDriver->redDepth = pDriver->greenDepth = + pDriver->blueDepth = 8; + break; + case D3DFMT_R5G6B5: + pDriver->redDepth = pDriver->blueDepth = 5; + pDriver->greenDepth = 6; + break; + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + pDriver->redDepth = pDriver->blueDepth = + pDriver->greenDepth = 5; + break; + case D3DFMT_A4R4G4B4: + case D3DFMT_X4R4G4B4: + pDriver->redDepth = pDriver->blueDepth = + pDriver->greenDepth = 4; + break; + case D3DFMT_R3G3B2: + case D3DFMT_A8R3G3B2: + pDriver->redDepth = pDriver->greenDepth = 3; + pDriver->blueDepth = 2; + break; + default: // 8 color indexed or less + pDriver->redDepth = pDriver->blueDepth = + pDriver->greenDepth = 0; + } + +} + + +VOID setInfo(D3dDeviceInfo* pDevice,D3DADAPTER_IDENTIFIER9 *identifier) +{ + char* str = (char *)"UNKNOW VGA Vendor."; + switch( identifier->VendorId ) + { + // A more complete list can be found from http://www.pcidatabase.com/vendors.php?sort=id + case 0x0000: str = (char *) "RDP Remote Desktop DirectDraw"; break; + case 0x1002: str = (char *) "ATI Technologies Inc."; break; + case 0x1004: str = (char *) "VLSI Technology."; break; + case 0x100B: str = (char *) "National Semiconductors."; break; + case 0x1013: str = (char *) "Cirrus Logic."; break; + case 0x1014: str = (char *) "IBM"; break; + case 0x1017: str = (char *) "Spea Software AG."; break; + + case 0x1022: str = (char *) "Advanced Micro Devices (AMD)."; break; + case 0x1025: str = (char *) "ALI Acer Labs Inc."; break; + case 0x1023: str = (char *) "Trident Microsistems."; break; + case 0x102C: str = (char *) "Asiliant (Chips And Technologies)."; break; + case 0x102B: str = (char *) "Matrox Electronic Systems Ltd."; break; + case 0x1031: str = (char *) "MIRO Computer Products AG"; break; + case 0x1033: str = (char *) "NEC Electronics."; break; + case 0x1039: str = (char *) "SiS Silicon Integrated Systems."; break; + case 0x1045: str = (char *) "OPTi"; break; + case 0x104C: str = (char *) "Texas Instruments."; break; + case 0x104E: str = (char *) "Oak Technology."; break; + case 0x1050: str = (char *) "Winbond Electronics Corp."; break; + case 0x105D: str = (char *) "Number Nine Visual Technology"; break; + case 0x1060: str = (char *) "United Microelectronics."; break; + case 0x106B: str = (char *) "Apple Computer,Inc."; break; + case 0x1073: str = (char *) "Yamaha Corporation."; break; + + case 0x108E: str = (char *) "Sun Microsystems."; break; + case 0x1091: str = (char *) "Intergraph Corporation."; break; + + case 0x10DE: str = (char *) "NVIDIA Corporation."; break; + case 0x10EA: str = (char *) "Tvia, Inc."; break; + case 0x10ED: str = (char *) "Ascii Corporation"; break; + case 0x1092: str = (char *) "Diamond Multimedia"; break; + case 0x1102: str = (char *) "Creative Technology LTD."; break; + case 0x1117: str = (char *) "Datacube Inc."; break; + case 0x1106: str = (char *) "VIA Technology. "; break; + case 0x1135: str = (char *) "Fuji Xerox Co Ltd."; break; + case 0x1142: str = (char *) "Alliance Semiconductor"; break; + case 0x117f: str = (char *) "Integrated Circuit Systems."; break; + case 0x11AE: str = (char *) "Scitex Corporation Ltd."; break; + + case 0x121A: str = (char *) "3dfx Interactive Inc."; break; + case 0x1251: str = (char *) "VLSI Solution OY."; break; + case 0x126F: str = (char *) "Silicon Motion."; break; + case 0x1295: str = (char *) "Imagination Technologies."; break; + case 0x1414: str = (char *) "MicroSoft."; break; + case 0x15AD: str = (char *) "VMware Inc."; break; + case 0x18CA: str = (char *) "XGI xgitech."; break; + case 0x1888: str = (char *) "Varisys Limited"; break; + + case 0x1B13: str = (char *) "Jaton Corporation USA."; break; + case 0x3D3D: str = (char *) "3Dlabs Inc, Ltd."; break; + case 0x5333: str = (char *) "S3 Graphics Co., Ltd."; break; + case 0x8086: str = (char *) "Intel Corporation."; break; + case 0xAA42: str = (char *) "Scitex Digital Video"; break; + + case 0xDEAF: str = (char *) "Middle Digital, Inc."; break; + case 0xEDD8: str = (char *) "ARK Logic, Inc."; break; + case 0xFFF3: str = (char *) "VMWare Inc.(Legacy)"; break; + } + pDevice->deviceVendor = str; + + pDevice->deviceRenderer = identifier->Description; + // better handling of RDP - Remote Desktop + if(identifier->VendorId==0 && identifier->DeviceId==0){ + pDevice->deviceRenderer = (char *) "RDP - No Hardware D3D"; + } + + char version[ 128 ]; + sprintf( version, "%x.%x.%x.%x", HIWORD( identifier->DriverVersion.HighPart ), + LOWORD( identifier->DriverVersion.HighPart ), + HIWORD( identifier->DriverVersion.LowPart ), + LOWORD( identifier->DriverVersion.LowPart ) ); + pDevice->deviceVersion = (char *)version; + +} + + +VOID buildDriverList(LPDIRECT3D9 pD3D) +{ + numDriver = pD3D->GetAdapterCount(); + if (numDriver <= 0) { + // keep d3dDriverList = NULL for checking later + D3dCtx::d3dError(DRIVERNOTFOUND); + return; + } + + d3dDriverList = new LPD3dDriverInfo[numDriver]; + + if (d3dDriverList == NULL) { + D3dCtx::d3dError(OUTOFMEMORY); + return; + } + + D3dDriverInfo *pDriver; + + for (int i = 0; i < numDriver; i++ ) { + pDriver = new D3dDriverInfo(); + d3dDriverList[i] = pDriver; + pD3D->GetAdapterIdentifier(i, 0, &pDriver->adapterIdentifier); + pD3D->GetAdapterDisplayMode(i, &pDriver->desktopMode); + computeRGBDepth(pDriver); + pDriver->hMonitor = pD3D->GetAdapterMonitor(i); + pDriver->iAdapter = i; + + + for (int j = 0; j < numDeviceTypes; j++ ) { + D3DCAPS9 d3dCaps; + D3dDeviceInfo* pDevice = pDriver->d3dDeviceList[j]; + pDevice->deviceType = deviceTypes[j]; + pD3D->GetDeviceCaps(i, deviceTypes[j], &d3dCaps); + pDevice->setCaps(&d3dCaps); + + pDevice->desktopCompatible = + SUCCEEDED(pD3D->CheckDeviceType(i, deviceTypes[j], + pDriver->desktopMode.Format, + pDriver->desktopMode.Format, + TRUE)); + + pDevice->fullscreenCompatible = + SUCCEEDED(pD3D->CheckDeviceType(i, deviceTypes[j], + pDriver->desktopMode.Format, + pDriver->desktopMode.Format, + FALSE)); + + pDevice->maxZBufferDepthSize = 0; + + + if (pDevice->isHardwareTnL) { + strcpy(pDevice->deviceName, "Transform & Light Hardware Rasterizer"); + } else if (pDevice->isHardware) { + strcpy(pDevice->deviceName, "Hardware Rasterizer"); + } else { + strcpy(pDevice->deviceName, "Reference Rasterizer"); + } + //issue 135 put here info about vendor and device model + setInfo(pDevice, &pDriver->adapterIdentifier); + + for (int k=0; k < D3DDEPTHFORMATSIZE; k++) { + + pDevice->depthFormatSupport[k] = + SUCCEEDED(pD3D->CheckDeviceFormat(i, deviceTypes[j], + pDriver->desktopMode.Format, + D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_SURFACE, + d3dDepthFormat[k])) + && + SUCCEEDED(pD3D->CheckDepthStencilMatch(i, deviceTypes[j], + pDriver->desktopMode.Format, + pDriver->desktopMode.Format, + d3dDepthFormat[k])); + if (pDevice->depthFormatSupport[k]) { + if (d3dDepthTable[k] > pDevice->maxZBufferDepthSize) { + pDevice->maxZBufferDepthSize = d3dDepthTable[k]; + pDevice->maxStencilDepthSize = d3dStencilDepthTable[k]; + if (d3dStencilDepthTable[k]>0) { + pDevice->supportStencil = true; + } + else { + pDevice->supportStencil = false; + } + } + } + } + // Fix to Issue 226 : D3D - fail on stress test for the creation and destruction of Canvases + DWORD bitmask = 0; + pDevice->multiSampleSupport = 0; + for (int mtype = D3DMULTISAMPLE_2_SAMPLES; + mtype <= D3DMULTISAMPLE_16_SAMPLES; mtype++) { + // consider desktop mode only for multisampling + HRESULT hrMSBack; + // HRESULT hrMSDepth; // should also check DephStencil ??? TODO - aces + + bitmask = 1 << mtype; + hrMSBack = pD3D->CheckDeviceMultiSampleType(i, deviceTypes[j], + pDriver->desktopMode.Format, + TRUE, + (D3DMULTISAMPLE_TYPE) mtype, NULL); + if(SUCCEEDED(hrMSBack)) { + pDevice->multiSampleSupport |= bitmask; + if(debug){ + /* + printf("Multisample: Back %s uses %s at bitmask %d, mtype %d, multiSampleSupport %d \n", + getPixelFormatName(pDriver->desktopMode.Format), + getMultiSampleName((D3DMULTISAMPLE_TYPE) mtype), + bitmask, mtype, pDevice->multiSampleSupport ); + */ + } + }//if hrMSBack + + }// for mtype + }//for j - device Types + }// for i - numDriver + +} + + + +// Cleanup when no more ctx exists +VOID D3dDriverInfo::release() +{ + for (int i = 0; i < numDriver; i++ ) { + SafeDelete(d3dDriverList[i]); + } + SafeDelete(d3dDriverList); + numDriver = 0; +} + +VOID printInfo() +{ + printf("javax.media.j3d 1.5.2, Windows version is %d.%d ", + osvi.dwMajorVersion, osvi.dwMinorVersion); + printf("Build: %d, ", LOWORD(osvi.dwBuildNumber)); + + switch(osvi.dwPlatformId) { + case VER_PLATFORM_WIN32s: + printf("Windows3.1"); + break; + case VER_PLATFORM_WIN32_WINDOWS: + printf("Windows 95/98"); + break; + case VER_PLATFORM_WIN32_NT: + //printf("Windows NT/2000/XP"); + if(osvi.dwMajorVersion==5){ + printf("Windows NT/2000/XP"); + } + if(osvi.dwMajorVersion==6){ + printf("Windows Server 2008/Vista"); + } + break; + } + + printf(" %s", osvi.szCSDVersion); + + D3dDriverInfo *pDriver; + for (int i=0; i < numDriver; i++) { + pDriver = d3dDriverList[i]; + D3DADAPTER_IDENTIFIER9 *id = &pDriver->adapterIdentifier; + D3DDISPLAYMODE *dm = &pDriver->desktopMode; + printf("\n[Display Driver] %s, %s, Product %d\n", + id->Driver, id->Description, + HIWORD(id->DriverVersion.HighPart)); + printf(" Version %d.%d, Build %d, VendorId %x\n", + LOWORD(id->DriverVersion.HighPart), + HIWORD(id->DriverVersion.LowPart), + LOWORD(id->DriverVersion.LowPart), + id->VendorId); + printf(" DeviceId %x, SubSysId %x, Revision %d\n", + id->VendorId, id->DeviceId, + id->SubSysId, id->Revision); + printf(" [Desktop Mode] %dx%d ", + dm->Width, dm->Height); + + if (dm->RefreshRate != 0) { + printf("%d MHz", dm->RefreshRate); + } + printf(", %s\n", getPixelFormatName(dm->Format)); + + for (int j=0; j < numDeviceTypes; j++) { + D3dDeviceInfo *pDevice = pDriver->d3dDeviceList[j]; + printf("\t[Device] %s ", pDevice->deviceName); + if (pDevice->multiSampleSupport) { + printf("(AA)"); + } + printf("\n"); + } + } + printf("\n"); +} + + +// Construct the D3dDriverList by enumerate all the drivers +VOID D3dDriverInfo::initialize(JNIEnv *env) +{ + HINSTANCE hD3D9DLL = LoadLibrary( "D3D9.DLL" ); + + // Simply see if D3D9.dll exists. + if ( hD3D9DLL == NULL ) + { + D3dCtx::d3dError(D3DNOTFOUND); + return; + } + FreeLibrary(hD3D9DLL); + + LPDIRECT3D9 pD3D = Direct3DCreate9( D3D_SDK_VERSION ); + if (debug && pD3D != NULL){ + printf("[j3d] Using DirectX D3D 9.0 or higher.\n"); + printf("[j3d] DirectX D3D renderer build 1.5.2\n"); + } + if (pD3D == NULL) { + D3dCtx::d3dError(D3DNOTFOUND); + return; + } + + // must appear before buildDriverList in order to + // set VertexBufferLimit correctly in D3dDeviceInfo + D3dCtx::setVBLimitProperty(env); + buildDriverList(pD3D); + + SafeRelease(pD3D); + + //D3dCtx::setDebugProperty(env); + D3dCtx::setDebugProperty(env); + + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + if (debug) { + printInfo(); + } + + // compute requiredGUID + D3dCtx::setDeviceFromProperty(env); + + D3dCtx::setImplicitMultisamplingProperty(env); + + /* + RasterList.init(); + BackgroundImageList.init(); + */ + + // Setup Global constant Ambient light + ambientLight.Type = D3DLIGHT_DIRECTIONAL; + ambientLight.Direction.x = 0; + ambientLight.Direction.y = 0; + ambientLight.Direction.z = 1; + CopyColor(ambientLight.Diffuse, 0, 0, 0, 1.0f); + CopyColor(ambientLight.Ambient, 1.0f, 1.0f, 1.0f, 1.0f); + CopyColor(ambientLight.Specular, 0, 0, 0, 1.0f); +} + + + diff --git a/j3d-core/src/native/d3d/D3dDriverInfo.hpp b/j3d-core/src/native/d3d/D3dDriverInfo.hpp new file mode 100644 index 0000000..6ad8454 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dDriverInfo.hpp @@ -0,0 +1,81 @@ +/* + * $RCSfile: D3dDriverInfo.hpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#if !defined(D3DDRIVERINFO_H) +#define D3DDRIVERINFO_H + +#include "StdAfx.h" + + +#define DEVICE_HAL 0 +#define DEVICE_REF 1 +#define DEVICE_HAL_TnL 2 + +extern D3DFORMAT d3dDepthFormat[D3DDEPTHFORMATSIZE]; +extern int d3dDepthTable[D3DDEPTHFORMATSIZE]; +extern int d3dStencilDepthTable[D3DDEPTHFORMATSIZE]; + +class D3dDriverInfo { +public: + // DDraw Driver info + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + // Desktop display mode for this adapter + D3DDISPLAYMODE desktopMode; + // monitor handle for this adapter + HMONITOR hMonitor; + + // Index position in the adapter list + UINT iAdapter; + + // Support devices : HAL or REF + D3dDeviceInfo* d3dDeviceList[2]; + + // Use for NativeConfigTemplate to + // determine the min. config support + UINT redDepth, greenDepth, blueDepth; + + D3dDriverInfo(); + ~D3dDriverInfo(); + + static VOID initialize(JNIEnv *env); + static VOID release(); +}; + +typedef D3dDriverInfo* LPD3dDriverInfo; +extern int numDriver; // size of above array list +extern D3dDriverInfo **d3dDriverList; +extern const DWORD numDeviceTypes; +extern const D3DDEVTYPE deviceTypes[2]; +extern int requiredDeviceID; // force to use HAL/REF or exit +extern int requiredDriverID; // force to use specific adapte +extern D3DLIGHT9 ambientLight; // constant ambient light +extern BOOL implicitMultisample; +#endif diff --git a/j3d-core/src/native/d3d/D3dUtil.cpp b/j3d-core/src/native/d3d/D3dUtil.cpp new file mode 100644 index 0000000..f485a93 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dUtil.cpp @@ -0,0 +1,12500 @@ +/* + * $RCSfile: D3dUtil.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.20 $ + * $Date: 2008/02/28 20:17:58 $ + * $State: Exp $ + */ + +#include "StdAfx.h" + +HANDLE hSema = CreateSemaphore(NULL, 1, 1, "Java3d_Ctx"); + +HANDLE geometrySema = CreateSemaphore(NULL, 1, 1, + "Java3d_GeometryArrayLock"); +HANDLE surfaceListSema = CreateSemaphore(NULL, 1, 1, "Java3d_SurfaceListLock"); + +BOOL firstError = true; +BOOL firstWarning = true; +BOOL debug = false; + + +vector freePointerList0; +vector freePointerList1; +BOOL useFreePointerList0 = true; + +char *D3dErrorMessage[] = { + "Can't found 3D Driver !", + "Current display driver did not support renderer inside window. Now switch to full screen mode...", + "DirectX 9.0c or above is required for this version of Java3D.", + "Your graphics card did not support >= 16 bit color mode which Java 3D required.", + "Please switch your display mode to at least 16 bit color depth.", + "No compatible device found, please switch to other display mode and try again !", + "Fail to create hardware D3D Device, switch to use reference rasterizer.", + "Fail to create reference rasterizer 3D Device.", + "Fail to set Viewport", + "Fail to get attach back buffer", + "256 color mode not support !", + "Out of memory !", + "Unknown 3D device specified in property j3d.d3ddevice, please use either \"reference\" or \"hardware\".", + "Graphics card did not support Hardware acceleration", + "Graphics card did not support Transform and light hardware acceleration", + "No Stencil buffer found in current display mode. DecalGroup may not work correctly.", + "Can't found a valid texture format, please try to use reference mode. DirectX SDK must be installed to use reference mode", + "Fail to create offscreen image for background", + "Fail to create Vertex Buffer", + "Fail to Reset() D3D device, try Recreate device again.", + "No compatible depth buffer found in your system, please switch to other display mode or try reference rasterizer.", + "Depth buffer with the required bit depth is not support, please try the default.", + "Fail to lock Vertex Buffer", + "Fail to create Vertex Buffer", + "Fail to create Index Buffer", + "Fail to lock Index Buffer", + "Graphics card doesn't support Hardware Acceleration. \n Java3D will use DirectX Reference Rasterizer (Soft).", + "Unable to create DirectX D3D context.\n Neither Hardware and Software Renderer are available.\n Please update your video card drivers\n and get the latest DirectX available at http://microsoft.com/directx \n" +}; + +D3DTRANSFORMSTATETYPE transformState[] = { + D3DTS_TEXTURE0, + D3DTS_TEXTURE1, + D3DTS_TEXTURE2, + D3DTS_TEXTURE3, + D3DTS_TEXTURE4, + D3DTS_TEXTURE5, + D3DTS_TEXTURE6, + D3DTS_TEXTURE7}; + +#define D3DFORMATTABLESIZE 40 + +D3DFORMAT d3dFormatTable[] = { + D3DFMT_UNKNOWN, //01 + D3DFMT_R8G8B8, //02 + D3DFMT_A8R8G8B8, //03 + D3DFMT_X8R8G8B8, //04 + D3DFMT_R5G6B5, //05 + D3DFMT_X1R5G5B5, //06 + D3DFMT_A1R5G5B5, //07 + D3DFMT_A4R4G4B4, //08 + D3DFMT_R3G3B2, //09 + D3DFMT_A8, //10 + D3DFMT_A8R3G3B2, //11 + D3DFMT_X4R4G4B4, //12 + D3DFMT_A8P8, //13 + D3DFMT_P8, //14 + D3DFMT_L8, //15 + D3DFMT_A8L8, //16 + D3DFMT_A4L4, //17 + D3DFMT_V8U8, //18 + D3DFMT_L6V5U5, //19 + D3DFMT_X8L8V8U8, //20 + D3DFMT_Q8W8V8U8, //21 + D3DFMT_V16U16, //22 + // D3DFMT_W11V11U10, //XX + D3DFMT_UYVY, //23 + D3DFMT_YUY2, //24 + D3DFMT_DXT1, //25 + D3DFMT_DXT2, //26 + D3DFMT_DXT3, //27 + D3DFMT_DXT4, //28 + D3DFMT_DXT5, //29 + D3DFMT_D16_LOCKABLE, //30 + D3DFMT_D32, //31 + D3DFMT_D15S1, //32 + D3DFMT_D24S8, //33 + D3DFMT_D16, //34 + D3DFMT_D24X8, //35 + D3DFMT_D24X4S4, //36 + D3DFMT_VERTEXDATA, //37 + D3DFMT_INDEX16, //38 + D3DFMT_INDEX32 //39 +}; + +char *d3dFormatTableChar[] = { + "D3DFMT_UNKNOWN", //01 + "D3DFMT_R8G8B8", //02 + "D3DFMT_A8R8G8B8", //03 + "D3DFMT_X8R8G8B8", //04 + "D3DFMT_R5G6B5", //05 + "D3DFMT_X1R5G5B5", //06 + "D3DFMT_A1R5G5B5", //07 + "D3DFMT_A4R4G4B4", //08 + "D3DFMT_R3G3B2", //09 + "D3DFMT_A8", //10 + "D3DFMT_A8R3G3B2", //11 + "D3DFMT_X4R4G4B4", //12 + "D3DFMT_A8P8", //13 + "D3DFMT_P8", //14 + "D3DFMT_L8", //15 + "D3DFMT_A8L8", //16 + "D3DFMT_A4L4", //17 + "D3DFMT_V8U8", //18 + "D3DFMT_L6V5U5", //19 + "D3DFMT_X8L8V8U8", //20 + "D3DFMT_Q8W8V8U8", //21 + "D3DFMT_V16U16", //22 + // "D3DFMT_W11V11U10", //XX + "D3DFMT_UYVY", //23 + "D3DFMT_YUY2", //24 + "D3DFMT_DXT1", //25 + "D3DFMT_DXT2", //26 + "D3DFMT_DXT3", //27 + "D3DFMT_DXT4", //28 + "D3DFMT_DXT5", //29 + "D3DFMT_D16_LOCKABLE",//30 + "D3DFMT_D32", //31 + "D3DFMT_D15S1", //32 + "D3DFMT_D24S8", //33 + "D3DFMT_D16", //34 + "D3DFMT_D24X8", //35 + "D3DFMT_D24X4S4", //36 + "D3DFMT_VERTEXDATA", //37 + "D3DFMT_INDEX16", //38 + "D3DFMT_INDEX32" //39 +}; + +char* multipleSampleTypeTable[] = { + "D3DMULTISAMPLE_NONE", + "D3DMULTISAMPLE_UNKNOWN", + "D3DMULTISAMPLE_2_SAMPLES", + "D3DMULTISAMPLE_3_SAMPLES", + "D3DMULTISAMPLE_4_SAMPLES", + "D3DMULTISAMPLE_5_SAMPLES", + "D3DMULTISAMPLE_6_SAMPLES", + "D3DMULTISAMPLE_7_SAMPLES", + "D3DMULTISAMPLE_8_SAMPLES", + "D3DMULTISAMPLE_9_SAMPLES", + "D3DMULTISAMPLE_10_SAMPLES", + "D3DMULTISAMPLE_11_SAMPLES", + "D3DMULTISAMPLE_12_SAMPLES", + "D3DMULTISAMPLE_13_SAMPLES", + "D3DMULTISAMPLE_14_SAMPLES", + "D3DMULTISAMPLE_15_SAMPLES", + "D3DMULTISAMPLE_16_SAMPLES" +}; + +char* swapEffectTable[] = { + "D3DSWAPEFFECT_UNKNOWN", + "D3DSWAPEFFECT_DISCARD", + "D3DSWAPEFFECT_FLIP", + "D3DSWAPEFFECT_COPY", + "D3DSWAPEFFECT_COPY_VSYNC" +}; + + +// mapping from java enum to d3d enum + +D3DCUBEMAP_FACES textureCubeMapFace[] = { + D3DCUBEMAP_FACE_POSITIVE_X, + D3DCUBEMAP_FACE_NEGATIVE_X, + D3DCUBEMAP_FACE_POSITIVE_Y, + D3DCUBEMAP_FACE_NEGATIVE_Y, + D3DCUBEMAP_FACE_NEGATIVE_Z, + D3DCUBEMAP_FACE_POSITIVE_Z, +}; + +typedef struct _PIXELFORMAT { + DWORD dwRGBBitCount; + DWORD dwRBitMask; + DWORD dwGBitMask; + DWORD dwBBitMask; + DWORD dwRGBAlphaBitMask; + BOOL noAlpha; +} PIXELFORMAT; + + +typedef struct _DEPTHPIXELFORMAT { + DWORD dwZBufferBitDepth; + DWORD dwZBitMask; + DWORD dwStencilBitDepth; + DWORD dwStencilBitMask; +} DEPTHPIXELFORMAT; + +void throwAssert(JNIEnv *env, char *str) +{ + jclass rte; + if ((rte = (jclass)env->FindClass("java/lang/AssertionError")) != NULL) { + (void *)env->ThrowNew(rte, str); + } +} + +char *getSwapEffectName(D3DSWAPEFFECT swapEffect) +{ + int t = (int) swapEffect; + if ((t < 0) || (t > 4)) { + return swapEffectTable[0]; + } + return swapEffectTable[t]; +} + +char *getMultiSampleName(D3DMULTISAMPLE_TYPE mtype) +{ + int t = (int) mtype; + if ((t < 0) || (t > 16)) { + // UNKNOWN + return multipleSampleTypeTable[1]; + } + return multipleSampleTypeTable[t]; +} + +char* getPixelFormatName(D3DFORMAT f) +{ + for (int i=0; i < D3DFORMATTABLESIZE; i++) { + if (f == d3dFormatTable[i]) { + return d3dFormatTableChar[i]; + } + } + // should not happen + return d3dFormatTableChar[0]; +} + +// If there is a new D3DFORMAT, just add it here and +// our copy procedures can handle any format specific +// as bit mask. +//@TODO add floating point pixelFormats +VOID computePixelFormat(PIXELFORMAT *ddpf, D3DFORMAT format) +{ + switch (format) { + case D3DFMT_R8G8B8: + ddpf->dwRGBBitCount = 24; + ddpf->dwRGBAlphaBitMask = 0; + ddpf->dwRBitMask = 0x00ff0000; + ddpf->dwGBitMask = 0x0000ff00; + ddpf->dwBBitMask = 0x000000ff; + ddpf->noAlpha = true; + break; + case D3DFMT_A8R8G8B8: + ddpf->dwRGBBitCount = 32; + ddpf->dwRGBAlphaBitMask = 0xff000000; + ddpf->dwRBitMask = 0x00ff0000; + ddpf->dwGBitMask = 0x0000ff00; + ddpf->dwBBitMask = 0x000000ff; + ddpf->noAlpha = false; + break; + case D3DFMT_X8R8G8B8: + ddpf->dwRGBBitCount = 32; + ddpf->dwRGBAlphaBitMask = 0; + ddpf->dwRBitMask = 0x00ff0000; + ddpf->dwGBitMask = 0x0000ff00; + ddpf->dwBBitMask = 0x000000ff; + ddpf->noAlpha = true; + break; + case D3DFMT_R5G6B5: + ddpf->dwRGBBitCount = 16; + ddpf->dwRGBAlphaBitMask = 0; + ddpf->dwRBitMask = 0xf800; + ddpf->dwGBitMask = 0x07e0; + ddpf->dwBBitMask = 0x001f; + ddpf->noAlpha = true; + break; + case D3DFMT_X1R5G5B5: + ddpf->dwRGBBitCount = 16; + ddpf->dwRGBAlphaBitMask = 0; + ddpf->dwRBitMask = 0x7c00; + ddpf->dwGBitMask = 0x03e0; + ddpf->dwBBitMask = 0x001f; + ddpf->noAlpha = true; + break; + case D3DFMT_A1R5G5B5: + ddpf->dwRGBBitCount = 16; + ddpf->dwRGBAlphaBitMask = 0x8000; + ddpf->dwRBitMask = 0x7c00; + ddpf->dwGBitMask = 0x03e0; + ddpf->dwBBitMask = 0x001f; + ddpf->noAlpha = false; + break; + case D3DFMT_A4R4G4B4: + ddpf->dwRGBBitCount = 16; + ddpf->dwRGBAlphaBitMask = 0xf000; + ddpf->dwRBitMask = 0x0f00; + ddpf->dwGBitMask = 0x00f0; + ddpf->dwBBitMask = 0x000f; + ddpf->noAlpha = false; + break; + case D3DFMT_X4R4G4B4: + ddpf->dwRGBBitCount = 16; + ddpf->dwRGBAlphaBitMask = 0; + ddpf->dwRBitMask = 0x0f00; + ddpf->dwGBitMask = 0x00f0; + ddpf->dwBBitMask = 0x000f; + ddpf->noAlpha = true; + break; + case D3DFMT_R3G3B2: + ddpf->dwRGBBitCount = 8; + ddpf->dwRGBAlphaBitMask = 0; + ddpf->dwRBitMask = 0xe0; + ddpf->dwGBitMask = 0x1c; + ddpf->dwBBitMask = 0x03; + ddpf->noAlpha = true; + break; + case D3DFMT_A8R3G3B2: + ddpf->dwRGBBitCount = 16; + ddpf->dwRGBAlphaBitMask = 0xff00; + ddpf->dwRBitMask = 0x00e0; + ddpf->dwGBitMask = 0x001c; + ddpf->dwBBitMask = 0x0003; + ddpf->noAlpha = false; + break; + case D3DFMT_A8: + ddpf->dwRGBBitCount = 8; + ddpf->dwRGBAlphaBitMask = 0xff; + ddpf->dwRBitMask = 0; + ddpf->dwGBitMask = 0; + ddpf->dwBBitMask = 0; + ddpf->noAlpha = false; + break; + case D3DFMT_L8: + ddpf->dwRGBBitCount = 8; + ddpf->dwRGBAlphaBitMask = 0; + ddpf->dwRBitMask = 0xff; + ddpf->dwGBitMask = 0; + ddpf->dwBBitMask = 0; + ddpf->noAlpha = true; + break; + case D3DFMT_A8L8: + ddpf->dwRGBBitCount = 16; + ddpf->dwRGBAlphaBitMask = 0xff00; + ddpf->dwRBitMask = 0x00ff; + ddpf->dwGBitMask = 0; + ddpf->dwBBitMask = 0; + ddpf->noAlpha = false; + break; + case D3DFMT_A4L4: + ddpf->dwRGBBitCount = 8; + ddpf->dwRGBAlphaBitMask = 0xf0; + ddpf->dwRBitMask = 0x0f; + ddpf->dwGBitMask = 0; + ddpf->dwBBitMask = 0; + ddpf->noAlpha = false; + break; + default: + printf("Unsupport format %d\n ", format); + ddpf->dwRGBBitCount = 8; + ddpf->dwRGBAlphaBitMask = 0; + ddpf->dwRBitMask = 0; + ddpf->dwGBitMask = 0; + ddpf->dwBBitMask = 0; + ddpf->noAlpha = true; + break; + } + +} + + +/* + * Right now only format D3DFMT_D16_LOCKABLE + * is lockable by application. So can't use + * with stencil buffer (in DecalGroup) together + */ +VOID computeDepthPixelFormat(DEPTHPIXELFORMAT *ddpf, + D3DFORMAT format) +{ + switch (format) { + case D3DFMT_D16_LOCKABLE: + case D3DFMT_D16: + ddpf->dwZBufferBitDepth = 16; + ddpf->dwZBitMask = 0xffff; + ddpf->dwStencilBitDepth = 0; + ddpf->dwStencilBitMask = 0x0000; + break; + case D3DFMT_D15S1: + ddpf->dwZBufferBitDepth = 16; + ddpf->dwZBitMask = 0xfffe; + ddpf->dwStencilBitDepth = 1; + ddpf->dwStencilBitMask = 0x0001; + break; + case D3DFMT_D32: + ddpf->dwZBufferBitDepth = 32; + ddpf->dwZBitMask = 0xffffffff; + ddpf->dwStencilBitDepth = 0; + ddpf->dwStencilBitMask = 0x000000; + break; + case D3DFMT_D24S8: + ddpf->dwZBufferBitDepth = 32; + ddpf->dwZBitMask = 0xffffff00; + ddpf->dwStencilBitDepth = 8; + ddpf->dwStencilBitMask = 0x00000ff; + break; + case D3DFMT_D24X8: + ddpf->dwZBufferBitDepth = 32; + ddpf->dwZBitMask = 0xffffff00; + ddpf->dwStencilBitDepth = 0; + ddpf->dwStencilBitMask = 0x0000000; + break; + case D3DFMT_D24X4S4: + ddpf->dwZBufferBitDepth = 32; + ddpf->dwZBitMask = 0xffffff00; + ddpf->dwStencilBitDepth = 4; + ddpf->dwStencilBitMask = 0x000000f; + break; + default: + printf("Unknown depth buffer format %d\n", format); + } +} + + +/* + * Set the correct D3DTSS_TEXTURETRANSFORMFLAGS + */ +void setTexTransformStageFlag(D3dCtx* d3dCtx, + LPDIRECT3DDEVICE9 device, + int tus, int ts, int genMode) +{ + /* + * In case of automatic texture generation, disable + * texture unit transform stage will cause crash in + * reference device mode. + */ + if ((!d3dCtx->texTransformSet[tus]) && + (d3dCtx->texGenMode == TEX_GEN_NONE)) { + device->SetTextureStageState(tus, + D3DTSS_TEXTURETRANSFORMFLAGS, + D3DTTFF_DISABLE); + } else { + D3DXMATRIX *m; + + switch (ts) { + case 2: + // Adjust for 2D texture transform in D3D + // 1 0 0 0 + // 0 1 0 0 + // du dv 0 0 + // 0 0 0 0 + // + + /* + * From DIRECTXDEV@DISCUSS.MICROSOFT.COM: + * + * The texture transform matrix is funky. With COUNT=2 + * and texture coordinates coming from the vertices, you + * can't use the stock transformation matrix functions to + * generate the matrix without adjusting it before setting + * the transform. Basically in the case of COUNT=2 with + * texcoords coming from the vertices, the pipeline uses + * the upper 3x3 submatrix of the 4x4 matrix as the + * transformation. So if you were expecting the (u,v) + * translation elements to be on the 4th row, these won't + * be applied properly in this case. + * + * What's funky is that if you were using COUNT=2 and + * texture coordinates coming in automatically, then it + * wants the translation in the 4th row. I can't decide + * yet if this is a poor specification that results in + * this matrix weirdness, or if its a bug in the runtime. + */ + if ((genMode != TEX_GEN_AUTO) && + !d3dCtx->texTranslateSet[tus]) { + m = &d3dCtx->texTransform[tus]; + (*m)._31 = (*m)._41; + (*m)._32 = (*m)._42; + device->SetTransform((D3DTRANSFORMSTATETYPE) + (D3DTS_TEXTURE0 + tus), m); + d3dCtx->texTranslateSet[tus] = true; + } + + device->SetTextureStageState(tus, + D3DTSS_TEXTURETRANSFORMFLAGS, + D3DTTFF_COUNT2); + break; + case 3: + device->SetTextureStageState(tus, + D3DTSS_TEXTURETRANSFORMFLAGS, + D3DTTFF_COUNT3); + break; + case 4: + if (d3dCtx->texGenMode[tus] == TEX_OBJ_LINEAR) { + // The texture transform matrix is funky that only the + // upper 3x3 matrix is used if we are not using + // automatic texture generation. In case of Object + // Linear we are need to workaround by doing our + // own texture transform when generate texture + // coordinate. + device->SetTextureStageState(tus, + D3DTSS_TEXTURETRANSFORMFLAGS, + D3DTTFF_DISABLE); + } else { + device->SetTextureStageState(tus, + D3DTSS_TEXTURETRANSFORMFLAGS, + D3DTTFF_COUNT4|D3DTTFF_PROJECTED); + } + break; + default: + printf("ERROR texCoordFormat, stage %d, format %d\n", + tus, ts); + } + } + +} + +/* + * Set the corresponding D3D texture coordinate + * mapping mode. + */ +inline int setTextureStage(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + int mapTexStage, + jint texStage) +{ + DWORD mode = 0; + int genMode = d3dCtx->texGenMode[mapTexStage]; + + // printf("Set TexStage mapTexStage = %d, texStage = %d, genMode = %d\n", + // mapTexStage, texStage, genMode); + + switch (genMode) { + case TEX_GEN_NONE: + case TEX_OBJ_LINEAR: + case TEX_GEN_INVALID: + // optimize for general case + device->SetTextureStageState(mapTexStage, + D3DTSS_TEXCOORDINDEX, + texStage); + return genMode; + case TEX_EYE_LINEAR: + mode = D3DTSS_TCI_CAMERASPACEPOSITION; + break; + case TEX_SPHERE_MAP: + mode = D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR; + break; + case TEX_NORMAL_MAP: + mode = D3DTSS_TCI_CAMERASPACENORMAL; + break; + case TEX_REFLECT_MAP: + mode = D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR; + break; + default: + // should not happen + printf("Unknown TexCoordGenMode %d\n", genMode); + break; + } + // Need to OR texStage for Wrapping mode even though + // there is no texture coordinate defined in that texStage in VB. + // This also clear the texStage previously set. + device->SetTextureStageState(mapTexStage, + D3DTSS_TEXCOORDINDEX, + mode | texStage); + + return TEX_GEN_AUTO; +} + + +void getTexWidthHeight(D3dDeviceInfo *deviceInfo, + jint* width, jint *height) +{ + int texWidth, texHeight; + + texWidth = *width; + texHeight = *height; + + + // Found a texture bigger than width/height + if (deviceInfo->texturePow2Only) { + for (texWidth=1; *width > texWidth; texWidth <<= 1); + for (texHeight=1; *height > texHeight; texHeight <<= 1); + } + + + if (deviceInfo->textureSquareOnly) { + if (texWidth >= texHeight) { + texHeight = texWidth; + } else { + texWidth = texHeight; + } + } + + // Check for maximum texture size support by hardware + if (texWidth > deviceInfo->maxTextureWidth) { + if (debug) { + printf("[Java 3D] Warning: Input texture width %d > maximum texture width %d hardware can support.\n", texWidth, deviceInfo->maxTextureWidth); + if (*width != texWidth) { + printf("Note that width is adjust from %d to %d to reflect texture limitation e.g. POW2, SQAUREONLY in hardware.\n", *width, texWidth); + } + } + texWidth = deviceInfo->maxTextureWidth; + } + + if (texHeight > deviceInfo->maxTextureHeight) { + if (debug) { + printf("[Java 3D] Warning: Input texture height %d > maximum texture height %d hardware can support.\n", texHeight, deviceInfo->maxTextureHeight); + if (*height != texHeight) { + printf("Note that height is adjust from %d to %d to reflect texture limitation e.g. POW2, SQAUREONLY in hardware.\n", *height, texHeight); + } + } + texHeight = deviceInfo->maxTextureHeight; + } + + *width = texWidth; + *height = texHeight; +} + +D3DFORMAT getTexFormat(jint textureFormat) { + + switch (textureFormat) { + case J3D_RGBA: + case INTENSITY: + // printf("[getTexFormat] textureFormat %d J3D_RGBA\n", textureFormat); + return D3DFMT_A8R8G8B8; + case J3D_RGB: + // printf("[getTexFormat] textureFormat %d J3D_RGB\n", textureFormat); + return D3DFMT_R8G8B8; + case LUMINANCE_ALPHA: + return D3DFMT_A8L8; + case ALPHA: + return D3DFMT_A8; + case LUMINANCE: + return D3DFMT_L8; + default: + printf("CreateTextureSurface: Unknown Java 3D Texture Format %d\n", textureFormat); + return D3DFMT_UNKNOWN; + } + +} + +D3dCtx* findCtx(HWND hwnd) +{ + D3dCtx *ctx = NULL; + + for (ITER_D3dCtxVector p = d3dCtxList.begin(); p != d3dCtxList.end(); p++) { + if ((*p)->hwnd == hwnd) { + ctx = *p; + break; + } + } + return ctx; +} + +inline VOID lock() +{ + if (hSema != NULL) { + WaitForSingleObject(hSema, INFINITE); + } +} + +inline VOID unlock() +{ + if (hSema != NULL) { + ReleaseSemaphore(hSema, 1, NULL); + } +} + + +inline VOID lockSurfaceList() +{ + if (surfaceListSema != NULL) { + WaitForSingleObject(surfaceListSema, INFINITE); + } +} + +inline VOID unlockSurfaceList() +{ + if (surfaceListSema != NULL) { + ReleaseSemaphore(surfaceListSema, 1, NULL); + } +} + +inline VOID lockGeometry() +{ + if (geometrySema != NULL) { + WaitForSingleObject(geometrySema, INFINITE); + } +} + +inline VOID unlockGeometry() +{ + if (geometrySema != NULL) { + ReleaseSemaphore(geometrySema, 1, NULL); + } +} + +VOID freePointer(void * ptr) +{ + if (ptr != NULL) { + lockSurfaceList(); + if (useFreePointerList0) { + freePointerList0.push_back(ptr); + } else { + freePointerList1.push_back(ptr); + } + unlockSurfaceList(); + } +} + + +char *getErrorMessage(int idx) +{ + return D3dErrorMessage[idx]; +} + + + +HWND getTopWindow(HWND hwnd) +{ + HWND desktop = GetDesktopWindow(); + HWND parent = GetParent(hwnd); + + while ((parent != NULL) && (parent != desktop)) { + hwnd = parent; + parent = GetParent(hwnd); + } + return hwnd; +} + + +DWORD firstBit(DWORD mask) +{ + int i; + + for (i=0; i < sizeof(DWORD)*8-1; i++) { + if ((mask & 0x01) > 0) { + return i; + } + mask >>= 1; + } + + return i; +} + +// create a DirectDraw Texture surface of specific width and height +LPDIRECT3DTEXTURE9 createTextureSurface(D3dCtx *d3dCtx, + jint numLevels, + jint textureFormat, + jint width, jint height, + jboolean useAutoMipMap) +{ + LPDIRECT3DTEXTURE9 pTexture; + D3DFORMAT format; + HRESULT hr; + DWORD usage = 0; + + LPDIRECT3DDEVICE9 pDevice = d3dCtx->pDevice; + D3dDeviceInfo *deviceInfo = d3dCtx->deviceInfo; + + if (!deviceInfo->supportMipmap) { + numLevels = 1; + } + + getTexWidthHeight(deviceInfo, &width, &height); + format = getTexFormat(textureFormat); + + if (useAutoMipMap) { + usage |= D3DUSAGE_AUTOGENMIPMAP; + } + + // If format not support, the utility function will adjust the + // calling parameters automatically + hr = D3DXCreateTexture(d3dCtx->pDevice, width, height, + numLevels, usage, format, D3DPOOL_MANAGED, + &pTexture); + + if (FAILED(hr)) { + printf("Fail to create texture surface %dx%d, format %d, level %d : %s\n", + width, height, format, numLevels, DXGetErrorString9(hr)); + return NULL; + } + + return pTexture; +} + + + +// create a DirectDraw Texture surface of specific width and height +LPDIRECT3DVOLUMETEXTURE9 createVolumeTexture(D3dCtx *d3dCtx, + jint numLevels, + jint textureFormat, + jint width, + jint height, + jint depth, + jboolean useAutoMipMap) + +{ + LPDIRECT3DVOLUMETEXTURE9 pTexture; + int texWidth, texHeight, texDepth; + D3DFORMAT format; + HRESULT hr; + DWORD usage = 0; + + LPDIRECT3DDEVICE9 pDevice = d3dCtx->pDevice; + D3dDeviceInfo *deviceInfo = d3dCtx->deviceInfo; + + texWidth = width; + texHeight = height; + texDepth = depth; + + if (!deviceInfo->supportMipmap) { + numLevels = 1; + } + + if (useAutoMipMap) { + usage |= D3DUSAGE_AUTOGENMIPMAP; + } + + // Found a texture bigger than width/height + if (deviceInfo->texturePow2Only) { + for (texWidth=1; width > texWidth; texWidth <<= 1); + for (texHeight=1; height > texHeight; texHeight <<= 1); + for (texDepth=1; depth > texDepth; texDepth <<= 1); + } + + if (deviceInfo->textureSquareOnly) { + if (texWidth >= texHeight) { + texHeight = texWidth; + } else { + texWidth = texHeight; + } + if (texDepth <= texWidth) { + texDepth = texWidth; + } else { + texWidth = texHeight = texDepth; + } + } + + // Check for maximum texture size support by hardware + if (texWidth > deviceInfo->maxTextureWidth) { + if (debug) { + printf("[Java 3D] Warning: Input texture width %d > maximum texture width %d hardware can support.\n", texWidth, deviceInfo->maxTextureWidth); + if (width != texWidth) { + printf("Note that width is adjust from %d to %d to reflect texture limitation e.g. POW2, SQAUREONLY in hardware.\n", width, texWidth); + } + } + texWidth = deviceInfo->maxTextureWidth; + } + + if (texHeight > deviceInfo->maxTextureHeight) { + if (debug) { + printf("[Java 3D] Warning: Input texture height %d > maximum texture height %d hardware can support.\n", texHeight, deviceInfo->maxTextureHeight); + if (height != texHeight) { + printf("Note that height is adjust from %d to %d to reflect texture limitation e.g. POW2, SQAUREONLY in hardware.\n", height, texHeight); + } + } + texHeight = deviceInfo->maxTextureHeight; + } + + if (texDepth > deviceInfo->maxTextureDepth) { + if (debug) { + printf("[Java 3D] Warning: Input texture depth %d > maximum texture depth %d hardware can support.\n", texDepth, deviceInfo->maxTextureDepth); + if (depth != texDepth) { + printf("Note that depth is adjust from %d to %d to reflect texture limitation e.g. POW2, SQAUREONLY in hardware.\n", depth, texDepth); + } + } + texDepth = deviceInfo->maxTextureDepth; + } + + format = getTexFormat(textureFormat); + + // If format not support, the utility function will adjust the + // calling parameters automatically + hr = D3DXCreateVolumeTexture(d3dCtx->pDevice, texWidth, texHeight, + texDepth, numLevels, usage, format, D3DPOOL_MANAGED, + &pTexture); + + if (FAILED(hr)) { + if (debug) { + printf("Fail to create volume texture %dx%dx%d, format %d, level %d : %s\n", + texWidth, texHeight, texDepth, format, numLevels, + DXGetErrorString9(hr)); + } + return NULL; + } + + return pTexture; +} + + +// copy data from DirectDraw surface to memory +// and reverse the Y axis +void copyDataFromSurface(jint imageFormat, + jint xoffset, jint yoffset, + jint subWidth, jint subHeight, + jbyte *data, + LPDIRECT3DSURFACE9 surf) +{ + D3DSURFACE_DESC ddsd; + D3DLOCKED_RECT lockedRect; + PIXELFORMAT ddpf; + HRESULT hr; + + if (surf == NULL) { + return; + } + + surf->GetDesc(&ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computePixelFormat(&ddpf, ddsd.Format); + + if ((xoffset >= width) || (yoffset >= height)) { + return; + } + + DWORD xlimit = min(xoffset + subWidth, width); + DWORD ylimit = min(yoffset + subHeight, height); + + hr = surf->LockRect(&lockedRect, NULL, D3DLOCK_NOSYSLOCK| + D3DLOCK_READONLY); + + if (FAILED(hr)) { + printf("Fail to lock surface: %s\n", DXGetErrorString9(hr)); + return; + } + + unsigned char *src; + unsigned char *dst; + byte b1, b2, b3, b4; + DWORD mask, t; + DWORD dstPitch; + + unsigned char *destRow = (unsigned char *) data; + unsigned char *srcRow = ((unsigned char *) lockedRect.pBits) + + xoffset*((int) ceil((float) ddpf.dwRGBBitCount/8.0)) + + (yoffset*lockedRect.Pitch); + + if ((imageFormat == IMAGE_FORMAT_INT_RGB) || + (imageFormat == IMAGE_FORMAT_INT_ARGB)) { + dstPitch = subWidth << 2; + destRow += (subHeight-1)*dstPitch; + + /* printf("[Java 3D] copyDataFromSurface: (1) %d\n", ddpf.dwRGBBitCount); */ + + if ((ddpf.dwRGBBitCount == 32) && + (ddpf.dwRBitMask == 0xff0000) && + (ddpf.dwGBitMask == 0xff00) && + (ddpf.dwBBitMask == 0xff)) { + // Optimize for the most common case + if (ddpf.noAlpha) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *src++; + *dst++ = (byte) 0xff; + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } + } else { // handle less common format + int rshift = firstBit(ddpf.dwRBitMask) + + ucountBits(ddpf.dwRBitMask) - 8; + int gshift = firstBit(ddpf.dwGBitMask) + + ucountBits(ddpf.dwGBitMask) - 8; + int bshift = firstBit(ddpf.dwBBitMask) + + ucountBits(ddpf.dwBBitMask) - 8; + int ashift = firstBit(ddpf.dwRGBAlphaBitMask) + + ucountBits(ddpf.dwRGBAlphaBitMask) - 8; + + if ((ddpf.dwRGBBitCount <= 32) && + (ddpf.dwRGBBitCount > 24)) { + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + b4 = *src++; + mask = ((b4 << 24) | (b3 << 16)| (b2 << 8) | b1); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + *dst++ = (byte) ((mask >> 24) & 0xff); + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if ((ddpf.dwRGBBitCount <= 24) && + (ddpf.dwRGBBitCount > 16)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + mask = ((b3 << 16) | (b2 << 8) | b1); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if ((ddpf.dwRGBBitCount <= 16) && + (ddpf.dwRGBBitCount > 8)) { + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + mask = ((b2 << 8) | b1); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if (ddpf.dwRGBBitCount <= 8) { + /* printf("[Java 3D] copyDataFromSurface: Format on (8 bits or less surface) not support %d\n", imageFormat); */ + } + } + } else if ((imageFormat == IMAGE_FORMAT_BYTE_RGBA) || + (imageFormat == IMAGE_FORMAT_BYTE_RGB) || + (imageFormat == IMAGE_FORMAT_INT_BGR)) { + + /* printf("[Java 3D] copyDataFromSurface: (2) %d\n", ddpf.dwRGBBitCount); */ + + dstPitch = subWidth << 2; + destRow += (subHeight-1)*dstPitch; + + if ((ddpf.dwRGBBitCount == 32) && + (ddpf.dwRBitMask == 0xff0000) && + (ddpf.dwGBitMask == 0xff00) && + (ddpf.dwBBitMask == 0xff)) { + // Optimize for the most common case + if (ddpf.noAlpha) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + *dst++ = b3; + *dst++ = b2; + *dst++ = b1; + *src++; + *dst++ = (byte) 0xff; + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + *dst++ = b3; + *dst++ = b2; + *dst++ = b1; + *dst++ = *src++; + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } + } else { // handle less common format + int rshift = firstBit(ddpf.dwRBitMask) + + ucountBits(ddpf.dwRBitMask) - 8; + int gshift = firstBit(ddpf.dwGBitMask) + + ucountBits(ddpf.dwGBitMask) - 8; + int bshift = firstBit(ddpf.dwBBitMask) + + ucountBits(ddpf.dwBBitMask) - 8; + int ashift = firstBit(ddpf.dwRGBAlphaBitMask) + + ucountBits(ddpf.dwRGBAlphaBitMask) - 8; + + if ((ddpf.dwRGBBitCount <= 32) && + (ddpf.dwRGBBitCount > 24)) { + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + b4 = *src++; + mask = ((b4 << 24) | (b3 << 16)| (b2 << 8) | b1); + if (rshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRBitMask) >> + rshift); + } else { + t = (mask & ddpf.dwRBitMask) << -rshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (bshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwBBitMask) >> + bshift); + } else { + t = (mask & ddpf.dwBBitMask) << -bshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + if (ashift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRGBAlphaBitMask) >> + ashift); + } else { + t = (mask & ddpf.dwRGBAlphaBitMask) <<-ashift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if ((ddpf.dwRGBBitCount <= 24) && + (ddpf.dwRGBBitCount > 16)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + mask = ((b3 << 16) | (b2 << 8) | b1); + if (rshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRBitMask) >> + rshift); + } else { + t = (mask & ddpf.dwRBitMask) << -rshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) <<-gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (bshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwBBitMask) >> + bshift); + } else { + t = (mask & ddpf.dwBBitMask) << -bshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + if (ashift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRGBAlphaBitMask) >> + ashift); + } else { + t = (mask & ddpf.dwRGBAlphaBitMask) <<-ashift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if ((ddpf.dwRGBBitCount <= 16) && + (ddpf.dwRGBBitCount > 8)) { + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + mask = ((b2 << 8) | b1); + if (rshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRBitMask) >> + rshift); + } else { + t = (mask & ddpf.dwRBitMask) << -rshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (bshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwBBitMask) >> + bshift); + } else { + t = (mask & ddpf.dwBBitMask) << -bshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + if (ashift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRGBAlphaBitMask) >> + ashift); + } else { + t = (mask & ddpf.dwRGBAlphaBitMask) <<-ashift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if (ddpf.dwRGBBitCount <= 8) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + mask = *src++; + if (rshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRBitMask) >> + rshift); + } else { + t = (mask & ddpf.dwRBitMask) << -rshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (bshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwBBitMask) >> + bshift); + } else { + t = (mask & ddpf.dwBBitMask) << -bshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + if (ashift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRGBAlphaBitMask) >> + ashift); + } else { + t = (mask & ddpf.dwRGBAlphaBitMask) <<-ashift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } + } + } else if (imageFormat == IMAGE_FORMAT_BYTE_LA) { + int gshift = firstBit(ddpf.dwGBitMask) + + ucountBits(ddpf.dwGBitMask) - 8; + int ashift = firstBit(ddpf.dwRGBAlphaBitMask) + + ucountBits(ddpf.dwRGBAlphaBitMask) - 8; + dstPitch = subWidth << 1; + destRow += (subHeight-1)*dstPitch; + + if ((ddpf.dwRGBBitCount == 32) && + (ddpf.dwRBitMask == 0xff0000) && + (ddpf.dwGBitMask == 0xff00) && + (ddpf.dwBBitMask == 0xff)) { + // Optimize for the most common case + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + *dst++ = b2; + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + *src++; + } else { + *dst++ = *src++; + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + + } + } else { // handle less common format + int gshift = firstBit(ddpf.dwGBitMask) + + ucountBits(ddpf.dwGBitMask) - 8; + if ((ddpf.dwRGBBitCount <= 32) && + (ddpf.dwRGBBitCount > 24)) { + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + b4 = *src++; + mask = ((b4 << 24) | (b3 << 16)| (b2 << 8) | b1); + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + if (ashift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRGBAlphaBitMask) >> + ashift); + } else { + t = (mask & ddpf.dwRGBAlphaBitMask) <<-ashift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if ((ddpf.dwRGBBitCount <= 24) && + (ddpf.dwRGBBitCount > 16)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + mask = ((b3 << 16) | (b2 << 8) | b1); + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + if (ashift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRGBAlphaBitMask) >> + ashift); + } else { + t = (mask & ddpf.dwRGBAlphaBitMask) <<-ashift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if ((ddpf.dwRGBBitCount <= 16) && + (ddpf.dwRGBBitCount > 8)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + mask = ((b2 << 8) | b1); + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + if (ashift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRGBAlphaBitMask) >> + ashift); + } else { + t = (mask & ddpf.dwRGBAlphaBitMask) <<-ashift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if (ddpf.dwRGBBitCount <= 8) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + mask = *src++; + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + if (ddpf.noAlpha) { + *dst++ = (byte) 0xff; + } else { + if (ashift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwRGBAlphaBitMask) >> + ashift); + } else { + t = (mask & ddpf.dwRGBAlphaBitMask) <<-ashift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } + } + + } else if (imageFormat == IMAGE_FORMAT_BYTE_GRAY) { + int gshift = firstBit(ddpf.dwGBitMask) + + ucountBits(ddpf.dwGBitMask) - 8; + dstPitch = subWidth; + destRow += (subHeight-1)*dstPitch; + + if ((ddpf.dwRGBBitCount == 32) && + (ddpf.dwRBitMask == 0xff0000) && + (ddpf.dwGBitMask == 0xff00) && + (ddpf.dwBBitMask == 0xff)) { + // Optimize for the most common case + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + *dst++ = b2; + *src++; + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else { // handle less common format + int gshift = firstBit(ddpf.dwGBitMask) + + ucountBits(ddpf.dwGBitMask) - 8; + if ((ddpf.dwRGBBitCount <= 32) && + (ddpf.dwRGBBitCount > 24)) { + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + b4 = *src++; + mask = ((b4 << 24) | (b3 << 16)| (b2 << 8) | b1); + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if ((ddpf.dwRGBBitCount <= 24) && + (ddpf.dwRGBBitCount > 16)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + mask = ((b3 << 16) | (b2 << 8) | b1); + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if ((ddpf.dwRGBBitCount <= 16) && + (ddpf.dwRGBBitCount > 8)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + mask = ((b2 << 8) | b1); + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } else if (ddpf.dwRGBBitCount <= 8) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + mask = *src++; + if (gshift >= 0) { + *dst++ = (byte) ((mask & ddpf.dwGBitMask) >> + gshift); + } else { + t = (mask & ddpf.dwGBitMask) << -gshift; + *dst++ = (t <= 0xff ? (byte) t : 0xff); + } + } + srcRow += lockedRect.Pitch; + destRow -= dstPitch; + } + } + } + + } else { + // IMAGE_FORMAT_USHORT_GRAY + printf("[Java 3D] copyDataFromSurface: Format not support %d\n", imageFormat); + } + + + hr = surf->UnlockRect(); + if (FAILED(hr)) { + printf("Fail to unlock surface: %s\n", DXGetErrorString9(hr)); + return; + } + +} + + +void copyDataToSurfaceABGR(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, a, l; + const DWORD srcPitch = subWidth*4; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Optimize for most common case + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + a = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = a; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + a = (*src++) >> 4; // discard the lower 4 bit + b = (*src++) >> 4; + g = (*src++) >> 4; + r = (*src++) >> 4; + *dst++ = (g << 4) | b; + *dst++ = (a << 4) | r; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + *dst++ = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + + +void copyDataToSurfaceBGR(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, l; + const DWORD srcPitch = subWidth*3; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Optimize for most common case + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = 0xff; + } + srcRow += srcPitch; + destRow += rectPitch; + } + + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b = (*src++) >> 4; + g = (*src++) >> 4; + r = (*src++) >> 4; + *dst++ = (g << 4) | b; + *dst++ = 0xf0 | r; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) |ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + byte m1 = (byte) (ddpf->dwRGBAlphaBitMask & 0xff); + byte m2 = (byte) ((ddpf->dwRGBAlphaBitMask >> 8) & 0xff); + byte m3 = (byte) ((ddpf->dwRGBAlphaBitMask >> 16) & 0xff); + byte m4 = (byte) ((ddpf->dwRGBAlphaBitMask >> 24) & 0xff); + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst++ = m1; + *dst++ = m2; + *dst++ = m3; + *dst++ = m4; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst++ = m1; + *dst++ = m2; + *dst++ = m3; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst++ = m1; + *dst++ = m2; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst++ = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + +/* + * Same as copyDataToSurfaceRGBA() + * but the pixel is written in the destination buffer + * from right to left. This is used for CubeMapping. + */ +void copyDataToSurfaceRGBARev(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, a, l; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + const DWORD srcPitch = subWidth*4; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Most common case + // Note that format of destination is ARGB, which + // in PC format are BGRA, so we can't directly + // copy a row using CopyMemory() + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = *src++; + g = *src++; + b = *src++; + *dst-- = *src++; + *dst-- = r; + *dst-- = g; + *dst-- = b; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = (*src++) >> 4; // discard the lower 4 bit + g = (*src++) >> 4; + b = (*src++) >> 4; + a = (*src++) >> 4; + *dst-- = (a << 4) | r; + *dst-- = (g << 4) | b; + + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) -1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += ((xlimit*3) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += ((xlimit*3) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + *dst-- = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += ((xlimit*3)-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst-- = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + +void copyDataToSurfaceABGRRev(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, a, l; + const DWORD srcPitch = subWidth*4; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Optimize for most common case + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + a = *src++; + b = *src++; + g = *src++; + r = *src++; + *dst-- = a; + *dst-- = r; + *dst-- = g; + *dst-- = b; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + a = (*src++) >> 4; // discard the lower 4 bit + b = (*src++) >> 4; + g = (*src++) >> 4; + r = (*src++) >> 4; + *dst-- = (a << 4) | r; + *dst-- = (g << 4) | b; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = a << ashift; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = a << ashift; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xlimit; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + *dst-- = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst-- = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } + +} + + +void copyDataToSurfaceBGRRev(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, l; + const DWORD srcPitch = subWidth*3; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Optimize for most common case + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b = *src++; + g = *src++; + r = *src++; + *dst-- = 0xff; + *dst-- = r; + *dst-- = g; + *dst-- = b; + } + srcRow += srcPitch; + destRow += rectPitch; + } + + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b = (*src++) >> 4; + g = (*src++) >> 4; + r = (*src++) >> 4; + *dst-- = 0xf0 | r; + *dst-- = (g << 4) | b; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3-1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) |ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + byte m1 = (byte) (ddpf->dwRGBAlphaBitMask & 0xff); + byte m2 = (byte) ((ddpf->dwRGBAlphaBitMask >> 8) & 0xff); + byte m3 = (byte) ((ddpf->dwRGBAlphaBitMask >> 16) & 0xff); + byte m4 = (byte) ((ddpf->dwRGBAlphaBitMask >> 24) & 0xff); + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst-- = m4; + *dst-- = m3; + *dst-- = m2; + *dst-- = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst-- = m3; + *dst-- = m2; + *dst-- = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst-- = m2; + *dst-- = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst-- = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src += 3; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst-- = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + + +void copyDataToSurfaceRGBRev(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, l; + const DWORD srcPitch = subWidth*3; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + destRow += ((xlimit << 2) - 1); + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Most common case + // Note that format of destination is ARGB, which + // in PC format are BGRA, so we can't directly + // copy a row using CopyMemory() + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = *src++; + g = *src++; + b = *src++; + *dst-- = (byte) 0xff; + *dst-- = r; + *dst-- = g; + *dst-- = b; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = (*src++) >> 4; // discard the lower 4 bit + g = (*src++) >> 4; + b = (*src++) >> 4; + *dst-- = 0xf0 | r; + *dst-- = (g << 4) | b; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + byte m1 = (byte) (ddpf->dwRGBAlphaBitMask & 0xff); + byte m2 = (byte) ((ddpf->dwRGBAlphaBitMask >> 8) & 0xff); + byte m3 = (byte) ((ddpf->dwRGBAlphaBitMask >> 16) & 0xff); + byte m4 = (byte) ((ddpf->dwRGBAlphaBitMask >> 24) & 0xff); + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst-- = m4; + *dst-- = m3; + *dst-- = m2; + *dst-- = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3- 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst-- = m3; + *dst-- = m2; + *dst-- = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst-- = m2; + *dst-- = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst-- = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst-- = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + +void copyDataToSurfaceLARev(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD a, r, g, b, l; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + const DWORD srcPitch = subWidth*2; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Most common case + // Note that format of destination is ARGB, which + // in PC format are BGRA, so we can't directly + // copy a row using CopyMemory() + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + *dst-- = *src++; + *dst-- = l; + *dst-- = l; + *dst-- = l; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = (*src++) >> 4; // discard the lower 4 bit + a = (*src++) >> 4; + *dst-- = (a << 4) | l; + *dst-- = (l << 4) | l; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + *dst-- = (byte) ((l << rshift) | (l << gshift) | + (l << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + *dst-- = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst-- = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + +void copyDataToSurfaceGrayRev(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD a, r, g, b, l; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + const DWORD srcPitch = subWidth; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Most common case + // Note that format of destination is ARGB, which + // in PC format are BGRA, so we can't directly + // copy a row using CopyMemory() + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + *dst-- = 0xff; + *dst-- = l; + *dst-- = l; + *dst-- = l; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = (*src++) >> 4; // discard the lower 4 bit + *dst-- = 0xf0 | l; + *dst-- = (l << 4) | l; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | ddpf->dwRGBAlphaBitMask; + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + *dst-- = (byte) ((l << rshift) | (l << gshift) | + (l << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst-- = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + *dst-- = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += ((xlimit << 2) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 24) & 0xff); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xlimit*3 - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 16) & 0xff); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += ((xlimit << 1) - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst-- = (byte) ((mask >> 8) & 0xff); + *dst-- = (byte) (mask & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += (xlimit - 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst-- = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + +/* + * Copy data to Texture memory surface *pRect + * with pitch = rectPitch + * Note that rectPitch >= surface width since + * D3D may allocate extra width in texture memory + * for other purpose or for alignment. Addional + * offset = (xoffset, yoffset) is added to copy + * data in texture memory. + * + * The source image has width = subWidth and + * pointer *data. + * + * + */ +void copyDataToSurfaceRGBA(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, a, l; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + const DWORD srcPitch = subWidth*4; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Most common case + // Note that format of destination is ARGB, which + // in PC format are BGRA, so we can't directly + // copy a row using CopyMemory() + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = *src++; + g = *src++; + b = *src++; + *dst++ = b; + *dst++ = g; + *dst++ = r; + *dst++ = *src++; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = (*src++) >> 4; // discard the lower 4 bit + g = (*src++) >> 4; + b = (*src++) >> 4; + a = (*src++) >> 4; + *dst++ = (g << 4) | b; + *dst++ = (a << 4) | r; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + *dst++ = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + + +void copyDataToSurfaceRGB(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, l; + const DWORD srcPitch = subWidth*3; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + destRow += (xoffset << 2); + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Most common case + // Note that format of destination is ARGB, which + // in PC format are BGRA, so we can't directly + // copy a row using CopyMemory() + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = *src++; + g = *src++; + b = *src++; + *dst++ = b; + *dst++ = g; + *dst++ = r; + *dst++ = (byte) 0xff; + + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = (*src++) >> 4; // discard the lower 4 bit + g = (*src++) >> 4; + b = (*src++) >> 4; + *dst++ = (g << 4) | b; + *dst++ = 0xf0 | r; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + byte m1 = (byte) (ddpf->dwRGBAlphaBitMask & 0xff); + byte m2 = (byte) ((ddpf->dwRGBAlphaBitMask >> 8) & 0xff); + byte m3 = (byte) ((ddpf->dwRGBAlphaBitMask >> 16) & 0xff); + byte m4 = (byte) ((ddpf->dwRGBAlphaBitMask >> 24) & 0xff); + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst++ = m1; + *dst++ = m2; + *dst++ = m3; + *dst++ = m4; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst++ = m1; + *dst++ = m2; + *dst++ = m3; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst++ = m1; + *dst++ = m2; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 3; + *dst++ = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + src++; + src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + + +void copyDataToSurfaceLA(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD a, r, g, b, l; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + const DWORD srcPitch = subWidth*2; + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Most common case + // Note that format of destination is ARGB, which + // in PC format are BGRA, so we can't directly + // copy a row using CopyMemory() + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + *dst++ = l; + *dst++ = l; + *dst++ = l; + *dst++ = *src++; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = (*src++) >> 4; // discard the lower 4 bit + a = (*src++) >> 4; + *dst++ = (l << 4) | l; + *dst++ = (a << 4) | l; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + *dst++ = (byte) ((l << rshift) | (l << gshift) | + (l << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + *dst++ = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + +void copyDataToSurfaceGray(jint internalFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD a, r, g, b, l; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + const DWORD srcPitch = subWidth; + + + if ((internalFormat == J3D_RGBA) || + (internalFormat == J3D_RGB)) { + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Most common case + // Note that format of destination is ARGB, which + // in PC format are BGRA, so we can't directly + // copy a row using CopyMemory() + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + *dst++ = l; + *dst++ = l; + *dst++ = l; + *dst++ = 0xff; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = (*src++) >> 4; // discard the lower 4 bit + *dst++ = (l << 4) | l; + *dst++ = 0xf0 | l; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + mask = (l << rshift) | (l << gshift) | + (l << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + l = (*src++) >> rDiscard; + } else { + l = (*src++) << -rDiscard; + } + *dst++ = (byte) ((l << rshift) | (l << gshift) | + (l << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (internalFormat == LUMINANCE_ALPHA) { + + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (internalFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + *dst++ = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((internalFormat == LUMINANCE) || + (internalFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", internalFormat); + } +} + + +/**************** NEW (1.5.0 stuff) ****************/ +/* Note this method only works on little endian architecture */ +void copyInt_ARGB_DataToSurface(jint textureFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, a, l; + const DWORD srcPitch = subWidth*4; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + if ((textureFormat == J3D_RGBA) || + (textureFormat == J3D_RGB)) { + /* printf("copyInt_ARGB_DataToSurface : RGBBitCount = %d \n", + ddpf->dwRGBBitCount); */ + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Optimize for most common case + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + *dst++ = *src++; /* b */ + *dst++ = *src++; /* g */ + *dst++ = *src++; /* r */ + *dst++ = *src++; /* a */ + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b = (*src++) >> 4; // discard the lower 4 bit + g = (*src++) >> 4; + r = (*src++) >> 4; + a = (*src++) >> 4; + *dst++ = (g << 4) | b; + *dst++ = (a << 4) | r; + } + srcRow += srcPitch; + destRow += rectPitch; + } + + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) >> -aDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) |(a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (textureFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) |(a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (textureFormat == ALPHA) { + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = a << ashift; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + mask = (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (aDiscard >= 0) { + a = (*src++) >> aDiscard; + } else { + a = (*src++) << -aDiscard; + } + src += 3; + *dst++ = (byte) (a << ashift); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((textureFormat == LUMINANCE) || + (textureFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int aDiscard = 8-ucountBits(ddpf->dwRGBAlphaBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + int ashift = firstBit(ddpf->dwRGBAlphaBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | (a << ashift); + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + if (aDiscard >= 0) { + a = l >> aDiscard; + } else { + a = l << -aDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + (a << ashift)); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", textureFormat); + } +} + +/* Note this method only works on little endian architecture */ +void copyInt_XRGB_DataToSurface(jint textureFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, a, l; + const DWORD srcPitch = subWidth*4; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + if ((textureFormat == J3D_RGBA) || + (textureFormat == J3D_RGB)) { + /* printf("copyInt_XRGB_DataToSurface : RGBBitCount = %d \n", + ddpf->dwRGBBitCount); */ + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Optimize for most common case + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + *dst++ = *src++; /* b */ + *dst++ = *src++; /* g */ + *dst++ = *src++; /* r */ + *dst++ = 0xff; *src++; /* a */ + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b = (*src++) >> 4; // discard the lower 4 bit + g = (*src++) >> 4; + r = (*src++) >> 4; + *src++; /* a */ + *dst++ = (g << 4) | b; + *dst++ = 0xf0 | r; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + *src++; /* a */ + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (textureFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src++; + src++; + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *src++; /* a */ + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) |ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (textureFormat == ALPHA) { + byte m1 = (byte) (ddpf->dwRGBAlphaBitMask & 0xff); + byte m2 = (byte) ((ddpf->dwRGBAlphaBitMask >> 8) & 0xff); + byte m3 = (byte) ((ddpf->dwRGBAlphaBitMask >> 16) & 0xff); + byte m4 = (byte) ((ddpf->dwRGBAlphaBitMask >> 24) & 0xff); + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 4; + *dst++ = m1; + *dst++ = m2; + *dst++ = m3; + *dst++ = m4; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 4; + *dst++ = m1; + *dst++ = m2; + *dst++ = m3; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 4; + *dst++ = m1; + *dst++ = m2; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 4; + *dst++ = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((textureFormat == LUMINANCE) || + (textureFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", textureFormat); + } +} + +/* Note this method only works on little endian architecture */ +void copyInt_XBGR_DataToSurface(jint textureFormat, + PIXELFORMAT *ddpf, + unsigned char* pRect, + DWORD rectPitch, + jbyte *data, + jint xoffset, jint yoffset, + DWORD xlimit, DWORD ylimit, + jint subWidth) +{ + unsigned char *src; + unsigned char *dst; + DWORD r, g, b, a, l; + const DWORD srcPitch = subWidth*4; + unsigned char *srcRow = (unsigned char *) data; + unsigned char *destRow = pRect + rectPitch*yoffset; + + if ((textureFormat == J3D_RGBA) || + (textureFormat == J3D_RGB)) { + /* printf("copyInt_XRGB_DataToSurface : RGBBitCount = %d \n", + ddpf->dwRGBBitCount); */ + if ((ddpf->dwRGBBitCount == 32) && + (ddpf->dwRBitMask == 0xff0000) && + (ddpf->dwGBitMask == 0xff00) && + (ddpf->dwBBitMask == 0xff)) { + // Optimize for most common case + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = *src++; + g = *src++; + b = *src++; + *dst++ = b; /* b */ + *dst++ = g; /* g */ + *dst++ = r; /* r */ + *dst++ = 0xff; *src++; /* a */ + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount == 16) && + (ddpf->dwRBitMask == 0xf00) && + (ddpf->dwGBitMask == 0xf0) && + (ddpf->dwBBitMask == 0xf)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + r = (*src++) >> 4; // discard the lower 4 bit + g = (*src++) >> 4; + b = (*src++) >> 4; + *src++; /* a */ + *dst++ = (g << 4) | b; + *dst++ = 0xf0 | r; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { // handle less common (even weird) format + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + *src++; /* a */ + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + if (rDiscard >= 0) { + r = (*src++) >> rDiscard; + } else { + r = (*src++) << -rDiscard; + } + if (gDiscard >= 0) { + g = (*src++) >> gDiscard; + } else { + g = (*src++) >> -gDiscard; + } + if (bDiscard >= 0) { + b = (*src++) >> bDiscard; + } else { + b = (*src++) >> -bDiscard; + } + *src++; /* a */ + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + // should not happen, RGBBitCount > 32. Even DirectX + // RGB mask can't address it. + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } + } else if (textureFormat == LUMINANCE_ALPHA) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + src += 3; + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + src += 3; + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + src += 3; + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src++; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + src += 3; + *dst++ = (byte) ((r << rshift) | (g << gshift) | + (b << bshift) |ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if (textureFormat == ALPHA) { + byte m1 = (byte) (ddpf->dwRGBAlphaBitMask & 0xff); + byte m2 = (byte) ((ddpf->dwRGBAlphaBitMask >> 8) & 0xff); + byte m3 = (byte) ((ddpf->dwRGBAlphaBitMask >> 16) & 0xff); + byte m4 = (byte) ((ddpf->dwRGBAlphaBitMask >> 24) & 0xff); + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 4; + *dst++ = m1; + *dst++ = m2; + *dst++ = m3; + *dst++ = m4; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 4; + *dst++ = m1; + *dst++ = m2; + *dst++ = m3; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 4; + *dst++ = m1; + *dst++ = m2; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + src += 4; + *dst++ = m1; + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else if ((textureFormat == LUMINANCE) || + (textureFormat == INTENSITY)) { + int rDiscard = 8-ucountBits(ddpf->dwRBitMask); + int gDiscard = 8-ucountBits(ddpf->dwGBitMask); + int bDiscard = 8-ucountBits(ddpf->dwBBitMask); + int rshift = firstBit(ddpf->dwRBitMask); + int gshift = firstBit(ddpf->dwGBitMask); + int bshift = firstBit(ddpf->dwBBitMask); + DWORD mask; + + if ((ddpf->dwRGBBitCount <= 32) && + (ddpf->dwRGBBitCount > 24)) { + destRow += (xoffset << 2); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 24) && + (ddpf->dwRGBBitCount > 16)) { + destRow += (xoffset*3); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if ((ddpf->dwRGBBitCount <= 16) && + (ddpf->dwRGBBitCount > 8)) { + destRow += (xoffset << 1); + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + mask = (r << rshift) | (g << gshift) | + (b << bshift) | ddpf->dwRGBAlphaBitMask; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else if (ddpf->dwRGBBitCount <= 8) { + destRow += xoffset; + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + l = *src; + src += 4; + if (rDiscard >= 0) { + r = l >> rDiscard; + } else { + r = l << -rDiscard; + } + if (gDiscard >= 0) { + g = l >> gDiscard; + } else { + g = l << -gDiscard; + } + if (bDiscard >= 0) { + b = l >> bDiscard; + } else { + b = l << -bDiscard; + } + *dst++ = (byte) ((r << rshift) | + (g << gshift) | + (b << bshift) | + ddpf->dwRGBAlphaBitMask); + } + srcRow += srcPitch; + destRow += rectPitch; + } + } else { + printf("Texture memory with RGBBitCount = %d not support. \n", + ddpf->dwRGBBitCount); + } + } else { + printf("Texture format %d not support.\n", textureFormat); + } +} + +/* + * Copy data from memory to DirectDraw surface + * + * Source image with WIDTH = tilew, the subimage with + * dimension (subWidth, subHeight) is copy with + * offset = (imgXOffset, imgYOffset) from the start + * pointer *data. + * + * Destination frame buffer is copy with + * offset = (xoffset, yoffset) + * + */ +void copyDataToSurface(jint imageFormat, + jint textureFormat, + jint xoffset, jint yoffset, + jint imgXOffset, jint imgYOffset, + jint subWidth, jint subHeight, + jint tilew, jbyte *data, + LPDIRECT3DTEXTURE9 surf, + jint level) +{ + D3DSURFACE_DESC ddsd; + D3DLOCKED_RECT lockedRect; + PIXELFORMAT ddpf; + HRESULT hr; + + if (surf == NULL) { + return; + } + surf->GetLevelDesc(level, &ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computePixelFormat(&ddpf, ddsd.Format); + + // It is possible when texture is not a power of 2 or + // square only texture is required in hardware. In these + // case the hardware memory buffer may smaller than the + // texture pass in. + + if ((xoffset >= width) || (yoffset >= height)) { + return; + } + + DWORD xlimit = min(xoffset + subWidth, width); + DWORD ylimit = min(yoffset + subHeight, height); + + hr = surf->LockRect(level, &lockedRect, NULL, 0); + + + if (FAILED(hr)) { + printf("Fail to lock surface: %s\n", DXGetErrorString9(hr)); + return; + } + int offset = tilew*imgYOffset + imgXOffset; + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_RGBA : + /* printf("[IMAGE_FORMAT_BYTE_RGBA] imageFormat %d, textureFormat %d\n", + imageFormat, textureFormat); */ + + // This is the one we use when byReference = false + copyDataToSurfaceRGBA(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + break; + case IMAGE_FORMAT_BYTE_RGB: + /* printf("[IMAGE_FORMAT_BYTE_RGB] imageFormat %d, textureFormat %d\n", + imageFormat, textureFormat); */ + copyDataToSurfaceRGB(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + 3*offset, + xoffset, yoffset, + xlimit, ylimit, tilew); + break; + case IMAGE_FORMAT_BYTE_ABGR: + /* printf("[IMAGE_FORMAT_BYTE_ABGR] imageFormat %d, textureFormat %d\n", + imageFormat, textureFormat); */ + + copyDataToSurfaceABGR(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + break; + case IMAGE_FORMAT_BYTE_BGR: + /* printf("[IMAGE_FORMAT_BYTE_BGR] imageFormat %d, textureFormat %d\n", + imageFormat, textureFormat); */ + + copyDataToSurfaceBGR(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + 3*offset, + xoffset, yoffset, + xlimit, ylimit, tilew); + break; + case IMAGE_FORMAT_BYTE_LA: + copyDataToSurfaceLA(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 1), + xoffset, yoffset, + xlimit, ylimit, tilew); + break; + case IMAGE_FORMAT_BYTE_GRAY: + copyDataToSurfaceGray(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + offset, + xoffset, yoffset, + xlimit, ylimit, tilew); + break; + case IMAGE_FORMAT_INT_BGR: + /* printf("[IMAGE_FORMAT_INT_BGR] imageFormat %d, textureFormat %d not support !\n", + imageFormat, textureFormat); */ + copyInt_XBGR_DataToSurface(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + + break; + case IMAGE_FORMAT_INT_RGB: + /* printf("[IMAGE_FORMAT_INT_RGB] imageFormat %d, textureFormat %d\n", + imageFormat, textureFormat); */ + copyInt_XRGB_DataToSurface(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + break; + case IMAGE_FORMAT_INT_ARGB: + /* printf("[IMAGE_FORMAT_INT_ABGR] imageFormat %d, textureFormat %d\n", + imageFormat, textureFormat); */ + copyInt_ARGB_DataToSurface(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + break; + default: // should not happen + printf("[Java 3D] imageFormat %d, textureFormat %d not support !\n", + imageFormat, textureFormat); + } + + hr = surf->UnlockRect(level); + if (FAILED(hr)) { + printf("Fail to unlock surface: %s\n", DXGetErrorString9(hr)); + return; + } +} + +// copy data from DirectDraw depth surface to memory +// and reverse the Y axis +void copyDepthFromSurface(jint xoffset, jint yoffset, + jint subWidth, jint subHeight, + jint *data, + LPDIRECT3DSURFACE9 surf) +{ + D3DSURFACE_DESC ddsd; + DEPTHPIXELFORMAT ddpf; + D3DLOCKED_RECT lockedRect; + HRESULT hr; + + if (surf == NULL) { + return; + } + surf->GetDesc(&ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computeDepthPixelFormat(&ddpf, ddsd.Format); + + if ((xoffset >= width) || (yoffset >= height)) { + return; + } + + DWORD xlimit = min(xoffset + subWidth, width); + DWORD ylimit = min(yoffset + subHeight, height); + + hr = surf->LockRect(&lockedRect, NULL, D3DLOCK_READONLY); + + if (FAILED(hr)) { + if (debug) { + printf("Fail to lock depth surface: %s\n", DXGetErrorString9(hr)); + } + return; + } + + DWORD b1, b2, b3, b4; + DWORD mask; + jint *destRow = data; + jint *dst; + unsigned char *src; + unsigned char *srcRow = ((unsigned char *) lockedRect.pBits) + + xoffset*((int) ceil((float) ddpf.dwZBufferBitDepth/8.0)) + + (yoffset*lockedRect.Pitch); + + int zshift = firstBit(ddpf.dwZBitMask); + + destRow += (subHeight-1)*subWidth; + + if ((ddpf.dwZBufferBitDepth <= 32) && + (ddpf.dwZBufferBitDepth > 24)) { + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + b4 = *src++; + mask = (b4 << 24) | (b3 << 16) | + (b2 << 8) | b1; + *dst++ = (mask & ddpf.dwZBitMask) >> zshift; + } + srcRow += lockedRect.Pitch; + destRow -= subWidth; + } + } else if ((ddpf.dwZBufferBitDepth <= 24) && + (ddpf.dwZBufferBitDepth > 16)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + mask = (b3 << 16) | (b2 << 8) | b1; + *dst++ = (mask & ddpf.dwZBitMask) >> zshift; + } + srcRow += lockedRect.Pitch; + destRow -= subWidth; + } + } else if ((ddpf.dwZBufferBitDepth <= 16) && + (ddpf.dwZBufferBitDepth > 8)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + mask = (b2 << 8) | b1; + *dst++ = (mask & ddpf.dwZBitMask) >> zshift; + } + srcRow += lockedRect.Pitch; + destRow -= subWidth; + } + } else if (ddpf.dwZBufferBitDepth <= 8) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + *dst++ = (*src++ & ddpf.dwZBitMask) >> zshift; + } + srcRow += lockedRect.Pitch; + destRow -= subWidth; + } + } else { + // This is not support by D3D 8 either + printf("[Java 3D] %d bit Z buffer not support !\n", + ddpf.dwZBufferBitDepth); + } + + hr = surf->UnlockRect(); + if (FAILED(hr)) { + printf("Fail to unlock depth surface: %s\n", DXGetErrorString9(hr)); + return; + } +} + + +// copy data from DirectDraw depth surface to memory +// and reverse the Y axis +void copyDepthFromSurface(jint xoffset, jint yoffset, + jint subWidth, jint subHeight, + jfloat *data, + LPDIRECT3DSURFACE9 surf) +{ + D3DSURFACE_DESC ddsd; + DEPTHPIXELFORMAT ddpf; + D3DLOCKED_RECT lockedRect; + HRESULT hr; + + if (surf == NULL) { + return; + } + + surf->GetDesc(&ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computeDepthPixelFormat(&ddpf, ddsd.Format); + + if ((xoffset >= width) || (yoffset >= height)) { + return; + } + + DWORD xlimit = min(xoffset + subWidth, width); + DWORD ylimit = min(yoffset + subHeight, height); + + hr = surf->LockRect(&lockedRect, NULL, D3DLOCK_READONLY); + + if (FAILED(hr)) { + if (debug) { + printf("Fail to lock depth surface: %s\n", DXGetErrorString9(hr)); + } + return; + } + + DWORD b1, b2, b3, b4; + DWORD mask; + jfloat *destRow = data; + jfloat *dst; + unsigned char *src; + unsigned char *srcRow = ((unsigned char *) lockedRect.pBits) + + xoffset*((int) ceil((float) ddpf.dwZBufferBitDepth/8.0)) + + (yoffset*lockedRect.Pitch); + + int zshift = firstBit(ddpf.dwZBitMask); + float maxdepth = float( 1 << ddpf.dwZBufferBitDepth); + + destRow += (subHeight-1)*subWidth; + + if ((ddpf.dwZBufferBitDepth <= 32) && + (ddpf.dwZBufferBitDepth > 24)) { + + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + b4 = *src++; + mask = (b4 << 24) | (b3 << 16) | + (b2 << 8) | b1; + *dst++ = (((mask & ddpf.dwZBitMask) >> + zshift))/ maxdepth; + } + srcRow += lockedRect.Pitch; + destRow -= subWidth; + } + } else if ((ddpf.dwZBufferBitDepth <= 24) && + (ddpf.dwZBufferBitDepth > 16)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + b3 = *src++; + mask = (b3 << 16) | (b2 << 8) | b1; + *dst++ = ((mask & ddpf.dwZBitMask) >> + zshift)/ maxdepth; + } + srcRow += lockedRect.Pitch; + destRow -= subWidth; + } + } else if ((ddpf.dwZBufferBitDepth <= 16) && + (ddpf.dwZBufferBitDepth > 8)) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + b1 = *src++; + b2 = *src++; + mask = (b2 << 8) | b1; + *dst++ = ((mask & ddpf.dwZBitMask) >> + zshift)/ maxdepth; + } + srcRow += lockedRect.Pitch; + destRow -= subWidth; + } + } else if (ddpf.dwZBufferBitDepth <= 8) { + for (int i=yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=xoffset; j < xlimit; j++) { + *dst++ = ((*src++ & ddpf.dwZBitMask) >> + zshift)/ maxdepth; + } + srcRow += lockedRect.Pitch; + destRow -= subWidth; + } + } else { + // This is not support by D3D 8 either + printf("[Java 3D] %d bit Z buffer not support !\n", + ddpf.dwZBufferBitDepth); + } + + hr = surf->UnlockRect(); + if (FAILED(hr)) { + printf("Fail to unlock depth surface: %s\n", DXGetErrorString9(hr)); + return; + } +} + + +// copy data to DirectDraw depth surface from memory +// and reverse the Y axis +void copyDepthToSurfaceAlways(jint dst_xoffset, jint dst_yoffset, + jint src_xoffset, jint src_yoffset, + jint subWidth, jint subHeight, + jint src_width, jint src_height, + jint *data, + LPDIRECT3DSURFACE9 surf) +{ + D3DSURFACE_DESC ddsd; + DEPTHPIXELFORMAT ddpf; + D3DLOCKED_RECT lockedRect; + HRESULT hr; + + if (surf == NULL) { + return; + } + + surf->GetDesc(&ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computeDepthPixelFormat(&ddpf, ddsd.Format); + + if ((dst_xoffset >= width) || (dst_yoffset >= height)) { + return; + } + + DWORD xlimit = min(dst_xoffset + subWidth, width); + DWORD ylimit = min(dst_yoffset + subHeight, height); + + hr = surf->LockRect(&lockedRect, NULL, 0); + + if (FAILED(hr)) { + if (debug) { + printf("Fail to lock depth surface: %s\n", DXGetErrorString9(hr)); + } + return; + } + jint *src; + jint *srcRow = data + src_xoffset + + (src_yoffset + subHeight-1)*src_width; + unsigned char *dst; + unsigned char *destRow = ((unsigned char *) lockedRect.pBits) + + dst_xoffset + dst_yoffset*lockedRect.Pitch; + + int zshift = firstBit(ddpf.dwZBitMask); + DWORD mask; + int maxValue = ddpf.dwZBitMask >> zshift; + + + if ((ddpf.dwZBufferBitDepth <= 32) && + (ddpf.dwZBufferBitDepth > 24)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + mask = *src++; + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if ((ddpf.dwZBufferBitDepth <= 24) && + (ddpf.dwZBufferBitDepth > 16)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + mask = *src++; + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if ((ddpf.dwZBufferBitDepth <= 16) && + (ddpf.dwZBufferBitDepth > 8)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + mask = *src++; + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if (ddpf.dwZBufferBitDepth <= 8) { + byte bmask = (byte) (ddpf.dwZBitMask & 0xff); + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + mask = *src++; + if (mask < maxValue) { + *dst++ = (byte) ((mask << zshift) & 0xff); + } else { + *dst++ = bmask; + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + + } + + hr = surf->UnlockRect(); + if (FAILED(hr)) { + printf("Fail to unlock depth surface: %s\n", DXGetErrorString9(hr)); + return; + } + +} + + +// copy data to DirectDraw depth surface from memory +// and reverse the Y axis +void copyDepthToSurfaceAlways(jint dst_xoffset, jint dst_yoffset, + jint src_xoffset, jint src_yoffset, + jint subWidth, jint subHeight, + jint src_width, jint src_height, + jfloat *data, + LPDIRECT3DSURFACE9 surf) +{ + D3DSURFACE_DESC ddsd; + DEPTHPIXELFORMAT ddpf; + D3DLOCKED_RECT lockedRect; + HRESULT hr; + + if (surf == NULL) { + return; + } + + surf->GetDesc(&ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computeDepthPixelFormat(&ddpf, ddsd.Format); + + + if ((dst_xoffset >= width) || (dst_yoffset >= height)) { + return; + } + + DWORD xlimit = min(dst_xoffset + subWidth, width); + DWORD ylimit = min(dst_yoffset + subHeight, height); + + hr = surf->LockRect(&lockedRect, NULL, 9); + + if (FAILED(hr)) { + if (debug) { + printf("Fail to lock depth surface: %s\n", DXGetErrorString9(hr)); + } + return; + } + jfloat *src; + jfloat *srcRow = data + src_xoffset + + (src_yoffset + subHeight-1)*src_width; + unsigned char *dst; + unsigned char *destRow = ((unsigned char *) lockedRect.pBits) + + dst_xoffset + dst_yoffset*lockedRect.Pitch; + + int zshift = firstBit(ddpf.dwZBitMask); + DWORD mask; + int maxValue = ddpf.dwZBitMask >> zshift; + float maxdepth = float( 1 << ddpf.dwZBufferBitDepth); + + if ((ddpf.dwZBufferBitDepth <= 32) && + (ddpf.dwZBufferBitDepth > 24)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + mask = DWORD((*src++)*maxdepth); + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if ((ddpf.dwZBufferBitDepth <= 24) && + (ddpf.dwZBufferBitDepth > 16)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + mask = DWORD((*src++)*maxdepth); + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if ((ddpf.dwZBufferBitDepth <= 16) && + (ddpf.dwZBufferBitDepth > 8)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + mask = DWORD((*src++)*maxdepth); + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if (ddpf.dwZBufferBitDepth <= 8) { + byte bmask = (byte) (ddpf.dwZBitMask & 0xff); + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + mask = DWORD((*src++)*maxdepth); + if (mask < maxValue) { + *dst++ = (byte) ((mask << zshift) & 0xff); + } else { + *dst++ = bmask; + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + + } + + hr = surf->UnlockRect(); + if (FAILED(hr)) { + printf("Fail to unlock depth surface: %s\n", DXGetErrorString9(hr)); + return; + } + +} + +// copy data to DirectDraw depth surface from memory +// and reverse the Y axis with Z test D3DCMP_LESS +void copyDepthToSurfaceCmp(jint dst_xoffset, jint dst_yoffset, + jint src_xoffset, jint src_yoffset, + jint subWidth, jint subHeight, + jint src_width, jint src_height, + jint *data, + LPDIRECT3DSURFACE9 surf) +{ + D3DSURFACE_DESC ddsd; + DEPTHPIXELFORMAT ddpf; + D3DLOCKED_RECT lockedRect; + HRESULT hr; + + if (surf == NULL) { + return; + } + + surf->GetDesc(&ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computeDepthPixelFormat(&ddpf, ddsd.Format); + + + if ((dst_xoffset >= width) || (dst_yoffset >= height)) { + return; + } + + DWORD xlimit = min(dst_xoffset + subWidth, width); + DWORD ylimit = min(dst_yoffset + subHeight, height); + + hr = surf->LockRect(&lockedRect, NULL, 0); + + if (FAILED(hr)) { + if (debug) { + printf("Fail to lock depth surface: %s\n", DXGetErrorString9(hr)); + } + return; + } + + jint *src; + jint *srcRow = data + src_xoffset + + (src_yoffset + subHeight-1)*src_width; + unsigned char *dst; + unsigned char *destRow = ((unsigned char *) lockedRect.pBits) + + dst_xoffset + dst_yoffset*lockedRect.Pitch; + + + int zshift = firstBit(ddpf.dwZBitMask); + DWORD mask; + DWORD b1, b2, b3, b4; + DWORD zmask; + int maxValue = ddpf.dwZBitMask >> zshift; + + + if ((ddpf.dwZBufferBitDepth <= 32) && + (ddpf.dwZBufferBitDepth > 24)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + b1 = *dst++; + b2 = *dst++; + b3 = *dst++; + b4 = *dst++; + zmask = (b4 << 24) | (b3 << 16) | + (b2 << 8) | b1; + zmask = (zmask & ddpf.dwZBitMask) >> zshift; + mask = *src++; + if (mask < zmask) { + // z depth test pass + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + dst -= 4; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if ((ddpf.dwZBufferBitDepth <= 24) && + (ddpf.dwZBufferBitDepth > 16)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + b1 = *dst++; + b2 = *dst++; + b3 = *dst++; + zmask = (b3 << 16) | (b2 << 8) | b1; + zmask = (zmask & ddpf.dwZBitMask) >> zshift; + mask = *src++; + if (mask < zmask) { + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + dst -= 3; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if ((ddpf.dwZBufferBitDepth <= 16) && + (ddpf.dwZBufferBitDepth > 8)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + b1 = *dst++; + b2 = *dst++; + zmask = (b2 << 8) | b1; + zmask = (zmask & ddpf.dwZBitMask) >> zshift; + mask = *src++; + if (mask < zmask) { + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + dst -= 2; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if (ddpf.dwZBufferBitDepth <= 8) { + byte bmask = (byte) (ddpf.dwZBitMask & 0xff); + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + zmask = (*dst++ & ddpf.dwZBitMask) >> zshift; + mask = *src++; + if (mask < zmask) { + dst--; + if (mask < maxValue) { + *dst++ = (byte) ((mask << zshift) & 0xff); + } else { + *dst++ = bmask; + } + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + + } + + hr = surf->UnlockRect(); + if (FAILED(hr)) { + printf("Fail to unlock depth surface: %s\n", DXGetErrorString9(hr)); + return; + } + +} + + +// copy data to DirectDraw depth surface from memory +// and reverse the Y axis with Z test D3DCMP_LESS +void copyDepthToSurfaceCmp(jint dst_xoffset, jint dst_yoffset, + jint src_xoffset, jint src_yoffset, + jint subWidth, jint subHeight, + jint src_width, jint src_height, + jfloat *data, + LPDIRECT3DSURFACE9 surf) +{ + D3DSURFACE_DESC ddsd; + DEPTHPIXELFORMAT ddpf; + D3DLOCKED_RECT lockedRect; + HRESULT hr; + + if (surf == NULL) { + return; + } + + surf->GetDesc(&ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computeDepthPixelFormat(&ddpf, ddsd.Format); + + + if ((dst_xoffset >= width) || (dst_yoffset >= height)) { + return; + } + + DWORD xlimit = min(dst_xoffset + subWidth, width); + DWORD ylimit = min(dst_yoffset + subHeight, height); + + hr = surf->LockRect(&lockedRect, NULL, 0); + + if (FAILED(hr)) { + if (debug) { + printf("Fail to lock depth surface: %s\n", DXGetErrorString9(hr)); + } + return; + } + jfloat *src; + jfloat *srcRow = data + src_xoffset + + (src_yoffset + subHeight-1)*src_width; + unsigned char *dst; + unsigned char *destRow = ((unsigned char *) lockedRect.pBits) + + dst_xoffset + dst_yoffset*lockedRect.Pitch; + + int zshift = firstBit(ddpf.dwZBitMask); + DWORD mask; + DWORD b1, b2, b3, b4; + DWORD zmask; + int maxValue = ddpf.dwZBitMask >> zshift; + float maxdepth = float(1 << ddpf.dwZBufferBitDepth); + + if ((ddpf.dwZBufferBitDepth <= 32) && + (ddpf.dwZBufferBitDepth > 24)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + b1 = *dst++; + b2 = *dst++; + b3 = *dst++; + b4 = *dst++; + zmask = (b4 << 24) | (b3 << 16) | + (b2 << 8) | b1; + zmask = (zmask & ddpf.dwZBitMask) >> zshift; + mask = DWORD((*src++)*maxdepth); + if (mask < zmask) { + // z depth test pass + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + dst -= 4; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + *dst++ = (byte) ((mask >> 24) & 0xff); + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if ((ddpf.dwZBufferBitDepth <= 24) && + (ddpf.dwZBufferBitDepth > 16)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + b1 = *dst++; + b2 = *dst++; + b3 = *dst++; + zmask = (b3 << 16) | (b2 << 8) | b1; + zmask = (zmask & ddpf.dwZBitMask) >> zshift; + mask = DWORD((*src++)*maxdepth); + if (mask < zmask) { + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + dst -= 3; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + *dst++ = (byte) ((mask >> 16) & 0xff); + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if ((ddpf.dwZBufferBitDepth <= 16) && + (ddpf.dwZBufferBitDepth > 8)) { + + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + b1 = *dst++; + b2 = *dst++; + zmask = (b2 << 8) | b1; + zmask = (zmask & ddpf.dwZBitMask) >> zshift; + mask = DWORD((*src++)*maxdepth); + if (mask < zmask) { + if (mask < maxValue) { + mask = mask << zshift; + } else { + mask = ddpf.dwZBitMask; + } + dst -= 2; + *dst++ = (byte) (mask & 0xff); + *dst++ = (byte) ((mask >> 8) & 0xff); + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + } else if (ddpf.dwZBufferBitDepth <= 8) { + byte bmask = (byte) (ddpf.dwZBitMask & 0xff); + for (int i=dst_yoffset; i < ylimit; i++) { + src = srcRow; + dst = destRow; + for (int j=dst_xoffset; j < xlimit; j++) { + zmask = (*dst++ & ddpf.dwZBitMask) >> zshift; + mask = DWORD((*src++)*maxdepth); + if (mask < zmask) { + dst--; + if (mask < maxValue) { + *dst++ = (byte) ((mask << zshift) & 0xff); + } else { + *dst++ = bmask; + } + } + } + srcRow -= src_width; + destRow += lockedRect.Pitch; + } + + } + + hr = surf->UnlockRect(); + if (FAILED(hr)) { + printf("Fail to unlock depth surface: %s\n", DXGetErrorString9(hr)); + return; + } + +} + +// copy data to DirectDraw depth surface from memory +// and reverse the Y axis +void copyDepthToSurface(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + jint dst_xoffset, jint dst_yoffset, + jint src_xoffset, jint src_yoffset, + jint subWidth, jint subHeight, + jint src_width, jint src_height, + jint *data, + LPDIRECT3DSURFACE9 surf) +{ + + if (!d3dCtx->zWriteEnable) { + return; + } + + if (!d3dCtx->zEnable) { + copyDepthToSurfaceAlways(dst_xoffset, dst_yoffset, + src_xoffset, src_yoffset, + subWidth, subHeight, + src_width, src_height, + data, surf); + } else { + // Currently ZFUNC must be D3DCMP_LESS + copyDepthToSurfaceCmp(dst_xoffset, dst_yoffset, + src_xoffset, src_yoffset, + subWidth, subHeight, + src_width, src_height, + data, surf); + } +} + + +// copy data to DirectDraw depth surface from memory +// and reverse the Y axis +void copyDepthToSurface(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + jint dst_xoffset, jint dst_yoffset, + jint src_xoffset, jint src_yoffset, + jint subWidth, jint subHeight, + jint src_width, jint src_height, + jfloat *data, + LPDIRECT3DSURFACE9 surf) +{ + if (!d3dCtx->zWriteEnable) { + return; + } + + if (!d3dCtx->zEnable) { + copyDepthToSurfaceAlways(dst_xoffset, dst_yoffset, + src_xoffset, src_yoffset, + subWidth, subHeight, + src_width, src_height, + data, surf); + } else { + // Currently ZFUNC must be D3DCMP_LESS + copyDepthToSurfaceCmp(dst_xoffset, dst_yoffset, + src_xoffset, src_yoffset, + subWidth, subHeight, + src_width, src_height, + data, surf); + } +} + +void copyDataToVolume(jint imageFormat, + jint textureFormat, + jint xoffset, jint yoffset, + jint zoffset, + jint imgXOffset, jint imgYOffset, + jint imgZOffset, + jint subWidth, jint subHeight, jint subDepth, + jint tilew, jint tileh, + jbyte* data, + LPDIRECT3DVOLUMETEXTURE9 surf, + jint level) +{ + + D3DVOLUME_DESC ddsd; + D3DLOCKED_BOX lockedBox; + PIXELFORMAT ddpf; + HRESULT hr; + UINT i; + + if (surf == NULL) { + return; + } + surf->GetLevelDesc(level, &ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + DWORD depth = ddsd.Depth; + computePixelFormat(&ddpf, ddsd.Format); + + // It is possible when texture is not a power of 2 or + // square only texture is required in hardware. In these + // case the hardware memory buffer may smaller than the + // texture pass in. + + if ((xoffset >= width) || + (yoffset >= height) || + (zoffset >= depth)) { + return; + } + + DWORD xlimit = min(xoffset + subWidth, width); + DWORD ylimit = min(yoffset + subHeight, height); + DWORD zlimit = min(zoffset + subDepth, depth); + + hr = surf->LockBox(level, &lockedBox, NULL, 0); + + + if (FAILED(hr)) { + printf("Fail to lock volume: %s\n", DXGetErrorString9(hr)); + return; + } + + int imgOffset = tilew*(tileh*imgZOffset + imgYOffset) + imgXOffset; + int srcSlicePitch = tilew*tileh; + unsigned char* p = (unsigned char *) lockedBox.pBits + + zoffset*lockedBox.SlicePitch; + + + + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_RGBA : + // This is the one we use when byReference = false + data += (imgOffset << 2); + srcSlicePitch <<= 2; + + for (i = zoffset; i < zlimit; i++) { + copyDataToSurfaceRGBA(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + + break; + case IMAGE_FORMAT_BYTE_RGB: + data += (imgOffset*3); + srcSlicePitch *= 3; + + for (i = zoffset; i < zlimit; i++) { + copyDataToSurfaceRGB(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + break; + case IMAGE_FORMAT_BYTE_ABGR: + data += (imgOffset << 2); + srcSlicePitch <<= 2; + + for (i = zoffset; i < zlimit; i++) { + copyDataToSurfaceABGR(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + break; + case IMAGE_FORMAT_BYTE_BGR: + data += (imgOffset*3); + srcSlicePitch *= 3; + + for (i = zoffset; i < zlimit; i++) { + copyDataToSurfaceBGR(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + break; + case IMAGE_FORMAT_BYTE_LA: + data += (imgOffset << 1); + srcSlicePitch <<= 1; + + for (i = zoffset; i < zlimit; i++) { + copyDataToSurfaceLA(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + break; + case IMAGE_FORMAT_BYTE_GRAY: + data += imgOffset; + + for (i = zoffset; i < zlimit; i++) { + copyDataToSurfaceGray(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + break; + case IMAGE_FORMAT_INT_BGR: + data += (imgOffset << 2); + srcSlicePitch <<= 2; + + for (i = zoffset; i < zlimit; i++) { + copyInt_XBGR_DataToSurface(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + break; + case IMAGE_FORMAT_INT_RGB: + data += (imgOffset << 2); + srcSlicePitch <<= 2; + + for (i = zoffset; i < zlimit; i++) { + copyInt_XRGB_DataToSurface(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + break; + case IMAGE_FORMAT_INT_ARGB: + data += (imgOffset << 2); + srcSlicePitch <<= 2; + + for (i = zoffset; i < zlimit; i++) { + copyInt_ARGB_DataToSurface(textureFormat, &ddpf, + p, + lockedBox.RowPitch, + data, + xoffset, yoffset, + xlimit, ylimit, + tilew); + p += lockedBox.SlicePitch; + data += srcSlicePitch; + } + break; + default: // should not happen + printf("[Java 3D] StoredFormat %d, textureFormat %d not support !\n", + imageFormat, textureFormat); + } + + hr = surf->UnlockBox(level); + if (FAILED(hr)) { + printf("Fail to unlock volume: %s\n", DXGetErrorString9(hr)); + return; + } +} + +VOID createLineModeIndexBuffer(D3dCtx *d3dCtx) +{ + HRESULT hr; + WORD *wptr; + + hr = d3dCtx->pDevice->CreateIndexBuffer(6*sizeof(WORD), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX16, + D3DPOOL_DEFAULT, + &d3dCtx->lineModeIndexBuffer, + NULL); + if (FAILED(hr)) { + D3dCtx::d3dWarning(CREATEINDEXVBFAIL, hr); + return; + } + + + hr = d3dCtx->lineModeIndexBuffer->Lock(0, 0, (VOID **) &wptr, 0); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKINDEXVBFAIL, hr); + return; + } + + *wptr++ = 0; + *wptr++ = 1; + *wptr++ = 2; + *wptr++ = 3; + *wptr++ = 0; + *wptr = 0; // not used + d3dCtx->lineModeIndexBuffer->Unlock(); +} + +// Return TRUE if index is adjust smaller +BOOL createQuadIndices(D3dCtx *d3dCtx, int vcount) +{ + DWORD dwIndexCount = (vcount*3) >> 1; + WORD *q; + LPDIRECT3DDEVICE9 device = d3dCtx->pDevice; + HRESULT hr; + BOOL adjustIdx = FALSE; + + if (dwIndexCount > d3dCtx->deviceInfo->maxVertexIndex) { + // We'll render the VB multiple times in this case + dwIndexCount = min(d3dCtx->deviceInfo->maxVertexIndex, + (d3dCtx->deviceInfo->maxPrimitiveCount << 1)); + adjustIdx = TRUE; + } + + if (dwIndexCount > d3dCtx->quadIndexBufferSize) { + d3dCtx->freeResource(d3dCtx->quadIndexBuffer); + hr = device->CreateIndexBuffer(dwIndexCount*sizeof(WORD), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX16, + D3DPOOL_MANAGED, + &d3dCtx->quadIndexBuffer, + NULL); + if (FAILED(hr)) { + printf("[Java3D] Error CREATEINDEXVBFAIL \n"); + D3dCtx::d3dWarning(CREATEINDEXVBFAIL, hr); + d3dCtx->quadIndexBufferSize = 0; + d3dCtx->quadIndexBuffer = NULL; + if (d3dCtx->quadIndexBufferSize > 0) { + // indices has successfully set before, we prevent + // setting this when indices did not set before. + // It is becasue there is a bug in Nvidia driver which + // will crash in this case. + device->SetIndices(NULL); + } + return adjustIdx; + } + + d3dCtx->quadIndexBufferSize = dwIndexCount; + hr = d3dCtx->quadIndexBuffer->Lock(0, 0, (VOID **) &q, 0); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKINDEXVBFAIL, hr); + if (d3dCtx->quadIndexBufferSize > 0) { + device->SetIndices(NULL); + } + return adjustIdx; + } + int i = -1; + int j = 0; + + while (j < dwIndexCount) { + q[j++] = ++i; // q[0] = 0 + q[j++] = i+1; // q[1] = 1 + q[j++] = i+2; // q[2] = 2 + q[j++] = i++; // q[3] = 0 + q[j++] = ++i; // q[4] = 2 + q[j++] = ++i; // q[5] = 3 + } + + d3dCtx->quadIndexBuffer->Unlock(); + } + + return adjustIdx; +} + + +int getPrimitiveNum(int primitive, int vcount) +{ + switch (primitive) { + case D3DPT_TRIANGLESTRIP: + return vcount-2; + case D3DPT_TRIANGLEFAN: + return vcount-2; + case D3DPT_LINESTRIP: + return vcount - 1; + case D3DPT_LINELIST: + return vcount >> 1; + case D3DPT_TRIANGLELIST: + return vcount/3; + case D3DPT_POINTLIST: + return vcount; + default: // should not happen + printf("[Java 3D] Unknown primitive type %d\n", primitive); + } + return 0; +} + + +/* + * Note that the condition width == height always holds + * when this function is invoked. + */ +LPDIRECT3DCUBETEXTURE9 createCubeMapTexture(D3dCtx *d3dCtx, + jint numLevels, + jint textureFormat, + jint width, + jint height, + jboolean useAutoMipMap) +{ + LPDIRECT3DCUBETEXTURE9 pTexture; + D3DFORMAT format; + HRESULT hr; + DWORD usage = 0; + + LPDIRECT3DDEVICE9 pDevice = d3dCtx->pDevice; + D3dDeviceInfo *deviceInfo = d3dCtx->deviceInfo; + + if (!deviceInfo->supportMipmap) { + numLevels = 1; + } + + getTexWidthHeight(deviceInfo, &width, &height); + format = getTexFormat(textureFormat); + + if (useAutoMipMap) { + usage |= D3DUSAGE_AUTOGENMIPMAP; + } + + // If format not support, the utility function will adjust the + // calling parameters automatically + hr = D3DXCreateCubeTexture(d3dCtx->pDevice, width, + numLevels, usage, format, D3DPOOL_MANAGED, + &pTexture); + + if (FAILED(hr)) { + if (debug) { + printf("Fail to create cube texture surface %dx%d, format %d, level %d : %s\n", + width, height, format, numLevels, DXGetErrorString9(hr)); + } + return NULL; + } + + return pTexture; +} + +void copyDataToCubeMap(jint imageFormat, + jint textureFormat, + jint xoffset, jint yoffset, + jint imgXOffset, jint imgYOffset, + jint subWidth, jint subHeight, + jint tilew, + jbyte* data, + LPDIRECT3DCUBETEXTURE9 surf, + jint level, + jint face) +{ + D3DSURFACE_DESC ddsd; + D3DLOCKED_RECT lockedRect; + PIXELFORMAT ddpf; + HRESULT hr; + + if (surf == NULL) { + return; + } + surf->GetLevelDesc(level, &ddsd); + DWORD width = ddsd.Width; + DWORD height = ddsd.Height; + computePixelFormat(&ddpf, ddsd.Format); + + // It is possible when texture is not a power of 2 or + // square only texture is required in hardware. In these + // case the hardware memory buffer may smaller than the + // texture pass in. + + if ((xoffset >= width) || (yoffset >= height)) { + return; + } + + DWORD xlimit = min(xoffset + subWidth, width); + DWORD ylimit = min(yoffset + subHeight, height); + + hr = surf->LockRect(textureCubeMapFace[face], + level, &lockedRect, NULL, 0); + + + if (FAILED(hr)) { + printf("Fail to lock surface: %s\n", DXGetErrorString9(hr)); + return; + } + int offset = tilew*imgYOffset + imgXOffset; + + switch (imageFormat) { + case IMAGE_FORMAT_BYTE_RGBA : + // This is the one we use when byReference = false + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + // Copy the pixel from bottom to up and + // left to right in this case to match OGL definition + copyDataToSurfaceRGBA(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + ((offset + tilew*(ylimit-yoffset-1)) << 2), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + // Copy the pixel from up to bottom and + // right to left in this case to match OGL definition + copyDataToSurfaceRGBARev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + } + break; + case IMAGE_FORMAT_BYTE_RGB: + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + copyDataToSurfaceRGB(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + 3*(offset + tilew*(ylimit-yoffset-1)), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + copyDataToSurfaceRGBRev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + 3*offset, + xoffset, yoffset, + xlimit, ylimit, tilew); + } + break; + case IMAGE_FORMAT_BYTE_ABGR: + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + copyDataToSurfaceABGR(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + ((offset+tilew*(ylimit-yoffset-1)) << 2), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + copyDataToSurfaceABGRRev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + } + break; + case IMAGE_FORMAT_BYTE_BGR: + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + copyDataToSurfaceBGR(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + 3*(offset + tilew*(ylimit-yoffset-1)), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + copyDataToSurfaceBGRRev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + 3*offset, + xoffset, yoffset, + xlimit, ylimit, tilew); + } + break; + case IMAGE_FORMAT_BYTE_LA: + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + copyDataToSurfaceLA(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + ((offset+tilew*(ylimit-yoffset-1)) << 1), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + copyDataToSurfaceLARev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 1), + xoffset, yoffset, + xlimit, ylimit, tilew); + } + break; + case IMAGE_FORMAT_BYTE_GRAY: + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + copyDataToSurfaceGray(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + offset + tilew*(ylimit-yoffset-1), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + copyDataToSurfaceGrayRev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + offset, + xoffset, yoffset, + xlimit, ylimit, tilew); + } + break; + case IMAGE_FORMAT_INT_BGR : + printf("[Java 3D] Cubemap doesn't support FORMAT_INT_BGR, \n"); + printf("please see issue 377 : https://java3d.dev.java.net/issues/show_bug.cgi?id=377\n"); + printf("For more information on reporting Java 3D related issue : https://java3d.dev.java.net/#Reporting_Issue \n"); + // This is the one we use when byReference = false + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + // Copy the pixel from bottom to up and + // left to right in this case to match OGL definition + copyInt_XBGR_DataToSurface(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + ((offset + tilew*(ylimit-yoffset-1)) << 2), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + // Copy the pixel from up to bottom and + // right to left in this case to match OGL definition + printf("[copyDataToCubeMap] copyInt_BGR_DataToSurfaceRev is unsupported!\n"); + /* + copyInt_XBGR_DataToSurfaceRev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + */ + } + break; + case IMAGE_FORMAT_INT_RGB : + printf("[Java 3D] Cubemap doesn't support FORMAT_INT_RGB!\n"); + printf("please see issue 377 : https://java3d.dev.java.net/issues/show_bug.cgi?id=377\n"); + printf("For more information on reporting Java 3D related issue : https://java3d.dev.java.net/#Reporting_Issue \n"); + + // This is the one we use when byReference = false + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + // Copy the pixel from bottom to up and + // left to right in this case to match OGL definition + copyInt_XRGB_DataToSurface(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + ((offset + tilew*(ylimit-yoffset-1)) << 2), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + // Copy the pixel from up to bottom and + // right to left in this case to match OGL definition + printf("[copyDataToCubeMap] copyInt_XRGB_DataToSurfaceRev is unsupported!\n"); + + /* + copyInt_XRGB_DataToSurfaceRev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + */ + } + break; + case IMAGE_FORMAT_INT_ARGB : + printf("[Java 3D] Cubemap doesn't support FORMAT_INT_ARGB!\n"); + printf("please see issue 377 : https://java3d.dev.java.net/issues/show_bug.cgi?id=377\n"); + printf("For more information on reporting Java 3D related issue : https://java3d.dev.java.net/#Reporting_Issue \n"); + + // This is the one we use when byReference = false + if ((face == D3DCUBEMAP_FACE_NEGATIVE_Y) || + (face == D3DCUBEMAP_FACE_POSITIVE_Y)) { + // Copy the pixel from bottom to up and + // left to right in this case to match OGL definition + copyInt_ARGB_DataToSurface(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + + ((offset + tilew*(ylimit-yoffset-1)) << 2), + xoffset, yoffset, + xlimit, ylimit, -tilew); + } else { + // Copy the pixel from up to bottom and + // right to left in this case to match OGL definition + printf("[copyDataToCubeMap] copyInt_ARGB_DataToSurfaceRev is unsupported!\n"); + + /* + copyInt_ARGB_DataToSurfaceRev(textureFormat, &ddpf, + (unsigned char *) lockedRect.pBits, + lockedRect.Pitch, + data + (offset << 2), + xoffset, yoffset, + xlimit, ylimit, tilew); + */ + } + break; + default: // should not happen + printf("[Java 3D] imageFormat %d, textureFormat %d not support !\n", + imageFormat, textureFormat); + } + + hr = surf->UnlockRect(textureCubeMapFace[face], level); + if (FAILED(hr)) { + printf("Fail to unlock surface: %s\n", DXGetErrorString9(hr)); + return; + } +} + + +void drawTextureRect(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + LPDIRECT3DTEXTURE9 surf, + D3DTLVERTEX screenCoord, + int startx, int starty, + int endx, int endy, + int scaleWidth, int scaleHeight, + boolean texModeRepeat) +{ + LPDIRECT3DTEXTURE9 texture = NULL; + DWORD transflag, minstate, magstate, texcoordstate; + DWORD wrapU, wrapV; + DWORD colorOp, colorArg, alphaOp, alphaArg; + D3DMATRIX m; + + magstate = 1; + minstate = 1; + + int h = endy - starty; + int w = endx - startx; + + device->SetRenderState(D3DRS_SPECULARENABLE, FALSE); + + device->GetTexture(0, (LPDIRECT3DBASETEXTURE9 *) &texture); + + device->GetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, + &transflag); + if (transflag != D3DTTFF_DISABLE) { + device->GetTransform(D3DTS_TEXTURE0, &m); + } + //alessandro + //device->GetTextureStageState(0, D3DTSS_MINFILTER, &minstate); + //device->GetTextureStageState(0, D3DTSS_MAGFILTER, &magstate); + device->GetTextureStageState(0, D3DTSS_TEXCOORDINDEX, &texcoordstate); + device->SetTexture(0, surf); + device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, + D3DTTFF_DISABLE); + + if ((w == scaleWidth) && (h == scaleHeight)) { + // alessandro + // device->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_POINT); + // device->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_POINT); + } else { + // device->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR); + // device->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); + } + device->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + device->GetTextureStageState(0, D3DTSS_COLOROP, &colorOp); + device->GetTextureStageState(0, D3DTSS_COLORARG1, &colorArg); + device->GetTextureStageState(0, D3DTSS_ALPHAOP, &alphaOp); + device->GetTextureStageState(0, D3DTSS_ALPHAARG1, &alphaArg); + + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + if (d3dCtx->fillMode != D3DFILL_SOLID) { + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + } + + D3DSURFACE_DESC ddsd; + surf->GetLevelDesc(0, &ddsd); + + + float tumax; + float tvmax; + float tumin = startx/(float) ddsd.Width; + float tvmin = starty/(float) ddsd.Height; + boolean multipleDraw; + + if (texModeRepeat) { + if ((w == ddsd.Width) && (h == ddsd.Height)) { + // width & height match texture, so there is + // no need to draw multiple time + tumax = scaleWidth/(float) ddsd.Width; + tvmax = scaleHeight/(float) ddsd.Height; + device->GetSamplerState (0, D3DSAMP_ADDRESSU, &wrapU); + device->GetSamplerState (0, D3DSAMP_ADDRESSV, &wrapV); + device->SetSamplerState (0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + device->SetSamplerState (0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + multipleDraw = false; + } else { + tumax = endx/(float) ddsd.Width; + tvmax = endy/(float) ddsd.Height; + multipleDraw = true; + } + } else { + tumax = endx/(float) ddsd.Width; + tvmax = endy/(float) ddsd.Height; + multipleDraw = false; + } + + + d3dCtx->rasterRect[0].tu = tumin; + d3dCtx->rasterRect[0].tv = tvmax; + d3dCtx->rasterRect[1].tu = tumin; + d3dCtx->rasterRect[1].tv = tvmin; + d3dCtx->rasterRect[2].tu = tumax; + d3dCtx->rasterRect[2].tv = tvmax; + d3dCtx->rasterRect[3].tu = tumax; + d3dCtx->rasterRect[3].tv = tvmin; + + d3dCtx->rasterRect[0].sx = screenCoord.sx; + d3dCtx->rasterRect[0].sz = screenCoord.sz; + d3dCtx->rasterRect[0].rhw = screenCoord.rhw; + + d3dCtx->rasterRect[1].sx = screenCoord.sx; + d3dCtx->rasterRect[1].sy = screenCoord.sy; + d3dCtx->rasterRect[1].sz = screenCoord.sz; + d3dCtx->rasterRect[1].rhw = screenCoord.rhw; + + d3dCtx->rasterRect[2].sz = screenCoord.sz; + d3dCtx->rasterRect[2].rhw = screenCoord.rhw; + + d3dCtx->rasterRect[3].sy = screenCoord.sy; + d3dCtx->rasterRect[3].sz = screenCoord.sz; + d3dCtx->rasterRect[3].rhw = screenCoord.rhw; + + if ((h > 0) && (w > 0)) { + //device->SetVertexShader(D3DFVF_XYZRHW|D3DFVF_TEX1); + //device->SetVertexShader(vertexFormat); + device->SetVertexShader(NULL); + device->SetFVF(D3DFVF_XYZRHW|D3DFVF_TEX1); + + if (!multipleDraw) { + d3dCtx->rasterRect[0].sy = screenCoord.sy + scaleHeight; + d3dCtx->rasterRect[2].sx = screenCoord.sx + scaleWidth; + d3dCtx->rasterRect[2].sy = screenCoord.sy + scaleHeight; + d3dCtx->rasterRect[3].sx = screenCoord.sx + scaleWidth; + device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, + 2, + d3dCtx->rasterRect, + sizeof(D3DTLVERTEX)); + } else { + d3dCtx->rasterRect[0].sy = screenCoord.sy + h; + d3dCtx->rasterRect[2].sx = screenCoord.sx + w; + d3dCtx->rasterRect[2].sy = screenCoord.sy + h; + d3dCtx->rasterRect[3].sx = screenCoord.sx + w; + for (int i=0; i < ceil(scaleHeight/((double) h)); i++) { + for (int j=0; j < ceil(scaleWidth/((double) w)); j++) { + device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, + 2, + d3dCtx->rasterRect, + sizeof(D3DTLVERTEX)); + d3dCtx->rasterRect[0].sx += w; + d3dCtx->rasterRect[1].sx += w; + d3dCtx->rasterRect[2].sx += w; + d3dCtx->rasterRect[3].sx += w; + } + d3dCtx->rasterRect[0].sx = screenCoord.sx; + d3dCtx->rasterRect[1].sx = screenCoord.sx; + d3dCtx->rasterRect[2].sx = screenCoord.sx + w; + d3dCtx->rasterRect[3].sx = screenCoord.sx + w; + d3dCtx->rasterRect[0].sy += h; + d3dCtx->rasterRect[1].sy += h; + d3dCtx->rasterRect[2].sy += h; + d3dCtx->rasterRect[3].sy += h; + } + + } + } + + // restore original texture stage values + if (texture != NULL) { + device->SetTexture(0, texture); + texture->Release(); + } else { + device->SetTexture(0, NULL); + } + + device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, + transflag); + if (transflag != D3DTTFF_DISABLE) { + device->SetTransform(D3DTS_TEXTURE0, &m); + } + if (d3dCtx->fillMode != D3DFILL_SOLID) { + device->SetRenderState(D3DRS_FILLMODE, d3dCtx->fillMode); + } + //device->SetTextureStageState(0, D3DTSS_MINFILTER, minstate); + //device->SetTextureStageState(0, D3DTSS_MAGFILTER, magstate); + device->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, texcoordstate); + + device->SetTextureStageState(0, D3DTSS_COLOROP, colorOp); + device->SetTextureStageState(0, D3DTSS_COLORARG1, colorArg); + device->SetTextureStageState(0, D3DTSS_ALPHAOP, alphaOp); + device->SetTextureStageState(0, D3DTSS_ALPHAARG1, alphaArg); + + if (texModeRepeat && !multipleDraw) { + device->SetSamplerState (0, D3DSAMP_ADDRESSU, wrapU); + device->SetSamplerState (0, D3DSAMP_ADDRESSV, wrapV); + } + device->SetRenderState(D3DRS_CULLMODE, d3dCtx->cullMode); + device->SetRenderState(D3DRS_SPECULARENABLE, TRUE); +} + +DWORD ucountBits(DWORD mask) +{ + DWORD count = 0; + int i; + + for (i=sizeof(DWORD)*8-1; i >=0 ; i--) { + if ((mask & 0x01) > 0) { + count++; + } + mask >>= 1; + } + return count; +} diff --git a/j3d-core/src/native/d3d/D3dUtil.hpp b/j3d-core/src/native/d3d/D3dUtil.hpp new file mode 100644 index 0000000..f923e12 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dUtil.hpp @@ -0,0 +1,327 @@ +/* + * $RCSfile: D3dUtil.hpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.12 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +#if !defined(D3DUTIL_H) +#define D3DUTIL_H + +#include "StdAfx.h" + + +// Index to D3dErrorMessage +#define DRIVERNOTFOUND 0 +#define CANNOTRENDERWINDOW 1 +#define D3DNOTFOUND 2 +#define CARDNOTSUPPORT 3 +#define NEEDSWITCHMODE 4 +#define DEVICENOTFOUND 5 +#define CREATEDEVICEFAIL 6 +#define CREATEREFDEVICEFAIL 7 +#define VIEWPORTFAIL 8 +#define GETBACKBUFFERFAIL 9 +#define COLORMODENOTSUPPORT 10 +#define OUTOFMEMORY 11 +#define UNKNOWNDEVICE 12 +#define HALDEVICENOTFOUND 13 +#define TNLHALDEVICENOTFOUND 14 +#define NOSTENCILBUFFER 15 +#define NOTEXTUREMEMORY 16 +#define OFFSCREENCREATEFAIL 17 +#define CREATEVERTEXBUFFER 18 +#define RESETFAIL 19 +#define HALNOTCOMPATIBLE 20 +#define DEPTHSTENCILNOTFOUND 21 +#define LOCKVBFAIL 22 +#define CREATEVBFAIL 23 +#define CREATEINDEXVBFAIL 24 +#define LOCKINDEXVBFAIL 25 +#define NOHARDWAREACCEL 26 +#define PLEASEUPDATEDRIVERS 27 + +#define PI 3.14159265f + +// Same definition as in ImageComponent2DRetained +#define CLEAN 0 +#define MODIFY 1 +#define NOTLIVE 2 + +// If we want to synchrinized draw primitive, change the +// following to D3DDP_WAIT +#define DEFAULTMODE 0 + +#define D3D_STEREO 1 + + +// Macro +#define SafeRelease(p) if(p) {p->Release(); p = NULL;} +#define SafeDelete(p) if(p) { delete p; p = NULL;} +#define SafeFree(p) if(p) { free(p); p = NULL;} + +#define GetCtx() \ + if (ctx == 0) return; \ + D3dCtx *d3dCtx = reinterpret_cast(ctx); \ + + +#define GetDevice() \ + GetCtx() \ + LPDIRECT3DDEVICE9 device = d3dCtx->pDevice; \ + if (device == NULL) return; + +#define GetCtx2() \ + if (ctx == 0) return 0;\ + D3dCtx *d3dCtx = reinterpret_cast(ctx); \ + + +#define GetDevice2() \ + GetCtx2(); \ + LPDIRECT3DDEVICE9 device = d3dCtx->pDevice; \ + if (device == NULL) return 0; + +#define CopyColor(c, red, green, blue, alpha) \ + (c).a = alpha; (c).r = red; (c).g = green; (c).b = blue; + + +#define CopyTranspose(m, s) { \ + (m)._11 = (s)[0]; (m)._12 = (s)[4]; (m)._13 = (s)[8]; (m)._14 = (s)[12]; \ + (m)._21 = (s)[1]; (m)._22 = (s)[5]; (m)._23 = (s)[9]; (m)._24 = (s)[13]; \ + (m)._31 = (s)[2]; (m)._32 = (s)[6]; (m)._33 = (s)[10]; (m)._34 = (s)[14]; \ + (m)._41 = (s)[3]; (m)._42 = (s)[7]; (m)._43 = (s)[11]; (m)._44 = (s)[15]; } + +// Note that v should not be one of the reference in m +#define MultiplyScaler(m, v) { \ + (m)._11 *= v; (m)._12 *= v; (m)._13 *= v; (m)._14 *= v; \ + (m)._21 *= v; (m)._22 *= v; (m)._23 *= v; (m)._24 *= v; \ + (m)._31 *= v; (m)._32 *= v; (m)._33 *= v; (m)._34 *= v; \ + (m)._41 *= v; (m)._42 *= v; (m)._43 *= v; (m)._44 *= v; } + +#define Clamp(c) \ + if (c > 1.0f) { \ + c = 1.0f; \ + } else if (c < 0.0f) { \ + c = 0.0f; \ + } + +#define Magitude(x, y, z, w) sqrt((x)*(x) + (y)*(y) + (z)*(z) + (w)*(w)); + +#define NORMALIZE(x, y, z, w) { \ + float d; \ + d = Magitude(x, y, z, w); \ + (x) /= d; (y) /= d; (z) /= d; (w) /= d; } + +extern vector freePointerList0; +extern vector freePointerList1; +extern BOOL useFreePointerList0; + +//ISSUE 135 a iterator to void * +typedef vector::iterator ITER_VOID; + +extern HANDLE hSema; // handle to semaphore +extern BOOL firstError; +extern BOOL debug; + +// use for VertexBuffer +extern OSVERSIONINFO osvi; // OS info + +extern D3dCtx* findCtx(HWND hwnd); +extern VOID lock(); +extern VOID unlock(); +extern VOID lockGeometry(); +extern VOID unlockGeometry(); +extern VOID lockSurfaceList(); +extern VOID unlockSurfaceList(); +extern VOID freeSurface(LPDIRECT3DBASETEXTURE9 surf); +extern VOID freePointer(void* surf); +extern VOID freePointerList(); +extern char* getErrorMessage(int idx); +extern HWND getTopWindow(HWND hwnd); + +extern LPDIRECT3DTEXTURE9 createTextureSurface(D3dCtx *d3dCtx, + jint numLevels, + jint internalFormat, + jint width, + jint height, + jboolean useAutoMipMap); + + +extern LPDIRECT3DVOLUMETEXTURE9 createVolumeTexture(D3dCtx *d3dCtx, + jint numLevels, + jint internalFormat, + jint width, + jint height, + jint depth, + jboolean useAutoMipMap); + + +extern LPDIRECT3DCUBETEXTURE9 createCubeMapTexture(D3dCtx *d3dCtx, + jint numLevels, + jint internalFormat, + jint width, + jint height, + jboolean useAutoMipMap); + + +extern void copyDataToSurface(jint format, + jint internalFormat, + jint xoffset, jint yoffset, + jint imgXOffset, jint imgYOffset, + jint width, jint height, jint tilew, + jshort *data, LPDIRECT3DTEXTURE9 surf, + jint level); + +extern void copyDataToSurface(jint format, + jint internalFormat, + jint xoffset, jint yoffset, + jint imgXOffset, jint imgYOffset, + jint width, jint height, jint tilew, + jbyte* data, + LPDIRECT3DTEXTURE9 surf, + jint level); + +extern void copyDataToVolume(jint format, + jint internalFormat, + jint xoffset, jint yoffset, + jint zoffset, + jint imgXOffset, jint imgYOffset, + jint imgZOffset, + jint width, jint height, jint depth, + jint tilew, jint tileh, + jshort *data, LPDIRECT3DVOLUMETEXTURE9 surf, + jint level); + + +extern void copyDataToVolume(jint format, + jint internalFormat, + jint xoffset, jint yoffset, + jint zoffset, + jint imgXOffset, jint imgYOffset, + jint imgZOffset, + jint width, jint height, jint depth, + jint tilew, jint tileh, + jbyte* data, + LPDIRECT3DVOLUMETEXTURE9 surf, + jint level); + +extern void copyDataToCubeMap(jint format, + jint internalFormat, + jint xoffset, jint yoffset, + jint imgXOffset, jint imgYOffset, + jint width, jint height, + jint tilew, + jshort *data, LPDIRECT3DCUBETEXTURE9 surf, + jint level, + jint face); + + +extern void copyDataToCubeMap(jint format, + jint internalFormat, + jint xoffset, jint yoffset, + jint imgXOffset, jint imgYOffset, + jint width, jint height, + jint tilew, + jbyte* data, + LPDIRECT3DCUBETEXTURE9 surf, + jint level, + jint face); + + +extern void copyDepthFromSurface(jint xoffset, jint yoffset, + jint subWidth, jint subHeight, + jint *data, + LPDIRECT3DSURFACE9 surf); + +extern void copyDepthFromSurface(jint xoffset, jint yoffset, + jint subWidth, jint subHeight, + jfloat *data, + LPDIRECT3DSURFACE9 surf); + +extern void copyDepthToSurface(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + jint dst_xoffset, jint dst_yoffset, + jint src_xoffset, jint src_yoffset, + jint subWidth, jint subHeight, + jint src_width, jint src_height, + jint *data, + LPDIRECT3DSURFACE9 surf); + +extern void copyDepthToSurface(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + jint dst_xoffset, jint dst_yoffset, + jint src_xoffset, jint src_yoffset, + jint subWidth, jint subHeight, + jint src_width, jint src_height, + jfloat *data, + LPDIRECT3DSURFACE9 surf); + +extern void copyDataFromSurface(jint internalFormat, + jint xoffset, jint yoffset, + jint width, jint height, + jbyte *data, LPDIRECT3DSURFACE9 surf); + +void compositeDataToSurface(jint px, jint py, + jint xoffset, jint yoffset, + jint subWidth, jint subHeight, + jint dataWidth, + jbyte *data, + LPDIRECT3DSURFACE9 surf); + +// extern BOOL isIdentity(jdouble *matrix); + +extern void CopyTextureStage(LPDIRECT3DDEVICE9 device, + int fromLevel, int toLevel); + +extern "C" +DWORD countBits(DWORD mask); // Define in MasterControl.c + +extern void throwAssert(JNIEnv *env, char *str); +extern BOOL createQuadIndices(D3dCtx *d3dCtx, int vcount); +extern VOID createLineModeIndexBuffer(D3dCtx *d3dCtx); +extern char *getPixelFormatName(D3DFORMAT format); +extern char *getMultiSampleName(D3DMULTISAMPLE_TYPE mtype); +extern char *getSwapEffectName(D3DSWAPEFFECT swapEffect); +extern int getPrimitiveNum(int primitive, int vcount); +extern int getMaxNumVertex(int primitive, int vcount); +extern void drawTextureRect(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + LPDIRECT3DTEXTURE9 tex, + D3DTLVERTEX screenCoord, + int startx, int starty, + int endx, int endy, + int scaleWidth, int scaleHeight, + boolean texModeRepeat); +extern int setTextureStage(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + int mapTexStage, + jint texStage); +extern void setTexTransformStageFlag(D3dCtx* d3dCtx, + LPDIRECT3DDEVICE9 device, + int tus, int ts, int genMode); +DWORD ucountBits(DWORD mask) ; +#endif + diff --git a/j3d-core/src/native/d3d/D3dVertexBuffer.cpp b/j3d-core/src/native/d3d/D3dVertexBuffer.cpp new file mode 100644 index 0000000..e9d6348 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dVertexBuffer.cpp @@ -0,0 +1,283 @@ +/* + * $RCSfile: D3dVertexBuffer.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +#include "StdAfx.h" +#include "D3dVertexBuffer.hpp" + + +D3dVertexBuffer::D3dVertexBuffer() +{ + buffer = NULL; + indexBuffer = NULL; + numVertices = NULL; + numVerticesLen = 0; + isIndexPrimitive = FALSE; + nextVB = NULL; + stripLen = 0; + totalVertexCount = 0; + ctx = NULL; + next = NULL; + previous = NULL; + isPointFlagUsed = FALSE; + primitiveType = D3DPT_FORCE_DWORD; +} + +D3dVertexBuffer::~D3dVertexBuffer() +{ + release(); +} + +VOID D3dVertexBuffer::release() +{ + SafeRelease(buffer); + SafeRelease(indexBuffer); + SafeDelete(numVertices); + + numVerticesLen = 0; + isIndexPrimitive = FALSE; + isPointFlagUsed = FALSE; + stripLen = 0; + totalVertexCount = 0; + // recursively free the list + SafeDelete(nextVB); +} + + + +VOID D3dVertexBuffer::render(D3dCtx *d3dCtx) +{ + D3DPRIMITIVETYPE oldPrimitiveType; + BOOL renderPoint = false; + BOOL restorePointSize = false; + float oldPointSize = 1.0f; + + if ((buffer != NULL) && (numVertices != NULL)) { + // device is already check for NULL in callDisplayList + LPDIRECT3DDEVICE9 device = d3dCtx->pDevice; + BOOL setAmbientLight = false; + + if (((vertexFormat & D3DFVF_DIFFUSE) == 0) && + (!d3dCtx->isLightEnable)) { + setAmbientLight = true; + if (totalVertexCount > 0) { + // This is the first Node in the list + d3dCtx->setAmbientLightMaterial(); + } + } + + if ((d3dCtx->pointSize > 1) && + ((d3dCtx->fillMode == D3DFILL_POINT) || + (primitiveType == D3DPT_POINTLIST))) { + // Some driver may cull the point away if not + // set to CULL_NONE + if (!isPointFlagUsed) { + // restore point size to 1 + if (debug) { + printf("VB render with pointSize %d without D3DPOINT flag set\n", d3dCtx->pointSize); + } + device->SetRenderState(D3DRS_POINTSIZE, *((LPDWORD) + &oldPointSize)); + restorePointSize = true; + } else { + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + // workaround for driver bug, otherwise you will + // see four corner points instead of one big point + // if fill mode is POINT + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + if (d3dCtx->deviceInfo->maxPointSize < d3dCtx->pointSize) { + // Use software vertex processing mode + //device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, TRUE); + device->SetSoftwareVertexProcessing(TRUE); + } + + oldPrimitiveType = primitiveType; + // For Polygon D3DFill_POINT mode we need to + // temporary switch primitive to point list + primitiveType = D3DPT_POINTLIST; + renderPoint = true; + } + } + + device->SetStreamSource(0, buffer,0, stride); + //device->SetVertexShader(vertexFormat); + device->SetVertexShader(NULL); + device->SetFVF(vertexFormat); + + int startIdx=0; + int vc, i; + + if (!isIndexPrimitive || + ((indexBuffer == NULL) && renderPoint)) { + for (i = 0; i < stripLen; i++) { + vc = numVertices[i]; + device->DrawPrimitive(primitiveType, + startIdx, + getPrimitiveNum(primitiveType,vc)); + startIdx += vc; + } + } else { + if (indexBuffer != NULL) { + device->SetIndices(indexBuffer); + for (i = 0; i < stripLen; i++) { + vc = numVertices[i]; + device->DrawIndexedPrimitive(primitiveType,0, + 0, + vcount, + startIdx, + getPrimitiveNum(primitiveType, vc)); + startIdx += vc; + } + } else { + if (d3dCtx->quadIndexBufferSize > 0) { + // Index is successfully set + device->SetIndices(d3dCtx->quadIndexBuffer); + device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0, + 0, + numVertices[0], + 0, + numVertices[0] >> 1); + } + // Otherwise not enough memory when index buffer + // is created, so draw nothing. + } + } + + if (setAmbientLight && (nextVB == NULL)) { + // This is the last Node in the list + d3dCtx->restoreDefaultLightMaterial(); + } + + if (renderPoint) { + device->SetRenderState(D3DRS_CULLMODE, d3dCtx->cullMode); + device->SetRenderState(D3DRS_FILLMODE, d3dCtx->fillMode); + /** device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, + d3dCtx->softwareVertexProcessing); + **/ + device->SetSoftwareVertexProcessing(d3dCtx->softwareVertexProcessing); + primitiveType = oldPrimitiveType; + } else if (restorePointSize) { + device->SetRenderState(D3DRS_POINTSIZE, + *((LPDWORD) &d3dCtx->pointSize)); + } + } + + if (nextVB != NULL) { + nextVB->render(d3dCtx); + } +} + + +VOID D3dVertexBuffer::addStride(int len) +{ + if (numVerticesLen <= stripLen) { + if (numVerticesLen == 0) { + numVertices = new USHORT[1]; + if (numVertices == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY); + return; + } + numVerticesLen = 1; + } else { + int size = numVerticesLen << 1; + USHORT *p = new USHORT[size]; + if (p == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY); + return; + } + CopyMemory(p, numVertices, numVerticesLen*sizeof(USHORT)); + delete numVertices; + numVertices = p; + numVerticesLen = size; + } + } + numVertices[stripLen++] = len; +} + + +/* + * This is used by Strip GeometryArray + * Replace all previously define stripLen by this one. + */ +VOID D3dVertexBuffer::addStrides(jint len, jint* strips) +{ + int i = len; + + if (numVerticesLen < len) { + if (numVertices) { + delete numVertices; + } + numVertices = new USHORT[len]; + numVerticesLen = len; + } + + USHORT *q = numVertices; + + while (--i >= 0) { + *q++ = *strips++; + } + stripLen = len; +} + + +/* + * This is used by D3dDisplayList optimize() + * Append this one to the current strip define. + */ +VOID D3dVertexBuffer::appendStrides(jint len, USHORT* strips) +{ + int i; + USHORT *oldVertices; + + if (numVerticesLen < stripLen + len) { + oldVertices = numVertices; + numVertices = new USHORT[len + stripLen]; + numVerticesLen = len + stripLen; + } + + USHORT *q = numVertices; + USHORT *p = oldVertices; + + if (oldVertices != NULL) { + i = stripLen; + while (--i >= 0) { + *q++ = *p++; + } + delete oldVertices; + } + + i = len; + while (--i >= 0) { + *q++ = *strips++; + } + + stripLen = numVerticesLen; +} + diff --git a/j3d-core/src/native/d3d/D3dVertexBuffer.hpp b/j3d-core/src/native/d3d/D3dVertexBuffer.hpp new file mode 100644 index 0000000..4924cb8 --- /dev/null +++ b/j3d-core/src/native/d3d/D3dVertexBuffer.hpp @@ -0,0 +1,153 @@ +/* + * $RCSfile: D3dVertexBuffer.hpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +#if !defined(D3DVERTEXBUFFER_H) +#define D3DVERTEXBUFFER_H + +#include "StdAfx.h" + +class D3dCtx; + +class D3dVertexBuffer; + +typedef D3dVertexBuffer* LPD3DVERTEXBUFFER; +typedef vector D3dVertexBufferVector; + +//ISSUE 135 iterator for D3dVertexBuffer +typedef vector::iterator ITER_LPD3DVERTEXBUFFER; + +class D3dVertexBuffer { +public: + + // Actual buffer memory to hold all the vertices + LPDIRECT3DVERTEXBUFFER9 buffer; + + // Indexed buffer for rendering IndexedGeometry + LPDIRECT3DINDEXBUFFER9 indexBuffer; + + // D3D type of this Vertex Buffer + D3DPRIMITIVETYPE primitiveType; + + // Length of following numVertices array allocate + UINT numVerticesLen; + + // Store the number of vertices for each strip + USHORT *numVertices; + + // It true when QuadArray is used or + // indexGeometry is used. + BOOL isIndexPrimitive; + + // If D3DUSAGE_POINTS flag is used to + // create this VertexBuffer + BOOL isPointFlagUsed; + + // Flexible vertex format for this VB + DWORD vertexFormat; + + // Stride of each vertex in the buffer + // compute from above vertexFormat + UINT stride; + + UINT numCoorTexSupported; + + + + + // Number of strips used for StripGeometryArray + // For each strip i the number of vertex is + // numVertices[i] + UINT stripLen; + + // Point to next overflow VB when size > VB limit + LPD3DVERTEXBUFFER nextVB; + + // content that this buffer belongs, only the first node set this one. + D3dCtx *ctx; + + // vcount is the number of vertex that this buffer + // can hold. vcount*stride is always equal to + // current VB size + UINT vcount; + + // indexCount is the number of index that this buffer + // can hold. indexCount*indexSize is always equal to + // current index VB size. + UINT indexCount; + + // Vertex count of all VBs link by nextVB, + // only the first node need to remember this info. + // The other overflow buffer always set it to zero. + DWORD totalVertexCount; + + // Same as above, except for indexBuffer + DWORD totalIndexCount; + + // This is a list of VB remember by D3dCtx + // so that it can release() all surface when canvas resize + // Only the header D3dVertexBuffer contains non-null entry + LPD3DVERTEXBUFFER next; + LPD3DVERTEXBUFFER previous; + + // Pointer back to the GeometryArrayRetained pVertexBuffers + // This is used to remove itself from pVertexBuffers table + // when ctx destroy + D3dVertexBufferVector* vbVector; + + // Last texture coordinate position = + // (i) textureCoordSetMap[pass] if executeVA() + // (ii) texCoordSetMapOffset[pass] if execute() or buildGA() + // (iii) TEX_EYE_LINEAR/TEX_SPHERE_MAP/TEX_OBJ_LINEAR/TEX_REFLECT_MAP + // if automatic texture generation is used + // This is used for VertexBuffer to know whether Texture + // coordinate need to copy or not in case texture unit swap + // or texture unit change from automatic texture generation + // to use coordinate index specifies by user. + int texCoordPosition[D3DDP_MAXTEXCOORD]; + + // Max vertex limit allow for this primitive type + // This is used for display list optimization without + // recompute it again. + int maxVertexLimit; + + D3dVertexBuffer(); + ~D3dVertexBuffer(); + + VOID release(); + VOID render(D3dCtx *d3dCtx); + BOOL initializeNumVertices(int len); + VOID addStride(int len); + VOID addStrides(jint stripLen, jint *strips); + VOID appendStrides(jint stripLen, USHORT *strips); +}; + + +#endif diff --git a/j3d-core/src/native/d3d/GeometryArrayRetained.cpp b/j3d-core/src/native/d3d/GeometryArrayRetained.cpp new file mode 100644 index 0000000..5ae8751 --- /dev/null +++ b/j3d-core/src/native/d3d/GeometryArrayRetained.cpp @@ -0,0 +1,5190 @@ +/* + * $RCSfile: GeometryArrayRetained.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +#include "StdAfx.h" + + +//#define VBDEBUG +//#define TEXDEBUG + +#define getVertexFormat(texSize) \ + (((texSize) << D3DFVF_TEXCOUNT_SHIFT) & D3DFVF_TEXCOUNT_MASK) + +/* + * This correspond to the constant in d3dtypes.h + * under D3D 7.0/8.0 header and may not portable : + * Still valid with D3D 9.0 (aces) + * D3DFVF_TEXTUREFORMAT1 3 + * D3DFVF_TEXTUREFORMAT2 0 + * D3DFVF_TEXTUREFORMAT3 1 + * D3DFVF_TEXTUREFORMAT4 2 + */ +CONST static DWORD TexFormatSizeTable[5] = {0, 3, 0, 1, 2}; +static float defaultTexCoord[4] = {0, 0, 0, 0}; + +typedef struct _D3DDRAWPRIMITIVESTRIDEDDATA +{ + DWORD positionStride; + jfloat *fpositionPtr; + jdouble *dpositionPtr; + DWORD normalStride; + jfloat *normalPtr; + DWORD diffuseStride; + jfloat *fdiffusePtr; + jbyte *bdiffusePtr; + jint *indexPtr; + jint initialIndexIndex; + DWORD textureCoordsStride[D3DDP_MAXTEXCOORD]; + jfloat* textureCoordsPtr[D3DDP_MAXTEXCOORD]; + jint texCoordPosition[D3DDP_MAXTEXCOORD]; + boolean useAlpha; + boolean modulateAlpha; + jfloat alpha; +} D3DDRAWPRIMITIVESTRIDEDDATA, *LPD3DDRAWPRIMITIVESTRIDEDDATA; + + +void copyIndexVertexToVB(D3dCtx *d3dCtx, + D3DDRAWPRIMITIVESTRIDEDDATA* strideData, + DWORD indexCount, + jint cDirty, + BOOL insertStrideToVB, + BOOL expandQuadIndex) +{ + HRESULT hr; + + if (cDirty & javax_media_j3d_GeometryArrayRetained_INDEX_CHANGED) { + jint *src = strideData->indexPtr + strideData->initialIndexIndex; + LPDIRECT3DINDEXBUFFER9 indexBuffer = d3dCtx->pVB->indexBuffer; + D3DINDEXBUFFER_DESC desc; + BYTE *bptr; + + indexBuffer->GetDesc(&desc); + hr = indexBuffer->Lock(0, 0, (VOID**)&bptr, 0); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKINDEXVBFAIL, hr); + return; + } + + int i = indexCount; + + if (desc.Format == D3DFMT_INDEX16) { + USHORT *dst = (USHORT *) bptr; + + if (!expandQuadIndex) { + while (--i >= 0) { + *dst++ = *src++; + } + } else { + USHORT *endptr = dst + (USHORT) 3*indexCount/2; + + while (dst < endptr) { + *dst++ = *src; + *dst++ = *(src+1); + *dst++ = *(src+2); + *dst++ = *src; + src++; + src++; + *dst++ = *src; + src++; + *dst++ = *src; + src++; + } + } + } else { + UINT *dst = (UINT *) bptr; + + if (!expandQuadIndex) { + while (--i >= 0) { + *dst++ = *src++; + } + } else { + UINT *endptr = dst + (UINT) 3*indexCount/2; + while (dst < endptr) { + *dst++ = *src; + *dst++ = *(src+1); + *dst++ = *(src+2); + *dst++ = *src; + src++; + src++; + *dst++ = *src; + src++; + *dst++ = *src; + src++; + } + + dst = (UINT *) bptr; + } + } + + indexBuffer->Unlock(); + } + + if (insertStrideToVB) { + d3dCtx->pVB->addStride(d3dCtx->pVB->indexCount); + } +} + +// This function copy the stride vertex data into Vertex Buffer +// point by vbptr and update vbptr +void copyVertexToVB(D3dCtx *d3dCtx, + D3DDRAWPRIMITIVESTRIDEDDATA* strideData, + DWORD vcount, + float **vbptr, + jint cDirty, + BOOL insertStrideToVB, + jdouble* xform, + jdouble* nxform) +{ + float *dst; + float *src; + double *dsrc; + DWORD i; + DWORD srcStride; + DWORD currStride; + + DWORD dstStride = d3dCtx->pVB->stride >> 2; + DWORD vertexFormat = d3dCtx->pVB->vertexFormat; + float *endptr; + + // Copy Position + if (cDirty & javax_media_j3d_GeometryArrayRetained_COORDINATE_CHANGED) { + dst = *vbptr; + // Before we call two times src++ in position and + // normal copy so we only need to add dstStride - 2 + // at the end. + srcStride = strideData->positionStride - 2; + endptr = dst + vcount*dstStride; + dstStride -= 2; + src = strideData->fpositionPtr; + + if (xform == NULL) { + if (src != NULL) { + while (dst < endptr) { + *dst++ = *src++; // pos x + *dst++ = *src++; // pos y + *dst = *src; // pos z + dst += dstStride; + src += srcStride; + } + } else { + // double is used for position coordinate in executeVA() + dsrc = strideData->dpositionPtr; + while (dst < endptr) { + *dst++ = *dsrc++; // pos x + *dst++ = *dsrc++; // pos y + *dst = *dsrc; // pos z + dst += dstStride; + dsrc += srcStride; + } + } + } else { + if (src != NULL) { + float x, y, z, w; + while (dst < endptr) { + x = *src++; + y = *src++; + z = *src; // pos z + w = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + *dst++ = (xform[0]*x + xform[1]*y + xform[2]*z + xform[3])*w; + *dst++ = (xform[4]*x + xform[5]*y + xform[6]*z + xform[7])*w; + *dst = (xform[8]*x + xform[9]*y + xform[10]*z + xform[11])*w; + dst += dstStride; + src += srcStride; + } + } else { + double x, y, z, w; + // double is used for position coordinate in executeVA() + dsrc = strideData->dpositionPtr; + while (dst < endptr) { + x = *src++; + y = *src++; + z = *src; // pos z + w = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + *dst++ = (xform[0]*x + xform[1]*y + xform[2]*z + xform[3])*w; + *dst++ = (xform[4]*x + xform[5]*y + xform[6]*z + xform[7])*w; + *dst = (xform[8]*x + xform[9]*y + xform[10]*z + xform[11])*w; + dst += dstStride; + dsrc += srcStride; + } + } + + } + // restore value + dstStride += 2; + } + + // Copy Normal + if (vertexFormat & D3DFVF_NORMAL) { + if (cDirty & javax_media_j3d_GeometryArrayRetained_NORMAL_CHANGED) { + dst = *vbptr + 3; + src = strideData->normalPtr; + srcStride = strideData->normalStride - 2; + endptr = dst + vcount*dstStride; + dstStride -= 2; + if (nxform == NULL) { + while (dst < endptr) { + *dst++ = *src++; // norm x + *dst++ = *src++; // norm y + *dst = *src; // norm z + dst += dstStride; + src += srcStride; + } + } else { + float nx, ny, nz, nw; + while (dst < endptr) { + nx = *src++; + ny = *src++; + nz = *src; // pos z + nw = 1/(nxform[12]*nx + nxform[13]*ny + nxform[14]*nz + nxform[15]); + *dst++ = (nxform[0]*nx + nxform[1]*ny + nxform[2]*nz + nxform[3])*nw; + *dst++ = (nxform[4]*nx + nxform[5]*ny + nxform[6]*nz + nxform[7])*nw; + *dst = (nxform[8]*nx + nxform[9]*ny + nxform[10]*nz + nxform[11])*nw; + dst += dstStride; + dsrc += srcStride; + } + } + // restore value + dstStride += 2; + } + // nx,ny,nz copy in addtion to x, y, z + currStride = 6; + } else { + // This is used to keep track of the offset + // from beginning of the current type copy. + currStride = 3; // x,y,z already copy + } + + // Copy Diffuse Color (DWORD & float are of the same size) + + if (vertexFormat & D3DFVF_DIFFUSE) { + if (cDirty & javax_media_j3d_GeometryArrayRetained_COLOR_CHANGED) { + + DWORD* wdst = (DWORD *) *vbptr + currStride; + DWORD* wendptr = wdst + vcount*dstStride; + + if (strideData->fdiffusePtr) { + float* wsrc = strideData->fdiffusePtr; + float r, g, b, a; + if ((d3dCtx->currDisplayListID <= 0) || + !strideData->modulateAlpha) { + // execute() or executeVA() + + if (strideData->useAlpha) { + srcStride = strideData->diffuseStride - 3; + while (wdst < wendptr) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc++; + a = *wsrc; + *wdst = D3DCOLOR_COLORVALUE(r, g, b, a); + wdst += dstStride; + wsrc += srcStride; + } + } else { + srcStride = strideData->diffuseStride - 2; + while (wdst < wendptr) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc; + *wdst = D3DCOLOR_COLORVALUE(r, g, b, 0); + wdst += dstStride; + wsrc += srcStride; + } + } + } else { + // buildGA() & modulateAlpha + float alpha = strideData->alpha; + if (strideData->useAlpha) { + srcStride = strideData->diffuseStride - 3; + while (wdst < wendptr) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc++; + a = *wsrc * alpha; + *wdst = D3DCOLOR_COLORVALUE(r, g, b, a); + wdst += dstStride; + wsrc += srcStride; + } + } else { + srcStride = strideData->diffuseStride - 2; + while (wdst < wendptr) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc; + *wdst = D3DCOLOR_COLORVALUE(r, g, b, alpha); + wdst += dstStride; + wsrc += srcStride; + } + } + + } + } else { // byte color pointer + jbyte* wsrc = strideData->bdiffusePtr; + jbyte r, g, b, a; + if ((d3dCtx->currDisplayListID <= 0) || + !strideData->modulateAlpha) { + // execute() or executeVA() + + if (strideData->useAlpha) { + srcStride = strideData->diffuseStride - 3; + while (wdst < wendptr) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc++; + a = *wsrc; + *wdst = D3DCOLOR_RGBA(r, g, b, a); + wdst += dstStride; + wsrc += srcStride; + } + } else { + srcStride = strideData->diffuseStride - 2; + while (wdst < wendptr) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc; + *wdst = D3DCOLOR_RGBA(r, g, b, 0); + wdst += dstStride; + wsrc += srcStride; + } + } + } else { + // buildGA() & modeulateAlpha + // Currently buildGA() will not use byte color + // so this code should never execute. + jbyte alpha = (jbyte)(255*strideData->alpha); + if (strideData->useAlpha) { + srcStride = strideData->diffuseStride - 3; + while (wdst < wendptr) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc++; + a = (jbyte)(((int)(*wsrc) & 0xff) * strideData->alpha); + *wdst = D3DCOLOR_RGBA(r, g, b, a); + wdst += dstStride; + wsrc += srcStride; + } + } else { + srcStride = strideData->diffuseStride - 2; + while (wdst < wendptr) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc; + *wdst = D3DCOLOR_RGBA(r, g, b, alpha); + wdst += dstStride; + wsrc += srcStride; + } + } + + } + } + + } + + currStride++; // additional one DWORD of color copy + } + + // Copy Texture + int ts; + int texPos; + boolean invalidTexCoord; + +#ifdef TEXDEBUG + printf("In copyVertexToVB TexSet Used %d\n", d3dCtx->texSetUsed); +#endif + for (i=0; i < d3dCtx->texSetUsed; i++) { + ts = d3dCtx->texStride[i]; + + // TODO: skip when ts = 0 + if (ts == 0) { + continue; + } + texPos = strideData->texCoordPosition[i]; + + invalidTexCoord = ((texPos != d3dCtx->pVB->texCoordPosition[i]) || + (texPos == TEX_OBJ_LINEAR)); + +#ifdef TEXDEBUG + printf("%d texPos %d, invalidate Cached TexCoord %d, ts %d\n",i, texPos, invalidTexCoord, ts); +#endif + if ((cDirty & javax_media_j3d_GeometryArrayRetained_TEXTURE_CHANGED) || + invalidTexCoord) { + + if (texPos >= 0) { + dst = *vbptr + currStride; + src = strideData->textureCoordsPtr[i]; + endptr = dst + vcount*dstStride; +#ifdef TEXDEBUG + printf("copy directly, ts %d\n", ts); +#endif + if (ts == 2) { + dstStride--; + srcStride = strideData->textureCoordsStride[i] - 1; + while (dst < endptr) { + *dst++ = *src++; // tx + *dst = *src; // ty + dst += dstStride; + src += srcStride; + } + dstStride++; + } else if (ts == 3) { + dstStride -= 2; + srcStride = strideData->textureCoordsStride[i] - 2; + while (dst < endptr) { + *dst++ = *src++; // tx + *dst++ = *src++; // ty + *dst = *src; // tz + dst += dstStride; + src += srcStride; + } + dstStride += 2; + } else { + // ts == 4 + dstStride -= 3; + srcStride = strideData->textureCoordsStride[i] - 3; + while (dst < endptr) { + *dst++ = *src++; // tx + *dst++ = *src++; // ty + *dst++ = *src++; // tz + *dst = *src; // tw + dst += dstStride; + src += srcStride; + } + dstStride += 3; + } + + } else { + if (texPos == TEX_OBJ_LINEAR) { + // automatic texture generation for Object Linear + float *ps = d3dCtx->planeS[i]; + float *pt = d3dCtx->planeT[i]; + float *pr = d3dCtx->planeR[i]; + float *pq = d3dCtx->planeQ[i]; +#ifdef TEXDEBUG + printf("gen obj linear tex, ts %d\n", ts); +#endif + if (strideData->fpositionPtr) { + float x, y, z; + dst = *vbptr + currStride; + endptr = dst + vcount*dstStride; + src = strideData->fpositionPtr; + srcStride = strideData->positionStride - 2; + if (ts == 2) { + dstStride--; + if (xform == NULL) { + while (dst < endptr) { + x = *src++; + y = *src++; + z = *src; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + dst += dstStride; + src += srcStride; + } + } else { + float tx, ty, tz, tw; + while (dst < endptr) { + tx = *src++; + ty = *src++; + tz = *src; + tw = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + x = (xform[0]*tx + xform[1]*ty + xform[2]*tz + xform[3])*tw; + y = (xform[4]*tx + xform[5]*ty + xform[6]*tz + xform[7])*tw; + z = (xform[8]*tx + xform[9]*ty + xform[10]*tz + xform[11])*tw; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + dst += dstStride; + src += srcStride; + } + } + dstStride++; + } else if (ts == 3) { + dstStride -= 2; + if (xform == NULL) { + while (dst < endptr) { + x = *src++; + y = *src++; + z = *src; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst++ = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + *dst = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + dst += dstStride; + src += srcStride; + } + } else { + float tx, ty, tz, tw; + while (dst < endptr) { + tx = *src++; + ty = *src++; + tz = *src; + tw = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + x = (xform[0]*tx + xform[1]*ty + xform[2]*tz + xform[3])*tw; + y = (xform[4]*tx + xform[5]*ty + xform[6]*tz + xform[7])*tw; + z = (xform[8]*tx + xform[9]*ty + xform[10]*tz + xform[11])*tw; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst++ = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + *dst = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + dst += dstStride; + src += srcStride; + } + } + + dstStride += 2; + } else { + // ts == 4 + dstStride -= 3; + + if (!d3dCtx->texTransformSet[i]) { + if (xform == NULL) { + while (dst < endptr) { + x = *src++; + y = *src++; + z = *src; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst++ = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + *dst++ = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + *dst = pq[0]*x + pq[1]*y + pq[2]*z + pq[3]; + dst += dstStride; + src += srcStride; + } + } else { + float tx, ty, tz, tw; + while (dst < endptr) { + tx = *src++; + ty = *src++; + tz = *src; + tw = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + x = (xform[0]*tx + xform[1]*ty + xform[2]*tz + xform[3])*tw; + y = (xform[4]*tx + xform[5]*ty + xform[6]*tz + xform[7])*tw; + z = (xform[8]*tx + xform[9]*ty + xform[10]*tz + xform[11])*tw; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst++ = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + *dst++ = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + *dst = pq[0]*x + pq[1]*y + pq[2]*z + pq[3]; + dst += dstStride; + src += srcStride; + } + } + } else { + // do texture transform manually + D3DXMATRIX *m = &(d3dCtx->texTransform[i]); + double tx, ty, tz, tw; + if (xform == NULL) { + while (dst < endptr) { + x = *src++; + y = *src++; + z = *src; + tx = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + ty = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + tz = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + tw = pq[0]*x + pq[1]*y + pq[2]*z + pq[3]; + *dst++ = (*m)._11*tx + (*m)._21*ty + (*m)._31*tz + (*m)._41*tw; + *dst++ = (*m)._12*tx + (*m)._22*ty + (*m)._32*tz + (*m)._42*tw; + *dst++ = (*m)._13*tx + (*m)._23*ty + (*m)._33*tz + (*m)._43*tw; + *dst = (*m)._14*tx + (*m)._24*ty + (*m)._34*tz + (*m)._44*tw; + dst += dstStride; + src += srcStride; + } + } else { + float tx, ty, tz, tw; + while (dst < endptr) { + tx = *src++; + ty = *src++; + tz = *src; + tw = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + x = (xform[0]*tx + xform[1]*ty + xform[2]*tz + xform[3])*tw; + y = (xform[4]*tx + xform[5]*ty + xform[6]*tz + xform[7])*tw; + z = (xform[8]*tx + xform[9]*ty + xform[10]*tz + xform[11])*tw; + tx = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + ty = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + tz = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + tw = pq[0]*x + pq[1]*y + pq[2]*z + pq[3]; + *dst++ = (*m)._11*tx + (*m)._21*ty + (*m)._31*tz + (*m)._41*tw; + *dst++ = (*m)._12*tx + (*m)._22*ty + (*m)._32*tz + (*m)._42*tw; + *dst++ = (*m)._13*tx + (*m)._23*ty + (*m)._33*tz + (*m)._43*tw; + *dst = (*m)._14*tx + (*m)._24*ty + (*m)._34*tz + (*m)._44*tw; + dst += dstStride; + src += srcStride; + } + } + } + dstStride += 3; + } + } else { + // double type position pointer + double x, y, z; + dst = *vbptr + currStride; + endptr = dst + vcount*dstStride; + dsrc = strideData->dpositionPtr; + srcStride = strideData->positionStride - 2; + if (ts == 2) { + dstStride--; + if (xform == NULL) { + while (dst < endptr) { + x = *dsrc++; + y = *dsrc++; + z = *dsrc; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + dst += dstStride; + dsrc += srcStride; + } + } else { + double tx, ty, tz, tw; + while (dst < endptr) { + tx = *src++; + ty = *src++; + tz = *src; + tw = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + x = (xform[0]*tx + xform[1]*ty + xform[2]*tz + xform[3])*tw; + y = (xform[4]*tx + xform[5]*ty + xform[6]*tz + xform[7])*tw; + z = (xform[8]*tx + xform[9]*ty + xform[10]*tz + xform[11])*tw; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + dst += dstStride; + src += srcStride; + } + } + dstStride++; + } else if (ts == 3) { + dstStride -= 2; + if (xform == NULL) { + while (dst < endptr) { + x = *dsrc++; + y = *dsrc++; + z = *dsrc; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst++ = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + *dst = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + dst += dstStride; + dsrc += srcStride; + } + } else { + double tx, ty, tz, tw; + while (dst < endptr) { + tx = *src++; + ty = *src++; + tz = *src; + tw = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + x = (xform[0]*tx + xform[1]*ty + xform[2]*tz + xform[3])*tw; + y = (xform[4]*tx + xform[5]*ty + xform[6]*tz + xform[7])*tw; + z = (xform[8]*tx + xform[9]*ty + xform[10]*tz + xform[11])*tw; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst++ = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + *dst = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + dst += dstStride; + src += srcStride; + } + } + dstStride += 2; + } else { + // ts == 4 + dstStride -= 3; + if (!d3dCtx->texTransformSet[i]) { + if (xform == NULL) { + while (dst < endptr) { + x = *dsrc++; + y = *dsrc++; + z = *dsrc; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst++ = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + *dst++ = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + *dst = pq[0]*x + pq[1]*y + pq[2]*z + pq[3]; + dst += dstStride; + dsrc += srcStride; + } + } else { + double tx, ty, tz, tw; + while (dst < endptr) { + tx = *src++; + ty = *src++; + tz = *src; + tw = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + x = (xform[0]*tx + xform[1]*ty + xform[2]*tz + xform[3])*tw; + y = (xform[4]*tx + xform[5]*ty + xform[6]*tz + xform[7])*tw; + z = (xform[8]*tx + xform[9]*ty + xform[10]*tz + xform[11])*tw; + *dst++ = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + *dst++ = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + *dst++ = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + *dst = pq[0]*x + pq[1]*y + pq[2]*z + pq[3]; + dst += dstStride; + src += srcStride; + } + } + } else { +// do texture transform manually + D3DXMATRIX *m = &(d3dCtx->texTransform[i]); + double tx, ty, tz, tw; + if (xform == NULL) { + while (dst < endptr) { + x = *src++; + y = *src++; + z = *src; + tx = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + ty = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + tz = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + tw = pq[0]*x + pq[1]*y + pq[2]*z + pq[3]; + *dst++ = ((*m)._11*tx + (*m)._21*ty + (*m)._31*tz + (*m)._41*tw); + *dst++ = ((*m)._12*tx + (*m)._22*ty + (*m)._32*tz + (*m)._42*tw); + *dst++ = ((*m)._13*tx + (*m)._23*ty + (*m)._33*tz + (*m)._43*tw); + *dst = (*m)._14*tx + (*m)._24*ty + (*m)._34*tz + (*m)._44*tw; + dst += dstStride; + src += srcStride; + } + } else { + float tx, ty, tz, tw; + while (dst < endptr) { + tx = *src++; + ty = *src++; + tz = *src; + tw = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + x = (xform[0]*tx + xform[1]*ty + xform[2]*tz + xform[3])*tw; + y = (xform[4]*tx + xform[5]*ty + xform[6]*tz + xform[7])*tw; + z = (xform[8]*tx + xform[9]*ty + xform[10]*tz + xform[11])*tw; + tx = ps[0]*x + ps[1]*y + ps[2]*z + ps[3]; + ty = pt[0]*x + pt[1]*y + pt[2]*z + pt[3]; + tz = pr[0]*x + pr[1]*y + pr[2]*z + pr[3]; + tw = pq[0]*x + pq[1]*y + pq[2]*z + pq[3]; + *dst++ = ((*m)._11*tx + (*m)._21*ty + (*m)._31*tz + (*m)._41*tw); + *dst++ = ((*m)._12*tx + (*m)._22*ty + (*m)._32*tz + (*m)._42*tw); + *dst++ = ((*m)._13*tx + (*m)._23*ty + (*m)._33*tz + (*m)._43*tw); + *dst = (*m)._14*tx + (*m)._24*ty + (*m)._34*tz + (*m)._44*tw; + dst += dstStride; + src += srcStride; + } + } + } + dstStride += 3; + } + } + } else if (texPos == TEX_GEN_INVALID) { + // application error, disable by setting texCoord to zero +#ifdef TEXDEBUG + printf("app error, ts %d\n", ts); +#endif + dst = *vbptr + currStride; + endptr = dst + vcount*dstStride; + if (ts == 2) { + dstStride--; + while (dst < endptr) { + *dst++ = 0; + *dst = 0; + dst += dstStride; + } + dstStride++; + } else if (ts == 3) { + dstStride -= 2; + while (dst < endptr) { + *dst++ = 0; + *dst++ = 0; + *dst = 0; + dst += dstStride; + } + dstStride += 2; + } else { + // ts == 4 + dstStride -= 3; + while (dst < endptr) { + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst = 0; + dst += dstStride; + } + dstStride += 3; + } + } else { + // Other automatic texture generation type handle + // by driver + //printf("TexStage %d, Tex gen by driver, texPos = %d\n", i, texPos); + } + } + } + + currStride += ts; + } + + if (insertStrideToVB) { + d3dCtx->pVB->addStride(vcount); + } + + // Adjust VB pointer so that when this function is invoked + // again, it append to the VB correctly. + *vbptr += (vcount*dstStride); +} + + +void copyOneVertexToVB(D3dCtx *d3dCtx, + float **vbptr, + D3DDRAWPRIMITIVESTRIDEDDATA* strideData, + DWORD idx, + jint cDirty, + jdouble* xform, + jdouble* nxform) +{ + float *src; + float *dst = *vbptr; + DWORD vertexFormat = d3dCtx->pVB->vertexFormat; + float posX, posY, posZ; + + // Copy Position + + // if (cDirty & javax_media_j3d_GeometryArrayRetained_COORDINATE_CHANGED) + // Set the posX, posY, posZ anyway since TexGeneration will use it + // if dirty. + + if (strideData->fpositionPtr != NULL) { + src = strideData->fpositionPtr + + idx*strideData->positionStride; + + if (xform == NULL) { + posX = *src++; // pos x + posY = *src++; // pos y + posZ = *src; // pos z + } else { + float x, y, z, w; + x = *src++; + y = *src++; + z = *src; + w = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + posX = (xform[0]*x + xform[1]*y + xform[2]*z + xform[3])*w; + posY = (xform[4]*x + xform[5]*y + xform[6]*z + xform[7])*w; + posZ = (xform[8]*x + xform[9]*y + xform[10]*z + xform[11])*w; + } + } else { + // double is used for position coordinate in executeVA() + double *dsrc = strideData->dpositionPtr + + idx*strideData->positionStride; + + if (xform == NULL) { + posX = (float) *dsrc++; // pos x + posY = (float) *dsrc++; // pos y + posZ = (float) *dsrc; // pos z + } else { + double x, y, z, w; + x = *dsrc++; + y = *dsrc++; + z = *dsrc; + w = 1/(xform[12]*x + xform[13]*y + xform[14]*z + xform[15]); + posX = (float) (xform[0]*x + xform[1]*y + xform[2]*z + xform[3])*w; + posY = (float) (xform[4]*x + xform[5]*y + xform[6]*z + xform[7])*w; + posZ = (float) (xform[8]*x + xform[9]*y + xform[10]*z + xform[11])*w; + } + } + *dst++ = posX; + *dst++ = posY; + *dst++ = posZ; + + // Copy Normal + if (vertexFormat & D3DFVF_NORMAL) { + if (cDirty & javax_media_j3d_GeometryArrayRetained_NORMAL_CHANGED) { + src = strideData->normalPtr + + idx*strideData->normalStride; + if (nxform == NULL) { + *dst++ = *src++; // norm x + *dst++ = *src++; // norm y + *dst++ = *src; // norm z + } else { + float nx, ny, nz, nw; + nx = *src++; // norm x + ny = *src++; // norm y + nz = *src; // norm z + nw = 1/(nxform[12]*nx + nxform[13]*ny + nxform[14]*nz + nxform[15]); + *dst++ = (nxform[0]*nx + nxform[1]*ny + nxform[2]*nz + nxform[3])*nw; + *dst++ = (nxform[4]*nx + nxform[5]*ny + nxform[6]*nz + nxform[7])*nw; + *dst = (nxform[8]*nx + nxform[9]*ny + nxform[10]*nz + nxform[11])*nw; + } + } + } + + + // Copy Diffuse Color (DWORD & float are of the same size) + if (vertexFormat & D3DFVF_DIFFUSE) { + if (cDirty & javax_media_j3d_GeometryArrayRetained_COLOR_CHANGED) { + DWORD* wdst = (DWORD *) dst; + if (strideData->fdiffusePtr) { + src = strideData->fdiffusePtr + + idx*strideData->diffuseStride; + float r, g, b, a; + if ((d3dCtx->currDisplayListID <= 0) || + !strideData->modulateAlpha) { + // execute() or executeVA() + if (strideData->useAlpha) { + r = *src++; + g = *src++; + b = *src++; + a = *src; + } else { + r = *src++; + g = *src++; + b = *src; + a = 0; + } + } else { + // buildGA() & modeulateAlpha + if (strideData->useAlpha) { + r = *src++; + g = *src++; + b = *src++; + a = *src * strideData->alpha; + } else { + r = *src++; + g = *src++; + b = *src; + a = strideData->alpha; + } + } + *wdst = D3DCOLOR_COLORVALUE(r, g, b, a); + } else { // byte color pointer + jbyte* wsrc = strideData->bdiffusePtr + + idx*strideData->diffuseStride; + jbyte r, g, b, a; + if ((d3dCtx->currDisplayListID <= 0) || + !strideData->modulateAlpha) { + // execute() or executeVA() + if (strideData->useAlpha) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc++; + a = *wsrc; + } else { + r = *wsrc++; + g = *wsrc++; + b = *wsrc; + a = 0; + } + } else { + // buildGA() & modeulateAlpha + // Currently buildGA() will not use byte color + // so this code should never execute. + jbyte alpha = (jbyte) (255*strideData->alpha); + if (strideData->useAlpha) { + r = *wsrc++; + g = *wsrc++; + b = *wsrc++; + a = (jbyte)(((int)(*wsrc) & 0xff) * strideData->alpha); + } else { + r = *wsrc++; + g = *wsrc++; + b = *wsrc; + a = alpha; + + } + } + *wdst = D3DCOLOR_RGBA(r, g, b, a); + } + } + dst++; // additional one DWORD of color copy + } + + + // Copy Texture + int ts; + int texPos; + boolean invalidTexCoord; + + for (int i=0; i < d3dCtx->texSetUsed; i++) { + ts = d3dCtx->texStride[i]; + if (ts == 0) { + continue; + } + texPos = strideData->texCoordPosition[i]; + + invalidTexCoord = ((texPos != d3dCtx->pVB->texCoordPosition[i]) || + (texPos == TEX_OBJ_LINEAR)); + + if ((cDirty & javax_media_j3d_GeometryArrayRetained_TEXTURE_CHANGED) || invalidTexCoord) { + if (texPos >= 0) { + src = strideData->textureCoordsPtr[i] + + idx*strideData->textureCoordsStride[i]; + *dst++ = *src++; // tx + *dst++ = *src++; // ty + if (ts >= 3) { + *dst++ = *src++; // tx + if (ts >= 4) { + *dst++ = *src; // tx + } + } + } else { + // automatic texture generation + if (texPos == TEX_OBJ_LINEAR) { + float *ps = d3dCtx->planeS[i]; + float *pt = d3dCtx->planeT[i]; + float *pr = d3dCtx->planeR[i]; + float *pq = d3dCtx->planeQ[i]; + + if ((ts < 4) || (!d3dCtx->texTransformSet[i])) { + *dst++ = ps[0]*posX + ps[1]*posY + ps[2]*posZ + ps[3]; + *dst++ = pt[0]*posX + pt[1]*posY + pt[2]*posZ + pt[3]; + if (ts >= 3) { + *dst++ = pr[0]*posX + pr[1]*posY + pr[2]*posZ + pr[3]; + if (ts >= 4) { + *dst++ = pq[0]*posX + pq[1]*posY + pq[2]*posZ + pq[3]; + } + } + } else { + float tx, ty, tz, tw; + D3DXMATRIX *m = &(d3dCtx->texTransform[i]); + tx = ps[0]*posX + ps[1]*posY + ps[2]*posZ + ps[3]; + ty = pt[0]*posX + pt[1]*posY + pt[2]*posZ + pt[3]; + tz = pr[0]*posX + pr[1]*posY + pr[2]*posZ + pr[3]; + tw = pq[0]*posX + pq[1]*posY + pq[2]*posZ + pq[3]; + *dst++ = (*m)._11*tx + (*m)._21*ty + (*m)._31*tz + (*m)._41*tw; + *dst++ = (*m)._12*tx + (*m)._22*ty + (*m)._32*tz + (*m)._42*tw; + *dst++ = (*m)._13*tx + (*m)._23*ty + (*m)._33*tz + (*m)._43*tw; + *dst++ = (*m)._14*tx + (*m)._24*ty + (*m)._34*tz + (*m)._44*tw; + } + } else if (texPos == TEX_GEN_INVALID) { + // application error, disable by setting texCoord to zero + *dst++ = 0; + *dst++ = 0; + if (ts >= 3) { + *dst++ = 0; + if (ts >= 4) { + *dst++ = 0; + } + } + } else { + // should not happen + dst += ts; + } + } + } else { + dst += ts; + } + } + + *vbptr = dst; +} + + +float* allocateVB(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + int vcount, + int maxVertexLimit, + jint *cdirty) +{ + LPD3DVERTEXBUFFER vb = d3dCtx->pVB->nextVB; + HRESULT hr; + float *ptr = NULL; + + + if (vcount > maxVertexLimit) { + vcount = maxVertexLimit; + } + + if ((vb != NULL) && (vb->vcount < vcount)) { + delete vb; + d3dCtx->pVB->nextVB = NULL; + vb = NULL; + } + + if (vb == NULL) { + vb = new D3dVertexBuffer(); + if (vb == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY); + return NULL; + } + + vb->stride = d3dCtx->pVB->stride; + vb->vertexFormat = d3dCtx->pVB->vertexFormat; + // Don't set totalVertexCount + vb->isIndexPrimitive = d3dCtx->pVB->isIndexPrimitive; + vb->primitiveType = d3dCtx->pVB->primitiveType; + vb->isPointFlagUsed = d3dCtx->pVB->isPointFlagUsed; + vb->vcount = vcount; + vb->maxVertexLimit = maxVertexLimit; + +#ifdef VBDEBUG + printf("Create secondary VertexBuffer of size %d, display list ID %d, pointFlag %d\n", + vb->vcount, d3dCtx->currDisplayListID, vb->isPointFlagUsed); +#endif + if (!vb->isPointFlagUsed) { + hr = device->CreateVertexBuffer(vb->stride*vcount, + D3DUSAGE_WRITEONLY, + vb->vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + } else { + hr = device->CreateVertexBuffer(vb->stride*vcount, + D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS, + vb->vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + } + if (FAILED(hr)) { + vb->buffer = NULL; + delete vb; + D3dCtx::d3dWarning(CREATEVBFAIL, hr); + return NULL; + } + d3dCtx->pVB->nextVB = vb; + *cdirty = javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED; + } + + hr = vb->buffer->Lock(0, 0,(VOID**) &ptr, 0); + + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKVBFAIL, hr); + delete vb; + d3dCtx->pVB->nextVB = NULL; + return NULL; + } + + d3dCtx->pVB = vb; + + vb->stripLen = 0; + return ptr; +} + + + +BOOL createCopyVBVertex(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + D3DDRAWPRIMITIVESTRIDEDDATA *strideData, + int vcount, jint cDirty, + jdouble* xform, + jdouble* nxform) +{ + LPD3DVERTEXBUFFER vb = d3dCtx->pVB; + float *vbptr; + + + if (vb->stripLen > 0) { + // VertexBuffer already used, create a new one or used + // the next VB in the list + // maxVertexLimit is already check before, so we can + // pass vcount as maxVertexLimit + vbptr = allocateVB(d3dCtx, device, vcount, vcount, &cDirty); + if (vbptr == NULL) { + return FALSE; + } + + } else { + // use the same VB + HRESULT hr; + hr = vb->buffer->Lock(0, 0, (VOID**)&vbptr, 0); + + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKVBFAIL, hr); + return FALSE; + } + + } + + copyVertexToVB(d3dCtx, strideData, vcount, &vbptr, cDirty, true, + xform, nxform); + + d3dCtx->pVB->buffer->Unlock(); + return TRUE; +} + + +/* + * Draw Primitive with vertexCount > D3DMAXNUMVERTICES. + * In this case we call the drawing routine multiple times. + */ +void splitVertexToMultipleVB(D3dCtx *d3dCtx, + LPD3DDRAWPRIMITIVESTRIDEDDATA strideData, + int vcount, + int maxVertexLimit, + jint cDirty, + jdouble* xform, + jdouble* nxform) +{ + int i, inc; + int min = 0; + int max = 0; + jfloat *oldfPosition; + double *olddPosition; + jfloat *oldNormal; + jfloat *oldfDiffuse; + jbyte *oldbDiffuse; + float* oldTexCoords[D3DDP_MAXTEXCOORD]; + int vc; + int texSetUsed = d3dCtx->texSetUsed; + LPDIRECT3DDEVICE9 device = d3dCtx->pDevice; + jfloat fr, fg, fb, fa; + jbyte br, bg, bb, ba; + boolean success; + + DWORD vertexFormat = d3dCtx->pVB->vertexFormat; + + // save stride pointers since strip set may have + // multiple call to this procedure. + oldfPosition = strideData->fpositionPtr; + olddPosition = strideData->dpositionPtr; + oldNormal = strideData->normalPtr; + oldfDiffuse = strideData->fdiffusePtr; + oldbDiffuse = strideData->bdiffusePtr; + + for (i=0; i < texSetUsed; i++) { + oldTexCoords[i] = strideData->textureCoordsPtr[i]; + } + + + + switch (d3dCtx->pVB->primitiveType) { + case D3DPT_TRIANGLEFAN: + { + // Copy the very first vertx and repeat the last vertex + jfloat fx, fy, fz, nx, ny, nz; + jdouble dx, dy, dz; + jfloat tx[D3DDP_MAXTEXCOORD]; + jfloat ty[D3DDP_MAXTEXCOORD]; + jfloat tz[D3DDP_MAXTEXCOORD]; + jfloat tw[D3DDP_MAXTEXCOORD]; + inc = maxVertexLimit - 2; + + if (oldfPosition) { + fx = *oldfPosition; + fy = *(oldfPosition+1); + fz = *(oldfPosition+2); + } else { + // must be double, since this routine will + // not invoke when there is no position available + dx = *olddPosition; + dy = *(olddPosition+1); + dz = *(olddPosition+2); + } + + if (oldNormal) { + nx = *oldNormal; + ny = *(oldNormal+1); + nz = *(oldNormal+2); + } + if (oldfDiffuse) { + fr = *oldfDiffuse; + fg = *(oldfDiffuse+1); + fb = *(oldfDiffuse+2); + if (strideData->useAlpha) { + fa = *(oldfDiffuse+3); + } + } else if (oldbDiffuse) { + br = *oldbDiffuse; + bg = *(oldbDiffuse+1); + bb = *(oldbDiffuse+2); + if (strideData->useAlpha) { + ba = *(oldbDiffuse+3); + } + } + + for (i=0; i < texSetUsed; i++) { + tx[i] = *oldTexCoords[i]; + ty[i] = *(oldTexCoords[i]+1); + if (d3dCtx->texStride[i] > 2) { + tz[i] = *(oldTexCoords[i]+2); + if (d3dCtx->texStride[i] > 3) { + tw[i] = *(oldTexCoords[i]+3); + } + } + } + while (true) { + vc = (vcount >= maxVertexLimit ? maxVertexLimit : vcount); + + success = createCopyVBVertex(d3dCtx, device, strideData, + vc, cDirty, xform, nxform); + // restore old values + if (oldfPosition) { + *(strideData->fpositionPtr) = fx; + *(strideData->fpositionPtr+1) = fy; + *(strideData->fpositionPtr+2) = fz; + } else { + *(strideData->dpositionPtr) = dx; + *(strideData->dpositionPtr+1) = dy; + *(strideData->dpositionPtr+2) = dz; + } + if (oldNormal) { + *(strideData->normalPtr) = nx; + *(strideData->normalPtr+1) = ny; + *(strideData->normalPtr+2) = nz; + } + if (oldfDiffuse) { + *(strideData->fdiffusePtr) = fr; + *(strideData->fdiffusePtr+1) = fg; + *(strideData->fdiffusePtr+2) = fb; + if (strideData->useAlpha) { + *(strideData->fdiffusePtr+3) = fa; + } + } else if (oldbDiffuse) { + *(strideData->bdiffusePtr) = br; + *(strideData->bdiffusePtr+1) = bg; + *(strideData->bdiffusePtr+2) = bb; + if (strideData->useAlpha) { + *(strideData->bdiffusePtr+3) = ba; + } + } + for (i=0; i < texSetUsed; i++) { + *(strideData->textureCoordsPtr[i]) = tx[i]; + *(strideData->textureCoordsPtr[i]+1) = ty[i]; + if (d3dCtx->texStride[i] > 2) { + *(strideData->textureCoordsPtr[i]+2) = tz[i]; + if (d3dCtx->texStride[i] > 3) { + *(strideData->textureCoordsPtr[i]+3) = tw[i]; + } + } + } + + vcount -= inc; + if (!success || (vcount <= 2)) { + break; + } + + if (oldfPosition) { + strideData->fpositionPtr += strideData->positionStride*inc; + fx = *strideData->fpositionPtr; + *strideData->fpositionPtr = *oldfPosition; + fy = *(strideData->fpositionPtr+1); + *(strideData->fpositionPtr+1) = *(oldfPosition+1); + fz = *(strideData->fpositionPtr+2); + *(strideData->fpositionPtr+2) = *(oldfPosition+2); + } else { + strideData->dpositionPtr += strideData->positionStride*inc; + dx = *strideData->dpositionPtr; + *strideData->dpositionPtr = *olddPosition; + dy = *(strideData->dpositionPtr+1); + *(strideData->dpositionPtr+1) = *(olddPosition+1); + dz = *(strideData->dpositionPtr+2); + *(strideData->dpositionPtr+2) = *(olddPosition+2); + } + + + if (oldNormal) { + strideData->normalPtr += strideData->normalStride*inc; + nx = *strideData->normalPtr; + *strideData->normalPtr = *oldNormal; + ny = *(strideData->normalPtr+1); + *(strideData->normalPtr+1) = *(oldNormal+1); + nz = *(strideData->normalPtr+2); + *(strideData->normalPtr+2) = *(oldNormal+2); + } + + if (oldfDiffuse) { + strideData->fdiffusePtr += strideData->diffuseStride*inc; + fr = *strideData->fdiffusePtr; + *strideData->fdiffusePtr = *oldfDiffuse; + fg = *(strideData->fdiffusePtr+1); + *(strideData->fdiffusePtr+1) = *(oldfDiffuse+1); + fb = *(strideData->fdiffusePtr+2); + *(strideData->fdiffusePtr+2) = *(oldfDiffuse+2); + if (strideData->useAlpha) { + fa = *(strideData->fdiffusePtr+3); + *(strideData->fdiffusePtr+3) = *(oldfDiffuse+3); + } + } else if (oldbDiffuse) { + strideData->bdiffusePtr += strideData->diffuseStride*inc; + br = *strideData->bdiffusePtr; + *strideData->bdiffusePtr = *oldbDiffuse; + bg = *(strideData->bdiffusePtr+1); + *(strideData->bdiffusePtr+1) = *(oldbDiffuse+1); + bb = *(strideData->bdiffusePtr+2); + *(strideData->bdiffusePtr+2) = *(oldbDiffuse+2); + if (strideData->useAlpha) { + ba = *(strideData->bdiffusePtr+3); + *(strideData->bdiffusePtr+3) = *(oldbDiffuse+3); + } + } + + for (i=0; i < texSetUsed; i++) { + strideData->textureCoordsPtr[i] += + strideData->textureCoordsStride[i]*inc; + + tx[i] = *strideData->textureCoordsPtr[i]; + ty[i] = *(strideData->textureCoordsPtr[i]+1); + *(strideData->textureCoordsPtr[i]) = *oldTexCoords[i]; + *(strideData->textureCoordsPtr[i]+1) = *(oldTexCoords[i]+1); + if (d3dCtx->texStride[i] > 2) { + tz[i] = *(strideData->textureCoordsPtr[i]+2); + *(strideData->textureCoordsPtr[i]+2) + = *(oldTexCoords[i]+ 2); + if (d3dCtx->texStride[i] > 3) { + tw[i] = *(strideData->textureCoordsPtr[i]+3); + *(strideData->textureCoordsPtr[i]+3) + = *(oldTexCoords[i]+ 3); + } + + } + } + + } + break; + } + case D3DPT_POINTLIST: + if (max == 0) { + max = maxVertexLimit; + } + // fall through + case D3DPT_LINESTRIP: + if (max == 0) { + max = maxVertexLimit; + min = 1; // repeat the last vertex; + } + // fall through + case D3DPT_TRIANGLELIST: + if (max == 0) { + if (d3dCtx->pVB->isIndexPrimitive) { + // QuadArray + max = maxVertexLimit - (maxVertexLimit % 4); + } else { + max = maxVertexLimit - (maxVertexLimit % 3); + } + } + // fall through + case D3DPT_LINELIST: + if (max == 0) { + max = maxVertexLimit - (maxVertexLimit % 2); + } + // fall through + case D3DPT_TRIANGLESTRIP: + if (max == 0) { + max = maxVertexLimit - (maxVertexLimit % 4); + min = 2; // repeat the last two vertices + } + inc = max - min; + + while (true) { + vc = (vcount >= max ? max : vcount); + + if (!createCopyVBVertex(d3dCtx, device, strideData, vc, + cDirty, xform, nxform)) { + break; + } + + vcount -= inc; + if (vcount <= min) { + break; + } + if (oldfPosition) { + strideData->fpositionPtr += strideData->positionStride*inc; + } else { + strideData->dpositionPtr += strideData->positionStride*inc; + } + + if (oldNormal) { + strideData->normalPtr += strideData->normalStride*inc; + } + if (oldfDiffuse) { + strideData->fdiffusePtr += strideData->diffuseStride*inc; + } else if (oldbDiffuse) { + strideData->bdiffusePtr += strideData->diffuseStride*inc; + } + for (i=0; i < texSetUsed; i++) { + strideData->textureCoordsPtr[i] += + strideData->textureCoordsStride[i]*inc; + } + } + break; + } + + // Restore old pointers; + strideData->fpositionPtr = oldfPosition; + strideData->dpositionPtr = olddPosition; + strideData->normalPtr = oldNormal; + strideData->fdiffusePtr = oldfDiffuse; + strideData->bdiffusePtr = oldbDiffuse; + + for (i=0; i < texSetUsed; i++) { + strideData->textureCoordsPtr[i] = oldTexCoords[i]; + } +} + + +BOOL reIndexifyIndexVertexToVBs(D3dCtx *d3dCtx, + D3DDRAWPRIMITIVESTRIDEDDATA* strideData, + DWORD indexCount, + DWORD vcount, + jint cDirty, + BOOL expandQuadIndex, + DWORD maxVertexLimit, + jdouble* xform, + jdouble* nxform) +{ + LPD3DVERTEXBUFFER vb = d3dCtx->pVB; + HRESULT hr; + LPDIRECT3DDEVICE9 device = d3dCtx->pDevice; + + int vbSize; + + if (!expandQuadIndex) { + vbSize = indexCount; + } else { + vbSize = (3*indexCount) >> 1; + } + + if (vb->stripLen > 0) { + // VertexBuffer already used, create a new one or used + // the next VB in the list + // maxVertexLimit is already check before, so we can + // pass indexCount as maxVertexLimit. + // The maximum vertex that can happens is equal + // to indexCount so we can just set vcount = indexCount + vb = vb->nextVB; + if ((vb != NULL) && (vb->vcount < vbSize)) { + delete vb; + d3dCtx->pVB->nextVB = NULL; + vb = NULL; + } + + if (vb == NULL) { + vb = new D3dVertexBuffer(); + if (vb == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY); + return false; + } + + vb->stride = d3dCtx->pVB->stride; + vb->vertexFormat = d3dCtx->pVB->vertexFormat; + // Don't set totalVertexCount + vb->isIndexPrimitive = d3dCtx->pVB->isIndexPrimitive; + vb->primitiveType = d3dCtx->pVB->primitiveType; + vb->isPointFlagUsed = d3dCtx->pVB->isPointFlagUsed; + vb->vcount = vbSize; + vb->maxVertexLimit = maxVertexLimit; + +#ifdef VBDEBUG + printf("Create secondary VertexBuffer of size %d, display list ID %d, pointFlag %d\n", + vbSize, d3dCtx->currDisplayListID, vb->isPointFlagUsed); +#endif + + if (!vb->isPointFlagUsed) { + hr = device->CreateVertexBuffer(vb->stride*vbSize, + D3DUSAGE_WRITEONLY, + vb->vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + } else { + hr = device->CreateVertexBuffer(vb->stride*vbSize, + D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS, + vb->vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + vb->isPointFlagUsed = true; + } + + if (FAILED(hr)) { + vb->buffer = NULL; + vb->release(); + D3dCtx::d3dWarning(CREATEVBFAIL, hr); + return false; + } + d3dCtx->pVB->nextVB = vb; + cDirty = javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED; + } + } + + if (vb->indexBuffer == NULL) { + // No need to set totalIndexCount + vb->indexCount = vbSize; + + if (indexCount <= 0xffff) { + hr = device->CreateIndexBuffer(vbSize*sizeof(WORD), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX16, + D3DPOOL_DEFAULT, + &vb->indexBuffer, + NULL); + } else { + hr = device->CreateIndexBuffer(vbSize*sizeof(UINT), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX32, + D3DPOOL_DEFAULT, + &vb->indexBuffer, + NULL); + } + + if (FAILED(hr)) { + vb->indexBuffer = NULL; + vb->release(); + D3dCtx::d3dWarning(CREATEINDEXVBFAIL, hr); + return false; + } + + cDirty |= javax_media_j3d_GeometryArrayRetained_INDEX_CHANGED; + } + + float *vbptr; + // Note that DWORD (use for color) is of same size + // as float (use for vertex/normal) + hr = vb->buffer->Lock(0, 0, (VOID**)&vbptr, 0); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKVBFAIL, hr); + // recreate it next time + vb->release(); + return false; + } + + d3dCtx->pVB = vb; + + // The current VB is not yet used. + vb->stripLen = 0; + + if (cDirty) { + D3DINDEXBUFFER_DESC desc; + BYTE *bptr; + + vb->indexBuffer->GetDesc(&desc); + hr = vb->indexBuffer->Lock(0, 0, (VOID**)&bptr, 0); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKINDEXVBFAIL, hr); + vb->buffer->Unlock(); + return false; + } + + if (d3dCtx->reIndexifyTable == NULL) { + // vcount will not change during renderIndexGeometry + // and splitIndexVertex so it is safe not to check + // size of reIndexifyTable and recreate a bigger + // one. + d3dCtx->reIndexifyTable = new DWORD[vcount]; + if (d3dCtx->reIndexifyTable == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY, hr); + vb->release(); + return false; + } + + } + + ZeroMemory(d3dCtx->reIndexifyTable, sizeof(DWORD)*vcount); + + DWORD i; + jint *idxPtr = strideData->indexPtr + strideData->initialIndexIndex; + USHORT firstEntry = *idxPtr; + DWORD *table = d3dCtx->reIndexifyTable; + + if (desc.Format == D3DFMT_INDEX16) { + USHORT *dst = (USHORT *) bptr; + USHORT newIdx, prevIdx = -1, count = 0; + USHORT idx[3], vc = 0; + + for (i=0; i < indexCount; i++) { + newIdx = table[*idxPtr]; + if ((newIdx == 0) && (*idxPtr != firstEntry)) { + newIdx = ++count; + table[*idxPtr] = newIdx; + } + if (!expandQuadIndex) { + *dst++ = newIdx; + } else { + if (vc < 3) { + idx[vc++] = newIdx; + } else { + // vc = 3 + *dst++ = idx[0]; + *dst++ = idx[1]; + *dst++ = idx[2]; + *dst++ = idx[0]; + *dst++ = idx[2]; + *dst++ = newIdx; + vc = 0; + } + } + if (newIdx != prevIdx) { + copyOneVertexToVB(d3dCtx, &vbptr, strideData, + *idxPtr++, cDirty, xform, nxform); + prevIdx = newIdx; + } else { + idxPtr++; + } + + } + } else { + DWORD *dst = (DWORD *) bptr; + DWORD newIdx, prevIdx = -1, count = 0; + DWORD idx[3], vc = 0; + + for (i=0; i < indexCount; i++) { + newIdx = table[*idxPtr]; + if ((newIdx == 0) && (*idxPtr != firstEntry)) { + newIdx = ++count; + table[*idxPtr] = newIdx; + } + if (!expandQuadIndex) { + *dst++ = newIdx; + } else { + if (vc < 3) { + idx[vc++] = newIdx; + } else { + // vc = 3 + *dst++ = idx[0]; + *dst++ = idx[1]; + *dst++ = idx[2]; + *dst++ = idx[0]; + *dst++ = idx[2]; + *dst++ = newIdx; + vc = 0; + } + } + if (newIdx != prevIdx) { + copyOneVertexToVB(d3dCtx, &vbptr, strideData, + *idxPtr++, cDirty, xform, nxform); + prevIdx = newIdx; + } else { + idxPtr++; + } + } + } + } + + + vb->addStride(vbSize); + vb->indexBuffer->Unlock(); + vb->buffer->Unlock(); + return true; +} + + +void splitIndexVertexToMultipleVB(D3dCtx *d3dCtx, + LPD3DDRAWPRIMITIVESTRIDEDDATA strideData, + int indexCount, + int vertexCount, + int maxVertexLimit, + jint cDirty, + BOOL expandQuadIndex, + jdouble* xform, + jdouble* nxform) +{ + int vc; + BOOL success; + int inc; + int min = 0; + int max = 0; + int initialIdxIdx = strideData->initialIndexIndex; + + + switch (d3dCtx->pVB->primitiveType) { + case D3DPT_TRIANGLEFAN: + { + jint firstIdx = strideData->indexPtr[initialIdxIdx]; + jint prevIdx = firstIdx; + + inc = maxVertexLimit - 2; + + while (true) { + vc = (indexCount >= maxVertexLimit ? maxVertexLimit : indexCount); + success = reIndexifyIndexVertexToVBs(d3dCtx, + strideData, + vc, + vertexCount, + cDirty, + expandQuadIndex, + maxVertexLimit, + xform, nxform); + // restore index + strideData->indexPtr[strideData->initialIndexIndex] = prevIdx; + indexCount -= inc; + + if (!success || (indexCount <= 2)) { + break; + } + // repeat the last index + strideData->initialIndexIndex += (vc - 2); + // replace by first index + prevIdx = strideData->indexPtr[strideData->initialIndexIndex]; + strideData->indexPtr[strideData->initialIndexIndex] = firstIdx; + } + } + break; + case D3DPT_POINTLIST: + if (max == 0) { + max = maxVertexLimit; + } + // fall through + case D3DPT_LINESTRIP: + if (max == 0) { + max = maxVertexLimit; + min = 1; // repeat the last vertex; + } + // fall through + case D3DPT_TRIANGLELIST: + if (max == 0) { + if (expandQuadIndex) { + // QuadArray + max = maxVertexLimit - (maxVertexLimit % 4); + } else { + max = maxVertexLimit - (maxVertexLimit % 3); + } + } + // fall through + case D3DPT_LINELIST: + if (max == 0) { + max = maxVertexLimit - (maxVertexLimit % 2); + } + // fall through + case D3DPT_TRIANGLESTRIP: + if (max == 0) { + max = maxVertexLimit - (maxVertexLimit % 4); + min = 2; // repeat the last two vertices + } + inc = max - min; + + while (true) { + vc = (indexCount >= max ? max : indexCount); + + if (!reIndexifyIndexVertexToVBs(d3dCtx, + strideData, + vc, + vertexCount, + cDirty, + expandQuadIndex, + maxVertexLimit, + xform, nxform)) { + break; + } + + indexCount -= inc; + if (indexCount <= min) { + break; + } + strideData->initialIndexIndex += inc; + } + } + strideData->initialIndexIndex = initialIdxIdx; +} + +// This is used by quad polygon line mode +void DrawPolygonLine(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + DWORD vertexFormat, + D3DDRAWPRIMITIVESTRIDEDDATA *strideData) +{ + HRESULT hr; + float *vbptr; + + hr = d3dCtx->pVB->buffer->Lock(0, 0, (VOID**) &vbptr, 0 ); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKVBFAIL, hr); + return; + } + // DisplayList will not use in this case, so xform = nxform = NULL + copyVertexToVB(d3dCtx, strideData, 4, &vbptr, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED, true, + NULL, NULL); + d3dCtx->pVB->buffer->Unlock(); + device->SetStreamSource(0, d3dCtx->pVB->buffer, 0, + d3dCtx->pVB->stride); + device->SetIndices(d3dCtx->lineModeIndexBuffer); + //device->SetVertexShader(vertexFormat); + device->SetVertexShader(NULL); + device->SetFVF(vertexFormat); + + device->DrawIndexedPrimitive(D3DPT_LINESTRIP,0, 0, 4, 0, 4); +} + + +// This is used by indexed quad polygon line mode +void DrawIndexPolygonLine(D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + DWORD vertexFormat, + D3DDRAWPRIMITIVESTRIDEDDATA *strideData, + jint idx0, jint idx1, jint idx2, jint idx3) +{ + HRESULT hr; + float *vbptr; + + hr = d3dCtx->pVB->buffer->Lock(0, 0, (VOID**) &vbptr, 0 ); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKVBFAIL, hr); + return; + } + + copyOneVertexToVB(d3dCtx, &vbptr, strideData, idx0, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED, + NULL, NULL); + copyOneVertexToVB(d3dCtx, &vbptr, strideData, idx1, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED, + NULL, NULL); + copyOneVertexToVB(d3dCtx, &vbptr, strideData, idx2, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED, + NULL, NULL); + copyOneVertexToVB(d3dCtx, &vbptr, strideData, idx3, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED, + NULL, NULL); + + d3dCtx->pVB->buffer->Unlock(); + device->SetStreamSource(0, d3dCtx->pVB->buffer, 0, + d3dCtx->pVB->stride); + //device->SetVertexShader(vertexFormat); + device->SetVertexShader(NULL); + device->SetFVF(vertexFormat); + + device->SetIndices(d3dCtx->lineModeIndexBuffer); + + device->DrawIndexedPrimitive(D3DPT_LINESTRIP,0, 0, 4, 0, 4); +} + + +void renderGeometry(JNIEnv *env, + D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + jobject geo, + jint geo_type, + D3DDRAWPRIMITIVESTRIDEDDATA *strideData, + DWORD vertexFormat, + jint vcount, + jdouble* xform, + jdouble* nxform, + jint cDirty) +{ + D3DPRIMITIVETYPE d3dRenderType; + BOOL renderTypeSet = false; + int i, j, genMode; + LPD3DVERTEXBUFFER vb = NULL; + D3dVertexBufferVector *vbVector; + float *vbptr; + +#ifdef VBDEBUG + BOOL createNew = false; +#endif + + if (vcount <= 0) { + return; + } + + jclass geoClass = env->GetObjectClass(geo); + DWORD maxVertexLimit = d3dCtx->deviceInfo->maxVertexCount[geo_type]; + DWORD texSetUsed = d3dCtx->texSetUsed; + HRESULT hr; + BOOL needPointFlag = (geo_type == GEO_TYPE_POINT_SET) || + ((geo_type != GEO_TYPE_LINE_STRIP_SET) && + (geo_type != GEO_TYPE_LINE_SET) && + (d3dCtx->fillMode == D3DFILL_POINT)); + + BOOL buildDL = (d3dCtx->currDisplayListID > 0); + + lockGeometry(); + + if (!buildDL) { + jfieldID fieldID = env->GetFieldID(geoClass, "pVertexBuffers", "J"); + jobject cloneSource = NULL; + + vbVector = reinterpret_cast + (env->GetLongField(geo, fieldID)); + + if (vbVector == NULL) { + // It is possible this is the mirrorGeometry + // from cloneNonIndexGeometry() + jfieldID fieldID2 = env->GetFieldID(geoClass, + "cloneSourceArray", + "Ljavax/media/j3d/IndexedGeometryArrayRetained;"); + cloneSource = env->GetObjectField(geo, fieldID2); + + if (cloneSource != NULL) { + jclass cloneClass = env->GetObjectClass(cloneSource); + fieldID = env->GetFieldID(cloneClass, "pVertexBuffers", "J"); + + vbVector = reinterpret_cast + (env->GetLongField(cloneSource, fieldID)); + } + + } + + + // This is the first time rendering is invoked on the + // first GeometryArray + if (vbVector == NULL) { + vbVector = new D3dVertexBufferVector(); + if (vbVector == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY); + unlockGeometry(); + return; + } + if (cloneSource == NULL) { + env->SetLongField(geo, fieldID, + reinterpret_cast(vbVector)); + } else { + env->SetLongField(cloneSource, fieldID, + reinterpret_cast(vbVector)); + } + + } else { + // Found the vb in the list of vbVector + for (ITER_LPD3DVERTEXBUFFER s = vbVector->begin(); + s != vbVector->end(); ++s) { + if ((*s)->ctx == d3dCtx) { + vb = *s; + break; + } + } + } + } + + if (vb == NULL) { + // This is the first time rendering is invoked + // using this ctx + vb = new D3dVertexBuffer(); + + if (vb == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY); + unlockGeometry(); + return; + } + vb->ctx = d3dCtx; + vb->maxVertexLimit = maxVertexLimit; + + if (!buildDL) { + vb->vbVector = vbVector; + + // add it to the GeometryArray pVertexBuffers list + vbVector->push_back(vb); + + // add it to the ctx lists + vb->next = d3dCtx->vertexBufferTable.next; + vb->previous = &(d3dCtx->vertexBufferTable); + d3dCtx->vertexBufferTable.next = vb; + if (vb->next != NULL) { + vb->next->previous = vb; + } + } + } + + if ((vb->buffer != NULL) && + ((vb->vertexFormat != vertexFormat) || + (vb->totalVertexCount < vcount) || + (cDirty & + javax_media_j3d_GeometryArrayRetained_STRIPCOUNT_CHANGED) || + (!vb->isPointFlagUsed && needPointFlag))) { + // immediate release VB and reconstruct a new one + vb->release(); + } + + if (vb->buffer == NULL) { + vb->stride = D3DXGetFVFVertexSize(vertexFormat); + vb->vertexFormat = vertexFormat; + vb->totalVertexCount = vcount; + vb->vcount = (vcount >= maxVertexLimit ? maxVertexLimit : vcount); +#ifdef VBDEBUG + printf("Create primary VertexBuffer of size %d, display list ID %d, pointFlag %d\n", + vb->vcount, d3dCtx->currDisplayListID, needPointFlag); +#endif + if (!needPointFlag) { + hr = device->CreateVertexBuffer(vb->stride*vb->vcount, + D3DUSAGE_WRITEONLY, + vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + } else { + hr = device->CreateVertexBuffer(vb->stride*vb->vcount, + D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS, + vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + vb->isPointFlagUsed = true; + } + + if (FAILED(hr)) { + vb->buffer = NULL; + D3dCtx::d3dWarning(CREATEVBFAIL, hr); + unlockGeometry(); + return; + } +#ifdef VBDEBUG + createNew = true; +#endif + cDirty = javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED; + } + + unlockGeometry(); + + if (buildDL) { + // In display list mode, add it to the displayList ID table + d3dCtx->displayListTable[d3dCtx->currDisplayListID]->add(vb); + } else { + + if (vb->primitiveType == D3DPT_FORCE_DWORD) { + // This happens when previous frame use Quad Line + // so buffer not yet initialize + cDirty = javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED; + } + + if (!cDirty && + ((geo_type != GEO_TYPE_QUAD_SET) || + (d3dCtx->fillMode != D3DFILL_WIREFRAME))) { + for (i=0; i < d3dCtx->texSetUsed; i++) { + genMode = strideData->texCoordPosition[i]; + if ((genMode == TEX_OBJ_LINEAR) || + ((genMode != vb->texCoordPosition[i]) && + (genMode != TEX_GEN_AUTO))) { + // For object linear mode user can set the plane + // equations so we need to change texture coordinate. + break; + } + } + if (i == d3dCtx->texSetUsed) { + vb->render(d3dCtx); +#ifdef TEXDEBUG + printf("Skip VB Copy\n"); +#endif + return; + } + } + } + + // Note that DWORD (use for color) is of same size + // as float (use for vertex/normal) + + hr = vb->buffer->Lock(0, 0, (VOID**)&vbptr, 0); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKVBFAIL, hr); + // recreate it next time + vb->release(); + return; + } + + d3dCtx->pVB = vb; + // The current VB is not yet used. + vb->stripLen = 0; + + switch (geo_type) { + case GEO_TYPE_TRI_STRIP_SET: + d3dRenderType = D3DPT_TRIANGLESTRIP; + renderTypeSet = true; +#ifdef VBDEBUG + if (createNew) { + printf("Tri strip set %d\n", vcount); + } +#endif + // fall through + case GEO_TYPE_TRI_FAN_SET: + if (renderTypeSet == false) { +#ifdef VBDEBUG + if (createNew) { + printf("Tri fan set %d\n", vcount); + } +#endif + d3dRenderType = D3DPT_TRIANGLEFAN; + renderTypeSet = true; + } + // fall through + case GEO_TYPE_LINE_STRIP_SET: + { + if (renderTypeSet == false) { + d3dRenderType = D3DPT_LINESTRIP; + renderTypeSet = true; +#ifdef VBDEBUG + if (createNew) { + printf("Tri line set %d \n", vcount); + } +#endif + } + + jfieldID strip_field = env->GetFieldID(geoClass, + "stripVertexCounts", "[I"); + jarray sarray = (jarray)env->GetObjectField(geo, strip_field); + jsize strip_len = (jsize)env->GetArrayLength(sarray); + + jint* strips = (jint *)env->GetPrimitiveArrayCritical(sarray, NULL); + + int nlastStrip = 0; + int totalLen = 0; + int oldTotalLen = 0; + int vsum = 0; + + vb->primitiveType = d3dRenderType; + + if (vcount <= vb->vcount) { + copyVertexToVB(d3dCtx, strideData, vcount, + &vbptr, cDirty, false, xform, nxform); + vb->addStrides(strip_len, strips); +#ifdef VBDEBUG + if (createNew) { + printf("Strip Length %d : ", strip_len); + for (int k=0; k < strip_len; k++) { + printf("%d ", strips[k]); + } + printf("\n"); + } +#endif + } else { +#ifdef VBDEBUG + if (createNew) { + printf("Strip Length %d : ", strip_len); + } +#endif + + for (i = 0; i < strip_len; i++) { + if (strideData->fpositionPtr) { + strideData->fpositionPtr += + strideData->positionStride*nlastStrip; + } else { + strideData->dpositionPtr += + strideData->positionStride*nlastStrip; + } + + if (strideData->normalPtr) { + strideData->normalPtr += + strideData->normalStride*nlastStrip; + } + + if (strideData->fdiffusePtr) { + strideData->fdiffusePtr += + strideData->diffuseStride*nlastStrip; + } else if (strideData->bdiffusePtr) { + strideData->bdiffusePtr += + strideData->diffuseStride*nlastStrip; + } + + + if (strideData->textureCoordsPtr[0]) { + for (j=0; j < texSetUsed; j++) { + strideData->textureCoordsPtr[j] += + strideData->textureCoordsStride[j]* nlastStrip; + } + } + + + nlastStrip = strips[i]; + oldTotalLen = totalLen; + totalLen += nlastStrip; + + if (totalLen > vcount) { + // This should not happen since + // setValidVertexCount is disable + // in v1.3. We should always have + // (sum of strips[] < vcount) + nlastStrip = (vcount - (totalLen - nlastStrip)); + totalLen = vcount; + } + + if (nlastStrip <= 0) { + continue; + } + + + if (vbptr == NULL) { + // This happen when the lastStrip copy + // is greater than maxVertexLimit. + // So we Unlock the last buffer + vbptr = allocateVB(d3dCtx, device, + vcount - oldTotalLen, + maxVertexLimit, &cDirty); + vsum = 0; + if (vbptr == NULL) { + break; // render whatever geometry the current VB have + } + } +#ifdef VBDEBUG + if (createNew) { + printf(" %d ", nlastStrip); + } +#endif + if ((vsum + nlastStrip) <= d3dCtx->pVB->vcount) { + // There is space available to put in vertices + vsum += nlastStrip; + copyVertexToVB(d3dCtx, strideData, nlastStrip, + &vbptr, cDirty, true, xform, nxform); + } else { + // Need to create a new VB + if (nlastStrip <= maxVertexLimit) { + // No need to split strip in multiple VB + if (d3dCtx->pVB->stripLen > 0) { + if (vbptr != NULL) { + d3dCtx->pVB->buffer->Unlock(); + } + vbptr = allocateVB(d3dCtx, device, + vcount - oldTotalLen, + maxVertexLimit, &cDirty); + if (vbptr == NULL) { + break; + } + vsum = 0; + } + vsum += nlastStrip; + copyVertexToVB(d3dCtx, strideData, nlastStrip, + &vbptr, cDirty, true, + xform, nxform); + } else { + d3dCtx->pVB->buffer->Unlock(); + vbptr = NULL; + vsum = 0; + // Multiple VBs for large vertex size + splitVertexToMultipleVB(d3dCtx, strideData, + nlastStrip, + maxVertexLimit, + cDirty, xform, nxform); + vbptr = NULL; + } + } + } +#ifdef VBDEBUG + if (createNew) { + printf("\n"); + } +#endif + } + env->ReleasePrimitiveArrayCritical(sarray, strips, NULL); + } + break; + case GEO_TYPE_QUAD_SET: +#ifdef VBDEBUG + if (createNew) { + printf("quad set %d\n", vcount); + } +#endif + + if (buildDL || + (d3dCtx->fillMode != D3DFILL_WIREFRAME)) { + /* + * Note we can't just check + * if (d3dCtx->fillMode != D3DFILL_WIREFRAME) + * since the fillMode may set back to + * non-line mode AFTER build display list + * In fact it is gaurantee that when displaylist + * mode is used we are not in line mode + */ + + // break down solid into two triangles + if (createQuadIndices(d3dCtx, vcount)) { + // It happens when + // vcount*3/2 != d3dCtx->quadIndexBufferSize + // to conform with index buffer Limitation in + // graphics card. So we adjust using a smaller + // maxVertexLimit when spliting into + // multiple Vertex Buffers. + maxVertexLimit = 2*d3dCtx->quadIndexBufferSize/3; + vb->maxVertexLimit = maxVertexLimit; + vb->vcount = vb->maxVertexLimit; + } + d3dRenderType = D3DPT_TRIANGLELIST; + vb->isIndexPrimitive = true; + renderTypeSet = true; + // fall through + } + else + { // line mode + // we don't want to see extra line appear in the + // diagonal of quads if it splits into two + // triangles. This is REALLY SLOW !!! + int len = vcount >> 2; + int offsetPos = 0; + int offsetNorm = 0; + int offsetColor = 0; + int strideOffsetPos = strideData->positionStride << 2; + int strideOffsetNorm = strideData->normalStride << 2; + int strideOffsetColor = strideData->diffuseStride << 2; + jfloat *pdf = strideData->fpositionPtr; + jdouble *pdd = strideData->dpositionPtr; + jfloat *pn = strideData->normalPtr; + jfloat *pcf = strideData->fdiffusePtr; + jbyte *pcb = strideData->bdiffusePtr; + jfloat* pt[D3DDP_MAXTEXCOORD]; + + pt[0] = NULL; + + if (((vertexFormat & D3DFVF_DIFFUSE) == 0) && + (!d3dCtx->isLightEnable)) { + d3dCtx->setAmbientLightMaterial(); + } + + vb->buffer->Unlock(); + vbptr = NULL; +#ifdef VBDEBUG + if (createNew) { + printf("quad set polygon line %d\n", vcount); + } +#endif + + for (i=0; i < texSetUsed; i++) { + pt[i] = (FLOAT *) strideData->textureCoordsPtr[i]; + } + + jfloat *fptr; + jdouble *dptr; + jbyte *bptr; + jfloat *fspt; + jdouble *dspt; + int posStride = strideData->positionStride; + D3DVERTEX worldCoord[3]; + D3DTLVERTEX screenCoord[3]; + + vb->primitiveType = D3DPT_FORCE_DWORD; + + if (d3dCtx->lineModeIndexBuffer == NULL) { + createLineModeIndexBuffer(d3dCtx); + } + + for (i = 0; i < (vcount >> 2); i++) { + if (pdf) { + fspt = fptr = pdf + offsetPos; + strideData->fpositionPtr = fptr; + } else { + dspt = dptr = pdd + offsetPos; + strideData->dpositionPtr = dptr; + } + + if (pn) { + fptr = pn + offsetNorm; + strideData->normalPtr = fptr; + } + + if (pcf) { + fptr = pcf + offsetColor; + strideData->fdiffusePtr = fptr; + } else if (pcb) { + bptr = pcb + offsetColor; + strideData->bdiffusePtr = bptr; + } + + if (pt[0]) { + for (j=0; j < texSetUsed; j++) { + DWORD stride3 = 3*strideData->textureCoordsStride[j]; + fptr = pt[j] + i*(strideData->textureCoordsStride[j] << 2); + strideData->textureCoordsPtr[j] = fptr; + } + } + if (d3dCtx->cullMode != D3DCULL_NONE) { + // Do back face culling here + if (pdf) { + worldCoord[0].x = fspt[0]; + worldCoord[0].y = fspt[1]; + worldCoord[0].z = fspt[2]; + fspt += posStride; + worldCoord[1].x = fspt[0]; + worldCoord[1].y = fspt[1]; + worldCoord[1].z = fspt[2]; + fspt += posStride; + worldCoord[2].x = fspt[0]; + worldCoord[2].y = fspt[1]; + worldCoord[2].z = fspt[2]; + } else { + worldCoord[0].x = dspt[0]; + worldCoord[0].y = dspt[1]; + worldCoord[0].z = dspt[2]; + dspt += posStride; + worldCoord[1].x = dspt[0]; + worldCoord[1].y = dspt[1]; + worldCoord[1].z = dspt[2]; + dspt += posStride; + worldCoord[2].x = dspt[0]; + worldCoord[2].y = dspt[1]; + worldCoord[2].z = dspt[2]; + } + d3dCtx->transform(&worldCoord[0], &screenCoord[0]); + d3dCtx->transform(&worldCoord[1], &screenCoord[1]); + d3dCtx->transform(&worldCoord[2], &screenCoord[2]); + screenCoord[0].sx -= screenCoord[1].sx; + screenCoord[0].sy -= screenCoord[1].sy; + screenCoord[2].sx -= screenCoord[1].sx; + screenCoord[2].sy -= screenCoord[1].sy; + if (d3dCtx->cullMode == D3DCULL_CW) { + // clip back face + if ((screenCoord[0].sx*screenCoord[2].sy - + screenCoord[2].sx*screenCoord[0].sy) >= 0) { + DrawPolygonLine(d3dCtx, + device, + vertexFormat, + strideData); + } + } else { // Clip front face + if ((screenCoord[0].sx*screenCoord[2].sy - + screenCoord[2].sx*screenCoord[0].sy) <= 0) { + DrawPolygonLine(d3dCtx, + device, + vertexFormat, + strideData); + } + } + } else { + // cullMode == D3DCULL_NONE + DrawPolygonLine(d3dCtx, + device, + vertexFormat, + strideData); + } + offsetPos += strideOffsetPos; + offsetNorm += strideOffsetNorm; + offsetColor += strideOffsetColor; + } + + if (((vertexFormat & D3DFVF_DIFFUSE) == 0) && + (!d3dCtx->isLightEnable)) { + d3dCtx->restoreDefaultLightMaterial(); + } + // Don't call vb->Renderer() at the end + return; + } + // fallthrough + case GEO_TYPE_TRI_SET: + if (renderTypeSet == false) { + d3dRenderType = D3DPT_TRIANGLELIST; + renderTypeSet = true; +#ifdef VBDEBUG + if (createNew) { + printf("tri set %d\n", vcount); + } +#endif + } + // fallthrough + case GEO_TYPE_LINE_SET: + if (renderTypeSet == false) { + d3dRenderType = D3DPT_LINELIST; + renderTypeSet = true; +#ifdef VBDEBUG + if (createNew) { + printf("line set %d\n", vcount); + } +#endif + } + // fallthrough + case GEO_TYPE_POINT_SET: + if (renderTypeSet == false) { + d3dRenderType = D3DPT_POINTLIST; +#ifdef VBDEBUG + if (createNew) { + printf("point set %d\n", vcount); + } +#endif + } + vb->primitiveType = d3dRenderType; + + if (vcount <= vb->vcount) { + copyVertexToVB(d3dCtx, strideData, vcount, &vbptr, + cDirty, true, xform, nxform); + } else { + if (vbptr != NULL) { + vb->buffer->Unlock(); + vbptr = NULL; + } + + splitVertexToMultipleVB(d3dCtx, strideData, vcount, + maxVertexLimit, + cDirty, xform, nxform); + vbptr = NULL; + } + break; + default: + printf("GeometryArrayRetained_execute:unknown geo_type %ld \n", geo_type); + } + + if (vbptr != NULL) { + // d3dCtx->pVB is the last reference in VB list + d3dCtx->pVB->buffer->Unlock(); + } + + for (i=0; i < d3dCtx->texSetUsed; i++) { + d3dCtx->pVB->texCoordPosition[i] = + strideData->texCoordPosition[i]; + } + + if (!buildDL) { + // Not in displaylist mode, directly render VB + // vb is the root reference in VB list + vb->render(d3dCtx); + } +} + + +void renderIndexGeometry(JNIEnv *env, + D3dCtx *d3dCtx, + LPDIRECT3DDEVICE9 device, + jobject geo, + jint geo_type, + D3DDRAWPRIMITIVESTRIDEDDATA *strideData, + DWORD vertexFormat, + jint vcount, + jint indexCount, + jdouble* xform, + jdouble* nxform, + jint cDirty) +{ + D3DPRIMITIVETYPE d3dRenderType; + BOOL renderTypeSet = false; + BOOL expandQuadIndex = false; + int i; + LPD3DVERTEXBUFFER vb = NULL; + D3dVertexBufferVector *vbVector; + float *vbptr; + +#ifdef VBDEBUG + BOOL createNew = false; +#endif + + if (indexCount <= 0) { + return; + } + + jclass geoClass = env->GetObjectClass(geo); + DWORD maxVertexLimit = + min(d3dCtx->deviceInfo->maxVertexCount[geo_type], + d3dCtx->deviceInfo->maxVertexIndex); + DWORD texSetUsed = d3dCtx->texSetUsed; + HRESULT hr; + BOOL needPointFlag = (geo_type == GEO_TYPE_INDEXED_POINT_SET) || + ((geo_type != GEO_TYPE_INDEXED_LINE_STRIP_SET) && + (geo_type != GEO_TYPE_INDEXED_LINE_SET) && + (d3dCtx->fillMode == D3DFILL_POINT)); + + BOOL buildDL = (d3dCtx->currDisplayListID > 0); + + if (geo_type == GEO_TYPE_INDEXED_QUAD_SET) { + // Since the index we create with be 1.5 times the original index + maxVertexLimit = 2*maxVertexLimit/3; + } + + + lockGeometry(); + + if (!buildDL) { + jfieldID fieldID = env->GetFieldID(geoClass, "pVertexBuffers", "J"); + vbVector = reinterpret_cast + (env->GetLongField(geo, fieldID)); + + if (vbVector == NULL) { + // This is the first time rendering is invoked on the + // first GeometryArray + vbVector = new D3dVertexBufferVector(); + if (vbVector == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY); + unlockGeometry(); + return; + } + env->SetLongField(geo, fieldID, reinterpret_cast(vbVector)); + } else { + // Found the vb in the list of vbVector + for (ITER_LPD3DVERTEXBUFFER s = vbVector->begin(); + s != vbVector->end(); ++s) { + if ((*s)->ctx == d3dCtx) { + vb = *s; + break; + } + } + } + } + + if (vb == NULL) { + // This is the first time rendering is invoked + // using this ctx + vb = new D3dVertexBuffer(); + + if (vb == NULL) { + D3dCtx::d3dWarning(OUTOFMEMORY); + unlockGeometry(); + return; + } + vb->ctx = d3dCtx; + vb->maxVertexLimit = maxVertexLimit; + + if (!buildDL) { + vb->vbVector = vbVector; + + // add it to the GeometryArray pVertexBuffers list + vbVector->push_back(vb); + + // add it to the ctx lists + vb->next = d3dCtx->vertexBufferTable.next; + vb->previous = &(d3dCtx->vertexBufferTable); + d3dCtx->vertexBufferTable.next = vb; + if (vb->next != NULL) { + vb->next->previous = vb; + } + } + } + + if (((vb->indexBuffer != NULL) && + (vb->totalIndexCount < indexCount)) || + ((vb->buffer != NULL) && + ((vb->vertexFormat != vertexFormat) || + (vb->totalVertexCount < vcount) || + (!vb->isPointFlagUsed && needPointFlag)))) { + // immediate release VB and reconstruct a new one + vb->release(); + } + + + if (vb->buffer == NULL) { + vb->stride = D3DXGetFVFVertexSize(vertexFormat); + vb->vertexFormat = vertexFormat; + vb->totalVertexCount = vcount; + vb->isIndexPrimitive = true; + vb->vcount = (vcount >= maxVertexLimit ? maxVertexLimit : vcount); +#ifdef VBDEBUG + printf("Create primary VertexBuffer of size %d, display list ID %d, pointFlag %d\n", + vb->vcount, d3dCtx->currDisplayListID, needPointFlag); +#endif + + if (!needPointFlag) { + hr = device->CreateVertexBuffer(vb->stride*vb->vcount, + D3DUSAGE_WRITEONLY, + vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + } else { + hr = device->CreateVertexBuffer(vb->stride*vb->vcount, + D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS, + vertexFormat, + D3DPOOL_DEFAULT, + &vb->buffer, + NULL); + vb->isPointFlagUsed = true; + } + + if (FAILED(hr)) { + vb->buffer = NULL; + D3dCtx::d3dWarning(CREATEVBFAIL, hr); + unlockGeometry(); + return; + } +#ifdef VBDEBUG + createNew = true; +#endif + cDirty = javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED; + } + + if (vb->indexBuffer == NULL) { + + vb->totalIndexCount = indexCount; + vb->indexCount = (indexCount >= maxVertexLimit ? + maxVertexLimit : indexCount); + + if (geo_type == GEO_TYPE_INDEXED_QUAD_SET) { + // Since we will construct another index with + // 1.5 times of the original. + vb->indexCount = (3*vb->indexCount) >> 1; + vb->totalIndexCount = (3*indexCount) >> 1; + } + + + if (indexCount <= 0xffff) { + hr = device->CreateIndexBuffer(vb->indexCount*sizeof(WORD), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX16, + D3DPOOL_DEFAULT, + &vb->indexBuffer, + NULL); + } else { + hr = device->CreateIndexBuffer(vb->indexCount*sizeof(UINT), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX32, + D3DPOOL_DEFAULT, + &vb->indexBuffer, + NULL); + } + + if (FAILED(hr)) { + vb->indexBuffer = NULL; + D3dCtx::d3dWarning(CREATEINDEXVBFAIL, hr); + unlockGeometry(); + return; + } + + cDirty |= javax_media_j3d_GeometryArrayRetained_INDEX_CHANGED; + } + + unlockGeometry(); + + if (buildDL) { + // In display list mode, add it to the displayList ID table + d3dCtx->displayListTable[d3dCtx->currDisplayListID]->add(vb); + } else { + + if (vb->primitiveType == D3DPT_FORCE_DWORD) { + // This happens when previous frame use Quad Line + // so buffer not yet initialize + cDirty = + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED | + javax_media_j3d_GeometryArrayRetained_INDEX_CHANGED; + } + + if (!cDirty && + ((geo_type != GEO_TYPE_INDEXED_QUAD_SET) || + (d3dCtx->fillMode != D3DFILL_WIREFRAME))) { + for (i=0; i < d3dCtx->texSetUsed; i++) { + if ((strideData->texCoordPosition[i] != + vb->texCoordPosition[i]) + && + (strideData->texCoordPosition[i] != TEX_GEN_AUTO)) { + break; + } + } + if (i == d3dCtx->texSetUsed) { + vb->render(d3dCtx); + return; + } + } + } + + // Note that DWORD (use for color) is of same size + // as float (use for vertex/normal) + hr = vb->buffer->Lock(0, 0, (VOID**)&vbptr, 0); + if (FAILED(hr)) { + D3dCtx::d3dWarning(LOCKVBFAIL, hr); + // recreate it next time + vb->release(); + return; + } + + d3dCtx->pVB = vb; + + // The current VB is not yet used. + vb->stripLen = 0; + + switch (geo_type) { + case GEO_TYPE_INDEXED_TRI_STRIP_SET: + d3dRenderType = D3DPT_TRIANGLESTRIP; + renderTypeSet = true; +#ifdef VBDEBUG + if (createNew) { + printf("Tri strip set %d\n", vcount); + } +#endif + // fall through + case GEO_TYPE_INDEXED_TRI_FAN_SET: + if (renderTypeSet == false) { +#ifdef VBDEBUG + if (createNew) { + printf("Tri fan set %d\n", vcount); + } +#endif + d3dRenderType = D3DPT_TRIANGLEFAN; + renderTypeSet = true; + } + // fall through + case GEO_TYPE_INDEXED_LINE_STRIP_SET: + { + if (renderTypeSet == false) { + d3dRenderType = D3DPT_LINESTRIP; + renderTypeSet = true; +#ifdef VBDEBUG + if (createNew) { + printf("Tri line set %d \n", vcount); + } +#endif + } + + jfieldID strip_field = env->GetFieldID(geoClass, + "stripIndexCounts", "[I"); + jarray sarray = (jarray)env->GetObjectField(geo, strip_field); + jsize strip_len = (jsize)env->GetArrayLength(sarray); + + jint* strips = (jint *)env->GetPrimitiveArrayCritical(sarray, NULL); + int nlastStrip = 0; + + vb->primitiveType = d3dRenderType; +#ifdef VBDEBUG + if (createNew) { + printf("Strip Length %d : ", strip_len); + } +#endif + + if ((vb->totalIndexCount <= vb->indexCount) && + (vcount <= vb->vcount)) { + copyIndexVertexToVB(d3dCtx, strideData, + indexCount, cDirty, false, false); + copyVertexToVB(d3dCtx, strideData, vcount, + &vbptr, cDirty, false, xform, nxform); + vb->addStrides(strip_len, strips); + } else { + vb->buffer->Unlock(); + vbptr = NULL; + strideData->indexPtr += strideData->initialIndexIndex; + strideData->initialIndexIndex = 0; + for (i = 0; i < strip_len; i++) { + strideData->indexPtr += nlastStrip; + + nlastStrip = strips[i]; + + if (nlastStrip <= 0) { + continue; + } +#ifdef VBDEBUG + if (createNew) { + printf(" %d", nlastStrip); + } +#endif + if (nlastStrip <= vb->indexCount) { + reIndexifyIndexVertexToVBs(d3dCtx, strideData, + nlastStrip, vcount, + cDirty, + false, + maxVertexLimit, + xform, nxform); + } else { + // Multiple VBs for large vertex size + splitIndexVertexToMultipleVB(d3dCtx, + strideData, + nlastStrip, + vcount, + maxVertexLimit, + cDirty, + false, + xform, nxform); + } + SafeDelete(d3dCtx->reIndexifyTable); + } +#ifdef VBDEBUG + if (createNew) { + printf("\n"); + } +#endif + } + env->ReleasePrimitiveArrayCritical(sarray, strips, NULL); + } + + break; + case GEO_TYPE_INDEXED_QUAD_SET: +#ifdef VBDEBUG + if (createNew) { + printf("quad set %d\n", vcount); + } +#endif + if (buildDL || + (d3dCtx->fillMode != D3DFILL_WIREFRAME)) { + d3dRenderType = D3DPT_TRIANGLELIST; + renderTypeSet = true; + expandQuadIndex = true; + // fall through + } + // start quad WireFrame + else { + // polygon line mode + // we don't want to see extra line appear in the + // diagonal of quads if it splits into two + // triangles. This is REALLY SLOW !!! + int posStride = strideData->positionStride; + D3DVERTEX worldCoord[3]; + D3DTLVERTEX screenCoord[3]; + jint *idxPtr = strideData->indexPtr; + jfloat *fspt; + jdouble *dspt; + jint idx0, idx1, idx2, idx3; + + if (((vertexFormat & D3DFVF_DIFFUSE) == 0) && + (!d3dCtx->isLightEnable)) { + d3dCtx->setAmbientLightMaterial(); + } + + vb->buffer->Unlock(); + vbptr = NULL; +#ifdef VBDEBUG + if (createNew) { + printf("indexed quad set polygon line %d\n", vcount); + } +#endif + if (d3dCtx->lineModeIndexBuffer == NULL) { + createLineModeIndexBuffer(d3dCtx); + } + + vb->primitiveType = D3DPT_FORCE_DWORD; + + for (i = 0; i < (indexCount >> 2); i++) + { + if (d3dCtx->cullMode != D3DCULL_NONE) + { + // Do back face culling here + idx0 = *idxPtr++; + idx1 = *idxPtr++; + idx2 = *idxPtr++; + idx3 = *idxPtr++; + + if (strideData->fpositionPtr) + { + fspt = strideData->fpositionPtr + posStride*idx0; + worldCoord[0].x = *fspt++; + worldCoord[0].y = *fspt++; + worldCoord[0].z = *fspt++; + fspt = strideData->fpositionPtr + posStride*idx1; + worldCoord[1].x = *fspt++; + worldCoord[1].y = *fspt++; + worldCoord[1].z = *fspt++; + fspt = strideData->fpositionPtr + posStride*idx2; + worldCoord[2].x = *fspt++; + worldCoord[2].y = *fspt++; + worldCoord[2].z = *fspt++; + } + else + { + dspt = strideData->dpositionPtr + posStride*idx0; + worldCoord[0].x = *dspt++; + worldCoord[0].y = *dspt++; + worldCoord[0].z = *dspt++; + dspt = strideData->dpositionPtr + posStride*idx1; + worldCoord[1].x = *dspt++; + worldCoord[1].y = *dspt++; + worldCoord[1].z = *dspt++; + dspt = strideData->dpositionPtr + posStride*idx2; + worldCoord[2].x = *dspt++; + worldCoord[2].y = *dspt++; + worldCoord[2].z = *dspt++; + } + + d3dCtx->transform(&worldCoord[0], &screenCoord[0]); + d3dCtx->transform(&worldCoord[1], &screenCoord[1]); + d3dCtx->transform(&worldCoord[2], &screenCoord[2]); + screenCoord[0].sx -= screenCoord[1].sx; + screenCoord[0].sy -= screenCoord[1].sy; + screenCoord[2].sx -= screenCoord[1].sx; + screenCoord[2].sy -= screenCoord[1].sy; + + if (d3dCtx->cullMode == D3DCULL_CW) + { + if ((screenCoord[0].sx*screenCoord[2].sy - + screenCoord[2].sx*screenCoord[0].sy) >= 0) + { + DrawIndexPolygonLine(d3dCtx, + device, + vertexFormat, + strideData, + idx0, idx1, + idx2, idx3); + } + } + else + { // Clip front face + if ((screenCoord[0].sx*screenCoord[2].sy - + screenCoord[2].sx*screenCoord[0].sy) <= 0) + { + DrawIndexPolygonLine(d3dCtx, + device, + vertexFormat, + strideData, + idx0, idx1, + idx2, idx3); + } + } + } + else + { + // cullMode == D3DCULL_NONE + DrawIndexPolygonLine(d3dCtx, + device, + vertexFormat, + strideData, + idx0, idx1, + idx2, idx3); + } + }//for + + if (((vertexFormat & D3DFVF_DIFFUSE) == 0) && + (!d3dCtx->isLightEnable)) + { + d3dCtx->restoreDefaultLightMaterial(); + } + // Don't call vb->Renderer() at the end + return; + } + + //end index Quad WireFrame + + // fall through + case GEO_TYPE_INDEXED_TRI_SET: + if (renderTypeSet == false) { + d3dRenderType = D3DPT_TRIANGLELIST; + renderTypeSet = true; +#ifdef VBDEBUG + if (createNew) { + printf("tri set %d\n", vcount); + } +#endif + } + // fallthrough + case GEO_TYPE_INDEXED_LINE_SET: + if (renderTypeSet == false) { + d3dRenderType = D3DPT_LINELIST; + renderTypeSet = true; +#ifdef VBDEBUG + if (createNew) { + printf("line set %d\n", vcount); + } +#endif + } + // fallthrough + case GEO_TYPE_INDEXED_POINT_SET: + if (renderTypeSet == false) { + d3dRenderType = D3DPT_POINTLIST; +#ifdef VBDEBUG + if (createNew) { + printf("point set %d\n", vcount); + } +#endif + } + vb->primitiveType = d3dRenderType; + + if (vb->totalIndexCount <= vb->indexCount) { + if (vcount <= vb->vcount) { + copyIndexVertexToVB(d3dCtx, strideData, + indexCount, + cDirty, true, expandQuadIndex); + copyVertexToVB(d3dCtx, strideData, vcount, &vbptr, + cDirty, false, xform, nxform); + } else { + vb->buffer->Unlock(); + vbptr = NULL; + reIndexifyIndexVertexToVBs(d3dCtx, strideData, + indexCount, vcount, + cDirty, + expandQuadIndex, + maxVertexLimit, + xform, nxform); + SafeDelete(d3dCtx->reIndexifyTable); + } + } else { + vb->buffer->Unlock(); + vbptr = NULL; + splitIndexVertexToMultipleVB(d3dCtx, + strideData, + indexCount, + vcount, + maxVertexLimit, + cDirty, + expandQuadIndex, + xform, nxform); + SafeDelete(d3dCtx->reIndexifyTable); + } + break; + default: + printf("IndexedGeometryArrayRetained_execute:unknown geo_type %ld \n", geo_type); + } + + if (vbptr != NULL) { + // d3dCtx->pVB is the last reference in VB list + d3dCtx->pVB->buffer->Unlock(); + } + + // Save new texture position to detect any change + // in next round. + for (i=0; i < d3dCtx->texSetUsed; i++) { + d3dCtx->pVB->texCoordPosition[i] = + strideData->texCoordPosition[i]; + } + + if (!buildDL) { + // Not in displaylist mode, directly render VB + // vb is the root reference in VB list + vb->render(d3dCtx); + } +} + + +/* + * Set the default texture coordinate pointers when automatically + * texture generation is used or when there is application error + */ +inline void setDefaultTextureCoordPointers(D3dCtx *d3dCtx, + D3DDRAWPRIMITIVESTRIDEDDATA *strideData, + DWORD* vertexFormat, + jint ts, + int genMode, + int tus) +{ + strideData->textureCoordsPtr[tus] = &defaultTexCoord[0]; + strideData->textureCoordsStride[tus] = 0; + strideData->texCoordPosition[tus] = genMode; + d3dCtx->texStride[tus] = ts; + *vertexFormat |= (TexFormatSizeTable[ts] << (tus*2 + 16)); +} + + +/* + * Set the textureCoordStride & textureCoordsPtr in strideData + */ +void setTextureCoordPointers(JNIEnv *env, + D3dCtx* d3dCtx, + LPDIRECT3DDEVICE9 device, + D3DDRAWPRIMITIVESTRIDEDDATA *strideData, + jint texoff, + jint texStride, + jint ts, + jboolean textureDefined, + jintArray tcoordsetmap, + jint texCoordMapLength, + jintArray texUnitOffset, + jint numActiveTexUnit, + DWORD* vertexFormat, + // Used by executeGeometryArray() & + // executeIndexedGeometryArray() only + jfloat* verts, + // Used by executeGeometryArrayVA() & + // executeIndexedGeometryArrayVA() only + jfloat** texCoordPointer, + // Used by executeGeometryArrayVA() only + jintArray texindices) + +{ + jint *texCoordSetMapOffset = NULL; + jint *initialTexIndices = NULL; + jint *texCoordSetMap = NULL; + jint textureUnitIndex; + int genMode; + jint offsetOrTexset; + BOOL nonVAGeom = (verts != NULL); + int texSetInVB = 0; + + // TODO : + int pass = -1; + + /* + * In case of automatic texture generation, + * (vformat & GA_TEXTURE_COORDINATE) may equal to zero so we + * can't wrap around this whole block with the condition. + */ + d3dCtx->texSetUsed = 0; + + // For GA buildGA(), numActiveTexUnit is 1 even though texture + // is not used. This is only accurate for execute() immediate case. + if (numActiveTexUnit <= 0) { + return; + } + + if (texCoordMapLength > 0) { + if (nonVAGeom) { + // In executeGeometryArray() or executeIndexedGeometryArray() + texCoordSetMapOffset = (jint *) env->GetPrimitiveArrayCritical(texUnitOffset, NULL); + } else { + // In executeGeometryArrayVA() or executeIndexedGeometryArrayVA() + texCoordSetMap = (jint *) + env->GetPrimitiveArrayCritical(tcoordsetmap, NULL); + } + + } + + if (texindices != NULL) { + // In executeGeometryArrayVA() + initialTexIndices = (jint *) env->GetPrimitiveArrayCritical(texindices, NULL); + } + + // DisplayList is used for multiple texture single pass mode + // Or when go through the VertexArray in OGL, pass = -1 + int tus; +#ifdef TEXDEBUG + printf("*** Multiple Pass *** %d, nonVAGeom %d, buildDL %d, numActiveTexUnit %d, texCoordMapLength %d, texDef %d\n", pass, + nonVAGeom, (d3dCtx->currDisplayListID > 0), + numActiveTexUnit, texCoordMapLength, textureDefined); +#endif + + + for (textureUnitIndex = 0; textureUnitIndex < numActiveTexUnit; + textureUnitIndex++) { + + tus = textureUnitIndex; + + if (d3dCtx->currDisplayListID > 0) { + genMode = setTextureStage(d3dCtx, device, + textureUnitIndex, tus); + } else { + // This happen when we switch from displayList to + // vertexArray mode. The displayList is already + // built with 1-1 mapping so we can't use the + // textureUnitIndex Mapping + genMode = setTextureStage(d3dCtx, device, + textureUnitIndex, + textureUnitIndex); + } +#ifdef TEXDEBUG + printf("[pass %d] genMode %d, tus %d\n", textureUnitIndex, + genMode, tus); +#endif + if (genMode != TEX_OBJ_LINEAR) { + if (textureDefined) { + if (tus < texCoordMapLength) { + offsetOrTexset = (nonVAGeom ? + texCoordSetMapOffset[tus]:texCoordSetMap[tus]); + + if (offsetOrTexset != -1) { + if (nonVAGeom) { + strideData->textureCoordsPtr[textureUnitIndex] = + &verts[texoff + offsetOrTexset]; + } else if (initialTexIndices != NULL) { + strideData->textureCoordsPtr[textureUnitIndex] = + &(texCoordPointer[offsetOrTexset][initialTexIndices[offsetOrTexset]*texStride]); + } else { + strideData->textureCoordsPtr[textureUnitIndex] = + &(texCoordPointer[offsetOrTexset][0]); + } + strideData->textureCoordsStride[textureUnitIndex] = texStride; + strideData->texCoordPosition[textureUnitIndex] + = offsetOrTexset; + *vertexFormat |= (TexFormatSizeTable[ts] << (textureUnitIndex*2 + 16)); + d3dCtx->texStride[textureUnitIndex] = ts; + setTexTransformStageFlag(d3dCtx, device, + textureUnitIndex, + ts, genMode); + texSetInVB++; +#ifdef TEXDEBUG + printf("[pass %d] Non Object Linear, texDefined, ts=%d, tus %d\n", textureUnitIndex, ts, tus); +#endif + } else { + // This texture status is disable, this + // should not happen in D3D since + // TextureBin always compact unused state + // - unless when DisplayList is build and + // automatic texture generation + // used. Since if DL use + // updateAttributes() not yet invoke to + // set genMode correctly. + if (debug && (d3dCtx->currDisplayListID <= 0)) { + printf("[Java3D] TextureBin not compact textureUnitState correctly, numActiveTex %d, disableUnit %d, current mapped Texture Unit %d\n", numActiveTexUnit, tus, textureUnitIndex); + } + setDefaultTextureCoordPointers(d3dCtx, strideData, + vertexFormat, ts, + genMode, + textureUnitIndex); + setTexTransformStageFlag(d3dCtx, device, + textureUnitIndex, + ts, genMode); + texSetInVB++; +#ifdef TEXDEBUG + printf("[pass %d] Non Object Linear, texDefined, ts=%d\n", textureUnitIndex, ts); +#endif + } + } else { + // Internal error, should not happen. + if (debug) { + printf("[Java3D] TextureCoordMapLength length %d, is smaller than texture unit %d, map texture unit %d\n", texCoordMapLength, tus, textureUnitIndex); + } + setDefaultTextureCoordPointers(d3dCtx, strideData, + vertexFormat, ts, + TEX_GEN_INVALID, + textureUnitIndex); + setTexTransformStageFlag(d3dCtx, device, + textureUnitIndex, ts, + genMode); + + texSetInVB++; +#ifdef TEXDEBUG + printf("[pass %d] Non Object Linear, texDefined, offset/texset = -1, ts=%d\n", textureUnitIndex, ts); +#endif + } + } else { + // May be in automatically texture coordinate + // generation mode. + // May have trouble if automatically texture + // coordinate not used. Note that we pass ts = 0 + // so that copyVertexToVB() will not inc. the + // stride for this unused tex stage. + + // It is also the case in buildGA() case when + // numActiveTexUnit is 1 by default even though + // texture is not used. + /* + if ((d3dCtx->currDisplayListID <= 0) && + (genMode == TEX_GEN_NONE)) { + // application error, use default TexCoord + setDefaultTextureCoordPointers(d3dCtx, strideData, + vertexFormat, + ts, + TEX_GEN_NONE, + textureUnitIndex); + texSetInVB++; + } + */ + + setDefaultTextureCoordPointers(d3dCtx, strideData, + vertexFormat, + 0, + // This must be < 0 + TEX_GEN_AUTO, + textureUnitIndex); + setTexTransformStageFlag(d3dCtx, device, textureUnitIndex, + d3dCtx->texCoordFormat[textureUnitIndex], genMode); + + +#ifdef TEXDEBUG + printf("[pass %d] Non Object Linear, No texDefined, ts=0\n", textureUnitIndex); +#endif + } + } else { + // Automatic Texture generation Object Linear is used + setDefaultTextureCoordPointers(d3dCtx, strideData, + vertexFormat, + d3dCtx->texCoordFormat[textureUnitIndex], + genMode, + textureUnitIndex); + setTexTransformStageFlag(d3dCtx, device, textureUnitIndex, + d3dCtx->texCoordFormat[textureUnitIndex], genMode); + texSetInVB++; +#ifdef TEXDEBUG + printf("[pass %d] Object Linear, No texDefined, ts=%d\n", textureUnitIndex, d3dCtx->texCoordFormat[textureUnitIndex]); +#endif + } + } + d3dCtx->texSetUsed = numActiveTexUnit; +#ifdef TEXDEBUG + printf("No of texSetInVB %d, numActiveTexUnit %d\n", + texSetInVB, numActiveTexUnit); +#endif + + + if (texCoordSetMapOffset != NULL) { + env->ReleasePrimitiveArrayCritical(texUnitOffset, + texCoordSetMapOffset, NULL); + } + + if (texCoordSetMap != NULL) { + env->ReleasePrimitiveArrayCritical(tcoordsetmap, + texCoordSetMap, NULL); + } + + if (initialTexIndices != NULL) { + env->ReleasePrimitiveArrayCritical(texindices, + initialTexIndices, NULL); + } + + // texSetInVB <= d3dCtx->TexSetUsed + *vertexFormat |= getVertexFormat(texSetInVB); +} + + + +void executeGeometryArrayVA( + JNIEnv *env, + jobject obj, + jlong ctx, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean modAlpha, + float alpha, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jfloat* fverts, + jdouble* dverts, + jint initialColorIndex, + jfloat* fclrs, + jbyte* bclrs, + jint initialNormalIndex, + jfloat* norms, + int texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jintArray texindices, + jint texStride, + jfloat** texCoordPointer, + jdoubleArray xform, + jdoubleArray nxform, + jint cDirty) +{ + D3DDRAWPRIMITIVESTRIDEDDATA strideData; + DWORD vertexFormat = 0; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + GetDevice(); + + ZeroMemory(&strideData, sizeof(D3DDRAWPRIMITIVESTRIDEDDATA)); + + strideData.modulateAlpha = modAlpha; + strideData.alpha = alpha; + + + // setup coordinate pointers + if (floatCoordDefined || doubleCoordDefined) { + vertexFormat |= D3DFVF_XYZ; + + if (floatCoordDefined) { + strideData.fpositionPtr = &fverts[initialCoordIndex*3]; + } else if (doubleCoordDefined) { + strideData.dpositionPtr = &dverts[initialCoordIndex*3]; + } + + strideData.positionStride = 3; + + } else { + // nothing worth doing if no coordinates define + return; + } + + // setup normal pointers + if (normalsDefined) { + vertexFormat |= D3DFVF_NORMAL; + strideData.normalPtr = &norms[initialNormalIndex*3]; + strideData.normalStride = 3; + } + + + // setup color pointers + if (!(floatColorsDefined || byteColorsDefined) + || ignoreVertexColors) { + // Use Material color + // Assume VertexBuffer will recreate when ignoreVertexColors + // property changed. Otherwise we need to remove + // the following one line + vertexFormat &= ~D3DFVF_DIFFUSE; + } else { + if ((vformat & GA_WITH_ALPHA) != 0) { + strideData.diffuseStride = 4; + strideData.useAlpha = true; + } else { + strideData.diffuseStride = 3; + strideData.useAlpha = false; + } + if (floatColorsDefined) { + strideData.fdiffusePtr = &fclrs[initialColorIndex*strideData.diffuseStride]; + } else { + strideData.bdiffusePtr = &bclrs[initialColorIndex*strideData.diffuseStride]; + } + + vertexFormat |= D3DFVF_DIFFUSE; + } + + int ts = 2; // In case of automatic texture generation + + if ((vformat & GA_TEXTURE_COORDINATE_3) != 0) { + ts = 3; + } else if ((vformat & GA_TEXTURE_COORDINATE_4) != 0) { + ts = 4; + } + + + // setup texture pointer + setTextureCoordPointers(env, d3dCtx, device, + &strideData, + 0, texStride, ts, + textureDefined, + tcoordsetmap, + texCoordMapLength, + NULL, + numActiveTexUnit, + &vertexFormat, + NULL, texCoordPointer, + texindices); + + + + jdouble* xform_ptr = NULL; + jdouble* nxform_ptr = NULL; + + if (xform != NULL) { + xform_ptr = (jdouble *) env->GetPrimitiveArrayCritical(xform, NULL); + + } + + if (nxform != NULL) { + nxform_ptr = (jdouble *) env->GetPrimitiveArrayCritical(nxform, NULL); + } + + // Construct/update VertexBuffer, render() if not in display list mode + renderGeometry(env, d3dCtx, device, geo, geo_type, &strideData, + vertexFormat, vcount, xform_ptr, nxform_ptr, cDirty); + + if (xform_ptr != NULL) { + env->ReleasePrimitiveArrayCritical(xform, xform_ptr, 0); + } + if (nxform_ptr != NULL) { + env->ReleasePrimitiveArrayCritical(nxform, nxform_ptr, 0); + } + +} + + + + +/* execute geometry array with java array format */ +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeVABuffer( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jobject vcoords, + jint initialColorIndex, + jobject cdataBuffer, + jfloatArray cfdata, + jbyteArray cbdata, + jint initialNormalIndex, + jobject ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jintArray vertexAttrIndices, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jintArray texindices, + jint texStride, + jobjectArray texCoords, + jint cdirty) +{ + + jfloat *fverts = NULL; + jdouble *dverts = NULL ; + jbyte *bclrs = NULL; + jfloat *fclrs = NULL, *norms = NULL; + jfloat* texCoordPointer[D3DDP_MAXTEXCOORD]; + jarray texobjs[D3DDP_MAXTEXCOORD]; + int i; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (jarray)env->GetObjectArrayElement(texCoords, i); + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts = (jfloat *)env->GetDirectBufferAddress( vcoords ); + } else if (doubleCoordDefined) { + dverts = (jdouble *)env->GetDirectBufferAddress( vcoords ); + } + + if(fverts == NULL && dverts == NULL) + return; + + /* get color array */ + if (floatColorsDefined) { + if(cfdata != NULL) { + fclrs = (jfloat *) env->GetPrimitiveArrayCritical( cfdata, NULL); + } else { + fclrs = (jfloat *) env->GetDirectBufferAddress (cdataBuffer); + + } + } + else if (byteColorsDefined) { + if(cbdata != NULL) { + bclrs = (jbyte *) env->GetPrimitiveArrayCritical( cbdata, NULL); + } else { + bclrs = (jbyte *) env->GetDirectBufferAddress(cdataBuffer); + } + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *)env->GetDirectBufferAddress(ndata); + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)env->GetDirectBufferAddress(texobjs[i]); + else + texCoordPointer[i] = NULL; + + } + } + + executeGeometryArrayVA(env, obj, ctxInfo, geo, geo_type, + isNonUniformScale, false, 0, ignoreVertexColors, + vcount, vformat, vdefined, initialCoordIndex, + fverts, dverts, initialColorIndex, + fclrs, bclrs, initialNormalIndex, + norms, + texCoordMapLength, + tcoordsetmap,numActiveTexUnit, + texindices,texStride,texCoordPointer, NULL, + NULL, cdirty); + + if(floatColorsDefined && cfdata != NULL) + env->ReleasePrimitiveArrayCritical( cfdata, fclrs, 0); + else if(byteColorsDefined && cbdata != NULL) + env->ReleasePrimitiveArrayCritical(cbdata, bclrs, 0); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeVA( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jfloatArray vfcoords, + jdoubleArray vdcoords, + jint initialColorIndex, + jfloatArray cfdata, + jbyteArray cbdata, + jint initialNormalIndex, + jfloatArray ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jintArray vertexAttrIndices, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jintArray texindices, + jint texStride, + jobjectArray texCoords, + jint cdirty) + { + + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jfloat *fclrs = NULL; + jbyte *bclrs = NULL; + jfloat *norms = NULL; + jfloat* texCoordPointer[D3DDP_MAXTEXCOORD]; + jarray texobjs[D3DDP_MAXTEXCOORD]; + int i; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (jarray)env->GetObjectArrayElement( texCoords, i); + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts= (jfloat *) env->GetPrimitiveArrayCritical( vfcoords, NULL); + } else if (doubleCoordDefined) { + dverts= (jdouble *) env->GetPrimitiveArrayCritical( vdcoords, NULL); + } + + if ((fverts == NULL) && (dverts == NULL)) { + return; + } + + /* get color array */ + if (floatColorsDefined) { + fclrs = (jfloat *) env->GetPrimitiveArrayCritical( cfdata, NULL); + } else if (byteColorsDefined) { + bclrs = (jbyte *)env->GetPrimitiveArrayCritical( cbdata, NULL); + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *) env->GetPrimitiveArrayCritical(ndata, NULL); + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) { + texCoordPointer[i] = (jfloat*)env->GetPrimitiveArrayCritical(texobjs[i], NULL); + } else { + texCoordPointer[i] = NULL; + } + + } + } + executeGeometryArrayVA(env, obj, ctxInfo, geo, geo_type, + isNonUniformScale, false, 0, + ignoreVertexColors, + vcount, vformat, vdefined, initialCoordIndex, + fverts, dverts, initialColorIndex, + fclrs, bclrs, initialNormalIndex, + norms, texCoordMapLength, + tcoordsetmap,numActiveTexUnit, + texindices,texStride,texCoordPointer, + NULL, NULL, cdirty); + + if (floatCoordDefined) { + env->ReleasePrimitiveArrayCritical( vfcoords, fverts, 0); + } + else if (doubleCoordDefined) { + env->ReleasePrimitiveArrayCritical( vdcoords, dverts, 0); + } + + if (floatColorsDefined) { + env->ReleasePrimitiveArrayCritical( cfdata, fclrs, 0); + } + else if (byteColorsDefined) { + env->ReleasePrimitiveArrayCritical( cbdata, bclrs, 0); + } + + if (normalsDefined) { + env->ReleasePrimitiveArrayCritical( ndata, norms, 0); + } + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texCoordPointer[i] != NULL) { + env->ReleasePrimitiveArrayCritical(texobjs[i], texCoordPointer[i], 0); + } + } + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_disableGlobalAlpha( + JNIEnv *env, + jobject obj, + jlong ctx, + jobject geo, + jint vformat, + jboolean useAlpha, + jboolean ignoreVertexColors) +{ + // not used in D3D +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setVertexFormat( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint vformat, + jboolean useAlpha, + jboolean ignoreVertexColors) +{ + // not used in D3D +} + + +void executeGeometryArray(JNIEnv *env, + jobject obj, jlong ctx, + jobject geo, jint geo_type, + jboolean isNonUniformScale, + jboolean modAlpha, // buildGA, should alpha be mode + jfloat alpha, + jboolean ignoreVertexColors, + jint startVIndex, + jint vcount, jint vformat, jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordMapLength, + jintArray texUnitOffset, + jint numActiveTexUnit, + jfloat* verts, jfloatArray carray, + jdoubleArray xform, jdoubleArray nxform, + jint cDirty, + jboolean useAlpha) // Should alpha be sent down +{ + D3DDRAWPRIMITIVESTRIDEDDATA strideData; + DWORD vertexFormat = 0; + jint stride, coordoff, normoff, coloroff, texoff; + int texStride, ts = 0; + + GetDevice(); + + ZeroMemory(&strideData, sizeof(D3DDRAWPRIMITIVESTRIDEDDATA)); + + strideData.modulateAlpha = modAlpha; + strideData.alpha = alpha; + + /* This matches the code in GeometryArrayRetained.java */ + stride = coordoff = normoff = coloroff = texoff = 0; + + if ((vformat & GA_COORDINATES) != 0) { + stride += 3; + vertexFormat |= D3DFVF_XYZ; + } else { + // nothing worth doing if no coordinates define + return; + } + + if ((vformat & GA_NORMALS) != 0) { + stride += 3; + coordoff += 3; + vertexFormat |= D3DFVF_NORMAL; + } + + if ((vformat & GA_COLOR) != 0) { + if ((vformat & GA_WITH_ALPHA) != 0 ) { + stride += 4; + normoff += 4; + coordoff += 4; + } else { // Handle the case of executeInterleaved 3f + stride += 3; + normoff += 3; + coordoff += 3; + } + vertexFormat |= D3DFVF_DIFFUSE; + } + + // In case of automatic texture generation + ts = 2; + + if (vformat & GA_TEXTURE_COORDINATE) { + if ((vformat & GA_TEXTURE_COORDINATE_2) != 0) { + texStride = texCoordSetCount << 1; + } else if ((vformat & GA_TEXTURE_COORDINATE_3) != 0) { + ts = 3; + texStride = texCoordSetCount*3; + } else { // GA_TEXTURE_COORDINATE_4 + ts = 4; + texStride = texCoordSetCount << 2; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + jfloat *cverts = NULL; + + texoff = startVIndex*stride; + coordoff += texoff; + normoff += texoff; + + if (carray != NULL) { + // separate color array is used + coloroff = startVIndex*4; + } else { + coloroff += texoff; + } + + // setup coordinates pointer + strideData.fpositionPtr = &verts[coordoff]; + strideData.positionStride = stride; + + // setup color pointer + if (((vformat & GA_COLOR) == 0) || ignoreVertexColors) { + // Use Material color + // Assume VertexBuffer will recreate when ignoreVertexColors + // property changed. Otherwise we need to remove + // the following one line + vertexFormat &= ~D3DFVF_DIFFUSE; + } else { + if (carray == NULL) { + strideData.fdiffusePtr = &verts[coloroff]; + strideData.diffuseStride = stride; + strideData.useAlpha = (vformat & GA_WITH_ALPHA); + } else { + cverts = (jfloat*) env->GetPrimitiveArrayCritical(carray, NULL); + strideData.fdiffusePtr = &cverts[coloroff]; + strideData.diffuseStride = 4; + strideData.useAlpha = true; + } + } + + + // setup normal pointer + if ((vformat & GA_NORMALS) != 0) { + strideData.normalPtr = &verts[normoff]; + strideData.normalStride = stride; + } + + // setup texture pointer + setTextureCoordPointers(env, d3dCtx, device, + &strideData, + texoff, stride, ts, + (vformat & GA_TEXTURE_COORDINATE), + NULL, + texCoordMapLength, + texUnitOffset, + numActiveTexUnit, + &vertexFormat, + verts, NULL, NULL); + + + jdouble* xform_ptr = NULL; + jdouble* nxform_ptr = NULL; + + if (xform != NULL) { + xform_ptr = (jdouble *) env->GetPrimitiveArrayCritical(xform, NULL); + + } + + if (nxform != NULL) { + nxform_ptr = (jdouble *) env->GetPrimitiveArrayCritical(nxform, NULL); + } + + renderGeometry(env, d3dCtx, device, geo, geo_type, &strideData, + vertexFormat, vcount, xform_ptr, nxform_ptr, cDirty); + + if (xform_ptr != NULL) { + env->ReleasePrimitiveArrayCritical(xform, xform_ptr, 0); + } + if (nxform_ptr != NULL) { + env->ReleasePrimitiveArrayCritical(nxform, nxform_ptr, 0); + } + + + /* env->ReleasePrimitiveArrayCritical(varray, verts, NULL); */ + + if (cverts != NULL) { + env->ReleasePrimitiveArrayCritical(carray, cverts, NULL); + } +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: buildGA + * Signature: (JLjavax/media/j3d/GeometryArrayRetained;IZZFZIIII[II[II[I[D[D[F)V + */ +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_buildGA(JNIEnv *env, + jobject obj, jlong ctx, jobject geo, + jint geo_type, + jboolean isNonUniformScale, jboolean updateAlpha, float alpha, + jboolean ignoreVertexColors, + jint startVIndex, + jint vcount, jint vformat, + jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordMapLength, + jintArray texUnitOffset, + jint vertexAttrCount, jintArray vertexAttrSizes, + jdoubleArray xform, jdoubleArray nxform, + jfloatArray varray) +{ + + jfloat *verts = NULL; + + if (varray != NULL) { + verts = (jfloat *) env->GetPrimitiveArrayCritical(varray, NULL); + } + + if (verts == NULL) { + return; + } + + if (((vformat & GA_COLOR) != 0) && + ((vformat & GA_BY_REFERENCE) == 0)) { + // alpha component is added for buildGA + vformat |= GA_WITH_ALPHA; + } + + + executeGeometryArray(env, + obj, ctx, geo, geo_type, isNonUniformScale, + updateAlpha, + alpha, + ignoreVertexColors, + startVIndex, + vcount, + vformat, + texCoordSetCount, + texCoordSetMapArray, + texCoordMapLength, + texUnitOffset, + texCoordMapLength, + verts, NULL, + xform, nxform, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED, + false); + + env->ReleasePrimitiveArrayCritical( varray, verts, 0); +} + + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_execute(JNIEnv *env, + jobject obj, jlong ctx,jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint startVIndex, + jint vcount, jint vformat, jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordMapLength, jintArray texUnitOffset, + jint numActiveTexUnit, + jint vertexAttrCount, jintArray vertexAttrSizes, + jfloatArray varray, jfloatArray carray, jint cDirty) +{ + jfloat *verts = NULL; + + if (varray != NULL) { + verts = (jfloat *) env->GetPrimitiveArrayCritical( varray, NULL); + } + + if (verts == NULL) { + return; + } + + executeGeometryArray(env, obj, ctx, geo, geo_type, + isNonUniformScale, + false, + 0, ignoreVertexColors, startVIndex, + vcount, vformat, texCoordSetCount, + texCoordSetMapArray, + texCoordMapLength, texUnitOffset, + numActiveTexUnit, + verts, carray, NULL, NULL, cDirty,useAlpha); + + env->ReleasePrimitiveArrayCritical( varray, verts, 0); + +} + + +/* interleaved data with nio buffer as data format */ +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeInterleavedBuffer(JNIEnv *env, + jobject obj, jlong ctx, jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint startVIndex, + jint vcount, jint vformat, + jint texCoordSetCount, + jintArray texCoordSetMapArray, jint texCoordMapLength, + jintArray texUnitOffset, + jint numActiveTexUnit, + jobject varray, jfloatArray carray, jint cDirty) { + + jfloat *verts = NULL; + + /* get the direct buffer address */ + if (varray != NULL) { + verts = (jfloat *) env->GetDirectBufferAddress(varray); + } + + if (verts == NULL) { + return; + } + + /* call executeGeometryArray */ + executeGeometryArray(env, obj, ctx, geo, geo_type, + isNonUniformScale, + false, + 0, ignoreVertexColors, startVIndex, + vcount, vformat, texCoordSetCount, + texCoordSetMapArray, + texCoordMapLength, texUnitOffset, + numActiveTexUnit, + verts, carray, NULL, NULL, cDirty,useAlpha); + +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_freeD3DArray( + JNIEnv *env, + jobject obj, + jobject geo, + jboolean deleteVB) +{ + + lockGeometry(); + + jclass geoClass = (jclass) env->GetObjectClass(geo); + // Free VertexBuffer associate with this GeometryArray + jfieldID fieldID = env->GetFieldID(geoClass, "pVertexBuffers", "J"); + + D3dVertexBufferVector *vbVector = + reinterpret_cast (env->GetLongField(geo, fieldID)); + + + if (vbVector != NULL) { + // clearLive() invoke this in Renderer thread + for (ITER_LPD3DVERTEXBUFFER s = vbVector->begin(); + s != vbVector->end(); ++s) { + // This notify vb that parent vector is already free + // so there is no need to remove itself from vbVector + (*s)->vbVector = NULL; + (*s)->ctx->freeVB(*s); + } + env->SetLongField(geo, fieldID, 0); + vbVector->clear(); + delete vbVector; + } + + unlockGeometry(); +} + + + +void executeIndexedGeometryArray(JNIEnv *env, + jobject obj, jlong ctx, + jobject geo, jint geo_type, + jboolean isNonUniformScale, + jboolean modAlpha, // buildGA, should alpha be mode + jfloat alpha, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordMapLength, + jintArray texUnitOffset, + jint numActiveTexUnit, + jfloat* verts, jfloatArray carray, + jdoubleArray xform, jdoubleArray nxform, + jint cDirty, + jboolean useAlpha, + jint initialIndexIndex, + jint indexCount, + jintArray indexCoord) // Should alpha be sent down +{ + D3DDRAWPRIMITIVESTRIDEDDATA strideData; + DWORD vertexFormat = 0; + jint stride, coordoff, normoff, coloroff, texoff; + int texStride, ts = 0; + + GetDevice(); + + ZeroMemory(&strideData, sizeof(D3DDRAWPRIMITIVESTRIDEDDATA)); + + strideData.modulateAlpha = modAlpha; + strideData.alpha = alpha; + + /* This matches the code in GeometryArrayRetained.java */ + stride = coordoff = normoff = coloroff = texoff = 0; + + if ((vformat & GA_COORDINATES) != 0) { + stride += 3; + vertexFormat |= D3DFVF_XYZ; + } else { + // nothing worth doing if no coordinates define + return; + } + + if ((vformat & GA_NORMALS) != 0) { + stride += 3; + coordoff += 3; + vertexFormat |= D3DFVF_NORMAL; + } + + if ((vformat & GA_COLOR) != 0) { + if ((vformat & GA_WITH_ALPHA) != 0 ) { + stride += 4; + normoff += 4; + coordoff += 4; + } else { // Handle the case of executeInterleaved 3f + stride += 3; + normoff += 3; + coordoff += 3; + } + vertexFormat |= D3DFVF_DIFFUSE; + } + + // In case of automatic texture generation + ts = 2; + + if (vformat & GA_TEXTURE_COORDINATE) { + if ((vformat & GA_TEXTURE_COORDINATE_2) != 0) { + texStride = texCoordSetCount << 1; + } else if ((vformat & GA_TEXTURE_COORDINATE_3) != 0) { + ts = 3; + texStride = texCoordSetCount*3; + } else { // GA_TEXTURE_COORDINATE_4 + ts = 4; + texStride = texCoordSetCount << 2; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + jfloat *cverts = NULL; + + if (carray != NULL) { + // separate color array is used + coloroff = 0; + } else { + coloroff += texoff; + } + + // setup coordinates pointer + strideData.fpositionPtr = &verts[coordoff]; + strideData.positionStride = stride; + + // setup color pointer + if (((vformat & GA_COLOR) == 0) || ignoreVertexColors) { + // Use Material color + // Assume VertexBuffer will recreate when ignoreVertexColors + // property changed. Otherwise we need to remove + // the following one line + vertexFormat &= ~D3DFVF_DIFFUSE; + } else { + if (carray == NULL) { + strideData.fdiffusePtr = &verts[coloroff]; + strideData.diffuseStride = stride; + strideData.useAlpha = (vformat & GA_WITH_ALPHA); + } else { + cverts = (jfloat*) env->GetPrimitiveArrayCritical(carray, NULL); + strideData.fdiffusePtr = &cverts[coloroff]; + strideData.diffuseStride = 4; + strideData.useAlpha = true; + } + } + + + // setup normal pointer + if ((vformat & GA_NORMALS) != 0) { + strideData.normalPtr = &verts[normoff]; + strideData.normalStride = stride; + } + + + // setup texture pointer + setTextureCoordPointers(env, d3dCtx, device, + &strideData, + texoff, stride, ts, + (vformat & GA_TEXTURE_COORDINATE), + NULL, + texCoordMapLength, + texUnitOffset, + numActiveTexUnit, + &vertexFormat, + verts, NULL, NULL); + + // setup index pointer + strideData.indexPtr = (jint *) env->GetPrimitiveArrayCritical(indexCoord, NULL); + strideData.initialIndexIndex = initialIndexIndex; + + + jdouble* xform_ptr = NULL; + jdouble* nxform_ptr = NULL; + + if (xform != NULL) { + xform_ptr = (jdouble *) env->GetPrimitiveArrayCritical(xform, NULL); + + } + + if (nxform != NULL) { + nxform_ptr = (jdouble *) env->GetPrimitiveArrayCritical(nxform, NULL); + } + + renderIndexGeometry(env, d3dCtx, device, geo, geo_type, &strideData, + vertexFormat, vcount, indexCount, + xform_ptr, nxform_ptr, cDirty); + + + + if (xform_ptr != NULL) { + env->ReleasePrimitiveArrayCritical(xform, xform_ptr, 0); + } + if (nxform_ptr != NULL) { + env->ReleasePrimitiveArrayCritical(nxform, nxform_ptr, 0); + } + + if (cverts != NULL) { + env->ReleasePrimitiveArrayCritical(carray, cverts, NULL); + } + + env->ReleasePrimitiveArrayCritical(indexCoord, + strideData.indexPtr, NULL); + +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeIndexedGeometry( + JNIEnv *env, + jobject obj, jlong ctx, + jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vcount, + jint vformat, + jint vertexAttrCount, jintArray vertexAttrSizes, + jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordMapLength, jintArray texUnitOffset, + jint numActiveTexUnit, + jfloatArray varray, jfloatArray carray, jint cDirty, + jintArray indexCoord) +{ + jfloat *verts = NULL; + + if (varray != NULL) { + verts = (jfloat *) env->GetPrimitiveArrayCritical( varray, NULL); + } + + if (verts == NULL) { + return; + } + + executeIndexedGeometryArray(env, obj, ctx, geo, geo_type, + isNonUniformScale, + false, 0, + ignoreVertexColors, + vcount, + vformat, texCoordSetCount, + texCoordSetMapArray, + texCoordMapLength, + texUnitOffset, + numActiveTexUnit, + verts, + carray, + NULL, NULL, + cDirty, + useAlpha, + initialIndexIndex, + indexCount, + indexCoord); + + env->ReleasePrimitiveArrayCritical( varray, verts, 0); +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeIndexedGeometryBuffer( + JNIEnv *env, + jobject obj, jlong ctx, + jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vcount, + jint vformat, jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordMapLength, jintArray texUnitOffset, + jint numActiveTexUnit, + jobject varray, jfloatArray carray, + jint cDirty, + jintArray indexCoord) +{ + jfloat *verts = NULL; + + /* get the direct buffer address */ + if (varray != NULL) { + verts = (jfloat *) env->GetDirectBufferAddress(varray ); + } + + if (verts == NULL) + return; + + executeIndexedGeometryArray(env, obj, ctx, geo, geo_type, + isNonUniformScale, + false, 0, + ignoreVertexColors, + vcount, + vformat, texCoordSetCount, + texCoordSetMapArray, + texCoordMapLength, + texUnitOffset, + numActiveTexUnit, + verts, + carray, + NULL, NULL, + cDirty, + useAlpha, + initialIndexIndex, + indexCount, + indexCoord); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_buildIndexedGeometry( + JNIEnv *env, + jobject obj, jlong ctx, jobject geo, + jint geo_type, + jboolean isNonUniformScale, jboolean updateAlpha, float alpha, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vertexCount, + jint vformat, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordMapLength, + jintArray texUnitOffset, + jdoubleArray xform, jdoubleArray nxform, + jfloatArray varray, jintArray indexCoord) +{ + + jfloat *verts = NULL; + + if (varray != NULL) { + verts = (jfloat *) env->GetPrimitiveArrayCritical( varray, NULL); + } + + if (verts == NULL) { + return; + } + + if ((vformat & GA_COLOR) != 0) { + // alpha component is added for buildGA + vformat |= GA_WITH_ALPHA; + } + + executeIndexedGeometryArray(env, obj, ctx, geo, geo_type, + isNonUniformScale, + updateAlpha, alpha, + ignoreVertexColors, + vertexCount, + vformat, + texCoordSetCount, + texCoordSetMapArray, + texCoordMapLength, + texUnitOffset, + texCoordMapLength, + verts, + NULL, + xform, nxform, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED| + javax_media_j3d_GeometryArrayRetained_INDEX_CHANGED, + false, + initialIndexIndex, + indexCount, + indexCoord); + + env->ReleasePrimitiveArrayCritical( varray, verts, 0); + +} + + + +void executeIndexedGeometryArrayVA( + JNIEnv *env, + jobject obj, + jlong ctx, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vertexCount, + jint vformat, + jint vdefined, + jfloat* fverts, + jdouble* dverts, + jfloat* fclrs, + jbyte* bclrs, + jfloat* norms, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jint texStride, + jfloat** texCoordPointer, + jint cDirty, + jintArray indexCoord) +{ + D3DDRAWPRIMITIVESTRIDEDDATA strideData; + DWORD vertexFormat = 0; + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + GetDevice(); + + ZeroMemory(&strideData, sizeof(D3DDRAWPRIMITIVESTRIDEDDATA)); + + // setup coordinate pointers + if (floatCoordDefined || doubleCoordDefined) { + vertexFormat |= D3DFVF_XYZ; + + if (floatCoordDefined ) { + strideData.fpositionPtr = &fverts[0]; + } else if (doubleCoordDefined) { + strideData.dpositionPtr = &dverts[0]; + } + strideData.positionStride = 3; + + } else { + // nothing worth doing if no coordinates define + return; + } + + // setup normal pointers + if (normalsDefined) { + vertexFormat |= D3DFVF_NORMAL; + strideData.normalPtr = &norms[0]; + strideData.normalStride = 3; + } + + // setup color pointers + if (!(floatColorsDefined || byteColorsDefined) + || ignoreVertexColors) { + // Use Material color + // Assume VertexBuffer will recreate when ignoreVertexColors + // property changed. Otherwise we need to remove + // the following one line + vertexFormat &= ~D3DFVF_DIFFUSE; + } else { + if ((vformat & GA_WITH_ALPHA) != 0) { + strideData.diffuseStride = 4; + strideData.useAlpha = true; + } else { + strideData.diffuseStride = 3; + strideData.useAlpha = false; + } + if (floatColorsDefined) { + strideData.fdiffusePtr = &fclrs[0]; + } else { + strideData.bdiffusePtr = &bclrs[0]; + } + + vertexFormat |= D3DFVF_DIFFUSE; + } + + + int ts = 2; // In case of automatic texture generation + + if ((vformat & GA_TEXTURE_COORDINATE_3) != 0) { + ts = 3; + } else if ((vformat & GA_TEXTURE_COORDINATE_4) != 0) { + ts = 4; + } + + // setup texture pointer + setTextureCoordPointers(env, d3dCtx, device, + &strideData, + 0, + texStride, ts, + textureDefined, + tcoordsetmap, + texCoordMapLength, + NULL, + numActiveTexUnit, + &vertexFormat, + NULL, texCoordPointer, + NULL); + + // setup index pointer + strideData.indexPtr = (jint *) env->GetPrimitiveArrayCritical(indexCoord, NULL); + strideData.initialIndexIndex = initialIndexIndex; + + // Construct/update VertexBuffer, render() if not in display list mode + renderIndexGeometry(env, d3dCtx, device, geo, geo_type, &strideData, + vertexFormat, vertexCount, indexCount, + NULL, NULL, cDirty); + + env->ReleasePrimitiveArrayCritical(indexCoord, + strideData.indexPtr, NULL); + + +} +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeIndexedGeometryVA( + JNIEnv *env, + jobject obj, + jlong ctx, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vertexCount, + jint vformat, + jint vdefined, + jfloatArray vfcoords, + jdoubleArray vdcoords, + jfloatArray cfdata, + jbyteArray cbdata, + jfloatArray ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jint texStride, + jobjectArray texCoords, + jint cDirty, + jintArray indexCoord) +{ + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jfloat *fclrs = NULL; + jbyte *bclrs = NULL; + jfloat *norms = NULL; + jfloat* texCoordPointer[D3DDP_MAXTEXCOORD]; + jarray texobjs[D3DDP_MAXTEXCOORD]; + int i; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (jarray)env->GetObjectArrayElement( texCoords, i); + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts= (jfloat *) env->GetPrimitiveArrayCritical( vfcoords, NULL); + } else if (doubleCoordDefined) { + dverts= (jdouble *) env->GetPrimitiveArrayCritical( vdcoords, NULL); + } + + if ((fverts == NULL) && (dverts == NULL)) { + return; + } + + /* get color array */ + if (floatColorsDefined) { + fclrs = (jfloat *) env->GetPrimitiveArrayCritical( cfdata, NULL); + } else if (byteColorsDefined) { + bclrs = (jbyte *)env->GetPrimitiveArrayCritical( cbdata, NULL); + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *) env->GetPrimitiveArrayCritical(ndata, NULL); + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) { + texCoordPointer[i] = + (jfloat*)env->GetPrimitiveArrayCritical(texobjs[i], NULL); + } else { + texCoordPointer[i] = NULL; + } + + } + } + + + executeIndexedGeometryArrayVA(env, + obj, + ctx, + geo, + geo_type, + isNonUniformScale, + ignoreVertexColors, + initialIndexIndex, + indexCount, + vertexCount, + vformat, + vdefined, + fverts, + dverts, + fclrs, + bclrs, + norms, + texCoordMapLength, + tcoordsetmap, + numActiveTexUnit, + texStride, + texCoordPointer, + cDirty, + indexCoord); + + // Free memory + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texCoordPointer[i] != NULL) { + env->ReleasePrimitiveArrayCritical(texobjs[i], texCoordPointer[i], NULL); + } + } + } + + if (floatColorsDefined) { + env->ReleasePrimitiveArrayCritical(cfdata, fclrs, 0); + } else if (byteColorsDefined) { + env->ReleasePrimitiveArrayCritical(cbdata, bclrs, 0); + } + + if (normalsDefined) { + env->ReleasePrimitiveArrayCritical(ndata, norms, 0); + } + + if (floatCoordDefined) { + env->ReleasePrimitiveArrayCritical(vfcoords, fverts, 0); + } else if (doubleCoordDefined) { + env->ReleasePrimitiveArrayCritical(vdcoords, dverts, 0); + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeIndexedGeometryVABuffer( + JNIEnv *env, + jobject obj, + jlong ctx, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vertexCount, + jint vformat, + jint vdefined, + jobject vcoords, + jobject cdataBuffer, + jfloatArray cfdata, + jbyteArray cbdata, + jobject ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jint texStride, + jobjectArray texCoords, + jint cDirty, + jintArray indexCoord) +{ + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jfloat *fclrs = NULL; + jbyte *bclrs = NULL; + jfloat *norms = NULL; + jfloat* texCoordPointer[D3DDP_MAXTEXCOORD]; + jarray texobjs[D3DDP_MAXTEXCOORD]; + int i; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (jarray)env->GetObjectArrayElement( texCoords, i); + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts = (jfloat *)env->GetDirectBufferAddress( vcoords ); + } else if (doubleCoordDefined) { + dverts = (jdouble *)env->GetDirectBufferAddress( vcoords ); + } + + if ((fverts == NULL) && (dverts == NULL)) { + return; + } + + /* get color array */ + if (floatColorsDefined) { + if(cfdata != NULL) { + fclrs = (jfloat *) env->GetPrimitiveArrayCritical( cfdata, NULL); + } else { + fclrs = (jfloat *) env->GetDirectBufferAddress (cdataBuffer); + } + } else if (byteColorsDefined) { + if (cbdata != NULL) { + bclrs = (jbyte *) env->GetPrimitiveArrayCritical( cbdata, NULL); + } else { + bclrs = (jbyte *) env->GetDirectBufferAddress(cdataBuffer); + } + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *)env->GetDirectBufferAddress(ndata); + } + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)env->GetDirectBufferAddress(texobjs[i]); + else + texCoordPointer[i] = NULL; + + } + } + + + executeIndexedGeometryArrayVA( + env, + obj, + ctx, + geo, + geo_type, + isNonUniformScale, + ignoreVertexColors, + initialIndexIndex, + indexCount, + vertexCount, + vformat, + vdefined, + fverts, + dverts, + fclrs, + bclrs, + norms, + texCoordMapLength, + tcoordsetmap, + numActiveTexUnit, + texStride, + texCoordPointer, + cDirty, + indexCoord); + + if (floatColorsDefined && cfdata != NULL) { + env->ReleasePrimitiveArrayCritical( cfdata, fclrs, 0); + } else if (byteColorsDefined && cbdata != NULL) { + env->ReleasePrimitiveArrayCritical(cbdata, bclrs, 0); + } +} + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_buildGAForBuffer( + JNIEnv *env, + jobject obj, + jlong ctx, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean updateAlpha, + jfloat alpha, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jobject vcoords, + jint initialColorIndex, + jobject cdataBuffer, + jint initialNormalIndex, + jobject ndata, + jint texCoordMapLength, + jintArray tcoordsetmap, + jintArray texindices, + jint texStride, + jobjectArray texCoords, + jdoubleArray xform, + jdoubleArray nxform) +{ + jfloat *fverts = NULL; + jdouble *dverts = NULL ; + jbyte *bclrs = NULL; + jfloat *fclrs = NULL, *norms = NULL; + jfloat* texCoordPointer[D3DDP_MAXTEXCOORD]; + jarray texobjs[D3DDP_MAXTEXCOORD]; + int i; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (jarray)env->GetObjectArrayElement(texCoords, i); + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts = (jfloat *)env->GetDirectBufferAddress( vcoords ); + } else if (doubleCoordDefined) { + dverts = (jdouble *)env->GetDirectBufferAddress( vcoords ); + } + + if ((fverts == NULL) && (dverts == NULL)) { + return; + } + + /* get color array */ + if (floatColorsDefined) { + fclrs = (jfloat *) env->GetDirectBufferAddress(cdataBuffer); + } else if (byteColorsDefined) { + bclrs = (jbyte *) env->GetDirectBufferAddress(cdataBuffer); + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *)env->GetDirectBufferAddress(ndata); + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)env->GetDirectBufferAddress(texobjs[i]); + else + texCoordPointer[i] = NULL; + + } + } + + executeGeometryArrayVA(env, obj, ctx, geo, geo_type, + isNonUniformScale, updateAlpha, alpha, + ignoreVertexColors, + vcount, vformat, vdefined, initialCoordIndex, + fverts, dverts, initialColorIndex, + fclrs, bclrs, initialNormalIndex, + norms, texCoordMapLength, + tcoordsetmap,texCoordMapLength, + texindices,texStride,texCoordPointer, + xform, nxform, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED); +} + +/* execute geometry array with java array format */ +/* + * Class: javax_media_j3d_NativePipeline + * Method: buildGAForByRef + * Signature: (JLjavax/media/j3d/GeometryArrayRetained;IZZFZIIII[F[DI[F[BI[FI[I[I[[FI[I[II[Ljava/lang/Object;[D[D)V + */ + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_buildGAForByRef( + JNIEnv *env, + jobject obj, + jlong ctx, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean updateAlpha, + jfloat alpha, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jfloatArray vfcoords, + jdoubleArray vdcoords, + jint initialColorIndex, + jfloatArray cfdata, + jbyteArray cbdata, + jint initialNormalIndex, + jfloatArray ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jintArray vertexAttrIndices, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jintArray texindices, + jint texStride, + jobjectArray texCoords, + jdoubleArray xform, + jdoubleArray nxform) +{ + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jfloat *fclrs = NULL; + jbyte *bclrs = NULL; + jfloat *norms = NULL; + jfloat* texCoordPointer[D3DDP_MAXTEXCOORD]; + jarray texobjs[D3DDP_MAXTEXCOORD]; + int i; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (jarray)env->GetObjectArrayElement( texCoords, i); + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts= (jfloat *) env->GetPrimitiveArrayCritical( vfcoords, NULL); + } else if (doubleCoordDefined) { + dverts= (jdouble *) env->GetPrimitiveArrayCritical( vdcoords, NULL); + } + + if ((fverts == NULL) && (dverts == NULL)) { + return; + } + + /* get color array */ + if (floatColorsDefined) { + fclrs = (jfloat *) env->GetPrimitiveArrayCritical( cfdata, NULL); + } else if (byteColorsDefined) { + bclrs = (jbyte *)env->GetPrimitiveArrayCritical( cbdata, NULL); + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *) env->GetPrimitiveArrayCritical(ndata, NULL); + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) { + texCoordPointer[i] = (jfloat*)env->GetPrimitiveArrayCritical(texobjs[i], NULL); + } else { + texCoordPointer[i] = NULL; + } + + } + } + + + executeGeometryArrayVA(env, obj, ctx, geo, geo_type, + isNonUniformScale, updateAlpha, alpha, + ignoreVertexColors, + vcount, vformat, vdefined, initialCoordIndex, + fverts, dverts, initialColorIndex, + fclrs, bclrs, initialNormalIndex, + norms, texCoordMapLength, + tcoordsetmap,texCoordMapLength, + texindices,texStride,texCoordPointer, + xform, nxform, + javax_media_j3d_GeometryArrayRetained_VERTEX_CHANGED); + + if (floatCoordDefined) { + env->ReleasePrimitiveArrayCritical( vfcoords, fverts, 0); + } + else if (doubleCoordDefined) { + env->ReleasePrimitiveArrayCritical( vdcoords, dverts, 0); + } + + if (floatColorsDefined) { + env->ReleasePrimitiveArrayCritical( cfdata, fclrs, 0); + } + else if (byteColorsDefined) { + env->ReleasePrimitiveArrayCritical( cbdata, bclrs, 0); + } + + if (normalsDefined) { + env->ReleasePrimitiveArrayCritical( ndata, norms, 0); + } + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texCoordPointer[i] != NULL) { + env->ReleasePrimitiveArrayCritical(texobjs[i], texCoordPointer[i], 0); + } + } + } +} diff --git a/j3d-core/src/native/d3d/GraphicsContext3D.cpp b/j3d-core/src/native/d3d/GraphicsContext3D.cpp new file mode 100644 index 0000000..63ca34c --- /dev/null +++ b/j3d-core/src/native/d3d/GraphicsContext3D.cpp @@ -0,0 +1,145 @@ +/* + * $RCSfile: GraphicsContext3D.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.10 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +#include "StdAfx.h" + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_readRaster( + JNIEnv *env, jobject obj, jlong ctx, + jint type, jint xOffset, jint yOffset, + jint wRaster, jint hRaster, jint hCanvas, + jint imageDataType, + jint imageFormat, jobject imageBuffer, + jint depthFormat, jobject depthBuffer) +{ + void *imageObjPtr; + void *depthObjPtr; + + GetDevice(); + + /* printf("[GraphicsContext3D] readRaster ...\n"); */ + + if ((type & javax_media_j3d_Raster_RASTER_COLOR) != 0) { + + if ((d3dCtx->d3dPresent.SwapEffect == D3DSWAPEFFECT_DISCARD) + // For offScreen rendering, swapBuffer never invoked + // so it is safe to use backBuffer + && (!d3dCtx->offScreen) + // If fail to createFrontBuffer, fallback to use + // backSurface. There is no gaurantee this fallback + // will work, but at least in non-debug DirectX library + // it works. + && ((d3dCtx->frontSurface != NULL) || + (d3dCtx->frontSurface == NULL) && + d3dCtx->createFrontBuffer())) { + + + HRESULT hr = device->GetFrontBufferData(0,d3dCtx->frontSurface);//iSwapChain as 0 + if (FAILED(hr)) { + printf("GetFrontBuffer fail %s\n", DXGetErrorString9(hr)); + return; + } + imageObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)imageBuffer, NULL); + + if (!d3dCtx->bFullScreen) { + // We need to invoke GetWindowRect() everytime + // since message resize() will not receive + // when Canvas3D inside browers. + d3dCtx->getScreenRect(d3dCtx->hwnd, &d3dCtx->windowRect); + copyDataFromSurface(imageFormat, + xOffset + d3dCtx->windowRect.left, + yOffset + d3dCtx->windowRect.top, + wRaster, + hRaster, + (jbyte *) imageObjPtr, + d3dCtx->frontSurface); + } + else { + copyDataFromSurface(imageFormat, xOffset, yOffset, + wRaster, hRaster, (jbyte *) imageObjPtr, + d3dCtx->frontSurface); + } + + env->ReleasePrimitiveArrayCritical((jarray) imageBuffer, imageObjPtr, 0); + + } + else { + if (d3dCtx->backSurface == NULL) { + HRESULT hr = device->GetBackBuffer(0,0, D3DBACKBUFFER_TYPE_MONO, //isSwapChain as 0 + &d3dCtx->backSurface); + if (FAILED(hr)) { + printf("GetBackBuffer fail %s\n", DXGetErrorString9(hr)); + return; + } + } + imageObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)imageBuffer, NULL); + + copyDataFromSurface(imageFormat, xOffset, yOffset, wRaster, + hRaster, (jbyte *) imageObjPtr, d3dCtx->backSurface); + + env->ReleasePrimitiveArrayCritical((jarray)imageBuffer, imageObjPtr, 0); + + } + + } + + if ((type & javax_media_j3d_Raster_RASTER_DEPTH) != 0) { + + if (d3dCtx->depthStencilSurface == NULL) { + HRESULT hr = + device->GetDepthStencilSurface(&d3dCtx->depthStencilSurface); + if (FAILED(hr)) { + if (debug) { + printf("[Java3D] Fail to get depth stencil surface %s\n", + DXGetErrorString9(hr)); + } + return; + } + } + + depthObjPtr = (void *) env->GetPrimitiveArrayCritical((jarray)depthBuffer, NULL); + + if (depthFormat == javax_media_j3d_DepthComponentRetained_DEPTH_COMPONENT_TYPE_INT) { + + // yOffset is adjusted for OpenGL - Y upward + copyDepthFromSurface(xOffset, yOffset, wRaster, + hRaster, (jint *) depthObjPtr, d3dCtx->depthStencilSurface); + + } else { // javax_media_j3d_DepthComponentRetained_DEPTH_COMPONENT_TYPE_FLOAT + + // yOffset is adjusted for OpenGL - Y upward + copyDepthFromSurface(xOffset, yOffset, wRaster, + hRaster, (jfloat *) depthObjPtr, d3dCtx->depthStencilSurface); + } + env->ReleasePrimitiveArrayCritical((jarray)depthBuffer, depthObjPtr, 0); + } +} + diff --git a/j3d-core/src/native/d3d/Lights.cpp b/j3d-core/src/native/d3d/Lights.cpp new file mode 100644 index 0000000..c0b6a22 --- /dev/null +++ b/j3d-core/src/native/d3d/Lights.cpp @@ -0,0 +1,174 @@ +/* + * $RCSfile: Lights.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +#include "StdAfx.h" + + #define D3DLIGHT_RANGE_MAX sqrt(FLT_MAX) + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateDirectionalLight( + JNIEnv *env, + jobject obj, + jlong ctx, + jint lightSlot, + jfloat red, + jfloat green, + jfloat blue, + jfloat dirx, + jfloat diry, + jfloat dirz) +{ + D3DLIGHT9 d3dLight; + + GetDevice(); + + d3dLight.Type = D3DLIGHT_DIRECTIONAL; + + d3dLight.Direction.x = dirx; + d3dLight.Direction.y = diry; + d3dLight.Direction.z = dirz; + + // Although spec. said this value is ignore, but + // if we don't set it the debug version will fail + // to set directional light + d3dLight.Range = D3DLIGHT_RANGE_MAX; + // D3D will not clamp to range [0, 1] automatically like OGL did + /* + Clamp(red); + Clamp(green); + Clamp(blue); + */ + CopyColor(d3dLight.Diffuse, red, green, blue, 1.0f); + CopyColor(d3dLight.Ambient, 0.0f, 0.0f, 0.0f, 1.0f); + CopyColor(d3dLight.Specular, red, green, blue, 1.0f); + + device->SetLight(lightSlot, &d3dLight); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updatePointLight( + JNIEnv *env, + jobject obj, + jlong ctx, + jint lightSlot, + jfloat red, + jfloat green, + jfloat blue, + jfloat attenx, + jfloat atteny, + jfloat attenz, + jfloat posx, + jfloat posy, + jfloat posz) +{ + D3DLIGHT9 d3dLight; + + GetDevice(); + + d3dLight.Type = D3DLIGHT_POINT; + + d3dLight.Position.x = posx; + d3dLight.Position.y = posy; + d3dLight.Position.z = posz; + /* + Clamp(red); + Clamp(green); + Clamp(blue); + */ + CopyColor(d3dLight.Diffuse, red, green, blue, 1.0f); + CopyColor(d3dLight.Ambient, 0.0f, 0.0f, 0.0f, 1.0f); + CopyColor(d3dLight.Specular, red, green, blue, 1.0f); + + d3dLight.Attenuation0 = attenx; + d3dLight.Attenuation1 = atteny; + d3dLight.Attenuation2 = attenz; + d3dLight.Range = D3DLIGHT_RANGE_MAX; + + device->SetLight(lightSlot, &d3dLight); +} + + +extern "C" JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateSpotLight( + JNIEnv *env, + jobject obj, + jlong ctx, + jint lightSlot, + jfloat red, + jfloat green, + jfloat blue, + jfloat attenx, + jfloat atteny, + jfloat attenz, + jfloat posx, + jfloat posy, + jfloat posz, + jfloat spreadAngle, + jfloat concentration, + jfloat dirx, + jfloat diry, + jfloat dirz) +{ + D3DLIGHT9 d3dLight; + + GetDevice(); + + d3dLight.Type = D3DLIGHT_SPOT; + d3dLight.Direction.x = dirx; + d3dLight.Direction.y = diry; + d3dLight.Direction.z = dirz; + d3dLight.Position.x = posx; + d3dLight.Position.y = posy; + d3dLight.Position.z = posz; + /* + Clamp(red); + Clamp(green); + Clamp(blue); + */ + CopyColor(d3dLight.Diffuse, red, green, blue, 1.0f); + CopyColor(d3dLight.Ambient, 0.0f, 0.0f, 0.0f, 1.0f); + CopyColor(d3dLight.Specular, red, green, blue, 1.0f); + + d3dLight.Attenuation0 = attenx; + d3dLight.Attenuation1 = atteny; + d3dLight.Attenuation2 = attenz; + d3dLight.Range = D3DLIGHT_RANGE_MAX; + d3dLight.Theta = 0; + d3dLight.Phi = spreadAngle*2; + if (d3dLight.Phi > PI) { + d3dLight.Phi = PI; + } + d3dLight.Falloff = concentration; + + device->SetLight(lightSlot, &d3dLight); +} + diff --git a/j3d-core/src/native/d3d/NativeConfigTemplate3D.cpp b/j3d-core/src/native/d3d/NativeConfigTemplate3D.cpp new file mode 100644 index 0000000..4c105df --- /dev/null +++ b/j3d-core/src/native/d3d/NativeConfigTemplate3D.cpp @@ -0,0 +1,198 @@ +/* + * $RCSfile: NativeConfigTemplate3D.cpp,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.12 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +#include "StdAfx.h" + + +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_isStereoAvailable( + JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen) +{ + // DirectX 9.0 don't support stereo + return false; + +} + +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_isDoubleBufferAvailable( + JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen) +{ + // D3D always support double buffer + return true; +} + +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_isSceneAntialiasingMultisampleAvailable( + JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen, + jint screen) +{ + BOOL antialiasingSupport = false; + + lock(); + if (d3dDriverList == NULL) + { + D3dDriverInfo::initialize(env); + } + + if (d3dDriverList != NULL) + { + D3dDriverInfo *driverInfo = d3dDriverList[screen]; + for (int i=0; i < numDeviceTypes; i++) + { + D3dDeviceInfo *pDeviceInfo = driverInfo->d3dDeviceList[i]; + if (pDeviceInfo->desktopCompatible && + pDeviceInfo->supportAntialiasing()) + { + antialiasingSupport = true; + break; + } + } + } + unlock(); + return antialiasingSupport; +} +extern "C" JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_isSceneAntialiasingAccumAvailable(JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen) +{ + return JNI_FALSE; +} + + + +extern "C" JNIEXPORT +jint JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_choosePixelFormat( + JNIEnv *env, + jobject obj, + jlong ctx, + jint screen, + jintArray attrList, + jlongArray offScreenPFArray) +{ + int depth, red, green, blue; + int stencilDepth; + int retValue = -1; + + jint *mx_ptr = (jint *) env->GetPrimitiveArrayCritical(attrList, NULL); + red = mx_ptr[RED_SIZE]; + green = mx_ptr[GREEN_SIZE]; + blue = mx_ptr[BLUE_SIZE]; + depth = mx_ptr[DEPTH_SIZE]; + stencilDepth = mx_ptr[STENCIL_SIZE]; + + env->ReleasePrimitiveArrayCritical(attrList, mx_ptr, 0); + + if (mx_ptr[STEREO] != REQUIRED) + { + lock(); + if (d3dDriverList == NULL) + { + D3dDriverInfo::initialize(env); + } + + if (d3dDriverList != NULL) + { + BOOL bFullScreen; + D3dDriverInfo *pDriver = d3dDriverList[screen]; + D3dDeviceInfo *deviceInfo = D3dCtx::setDeviceInfo(pDriver, &bFullScreen, depth, stencilDepth); + + if (deviceInfo != NULL) + { + if ((depth <= deviceInfo->maxZBufferDepthSize) && + (red <= pDriver->redDepth) && + (green <= pDriver->greenDepth) && + (blue <= pDriver->blueDepth)&& + (stencilDepth)<= deviceInfo->maxStencilDepthSize) + { + // printf("\n[Java3D] NativeConfigTemplate3D.choosePixelFormat ZBuffer depth %d", deviceInfo->maxZBufferDepthSize); + // printf("\n[Java3D] NativeConfigTemplate3D.choosePixelFormat stencil depth %d", deviceInfo->maxStencilDepthSize); + + // first 0-7bits for depth,8-15 Stencil + retValue = deviceInfo->maxZBufferDepthSize |(deviceInfo->maxStencilDepthSize <<8); + // set value for Canvas3D GraphicsConfigInfo + jlong *pfi_ptr = (jlong *) env->GetLongArrayElements(offScreenPFArray, NULL); + pfi_ptr[0] = retValue; + env->ReleaseLongArrayElements(offScreenPFArray, pfi_ptr, 0); + } + } + } + unlock(); + } + + if (mx_ptr[ANTIALIASING] == REQUIRED) + { + if (Java_javax_media_j3d_Win32NativeConfigTemplate3D_isSceneAntialiasingMultisampleAvailable(env, obj, 0, JNI_TRUE, screen) == JNI_TRUE) + { + retValue |= (1 << 31); + } + else + { + retValue = -1; + } + } + return retValue; +} + + + +/* + * Class: javax_media_j3d_Win32NativeConfigTemplate3D + * Method: getStencilSize + * Signature: (JZ)I * + */ +JNIEXPORT jint JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_getStencilSize + (JNIEnv *env, jobject obj, jlong pFormatInfo, jboolean offScreen) +{ + jlong stencilSize = pFormatInfo; + stencilSize &= 0x0000ff00 ; //clean + stencilSize = (stencilSize >> 8); + + /** // next version pFormatInfo will be a D3DFORMAT value or index for + D3DFORMAT fmt = d3dCtx->deviceInfo->depthStencilFormat; + if (fmt == D3DFMT_D15S1) stencilSize = 1; + else + if (fmt == D3DFMT_D24X4S4) stencilSize = 4; + else + if(fmt == D3DFMT_D24S8)stencilSize = 8; + */ + return (int)stencilSize; +} diff --git a/j3d-core/src/native/d3d/StdAfx.h b/j3d-core/src/native/d3d/StdAfx.h new file mode 100644 index 0000000..f584aa3 --- /dev/null +++ b/j3d-core/src/native/d3d/StdAfx.h @@ -0,0 +1,91 @@ +/* + * $RCSfile: StdAfx.h,v $ + * + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +#if !defined(AFX_STDAFX_H) +#define AFX_STDAFX_H + +#ifndef WINVER +#define WINVER 0x0501 +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef _MT +#define _MT +#endif + +// Exclude rarely-used stuff from Windows headers +#define VC_EXTRALEAN +#define WIN32_LEAN_AND_MEAN + + +//#undef _AFXDLL +//#undef _UNICODE + +// Windows Header Files: +#include +#include +#include +#include + +// C RunTime Header Files +#include +#include +#include +#include +#include +#include +#include +#define D3D_OVERLOADS +#include +#include +#include +#include +#include +#include +using namespace std ; + +// Local header file +#include "gldefs.h" +#include "D3dDeviceInfo.hpp" +#include "D3dDriverInfo.hpp" +#include "D3dCtx.hpp" +#include "D3dUtil.hpp" +#include "D3dVertexBuffer.hpp" +#include "D3dDisplayList.hpp" +#endif + diff --git a/j3d-core/src/native/d3d/build-windows-amd64-vc.xml b/j3d-core/src/native/d3d/build-windows-amd64-vc.xml new file mode 100644 index 0000000..4b7877a --- /dev/null +++ b/j3d-core/src/native/d3d/build-windows-amd64-vc.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/d3d/build-windows-i586-gcc.xml b/j3d-core/src/native/d3d/build-windows-i586-gcc.xml new file mode 100644 index 0000000..1e13faf --- /dev/null +++ b/j3d-core/src/native/d3d/build-windows-i586-gcc.xml @@ -0,0 +1,3 @@ + + + diff --git a/j3d-core/src/native/d3d/build-windows-i586-vc.xml b/j3d-core/src/native/d3d/build-windows-i586-vc.xml new file mode 100644 index 0000000..5507ba5 --- /dev/null +++ b/j3d-core/src/native/d3d/build-windows-i586-vc.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/Attributes.c b/j3d-core/src/native/ogl/Attributes.c new file mode 100644 index 0000000..755bdb9 --- /dev/null +++ b/j3d-core/src/native/ogl/Attributes.c @@ -0,0 +1,3716 @@ +/* + * $RCSfile: Attributes.c,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.14 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include +#include +#include +#include +#include + +#include "gldefs.h" + +#ifdef DEBUG +/* Uncomment the following for VERBOSE debug messages */ +/* #define VERBOSE */ +#endif /* DEBUG */ + +/* + * Screen door transparency table. + */ +const unsigned int screen_door[17][32] = { +/* 0 / 16 */ + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, +/* 1 / 16 */ + { + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + }, +/* 2 / 16 */ + { + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + }, +/* 3 / 16 */ + { + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + }, +/* 4 / 16 */ + { + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + }, +/* 5 / 16 */ + { + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + }, +/* 6 / 16 */ + { + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + }, +/* 7 / 16 */ + { + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + }, +/* 8 / 16 */ + { + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + }, +/* 9 / 16 */ + { + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + }, +/* 10 / 16 */ + { + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + }, +/* 11 / 16 */ + { + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + }, +/* 12 / 16 */ + { + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + }, +/* 13 / 16 */ + { + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + }, +/* 14 / 16 */ + { + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + }, +/* 15 / 16 */ + { + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + }, +/* 16 / 16 */ + { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, +}; + +void +throwAssert(JNIEnv *env, char *str) +{ + jclass rte; + if ((rte = (*env)->FindClass(env, "java/lang/AssertionError")) != NULL) { + (*env)->ThrowNew(env, rte, str); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateLinearFog( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat red, + jfloat green, + jfloat blue, + jdouble fdist, + jdouble bdist) +{ + + float color[3]; +#ifdef VERBOSE + fprintf(stderr, "LinearFog is on: %f %f %f %f %f\n", + red, green, blue, fdist, bdist); +#endif + + color[0] = red; + color[1] = green; + color[2] = blue; + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogfv(GL_FOG_COLOR, color); + glFogf(GL_FOG_START, (float) fdist); + glFogf(GL_FOG_END, (float) bdist); + glEnable(GL_FOG); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateExponentialFog( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat red, + jfloat green, + jfloat blue, + jfloat density) +{ + + float color[3]; +#ifdef VERBOSE + fprintf(stderr, "ExponentialFog is on: %f %f %f %f\n", + red, green, blue, density); +#endif + + color[0] = red; + color[1] = green; + color[2] = blue; + glFogi(GL_FOG_MODE, GL_EXP); + glFogfv(GL_FOG_COLOR, color); + glFogf(GL_FOG_DENSITY, density); + glEnable(GL_FOG); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateModelClip( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint planeNum, + jboolean enableFlag, + jdouble A, + jdouble B, + jdouble C, + jdouble D) +{ + + double equation[4]; + GLenum pl = GL_CLIP_PLANE0 + planeNum; + +#ifdef VERBOSE + fprintf(stderr, "ModelClip is on: %d %d %f %f %f %f\n", + planeNum, enableFlag, A, B, C, D); +#endif + + /* OpenGL clip planes are opposite to J3d clip planes + */ + if (enableFlag) { + equation[0] = -A; + equation[1] = -B; + equation[2] = -C; + equation[3] = -D; + glClipPlane(pl, equation); + glEnable(pl); + } else + glDisable(pl); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setModelViewMatrix( + JNIEnv * env, + jobject obj, + jlong ctxInfo, + jdoubleArray viewMatrix, + jdoubleArray modelMatrix) +{ + jdouble *vmatrix_pointer; + jdouble *mmatrix_pointer; + JNIEnv table = *env; + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + vmatrix_pointer = (jdouble *)(*(table->GetPrimitiveArrayCritical))(env, + viewMatrix , NULL); + mmatrix_pointer = (jdouble *)(*(table->GetPrimitiveArrayCritical))(env, + modelMatrix , NULL); + + + glMatrixMode(GL_MODELVIEW); + + if (ctxProperties->gl13) { + ctxProperties->glLoadTransposeMatrixd(vmatrix_pointer); + ctxProperties->glMultTransposeMatrixd(mmatrix_pointer); + } else { + double v[16]; + double m[16]; + + COPY_TRANSPOSE(vmatrix_pointer, v); + COPY_TRANSPOSE(mmatrix_pointer, m); + + glLoadMatrixd(v); + glMultMatrixd(m); +#ifdef VERBOSE + fprintf(stderr, "\n"); + fprintf(stderr, "Canvas3D.setModelViewMatrix()\n"); + fprintf(stderr, "-----------------------------\n"); + fprintf(stderr, "VIEW : %f %f %f %f\n", v[0], v[4], v[8], v[12]); + fprintf(stderr, " : %f %f %f %f\n", v[1], v[5], v[9], v[13]); + fprintf(stderr, " : %f %f %f %f\n", v[2], v[6], v[10], v[14]); + fprintf(stderr, " : %f %f %f %f\n", v[3], v[7], v[11], v[15]); + fprintf(stderr, "\n"); + fprintf(stderr, "MODEL : %f %f %f %f\n", m[0], m[4], m[8], m[12]); + fprintf(stderr, " : %f %f %f %f\n", m[1], m[5], m[9], m[13]); + fprintf(stderr, " : %f %f %f %f\n", m[2], m[6], m[10], m[14]); + fprintf(stderr, " : %f %f %f %f\n", m[3], m[7], m[11], m[15]); + fprintf(stderr, "\n\n"); +#endif + } + (*(table->ReleasePrimitiveArrayCritical))(env, viewMatrix, + vmatrix_pointer, 0); + (*(table->ReleasePrimitiveArrayCritical))(env, modelMatrix, + mmatrix_pointer, 0); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setProjectionMatrix( + JNIEnv * env, + jobject obj, + jlong ctxInfo, + jdoubleArray projMatrix) +{ + jdouble *matrix_pointer; + JNIEnv table = *env; + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + matrix_pointer = (jdouble *)(*(table->GetPrimitiveArrayCritical))(env, + projMatrix, NULL); + + glMatrixMode(GL_PROJECTION); + + if (ctxProperties->gl13) { + /* + * Invert the Z value in clipping coordinates because OpenGL uses + * left-handed clipping coordinates, while Java3D defines right-handed + * coordinates everywhere. + */ + matrix_pointer[8] *= -1.0; + matrix_pointer[9] *= -1.0; + matrix_pointer[10] *= -1.0; + matrix_pointer[11] *= -1.0; + ctxProperties->glLoadTransposeMatrixd(matrix_pointer); + matrix_pointer[8] *= -1.0; + matrix_pointer[9] *= -1.0; + matrix_pointer[10] *= -1.0; + matrix_pointer[11] *= -1.0; + } else { + double p[16]; + + COPY_TRANSPOSE(matrix_pointer, p); + /* + * Invert the Z value in clipping coordinates because OpenGL uses + * left-handed clipping coordinates, while Java3D defines right-handed + * coordinates everywhere. + */ + p[2] *= -1.0; + p[6] *= -1.0; + p[10] *= -1.0; + p[14] *= -1.0; + + glLoadMatrixd(p); +#ifdef VERBOSE + fprintf(stderr, "\n"); + fprintf(stderr, "Canvas3D.setProjectionMatrix()\n"); + fprintf(stderr, "------------------------------\n"); + fprintf(stderr, "PROJECTION : %f %f %f %f\n", p[0], p[4], p[8], p[12]); + fprintf(stderr, " : %f %f %f %f\n", p[1], p[5], p[9], p[13]); + fprintf(stderr, " : %f %f %f %f\n", p[2], p[6], p[10], p[14]); + fprintf(stderr, " : %f %f %f %f\n", p[3], p[7], p[11], p[15]); + fprintf(stderr, "\n\n"); +#endif + + } + + (*(table->ReleasePrimitiveArrayCritical))(env, projMatrix, + matrix_pointer, 0); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setViewport( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint x, + jint y, + jint width, + jint height) +{ + + glViewport(x, y, width, height); +} + +#ifdef WIN32 +#define M_PI 3.14159265358979323846 +#endif + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setSceneAmbient( + JNIEnv *env, + jobject cv, + jlong ctxInfo, + jfloat red, + jfloat green, + jfloat blue) +{ + float color[4]; + + color[0] = red; + color[1] = green; + color[2] = blue; + color[3] = 1.0f; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setLightEnables( + JNIEnv *env, + jobject cv, + jlong ctxInfo, + jlong enable_mask, + jint nlights) +{ + int i; + +#ifdef VERBOSE + fprintf(stderr, "Canvas3D.updateLightEnables: mask = 0x%x, 0x%x\n", + (int) ((enable_mask >> 32L) & 0xffffffff), + (int) (enable_mask & 0xffffffff)); +#endif + + for (i=0; iGetPrimitiveArrayCritical))(env, + vworldToEc, NULL); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + if (ctxProperties->gl13) { + ctxProperties->glLoadTransposeMatrixd(mat); + } else { + jdouble v[16]; + COPY_TRANSPOSE(mat, v); + glLoadMatrixd(v); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, vworldToEc, + mat, 0); + + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_S, GL_EYE_PLANE, planeS); + glTexGenfv(GL_T, GL_EYE_PLANE, planeT); + + if (format == javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_3) { + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_R, GL_EYE_PLANE, planeR); + } else if (format == javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_4) { + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_R, GL_EYE_PLANE, planeR); + glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_Q, GL_EYE_PLANE, planeQ); + } + glPopMatrix(); + break; + case javax_media_j3d_TexCoordGeneration_SPHERE_MAP: + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + if (format == javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_3) { + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + } else if (format == javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_4) { + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + } + + break; + case javax_media_j3d_TexCoordGeneration_NORMAL_MAP: + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT); + if (format == javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_3) { + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT); + } else if (format == javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_4) { + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT); + glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT); + } + break; + case javax_media_j3d_TexCoordGeneration_REFLECTION_MAP: + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT); + if (format == javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_3) { + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT); + } else if (format == javax_media_j3d_TexCoordGeneration_TEXTURE_COORDINATE_4) { + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT); + glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT); + } + break; + } + } else { + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_Q); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetTextureAttributes( + JNIEnv *env, + jobject cv, + jlong ctxInfo) +{ + float color[] = {0.0, 0.0, 0.0, 0.0}; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + glPushAttrib(GL_TRANSFORM_BIT); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glPopAttrib(); + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + if(ctxProperties->textureRegisterCombinersAvailable) + glDisable(GL_REGISTER_COMBINERS_NV); + + if(ctxProperties->textureColorTableAvailable) + glDisable(GL_TEXTURE_COLOR_TABLE_SGI); + /* GL_SGI_texture_color_table */ +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureAttributes( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jdoubleArray transform, + jboolean isIdentity, + jint textureMode, + jint perspCorrectionMode, + jfloat textureBlendColorRed, + jfloat textureBlendColorGreen, + jfloat textureBlendColorBlue, + jfloat textureBlendColorAlpha, + jint textureFormat) +{ + jdouble *mx_ptr; + float color[4]; + JNIEnv table = *env; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + if (perspCorrectionMode == javax_media_j3d_TextureAttributes_NICEST) { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + } else { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + } + + /* set OGL texture matrix */ + glPushAttrib(GL_TRANSFORM_BIT); + glMatrixMode(GL_TEXTURE); + + mx_ptr = (jdouble *)(*(table->GetPrimitiveArrayCritical))(env, transform, + NULL); + if (isIdentity) { + glLoadIdentity(); + } else if (ctxProperties->gl13) { + ctxProperties->glLoadTransposeMatrixd(mx_ptr); + } else { + double mx[16]; + COPY_TRANSPOSE(mx_ptr, mx); + glLoadMatrixd(mx); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, transform, mx_ptr, 0); + + glPopAttrib(); + + /* set texture color */ + color[0] = textureBlendColorRed; + color[1] = textureBlendColorGreen; + color[2] = textureBlendColorBlue; + color[3] = textureBlendColorAlpha; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); + + /* set texture environment mode */ + + switch (textureMode) { + case javax_media_j3d_TextureAttributes_MODULATE: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + break; + case javax_media_j3d_TextureAttributes_DECAL: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + break; + case javax_media_j3d_TextureAttributes_BLEND: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); + break; + case javax_media_j3d_TextureAttributes_REPLACE: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + break; + case javax_media_j3d_TextureAttributes_COMBINE: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, + ctxProperties->combine_enum); + break; + } + + if(ctxProperties->textureColorTableAvailable) + glDisable(GL_TEXTURE_COLOR_TABLE_SGI); + /* GL_SGI_texture_color_table */ +} + +GLenum getCombinerArg(jint arg, GLenum textureUnit, GLenum combUnit) { + GLenum comb; + + switch (arg) { + case javax_media_j3d_TextureAttributes_COMBINE_OBJECT_COLOR: + if (combUnit == GL_COMBINER0_NV) { + comb = GL_PRIMARY_COLOR_NV; + } else { + comb = GL_SPARE0_NV; + } + break; + case javax_media_j3d_TextureAttributes_COMBINE_TEXTURE_COLOR: + comb = textureUnit; + break; + case javax_media_j3d_TextureAttributes_COMBINE_CONSTANT_COLOR: + comb = GL_CONSTANT_COLOR0_NV; + break; + case javax_media_j3d_TextureAttributes_COMBINE_PREVIOUS_TEXTURE_UNIT_STATE: + comb = textureUnit -1; + break; + } + + return (comb); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateRegisterCombiners( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jdoubleArray transform, + jboolean isIdentity, + jint textureMode, + jint perspCorrectionMode, + jfloat textureBlendColorRed, + jfloat textureBlendColorGreen, + jfloat textureBlendColorBlue, + jfloat textureBlendColorAlpha, + jint textureFormat, + jint combineRgbMode, + jint combineAlphaMode, + jintArray combineRgbSrc, + jintArray combineAlphaSrc, + jintArray combineRgbFcn, + jintArray combineAlphaFcn, + jint combineRgbScale, + jint combineAlphaScale) +{ + jdouble *mx_ptr; + float color[4]; + JNIEnv table = *env; + GLenum textureUnit; + GLenum combinerUnit; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jint * rgbSrc; + GLenum color1, color2; + GLenum fragment; + + if (perspCorrectionMode == javax_media_j3d_TextureAttributes_NICEST) { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + } else { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + } + + /* set OGL texture matrix */ + glPushAttrib(GL_TRANSFORM_BIT); + glMatrixMode(GL_TEXTURE); + + mx_ptr = (jdouble *)(*(table->GetPrimitiveArrayCritical))(env, transform, + NULL); + if (isIdentity) { + glLoadIdentity(); + } else if (ctxProperties->gl13) { + ctxProperties->glLoadTransposeMatrixd(mx_ptr); + } else { + double mx[16]; + COPY_TRANSPOSE(mx_ptr, mx); + glLoadMatrixd(mx); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, transform, mx_ptr, 0); + + glPopAttrib(); + + /* set texture color */ + color[0] = textureBlendColorRed; + color[1] = textureBlendColorGreen; + color[2] = textureBlendColorBlue; + color[3] = textureBlendColorAlpha; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); + + /* set texture environment mode */ + glEnable(GL_REGISTER_COMBINERS_NV); + textureUnit = ctxProperties->currentTextureUnit; + combinerUnit = ctxProperties->currentCombinerUnit; + if (combinerUnit == GL_COMBINER0_NV) { + fragment = GL_PRIMARY_COLOR_NV; + } else { + fragment = GL_SPARE0_NV; + } + + switch (textureMode) { + case javax_media_j3d_TextureAttributes_MODULATE: + + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_A_NV, fragment, + GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_B_NV, textureUnit, + GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_A_NV, fragment, + GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_B_NV, textureUnit, + GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); + + ctxProperties->glCombinerOutputNV(combinerUnit, GL_RGB, + GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, + GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); + ctxProperties->glCombinerOutputNV(combinerUnit, GL_ALPHA, + GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, + GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); + break; + + case javax_media_j3d_TextureAttributes_DECAL: + + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_A_NV, fragment, + GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_B_NV, textureUnit, + GL_UNSIGNED_INVERT_NV, GL_ALPHA); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_C_NV, textureUnit, + GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_D_NV, textureUnit, + GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); + + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_A_NV, fragment, + GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_B_NV, GL_ZERO, + GL_UNSIGNED_INVERT_NV, GL_ALPHA); + + ctxProperties->glCombinerOutputNV(combinerUnit, GL_RGB, + GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV, + GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); + ctxProperties->glCombinerOutputNV(combinerUnit, GL_ALPHA, + GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, + GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); + break; + + case javax_media_j3d_TextureAttributes_BLEND: + + ctxProperties->glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, color); + + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_A_NV, fragment, + GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_B_NV, textureUnit, + GL_UNSIGNED_INVERT_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_C_NV, GL_CONSTANT_COLOR0_NV, + GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_D_NV, textureUnit, + GL_UNSIGNED_IDENTITY_NV, GL_RGB); + + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_A_NV, fragment, + GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_B_NV, textureUnit, + GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); + + ctxProperties->glCombinerOutputNV(combinerUnit, GL_RGB, + GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV, + GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); + ctxProperties->glCombinerOutputNV(combinerUnit, GL_ALPHA, + GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, + GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); + break; + + case javax_media_j3d_TextureAttributes_REPLACE: + + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_A_NV, textureUnit, + GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_B_NV, GL_ZERO, + GL_UNSIGNED_INVERT_NV, GL_RGB); + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_A_NV, textureUnit, + GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_B_NV, GL_ZERO, + GL_UNSIGNED_INVERT_NV, GL_ALPHA); + + ctxProperties->glCombinerOutputNV(combinerUnit, GL_RGB, + GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, + GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); + ctxProperties->glCombinerOutputNV(combinerUnit, GL_ALPHA, + GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, + GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); + break; + + case javax_media_j3d_TextureAttributes_COMBINE: + if (combineRgbMode == + javax_media_j3d_TextureAttributes_COMBINE_DOT3) { + rgbSrc = (jint *)(*(table->GetPrimitiveArrayCritical))( + env, combineRgbSrc, NULL); + color1 = getCombinerArg(rgbSrc[0], textureUnit, combinerUnit); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_A_NV, color1, + GL_EXPAND_NORMAL_NV, GL_RGB); + color2 = getCombinerArg(rgbSrc[1], textureUnit, combinerUnit); + ctxProperties->glCombinerInputNV(combinerUnit, GL_RGB, + GL_VARIABLE_B_NV, color2, + GL_EXPAND_NORMAL_NV, GL_RGB); + (*(table->ReleasePrimitiveArrayCritical))(env, combineRgbSrc, + rgbSrc, 0); + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_A_NV, GL_ZERO, + GL_UNSIGNED_INVERT_NV, GL_ALPHA); + ctxProperties->glCombinerInputNV(combinerUnit, GL_ALPHA, + GL_VARIABLE_B_NV, GL_ZERO, + GL_UNSIGNED_INVERT_NV, GL_ALPHA); + + ctxProperties->glCombinerOutputNV(combinerUnit, GL_RGB, + GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, + GL_NONE/*SCALE_BY_FOUR_NV*/, GL_NONE, GL_TRUE, + GL_FALSE, GL_FALSE); + ctxProperties->glCombinerOutputNV(combinerUnit, GL_ALPHA, + GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, + GL_NONE, GL_NONE, GL_FALSE, + GL_FALSE, GL_FALSE); + } + break; + } + + + ctxProperties->glFinalCombinerInputNV(GL_VARIABLE_A_NV, + GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glFinalCombinerInputNV(GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB); + ctxProperties->glFinalCombinerInputNV(GL_VARIABLE_C_NV, + GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glFinalCombinerInputNV(GL_VARIABLE_D_NV, + GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glFinalCombinerInputNV(GL_VARIABLE_E_NV, + GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glFinalCombinerInputNV(GL_VARIABLE_F_NV, + GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB); + ctxProperties->glFinalCombinerInputNV(GL_VARIABLE_G_NV, + GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); + + if(ctxProperties->textureColorTableAvailable) + glDisable(GL_TEXTURE_COLOR_TABLE_SGI); + /* GL_SGI_texture_color_table */ +} + +void getGLCombineMode(GraphicsContextPropertiesInfo *ctxInfo, + jint combineRgbMode, jint combineAlphaMode, + jint *GLrgbMode, jint *GLalphaMode) { + + switch (combineRgbMode) { + case javax_media_j3d_TextureAttributes_COMBINE_REPLACE: + *GLrgbMode = GL_REPLACE; + break; + case javax_media_j3d_TextureAttributes_COMBINE_MODULATE: + *GLrgbMode = GL_MODULATE; + break; + case javax_media_j3d_TextureAttributes_COMBINE_ADD: + *GLrgbMode = GL_ADD; + break; + case javax_media_j3d_TextureAttributes_COMBINE_ADD_SIGNED: + *GLrgbMode = ctxInfo->combine_add_signed_enum; + break; + case javax_media_j3d_TextureAttributes_COMBINE_SUBTRACT: + *GLrgbMode = ctxInfo->combine_subtract_enum; + break; + case javax_media_j3d_TextureAttributes_COMBINE_INTERPOLATE: + *GLrgbMode = ctxInfo->combine_interpolate_enum; + break; + case javax_media_j3d_TextureAttributes_COMBINE_DOT3: + *GLrgbMode = ctxInfo->combine_dot3_rgb_enum; + break; + default: + break; + } + + switch (combineAlphaMode) { + case javax_media_j3d_TextureAttributes_COMBINE_REPLACE: + *GLalphaMode = GL_REPLACE; + break; + case javax_media_j3d_TextureAttributes_COMBINE_MODULATE: + *GLalphaMode = GL_MODULATE; + break; + case javax_media_j3d_TextureAttributes_COMBINE_ADD: + *GLalphaMode = GL_ADD; + break; + case javax_media_j3d_TextureAttributes_COMBINE_ADD_SIGNED: + *GLalphaMode = ctxInfo->combine_add_signed_enum; + break; + case javax_media_j3d_TextureAttributes_COMBINE_SUBTRACT: + *GLalphaMode = ctxInfo->combine_subtract_enum; + break; + case javax_media_j3d_TextureAttributes_COMBINE_INTERPOLATE: + *GLalphaMode = ctxInfo->combine_interpolate_enum; + break; + case javax_media_j3d_TextureAttributes_COMBINE_DOT3: + /* dot3 will only make sense for alpha if rgb is also + doing dot3. So if rgb is not doing dot3, fallback to replace + */ + if (combineRgbMode == javax_media_j3d_TextureAttributes_COMBINE_DOT3) { + *GLrgbMode = ctxInfo->combine_dot3_rgba_enum; + } else { + *GLalphaMode = GL_REPLACE; + } + break; + default: + break; + } + + return; +} + +/* mapping from java enum to gl enum + */ + +jint _gl_combineRgbSrcIndex[] = { + GL_SOURCE0_RGB_ARB, + GL_SOURCE1_RGB_ARB, + GL_SOURCE2_RGB_ARB, +}; + +jint _gl_combineAlphaSrcIndex[] = { + GL_SOURCE0_ALPHA_ARB, + GL_SOURCE1_ALPHA_ARB, + GL_SOURCE2_ALPHA_ARB, +}; + +jint _gl_combineRgbOpIndex[] = { + GL_OPERAND0_RGB_ARB, + GL_OPERAND1_RGB_ARB, + GL_OPERAND2_RGB_ARB, +}; + +jint _gl_combineAlphaOpIndex[] = { + GL_OPERAND0_ALPHA_ARB, + GL_OPERAND1_ALPHA_ARB, + GL_OPERAND2_ALPHA_ARB, +}; + +jint _gl_combineSrc[] = { + GL_PRIMARY_COLOR_ARB, /* TextureAttributes.COMBINE_OBJECT_COLOR */ + GL_TEXTURE, /* TextureAttributes.COMBINE_TEXTURE */ + GL_CONSTANT_ARB, /* TextureAttributes.COMBINE_CONSTANT_COLOR */ + GL_PREVIOUS_ARB, /* TextureAttributes.COMBINE_PREVIOUS_TEXTURE_UNIT_STATE */ +}; + +jint _gl_combineFcn[] = { + GL_SRC_COLOR, /* TextureAttributes.COMBINE_SRC_COLOR */ + GL_ONE_MINUS_SRC_COLOR, /* TextureAttributes.COMBINE_ONE_MINUS_SRC_COLOR */ + GL_SRC_ALPHA, /* TextureAttributes.COMBINE_SRC_ALPHA */ + GL_ONE_MINUS_SRC_ALPHA, /* TextureAttributes.COMBINE_ONE_MINUS_SRC_ALPHA */ +}; + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateCombiner( + JNIEnv *env, + jobject obj, + jlong ctxProperties, + jint combineRgbMode, + jint combineAlphaMode, + jintArray combineRgbSrc, + jintArray combineAlphaSrc, + jintArray combineRgbFcn, + jintArray combineAlphaFcn, + jint combineRgbScale, + jint combineAlphaScale) { + + + JNIEnv table = *env; + GraphicsContextPropertiesInfo *ctxInfo = + (GraphicsContextPropertiesInfo *)ctxProperties; + jint *rgbSrc, *alphaSrc, *rgbFcn, *alphaFcn; + jint GLrgbMode, GLalphaMode; + jint nargs, i; + + rgbSrc = (jint *)(*(table->GetPrimitiveArrayCritical))( + env, combineRgbSrc, NULL); + alphaSrc = (jint *)(*(table->GetPrimitiveArrayCritical))( + env, combineAlphaSrc, NULL); + rgbFcn = (jint *)(*(table->GetPrimitiveArrayCritical))( + env, combineRgbFcn, NULL); + alphaFcn = (jint *)(*(table->GetPrimitiveArrayCritical))( + env, combineAlphaFcn, NULL); + + getGLCombineMode(ctxInfo, combineRgbMode, combineAlphaMode, + &GLrgbMode, &GLalphaMode); + + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GLrgbMode); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GLalphaMode); + + if (combineRgbMode == javax_media_j3d_TextureAttributes_COMBINE_REPLACE) { + nargs = 1; + } else if (combineRgbMode == javax_media_j3d_TextureAttributes_COMBINE_INTERPOLATE) { + nargs = 3; + } else { + nargs = 2; + } + + for (i = 0; i < nargs; i++) { + glTexEnvi(GL_TEXTURE_ENV, _gl_combineRgbSrcIndex[i], + _gl_combineSrc[rgbSrc[i]]); + glTexEnvi(GL_TEXTURE_ENV, _gl_combineRgbOpIndex[i], + _gl_combineFcn[rgbFcn[i]]); + } + + if (combineAlphaMode == javax_media_j3d_TextureAttributes_COMBINE_REPLACE) { + nargs = 1; + } else if (combineAlphaMode == javax_media_j3d_TextureAttributes_COMBINE_INTERPOLATE) { + nargs = 3; + } else { + nargs = 2; + } + + for (i = 0; i < nargs; i++) { + glTexEnvi(GL_TEXTURE_ENV, _gl_combineAlphaSrcIndex[i], + _gl_combineSrc[alphaSrc[i]]); + glTexEnvi(GL_TEXTURE_ENV, _gl_combineAlphaOpIndex[i], + _gl_combineFcn[alphaFcn[i]]); + } + + glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, combineRgbScale); + glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, combineAlphaScale); + + (*(table->ReleasePrimitiveArrayCritical))(env, combineRgbSrc, rgbSrc, 0); + (*(table->ReleasePrimitiveArrayCritical))(env, combineAlphaSrc, alphaSrc, 0); + (*(table->ReleasePrimitiveArrayCritical))(env, combineRgbFcn, rgbFcn, 0); + (*(table->ReleasePrimitiveArrayCritical))(env, combineAlphaFcn, alphaFcn, 0); + +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureColorTable( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numComponents, + jint colorTableSize, + jintArray textureColorTable) +{ + JNIEnv table = *env; + jint *ctable; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + if(ctxProperties->textureColorTableAvailable) { + ctable = (jint *)(*(table->GetPrimitiveArrayCritical))(env, + textureColorTable, NULL); + if (numComponents == 3) { + ctxProperties->glColorTable(GL_TEXTURE_COLOR_TABLE_SGI, GL_RGB, + colorTableSize, GL_RGB, GL_INT, ctable); + } else { + ctxProperties->glColorTable(GL_TEXTURE_COLOR_TABLE_SGI, GL_RGBA, + colorTableSize, GL_RGBA, GL_INT, ctable); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, textureColorTable, ctable, 0); + glEnable(GL_TEXTURE_COLOR_TABLE_SGI); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateMaterialColor( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat transparency) +{ + float color[4]; + + color[0] = colorRed; + color[1] = colorGreen; + color[2] = colorBlue; + color[3] = transparency; + glColor4fv(color); + glDisable(GL_LIGHTING); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateMaterial( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat transparency, + jfloat aRed, + jfloat aGreen, + jfloat aBlue, + jfloat eRed, + jfloat eGreen, + jfloat eBlue, + jfloat dRed, + jfloat dGreen, + jfloat dBlue, + jfloat sRed, + jfloat sGreen, + jfloat sBlue, + jfloat shininess, + jint colorTarget, + jboolean lightEnable) +{ + float color[4]; + + color[3] = 1.0f; + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shininess); + if (colorTarget == javax_media_j3d_Material_DIFFUSE) { + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + } + else if (colorTarget == javax_media_j3d_Material_AMBIENT) { + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT); + } + else if (colorTarget == javax_media_j3d_Material_EMISSIVE) { + glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION); + } + else if (colorTarget == javax_media_j3d_Material_SPECULAR) { + glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); + } + else if (colorTarget == javax_media_j3d_Material_AMBIENT_AND_DIFFUSE) { + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + } + + color[0] = eRed; color[1] = eGreen; color[2] = eBlue; + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); + + color[0] = aRed; color[1] = aGreen; color[2] = aBlue; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); + + color[0] = sRed; color[1] = sGreen; color[2] = sBlue; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); + + if (lightEnable == JNI_TRUE) { + color[0] = dRed; color[1] = dGreen; color[2] = dBlue; + } else { + color[0] = colorRed; color[1] = colorGreen; color[2] = colorBlue; + } + color[3] = transparency; + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); + glColor4fv(color); + + if (lightEnable) { + glEnable(GL_LIGHTING); + } else { + glDisable(GL_LIGHTING); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetTransparency( + JNIEnv *env, + jobject cv, + jlong ctxInfo, + jint geometryType, + jint polygonMode, + jboolean lineAA, + jboolean pointAA) +{ + if (((((geometryType & javax_media_j3d_RenderMolecule_LINE) != 0) || + (polygonMode == javax_media_j3d_PolygonAttributes_POLYGON_LINE)) + && lineAA == JNI_TRUE) || + ((((geometryType & javax_media_j3d_RenderMolecule_POINT) != 0) || + (polygonMode == javax_media_j3d_PolygonAttributes_POLYGON_POINT)) + && pointAA == JNI_TRUE)) { + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable (GL_BLEND); + } + glDisable(GL_POLYGON_STIPPLE); + +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTransparencyAttributes( + JNIEnv *env, + jobject tr, + jlong ctxInfo, + jfloat transparency, + jint geometryType, + jint polygonMode, + jboolean lineAA, + jboolean pointAA, + jint transparencyMode, + jint srcBlendFunction, + jint dstBlendFunction) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + if (transparencyMode != javax_media_j3d_TransparencyAttributes_SCREEN_DOOR) { + glDisable(GL_POLYGON_STIPPLE); + } else { + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple((GLubyte *)(screen_door[(int)((transparency)*16)])); + } + + if ((transparencyMode < javax_media_j3d_TransparencyAttributes_SCREEN_DOOR) || + ((((geometryType & javax_media_j3d_RenderMolecule_LINE) != 0) || + (polygonMode == javax_media_j3d_PolygonAttributes_POLYGON_LINE)) + && lineAA == JNI_TRUE) || + ((((geometryType & javax_media_j3d_RenderMolecule_POINT) != 0) || + (polygonMode == javax_media_j3d_PolygonAttributes_POLYGON_POINT)) + && pointAA == JNI_TRUE)) { + glEnable (GL_BLEND); + /* valid range of blendFunction 0..3 is already verify in Java code. */ + glBlendFunc(ctxProperties->blendFunctionTable[srcBlendFunction], + ctxProperties->blendFunctionTable[dstBlendFunction]); + } else { + glDisable (GL_BLEND); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetColoringAttributes( + JNIEnv *env, + jobject cv, + jlong ctxInfo, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat transparency, + jboolean lightEnable) +{ + + float color[4]; + + if (lightEnable != JNI_TRUE) { + color[0] = colorRed; color[1] = colorGreen; color[2] = colorBlue; + color[3] = transparency; + glColor4fv(color); + + } + glShadeModel(GL_SMOOTH); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateColoringAttributes( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat dRed, + jfloat dGreen, + jfloat dBlue, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat transparency, + jboolean lightEnable, + jint shadeModel) +{ + + float color[4]; + + if (lightEnable == JNI_TRUE) { + color[0] = dRed; color[1] = dGreen; color[2] = dBlue; + } else { + color[0] = colorRed; color[1] = colorGreen; color[2] = colorBlue; + } + color[3] = transparency; + + glColor4fv(color); + if (shadeModel == javax_media_j3d_ColoringAttributes_SHADE_FLAT) { + glShadeModel(GL_FLAT); + } else { + glShadeModel(GL_SMOOTH); + } +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_resetTextureNative( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint texUnitIndex) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + if(ctxProperties->gl13) { + if (texUnitIndex >= 0) { + ctxProperties->glActiveTexture(texUnitIndex + GL_TEXTURE0); + ctxProperties->glClientActiveTexture(texUnitIndex + GL_TEXTURE0); + } + } + + glDisable(GL_TEXTURE_1D); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_3D); + glDisable(GL_TEXTURE_CUBE_MAP); +} + + +/* + * A set of common updateTexture functions shared among Texture2D, Texture3D, + * and TextureCubeMap for setting texture parameters + */ +void updateTextureFilterModes( + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + jint minFilter, + jint magFilter) { + + /* set texture min filter */ + switch(minFilter) { + case javax_media_j3d_Texture_FASTEST: + case javax_media_j3d_Texture_BASE_LEVEL_POINT: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + break; + case javax_media_j3d_Texture_BASE_LEVEL_LINEAR: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + break; + case javax_media_j3d_Texture_MULTI_LEVEL_POINT: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + break; + case javax_media_j3d_Texture_NICEST: + case javax_media_j3d_Texture_MULTI_LEVEL_LINEAR: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + break; + case javax_media_j3d_Texture_FILTER4: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, + ctxProperties->filter4_enum); + break; + + } + + /* set texture mag filter */ + switch(magFilter){ + case javax_media_j3d_Texture_FASTEST: + case javax_media_j3d_Texture_BASE_LEVEL_POINT: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + case javax_media_j3d_Texture_NICEST: + case javax_media_j3d_Texture_BASE_LEVEL_LINEAR: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + case javax_media_j3d_Texture_LINEAR_SHARPEN: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, + ctxProperties->linear_sharpen_enum); + break; + case javax_media_j3d_Texture_LINEAR_SHARPEN_RGB: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, + ctxProperties->linear_sharpen_rgb_enum); + break; + case javax_media_j3d_Texture_LINEAR_SHARPEN_ALPHA: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, + ctxProperties->linear_sharpen_alpha_enum); + break; + case javax_media_j3d_Texture2D_LINEAR_DETAIL: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, + ctxProperties->linear_detail_enum); + break; + case javax_media_j3d_Texture2D_LINEAR_DETAIL_RGB: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, + ctxProperties->linear_detail_rgb_enum); + break; + case javax_media_j3d_Texture2D_LINEAR_DETAIL_ALPHA: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, + ctxProperties->linear_detail_alpha_enum); + break; + case javax_media_j3d_Texture_FILTER4: + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, + ctxProperties->filter4_enum); + break; + } +} + + +void updateTextureLodRange( + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + jint baseLevel, + jint maximumLevel, + float minimumLod, float maximumLod) { + + /* + * checking of the availability of the extension is already done + * in the java side + */ + glTexParameteri(target, ctxProperties->texture_base_level_enum, + baseLevel); + glTexParameteri(target, ctxProperties->texture_max_level_enum, + maximumLevel); + glTexParameterf(target, ctxProperties->texture_min_lod_enum, + minimumLod); + glTexParameterf(target, ctxProperties->texture_max_lod_enum, + maximumLod); +} + +void updateTextureLodOffset( + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + float lodOffsetS, float lodOffsetT, float lodOffsetR) { + + /* + * checking of the availability of the extension is already done + * in the java side + */ + glTexParameterf(target, GL_TEXTURE_LOD_BIAS_S_SGIX, lodOffsetS); + glTexParameterf(target, GL_TEXTURE_LOD_BIAS_T_SGIX, lodOffsetT); + glTexParameterf(target, GL_TEXTURE_LOD_BIAS_R_SGIX, lodOffsetR); +} + + +void updateTextureBoundary( + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + jint boundaryModeS, + jint boundaryModeT, + jint boundaryModeR, + jfloat boundaryRed, + jfloat boundaryGreen, + jfloat boundaryBlue, + jfloat boundaryAlpha) +{ + float color[4]; + + /* set texture wrap parameter */ + switch (boundaryModeS){ + case javax_media_j3d_Texture_WRAP: + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); + break; + case javax_media_j3d_Texture_CLAMP: + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP); + break; + case javax_media_j3d_Texture_CLAMP_TO_EDGE: + glTexParameteri(target, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + break; + case javax_media_j3d_Texture_CLAMP_TO_BOUNDARY: + glTexParameteri(target, GL_TEXTURE_WRAP_S, + ctxProperties->texture_clamp_to_border_enum); + break; + } + + switch (boundaryModeT) { + case javax_media_j3d_Texture_WRAP: + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case javax_media_j3d_Texture_CLAMP: + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP); + break; + case javax_media_j3d_Texture_CLAMP_TO_EDGE: + glTexParameteri(target, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + break; + case javax_media_j3d_Texture_CLAMP_TO_BOUNDARY: + glTexParameteri(target, GL_TEXTURE_WRAP_T, + ctxProperties->texture_clamp_to_border_enum); + break; + } + + /* applies to Texture3D only */ + if (boundaryModeR != -1) { + switch (boundaryModeR) { + case javax_media_j3d_Texture_WRAP: + glTexParameteri(target, + GL_TEXTURE_WRAP_R, GL_REPEAT); + break; + + case javax_media_j3d_Texture_CLAMP: + glTexParameteri(target, + GL_TEXTURE_WRAP_R, GL_CLAMP); + break; + case javax_media_j3d_Texture_CLAMP_TO_EDGE: + glTexParameteri(target, + GL_TEXTURE_WRAP_R, + GL_CLAMP_TO_EDGE); + break; + case javax_media_j3d_Texture_CLAMP_TO_BOUNDARY: + glTexParameteri(target, + GL_TEXTURE_WRAP_R, + ctxProperties->texture_clamp_to_border_enum); + break; + } + } + + if (boundaryModeS == javax_media_j3d_Texture_CLAMP || + boundaryModeT == javax_media_j3d_Texture_CLAMP || + boundaryModeR == javax_media_j3d_Texture_CLAMP) { + /* set texture border color */ + color[0] = boundaryRed; + color[1] = boundaryGreen; + color[2] = boundaryBlue; + color[3] = boundaryAlpha; + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color); + } +} + +void updateTextureSharpenFunc( + JNIEnv *env, + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + jint numPts, + jfloatArray pts) +{ + /* + * checking of the availability of sharpen texture functionality + * is already done in the java side + */ + + JNIEnv table = *env; + jfloat *funcPts = NULL; + + if (numPts > 0) { + funcPts = (jfloat *)(*(table->GetPrimitiveArrayCritical))( + env, pts, NULL); + } + + ctxProperties->glSharpenTexFuncSGIS(target, numPts, funcPts); + + if (funcPts != NULL) { + (*(table->ReleasePrimitiveArrayCritical))(env, pts, funcPts, 0); + } +} + + +void updateTextureFilter4Func( + JNIEnv *env, + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + jint numPts, + jfloatArray pts) +{ + /* + * checking of the availability of filter4 functionality + * is already done in the java side + */ + + JNIEnv table = *env; + jfloat *funcPts = NULL; + + if (numPts > 0) { + funcPts = (jfloat *)(*(table->GetPrimitiveArrayCritical))( + env, pts, NULL); + } + + ctxProperties->glTexFilterFuncSGIS(target, ctxProperties->filter4_enum, + numPts, funcPts); + + if (funcPts != NULL) { + (*(table->ReleasePrimitiveArrayCritical))(env, pts, funcPts, 0); + } +} + +void updateTextureAnisotropicFilter( + JNIEnv *env, + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + jfloat degree) +{ + /* + * checking of the availability of anisotropic filter functionality + * is already done in the java side + */ + glTexParameterf(target, + ctxProperties->texture_filter_anisotropic_ext_enum, + degree); +} + +/* + * common function to define 2D texture image for different target + */ +void updateTexture2DImage( + JNIEnv *env, + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + jint numLevels, + jint level, + jint textureFormat, + jint imageFormat, + jint width, + jint height, + jint boundaryWidth, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + void *imageObjPtr; + GLenum format = 0, internalFormat = 0, type = GL_UNSIGNED_INT_8_8_8_8; + JNIEnv table = *env; + GLboolean forceAlphaToOne = GL_FALSE; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *)(*(table->GetPrimitiveArrayCritical))(env, (jarray)data, NULL); + } + else { + imageObjPtr = (void *)(*(table->GetDirectBufferAddress))(env, data); + } + + switch (textureFormat) { + case INTENSITY: + internalFormat = GL_INTENSITY; + break; + case LUMINANCE: + internalFormat = GL_LUMINANCE; + break; + case ALPHA: + internalFormat = GL_ALPHA; + break; + case LUMINANCE_ALPHA: + internalFormat = GL_LUMINANCE_ALPHA; + break; + case J3D_RGB: + internalFormat = GL_RGB; + break; + case J3D_RGBA: + internalFormat = GL_RGBA; + break; + default: + throwAssert(env, "updateTexture2DImage : textureFormat illegal format"); + return; + } + + if (useAutoMipMap) { + glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE); + } + else { + glTexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_BYTE_BUFFER)) { + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_BYTE_BGR: + format = GL_BGR; + break; + case IMAGE_FORMAT_BYTE_RGB: + format = GL_RGB; + break; + /* GL_ABGR_EXT */ + case IMAGE_FORMAT_BYTE_ABGR: + if (ctxProperties->abgr_ext) { /* If its zero, should never come here! */ + format = GL_ABGR_EXT; + } + else { + throwAssert(env, "updateTexture2DImage : GL_ABGR_EXT format is unsupported"); + return; + } + break; + case IMAGE_FORMAT_BYTE_RGBA: + format = GL_RGBA; + break; + case IMAGE_FORMAT_BYTE_LA: + /* all LA types are stored as LA8 */ + format = GL_LUMINANCE_ALPHA; + break; + case IMAGE_FORMAT_BYTE_GRAY: + if (internalFormat == GL_ALPHA) { + format = GL_ALPHA; + } else { + format = GL_LUMINANCE; + } + break; + + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + default: + throwAssert(env, "updateTexture2DImage : imageFormat illegal format"); + return; + } + + glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, GL_UNSIGNED_BYTE, imageObjPtr); + + } + else if((dataType == IMAGE_DATA_TYPE_INT_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_BUFFER)) { + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_INT_BGR: /* Assume XBGR format */ + format = GL_RGBA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = GL_TRUE; + break; + case IMAGE_FORMAT_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = GL_TRUE; + /* Fall through to next case */ + case IMAGE_FORMAT_INT_ARGB: + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_ABGR: + default: + throwAssert(env, "updateTexture2DImage : imageFormat illegal format"); + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 0.0f); + glPixelTransferf(GL_ALPHA_BIAS, 1.0f); + } + + glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, type, imageObjPtr); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + glPixelTransferf(GL_ALPHA_BIAS, 0.0f); + } + } + else { + throwAssert(env, "updateTexture2DImage : illegal image data type"); + return; + } + + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + (*(table->ReleasePrimitiveArrayCritical))(env, data, imageObjPtr, 0); + } + +} + + +/* + * common function to update 2D texture image for different target + */ + +void updateTexture2DSubImage( + JNIEnv *env, + GraphicsContextPropertiesInfo *ctxProperties, + jint target, + jint level, + jint xoffset, + jint yoffset, + jint textureFormat, + jint imageFormat, + jint imgXOffset, + jint imgYOffset, + jint tilew, + jint width, + jint height, + jint dataType, + jobject data) { + + void *imageObjPtr; + GLenum format = 0, internalFormat = 0, type = GL_UNSIGNED_INT_8_8_8_8; + JNIEnv table = *env; + GLboolean forceAlphaToOne = GL_FALSE; + jbyte *tmpByte; + jint *tmpInt; + jint numBytes = 0; + jboolean pixelStore = JNI_FALSE; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *)(*(table->GetPrimitiveArrayCritical))(env, (jarray)data, NULL); + } + else { + imageObjPtr = (void *)(*(table->GetDirectBufferAddress))(env, data); + } + + if (imgXOffset > 0 || (width < tilew)) { + pixelStore = JNI_TRUE; + glPixelStorei(GL_UNPACK_ROW_LENGTH, tilew); + } + + switch (textureFormat) { + case INTENSITY: + internalFormat = GL_INTENSITY; + break; + case LUMINANCE: + internalFormat = GL_LUMINANCE; + break; + case ALPHA: + internalFormat = GL_ALPHA; + break; + case LUMINANCE_ALPHA: + internalFormat = GL_LUMINANCE_ALPHA; + break; + case J3D_RGB: + internalFormat = GL_RGB; + break; + case J3D_RGBA: + internalFormat = GL_RGBA; + break; + default: + throwAssert(env, "updateTexture2DSubImage : textureFormat illegal format"); + return; + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_BYTE_BUFFER)) { + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_BYTE_BGR: + format = GL_BGR; + numBytes = 3; + break; + case IMAGE_FORMAT_BYTE_RGB: + format = GL_RGB; + numBytes = 3; + break; + /* GL_ABGR_EXT */ + case IMAGE_FORMAT_BYTE_ABGR: + if (ctxProperties->abgr_ext) { /* If its zero, should never come here! */ + format = GL_ABGR_EXT; + numBytes = 4; + } + else { + throwAssert(env, "updateTexture2DSubImage : GL_ABGR_EXT format is unsupported"); + return; + } + break; + case IMAGE_FORMAT_BYTE_RGBA: + format = GL_RGBA; + numBytes = 4; + break; + case IMAGE_FORMAT_BYTE_LA: + /* all LA types are stored as LA8 */ + numBytes = 2; + format = GL_LUMINANCE_ALPHA; + break; + case IMAGE_FORMAT_BYTE_GRAY: + if (internalFormat == GL_ALPHA) { + format = GL_ALPHA; + numBytes = 1; + } else { + format = GL_LUMINANCE; + numBytes = 1; + } + break; + + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + default: + throwAssert(env, "updateTexture2DSubImage : imageFormat illegal format"); + return; + } + + tmpByte = (jbyte*)imageObjPtr + + (tilew * imgYOffset + imgXOffset) * numBytes; + + + glTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, GL_UNSIGNED_BYTE, (GLvoid *)tmpByte); + + } + else if((dataType == IMAGE_DATA_TYPE_INT_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_BUFFER)) { + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_INT_BGR: /* Assume XBGR format */ + format = GL_RGBA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = GL_TRUE; + break; + case IMAGE_FORMAT_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = GL_TRUE; + /* Fall through to next case */ + case IMAGE_FORMAT_INT_ARGB: + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_ABGR: + default: + throwAssert(env, "updateTexture2DSubImage : imageFormat illegal format"); + return; + } + + numBytes = 4; + + tmpInt = (jint*)((jbyte*)imageObjPtr + + (tilew * imgYOffset + imgXOffset)*numBytes); + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 0.0f); + glPixelTransferf(GL_ALPHA_BIAS, 1.0f); + } + + glTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, type, (GLvoid *)tmpInt); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + glPixelTransferf(GL_ALPHA_BIAS, 0.0f); + } + } + else { + throwAssert(env, "updateTexture2DImage : illegal image data type"); + return; + } + + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + (*(table->ReleasePrimitiveArrayCritical))(env, data, imageObjPtr, 0); + } + + if (pixelStore) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_bindTexture2D( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint objectId, + jboolean enable) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + glDisable(GL_TEXTURE_CUBE_MAP); + glDisable(GL_TEXTURE_3D); + + if (enable == JNI_FALSE) { + glDisable(GL_TEXTURE_2D); + } else { + glBindTexture(GL_TEXTURE_2D, objectId); + glEnable(GL_TEXTURE_2D); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DFilterModes( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint minFilter, + jint magFilter) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureFilterModes(ctxProperties, GL_TEXTURE_2D, + minFilter, magFilter); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DLodRange( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint baseLevel, + jint maximumLevel, + jfloat minimumLOD, + jfloat maximumLOD) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureLodRange(ctxProperties, GL_TEXTURE_2D, + baseLevel, maximumLevel, + minimumLOD, maximumLOD); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DLodOffset( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat lodOffsetS, + jfloat lodOffsetT, + jfloat lodOffsetR) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureLodOffset(ctxProperties, GL_TEXTURE_2D, + lodOffsetS, lodOffsetT, lodOffsetR); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DBoundary( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint boundaryModeS, + jint boundaryModeT, + jfloat boundaryRed, + jfloat boundaryGreen, + jfloat boundaryBlue, + jfloat boundaryAlpha) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureBoundary(ctxProperties, GL_TEXTURE_2D, + boundaryModeS, boundaryModeT, -1, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DSharpenFunc( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numPts, + jfloatArray pts) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureSharpenFunc(env, ctxProperties, GL_TEXTURE_2D, numPts, pts); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DFilter4Func( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numPts, + jfloatArray pts) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureFilter4Func(env, ctxProperties, GL_TEXTURE_2D, numPts, pts); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DAnisotropicFilter( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat degree) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureAnisotropicFilter(env, ctxProperties, GL_TEXTURE_2D, degree); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DSubImage( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint level, + jint xoffset, + jint yoffset, + jint textureFormat, + jint imageFormat, + jint imgXOffset, + jint imgYOffset, + jint tilew, + jint width, + jint height, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + /* Note : useAutoMipMap is not use for subImage in ogl pipe */ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + updateTexture2DSubImage(env, ctxProperties, GL_TEXTURE_2D, + level, xoffset, yoffset, + textureFormat, imageFormat, + imgXOffset, imgYOffset, tilew, width, height, + dataType, data); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture2DImage( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numLevels, + jint level, + jint textureFormat, + jint imageFormat, + jint width, + jint height, + jint boundaryWidth, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTexture2DImage(env, ctxProperties, GL_TEXTURE_2D, + numLevels, level, textureFormat, imageFormat, + width, height, boundaryWidth, dataType, data, useAutoMipMap); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_bindTexture3D( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint objectId, + jboolean enable) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + /* textureCubeMap will take precedure over 3D Texture */ + glDisable(GL_TEXTURE_CUBE_MAP); + + if (enable == JNI_FALSE) { + glDisable(GL_TEXTURE_3D); + } else { + glBindTexture(GL_TEXTURE_3D, objectId); + glEnable(GL_TEXTURE_3D); + } +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DFilterModes( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint minFilter, + jint magFilter) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureFilterModes(ctxProperties, GL_TEXTURE_3D, + minFilter, magFilter); +} + + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DLodRange( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint baseLevel, + jint maximumLevel, + jfloat minimumLOD, + jfloat maximumLOD) +{ + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureLodRange(ctxProperties, GL_TEXTURE_3D, + baseLevel, maximumLevel, + minimumLOD, maximumLOD); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DLodOffset( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat lodOffsetS, + jfloat lodOffsetT, + jfloat lodOffsetR) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureLodOffset(ctxProperties, GL_TEXTURE_3D, + lodOffsetS, lodOffsetT, lodOffsetR); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DBoundary( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint boundaryModeS, + jint boundaryModeT, + jint boundaryModeR, + jfloat boundaryRed, + jfloat boundaryGreen, + jfloat boundaryBlue, + jfloat boundaryAlpha) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureBoundary(ctxProperties, GL_TEXTURE_3D, + boundaryModeS, boundaryModeT, boundaryModeR, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DSharpenFunc( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numPts, + jfloatArray pts) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureSharpenFunc(env, ctxProperties, GL_TEXTURE_3D, numPts, pts); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DFilter4Func( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numPts, + jfloatArray pts) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureFilter4Func(env, ctxProperties, GL_TEXTURE_3D, numPts, pts); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DAnisotropicFilter( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat degree) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureAnisotropicFilter(env, ctxProperties, GL_TEXTURE_3D, degree); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DImage( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numLevels, + jint level, + jint textureFormat, + jint imageFormat, + jint width, + jint height, + jint depth, + jint boundaryWidth, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + void *imageObjPtr; + GLenum format = 0, internalFormat = 0, type = GL_UNSIGNED_INT_8_8_8_8; + JNIEnv table = *env; + GLboolean forceAlphaToOne = GL_FALSE; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *)(*(table->GetPrimitiveArrayCritical))(env, (jarray)data, NULL); + } + else { + imageObjPtr = (void *)(*(table->GetDirectBufferAddress))(env, data); + } + + switch (textureFormat) { + case INTENSITY: + internalFormat = GL_INTENSITY; + break; + case LUMINANCE: + internalFormat = GL_LUMINANCE; + break; + case ALPHA: + internalFormat = GL_ALPHA; + break; + case LUMINANCE_ALPHA: + internalFormat = GL_LUMINANCE_ALPHA; + break; + case J3D_RGB: + internalFormat = GL_RGB; + break; + case J3D_RGBA: + internalFormat = GL_RGBA; + break; + default: + throwAssert(env, "updateTexture3DImage : textureFormat illegal format"); + return; + } + + if (useAutoMipMap) { + glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_TRUE); + } + else { + glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_FALSE); + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_BYTE_BUFFER)) { + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_BYTE_BGR: + format = GL_BGR; + break; + case IMAGE_FORMAT_BYTE_RGB: + format = GL_RGB; + break; + /* GL_ABGR_EXT */ + case IMAGE_FORMAT_BYTE_ABGR: + if (ctxProperties->abgr_ext) { /* If its zero, should never come here! */ + format = GL_ABGR_EXT; + } + else { + throwAssert(env, "updateTexture3DImage : GL_ABGR_EXT format is unsupported"); + return; + } + break; + case IMAGE_FORMAT_BYTE_RGBA: + format = GL_RGBA; + break; + case IMAGE_FORMAT_BYTE_LA: + /* all LA types are stored as LA8 */ + format = GL_LUMINANCE_ALPHA; + break; + case IMAGE_FORMAT_BYTE_GRAY: + if (internalFormat == GL_ALPHA) { + format = GL_ALPHA; + } else { + format = GL_LUMINANCE; + } + break; + + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + default: + throwAssert(env, "updateTexture3DImage : imageFormat illegal format"); + return; + } + + ctxProperties->glTexImage3DEXT(GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, GL_UNSIGNED_BYTE, + imageObjPtr); + + } + else if((dataType == IMAGE_DATA_TYPE_INT_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_BUFFER)) { + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_INT_BGR: /* Assume XBGR format */ + format = GL_RGBA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = GL_TRUE; + break; + case IMAGE_FORMAT_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = GL_TRUE; + /* Fall through to next case */ + case IMAGE_FORMAT_INT_ARGB: + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_ABGR: + default: + throwAssert(env, "updateTexture3DImage : imageFormat illegal format"); + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 0.0f); + glPixelTransferf(GL_ALPHA_BIAS, 1.0f); + } + + ctxProperties->glTexImage3DEXT(GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, type, imageObjPtr); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + glPixelTransferf(GL_ALPHA_BIAS, 0.0f); + } + } + else { + throwAssert(env, "updateTexture3DImage : illegal image data type"); + } + + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + (*(table->ReleasePrimitiveArrayCritical))(env, data, imageObjPtr, 0); + } + +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTexture3DSubImage( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint level, + jint xoffset, + jint yoffset, + jint zoffset, + jint textureFormat, + jint imageFormat, + jint imgXOffset, + jint imgYOffset, + jint imgZOffset, + jint tilew, + jint tileh, + jint width, + jint height, + jint depth, + jint dataType, + jobject data, + jboolean useAutoMipMap) { + + /* Note : useAutoMipMap is not use for SubImage in ogl pipe */ + + void *imageObjPtr; + GLenum format = 0, internalFormat = 0, type = GL_UNSIGNED_INT_8_8_8_8; + JNIEnv table = *env; + GLboolean forceAlphaToOne = GL_FALSE; + jbyte *tmpByte; + jint *tmpInt; + jint numBytes = 0; + jboolean pixelStore = JNI_FALSE; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *)(*(table->GetPrimitiveArrayCritical))(env, (jarray)data, NULL); + } + else { + imageObjPtr = (void *)(*(table->GetDirectBufferAddress))(env, data); + } + + if (imgXOffset > 0 || (width < tilew)) { + pixelStore = JNI_TRUE; + glPixelStorei(GL_UNPACK_ROW_LENGTH, tilew); + } + + switch (textureFormat) { + case INTENSITY: + internalFormat = GL_INTENSITY; + break; + case LUMINANCE: + internalFormat = GL_LUMINANCE; + break; + case ALPHA: + internalFormat = GL_ALPHA; + break; + case LUMINANCE_ALPHA: + internalFormat = GL_LUMINANCE_ALPHA; + break; + case J3D_RGB: + internalFormat = GL_RGB; + break; + case J3D_RGBA: + internalFormat = GL_RGBA; + break; + default: + throwAssert(env, "updateTexture3DSubImage : textureFormat illegal format"); + break; + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_BYTE_BUFFER)) { + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_BYTE_BGR: + format = GL_BGR; + numBytes = 3; + break; + case IMAGE_FORMAT_BYTE_RGB: + format = GL_RGB; + numBytes = 3; + break; + /* GL_ABGR_EXT */ + case IMAGE_FORMAT_BYTE_ABGR: + if (ctxProperties->abgr_ext) { /* If its zero, should never come here! */ + format = GL_ABGR_EXT; + numBytes = 4; + } + else { + throwAssert(env, "updateTexture3DSubImage : GL_ABGR_EXT format is unsupported"); + } + break; + case IMAGE_FORMAT_BYTE_RGBA: + format = GL_RGBA; + numBytes = 4; + break; + case IMAGE_FORMAT_BYTE_LA: + /* all LA types are stored as LA8 */ + format = GL_LUMINANCE_ALPHA; + numBytes = 2; + break; + case IMAGE_FORMAT_BYTE_GRAY: + if (internalFormat == GL_ALPHA) { + format = GL_ALPHA; + numBytes = 1; + } else { + format = GL_LUMINANCE; + numBytes = 1; + } + break; + + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + default: + throwAssert(env, "updateTexture3DSubImage : imageFormat illegal format"); + break; + } + + tmpByte = (jbyte*)imageObjPtr + + (tilew * tileh * imgZOffset + tilew * imgYOffset + imgXOffset) * + numBytes; + + ctxProperties->glTexSubImage3DEXT(GL_TEXTURE_3D, + level, xoffset, yoffset, zoffset, + width, height, depth, + format, GL_UNSIGNED_BYTE, + (GLvoid *)tmpByte); + + + } + else if((dataType == IMAGE_DATA_TYPE_INT_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_BUFFER)) { + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_INT_BGR: /* Assume XBGR format */ + format = GL_RGBA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = GL_TRUE; + break; + case IMAGE_FORMAT_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = GL_TRUE; + /* Fall through to next case */ + case IMAGE_FORMAT_INT_ARGB: + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_ABGR: + default: + throwAssert(env, "updateTexture3DSubImage : imageFormat illegal format"); + break; + } + + numBytes = 4; + + tmpInt = (jint*)((jbyte*)imageObjPtr + + (tilew * tileh * imgZOffset + + tilew * imgYOffset + imgXOffset)*numBytes); + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 0.0f); + glPixelTransferf(GL_ALPHA_BIAS, 1.0f); + } + + ctxProperties->glTexSubImage3DEXT(GL_TEXTURE_3D, + level, xoffset, yoffset, zoffset, + width, height, depth, + format, type, + (GLvoid *)tmpInt); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + glPixelTransferf(GL_ALPHA_BIAS, 0.0f); + } + } + else { + throwAssert(env, "updateTexture3DImage : illegal image data type"); + return; + } + + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + (*(table->ReleasePrimitiveArrayCritical))(env, data, imageObjPtr, 0); + } + + if (pixelStore) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } +} + + +/* + * mapping from java enum to gl enum + */ + +jint _gl_textureCubeMapFace[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT, +}; + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_bindTextureCubeMap( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint objectId, + jboolean enable) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + /* + * TextureCubeMap will take precedure over 3D Texture so + * there is no need to disable 3D Texture here. + */ + if (enable == JNI_FALSE) { + glDisable(GL_TEXTURE_CUBE_MAP); + } else { + glBindTexture(GL_TEXTURE_CUBE_MAP, objectId); + glEnable(GL_TEXTURE_CUBE_MAP); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapFilterModes( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint minFilter, + jint magFilter) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureFilterModes(ctxProperties, + GL_TEXTURE_CUBE_MAP, + minFilter, magFilter); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapLodRange( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint baseLevel, + jint maximumLevel, + jfloat minimumLOD, + jfloat maximumLOD) +{ + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureLodRange(ctxProperties, + GL_TEXTURE_CUBE_MAP, + baseLevel, maximumLevel, + minimumLOD, maximumLOD); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapLodOffset( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat lodOffsetS, + jfloat lodOffsetT, + jfloat lodOffsetR) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureLodOffset(ctxProperties, + GL_TEXTURE_CUBE_MAP, + lodOffsetS, lodOffsetT, lodOffsetR); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapBoundary( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint boundaryModeS, + jint boundaryModeT, + jfloat boundaryRed, + jfloat boundaryGreen, + jfloat boundaryBlue, + jfloat boundaryAlpha) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureBoundary(ctxProperties, + GL_TEXTURE_CUBE_MAP, + boundaryModeS, boundaryModeT, -1, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapSharpenFunc( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numPts, + jfloatArray pts) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureSharpenFunc(env, ctxProperties, + GL_TEXTURE_CUBE_MAP, + numPts, pts); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapFilter4Func( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint numPts, + jfloatArray pts) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureFilter4Func(env, ctxProperties, + GL_TEXTURE_CUBE_MAP, + numPts, pts); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapAnisotropicFilter( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat degree) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + updateTextureAnisotropicFilter(env, ctxProperties, + GL_TEXTURE_CUBE_MAP, + degree); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapSubImage( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint face, + jint level, + jint xoffset, + jint yoffset, + jint textureFormat, + jint imageFormat, + jint imgXOffset, + jint imgYOffset, + jint tilew, + jint width, + jint height, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + /* Note : useAutoMipMap is not use for SubImage in ogl pipe */ + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + updateTexture2DSubImage(env, ctxProperties, _gl_textureCubeMapFace[face], + level, xoffset, yoffset, textureFormat, + imageFormat, imgXOffset, imgYOffset, tilew, + width, height, dataType, data); +} + + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureCubeMapImage( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint face, + jint numLevels, + jint level, + jint textureFormat, + jint imageFormat, + jint width, + jint height, + jint boundaryWidth, + jint dataType, + jobject data, + jboolean useAutoMipMap) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + updateTexture2DImage(env, ctxProperties, _gl_textureCubeMapFace[face], + numLevels, level, textureFormat, imageFormat, + width, height, boundaryWidth, dataType, data, useAutoMipMap); +} + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_decal1stChildSetup( + JNIEnv *env, + jobject obj, + jlong ctxInfo) +{ + glEnable(GL_STENCIL_TEST); + glClearStencil(0x0); + glClear(GL_STENCIL_BUFFER_BIT); + glStencilFunc (GL_ALWAYS, 0x1, 0x1); + glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); + if (glIsEnabled(GL_DEPTH_TEST)) + return JNI_TRUE; + else + return JNI_FALSE; +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_decalNthChildSetup( + JNIEnv *env, + jobject obj, + jlong ctxInfo) +{ + glDisable(GL_DEPTH_TEST); + glStencilFunc (GL_EQUAL, 0x1, 0x1); + glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_decalReset( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jboolean depthBufferEnable) +{ + glDisable(GL_STENCIL_TEST); + if (depthBufferEnable == JNI_TRUE) + glEnable(GL_DEPTH_TEST); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_ctxUpdateEyeLightingEnable( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jboolean localEyeLightingEnable) +{ + if (localEyeLightingEnable == JNI_TRUE) { + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); + } else { + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateSeparateSpecularColorEnable( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jboolean enable) +{ + if (enable) { + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); + } else { + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateTextureUnitState( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint index, + jboolean enable) +{ + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + if (ctxProperties->gl13 && index >= 0) { + ctxProperties->glActiveTexture(index + GL_TEXTURE0); + ctxProperties->glClientActiveTexture(GL_TEXTURE0 + index); + if (ctxProperties->textureRegisterCombinersAvailable) { + ctxProperties->currentTextureUnit = index + GL_TEXTURE0; + ctxProperties->currentCombinerUnit = index + GL_COMBINER0_NV; + if (ctxProperties->glCombinerParameteriNV != NULL) + ctxProperties->glCombinerParameteriNV( + GL_NUM_GENERAL_COMBINERS_NV, index + 1); + } + } + + if (enable == JNI_FALSE) { + /* if not enabled, then don't enable any tex mapping */ + + glDisable(GL_TEXTURE_1D); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_3D); + glDisable(GL_TEXTURE_CUBE_MAP); + } + + /* + * if it is enabled, the enable flag will be taken care of + * in the bindTexture call + */ +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setBlendColor( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat colorRed, + jfloat colorGreen, + jfloat colorBlue, + jfloat colorAlpha) +{ + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + if (ctxProperties->blend_color_ext) { + /* + fprintf(stderr, "setBlendColor is on: %f %f %f %f\n", + colorRed, colorGreen, colorBlue, colorAlpha); + */ + + ctxProperties->glBlendColor(colorRed, colorGreen, colorBlue, colorAlpha); + } +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setBlendFunc( + JNIEnv * env, + jobject obj, + jlong ctxInfo, + jint srcBlendFunction, + jint dstBlendFunction) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + glEnable(GL_BLEND); + glBlendFunc(ctxProperties->blendFunctionTable[srcBlendFunction], + ctxProperties->blendFunctionTable[dstBlendFunction]); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setFogEnableFlag( + JNIEnv * env, + jobject obj, + jlong ctxInfo, + jboolean enable) +{ + if (enable == JNI_TRUE) + glEnable(GL_FOG); + else + glDisable(GL_FOG); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_activeTextureUnit( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint index) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + if (ctxProperties->gl13) { + ctxProperties->glActiveTexture(GL_TEXTURE0 + index); + ctxProperties->glClientActiveTexture(GL_TEXTURE0 + index); + } +} + + +/* + * strJavaToC + * + * Returns a copy of the specified Java String object as a new, + * null-terminated "C" string. The caller must free this string. + */ +char * +strJavaToC(JNIEnv *env, jstring str) +{ + JNIEnv table = *env; + jclass oom; + + const char *strUTFBytes; /* Array of UTF-8 bytes */ + char *cString = NULL; /* Null-terminated "C" string */ + + if (str == NULL) { + return NULL; + } + + strUTFBytes = table->GetStringUTFChars(env, str, NULL); + if (strUTFBytes == NULL) { + /* Just return, since GetStringUTFChars will throw OOM if it returns NULL */ + return NULL; + } + + cString = strdup(strUTFBytes); + table->ReleaseStringUTFChars(env, str, strUTFBytes); + if (cString == NULL) { + if ((oom = table->FindClass(env, "java/lang/OutOfMemoryError")) != NULL) { + table->ThrowNew(env, oom, "strdup"); + } + return NULL; + } + + return cString; +} + + +/* + * createShaderError + * + * Constructs a new ShaderError object from the given error code, + * error message, and detail message. + */ +jobject +createShaderError( + JNIEnv *env, + int errorCode, + const char *errorMsg, + const char *detailMsg) +{ + JNIEnv table = *env; + jclass shaderErrorClass; + jobject shaderError; + jmethodID methodID; + jstring errorMsgString = NULL; + jstring detailMsgString = NULL; + + if (errorMsg != NULL) { + if ((errorMsgString = table->NewStringUTF(env, errorMsg)) == NULL) { + return NULL; + } + } + + if (detailMsg != NULL) { + if ((detailMsgString = table->NewStringUTF(env, detailMsg)) == NULL) { + return NULL; + } + } + + shaderErrorClass = (*(table->FindClass))(env, "javax/media/j3d/ShaderError"); + if (shaderErrorClass == NULL) { + return NULL; + } + + methodID = table->GetMethodID(env, shaderErrorClass, + "", + "(ILjava/lang/String;)V"); + if (methodID == NULL) { + return NULL; + } + + shaderError = table->NewObject(env, shaderErrorClass, methodID, + errorCode, errorMsgString); + if (shaderError == NULL) { + return NULL; + } + + methodID = table->GetMethodID(env, shaderErrorClass, + "setDetailMessage", + "(Ljava/lang/String;)V"); + if (methodID == NULL) { + return NULL; + } + + table->CallVoidMethod(env, shaderError, methodID, + detailMsgString); + + return shaderError; +} diff --git a/j3d-core/src/native/ogl/Canvas3D.c b/j3d-core/src/native/ogl/Canvas3D.c new file mode 100644 index 0000000..8b6b874 --- /dev/null +++ b/j3d-core/src/native/ogl/Canvas3D.c @@ -0,0 +1,3230 @@ +/* + * $RCSfile: Canvas3D.c,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.43 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include +#include +#include +#include +#include + +#include "gldefs.h" + +#if defined(UNIX) +#include +#endif + +#ifdef DEBUG +/* Uncomment the following for VERBOSE debug messages */ +/* #define VERBOSE */ +#endif /* DEBUG */ + +extern void throwAssert(JNIEnv *env, char *str); +jboolean getJavaBoolEnv(JNIEnv *env, char* envStr); +static void initializeCtxInfo(JNIEnv *env, GraphicsContextPropertiesInfo* ctxInfo); +static void cleanupCtxInfo(GraphicsContextPropertiesInfo* ctxInfo); +static void disableAttribFor2D(GraphicsContextPropertiesInfo *ctxProperties); +static void disableAttribForRaster(GraphicsContextPropertiesInfo *ctxProperties); + +/* + * Class: javax_media_j3d_Canvas3D + * Method: getTextureColorTableSize + * Signature: ()I + */ +static int getTextureColorTableSize( + JNIEnv *env, + jobject obj, + GraphicsContextPropertiesInfo *ctxInfo, + char *extensionStr); + +extern void checkGLSLShaderExtensions( + JNIEnv *env, + jobject obj, + char *tmpExtensionStr, + GraphicsContextPropertiesInfo *ctxInfo, + jboolean glslLibraryAvailable); + +extern void checkCgShaderExtensions( + JNIEnv *env, + jobject obj, + char *tmpExtensionStr, + GraphicsContextPropertiesInfo *ctxInfo, + jboolean cgLibraryAvailable); + + +#ifdef WIN32 +extern void printErrorMessage(char *message); +extern PIXELFORMATDESCRIPTOR getDummyPFD(); +extern HDC getMonitorDC(int screen); +HWND createDummyWindow(const char* szAppName); +#endif + +/* + * Extract the version numbers from a copy of the version string. + * Upon return, numbers[0] contains major version number + * numbers[1] contains minor version number + * Note that the passed in version string is modified. + */ +void extractVersionInfo(char *versionStr, int* numbers){ + char *majorNumStr; + char *minorNumStr; + + majorNumStr = strtok(versionStr, (char *)"."); + minorNumStr = strtok(0, (char *)"."); + if (majorNumStr != NULL) + numbers[0] = atoi(majorNumStr); + if (minorNumStr != NULL) + numbers[1] = atoi(minorNumStr); + + return; +} + +/* + * check if the extension is supported + */ +int +isExtensionSupported(const char *allExtensions, const char *extension) +{ + const char *start; + const char *where, *terminator; + + /* Extension names should not have spaces. */ + where = (const char *) strchr(extension, ' '); + if (where || *extension == '\0') + return 0; + + /* + * It takes a bit of care to be fool-proof about parsing the + * OpenGL extensions string. Don't be fooled by sub-strings, + * etc. + */ + start = allExtensions; + for (;;) { + where = (const char *) strstr((const char *) start, extension); + if (!where) + break; + terminator = where + strlen(extension); + if (where == start || *(where - 1) == ' ') + if (*terminator == ' ' || *terminator == '\0') + return 1; + start = terminator; + } + return 0; +} + + +static void +checkTextureExtensions( + JNIEnv *env, + jobject obj, + char *tmpExtensionStr, + GraphicsContextPropertiesInfo* ctxInfo) +{ + if (ctxInfo->gl13) { + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_MULTI_TEXTURE; + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &ctxInfo->maxTextureUnits); + ctxInfo->maxTexCoordSets = ctxInfo->maxTextureUnits; + if (isExtensionSupported(tmpExtensionStr, "GL_ARB_vertex_shader")) { + glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &ctxInfo->maxTexCoordSets); + } + } + + if(isExtensionSupported(tmpExtensionStr,"GL_SGI_texture_color_table" )){ + ctxInfo->textureColorTableAvailable = JNI_TRUE; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_COLOR_TABLE; + + /* get texture color table size */ + /* need to check later */ + ctxInfo->textureColorTableSize = getTextureColorTableSize(env, obj, + ctxInfo, tmpExtensionStr); + if (ctxInfo->textureColorTableSize <= 0) { + ctxInfo->textureColorTableAvailable = JNI_FALSE; + ctxInfo->textureExtMask &= ~javax_media_j3d_Canvas3D_TEXTURE_COLOR_TABLE; + } + if (ctxInfo->textureColorTableSize > 256) { + ctxInfo->textureColorTableSize = 256; + } + } + + if(isExtensionSupported(tmpExtensionStr,"GL_ARB_texture_env_combine" )){ + ctxInfo->textureEnvCombineAvailable = JNI_TRUE; + ctxInfo->textureCombineSubtractAvailable = JNI_TRUE; + + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE_SUBTRACT; + ctxInfo->combine_enum = GL_COMBINE_ARB; + ctxInfo->combine_add_signed_enum = GL_ADD_SIGNED_ARB; + ctxInfo->combine_interpolate_enum = GL_INTERPOLATE_ARB; + ctxInfo->combine_subtract_enum = GL_SUBTRACT_ARB; + + } else if(isExtensionSupported(tmpExtensionStr,"GL_EXT_texture_env_combine" )){ + ctxInfo->textureEnvCombineAvailable = JNI_TRUE; + ctxInfo->textureCombineSubtractAvailable = JNI_FALSE; + + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE; + ctxInfo->combine_enum = GL_COMBINE_EXT; + ctxInfo->combine_add_signed_enum = GL_ADD_SIGNED_EXT; + ctxInfo->combine_interpolate_enum = GL_INTERPOLATE_EXT; + + /* EXT_texture_env_combine does not include subtract */ + ctxInfo->combine_subtract_enum = 0; + } + + if(isExtensionSupported(tmpExtensionStr,"GL_NV_register_combiners" )) { + ctxInfo->textureRegisterCombinersAvailable = JNI_TRUE; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_REGISTER_COMBINERS; +#if defined(UNIX) + ctxInfo->glCombinerInputNV = + (MYPFNGLCOMBINERINPUTNV) dlsym(RTLD_DEFAULT, "glCombinerInputNV"); + ctxInfo->glFinalCombinerInputNV = + (MYPFNGLFINALCOMBINERINPUTNV) dlsym(RTLD_DEFAULT, "glFinalCombinerInputNV"); + ctxInfo->glCombinerOutputNV = + (MYPFNGLCOMBINEROUTPUTNV) dlsym(RTLD_DEFAULT, "glCombinerOutputNV"); + ctxInfo->glCombinerParameterfvNV = + (MYPFNGLCOMBINERPARAMETERFVNV) dlsym(RTLD_DEFAULT, "glCombinerParameterfvNV"); + ctxInfo->glCombinerParameterivNV = + (MYPFNGLCOMBINERPARAMETERIVNV) dlsym(RTLD_DEFAULT, "glCombinerParameterivNV"); + ctxInfo->glCombinerParameterfNV = + (MYPFNGLCOMBINERPARAMETERFNV) dlsym(RTLD_DEFAULT, "glCombinerParameterfNV"); + ctxInfo->glCombinerParameteriNV = + (MYPFNGLCOMBINERPARAMETERINV) dlsym(RTLD_DEFAULT, "glCombinerParameteriNV"); + if (ctxInfo->glCombinerInputNV == NULL || + ctxInfo->glFinalCombinerInputNV == NULL || + ctxInfo->glCombinerOutputNV == NULL || + ctxInfo->glCombinerParameterfvNV == NULL || + ctxInfo->glCombinerParameterivNV == NULL || + ctxInfo->glCombinerParameterfNV == NULL || + ctxInfo->glCombinerParameteriNV == NULL) { + /* lets play safe: */ + ctxInfo->textureExtMask &= + ~javax_media_j3d_Canvas3D_TEXTURE_REGISTER_COMBINERS; + ctxInfo->textureRegisterCombinersAvailable = JNI_FALSE; + } +#endif + +#ifdef WIN32 + ctxInfo->glCombinerInputNV = + (MYPFNGLCOMBINERINPUTNV) wglGetProcAddress("glCombinerInputNV"); + ctxInfo->glFinalCombinerInputNV = + (MYPFNGLFINALCOMBINERINPUTNV) wglGetProcAddress("glFinalCombinerInputNV"); + ctxInfo->glCombinerOutputNV = + (MYPFNGLCOMBINEROUTPUTNV) wglGetProcAddress("glCombinerOutputNV"); + ctxInfo->glCombinerParameterfvNV = + (MYPFNGLCOMBINERPARAMETERFVNV) wglGetProcAddress("glCombinerParameterfvNV"); + ctxInfo->glCombinerParameterivNV = + (MYPFNGLCOMBINERPARAMETERIVNV) wglGetProcAddress("glCombinerParameterivNV"); + ctxInfo->glCombinerParameterfNV = + (MYPFNGLCOMBINERPARAMETERFNV) wglGetProcAddress("glCombinerParameterfNV"); + ctxInfo->glCombinerParameteriNV = + (MYPFNGLCOMBINERPARAMETERINV) wglGetProcAddress("glCombinerParameteriNV"); + + /* + if (ctxInfo->glCombinerInputNV == NULL) { + printf("glCombinerInputNV == NULL\n"); + } + if (ctxInfo->glFinalCombinerInputNV == NULL) { + printf("glFinalCombinerInputNV == NULL\n"); + } + if (ctxInfo->glCombinerOutputNV == NULL) { + printf("ctxInfo->glCombinerOutputNV == NULL\n"); + } + if (ctxInfo->glCombinerParameterfvNV == NULL) { + printf("ctxInfo->glCombinerParameterfvNV == NULL\n"); + } + if (ctxInfo->glCombinerParameterivNV == NULL) { + printf("ctxInfo->glCombinerParameterivNV == NULL\n"); + } + if (ctxInfo->glCombinerParameterfNV == NULL) { + printf("ctxInfo->glCombinerParameterfNV == NULL\n"); + } + if (ctxInfo->glCombinerParameteriNV == NULL) { + printf("ctxInfo->glCombinerParameteriNV == NULL\n"); + } + */ + if ((ctxInfo->glCombinerInputNV == NULL) || + (ctxInfo->glFinalCombinerInputNV == NULL) || + (ctxInfo->glCombinerOutputNV == NULL) || + (ctxInfo->glCombinerParameterfvNV == NULL) || + (ctxInfo->glCombinerParameterivNV == NULL) || + (ctxInfo->glCombinerParameterfNV == NULL) || + (ctxInfo->glCombinerParameteriNV == NULL)) { + ctxInfo->textureExtMask &= ~javax_media_j3d_Canvas3D_TEXTURE_REGISTER_COMBINERS; + ctxInfo->textureRegisterCombinersAvailable = JNI_FALSE; + } + +#endif + + } + + if(isExtensionSupported(tmpExtensionStr,"GL_ARB_texture_env_dot3" )) { + ctxInfo->textureCombineDot3Available = JNI_TRUE; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE_DOT3; + ctxInfo->combine_dot3_rgb_enum = GL_DOT3_RGB_ARB; + ctxInfo->combine_dot3_rgba_enum = GL_DOT3_RGBA_ARB; + } else if(isExtensionSupported(tmpExtensionStr,"GL_EXT_texture_env_dot3" )) { + ctxInfo->textureCombineDot3Available = JNI_TRUE; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_COMBINE_DOT3; + ctxInfo->combine_dot3_rgb_enum = GL_DOT3_RGB_EXT; + ctxInfo->combine_dot3_rgba_enum = GL_DOT3_RGBA_EXT; + } + + if (ctxInfo->gl13) { + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_CUBE_MAP; + } + + if (isExtensionSupported(tmpExtensionStr, "GL_SGIS_sharpen_texture")) { + ctxInfo->textureSharpenAvailable = JNI_TRUE; + ctxInfo->linear_sharpen_enum = GL_LINEAR_SHARPEN_SGIS; + ctxInfo->linear_sharpen_rgb_enum = GL_LINEAR_SHARPEN_COLOR_SGIS; + ctxInfo->linear_sharpen_alpha_enum = GL_LINEAR_SHARPEN_ALPHA_SGIS; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_SHARPEN; +#if defined(UNIX) + ctxInfo->glSharpenTexFuncSGIS = + (MYPFNGLSHARPENTEXFUNCSGI) dlsym(RTLD_DEFAULT, "glSharpenTexFuncSGIS"); +#endif +#ifdef WIN32 + ctxInfo->glSharpenTexFuncSGIS = (MYPFNGLSHARPENTEXFUNCSGI) + wglGetProcAddress("glSharpenTexFuncSGIS"); + if (ctxInfo->glSharpenTexFuncSGIS == NULL) { + /* printf("ctxInfo->glSharpenTexFuncSGIS == NULL\n"); */ + ctxInfo->textureExtMask &= ~javax_media_j3d_Canvas3D_TEXTURE_SHARPEN; + ctxInfo->textureSharpenAvailable = JNI_FALSE; + } +#endif + } + + if (isExtensionSupported(tmpExtensionStr, "GL_SGIS_detail_texture")) { + ctxInfo->textureDetailAvailable = JNI_TRUE; + ctxInfo->texture_detail_ext_enum = GL_DETAIL_TEXTURE_2D_SGIS; + ctxInfo->linear_detail_enum = GL_LINEAR_DETAIL_SGIS; + ctxInfo->linear_detail_rgb_enum = GL_LINEAR_DETAIL_COLOR_SGIS; + ctxInfo->linear_detail_alpha_enum = GL_LINEAR_DETAIL_ALPHA_SGIS; + ctxInfo->texture_detail_mode_enum = GL_DETAIL_TEXTURE_MODE_SGIS; + ctxInfo->texture_detail_level_enum = GL_DETAIL_TEXTURE_LEVEL_SGIS; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_DETAIL; +#if defined(UNIX) + ctxInfo->glDetailTexFuncSGIS = + (MYPFNGLDETAILTEXFUNCSGI) dlsym(RTLD_DEFAULT, "glDetailTexFuncSGIS"); +#endif +#ifdef WIN32 + ctxInfo->glDetailTexFuncSGIS = (MYPFNGLDETAILTEXFUNCSGI) + wglGetProcAddress("glDetailTexFuncSGIS"); + if (ctxInfo->glDetailTexFuncSGIS == NULL) { + /* printf("ctxInfo->glDetailTexFuncSGIS == NULL\n"); */ + ctxInfo->textureExtMask &= ~javax_media_j3d_Canvas3D_TEXTURE_DETAIL; + ctxInfo->textureDetailAvailable = JNI_FALSE; + } +#endif + } + + if (isExtensionSupported(tmpExtensionStr, "GL_SGIS_texture_filter4")) { + ctxInfo->textureFilter4Available = JNI_TRUE; + ctxInfo->filter4_enum = GL_FILTER4_SGIS; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_FILTER4; +#if defined(UNIX) + ctxInfo->glTexFilterFuncSGIS = + (MYPFNGLTEXFILTERFUNCSGI) dlsym(RTLD_DEFAULT, "glTexFilterFuncSGIS"); +#endif +#ifdef WIN32 + ctxInfo->glTexFilterFuncSGIS = (MYPFNGLTEXFILTERFUNCSGI) + wglGetProcAddress("glTexFilterFuncSGIS"); + if (ctxInfo->glTexFilterFuncSGIS == NULL) { + /* printf("ctxInfo->glTexFilterFuncSGIS == NULL\n"); */ + ctxInfo->textureExtMask &= ~javax_media_j3d_Canvas3D_TEXTURE_FILTER4; + ctxInfo->textureFilter4Available = JNI_FALSE; + } +#endif + } + + if (isExtensionSupported(tmpExtensionStr, + "GL_EXT_texture_filter_anisotropic")) { + ctxInfo->textureAnisotropicFilterAvailable = JNI_TRUE; + ctxInfo->texture_filter_anisotropic_ext_enum = + GL_TEXTURE_MAX_ANISOTROPY_EXT; + ctxInfo->max_texture_filter_anisotropy_enum = + GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT; + ctxInfo->textureExtMask |= + javax_media_j3d_Canvas3D_TEXTURE_ANISOTROPIC_FILTER; + } + + if (ctxInfo->gl13) { + ctxInfo->texture_clamp_to_border_enum = GL_CLAMP_TO_BORDER; + } else { + ctxInfo->texture_clamp_to_border_enum = GL_CLAMP; + } + + if (isExtensionSupported(tmpExtensionStr, + "GL_SGIX_texture_lod_bias")) { + ctxInfo->textureLodBiasAvailable = JNI_TRUE; + ctxInfo->textureExtMask |= + javax_media_j3d_Canvas3D_TEXTURE_LOD_OFFSET; + } + + if (isExtensionSupported(tmpExtensionStr, "GL_ARB_texture_non_power_of_two") && + !getJavaBoolEnv(env, "enforcePowerOfTwo")) { + ctxInfo->textureExtMask |= + javax_media_j3d_Canvas3D_TEXTURE_NON_POWER_OF_TWO; + } + + if (isExtensionSupported(tmpExtensionStr, + "GL_SGIS_generate_mipmap")) { + ctxInfo->textureExtMask |= + javax_media_j3d_Canvas3D_TEXTURE_AUTO_MIPMAP_GENERATION; + } + + +} + +jboolean +getJavaBoolEnv(JNIEnv *env, char* envStr) +{ + JNIEnv table = *env; + jclass cls; + jfieldID fieldID; + jobject obj; + + cls = (jclass) (*(table->FindClass))(env, "javax/media/j3d/VirtualUniverse"); + + if (cls == NULL) { + return JNI_FALSE; + } + + fieldID = (jfieldID) (*(table->GetStaticFieldID))(env, cls, "mc", + "Ljavax/media/j3d/MasterControl;"); + if (fieldID == NULL) { + return JNI_FALSE; + } + + obj = (*(table->GetStaticObjectField))(env, cls, fieldID); + + if (obj == NULL) { + return JNI_FALSE; + } + + cls = (jclass) (*(table->FindClass))(env, "javax/media/j3d/MasterControl"); + + if (cls == NULL) { + return JNI_FALSE; + } + + fieldID = (jfieldID) (*(table->GetFieldID))(env, cls, envStr, "Z"); + + if (fieldID == NULL ) { + return JNI_FALSE; + } + + return (*(table->GetBooleanField))(env, obj, fieldID); +} + +jint +getJavaIntEnv(JNIEnv *env, char* envStr) +{ + JNIEnv table = *env; + jclass cls; + jfieldID fieldID; + jobject obj; + + cls = (jclass) (*(table->FindClass))(env, "javax/media/j3d/VirtualUniverse"); + + if (cls == NULL) { + return JNI_FALSE; + } + + fieldID = (jfieldID) (*(table->GetStaticFieldID))(env, cls, "mc", + "Ljavax/media/j3d/MasterControl;"); + if (fieldID == NULL) { + return JNI_FALSE; + } + + obj = (*(table->GetStaticObjectField))(env, cls, fieldID); + + if (obj == NULL) { + return JNI_FALSE; + } + + cls = (jclass) (*(table->FindClass))(env, "javax/media/j3d/MasterControl"); + + if (cls == NULL) { + return JNI_FALSE; + } + + fieldID = (jfieldID) (*(table->GetFieldID))(env, cls, envStr, "I"); + + if (fieldID == NULL ) { + return JNI_FALSE; + } + + return (*(table->GetIntField))(env, obj, fieldID); +} + +/* + * Dummy functions for language-independent vertex attribute functions + */ +static void +dummyVertexAttrPointer( + GraphicsContextPropertiesInfo *ctxProperties, + int index, int size, int type, int stride, + const void *pointer) +{ +#ifdef DEBUG + fprintf(stderr, "dummyVertexAttrPointer()\n"); +#endif /* DEBUG */ +} + +static void +dummyEnDisableVertexAttrArray( + GraphicsContextPropertiesInfo *ctxProperties, int index) +{ +#ifdef DEBUG + fprintf(stderr, "dummyEnDisableVertexAttrArray()\n"); +#endif /* DEBUG */ +} + +static void +dummyVertexAttr( + GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v) +{ +#ifdef DEBUG + fprintf(stderr, "dummyVertexAttr()\n"); +#endif /* DEBUG */ +} + +/* + * get properties from current context + */ +static jboolean +getPropertiesFromCurrentContext( + JNIEnv *env, + jobject obj, + GraphicsContextPropertiesInfo *ctxInfo, + jlong hdc, + int pixelFormat, + jlong fbConfigListPtr, + jboolean offScreen, + jboolean glslLibraryAvailable, + jboolean cgLibraryAvailable) +{ + JNIEnv table = *env; + + /* version and extension */ + char *glVersion; + char *glVendor; + char *glRenderer; + char *extensionStr; + char *tmpVersionStr; + char *tmpExtensionStr; + int versionNumbers[2]; + char *cgHwStr = 0; + +#ifdef WIN32 + PixelFormatInfo *PixelFormatInfoPtr = (PixelFormatInfo *)fbConfigListPtr; +#endif + + /* Get the list of extension */ + extensionStr = (char *)glGetString(GL_EXTENSIONS); + if (extensionStr == NULL) { + fprintf(stderr, "extensionStr == null\n"); + return JNI_FALSE; + } + tmpExtensionStr = strdup(extensionStr); + + /* Get the OpenGL version */ + glVersion = (char *)glGetString(GL_VERSION); + if (glVersion == NULL) { + fprintf(stderr, "glVersion == null\n"); + return JNI_FALSE; + } + tmpVersionStr = strdup(glVersion); + + /* Get the OpenGL vendor and renderer */ + glVendor = (char *)glGetString(GL_VENDOR); + if (glVendor == NULL) { + glVendor = ""; + } + glRenderer = (char *)glGetString(GL_RENDERER); + if (glRenderer == NULL) { + glRenderer = ""; + } + + /* + fprintf(stderr, " pixelFormat : %d\n", pixelFormat); + fprintf(stderr, " extensionStr : %s\n", tmpExtensionStr); + */ + + ctxInfo->versionStr = strdup(glVersion); + ctxInfo->vendorStr = strdup(glVendor); + ctxInfo->rendererStr = strdup(glRenderer); + ctxInfo->extensionStr = strdup(extensionStr); + + /* find out the version, major and minor version number */ + extractVersionInfo(tmpVersionStr, versionNumbers); + + + /* *********************************************************/ + /* setup the graphics context properties */ + + /* + * NOTE: Java 3D now requires OpenGL 1.3 for full functionality. + * For backwards compatibility with certain older graphics cards and + * drivers (e.g., the Linux DRI driver for older ATI cards), + * we will try to run on OpenGL 1.2 in an unsupported manner. However, + * we will not attempt to use OpenGL extensions for any features that + * are available in OpenGL 1.3, specifically multitexture, multisample, + * and cube map textures. + */ + if (versionNumbers[0] < 1 || + (versionNumbers[0] == 1 && versionNumbers[1] < 2)) { + jclass rte; + + fprintf(stderr, + "Java 3D ERROR : OpenGL 1.2 or better is required (GL_VERSION=%d.%d)\n", + versionNumbers[0], versionNumbers[1]); + if ((rte = (*(table->FindClass))(env, "javax/media/j3d/IllegalRenderingStateException")) != NULL) { + (*(table->ThrowNew))(env, rte, "GL_VERSION"); + } + return JNI_FALSE; + } + + if (versionNumbers[0] == 1) { + if (versionNumbers[1] == 2) { + fprintf(stderr, + "JAVA 3D: OpenGL 1.2 detected; will run with reduced functionality\n"); + } + if (versionNumbers[1] >= 3) { + ctxInfo->gl13 = JNI_TRUE; + } + if (versionNumbers[1] >= 4) { + ctxInfo->gl14 = JNI_TRUE; + } + } else /* major >= 2 */ { + ctxInfo->gl20 = JNI_TRUE; + ctxInfo->gl14 = JNI_TRUE; + ctxInfo->gl13 = JNI_TRUE; + } + + /* Setup function pointers for core OpenGL 1.3 features */ + + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_3D; +#if defined(UNIX) + ctxInfo->glTexImage3DEXT = (MYPFNGLTEXIMAGE3DPROC )dlsym(RTLD_DEFAULT, "glTexImage3D"); + ctxInfo->glTexSubImage3DEXT = (MYPFNGLTEXSUBIMAGE3DPROC )dlsym(RTLD_DEFAULT, "glTexSubImage3D"); +#endif +#ifdef WIN32 + ctxInfo->glTexImage3DEXT = (MYPFNGLTEXIMAGE3DPROC )wglGetProcAddress("glTexImage3D"); + ctxInfo->glTexSubImage3DEXT = (MYPFNGLTEXSUBIMAGE3DPROC )wglGetProcAddress("glTexSubImage3D"); +#endif + + if(isExtensionSupported(tmpExtensionStr, "GL_ARB_imaging")){ + ctxInfo->blend_color_ext = JNI_TRUE; + + ctxInfo->blendFunctionTable[BLEND_CONSTANT_COLOR] = GL_CONSTANT_COLOR; +#if defined(UNIX) + ctxInfo->glBlendColor = (MYPFNGLBLENDCOLORPROC )dlsym(RTLD_DEFAULT, "glBlendColor"); +#endif +#ifdef WIN32 + ctxInfo->glBlendColor = (MYPFNGLBLENDCOLORPROC )wglGetProcAddress("glBlendColor"); + if (ctxInfo->glBlendColor == NULL) { + ctxInfo->blend_color_ext = JNI_FALSE; + } +#endif + } + + ctxInfo->textureLodAvailable = JNI_TRUE; + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_LOD_RANGE; + ctxInfo->texture_min_lod_enum = GL_TEXTURE_MIN_LOD; + ctxInfo->texture_max_lod_enum = GL_TEXTURE_MAX_LOD; + ctxInfo->texture_base_level_enum = GL_TEXTURE_BASE_LEVEL; + ctxInfo->texture_max_level_enum = GL_TEXTURE_MAX_LEVEL; + + if (ctxInfo->gl14) { + ctxInfo->textureExtMask |= javax_media_j3d_Canvas3D_TEXTURE_AUTO_MIPMAP_GENERATION; + } + + /* look for OpenGL 2.0 features */ + /* + // Fix to Issue 455 : Need to disable NPOT textures for older cards that claim to support it. + // Some older cards (e.g., Nvidia fx500 and ATI 9800) claim to support OpenGL 2.0. + // This means that these cards have to support non-power-of-two (NPOT) texture, + // but their lack the necessary HW force the vendors the emulate this feature in software. + // The result is a ~100x slower down compare to power-of-two textures. + // Do not check for gl20 but instead check of GL_ARB_texture_non_power_of_two extension string + if (ctxInfo->gl20) { + if (!getJavaBoolEnv(env, "enforcePowerOfTwo")) { + ctxInfo->textureExtMask |= + javax_media_j3d_Canvas3D_TEXTURE_NON_POWER_OF_TWO; + } + } + */ + + /* check extensions for remaining of 1.1 and 1.2 */ + if(isExtensionSupported(tmpExtensionStr, "GL_EXT_multi_draw_arrays")){ + ctxInfo->multi_draw_arrays_ext = JNI_TRUE; + } + if(isExtensionSupported(tmpExtensionStr, "GL_SUN_multi_draw_arrays")){ + ctxInfo->multi_draw_arrays_sun = JNI_TRUE; + } + + if (isExtensionSupported(tmpExtensionStr, "GL_EXT_compiled_vertex_array") && + getJavaBoolEnv(env, "isCompiledVertexArray")) { + ctxInfo->compiled_vertex_array_ext = JNI_TRUE; + } + + if(isExtensionSupported(tmpExtensionStr, "GL_SUN_global_alpha")){ + ctxInfo->global_alpha_sun = JNI_TRUE; + } + + if(isExtensionSupported(tmpExtensionStr, "GL_EXT_abgr")) { + ctxInfo->abgr_ext = JNI_TRUE; + } + + /* + * Setup ctxInfo->multisample; under windows this is setup in + * NativeConfigTemplate when pixel format is choose + */ + +#if defined(UNIX) + ctxInfo->multisample = ctxInfo->gl13; +#endif + +#ifdef WIN32 + if(offScreen) { + ctxInfo->multisample = PixelFormatInfoPtr->offScreenHasMultisample; + } + else { + ctxInfo->multisample = PixelFormatInfoPtr->onScreenHasMultisample; + } + + /* + fprintf(stderr, "Canvas3D - onScreenHasMultisample = %d, offScreenHasMultisample = %d\n", + PixelFormatInfoPtr->onScreenHasMultisample, + PixelFormatInfoPtr->offScreenHasMultisample); + + fprintf(stderr, "Canvas3D - ctxInfo->multisample = %d, offScreen = %d\n", + ctxInfo->multisample, offScreen); + */ + +#endif + + /* + * Disable multisample by default since OpenGL will enable + * it by default if the surface is multisample capable. + */ + if (ctxInfo->multisample && !ctxInfo->implicit_multisample) { + glDisable(GL_MULTISAMPLE); + } + + /* Check texture extensions */ + checkTextureExtensions(env, obj, tmpExtensionStr, ctxInfo); + + /* Check shader extensions */ + if (ctxInfo->gl13) { + checkGLSLShaderExtensions(env, obj, tmpExtensionStr, ctxInfo, glslLibraryAvailable); + checkCgShaderExtensions(env, obj, tmpExtensionStr, ctxInfo, cgLibraryAvailable); + } else { + /* Force shaders to be disabled, since no multitexture support */ + char *emptyExtStr = " "; + checkGLSLShaderExtensions(env, obj, emptyExtStr, ctxInfo, JNI_FALSE); + checkCgShaderExtensions(env, obj, emptyExtStr, ctxInfo, JNI_FALSE); + } + + /* *********************************************************/ + + /* Setup GL_SUN_gloabl_alpha */ + if (ctxInfo->global_alpha_sun) { + ctxInfo->extMask |= javax_media_j3d_Canvas3D_SUN_GLOBAL_ALPHA; + } + + /* Setup GL_EXT_abgr */ + if (ctxInfo->abgr_ext) { + ctxInfo->extMask |= javax_media_j3d_Canvas3D_EXT_ABGR; + } + + /* GL_BGR is always supported */ + ctxInfo->extMask |= javax_media_j3d_Canvas3D_EXT_BGR; + + if(ctxInfo->multisample) { + ctxInfo->extMask |= javax_media_j3d_Canvas3D_MULTISAMPLE; + } + + /* setup those functions pointers */ +#ifdef WIN32 + + if (ctxInfo->multi_draw_arrays_ext) { + ctxInfo->glMultiDrawArraysEXT = (MYPFNGLMULTIDRAWARRAYSEXTPROC)wglGetProcAddress("glMultiDrawArraysEXT"); + ctxInfo->glMultiDrawElementsEXT = (MYPFNGLMULTIDRAWELEMENTSEXTPROC)wglGetProcAddress("glMultiDrawElementsEXT"); + if ((ctxInfo->glMultiDrawArraysEXT == NULL) || + (ctxInfo->glMultiDrawElementsEXT == NULL)) { + ctxInfo->multi_draw_arrays_ext = JNI_FALSE; + } + } + else if (ctxInfo->multi_draw_arrays_sun) { + ctxInfo->glMultiDrawArraysEXT = (MYPFNGLMULTIDRAWARRAYSEXTPROC)wglGetProcAddress("glMultiDrawArraysSUN"); + ctxInfo->glMultiDrawElementsEXT = (MYPFNGLMULTIDRAWELEMENTSEXTPROC)wglGetProcAddress("glMultiDrawElementsSUN"); + if ((ctxInfo->glMultiDrawArraysEXT == NULL) || + (ctxInfo->glMultiDrawElementsEXT == NULL)) { + ctxInfo->multi_draw_arrays_sun = JNI_FALSE; + } + + } + if (ctxInfo->compiled_vertex_array_ext) { + ctxInfo->glLockArraysEXT = (MYPFNGLLOCKARRAYSEXTPROC)wglGetProcAddress("glLockArraysEXT"); + ctxInfo->glUnlockArraysEXT = (MYPFNGLUNLOCKARRAYSEXTPROC)wglGetProcAddress("glUnlockArraysEXT"); + if ((ctxInfo->glLockArraysEXT == NULL) || + (ctxInfo->glUnlockArraysEXT == NULL)) { + ctxInfo->compiled_vertex_array_ext = JNI_FALSE; + } + } + + if (ctxInfo->gl13) { + ctxInfo->glClientActiveTexture = (MYPFNGLCLIENTACTIVETEXTUREPROC)wglGetProcAddress("glClientActiveTexture"); + ctxInfo->glActiveTexture = (MYPFNGLACTIVETEXTUREPROC) wglGetProcAddress("glActiveTexture"); + ctxInfo->glMultiTexCoord2fv = (MYPFNGLMULTITEXCOORD2FVPROC)wglGetProcAddress("glMultiTexCoord2fv"); + ctxInfo->glMultiTexCoord3fv = (MYPFNGLMULTITEXCOORD3FVPROC)wglGetProcAddress("glMultiTexCoord3fv"); + ctxInfo->glMultiTexCoord4fv = (MYPFNGLMULTITEXCOORD4FVPROC)wglGetProcAddress("glMultiTexCoord4fv"); + + ctxInfo->glLoadTransposeMatrixd = (MYPFNGLLOADTRANSPOSEMATRIXDPROC)wglGetProcAddress("glLoadTransposeMatrixd"); + ctxInfo->glMultTransposeMatrixd = (MYPFNGLMULTTRANSPOSEMATRIXDPROC)wglGetProcAddress("glMultTransposeMatrixd"); + } + + if (ctxInfo->global_alpha_sun) { + ctxInfo->glGlobalAlphaFactorfSUN = (MYPFNGLGLOBALALPHAFACTORFSUNPROC )wglGetProcAddress("glGlobalAlphaFactorfSUN"); + + if (ctxInfo->glGlobalAlphaFactorfSUN == NULL) { + /* printf("ctxInfo->glGlobalAlphaFactorfSUN == NULL\n");*/ + ctxInfo->global_alpha_sun = JNI_FALSE; + } + } + +#endif + +#if defined(UNIX) + if(ctxInfo->multi_draw_arrays_ext) { + ctxInfo->glMultiDrawArraysEXT = + (MYPFNGLMULTIDRAWARRAYSEXTPROC)dlsym(RTLD_DEFAULT, "glMultiDrawArraysEXT"); + ctxInfo->glMultiDrawElementsEXT = + (MYPFNGLMULTIDRAWELEMENTSEXTPROC)dlsym(RTLD_DEFAULT, "glMultiDrawElementsEXT"); + if ((ctxInfo->glMultiDrawArraysEXT == NULL) || + (ctxInfo->glMultiDrawElementsEXT == NULL)) { + ctxInfo->multi_draw_arrays_ext = JNI_FALSE; + } + } + else if (ctxInfo->multi_draw_arrays_sun) { + ctxInfo->glMultiDrawArraysEXT = + (MYPFNGLMULTIDRAWARRAYSEXTPROC)dlsym(RTLD_DEFAULT, "glMultiDrawArraysSUN"); + ctxInfo->glMultiDrawElementsEXT = + (MYPFNGLMULTIDRAWELEMENTSEXTPROC)dlsym(RTLD_DEFAULT, "glMultiDrawElementsSUN"); + if ((ctxInfo->glMultiDrawArraysEXT == NULL) || + (ctxInfo->glMultiDrawElementsEXT == NULL)) { + ctxInfo->multi_draw_arrays_ext = JNI_FALSE; + } + } + if(ctxInfo->compiled_vertex_array_ext) { + ctxInfo->glLockArraysEXT = + (MYPFNGLLOCKARRAYSEXTPROC)dlsym(RTLD_DEFAULT, "glLockArraysEXT"); + ctxInfo->glUnlockArraysEXT = + (MYPFNGLUNLOCKARRAYSEXTPROC)dlsym(RTLD_DEFAULT, "glUnlockArraysEXT"); + if ((ctxInfo->glLockArraysEXT == NULL) || + (ctxInfo->glUnlockArraysEXT == NULL)) { + ctxInfo->compiled_vertex_array_ext = JNI_FALSE; + } + } + + if(ctxInfo->gl13){ + ctxInfo->glClientActiveTexture = + (MYPFNGLCLIENTACTIVETEXTUREPROC)dlsym(RTLD_DEFAULT, "glClientActiveTexture"); + ctxInfo->glMultiTexCoord2fv = + (MYPFNGLMULTITEXCOORD2FVPROC)dlsym(RTLD_DEFAULT, "glMultiTexCoord2fv"); + ctxInfo->glMultiTexCoord3fv = + (MYPFNGLMULTITEXCOORD3FVPROC)dlsym(RTLD_DEFAULT, "glMultiTexCoord3fv"); + ctxInfo->glMultiTexCoord4fv = + (MYPFNGLMULTITEXCOORD4FVPROC)dlsym(RTLD_DEFAULT, "glMultiTexCoord4fv"); + ctxInfo->glActiveTexture = + (MYPFNGLACTIVETEXTUREPROC)dlsym(RTLD_DEFAULT, "glActiveTexture"); + + ctxInfo->glLoadTransposeMatrixd = + (MYPFNGLLOADTRANSPOSEMATRIXDPROC)dlsym(RTLD_DEFAULT, "glLoadTransposeMatrixd"); + ctxInfo->glMultTransposeMatrixd = + (MYPFNGLMULTTRANSPOSEMATRIXDPROC)dlsym(RTLD_DEFAULT, "glMultTransposeMatrixd"); + } + + if(ctxInfo->global_alpha_sun) { + ctxInfo->glGlobalAlphaFactorfSUN = + (MYPFNGLGLOBALALPHAFACTORFSUNPROC)dlsym(RTLD_DEFAULT, "glGlobalAlphaFactorfSUN"); + if (ctxInfo->glGlobalAlphaFactorfSUN == NULL) { + ctxInfo->global_alpha_sun = JNI_FALSE; + } + } + +#endif /* UNIX */ + + /* clearing up the memory */ + free(tmpExtensionStr); + free(tmpVersionStr); + return JNI_TRUE; +} + + +/* + * put properties to the java side + */ +void setupCanvasProperties( + JNIEnv *env, + jobject obj, + GraphicsContextPropertiesInfo *ctxInfo) +{ + jclass cv_class; + jfieldID rsc_field; + JNIEnv table = *env; + GLint param; + + cv_class = (jclass) (*(table->GetObjectClass))(env, obj); + + /* set the canvas.multiTexAccelerated flag */ + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "multiTexAccelerated", "Z"); + (*(table->SetBooleanField))(env, obj, rsc_field, ctxInfo->gl13); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "maxTextureUnits", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->maxTextureUnits); + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "maxTexCoordSets", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->maxTexCoordSets); + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "maxTextureImageUnits", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->maxTextureImageUnits); + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "maxVertexTextureImageUnits", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->maxVertexTextureImageUnits); + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "maxCombinedTextureImageUnits", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->maxCombinedTextureImageUnits); + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "maxVertexAttrs", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->maxVertexAttrs); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "extensionsSupported", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->extMask); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "textureExtendedFeatures", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->textureExtMask); + + /* get texture color table size */ + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "textureColorTableSize", "I"); + (*(table->SetIntField))(env, obj, rsc_field, ctxInfo->textureColorTableSize); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "nativeGraphicsVersion", "Ljava/lang/String;"); + (*(table->SetObjectField))(env, obj, rsc_field, (*env)->NewStringUTF(env, ctxInfo->versionStr)); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "nativeGraphicsVendor", "Ljava/lang/String;"); + (*(table->SetObjectField))(env, obj, rsc_field, (*env)->NewStringUTF(env, ctxInfo->vendorStr)); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "nativeGraphicsRenderer", "Ljava/lang/String;"); + (*(table->SetObjectField))(env, obj, rsc_field, (*env)->NewStringUTF(env, ctxInfo->rendererStr)); + + if (ctxInfo->textureAnisotropicFilterAvailable) { + + float degree; + + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, °ree); + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "anisotropicDegreeMax", "F"); + (*(table->SetFloatField))(env, obj, rsc_field, degree); + } + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "textureBoundaryWidthMax", "I"); + (*(table->SetIntField))(env, obj, rsc_field, 1); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, ¶m); + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "textureWidthMax", "I"); + (*(table->SetIntField))(env, obj, rsc_field, param); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "textureHeightMax", "I"); + (*(table->SetIntField))(env, obj, rsc_field, param); + + param = -1; + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, ¶m); + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "texture3DWidthMax", "I"); + (*(table->SetIntField))(env, obj, rsc_field, param); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "texture3DHeightMax", "I"); + (*(table->SetIntField))(env, obj, rsc_field, param); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "texture3DDepthMax", "I"); + (*(table->SetIntField))(env, obj, rsc_field, param); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "shadingLanguageGLSL", "Z"); + (*(table->SetBooleanField))(env, obj, rsc_field, ctxInfo->shadingLanguageGLSL); + + rsc_field = (jfieldID) (*(table->GetFieldID))(env, cv_class, "shadingLanguageCg", "Z"); + (*(table->SetBooleanField))(env, obj, rsc_field, ctxInfo->shadingLanguageCg); + +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_destroyContext( + JNIEnv *env, + jobject obj, + jlong display, + jlong window, + jlong ctxInfo) +{ + GraphicsContextPropertiesInfo* s = (GraphicsContextPropertiesInfo* )ctxInfo; + jlong context = s->context; + +#ifdef WIN32 + /* + * It is possible the window is removed by removeNotify() + * before the following is invoked : + * wglMakeCurrent((HDC)window, NULL); + * This will cause WinMe crash on swapBuffers() + */ + wglDeleteContext((HGLRC)context); +#endif /* WIN32 */ + +#if defined(UNIX) + /* + glXMakeCurrent((Display *)display, None, NULL); + */ + glXDestroyContext((Display *)display, (GLXContext)context); +#endif /* UNIX */ + /* cleanup CtxInfo and free its memory */ + cleanupCtxInfo(s); + + free(s); + + +} + +/* + * A dummy WndProc for dummy window + */ +#ifdef WIN32 +LONG WINAPI WndProc( HWND hWnd, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + + /* This function handles any messages that we didn't. */ + /* (Which is most messages) It belongs to the OS. */ + return (LONG) DefWindowProc( hWnd, msg, wParam, lParam ); +} +#endif /*end of WIN32 */ + + +JNIEXPORT +jlong JNICALL Java_javax_media_j3d_NativePipeline_createNewContext( + JNIEnv *env, + jobject obj, + jobject cv, + jlong display, + jlong window, + jlong fbConfigListPtr, + jlong sharedCtxInfo, + jboolean isSharedCtx, + jboolean offScreen, + jboolean glslLibraryAvailable, + jboolean cgLibraryAvailable) +{ + jlong gctx; + jlong sharedCtx; + int stencilSize=0; + + GraphicsContextPropertiesInfo *ctxInfo = NULL; + GraphicsContextPropertiesInfo *sharedCtxStructure; + int PixelFormatID=0; + +#if defined(UNIX) + + /* Fix for issue 20 */ + + GLXContext ctx; + jlong hdc; + + GLXFBConfig *fbConfigList = NULL; + + fbConfigList = (GLXFBConfig *)fbConfigListPtr; + + /* + fprintf(stderr, "Canvas3D_createNewContext: \n"); + fprintf(stderr, " fbConfigListPtr 0x%x\n", (int) fbConfigListPtr); + fprintf(stderr, " fbConfigList 0x%x, fbConfigList[0] 0x%x\n", + (int) fbConfigList, (int) fbConfigList[0]); + fprintf(stderr, " glslLibraryAvailable = %d\n", glslLibraryAvailable); + fprintf(stderr, " cgLibraryAvailable = %d\n", cgLibraryAvailable); + */ + + if(sharedCtxInfo == 0) + sharedCtx = 0; + else { + sharedCtxStructure = (GraphicsContextPropertiesInfo *)sharedCtxInfo; + sharedCtx = sharedCtxStructure->context; + } + + if (display == 0) { + fprintf(stderr, "Canvas3D_createNewContext: display is null\n"); + ctx = NULL; + } + else if((fbConfigList == NULL) || (fbConfigList[0] == NULL)) { + /* + * fbConfig must be a valid pointer to an GLXFBConfig struct returned + * by glXChooseFBConfig() for a physical screen. The visual id + * is not sufficient for handling OpenGL with Xinerama mode disabled: + * it doesn't distinguish between the physical screens making up the + * virtual screen when the X server is running in Xinerama mode. + */ + fprintf(stderr, "Canvas3D_createNewContext: FBConfig is null\n"); + ctx = NULL; + } + else { + ctx = glXCreateNewContext((Display *)display, fbConfigList[0], + GLX_RGBA_TYPE, (GLXContext)sharedCtx, True); + } + + if (ctx == NULL) { + fprintf(stderr, "Canvas3D_createNewContext: couldn't create context\n"); + return 0; + } + + /* There is a known interportability issue between Solaris and Linux(Nvidia) + on the new glxMakeContextCurrent() call. Bug Id 5109045. + if (!glXMakeContextCurrent((Display *)display, (GLXDrawable)window, + (GLXDrawable)window,(GLXContext)ctx)) { + */ + + if (!glXMakeCurrent((Display *)display, (GLXDrawable)window,(GLXContext)ctx)) { + + fprintf( stderr, "Canvas3D_createNewContext: couldn't make current\n"); + return 0; + } + + /* Shouldn't this be moved to NativeConfig. ? */ + glXGetFBConfigAttrib((Display *) display, fbConfigList[0], + GLX_STENCIL_SIZE, &stencilSize); + + + gctx = (jlong)ctx; +#endif /* UNIX */ + +#ifdef WIN32 + HGLRC hrc; /* HW Rendering Context */ + HDC hdc; /* HW Device Context */ + jboolean rescale = JNI_FALSE; + JNIEnv table = *env; + DWORD err; + LPTSTR errString; + jboolean result; + PixelFormatInfo *PixelFormatInfoPtr = (PixelFormatInfo *)fbConfigListPtr; + /* Fix for issue 76 */ + /* + fprintf(stderr, "Canvas3D_createNewContext: \n"); + fprintf(stderr, "window 0x%x\n", window); + */ + if(sharedCtxInfo == 0) + sharedCtx = 0; + else { + sharedCtxStructure = (GraphicsContextPropertiesInfo *)sharedCtxInfo; + sharedCtx = sharedCtxStructure->context; + } + + hdc = (HDC) window; + + /* Need to handle onScreen and offScreen differently */ + /* fbConfigListPtr has both an on-screen and off-screen pixel format */ + + if(!offScreen) { /* Fix to issue 104 */ + if ((PixelFormatInfoPtr == NULL) || (PixelFormatInfoPtr->onScreenPFormat <= 0)) { + printErrorMessage("Canvas3D_createNewContext: onScreen PixelFormat is invalid"); + return 0; + } + else { + PixelFormatID = PixelFormatInfoPtr->onScreenPFormat; + } + } + else { /* offScreen case */ + if ((PixelFormatInfoPtr == NULL) || (PixelFormatInfoPtr->offScreenPFormat <= 0)) { + printErrorMessage("Canvas3D_createNewContext: offScreen PixelFormat is invalid"); + return 0; + } + else { + PixelFormatID = PixelFormatInfoPtr->offScreenPFormat; + } + } + + if (!SetPixelFormat(hdc, PixelFormatID, NULL)) { + printErrorMessage("Canvas3D_createNewContext: Failed in SetPixelFormat"); + return 0; + } + + /* fprintf(stderr, "Before wglCreateContext\n"); */ + + hrc = wglCreateContext( hdc ); + + /* fprintf(stderr, "After wglCreateContext hrc = 0x%x\n", hrc); */ + + if (!hrc) { + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + + fprintf(stderr, "wglCreateContext Failed: %s\n", errString); + return 0; + } + + if (sharedCtx != 0) { + wglShareLists( (HGLRC) sharedCtx, hrc ); + } + + /* fprintf(stderr, "Before wglMakeCurrent\n"); */ + result = wglMakeCurrent(hdc, hrc); + /* fprintf(stderr, "After wglMakeCurrent result = %d\n", result); */ + + if (!result) { + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + fprintf(stderr, "wglMakeCurrent Failed: %s\n", errString); + return 0; + } + + gctx = (jlong)hrc; +#endif /* WIN32 */ + + /* allocate the structure */ + ctxInfo = (GraphicsContextPropertiesInfo *)malloc(sizeof(GraphicsContextPropertiesInfo)); + + /* initialize the structure */ + initializeCtxInfo(env, ctxInfo); + ctxInfo->context = gctx; + + if (!getPropertiesFromCurrentContext(env, cv, ctxInfo, (jlong) hdc, PixelFormatID, + fbConfigListPtr, offScreen, + glslLibraryAvailable, cgLibraryAvailable)) { + return 0; + } + + /* setup structure */ + + if(!isSharedCtx){ + /* Setup field in Java side */ + setupCanvasProperties(env, cv, ctxInfo); + } + + /* Enable rescale normal */ + glEnable(GL_RESCALE_NORMAL); + + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + glDepthFunc(GL_LEQUAL); + glEnable(GL_COLOR_MATERIAL); + glReadBuffer(GL_FRONT); + + /* Java 3D images are aligned to 1 byte */ + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + return ((jlong)ctxInfo); +} + + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_useCtx( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong display, + jlong window) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + int result; +#if defined(UNIX) + + result = glXMakeCurrent((Display *)display, (GLXDrawable)window, (GLXContext)ctx); + if (!result) { + fprintf(stderr, "Java 3D ERROR : In Canvas3D.useCtx() glXMakeCurrent fails\n"); + return JNI_FALSE; + } + +#endif + +#ifdef WIN32 + DWORD err; + LPTSTR errString; + + result = wglMakeCurrent((HDC) window, (HGLRC) ctx); + /* fprintf(stderr, "useCtx : wglMakeCurrent : window %d, ctx %d, result = %d\n", + window, (int) ctx, result); */ + + if (!result) { + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + fprintf(stderr, "wglMakeCurrent Failed: %s\n", errString); + return JNI_FALSE; + } + +#endif + return JNI_TRUE; +} + +JNIEXPORT +jint JNICALL Java_javax_media_j3d_NativePipeline_getNumCtxLights( + JNIEnv *env, + jobject obj, + jlong ctxInfo) +{ + GLint nlights; + + glGetIntegerv(GL_MAX_LIGHTS, &nlights); + return((jint)nlights); +} + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_initTexturemapping( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint texWidth, + jint texHeight, + jint objectId) +{ + GraphicsContextPropertiesInfo *ctxProperties = + (GraphicsContextPropertiesInfo *)ctxInfo; + GLint gltype; + GLint width; + + gltype = (ctxProperties->abgr_ext ? GL_ABGR_EXT : GL_RGBA); + + glBindTexture(GL_TEXTURE_2D, objectId); + + + glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, texWidth, + texHeight, 0, gltype, GL_UNSIGNED_BYTE, NULL); + + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, + GL_TEXTURE_WIDTH, &width); + + if (width <= 0) { + return JNI_FALSE; + } + + /* init texture size only without filling the pixels */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, + texHeight, 0, gltype, GL_UNSIGNED_BYTE, NULL); + + + return JNI_TRUE; +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_texturemapping( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint px, + jint py, + jint minX, + jint minY, + jint maxX, + jint maxY, + jint texWidth, + jint texHeight, + jint rasWidth, + jint format, + jint objectId, + jbyteArray imageYdown, + jint winWidth, + jint winHeight) +{ + JNIEnv table; + GLint gltype; + GLfloat texMinU,texMinV,texMaxU,texMaxV; + GLfloat mapMinX,mapMinY,mapMaxX,mapMaxY; + GLfloat halfWidth,halfHeight; + jbyte *byteData; + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + table = *env; + gltype = GL_RGBA; + + /* Temporarily disable fragment and most 3D operations */ + glPushAttrib(GL_ENABLE_BIT|GL_TEXTURE_BIT|GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT); + disableAttribFor2D(ctxProperties); + + /* Reset the polygon mode */ + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + /* glGetIntegerv(GL_TEXTURE_BINDING_2D,&binding); */ + glDepthMask(GL_FALSE); + glBindTexture(GL_TEXTURE_2D, objectId); + /* set up texture parameter */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + +#ifdef VERBOSE + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); +#endif + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_TEXTURE_2D); + + /* glGetIntegerv (GL_VIEWPORT, viewport); */ + + /* loaded identity modelview and projection matrix */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glOrtho(0.0, (double)winWidth, 0.0, (double)winHeight,0.0, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + byteData = (jbyte *)(*(table->GetPrimitiveArrayCritical))(env, + imageYdown, + NULL); + + if (ctxProperties->abgr_ext) { + gltype = GL_ABGR_EXT; + } else { + switch (format) { + case IMAGE_FORMAT_BYTE_RGBA: + gltype = GL_RGBA; + break; + case IMAGE_FORMAT_BYTE_RGB: + gltype = GL_RGB; + break; + } + } + glPixelStorei(GL_UNPACK_ROW_LENGTH, rasWidth); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, minX); + glPixelStorei(GL_UNPACK_SKIP_ROWS, minY); + glTexSubImage2D(GL_TEXTURE_2D, 0, minX, minY, + maxX - minX, maxY - minY, + gltype, GL_UNSIGNED_BYTE, + byteData); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + + + (*(table->ReleasePrimitiveArrayCritical))(env, imageYdown, byteData, 0); + + texMinU = (float) minX/ (float) texWidth; + texMinV = (float) minY/ (float) texHeight; + texMaxU = (float) maxX/ (float) texWidth; + texMaxV = (float) maxY/ (float) texHeight; + halfWidth = (GLfloat)winWidth/2.0f; + halfHeight = (GLfloat)winHeight/2.0f; + + mapMinX = (float) (((px + minX)- halfWidth)/halfWidth); + mapMinY = (float) ((halfHeight - (py + maxY))/halfHeight); + mapMaxX = (float) ((px + maxX - halfWidth)/halfWidth); + mapMaxY = (float) ((halfHeight - (py + minY))/halfHeight); + +#ifdef VERBOSE + printf("(texMinU,texMinV,texMaxU,texMaxV) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + texMinU,texMinV,texMaxU,texMaxV); + printf("(mapMinX,mapMinY,mapMaxX,mapMaxY) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + mapMinX,mapMinY,mapMaxX,mapMaxY); + +#endif + glBegin(GL_QUADS); + + glTexCoord2f(texMinU, texMaxV); glVertex2f(mapMinX,mapMinY); + glTexCoord2f(texMaxU, texMaxV); glVertex2f(mapMaxX,mapMinY); + glTexCoord2f(texMaxU, texMinV); glVertex2f(mapMaxX,mapMaxY); + glTexCoord2f(texMinU, texMinV); glVertex2f(mapMinX,mapMaxY); + glEnd(); + + /* Java 3D always clears the Z-buffer */ + glDepthMask(GL_TRUE); + glClear(GL_DEPTH_BUFFER_BIT); + glPopAttrib(); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_clear( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat r, + jfloat g, + jfloat b, + jboolean clearStencil) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + +#ifdef VERBOSE + fprintf(stderr, "Canvas3D.clear(%g, %g, %g, %s)\n", + r, g, b, (stencilClear ? "true" : "false")); +#endif + +#ifdef OBSOLETE_CLEAR_CODE + glClearColor((float)r, (float)g, (float)b, ctxProperties->alphaClearValue); + glClear(GL_COLOR_BUFFER_BIT); + + /* Java 3D always clears the Z-buffer */ + glPushAttrib(GL_DEPTH_BUFFER_BIT); + glDepthMask(GL_TRUE); + glClear(GL_DEPTH_BUFFER_BIT); + glPopAttrib(); + + /* Issue 239 - clear stencil if specified */ + if (clearStencil) { + glPushAttrib(GL_STENCIL_BUFFER_BIT); + glClearStencil(0); + glStencilMask(~0); + glClear(GL_STENCIL_BUFFER_BIT); + glPopAttrib(); + } + +#endif /* OBSOLETE_CLEAR_CODE */ + + /* Mask of which buffers to clear, this always includes color & depth */ + int clearMask = GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT; + + /* Issue 239 - clear stencil if specified */ + if (clearStencil) { + glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + glClearStencil(0); + glStencilMask(~0); + clearMask |= GL_STENCIL_BUFFER_BIT; + } else { + glPushAttrib(GL_DEPTH_BUFFER_BIT); + } + + glDepthMask(GL_TRUE); + glClearColor((float)r, (float)g, (float)b, ctxProperties->alphaClearValue); + glClear(clearMask); + glPopAttrib(); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_textureFillBackground(JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat texMinU, + jfloat texMaxU, + jfloat texMinV, + jfloat texMaxV, + jfloat mapMinX, + jfloat mapMaxX, + jfloat mapMinY, + jfloat mapMaxY, + jboolean useBilinearFilter ) +{ + JNIEnv table; + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + table = *env; + +#ifdef VERBOSE + fprintf(stderr, "Canvas3D.textureFillBackground()\n"); +#endif + /* Temporarily disable fragment and most 3D operations */ + glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_POLYGON_BIT); + + disableAttribFor2D(ctxProperties); + glDepthMask(GL_FALSE); + glEnable(GL_TEXTURE_2D); + + /* Setup filter mode if needed */ + if(useBilinearFilter) { + /* fprintf(stderr, "Background : use bilinear filter\n"); */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + /* For debugging only + else { + fprintf(stderr, "Background : Not use bilinear filter\n"); + } + */ + + /* reset the polygon mode */ + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + /* loaded identity modelview and projection matrix */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + +#ifdef VERBOSE + printf("(texMinU,texMinV,texMaxU,texMaxV) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + texMinU,texMinV,texMaxU,texMaxV); + printf("(mapMinX,mapMinY,mapMaxX,mapMaxY) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + mapMinX,mapMinY,mapMaxX,mapMaxY); +#endif + + glBegin(GL_QUADS); + glTexCoord2f((float) texMinU, (float) texMinV); + glVertex2f((float) mapMinX, (float) mapMinY); + glTexCoord2f((float) texMaxU, (float) texMinV); + glVertex2f((float) mapMaxX, (float) mapMinY); + glTexCoord2f((float) texMaxU, (float) texMaxV); + glVertex2f((float) mapMaxX, (float) mapMaxY); + glTexCoord2f((float) texMinU, (float) texMaxV); + glVertex2f((float) mapMinX, (float) mapMaxY); + glEnd(); + + /* Restore texture Matrix transform */ + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + /* Restore attributes */ + glPopAttrib(); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_textureFillRaster(JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat texMinU, + jfloat texMaxU, + jfloat texMinV, + jfloat texMaxV, + jfloat mapMinX, + jfloat mapMaxX, + jfloat mapMinY, + jfloat mapMaxY, + jfloat mapZ, + jfloat alpha, + jboolean useBilinearFilter ) +{ + JNIEnv table; + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + table = *env; + +#ifdef VERBOSE + fprintf(stderr, "Canvas3D.textureFillRaster()\n"); +#endif + /* Temporarily disable fragment and most 3D operations */ + glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_POLYGON_BIT | + GL_CURRENT_BIT); + + disableAttribForRaster(ctxProperties); + + /* Setup filter mode if needed */ + if(useBilinearFilter) { + /* fprintf(stderr, "Raster : use bilinear filter\n"); */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + /* For debugging only + else { + fprintf(stderr, "Raster : Not use bilinear filter\n"); + } + */ + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f(1.0f, 1.0f, 1.0f, (float) alpha); + + /* reset the polygon mode */ + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + /* loaded identity modelview and projection matrix */ + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0); + +#ifdef VERBOSE + printf("(texMinU,texMinV,texMaxU,texMaxV) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + texMinU,texMinV,texMaxU,texMaxV); + printf("(mapMinX,mapMinY,mapMaxX,mapMaxY) = (%3.2f,%3.2f,%3.2f,%3.2f)\n", + mapMinX,mapMinY,mapMaxX,mapMaxY); +#endif + + glBegin(GL_QUADS); + + glTexCoord2f((float) texMinU, (float) texMinV); + glVertex3f((float) mapMinX, (float) mapMinY, (float) mapZ); + glTexCoord2f((float) texMaxU, (float) texMinV); + glVertex3f((float) mapMaxX, (float) mapMinY, (float) mapZ); + glTexCoord2f((float) texMaxU, (float) texMaxV); + glVertex3f((float) mapMaxX, (float) mapMaxY, (float) mapZ); + glTexCoord2f((float) texMinU, (float) texMaxV); + glVertex3f((float) mapMinX, (float) mapMaxY, (float) mapZ); + + glEnd(); + + /* Restore matrices */ + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + /* Restore attributes */ + glPopAttrib(); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeRasterDepth(JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat posX, + jfloat posY, + jfloat posZ, + jint srcOffsetX, + jint srcOffsetY, + jint rasterWidth, + jint rasterHeight, + jint depthWidth, + jint depthHeight, + jint depthFormat, + jobject depthData) +{ + GLint drawBuf; + void *depthObjPtr; + + JNIEnv table; + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + table = *env; + +#ifdef VERBOSE + fprintf(stderr, "Canvas3D.executeRasterDepth()\n"); +#endif + glRasterPos3f(posX, posY, posZ); + + glGetIntegerv(GL_DRAW_BUFFER, &drawBuf); + /* disable draw buffer */ + glDrawBuffer(GL_NONE); + + /* + * raster position is upper left corner, default for Java3D + * ImageComponent currently has the data reverse in Y + */ + glPixelZoom(1.0, -1.0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, depthWidth); + if (srcOffsetX >= 0) { + glPixelStorei(GL_UNPACK_SKIP_PIXELS, srcOffsetX); + if (srcOffsetX + rasterWidth > depthWidth) { + rasterWidth = depthWidth - srcOffsetX; + } + } else { + rasterWidth += srcOffsetX; + if (rasterWidth > depthWidth) { + rasterWidth = depthWidth; + } + } + if (srcOffsetY >= 0) { + glPixelStorei(GL_UNPACK_SKIP_ROWS, srcOffsetY); + if (srcOffsetY + rasterHeight > depthHeight) { + rasterHeight = depthHeight - srcOffsetY; + } + } else { + rasterHeight += srcOffsetY; + if (rasterHeight > depthHeight) { + rasterHeight = depthHeight; + } + } + + depthObjPtr = + (void *)(*(table->GetPrimitiveArrayCritical))(env, (jarray)depthData, NULL); + + if (depthFormat == javax_media_j3d_DepthComponentRetained_DEPTH_COMPONENT_TYPE_INT) { + glDrawPixels(rasterWidth, rasterHeight, GL_DEPTH_COMPONENT, + GL_UNSIGNED_INT, depthObjPtr); + } else { /* javax_media_j3d_DepthComponentRetained_DEPTH_COMPONENT_TYPE_FLOAT */ + + glDrawPixels(rasterWidth, rasterHeight, GL_DEPTH_COMPONENT, + GL_FLOAT, depthObjPtr); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, depthData, depthObjPtr, 0); + + + /* re-enable draw buffer */ + glDrawBuffer(drawBuf); + + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setRenderMode( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint mode, + jboolean dbEnable) +{ + GLint drawBuf; + + if (dbEnable) { + drawBuf = GL_BACK; + switch (mode) { + case 0: /* FIELD_LEFT */ + drawBuf = GL_BACK_LEFT; + break; + case 1: /* FIELD_RIGHT */ + drawBuf = GL_BACK_RIGHT; + break; + case 2: /* FIELD_ALL */ + drawBuf = GL_BACK; + break; + } + } + else { + drawBuf = GL_FRONT; + switch (mode) { + case 0: /* FIELD_LEFT */ + drawBuf = GL_FRONT_LEFT; + break; + case 1: /* FIELD_RIGHT */ + drawBuf = GL_FRONT_RIGHT; + break; + case 2: /* FIELD_ALL */ + drawBuf = GL_FRONT; + break; + } + } + +#ifdef VERBOSE + switch (drawBuf) { + case GL_FRONT_LEFT: + fprintf(stderr, "glDrawBuffer(GL_FRONT_LEFT)\n"); + break; + case GL_FRONT_RIGHT: + fprintf(stderr, "glDrawBuffer(GL_FRONT_RIGHT)\n"); + break; + case GL_FRONT: + fprintf(stderr, "glDrawBuffer(GL_FRONT)\n"); + break; + case GL_BACK_LEFT: + fprintf(stderr, "glDrawBuffer(GL_BACK_LEFT)\n"); + break; + case GL_BACK_RIGHT: + fprintf(stderr, "glDrawBuffer(GL_BACK_RIGHT)\n"); + break; + case GL_BACK: + fprintf(stderr, "glDrawBuffer(GL_BACK)\n"); + break; + default: + fprintf(stderr, "Unknown glDrawBuffer!!!\n"); + break; + } +#endif + + glDrawBuffer(drawBuf); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_clearAccum( + JNIEnv *env, + jobject obj, + jlong ctxInfo) +{ + + glClear(GL_ACCUM_BUFFER_BIT); + +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_accum( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat value) +{ + + glReadBuffer(GL_BACK); + + glAccum(GL_ACCUM, (float)value); + + glReadBuffer(GL_FRONT); + +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_accumReturn( + JNIEnv *env, + jobject obj, + jlong ctxInfo) +{ + + glAccum(GL_RETURN, 1.0); + +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setDepthBufferWriteEnable( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jboolean mode) +{ + if (mode) + glDepthMask(GL_TRUE); + else + glDepthMask(GL_FALSE); + +} + + +JNIEXPORT +jint JNICALL Java_javax_media_j3d_NativePipeline_swapBuffers( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctxInfo, + jlong display, + jlong window) +{ + +#if defined(UNIX) + glXSwapBuffers((Display *)display, (Window)window); + +#endif + +#ifdef WIN32 + HDC hdc; + + hdc = (HDC) window; + + SwapBuffers(hdc); +#endif + /* + * It would be nice to do a glFinish here, but we can't do this + * in the ViewThread Java thread in MT-aware OGL libraries without + * switching from the ViewThread to the Renderer thread an extra time + * per frame. Instead, we do glFinish after every rendering but before + * swap in the Renderer thread. + */ + /* glFinish(); */ + return 0; +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_syncRender( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jboolean waitFlag) +{ + + if (waitFlag == JNI_TRUE) + glFinish(); + else + glFlush(); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_newDisplayList( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint id) +{ + if (id <= 0) { + fprintf(stderr, "JAVA 3D ERROR : glNewList(%d) -- IGNORED\n", id); + return; + } + + glNewList(id, GL_COMPILE); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_endDisplayList( + JNIEnv *env, + jobject obj, + jlong ctxInfo) +{ + + glEndList(); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setGlobalAlpha( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jfloat alpha) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + /* GL_GLOBAL_ALPHA_SUN */ + if(ctxProperties->global_alpha_sun){ + glEnable(GL_GLOBAL_ALPHA_SUN); + ctxProperties->glGlobalAlphaFactorfSUN(alpha); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_callDisplayList( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint id, + jboolean isNonUniformScale) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + static int numInvalidLists = 0; + + if (id <= 0) { + if (numInvalidLists < 3) { + fprintf(stderr, "JAVA 3D ERROR : glCallList(%d) -- IGNORED\n", id); + ++numInvalidLists; + } + else if (numInvalidLists == 3) { + fprintf(stderr, "JAVA 3D : further glCallList error messages discarded\n"); + ++numInvalidLists; + } + return; + } + + /* Set normalization if non-uniform scale */ + if (isNonUniformScale) { + glEnable(GL_NORMALIZE); + } + + glCallList(id); + + /* Turn normalization back off */ + if (isNonUniformScale) { + glDisable(GL_NORMALIZE); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_freeDisplayList( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint id) +{ + + if (id <= 0) { + fprintf(stderr, "JAVA 3D ERROR : glDeleteLists(%d,1) -- IGNORED\n", id); + return; + } + + glDeleteLists(id, 1); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_freeTexture( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint id) +{ + GLuint texObj; + + if(id > 0) { + texObj = id; + glDeleteTextures(1, &texObj); + } + else + fprintf(stderr, "try to delete tex with texid <= 0. \n"); + +} + + +/* + * Method: getTextureColorTableSize + */ +int getTextureColorTableSize( + JNIEnv *env, + jobject obj, + GraphicsContextPropertiesInfo *ctxInfo, + char *extensionStr) +{ + GraphicsContextPropertiesInfo* ctxProperties = ctxInfo; + int size; + + if (isExtensionSupported(extensionStr, "GL_ARB_imaging")) { + +#ifdef WIN32 + ctxProperties->glColorTable = (MYPFNGLCOLORTABLEPROC)wglGetProcAddress("glColorTable"); + ctxProperties->glGetColorTableParameteriv = + (MYPFNGLGETCOLORTABLEPARAMETERIVPROC)wglGetProcAddress("glGetColorTableParameteriv"); +#endif +#if defined(UNIX) + ctxProperties->glColorTable = + (MYPFNGLCOLORTABLEPROC)dlsym(RTLD_DEFAULT, "glColorTable"); + ctxProperties->glGetColorTableParameteriv = + (MYPFNGLGETCOLORTABLEPARAMETERIVPROC)dlsym(RTLD_DEFAULT, "glGetColorTableParameteriv"); +#endif + + } else if(isExtensionSupported(extensionStr, "GL_SGI_color_table")) { + +#ifdef WIN32 + ctxProperties->glColorTable = (MYPFNGLCOLORTABLEPROC)wglGetProcAddress("glColorTableSGI"); + ctxProperties->glGetColorTableParameteriv = + (MYPFNGLGETCOLORTABLEPARAMETERIVPROC)wglGetProcAddress("glGetColorTableParameterivSGI"); +#endif +#if defined(UNIX) + ctxProperties->glColorTable = + (MYPFNGLCOLORTABLEPROC)dlsym(RTLD_DEFAULT, "glColorTableSGI"); + ctxProperties->glGetColorTableParameteriv = + (MYPFNGLGETCOLORTABLEPARAMETERIVPROC)dlsym(RTLD_DEFAULT, "glGetColorTableParameterivSGI"); +#endif + + } else { + return 0; + } + + if ((ctxProperties->glColorTable == NULL) || + (ctxProperties->glGetColorTableParameteriv == NULL)) { + return 0; + } + + ctxProperties->glColorTable(GL_PROXY_TEXTURE_COLOR_TABLE_SGI, GL_RGBA, 256, GL_RGB, + GL_INT, NULL); + ctxProperties->glGetColorTableParameteriv(GL_PROXY_TEXTURE_COLOR_TABLE_SGI, + GL_COLOR_TABLE_WIDTH_SGI, &size); + return size; +} + +JNIEXPORT +jlong JNICALL Java_javax_media_j3d_NativePipeline_createOffScreenBuffer( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctxInfo, + jlong display, + jlong fbConfigListPtr, + jint width, + jint height) +{ + +#if defined(UNIX) + + /* Fix for issue 20 */ + + const char *extStr; + int attrCount, configAttr[10]; + GLXPbuffer pbuff = None; + GLXFBConfig *fbConfigList = (GLXFBConfig *)fbConfigListPtr; + int val; + + /* + glXGetFBConfigAttrib((Display *) display, fbConfigList[0], + GLX_FBCONFIG_ID, &val); + fprintf(stderr, "GLX_FBCONFIG_ID returns %d\n", val); + + fprintf(stderr, "display 0x%x, fbConfigList[0] 0x%x, width %d, height %d\n", + (int) display, (int) fbConfigList[0], width, height); + + */ + + + /* Query DRAWABLE_TYPE. Will use Pbuffer if fbConfig support it, + else will try for Pixmap. If neither one exists, flag error message + and return None */ + + glXGetFBConfigAttrib((Display *) display, fbConfigList[0], + GLX_DRAWABLE_TYPE, &val); + /* fprintf(stderr, "GLX_DRAWABLE_TYPE returns %d\n", val); */ + + if (getJavaBoolEnv(env,"usePbuffer") && (val & GLX_PBUFFER_BIT) != 0) { + /* fprintf(stderr, "Using pbuffer %d\n", val); */ + + /* Initialize the attribute list to be used for choosing FBConfig */ + + attrCount = 0; + configAttr[attrCount++] = GLX_PBUFFER_WIDTH; + configAttr[attrCount++] = width; + configAttr[attrCount++] = GLX_PBUFFER_HEIGHT; + configAttr[attrCount++] = height; + configAttr[attrCount++] = GLX_PRESERVED_CONTENTS; + configAttr[attrCount++] = GL_TRUE; + configAttr[attrCount++] = None; + + + pbuff = glXCreatePbuffer((Display *) display, fbConfigList[0], configAttr); + + if (pbuff == None) { + fprintf(stderr, "Java 3D ERROR : glXCreateGLXPbuffer() returns None\n"); + } + + return (jlong)pbuff; + } + else if((val & GLX_PIXMAP_BIT) != 0) { + Pixmap pixmap; + GLXPixmap glxpixmap = None; + XVisualInfo *vinfo; + Window root; + Window glWin; + XSetWindowAttributes win_attrs; + Colormap cmap; + unsigned long win_mask; + + /* fprintf(stderr, "Using pixmap %d\n", val); */ + + vinfo = glXGetVisualFromFBConfig((Display*)display, fbConfigList[0]); + if (vinfo == NULL) { + fprintf(stderr, "Java 3D ERROR : glXGetVisualFromFBConfig failed\n"); + } + else { + /* fprintf(stderr, "found a %d-bit visual (visual ID = 0x%x)\n", + vinfo->depth, vinfo->visualid); */ + + /* fall back to pixmap */ + root = RootWindow((Display *)display, vinfo->screen); + + /* Create a colormap */ + cmap = XCreateColormap((Display *)display, root, vinfo->visual, AllocNone); + + /* Create a window */ + win_attrs.colormap = cmap; + win_attrs.border_pixel = 0; + win_mask = CWColormap | CWBorderPixel; + glWin = XCreateWindow((Display *)display, root, 0, 0, 1, 1, 0, + vinfo->depth, InputOutput, vinfo->visual, + win_mask, &win_attrs); + + /* fprintf(stderr, "glWin %d\n",(int) glWin); */ + + pixmap = XCreatePixmap((Display*)display, (GLXDrawable)glWin, + width, height, vinfo->depth); + + /* fprintf(stderr, "XCreatePixmap returns %d\n", (int) pixmap); */ + + glxpixmap = glXCreatePixmap((Display*)display, fbConfigList[0], pixmap, NULL); + if (glxpixmap == None) { + fprintf(stderr, "Java 3D ERROR : glXCreateGLXPixmap() returns None\n"); + } + } + + /* fprintf(stderr, "glxpixmap %d\n",(int) glxpixmap); */ + return (jlong)glxpixmap; + } + else { + fprintf(stderr, "Java 3D ERROR : FBConfig doesn't support pbuffer or pixmap returns None\n"); + return (jlong)None; + } + + +#endif /* UNIX */ + +#ifdef WIN32 + /* Fix for issue 76 */ + int dpy = (int)display; + static char szAppName[] = "CreateOffScreen"; + HWND hwnd; + HGLRC hrc; + HDC hdc; + int pixelFormat; + PixelFormatInfo *pFormatInfoPtr = (PixelFormatInfo *)fbConfigListPtr; + int piAttrs[2]; + + HPBUFFERARB hpbuf = NULL; /* Handle to the Pbuffer */ + HDC hpbufdc = NULL; /* Handle to the Pbuffer's device context */ + + HDC bitmapHdc; + HBITMAP hbitmap; + + BITMAPINFOHEADER bih; + void *ppvBits; + int err; + LPTSTR errString; + OffScreenBufferInfo *offScreenBufferInfo = NULL; + + PIXELFORMATDESCRIPTOR dummy_pfd = getDummyPFD(); + jclass cv_class; + jfieldID offScreenBuffer_field; + JNIEnv table = *env; + + /* + fprintf(stderr, "****** CreateOffScreenBuffer ******\n"); + fprintf(stderr, "display 0x%x, pFormat %d, width %d, height %d\n", + (int) display, pFormatInfoPtr->offScreenPFormat, width, height); + */ + + cv_class = (jclass) (*(table->GetObjectClass))(env, cv); + offScreenBuffer_field = + (jfieldID) (*(table->GetFieldID))(env, cv_class, "offScreenBufferInfo", "J"); + + /* + * Select any pixel format and bound current context to + * it so that we can get the wglChoosePixelFormatARB entry point. + * Otherwise wglxxx entry point will always return null. + * That's why we need to create a dummy window also. + */ + hwnd = createDummyWindow((const char *)szAppName); + + if (!hwnd) { + return 0; + } + hdc = GetDC(hwnd); + + pixelFormat = ChoosePixelFormat(hdc, &dummy_pfd); + + if (pixelFormat<1) { + printErrorMessage("In Canvas3D : Failed in ChoosePixelFormat"); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return 0; + } + + SetPixelFormat(hdc, pixelFormat, NULL); + + hrc = wglCreateContext(hdc); + if (!hrc) { + printErrorMessage("In Canvas3D : Failed in wglCreateContext"); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return 0; + } + + if (!wglMakeCurrent(hdc, hrc)) { + printErrorMessage("In Canvas3D : Failed in wglMakeCurrent"); + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return 0; + } + + if (pFormatInfoPtr->drawToPbuffer) { + + /* fprintf(stderr, "***** Use PBuffer for offscreen ******\n"); */ + + piAttrs[0] = 0; + piAttrs[1] = 0; + + hpbuf = pFormatInfoPtr->wglCreatePbufferARB( hdc, pFormatInfoPtr->offScreenPFormat, + width, height, piAttrs); + if(hpbuf == NULL) { + printErrorMessage("In Canvas3D : wglCreatePbufferARB FAIL."); + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return 0; + } + + hpbufdc = pFormatInfoPtr->wglGetPbufferDCARB(hpbuf); + + if(hpbufdc == NULL) { + printErrorMessage("In Canvas3D : Can't get pbuffer's device context."); + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return 0; + } + + /* + fprintf(stderr, + "Successfully created PBuffer = 0x%x, hdc = 0x%x\n", + (int)hpbuf, (int)hpbufdc); + */ + + /* Destroy all dummy objects */ + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + + offScreenBufferInfo = + (OffScreenBufferInfo *) malloc(sizeof(OffScreenBufferInfo)); + offScreenBufferInfo->isPbuffer = GL_TRUE; + offScreenBufferInfo->hpbuf = hpbuf; + + (*(table->SetLongField))(env, cv, offScreenBuffer_field, (jlong)offScreenBufferInfo); + + return (jlong) hpbufdc; + } + + /* fprintf(stderr, "***** Use Bitmap for offscreen ******\n"); */ + + /* create a DIB */ + memset(&bih, 0, sizeof(BITMAPINFOHEADER)); + + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biWidth = width; + bih.biHeight = height; + bih.biPlanes = 1; + + + /* by MIK OF CLASSX */ + if (getJavaBoolEnv(env, "transparentOffScreen")) { + bih.biBitCount = 32; + } + else { + bih.biBitCount = 24; + } + + bih.biCompression = BI_RGB; + + bitmapHdc = CreateCompatibleDC(hdc); + + hbitmap = CreateDIBSection(bitmapHdc, (BITMAPINFO *)&bih, + DIB_PAL_COLORS, &ppvBits, NULL, 0); + + + if (!hbitmap) { + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + fprintf(stderr, "CreateDIBSection failed: %s\n", errString); + } + + SelectObject(bitmapHdc, hbitmap); + + /* Choosing and setting of pixel format is done in createContext */ + + /* Destroy all dummy objects and fall BitMap */ + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + + offScreenBufferInfo = + (OffScreenBufferInfo *) malloc(sizeof(OffScreenBufferInfo)); + offScreenBufferInfo->isPbuffer = GL_FALSE; + offScreenBufferInfo->hpbuf = 0; + + (*(table->SetLongField))(env, cv, offScreenBuffer_field, (jlong)offScreenBufferInfo); + + return ((jlong)bitmapHdc); + +#endif /* WIN32 */ +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_destroyOffScreenBuffer( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctxInfo, + jlong display, + jlong fbConfigListPtr, + jlong window) +{ + jclass cv_class; + jfieldID offScreenBuffer_field; + JNIEnv table = *env; + +#if defined(UNIX) + /* Fix for Issue 20 */ + GLXFBConfig *fbConfigList = (GLXFBConfig *)fbConfigListPtr; + int val; + + glXGetFBConfigAttrib((Display *) display, (GLXFBConfig) fbConfigList[0], + GLX_DRAWABLE_TYPE, &val); + /* fprintf(stderr, "GLX_DRAWABLE_TYPE returns %d\n", val); */ + + if((val & GLX_PBUFFER_BIT) != 0) { + glXDestroyPbuffer((Display *) display, (GLXPbuffer)window); + } + else if((val & GLX_PIXMAP_BIT) != 0) { + glXDestroyPixmap((Display *) display, (GLXPixmap)window); + } + +#endif /* UNIX */ + +#ifdef WIN32 + /* Fix for issue 76 */ + PixelFormatInfo *pFormatInfoPtr = (PixelFormatInfo *)fbConfigListPtr; + OffScreenBufferInfo *offScreenBufferInfo = NULL; + HDC hpbufdc = (HDC) window; + + cv_class = (jclass) (*(table->GetObjectClass))(env, cv); + offScreenBuffer_field = + (jfieldID) (*(table->GetFieldID))(env, cv_class, "offScreenBufferInfo", "J"); + + offScreenBufferInfo = + (OffScreenBufferInfo *) (*(table->GetLongField))(env, cv, offScreenBuffer_field); + + /* + fprintf(stderr,"Canvas3D_destroyOffScreenBuffer : offScreenBufferInfo 0x%x\n", + offScreenBufferInfo); + */ + + if(offScreenBufferInfo == NULL) { + return; + } + + if(offScreenBufferInfo->isPbuffer) { + /* + fprintf(stderr,"Canvas3D_destroyOffScreenBuffer : Pbuffer\n"); + */ + + pFormatInfoPtr->wglReleasePbufferDCARB(offScreenBufferInfo->hpbuf, hpbufdc); + pFormatInfoPtr->wglDestroyPbufferARB(offScreenBufferInfo->hpbuf); + } + else { + HBITMAP oldhbitmap; + HDC hdc = (HDC) window; + + /* fprintf(stderr,"Canvas3D_destroyOffScreenBuffer : BitMap\n"); */ + oldhbitmap = SelectObject(hdc, NULL); + DeleteObject(oldhbitmap); + DeleteDC(hdc); + } + + free(offScreenBufferInfo); + (*(table->SetLongField))(env, cv, offScreenBuffer_field, (jlong)0); + +#endif /* WIN32 */ +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_readOffScreenBuffer( + JNIEnv *env, + jobject obj, + jobject cv, + jlong ctxInfo, + jint format, + jint dataType, + jobject data, + jint width, + jint height) +{ + JNIEnv table = *env; + int type; + void *imageObjPtr; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + glPixelStorei(GL_PACK_ROW_LENGTH, width); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + imageObjPtr = (void *)(*(table->GetPrimitiveArrayCritical))(env, (jarray)data, NULL); + } + else { + imageObjPtr = (void *)(*(table->GetDirectBufferAddress))(env, data); + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_BYTE_BUFFER)) { + switch (format) { + /* GL_BGR */ + case IMAGE_FORMAT_BYTE_BGR: + type = GL_BGR; + break; + case IMAGE_FORMAT_BYTE_RGB: + type = GL_RGB; + break; + /* GL_ABGR_EXT */ + case IMAGE_FORMAT_BYTE_ABGR: + if (ctxProperties->abgr_ext) { /* If its zero, should never come here! */ + type = GL_ABGR_EXT; + } + else { + throwAssert(env, "GL_ABGR_EXT format is unsupported"); + return; + } + break; + case IMAGE_FORMAT_BYTE_RGBA: + type = GL_RGBA; + break; + + /* This method only supports 3 and 4 components formats and BYTE types. */ + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + default: + throwAssert(env, "illegal format"); + return; + } + + glReadPixels(0, 0, width, height, type, GL_UNSIGNED_BYTE, imageObjPtr); + + } + else if((dataType == IMAGE_DATA_TYPE_INT_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_BUFFER)) { + GLenum intType = GL_UNSIGNED_INT_8_8_8_8; + GLboolean forceAlphaToOne = GL_FALSE; + + switch (format) { + /* GL_BGR */ + case IMAGE_FORMAT_INT_BGR: /* Assume XBGR format */ + type = GL_RGBA; + intType = GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = GL_TRUE; + break; + case IMAGE_FORMAT_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = GL_TRUE; + /* Fall through to next case */ + case IMAGE_FORMAT_INT_ARGB: + type = GL_BGRA; + intType = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_ABGR: + default: + throwAssert(env, "illegal format"); + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 0.0f); + glPixelTransferf(GL_ALPHA_BIAS, 1.0f); + } + + glReadPixels(0, 0, width, height, type, intType, imageObjPtr); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + glPixelTransferf(GL_ALPHA_BIAS, 0.0f); + } + } + else { + throwAssert(env, "illegal image data type"); + } + + if((dataType == IMAGE_DATA_TYPE_BYTE_ARRAY) || (dataType == IMAGE_DATA_TYPE_INT_ARRAY)) { + (*(table->ReleasePrimitiveArrayCritical))(env, data, imageObjPtr, 0); + } + +} + +static void +initializeCtxInfo(JNIEnv *env , GraphicsContextPropertiesInfo* ctxInfo) +{ + ctxInfo->context = 0; + + /* version and extension info */ + ctxInfo->versionStr = NULL; + ctxInfo->vendorStr = NULL; + ctxInfo->rendererStr = NULL; + ctxInfo->extensionStr = NULL; + ctxInfo->versionNumbers[0] = 1; + ctxInfo->versionNumbers[1] = 1; + ctxInfo->gl13 = JNI_FALSE; + ctxInfo->gl14 = JNI_FALSE; + ctxInfo->gl20 = JNI_FALSE; + + /* 1.2 and GL_ARB_imaging */ + ctxInfo->blend_color_ext = JNI_FALSE; + ctxInfo->blendFunctionTable[BLEND_ZERO] = GL_ZERO; + ctxInfo->blendFunctionTable[BLEND_ONE] = GL_ONE; + ctxInfo->blendFunctionTable[BLEND_SRC_ALPHA] = GL_SRC_ALPHA; + ctxInfo->blendFunctionTable[BLEND_ONE_MINUS_SRC_ALPHA] = GL_ONE_MINUS_SRC_ALPHA; + ctxInfo->blendFunctionTable[BLEND_DST_COLOR] = GL_DST_COLOR; + ctxInfo->blendFunctionTable[BLEND_ONE_MINUS_DST_COLOR] = GL_ONE_MINUS_DST_COLOR; + ctxInfo->blendFunctionTable[BLEND_SRC_COLOR] = GL_SRC_COLOR; + ctxInfo->blendFunctionTable[BLEND_ONE_MINUS_SRC_COLOR] = GL_ONE_MINUS_SRC_COLOR; + ctxInfo->blendFunctionTable[BLEND_CONSTANT_COLOR] = GL_CONSTANT_COLOR; + + /* 1.1 extensions or 1.2 extensions */ + /* sun extensions */ + ctxInfo->multi_draw_arrays_sun = JNI_FALSE; + ctxInfo->compiled_vertex_array_ext = JNI_FALSE; + + ctxInfo->texture_clamp_to_border_enum = GL_CLAMP; + + ctxInfo->global_alpha_sun = JNI_FALSE; + + /* EXT extensions */ + ctxInfo->abgr_ext = JNI_FALSE; + + ctxInfo->multi_draw_arrays_ext = JNI_FALSE; + + ctxInfo->implicit_multisample = getJavaBoolEnv(env, "implicitAntialiasing"); + + /* by MIK OF CLASSX */ + ctxInfo->alphaClearValue = (getJavaBoolEnv(env, "transparentOffScreen") ? 0.0f : 1.0f); + + ctxInfo->multisample = JNI_FALSE; + + /* Multitexture support */ + ctxInfo->maxTexCoordSets = 1; + ctxInfo->maxTextureUnits = 1; + ctxInfo->maxTextureImageUnits = 0; + ctxInfo->maxVertexTextureImageUnits = 0; + ctxInfo->maxCombinedTextureImageUnits = 0; + + ctxInfo->textureEnvCombineAvailable = JNI_FALSE; + ctxInfo->textureCombineDot3Available = JNI_FALSE; + ctxInfo->textureCombineSubtractAvailable = JNI_FALSE; + + /* NV extensions */ + ctxInfo->textureRegisterCombinersAvailable = JNI_FALSE; + + /* SGI extensions */ + ctxInfo->textureSharpenAvailable = JNI_FALSE; + ctxInfo->textureDetailAvailable = JNI_FALSE; + ctxInfo->textureFilter4Available = JNI_FALSE; + ctxInfo->textureAnisotropicFilterAvailable = JNI_FALSE; + ctxInfo->textureColorTableAvailable = JNI_FALSE; + ctxInfo->textureColorTableSize = 0; + ctxInfo->textureLodAvailable = JNI_FALSE; + ctxInfo->textureLodBiasAvailable = JNI_FALSE; + + /* extension mask */ + ctxInfo->extMask = 0; + ctxInfo->textureExtMask = 0; + + ctxInfo->shadingLanguageGLSL = JNI_FALSE; + ctxInfo->shadingLanguageCg = JNI_FALSE; + + ctxInfo->glBlendColor = NULL; + ctxInfo->glBlendColorEXT = NULL; + ctxInfo->glColorTable = NULL; + ctxInfo->glGetColorTableParameteriv = NULL; + ctxInfo->glTexImage3DEXT = NULL; + ctxInfo->glTexSubImage3DEXT = NULL; + ctxInfo->glClientActiveTexture = NULL; + ctxInfo->glMultiDrawArraysEXT = NULL; + ctxInfo->glMultiDrawElementsEXT = NULL; + ctxInfo->glLockArraysEXT = NULL; + ctxInfo->glUnlockArraysEXT = NULL; + ctxInfo->glMultiTexCoord2fv = NULL; + ctxInfo->glMultiTexCoord3fv = NULL; + ctxInfo->glMultiTexCoord4fv = NULL; + ctxInfo->glLoadTransposeMatrixd = NULL; + ctxInfo->glMultTransposeMatrixd = NULL; + ctxInfo->glActiveTexture = NULL; + ctxInfo->glGlobalAlphaFactorfSUN = NULL; + + ctxInfo->glCombinerInputNV = NULL; + ctxInfo->glCombinerOutputNV = NULL; + ctxInfo->glFinalCombinerInputNV = NULL; + ctxInfo->glCombinerParameterfvNV = NULL; + ctxInfo->glCombinerParameterivNV= NULL; + ctxInfo->glCombinerParameterfNV = NULL; + ctxInfo->glCombinerParameteriNV = NULL; + + ctxInfo->glSharpenTexFuncSGIS = NULL; + ctxInfo->glDetailTexFuncSGIS = NULL; + ctxInfo->glTexFilterFuncSGIS = NULL; + + /* Initialize shader program Id */ + ctxInfo->shaderProgramId = 0; + + /* Initialize maximum number of vertex attrs */ + ctxInfo->maxVertexAttrs = 0; + + /* Initialize shader vertex attribute function pointers */ + ctxInfo->vertexAttrPointer = dummyVertexAttrPointer; + ctxInfo->enableVertexAttrArray = dummyEnDisableVertexAttrArray; + ctxInfo->disableVertexAttrArray = dummyEnDisableVertexAttrArray; + ctxInfo->vertexAttr1fv = dummyVertexAttr; + ctxInfo->vertexAttr2fv = dummyVertexAttr; + ctxInfo->vertexAttr3fv = dummyVertexAttr; + ctxInfo->vertexAttr4fv = dummyVertexAttr; + + /* Initialize shader info pointers */ + ctxInfo->glslCtxInfo = NULL; + ctxInfo->cgCtxInfo = NULL; +} + +static void +cleanupCtxInfo(GraphicsContextPropertiesInfo* ctxInfo) +{ + if( ctxInfo->versionStr != NULL) + free(ctxInfo->versionStr); + if( ctxInfo->vendorStr != NULL) + free(ctxInfo->vendorStr); + if( ctxInfo->rendererStr != NULL) + free(ctxInfo->rendererStr); + if( ctxInfo->extensionStr != NULL) + free(ctxInfo->extensionStr); + ctxInfo->versionStr = NULL; + ctxInfo->vendorStr = NULL; + ctxInfo->rendererStr = NULL; + ctxInfo->extensionStr = NULL; +} + +#ifdef WIN32 +HWND createDummyWindow(const char* szAppName) { + static const char *szTitle = "Dummy Window"; + WNDCLASS wc; /* windows class sruct */ + + HWND hWnd; + + /* Fill in window class structure with parameters that */ + /* describe the main window. */ + + wc.style = + CS_HREDRAW | CS_VREDRAW;/* Class style(s). */ + wc.lpfnWndProc = + (WNDPROC)WndProc; /* Window Procedure */ + wc.cbClsExtra = 0; /* No per-class extra data. */ + wc.cbWndExtra = 0; /* No per-window extra data. */ + wc.hInstance = + NULL; /* Owner of this class */ + wc.hIcon = NULL; /* Icon name */ + wc.hCursor = + NULL;/* Cursor */ + wc.hbrBackground = + (HBRUSH)(COLOR_WINDOW+1);/* Default color */ + wc.lpszMenuName = NULL; /* Menu from .RC */ + wc.lpszClassName = + szAppName; /* Name to register as + + /* Register the window class */ + + if(RegisterClass( &wc )==0) { + printErrorMessage("createDummyWindow: couldn't register class"); + return NULL; + } + + /* Create a main window for this application instance. */ + + hWnd = CreateWindow( + szAppName, /* app name */ + szTitle, /* Text for window title bar */ + WS_OVERLAPPEDWINDOW/* Window style */ + /* NEED THESE for OpenGL calls to work!*/ + | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + NULL, /* no parent window */ + NULL, /* Use the window class menu.*/ + NULL, /* This instance owns this window */ + NULL /* We don't use any extra data */ + ); + + /* If window could not be created, return zero */ + if ( !hWnd ){ + printErrorMessage("createDummyWindow: couldn't create window"); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return NULL; + } + return hWnd; +} +#endif + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_createQueryContext( + JNIEnv *env, + jobject obj, + jobject cv, + jlong display, + jlong window, + jlong fbConfigListPtr, + jboolean offScreen, + jint width, + jint height, + jboolean glslLibraryAvailable, + jboolean cgLibraryAvailable) +{ + JNIEnv table = *env; + jlong gctx; + int stencilSize=0; + jlong newWin; + int PixelFormatID=0; + GraphicsContextPropertiesInfo* ctxInfo = (GraphicsContextPropertiesInfo *)malloc(sizeof(GraphicsContextPropertiesInfo)); + +#if defined(UNIX) + + /* Fix for issue 20 */ + + XVisualInfo *vinfo, template; + int nitems; + GLXContext ctx; + int result; + Window root; + Window glWin; + XSetWindowAttributes win_attrs; + Colormap cmap; + unsigned long win_mask; + jlong hdc; + + GLXFBConfig *fbConfigList = NULL; + + fbConfigList = (GLXFBConfig *)fbConfigListPtr; + + /* + fprintf(stderr, "Canvas3D_createQueryContext:\n"); + fprintf(stderr, "fbConfigListPtr 0x%x\n", (int) fbConfigListPtr); + fprintf(stderr, "fbConfigList 0x%x, fbConfigList[0] 0x%x\n", + (int) fbConfigList, (int) fbConfigList[0]); + */ + + ctx = glXCreateNewContext((Display *)display, fbConfigList[0], + GLX_RGBA_TYPE, NULL, True); + + if (ctx == NULL) { + fprintf(stderr, "Java 3D ERROR : Canvas3D_createQueryContext: couldn't create context.\n"); + } + + + /* onscreen rendering and window is 0 now */ + if(window == 0 && !offScreen) { + + vinfo = glXGetVisualFromFBConfig((Display*)display, fbConfigList[0]); + if (vinfo == NULL) { + fprintf(stderr, "Java 3D ERROR : glXGetVisualFromFBConfig failed\n"); + } + else { + /* fprintf(stderr, "found a %d-bit visual (visual ID = 0x%x)\n", + vinfo->depth, vinfo->visualid); + */ + root = RootWindow((Display *)display, vinfo->screen); + + /* Create a colormap */ + cmap = XCreateColormap((Display *)display, root, vinfo->visual, AllocNone); + + /* Create a window */ + win_attrs.colormap = cmap; + win_attrs.border_pixel = 0; + win_attrs.event_mask = KeyPressMask | ExposureMask | StructureNotifyMask; + win_mask = CWColormap | CWBorderPixel | CWEventMask; + glWin = XCreateWindow((Display *)display, root, 0, 0, width, height, 0, + vinfo->depth, InputOutput, vinfo->visual, + win_mask, &win_attrs); + newWin = (jlong)glWin; + } + } + else if(window == 0 && offScreen){ + newWin = Java_javax_media_j3d_NativePipeline_createOffScreenBuffer(env, + obj, cv, 0, display, + fbConfigListPtr, + width, height); + } + else if(window != 0) { + newWin = window; + } + + result = glXMakeCurrent((Display *)display, (GLXDrawable)newWin, (GLXContext)ctx); + if (!result) + fprintf(stderr, "Java 3D ERROR : glXMakeCurrent fails\n"); + + glXGetFBConfigAttrib((Display *) display, fbConfigList[0], + GLX_STENCIL_SIZE, &stencilSize); + + + gctx = (jlong)ctx; +#endif + +#ifdef WIN32 + HGLRC hrc; /* HW Rendering Context */ + HDC hdc; /* HW Device Context */ + DWORD err; + LPTSTR errString; + HWND hDummyWnd = 0; + static char szAppName[] = "OpenGL"; + jlong vinfo = 0; + jboolean result; + PixelFormatInfo *PixelFormatInfoPtr = (PixelFormatInfo *)fbConfigListPtr; + + /* Fix for issue 76 */ + + /* + fprintf(stderr, "Canvas3D_createQueryContext:\n"); + fprintf(stderr, "window is 0x%x, offScreen %d\n", window, offScreen); + */ + + /* Fix to issue 104 */ + if(!offScreen) { + if ((PixelFormatInfoPtr == NULL) || (PixelFormatInfoPtr->onScreenPFormat <= 0)) { + printErrorMessage("Canvas3D_createNewContext: onScreen PixelFormat is invalid"); + return; + } + else { + PixelFormatID = PixelFormatInfoPtr->onScreenPFormat; + } + } + else { + if ((PixelFormatInfoPtr == NULL) || (PixelFormatInfoPtr->offScreenPFormat <= 0)) { + printErrorMessage("Canvas3D_createNewContext: offScreen PixelFormat is invalid"); + return; + } + else { + PixelFormatID = PixelFormatInfoPtr->offScreenPFormat; + } + } + + /* onscreen rendering and window is 0 now */ + if(window == 0 && !offScreen){ + /* fprintf(stderr, "CreateQueryContext : window == 0 && !offScreen\n"); */ + hDummyWnd = createDummyWindow(szAppName); + if (!hDummyWnd) { + return; + } + hdc = GetDC(hDummyWnd); + } + else if(window == 0 && offScreen){ + /* fprintf(stderr, "CreateQueryContext : window == 0 && offScreen\n"); */ + hdc = (HDC)Java_javax_media_j3d_NativePipeline_createOffScreenBuffer(env, + obj, cv, 0, display, + fbConfigListPtr, + width, height); + } + else if(window != 0){ + /* fprintf(stderr, "CreateQueryContext : window != 0 0x%x\n", window); */ + hdc = (HDC) window; + } + + newWin = (jlong)hdc; + + SetPixelFormat(hdc, PixelFormatID, NULL); + + hrc = wglCreateContext( hdc ); + + if (!hrc) { + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + + fprintf(stderr, "wglCreateContext Failed: %s\n", errString); + } + + + result = wglMakeCurrent(hdc, hrc); + + if (!result) { + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + fprintf(stderr, "wglMakeCurrent Failed: %s\n", errString); + } + + gctx = (jlong)hrc; + +#endif + + initializeCtxInfo(env, ctxInfo); + ctxInfo->context = gctx; + + /* get current context properties */ + if (getPropertiesFromCurrentContext(env, cv, ctxInfo, (jlong) hdc, PixelFormatID, + fbConfigListPtr, offScreen, + glslLibraryAvailable, cgLibraryAvailable)) { + /* put the properties to the Java side */ + setupCanvasProperties(env, cv, ctxInfo); + } + + + /* clear up the context , colormap and window if appropriate */ + if(window == 0 && !offScreen){ +#if defined(UNIX) + Java_javax_media_j3d_NativePipeline_destroyContext(env, obj, display, newWin, (jlong)ctxInfo); + XDestroyWindow((Display *)display, glWin); + XFreeColormap((Display *)display, cmap); +#endif /* UNIX */ +#ifdef WIN32 + /* Release DC */ + ReleaseDC(hDummyWnd, hdc); + /* Destroy context */ + /* This will free ctxInfo also */ + Java_javax_media_j3d_NativePipeline_destroyContext(env, obj, display,newWin, (jlong)ctxInfo); + DestroyWindow(hDummyWnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); +#endif /* WIN32 */ + } + else if(window == 0 && offScreen) { + Java_javax_media_j3d_NativePipeline_destroyOffScreenBuffer(env, obj, cv, gctx, display, fbConfigListPtr, newWin); + Java_javax_media_j3d_NativePipeline_destroyContext(env, obj, display, newWin, (jlong)ctxInfo); + } + else if(window != 0){ + Java_javax_media_j3d_NativePipeline_destroyContext(env, obj, display, newWin, (jlong)ctxInfo); + } +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_beginScene( + JNIEnv *env, + jobject obj, + jlong ctxInfo) +{ + /* Not used by OGL renderer */ +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_endScene( + JNIEnv *env, + jobject obj, + jlong ctxInfo) +{ + /* This function is a no-op */ + /* + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + */ +} + +/* Setup the multisampling for full scene antialiasing */ +JNIEXPORT void JNICALL Java_javax_media_j3d_NativePipeline_setFullSceneAntialiasing +(JNIEnv *env, jobject obj, jlong ctxInfo, jboolean enable) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + if (ctxProperties->multisample && !ctxProperties->implicit_multisample) { + if(enable == JNI_TRUE) { + glEnable(GL_MULTISAMPLE); + } + else { + glDisable(GL_MULTISAMPLE); + + } + } + +} + + +/* + * Return false if <= 8 bit color under windows + */ +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_NativePipeline_validGraphicsMode( + JNIEnv *env, + jobject obj) +{ +#ifdef WIN32 + DEVMODE devMode; + + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode); + return (devMode.dmBitsPerPel > 8); +#endif + +#if defined(UNIX) + return JNI_TRUE; +#endif +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_cleanupRenderer( + JNIEnv *env, + jobject obj) +{ + /* No-op for OGL pipeline */ +} + + +/* + * Function to disable most rendering attributes when doing a 2D + * clear, or image copy operation. Note that the + * caller must save/restore the attributes with + * pushAttrib(GL_ENABLE_BIT|...) and popAttrib() + */ +static void +disableAttribFor2D(GraphicsContextPropertiesInfo *ctxProperties) +{ + int i; + + glDisable(GL_ALPHA_TEST); + glDisable(GL_BLEND); + glDisable(GL_COLOR_LOGIC_OP); + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_FOG); + glDisable(GL_LIGHTING); + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_POLYGON_STIPPLE); + glDisable(GL_STENCIL_TEST); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_GEN_Q); + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + + for (i = 0; i < 6; i++) { + glDisable(GL_CLIP_PLANE0 + i); + } + + glDisable(GL_TEXTURE_3D); + glDisable(GL_TEXTURE_CUBE_MAP); + + if (ctxProperties->textureRegisterCombinersAvailable) { + glDisable(GL_REGISTER_COMBINERS_NV); + } + + if (ctxProperties->textureColorTableAvailable) { + glDisable(GL_TEXTURE_COLOR_TABLE_SGI); + } + + if (ctxProperties->global_alpha_sun) { + glDisable(GL_GLOBAL_ALPHA_SUN); + } +} + +/* + * Function to disable most rendering attributes when doing a Raster + * clear, or image copy operation. Note that the + * caller must save/restore the attributes with + * pushAttrib(GL_ENABLE_BIT|...) and popAttrib() + */ +static void +disableAttribForRaster(GraphicsContextPropertiesInfo *ctxProperties) +{ + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_CULL_FACE); + glDisable(GL_LIGHTING); + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_POLYGON_STIPPLE); + + // TODO: Disable if Raster.CLIP_POSITION is true +// for (int i = 0; i < 6; i++) { +// glDisable(GL_CLIP_PLANE0 + i); +// } + + if (ctxProperties->global_alpha_sun) { + glDisable(GL_GLOBAL_ALPHA_SUN); + } +} diff --git a/j3d-core/src/native/ogl/CgShaderProgram.c b/j3d-core/src/native/ogl/CgShaderProgram.c new file mode 100644 index 0000000..c03dc14 --- /dev/null +++ b/j3d-core/src/native/ogl/CgShaderProgram.c @@ -0,0 +1,2460 @@ +/* + * $RCSfile: CgShaderProgram.c,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.11 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include +#include +#include +#include +#include + +#include "gldefs.h" +#include "CgWrapper.h" + +#if defined(UNIX) +#include +#endif + +#ifdef DEBUG +/* Uncomment the following for VERBOSE debug messages */ +/* #define VERBOSE */ +#endif /* DEBUG */ + + +extern char *strJavaToC(JNIEnv *env, jstring str); +extern void throwAssert(JNIEnv *env, char *str); +extern jobject createShaderError(JNIEnv *env, + int errorCode, + const char *errorMsg, + const char *detailMsg); + +static void cgVertexAttrPointer(GraphicsContextPropertiesInfo *ctxProperties, + int index, int size, int type, int stride, + const void *pointer); +static void cgEnableVertexAttrArray(GraphicsContextPropertiesInfo *ctxProperties, + int index); +static void cgDisableVertexAttrArray(GraphicsContextPropertiesInfo *ctxProperties, + int index); +static void cgVertexAttr(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); + + +/* Global CG wrapper info struct, created by MasterControl during initialization */ +static CgWrapperInfo *globalCgWrapperInfo = NULL; + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: loadNativeCgLibrary + * Signature: ([Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL +Java_javax_media_j3d_NativePipeline_loadNativeCgLibrary( + JNIEnv *env, + jobject thiz, + jobjectArray libpath) +{ + CgWrapperInfo *cgWrapperInfo; + +#ifdef COMPILE_CG_SHADERS + int i, pathLen; + char *errName = NULL; + +#ifdef WIN32 + DWORD err; + LPTSTR errString; + UINT origErrorMode; +#endif /* WIN32 */ + +#endif /* COMPILE_CG_SHADERS */ + + /* + * This method is called exactly once to load and initialize the + * CG wrapper library. + */ + + /* Assertion check that we don't get called more than once */ + if (globalCgWrapperInfo != NULL) { + throwAssert(env, "NativePipeline.loadNativeCgLibrary called more than once"); + return JNI_FALSE; + } + + /* Allocate global Cg wrapper struct */ + cgWrapperInfo = (CgWrapperInfo*)malloc(sizeof(CgWrapperInfo)); + cgWrapperInfo->loaded = JNI_FALSE; + cgWrapperInfo->cgLibraryHandle = NULL; + +#ifdef COMPILE_CG_SHADERS + + /* Remove the following print statement when the native Cg code is stable */ + fprintf(stderr, "*** JAVA 3D : loading experimental native Cg library\n"); + + /* Get number of entries in libpath array */ + pathLen = (*env)->GetArrayLength(env, libpath); + /*fprintf(stderr, "pathLen = %d\n", pathLen);*/ + +#ifdef UNIX + + for (i = 0; i < pathLen; i++) { + jstring libname; + char *libnameStr; + + libname = (*env)->GetObjectArrayElement(env, libpath, i); + libnameStr = strJavaToC(env, libname); + /*fprintf(stderr, "dlopen(%s)\n", libnameStr);*/ + cgWrapperInfo->cgLibraryHandle = dlopen(libnameStr, RTLD_LAZY); + if ((cgWrapperInfo->cgLibraryHandle == NULL) && (i == pathLen-1)) { + errName = strdup(libnameStr); + } + free(libnameStr); + if (cgWrapperInfo->cgLibraryHandle != NULL) { + break; + } + } + + if (cgWrapperInfo->cgLibraryHandle == NULL) { + fprintf(stderr, "JAVA 3D ERROR : Unable to load library "); + perror(errName); + free(errName); + free(cgWrapperInfo); + return JNI_FALSE; + } + + /* Get pointer to library function to setup function pointers */ + cgWrapperInfo->j3dLoadCgFunctionPointers = + (PFNJ3DLOADCGFUNCTIONPOINTERS)dlsym(cgWrapperInfo->cgLibraryHandle, + "j3dLoadCgFunctionPointers"); + +#endif /* UNIX */ + +#ifdef WIN32 + + /* Load the library, suppressing any dialog boxes that may occur */ + origErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | + SEM_FAILCRITICALERRORS); + + for (i = 0; i < pathLen; i++) { + jstring libname; + char *libnameStr; + + libname = (*env)->GetObjectArrayElement(env, libpath, i); + libnameStr = strJavaToC(env, libname); + /*fprintf(stderr, "LoadLibrary(%s)\n", libnameStr);*/ + cgWrapperInfo->cgLibraryHandle = LoadLibrary(libnameStr); + if ((cgWrapperInfo->cgLibraryHandle == NULL) && (i == pathLen-1)) { + errName = strdup(libnameStr); + } + free(libnameStr); + if (cgWrapperInfo->cgLibraryHandle != NULL) { + break; + } + } + + SetErrorMode(origErrorMode); + + if (cgWrapperInfo->cgLibraryHandle == NULL) { + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + + fprintf(stderr, + "JAVA 3D ERROR : Unable to load library %s: %s\n", + errName, errString); + free(errName); + return JNI_FALSE; + } + + cgWrapperInfo->j3dLoadCgFunctionPointers = + (PFNJ3DLOADCGFUNCTIONPOINTERS)GetProcAddress( + (HMODULE)cgWrapperInfo->cgLibraryHandle, + "j3dLoadCgFunctionPointers"); + + if (cgWrapperInfo->j3dLoadCgFunctionPointers == NULL) { + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + + fprintf(stderr, + "JAVA 3D ERROR : Unable to find: j3dLoadCgFunctionPointers: %s\n", + errString); + return JNI_FALSE; + } + +#endif /* WIN32 */ + + if (cgWrapperInfo->j3dLoadCgFunctionPointers) { + cgWrapperInfo->j3dLoadCgFunctionPointers(cgWrapperInfo); + cgWrapperInfo->loaded = JNI_TRUE; + } + +#else /* COMPILE_CG_SHADERS */ + + fprintf(stderr, "Java 3D: CgShaderProgram code not compiled\n"); + +#endif /* COMPILE_CG_SHADERS */ + + /* Save pointer in global variable */ + globalCgWrapperInfo = cgWrapperInfo; + + return cgWrapperInfo->loaded; +} + + +#ifdef COMPILE_CG_SHADERS + +static char * +getErrorLog( + GraphicsContextPropertiesInfo* ctxProperties, + CGerror lastError) +{ + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + + if (lastError != 0) { + const char *errString = cgWrapperInfo->cgGetErrorString(lastError); + const char *delimeter1 = "\n"; + const char *listing = cgWrapperInfo->cgGetLastListing(cgCtxInfo->cgCtx); + + char *errMsg = (char *) + malloc(strlen(errString) + strlen(delimeter1) + strlen(listing) + 1); + + if (errMsg == NULL) { + perror("malloc"); + return NULL; + } + + strcpy(errMsg, errString); + strcat(errMsg, delimeter1); + strcat(errMsg, listing); + + return errMsg; + } + + fprintf(stderr, "Assertion error: assert(lastError != 0) failed\n"); + return NULL; +} + + +static CgCtxInfo * +createCgShaderContext( + JNIEnv *env, + GraphicsContextPropertiesInfo *ctxInfo) +{ + jclass oom; + CGerror lastError; + CgCtxInfo *cgCtxInfo = NULL; + CgWrapperInfo *cgWrapperInfo; + + /* Assertion check that we don't get here unless the library is loaded */ + if (globalCgWrapperInfo == NULL) { + throwAssert(env, "createCgShaderContext: cgWrapperInfo is NULL"); + return NULL; + } + + if (!globalCgWrapperInfo->loaded) { + throwAssert(env, "createCgShaderContext: cgWrapper library not loaded"); + return NULL; + } + + cgCtxInfo = (CgCtxInfo*)malloc(sizeof(CgCtxInfo)); + if (cgCtxInfo == NULL) { + if ((oom = (*env)->FindClass(env, "java/lang/OutOfMemoryError")) != NULL) { + (*env)->ThrowNew(env, oom, "malloc"); + } + return NULL; + } + + /* Point to the global CG wrapper info */ + cgWrapperInfo = cgCtxInfo->cgWrapperInfo = globalCgWrapperInfo; + + /* Create CG context */ + cgCtxInfo->cgCtx = cgWrapperInfo->cgCreateContext(); + + if ((lastError = cgWrapperInfo->cgGetError()) != 0) { + fprintf(stderr, "Fatal error in creating Cg context:\n"); + fprintf(stderr, "\t%s\n", cgWrapperInfo->cgGetErrorString(lastError)); + free(cgCtxInfo); + return NULL; + } + + if (cgCtxInfo->cgCtx == 0) { + fprintf(stderr, "Invalid NULL Cg context\n"); + free(cgCtxInfo); + return NULL; + } + + /* Use GL_ARB_vertex_program extension if supported by video card */ + if (cgWrapperInfo->cgGLIsProfileSupported(CG_PROFILE_ARBVP1)) { +#ifdef VERBOSE + fprintf(stderr, "Using CG_PROFILE_ARBVP1\n"); +#endif /* VERBOSE */ + cgCtxInfo->vProfile = CG_PROFILE_ARBVP1; + } + else if (cgWrapperInfo->cgGLIsProfileSupported(CG_PROFILE_VP20)) { +#ifdef VERBOSE + fprintf(stderr, "Using CG_PROFILE_VP20\n"); +#endif /* VERBOSE */ + cgCtxInfo->vProfile = CG_PROFILE_VP20; + } + else { + fprintf(stderr, + "JAVA 3D ERROR : No CG vertex program profile is supported\n"); + free(cgCtxInfo); + return NULL; + } + + /* Use GL_ARB_fragment_program extension if supported by video card */ + if (cgWrapperInfo->cgGLIsProfileSupported(CG_PROFILE_ARBFP1)) { +#ifdef VERBOSE + fprintf(stderr, "Using CG_PROFILE_ARBFP1\n"); +#endif /* VERBOSE */ + cgCtxInfo->fProfile = CG_PROFILE_ARBFP1; + } + else if (cgWrapperInfo->cgGLIsProfileSupported(CG_PROFILE_FP20)) { +#ifdef VERBOSE + fprintf(stderr, "Using CG_PROFILE_FP20\n"); +#endif /* VERBOSE */ + cgCtxInfo->fProfile = CG_PROFILE_FP20; + } + else { + fprintf(stderr, + "JAVA 3D ERROR : No CG fragment program profile is supported\n"); + free(cgCtxInfo); + return NULL; + } + +#ifdef VERBOSE + fprintf(stderr, "createCgShaderContext: SUCCESS\n"); + fprintf(stderr, " cgCtx = 0x%x\n", cgCtxInfo->cgCtx); + fprintf(stderr, " vProfile = 0x%x\n", cgCtxInfo->vProfile); + fprintf(stderr, " fProfile = 0x%x\n", cgCtxInfo->fProfile); +#endif /* VERBOSE */ + + return cgCtxInfo; +} + +#endif /* COMPILE_CG_SHADERS */ + + +/* + * Called by getPropertiesFromCurrentContext to initialize the Cg + * shader function pointers and set the flag indicating whether Cg + * shaders are available. + */ +void +checkCgShaderExtensions( + JNIEnv *env, + jobject obj, + char *tmpExtensionStr, + GraphicsContextPropertiesInfo *ctxInfo, + jboolean cgLibraryAvailable) +{ + ctxInfo->shadingLanguageCg = JNI_FALSE; + ctxInfo->cgCtxInfo = NULL; + +#ifdef COMPILE_CG_SHADERS + if (cgLibraryAvailable) { + /* TODO: need to free ctxInfo->cgCtxInfo when ctxInfo is freed */ + ctxInfo->cgCtxInfo = createCgShaderContext(env, ctxInfo); + if (ctxInfo->cgCtxInfo != NULL) { + CgWrapperInfo *cgWrapperInfo = ctxInfo->cgCtxInfo->cgWrapperInfo; + +#ifdef VERBOSE + fprintf(stderr, "Cg ctx is available\n"); +#endif /* VERBOSE */ + ctxInfo->shadingLanguageCg = JNI_TRUE; + + /* TODO: Query Cg texture sampler limits */ + ctxInfo->maxTextureImageUnits = ctxInfo->maxTextureUnits; + ctxInfo->maxVertexTextureImageUnits = 0; + ctxInfo->maxCombinedTextureImageUnits = ctxInfo->maxTextureUnits; + + /* TODO: Query max vertex attrs */ + ctxInfo->maxVertexAttrs = 7; + + /* Initialize shader vertex attribute function pointers */ + ctxInfo->vertexAttrPointer = cgVertexAttrPointer; + ctxInfo->enableVertexAttrArray = cgEnableVertexAttrArray; + ctxInfo->disableVertexAttrArray = cgDisableVertexAttrArray; + ctxInfo->vertexAttr1fv = cgVertexAttr; + ctxInfo->vertexAttr2fv = cgVertexAttr; + ctxInfo->vertexAttr3fv = cgVertexAttr; + ctxInfo->vertexAttr4fv = cgVertexAttr; + } +#ifdef VERBOSE + else { + fprintf(stderr, "ERROR: Cg ctx *not* available\n"); + } +#endif /* VERBOSE */ + } +#endif /* COMPILE_CG_SHADERS */ + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: createCgShader + * Signature: (JI[J)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_createCgShader( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint shaderType, + jlongArray shaderIdArray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + + jlong *shaderIdPtr; + CGprogram shaderId = 0; + jclass oom; + CgShaderInfo *cgShaderInfo; + +#ifdef VERBOSE + fprintf(stderr, "CgShaderProgramRetained.createCgShader\n"); +#endif /* VERBOSE */ + + cgShaderInfo = (CgShaderInfo*)malloc(sizeof(CgShaderInfo)); + if (cgShaderInfo == NULL) { + if ((oom = (*env)->FindClass(env, "java/lang/OutOfMemoryError")) != NULL) { + (*env)->ThrowNew(env, oom, "malloc"); + } + return NULL; + } + cgShaderInfo->cgShader = 0; + cgShaderInfo->shaderType = shaderType; + if (shaderType == javax_media_j3d_Shader_SHADER_TYPE_VERTEX) { + cgShaderInfo->shaderProfile = cgCtxInfo->vProfile; + } + else if (shaderType == javax_media_j3d_Shader_SHADER_TYPE_FRAGMENT) { + cgShaderInfo->shaderProfile = cgCtxInfo->fProfile; + } + else { + cgShaderInfo->shaderProfile = 0; + fprintf(stderr, "shaderType = %d\n", shaderType); + throwAssert(env, "unrecognized shaderType"); + return NULL; + } + + shaderIdPtr = (*env)->GetLongArrayElements(env, shaderIdArray, NULL); + shaderIdPtr[0] = (jlong) cgShaderInfo; + (*env)->ReleaseLongArrayElements(env, shaderIdArray, shaderIdPtr, 0); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: destroyCgShader + * Signature: (JJ)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_destroyCgShader( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderId) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + + CgShaderInfo *cgShaderInfo = (CgShaderInfo *)shaderId; + +#ifdef VERBOSE + fprintf(stderr, "CgShaderProgramRetained.destroyCgShader\n"); +#endif /* VERBOSE */ + + if (cgShaderInfo != NULL) { + if (cgShaderInfo->cgShader != 0) { + cgWrapperInfo->cgDestroyProgram(cgShaderInfo->cgShader); + } + + free(cgShaderInfo); + } + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: compileCgShader + * Signature: (JJLjava/lang/String;)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_compileCgShader( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderId, + jstring program) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + + CgShaderInfo *cgShaderInfo = (CgShaderInfo *)shaderId; + CGerror lastError; + GLcharARB *shaderString = NULL; + +#ifdef VERBOSE + fprintf(stderr, "CgShaderProgramRetained.compileCgShader\n"); +#endif /* VERBOSE */ + + /* Assertion check the cgShaderInfo pointer */ + if (cgShaderInfo == NULL) { + throwAssert(env, "cgShaderInfo is NULL"); + return NULL; + } + + /* Assertion check the program string */ + if (program == NULL) { + throwAssert(env, "shader program string is NULL"); + return NULL; + } + + shaderString = strJavaToC(env, program); + if (shaderString == NULL) { + /* Just return, since strJavaToC will throw OOM if it returns NULL */ + return NULL; + } + + /* create the shader */ +#ifdef VERBOSE + if (cgShaderInfo->shaderType == javax_media_j3d_Shader_SHADER_TYPE_VERTEX) { + fprintf(stderr, "Create vertex shader\n"); + } + else if (cgShaderInfo->shaderType == javax_media_j3d_Shader_SHADER_TYPE_FRAGMENT) { + fprintf(stderr, "Create fragment shader\n"); + } + fprintf(stderr, "cgCtx = 0x%x\n", cgCtxInfo->cgCtx); + fprintf(stderr, "shaderProfile = 0x%x\n", cgShaderInfo->shaderProfile); +#endif /* VERBOSE */ + + cgShaderInfo->cgShader = cgWrapperInfo->cgCreateProgram(cgCtxInfo->cgCtx, + CG_SOURCE, shaderString, + cgShaderInfo->shaderProfile, NULL, NULL); + +#ifdef VERBOSE + fprintf(stderr, " cgShader = 0x%x\n", cgShaderInfo->cgShader); +#endif /* VERBOSE */ + + free(shaderString); + + if ((lastError = cgWrapperInfo->cgGetError()) != 0) { + char *detailMsg = getErrorLog(ctxProperties, lastError); + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_COMPILE_ERROR, + "Cg shader compile error", + detailMsg); + if (detailMsg != NULL) { + free(detailMsg); + } + } + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: createCgShaderProgram + * Signature: (J[J)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_createCgShaderProgram( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlongArray shaderProgramIdArray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jlong *shaderProgramIdPtr; + + CgShaderProgramInfo *shaderProgramInfo = + (CgShaderProgramInfo*)malloc(sizeof(CgShaderProgramInfo)); + +#ifdef VERBOSE + fprintf(stderr, "CgShaderProgramRetained.createCgShaderProgram\n"); +#endif /* VERBOSE */ + + shaderProgramInfo->vShader = NULL; + shaderProgramInfo->fShader = NULL; + shaderProgramInfo->numVtxAttrs = 0; + shaderProgramInfo->vtxAttrs = NULL; + + shaderProgramIdPtr = (*env)->GetLongArrayElements(env, shaderProgramIdArray, NULL); + shaderProgramIdPtr[0] = (jlong)shaderProgramInfo; + (*env)->ReleaseLongArrayElements(env, shaderProgramIdArray, shaderProgramIdPtr, 0); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: destroyCgShaderProgram + * Signature: (JJ)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_destroyCgShaderProgram( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + CgShaderProgramInfo *shaderProgramInfo = (CgShaderProgramInfo*)shaderProgramId; + +#ifdef VERBOSE + fprintf(stderr, "CgShaderProgramRetained.destroyCgShaderProgram\n"); +#endif /* VERBOSE */ + + if (shaderProgramInfo != NULL) { + if (shaderProgramInfo->vtxAttrs != NULL) { + free(shaderProgramInfo->vtxAttrs); + shaderProgramInfo->vtxAttrs = NULL; + } + free(shaderProgramInfo); + } + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: linkCgShaderProgram + * Signature: (JJ[J)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_linkCgShaderProgram( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlongArray shaderIdArray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + + jsize shaderIdArrayLength = (*env)->GetArrayLength(env, shaderIdArray); + jlong *shaderIdPtr = (*env)->GetLongArrayElements(env, shaderIdArray, NULL); + CGerror lastError; + + int i; + + CgShaderProgramInfo *shaderProgramInfo = (CgShaderProgramInfo*)shaderProgramId; + +#ifdef VERBOSE + fprintf(stderr, "CgShaderProgramRetained.linkCgShaderProgram\n"); +#endif /* VERBOSE */ + + /* + * NOTE: we assume that the caller has already verified that there + * is at most one vertex program and one fragment program + */ + shaderProgramInfo->vShader = NULL; + shaderProgramInfo->fShader = NULL; + for (i = 0; i < shaderIdArrayLength; i++) { + CgShaderInfo *shader = (CgShaderInfo*)shaderIdPtr[i]; + if (shader->shaderType == javax_media_j3d_Shader_SHADER_TYPE_VERTEX) { + shaderProgramInfo->vShader = shader; + } else { + shaderProgramInfo->fShader = shader; + } + + cgWrapperInfo->cgGLLoadProgram(shader->cgShader); + + if ((lastError = cgWrapperInfo->cgGetError()) != 0) { + char *detailMsg = getErrorLog(ctxProperties, lastError); + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_LINK_ERROR, + "Cg shader link/load error", + detailMsg); + if (detailMsg != NULL) { + free(detailMsg); + } + } + + cgWrapperInfo->cgGLBindProgram(shader->cgShader); + + if ((lastError = cgWrapperInfo->cgGetError()) != 0) { + char *detailMsg = getErrorLog(ctxProperties, lastError); + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_LINK_ERROR, + "Cg shader link/bind error", + detailMsg); + if (detailMsg != NULL) { + free(detailMsg); + } + } + } + + (*env)->ReleaseLongArrayElements(env, shaderIdArray, shaderIdPtr, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: lookupCgVertexAttrNames + * Signature: (JJI[Ljava/lang/String;[Z)V + */ +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_lookupCgVertexAttrNames( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jint numAttrNames, + jobjectArray attrNames, + jbooleanArray errArr) +{ +#ifdef COMPILE_CG_SHADERS + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + + CgShaderProgramInfo *shaderProgramInfo = (CgShaderProgramInfo*)shaderProgramId; + + int i; + jstring attrName; + char *attrNameString; + jboolean *errPtr; + + errPtr = (*env)->GetBooleanArrayElements(env, errArr, NULL); + + if (shaderProgramInfo->vShader == NULL) { + /* If there if no vertex shader, no attributes can be looked up, so all fail */ + for (i = 0; i < numAttrNames; i++) { + errPtr[i] = JNI_TRUE; + } + (*env)->ReleaseBooleanArrayElements(env, errArr, errPtr, 0); + return; + } + + shaderProgramInfo->numVtxAttrs = numAttrNames; + shaderProgramInfo->vtxAttrs = (CGparameter *)malloc(numAttrNames * sizeof(CGparameter)); + +#ifdef VERBOSE + fprintf(stderr, "CgShaderProgramRetained.lookupCgVertexAttrNames()\n"); +#endif /* VERBOSE */ + + for (i = 0; i < numAttrNames; i++) { + attrName = (*env)->GetObjectArrayElement(env, attrNames, i); + attrNameString = strJavaToC(env, attrName); + + shaderProgramInfo->vtxAttrs[i] = + cgWrapperInfo->cgGetNamedParameter(shaderProgramInfo->vShader->cgShader, + attrNameString); +#ifdef VERBOSE + fprintf(stderr, " %s : 0x%x\n", attrNameString, shaderProgramInfo->vtxAttrs[i]); +#endif /* VERBOSE */ + if (shaderProgramInfo->vtxAttrs[i] == NULL) { + errPtr[i] = JNI_TRUE; + } + + free(attrNameString); + } + + (*env)->ReleaseBooleanArrayElements(env, errArr, errPtr, 0); + +#endif /* COMPILE_CG_SHADERS */ +} + + +#ifdef COMPILE_CG_SHADERS + +static jint +cgToJ3dType(CGtype type) +{ + switch (type) { + case CG_BOOL: + case CG_BOOL1: + case CG_FIXED: + case CG_FIXED1: + case CG_HALF: + case CG_HALF1: + case CG_INT: + case CG_INT1: + return TYPE_INTEGER; + + /* + * XXXX: add ShaderAttribute support for setting samplers. In the + * mean time, the binding between sampler and texture unit will + * need to be specified in the shader itself (which it already is + * in most example shaders). + * + * case CG_SAMPLER2D: + * case CG_SAMPLER3D: + * case CG_SAMPLERCUBE: + * + */ + + case CG_BOOL2: + case CG_FIXED2: + case CG_HALF2: + case CG_INT2: + return TYPE_TUPLE2I; + + case CG_BOOL3: + case CG_FIXED3: + case CG_HALF3: + case CG_INT3: + return TYPE_TUPLE3I; + + case CG_BOOL4: + case CG_FIXED4: + case CG_HALF4: + case CG_INT4: + return TYPE_TUPLE4I; + + case CG_FLOAT: + case CG_FLOAT1: + return TYPE_FLOAT; + + case CG_FLOAT2: + return TYPE_TUPLE2F; + + case CG_FLOAT3: + return TYPE_TUPLE3F; + + case CG_FLOAT4: + return TYPE_TUPLE4F; + + case CG_FLOAT3x3: + return TYPE_MATRIX3F; + + case CG_FLOAT4x4: + return TYPE_MATRIX4F; + + /* + * Java 3D does not support the following sampler types: + * + * case CG_SAMPLER1D: + * case CG_SAMPLERRECT: + */ + } + + return -1; +} + +static CGparameter +lookupParams( + CgWrapperInfo *cgWrapperInfo, + CgShaderInfo *shader, + char *attrNameString, + CGtype *type, + int *size, + jboolean *isArray) +{ + CGparameter loc; + CGparameter firstElem; + + loc = cgWrapperInfo->cgGetNamedParameter(shader->cgShader, + attrNameString); + if (loc != NULL) { + *type = cgWrapperInfo->cgGetParameterType(loc); + if (*type == CG_ARRAY) { + *isArray = JNI_TRUE; + *size = cgWrapperInfo->cgGetArraySize(loc, 0); + /**type = cgWrapperInfo->cgGetArrayType(loc);*/ + firstElem = cgWrapperInfo->cgGetArrayParameter(loc, 0); + *type = cgWrapperInfo->cgGetParameterType(firstElem); + /* + fprintf(stderr, + "firstElem = %d, *type = %d\n", + firstElem, *type); + */ + } + else { + *isArray = JNI_FALSE; + *size = 1; + } + } + + return loc; +} + +#endif /* COMPILE_CG_SHADERS */ + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: lookupCgShaderAttrNames + * Signature: (JJI[Ljava/lang/String;[J[I[I[Z)V + */ +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_lookupCgShaderAttrNames( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jint numAttrNames, + jobjectArray attrNames, + jlongArray locArr, + jintArray typeArr, + jintArray sizeArr, + jbooleanArray isArrayArr) +{ + +#ifdef COMPILE_CG_SHADERS + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgShaderProgramInfo *shaderProgramInfo = (CgShaderProgramInfo*)shaderProgramId; + + jstring attrName; + char *attrNameString; + jlong *locPtr; + jint *typePtr; + jint *sizePtr; + jboolean *isArrayPtr; + CGparameter vLoc, fLoc; + CGtype vType, fType; + int vSize, fSize; + jboolean vIsArray, fIsArray; + int i; + + locPtr = (*env)->GetLongArrayElements(env, locArr, NULL); + typePtr = (*env)->GetIntArrayElements(env, typeArr, NULL); + sizePtr = (*env)->GetIntArrayElements(env, sizeArr, NULL); + isArrayPtr = (*env)->GetBooleanArrayElements(env, isArrayArr, NULL); + + /* + * Set the loc, type, and size arrays to out-of-band values + */ + for (i = 0; i < numAttrNames; i++) { + locPtr[i] = -1; + typePtr[i] = -1; + sizePtr[i] = -1; + } + + /* Now lookup the location of each name in the attrNames array */ + for (i = 0; i < numAttrNames; i++) { + jboolean err; + CgParameterInfo *cgParamInfo; + + attrName = (*env)->GetObjectArrayElement(env, attrNames, i); + attrNameString = (GLcharARB *)strJavaToC(env, attrName); + +#ifdef VERBOSE + fprintf(stderr, "lookup %s\n", attrNameString); +#endif /* VERBOSE */ + + /* + * Get uniform attribute location -- note that we need to + * lookup the name in both the vertex and fragment shader + * (although we will generalize it to look at the list of "N" + * shaders). If all parameter locations are NULL, then no + * struct will be allocated and -1 will be stored for this + * attribute. If there is more than one non-NULL parameter, + * then all must be of the same type and dimensionality, + * otherwise an error will be generated and -1 will be stored + * for this attribute. If all non-NULL parameters are of the + * same type and dimensionality, then a struct is allocated + * containing the list of parameters. + * + * When any of the setCgUniform methods are called, the attribute + * will be set for each parameter in the list. + */ + cgParamInfo = (CgParameterInfo *)malloc(sizeof(CgParameterInfo)); + cgParamInfo->vParam = NULL; + cgParamInfo->fParam = NULL; + err = JNI_FALSE; + + vLoc = NULL; + if (shaderProgramInfo->vShader != NULL) { + vLoc = lookupParams(cgWrapperInfo, shaderProgramInfo->vShader, + attrNameString, &vType, &vSize, &vIsArray); + cgParamInfo->vParam = vLoc; + if (vLoc != NULL) { + sizePtr[i] = (jint)vSize; + isArrayPtr[i] = vIsArray; + typePtr[i] = cgToJ3dType(vType); + +#ifdef VERBOSE + fprintf(stderr, " vLoc = %d, vType = %d, vSize = %d, vIsArray = %d\n", + vLoc, vType, vSize, vIsArray); +#endif /* VERBOSE */ + } + } + + fLoc = NULL; + if (shaderProgramInfo->fShader != NULL) { + fLoc = lookupParams(cgWrapperInfo, shaderProgramInfo->fShader, + attrNameString, &fType, &fSize, &fIsArray); + cgParamInfo->fParam = fLoc; + if (fLoc != NULL) { + sizePtr[i] = (jint)fSize; + isArrayPtr[i] = fIsArray; + typePtr[i] = cgToJ3dType(fType); + +#ifdef VERBOSE + fprintf(stderr, " fLoc = %d, fType = %d, fSize = %d, fIsArray = %d\n", + fLoc, fType, fSize, fIsArray); +#endif /* VERBOSE */ + } + } + + /* + * If the name lookup found an entry in both vertex and + * fragment program, verify that the type and size are the + * same. + */ + if (cgParamInfo->vParam != NULL && cgParamInfo->fParam != NULL) { + if (vType != fType || vSize != fSize || vIsArray != fIsArray) { + /* TODO: the following needs to be propagated to ShaderError */ + fprintf(stderr, + "JAVA 3D : error shader attribute type mismatch: %s\n", + attrNameString); + fprintf(stderr, + " 1 : type = %d, size = %d, isArray = %d\n", + vType, vSize, vIsArray); + fprintf(stderr, + " 0 : type = %d, size = %d, isArray = %d\n", + fType, fSize, fIsArray); + err = JNI_TRUE; + } + } + + /* + * Report an error if we got a mismatch or if the attribute + * was not found in either the vertex or the fragment program + */ + if (err || (cgParamInfo->vParam == NULL && cgParamInfo->fParam == NULL)) { + /* + * TODO: distinguish between (err) and (vParam and fParam both NULL) + * so we can report a more helpful error message + */ + free(cgParamInfo); + locPtr[i] = (jlong)-1; + } + else { + /* + * TODO: need to store the cgParamInfo pointers in the + * shader program so we can free them later. + * + * NOTE: WE CURRENTLY HAVE A MEMORY LEAK. + */ + locPtr[i] = (jlong)cgParamInfo; + } + + free(attrNameString); + } + + /* Release JNI arrays */ + (*env)->ReleaseLongArrayElements(env, locArr, locPtr, 0); + (*env)->ReleaseIntArrayElements(env, typeArr, typePtr, 0); + (*env)->ReleaseIntArrayElements(env, sizeArr, sizePtr, 0); + (*env)->ReleaseBooleanArrayElements(env, isArrayArr, isArrayPtr, 0); + +#endif /* COMPILE_CG_SHADERS */ + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: useCgShaderProgram + * Signature: (JJ)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_useCgShaderProgram( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId) +{ +#ifdef COMPILE_CG_SHADERS + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + + CgShaderProgramInfo *shaderProgramInfo = (CgShaderProgramInfo*)shaderProgramId; + + /* Disable shader profiles */ + cgWrapperInfo->cgGLDisableProfile(cgCtxInfo->vProfile); + cgWrapperInfo->cgGLDisableProfile(cgCtxInfo->fProfile); + + if (shaderProgramId != 0) { + if (shaderProgramInfo->vShader != NULL) { + cgWrapperInfo->cgGLBindProgram(shaderProgramInfo->vShader->cgShader); + cgWrapperInfo->cgGLEnableProfile(shaderProgramInfo->vShader->shaderProfile); + } else { + cgWrapperInfo->cgGLUnbindProgram(cgCtxInfo->vProfile); + } + + if (shaderProgramInfo->fShader != NULL) { + cgWrapperInfo->cgGLBindProgram(shaderProgramInfo->fShader->cgShader); + cgWrapperInfo->cgGLEnableProfile(shaderProgramInfo->fShader->shaderProfile); + } else { + cgWrapperInfo->cgGLUnbindProgram(cgCtxInfo->fProfile); + } + } else { + cgWrapperInfo->cgGLUnbindProgram(cgCtxInfo->vProfile); + cgWrapperInfo->cgGLUnbindProgram(cgCtxInfo->fProfile); + } + + ctxProperties->shaderProgramId = shaderProgramId; + +#endif /* COMPILE_CG_SHADERS */ + + return NULL; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform1i + * Signature: (JJJI)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform1i( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint value) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameter1f(cgParamInfo->vParam, (float)value); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameter1f(cgParamInfo->fParam, (float)value); + } + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform1f + * Signature: (JJJF)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform1f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloat value) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameter1f(cgParamInfo->vParam, value); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameter1f(cgParamInfo->fParam, value); + } + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform2i + * Signature: (JJJ[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform2i( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jintArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jint *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetIntArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameter2f(cgParamInfo->vParam, + (float)values[0], + (float)values[1]); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameter2f(cgParamInfo->fParam, + (float)values[0], + (float)values[1]); + } + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform2f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform2f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameter2f(cgParamInfo->vParam, + values[0], + values[1]); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameter2f(cgParamInfo->fParam, + values[0], + values[1]); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform3i + * Signature: (JJJ[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform3i( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jintArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jint *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetIntArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameter3f(cgParamInfo->vParam, + (float)values[0], + (float)values[1], + (float)values[2]); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameter3f(cgParamInfo->fParam, + (float)values[0], + (float)values[1], + (float)values[2]); + } + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform3f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform3f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameter3f(cgParamInfo->vParam, + values[0], + values[1], + values[2]); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameter3f(cgParamInfo->fParam, + values[0], + values[1], + values[2]); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform4i + * Signature: (JJJ[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform4i( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jintArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jint *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetIntArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameter4f(cgParamInfo->vParam, + (float)values[0], + (float)values[1], + (float)values[2], + (float)values[3]); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameter4f(cgParamInfo->fParam, + (float)values[0], + (float)values[1], + (float)values[2], + (float)values[3]); + } + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform4f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform4f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameter4f(cgParamInfo->vParam, + values[0], + values[1], + values[2], + values[3]); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameter4f(cgParamInfo->fParam, + values[0], + values[1], + values[2], + values[3]); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniformMatrix3f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniformMatrix3f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetMatrixParameterfr(cgParamInfo->vParam, values); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetMatrixParameterfr(cgParamInfo->fParam, values); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniformMatrix4f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniformMatrix4f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetMatrixParameterfr(cgParamInfo->vParam, values); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetMatrixParameterfr(cgParamInfo->fParam, values); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform1iArray + * Signature: (JJJI[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform1iArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jintArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + int i; + jint *ivalues; + float *fvalues; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + ivalues = (*env)->GetIntArrayElements(env, varray, NULL); + fvalues = malloc(length * sizeof(float)); + for (i = 0; i < length; i++) { + fvalues[i] = (float)ivalues[i]; + } + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray1f(cgParamInfo->vParam, + 0, length, fvalues); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray1f(cgParamInfo->fParam, + 0, length, fvalues); + } + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, ivalues, JNI_ABORT); + free(fvalues); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform1fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform1fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray1f(cgParamInfo->vParam, + 0, length, values); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray1f(cgParamInfo->fParam, + 0, length, values); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform2iArray + * Signature: (JJJI[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform2iArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jintArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + int i; + jint *ivalues; + float *fvalues; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + ivalues = (*env)->GetIntArrayElements(env, varray, NULL); + fvalues = malloc(length * sizeof(float)); + for (i = 0; i < 2 * length; i++) { + fvalues[i] = (float)ivalues[i]; + } + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray2f(cgParamInfo->vParam, + 0, length, fvalues); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray2f(cgParamInfo->fParam, + 0, length, fvalues); + } + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, ivalues, JNI_ABORT); + free(fvalues); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform2fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform2fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray2f(cgParamInfo->vParam, + 0, length, values); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray2f(cgParamInfo->fParam, + 0, length, values); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform3iArray + * Signature: (JJJI[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform3iArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jintArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + int i; + jint *ivalues; + float *fvalues; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + ivalues = (*env)->GetIntArrayElements(env, varray, NULL); + fvalues = malloc(length * sizeof(float)); + for (i = 0; i < 3 * length; i++) { + fvalues[i] = (float)ivalues[i]; + } + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray3f(cgParamInfo->vParam, + 0, length, fvalues); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray3f(cgParamInfo->fParam, + 0, length, fvalues); + } + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, ivalues, JNI_ABORT); + free(fvalues); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform3fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform3fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray3f(cgParamInfo->vParam, + 0, length, values); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray3f(cgParamInfo->fParam, + 0, length, values); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform4iArray + * Signature: (JJJI[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform4iArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jintArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + int i; + jint *ivalues; + float *fvalues; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + ivalues = (*env)->GetIntArrayElements(env, varray, NULL); + fvalues = malloc(length * sizeof(float)); + for (i = 0; i < 4 * length; i++) { + fvalues[i] = (float)ivalues[i]; + } + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray4f(cgParamInfo->vParam, + 0, length, fvalues); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray4f(cgParamInfo->fParam, + 0, length, fvalues); + } + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, ivalues, JNI_ABORT); + free(fvalues); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniform4fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniform4fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray4f(cgParamInfo->vParam, + 0, length, values); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetParameterArray4f(cgParamInfo->fParam, + 0, length, values); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniformMatrix3fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniformMatrix3fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetMatrixParameterArrayfr(cgParamInfo->vParam, + 0, length, values); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetMatrixParameterArrayfr(cgParamInfo->fParam, + 0, length, values); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setCgUniformMatrix4fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_setCgUniformMatrix4fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray varray) +{ + jobject shaderError = NULL; + +#ifdef COMPILE_CG_SHADERS + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgParameterInfo *cgParamInfo = (CgParameterInfo *)location; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + if (cgParamInfo->vParam != NULL) { + cgWrapperInfo->cgGLSetMatrixParameterArrayfr(cgParamInfo->vParam, + 0, length, values); + } + + if (cgParamInfo->fParam != NULL) { + cgWrapperInfo->cgGLSetMatrixParameterArrayfr(cgParamInfo->fParam, + 0, length, values); + } + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + +#else /* COMPILE_CG_SHADERS */ + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_UNSUPPORTED_LANGUAGE_ERROR, + "CgShaderProgram support not compiled", + NULL); + +#endif /* !COMPILE_CG_SHADERS */ + + return shaderError; +} + + +/* + * Cg vertex attribute functions + */ + +static void +cgVertexAttrPointer( + GraphicsContextPropertiesInfo *ctxProperties, + int index, int size, int type, int stride, + const void *pointer) +{ +#ifdef COMPILE_CG_SHADERS + + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgShaderProgramInfo *shaderProgramInfo = + (CgShaderProgramInfo *)ctxProperties->shaderProgramId; + +#ifdef VERBOSE + fprintf(stderr, "cgVertexAttrPointer()\n"); +#endif /* VERBOSE */ + + if (shaderProgramInfo != NULL && index < shaderProgramInfo->numVtxAttrs) { + cgWrapperInfo->cgGLSetParameterPointer(shaderProgramInfo->vtxAttrs[index], + size, + type, + stride, + pointer); + } +#ifdef VERBOSE + else { + if (shaderProgramInfo == NULL) { + fprintf(stderr, + " shaderProgramInfo is NULL\n"); + } else { + fprintf(stderr, + " index (%d) out of range; numVtxAttrs = %d\n", + index, shaderProgramInfo->numVtxAttrs); + } + } +#endif /* VERBOSE */ + +#endif /* COMPILE_CG_SHADERS */ +} + +static void +cgEnableVertexAttrArray( + GraphicsContextPropertiesInfo *ctxProperties, + int index) +{ +#ifdef COMPILE_CG_SHADERS + + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgShaderProgramInfo *shaderProgramInfo = + (CgShaderProgramInfo *)ctxProperties->shaderProgramId; + +#ifdef VERBOSE + fprintf(stderr, "cgEnableVertexAttrArray()\n"); +#endif /* VERBOSE */ + + if (shaderProgramInfo != NULL && index < shaderProgramInfo->numVtxAttrs) { + cgWrapperInfo->cgGLEnableClientState(shaderProgramInfo->vtxAttrs[index]); + } +#ifdef VERBOSE + else { + if (shaderProgramInfo == NULL) { + fprintf(stderr, + " shaderProgramInfo is NULL\n"); + } else { + fprintf(stderr, + " index (%d) out of range; numVtxAttrs = %d\n", + index, shaderProgramInfo->numVtxAttrs); + } + } +#endif /* VERBOSE */ + +#endif /* COMPILE_CG_SHADERS */ +} + +static void +cgDisableVertexAttrArray( + GraphicsContextPropertiesInfo *ctxProperties, + int index) +{ +#ifdef COMPILE_CG_SHADERS + + CgCtxInfo *cgCtxInfo = ctxProperties->cgCtxInfo; + CgWrapperInfo *cgWrapperInfo = cgCtxInfo->cgWrapperInfo; + CgShaderProgramInfo *shaderProgramInfo = + (CgShaderProgramInfo *)ctxProperties->shaderProgramId; + +#ifdef VERBOSE + fprintf(stderr, "cgDisableVertexAttrArray()\n"); +#endif /* VERBOSE */ + + if (shaderProgramInfo != NULL && index < shaderProgramInfo->numVtxAttrs) { + cgWrapperInfo->cgGLDisableClientState(shaderProgramInfo->vtxAttrs[index]); + } +#ifdef VERBOSE + else { + if (shaderProgramInfo == NULL) { + fprintf(stderr, + " shaderProgramInfo is NULL\n"); + } else { + fprintf(stderr, + " index (%d) out of range; numVtxAttrs = %d\n", + index, shaderProgramInfo->numVtxAttrs); + } + } +#endif /* VERBOSE */ + +#endif /* COMPILE_CG_SHADERS */ +} + +static void +cgVertexAttr( + GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v) +{ + /* + * NOTE: we should never get here. This function is only called + * when building display lists for geometry arrays with vertex + * attributes, and such display lists are disabled in Cg mode. + */ + fprintf(stderr, + "Java 3D ERROR : Assertion failed: invalid call to cgVertexAttr*f\n"); +} diff --git a/j3d-core/src/native/ogl/CgWrapper.c b/j3d-core/src/native/ogl/CgWrapper.c new file mode 100644 index 0000000..bf7f5db --- /dev/null +++ b/j3d-core/src/native/ogl/CgWrapper.c @@ -0,0 +1,86 @@ +/* + * $RCSfile: CgWrapper.c,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:17:59 $ + * $State: Exp $ + */ + +/* + * Note: since this is just a wrapper around the CG functions, it + * won't be compiled or linked unless the CG library is + * available. This means we don't need to use "#ifdef COMPILE_CG". + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include +#include + +#include "gldefs.h" +#include "CgWrapper.h" + +/* + * Setup the function pointers + */ +JNIEXPORT void +j3dLoadCgFunctionPointers(CgWrapperInfo *cgWrapperInfo) +{ + cgWrapperInfo->cgCreateContext = &cgCreateContext; + cgWrapperInfo->cgGLIsProfileSupported = &cgGLIsProfileSupported; + cgWrapperInfo->cgGetError = &cgGetError; + cgWrapperInfo->cgGetErrorString = &cgGetErrorString; + cgWrapperInfo->cgGetLastListing = &cgGetLastListing; + cgWrapperInfo->cgCreateProgram = &cgCreateProgram; + cgWrapperInfo->cgDestroyProgram = &cgDestroyProgram; + cgWrapperInfo->cgGLLoadProgram = &cgGLLoadProgram; + cgWrapperInfo->cgGLBindProgram = &cgGLBindProgram; + cgWrapperInfo->cgGLUnbindProgram = &cgGLUnbindProgram; + cgWrapperInfo->cgGLEnableProfile = &cgGLEnableProfile; + cgWrapperInfo->cgGLDisableProfile = &cgGLDisableProfile; + cgWrapperInfo->cgGetNamedParameter = &cgGetNamedParameter; + cgWrapperInfo->cgGetParameterType = &cgGetParameterType; + cgWrapperInfo->cgGetArrayDimension = &cgGetArrayDimension; + cgWrapperInfo->cgGetArrayType = &cgGetArrayType; + cgWrapperInfo->cgGetArraySize = &cgGetArraySize; + cgWrapperInfo->cgGetArrayParameter = &cgGetArrayParameter; + cgWrapperInfo->cgGLSetParameter1f = &cgGLSetParameter1f; + cgWrapperInfo->cgGLSetParameter2f = &cgGLSetParameter2f; + cgWrapperInfo->cgGLSetParameter3f = &cgGLSetParameter3f; + cgWrapperInfo->cgGLSetParameter4f = &cgGLSetParameter4f; + cgWrapperInfo->cgGLSetParameterArray1f = &cgGLSetParameterArray1f; + cgWrapperInfo->cgGLSetParameterArray2f = &cgGLSetParameterArray2f; + cgWrapperInfo->cgGLSetParameterArray3f = &cgGLSetParameterArray3f; + cgWrapperInfo->cgGLSetParameterArray4f = &cgGLSetParameterArray4f; + cgWrapperInfo->cgGLSetMatrixParameterfr = &cgGLSetMatrixParameterfr; + cgWrapperInfo->cgGLSetMatrixParameterArrayfr = &cgGLSetMatrixParameterArrayfr; + cgWrapperInfo->cgGLSetParameterPointer = &cgGLSetParameterPointer; + cgWrapperInfo->cgGLEnableClientState = &cgGLEnableClientState; + cgWrapperInfo->cgGLDisableClientState = &cgGLDisableClientState; + + return; +} diff --git a/j3d-core/src/native/ogl/CgWrapper.h b/j3d-core/src/native/ogl/CgWrapper.h new file mode 100644 index 0000000..ae21ea0 --- /dev/null +++ b/j3d-core/src/native/ogl/CgWrapper.h @@ -0,0 +1,211 @@ +/* + * $RCSfile: CgWrapper.h,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.7 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +#ifndef _Java3D_CgWrapper_h_ +#define _Java3D_CgWrapper_h_ + +#include "gldefs.h" + +#ifdef COMPILE_CG_SHADERS +#include +#endif /* COMPILE_CG_SHADERS */ + + +/* Forward references for structure typedefs */ +typedef struct CgWrapperInfoRec CgWrapperInfo; +typedef struct CgShaderInfoRec CgShaderInfo; +typedef struct CgShaderProgramInfoRec CgShaderProgramInfo; +typedef struct CgParameterInfoRec CgParameterInfo; + + +/* Typedef for function pointer to entry point in CgWrapper library */ +typedef void (*PFNJ3DLOADCGFUNCTIONPOINTERS)(CgWrapperInfo *); + + +#ifdef COMPILE_CG_SHADERS +typedef CGcontext (*PFNCGCREATECONTEXT)(void); +typedef CGbool (*PFNCGGLISPROFILESUPPORTED)(CGprofile); +typedef CGerror (*PFNCGGETERROR)(void); +typedef const char * (*PFNCGGETERRORSTRING)(CGerror); +typedef const char * (*PFNCGGETLASTLISTING)(CGcontext); +typedef CGprogram (*PFNCGCREATEPROGRAM)(CGcontext, CGenum, const char *, + CGprofile, const char *, const char **); +typedef void (*PFNCGDESTROYPROGRAM)(CGprogram program); +typedef void (*PFNCGGLLOADPROGRAM)(CGprogram); +typedef void (*PFNCGGLBINDPROGRAM)(CGprogram); +typedef void (*PFNCGGLUNBINDPROGRAM)(CGprofile); +typedef void (*PFNCGGLENABLEPROFILE)(CGprofile); +typedef void (*PFNCGGLDISABLEPROFILE)(CGprofile); +typedef CGparameter (*PFNCGGETNAMEDPARAMETER)(CGprogram, const char *); +typedef CGtype (*PFNCGGETPARAMETERTYPE)(CGparameter); +typedef int (*PFNCGGETARRAYDIMENSION)(CGparameter); +typedef CGtype (*PFNCGGETARRAYTYPE)(CGparameter); +typedef int (*PFNCGGETARRAYSIZE)(CGparameter, int); +typedef CGparameter (*PFNCGGETARRAYPARAMETER)(CGparameter, int); +typedef void (*PFNCGGLSETPARAMETER1F)(CGparameter, float); +typedef void (*PFNCGGLSETPARAMETER2F)(CGparameter, float, float); +typedef void (*PFNCGGLSETPARAMETER3F)(CGparameter, float, float, float); +typedef void (*PFNCGGLSETPARAMETER4F)(CGparameter, float, float, float, float); +typedef void (*PFNCGGLSETPARAMETERARRAY1F)(CGparameter, long, long, const float *); +typedef void (*PFNCGGLSETPARAMETERARRAY2F)(CGparameter, long, long, const float *); +typedef void (*PFNCGGLSETPARAMETERARRAY3F)(CGparameter, long, long, const float *); +typedef void (*PFNCGGLSETPARAMETERARRAY4F)(CGparameter, long, long, const float *); +typedef void (*PFNCGGLSETMATRIXPARAMETERFR)(CGparameter, const float *); +typedef void (*PFNCGGLSETMATRIXPARAMETERARRAYFR)(CGparameter, long, long, const float *); +typedef void (*PFNCGGLSETPARAMETERPOINTER)(CGparameter, GLint, GLenum, + GLsizei, const GLvoid *); +typedef void (*PFNCGGLENABLECLIENTSTATE)(CGparameter); +typedef void (*PFNCGGLDISABLECLIENTSTATE)(CGparameter); + +#endif /* COMPILE_CG_SHADERS */ + + +/* + * Global struct that contains the reference to the CG wrapper library + * and the function pointers to each wrapper function. This is a + * singleton (only one instance exists), and is initialized by a + * static MasterControl method. For performance, we will cache the + * pointer to this global struct in each context. + */ +struct CgWrapperInfoRec { + /* + * Flag indicating whether the library and all function pointers + * were successfully loaded. + */ + jboolean loaded; + + /* + * Pointer to library, returned by dlopen (UNIX) or LoadLibrary (Windows) + */ + void *cgLibraryHandle; + + /* Function pointer to entry point in CgWrapper library */ + PFNJ3DLOADCGFUNCTIONPOINTERS j3dLoadCgFunctionPointers; + + /* Function pointers for warapper functions */ +#ifdef COMPILE_CG_SHADERS + + /* CG function pointers */ + PFNCGCREATECONTEXT cgCreateContext; + PFNCGGLISPROFILESUPPORTED cgGLIsProfileSupported; + PFNCGGETERROR cgGetError; + PFNCGGETERRORSTRING cgGetErrorString; + PFNCGGETLASTLISTING cgGetLastListing; + PFNCGCREATEPROGRAM cgCreateProgram; + PFNCGDESTROYPROGRAM cgDestroyProgram; + PFNCGGLLOADPROGRAM cgGLLoadProgram; + PFNCGGLBINDPROGRAM cgGLBindProgram; + PFNCGGLUNBINDPROGRAM cgGLUnbindProgram; + PFNCGGLENABLEPROFILE cgGLEnableProfile; + PFNCGGLDISABLEPROFILE cgGLDisableProfile; + PFNCGGETNAMEDPARAMETER cgGetNamedParameter; + PFNCGGETPARAMETERTYPE cgGetParameterType; + PFNCGGETARRAYDIMENSION cgGetArrayDimension; + PFNCGGETARRAYTYPE cgGetArrayType; + PFNCGGETARRAYSIZE cgGetArraySize; + PFNCGGETARRAYPARAMETER cgGetArrayParameter; + PFNCGGLSETPARAMETER1F cgGLSetParameter1f; + PFNCGGLSETPARAMETER2F cgGLSetParameter2f; + PFNCGGLSETPARAMETER3F cgGLSetParameter3f; + PFNCGGLSETPARAMETER4F cgGLSetParameter4f; + PFNCGGLSETPARAMETERARRAY1F cgGLSetParameterArray1f; + PFNCGGLSETPARAMETERARRAY2F cgGLSetParameterArray2f; + PFNCGGLSETPARAMETERARRAY3F cgGLSetParameterArray3f; + PFNCGGLSETPARAMETERARRAY4F cgGLSetParameterArray4f; + PFNCGGLSETMATRIXPARAMETERFR cgGLSetMatrixParameterfr; + PFNCGGLSETMATRIXPARAMETERARRAYFR cgGLSetMatrixParameterArrayfr; + PFNCGGLSETPARAMETERPOINTER cgGLSetParameterPointer; + PFNCGGLENABLECLIENTSTATE cgGLEnableClientState; + PFNCGGLDISABLECLIENTSTATE cgGLDisableClientState; + +#endif /* COMPILE_CG_SHADERS */ +}; + + +/* Structure used to hold CG context information; stored in ctxInfo */ +struct CgCtxInfoRec { + CgWrapperInfo *cgWrapperInfo; /* Pointer to static wrapper info */ + +#ifdef COMPILE_CG_SHADERS + CGcontext cgCtx; + CGprofile vProfile; + CGprofile fProfile; +#endif /* COMPILE_CG_SHADERS */ +}; + + +/* Structure used to hold CG shader information; passed back to Java as cgShaderId */ +struct CgShaderInfoRec { +#ifdef COMPILE_CG_SHADERS + CGprogram cgShader; + jint shaderType; + CGprofile shaderProfile; +#else /* COMPILE_CG_SHADERS */ + int dummy; +#endif /* COMPILE_CG_SHADERS */ +}; + +/* + * Structure used to hold CG shader program information; passed back + * to Java as cgShaderProgramId + */ +struct CgShaderProgramInfoRec { +#ifdef COMPILE_CG_SHADERS + /* + * Vertex and fragment shader -- may be null to indicate that one + * or the other is not present + */ + CgShaderInfo *vShader; /* Vertex shader */ + CgShaderInfo *fShader; /* Fragment shader */ + + /* Array of parameters for (varying) vertex attributes */ + int numVtxAttrs; + CGparameter *vtxAttrs; +#else /* COMPILE_CG_SHADERS */ + int dummy; +#endif /* COMPILE_CG_SHADERS */ +}; + +/* + * Structure used to hold CG shader parameter information for uniform + * shader attributes; passed back to Java in the locArr array + */ +struct CgParameterInfoRec { +#ifdef COMPILE_CG_SHADERS + CGparameter vParam; /* Parameter handle for vertex shader */ + CGparameter fParam; /* Parameter handle for fragment shader */ +#else /* COMPILE_CG_SHADERS */ + int dummy; +#endif /* COMPILE_CG_SHADERS */ +}; + + +#endif /* _Java3D_CgWrapper_h_ */ diff --git a/j3d-core/src/native/ogl/DrawingSurfaceObjectAWT.c b/j3d-core/src/native/ogl/DrawingSurfaceObjectAWT.c new file mode 100644 index 0000000..a744e24 --- /dev/null +++ b/j3d-core/src/native/ogl/DrawingSurfaceObjectAWT.c @@ -0,0 +1,290 @@ +/* + * $RCSfile: DrawingSurfaceObjectAWT.c,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +#include +#include +#include +#include +#include +#include + +#include "javax_media_j3d_NativePipeline.h" +#include "javax_media_j3d_DrawingSurfaceObjectAWT.h" + +#ifdef DEBUG +/* Uncomment the following for VERBOSE debug messages */ +/* #define VERBOSE */ +#endif /* DEBUG */ + + +#if defined(SOLARIS) && defined(__sparc) +#pragma weak XDgaGetXineramaInfo + +/* + * The following include file contains the definitions of unsupported, + * undocumented data structures and functions used to implement Xinerama. + * They are also used by the Solaris implementations of OpenGL and AWT. This + * is an interim solution until they are made part of the X Window System + * standard or replaced with a fully supported API. + */ +#include "panoramiXext.h" +#endif /* SOLARIS && __sparc */ + + +JNIEXPORT jlong JNICALL +Java_javax_media_j3d_NativePipeline_getAWT( + JNIEnv *env, jobject obj) +{ + JAWT *awt; + + awt = (JAWT*) malloc(sizeof(JAWT)); + if (awt == NULL) { + fprintf(stderr, "malloc failed\n"); + return 0; + } + + awt->version = JAWT_VERSION_1_4; + + if (JAWT_GetAWT(env, awt) == JNI_FALSE) { + fprintf(stderr, "AWT not found\n"); + return 0; + } + + return (jlong)awt; +} + +JNIEXPORT +jlong JNICALL +Java_javax_media_j3d_DrawingSurfaceObjectAWT_getDrawingSurfaceAWT( + JNIEnv *env, + jobject obj, + jobject canvas, + jlong awtObj) +{ + JAWT *awt = (JAWT*) awtObj; + JAWT_DrawingSurface *ds; + + ds = awt->GetDrawingSurface(env, canvas); + if (ds == NULL) { + fprintf(stderr, "NULL drawing surface\n"); + return 0; + } + return (jlong)ds; +} + + +JNIEXPORT +jint JNICALL +Java_javax_media_j3d_DrawingSurfaceObjectAWT_getDrawingSurfaceWindowIdAWT( + JNIEnv *env, + jobject obj, + jobject canvas, + jlong dsObj, + jlong dsiObj, + jlong display, + jint screen, + jboolean xineramaDisabled) +{ + JAWT_DrawingSurface *ds = (JAWT_DrawingSurface*) dsObj; + JAWT_DrawingSurfaceInfo *dsi = (JAWT_DrawingSurfaceInfo *) dsiObj; + jint window; + +#ifdef WIN32 + JAWT_Win32DrawingSurfaceInfo *wds = + (JAWT_Win32DrawingSurfaceInfo*) dsi->platformInfo; + window = (jint)wds->hdc; +#endif /* WIN32 */ + +#ifdef SOLARIS + JAWT_X11DrawingSurfaceInfo *xds = + (JAWT_X11DrawingSurfaceInfo*) dsi->platformInfo; + window = (jint)xds->drawable; + +#ifdef __sparc + if (xineramaDisabled) { + XineramaInfo xineramaInfo; + +#ifdef VERBOSE + fprintf(stderr, "getDrawingSurfaceWindowIdAWT: Xinerama disabled\n"); +#endif /* VERBOSE */ + + /* + * The existence of the weak symbol XDgaGetXineramaInfo is checked in + * the native MasterControl.initializeJ3D(); execution will not get + * here if it is unbound. + */ + if (XDgaGetXineramaInfo((Display *)display, + xds->drawable, &xineramaInfo)) { + + /* return Xinerama subwid instead of primary Xinerama wid */ + window = (jint)xineramaInfo.subs[screen].wid; + +#ifdef VERBOSE + fprintf(stderr, + " subwid for display %d screen %d window %d: %d\n", + (Display *)display, screen, xds->drawable, window); +#endif /* VERBOSE */ + } + else { + window = (jint)xds->drawable; + fprintf(stderr, "Get Xinerama subwid, screen %d failed\n", screen); + } + } +#endif /* __sparc */ +#endif /* SOLARIS */ + +#ifdef LINUX + JAWT_X11DrawingSurfaceInfo *xds = + (JAWT_X11DrawingSurfaceInfo*) dsi->platformInfo; + window = (jint)xds->drawable; +#endif /* LINUX */ + + /* + * Don't free DrawingSurfaceInfo here, otherwise + * HDC will free in windows JDK1.4 and window + * is invalid. + */ + ds->env = env; + ds->Unlock(ds); + + return window; +} + + + +JNIEXPORT +jlong JNICALL +Java_javax_media_j3d_DrawingSurfaceObjectAWT_getDrawingSurfaceInfo( + JNIEnv *env, + jobject obj, + jlong dsObj) +{ + JAWT_DrawingSurface *ds = (JAWT_DrawingSurface*) dsObj; + JAWT_DrawingSurfaceInfo *dsi; + jint lock; + + ds->env = env; + lock = ds->Lock(ds); + if ((lock & JAWT_LOCK_ERROR) != 0) { + fprintf(stderr, "Error locking surface\n"); + return 0; + } + + dsi = ds->GetDrawingSurfaceInfo(ds); + + if (dsi == NULL) { + fprintf(stderr, "Error GetDrawingSurfaceInfo\n"); + ds->Unlock(ds); + return 0; + } + return (jlong)dsi; +} + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_DrawingSurfaceObjectAWT_lockAWT( + JNIEnv *env, + jobject obj, + jlong drawingSurface) +{ + JAWT_DrawingSurface *ds = (JAWT_DrawingSurface*)drawingSurface; + jint lock; + + ds->env = env; + lock = ds->Lock(ds); + + if ((lock & JAWT_LOCK_ERROR) != 0) { + return JNI_FALSE; + } else if ((lock & JAWT_LOCK_SURFACE_CHANGED) != 0) { + ds->Unlock(ds); + return JNI_FALSE; + } else { + return JNI_TRUE; + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_DrawingSurfaceObjectAWT_unlockAWT( + JNIEnv *env, + jobject obj, + jlong drawingSurface) +{ + JAWT_DrawingSurface *ds = (JAWT_DrawingSurface*)drawingSurface; + ds->env = env; + ds->Unlock(ds); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_DrawingSurfaceObjectAWT_lockGlobal( + JNIEnv *env, + jclass obj, + jlong awt) +{ + ((JAWT *) awt)->Lock(env); +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_DrawingSurfaceObjectAWT_unlockGlobal( + JNIEnv *env, + jclass obj, + jlong awt) +{ + ((JAWT *) awt)->Unlock(env); +} + + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_DrawingSurfaceObjectAWT_freeResource( + JNIEnv *env, + jclass obj, + jlong awtObj, + jlong drawingSurface, + jlong drawingSurfaceInfo) +{ + JAWT *awt = (JAWT*) awtObj; + JAWT_DrawingSurface *ds = (JAWT_DrawingSurface*)drawingSurface; + JAWT_DrawingSurfaceInfo *dsi = (JAWT_DrawingSurfaceInfo *) drawingSurfaceInfo; + + ds->env = env; + ds->FreeDrawingSurfaceInfo(dsi); + awt->FreeDrawingSurface(ds); +} + + + diff --git a/j3d-core/src/native/ogl/GLSLInfo.h b/j3d-core/src/native/ogl/GLSLInfo.h new file mode 100644 index 0000000..c5fc960 --- /dev/null +++ b/j3d-core/src/native/ogl/GLSLInfo.h @@ -0,0 +1,82 @@ +/* + * $RCSfile: GLSLInfo.h,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +#ifndef _Java3D_GLSLInfo_h_ +#define _Java3D_GLSLInfo_h_ + +#include "gldefs.h" + +/* Structure used to hold GLSL context information; stored in ctxInfo */ +struct GLSLCtxInfoRec { + int vertexAttrOffset; + + PFNGLATTACHOBJECTARBPROC pfnglAttachObjectARB; + PFNGLCOMPILESHADERARBPROC pfnglCompileShaderARB; + PFNGLCREATEPROGRAMOBJECTARBPROC pfnglCreateProgramObjectARB; + PFNGLCREATESHADEROBJECTARBPROC pfnglCreateShaderObjectARB; + PFNGLDELETEOBJECTARBPROC pfnglglDeleteObjectARB; + PFNGLGETINFOLOGARBPROC pfnglGetInfoLogARB; + PFNGLGETOBJECTPARAMETERIVARBPROC pfnglGetObjectParameterivARB; + PFNGLLINKPROGRAMARBPROC pfnglLinkProgramARB; + PFNGLSHADERSOURCEARBPROC pfnglShaderSourceARB; + PFNGLUSEPROGRAMOBJECTARBPROC pfnglUseProgramObjectARB; + PFNGLGETUNIFORMLOCATIONARBPROC pfnglGetUniformLocationARB; + PFNGLGETATTRIBLOCATIONARBPROC pfnglGetAttribLocationARB; + PFNGLBINDATTRIBLOCATIONARBPROC pfnglBindAttribLocationARB; + PFNGLVERTEXATTRIB1FVARBPROC pfnglVertexAttrib1fvARB; + PFNGLVERTEXATTRIB2FVARBPROC pfnglVertexAttrib2fvARB; + PFNGLVERTEXATTRIB3FVARBPROC pfnglVertexAttrib3fvARB; + PFNGLVERTEXATTRIB4FVARBPROC pfnglVertexAttrib4fvARB; + PFNGLVERTEXATTRIBPOINTERARBPROC pfnglVertexAttribPointerARB; + PFNGLENABLEVERTEXATTRIBARRAYARBPROC pfnglEnableVertexAttribArrayARB; + PFNGLDISABLEVERTEXATTRIBARRAYARBPROC pfnglDisableVertexAttribArrayARB; + PFNGLGETACTIVEUNIFORMARBPROC pfnglGetActiveUniformARB; + PFNGLUNIFORM1IARBPROC pfnglUniform1iARB; + PFNGLUNIFORM1FARBPROC pfnglUniform1fARB; + PFNGLUNIFORM2IARBPROC pfnglUniform2iARB; + PFNGLUNIFORM2FARBPROC pfnglUniform2fARB; + PFNGLUNIFORM3IARBPROC pfnglUniform3iARB; + PFNGLUNIFORM3FARBPROC pfnglUniform3fARB; + PFNGLUNIFORM4IARBPROC pfnglUniform4iARB; + PFNGLUNIFORM4FARBPROC pfnglUniform4fARB; + PFNGLUNIFORM1IVARBPROC pfnglUniform1ivARB; + PFNGLUNIFORM1FVARBPROC pfnglUniform1fvARB; + PFNGLUNIFORM2IVARBPROC pfnglUniform2ivARB; + PFNGLUNIFORM2FVARBPROC pfnglUniform2fvARB; + PFNGLUNIFORM3IVARBPROC pfnglUniform3ivARB; + PFNGLUNIFORM3FVARBPROC pfnglUniform3fvARB; + PFNGLUNIFORM4IVARBPROC pfnglUniform4ivARB; + PFNGLUNIFORM4FVARBPROC pfnglUniform4fvARB; + PFNGLUNIFORMMATRIX3FVARBPROC pfnglUniformMatrix3fvARB; + PFNGLUNIFORMMATRIX4FVARBPROC pfnglUniformMatrix4fvARB; +}; + +#endif /* _Java3D_GLSLInfo_h_ */ diff --git a/j3d-core/src/native/ogl/GLSLShaderProgram.c b/j3d-core/src/native/ogl/GLSLShaderProgram.c new file mode 100644 index 0000000..e317fb0 --- /dev/null +++ b/j3d-core/src/native/ogl/GLSLShaderProgram.c @@ -0,0 +1,1677 @@ +/* + * $RCSfile: GLSLShaderProgram.c,v $ + * + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.11 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include +#include +#include +#include +#include + +#include "gldefs.h" +#include "GLSLInfo.h" + +#if defined(UNIX) +#include +#endif + +#ifdef DEBUG +/* Uncomment the following for VERBOSE debug messages */ +/* #define VERBOSE */ +#endif /* DEBUG */ + + +extern jint getJavaIntEnv(JNIEnv *env, char* envStr); +extern char *strJavaToC(JNIEnv *env, jstring str); +extern void throwAssert(JNIEnv *env, char *str); +extern jobject createShaderError(JNIEnv *env, + int errorCode, + const char *errorMsg, + const char *detailMsg); + +extern int isExtensionSupported(const char *allExtensions, const char *extension); + + +static void glslVertexAttrPointer(GraphicsContextPropertiesInfo *ctxProperties, + int index, int size, int type, int stride, + const void *pointer); +static void glslEnableVertexAttrArray(GraphicsContextPropertiesInfo *ctxProperties, + int index); +static void glslDisableVertexAttrArray(GraphicsContextPropertiesInfo *ctxProperties, + int index); +static void glslVertexAttr1fv(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); +static void glslVertexAttr2fv(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); +static void glslVertexAttr3fv(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); +static void glslVertexAttr4fv(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); + + +/* + * Called by getPropertiesFromCurrentContext to initialize the GLSL + * shader function pointers and set the flag indicating whether GLSL + * shaders are available. + */ +void +checkGLSLShaderExtensions( + JNIEnv *env, + jobject obj, + char *tmpExtensionStr, + GraphicsContextPropertiesInfo *ctxInfo, + jboolean glslLibraryAvailable) +{ + ctxInfo->shadingLanguageGLSL = JNI_FALSE; + ctxInfo->glslCtxInfo = NULL; + + if (glslLibraryAvailable && + isExtensionSupported(tmpExtensionStr, "GL_ARB_shader_objects") && + isExtensionSupported(tmpExtensionStr, "GL_ARB_shading_language_100")) { + + GLSLCtxInfo *glslCtxInfo = (GLSLCtxInfo *)malloc(sizeof(GLSLCtxInfo)); + memset(glslCtxInfo, 0, sizeof(GLSLCtxInfo)); + +#if defined(UNIX) + glslCtxInfo->pfnglAttachObjectARB = + (PFNGLATTACHOBJECTARBPROC)dlsym(RTLD_DEFAULT, "glAttachObjectARB"); + glslCtxInfo->pfnglCompileShaderARB = + (PFNGLCOMPILESHADERARBPROC)dlsym(RTLD_DEFAULT, "glCompileShaderARB"); + glslCtxInfo->pfnglCreateProgramObjectARB = + (PFNGLCREATEPROGRAMOBJECTARBPROC)dlsym(RTLD_DEFAULT, "glCreateProgramObjectARB"); + glslCtxInfo->pfnglCreateShaderObjectARB = + (PFNGLCREATESHADEROBJECTARBPROC)dlsym(RTLD_DEFAULT, "glCreateShaderObjectARB"); + glslCtxInfo->pfnglglDeleteObjectARB = + (PFNGLDELETEOBJECTARBPROC)dlsym(RTLD_DEFAULT, "glDeleteObjectARB"); + glslCtxInfo->pfnglGetInfoLogARB = + (PFNGLGETINFOLOGARBPROC)dlsym(RTLD_DEFAULT, "glGetInfoLogARB"); + glslCtxInfo->pfnglGetObjectParameterivARB = + (PFNGLGETOBJECTPARAMETERIVARBPROC)dlsym(RTLD_DEFAULT, "glGetObjectParameterivARB"); + glslCtxInfo->pfnglLinkProgramARB = + (PFNGLLINKPROGRAMARBPROC)dlsym(RTLD_DEFAULT, "glLinkProgramARB"); + glslCtxInfo->pfnglShaderSourceARB = + (PFNGLSHADERSOURCEARBPROC)dlsym(RTLD_DEFAULT, "glShaderSourceARB"); + glslCtxInfo->pfnglUseProgramObjectARB = + (PFNGLUSEPROGRAMOBJECTARBPROC)dlsym(RTLD_DEFAULT, "glUseProgramObjectARB"); + glslCtxInfo->pfnglGetUniformLocationARB = + (PFNGLGETUNIFORMLOCATIONARBPROC)dlsym(RTLD_DEFAULT, "glGetUniformLocationARB"); + glslCtxInfo->pfnglGetAttribLocationARB = + (PFNGLGETATTRIBLOCATIONARBPROC)dlsym(RTLD_DEFAULT, "glGetAttribLocationARB"); + glslCtxInfo->pfnglBindAttribLocationARB = + (PFNGLBINDATTRIBLOCATIONARBPROC)dlsym(RTLD_DEFAULT, "glBindAttribLocationARB"); + glslCtxInfo->pfnglVertexAttrib1fvARB = + (PFNGLVERTEXATTRIB1FVARBPROC)dlsym(RTLD_DEFAULT, "glVertexAttrib1fvARB"); + glslCtxInfo->pfnglVertexAttrib2fvARB = + (PFNGLVERTEXATTRIB2FVARBPROC)dlsym(RTLD_DEFAULT, "glVertexAttrib2fvARB"); + glslCtxInfo->pfnglVertexAttrib3fvARB = + (PFNGLVERTEXATTRIB3FVARBPROC)dlsym(RTLD_DEFAULT, "glVertexAttrib3fvARB"); + glslCtxInfo->pfnglVertexAttrib4fvARB = + (PFNGLVERTEXATTRIB4FVARBPROC)dlsym(RTLD_DEFAULT, "glVertexAttrib4fvARB"); + glslCtxInfo->pfnglVertexAttribPointerARB = + (PFNGLVERTEXATTRIBPOINTERARBPROC)dlsym(RTLD_DEFAULT, "glVertexAttribPointerARB"); + glslCtxInfo->pfnglEnableVertexAttribArrayARB = + (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)dlsym(RTLD_DEFAULT, "glEnableVertexAttribArrayARB"); + glslCtxInfo->pfnglDisableVertexAttribArrayARB = + (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)dlsym(RTLD_DEFAULT, "glDisableVertexAttribArrayARB"); + glslCtxInfo->pfnglVertexAttribPointerARB = + (PFNGLVERTEXATTRIBPOINTERARBPROC)dlsym(RTLD_DEFAULT, "glVertexAttribPointerARB"); + glslCtxInfo->pfnglGetActiveUniformARB = + (PFNGLGETACTIVEUNIFORMARBPROC)dlsym(RTLD_DEFAULT, "glGetActiveUniformARB"); + glslCtxInfo->pfnglUniform1iARB = + (PFNGLUNIFORM1IARBPROC)dlsym(RTLD_DEFAULT, "glUniform1iARB"); + glslCtxInfo->pfnglUniform1fARB = + (PFNGLUNIFORM1FARBPROC)dlsym(RTLD_DEFAULT, "glUniform1fARB"); + glslCtxInfo->pfnglUniform2iARB = + (PFNGLUNIFORM2IARBPROC)dlsym(RTLD_DEFAULT, "glUniform2iARB"); + glslCtxInfo->pfnglUniform2fARB = + (PFNGLUNIFORM2FARBPROC)dlsym(RTLD_DEFAULT, "glUniform2fARB"); + glslCtxInfo->pfnglUniform3iARB = + (PFNGLUNIFORM3IARBPROC)dlsym(RTLD_DEFAULT, "glUniform3iARB"); + glslCtxInfo->pfnglUniform3fARB = + (PFNGLUNIFORM3FARBPROC)dlsym(RTLD_DEFAULT, "glUniform3fARB"); + glslCtxInfo->pfnglUniform4iARB = + (PFNGLUNIFORM4IARBPROC)dlsym(RTLD_DEFAULT, "glUniform4iARB"); + glslCtxInfo->pfnglUniform4fARB = + (PFNGLUNIFORM4FARBPROC)dlsym(RTLD_DEFAULT, "glUniform4fARB"); + glslCtxInfo->pfnglUniform1ivARB = + (PFNGLUNIFORM1IVARBPROC)dlsym(RTLD_DEFAULT, "glUniform1ivARB"); + glslCtxInfo->pfnglUniform1fvARB = + (PFNGLUNIFORM1FVARBPROC)dlsym(RTLD_DEFAULT, "glUniform1fvARB"); + glslCtxInfo->pfnglUniform2ivARB = + (PFNGLUNIFORM2IVARBPROC)dlsym(RTLD_DEFAULT, "glUniform2ivARB"); + glslCtxInfo->pfnglUniform2fvARB = + (PFNGLUNIFORM2FVARBPROC)dlsym(RTLD_DEFAULT, "glUniform2fvARB"); + glslCtxInfo->pfnglUniform3ivARB = + (PFNGLUNIFORM3IVARBPROC)dlsym(RTLD_DEFAULT, "glUniform3ivARB"); + glslCtxInfo->pfnglUniform3fvARB = + (PFNGLUNIFORM3FVARBPROC)dlsym(RTLD_DEFAULT, "glUniform3fvARB"); + glslCtxInfo->pfnglUniform4ivARB = + (PFNGLUNIFORM4IVARBPROC)dlsym(RTLD_DEFAULT, "glUniform4ivARB"); + glslCtxInfo->pfnglUniform4fvARB = + (PFNGLUNIFORM4FVARBPROC)dlsym(RTLD_DEFAULT, "glUniform4fvARB"); + glslCtxInfo->pfnglUniformMatrix3fvARB = + (PFNGLUNIFORMMATRIX3FVARBPROC)dlsym(RTLD_DEFAULT, "glUniformMatrix3fvARB"); + glslCtxInfo->pfnglUniformMatrix4fvARB = + (PFNGLUNIFORMMATRIX4FVARBPROC)dlsym(RTLD_DEFAULT, "glUniformMatrix4fvARB"); +#endif +#ifdef WIN32 + glslCtxInfo->pfnglAttachObjectARB = + (PFNGLATTACHOBJECTARBPROC)wglGetProcAddress("glAttachObjectARB"); + glslCtxInfo->pfnglCompileShaderARB = + (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB"); + glslCtxInfo->pfnglCreateProgramObjectARB = + (PFNGLCREATEPROGRAMOBJECTARBPROC)wglGetProcAddress("glCreateProgramObjectARB"); + glslCtxInfo->pfnglCreateShaderObjectARB = + (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB"); + glslCtxInfo->pfnglglDeleteObjectARB = + (PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB"); + glslCtxInfo->pfnglGetInfoLogARB = + (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB"); + glslCtxInfo->pfnglGetObjectParameterivARB = + (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB"); + glslCtxInfo->pfnglLinkProgramARB = + (PFNGLLINKPROGRAMARBPROC)wglGetProcAddress("glLinkProgramARB"); + glslCtxInfo->pfnglShaderSourceARB = + (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB"); + glslCtxInfo->pfnglUseProgramObjectARB = + (PFNGLUSEPROGRAMOBJECTARBPROC)wglGetProcAddress("glUseProgramObjectARB"); + glslCtxInfo->pfnglGetUniformLocationARB = + (PFNGLGETUNIFORMLOCATIONARBPROC)wglGetProcAddress("glGetUniformLocationARB"); + glslCtxInfo->pfnglGetAttribLocationARB = + (PFNGLGETATTRIBLOCATIONARBPROC)wglGetProcAddress("glGetAttribLocationARB"); + glslCtxInfo->pfnglBindAttribLocationARB = + (PFNGLBINDATTRIBLOCATIONARBPROC)wglGetProcAddress("glBindAttribLocationARB"); + glslCtxInfo->pfnglVertexAttrib1fvARB = + (PFNGLVERTEXATTRIB1FVARBPROC)wglGetProcAddress("glVertexAttrib1fvARB"); + glslCtxInfo->pfnglVertexAttrib2fvARB = + (PFNGLVERTEXATTRIB2FVARBPROC)wglGetProcAddress("glVertexAttrib2fvARB"); + glslCtxInfo->pfnglVertexAttrib3fvARB = + (PFNGLVERTEXATTRIB3FVARBPROC)wglGetProcAddress("glVertexAttrib3fvARB"); + glslCtxInfo->pfnglVertexAttrib4fvARB = + (PFNGLVERTEXATTRIB4FVARBPROC)wglGetProcAddress("glVertexAttrib4fvARB"); + glslCtxInfo->pfnglVertexAttribPointerARB = + (PFNGLVERTEXATTRIBPOINTERARBPROC)wglGetProcAddress("glVertexAttribPointerARB"); + glslCtxInfo->pfnglEnableVertexAttribArrayARB = + (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)wglGetProcAddress("glEnableVertexAttribArrayARB"); + glslCtxInfo->pfnglDisableVertexAttribArrayARB = + (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)wglGetProcAddress("glDisableVertexAttribArrayARB"); + glslCtxInfo->pfnglVertexAttribPointerARB = + (PFNGLVERTEXATTRIBPOINTERARBPROC)wglGetProcAddress("glVertexAttribPointerARB"); + glslCtxInfo->pfnglGetActiveUniformARB = + (PFNGLGETACTIVEUNIFORMARBPROC)wglGetProcAddress("glGetActiveUniformARB"); + glslCtxInfo->pfnglUniform1iARB = + (PFNGLUNIFORM1IARBPROC)wglGetProcAddress("glUniform1iARB"); + glslCtxInfo->pfnglUniform1fARB = + (PFNGLUNIFORM1FARBPROC)wglGetProcAddress("glUniform1fARB"); + glslCtxInfo->pfnglUniform2iARB = + (PFNGLUNIFORM2IARBPROC)wglGetProcAddress("glUniform2iARB"); + glslCtxInfo->pfnglUniform2fARB = + (PFNGLUNIFORM2FARBPROC)wglGetProcAddress("glUniform2fARB"); + glslCtxInfo->pfnglUniform3iARB = + (PFNGLUNIFORM3IARBPROC)wglGetProcAddress("glUniform3iARB"); + glslCtxInfo->pfnglUniform3fARB = + (PFNGLUNIFORM3FARBPROC)wglGetProcAddress("glUniform3fARB"); + glslCtxInfo->pfnglUniform4iARB = + (PFNGLUNIFORM4IARBPROC)wglGetProcAddress("glUniform4iARB"); + glslCtxInfo->pfnglUniform4fARB = + (PFNGLUNIFORM4FARBPROC)wglGetProcAddress("glUniform4fARB"); + glslCtxInfo->pfnglUniform1ivARB = + (PFNGLUNIFORM1IVARBPROC)wglGetProcAddress("glUniform1ivARB"); + glslCtxInfo->pfnglUniform1fvARB = + (PFNGLUNIFORM1FVARBPROC)wglGetProcAddress("glUniform1fvARB"); + glslCtxInfo->pfnglUniform2ivARB = + (PFNGLUNIFORM2IVARBPROC)wglGetProcAddress("glUniform2ivARB"); + glslCtxInfo->pfnglUniform2fvARB = + (PFNGLUNIFORM2FVARBPROC)wglGetProcAddress("glUniform2fvARB"); + glslCtxInfo->pfnglUniform3ivARB = + (PFNGLUNIFORM3IVARBPROC)wglGetProcAddress("glUniform3ivARB"); + glslCtxInfo->pfnglUniform3fvARB = + (PFNGLUNIFORM3FVARBPROC)wglGetProcAddress("glUniform3fvARB"); + glslCtxInfo->pfnglUniform4ivARB = + (PFNGLUNIFORM4IVARBPROC)wglGetProcAddress("glUniform4ivARB"); + glslCtxInfo->pfnglUniform4fvARB = + (PFNGLUNIFORM4FVARBPROC)wglGetProcAddress("glUniform4fvARB"); + glslCtxInfo->pfnglUniformMatrix3fvARB = + (PFNGLUNIFORMMATRIX3FVARBPROC)wglGetProcAddress("glUniformMatrix3fvARB"); + glslCtxInfo->pfnglUniformMatrix4fvARB = + (PFNGLUNIFORMMATRIX4FVARBPROC)wglGetProcAddress("glUniformMatrix4fvARB"); +#endif + + /* Initialize shader vertex attribute function pointers */ + ctxInfo->vertexAttrPointer = glslVertexAttrPointer; + ctxInfo->enableVertexAttrArray = glslEnableVertexAttrArray; + ctxInfo->disableVertexAttrArray = glslDisableVertexAttrArray; + ctxInfo->vertexAttr1fv = glslVertexAttr1fv; + ctxInfo->vertexAttr2fv = glslVertexAttr2fv; + ctxInfo->vertexAttr3fv = glslVertexAttr3fv; + ctxInfo->vertexAttr4fv = glslVertexAttr4fv; + + ctxInfo->maxTextureImageUnits = 0; + ctxInfo->maxVertexTextureImageUnits = 0; + ctxInfo->maxCombinedTextureImageUnits = 0; + + /* Initialize GLSL texture sampler limits */ + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &ctxInfo->maxTextureImageUnits); + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, &ctxInfo->maxVertexTextureImageUnits); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, &ctxInfo->maxCombinedTextureImageUnits); + + /* Initialize GLSL VertexAttr info */ + glslCtxInfo->vertexAttrOffset = getJavaIntEnv(env, "glslVertexAttrOffset"); + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &ctxInfo->maxVertexAttrs); + /* decr count to allow for reserved vertex attrs */ + ctxInfo->maxVertexAttrs -= glslCtxInfo->vertexAttrOffset; + if (ctxInfo->maxVertexAttrs < 0) { + ctxInfo->maxVertexAttrs = 0; + } + + if (glslCtxInfo->pfnglCreateShaderObjectARB != NULL) { + /*fprintf(stderr, "Java 3D : GLSLShader extension is available\n");*/ + ctxInfo->shadingLanguageGLSL = JNI_TRUE; + /* TODO: need to free ctxInfo->glslCtxInfo when ctxInfo is freed */ + ctxInfo->glslCtxInfo = glslCtxInfo; + } + else { + free(glslCtxInfo); + } + } +} + + +/* + * Return the info log as a string. This is used as the detail message + * for a ShaderError. + */ +static const char * +getInfoLog( + GraphicsContextPropertiesInfo* ctxProperties, + GLhandleARB obj) +{ + int infoLogLength = 0; + int len = 0; + GLcharARB *infoLog = NULL; + + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + static const char *allocMsg = + "Java 3D ERROR: could not allocate infoLog buffer\n"; + + glslCtxInfo->pfnglGetObjectParameterivARB(obj, + GL_OBJECT_INFO_LOG_LENGTH_ARB, + &infoLogLength); + if (infoLogLength > 0) { + infoLog = (GLcharARB *)malloc(infoLogLength); + if (infoLog == NULL) { + return allocMsg; + } + + glslCtxInfo->pfnglGetInfoLogARB(obj, infoLogLength, &len, infoLog); + } + + return infoLog; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: createGLSLShader + * Signature: (JI[J)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_createGLSLShader( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint shaderType, + jlongArray shaderIdArray) +{ + + jlong *shaderIdPtr; + GLhandleARB shaderHandle = 0; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + jobject shaderError = NULL; + + shaderIdPtr = (*env)->GetLongArrayElements(env, shaderIdArray, NULL); + + /* Process shader */ + /* + fprintf(stderr, " shaderType == %d\n", shaderType); + */ + if (shaderType == javax_media_j3d_Shader_SHADER_TYPE_VERTEX) { + /* create the vertex shader */ + shaderHandle = glslCtxInfo->pfnglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); + } + else if (shaderType == javax_media_j3d_Shader_SHADER_TYPE_FRAGMENT) { + /* create the fragment shader */ + shaderHandle = glslCtxInfo->pfnglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + } + + if (shaderHandle == 0) { + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_COMPILE_ERROR, + "Unable to create native shader object", + NULL); + } + + shaderIdPtr[0] = (jlong) shaderHandle; + (*env)->ReleaseLongArrayElements(env, shaderIdArray, shaderIdPtr, 0); + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: destroyGLSLShader + * Signature: (JJ)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_destroyGLSLShader( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderId) +{ + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + glslCtxInfo->pfnglglDeleteObjectARB( (GLhandleARB) shaderId); + + return NULL; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: compileGLSLShader + * Signature: (JJLjava/lang/String;)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_compileGLSLShader( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderId, + jstring program) +{ + GLint status; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + jobject shaderError = NULL; + + /* Null-terminated "C" strings */ + GLcharARB *shaderString = NULL; + const GLcharARB *shaderStringArr[1]; + + + /* Assertion check the shaderId */ + if (shaderId == 0) { + throwAssert(env, "shaderId == 0"); + return NULL; + } + + /* Assertion check the program string */ + if (program == NULL) { + throwAssert(env, "shader program string is NULL"); + return NULL; + } + + shaderString = (GLcharARB *)strJavaToC(env, program); + if (shaderString == NULL) { + /* Just return, since strJavaToC will throw OOM if it returns NULL */ + return NULL; + } + + shaderStringArr[0] = shaderString; + glslCtxInfo->pfnglShaderSourceARB((GLhandleARB)shaderId, 1, shaderStringArr, NULL); + glslCtxInfo->pfnglCompileShaderARB((GLhandleARB)shaderId); + glslCtxInfo->pfnglGetObjectParameterivARB((GLhandleARB)shaderId, + GL_OBJECT_COMPILE_STATUS_ARB, + &status); + if (!status) { + const char *detailMsg = getInfoLog(ctxProperties, (GLhandleARB)shaderId); + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_COMPILE_ERROR, + "GLSL shader compile error", + detailMsg); + } + + free(shaderString); + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: createGLSLShaderProgram + * Signature: (J[J)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_createGLSLShaderProgram( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlongArray shaderProgramIdArray) +{ + + jlong *shaderProgramIdPtr; + GLhandleARB shaderProgramHandle; + jobject shaderError = NULL; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + shaderProgramIdPtr = (*env)->GetLongArrayElements(env, shaderProgramIdArray, NULL); + + shaderProgramHandle = glslCtxInfo->pfnglCreateProgramObjectARB(); + + if (shaderProgramHandle == 0) { + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_LINK_ERROR, + "Unable to create native shader program object", + NULL); + } + + shaderProgramIdPtr[0] = (jlong) shaderProgramHandle; + (*env)->ReleaseLongArrayElements(env, shaderProgramIdArray, shaderProgramIdPtr, 0); + + return shaderError; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: destroyGLSLShaderProgram + * Signature: (JJ)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_destroyGLSLShaderProgram( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId) +{ + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + glslCtxInfo->pfnglglDeleteObjectARB((GLhandleARB)shaderProgramId); + + return NULL; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: linkGLSLShaderProgram + * Signature: (JJ[J)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_linkGLSLShaderProgram( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlongArray shaderIdArray) +{ + GLint status; + int i; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + jlong *shaderIdPtr = (*env)->GetLongArrayElements(env, shaderIdArray, NULL); + jsize shaderIdArrayLength = (*env)->GetArrayLength(env, shaderIdArray); + jobject shaderError = NULL; + + /* + fprintf(stderr, "linkShaderProgram: shaderIdArrayLength %d\n", shaderIdArrayLength); + */ + + for(i=0; ipfnglAttachObjectARB((GLhandleARB)shaderProgramId, + (GLhandleARB)shaderIdPtr[i]); + } + + glslCtxInfo->pfnglLinkProgramARB((GLhandleARB)shaderProgramId); + glslCtxInfo->pfnglGetObjectParameterivARB((GLhandleARB)shaderProgramId, + GL_OBJECT_LINK_STATUS_ARB, + &status); + + if (!status) { + const char *detailMsg = getInfoLog(ctxProperties, (GLhandleARB)shaderProgramId); + + shaderError = createShaderError(env, + javax_media_j3d_ShaderError_LINK_ERROR, + "GLSL shader program link error", + detailMsg); + } + + (*env)->ReleaseLongArrayElements(env, shaderIdArray, shaderIdPtr, JNI_ABORT); + + return shaderError; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: bindGLSLVertexAttrName + * Signature: (JJLjava/lang/String;I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL +Java_javax_media_j3d_NativePipeline_bindGLSLVertexAttrName( + JNIEnv * env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jstring attrName, + jint attrIndex) +{ + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + jobject shaderError = NULL; + GLcharARB *attrNameString = (GLcharARB *)strJavaToC(env, attrName); + + /* + fprintf(stderr, + "GLSLShaderProgramRetained.bindGLSLVertexAttrName: %s\n", + attrNameString); + */ + + glslCtxInfo->pfnglBindAttribLocationARB((GLhandleARB)shaderProgramId, + attrIndex + glslCtxInfo->vertexAttrOffset, + attrNameString); + + /* No error checking needed, so just return */ + + return shaderError; +} + + +static jint +glslToJ3dType(GLint type) +{ + switch (type) { + case GL_BOOL_ARB: + case GL_INT: + case GL_SAMPLER_2D_ARB: + case GL_SAMPLER_3D_ARB: + case GL_SAMPLER_CUBE_ARB: + return TYPE_INTEGER; + + case GL_FLOAT: + return TYPE_FLOAT; + + case GL_INT_VEC2_ARB: + case GL_BOOL_VEC2_ARB: + return TYPE_TUPLE2I; + + case GL_FLOAT_VEC2_ARB: + return TYPE_TUPLE2F; + + case GL_INT_VEC3_ARB: + case GL_BOOL_VEC3_ARB: + return TYPE_TUPLE3I; + + case GL_FLOAT_VEC3_ARB: + return TYPE_TUPLE3F; + + case GL_INT_VEC4_ARB: + case GL_BOOL_VEC4_ARB: + return TYPE_TUPLE4I; + + case GL_FLOAT_VEC4_ARB: + return TYPE_TUPLE4F; + + /* case GL_FLOAT_MAT2_ARB: */ + + case GL_FLOAT_MAT3_ARB: + return TYPE_MATRIX3F; + + case GL_FLOAT_MAT4_ARB: + return TYPE_MATRIX4F; + + /* + * Java 3D does not support the following sampler types: + * + * case GL_SAMPLER_1D_ARB: + * case GL_SAMPLER_1D_SHADOW_ARB: + * case GL_SAMPLER_2D_SHADOW_ARB: + * case GL_SAMPLER_2D_RECT_ARB: + * case GL_SAMPLER_2D_RECT_SHADOW_ARB: + */ + } + + return -1; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: lookupGLSLShaderAttrNames + * Signature: (JJI[Ljava/lang/String;[J[I[I[Z)V + */ +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_lookupGLSLShaderAttrNames( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jint numAttrNames, + jobjectArray attrNames, + jlongArray locArr, + jintArray typeArr, + jintArray sizeArr, + jbooleanArray isArrayArr) +{ + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + GLcharARB **attrNamesString; + jlong *locPtr; + jint *typePtr; + jint *sizePtr; + jboolean *isArrayPtr; + GLint loc; + GLenum type; + GLint size; + GLcharARB *name; + GLint maxStrLen; + int numActiveUniforms; + int i, j; + + JNIEnv table = *env; + +#ifdef VERBOSE + fprintf(stderr, "GLSLShaderProgramRetained.lookupGLSLShaderAttrNames\n"); +#endif + + locPtr = (*env)->GetLongArrayElements(env, locArr, NULL); + typePtr = (*env)->GetIntArrayElements(env, typeArr, NULL); + sizePtr = (*env)->GetIntArrayElements(env, sizeArr, NULL); + isArrayPtr = (*env)->GetBooleanArrayElements(env, isArrayArr, NULL); + + /* + * Initialize the name array, also set the loc, type, and size + * arrays to out-of-band values + */ + attrNamesString = (GLcharARB **)malloc(numAttrNames * sizeof(GLcharARB *)); + for (i = 0; i < numAttrNames; i++) { + jstring attrName; + + attrName = (*env)->GetObjectArrayElement(env, attrNames, i); + attrNamesString[i] = (GLcharARB *)strJavaToC(env, attrName); + + locPtr[i] = -1; + typePtr[i] = -1; + sizePtr[i] = -1; + } + + /* + * Loop through the list of active uniform variables, one at a + * time, searching for a match in the attrNames array. + * + * NOTE: Since attrNames isn't sorted, and we don't have a + * hashtable of names to index locations, we will do a + * brute-force, linear search of the array. This leads to an + * O(n^2) algorithm (actually O(n*m) where n is attrNames.length + * and m is the number of uniform variables), but since we expect + * N to be small, we will not optimize this at this time. + */ + glslCtxInfo->pfnglGetObjectParameterivARB((GLhandleARB) shaderProgramId, + GL_OBJECT_ACTIVE_UNIFORMS_ARB, + &numActiveUniforms); + glslCtxInfo->pfnglGetObjectParameterivARB((GLhandleARB) shaderProgramId, + GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, + &maxStrLen); + name = malloc(maxStrLen + 1); + +#ifdef VERBOSE + fprintf(stderr, + "numActiveUniforms = %d, maxStrLen = %d\n", + numActiveUniforms, maxStrLen); +#endif + + for (i = 0; i < numActiveUniforms; i++) { + int len; + + glslCtxInfo->pfnglGetActiveUniformARB((GLhandleARB) shaderProgramId, + i, + maxStrLen, + NULL, + &size, + &type, + name); + + /* + * Issue 247 - we need to workaround an ATI bug where they erroneously + * report individual elements of arrays rather than the array itself + */ + len = (int) strlen(name); + if (len >= 3 && name[len-1] == ']') { + if (strcmp(&name[len-3], "[0]") == 0) { + /* fprintf(stderr, "**** changing \"%s\" ", name); */ + name[len-3] = '\0'; + /* fprintf(stderr, "to \"%s\"\n", name); */ + } else { + /* Ignore this name */ + /* fprintf(stderr, "Uniform[%d] : %s ignored\n", i, name); */ + continue; + } + } + +#ifdef VERBOSE + fprintf(stderr, + "Uniform[%d] : name = %s ; type = %d ; size = %d\n", + i, name, type, size); +#endif + + /* Now try to find the name */ + for (j = 0; j < numAttrNames; j++) { + if (strcmp(attrNamesString[j], name) == 0) { + sizePtr[j] = (jint)size; + isArrayPtr[j] = (size > 1); + typePtr[j] = glslToJ3dType(type); + break; + } + } + } + + free(name); + + /* Now lookup the location of each name in the attrNames array */ + for (i = 0; i < numAttrNames; i++) { + /* + * Get uniform attribute location + */ + loc = glslCtxInfo->pfnglGetUniformLocationARB((GLhandleARB)shaderProgramId, + attrNamesString[i]); + +#ifdef VERBOSE + fprintf(stderr, + "str = %s, loc = %d\n", + attrNamesString[i], loc); +#endif + + locPtr[i] = (jlong)loc; + } + + /* Free the array of strings */ + for (i = 0; i < numAttrNames; i++) { + free(attrNamesString[i]); + } + free(attrNamesString); + + /* Release JNI arrays */ + (*env)->ReleaseLongArrayElements(env, locArr, locPtr, 0); + (*env)->ReleaseIntArrayElements(env, typeArr, typePtr, 0); + (*env)->ReleaseIntArrayElements(env, sizeArr, sizePtr, 0); + (*env)->ReleaseBooleanArrayElements(env, isArrayArr, isArrayPtr, 0); +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: useGLSLShaderProgram + * Signature: (JI)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_useGLSLShaderProgram( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId) +{ + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + glslCtxInfo->pfnglUseProgramObjectARB((GLhandleARB)shaderProgramId); + + ctxProperties->shaderProgramId = shaderProgramId; + + return NULL; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform1i + * Signature: (JJJI)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform1i( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint value) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Load attribute */ + glslCtxInfo->pfnglUniform1iARB((GLint)location, value); + + return NULL; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform1f + * Signature: (JJJF)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform1f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloat value) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Load attribute */ + glslCtxInfo->pfnglUniform1fARB((GLint)location, value); + + return NULL; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform2i + * Signature: (JJJ[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform2i( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jintArray varray) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + jint *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (*env)->GetIntArrayElements(env, varray, NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform2iARB((GLint)location, values[0], values[1]); + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, values, JNI_ABORT); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform2f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform2f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Why shaderProgramId is not needed ? */ + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform2fARB((GLint)location, values[0], values[1]); + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform3i + * Signature: (JJJ[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform3i( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jintArray varray) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + jint *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (*env)->GetIntArrayElements(env, varray, NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform3iARB((GLint)location, values[0], values[1], values[2]); + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, values, JNI_ABORT); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform3f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform3f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform3fARB((GLint)location, values[0], values[1], values[2]); + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform4i + * Signature: (JJJ[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform4i( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jintArray varray) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + jint *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + /* Get array values */ + values = (*env)->GetIntArrayElements(env, varray, NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform4iARB((GLint)location, values[0], values[1], values[2], values[3]); + + /* Release array values */ + (*env)->ReleaseIntArrayElements(env, varray, values, JNI_ABORT); + + return NULL; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform4f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform4f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform4fARB((GLint)location, values[0], values[1], values[2], values[3]); + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + + return NULL; + +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniformMatrix3f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniformMatrix3f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + /* Load attribute */ + /* transpose is GL_TRUE : each matrix is supplied in row major order */ + glslCtxInfo->pfnglUniformMatrix3fvARB((GLint)location, 1, GL_TRUE, (GLfloat *)values); + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + + return NULL; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniformMatrix4f + * Signature: (JJJ[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniformMatrix4f( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jfloatArray varray) +{ + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + jfloat *values; + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (*env)->GetFloatArrayElements(env, varray, NULL); + + /* Load attribute */ + /* transpose is GL_TRUE : each matrix is supplied in row major order */ + glslCtxInfo->pfnglUniformMatrix4fvARB((GLint)location, 1, GL_TRUE, (GLfloat *)values); + + /* Release array values */ + (*env)->ReleaseFloatArrayElements(env, varray, values, JNI_ABORT); + + return NULL; +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform1iArray + * Signature: (JJJI[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform1iArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jintArray vArray) +{ + + JNIEnv table = *env; + jint *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jint *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform1ivARB((GLint)location, length, values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform1fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform1fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray vArray) +{ + + JNIEnv table = *env; + jfloat *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jfloat *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform1fvARB((GLint)location, length, values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; + +} + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform2iArray + * Signature: (JJJI[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform2iArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jintArray vArray) +{ + + JNIEnv table = *env; + jint *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jint *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform2ivARB((GLint)location, length, values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; + +} + + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform2fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform2fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray vArray) +{ + + JNIEnv table = *env; + jfloat *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jfloat *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform2fvARB((GLint)location, length, values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform3iArray + * Signature: (JJJI[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform3iArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jintArray vArray) +{ + + JNIEnv table = *env; + jint *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jint *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform3ivARB((GLint)location, length, values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform3fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform3fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray vArray) +{ + + JNIEnv table = *env; + jfloat *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jfloat *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform3fvARB((GLint)location, length, values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform4iArray + * Signature: (JJJI[I)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform4iArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jintArray vArray) +{ + + JNIEnv table = *env; + jint *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jint *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform4ivARB((GLint)location, length, values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniform4fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniform4fArray( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray vArray) +{ + + JNIEnv table = *env; + jfloat *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jfloat *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + glslCtxInfo->pfnglUniform4fvARB((GLint)location, length, values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniformMatrix3fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniformMatrix3fArray +( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray vArray) +{ + + JNIEnv table = *env; + jfloat *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jfloat *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + /* transpose is GL_TRUE : each matrix is supplied in row major order */ + glslCtxInfo->pfnglUniformMatrix3fvARB((GLint)location, length, + GL_TRUE, (GLfloat *)values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setGLSLUniformMatrix4fArray + * Signature: (JJJI[F)Ljavax/media/j3d/ShaderError; + */ +JNIEXPORT jobject +JNICALL Java_javax_media_j3d_NativePipeline_setGLSLUniformMatrix4fArray +( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jlong shaderProgramId, + jlong location, + jint length, + jfloatArray vArray) +{ + + JNIEnv table = *env; + jfloat *values; + + /* We do not need to use shaderProgramId because caller has already called + useShaderProgram(). */ + + GraphicsContextPropertiesInfo* ctxProperties = (GraphicsContextPropertiesInfo* )ctxInfo; + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + /* Get array values */ + values = (jfloat *)(*(table->GetPrimitiveArrayCritical))(env, vArray , NULL); + + /* Load attribute */ + /* transpose is GL_TRUE : each matrix is supplied in row major order */ + glslCtxInfo->pfnglUniformMatrix4fvARB((GLint)location, length, + GL_TRUE, (GLfloat *)values); + + /* Release array values */ + (*(table->ReleasePrimitiveArrayCritical))(env, vArray, values, 0); + + return NULL; +} + + +/* + * GLSL vertex attribute functions + */ + +static void +glslVertexAttrPointer( + GraphicsContextPropertiesInfo *ctxProperties, + int index, int size, int type, int stride, + const void *pointer) +{ + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + glslCtxInfo->pfnglVertexAttribPointerARB(index+glslCtxInfo->vertexAttrOffset, + size, type, GL_FALSE, stride, pointer); +} + +static void +glslEnableVertexAttrArray( + GraphicsContextPropertiesInfo *ctxProperties, + int index) +{ + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + glslCtxInfo->pfnglEnableVertexAttribArrayARB(index+glslCtxInfo->vertexAttrOffset); +} + +static void +glslDisableVertexAttrArray( + GraphicsContextPropertiesInfo *ctxProperties, + int index) +{ + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + + glslCtxInfo->pfnglDisableVertexAttribArrayARB(index+glslCtxInfo->vertexAttrOffset); +} + +static void +glslVertexAttr1fv( + GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v) +{ + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + +#ifdef VERBOSE + fprintf(stderr, "glslVertexAttr1fv()\n"); +#endif + glslCtxInfo->pfnglVertexAttrib1fvARB(index+glslCtxInfo->vertexAttrOffset, v); +} + +static void +glslVertexAttr2fv( + GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v) +{ + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + +#ifdef VERBOSE + fprintf(stderr, "glslVertexAttr2fv()\n"); +#endif + glslCtxInfo->pfnglVertexAttrib2fvARB(index+glslCtxInfo->vertexAttrOffset, v); +} + +static void +glslVertexAttr3fv( + GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v) +{ + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + +#ifdef VERBOSE + fprintf(stderr, "glslVertexAttr3fv()\n"); +#endif + glslCtxInfo->pfnglVertexAttrib3fvARB(index+glslCtxInfo->vertexAttrOffset, v); +} + +static void +glslVertexAttr4fv( + GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v) +{ + GLSLCtxInfo *glslCtxInfo = ctxProperties->glslCtxInfo; + +#ifdef VERBOSE + fprintf(stderr, "glslVertexAttr4fv()\n"); +#endif + glslCtxInfo->pfnglVertexAttrib4fvARB(index+glslCtxInfo->vertexAttrOffset, v); +} + diff --git a/j3d-core/src/native/ogl/GeometryArrayRetained.c b/j3d-core/src/native/ogl/GeometryArrayRetained.c new file mode 100644 index 0000000..c003119 --- /dev/null +++ b/j3d-core/src/native/ogl/GeometryArrayRetained.c @@ -0,0 +1,4162 @@ +/* + * $RCSfile: GeometryArrayRetained.c,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +#include +#include + +#include "gldefs.h" + +#ifdef WIN32 +#include + +#endif /* WIN32 */ + +#ifdef DEBUG +/* Uncomment the following for VERBOSE debug messages */ +/* #define VERBOSE */ +#endif /* DEBUG */ + + +static float EPS = 0.0001f; + +#define INTERLEAVEDARRAYS_TEST() \ + useInterleavedArrays = 1; \ + switch (vformat) { \ + case GA_COORDINATES : \ + iaFormat = GL_V3F; break; \ + case (GA_COORDINATES | GA_NORMALS) : \ + iaFormat = GL_N3F_V3F; break; \ + case (GA_COORDINATES | GA_TEXTURE_COORDINATE_2) :\ + iaFormat = GL_T2F_V3F; break; \ + case (GA_COORDINATES | GA_NORMALS | GA_COLOR) : \ + case (GA_COORDINATES | GA_NORMALS | GA_COLOR | GA_WITH_ALPHA) :\ + iaFormat = GL_C4F_N3F_V3F; break; \ + case (GA_COORDINATES | GA_NORMALS | GA_TEXTURE_COORDINATE_2) :\ + iaFormat = GL_T2F_N3F_V3F; break; \ + case (GA_COORDINATES | GA_NORMALS | GA_COLOR | GA_TEXTURE_COORDINATE_2):\ + case (GA_COORDINATES | GA_NORMALS | GA_COLOR | GA_WITH_ALPHA | GA_TEXTURE_COORDINATE_2):\ + iaFormat = GL_T2F_C4F_N3F_V3F; break;\ + default: \ + useInterleavedArrays = 0; break; \ + } + + +static void enableTexCoordPointer(GraphicsContextPropertiesInfo *, int, int, + int, int, void *); +static void disableTexCoordPointer(GraphicsContextPropertiesInfo *, int); +static void clientActiveTextureUnit(GraphicsContextPropertiesInfo *, int); + + +static void +executeTexture(int texCoordSetMapLen, + int texSize, int bstride, int texCoordoff, + jint texCoordSetMapOffset[], + jint numActiveTexUnit, + float verts[], jlong ctxInfo) +{ + int i; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + int tus; /* texture unit state index */ + + for (i = 0; i < numActiveTexUnit; i++) { + + tus = i; + + /* + * it's possible that texture unit state index (tus) + * is greater than the texCoordSetMapOffsetLen, in this + * case, just disable TexCoordPointer. + */ + if ((tus < texCoordSetMapLen) && + (texCoordSetMapOffset[tus] != -1)) { + enableTexCoordPointer(ctxProperties, i, + texSize, GL_FLOAT, bstride, + &(verts[texCoordoff + texCoordSetMapOffset[tus]])); + + } else { + disableTexCoordPointer(ctxProperties, i); + } + } +} + +static void +resetTexture(jlong ctxInfo) +{ + int i; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + /* Disable texture coordinate arrays for all texture units */ + for (i = 0; i < ctxProperties->maxTexCoordSets; i++) { + disableTexCoordPointer(ctxProperties, i); + } + /* Reset client active texture unit to 0 */ + clientActiveTextureUnit(ctxProperties, 0); +} + + +static void +resetVertexAttrs(jlong ctxInfo, int vertexAttrCount) +{ + int i; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + + /* Disable specified vertex attr arrays */ + for (i = 0; i < vertexAttrCount; i++) { + ctxProperties->disableVertexAttrArray(ctxProperties, i); + } +} + + +/* + * glLockArrays() is invoked only for indexed geometry, and the + * vertexCount is guarenteed to be >= 0. + */ +static void +lockArray(GraphicsContextPropertiesInfo *ctxProperties, + int vertexCount) { + + if (ctxProperties->compiled_vertex_array_ext) { + ctxProperties->glLockArraysEXT(0, vertexCount); + } +} + +static void +unlockArray(GraphicsContextPropertiesInfo *ctxProperties) +{ + if (ctxProperties->compiled_vertex_array_ext) { + ctxProperties->glUnlockArraysEXT(); + } +} + + +static void +executeGeometryArray( + JNIEnv *env, + jobject obj, jlong ctxInfo, jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint startVIndex, + jint vcount, jint vformat, + jint texCoordSetCount, + jintArray texCoordSetMap, jint texCoordSetMapLen, + jintArray texUnitOffset, + jint numActiveTexUnit, + jint vertexAttrCount, jintArray vertexAttrSizes, + jfloatArray varray, jobject varrayBuffer, jfloatArray carray, + jint cDirty) +{ + jclass geo_class; + JNIEnv table; + + jfloat *verts, *startVertex, *clrs, *startClrs; + jint i; + jint bstride, cbstride; + jsize strip_len; + GLsizei *strips; + GLenum iaFormat; + int useInterleavedArrays; + int primType; + jint stride, coordoff, normoff, coloroff, texCoordoff; + int alphaNeedsUpdate = 0; /* used so we can get alpha data from */ + /* JNI before using it so we can use */ + /* GetPrimitiveArrayCritical */ + jfieldID strip_field; + jarray sarray; + + jint texSize, texStride, *texCoordSetMapOffset = NULL; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + jarray start_array; + jfieldID start_field; + GLint *start; + int cstride = 0; + int vAttrStride = 0; + int vAttrOff; + jint *vAttrSizesPtr = NULL; + table = *env; + + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + /* This matches the code in GeometryArrayRetained.java */ + stride = coordoff = normoff = coloroff = texCoordoff = 0; + vAttrOff = 0; + if ((vformat & GA_COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GA_NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + if ((vformat & GA_COLOR) != 0) { + if ((vformat & GA_WITH_ALPHA) != 0 ) { + stride += 4; + normoff += 4; + coordoff += 4; + } + else { /* Handle the case of executeInterleaved 3f */ + stride += 3; + normoff += 3; + coordoff += 3; + } + } + if ((vformat & GA_TEXTURE_COORDINATE) != 0) { + if ((vformat & GA_TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GA_TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GA_TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + if ((vformat & GA_VERTEX_ATTRIBUTES) != 0) { + if (vertexAttrSizes != NULL) { + vAttrSizesPtr = table->GetIntArrayElements(env, vertexAttrSizes, NULL); + } + for (i = 0; i < vertexAttrCount; i++) { + vAttrStride += vAttrSizesPtr[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride*sizeof(float); + + /* + * Call other JNI functions before entering Critical region + * i.e., GetPrimitiveArrayCritical + */ + + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripVertexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + + + start_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripStartOffsetIndices", "[I"); + start_array = (jarray)(*(table->GetObjectField))(env, geo, + start_field); + } + + /* begin critical region */ + verts = NULL; + if(varray != NULL) { + verts = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, varray, NULL); + } + else if(varrayBuffer != NULL) { + verts = (jfloat *) (*(table->GetDirectBufferAddress))(env, varrayBuffer ); + } + if (verts == NULL) { + /* This should never happen */ + fprintf(stderr, "JAVA 3D ERROR : unable to get vertex pointer\n"); + if (vAttrSizesPtr != NULL) { + table->ReleaseIntArrayElements(env, vertexAttrSizes, vAttrSizesPtr, JNI_ABORT); + } + return; + } + + /* using byRef interleaved array and has a separate pointer, then .. */ + cstride = stride; + if (carray != NULL) { + clrs = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, carray, NULL); + cstride = 4; + + } + else { + clrs = &(verts[coloroff]); + } + + + cbstride = cstride * sizeof(float); + if (texCoordSetMapLen >0) { + texCoordSetMapOffset = (jint *) (*(table->GetPrimitiveArrayCritical))(env, texUnitOffset, NULL); + } + + /* Enable normalize for non-uniform scale (which rescale can't handle) */ + if (isNonUniformScale) { + glEnable(GL_NORMALIZE); + } + + + startVertex = verts + (stride * startVIndex); + startClrs = clrs + (cstride * startVIndex); + + /*** Handle non-indexed strip GeometryArray first *******/ + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + + strips = (GLsizei *) (*(table->GetPrimitiveArrayCritical))(env, sarray, + NULL); + + if ((ignoreVertexColors == JNI_TRUE) || (carray != NULL) || + ((vformat & GA_TEXTURE_COORDINATE) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = 0; + } else { + INTERLEAVEDARRAYS_TEST() + } + if (useInterleavedArrays) { + glInterleavedArrays(iaFormat, bstride, startVertex); + } else { + if (vformat & GA_NORMALS) { + glNormalPointer(GL_FLOAT, bstride, &(startVertex[normoff])); + } + if (ignoreVertexColors == JNI_FALSE && vformat & GA_COLOR) { + if (vformat & GA_WITH_ALPHA || (useAlpha == GL_TRUE)) { + glColorPointer(4, GL_FLOAT, cbstride, startClrs); + } else { + /* + for (i = 0; i < vcount; i++) { + fprintf(stderr, "r = %f, g = %f, b = %f\n", verts[i*bstride +coloroff], verts[i*bstride +coloroff+1],verts[i*bstride +coloroff+2]); + } + */ + glColorPointer(3, GL_FLOAT, cbstride, startClrs); + } + } + if (vformat & GA_COORDINATES) { + /* + for (i = 0; i < vcount; i++) { + fprintf(stderr, "x = %f, y = %f, z = %f\n", verts[i*bstride +coordoff], verts[i*bstride +coordoff+1],verts[i*bstride +coordoff+2]); + } + */ + glVertexPointer(3, GL_FLOAT, bstride, &(startVertex[coordoff])); + } + + if (vformat & GA_TEXTURE_COORDINATE) { + + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + numActiveTexUnit, + startVertex, ctxInfo); + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + jfloat *vAttrPtr = &startVertex[vAttrOff]; + + for (i = 0; i < vertexAttrCount; i++) { + ctxProperties->enableVertexAttrArray(ctxProperties, i); + ctxProperties->vertexAttrPointer(ctxProperties, i, vAttrSizesPtr[i], + GL_FLOAT, bstride, vAttrPtr); + vAttrPtr += vAttrSizesPtr[i]; + } + } + } + + switch (geo_type) { + case GEO_TYPE_TRI_STRIP_SET : + primType = GL_TRIANGLE_STRIP; + break; + case GEO_TYPE_TRI_FAN_SET : + primType = GL_TRIANGLE_FAN; + break; + case GEO_TYPE_LINE_STRIP_SET : + primType = GL_LINE_STRIP; + break; + } + /* + fprintf(stderr, "strip_len = %d\n",strip_len); + for (i=0; i < strip_len;i++) { + fprintf(stderr, "strips[i] = %d\n",strips[i]); + } + */ + + + start = (GLint *)(*(table->GetPrimitiveArrayCritical))(env, + start_array, NULL); + + if (ctxProperties->multi_draw_arrays_ext || ctxProperties->multi_draw_arrays_sun) { + /* + * Only used in the "by_copy case, so its ok to + * to temporarily modify + */ + + ctxProperties->glMultiDrawArraysEXT(primType, start, strips, strip_len); + } else { + for (i=0; i < strip_len;i++) { + glDrawArrays(primType, start[i], strips[i]); + } + } + (*(table->ReleasePrimitiveArrayCritical))(env, start_array, start, + 0); + (*(table->ReleasePrimitiveArrayCritical))(env, sarray, strips, 0); + } + /******* Handle non-indexed non-striped GeometryArray now *****/ + else if ((geo_type == GEO_TYPE_QUAD_SET) || + (geo_type == GEO_TYPE_TRI_SET) || + (geo_type == GEO_TYPE_POINT_SET) || + (geo_type == GEO_TYPE_LINE_SET)) + { + + + if ((ignoreVertexColors == JNI_TRUE) || (carray != NULL) || + ((vformat & GA_TEXTURE_COORDINATE) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = 0; + } else { + INTERLEAVEDARRAYS_TEST() + } + + if (useInterleavedArrays) { + glInterleavedArrays(iaFormat, bstride, startVertex); + } else { + if (vformat & GA_NORMALS) { + glNormalPointer(GL_FLOAT, bstride, &(startVertex[normoff])); + } + if (ignoreVertexColors == JNI_FALSE && vformat & GA_COLOR) { + if (vformat & GA_WITH_ALPHA || (useAlpha == GL_TRUE)) { + + glColorPointer(4, GL_FLOAT, cbstride, startClrs); + } else { + glColorPointer(3, GL_FLOAT, cbstride, startClrs); + } + } + if (vformat & GA_COORDINATES) { + glVertexPointer(3, GL_FLOAT, bstride, &(startVertex[coordoff])); + } + + if (vformat & GA_TEXTURE_COORDINATE) { + + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + numActiveTexUnit, + startVertex, ctxInfo); + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + jfloat *vAttrPtr = &startVertex[vAttrOff]; + + for (i = 0; i < vertexAttrCount; i++) { + ctxProperties->enableVertexAttrArray(ctxProperties, i); + ctxProperties->vertexAttrPointer(ctxProperties, i, vAttrSizesPtr[i], + GL_FLOAT, bstride, vAttrPtr); + vAttrPtr += vAttrSizesPtr[i]; + } + } + } + switch (geo_type){ + case GEO_TYPE_QUAD_SET : glDrawArrays(GL_QUADS, 0, vcount);break; + case GEO_TYPE_TRI_SET : glDrawArrays(GL_TRIANGLES, 0, vcount);break; + case GEO_TYPE_POINT_SET : glDrawArrays(GL_POINTS, 0, vcount);break; + case GEO_TYPE_LINE_SET: glDrawArrays(GL_LINES, 0, vcount);break; + } + } + /* clean up if we turned on normalize */ + + if (isNonUniformScale) { + glDisable(GL_NORMALIZE); + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + resetVertexAttrs(ctxInfo, vertexAttrCount); + } + + if (vformat & GA_TEXTURE_COORDINATE) { + resetTexture(ctxInfo); + } + + if (carray != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, carray, clrs, 0); + + if (texCoordSetMapLen > 0) + (*(table->ReleasePrimitiveArrayCritical))(env, texUnitOffset, + texCoordSetMapOffset, 0); + + if(varray != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, varray, verts, 0); + + if (vAttrSizesPtr != NULL) { + table->ReleaseIntArrayElements(env, vertexAttrSizes, vAttrSizesPtr, JNI_ABORT); + } +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: execute + * Signature: (JLjavax/media/j3d/GeometryArrayRetained;IZZZZIIII[II[II[II[I[F[FII)V + */ +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_execute(JNIEnv *env, + jobject obj, jlong ctxInfo, jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint startVIndex, + jint vcount, jint vformat, + jint texCoordSetCount, + jintArray texCoordSetMap, jint texCoordSetMapLen, + jintArray texUnitOffset, + jint numActiveTexUnit, + jint vertexAttrCount, jintArray vertexAttrSizes, + jfloatArray varray, jfloatArray carray, + jint cDirty) +{ + +#ifdef VERBOSE + fprintf(stderr, "GeometryArrayRetained.execute() -- calling executeGeometryArray\n"); +#endif /* VERBOSE */ + + /* call executeGeometryArray */ + executeGeometryArray(env, obj, ctxInfo, geo, geo_type, isNonUniformScale, useAlpha, + ignoreVertexColors, startVIndex, vcount, vformat, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, + texUnitOffset, numActiveTexUnit, + vertexAttrCount, vertexAttrSizes, + varray, NULL, carray, cDirty); + +} + +/* interleaved data with nio buffer as data format */ +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_executeInterleavedBuffer( + JNIEnv *env, + jobject obj, jlong ctxInfo, jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint startVIndex, + jint vcount, jint vformat, + jint texCoordSetCount, + jintArray texCoordSetMap, jint texCoordSetMapLen, + jintArray texUnitOffset, + jint numActiveTexUnit, + jobject varray, jfloatArray carray, + jint cDirty) +{ + +#ifdef VERBOSE + fprintf(stderr, "GeometryArrayRetained.executeInterleavedBuffer() -- calling executeGeometryArray\n"); +#endif /* VERBOSE */ + + /* call executeGeometryArray */ + executeGeometryArray(env, obj, ctxInfo, geo, geo_type, isNonUniformScale, useAlpha, + ignoreVertexColors, startVIndex, vcount, vformat, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, + texUnitOffset, numActiveTexUnit, + 0, NULL, + NULL, varray, carray, cDirty); + +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: buildGA + * Signature: (JLjavax/media/j3d/GeometryArrayRetained;IZZFZIIII[II[II[I[D[D[F)V + */ +JNIEXPORT + void JNICALL Java_javax_media_j3d_NativePipeline_buildGA(JNIEnv *env, + jobject obj, jlong ctxInfo, jobject geo, + jint geo_type, + jboolean isNonUniformScale, jboolean updateAlpha, float alpha, + jboolean ignoreVertexColors, + jint startVIndex, + jint vcount, jint vformat, + jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordSetMapLen, + jintArray texUnitOffset, + jint vertexAttrCount, jintArray vertexAttrSizes, + jdoubleArray xform, jdoubleArray nxform, + jfloatArray varray) +{ + jclass geo_class; + JNIEnv table; + jboolean useAlpha = JNI_FALSE; + + jfloat *verts; + jint i, j; + jint bstride; + jint texStride, *texCoordSetMapOffset; + int vAttrStride = 0; + int vAttrOff; + jint *vAttrSizesPtr = NULL; + GLsizei *strips; + jfloat vertex[3]; + jfloat normal[3]; + jfloat w, winv; + + jsize strip_len; + int primType; + jint stride, coordoff, normoff, coloroff, texCoordoff; + jfieldID strip_field; + jarray sarray; + jint initialOffset = 0; + jint saveVformat = 0; + float color[4]; + jdouble *xform_ptr = NULL; + jdouble *nxform_ptr = NULL; + + jint k; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + +#ifdef VERBOSE + fprintf(stderr, "GeometryArrayRetained.buildGA()\n"); +#endif /* VERBOSE */ + + table = *env; + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + /* This matches the code in GeometryArrayRetained.java */ + stride = coordoff = normoff = coloroff = texCoordoff = 0; + vAttrOff = 0; + if ((vformat & GA_COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GA_NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + + if ((vformat & GA_COLOR) != 0) { + if ((vformat & GA_BY_REFERENCE) != 0) { + if (vformat & GA_WITH_ALPHA) { + stride += 4; + normoff += 4; + coordoff += 4; + } + else { + stride += 3; + normoff += 3; + coordoff += 3; + } + } + else { + stride += 4; + normoff += 4; + coordoff += 4; + } + } + + if ((vformat & GA_TEXTURE_COORDINATE) != 0) { + if ((vformat & GA_TEXTURE_COORDINATE_2) != 0) { + texStride = 2 * texCoordSetCount; + } else if ((vformat & GA_TEXTURE_COORDINATE_3) != 0) { + texStride = 3 * texCoordSetCount; + } else if ((vformat & GA_TEXTURE_COORDINATE_4) != 0) { + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + if ((vformat & GA_VERTEX_ATTRIBUTES) != 0) { + if (vertexAttrSizes != NULL) { + vAttrSizesPtr = table->GetIntArrayElements(env, vertexAttrSizes, NULL); + } + for (i = 0; i < vertexAttrCount; i++) { + vAttrStride += vAttrSizesPtr[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride*sizeof(float); + /* Start send down from the startVIndex */ + initialOffset = startVIndex * stride; + normoff += initialOffset; + coloroff += initialOffset; + coordoff += initialOffset; + texCoordoff += initialOffset; + vAttrOff += initialOffset; + + /* + * process alpha for geometryArray without alpha + */ + if (updateAlpha == JNI_TRUE && ignoreVertexColors == JNI_FALSE) { + useAlpha = JNI_TRUE; + } + + /* + * call other JNI functions before entering Critical region + * i.e., GetPrimitiveArrayCritical + */ + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripVertexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + } + + + /* begin critical region */ + verts = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, varray, NULL); + + if (texCoordSetMapLen >0) { + texCoordSetMapOffset = (jint *)(*(table->GetPrimitiveArrayCritical)) + (env, texUnitOffset, NULL); + } + + + /* get the static transform if exists */ + if (xform != NULL) { + xform_ptr = (jdouble *) (*(table->GetPrimitiveArrayCritical))( + env, xform, NULL); + } + + /* get the static normals transform if exists */ + if (nxform != NULL) { + nxform_ptr = (jdouble *) (*(table->GetPrimitiveArrayCritical))( + env, nxform, NULL); + } + + + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + + switch (geo_type) { + case GEO_TYPE_TRI_STRIP_SET : + primType = GL_TRIANGLE_STRIP; + break; + case GEO_TYPE_TRI_FAN_SET : + primType = GL_TRIANGLE_FAN; + break; + case GEO_TYPE_LINE_STRIP_SET : + primType = GL_LINE_STRIP; + break; + } + + + strips = (GLsizei *) (*(table->GetPrimitiveArrayCritical))(env, sarray, NULL); + saveVformat = vformat; + if (ignoreVertexColors == JNI_TRUE) { + vformat &= ~GA_COLOR; + } + for (i = 0; i < strip_len; i++) { + glBegin(primType); + for (j = 0; j < strips[i]; j++) { + if (vformat & GA_NORMALS) { + if (nxform_ptr != NULL) { + normal[0] = (float) (nxform_ptr[0] * verts[normoff] + + nxform_ptr[1] * verts[normoff+1] + + nxform_ptr[2] * verts[normoff+2]); + normal[1] = (float ) (nxform_ptr[4] * verts[normoff] + + nxform_ptr[5] * verts[normoff+1] + + nxform_ptr[6] * verts[normoff+2]); + normal[2] = (float) (nxform_ptr[8] * verts[normoff] + + nxform_ptr[9] * verts[normoff+1] + + nxform_ptr[10] * verts[normoff+2]); +/* +printf("orig: < %g %g %g > transformed: < %g %g %g >\n", + verts[normoff], verts[normoff+1], verts[normoff+2], + normal[0], normal[1], normal[2]); +*/ + glNormal3fv(normal); + } else { + glNormal3fv(&verts[normoff]); + } + } + if (vformat & GA_COLOR) { + if (useAlpha ) { + color[0] = verts[coloroff]; + color[1] = verts[coloroff+1]; + color[2] = verts[coloroff+2]; + color[3] = verts[coloroff+3] * alpha; + glColor4fv(&color[0]); + } + else { + if (vformat & GA_WITH_ALPHA) { /* alpha is present */ + glColor4fv(&verts[coloroff]); + } + else { + glColor3fv(&verts[coloroff]); + } + } + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + int vaIdx, vaOff; + + vaOff = vAttrOff; + for (vaIdx = 0; vaIdx < vertexAttrCount; vaIdx++) { +#ifdef VERBOSE + fprintf(stderr, "vertexAttrs[%d] = (", vaIdx); + for (k = 0; k < vAttrSizesPtr[vaIdx]; k++) { + fprintf(stderr, "%g, ", + verts[vaOff+k]); + } + fprintf(stderr, ")\n"); +#endif /* VERBOSE */ + switch (vAttrSizesPtr[vaIdx]) { + case 1: + ctxProperties->vertexAttr1fv(ctxProperties, vaIdx, &verts[vaOff]); + break; + case 2: + ctxProperties->vertexAttr2fv(ctxProperties, vaIdx, &verts[vaOff]); + break; + case 3: + ctxProperties->vertexAttr3fv(ctxProperties, vaIdx, &verts[vaOff]); + break; + case 4: + ctxProperties->vertexAttr4fv(ctxProperties, vaIdx, &verts[vaOff]); + break; + } + + vaOff += vAttrSizesPtr[vaIdx]; + } + } + + if (vformat & GA_TEXTURE_COORDINATE) { + + if (texCoordSetMapLen > 0) { + + if (ctxProperties->gl13) { + if (vformat & GA_TEXTURE_COORDINATE_2) { + for (k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + ctxProperties->glMultiTexCoord2fv( + GL_TEXTURE0 + k, + &verts[texCoordoff + + texCoordSetMapOffset[k]]); + } + } + } else if (vformat & GA_TEXTURE_COORDINATE_3) { + for (k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + ctxProperties->glMultiTexCoord3fv( + GL_TEXTURE0 + k, + &verts[texCoordoff + + texCoordSetMapOffset[k]]); + } + } + } else { + for (k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + ctxProperties->glMultiTexCoord4fv( + GL_TEXTURE0 + k, + &verts[texCoordoff + + texCoordSetMapOffset[k]]); + } + } + } + } + else { /* no multitexture */ + + if (texCoordSetMapOffset[0] != -1) { + if (vformat & GA_TEXTURE_COORDINATE_2) { + glTexCoord2fv(&verts[texCoordoff + + texCoordSetMapOffset[0]]); + } else if (vformat & GA_TEXTURE_COORDINATE_3) { + glTexCoord3fv(&verts[texCoordoff + + texCoordSetMapOffset[0]]); + } else { + glTexCoord4fv(&verts[texCoordoff + + texCoordSetMapOffset[0]]); + } + } + } /* no multitexture */ + } + /* + * texCoordSetMapLen can't be 0 if texture coordinates + * is to be specified + */ + } + if (vformat & GA_COORDINATES) { + if (xform_ptr != NULL) { + + /* + * transform the vertex data with the + * static transform + */ + w = (float ) (xform_ptr[12] * verts[coordoff] + + xform_ptr[13] * verts[coordoff+1] + + xform_ptr[14] * verts[coordoff+2] + + xform_ptr[15]); + winv = 1.0f/w; + vertex[0] = (float ) (xform_ptr[0] * verts[coordoff] + + xform_ptr[1] * verts[coordoff+1] + + xform_ptr[2] * verts[coordoff+2] + + xform_ptr[3]) * winv; + vertex[1] = (float) (xform_ptr[4] * verts[coordoff] + + xform_ptr[5] * verts[coordoff+1] + + xform_ptr[6] * verts[coordoff+2] + + xform_ptr[7]) * winv; + vertex[2] = (float) (xform_ptr[8] * verts[coordoff] + + xform_ptr[9] * verts[coordoff+1] + + xform_ptr[10] * verts[coordoff+2] + + xform_ptr[11]) * winv; +/* +printf("orig: < %g %g %g > transformed: < %g %g %g >\n", + verts[coordoff], verts[coordoff+1], verts[coordoff+2], + vertex[0], vertex[1], vertex[2]); +*/ + glVertex3fv(vertex); + } else { + glVertex3fv(&verts[coordoff]); + } + } + normoff += stride; + coloroff += stride; + coordoff += stride; + texCoordoff += stride; + vAttrOff += stride; + } + glEnd(); + } + /* Restore the vertex format */ + vformat = saveVformat; + (*(table->ReleasePrimitiveArrayCritical))(env, sarray, strips, + 0); + + } + else if ((geo_type == GEO_TYPE_QUAD_SET) || + (geo_type == GEO_TYPE_TRI_SET) || + (geo_type == GEO_TYPE_POINT_SET) || + (geo_type == GEO_TYPE_LINE_SET)) { + + switch (geo_type) { + case GEO_TYPE_QUAD_SET : + primType = GL_QUADS; + break; + case GEO_TYPE_TRI_SET : + primType = GL_TRIANGLES; + break; + case GEO_TYPE_POINT_SET : + primType = GL_POINTS; + break; + case GEO_TYPE_LINE_SET : + primType = GL_LINES; + break; + + } + + saveVformat = vformat; + if (ignoreVertexColors == JNI_TRUE) { + vformat &= ~GA_COLOR; + } + glBegin(primType); + for (j = 0; j < vcount; j++) { + if (vformat & GA_NORMALS) { + if (nxform_ptr != NULL) { + normal[0] = (float) (nxform_ptr[0] * verts[normoff] + + nxform_ptr[1] * verts[normoff+1] + + nxform_ptr[2] * verts[normoff+2]); + normal[1] = (float) (nxform_ptr[4] * verts[normoff] + + nxform_ptr[5] * verts[normoff+1] + + nxform_ptr[6] * verts[normoff+2]); + normal[2] = (float) (nxform_ptr[8] * verts[normoff] + + nxform_ptr[9] * verts[normoff+1] + + nxform_ptr[10] * verts[normoff+2]); +/* +printf("orig: < %g %g %g > transformed: < %g %g %g >\n", + verts[normoff], verts[normoff+1], verts[normoff+2], + normal[0], normal[1], normal[2]); +*/ + glNormal3fv(normal); + } else { + glNormal3fv(&verts[normoff]); + } + } + if (vformat & GA_COLOR) { + if (useAlpha ) { + if (vformat & GA_WITH_ALPHA) { + color[0] = verts[coloroff]; + color[1] = verts[coloroff+1]; + color[2] = verts[coloroff+2]; + color[3] = verts[coloroff+3] * alpha; + } + else { + color[0] = verts[coloroff]; + color[1] = verts[coloroff+1]; + color[2] = verts[coloroff+2]; + color[3] = alpha; + } + glColor4fv(&color[0]); + + } + else { + if (vformat & GA_WITH_ALPHA) { /* alpha is present */ + glColor4fv(&verts[coloroff]); + } + else { + glColor3fv(&verts[coloroff]); + } + } + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + int vaIdx, vaOff; + + vaOff = vAttrOff; + for (vaIdx = 0; vaIdx < vertexAttrCount; vaIdx++) { +#ifdef VERBOSE + fprintf(stderr, "vertexAttrs[%d] = (", vaIdx); + for (k = 0; k < vAttrSizesPtr[vaIdx]; k++) { + fprintf(stderr, "%g, ", + verts[vaOff+k]); + } + fprintf(stderr, ")\n"); +#endif /* VERBOSE */ + switch (vAttrSizesPtr[vaIdx]) { + case 1: + ctxProperties->vertexAttr1fv(ctxProperties, vaIdx, &verts[vaOff]); + break; + case 2: + ctxProperties->vertexAttr2fv(ctxProperties, vaIdx, &verts[vaOff]); + break; + case 3: + ctxProperties->vertexAttr3fv(ctxProperties, vaIdx, &verts[vaOff]); + break; + case 4: + ctxProperties->vertexAttr4fv(ctxProperties, vaIdx, &verts[vaOff]); + break; + } + + vaOff += vAttrSizesPtr[vaIdx]; + } + } + + if (vformat & GA_TEXTURE_COORDINATE) { + + if (texCoordSetMapLen > 0) { + + if(ctxProperties->gl13) { + if (vformat & GA_TEXTURE_COORDINATE_2) { + for (k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + ctxProperties->glMultiTexCoord2fv( + GL_TEXTURE0 + k, + &verts[texCoordoff + + texCoordSetMapOffset[k]]); + } + } + } else if (vformat & GA_TEXTURE_COORDINATE_3) { + for (k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + ctxProperties->glMultiTexCoord3fv( + GL_TEXTURE0 + k, + &verts[texCoordoff + + texCoordSetMapOffset[k]]); + } + } + } else { + for (k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + ctxProperties->glMultiTexCoord4fv( + GL_TEXTURE0 + k, + &verts[texCoordoff + + texCoordSetMapOffset[k]]); + } + } + } + } + else { /* no multitexture */ + + if (texCoordSetMapOffset[0] != -1) { + if (vformat & GA_TEXTURE_COORDINATE_2) { + glTexCoord2fv(&verts[texCoordoff + + texCoordSetMapOffset[0]]); + } else if (vformat & GA_TEXTURE_COORDINATE_3) { + glTexCoord3fv(&verts[texCoordoff + + texCoordSetMapOffset[0]]); + } else { + glTexCoord4fv(&verts[texCoordoff + + texCoordSetMapOffset[0]]); + } + } + } /* no multitexture */ + } + + /* + * texCoordSetMapLen can't be 0 if texture coordinates + * is to be specified + */ + } + + if (vformat & GA_COORDINATES) { + if (xform_ptr != NULL) { + + /* + * transform the vertex data with the + * static transform + */ + w = (float) (xform_ptr[12] * verts[coordoff] + + xform_ptr[13] * verts[coordoff+1] + + xform_ptr[14] * verts[coordoff+2] + + xform_ptr[15]); + winv = 1.0f/w; + vertex[0] = (float) (xform_ptr[0] * verts[coordoff] + + xform_ptr[1] * verts[coordoff+1] + + xform_ptr[2] * verts[coordoff+2] + + xform_ptr[3]) * winv; + vertex[1] = (float) (xform_ptr[4] * verts[coordoff] + + xform_ptr[5] * verts[coordoff+1] + + xform_ptr[6] * verts[coordoff+2] + + xform_ptr[7]) * winv; + vertex[2] = (float) (xform_ptr[8] * verts[coordoff] + + xform_ptr[9] * verts[coordoff+1] + + xform_ptr[10] * verts[coordoff+2] + + xform_ptr[11]) * winv; +/* +printf("orig: < %g %g %g > transformed: < %g %g %g >\n", + verts[coordoff], verts[coordoff+1], verts[coordoff+2], + vertex[0], vertex[1], vertex[2]); +*/ + glVertex3fv(vertex); + } else { + glVertex3fv(&verts[coordoff]); + } + } + normoff += stride; + coloroff += stride; + coordoff += stride; + texCoordoff += stride; + vAttrOff += stride; + } + glEnd(); + } + /* Restore the vertex format */ + vformat = saveVformat; + + + (*(table->ReleasePrimitiveArrayCritical))(env, varray, verts, 0); + + if (texCoordSetMapLen > 0) + (*(table->ReleasePrimitiveArrayCritical))(env, texUnitOffset, + texCoordSetMapOffset, 0); + + if (xform_ptr != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, xform, xform_ptr, 0); + + if (nxform_ptr != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, nxform, nxform_ptr, 0); + + if (vAttrSizesPtr != NULL) { + table->ReleaseIntArrayElements(env, vertexAttrSizes, vAttrSizesPtr, JNI_ABORT); + } +} + +static void +enableTexCoordPointer( + GraphicsContextPropertiesInfo *ctxProperties, + int texUnit, + int texSize, + int texDataType, + int stride, + void *pointer) +{ + clientActiveTextureUnit(ctxProperties, texUnit); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(texSize, texDataType, stride, pointer); +} + +static void +disableTexCoordPointer( + GraphicsContextPropertiesInfo *ctxProperties, + int texUnit) +{ + clientActiveTextureUnit(ctxProperties, texUnit); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +static void +clientActiveTextureUnit( + GraphicsContextPropertiesInfo *ctxProperties, + int texUnit) +{ + if (ctxProperties->gl13) { + ctxProperties->glClientActiveTexture(texUnit + GL_TEXTURE0); + } +} + + +static void +executeGeometryArrayVA( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jfloat* fverts, + jdouble* dverts, + jint initialColorIndex, + jfloat* fclrs, + jbyte* bclrs, + jint initialNormalIndex, + jfloat* norms, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jintArray vertexAttrIndices, + jfloat ** vertexAttrPointer, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jintArray texindices, + jint texStride, + jfloat** texCoordPointer, + jint cdirty, + jarray sarray, + jsize strip_len, + jarray start_array) +{ + int primType; + JNIEnv table; + jint i; + GLsizei *strips; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + GLint *start; + + jint coordoff, coloroff, normoff; + jint* initialVAttrIndices; + jint* vAttrSizes; + int texSet; + jint *texCoordSetMap; + jint* initialTexIndices; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean vattrDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_VATTR_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + table = *env; + +#ifdef VERBOSE + fprintf(stderr, "executeGeometryArrayVA()\n"); +#endif /* VERBOSE */ + + /* Enable normalize for non-uniform scale (which rescale can't handle) */ + if (isNonUniformScale) { + glEnable(GL_NORMALIZE); + } + + coordoff = 3 * initialCoordIndex; + /* Define the data pointers */ + if (floatCoordDefined) { + glVertexPointer(3, GL_FLOAT, 0, &(fverts[coordoff])); + } else if (doubleCoordDefined){ + glVertexPointer(3, GL_DOUBLE, 0, &(dverts[coordoff])); + } + + if (floatColorsDefined) { + if (vformat & GA_WITH_ALPHA) { + coloroff = 4 * initialColorIndex; + glColorPointer(4, GL_FLOAT, 0, &(fclrs[coloroff])); + } else { + coloroff = 3 * initialColorIndex; + glColorPointer(3, GL_FLOAT, 0, &(fclrs[coloroff])); + } + } else if (byteColorsDefined) { + if (vformat & GA_WITH_ALPHA) { + coloroff = 4 * initialColorIndex; + glColorPointer(4, GL_UNSIGNED_BYTE, 0, &(bclrs[coloroff])); + } else { + coloroff = 3 * initialColorIndex; + glColorPointer(3, GL_UNSIGNED_BYTE, 0, &(bclrs[coloroff])); + } + } + if (normalsDefined) { + normoff = 3 * initialNormalIndex; + glNormalPointer(GL_FLOAT, 0, &(norms[normoff])); + } + + if (vattrDefined) { + float *pVertexAttrs; + int sz, initIdx; + + vAttrSizes = (jint *) (*(table->GetPrimitiveArrayCritical))(env, vertexAttrSizes, NULL); + initialVAttrIndices = (jint *) (*(table->GetPrimitiveArrayCritical))(env, vertexAttrIndices, NULL); + + for (i = 0; i < vertexAttrCount; i++) { + pVertexAttrs = vertexAttrPointer[i]; + sz = vAttrSizes[i]; + initIdx = initialVAttrIndices[i]; + + ctxProperties->enableVertexAttrArray(ctxProperties, i); + ctxProperties->vertexAttrPointer(ctxProperties, i, sz, + GL_FLOAT, 0, + &pVertexAttrs[initIdx * sz]); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, vertexAttrSizes, vAttrSizes, 0); + (*(table->ReleasePrimitiveArrayCritical))(env, vertexAttrIndices, initialVAttrIndices, 0); + } + + if (textureDefined) { + + int tus = 0; + float *ptexCoords; + + initialTexIndices = (jint *) (*(table->GetPrimitiveArrayCritical))(env,texindices, NULL); + + texCoordSetMap = (jint *) (*(table->GetPrimitiveArrayCritical))(env,tcoordsetmap, NULL); + for (i = 0; i < numActiveTexUnit; i++) { + if ((i < texCoordMapLength) && ( + ((texSet=texCoordSetMap[i]) != -1))) { + + ptexCoords = texCoordPointer[texSet]; + + enableTexCoordPointer(ctxProperties, i, texStride, + GL_FLOAT, 0, + &ptexCoords[texStride * initialTexIndices[texSet]]); + + } else { + disableTexCoordPointer(ctxProperties, i); + } + } + + /* Reset client active texture unit to 0 */ + clientActiveTextureUnit(ctxProperties, 0); + } + + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + strips = (GLint *) (*(table->GetPrimitiveArrayCritical))(env, sarray, + NULL); + + switch (geo_type) { + case GEO_TYPE_TRI_STRIP_SET : + primType = GL_TRIANGLE_STRIP; + break; + case GEO_TYPE_TRI_FAN_SET : + primType = GL_TRIANGLE_FAN; + break; + case GEO_TYPE_LINE_STRIP_SET : + primType = GL_LINE_STRIP; + break; + } + + start = (GLint *)(*(table->GetPrimitiveArrayCritical))(env, + start_array, NULL); + if (ctxProperties->multi_draw_arrays_ext || ctxProperties->multi_draw_arrays_sun) { + + /* + fprintf(stderr, "strip_len = %d \n",strip_len); + for (i=0; i < strip_len;i++) { + fprintf(stderr, "numVertices = %d\n",strips[i]); + fprintf(stderr, "start = %d \n",start[i]); + } + */ + ctxProperties->glMultiDrawArraysEXT(primType, start, strips, strip_len); + } else { + for (i=0; i < strip_len;i++) { + glDrawArrays(primType, start[i], strips[i]); + } + } + (*(table->ReleasePrimitiveArrayCritical))(env, start_array, start, + 0); + (*(table->ReleasePrimitiveArrayCritical))(env, sarray, strips, 0); + } + else { + switch (geo_type){ + case GEO_TYPE_QUAD_SET : glDrawArrays(GL_QUADS, 0, vcount);break; + case GEO_TYPE_TRI_SET : glDrawArrays(GL_TRIANGLES, 0, vcount);break; + case GEO_TYPE_POINT_SET : glDrawArrays(GL_POINTS, 0, vcount);break; + case GEO_TYPE_LINE_SET: glDrawArrays(GL_LINES, 0, vcount);break; + } + } + /* clean up if we turned on normalize */ + if (isNonUniformScale) { + glDisable(GL_NORMALIZE); + } + + + if (vattrDefined) { + resetVertexAttrs(ctxInfo, vertexAttrCount); + } + + if (textureDefined) { + resetTexture(ctxInfo); + + (*(table->ReleasePrimitiveArrayCritical))(env, tcoordsetmap, texCoordSetMap, 0); + (*(table->ReleasePrimitiveArrayCritical))(env, texindices, initialTexIndices, 0); + } +} + +/* execute geometry array with java array format */ +/* + * Class: javax_media_j3d_NativePipeline + * Method: executeVA + * Signature: (JLjavax/media/j3d/GeometryArrayRetained;IZZZIIII[F[DI[F[BI[FI[I[I[[FII[II[I[II[Ljava/lang/Object;I)V + */ +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_executeVA( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jfloatArray vfcoords, + jdoubleArray vdcoords, + jint initialColorIndex, + jfloatArray cfdata, + jbyteArray cbdata, + jint initialNormalIndex, + jfloatArray ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jintArray vertexAttrIndices, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jintArray texindices, + jint texStride, + jobjectArray texCoords, + jint cdirty) +{ + + jfieldID strip_field; + jarray sarray; + jsize strip_len; + jclass geo_class; + + jarray start_array; + jfieldID start_field; + + JNIEnv table = *env; + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jbyte *bclrs = NULL; + jfloat *fclrs = NULL, *norms = NULL; + jarray *vaobjs = NULL; + jfloat **vertexAttrPointer = NULL; + jfloat **texCoordPointer = NULL; + jarray *texobjs = NULL; + int i; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean vattrDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_VATTR_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + if (vattrDefined) { + vaobjs = (jarray *)malloc(vertexAttrCount * sizeof(jarray)); + vertexAttrPointer = (jfloat **)malloc(vertexAttrCount * sizeof(jfloat *)); + + for (i = 0; i < vertexAttrCount; i++) { + vaobjs[i] = (*(table->GetObjectArrayElement))(env, vertexAttrData, i); + } + } + + if (textureDefined) { + texobjs = (jarray*)malloc(texCoordMapLength * sizeof(jarray)); + texCoordPointer = (jfloat**)malloc(texCoordMapLength * sizeof(jfloat*)); + + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (*(table->GetObjectArrayElement))(env, texCoords, i); + } + } + + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripVertexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + + start_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripStartOffsetIndices", "[I"); + start_array = (jarray)(*(table->GetObjectField))(env, geo, + start_field); + } + + /* Get vertex attribute arrays */ + if (vattrDefined) { + for (i = 0; i < vertexAttrCount; i++) { + vertexAttrPointer[i] = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, vaobjs[i], NULL); + } + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)(*(table->GetPrimitiveArrayCritical))(env,texobjs[i], NULL); + else + texCoordPointer[i] = NULL; + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts= (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, vfcoords, NULL); + } else if (doubleCoordDefined) { + dverts= (jdouble *) (*(table->GetPrimitiveArrayCritical))(env, vdcoords, NULL); + } + + /* get color array */ + if (floatColorsDefined) { + fclrs = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, cfdata, NULL); + } else if (byteColorsDefined) { + bclrs = (jbyte *) (*(table->GetPrimitiveArrayCritical))(env, cbdata, NULL); + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env,ndata, NULL); + } + +#ifdef VERBOSE + fprintf(stderr, "GeometryArrayRetained.executeVA() -- calling executeGeometryArrayVA\n"); +#endif /* VERBOSE */ + + executeGeometryArrayVA(env, obj, ctxInfo, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, initialCoordIndex, + fverts, dverts, initialColorIndex, + fclrs, bclrs, initialNormalIndex, + norms, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrPointer, + texCoordMapLength, + tcoordsetmap,numActiveTexUnit, + texindices,texStride,texCoordPointer,cdirty, sarray, strip_len, start_array); + + + if (vattrDefined) { + for (i = 0; i < vertexAttrCount; i++) { + (*(table->ReleasePrimitiveArrayCritical))(env, vaobjs[i], vertexAttrPointer[i], 0); + } + } + + if (vaobjs != NULL) { + free(vaobjs); + } + if (vertexAttrPointer != NULL) { + free(vertexAttrPointer); + } + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texCoordPointer[i] != NULL) { + (*(table->ReleasePrimitiveArrayCritical))(env, texobjs[i], texCoordPointer[i], 0); + } + } + } + + if (texobjs != NULL) { + free(texobjs); + } + if (texCoordPointer != NULL) { + free(texCoordPointer); + } + + if (normalsDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, ndata, norms, 0); + } + + + if (floatColorsDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, cfdata, fclrs, 0); + } + else if (byteColorsDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, cbdata, bclrs, 0); + } + + + if (floatCoordDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, vfcoords, fverts, 0); + } + else if (doubleCoordDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, vdcoords, dverts, 0); + } +} + +/* execute geometry array with java array format */ +/* + * Class: javax_media_j3d_NativePipeline + * Method: executeVABuffer + * Signature: (JLjavax/media/j3d/GeometryArrayRetained;IZZZIIIILjava/lang/Object;ILjava/lang/Object;[F[BILjava/lang/Object;I[I[I[Ljava/lang/Object;II[II[I[II[Ljava/lang/Object;I)V + */ +JNIEXPORT void JNICALL Java_javax_media_j3d_NativePipeline_executeVABuffer( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jobject vcoords, + jint initialColorIndex, + jobject cdataBuffer, + jfloatArray cfdata, + jbyteArray cbdata, + jint initialNormalIndex, + jobject ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jintArray vertexAttrIndices, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jintArray texindices, + jint texStride, + jobjectArray texCoords, + jint cdirty) +{ + jfieldID strip_field; + jarray sarray; + jsize strip_len; + jclass geo_class; + + jarray start_array; + jfieldID start_field; + + JNIEnv table = *env; + jfloat *fverts = NULL; + jdouble *dverts = NULL ; + jbyte *bclrs = NULL; + jfloat *fclrs = NULL, *norms = NULL; + jarray *vaobjs = NULL; + jfloat **vertexAttrPointer = NULL; + jfloat **texCoordPointer = NULL; + jarray *texobjs = NULL; + int i; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean vattrDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_VATTR_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + if (vattrDefined) { + vaobjs = (jarray *)malloc(vertexAttrCount * sizeof(jarray)); + vertexAttrPointer = (jfloat **)malloc(vertexAttrCount * sizeof(jfloat *)); + + for (i = 0; i < vertexAttrCount; i++) { + vaobjs[i] = (*(table->GetObjectArrayElement))(env, vertexAttrData, i); + } + } + + if (textureDefined) { + texobjs = (jarray*)malloc(texCoordMapLength * sizeof(jarray)); + texCoordPointer = (jfloat**)malloc(texCoordMapLength * sizeof(jfloat*)); + + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (*(table->GetObjectArrayElement))(env, texCoords, i); + } + } + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripVertexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + + start_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripStartOffsetIndices", "[I"); + start_array = (jarray)(*(table->GetObjectField))(env, geo, + start_field); + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts= (jfloat *)(*(table->GetDirectBufferAddress))(env, vcoords ); + } else if (doubleCoordDefined) { + dverts= (jdouble *)(*(table->GetDirectBufferAddress))(env, vcoords ); + } + + if(fverts == NULL && dverts == NULL) { + return; + } + + + /* get color array */ + if (floatColorsDefined) { + if(cfdata != NULL) + fclrs = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, cfdata, NULL); + else + fclrs = (jfloat *)(*(table->GetDirectBufferAddress))(env, cdataBuffer); + } + else if (byteColorsDefined) { + if(cbdata != NULL) + bclrs = (jbyte *) (*(table->GetPrimitiveArrayCritical))(env, cbdata, NULL); + else + bclrs = (jbyte *)(*(table->GetDirectBufferAddress))(env, cdataBuffer); + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *)(*(table->GetDirectBufferAddress))(env, ndata); + } + + /* get vertex attr arrays */ + if (vattrDefined) { + for (i = 0; i < vertexAttrCount; i++) { + vertexAttrPointer[i] = (jfloat *) (*(table->GetDirectBufferAddress))(env, vaobjs[i]); + } + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)(*(table->GetDirectBufferAddress))(env,texobjs[i]); + else + texCoordPointer[i] = NULL; + } + } + + +#ifdef VERBOSE + fprintf(stderr, "GeometryArrayRetained.executeVABuffer() -- calling executeGeometryArrayVA\n"); +#endif /* VERBOSE */ + + executeGeometryArrayVA(env, obj, ctxInfo, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, initialCoordIndex, + fverts, dverts, initialColorIndex, + fclrs, bclrs, initialNormalIndex, + norms, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrPointer, + texCoordMapLength, + tcoordsetmap,numActiveTexUnit, + texindices,texStride,texCoordPointer,cdirty, sarray, strip_len, start_array); + + if (vaobjs != NULL) { + free(vaobjs); + } + if (vertexAttrPointer != NULL) { + free(vertexAttrPointer); + } + + if (texobjs != NULL) { + free(texobjs); + } + if (texCoordPointer != NULL) { + free(texCoordPointer); + } + + if(floatColorsDefined && cfdata != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, cfdata, fclrs, 0); + else if(byteColorsDefined && cbdata != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, cbdata, bclrs, 0); +} + + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_disableGlobalAlpha( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint vformat, + jboolean useAlpha, + jboolean ignoreVertexColors) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + if(ctxProperties->global_alpha_sun){ + if (ignoreVertexColors == JNI_FALSE && vformat & 0x04) { + if (useAlpha && ctxProperties->global_alpha_sun ) { + glDisable(GL_GLOBAL_ALPHA_SUN); + } + } + } +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: setVertexFormat + * Signature: (JIZZI[I)V + */ +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_setVertexFormat( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint vformat, + jboolean useAlpha, + jboolean ignoreVertexColors) +{ + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + +#ifdef VERBOSE + fprintf(stderr, + "GeometryArrayRetained.setVertexFormat() : vformat = %d\n", + vformat); +#endif /* VERBOSE */ + + /* Enable and disable the appropriate pointers */ + if (vformat & GA_NORMALS) { + glEnableClientState(GL_NORMAL_ARRAY); + } + else { + glDisableClientState(GL_NORMAL_ARRAY); + } + if (ignoreVertexColors == JNI_FALSE && vformat & GA_COLOR) { + glEnableClientState(GL_COLOR_ARRAY); + } + else { + glDisableClientState(GL_COLOR_ARRAY); + + } + + if (ctxProperties->global_alpha_sun) { + if (useAlpha) { + glEnable(GL_GLOBAL_ALPHA_SUN); + } + else { + glDisable(GL_GLOBAL_ALPHA_SUN); + } + } + + if (vformat & GA_COORDINATES) { + glEnableClientState(GL_VERTEX_ARRAY); + } + else { + glDisableClientState(GL_VERTEX_ARRAY); + } +} + +static void +executeIndexedGeometryArray( + JNIEnv *env, + jobject obj, jlong ctxInfo, jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vertexCount, + jint vformat, + jint vertexAttrCount, jintArray vertexAttrSizes, + jint texCoordSetCount, + jintArray texCoordSetMap, jint texCoordSetMapLen, + jintArray texUnitOffset, + jint numActiveTexUnit, + jfloatArray varray, jobject varrayBuffer, jfloatArray carray, + jint cDirty, + jintArray indexCoord) +{ + jclass geo_class; + JNIEnv table; + + jfloat *verts,*clrs; + jint *indices; + jint i; + jint bstride, cbstride; + jsize strip_len; + GLsizei *countArray; + int offset; + GLenum iaFormat; + int useInterleavedArrays; + int primType; + jint stride, coordoff, normoff, coloroff, texCoordoff; + int alphaNeedsUpdate = 0; /* used so we can get alpha data from */ + /* JNI before using it so we can use */ + /* GetPrimitiveArrayCritical */ + jfieldID strip_field; + jarray sarray; + jint* tmpDrawElementsIndices[100]; + + jint** multiDrawElementsIndices = NULL; + jint allocated = 0; + + jint texSize, texStride, *texCoordSetMapOffset = NULL; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + int cstride = 0; + int vAttrStride = 0; + int vAttrOff; + jint *vAttrSizesPtr = NULL; + + table = *env; + +#ifdef VERBOSE + fprintf(stderr, + "executeIndexedGeometryArray: vertexAttrCount = %d\n", + vertexAttrCount); +#endif /* VERBOSE */ + + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + /* This matches the code in GeometryArrayRetained.java */ + stride = coordoff = normoff = coloroff = texCoordoff = 0; + vAttrOff = 0; + if ((vformat & GA_COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GA_NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + if ((vformat & GA_COLOR) != 0) { + if ((vformat & GA_WITH_ALPHA) != 0 ) { + stride += 4; + normoff += 4; + coordoff += 4; + } + else { /* Handle the case of executeInterleaved 3f */ + stride += 3; + normoff += 3; + coordoff += 3; + } + } + if ((vformat & GA_TEXTURE_COORDINATE) != 0) { + if ((vformat & GA_TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GA_TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GA_TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + if ((vformat & GA_VERTEX_ATTRIBUTES) != 0) { + if (vertexAttrSizes != NULL) { + vAttrSizesPtr = table->GetIntArrayElements(env, vertexAttrSizes, NULL); + } + for (i = 0; i < vertexAttrCount; i++) { + vAttrStride += vAttrSizesPtr[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride*sizeof(float); + + /* + * call other JNI functions before entering Critical region + * i.e., GetPrimitiveArrayCritical + */ + + + if (geo_type == GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GEO_TYPE_INDEXED_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripIndexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + + + } + + /* begin critical region */ + if(varray != NULL) + verts = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, varray, NULL); + else if(varrayBuffer != NULL) + verts = (jfloat *) (*(table->GetDirectBufferAddress))(env, varrayBuffer); + + indices = (jint *) (*(table->GetPrimitiveArrayCritical))(env, indexCoord, NULL); + + + /* using byRef interleaved array and has a separate pointer, then .. */ + cstride = stride; + if (carray != NULL) { + clrs = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, carray, NULL); + cstride = 4; + + } + else { + clrs = &(verts[coloroff]); + } + cbstride = cstride * sizeof(float); + if (texCoordSetMapLen >0) { + texCoordSetMapOffset = (jint *) (*(table->GetPrimitiveArrayCritical))(env, texUnitOffset, NULL); + } + + /* Enable normalize for non-uniform scale (which rescale can't handle) */ + if (isNonUniformScale) { + glEnable(GL_NORMALIZE); + } + + /*** Handle non-indexed strip GeometryArray first *******/ + if (geo_type == GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GEO_TYPE_INDEXED_LINE_STRIP_SET) { + + + countArray = (GLsizei *) (*(table->GetPrimitiveArrayCritical))(env, sarray, + NULL); + + if ((ignoreVertexColors == JNI_TRUE) || (carray != NULL) || + ((vformat & GA_TEXTURE_COORDINATE) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = 0; + } else { + INTERLEAVEDARRAYS_TEST() + } + if (useInterleavedArrays) { + glInterleavedArrays(iaFormat, bstride, verts); + } else { + if (vformat & GA_NORMALS) { + glNormalPointer(GL_FLOAT, bstride, &(verts[normoff])); + } + if (ignoreVertexColors == JNI_FALSE && vformat & GA_COLOR) { + if (vformat & GA_WITH_ALPHA || (useAlpha == GL_TRUE)) { + glColorPointer(4, GL_FLOAT, cbstride, clrs); + } else { + /* + for (i = 0; i < 4; i++) { + fprintf(stderr, "r = %f, g = %f, b = %f\n", verts[i*stride +coloroff], verts[i*stride +coloroff+1],verts[i*stride +coloroff+2]); + } + */ + glColorPointer(3, GL_FLOAT, cbstride, clrs); + } + } + if (vformat & GA_COORDINATES) { + /* + for (i = 0; i < 4; i++) { + fprintf(stderr, "x = %f, y = %f, z = %f\n", verts[i*stride +coordoff], verts[i*stride +coordoff+1],verts[i*stride +coordoff+2]); + } + */ + glVertexPointer(3, GL_FLOAT, bstride, &(verts[coordoff])); + } + + if (vformat & GA_TEXTURE_COORDINATE) { + + /* XXXX: texCoordoff == 0 ???*/ + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + numActiveTexUnit, + verts, ctxInfo); + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + jfloat *vAttrPtr = &verts[vAttrOff]; + + for (i = 0; i < vertexAttrCount; i++) { + ctxProperties->enableVertexAttrArray(ctxProperties, i); + ctxProperties->vertexAttrPointer(ctxProperties, i, vAttrSizesPtr[i], + GL_FLOAT, bstride, vAttrPtr); + vAttrPtr += vAttrSizesPtr[i]; + } + } + } + + switch (geo_type) { + case GEO_TYPE_INDEXED_TRI_STRIP_SET : + primType = GL_TRIANGLE_STRIP; + break; + case GEO_TYPE_INDEXED_TRI_FAN_SET : + primType = GL_TRIANGLE_FAN; + break; + case GEO_TYPE_INDEXED_LINE_STRIP_SET : + primType = GL_LINE_STRIP; + break; + } + /* + fprintf(stderr, "strip_len = %d\n",strip_len); + for (i=0; i < strip_len;i++) { + fprintf(stderr, "strips[i] = %d\n",strips[i]); + } + */ + + lockArray(ctxProperties, vertexCount); + + if (ctxProperties->multi_draw_arrays_ext || ctxProperties->multi_draw_arrays_sun) { + if (strip_len > 100) { + multiDrawElementsIndices = (jint**)malloc(strip_len * sizeof(int*)); + allocated = 1; + } + else { + multiDrawElementsIndices =(jint**) &tmpDrawElementsIndices; + } + + offset = initialIndexIndex; + for (i=0; i < strip_len;i++) { + multiDrawElementsIndices[i] = &indices[offset]; + offset += countArray[i]; + } + ctxProperties->glMultiDrawElementsEXT(primType, countArray, GL_UNSIGNED_INT,(const void **)multiDrawElementsIndices, strip_len); + + } else { + offset = initialIndexIndex; + for (i=0; i < strip_len;i++) { + + glDrawElements(primType, countArray[i], GL_UNSIGNED_INT, &indices[offset]); + offset += countArray[i]; + } + } + (*(table->ReleasePrimitiveArrayCritical))(env, sarray, countArray, 0); + if (allocated) { + free(multiDrawElementsIndices); + } + + } + /******* Handle non-indexed non-striped GeometryArray now *****/ + else if ((geo_type == GEO_TYPE_INDEXED_QUAD_SET) || + (geo_type == GEO_TYPE_INDEXED_TRI_SET) || + (geo_type == GEO_TYPE_INDEXED_POINT_SET) || + (geo_type == GEO_TYPE_INDEXED_LINE_SET)) + { + if ((ignoreVertexColors == JNI_TRUE) || (carray != NULL) || + ((vformat & GA_TEXTURE_COORDINATE) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = 0; + } else { + INTERLEAVEDARRAYS_TEST() + } + if (useInterleavedArrays) { + glInterleavedArrays(iaFormat, bstride, verts); + } else { + if (vformat & GA_NORMALS) { + glNormalPointer(GL_FLOAT, bstride, &(verts[normoff])); + } + if (ignoreVertexColors == JNI_FALSE && vformat & GA_COLOR) { + if (vformat & GA_WITH_ALPHA || (useAlpha == GL_TRUE)) { + + glColorPointer(4, GL_FLOAT, cbstride, clrs); + } else { + glColorPointer(3, GL_FLOAT, cbstride, clrs); + } + } + if (vformat & GA_COORDINATES) { + glVertexPointer(3, GL_FLOAT, bstride, &(verts[coordoff])); + } + + if (vformat & GA_TEXTURE_COORDINATE) { + + /* XXXX: texCoordoff == 0 ???*/ + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + numActiveTexUnit, + verts, ctxInfo); + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + jfloat *vAttrPtr = &verts[vAttrOff]; + + for (i = 0; i < vertexAttrCount; i++) { + ctxProperties->enableVertexAttrArray(ctxProperties, i); + ctxProperties->vertexAttrPointer(ctxProperties, i, vAttrSizesPtr[i], + GL_FLOAT, bstride, vAttrPtr); + vAttrPtr += vAttrSizesPtr[i]; + } + } + } + + lockArray(ctxProperties, vertexCount); + + switch (geo_type){ + case GEO_TYPE_INDEXED_QUAD_SET : glDrawElements(GL_QUADS,indexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_TRI_SET : glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_POINT_SET : glDrawElements(GL_POINTS, indexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_LINE_SET: glDrawElements(GL_LINES, indexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + } + } + + unlockArray(ctxProperties); + + if (vformat & GA_VERTEX_ATTRIBUTES) { + resetVertexAttrs(ctxInfo, vertexAttrCount); + } + + if (vformat & GA_TEXTURE_COORDINATE) { + resetTexture(ctxInfo); + } + + /* clean up if we turned on normalize */ + + if (isNonUniformScale) { + glDisable(GL_NORMALIZE); + } + if(varray != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, varray, verts, 0); + + (*(table->ReleasePrimitiveArrayCritical))(env, indexCoord, indices, 0); + + if (carray != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, carray, clrs, 0); + + if (texCoordSetMapLen > 0) + (*(table->ReleasePrimitiveArrayCritical))(env, texUnitOffset, + texCoordSetMapOffset, 0); + + if (vAttrSizesPtr != NULL) { + table->ReleaseIntArrayElements(env, vertexAttrSizes, vAttrSizesPtr, JNI_ABORT); + } +} + +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_executeIndexedGeometry( + JNIEnv *env, + jobject obj, jlong ctxInfo, jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vertexCount, + jint vformat, + jint vertexAttrCount, jintArray vertexAttrSizes, + jint texCoordSetCount, + jintArray texCoordSetMap, jint texCoordSetMapLen, + jintArray texUnitOffset, + jint numActiveTexUnit, + jfloatArray varray, jfloatArray carray, + jint cDirty, + jintArray indexCoord) +{ + +#ifdef VERBOSE + fprintf(stderr, "IndexedGeometryArrayRetained.executeIndexedGeometry() -- calling executeIndexedGeometryArray\n"); +#endif /* VERBOSE */ + + executeIndexedGeometryArray(env, obj, ctxInfo, geo, geo_type, + isNonUniformScale, useAlpha, + ignoreVertexColors, + initialIndexIndex, + indexCount, + vertexCount, + vformat, + vertexAttrCount, vertexAttrSizes, + texCoordSetCount, + texCoordSetMap, texCoordSetMapLen, + texUnitOffset, + numActiveTexUnit, + varray, NULL, carray, + cDirty, + indexCoord); +} + +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_executeIndexedGeometryBuffer( + JNIEnv *env, + jobject obj, jlong ctxInfo, jobject geo, jint geo_type, + jboolean isNonUniformScale, jboolean useAlpha, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint indexCount, + jint vertexCount, + jint vformat, + jint texCoordSetCount, + jintArray texCoordSetMap, jint texCoordSetMapLen, + jintArray texUnitOffset, + jint numActiveTexUnit, + jobject varray, jfloatArray carray, + jint cDirty, + jintArray indexCoord) +{ + +#ifdef VERBOSE + fprintf(stderr, "IndexedGeometryArrayRetained.executeIndexedGeometryBuffer() -- calling executeIndexedGeometryArray\n"); +#endif /* VERBOSE */ + + executeIndexedGeometryArray(env, obj, ctxInfo, geo, geo_type, + isNonUniformScale, useAlpha, + ignoreVertexColors, + initialIndexIndex, + indexCount, + vertexCount, + vformat, + 0, NULL, + texCoordSetCount, + texCoordSetMap, texCoordSetMapLen, + texUnitOffset, + numActiveTexUnit, + NULL, varray, carray, + cDirty, + indexCoord); +} + + +static void +executeIndexedGeometryArrayVA( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint validIndexCount, + jint vertexCount, + jint vformat, + jint vdefined, + jfloat* fverts, + jdouble* dverts, + jfloat* fclrs, + jbyte* bclrs, + jfloat* norms, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jfloat ** vertexAttrPointer, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jint texStride, + jfloat** texCoordPointer, + jint cdirty, + jintArray indexCoord, + jarray sarray, + jsize strip_len) +{ + int primType; + JNIEnv table; + jint i; + jint* tmpDrawElementsIndices[100]; + jint** multiDrawElementsIndices = NULL; + jint allocated = 0; + jint *indices; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean vattrDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_VATTR_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + int texSet; + jint *texCoordSetMap; + GLsizei *countArray; + jint* vAttrSizes; + jint offset = 0; + + table = *env; + +#ifdef VERBOSE + fprintf(stderr, + "executeIndexedGeometryArrayVA: vertexAttrCount = %d\n", + vertexAttrCount); +#endif /* VERBOSE */ + + /* Enable normalize for non-uniform scale (which rescale can't handle) */ + if (isNonUniformScale) { + glEnable(GL_NORMALIZE); + } + + /* Define the data pointers */ + if (floatCoordDefined) { + glVertexPointer(3, GL_FLOAT, 0, fverts); + } else if (doubleCoordDefined){ + glVertexPointer(3, GL_DOUBLE, 0, dverts); + } + if (floatColorsDefined) { + if (vformat & GA_WITH_ALPHA) { + glColorPointer(4, GL_FLOAT, 0, fclrs); + } else { + glColorPointer(3, GL_FLOAT, 0, fclrs); + } + } else if (byteColorsDefined) { + if (vformat & GA_WITH_ALPHA) { + glColorPointer(4, GL_UNSIGNED_BYTE, 0, bclrs); + } else { + glColorPointer(3, GL_UNSIGNED_BYTE, 0, bclrs); + } + } + if (normalsDefined) { + glNormalPointer(GL_FLOAT, 0, norms); + } + + if (vattrDefined) { + float *pVertexAttrs; + int sz; + + vAttrSizes = (jint *) (*(table->GetPrimitiveArrayCritical))(env, vertexAttrSizes, NULL); + + for (i = 0; i < vertexAttrCount; i++) { + pVertexAttrs = vertexAttrPointer[i]; + sz = vAttrSizes[i]; + + ctxProperties->enableVertexAttrArray(ctxProperties, i); + ctxProperties->vertexAttrPointer(ctxProperties, i, sz, + GL_FLOAT, 0, + pVertexAttrs); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, vertexAttrSizes, vAttrSizes, 0); + } + + if (textureDefined) { + + int tus = 0; + float *ptexCoords; + + texCoordSetMap = (jint *) (*(table->GetPrimitiveArrayCritical))(env,tcoordsetmap, NULL); + for (i = 0; i < numActiveTexUnit; i++) { + if ((i < texCoordMapLength) && ( + ((texSet=texCoordSetMap[i]) != -1))) { + + ptexCoords = texCoordPointer[texSet]; + + enableTexCoordPointer(ctxProperties, i, texStride, + GL_FLOAT, 0, + ptexCoords); + + } else { + + disableTexCoordPointer(ctxProperties, i); + } + } + + /* Reset client active texture unit to 0 */ + clientActiveTextureUnit(ctxProperties, 0); + } + indices = (jint *) (*(table->GetPrimitiveArrayCritical))(env, indexCoord, NULL); + + lockArray(ctxProperties, vertexCount); + + if (geo_type == GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GEO_TYPE_INDEXED_LINE_STRIP_SET) { + + countArray = (GLint *) (*(table->GetPrimitiveArrayCritical))(env, sarray, + NULL); + + switch (geo_type) { + case GEO_TYPE_INDEXED_TRI_STRIP_SET : + primType = GL_TRIANGLE_STRIP; + break; + case GEO_TYPE_INDEXED_TRI_FAN_SET : + primType = GL_TRIANGLE_FAN; + break; + case GEO_TYPE_INDEXED_LINE_STRIP_SET : + primType = GL_LINE_STRIP; + break; + } + + + + if (ctxProperties->multi_draw_arrays_ext || ctxProperties->multi_draw_arrays_sun) { + if (strip_len > 100) { + multiDrawElementsIndices = (jint**)malloc(strip_len * sizeof(int*)); + allocated = 1; + } + else { + multiDrawElementsIndices = (jint**)&tmpDrawElementsIndices; + } + + offset = initialIndexIndex; + for (i=0; i < strip_len;i++) { + multiDrawElementsIndices[i] = &indices[offset]; + offset += countArray[i]; + } + ctxProperties->glMultiDrawElementsEXT(primType, countArray, GL_UNSIGNED_INT,(const void **)multiDrawElementsIndices, strip_len); + + } else { + offset = initialIndexIndex; + for (i=0; i < strip_len;i++) { + glDrawElements(primType, countArray[i], GL_UNSIGNED_INT, &indices[offset]); + offset += countArray[i]; + } + } + + (*(table->ReleasePrimitiveArrayCritical))(env, sarray, countArray, 0); + if (allocated) { + free(multiDrawElementsIndices); + } + } + else { + switch (geo_type){ + case GEO_TYPE_INDEXED_QUAD_SET : glDrawElements(GL_QUADS,validIndexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_TRI_SET : glDrawElements(GL_TRIANGLES, validIndexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_POINT_SET : glDrawElements(GL_POINTS, validIndexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_LINE_SET: glDrawElements(GL_LINES, validIndexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + } + } + + unlockArray(ctxProperties); + + /* clean up if we turned on normalize */ + if (isNonUniformScale) { + glDisable(GL_NORMALIZE); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, indexCoord, indices, 0); + + if (vattrDefined) { + resetVertexAttrs(ctxInfo, vertexAttrCount); + } + + if (textureDefined) { + resetTexture(ctxInfo); + + (*(table->ReleasePrimitiveArrayCritical))(env, tcoordsetmap, texCoordSetMap, 0); + } +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeIndexedGeometryVA( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint validIndexCount, + jint vertexCount, + jint vformat, + jint vdefined, + jfloatArray vfcoords, + jdoubleArray vdcoords, + jfloatArray cfdata, + jbyteArray cbdata, + jfloatArray ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jint texStride, + jobjectArray texCoords, + jint cdirty, + jintArray indexCoord) +{ + jfieldID strip_field; + jarray sarray; + jsize strip_len; + JNIEnv table; + jint i; + jclass geo_class; + + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jbyte *bclrs = NULL; + jfloat *fclrs = NULL, *norms = NULL; + jarray *vaobjs = NULL; + jfloat **vertexAttrPointer = NULL; + jfloat **texCoordPointer = NULL; + jarray *texobjs = NULL; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean vattrDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_VATTR_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + table = *env; + + if (vattrDefined) { + vaobjs = (jarray *)malloc(vertexAttrCount * sizeof(jarray)); + vertexAttrPointer = (jfloat **)malloc(vertexAttrCount * sizeof(jfloat *)); + + for (i = 0; i < vertexAttrCount; i++) { + vaobjs[i] = (*(table->GetObjectArrayElement))(env, vertexAttrData, i); + } + } + + if (textureDefined) { + texobjs = (jarray*)malloc(texCoordMapLength * sizeof(jarray)); + texCoordPointer = (jfloat**)malloc(texCoordMapLength * sizeof(jfloat*)); + + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (jarray)(*(table->GetObjectArrayElement))(env, texCoords, i); + } + } + + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + if (geo_type == GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GEO_TYPE_INDEXED_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripIndexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + + } + + /* Get vertex attribute arrays */ + if (vattrDefined) { + for (i = 0; i < vertexAttrCount; i++) { + vertexAttrPointer[i] = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, vaobjs[i], NULL); + } + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)(*(table->GetPrimitiveArrayCritical))(env,texobjs[i], NULL); + else + texCoordPointer[i] = NULL; + + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts= (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, vfcoords, NULL); + } else if (doubleCoordDefined) { + dverts= (jdouble *) (*(table->GetPrimitiveArrayCritical))(env, vdcoords, NULL); + } + + /* get color array */ + if (floatColorsDefined) { + fclrs = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, cfdata, NULL); + } else if (byteColorsDefined) { + bclrs = (jbyte *) (*(table->GetPrimitiveArrayCritical))(env, cbdata, NULL); + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env,ndata, NULL); + } + +#ifdef VERBOSE + fprintf(stderr, "IndexedGeometryArrayRetained.executeIndexedGeometryVA() -- calling executeIndexedGeometryArrayVA\n"); +#endif /* VERBOSE */ + + executeIndexedGeometryArrayVA(env, + obj, + ctxInfo, + geo, + geo_type, + isNonUniformScale, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + vertexCount, + vformat, + vdefined, + fverts, + dverts, + fclrs, + bclrs, + norms, + vertexAttrCount, + vertexAttrSizes, + vertexAttrPointer, + texCoordMapLength, + tcoordsetmap, + numActiveTexUnit, + texStride, + texCoordPointer, + cdirty, + indexCoord, + sarray, + strip_len); + + if (floatCoordDefined) { + (*(table->ReleasePrimitiveArrayCritical))(env, vfcoords, fverts, 0); + } + else if (doubleCoordDefined) { + (*(table->ReleasePrimitiveArrayCritical))(env, vdcoords, dverts, 0); + } + + if (floatColorsDefined) { + (*(table->ReleasePrimitiveArrayCritical))(env, cfdata, fclrs, 0); + } + else if (byteColorsDefined) { + (*(table->ReleasePrimitiveArrayCritical))(env, cbdata, bclrs, 0); + } + + if (normalsDefined) { + (*(table->ReleasePrimitiveArrayCritical))(env, ndata, norms, 0); + } + + if (vattrDefined) { + for (i = 0; i < vertexAttrCount; i++) { + (*(table->ReleasePrimitiveArrayCritical))(env, vaobjs[i], vertexAttrPointer[i], 0); + } + } + + if (vaobjs != NULL) { + free(vaobjs); + } + if (vertexAttrPointer != NULL) { + free(vertexAttrPointer); + } + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texCoordPointer[i] != NULL) { + (*(table->ReleasePrimitiveArrayCritical))(env, texobjs[i], texCoordPointer[i], 0); + } + } + } + + if (texobjs != NULL) { + free(texobjs); + } + if (texCoordPointer != NULL) { + free(texCoordPointer); + } +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_executeIndexedGeometryVABuffer( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint validIndexCount, + jint vertexCount, + jint vformat, + jint vdefined, + jobject vcoords, + jobject cdataBuffer, + jfloatArray cfdata, + jbyteArray cbdata, + jobject ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jint numActiveTexUnit, + jint texStride, + jobjectArray texCoords, + jint cdirty, + jintArray indexCoord) +{ + jfieldID strip_field; + jarray sarray; + jsize strip_len; + JNIEnv table; + jint i; + jclass geo_class; + + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jbyte *bclrs = NULL; + jfloat *fclrs = NULL, *norms = NULL; + jarray *vaobjs = NULL; + jfloat **vertexAttrPointer = NULL; + jfloat **texCoordPointer = NULL; + jarray *texobjs = NULL; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean vattrDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_VATTR_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + table = *env; + + if (vattrDefined) { + vaobjs = (jarray *)malloc(vertexAttrCount * sizeof(jarray)); + vertexAttrPointer = (jfloat **)malloc(vertexAttrCount * sizeof(jfloat *)); + + for (i = 0; i < vertexAttrCount; i++) { + vaobjs[i] = (*(table->GetObjectArrayElement))(env, vertexAttrData, i); + } + } + + if (textureDefined) { + texobjs = (jarray *)malloc(texCoordMapLength * sizeof(jarray)); + texCoordPointer = (jfloat **)malloc(texCoordMapLength * sizeof(jfloat *)); + + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (jarray)(*(table->GetObjectArrayElement))(env, texCoords, i); + } + } + + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + if (geo_type == GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GEO_TYPE_INDEXED_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripIndexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + + } + + /* Get vertex attribute arrays */ + if (vattrDefined) { + for (i = 0; i < vertexAttrCount; i++) { + vertexAttrPointer[i] = (jfloat *) (*(table->GetDirectBufferAddress))(env, vaobjs[i]); + } + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)(*(table->GetDirectBufferAddress))(env,texobjs[i]); + else + texCoordPointer[i] = NULL; + + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + fverts= (jfloat *)(*(table->GetDirectBufferAddress))(env, vcoords ); + } else if (doubleCoordDefined) { + dverts= (jdouble *)(*(table->GetDirectBufferAddress))(env, vcoords ); + } + + /* get color array */ + if (floatColorsDefined) { + if(cfdata != NULL) + fclrs = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, cfdata, NULL); + else + fclrs = (jfloat *)(*(table->GetDirectBufferAddress))(env, cdataBuffer); + } + else if (byteColorsDefined) { + if(cbdata != NULL) + bclrs = (jbyte *) (*(table->GetPrimitiveArrayCritical))(env, cbdata, NULL); + else + bclrs = (jbyte *)(*(table->GetDirectBufferAddress))(env, cdataBuffer); + } + + /* get normal array */ + if (normalsDefined) { + norms = (jfloat *)(*(table->GetDirectBufferAddress))(env, ndata); + } + +#ifdef VERBOSE + fprintf(stderr, "IndexedGeometryArrayRetained.executeIndexedGeometryVABuffer() -- calling executeIndexedGeometryArrayVA\n"); +#endif /* VERBOSE */ + + executeIndexedGeometryArrayVA(env, + obj, + ctxInfo, + geo, + geo_type, + isNonUniformScale, + ignoreVertexColors, + initialIndexIndex, + validIndexCount, + vertexCount, + vformat, + vdefined, + fverts, + dverts, + fclrs, + bclrs, + norms, + vertexAttrCount, + vertexAttrSizes, + vertexAttrPointer, + texCoordMapLength, + tcoordsetmap, + numActiveTexUnit, + texStride, + texCoordPointer, + cdirty, + indexCoord, + sarray, + strip_len); + + if(floatColorsDefined && cfdata != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, cfdata, fclrs, 0); + else if(byteColorsDefined && cbdata != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, cbdata, bclrs, 0); + + if (vaobjs != NULL) { + free(vaobjs); + } + if (vertexAttrPointer != NULL) { + free(vertexAttrPointer); + } + + if (texobjs != NULL) { + free(texobjs); + } + if (texCoordPointer != NULL) { + free(texCoordPointer); + } +} + +JNIEXPORT void JNICALL +Java_javax_media_j3d_NativePipeline_buildIndexedGeometry( + JNIEnv *env, + jobject obj, jlong ctxInfo, jobject geo, + jint geo_type, + jboolean isNonUniformScale, jboolean updateAlpha, float alpha, + jboolean ignoreVertexColors, + jint initialIndexIndex, + jint validIndexCount, + jint vertexCount, + jint vformat, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jint texCoordSetCount, + jintArray texCoordSetMapArray, + jint texCoordSetMapLen, + jintArray texUnitOffset, + jdoubleArray xform, jdoubleArray nxform, + jfloatArray varray, jintArray indexCoord) +{ + jclass geo_class; + JNIEnv table; + jboolean useAlpha = JNI_FALSE; + + jfloat *verts; + jint *indices; + jint i; + jint bstride; + jint texStride, *texCoordSetMapOffset, texSize; + GLsizei *countArray; + GLenum iaFormat; + int useInterleavedArrays; + jsize strip_len; + int primType; + jint stride, coordoff, normoff, coloroff, texCoordoff; + jfieldID strip_field; + jarray sarray; + jdouble *xform_ptr = NULL; + jdouble *nxform_ptr = NULL; + jfloat *tmpCoordArray = NULL, *tmpNormalArray = NULL; + jint* tmpDrawElementsIndices[100]; + + jint** multiDrawElementsIndices = NULL; + jint allocated = 0; + int offset = 0; + int vAttrStride = 0; + int vAttrOff; + jint *vAttrSizesPtr = NULL; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + +#ifdef VERBOSE + fprintf(stderr, "IndexedGeometryArrayRetained.buildIndexedGeometry()\n"); +#endif /* VERBOSE */ + + table = *env; + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + /* This matches the code in GeometryArrayRetained.java */ + stride = coordoff = normoff = coloroff = texCoordoff = 0; + vAttrOff = 0; + if ((vformat & GA_COORDINATES) != 0) { + glEnableClientState(GL_VERTEX_ARRAY); + stride += 3; + } + else { + glDisableClientState(GL_VERTEX_ARRAY); + } + + if ((vformat & GA_NORMALS) != 0) { + glEnableClientState(GL_NORMAL_ARRAY); + stride += 3; + coordoff += 3; + } + else { + glDisableClientState(GL_NORMAL_ARRAY); + } + + if ((vformat & GA_COLOR) != 0) { + glEnableClientState(GL_COLOR_ARRAY); + stride += 4; + normoff += 4; + coordoff += 4; + } + else { + glDisableClientState(GL_COLOR_ARRAY); + } + + if ((vformat & GA_TEXTURE_COORDINATE) != 0) { + if ((vformat & GA_TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GA_TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GA_TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + if ((vformat & GA_VERTEX_ATTRIBUTES) != 0) { + if (vertexAttrSizes != NULL) { + vAttrSizesPtr = table->GetIntArrayElements(env, vertexAttrSizes, NULL); + } + for (i = 0; i < vertexAttrCount; i++) { + vAttrStride += vAttrSizesPtr[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride*sizeof(float); + + /* + * process alpha for geometryArray without alpha + */ + if (updateAlpha == JNI_TRUE && ignoreVertexColors == JNI_FALSE) { + useAlpha = JNI_TRUE; + } + + /* + * call other JNI functions before entering Critical region + * i.e., GetPrimitiveArrayCritical + */ + if (geo_type == GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GEO_TYPE_INDEXED_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripIndexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + } + + + + /* begin critical region */ + verts = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, varray, NULL); + + indices = (jint *) (*(table->GetPrimitiveArrayCritical))(env, indexCoord, NULL); + + if (texCoordSetMapLen >0) { + texCoordSetMapOffset = (jint *)(*(table->GetPrimitiveArrayCritical)) + (env, texUnitOffset, NULL); + } + + + /* get the static transform if exists */ + if (xform != NULL) { + xform_ptr = (jdouble *) (*(table->GetPrimitiveArrayCritical))( + env, xform, NULL); + + } + + + /* get the static normals transform if exists */ + if (nxform != NULL) { + nxform_ptr = (jdouble *) (*(table->GetPrimitiveArrayCritical))( + env, nxform, NULL); + } + + + /* + * Check if normal is present and nxform_ptr id non-null, if yes, + * create a new normal array and apply the xform + */ + if ((vformat & GA_NORMALS) != 0 && (nxform_ptr != NULL)) { + /* create a temporary array for normals */ + tmpNormalArray = (jfloat*) malloc(vertexCount * sizeof(float) * 3); + for (i = 0; i < vertexCount*3; i+=3) { + tmpNormalArray[i] = (float) (nxform_ptr[0] * verts[normoff] + + nxform_ptr[1] * verts[normoff+1] + + nxform_ptr[2] * verts[normoff+2]); + tmpNormalArray[i+1] = (float) (nxform_ptr[4] * verts[normoff] + + nxform_ptr[5] * verts[normoff+1] + + nxform_ptr[6] * verts[normoff+2]); + tmpNormalArray[i+2] = (float) (nxform_ptr[8] * verts[normoff] + + nxform_ptr[9] * verts[normoff+1] + + nxform_ptr[10] * verts[normoff+2]); + normoff += stride; + } + } + + if ((vformat & GA_COORDINATES) != 0 && xform_ptr != NULL) { + /* create a temporary array for normals */ + tmpCoordArray = (jfloat*) malloc(vertexCount * sizeof(float) * 3); + for (i = 0; i < vertexCount*3; i+=3) { + tmpCoordArray[i] = (float) (xform_ptr[0] * verts[coordoff] + + xform_ptr[1] * verts[coordoff+1] + + xform_ptr[2] * verts[coordoff+2]); + tmpCoordArray[i+1] = (float) (xform_ptr[4] * verts[coordoff] + + xform_ptr[5] * verts[coordoff+1] + + xform_ptr[6] * verts[coordoff+2]); + tmpCoordArray[i+2] = (float) (xform_ptr[8] * verts[coordoff] + + xform_ptr[9] * verts[coordoff+1] + + xform_ptr[10] * verts[coordoff+2]); + coordoff += stride; + } + } + + + if (geo_type == GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GEO_TYPE_INDEXED_LINE_STRIP_SET) { + + + switch (geo_type) { + case GEO_TYPE_INDEXED_TRI_STRIP_SET : + primType = GL_TRIANGLE_STRIP; + break; + case GEO_TYPE_INDEXED_TRI_FAN_SET : + primType = GL_TRIANGLE_FAN; + break; + case GEO_TYPE_INDEXED_LINE_STRIP_SET : + primType = GL_LINE_STRIP; + break; + } + + + countArray = (GLsizei *) (*(table->GetPrimitiveArrayCritical))(env, sarray, + NULL); + + if ((ignoreVertexColors == JNI_TRUE) || (xform_ptr != NULL) || + ((vformat & GA_TEXTURE_COORDINATE) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = 0; + } else { + INTERLEAVEDARRAYS_TEST() + } + + if (useInterleavedArrays) { + glInterleavedArrays(iaFormat, bstride, verts); + } else { + if (vformat & GA_NORMALS) { + if (nxform_ptr == NULL) { + glNormalPointer(GL_FLOAT, bstride, &(verts[normoff])); + } + else { + glNormalPointer(GL_FLOAT, 3 * sizeof(float), tmpNormalArray); + } + } + if (ignoreVertexColors == JNI_FALSE && vformat & GA_COLOR) { + if (vformat & GA_WITH_ALPHA || (useAlpha == GL_TRUE)) { + glColorPointer(4, GL_FLOAT, bstride, &(verts[coloroff])); + } else { + /* + for (i = 0; i < vcount; i++) { + fprintf(stderr, "r = %f, g = %f, b = %f\n", verts[i*bstride +coloroff], verts[i*bstride +coloroff+1],verts[i*bstride +coloroff+2]); + } + */ + glColorPointer(3, GL_FLOAT, bstride, &(verts[coloroff])); + } + } + if (vformat & GA_COORDINATES) { + if (xform_ptr == NULL) { + /* + for (i = 0; i < vcount; i++) { + fprintf(stderr, "x = %f, y = %f, z = %f\n", verts[i*bstride +coordoff], verts[i*bstride +coordoff+1],verts[i*bstride +coordoff+2]); + } + */ + glVertexPointer(3, GL_FLOAT, bstride, &(verts[coordoff])); + } + else { + glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), tmpCoordArray); + } + } + + if (vformat & GA_TEXTURE_COORDINATE) { + + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + texCoordSetMapLen, + verts, ctxInfo); + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + jfloat *vAttrPtr = &verts[vAttrOff]; + + for (i = 0; i < vertexAttrCount; i++) { + ctxProperties->enableVertexAttrArray(ctxProperties, i); + ctxProperties->vertexAttrPointer(ctxProperties, i, vAttrSizesPtr[i], + GL_FLOAT, bstride, vAttrPtr); + vAttrPtr += vAttrSizesPtr[i]; + } + } + } + + switch (geo_type) { + case GEO_TYPE_INDEXED_TRI_STRIP_SET : + primType = GL_TRIANGLE_STRIP; + break; + case GEO_TYPE_INDEXED_TRI_FAN_SET : + primType = GL_TRIANGLE_FAN; + break; + case GEO_TYPE_INDEXED_LINE_STRIP_SET : + primType = GL_LINE_STRIP; + break; + } + + lockArray(ctxProperties, vertexCount); + + if (ctxProperties->multi_draw_arrays_ext || ctxProperties->multi_draw_arrays_sun) { + if (strip_len > 100) { + multiDrawElementsIndices = (jint**)malloc(strip_len * sizeof(int*)); + allocated = 1; + } + else { + multiDrawElementsIndices =(jint**) &tmpDrawElementsIndices; + } + + offset = initialIndexIndex; + for (i=0; i < strip_len;i++) { + multiDrawElementsIndices[i] = &indices[offset]; + offset += countArray[i]; + } + ctxProperties->glMultiDrawElementsEXT(primType, countArray, GL_UNSIGNED_INT,(const void **)multiDrawElementsIndices, strip_len); + + } else { + offset = initialIndexIndex; + for (i=0; i < strip_len;i++) { + glDrawElements(primType, countArray[i], GL_UNSIGNED_INT, &indices[offset]); + offset += countArray[i]; + } + } + (*(table->ReleasePrimitiveArrayCritical))(env, sarray, countArray, 0); + if (allocated) { + free(multiDrawElementsIndices); + } + + + } + else if ((geo_type == GEO_TYPE_INDEXED_QUAD_SET) || + (geo_type == GEO_TYPE_INDEXED_TRI_SET) || + (geo_type == GEO_TYPE_INDEXED_POINT_SET) || + (geo_type == GEO_TYPE_INDEXED_LINE_SET)) { + + switch (geo_type) { + case GEO_TYPE_INDEXED_QUAD_SET : + primType = GL_QUADS; + break; + case GEO_TYPE_INDEXED_TRI_SET : + primType = GL_TRIANGLES; + break; + case GEO_TYPE_INDEXED_POINT_SET : + primType = GL_POINTS; + break; + case GEO_TYPE_INDEXED_LINE_SET : + primType = GL_LINES; + break; + + } + + if ((ignoreVertexColors == JNI_TRUE) || (xform_ptr != NULL) || + ((vformat & GA_TEXTURE_COORDINATE) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = 0; + } else { + INTERLEAVEDARRAYS_TEST() + } + + if (useInterleavedArrays) { + glInterleavedArrays(iaFormat, bstride, verts); + } else { + if (vformat & GA_NORMALS) { + + if (nxform_ptr == NULL) { + glNormalPointer(GL_FLOAT, bstride, &(verts[normoff])); + } + else { + glNormalPointer(GL_FLOAT, 3 * sizeof(float), tmpNormalArray); + } + } + if (ignoreVertexColors == JNI_FALSE && vformat & GA_COLOR) { + if (vformat & GA_WITH_ALPHA || (useAlpha == GL_TRUE)) { + glColorPointer(4, GL_FLOAT, bstride, &(verts[coloroff])); + } else { + glColorPointer(3, GL_FLOAT, bstride, &(verts[coloroff])); + } + } + if (vformat & GA_COORDINATES) { + + if (xform_ptr == NULL) { + glVertexPointer(3, GL_FLOAT, bstride, &(verts[coordoff])); + } + else { + glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), tmpCoordArray); + } + } + + if (vformat & GA_TEXTURE_COORDINATE) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + texCoordSetMapLen, + verts, ctxInfo); + } + + if (vformat & GA_VERTEX_ATTRIBUTES) { + jfloat *vAttrPtr = &verts[vAttrOff]; + + for (i = 0; i < vertexAttrCount; i++) { + ctxProperties->enableVertexAttrArray(ctxProperties, i); + ctxProperties->vertexAttrPointer(ctxProperties, i, vAttrSizesPtr[i], + GL_FLOAT, bstride, vAttrPtr); + vAttrPtr += vAttrSizesPtr[i]; + } + } + } + lockArray(ctxProperties, vertexCount); + switch (geo_type){ + case GEO_TYPE_INDEXED_QUAD_SET : glDrawElements(GL_QUADS,validIndexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_TRI_SET : glDrawElements(GL_TRIANGLES, validIndexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_POINT_SET : glDrawElements(GL_POINTS, validIndexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + case GEO_TYPE_INDEXED_LINE_SET: glDrawElements(GL_LINES, validIndexCount, GL_UNSIGNED_INT, &indices[initialIndexIndex]);break; + } + } + + unlockArray(ctxProperties); + + if (vformat & GA_VERTEX_ATTRIBUTES) { + resetVertexAttrs(ctxInfo, vertexAttrCount); + } + + if (vformat & GA_TEXTURE_COORDINATE) { + resetTexture(ctxInfo); + } + + if (tmpNormalArray != NULL) { + free(tmpNormalArray); + } + if (tmpCoordArray != NULL) { + free(tmpCoordArray); + } + + (*(table->ReleasePrimitiveArrayCritical))(env, varray, verts, 0); + + (*(table->ReleasePrimitiveArrayCritical))(env, indexCoord, indices, 0); + + + if (texCoordSetMapLen > 0) + (*(table->ReleasePrimitiveArrayCritical))(env, texUnitOffset, + texCoordSetMapOffset, 0); + + if (xform_ptr != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, xform, xform_ptr, 0); + + if (nxform_ptr != NULL) + (*(table->ReleasePrimitiveArrayCritical))(env, nxform, nxform_ptr, 0); + + if (vAttrSizesPtr != NULL) { + table->ReleaseIntArrayElements(env, vertexAttrSizes, vAttrSizesPtr, JNI_ABORT); + } +} + + +/* execute geometry array with java array format */ +/* + * Class: javax_media_j3d_GeometryArrayRetained + * Method: buildGAForByRef + * Signature: (JLjavax/media/j3d/GeometryArrayRetained;IZZFZIIII[F[DI[F[BI[FI[I[I[[FI[I[II[Ljava/lang/Object;[D[D)V + */ +JNIEXPORT void JNICALL Java_javax_media_j3d_NativePipeline_buildGAForByRef( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean updateAlpha, + jfloat alpha, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jfloatArray vfcoords, + jdoubleArray vdcoords, + jint initialColorIndex, + jfloatArray cfdata, + jbyteArray cbdata, + jint initialNormalIndex, + jfloatArray ndata, + jint vertexAttrCount, + jintArray vertexAttrSizes, + jintArray vertexAttrIndices, + jobjectArray vertexAttrData, + jint texCoordMapLength, + jintArray tcoordsetmap, + jintArray texindices, + jint texStride, + jobjectArray texCoords, + jdoubleArray xform, + jdoubleArray nxform) +{ + jclass geo_class; + JNIEnv table; + jboolean useAlpha = JNI_FALSE; + jfieldID strip_field; + jarray sarray; + jint i; + jsize strip_len; + jarray start_array; + jfieldID start_field; + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jbyte *bclrs = NULL; + jfloat *fclrs = NULL, *norms = NULL; + jdouble *xform_ptr = NULL; + jdouble *nxform_ptr = NULL; + jfloat *tmpFloatCoordArray = NULL, *tmpNormalArray = NULL, *tmpFloatColors = NULL; + jdouble *tmpDoubleCoordArray = NULL; + jbyte* tmpByteColors= NULL; + jfloat* fvptr = NULL, *nptr = NULL, *fcptr = NULL; + jdouble* dvptr = NULL; + jbyte* bcptr = NULL; + jarray *vaobjs = NULL; + jfloat **vertexAttrPointer = NULL; + jfloat **texCoordPointer = NULL; + jarray *texobjs = NULL; + int offset = 0; + + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean vattrDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_VATTR_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + table = *env; + + if (vattrDefined) { + vaobjs = (jarray *)malloc(vertexAttrCount * sizeof(jarray)); + vertexAttrPointer = (jfloat **)malloc(vertexAttrCount * sizeof(jfloat *)); + + for (i = 0; i < vertexAttrCount; i++) { + vaobjs[i] = (*(table->GetObjectArrayElement))(env, vertexAttrData, i); + } + } + + if (textureDefined) { + texobjs = (jarray*)malloc(texCoordMapLength * sizeof(jarray)); + texCoordPointer = (jfloat**)malloc(texCoordMapLength * sizeof(jfloat*)); + + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (*(table->GetObjectArrayElement))(env, texCoords, i); + } + } + + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + /* + * process alpha for geometryArray without alpha + */ + if (updateAlpha == JNI_TRUE && ignoreVertexColors== JNI_FALSE) { + useAlpha = JNI_TRUE; + } + + /* + * call other JNI functions before entering Critical region + * i.e., GetPrimitiveArrayCritical + */ + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripVertexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + start_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripStartOffsetIndices", "[I"); + start_array = (jarray)(*(table->GetObjectField))(env, geo, + start_field); + } + + if (ignoreVertexColors == JNI_TRUE) { + vformat &= ~GA_COLOR; + floatColorsDefined = JNI_FALSE; + byteColorsDefined = JNI_FALSE; + } + + /* get vertex attr arrays */ + if (vattrDefined) { + for (i = 0; i < vertexAttrCount; i++) { + vertexAttrPointer[i] = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, vaobjs[i], NULL); + } + } + + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)(*(table->GetPrimitiveArrayCritical))(env,texobjs[i], NULL); + else + texCoordPointer[i] = NULL; + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + glEnableClientState(GL_VERTEX_ARRAY); + fverts= (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, vfcoords, NULL); + fvptr = fverts; + } else if (doubleCoordDefined) { + glEnableClientState(GL_VERTEX_ARRAY); + dverts= (jdouble *) (*(table->GetPrimitiveArrayCritical))(env, vdcoords, NULL); + dvptr = dverts; + } + else { + glDisableClientState(GL_VERTEX_ARRAY); + } + + /* get color array */ + if (floatColorsDefined) { + glEnableClientState(GL_COLOR_ARRAY); + fclrs = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env, cfdata, NULL); + fcptr = fclrs; + } else if (byteColorsDefined) { + glEnableClientState(GL_COLOR_ARRAY); + bclrs = (jbyte *) (*(table->GetPrimitiveArrayCritical))(env, cbdata, NULL); + bcptr = bclrs; + } + else { + glDisableClientState(GL_COLOR_ARRAY); + } + /* get normal array */ + if (normalsDefined) { + glEnableClientState(GL_NORMAL_ARRAY); + norms = (jfloat *) (*(table->GetPrimitiveArrayCritical))(env,ndata, NULL); + nptr = norms; + } + else { + glDisableClientState(GL_NORMAL_ARRAY); + } + + /* get the static transform if exists */ + if (xform != NULL) { + xform_ptr = (jdouble *) (*(table->GetPrimitiveArrayCritical))( + env, xform, NULL); + + } + + + /* get the static normals transform if exists */ + if (nxform != NULL) { + nxform_ptr = (jdouble *) (*(table->GetPrimitiveArrayCritical))( + env, nxform, NULL); + } + + /* + * Check if normal is present and nxform_ptr id non-null, if yes, + * create a new normal array and apply the xform + */ + if (normalsDefined) { + if(nxform_ptr != NULL) { + /* create a temporary array for normals */ + tmpNormalArray = (jfloat*) malloc(vcount * sizeof(float) * 3); + for (i = initialNormalIndex; i < vcount*3; i+=3) { + tmpNormalArray[i] = (float) (nxform_ptr[0] * norms[i] + + nxform_ptr[1] * norms[i+1] + + nxform_ptr[2] * norms[i+2]); + tmpNormalArray[i+1] = (float) (nxform_ptr[4] * norms[i] + + nxform_ptr[5] * norms[i+1] + + nxform_ptr[6] * norms[i+2]); + tmpNormalArray[i+2] = (float) (nxform_ptr[8] * norms[i] + + nxform_ptr[9] * norms[i+1] + + nxform_ptr[10] * norms[i+2]); + } + nptr = tmpNormalArray; + } + + } + + if (xform_ptr != NULL) { + if (floatCoordDefined) { + /* create a temporary array for normals */ + tmpFloatCoordArray = (jfloat*) malloc(vcount * sizeof(float) * 3); + for (i = initialCoordIndex; i < vcount*3; i+=3) { + tmpFloatCoordArray[i] = (float) (xform_ptr[0] * fverts[i] + + xform_ptr[1] * fverts[i+1] + + xform_ptr[2] * fverts[i+2]); + tmpFloatCoordArray[i+1] = (float) (xform_ptr[4] * fverts[i] + + xform_ptr[5] * fverts[i+1] + + xform_ptr[6] * fverts[i+2]); + tmpFloatCoordArray[i+2] = (float) (xform_ptr[8] * fverts[i] + + xform_ptr[9] * fverts[i+1] + + xform_ptr[10] * fverts[i+2]); + } + fvptr = tmpFloatCoordArray; + } + else { + tmpDoubleCoordArray = (jdouble*) malloc(vcount * sizeof(double) * 3); + for (i = initialCoordIndex; i < vcount*3; i+=3) { + tmpDoubleCoordArray[i] = (double) (xform_ptr[0] * dverts[i] + + xform_ptr[1] * dverts[i+1] + + xform_ptr[2] * dverts[i+2]); + tmpDoubleCoordArray[i+1] = (double) (xform_ptr[4] * dverts[i] + + xform_ptr[5] * dverts[i+1] + + xform_ptr[6] * dverts[i+2]); + tmpDoubleCoordArray[i+2] = (double) (xform_ptr[8] * dverts[i] + + xform_ptr[9] * dverts[i+1] + + xform_ptr[10] * dverts[i+2]); + } + dvptr = tmpDoubleCoordArray; + } + + } + /* + fprintf(stderr, "floatColorsDefined = %d, useAlpha = %d\n", + floatColorsDefined,useAlpha); + */ + if (floatColorsDefined && useAlpha) { + tmpFloatColors = (jfloat*)malloc(vcount*sizeof(float) * 4); + if ((vformat & GA_WITH_ALPHA) != 0) { + /* fprintf(stderr, "with Alpha\n") */ + for (i = initialColorIndex; i < vcount*4; i+=4) { + tmpFloatColors[i] = fclrs[i]; + tmpFloatColors[i+1] = fclrs[i+1]; + tmpFloatColors[i+2] = fclrs[i+2]; + tmpFloatColors[i+3] = (float)(alpha* fclrs[i+3]); + } + } + else { + /* fprintf(stderr, "without Alpha\n") */ + int k = 0; + for (i = initialColorIndex; i < vcount*4; i+=4) { + tmpFloatColors[i] = fclrs[k++]; + tmpFloatColors[i+1] = fclrs[k++]; + tmpFloatColors[i+2] = fclrs[k++]; + tmpFloatColors[i+3] = (float)(alpha); + } + } + fcptr = tmpFloatColors; + vformat |= GA_WITH_ALPHA; + } + else if (byteColorsDefined && useAlpha) { + tmpByteColors = (jbyte*)malloc(vcount*sizeof(jbyte) * 4); + if ((vformat & GA_WITH_ALPHA) != 0) { + for (i = initialColorIndex; i < vcount*4; i+=4) { + tmpByteColors[i] = bclrs[i]; + tmpByteColors[i+1] = bclrs[i+1]; + tmpByteColors[i+2] =bclrs[i+2]; + tmpByteColors[i+3] = (jbyte) (alpha * ((int)bclrs[i+3] & 0xff)); + } + } + else { + int k = 0; + for (i = initialColorIndex; i < vcount*4; i+=4) { + tmpByteColors[i] = bclrs[k++]; + tmpByteColors[i+1] = bclrs[k++]; + tmpByteColors[i+2] =bclrs[k++]; + tmpByteColors[i+3] = (jbyte) (alpha * 255.0); + } + } + bcptr = tmpByteColors; + vformat |= GA_WITH_ALPHA; + + } + +#ifdef VERBOSE + fprintf(stderr, "GeometryArrayRetained.buildGAForByRef() -- calling executeGeometryArrayVA\n"); +#endif /* VERBOSE */ + + executeGeometryArrayVA(env, obj, ctxInfo, geo, geo_type, isNonUniformScale, + ignoreVertexColors, vcount, vformat, vdefined, + initialCoordIndex, fvptr, dvptr, initialColorIndex, + fcptr, bcptr, initialNormalIndex, + nptr, vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrPointer, texCoordMapLength, + tcoordsetmap, texCoordMapLength, + texindices, texStride, texCoordPointer, 0, sarray, + strip_len, start_array); + + if (vattrDefined) { + for (i = 0; i < vertexAttrCount; i++) { + (*(table->ReleasePrimitiveArrayCritical))(env, vaobjs[i], vertexAttrPointer[i], 0); + } + } + + if (vaobjs != NULL) { + free(vaobjs); + } + if (vertexAttrPointer != NULL) { + free(vertexAttrPointer); + } + + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texCoordPointer[i] != NULL) { + (*(table->ReleasePrimitiveArrayCritical))(env, texobjs[i], texCoordPointer[i], 0); + } + } + } + + if (texobjs != NULL) { + free(texobjs); + } + if (texCoordPointer != NULL) { + free(texCoordPointer); + } + + if (normalsDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, ndata, norms, 0); + if (tmpNormalArray != NULL) { + free(tmpNormalArray); + } + } + + + if (floatColorsDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, cfdata, fclrs, 0); + if (tmpFloatColors != NULL) { + free(tmpFloatColors); + } + } + else if (byteColorsDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, cbdata, bclrs, 0); + if (tmpByteColors != NULL) { + free(tmpByteColors); + } + } + + + if (floatCoordDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, vfcoords, fverts, 0); + if (tmpFloatCoordArray != NULL) { + free(tmpFloatCoordArray); + } + } + else if (doubleCoordDefined) { + (*env)->ReleasePrimitiveArrayCritical(env, vdcoords, dverts, 0); + if (tmpDoubleCoordArray != NULL) { + free(tmpDoubleCoordArray); + } + } +} + + +/* NOTE: NIO buffers are no longer supported in display lists. */ +#if 0 +/* execute geometry array with java array format */ +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_buildGAForBuffer( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jobject geo, + jint geo_type, + jboolean isNonUniformScale, + jboolean updateAlpha, + jfloat alpha, + jboolean ignoreVertexColors, + jint vcount, + jint vformat, + jint vdefined, + jint initialCoordIndex, + jobject vcoords, + jint initialColorIndex, + jobject cdataBuffer, + jint initialNormalIndex, + jobject ndata, + jint texCoordMapLength, + jintArray tcoordsetmap, + jintArray texindices, + jint texStride, + jobjectArray texCoords, + jdoubleArray xform, + jdoubleArray nxform) +{ + jclass geo_class; + JNIEnv table; + jboolean useAlpha = JNI_FALSE; + jfieldID strip_field; + jarray sarray; + jint i; + jsize strip_len; + jarray start_array; + jfieldID start_field; + jfloat *fverts = NULL; + jdouble *dverts = NULL; + jbyte *bclrs = NULL; + jfloat *fclrs = NULL, *norms = NULL; + jdouble *xform_ptr = NULL; + jdouble *nxform_ptr = NULL; + jfloat *tmpFloatCoordArray = NULL, *tmpNormalArray = NULL, *tmpFloatColors = NULL; + jdouble *tmpDoubleCoordArray = NULL; + jbyte* tmpByteColors= NULL; + jfloat* fvptr = NULL, *nptr = NULL, *fcptr = NULL; + jdouble* dvptr = NULL; + jbyte* bcptr = NULL; + jfloat **texCoordPointer = NULL; + jarray *texobjs = NULL; + jboolean floatCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_FLOAT) != 0); + jboolean doubleCoordDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE) != 0); + jboolean floatColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT) != 0); + jboolean byteColorsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_COLOR_BYTE) != 0); + jboolean normalsDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT) != 0); + jboolean textureDefined = ((vdefined & javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT) != 0); + int offset = 0; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + + table = *env; + + if (textureDefined) { + texobjs = (jarray*)malloc(texCoordMapLength * sizeof(jarray)); + texCoordPointer = (jfloat**)malloc(texCoordMapLength * sizeof(jfloat*)); + + for (i = 0; i < texCoordMapLength; i++) { + texobjs[i] = (*(table->GetObjectArrayElement))(env, texCoords, i); + } + } + + geo_class = (jclass) (*(table->GetObjectClass))(env, geo); + + + /* + * process alpha for geometryArray without alpha + */ + if (updateAlpha == JNI_TRUE && ignoreVertexColors== JNI_FALSE) { + useAlpha = JNI_TRUE; + } + + /* + * call other JNI functions before entering Critical region + * i.e., GetPrimitiveArrayCritical + */ + if (geo_type == GEO_TYPE_TRI_STRIP_SET || + geo_type == GEO_TYPE_TRI_FAN_SET || + geo_type == GEO_TYPE_LINE_STRIP_SET) { + + strip_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripVertexCounts", "[I"); + sarray = (jarray)(*(table->GetObjectField))(env, geo, strip_field); + strip_len = (jsize)(*(table->GetArrayLength))(env, sarray); + start_field = (jfieldID) (*(table->GetFieldID))(env, geo_class, + "stripStartOffsetIndices", "[I"); + start_array = (jarray)(*(table->GetObjectField))(env, geo, + start_field); + } + + if (ignoreVertexColors == JNI_TRUE) { + vformat &= ~GA_COLOR; + floatColorsDefined = JNI_FALSE; + byteColorsDefined = JNI_FALSE; + } + /* get texture arrays */ + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texobjs[i] != NULL) + texCoordPointer[i] = (jfloat*)(*(table->GetPrimitiveArrayCritical))(env,texobjs[i], NULL); + else + texCoordPointer[i] = NULL; + + } + } + + /* get coordinate array */ + if (floatCoordDefined) { + glEnableClientState(GL_VERTEX_ARRAY); + fverts= (jfloat *)(*(table->GetDirectBufferAddress))(env, vcoords ); + fvptr = fverts; + } else if (doubleCoordDefined) { + glEnableClientState(GL_VERTEX_ARRAY); + dverts= (jdouble *)(*(table->GetDirectBufferAddress))(env, vcoords ); + dvptr = dverts; + } + else { + glDisableClientState(GL_VERTEX_ARRAY); + } + + if(fverts == NULL && dverts == NULL) { + return; + } + + /* TODO KCR : get vertex attr arrays */ + + /* get color array */ + if (floatColorsDefined) { + glEnableClientState(GL_COLOR_ARRAY); + fclrs = (jfloat *)(*(table->GetDirectBufferAddress))(env, cdataBuffer); + fcptr = fclrs; + } else if (byteColorsDefined) { + glEnableClientState(GL_COLOR_ARRAY); + bclrs = (jbyte *)(*(table->GetDirectBufferAddress))(env, cdataBuffer); + bcptr = bclrs; + } + else { + glDisableClientState(GL_COLOR_ARRAY); + } + /* get normal array */ + if (normalsDefined) { + glEnableClientState(GL_NORMAL_ARRAY); + norms = (jfloat *)(*(table->GetDirectBufferAddress))(env, ndata); + nptr = norms; + } + else { + glDisableClientState(GL_NORMAL_ARRAY); + } + /* get the static transform if exists */ + if (xform != NULL) { + xform_ptr = (jdouble *) (*(table->GetPrimitiveArrayCritical))( + env, xform, NULL); + + } + + + /* get the static normals transform if exists */ + if (nxform != NULL) { + nxform_ptr = (jdouble *) (*(table->GetPrimitiveArrayCritical))( + env, nxform, NULL); + } + + + /* + * Check if normal is present and nxform_ptr id non-null, if yes, + * create a new normal array and apply the xform + */ + if (normalsDefined) { + if(nxform_ptr != NULL) { + /* create a temporary array for normals */ + tmpNormalArray = (jfloat*) malloc(vcount * sizeof(float) * 3); + for (i = initialNormalIndex; i < vcount*3; i+=3) { + tmpNormalArray[i] = (float) (nxform_ptr[0] * norms[i] + + nxform_ptr[1] * norms[i+1] + + nxform_ptr[2] * norms[i+2]); + tmpNormalArray[i+1] = (float) (nxform_ptr[4] * norms[i] + + nxform_ptr[5] * norms[i+1] + + nxform_ptr[6] * norms[i+2]); + tmpNormalArray[i+2] = (float) (nxform_ptr[8] * norms[i] + + nxform_ptr[9] * norms[i+1] + + nxform_ptr[10] * norms[i+2]); + } + nptr = tmpNormalArray; + } + + } + + if (xform_ptr != NULL) { + if (floatCoordDefined) { + /* create a temporary array for normals */ + tmpFloatCoordArray = (jfloat*) malloc(vcount * sizeof(float) * 3); + for (i = initialCoordIndex; i < vcount*3; i+=3) { + tmpFloatCoordArray[i] = (float) (xform_ptr[0] * fverts[i] + + xform_ptr[1] * fverts[i+1] + + xform_ptr[2] * fverts[i+2]); + tmpFloatCoordArray[i+1] = (float) (xform_ptr[4] * fverts[i] + + xform_ptr[5] * fverts[i+1] + + xform_ptr[6] * fverts[i+2]); + tmpFloatCoordArray[i+2] = (float) (xform_ptr[8] * fverts[i] + + xform_ptr[9] * fverts[i+1] + + xform_ptr[10] * fverts[i+2]); + } + fvptr = tmpFloatCoordArray; + } + else { + tmpDoubleCoordArray = (jdouble*) malloc(vcount * sizeof(double) * 3); + for (i = initialCoordIndex; i < vcount*3; i+=3) { + tmpDoubleCoordArray[i] = (double) (xform_ptr[0] * dverts[i] + + xform_ptr[1] * dverts[i+1] + + xform_ptr[2] * dverts[i+2]); + tmpDoubleCoordArray[i+1] = (double) (xform_ptr[4] * dverts[i] + + xform_ptr[5] * dverts[i+1] + + xform_ptr[6] * dverts[i+2]); + tmpDoubleCoordArray[i+2] = (double) (xform_ptr[8] * dverts[i] + + xform_ptr[9] * dverts[i+1] + + xform_ptr[10] * dverts[i+2]); + } + dvptr = tmpDoubleCoordArray; + } + + } + if (floatColorsDefined && useAlpha) { + tmpFloatColors = (jfloat*)malloc(vcount*sizeof(float) * 4); + if ((vformat & GA_WITH_ALPHA) != 0) { + for (i = initialColorIndex; i < vcount*4; i+=4) { + tmpFloatColors[i] = fclrs[i]; + tmpFloatColors[i+1] = fclrs[i+1]; + tmpFloatColors[i+2] = fclrs[i+2]; + tmpFloatColors[i+3] = (float)(alpha* fclrs[i+3]); + } + } + else { + int k = 0; + for (i = initialColorIndex; i < vcount*4; i+=4) { + tmpFloatColors[i] = fclrs[k++]; + tmpFloatColors[i+1] = fclrs[k++]; + tmpFloatColors[i+2] = fclrs[k++]; + tmpFloatColors[i+3] = (float)(alpha); + } + } + fcptr = tmpFloatColors; + vformat |= GA_WITH_ALPHA; + } + else if (byteColorsDefined && useAlpha) { + tmpByteColors = (jbyte*)malloc(vcount*sizeof(jbyte) * 4); + if ((vformat & GA_WITH_ALPHA) != 0) { + for (i = initialColorIndex; i < vcount*4; i+=4) { + tmpByteColors[i] = bclrs[i]; + tmpByteColors[i+1] = bclrs[i+1]; + tmpByteColors[i+2] =bclrs[i+2]; + tmpByteColors[i+3] = (jbyte) (alpha * ((int)bclrs[i+3] & 0xff)); + } + } + else { + int k = 0; + for (i = initialColorIndex; i < vcount*4; i+=4) { + tmpByteColors[i] = bclrs[k++]; + tmpByteColors[i+1] = bclrs[k++]; + tmpByteColors[i+2] =bclrs[k++]; + tmpByteColors[i+3] = (jbyte) (alpha * 255.0); + } + } + bcptr = tmpByteColors; + vformat |= GA_WITH_ALPHA; + + } + +#ifdef VERBOSE + fprintf(stderr, "GeometryArrayRetained.buildGAForBuffer() -- calling executeGeometryArrayVA\n"); +#endif /* VERBOSE */ + + executeGeometryArrayVA(env, obj, ctxInfo, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, initialCoordIndex, + fvptr, dvptr, initialColorIndex, + fcptr, bcptr, initialNormalIndex, + nptr, + /* TODO: vertexAttrCount, vertexAttrSizes, */ + /* TODO: vertexAttrIndices, vertexAttrPointer, */ + texCoordMapLength, + tcoordsetmap, texCoordMapLength, + texindices,texStride,texCoordPointer,0, sarray, strip_len, start_array); + if (textureDefined) { + for (i = 0; i < texCoordMapLength; i++) { + if (texCoordPointer[i] != NULL) { + (*(table->ReleasePrimitiveArrayCritical))(env, texobjs[i], texCoordPointer[i], 0); + } + } + } + + if (texobjs != NULL) { + free(texobjs); + } + if (texCoordPointer != NULL) { + free(texCoordPointer); + } + + if (tmpNormalArray != NULL) { + free(tmpNormalArray); + } + + + if (tmpFloatColors != NULL) { + free(tmpFloatColors); + } + else if (tmpByteColors != NULL) { + free(tmpByteColors); + } + + + if (tmpFloatCoordArray != NULL) { + free(tmpFloatCoordArray); + } + else if (tmpDoubleCoordArray != NULL) { + free(tmpFloatCoordArray); + } +} + +#endif /* 0 */ + diff --git a/j3d-core/src/native/ogl/GraphicsContext3D.c b/j3d-core/src/native/ogl/GraphicsContext3D.c new file mode 100644 index 0000000..012e1aa --- /dev/null +++ b/j3d-core/src/native/ogl/GraphicsContext3D.c @@ -0,0 +1,181 @@ +/* + * $RCSfile: GraphicsContext3D.c,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.8 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +#include +#include + +#include "gldefs.h" + +extern void throwAssert(JNIEnv *env, char *str); + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_readRaster( + JNIEnv *env, jobject obj, jlong ctx, + jint type, jint xOffset, jint yOffset, + jint wRaster, jint hRaster, jint hCanvas, + jint imageDataType, + jint imageFormat, jobject imageBuffer, + jint depthFormat, jobject depthBuffer) +{ + JNIEnv table; + int yAdjusted; + GLenum oglFormat; + void *imageObjPtr; + void *depthObjPtr; + + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctx; + + table = *env; + + glPixelStorei(GL_PACK_ROW_LENGTH, wRaster); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + yAdjusted = hCanvas - hRaster - yOffset; + + if ((type & javax_media_j3d_Raster_RASTER_COLOR) != 0) { + + imageObjPtr = + (void *)(*(table->GetPrimitiveArrayCritical))(env, (jarray)imageBuffer, NULL); + + if(imageDataType == IMAGE_DATA_TYPE_BYTE_ARRAY) { + + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_BYTE_BGR: + oglFormat = GL_BGR; + break; + case IMAGE_FORMAT_BYTE_RGB: + oglFormat = GL_RGB; + break; + /* GL_ABGR_EXT */ + case IMAGE_FORMAT_BYTE_ABGR: + if (ctxProperties->abgr_ext) { /* If its zero, should never come here! */ + oglFormat = GL_ABGR_EXT; + } + else { + throwAssert(env, "readRaster : GL_ABGR_EXT format is unsupported"); + return; + } + break; + case IMAGE_FORMAT_BYTE_RGBA: + oglFormat = GL_RGBA; + break; + case IMAGE_FORMAT_BYTE_LA: + /* all LA types are stored as LA8 */ + oglFormat = GL_LUMINANCE_ALPHA; + break; + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_INT_BGR: + case IMAGE_FORMAT_INT_RGB: + case IMAGE_FORMAT_INT_ARGB: + default: + throwAssert(env, "readRaster : imageFormat illegal format"); + return; + } + + glReadPixels(xOffset, yAdjusted, wRaster, hRaster, + oglFormat, GL_UNSIGNED_BYTE, imageObjPtr); + + } + else if(imageDataType == IMAGE_DATA_TYPE_INT_ARRAY) { + GLenum intType = GL_UNSIGNED_INT_8_8_8_8; + GLboolean forceAlphaToOne = GL_FALSE; + + switch (imageFormat) { + /* GL_BGR */ + case IMAGE_FORMAT_INT_BGR: /* Assume XBGR format */ + oglFormat = GL_RGBA; + intType = GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = GL_TRUE; + break; + case IMAGE_FORMAT_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = GL_TRUE; + /* Fall through to next case */ + case IMAGE_FORMAT_INT_ARGB: + oglFormat = GL_BGRA; + intType = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case IMAGE_FORMAT_BYTE_LA: + case IMAGE_FORMAT_BYTE_GRAY: + case IMAGE_FORMAT_USHORT_GRAY: + case IMAGE_FORMAT_BYTE_BGR: + case IMAGE_FORMAT_BYTE_RGB: + case IMAGE_FORMAT_BYTE_RGBA: + case IMAGE_FORMAT_BYTE_ABGR: + default: + throwAssert(env, "readRaster : imageFormat illegal format"); + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 0.0f); + glPixelTransferf(GL_ALPHA_BIAS, 1.0f); + } + + glReadPixels(xOffset, yAdjusted, wRaster, hRaster, + oglFormat, intType, imageObjPtr); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + glPixelTransferf(GL_ALPHA_BIAS, 0.0f); + } + } + else { + throwAssert(env, "readRaster : illegal image data type"); + return; + } + + (*(table->ReleasePrimitiveArrayCritical))(env, imageBuffer, imageObjPtr, 0); + } + + if ((type & javax_media_j3d_Raster_RASTER_DEPTH) != 0) { + GLenum depthType = 0; + depthObjPtr = + (void *)(*(table->GetPrimitiveArrayCritical))(env, (jarray)depthBuffer, NULL); + + if (depthFormat == javax_media_j3d_DepthComponentRetained_DEPTH_COMPONENT_TYPE_INT) { + depthType = GL_UNSIGNED_INT; + } else { /* javax_media_j3d_DepthComponentRetained_DEPTH_COMPONENT_TYPE_FLOAT */ + depthType = GL_FLOAT; + } + + /* yOffset is adjusted for OpenGL - Y upward */ + glReadPixels(xOffset, yAdjusted, wRaster, hRaster, + GL_DEPTH_COMPONENT, depthType , depthObjPtr); + + (*(table->ReleasePrimitiveArrayCritical))(env, depthBuffer, depthObjPtr, 0); + } + +} + diff --git a/j3d-core/src/native/ogl/Lights.c b/j3d-core/src/native/ogl/Lights.c new file mode 100644 index 0000000..5c2830d --- /dev/null +++ b/j3d-core/src/native/ogl/Lights.c @@ -0,0 +1,187 @@ +/* + * $RCSfile: Lights.c,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.6 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +#include +#include +#include +#include +#include + +#include "gldefs.h" + +#ifdef DEBUG +/* Uncomment the following for VERBOSE debug messages */ +/* #define VERBOSE */ +#endif /* DEBUG */ + + +const float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateDirectionalLight( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint lightSlot, + jfloat red, + jfloat green, + jfloat blue, + jfloat dirx, + jfloat diry, + jfloat dirz) +{ + int lightNum; + float values[4]; + GraphicsContextPropertiesInfo *ctxProperties = (GraphicsContextPropertiesInfo *)ctxInfo; + jlong ctx = ctxProperties->context; + +#ifdef VERBOSE + fprintf(stderr, + "Directional Light %d: %f %f %f direction, %f %f %f color\n", + lightSlot, dirx, diry, dirz, red, green, blue); +#endif + lightNum = GL_LIGHT0 + lightSlot; + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + glLightfv(lightNum, GL_DIFFUSE, values); + glLightfv(lightNum, GL_SPECULAR, values); + values[0] = -dirx; + values[1] = -diry; + values[2] = -dirz; + values[3] = 0.0f; + glLightfv(lightNum, GL_POSITION, values); + glLightfv(lightNum, GL_AMBIENT, black); + glLightf(lightNum, GL_CONSTANT_ATTENUATION, 1.0f); + glLightf(lightNum, GL_LINEAR_ATTENUATION, 0.0f); + glLightf(lightNum, GL_QUADRATIC_ATTENUATION, 0.0f); + glLightf(lightNum, GL_SPOT_EXPONENT, 0.0f); + glLightf(lightNum, GL_SPOT_CUTOFF, 180.0f); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updatePointLight( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint lightSlot, + jfloat red, + jfloat green, + jfloat blue, + jfloat attenx, + jfloat atteny, + jfloat attenz, + jfloat posx, + jfloat posy, + jfloat posz) +{ + int lightNum; + float values[4]; + +#ifdef VERBOSE + fprintf(stderr, "Positional Light %d: %f %f %f position, %f %f %f color\n\t %f %f %f attenuation\n", + lightSlot, posx, posy, posz, red, green, blue, + attenx, atteny, attenz); +#endif + + lightNum = GL_LIGHT0 + lightSlot; + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + glLightfv(lightNum, GL_DIFFUSE, values); + glLightfv(lightNum, GL_SPECULAR, values); + glLightfv(lightNum, GL_AMBIENT, black); + values[0] = posx; + values[1] = posy; + values[2] = posz; + glLightfv(lightNum, GL_POSITION, values); + glLightf(lightNum, GL_CONSTANT_ATTENUATION, attenx); + glLightf(lightNum, GL_LINEAR_ATTENUATION, atteny); + glLightf(lightNum, GL_QUADRATIC_ATTENUATION, attenz); + glLightf(lightNum, GL_SPOT_EXPONENT, 0.0f); + glLightf(lightNum, GL_SPOT_CUTOFF, 180.0f); +} + +JNIEXPORT +void JNICALL Java_javax_media_j3d_NativePipeline_updateSpotLight( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint lightSlot, + jfloat red, + jfloat green, + jfloat blue, + jfloat attenx, + jfloat atteny, + jfloat attenz, + jfloat posx, + jfloat posy, + jfloat posz, + jfloat spreadAngle, + jfloat concentration, + jfloat dirx, + jfloat diry, + jfloat dirz) +{ + int lightNum; + float values[4]; + +#ifdef VERBOSE + fprintf(stderr, "Spot Light %d: %f %f %f position, %f %f %f color\n\t %f %f %f attenuation\n\t %f %f %f direction, %f spreadAngle, %f concentration\n", + lightSlot, posx, posy, posz, red, green, blue, + attenx, atteny, attenz, dirx, diry, dirz, + spreadAngle*180.0 / M_PI, concentration); +#endif + lightNum = GL_LIGHT0 + lightSlot; + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + glLightfv(lightNum, GL_DIFFUSE, values); + glLightfv(lightNum, GL_SPECULAR, values); + glLightfv(lightNum, GL_AMBIENT, black); + values[0] = posx; + values[1] = posy; + values[2] = posz; + glLightfv(lightNum, GL_POSITION, values); + glLightf(lightNum, GL_CONSTANT_ATTENUATION, attenx); + glLightf(lightNum, GL_LINEAR_ATTENUATION, atteny); + glLightf(lightNum, GL_QUADRATIC_ATTENUATION, attenz); + values[0] = dirx; + values[1] = diry; + values[2] = dirz; + glLightfv(lightNum, GL_SPOT_DIRECTION, values); + glLightf(lightNum, GL_SPOT_EXPONENT, concentration); + glLightf(lightNum, GL_SPOT_CUTOFF, (float) (spreadAngle * 180.0f / M_PI)); +} + diff --git a/j3d-core/src/native/ogl/MasterControl.c b/j3d-core/src/native/ogl/MasterControl.c new file mode 100644 index 0000000..3da4605 --- /dev/null +++ b/j3d-core/src/native/ogl/MasterControl.c @@ -0,0 +1,203 @@ +/* + * $RCSfile: MasterControl.c,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.9 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +#ifdef DEBUG +#define DPRINT(args) fprintf args +#else +#define DPRINT(args) +#endif /* DEBUG */ + +#include +#include +#include +#include "gldefs.h" + +#ifdef WIN32 +#include +#include +#endif /* WIN32 */ + +#if defined(UNIX) +#include +#ifdef SOLARIS +#include +#else +#include +#endif +#include +#include +#include +#include + +#if defined(SOLARIS) && defined(__sparc) +#pragma weak glXInitThreadsSUN +#pragma weak glXDisableXineramaSUN +#pragma weak XPanoramiXQueryExtension + +extern int glXInitThreadsSUN(); +extern int glXDisableXineramaSUN(Display *dpy); + + +/* + * The following is currently an unsupported, undocumented function to query + * whether the X server is running with Xinerama support. This is an interim + * solution until it is made part of the X Window System standard or replaced + * with a fully supported API. It is currently available in the libXext + * shipped with Solaris 9 and patched versions of Solaris 7 and 8. dlsym() is + * used to check for its existence. + */ +extern Bool XPanoramiXQueryExtension(Display *dpy, + int *event_base, int *error_base); +#endif /* SOLARIS && __sparc */ + +#endif /* UNIX_ */ + +/* defined in Canvas3D.c */ +extern int isExtensionSupported(const char *allExtensions, + const char *extension); + +JNIEXPORT jboolean JNICALL +Java_javax_media_j3d_NativePipeline_initializeJ3D( + JNIEnv *env, jobject obj, jboolean disableXinerama) +{ + jboolean glIsMTSafe = JNI_TRUE; + + /* Nothing to do for non-sparc-solaris platforms */ + +#if defined(SOLARIS) && defined(__sparc) + Display* dpy; + int event_base, error_base; + const char *glxExtStr = NULL; + + glIsMTSafe = JNI_FALSE; + + dpy = XOpenDisplay(NULL); + glxExtStr = glXGetClientString((Display*)dpy, GLX_EXTENSIONS); + +#ifdef GLX_SUN_init_threads + if(isExtensionSupported(glxExtStr, "GLX_SUN_init_threads")) { + if (glXInitThreadsSUN()) { + glIsMTSafe = JNI_TRUE; + } + else { + DPRINT((stderr, "Failed initializing OpenGL for MT rendering.\n")); + DPRINT((stderr, "glXInitThreadsSUN returned false.\n")); + } + } + else { + DPRINT((stderr, "Failed to initialize OpenGL for MT rendering.\n")); + DPRINT((stderr, "GLX_SUN_init_threads not available.\n")); + } +#endif /* GLX_SUN_init_threads */ + + if (disableXinerama) { + DPRINT((stderr, "Property j3d.disableXinerama true ")); + + if ((! dlsym(RTLD_DEFAULT, "XPanoramiXQueryExtension")) || + (! dlsym(RTLD_DEFAULT, "XDgaGetXineramaInfo"))) { + + DPRINT((stderr, "but required API not available.\n")); + return glIsMTSafe; + } + + if (XPanoramiXQueryExtension(dpy, &event_base, &error_base)) { + DPRINT((stderr, "and Xinerama is in use.\n")); +#ifdef GLX_SUN_disable_xinerama + if(isExtensionSupported(glxExtStr, "GLX_SUN_disable_xinerama")) { + + if (glXDisableXineramaSUN((Display *)dpy)) { + jclass cls = (*env)->GetObjectClass(env, obj); + jfieldID disabledField = + (*env)->GetFieldID(env, cls, "xineramaDisabled", "Z"); + + (*env)->SetBooleanField(env, obj, disabledField, JNI_TRUE); + DPRINT((stderr, "Successfully disabled Xinerama.\n")); + } + else { + DPRINT((stderr, "Failed to disable Xinerama: ")); + DPRINT((stderr, "glXDisableXineramaSUN returns false.\n")); + } + } else { + DPRINT((stderr, "Failed to disable Xinerama: ")); + DPRINT((stderr, "GLX_SUN_disable_xinerama not available.\n")); + } +#endif /* GLX_SUN_disable_xinerama */ + } else { + DPRINT((stderr, "but Xinerama is not in use.\n")); + } + } +#endif /* SOLARIS && __sparc */ + + return glIsMTSafe; +} + + +#ifdef WIN32 +DWORD countBits(DWORD mask) +{ + DWORD count = 0; + int i; + + for (i=sizeof(DWORD)*8-1; i >=0 ; i--) { + if ((mask & 0x01) > 0) { + count++; + } + mask >>= 1; + } + return count; +} + +#endif /* WIN32 */ + +JNIEXPORT +jint JNICALL Java_javax_media_j3d_NativePipeline_getMaximumLights( + JNIEnv *env, + jobject obj + ) { + +#ifdef SOLARIS + return 32; +#endif /* SOLARIS */ + +#ifdef WIN32 + return 8; +#endif /* WIN32 */ + +#ifdef LINUX + return 8; +#endif /* LINUX */ +} diff --git a/j3d-core/src/native/ogl/NativeConfigTemplate3D.c b/j3d-core/src/native/ogl/NativeConfigTemplate3D.c new file mode 100644 index 0000000..66c42bb --- /dev/null +++ b/j3d-core/src/native/ogl/NativeConfigTemplate3D.c @@ -0,0 +1,1807 @@ +/* + * $RCSfile: NativeConfigTemplate3D.c,v $ + * + * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.22 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include +#include +#include + +#include "gldefs.h" + +#if defined(UNIX) +#include +#include +#include +#include +#endif + +#ifdef WIN32 +#include +#endif + +/* check if the extension is supported */ +extern int isExtensionSupported(const char *allExtensions, const char *extension); + +/* by MIK OF CLASSX */ +extern jboolean getJavaBoolEnv(JNIEnv *env, char* envStr); + +#if defined(UNIX) + +/* Fix for issue 20 */ +#define MAX_GLX_ATTRS_LENGTH 100 + + +GLXFBConfig *find_S_FBConfigs(jlong display, + jint screen, + int* glxAttrs, + int stencilVal, + int sIndex) { + + + GLXFBConfig *fbConfigList = NULL; + int numFBConfigs, index; + MYPFNGLXCHOOSEFBCONFIG pGLXChooseFbConfig = NULL; + GLboolean userReq = GL_TRUE; + + pGLXChooseFbConfig = + (MYPFNGLXCHOOSEFBCONFIG) dlsym(RTLD_DEFAULT, "glXChooseFBConfig"); + + J3D_ASSERT((sIndex+3) < MAX_GLX_ATTRS_LENGTH); + + /* if user not use stencil we will request one of internal use. */ + if (stencilVal < 1) { + userReq = GL_FALSE; + stencilVal = 1; + } + + index = sIndex; + glxAttrs[index++] = GLX_STENCIL_SIZE; + glxAttrs[index++] = stencilVal; + glxAttrs[index] = None; + + fbConfigList = pGLXChooseFbConfig((Display*)display, screen, + glxAttrs, &numFBConfigs); + + + if(fbConfigList != NULL) { + return fbConfigList; + } + + /* + fprintf(stderr, "Stencil : find_S_FBConfigs (TRY 1): FAIL -- stencilVal = %d\n", + stencilVal); + */ + + if (userReq == GL_TRUE) { + /* fprintf(stderr, " userReq : *** FAILED ***\n"); */ + return NULL; + } + + index = sIndex; + glxAttrs[index] = None; + + fbConfigList = pGLXChooseFbConfig((Display*)display, screen, + glxAttrs, &numFBConfigs); + + + if(fbConfigList != NULL) { + return fbConfigList; + } + + /* + fprintf(stderr, "Stencil : find_S_FBConfigs (TRY 2): FAIL -- stencilVal = %d\n", + stencilVal); + */ + + return NULL; + +} + +GLXFBConfig *find_S_S_FBConfigs(jlong display, + jint screen, + int* glxAttrs, + int stereoVal, + int stencilVal, + int sIndex) { + + GLXFBConfig *fbConfigList = NULL; + int numFBConfigs, index; + + J3D_ASSERT((sIndex+3) < MAX_GLX_ATTRS_LENGTH); + + if (stereoVal == REQUIRED || stereoVal== PREFERRED) { + + index = sIndex; + glxAttrs[index++] = GLX_STEREO; + glxAttrs[index++] = True; + glxAttrs[index] = None; + + fbConfigList = find_S_FBConfigs(display, screen, glxAttrs, stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + if (stereoVal == UNNECESSARY || stereoVal== PREFERRED) { + /* This is a workaround to BugId : 5106472 in Solaris OGL. + We can't set glxAttrs with GLX_STEREO follow by a boolean */ + + index = sIndex; + glxAttrs[index] = None; + + /* For debug only + { + int i=0; + fprintf(stderr, "find_S_S_FBConfigs stereoVal = %d\n", stereoVal); + + while(glxAttrs[i] != None) { + fprintf(stderr, "glxAttrs[%d] = %x", i, glxAttrs[i]); + i++; + fprintf(stderr, " glxAttrs[%d] = %x\n", i, glxAttrs[i]); + i++; + } + } + */ + + fbConfigList = find_S_FBConfigs(display, screen, glxAttrs, stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + if (stereoVal == UNNECESSARY) { + index = sIndex; + glxAttrs[index++] = GLX_STEREO; + glxAttrs[index++] = True; + glxAttrs[index] = None; + + /* + fbConfigList = pGLXChooseFbConfig((Display*)display, screen, + glxAttrs, &numFBConfigs); + */ + fbConfigList = find_S_FBConfigs(display, screen, glxAttrs, stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + return NULL; +} + +GLXFBConfig *find_AA_S_S_FBConfigs(jlong display, + jint screen, + int* glxAttrs, + int stereoVal, + int antialiasVal, + int stencilVal, + int antialiasIndex) { + + const char *glxExtensions = NULL; + GLXFBConfig *fbConfigList = NULL; + int index = antialiasIndex; + + + J3D_ASSERT((antialiasIndex+7) < MAX_GLX_ATTRS_LENGTH); + + if(antialiasVal == REQUIRED || antialiasVal== PREFERRED) { + glxExtensions = (const char *) glXGetClientString((Display*)display, GLX_EXTENSIONS); + + if(isExtensionSupported(glxExtensions, "GLX_ARB_multisample")){ + static const int SAMPLE_LENGTH = 5; + static const int samples[] = {8,6,4,3,2}; + int i, samplesIndex; + + index = antialiasIndex; + glxAttrs[index++] = GLX_SAMPLE_BUFFERS_ARB; + glxAttrs[index++] = 1; + glxAttrs[index++] = GLX_SAMPLES_ARB; + samplesIndex = index++; /* Will assign samples in the sample selection loop */ + glxAttrs[index] = None; + + for(i=0; i < SAMPLE_LENGTH; i++) { + /* fprintf(stderr, "find_AA_S_S_FBConfigs samples = %d\n", samples[i]); */ + glxAttrs[samplesIndex] = samples[i]; + fbConfigList = find_S_S_FBConfigs(display, screen, glxAttrs, stereoVal, + stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + } + } + + if ( antialiasVal == REQUIRED ) { + index = antialiasIndex; + glxAttrs[index++] = GLX_ACCUM_RED_SIZE; + glxAttrs[index++] = 8; + glxAttrs[index++] = GLX_ACCUM_GREEN_SIZE; + glxAttrs[index++] = 8; + glxAttrs[index++] = GLX_ACCUM_BLUE_SIZE; + glxAttrs[index++] = 8; + glxAttrs[index] = None; + + fbConfigList = find_S_S_FBConfigs(display, screen, glxAttrs, + stereoVal, stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + glxAttrs[antialiasIndex] = None; + + if (antialiasVal == UNNECESSARY || antialiasVal == PREFERRED) { + fbConfigList = find_S_S_FBConfigs(display, screen, glxAttrs, + stereoVal, stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + /* We will stop trying even if no fbConfigList is found and + antialiasVal = UNNECESSARY */ + + return NULL; + +} + +GLXFBConfig *find_DB_AA_S_S_FBConfigs(jlong display, + jint screen, + int* glxAttrs, + int stereoVal, int dbVal, + int antialiasVal, + int stencilVal, + int dbIndex) { + + GLXFBConfig *fbConfigList = NULL; + int index = dbIndex; + + J3D_ASSERT((dbIndex+3) < MAX_GLX_ATTRS_LENGTH); + + if (dbVal == REQUIRED || dbVal== PREFERRED) { + + index = dbIndex; + glxAttrs[index++] = GLX_DOUBLEBUFFER; + glxAttrs[index++] = True; + glxAttrs[index] = None; + + fbConfigList = find_AA_S_S_FBConfigs(display, screen, glxAttrs, + stereoVal, antialiasVal, + stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + if (dbVal == UNNECESSARY || dbVal== PREFERRED) { + index = dbIndex; + glxAttrs[index++] = GLX_DOUBLEBUFFER; + glxAttrs[index++] = False; + glxAttrs[index] = None; + + fbConfigList = find_AA_S_S_FBConfigs(display, screen, glxAttrs, + stereoVal, antialiasVal, + stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + if (dbVal == UNNECESSARY) { + index = dbIndex; + glxAttrs[index++] = GLX_DOUBLEBUFFER; + glxAttrs[index++] = True; + glxAttrs[index] = None; + + fbConfigList = find_AA_S_S_FBConfigs(display, screen, glxAttrs, + stereoVal, antialiasVal, + stencilVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + return NULL; +} + +/* + * Uses the passed in array to choose the best OpenGL visual. + * When the "best" visual cannot be used, the "enums" (three + * state attributes) are looped through setting/resetting in all + * combinations in hopes of finding an valid visual. + */ +JNIEXPORT +jint JNICALL Java_javax_media_j3d_X11NativeConfigTemplate3D_chooseOglVisual( + JNIEnv *env, + jobject obj, + jlong display, + jint screen, + jintArray attrList, + jlongArray fbConfigArray) +{ + jint *mx_ptr; + int glxAttrs[MAX_GLX_ATTRS_LENGTH]; /* value, attr pair plus a None */ + int index; + GLXFBConfig *fbConfigList = NULL; + + /* use to cycle through when attr is not REQUIRED */ + int dbVal; /* value for double buffering */ + int stereoVal; /* value for stereo */ + int antialiasVal; /* value for antialias */ + int stencilVal; /* value for stencil size */ + + int drawableIndex; + + jlong *fbConfigListPtr = NULL; + int status, major, minor; + + Display *dpy = (Display *) display; + + fbConfigListPtr = (*env)->GetLongArrayElements(env, fbConfigArray, NULL); + mx_ptr = (*env)->GetIntArrayElements(env, attrList, NULL); + + /* + * convert Java 3D values to GLX + */ + index = 0; + + /* Specify pbuffer as default */ + /* Fix for Issue 20 */ + glxAttrs[index++] = GLX_DRAWABLE_TYPE; + drawableIndex = index; + glxAttrs[index++] = (GLX_PBUFFER_BIT | GLX_WINDOW_BIT); + + /* only interested in RGBA type */ + glxAttrs[index++] = GLX_RENDER_TYPE; + glxAttrs[index++] = GLX_RGBA_BIT; + + /* only interested in FBConfig with associated X Visual type */ + glxAttrs[index++] = GLX_X_RENDERABLE; + glxAttrs[index++] = True; + + glxAttrs[index++] = GLX_RED_SIZE; + glxAttrs[index++] = mx_ptr[RED_SIZE]; + glxAttrs[index++] = GLX_GREEN_SIZE; + glxAttrs[index++] = mx_ptr[GREEN_SIZE]; + glxAttrs[index++] = GLX_BLUE_SIZE; + glxAttrs[index++] = mx_ptr[BLUE_SIZE]; + + /* by MIK OF CLASSX */ + if (getJavaBoolEnv(env, "transparentOffScreen")) { + glxAttrs[index++] = GLX_ALPHA_SIZE; + glxAttrs[index++] = 1; + } + + glxAttrs[index++] = GLX_DEPTH_SIZE; + glxAttrs[index++] = mx_ptr[DEPTH_SIZE]; + glxAttrs[index] = None; + + dbVal = mx_ptr[DOUBLEBUFFER]; + stereoVal = mx_ptr[STEREO]; + antialiasVal = mx_ptr[ANTIALIASING]; + stencilVal = mx_ptr[STENCIL_SIZE]; + + (*env)->ReleaseIntArrayElements(env, attrList, mx_ptr, JNI_ABORT); + + /* Get Pbuffer-capable visual unless j3d.usePbuffer property is FALSE */ + if (getJavaBoolEnv(env,"usePbuffer")) { + fbConfigList = find_DB_AA_S_S_FBConfigs(display, screen, glxAttrs, stereoVal, + dbVal, antialiasVal, stencilVal, index); + } + + if(fbConfigList == NULL) { /* Try with Pixmap, if Pbuffer fail. */ + glxAttrs[drawableIndex] = (GLX_PIXMAP_BIT | GLX_WINDOW_BIT); + fbConfigList = find_DB_AA_S_S_FBConfigs(display, screen, glxAttrs, stereoVal, + dbVal, antialiasVal, stencilVal, index); + } + + if(fbConfigList == NULL) { /* Try with Window only, if Pixmap fail. */ + glxAttrs[drawableIndex] = GLX_WINDOW_BIT; + fbConfigList = find_DB_AA_S_S_FBConfigs(display, screen, glxAttrs, stereoVal, + dbVal, antialiasVal, stencilVal, index); + } + + fbConfigListPtr[0] = (jlong)fbConfigList; + (*env)->ReleaseLongArrayElements(env, fbConfigArray, fbConfigListPtr, 0); + + /* For debug only. + if(fbConfigList != NULL) { + int val; + + glXGetFBConfigAttrib(dpy, fbConfigList[0], + GLX_FBCONFIG_ID, &val); + + fprintf(stderr, "display 0x%x, fbConfigList 0x%x, fbConfig 0x%x, fbConfigId %d\n", + (int) display, (int) fbConfigList, (int) fbConfigList[0], val); + + } + else { + fprintf(stderr, "display 0x%x, fbConfigList 0x%x\n", + (int) display, (int) fbConfigList); + } + */ + + if(fbConfigList != NULL) { + int vis_id; + + if(glXGetFBConfigAttrib(dpy, fbConfigList[0], GLX_VISUAL_ID, &vis_id) != Success) { + fprintf(stderr, "Java 3D ERROR: unable to get VisualID\n"); + return 0; + } + + /* fprintf(stderr, "********* VisualID = %d\n", vis_id ); */ + + return (jint) vis_id; + + } else { + return 0; + } +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_X11NativeConfigTemplate3D_freeFBConfig( + JNIEnv *env, + jclass class, /* this is a static native method */ + jlong fbConfigListPtr) +{ + GLXFBConfig *fbConfigList = (GLXFBConfig *) fbConfigListPtr; + XFree(fbConfigList); +} + + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_X11NativeConfigTemplate3D_isStereoAvailable( + JNIEnv *env, + jobject obj, + jlong display, + jint screen, + jint vid) +{ + Display *dpy = (Display*) display; + XVisualInfo *vinfo, template; + int nitems; + int stereoFlag; + static GLboolean first_time = GL_TRUE; + static GLboolean force_no_stereo = GL_FALSE; + + if (first_time) { + if (getenv("J3D_NO_STEREO") != NULL) { + fprintf(stderr, "Java 3D: stereo mode disabled\n"); + force_no_stereo = GL_TRUE; + } + first_time = GL_FALSE; + } + + if (force_no_stereo) + return JNI_FALSE; + + template.visualid = vid; + vinfo = XGetVisualInfo(dpy, VisualIDMask, &template, &nitems); + if (nitems != 1) { + fprintf(stderr, "Warning Canvas3D_isStereoAvailable got unexpected number of matching visuals %d\n", nitems); + } + + glXGetConfig(dpy, vinfo, GLX_STEREO, &stereoFlag); + + return (stereoFlag ? JNI_TRUE : JNI_FALSE); +} + +JNIEXPORT jint JNICALL Java_javax_media_j3d_X11NativeConfigTemplate3D_getStencilSize( + JNIEnv *env, + jobject obj, + jlong display, + jint screen, + jint vid) +{ + Display *dpy = (Display*) display; + XVisualInfo *vinfo, template; + int nitems; + int stencilVal = 0; + + template.visualid = vid; + vinfo = XGetVisualInfo(dpy, VisualIDMask, &template, &nitems); + if (nitems != 1) { + fprintf(stderr, "Warning Canvas3D_getStencilSize got unexpected number of matching visuals %d\n", nitems); + } + + glXGetConfig(dpy, vinfo, GLX_STENCIL_SIZE, &stencilVal); + + return stencilVal; +} + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_X11NativeConfigTemplate3D_isDoubleBufferAvailable( + JNIEnv *env, + jobject obj, + jlong display, + jint screen, + jint vid) +{ + Display *dpy = (Display*) display; + XVisualInfo *vinfo, template; + int nitems; + int doubleBufferFlag; + + template.visualid = vid; + vinfo = XGetVisualInfo(dpy, VisualIDMask, &template, &nitems); + if (nitems != 1) { + fprintf(stderr, "Warning Canvas3D_isDoubleBufferAvailable got unexpected number of matching visuals %d\n", nitems); + } + + glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &doubleBufferFlag); + + return (doubleBufferFlag ? JNI_TRUE : JNI_FALSE); +} + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_X11NativeConfigTemplate3D_isSceneAntialiasingAccumAvailable( + JNIEnv *env, + jobject obj, + jlong display, + jint screen, + jint vid) +{ + Display *dpy = (Display*) display; + XVisualInfo *vinfo, template; + int nitems; + int numAccumRedBits; + + template.visualid = vid; + vinfo = XGetVisualInfo(dpy, VisualIDMask, &template, &nitems); + if (nitems != 1) { + fprintf(stderr, "Warning Canvas3D_isSceneAntialiasingAvailable got unexpected number of matching visuals %d\n", nitems); + } + + glXGetConfig(dpy, vinfo, GLX_ACCUM_RED_SIZE, &numAccumRedBits); + + return (numAccumRedBits > 0 ? JNI_TRUE : JNI_FALSE); +} + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_X11NativeConfigTemplate3D_isSceneAntialiasingMultisampleAvailable( + JNIEnv *env, + jobject obj, + jlong display, + jint screen, + jint vid) +{ + Display *dpy = (Display*) display; + XVisualInfo *vinfo, template; + int nitems; + + const char *glxExtensions; + int numSampleBuffers; + int numSamples; + + template.visualid = vid; + vinfo = XGetVisualInfo(dpy, VisualIDMask, &template, &nitems); + if (nitems != 1) { + fprintf(stderr, "Warning Canvas3D_isSceneAntialiasingAvailable got unexpected number of matching visuals %d\n", nitems); + } + /* try GLX_ARB_multisample */ + glxExtensions = (const char *)glXGetClientString((Display*)display, GLX_EXTENSIONS); + + if(isExtensionSupported(glxExtensions, "GLX_ARB_multisample")){ + glXGetConfig(dpy, vinfo, GLX_SAMPLE_BUFFERS_ARB, &numSampleBuffers); + glXGetConfig(dpy, vinfo, GLX_SAMPLES_ARB, &numSamples); + if(numSampleBuffers > 0 && numSamples > 1){ + return JNI_TRUE; + } + } + + return JNI_FALSE; +} +#endif /* UNIX_ */ + + +#ifdef WIN32 + +extern HWND createDummyWindow(const char* szAppName); + + +PIXELFORMATDESCRIPTOR getDummyPFD() { + + /* Dummy pixel format. -- Chien */ + static PIXELFORMATDESCRIPTOR dummy_pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, /* Version number */ + PFD_DRAW_TO_WINDOW | + PFD_SUPPORT_OPENGL, + PFD_TYPE_RGBA, + 16, /* 16 bit color depth */ + 0, 0, 0, /* RGB bits and pixel sizes */ + 0, 0, 0, /* Do not care about them */ + 0, 0, /* no alpha buffer info */ + 0, 0, 0, 0, 0, /* no accumulation buffer */ + 8, /* 8 bit depth buffer */ + 0, /* no stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* layer type */ + 0, /* reserved, must be 0 */ + 0, /* no layer mask */ + 0, /* no visible mask */ + 0 /* no damage mask */ + }; + + return dummy_pfd; +} + +/* +void printPixelDescriptor(PIXELFORMATDESCRIPTOR *pfd) +{ + + printf("color : r=%d, g=%d, b=%d, a=%d, shift r=%d, g=%d, b=%d, a=%d\n", + pfd->cRedBits, pfd->cGreenBits, pfd->cBlueBits, pfd->cAlphaBits, + pfd->cRedShift, pfd->cGreenShift, pfd->cBlueShift, pfd->cAlphaShift); + printf("Accum r=%d, g=%d, b=%d, a=%d, depth %d, stencil %d, AuxBuffers %d\n", + pfd->cAccumRedBits, pfd->cAccumGreenBits, pfd->cAccumBlueBits, + pfd->cAccumAlphaBits, pfd->cDepthBits, pfd->cStencilBits, pfd->cAuxBuffers); + printf("iLayerType %x, bReserved %x, dwLayerMask %x, dwVisibleMask %x, dwDamageMask %x\n", + pfd->iLayerType, pfd->bReserved, pfd->dwLayerMask, pfd->dwVisibleMask, pfd->dwDamageMask); + if (pfd->dwFlags & PFD_SUPPORT_OPENGL) { + printf("SUPPORT_OPENGL "); + } + if (pfd->dwFlags & PFD_DRAW_TO_WINDOW) { + printf("DRAW_TO_WINDOW "); + } + if (pfd->dwFlags & PFD_DRAW_TO_BITMAP) { + printf("DRAW_TO_BITMAP "); + } + if (pfd->dwFlags & PFD_SUPPORT_GDI) { + printf("SUPPORT_GDI "); + } + if (pfd->dwFlags & PFD_SUPPORT_GDI) { + printf("NEED_PALETTE "); + } + if (pfd->dwFlags & PFD_SUPPORT_GDI) { + printf("NEED_SYSTEM_PALETTE "); + } + if (pfd->dwFlags & PFD_STEREO) { + printf("STEREO "); + } + if (pfd->dwFlags & PFD_SUPPORT_GDI) { + printf("SWAP_LAYER_BUFFERS "); + } + if (pfd->dwFlags & PFD_GENERIC_FORMAT) { + printf("PFD_GENERIC_FORMAT "); + } + if (pfd->dwFlags & PFD_GENERIC_ACCELERATED) { + printf("PFD_GENERIC_FORMAT "); + } + if (pfd->dwFlags & PFD_DOUBLEBUFFER) { + printf("PFD_DOUBLEBUFFER "); + } + printf("\n"); + +} +*/ + +BOOL isSupportedWGL(const char *extensions, const char *extension_string) { + /* get the list of supported extensions */ + const char *p = extensions; + + /* search for extension_string in the list */ + while(p = strstr(p, extension_string)){ + const char *q = p + strlen(extension_string); + + /* must be terminated by or */ + if(*q == ' ' || *q == '\0') { + return TRUE; + } + + /* try to find another match */ + p = q; + } + return FALSE; +} + +HDC getMonitorDC(int screen) +{ + return CreateDC("DISPLAY", NULL, NULL, NULL); +} + +/* NOTE : Since OpenGL 1.2 or greater is required. This is method will not be + * called. Need to remove in Java 3D 1.5 + */ +int find_DB_S_STDPixelFormat(PIXELFORMATDESCRIPTOR* pfd, HDC hdc, + int *mx_ptr, GLboolean offScreen, int stencilVal) +{ + int pf; + PIXELFORMATDESCRIPTOR newpfd; + + pf = ChoosePixelFormat(hdc, pfd); + + if(!offScreen) { + /* onScreen : Check if pixel format support min. requirement */ + DescribePixelFormat(hdc, pf, sizeof(newpfd), &newpfd); + + if ((newpfd.cRedBits < (unsigned char) mx_ptr[RED_SIZE]) || + (newpfd.cGreenBits < (unsigned char) mx_ptr[GREEN_SIZE]) || + (newpfd.cBlueBits < (unsigned char) mx_ptr[BLUE_SIZE]) || + (newpfd.cDepthBits < (unsigned char) mx_ptr[DEPTH_SIZE]) || + (newpfd.cStencilBits < (unsigned char) mx_ptr[STENCIL_SIZE]) || + ((mx_ptr[DOUBLEBUFFER] == REQUIRED) && + ((newpfd.dwFlags & PFD_DOUBLEBUFFER) == 0)) || + ((mx_ptr[STEREO] == REQUIRED) && ((newpfd.dwFlags & PFD_STEREO) == 0))) + { + return -1; + } + + if ((mx_ptr[ANTIALIASING] == REQUIRED) && + ((newpfd.cAccumRedBits <= 0) || + (newpfd.cAccumGreenBits <= 0) || + (newpfd.cAccumBlueBits <= 0))) + { + return -1; + } + } + + return pf; +} + + +void printErrorMessage(char *message) +{ + DWORD err; + char * errString; + + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + fprintf(stderr, "Java 3D ERROR : %s - %s\n", message, errString); + LocalFree(errString); +} + +/* Fix for issue 76 */ +#define MAX_WGL_ATTRS_LENGTH 100 + + +int find_S_PixelFormat(HDC hdc, PixelFormatInfo * pFormatInfo, + int* wglAttrs, int stencilVal, int sIndex) { + + int pFormat, availableFormats, index; + GLboolean userReq = GL_TRUE; + + J3D_ASSERT((sIndex+4) < MAX_WGL_ATTRS_LENGTH); + /* if user not use stencil we will request one of internal use. */ + if (stencilVal < 1) { + userReq = GL_FALSE; + stencilVal = 1; + } + + index = sIndex; + wglAttrs[index++] = WGL_STENCIL_BITS_ARB; + wglAttrs[index++] = stencilVal; + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = -1; + + if ((pFormatInfo->wglChoosePixelFormatARB(hdc, wglAttrs, NULL, 1, + &pFormat, &availableFormats)) && (availableFormats > 0)) { + + /* + fprintf(stderr, "Stencil : wglChoosePixelFormatARB : pFormat %d availableFormats %d\n", + pFormat, availableFormats); + */ + return pFormat; + } + + /* + fprintf(stderr, "Stencil : wglChoosePixelFormatARB (TRY 1): FAIL -- stencilVal = %d\n", + stencilVal); + */ + + if (userReq == GL_TRUE) { + /* fprintf(stderr, " userReq : *** FAILED ***\n"); */ + return -1; + } + + index = sIndex; + + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = -1; + + if ((pFormatInfo->wglChoosePixelFormatARB(hdc, wglAttrs, NULL, 1, + &pFormat, &availableFormats)) && (availableFormats > 0)) { + + /* fprintf(stderr, "wglChoosePixelFormatARB : pFormat %d availableFormats %d\n", + pFormat, availableFormats); */ + + return pFormat; + } + + /* fprintf(stderr, "wglChoosePixelFormatARB (TRY 2): FAIL\n"); */ + return -1; +} + +int find_S_S_PixelFormat(HDC hdc, PixelFormatInfo * pFormatInfo, int* wglAttrs, + int stereoVal, int stencilVal, int sIndex) { + + int pFormat, index; + + J3D_ASSERT((sIndex+4) < MAX_WGL_ATTRS_LENGTH); + + if (stereoVal == REQUIRED || stereoVal== PREFERRED) { + + index = sIndex; + wglAttrs[index++] = WGL_STEREO_ARB; + wglAttrs[index++] = TRUE; + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = find_S_PixelFormat(hdc, pFormatInfo, wglAttrs, + stencilVal, index); + /* fprintf(stderr,"STEREO REQUIRED or PREFERRED ***pFormat %d\n", pFormat); */ + + if(pFormat >= 0) { + return pFormat; + } + } + + if (stereoVal == UNNECESSARY || stereoVal== PREFERRED) { + + index = sIndex; + wglAttrs[index++] = WGL_STEREO_ARB; + wglAttrs[index++] = FALSE; + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = find_S_PixelFormat(hdc, pFormatInfo, wglAttrs, + stencilVal, index); + + /* fprintf(stderr,"STEREO UNNECC. or PREFERRED ***pFormat %d\n", pFormat); */ + + if(pFormat >= 0) { + return pFormat; + } + } + + if (stereoVal == UNNECESSARY) { + index = sIndex; + wglAttrs[index++] = WGL_STEREO_ARB; + wglAttrs[index++] = TRUE; + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = find_S_PixelFormat(hdc, pFormatInfo, wglAttrs, + stencilVal, index); + + /* fprintf(stderr,"STEREO UNNECC. ***pFormat %d\n", pFormat); */ + + if(pFormat >= 0) { + return pFormat; + } + } + + return -1; +} + + +int find_AA_S_S_PixelFormat( HDC hdc, PixelFormatInfo * pFormatInfo, + int* wglAttrs, int stereoVal, int antialiasVal, + int stencilVal, int antialiasIndex) { + + int index; + int pFormat; + GLboolean supportMS = GL_FALSE; + + J3D_ASSERT((antialiasIndex+8) < MAX_WGL_ATTRS_LENGTH); + + if(antialiasVal == REQUIRED || antialiasVal== PREFERRED) { + + if(isSupportedWGL(pFormatInfo->supportedExtensions, "WGL_ARB_multisample")) { + supportMS = GL_TRUE; + } + else { + /* Under Wildcat III it doesn't use wglGetExtensionString */ + char *supportedExtensions = (char *) glGetString(GL_EXTENSIONS); + + /* fprintf(stderr, "GL Supported extensions: %s.\n", supportedExtensions); */ + + if (isSupportedWGL(supportedExtensions, "GL_ARB_multisample")) { + supportMS = GL_TRUE; + } + } + + if(supportMS) { + static const int SAMPLE_LENGTH = 5; + static const int samples[] = {8,6,4,3,2}; + int i, samplesIndex; + + index = antialiasIndex; + wglAttrs[index++] = WGL_SAMPLE_BUFFERS_ARB; + wglAttrs[index++] = 1; + wglAttrs[index++] = WGL_SAMPLES_ARB; + samplesIndex = index++; /* Will assign samples in the sample selection loop */ + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + + for(i=0; i < SAMPLE_LENGTH; i++) { + /* fprintf(stderr, "find_AA_S_S_PixelFormat samples = %d\n", samples[i]); */ + + wglAttrs[samplesIndex] = samples[i]; + pFormat = find_S_S_PixelFormat(hdc, pFormatInfo, wglAttrs, + stereoVal, stencilVal, index); + if(pFormat >= 0) { + return pFormat; + } + } + } + } + + if ( antialiasVal == REQUIRED ) { + + index = antialiasIndex; + wglAttrs[index++] = WGL_ACCUM_RED_BITS_ARB; + wglAttrs[index++] = 8; + wglAttrs[index++] = WGL_ACCUM_GREEN_BITS_ARB; + wglAttrs[index++] = 8; + wglAttrs[index++] = WGL_ACCUM_BLUE_BITS_ARB; + wglAttrs[index++] = 8; + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = find_S_S_PixelFormat(hdc, pFormatInfo, wglAttrs, + stereoVal, stencilVal, index); + + if(pFormat >= 0) { + return pFormat; + } + } + + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + index = antialiasIndex; + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + if (antialiasVal == UNNECESSARY || antialiasVal == PREFERRED) { + + pFormat = find_S_S_PixelFormat(hdc, pFormatInfo, wglAttrs, + stereoVal, stencilVal, index); + + if(pFormat >= 0) { + return pFormat; + } + + } + + return -1; + +} + + +int find_DB_AA_S_S_PixelFormat( HDC hdc, PixelFormatInfo * pFormatInfo, + int* wglAttrs, int stereoVal, int dbVal, + int antialiasVal, int stencilVal, int dbIndex) { + + int index = dbIndex; + int pFormat; + + J3D_ASSERT((dbIndex+4) < MAX_WGL_ATTRS_LENGTH); + + if (dbVal == REQUIRED || dbVal== PREFERRED) { + + index = dbIndex; + wglAttrs[index++] = WGL_DOUBLE_BUFFER_ARB; + wglAttrs[index++] = TRUE; + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = find_AA_S_S_PixelFormat(hdc, pFormatInfo, + wglAttrs, stereoVal, + antialiasVal, stencilVal, index); + + if(pFormat >= 0) { + return pFormat; + } + } + + if (dbVal == UNNECESSARY || dbVal== PREFERRED) { + index = dbIndex; + wglAttrs[index++] = WGL_DOUBLE_BUFFER_ARB; + wglAttrs[index++] = FALSE; /* Partial fix to issue 100. */ + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = find_AA_S_S_PixelFormat(hdc, pFormatInfo, + wglAttrs, stereoVal, + antialiasVal, stencilVal, index); + + if(pFormat >= 0) { + return pFormat; + } + } + + if (dbVal == UNNECESSARY) { + index = dbIndex; + wglAttrs[index++] = WGL_DOUBLE_BUFFER_ARB; + wglAttrs[index++] = TRUE; + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormat = find_AA_S_S_PixelFormat(hdc, pFormatInfo, + wglAttrs, stereoVal, + antialiasVal, stencilVal, index); + + if(pFormat >= 0) { + return pFormat; + } + } + + return -1; +} + +/* Fix to issue 77 */ +/* Check PixelFormat capabilities and cache the info. into pFormatInfo structure */ +void checkPixelFormat(HDC hdc, + PixelFormatInfo *pFormatInfo, + GLboolean offScreen ) +{ + int wglAttrs[3]; + int piValues[2]; + int pf = -1; + GLboolean hasMultisample = GL_FALSE; + GLboolean hasStereo = GL_FALSE; + GLboolean hasDoubleBuffer = GL_FALSE; + GLboolean hasAccum + = GL_FALSE; + int stencilSize = 0; + PIXELFORMATDESCRIPTOR pfd; + + /* fprintf(stderr, "*** checkPixelFormat : offScreen = %d\n", offScreen); */ + + if(!offScreen) { + pf = pFormatInfo->onScreenPFormat; + } + else { + pf = pFormatInfo->offScreenPFormat; + } + + /* Assert that pf is valid */ + J3D_ASSERT(pf >= 0); + piValues[0] = GL_FALSE; + piValues[1] = -1; + + if( pFormatInfo->supportARB && + isSupportedWGL( pFormatInfo->supportedExtensions, "WGL_ARB_multisample")){ + wglAttrs[0] = WGL_SAMPLE_BUFFERS_ARB; + wglAttrs[1] = WGL_SAMPLES_ARB; + wglAttrs[2] = 0; + if (pFormatInfo->wglGetPixelFormatAttribivARB(hdc, pf, 0, 2, + wglAttrs, piValues)) { + if ((piValues[0]) && (piValues[1] > 1)) { + hasMultisample = GL_TRUE; + } + } + /* + fprintf(stderr, "*** checkPixelFormat : hasMultisample = %d numSamples %d\n", + hasMultisample, piValues[1]); + */ + } + + DescribePixelFormat(hdc, pf, sizeof(pfd), &pfd); + + if (pfd.dwFlags & PFD_STEREO) { + hasStereo = GL_TRUE; + } + if (pfd.dwFlags & PFD_DOUBLEBUFFER) { + hasDoubleBuffer = GL_TRUE; + } + if (pfd.cAccumRedBits > 0) { + hasAccum = GL_TRUE; + } + + stencilSize = pfd.cStencilBits; + + /* + fprintf(stderr, "hasStereo = %d, hasDoubleBuffer %d, hasAccum %d stencilSize %d\n", + hasStereo, hasDoubleBuffer, hasAccum, pfd.cStencilBits); + */ + + if(pFormatInfo->onScreenPFormat == pFormatInfo->offScreenPFormat) { + pFormatInfo->onScreenHasMultisample = hasMultisample; + pFormatInfo->onScreenHasStereo = hasStereo; + pFormatInfo->onScreenHasDoubleBuffer = hasDoubleBuffer; + pFormatInfo->onScreenHasAccum = hasAccum; + pFormatInfo->onScreenStencilSize = stencilSize; + + pFormatInfo->offScreenHasMultisample = hasMultisample; + pFormatInfo->offScreenHasStereo = hasStereo; + pFormatInfo->offScreenHasDoubleBuffer = hasDoubleBuffer; + pFormatInfo->offScreenHasAccum = hasAccum; + pFormatInfo->offScreenStencilSize = stencilSize; + } + else if(!offScreen) { + pFormatInfo->onScreenHasMultisample = hasMultisample; + pFormatInfo->onScreenHasStereo = hasStereo; + pFormatInfo->onScreenHasDoubleBuffer = hasDoubleBuffer; + pFormatInfo->onScreenHasAccum = hasAccum; + pFormatInfo->onScreenStencilSize = stencilSize; + } + else { + pFormatInfo->offScreenHasMultisample = hasMultisample; + pFormatInfo->offScreenHasStereo = hasStereo; + pFormatInfo->offScreenHasDoubleBuffer = hasDoubleBuffer; + pFormatInfo->offScreenHasAccum = hasAccum; + pFormatInfo->offScreenStencilSize = stencilSize; + } + +} + + +int chooseSTDPixelFormat( + JNIEnv *env, + jint screen, + jintArray attrList, + HDC hdc, + GLboolean offScreen) +{ + int *mx_ptr; + int dbVal; /* value for double buffering */ + int stereoVal; /* value for stereo */ + int pFormat = -1; /* PixelFormat */ + PIXELFORMATDESCRIPTOR pfd; + int stencilVal = 0; /* value for stencil size */ + GLboolean userReq = GL_TRUE; + + /* fprintf(stderr, "chooseSTDPixelFormat : screen 0x%x, offScreen %d hdc 0x%x\n", + screen, offScreen, hdc); */ + + ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; /* When would this change? */ + pfd.iPixelType = PFD_TYPE_RGBA; + + /* + * Convert Java 3D values to PixelFormat + */ + mx_ptr = (*env)->GetIntArrayElements(env, attrList, NULL); + + if(!offScreen) { + + pfd.cRedBits = (unsigned char) mx_ptr[RED_SIZE]; + pfd.cGreenBits = (unsigned char) mx_ptr[GREEN_SIZE]; + pfd.cBlueBits = (unsigned char) mx_ptr[BLUE_SIZE]; + pfd.cDepthBits = (unsigned char) mx_ptr[DEPTH_SIZE]; + + if (mx_ptr[DOUBLEBUFFER] == REQUIRED || mx_ptr[DOUBLEBUFFER] == PREFERRED) + dbVal = PFD_DOUBLEBUFFER; + else + dbVal = PFD_DOUBLEBUFFER_DONTCARE; + + stereoVal = 0; + if (mx_ptr[STEREO] == REQUIRED || mx_ptr[STEREO] == PREFERRED) { + stereoVal = PFD_STEREO; + } else { + stereoVal = PFD_STEREO_DONTCARE; + } + + pfd.dwFlags = dbVal | stereoVal | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + + /* if user not use stencil we will request one of internal use. */ + stencilVal = mx_ptr[STENCIL_SIZE]; + if (stencilVal < 1) { + userReq = GL_FALSE; + stencilVal = 1; + } + + pfd.cStencilBits = stencilVal; + + if (mx_ptr[ANTIALIASING] == REQUIRED) { + pfd.cAccumRedBits = 8; + pfd.cAccumGreenBits = 8; + pfd.cAccumBlueBits = 8; + } + + } + else { /* Offscreen setting. */ + /* We are here b/c there is no support for Pbuffer on the HW. + This is a fallback path, we will hardcore the value. */ + + /* NOTE : Stencil size isn't handle for Offscreen */ + + /* by MIK OF CLASSX */ + pfd.iPixelType = PFD_TYPE_RGBA; + if (getJavaBoolEnv(env, "transparentOffScreen")) { + pfd.cRedBits = 8; + pfd.cGreenBits = 8; + pfd.cBlueBits = 8; + pfd.cAlphaBits = 8; + pfd.cColorBits = 32; + } + else { + pfd.cRedBits = 8; + pfd.cGreenBits = 8; + pfd.cBlueBits = 8; + pfd.cAlphaBits = 0; + pfd.cColorBits = 24; + } + pfd.cDepthBits = 32; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI; + + } + + pFormat = find_DB_S_STDPixelFormat(&pfd, hdc, mx_ptr, offScreen, stencilVal); + + if ((pFormat == -1) && (userReq == GL_FALSE)) { + /* try disable stencil buffer */ + pfd.cStencilBits = 0; + stencilVal = 0; + pFormat = find_DB_S_STDPixelFormat(&pfd, hdc, mx_ptr, offScreen, stencilVal); + } + + (*env)->ReleaseIntArrayElements(env, attrList, mx_ptr, JNI_ABORT); + return pFormat; +} + +PixelFormatInfo * newPixelFormatInfo(HDC hdc, jboolean usePbuffer) +{ + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL; + + PixelFormatInfo *pFormatInfo = (PixelFormatInfo *) malloc(sizeof(PixelFormatInfo)); + + /* Initialize pFormatInfo */ + pFormatInfo->onScreenPFormat = -1; + pFormatInfo->onScreenHasMultisample = GL_FALSE; + pFormatInfo->onScreenHasStereo = GL_FALSE; + pFormatInfo->onScreenHasDoubleBuffer = GL_FALSE; + pFormatInfo->onScreenHasAccum = GL_FALSE; + pFormatInfo->onScreenStencilSize = 0; + + pFormatInfo->offScreenPFormat = -1; + pFormatInfo->offScreenHasMultisample = GL_FALSE; + pFormatInfo->offScreenHasStereo = GL_FALSE; + pFormatInfo->offScreenHasDoubleBuffer = GL_FALSE; + pFormatInfo->offScreenHasAccum = GL_FALSE; + pFormatInfo->offScreenStencilSize = 0; + pFormatInfo->drawToPbuffer = GL_FALSE; + + pFormatInfo->supportARB = GL_FALSE; + pFormatInfo->supportPbuffer = GL_FALSE; + pFormatInfo->supportedExtensions = NULL; + pFormatInfo->wglChoosePixelFormatARB = NULL; + pFormatInfo->wglGetPixelFormatAttribivARB = NULL; + pFormatInfo->wglCreatePbufferARB = NULL; + pFormatInfo->wglGetPbufferDCARB = NULL; + pFormatInfo->wglReleasePbufferDCARB = NULL; + pFormatInfo->wglDestroyPbufferARB = NULL; + pFormatInfo->wglQueryPbufferARB = NULL; + + wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) + wglGetProcAddress("wglGetExtensionsStringARB"); + if (wglGetExtensionsStringARB == NULL) { + printErrorMessage("wglGetExtensionsStringARB not support !\n"); + /* Doesn't support extensions, return to use standard choosePixelFormat. */ + return pFormatInfo; + } + + /* get the list of supported extensions */ + pFormatInfo->supportedExtensions = (char *)wglGetExtensionsStringARB(hdc); + + /* fprintf(stderr, "WGL Supported extensions: %s.\n", + pFormatInfo->supportedExtensions); */ + + if (isSupportedWGL(pFormatInfo->supportedExtensions, "WGL_ARB_pixel_format")) { + pFormatInfo->wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) + wglGetProcAddress("wglChoosePixelFormatARB"); + + pFormatInfo->wglGetPixelFormatAttribivARB = + (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) + wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + if ((pFormatInfo->wglChoosePixelFormatARB != NULL) && + (pFormatInfo->wglGetPixelFormatAttribivARB != NULL)){ + + /* fprintf(stderr, "wglChoosePixelFormatARB is supported.\n"); */ + pFormatInfo->supportARB = GL_TRUE; + + if (usePbuffer && + isSupportedWGL(pFormatInfo->supportedExtensions, "WGL_ARB_pbuffer")) { + /* Get pbuffer entry points */ + pFormatInfo->wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC) + wglGetProcAddress("wglCreatePbufferARB"); + pFormatInfo->wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC) + wglGetProcAddress("wglGetPbufferDCARB"); + pFormatInfo->wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC) + wglGetProcAddress("wglReleasePbufferDCARB"); + pFormatInfo->wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC) + wglGetProcAddress("wglDestroyPbufferARB"); + pFormatInfo->wglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC) + wglGetProcAddress("wglQueryPbufferARB"); + + if((pFormatInfo->wglCreatePbufferARB != NULL) && + (pFormatInfo->wglGetPbufferDCARB != NULL) && + (pFormatInfo->wglReleasePbufferDCARB != NULL) && + (pFormatInfo->wglDestroyPbufferARB != NULL) && + (pFormatInfo->wglQueryPbufferARB != NULL)) { + + pFormatInfo->supportPbuffer = GL_TRUE; + /* fprintf(stderr, "WGL support Pbuffer\n"); */ + + } + else { + printErrorMessage("Problem in getting WGL_ARB_pbuffer functions !\n"); + } + } + } + else { + printErrorMessage("Problem in getting WGL_ARB_pixel_format functions !\n"); + } + } + + return pFormatInfo; +} + + +JNIEXPORT +jint JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_choosePixelFormat( + JNIEnv *env, + jobject obj, + jlong ctxInfo, + jint screen, + jintArray attrList, + jlongArray offScreenPFArray) +{ + static const BOOL debug = TRUE; + static char szAppName[] = "Choose Pixel Format"; + + int *mx_ptr; + int dbVal; /* value for double buffering */ + int stereoVal; /* value for stereo */ + int antialiasVal; /* value for antialias */ + int stencilVal; /* value for stencil size */ + + HWND hwnd; + HGLRC hrc; + HDC hdc; + int pixelFormat; + int wglAttrs[MAX_WGL_ATTRS_LENGTH]; + int index, lastIndex; + PixelFormatInfo *pFormatInfo = NULL; + jlong * offScreenPFListPtr; + PIXELFORMATDESCRIPTOR dummy_pfd = getDummyPFD(); + + /* + * Select any pixel format and bound current context to + * it so that we can get the wglChoosePixelFormatARB entry point. + * Otherwise wglxxx entry point will always return null. + * That's why we need to create a dummy window also. + */ + hwnd = createDummyWindow((const char *)szAppName); + + if (!hwnd) { + return -1; + } + hdc = GetDC(hwnd); + + pixelFormat = ChoosePixelFormat(hdc, &dummy_pfd); + + if (pixelFormat<1) { + printErrorMessage("In NativeConfigTemplate : Failed in ChoosePixelFormat"); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return -1; + } + + if (!SetPixelFormat(hdc, pixelFormat, NULL)) { + printErrorMessage("In NativeConfigTemplate : Failed in SetPixelFormat"); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return -1; + } + + hrc = wglCreateContext(hdc); + if (!hrc) { + printErrorMessage("In NativeConfigTemplate : Failed in wglCreateContext"); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return -1; + } + + if (!wglMakeCurrent(hdc, hrc)) { + printErrorMessage("In NativeConfigTemplate : Failed in wglMakeCurrent"); + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return -1; + } + + pFormatInfo = newPixelFormatInfo(hdc, getJavaBoolEnv(env,"usePbuffer")); + + offScreenPFListPtr = (*env)->GetLongArrayElements(env, offScreenPFArray, NULL); + + if (pFormatInfo->supportARB) { + + /* fprintf(stderr, "Using non standard ChoosePixelFormat.\n"); */ + + mx_ptr = (*env)->GetIntArrayElements(env, attrList, NULL); + + /* + * convert Java 3D values to WGL + */ + index = 0; + + wglAttrs[index++] = WGL_SUPPORT_OPENGL_ARB; + wglAttrs[index++] = TRUE; + wglAttrs[index++] = WGL_ACCELERATION_ARB; + wglAttrs[index++] = WGL_FULL_ACCELERATION_ARB; + wglAttrs[index++] = WGL_DRAW_TO_WINDOW_ARB; + wglAttrs[index++] = TRUE; + wglAttrs[index++] = WGL_RED_BITS_ARB; + wglAttrs[index++] = mx_ptr[RED_SIZE]; + wglAttrs[index++] = WGL_GREEN_BITS_ARB; + wglAttrs[index++] = mx_ptr[GREEN_SIZE]; + wglAttrs[index++] = WGL_BLUE_BITS_ARB; + wglAttrs[index++] = mx_ptr[BLUE_SIZE]; + + /* by MIK OF CLASSX */ + if (getJavaBoolEnv(env, "transparentOffScreen")) { + wglAttrs[index++] = WGL_ALPHA_BITS_ARB; + wglAttrs[index++] = 1; + } + + wglAttrs[index++] = WGL_DEPTH_BITS_ARB; + wglAttrs[index++] = mx_ptr[DEPTH_SIZE]; + + lastIndex = index; + + dbVal = mx_ptr[DOUBLEBUFFER]; + stereoVal = mx_ptr[STEREO]; + antialiasVal = mx_ptr[ANTIALIASING]; + stencilVal = mx_ptr[STENCIL_SIZE]; + + (*env)->ReleaseIntArrayElements(env, attrList, mx_ptr, JNI_ABORT); + + if(pFormatInfo->supportPbuffer) { + + wglAttrs[index++] = WGL_DRAW_TO_PBUFFER_ARB; + wglAttrs[index++] = TRUE; + + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormatInfo->onScreenPFormat = find_DB_AA_S_S_PixelFormat( hdc, pFormatInfo, + wglAttrs, stereoVal, + dbVal, antialiasVal, + stencilVal, index); + + if(pFormatInfo->onScreenPFormat >= 0) { + /* Since the return pixel format support pbuffer, + we can use it for onScreen and offScreen. */ + pFormatInfo->drawToPbuffer = GL_TRUE; + pFormatInfo->offScreenPFormat = pFormatInfo->onScreenPFormat; + + /* Fix to issue 77 */ + checkPixelFormat(hdc, pFormatInfo, GL_FALSE ); + + offScreenPFListPtr[0] = (jlong) pFormatInfo; + (*env)->ReleaseLongArrayElements(env, offScreenPFArray, offScreenPFListPtr, 0); + + /* Destroy all dummy objects */ + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + + return (jint) pFormatInfo->onScreenPFormat; + } + } + + /* Create a onScreen without Pbuffer */ + pFormatInfo->drawToPbuffer = GL_FALSE; + index = lastIndex; + + /* + * Terminate by 2 zeros to avoid driver bugs + * that assume attributes always come in pairs. + */ + wglAttrs[index] = 0; + wglAttrs[index+1] = 0; + + pFormatInfo->onScreenPFormat = find_DB_AA_S_S_PixelFormat( hdc, pFormatInfo, + wglAttrs, stereoVal, + dbVal, antialiasVal, + stencilVal, index); + } + else { + fprintf(stderr, "Fallback to use standard ChoosePixelFormat.\n"); + + pFormatInfo->onScreenPFormat = (jint) chooseSTDPixelFormat( env, screen, + attrList, hdc, GL_FALSE); + } + + if(pFormatInfo->onScreenPFormat < 0) { + /* + printErrorMessage("In NativeConfigTemplate : Can't choose a onScreen pixel format"); + */ + + offScreenPFListPtr[0] = (jlong) pFormatInfo; + (*env)->ReleaseLongArrayElements(env, offScreenPFArray, offScreenPFListPtr, 0); + + /* We are done with dummy context, so destroy all dummy objects */ + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + + return -1; + } + + /* Fix to issue 77 */ + checkPixelFormat(hdc, pFormatInfo, GL_FALSE ); + + /* Create offScreen with standard ChoosePixelFormat */ + pFormatInfo->offScreenPFormat = chooseSTDPixelFormat( env, screen, attrList, hdc, GL_TRUE); + + /* fprintf(stderr, "********* offScreenPFormat = %d\n", pFormatInfo->offScreenPFormat ); */ + + /* Fix to issue 77 */ + if(pFormatInfo->offScreenPFormat >= 0) { + checkPixelFormat(hdc, pFormatInfo, GL_TRUE ); + } + + offScreenPFListPtr[0] = (jlong) pFormatInfo; + (*env)->ReleaseLongArrayElements(env, offScreenPFArray, offScreenPFListPtr, 0); + + /* We are done with dummy context, so destroy all dummy objects */ + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + + return (jint) pFormatInfo->onScreenPFormat; +} + + +JNIEXPORT +void JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_freePixelFormatInfo( + JNIEnv *env, + jclass class, /* this is a static native method */ + jlong pFormatInfo) +{ + PixelFormatInfo *pfInfo = (PixelFormatInfo *) pFormatInfo; + if(pfInfo->supportedExtensions != NULL) { + free(pfInfo->supportedExtensions); + pfInfo->supportedExtensions = NULL; + } + pfInfo->wglChoosePixelFormatARB = NULL; + pfInfo->wglGetPixelFormatAttribivARB = NULL; + pfInfo->wglCreatePbufferARB = NULL; + pfInfo->wglGetPbufferDCARB = NULL; + pfInfo->wglReleasePbufferDCARB = NULL; + pfInfo->wglDestroyPbufferARB = NULL; + pfInfo->wglQueryPbufferARB = NULL; + free(pfInfo); +} + + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_isStereoAvailable( + JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen) +{ + + static GLboolean first_time = GL_TRUE; + static GLboolean force_no_stereo = GL_FALSE; + PixelFormatInfo *pfInfo = (PixelFormatInfo *) pFormatInfo; + + if (first_time) { + if (getenv("J3D_NO_STEREO") != NULL) { + fprintf(stderr, "Java 3D: stereo mode disabled\n"); + force_no_stereo = GL_TRUE; + } + first_time = GL_FALSE; + } + + if (force_no_stereo) + return JNI_FALSE; + + if(offScreen) { + /* fprintf(stderr, "offScreen isStereoAvailable %d\n", + pfInfo->offScreenHasStereo); */ + + return pfInfo->offScreenHasStereo; + } + else { + /* fprintf(stderr, "onScreen isStereoAvailable %d\n", + pfInfo->onScreenHasStereo); */ + + return pfInfo->onScreenHasStereo; + } + +} + +JNIEXPORT jint JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_getStencilSize( + JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen) +{ + + PixelFormatInfo *pfInfo = (PixelFormatInfo *) pFormatInfo; + if(offScreen) { + /* fprintf(stderr, "offScreen getStencilSize %d\n", + pfInfo->offScreenStencilSize); */ + + return pfInfo->offScreenStencilSize; + } + else { + /* fprintf(stderr, "onScreen getStencilSize %d\n", + pfInfo->onScreenStencilSize); */ + + return pfInfo->onScreenStencilSize; + } + +} + + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_isDoubleBufferAvailable( + JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen) +{ + + PixelFormatInfo *pfInfo = (PixelFormatInfo *) pFormatInfo; + if(offScreen) { + /* fprintf(stderr, "offScreen isDoubleBufferAvailable %d\n", + pfInfo->offScreenHasDoubleBuffer); */ + + return pfInfo->offScreenHasDoubleBuffer; + } + else { + /* fprintf(stderr, "onScreen isDoubleBufferAvailable %d\n", + pfInfo->onScreenHasDoubleBuffer); */ + + return pfInfo->onScreenHasDoubleBuffer; + } + +} + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_isSceneAntialiasingAccumAvailable( + JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen) +{ + PixelFormatInfo *pfInfo = (PixelFormatInfo *) pFormatInfo; + if(offScreen) { + /* fprintf(stderr, "offScreen isSceneAntialiasingAccumAvailable %d\n", + pfInfo->offScreenHasAccum); */ + + return pfInfo->offScreenHasAccum; + } + else { + /* fprintf(stderr, "onScreen isSceneAntialiasingAccumAvailable %d\n", + pfInfo->onScreenHasAccum); */ + + return pfInfo->onScreenHasAccum; + } +} + +JNIEXPORT +jboolean JNICALL Java_javax_media_j3d_Win32NativeConfigTemplate3D_isSceneAntialiasingMultisampleAvailable( + JNIEnv *env, + jobject obj, + jlong pFormatInfo, + jboolean offScreen, + jint screen) +{ + /* Fix to issue 77 */ + PixelFormatInfo *pfInfo = (PixelFormatInfo *) pFormatInfo; + if(offScreen) { + /* fprintf(stderr, "offScreen isSceneAntialiasingMultisampleAvailable %d\n", + pfInfo->offScreenHasMultisample); */ + + return pfInfo->offScreenHasMultisample; + } + else { + /* fprintf(stderr, "onScreen isSceneAntialiasingMultisampleAvailable %d\n", + pfInfo->onScreenHasMultisample); */ + + return pfInfo->onScreenHasMultisample; + } +} +#endif /* WIN32 */ diff --git a/j3d-core/src/native/ogl/NativeScreenInfo.c b/j3d-core/src/native/ogl/NativeScreenInfo.c new file mode 100644 index 0000000..3084241 --- /dev/null +++ b/j3d-core/src/native/ogl/NativeScreenInfo.c @@ -0,0 +1,261 @@ +/* + * $RCSfile: NativeScreenInfo.c,v $ + * + * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.15 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include +#include +#include + +#include "gldefs.h" + +#if defined(UNIX) +#include +#include +#include +#include +#endif + +#ifdef WIN32 +#include +#endif + +#if defined(UNIX) + + +/* + * Class: javax_media_j3d_X11NativeScreenInfo + * Method: openDisplay + * Signature: ()J + */ +JNIEXPORT jlong JNICALL +Java_javax_media_j3d_X11NativeScreenInfo_openDisplay( + JNIEnv *env, + jclass cls) +{ + Display* dpy; + dpy = XOpenDisplay(NULL); + return (jlong)dpy; +} + +/* + * Class: javax_media_j3d_X11NativeScreenInfo + * Method: getDefaultScreen + * Signature: (J)I + */ +JNIEXPORT jint JNICALL +Java_javax_media_j3d_X11NativeScreenInfo_getDefaultScreen( + JNIEnv *env, + jclass cls, + jlong display) +{ + Display* dpy = (Display*)display; + return (jint)DefaultScreen(dpy); +} + +/* + * Class: javax_media_j3d_X11NativeScreenInfo + * Method: queryGLX13 + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL +Java_javax_media_j3d_X11NativeScreenInfo_queryGLX13( + JNIEnv *env, + jclass cls, + jlong display) +{ + /* Fix for Issue 20 */ + MYPFNGLXCHOOSEFBCONFIG tmpfp; + int major, minor; + int errorBase, eventBase; + Display* dpy = (Display*)display; + /* It should be cleaner to return both the major and minor to the caller. */ + + if (!glXQueryExtension(dpy, &errorBase, &eventBase)) { + fprintf(stderr, "Java 3D ERROR : GLX extension is not supported\n"); + fprintf(stderr, " GLX version 1.3 or higher is required\n"); + return JNI_FALSE; + } + + /* Query the GLX version number */ + if (!glXQueryVersion(dpy, &major, &minor)) { + fprintf(stderr, "Java 3D ERROR : Unable to query GLX version\n"); + fprintf(stderr, " GLX version 1.3 or higher is required\n"); + return JNI_FALSE; + } + /*fprintf(stderr, "Checking GLX version : %d.%d\n", major, minor);*/ + + tmpfp = (MYPFNGLXCHOOSEFBCONFIG)dlsym(RTLD_DEFAULT, "glXChooseFBConfig"); + + if (tmpfp == NULL) { + fprintf(stderr, "Java 3D ERROR : glXChooseFBConfig not found\n"); + fprintf(stderr, " GLX version = %d.%d\n", major, minor); + fprintf(stderr, " GLX version 1.3 or higher is required\n"); + return JNI_FALSE; + } + + /* Check for GLX 1.3 and higher */ + if (!(major == 1 && minor >= 3)) { + fprintf(stderr, "Java 3D WARNING : reported GLX version = %d.%d\n", major, minor); + fprintf(stderr, " GLX version 1.3 or higher is required\n"); + + fprintf(stderr, + " The reported version number may be incorrect. There is a known\n"); + fprintf(stderr, + " ATI driver bug in glXQueryVersion that incorrectly reports the GLX\n"); + fprintf(stderr, + " version as 1.2 when it really is 1.3, so Java 3D will attempt to\n"); + fprintf(stderr, + " run anyway.\n"); + + /*return JNI_FALSE;*/ + } + + return JNI_TRUE; +} + +#endif /* Solaris and Linux */ + + +#ifdef WIN32 + +extern HWND createDummyWindow(const char* szAppName); +extern void printErrorMessage(char *message); +extern PIXELFORMATDESCRIPTOR getDummyPFD(); +extern BOOL isSupportedWGL(const char *extensions, const char *extension_string); + +/* + * Class: javax_media_j3d_Win32NativeScreenInfo + * Method: queryWglARB + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL +Java_javax_media_j3d_Win32NativeScreenInfo_queryWglARB( + JNIEnv *env, + jclass cls) +{ + + static const BOOL debug = TRUE; + static char szAppName[] = "Choose Pixel Format"; + + PIXELFORMATDESCRIPTOR dummy_pfd = getDummyPFD(); + HWND hwnd; + HGLRC hrc; + HDC hdc; + int pixelFormat; + const char* supportedExtensions; + + /* declare function pointers for WGL functions */ + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL; + + /* + * Select any pixel format and bound current context to + * it so that we can get the wglChoosePixelFormatARB entry point. + * Otherwise wglxxx entry point will always return null. + * That's why we need to create a dummy window also. + */ + hwnd = createDummyWindow((const char *)szAppName); + + if (!hwnd) { + return JNI_FALSE; + } + hdc = GetDC(hwnd); + + pixelFormat = ChoosePixelFormat(hdc, &dummy_pfd); + + if (pixelFormat<1) { + printErrorMessage("Failed in ChoosePixelFormat"); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return JNI_FALSE; + } + + if (!SetPixelFormat(hdc, pixelFormat, NULL)) { + printErrorMessage("Failed in SetPixelFormat"); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return -1; + } + + hrc = wglCreateContext(hdc); + if (!hrc) { + printErrorMessage("Failed in wglCreateContext"); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return JNI_FALSE; + } + + if (!wglMakeCurrent(hdc, hrc)) { + printErrorMessage("Failed in wglMakeCurrent"); + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return JNI_FALSE; + } + + wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) + wglGetProcAddress("wglGetExtensionsStringARB"); + if (wglGetExtensionsStringARB == NULL) { + /* printErrorMessage("wglGetExtensionsStringARB not support !\n"); */ + return JNI_FALSE; + } + else { + + /* get the list of supported extensions */ + supportedExtensions = (const char *)wglGetExtensionsStringARB(hdc); + + if (debug) { + fprintf(stderr, "WGL Supported extensions: %s.\n", supportedExtensions); + } + + if(!isSupportedWGL(supportedExtensions, "WGL_ARB_pixel_format")) { + fprintf(stderr, "WGL_ARB_pixel_format not supported.\n"); + return JNI_FALSE; + } + } + + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return JNI_TRUE; + + +} +#endif /* WIN32 */ diff --git a/j3d-core/src/native/ogl/OglCheck.c b/j3d-core/src/native/ogl/OglCheck.c new file mode 100644 index 0000000..75c8248 --- /dev/null +++ b/j3d-core/src/native/ogl/OglCheck.c @@ -0,0 +1,421 @@ +/* + * $RCSfile: OglCheck.c,v $ + * + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.3 $ + * $Date: 2008/02/28 20:18:00 $ + * $State: Exp $ + */ + +#ifdef DEBUG +/* #define VERBOSE */ +#endif /* DEBUG */ + +/* This entire file is Windows-only */ +#ifdef WIN32 + +/* j3dsys.h needs to be included before any other include files to suppres VC warning */ +#include "j3dsys.h" + +#include +#include +#include +#include +#include + +#include +#include "wglext.h" +#include "javax_media_j3d_NativePipeline.h" + + +static void +printErrorMessage(char *message) +{ + DWORD err; + char * errString; + + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR)&errString, 0, NULL); + fprintf(stderr, "Java 3D ERROR : %s - %s\n", message, errString); + LocalFree(errString); +} + + +/* + * A dummy WndProc for dummy window + */ +static LONG WINAPI +WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + /* This function handles any messages that we didn't. */ + /* (Which is most messages) It belongs to the OS. */ + return (LONG) DefWindowProc( hWnd, msg, wParam, lParam ); +} + + +static HWND +createDummyWindow(const char* szAppName) +{ + static const char *szTitle = "Dummy Window"; + WNDCLASS wc; /* windows class sruct */ + + HWND hWnd; + + /* Fill in window class structure with parameters that */ + /* describe the main window. */ + + wc.style = + CS_HREDRAW | CS_VREDRAW;/* Class style(s). */ + wc.lpfnWndProc = + (WNDPROC)WndProc; /* Window Procedure */ + wc.cbClsExtra = 0; /* No per-class extra data. */ + wc.cbWndExtra = 0; /* No per-window extra data. */ + wc.hInstance = + NULL; /* Owner of this class */ + wc.hIcon = NULL; /* Icon name */ + wc.hCursor = + NULL;/* Cursor */ + wc.hbrBackground = + (HBRUSH)(COLOR_WINDOW+1);/* Default color */ + wc.lpszMenuName = NULL; /* Menu from .RC */ + wc.lpszClassName = + szAppName; /* Name to register as + + /* Register the window class */ + + if(RegisterClass( &wc )==0) { + printErrorMessage("createDummyWindow: couldn't register class"); + return NULL; + } + + /* Create a main window for this application instance. */ + + hWnd = CreateWindow( + szAppName, /* app name */ + szTitle, /* Text for window title bar */ + WS_OVERLAPPEDWINDOW/* Window style */ + /* NEED THESE for OpenGL calls to work!*/ + | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + NULL, /* no parent window */ + NULL, /* Use the window class menu.*/ + NULL, /* This instance owns this window */ + NULL /* We don't use any extra data */ + ); + + /* If window could not be created, return zero */ + if ( !hWnd ){ + printErrorMessage("createDummyWindow: couldn't create window"); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return NULL; + } + return hWnd; +} + + +static PIXELFORMATDESCRIPTOR +getDummyPFD() +{ + + /* Dummy pixel format. -- Chien */ + static PIXELFORMATDESCRIPTOR dummy_pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, /* Version number */ + PFD_DRAW_TO_WINDOW | + PFD_SUPPORT_OPENGL, + PFD_TYPE_RGBA, + 16, /* 16 bit color depth */ + 0, 0, 0, /* RGB bits and pixel sizes */ + 0, 0, 0, /* Do not care about them */ + 0, 0, /* no alpha buffer info */ + 0, 0, 0, 0, 0, /* no accumulation buffer */ + 8, /* 8 bit depth buffer */ + 0, /* no stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* layer type */ + 0, /* reserved, must be 0 */ + 0, /* no layer mask */ + 0, /* no visible mask */ + 0 /* no damage mask */ + }; + + return dummy_pfd; +} + + +static BOOL +isSupportedWGL(const char *extensions, const char *extension_string) +{ + /* get the list of supported extensions */ + const char *p = extensions; + + /* search for extension_string in the list */ + while(p = strstr(p, extension_string)){ + const char *q = p + strlen(extension_string); + + /* must be terminated by or */ + if(*q == ' ' || *q == '\0') { + return TRUE; + } + + /* try to find another match */ + p = q; + } + return FALSE; +} + + +/* +static HDC +getMonitorDC(int screen) +{ + return CreateDC("DISPLAY", NULL, NULL, NULL); +} +*/ + + +/* + * Extract the version numbers from a copy of the version string. + * Upon return, numbers[0] contains major version number + * numbers[1] contains minor version number + * Note that the passed in version string is modified. + */ +static void +extractVersionInfo(char *versionStr, int* numbers) +{ + char *majorNumStr; + char *minorNumStr; + + numbers[0] = numbers[1] = -1; + majorNumStr = strtok(versionStr, (char *)"."); + minorNumStr = strtok(0, (char *)"."); + if (majorNumStr != NULL) + numbers[0] = atoi(majorNumStr); + if (minorNumStr != NULL) + numbers[1] = atoi(minorNumStr); +} + + +/* + * get properties from current context + */ +static char* +queryVendorString(HDC hdc, HGLRC hrc) +{ + char *glVersion; + char *tmpVersionStr; + int versionNumbers[2]; + char *glVendor; + char *supportedExtensions; + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB; + + if (!wglMakeCurrent(hdc, hrc)) { +#ifdef DEBUG + printErrorMessage("getSupportedOglVendorNative : Failed in wglMakeCurrent"); +#endif /* DEBUG */ + return NULL; + } + + wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) + wglGetProcAddress("wglGetExtensionsStringARB"); + if (wglGetExtensionsStringARB == NULL) { +#ifdef DEBUG + printErrorMessage("getSupportedOglVendorNative : wglGetExtensionsStringARB not supported\n"); +#endif /* DEBUG */ + return NULL; + } + + /* get the list of supported extensions */ + supportedExtensions = (char *)wglGetExtensionsStringARB(hdc); + +#ifdef VERBOSE + fprintf(stderr, "WGL Supported extensions: %s\n", + supportedExtensions); +#endif /* VERBOSE */ + + if (supportedExtensions == NULL || + !isSupportedWGL(supportedExtensions, "WGL_ARB_pixel_format") || + wglGetProcAddress("wglChoosePixelFormatARB") == NULL || + wglGetProcAddress("wglGetPixelFormatAttribivARB") == NULL) { +#ifdef DEBUG + printErrorMessage("getSupportedOglVendorNative : wglChoosePixelFormatARB/GetPixelFormatAttribivARB not supported\n"); +#endif /* DEBUG */ + return NULL; + } + + /* Get the OpenGL version */ + glVersion = (char *)glGetString(GL_VERSION); + if (glVersion == NULL) { +#ifdef DEBUG + fprintf(stderr, "JAVA 3D ERROR : glVersion == null\n"); +#endif /* DEBUG */ + return NULL; + } + + /* find out the version, major and minor version number */ + tmpVersionStr = strdup(glVersion); + extractVersionInfo(tmpVersionStr, versionNumbers); + free(tmpVersionStr); + +#ifdef VERBOSE + fprintf(stderr, "GL_VERSION string = %s\n", glVersion); + fprintf(stderr, "GL_VERSION (major.minor) = %d.%d\n", + versionNumbers[0], versionNumbers[1]); +#endif /* VERBOSE */ + + /* + * Check for OpenGL 1.2 or later. + */ + if (versionNumbers[0] < 1 || + (versionNumbers[0] == 1 && versionNumbers[1] < 2)) { +#ifdef DEBUG + fprintf(stderr, + "Java 3D ERROR : OpenGL 1.2 or better is required (GL_VERSION=%d.%d)\n", + versionNumbers[0], versionNumbers[1]); +#endif /* DEBUG */ + return NULL; + } + + /* Get the OpenGL vendor */ + glVendor = (char *)glGetString(GL_VENDOR); + if (glVendor == NULL) { +#ifdef DEBUG + fprintf(stderr, "JAVA 3D ERROR : glVendor == null\n"); +#endif /* DEBUG */ + return NULL; + } + +#ifdef VERBOSE + fprintf(stderr, "GL_VENDOR = %s\n", glVendor); +#endif /* VERBOSE */ + + return glVendor; +} + + +/* + * Class: javax_media_j3d_NativePipeline + * Method: getSupportedOglVendorNative + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_javax_media_j3d_NativePipeline_getSupportedOglVendorNative( + JNIEnv *env, + jclass clazz) +{ + static char szAppName[] = "OglCheck"; + + static int wglAttrs[] = { + WGL_SUPPORT_OPENGL_ARB, + TRUE, + WGL_ACCELERATION_ARB, + WGL_FULL_ACCELERATION_ARB, + WGL_DRAW_TO_WINDOW_ARB, + TRUE, + WGL_RED_BITS_ARB, + 4, + WGL_GREEN_BITS_ARB, + 4, + WGL_BLUE_BITS_ARB, + 4, + WGL_DEPTH_BITS_ARB, + 16, + }; + + HWND hwnd; + HGLRC hrc; + HDC hdc; + int pixelFormat; + PIXELFORMATDESCRIPTOR dummy_pfd = getDummyPFD(); + char *glVendor = NULL; + jstring glVendorString = NULL; + + JNIEnv table = *env; + +#ifdef VERBOSE + fprintf(stderr, "NativePipeline.getSupportedOglVendorNative()\n"); +#endif /* VERBOSE */ + + /* + * Select any pixel format and bound current context to + * it so that we can get the wglChoosePixelFormatARB entry point. + * Otherwise wglxxx entry point will always return null. + * That's why we need to create a dummy window also. + */ + hwnd = createDummyWindow((const char *)szAppName); + + if (!hwnd) { + return NULL; + } + hdc = GetDC(hwnd); + + pixelFormat = ChoosePixelFormat(hdc, &dummy_pfd); + + if (pixelFormat<1) { +#ifdef DEBUG + printErrorMessage("getSupportedOglVendorNative : Failed in ChoosePixelFormat"); +#endif /* DEBUG */ + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return NULL; + } + + if (!SetPixelFormat(hdc, pixelFormat, NULL)) { +#ifdef DEBUG + printErrorMessage("getSupportedOglVendorNative : Failed in SetPixelFormat"); +#endif /* DEBUG */ + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return NULL; + } + + hrc = wglCreateContext(hdc); + if (!hrc) { +#ifdef DEBUG + printErrorMessage("getSupportedOglVendorNative : Failed in wglCreateContext"); +#endif /* DEBUG */ + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + return NULL; + } + + /* Check OpenGL extensions & version, and return vendor string */ + glVendor = queryVendorString(hdc, hrc); + if (glVendor != NULL) { + glVendorString = table->NewStringUTF(env, glVendor); + } + + /* Destroy all dummy objects */ + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass(szAppName, (HINSTANCE)NULL); + + return glVendorString; +} + +#endif /* WIN32 */ diff --git a/j3d-core/src/native/ogl/build-linux-amd64.xml b/j3d-core/src/native/ogl/build-linux-amd64.xml new file mode 100644 index 0000000..e3e5b6a --- /dev/null +++ b/j3d-core/src/native/ogl/build-linux-amd64.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-linux-i586.xml b/j3d-core/src/native/ogl/build-linux-i586.xml new file mode 100644 index 0000000..df697c5 --- /dev/null +++ b/j3d-core/src/native/ogl/build-linux-i586.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-linux-ia64.xml b/j3d-core/src/native/ogl/build-linux-ia64.xml new file mode 100644 index 0000000..de2afad --- /dev/null +++ b/j3d-core/src/native/ogl/build-linux-ia64.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-linux-ppc.xml b/j3d-core/src/native/ogl/build-linux-ppc.xml new file mode 100644 index 0000000..dce7a6f --- /dev/null +++ b/j3d-core/src/native/ogl/build-linux-ppc.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-solaris-sparc-forte.xml b/j3d-core/src/native/ogl/build-solaris-sparc-forte.xml new file mode 100644 index 0000000..cdd7832 --- /dev/null +++ b/j3d-core/src/native/ogl/build-solaris-sparc-forte.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-solaris-sparc-gcc.xml b/j3d-core/src/native/ogl/build-solaris-sparc-gcc.xml new file mode 100644 index 0000000..b58abe0 --- /dev/null +++ b/j3d-core/src/native/ogl/build-solaris-sparc-gcc.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-solaris-x86-forte.xml b/j3d-core/src/native/ogl/build-solaris-x86-forte.xml new file mode 100644 index 0000000..61d6048 --- /dev/null +++ b/j3d-core/src/native/ogl/build-solaris-x86-forte.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-solaris-x86-gcc.xml b/j3d-core/src/native/ogl/build-solaris-x86-gcc.xml new file mode 100644 index 0000000..bcd7b18 --- /dev/null +++ b/j3d-core/src/native/ogl/build-solaris-x86-gcc.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-windows-amd64-vc.xml b/j3d-core/src/native/ogl/build-windows-amd64-vc.xml new file mode 100644 index 0000000..a0fffd7 --- /dev/null +++ b/j3d-core/src/native/ogl/build-windows-amd64-vc.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-windows-i586-gcc.xml b/j3d-core/src/native/ogl/build-windows-i586-gcc.xml new file mode 100644 index 0000000..8274695 --- /dev/null +++ b/j3d-core/src/native/ogl/build-windows-i586-gcc.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/build-windows-i586-vc.xml b/j3d-core/src/native/ogl/build-windows-i586-vc.xml new file mode 100644 index 0000000..d675afe --- /dev/null +++ b/j3d-core/src/native/ogl/build-windows-i586-vc.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/j3d-core/src/native/ogl/gldefs.h b/j3d-core/src/native/ogl/gldefs.h new file mode 100644 index 0000000..bf4434f --- /dev/null +++ b/j3d-core/src/native/ogl/gldefs.h @@ -0,0 +1,705 @@ +/* + * $RCSfile: gldefs.h,v $ + * + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.20 $ + * $Date: 2008/02/28 20:18:01 $ + * $State: Exp $ + */ + +#ifndef _Java3D_gldefs_h_ +#define _Java3D_gldefs_h_ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +#include +#include +#include + +/* + * Before we include gl.h we need to ensure that our versions of the + * wglext.h and glext.h files get loaded, not the platform's versions. + */ +#ifndef __glext_h_ +#define __glext_h_ +#define Java3D_undef__glext_h_ +#endif + +#ifndef __wglext_h_ +#define __wglext_h_ +#define Java3D_undef__wglext_h_ +#endif + +#if defined(SOLARIS) || defined(LINUX) +#define GLX_GLEXT_PROTOTYPES +#define GLX_GLXEXT_PROTOTYPES +#define UNIX + +#include +#include +#include + +#include +#include +#ifdef Java3D_undef__glext_h_ +#undef __glext_h_ +#endif +#include "glext.h" +#endif + +#ifdef WIN32 +#include + +#ifndef _WIN32 +#define _WIN32 +#endif + +#define M_PI 3.14159265358979323846 + +/* Some constant defined in those javax_media_j3d_*.h */ +/* TODO: remove those constant when D3D automatically include those *.h files */ +#ifdef D3D + +/* used in GeometryArrayRetained, execute geometry in by REFERENCE case */ +#ifndef javax_media_j3d_GeometryArrayRetained_COORD_FLOAT +#define javax_media_j3d_GeometryArrayRetained_COORD_FLOAT 1L +#endif +#ifndef javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE +#define javax_media_j3d_GeometryArrayRetained_COORD_DOUBLE 2L +#endif +#ifndef javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT +#define javax_media_j3d_GeometryArrayRetained_COLOR_FLOAT 4L +#endif +#ifndef javax_media_j3d_GeometryArrayRetained_COLOR_BYTE +#define javax_media_j3d_GeometryArrayRetained_COLOR_BYTE 8L +#endif +#ifndef javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT +#define javax_media_j3d_GeometryArrayRetained_NORMAL_FLOAT 16L +#endif +#ifndef javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT +#define javax_media_j3d_GeometryArrayRetained_TEXCOORD_FLOAT 32L +#endif + +#endif /* end of ifdef D3D */ + +#ifndef D3D +#include +#ifdef Java3D_undef__wglext_h_ +#undef __wglext_h_ +#endif +#ifdef Java3D_undef__glext_h_ +#undef __glext_h_ +#endif +#include "wglext.h" +#include "glext.h" +#endif + +#endif /* WIN32 */ + +/* include those .h files generated by javah */ +#include "javax_media_j3d_Background.h" +#include "javax_media_j3d_Canvas3D.h" +#include "javax_media_j3d_ColoringAttributes.h" +#include "javax_media_j3d_ColoringAttributesRetained.h" +#include "javax_media_j3d_DepthComponentRetained.h" +#include "javax_media_j3d_DirectionalLightRetained.h" +#include "javax_media_j3d_DisplayListRenderMethod.h" +#include "javax_media_j3d_DrawingSurfaceObjectAWT.h" +#include "javax_media_j3d_ExponentialFogRetained.h" +#include "javax_media_j3d_GeometryRetained.h" +#include "javax_media_j3d_GeometryArray.h" +#include "javax_media_j3d_GeometryArrayRetained.h" +#include "javax_media_j3d_GraphicsContext3D.h" +#include "javax_media_j3d_ImageComponent.h" +#include "javax_media_j3d_ImageComponentRetained.h" +#include "javax_media_j3d_ImageComponent2DRetained.h" +#include "javax_media_j3d_IndexedGeometryArrayRetained.h" +#include "javax_media_j3d_LineAttributes.h" +#include "javax_media_j3d_LineAttributesRetained.h" +#include "javax_media_j3d_LinearFogRetained.h" +#include "javax_media_j3d_MasterControl.h" +#include "javax_media_j3d_Material.h" +#include "javax_media_j3d_MaterialRetained.h" +#include "javax_media_j3d_ModelClipRetained.h" +#include "javax_media_j3d_NativeConfigTemplate3D.h" +#include "javax_media_j3d_NativePipeline.h" +#include "javax_media_j3d_NodeRetained.h" +#include "javax_media_j3d_PointAttributesRetained.h" +#include "javax_media_j3d_PointLightRetained.h" +#include "javax_media_j3d_PolygonAttributes.h" +#include "javax_media_j3d_PolygonAttributesRetained.h" +#include "javax_media_j3d_Raster.h" +#include "javax_media_j3d_RasterRetained.h" +#include "javax_media_j3d_Renderer.h" +#include "javax_media_j3d_RenderingAttributes.h" +#include "javax_media_j3d_RenderingAttributesRetained.h" +#include "javax_media_j3d_RenderMolecule.h" +#include "javax_media_j3d_SpotLightRetained.h" +#include "javax_media_j3d_TexCoordGeneration.h" +#include "javax_media_j3d_TexCoordGenerationRetained.h" +#include "javax_media_j3d_Texture.h" +#include "javax_media_j3d_Texture2D.h" +#include "javax_media_j3d_Texture2DRetained.h" +#include "javax_media_j3d_Texture3DRetained.h" +#include "javax_media_j3d_TextureAttributes.h" +#include "javax_media_j3d_TextureAttributesRetained.h" +#include "javax_media_j3d_TextureCubeMapRetained.h" +#include "javax_media_j3d_TextureRetained.h" +#include "javax_media_j3d_TextureUnitStateRetained.h" +#include "javax_media_j3d_TransparencyAttributes.h" +#include "javax_media_j3d_TransparencyAttributesRetained.h" +#include "javax_media_j3d_GLSLShaderProgramRetained.h" +#include "javax_media_j3d_CgShaderProgramRetained.h" +#include "javax_media_j3d_Shader.h" +#include "javax_media_j3d_ShaderAttributeObjectRetained.h" +#include "javax_media_j3d_ShaderError.h" + +#ifdef WIN32 +#include "javax_media_j3d_Win32NativeConfigTemplate3D.h" +#include "javax_media_j3d_Win32NativeScreenInfo.h" +#else +#include "javax_media_j3d_X11NativeConfigTemplate3D.h" +#include "javax_media_j3d_X11NativeScreenInfo.h" +#endif + +/* Used to compare floating point values close to 0.0 */ +#define J3D_SMALL_FLOAT 0.00001f + +/* + * General purpose assertion macro + */ +#define J3D_ASSERT(expr) \ + if (!(expr)) { \ + fprintf(stderr, \ + "\nAssertion failed in module '%s' at line %d\n", \ + __FILE__, __LINE__); \ + fprintf(stderr, "\t%s\n\n", #expr); \ + } + +#define EPSILON 1e-2 +#define J3D_FNE(a,b) ((a)>((b)+EPSILON)||(a)<((b)-EPSILON)) + + +/* + * Macro to copy and transpose one matrix to another. + * + * NOTE: the source and dest must not be the same (no aliasing check + * is performed). + */ +#define COPY_TRANSPOSE(src,dst) { \ + (dst)[0] = (src)[0]; \ + (dst)[1] = (src)[4]; \ + (dst)[2] = (src)[8]; \ + (dst)[3] = (src)[12]; \ + (dst)[4] = (src)[1]; \ + (dst)[5] = (src)[5]; \ + (dst)[6] = (src)[9]; \ + (dst)[7] = (src)[13]; \ + (dst)[8] = (src)[2]; \ + (dst)[9] = (src)[6]; \ + (dst)[10] = (src)[10]; \ + (dst)[11] = (src)[14]; \ + (dst)[12] = (src)[3]; \ + (dst)[13] = (src)[7]; \ + (dst)[14] = (src)[11]; \ + (dst)[15] = (src)[15]; \ +} + + +/* + * These match the constants in GeometryRetained + */ + +#define GEO_TYPE_NONE javax_media_j3d_GeometryRetained_GEO_TYPE_NONE +#define GEO_TYPE_QUAD_SET javax_media_j3d_GeometryRetained_GEO_TYPE_QUAD_SET +#define GEO_TYPE_TRI_SET javax_media_j3d_GeometryRetained_GEO_TYPE_TRI_SET +#define GEO_TYPE_POINT_SET javax_media_j3d_GeometryRetained_GEO_TYPE_POINT_SET +#define GEO_TYPE_LINE_SET javax_media_j3d_GeometryRetained_GEO_TYPE_LINE_SET +#define GEO_TYPE_TRI_STRIP_SET javax_media_j3d_GeometryRetained_GEO_TYPE_TRI_STRIP_SET +#define GEO_TYPE_TRI_FAN_SET javax_media_j3d_GeometryRetained_GEO_TYPE_TRI_FAN_SET +#define GEO_TYPE_LINE_STRIP_SET javax_media_j3d_GeometryRetained_GEO_TYPE_LINE_STRIP_SET +#define GEO_TYPE_INDEXED_QUAD_SET javax_media_j3d_GeometryRetained_GEO_TYPE_INDEXED_QUAD_SET +#define GEO_TYPE_INDEXED_TRI_SET javax_media_j3d_GeometryRetained_GEO_TYPE_INDEXED_TRI_SET +#define GEO_TYPE_INDEXED_POINT_SET javax_media_j3d_GeometryRetained_GEO_TYPE_INDEXED_POINT_SET +#define GEO_TYPE_INDEXED_LINE_SET javax_media_j3d_GeometryRetained_GEO_TYPE_INDEXED_LINE_SET +#define GEO_TYPE_INDEXED_TRI_STRIP_SET javax_media_j3d_GeometryRetained_GEO_TYPE_INDEXED_TRI_STRIP_SET +#define GEO_TYPE_INDEXED_TRI_FAN_SET javax_media_j3d_GeometryRetained_GEO_TYPE_INDEXED_TRI_FAN_SET +#define GEO_TYPE_INDEXED_LINE_STRIP_SET javax_media_j3d_GeometryRetained_GEO_TYPE_INDEXED_LINE_STRIP_SET +#define GEO_TYPE_RASTER javax_media_j3d_GeometryRetained_GEO_TYPE_RASTER +#define GEO_TYPE_TEXT3D javax_media_j3d_GeometryRetained_GEO_TYPE_TEXT3D +#define GEO_TYPE_COMPRESSED javax_media_j3d_GeometryRetained_GEO_TYPE_COMPRESSED +#define GEO_TYPE_TOTAL javax_media_j3d_GeometryRetained_GEO_TYPE_TOTAL + +/* + * These match the constants in ImageComponent + */ + +#define FORMAT_RGB javax_media_j3d_ImageComponent_FORMAT_RGB +#define FORMAT_RGBA javax_media_j3d_ImageComponent_FORMAT_RGBA +#define FORMAT_RGB5 javax_media_j3d_ImageComponent_FORMAT_RGB5 +#define FORMAT_RGB5_A1 javax_media_j3d_ImageComponent_FORMAT_RGB5_A1 +#define FORMAT_RGB4 javax_media_j3d_ImageComponent_FORMAT_RGB4 +#define FORMAT_RGBA4 javax_media_j3d_ImageComponent_FORMAT_RGBA4 +#define FORMAT_LUM4_ALPHA4 javax_media_j3d_ImageComponent_FORMAT_LUM4_ALPHA4 +#define FORMAT_LUM8_ALPHA8 javax_media_j3d_ImageComponent_FORMAT_LUM8_ALPHA8 +#define FORMAT_R3_G3_B2 javax_media_j3d_ImageComponent_FORMAT_R3_G3_B2 +#define FORMAT_CHANNEL8 javax_media_j3d_ImageComponent_FORMAT_CHANNEL8 + + +/* now the imagecomponent formats are reduced the ones below */ +#define IMAGE_FORMAT_BYTE_BGR javax_media_j3d_ImageComponentRetained_TYPE_BYTE_BGR +#define IMAGE_FORMAT_BYTE_RGB javax_media_j3d_ImageComponentRetained_TYPE_BYTE_RGB +#define IMAGE_FORMAT_BYTE_ABGR javax_media_j3d_ImageComponentRetained_TYPE_BYTE_ABGR +#define IMAGE_FORMAT_BYTE_RGBA javax_media_j3d_ImageComponentRetained_TYPE_BYTE_RGBA +#define IMAGE_FORMAT_BYTE_LA javax_media_j3d_ImageComponentRetained_TYPE_BYTE_LA +#define IMAGE_FORMAT_BYTE_GRAY javax_media_j3d_ImageComponentRetained_TYPE_BYTE_GRAY +#define IMAGE_FORMAT_USHORT_GRAY javax_media_j3d_ImageComponentRetained_TYPE_USHORT_GRAY +#define IMAGE_FORMAT_INT_BGR javax_media_j3d_ImageComponentRetained_TYPE_INT_BGR +#define IMAGE_FORMAT_INT_RGB javax_media_j3d_ImageComponentRetained_TYPE_INT_RGB +#define IMAGE_FORMAT_INT_ARGB javax_media_j3d_ImageComponentRetained_TYPE_INT_ARGB + +#define IMAGE_DATA_TYPE_BYTE_ARRAY javax_media_j3d_ImageComponentRetained_IMAGE_DATA_TYPE_BYTE_ARRAY +#define IMAGE_DATA_TYPE_INT_ARRAY javax_media_j3d_ImageComponentRetained_IMAGE_DATA_TYPE_INT_ARRAY +#define IMAGE_DATA_TYPE_BYTE_BUFFER javax_media_j3d_ImageComponentRetained_IMAGE_DATA_TYPE_BYTE_BUFFER +#define IMAGE_DATA_TYPE_INT_BUFFER javax_media_j3d_ImageComponentRetained_IMAGE_DATA_TYPE_INT_BUFFER + + +/* These match the definitions in GeometryArray.java */ +/* These have a GA prefix to avoid confusion with TEXTURE_COORDINATE_2 above */ +#define GA_COORDINATES javax_media_j3d_GeometryArray_COORDINATES +#define GA_NORMALS javax_media_j3d_GeometryArray_NORMALS +#define GA_COLOR javax_media_j3d_GeometryArray_COLOR +#define GA_WITH_ALPHA javax_media_j3d_GeometryArray_WITH_ALPHA +#define GA_TEXTURE_COORDINATE_2 javax_media_j3d_GeometryArray_TEXTURE_COORDINATE_2 +#define GA_TEXTURE_COORDINATE_3 javax_media_j3d_GeometryArray_TEXTURE_COORDINATE_3 +#define GA_TEXTURE_COORDINATE_4 javax_media_j3d_GeometryArray_TEXTURE_COORDINATE_4 +#define GA_TEXTURE_COORDINATE javax_media_j3d_GeometryArray_TEXTURE_COORDINATE +#define GA_VERTEX_ATTRIBUTES javax_media_j3d_GeometryArray_VERTEX_ATTRIBUTES +#define GA_BY_REFERENCE javax_media_j3d_GeometryArray_BY_REFERENCE + + +/* + * These match the constants in ShaderAttributeObjectRetained + */ + +#define TYPE_INTEGER javax_media_j3d_ShaderAttributeObjectRetained_TYPE_INTEGER +#define TYPE_FLOAT javax_media_j3d_ShaderAttributeObjectRetained_TYPE_FLOAT +#define TYPE_TUPLE2I javax_media_j3d_ShaderAttributeObjectRetained_TYPE_TUPLE2I +#define TYPE_TUPLE2F javax_media_j3d_ShaderAttributeObjectRetained_TYPE_TUPLE2F +#define TYPE_TUPLE3I javax_media_j3d_ShaderAttributeObjectRetained_TYPE_TUPLE3I +#define TYPE_TUPLE3F javax_media_j3d_ShaderAttributeObjectRetained_TYPE_TUPLE3F +#define TYPE_TUPLE4I javax_media_j3d_ShaderAttributeObjectRetained_TYPE_TUPLE4I +#define TYPE_TUPLE4F javax_media_j3d_ShaderAttributeObjectRetained_TYPE_TUPLE4F +#define TYPE_MATRIX3F javax_media_j3d_ShaderAttributeObjectRetained_TYPE_MATRIX3F +#define TYPE_MATRIX4F javax_media_j3d_ShaderAttributeObjectRetained_TYPE_MATRIX4F + + +/* + * These match the constants in NativeConfigTemplate3D + */ + +#define RED_SIZE javax_media_j3d_NativeConfigTemplate3D_RED_SIZE +#define GREEN_SIZE javax_media_j3d_NativeConfigTemplate3D_GREEN_SIZE +#define BLUE_SIZE javax_media_j3d_NativeConfigTemplate3D_BLUE_SIZE +#define ALPHA_SIZE javax_media_j3d_NativeConfigTemplate3D_ALPHA_SIZE +#define ACCUM_BUFFER javax_media_j3d_NativeConfigTemplate3D_ACCUM_BUFFER +#define DEPTH_SIZE javax_media_j3d_NativeConfigTemplate3D_DEPTH_SIZE + /* this maps to GLX_ACCUM_RED, */ + /* GLX_ACCUM_GREEN and */ + /* GLX_ACCUM_BLUE so NUM_ITEMS */ + /* must be incremented by 3 for */ + /* this attribute. */ +#define DOUBLEBUFFER javax_media_j3d_NativeConfigTemplate3D_DOUBLEBUFFER +#define STEREO javax_media_j3d_NativeConfigTemplate3D_STEREO +#define ANTIALIASING javax_media_j3d_NativeConfigTemplate3D_ANTIALIASING +#define STENCIL_SIZE javax_media_j3d_NativeConfigTemplate3D_STENCIL_SIZE + +/* set this to the number of indices (from above) */ +#define NUM_ITEMS (javax_media_j3d_NativeConfigTemplate3D_NUM_ITEMS + 2) + /* total + 2 beacause of */ + /* DEPTH_SIZE */ + +/* values for "enum" entries for GraphicsConfiguration */ +#define REQUIRED 1 +#define PREFERRED 2 +#define UNNECESSARY 3 + + + +#define INTENSITY javax_media_j3d_Texture_INTENSITY +#define LUMINANCE javax_media_j3d_Texture_LUMINANCE +#define ALPHA javax_media_j3d_Texture_ALPHA +#define LUMINANCE_ALPHA javax_media_j3d_Texture_LUMINANCE_ALPHA +#define J3D_RGB javax_media_j3d_Texture_RGB +#define J3D_RGBA javax_media_j3d_Texture_RGBA + + +/* + * These match the constants in TransparencyAttributes.java + */ +#define BLEND_ZERO javax_media_j3d_TransparencyAttributes_BLEND_ZERO +#define BLEND_ONE javax_media_j3d_TransparencyAttributes_BLEND_ONE +#define BLEND_SRC_ALPHA javax_media_j3d_TransparencyAttributes_BLEND_SRC_ALPHA +#define BLEND_ONE_MINUS_SRC_ALPHA javax_media_j3d_TransparencyAttributes_BLEND_ONE_MINUS_SRC_ALPHA +#define BLEND_DST_COLOR javax_media_j3d_TransparencyAttributes_BLEND_DST_COLOR +#define BLEND_ONE_MINUS_DST_COLOR javax_media_j3d_TransparencyAttributes_BLEND_ONE_MINUS_DST_COLOR +#define BLEND_SRC_COLOR javax_media_j3d_TransparencyAttributes_BLEND_SRC_COLOR +#define BLEND_ONE_MINUS_SRC_COLOR javax_media_j3d_TransparencyAttributes_BLEND_ONE_MINUS_SRC_COLOR +#define BLEND_CONSTANT_COLOR javax_media_j3d_TransparencyAttributes_BLEND_CONSTANT_COLOR +#define MAX_BLEND_FUNC_TABLE_SIZE javax_media_j3d_TransparencyAttributes_MAX_BLEND_FUNC_TABLE_SIZE + + + +#ifndef D3D + +#ifndef APIENTRY +#define APIENTRY +#endif + +/* define function prototypes */ +typedef void (APIENTRY * MYPFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, + GLclampf blue, GLclampf alpha); +typedef void (APIENTRY * MYPFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, + GLclampf blue, GLclampf alpha); +typedef void (APIENTRY * MYPFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRY * MYPFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRY * MYPFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); +typedef void (APIENTRY * MYPFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRY * MYPFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); +typedef void (APIENTRY * MYPFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum, GLsizei *, GLenum, const GLvoid**, GLsizei); +typedef void (APIENTRY * MYPFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); +typedef void (APIENTRY * MYPFNGLUNLOCKARRAYSEXTPROC) (void); + +typedef void (APIENTRY * MYPFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * MYPFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * MYPFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * MYPFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); +typedef void (APIENTRY * MYPFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); +typedef void (APIENTRY * MYPFNGLACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRY * MYPFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY * MYPFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); + +typedef void (APIENTRY * MYPFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); + +typedef void (APIENTRY * MYPFNGLCOMBINERINPUTNV) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRY * MYPFNGLFINALCOMBINERINPUTNV) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRY * MYPFNGLCOMBINEROUTPUTNV) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +typedef void (APIENTRY * MYPFNGLCOMBINERPARAMETERFVNV) (GLenum pname, const GLfloat *params); +typedef void (APIENTRY * MYPFNGLCOMBINERPARAMETERIVNV) (GLenum pname, const GLint *params); +typedef void (APIENTRY * MYPFNGLCOMBINERPARAMETERFNV) (GLenum pname, GLfloat param); +typedef void (APIENTRY * MYPFNGLCOMBINERPARAMETERINV) (GLenum pname, GLint param); +typedef void (APIENTRY * MYPFNGLSHARPENTEXFUNCSGI) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRY * MYPFNGLDETAILTEXFUNCSGI) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRY * MYPFNGLTEXFILTERFUNCSGI) (GLenum target, GLenum filter, GLsizei n, const GLfloat *points); + +#if defined(UNIX) +typedef GLXFBConfig * (APIENTRY * MYPFNGLXCHOOSEFBCONFIG) (Display *dpy, int screen, const int *attrib_list, int *nelements); +#endif /* UNIX_ */ + + +/* Typedef for context properties struct */ +typedef struct GraphicsContextPropertiesInfoRec GraphicsContextPropertiesInfo; + +/* Typedefs for language-independent vertex attribute functions */ +typedef void (*MYPFNVERTEXATTRPOINTER)(GraphicsContextPropertiesInfo *ctxProperties, + int index, int size, int type, int stride, + const void *pointer); +typedef void (*MYPFNENABLEVERTEXATTRARRAY)(GraphicsContextPropertiesInfo *ctxProperties, + int index); +typedef void (*MYPFNDISABLEVERTEXATTRARRAY)(GraphicsContextPropertiesInfo *ctxProperties, + int index); +typedef void (*MYPFNVERTEXATTR1FV)(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); +typedef void (*MYPFNVERTEXATTR2FV)(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); +typedef void (*MYPFNVERTEXATTR3FV)(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); +typedef void (*MYPFNVERTEXATTR4FV)(GraphicsContextPropertiesInfo *ctxProperties, + int index, const float *v); + + +/* Typedefs for (opaque) GLSL context info */ +typedef struct GLSLCtxInfoRec GLSLCtxInfo; + +/* Typedefs for (opaque) Cg context info */ +typedef struct CgCtxInfoRec CgCtxInfo; + +/* define the structure to hold the properties of graphics context */ +struct GraphicsContextPropertiesInfoRec { + jlong context; + + /* version and extension info */ + char *versionStr; + char *vendorStr; + char *rendererStr; + char *extensionStr; + int versionNumbers[2]; + jboolean gl13; /* OpenGL 1.3 or greater */ + jboolean gl14; /* OpenGL 1.4 or greater */ + jboolean gl20; /* OpenGL 2.0 or greater */ + + /* GL_ARB_imaging subset */ + /* GL_EXT_blend_color or GL_BLEND_COLOR */ + jboolean blend_color_ext; + GLenum blendFunctionTable[MAX_BLEND_FUNC_TABLE_SIZE]; + + /* texture_lod */ + jboolean textureLodAvailable; + GLenum texture_min_lod_enum; + GLenum texture_max_lod_enum; + GLenum texture_base_level_enum; + GLenum texture_max_level_enum; + + + /* ***** GL extensions ***** */ + + /* GL_CLAMP_TO_BORDER or GL_CLAMP */ + GLenum texture_clamp_to_border_enum; + + /* GL_SUN_multi_draw_arrays */ + jboolean multi_draw_arrays_sun; + + /* GL_SUN_global_alpha */ + jboolean global_alpha_sun; + + /* GL_EXT_abgr */ + jboolean abgr_ext; + /* GL_EXT_multi_draw_arrays */ + jboolean multi_draw_arrays_ext; + + /* GL_EXT_compiled_vertex_array */ + jboolean compiled_vertex_array_ext; + + /* Multitexture parameters */ + int maxTexCoordSets; /* maximum number of texture coordinate sets */ + int maxTextureUnits; /* number of fixed-function texture units */ + int maxTextureImageUnits; /* number of fragment shader texture units */ + int maxVertexTextureImageUnits; /* number of vertex shader texture units */ + int maxCombinedTextureImageUnits; /* total number of shader texture units */ + + /* GL_SGI_texture_color_table */ + jboolean textureColorTableAvailable; + int textureColorTableSize; + + /* GL_ARB_texture_env_combine */ + /* GL_EXT_texture_env_combine */ + jboolean textureEnvCombineAvailable; + jboolean textureCombineDot3Available; + jboolean textureCombineSubtractAvailable; + + /* GL_NV_register_combiners */ + jboolean textureRegisterCombinersAvailable; + GLenum currentTextureUnit; + GLenum currentCombinerUnit; + + /* save the enum for the combine modes since the enums between + ARB & EXT might be different. + */ + GLenum combine_enum; + GLenum combine_add_signed_enum; + GLenum combine_interpolate_enum; + GLenum combine_subtract_enum; + GLenum combine_dot3_rgb_enum; + GLenum combine_dot3_rgba_enum; + + /* GL mulitsample functionality */ + jboolean multisample; + + /* + By default, full scene antialiasing is disable if + multisampling pixel format (or visual) is chosen. + To honor display driver multisampling antialiasing + setting (e.g. force scene antialiasing), set the + implicit multisample flag to true in this case. + This cause Java3D not to invoke any native + multisampling API to enable/disable scene antialiasing. + */ + jboolean implicit_multisample; + + /* by MIK OF CLASSX */ + /* + Used by transparentOffScreen feature. + This is the value of the alpha channel + of the background. + */ + GLfloat alphaClearValue; + + /* GL_SGIS_sharpen_texture */ + jboolean textureSharpenAvailable; + GLenum linear_sharpen_enum; + GLenum linear_sharpen_rgb_enum; + GLenum linear_sharpen_alpha_enum; + + /* GL_SGIS_detail_texture */ + jboolean textureDetailAvailable; + GLenum texture_detail_ext_enum; + GLenum linear_detail_enum; + GLenum linear_detail_rgb_enum; + GLenum linear_detail_alpha_enum; + GLenum texture_detail_mode_enum; + GLenum texture_detail_level_enum; + + /* GL_SGIS_texture_filter4 */ + jboolean textureFilter4Available; + GLenum filter4_enum; + + /* GL_EXT_texture_filter_anisotropic */ + jboolean textureAnisotropicFilterAvailable; + GLenum texture_filter_anisotropic_ext_enum; + GLenum max_texture_filter_anisotropy_enum; + + /* GL_SGIX_texture_lod_bias */ + jboolean textureLodBiasAvailable; + + /* extension mask */ + jint extMask; + jint textureExtMask; + + /* function pointers */ + MYPFNGLBLENDCOLORPROC glBlendColor; + MYPFNGLBLENDCOLOREXTPROC glBlendColorEXT; + MYPFNGLCOLORTABLEPROC glColorTable; + MYPFNGLGETCOLORTABLEPARAMETERIVPROC glGetColorTableParameteriv; + MYPFNGLTEXIMAGE3DPROC glTexImage3DEXT; + MYPFNGLTEXSUBIMAGE3DPROC glTexSubImage3DEXT; + MYPFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture; + MYPFNGLACTIVETEXTUREPROC glActiveTexture; + MYPFNGLMULTIDRAWARRAYSEXTPROC glMultiDrawArraysEXT; + MYPFNGLMULTIDRAWELEMENTSEXTPROC glMultiDrawElementsEXT; + MYPFNGLLOCKARRAYSEXTPROC glLockArraysEXT; + MYPFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT; + MYPFNGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv; + MYPFNGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv; + MYPFNGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv; + MYPFNGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd; + MYPFNGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd; + MYPFNGLGLOBALALPHAFACTORFSUNPROC glGlobalAlphaFactorfSUN; + + MYPFNGLCOMBINERINPUTNV glCombinerInputNV; + MYPFNGLCOMBINEROUTPUTNV glCombinerOutputNV; + MYPFNGLFINALCOMBINERINPUTNV glFinalCombinerInputNV; + MYPFNGLCOMBINERPARAMETERFVNV glCombinerParameterfvNV; + MYPFNGLCOMBINERPARAMETERIVNV glCombinerParameterivNV; + MYPFNGLCOMBINERPARAMETERFNV glCombinerParameterfNV; + MYPFNGLCOMBINERPARAMETERINV glCombinerParameteriNV; + + MYPFNGLSHARPENTEXFUNCSGI glSharpenTexFuncSGIS; + MYPFNGLDETAILTEXFUNCSGI glDetailTexFuncSGIS; + MYPFNGLTEXFILTERFUNCSGI glTexFilterFuncSGIS; + + /* Shading language support */ + jboolean shadingLanguageGLSL; + jboolean shadingLanguageCg; + + /* Function pointers for language-independent vertex attribute functions */ + MYPFNVERTEXATTRPOINTER vertexAttrPointer; + MYPFNENABLEVERTEXATTRARRAY enableVertexAttrArray; + MYPFNDISABLEVERTEXATTRARRAY disableVertexAttrArray; + MYPFNVERTEXATTR1FV vertexAttr1fv; + MYPFNVERTEXATTR2FV vertexAttr2fv; + MYPFNVERTEXATTR3FV vertexAttr3fv; + MYPFNVERTEXATTR4FV vertexAttr4fv; + + /* Pointer to currently bound shader program */ + jlong shaderProgramId; + + /* Implementation-dependent maximum number of vertex attributes */ + int maxVertexAttrs; + + /* GLSL shader context information */ + GLSLCtxInfo *glslCtxInfo; + + /* Cg shader context information */ + CgCtxInfo *cgCtxInfo; + +}; + + +#ifdef WIN32 + +/* define the structure to hold the info. of a pixel format */ +typedef struct PixelFormatInfoRec PixelFormatInfo; + +struct PixelFormatInfoRec { + /* Information about onScreen pixel format */ + int onScreenPFormat; /* PixelFormat for onScreen */ + GLboolean onScreenHasMultisample; /* TRUE if WGL_SAMPLE_BUFFERS_ARB is TRUE and + WGL_SAMPLES_ARB > 1 */ + GLboolean onScreenHasStereo; + GLboolean onScreenHasDoubleBuffer; + GLboolean onScreenHasAccum; + int onScreenStencilSize; + + /* Information about onScreen pixel format */ + int offScreenPFormat; /* PixelFormat for offScreen */ + GLboolean offScreenHasMultisample; /* TRUE if WGL_SAMPLE_BUFFERS_ARB is TRUE and + WGL_SAMPLES_ARB > 1 */ + GLboolean offScreenHasStereo; + GLboolean offScreenHasDoubleBuffer; + GLboolean offScreenHasAccum; + int offScreenStencilSize; + + GLboolean drawToPbuffer; /* value of DRAW_TO_PBUFFER attr for offScreenPFormat */ + + /* Information about extension support */ + char* supportedExtensions; /* list of supported ARB extensions */ + GLboolean supportARB; /* TRUE if wgl*PixelFormat*ARB functions supported */ + GLboolean supportPbuffer; /* TRUE if wgl*Pbuffer functions supported */ + + + /* handle to ARB functions */ + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; + PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB; + PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB; + PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB; + PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB; + PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB; + PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB; +}; + +#endif /* WIN32 */ + +/* define the structure to hold the info. of a offScreen buffer */ +typedef struct OffScreenBufferInfoRec OffScreenBufferInfo; + +struct OffScreenBufferInfoRec { + GLboolean isPbuffer; /* GL_TRUE if Pbuffer is used. */ + +#if defined(UNIX) +#endif + +#ifdef WIN32 + HPBUFFERARB hpbuf; /* Handle to the Pbuffer */ +#endif /* WIN32 */ + +}; + + +#endif /* D3D */ +#endif /* _Java3D_gldefs_h_ */ diff --git a/j3d-core/src/native/ogl/glext.h b/j3d-core/src/native/ogl/glext.h new file mode 100644 index 0000000..2519a6c --- /dev/null +++ b/j3d-core/src/native/ogl/glext.h @@ -0,0 +1,7260 @@ +#ifndef __glext_h_ +#define __glext_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2007 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +/*************************************************************/ + +/* Header file version number, required by OpenGL ABI for Linux */ +/* glext.h last updated 2007/02/12 */ +/* Current version at http://www.opengl.org/registry/ */ +#define GL_GLEXT_VERSION 39 + +#ifndef GL_VERSION_1_2 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_RESCALE_NORMAL 0x803A +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#endif + +#ifndef GL_ARB_imaging +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_COLOR 0x8005 +#define GL_FUNC_ADD 0x8006 +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_BLEND_EQUATION 0x8009 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_CONVOLUTION_1D 0x8010 +#define GL_CONVOLUTION_2D 0x8011 +#define GL_SEPARABLE_2D 0x8012 +#define GL_CONVOLUTION_BORDER_MODE 0x8013 +#define GL_CONVOLUTION_FILTER_SCALE 0x8014 +#define GL_CONVOLUTION_FILTER_BIAS 0x8015 +#define GL_REDUCE 0x8016 +#define GL_CONVOLUTION_FORMAT 0x8017 +#define GL_CONVOLUTION_WIDTH 0x8018 +#define GL_CONVOLUTION_HEIGHT 0x8019 +#define GL_MAX_CONVOLUTION_WIDTH 0x801A +#define GL_MAX_CONVOLUTION_HEIGHT 0x801B +#define GL_POST_CONVOLUTION_RED_SCALE 0x801C +#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D +#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E +#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F +#define GL_POST_CONVOLUTION_RED_BIAS 0x8020 +#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 +#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 +#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 +#define GL_HISTOGRAM 0x8024 +#define GL_PROXY_HISTOGRAM 0x8025 +#define GL_HISTOGRAM_WIDTH 0x8026 +#define GL_HISTOGRAM_FORMAT 0x8027 +#define GL_HISTOGRAM_RED_SIZE 0x8028 +#define GL_HISTOGRAM_GREEN_SIZE 0x8029 +#define GL_HISTOGRAM_BLUE_SIZE 0x802A +#define GL_HISTOGRAM_ALPHA_SIZE 0x802B +#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C +#define GL_HISTOGRAM_SINK 0x802D +#define GL_MINMAX 0x802E +#define GL_MINMAX_FORMAT 0x802F +#define GL_MINMAX_SINK 0x8030 +#define GL_TABLE_TOO_LARGE 0x8031 +#define GL_COLOR_MATRIX 0x80B1 +#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 +#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 +#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 +#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 +#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 +#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 +#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 +#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 +#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA +#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB +#define GL_COLOR_TABLE 0x80D0 +#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 +#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 +#define GL_PROXY_COLOR_TABLE 0x80D3 +#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 +#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 +#define GL_COLOR_TABLE_SCALE 0x80D6 +#define GL_COLOR_TABLE_BIAS 0x80D7 +#define GL_COLOR_TABLE_FORMAT 0x80D8 +#define GL_COLOR_TABLE_WIDTH 0x80D9 +#define GL_COLOR_TABLE_RED_SIZE 0x80DA +#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB +#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC +#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD +#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE +#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF +#define GL_CONSTANT_BORDER 0x8151 +#define GL_REPLICATE_BORDER 0x8153 +#define GL_CONVOLUTION_BORDER_COLOR 0x8154 +#endif + +#ifndef GL_VERSION_1_3 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +#endif + +#ifndef GL_VERSION_1_4 +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#endif + +#ifndef GL_VERSION_1_5 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_FOG_COORD_SRC GL_FOG_COORDINATE_SOURCE +#define GL_FOG_COORD GL_FOG_COORDINATE +#define GL_CURRENT_FOG_COORD GL_CURRENT_FOG_COORDINATE +#define GL_FOG_COORD_ARRAY_TYPE GL_FOG_COORDINATE_ARRAY_TYPE +#define GL_FOG_COORD_ARRAY_STRIDE GL_FOG_COORDINATE_ARRAY_STRIDE +#define GL_FOG_COORD_ARRAY_POINTER GL_FOG_COORDINATE_ARRAY_POINTER +#define GL_FOG_COORD_ARRAY GL_FOG_COORDINATE_ARRAY +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING +#define GL_SRC0_RGB GL_SOURCE0_RGB +#define GL_SRC1_RGB GL_SOURCE1_RGB +#define GL_SRC2_RGB GL_SOURCE2_RGB +#define GL_SRC0_ALPHA GL_SOURCE0_ALPHA +#define GL_SRC1_ALPHA GL_SOURCE1_ALPHA +#define GL_SRC2_ALPHA GL_SOURCE2_ALPHA +#endif + +#ifndef GL_VERSION_2_0 +#define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#endif + +#ifndef GL_VERSION_2_1 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +#endif + +#ifndef GL_ARB_multitexture +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1_ARB 0x84C1 +#define GL_TEXTURE2_ARB 0x84C2 +#define GL_TEXTURE3_ARB 0x84C3 +#define GL_TEXTURE4_ARB 0x84C4 +#define GL_TEXTURE5_ARB 0x84C5 +#define GL_TEXTURE6_ARB 0x84C6 +#define GL_TEXTURE7_ARB 0x84C7 +#define GL_TEXTURE8_ARB 0x84C8 +#define GL_TEXTURE9_ARB 0x84C9 +#define GL_TEXTURE10_ARB 0x84CA +#define GL_TEXTURE11_ARB 0x84CB +#define GL_TEXTURE12_ARB 0x84CC +#define GL_TEXTURE13_ARB 0x84CD +#define GL_TEXTURE14_ARB 0x84CE +#define GL_TEXTURE15_ARB 0x84CF +#define GL_TEXTURE16_ARB 0x84D0 +#define GL_TEXTURE17_ARB 0x84D1 +#define GL_TEXTURE18_ARB 0x84D2 +#define GL_TEXTURE19_ARB 0x84D3 +#define GL_TEXTURE20_ARB 0x84D4 +#define GL_TEXTURE21_ARB 0x84D5 +#define GL_TEXTURE22_ARB 0x84D6 +#define GL_TEXTURE23_ARB 0x84D7 +#define GL_TEXTURE24_ARB 0x84D8 +#define GL_TEXTURE25_ARB 0x84D9 +#define GL_TEXTURE26_ARB 0x84DA +#define GL_TEXTURE27_ARB 0x84DB +#define GL_TEXTURE28_ARB 0x84DC +#define GL_TEXTURE29_ARB 0x84DD +#define GL_TEXTURE30_ARB 0x84DE +#define GL_TEXTURE31_ARB 0x84DF +#define GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 +#endif + +#ifndef GL_ARB_transpose_matrix +#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 +#endif + +#ifndef GL_ARB_multisample +#define GL_MULTISAMPLE_ARB 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLES_ARB 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 +#endif + +#ifndef GL_ARB_texture_env_add +#endif + +#ifndef GL_ARB_texture_cube_map +#define GL_NORMAL_MAP_ARB 0x8511 +#define GL_REFLECTION_MAP_ARB 0x8512 +#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C +#endif + +#ifndef GL_ARB_texture_compression +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGBA_ARB 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 +#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 +#endif + +#ifndef GL_ARB_texture_border_clamp +#define GL_CLAMP_TO_BORDER_ARB 0x812D +#endif + +#ifndef GL_ARB_point_parameters +#define GL_POINT_SIZE_MIN_ARB 0x8126 +#define GL_POINT_SIZE_MAX_ARB 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 +#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 +#endif + +#ifndef GL_ARB_vertex_blend +#define GL_MAX_VERTEX_UNITS_ARB 0x86A4 +#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 +#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 +#define GL_VERTEX_BLEND_ARB 0x86A7 +#define GL_CURRENT_WEIGHT_ARB 0x86A8 +#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 +#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA +#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB +#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC +#define GL_WEIGHT_ARRAY_ARB 0x86AD +#define GL_MODELVIEW0_ARB 0x1700 +#define GL_MODELVIEW1_ARB 0x850A +#define GL_MODELVIEW2_ARB 0x8722 +#define GL_MODELVIEW3_ARB 0x8723 +#define GL_MODELVIEW4_ARB 0x8724 +#define GL_MODELVIEW5_ARB 0x8725 +#define GL_MODELVIEW6_ARB 0x8726 +#define GL_MODELVIEW7_ARB 0x8727 +#define GL_MODELVIEW8_ARB 0x8728 +#define GL_MODELVIEW9_ARB 0x8729 +#define GL_MODELVIEW10_ARB 0x872A +#define GL_MODELVIEW11_ARB 0x872B +#define GL_MODELVIEW12_ARB 0x872C +#define GL_MODELVIEW13_ARB 0x872D +#define GL_MODELVIEW14_ARB 0x872E +#define GL_MODELVIEW15_ARB 0x872F +#define GL_MODELVIEW16_ARB 0x8730 +#define GL_MODELVIEW17_ARB 0x8731 +#define GL_MODELVIEW18_ARB 0x8732 +#define GL_MODELVIEW19_ARB 0x8733 +#define GL_MODELVIEW20_ARB 0x8734 +#define GL_MODELVIEW21_ARB 0x8735 +#define GL_MODELVIEW22_ARB 0x8736 +#define GL_MODELVIEW23_ARB 0x8737 +#define GL_MODELVIEW24_ARB 0x8738 +#define GL_MODELVIEW25_ARB 0x8739 +#define GL_MODELVIEW26_ARB 0x873A +#define GL_MODELVIEW27_ARB 0x873B +#define GL_MODELVIEW28_ARB 0x873C +#define GL_MODELVIEW29_ARB 0x873D +#define GL_MODELVIEW30_ARB 0x873E +#define GL_MODELVIEW31_ARB 0x873F +#endif + +#ifndef GL_ARB_matrix_palette +#define GL_MATRIX_PALETTE_ARB 0x8840 +#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 +#define GL_MAX_PALETTE_MATRICES_ARB 0x8842 +#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 +#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 +#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 +#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 +#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 +#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 +#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 +#endif + +#ifndef GL_ARB_texture_env_combine +#define GL_COMBINE_ARB 0x8570 +#define GL_COMBINE_RGB_ARB 0x8571 +#define GL_COMBINE_ALPHA_ARB 0x8572 +#define GL_SOURCE0_RGB_ARB 0x8580 +#define GL_SOURCE1_RGB_ARB 0x8581 +#define GL_SOURCE2_RGB_ARB 0x8582 +#define GL_SOURCE0_ALPHA_ARB 0x8588 +#define GL_SOURCE1_ALPHA_ARB 0x8589 +#define GL_SOURCE2_ALPHA_ARB 0x858A +#define GL_OPERAND0_RGB_ARB 0x8590 +#define GL_OPERAND1_RGB_ARB 0x8591 +#define GL_OPERAND2_RGB_ARB 0x8592 +#define GL_OPERAND0_ALPHA_ARB 0x8598 +#define GL_OPERAND1_ALPHA_ARB 0x8599 +#define GL_OPERAND2_ALPHA_ARB 0x859A +#define GL_RGB_SCALE_ARB 0x8573 +#define GL_ADD_SIGNED_ARB 0x8574 +#define GL_INTERPOLATE_ARB 0x8575 +#define GL_SUBTRACT_ARB 0x84E7 +#define GL_CONSTANT_ARB 0x8576 +#define GL_PRIMARY_COLOR_ARB 0x8577 +#define GL_PREVIOUS_ARB 0x8578 +#endif + +#ifndef GL_ARB_texture_env_crossbar +#endif + +#ifndef GL_ARB_texture_env_dot3 +#define GL_DOT3_RGB_ARB 0x86AE +#define GL_DOT3_RGBA_ARB 0x86AF +#endif + +#ifndef GL_ARB_texture_mirrored_repeat +#define GL_MIRRORED_REPEAT_ARB 0x8370 +#endif + +#ifndef GL_ARB_depth_texture +#define GL_DEPTH_COMPONENT16_ARB 0x81A5 +#define GL_DEPTH_COMPONENT24_ARB 0x81A6 +#define GL_DEPTH_COMPONENT32_ARB 0x81A7 +#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A +#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B +#endif + +#ifndef GL_ARB_shadow +#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C +#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D +#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E +#endif + +#ifndef GL_ARB_shadow_ambient +#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF +#endif + +#ifndef GL_ARB_window_pos +#endif + +#ifndef GL_ARB_vertex_program +#define GL_COLOR_SUM_ARB 0x8458 +#define GL_VERTEX_PROGRAM_ARB 0x8620 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 +#define GL_PROGRAM_LENGTH_ARB 0x8627 +#define GL_PROGRAM_STRING_ARB 0x8628 +#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E +#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F +#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 +#define GL_CURRENT_MATRIX_ARB 0x8641 +#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 +#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B +#define GL_PROGRAM_BINDING_ARB 0x8677 +#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A +#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +#define GL_PROGRAM_FORMAT_ARB 0x8876 +#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 +#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 +#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 +#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 +#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 +#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 +#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 +#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 +#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 +#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 +#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA +#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB +#define GL_PROGRAM_ATTRIBS_ARB 0x88AC +#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD +#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE +#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF +#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 +#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 +#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 +#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 +#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 +#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 +#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 +#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 +#define GL_MATRIX0_ARB 0x88C0 +#define GL_MATRIX1_ARB 0x88C1 +#define GL_MATRIX2_ARB 0x88C2 +#define GL_MATRIX3_ARB 0x88C3 +#define GL_MATRIX4_ARB 0x88C4 +#define GL_MATRIX5_ARB 0x88C5 +#define GL_MATRIX6_ARB 0x88C6 +#define GL_MATRIX7_ARB 0x88C7 +#define GL_MATRIX8_ARB 0x88C8 +#define GL_MATRIX9_ARB 0x88C9 +#define GL_MATRIX10_ARB 0x88CA +#define GL_MATRIX11_ARB 0x88CB +#define GL_MATRIX12_ARB 0x88CC +#define GL_MATRIX13_ARB 0x88CD +#define GL_MATRIX14_ARB 0x88CE +#define GL_MATRIX15_ARB 0x88CF +#define GL_MATRIX16_ARB 0x88D0 +#define GL_MATRIX17_ARB 0x88D1 +#define GL_MATRIX18_ARB 0x88D2 +#define GL_MATRIX19_ARB 0x88D3 +#define GL_MATRIX20_ARB 0x88D4 +#define GL_MATRIX21_ARB 0x88D5 +#define GL_MATRIX22_ARB 0x88D6 +#define GL_MATRIX23_ARB 0x88D7 +#define GL_MATRIX24_ARB 0x88D8 +#define GL_MATRIX25_ARB 0x88D9 +#define GL_MATRIX26_ARB 0x88DA +#define GL_MATRIX27_ARB 0x88DB +#define GL_MATRIX28_ARB 0x88DC +#define GL_MATRIX29_ARB 0x88DD +#define GL_MATRIX30_ARB 0x88DE +#define GL_MATRIX31_ARB 0x88DF +#endif + +#ifndef GL_ARB_fragment_program +#define GL_FRAGMENT_PROGRAM_ARB 0x8804 +#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 +#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 +#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 +#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 +#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 +#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A +#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B +#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C +#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D +#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E +#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F +#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 +#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 +#endif + +#ifndef GL_ARB_vertex_buffer_object +#define GL_BUFFER_SIZE_ARB 0x8764 +#define GL_BUFFER_USAGE_ARB 0x8765 +#define GL_ARRAY_BUFFER_ARB 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 +#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 +#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F +#define GL_READ_ONLY_ARB 0x88B8 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_READ_WRITE_ARB 0x88BA +#define GL_BUFFER_ACCESS_ARB 0x88BB +#define GL_BUFFER_MAPPED_ARB 0x88BC +#define GL_BUFFER_MAP_POINTER_ARB 0x88BD +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_STREAM_READ_ARB 0x88E1 +#define GL_STREAM_COPY_ARB 0x88E2 +#define GL_STATIC_DRAW_ARB 0x88E4 +#define GL_STATIC_READ_ARB 0x88E5 +#define GL_STATIC_COPY_ARB 0x88E6 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 +#define GL_DYNAMIC_READ_ARB 0x88E9 +#define GL_DYNAMIC_COPY_ARB 0x88EA +#endif + +#ifndef GL_ARB_occlusion_query +#define GL_QUERY_COUNTER_BITS_ARB 0x8864 +#define GL_CURRENT_QUERY_ARB 0x8865 +#define GL_QUERY_RESULT_ARB 0x8866 +#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 +#define GL_SAMPLES_PASSED_ARB 0x8914 +#endif + +#ifndef GL_ARB_shader_objects +#define GL_PROGRAM_OBJECT_ARB 0x8B40 +#define GL_SHADER_OBJECT_ARB 0x8B48 +#define GL_OBJECT_TYPE_ARB 0x8B4E +#define GL_OBJECT_SUBTYPE_ARB 0x8B4F +#define GL_FLOAT_VEC2_ARB 0x8B50 +#define GL_FLOAT_VEC3_ARB 0x8B51 +#define GL_FLOAT_VEC4_ARB 0x8B52 +#define GL_INT_VEC2_ARB 0x8B53 +#define GL_INT_VEC3_ARB 0x8B54 +#define GL_INT_VEC4_ARB 0x8B55 +#define GL_BOOL_ARB 0x8B56 +#define GL_BOOL_VEC2_ARB 0x8B57 +#define GL_BOOL_VEC3_ARB 0x8B58 +#define GL_BOOL_VEC4_ARB 0x8B59 +#define GL_FLOAT_MAT2_ARB 0x8B5A +#define GL_FLOAT_MAT3_ARB 0x8B5B +#define GL_FLOAT_MAT4_ARB 0x8B5C +#define GL_SAMPLER_1D_ARB 0x8B5D +#define GL_SAMPLER_2D_ARB 0x8B5E +#define GL_SAMPLER_3D_ARB 0x8B5F +#define GL_SAMPLER_CUBE_ARB 0x8B60 +#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 +#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 +#define GL_SAMPLER_2D_RECT_ARB 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 +#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 +#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 +#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 +#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 +#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 +#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 +#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 +#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 +#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 +#endif + +#ifndef GL_ARB_vertex_shader +#define GL_VERTEX_SHADER_ARB 0x8B31 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A +#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D +#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 +#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A +#endif + +#ifndef GL_ARB_fragment_shader +#define GL_FRAGMENT_SHADER_ARB 0x8B30 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B +#endif + +#ifndef GL_ARB_shading_language_100 +#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C +#endif + +#ifndef GL_ARB_texture_non_power_of_two +#endif + +#ifndef GL_ARB_point_sprite +#define GL_POINT_SPRITE_ARB 0x8861 +#define GL_COORD_REPLACE_ARB 0x8862 +#endif + +#ifndef GL_ARB_fragment_program_shadow +#endif + +#ifndef GL_ARB_draw_buffers +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 +#define GL_DRAW_BUFFER0_ARB 0x8825 +#define GL_DRAW_BUFFER1_ARB 0x8826 +#define GL_DRAW_BUFFER2_ARB 0x8827 +#define GL_DRAW_BUFFER3_ARB 0x8828 +#define GL_DRAW_BUFFER4_ARB 0x8829 +#define GL_DRAW_BUFFER5_ARB 0x882A +#define GL_DRAW_BUFFER6_ARB 0x882B +#define GL_DRAW_BUFFER7_ARB 0x882C +#define GL_DRAW_BUFFER8_ARB 0x882D +#define GL_DRAW_BUFFER9_ARB 0x882E +#define GL_DRAW_BUFFER10_ARB 0x882F +#define GL_DRAW_BUFFER11_ARB 0x8830 +#define GL_DRAW_BUFFER12_ARB 0x8831 +#define GL_DRAW_BUFFER13_ARB 0x8832 +#define GL_DRAW_BUFFER14_ARB 0x8833 +#define GL_DRAW_BUFFER15_ARB 0x8834 +#endif + +#ifndef GL_ARB_texture_rectangle +#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 +#endif + +#ifndef GL_ARB_color_buffer_float +#define GL_RGBA_FLOAT_MODE_ARB 0x8820 +#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A +#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B +#define GL_CLAMP_READ_COLOR_ARB 0x891C +#define GL_FIXED_ONLY_ARB 0x891D +#endif + +#ifndef GL_ARB_half_float_pixel +#define GL_HALF_FLOAT_ARB 0x140B +#endif + +#ifndef GL_ARB_texture_float +#define GL_TEXTURE_RED_TYPE_ARB 0x8C10 +#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 +#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 +#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 +#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 +#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 +#define GL_RGBA32F_ARB 0x8814 +#define GL_RGB32F_ARB 0x8815 +#define GL_ALPHA32F_ARB 0x8816 +#define GL_INTENSITY32F_ARB 0x8817 +#define GL_LUMINANCE32F_ARB 0x8818 +#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 +#define GL_RGBA16F_ARB 0x881A +#define GL_RGB16F_ARB 0x881B +#define GL_ALPHA16F_ARB 0x881C +#define GL_INTENSITY16F_ARB 0x881D +#define GL_LUMINANCE16F_ARB 0x881E +#define GL_LUMINANCE_ALPHA16F_ARB 0x881F +#endif + +#ifndef GL_ARB_pixel_buffer_object +#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF +#endif + +#ifndef GL_EXT_abgr +#define GL_ABGR_EXT 0x8000 +#endif + +#ifndef GL_EXT_blend_color +#define GL_CONSTANT_COLOR_EXT 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 +#define GL_CONSTANT_ALPHA_EXT 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 +#define GL_BLEND_COLOR_EXT 0x8005 +#endif + +#ifndef GL_EXT_polygon_offset +#define GL_POLYGON_OFFSET_EXT 0x8037 +#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 +#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 +#endif + +#ifndef GL_EXT_texture +#define GL_ALPHA4_EXT 0x803B +#define GL_ALPHA8_EXT 0x803C +#define GL_ALPHA12_EXT 0x803D +#define GL_ALPHA16_EXT 0x803E +#define GL_LUMINANCE4_EXT 0x803F +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE12_EXT 0x8041 +#define GL_LUMINANCE16_EXT 0x8042 +#define GL_LUMINANCE4_ALPHA4_EXT 0x8043 +#define GL_LUMINANCE6_ALPHA2_EXT 0x8044 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_LUMINANCE12_ALPHA4_EXT 0x8046 +#define GL_LUMINANCE12_ALPHA12_EXT 0x8047 +#define GL_LUMINANCE16_ALPHA16_EXT 0x8048 +#define GL_INTENSITY_EXT 0x8049 +#define GL_INTENSITY4_EXT 0x804A +#define GL_INTENSITY8_EXT 0x804B +#define GL_INTENSITY12_EXT 0x804C +#define GL_INTENSITY16_EXT 0x804D +#define GL_RGB2_EXT 0x804E +#define GL_RGB4_EXT 0x804F +#define GL_RGB5_EXT 0x8050 +#define GL_RGB8_EXT 0x8051 +#define GL_RGB10_EXT 0x8052 +#define GL_RGB12_EXT 0x8053 +#define GL_RGB16_EXT 0x8054 +#define GL_RGBA2_EXT 0x8055 +#define GL_RGBA4_EXT 0x8056 +#define GL_RGB5_A1_EXT 0x8057 +#define GL_RGBA8_EXT 0x8058 +#define GL_RGB10_A2_EXT 0x8059 +#define GL_RGBA12_EXT 0x805A +#define GL_RGBA16_EXT 0x805B +#define GL_TEXTURE_RED_SIZE_EXT 0x805C +#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D +#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E +#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F +#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 +#define GL_REPLACE_EXT 0x8062 +#define GL_PROXY_TEXTURE_1D_EXT 0x8063 +#define GL_PROXY_TEXTURE_2D_EXT 0x8064 +#define GL_TEXTURE_TOO_LARGE_EXT 0x8065 +#endif + +#ifndef GL_EXT_texture3D +#define GL_PACK_SKIP_IMAGES_EXT 0x806B +#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C +#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D +#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E +#define GL_TEXTURE_3D_EXT 0x806F +#define GL_PROXY_TEXTURE_3D_EXT 0x8070 +#define GL_TEXTURE_DEPTH_EXT 0x8071 +#define GL_TEXTURE_WRAP_R_EXT 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 +#endif + +#ifndef GL_SGIS_texture_filter4 +#define GL_FILTER4_SGIS 0x8146 +#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 +#endif + +#ifndef GL_EXT_subtexture +#endif + +#ifndef GL_EXT_copy_texture +#endif + +#ifndef GL_EXT_histogram +#define GL_HISTOGRAM_EXT 0x8024 +#define GL_PROXY_HISTOGRAM_EXT 0x8025 +#define GL_HISTOGRAM_WIDTH_EXT 0x8026 +#define GL_HISTOGRAM_FORMAT_EXT 0x8027 +#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 +#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 +#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A +#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B +#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C +#define GL_HISTOGRAM_SINK_EXT 0x802D +#define GL_MINMAX_EXT 0x802E +#define GL_MINMAX_FORMAT_EXT 0x802F +#define GL_MINMAX_SINK_EXT 0x8030 +#define GL_TABLE_TOO_LARGE_EXT 0x8031 +#endif + +#ifndef GL_EXT_convolution +#define GL_CONVOLUTION_1D_EXT 0x8010 +#define GL_CONVOLUTION_2D_EXT 0x8011 +#define GL_SEPARABLE_2D_EXT 0x8012 +#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 +#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 +#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 +#define GL_REDUCE_EXT 0x8016 +#define GL_CONVOLUTION_FORMAT_EXT 0x8017 +#define GL_CONVOLUTION_WIDTH_EXT 0x8018 +#define GL_CONVOLUTION_HEIGHT_EXT 0x8019 +#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A +#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B +#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C +#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D +#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E +#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F +#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 +#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 +#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 +#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 +#endif + +#ifndef GL_SGI_color_matrix +#define GL_COLOR_MATRIX_SGI 0x80B1 +#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 +#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 +#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 +#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 +#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 +#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 +#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 +#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 +#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA +#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB +#endif + +#ifndef GL_SGI_color_table +#define GL_COLOR_TABLE_SGI 0x80D0 +#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 +#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 +#define GL_PROXY_COLOR_TABLE_SGI 0x80D3 +#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 +#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 +#define GL_COLOR_TABLE_SCALE_SGI 0x80D6 +#define GL_COLOR_TABLE_BIAS_SGI 0x80D7 +#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 +#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 +#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA +#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB +#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC +#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD +#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE +#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF +#endif + +#ifndef GL_SGIS_pixel_texture +#define GL_PIXEL_TEXTURE_SGIS 0x8353 +#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 +#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 +#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 +#endif + +#ifndef GL_SGIX_pixel_texture +#define GL_PIXEL_TEX_GEN_SGIX 0x8139 +#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B +#endif + +#ifndef GL_SGIS_texture4D +#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 +#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 +#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 +#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 +#define GL_TEXTURE_4D_SGIS 0x8134 +#define GL_PROXY_TEXTURE_4D_SGIS 0x8135 +#define GL_TEXTURE_4DSIZE_SGIS 0x8136 +#define GL_TEXTURE_WRAP_Q_SGIS 0x8137 +#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 +#define GL_TEXTURE_4D_BINDING_SGIS 0x814F +#endif + +#ifndef GL_SGI_texture_color_table +#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC +#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD +#endif + +#ifndef GL_EXT_cmyka +#define GL_CMYK_EXT 0x800C +#define GL_CMYKA_EXT 0x800D +#define GL_PACK_CMYK_HINT_EXT 0x800E +#define GL_UNPACK_CMYK_HINT_EXT 0x800F +#endif + +#ifndef GL_EXT_texture_object +#define GL_TEXTURE_PRIORITY_EXT 0x8066 +#define GL_TEXTURE_RESIDENT_EXT 0x8067 +#define GL_TEXTURE_1D_BINDING_EXT 0x8068 +#define GL_TEXTURE_2D_BINDING_EXT 0x8069 +#define GL_TEXTURE_3D_BINDING_EXT 0x806A +#endif + +#ifndef GL_SGIS_detail_texture +#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 +#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 +#define GL_LINEAR_DETAIL_SGIS 0x8097 +#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 +#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 +#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A +#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B +#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C +#endif + +#ifndef GL_SGIS_sharpen_texture +#define GL_LINEAR_SHARPEN_SGIS 0x80AD +#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE +#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF +#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 +#endif + +#ifndef GL_EXT_packed_pixels +#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 +#endif + +#ifndef GL_SGIS_texture_lod +#define GL_TEXTURE_MIN_LOD_SGIS 0x813A +#define GL_TEXTURE_MAX_LOD_SGIS 0x813B +#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C +#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D +#endif + +#ifndef GL_SGIS_multisample +#define GL_MULTISAMPLE_SGIS 0x809D +#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F +#define GL_SAMPLE_MASK_SGIS 0x80A0 +#define GL_1PASS_SGIS 0x80A1 +#define GL_2PASS_0_SGIS 0x80A2 +#define GL_2PASS_1_SGIS 0x80A3 +#define GL_4PASS_0_SGIS 0x80A4 +#define GL_4PASS_1_SGIS 0x80A5 +#define GL_4PASS_2_SGIS 0x80A6 +#define GL_4PASS_3_SGIS 0x80A7 +#define GL_SAMPLE_BUFFERS_SGIS 0x80A8 +#define GL_SAMPLES_SGIS 0x80A9 +#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA +#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB +#define GL_SAMPLE_PATTERN_SGIS 0x80AC +#endif + +#ifndef GL_EXT_rescale_normal +#define GL_RESCALE_NORMAL_EXT 0x803A +#endif + +#ifndef GL_EXT_vertex_array +#define GL_VERTEX_ARRAY_EXT 0x8074 +#define GL_NORMAL_ARRAY_EXT 0x8075 +#define GL_COLOR_ARRAY_EXT 0x8076 +#define GL_INDEX_ARRAY_EXT 0x8077 +#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 +#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 +#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A +#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B +#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C +#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D +#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E +#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F +#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 +#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 +#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 +#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 +#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 +#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 +#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 +#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 +#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A +#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B +#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C +#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D +#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E +#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F +#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 +#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 +#endif + +#ifndef GL_EXT_misc_attribute +#endif + +#ifndef GL_SGIS_generate_mipmap +#define GL_GENERATE_MIPMAP_SGIS 0x8191 +#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 +#endif + +#ifndef GL_SGIX_clipmap +#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 +#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 +#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 +#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 +#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 +#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 +#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 +#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 +#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 +#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D +#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E +#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F +#endif + +#ifndef GL_SGIX_shadow +#define GL_TEXTURE_COMPARE_SGIX 0x819A +#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B +#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C +#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D +#endif + +#ifndef GL_SGIS_texture_edge_clamp +#define GL_CLAMP_TO_EDGE_SGIS 0x812F +#endif + +#ifndef GL_SGIS_texture_border_clamp +#define GL_CLAMP_TO_BORDER_SGIS 0x812D +#endif + +#ifndef GL_EXT_blend_minmax +#define GL_FUNC_ADD_EXT 0x8006 +#define GL_MIN_EXT 0x8007 +#define GL_MAX_EXT 0x8008 +#define GL_BLEND_EQUATION_EXT 0x8009 +#endif + +#ifndef GL_EXT_blend_subtract +#define GL_FUNC_SUBTRACT_EXT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B +#endif + +#ifndef GL_EXT_blend_logic_op +#endif + +#ifndef GL_SGIX_interlace +#define GL_INTERLACE_SGIX 0x8094 +#endif + +#ifndef GL_SGIX_pixel_tiles +#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E +#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F +#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 +#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 +#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 +#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 +#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 +#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 +#endif + +#ifndef GL_SGIS_texture_select +#define GL_DUAL_ALPHA4_SGIS 0x8110 +#define GL_DUAL_ALPHA8_SGIS 0x8111 +#define GL_DUAL_ALPHA12_SGIS 0x8112 +#define GL_DUAL_ALPHA16_SGIS 0x8113 +#define GL_DUAL_LUMINANCE4_SGIS 0x8114 +#define GL_DUAL_LUMINANCE8_SGIS 0x8115 +#define GL_DUAL_LUMINANCE12_SGIS 0x8116 +#define GL_DUAL_LUMINANCE16_SGIS 0x8117 +#define GL_DUAL_INTENSITY4_SGIS 0x8118 +#define GL_DUAL_INTENSITY8_SGIS 0x8119 +#define GL_DUAL_INTENSITY12_SGIS 0x811A +#define GL_DUAL_INTENSITY16_SGIS 0x811B +#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C +#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D +#define GL_QUAD_ALPHA4_SGIS 0x811E +#define GL_QUAD_ALPHA8_SGIS 0x811F +#define GL_QUAD_LUMINANCE4_SGIS 0x8120 +#define GL_QUAD_LUMINANCE8_SGIS 0x8121 +#define GL_QUAD_INTENSITY4_SGIS 0x8122 +#define GL_QUAD_INTENSITY8_SGIS 0x8123 +#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 +#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 +#endif + +#ifndef GL_SGIX_sprite +#define GL_SPRITE_SGIX 0x8148 +#define GL_SPRITE_MODE_SGIX 0x8149 +#define GL_SPRITE_AXIS_SGIX 0x814A +#define GL_SPRITE_TRANSLATION_SGIX 0x814B +#define GL_SPRITE_AXIAL_SGIX 0x814C +#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D +#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E +#endif + +#ifndef GL_SGIX_texture_multi_buffer +#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E +#endif + +#ifndef GL_EXT_point_parameters +#define GL_POINT_SIZE_MIN_EXT 0x8126 +#define GL_POINT_SIZE_MAX_EXT 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 +#define GL_DISTANCE_ATTENUATION_EXT 0x8129 +#endif + +#ifndef GL_SGIS_point_parameters +#define GL_POINT_SIZE_MIN_SGIS 0x8126 +#define GL_POINT_SIZE_MAX_SGIS 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 +#define GL_DISTANCE_ATTENUATION_SGIS 0x8129 +#endif + +#ifndef GL_SGIX_instruments +#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 +#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 +#endif + +#ifndef GL_SGIX_texture_scale_bias +#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 +#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A +#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B +#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C +#endif + +#ifndef GL_SGIX_framezoom +#define GL_FRAMEZOOM_SGIX 0x818B +#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C +#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D +#endif + +#ifndef GL_SGIX_tag_sample_buffer +#endif + +#ifndef GL_FfdMaskSGIX +#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 +#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 +#endif + +#ifndef GL_SGIX_polynomial_ffd +#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 +#define GL_TEXTURE_DEFORMATION_SGIX 0x8195 +#define GL_DEFORMATIONS_MASK_SGIX 0x8196 +#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 +#endif + +#ifndef GL_SGIX_reference_plane +#define GL_REFERENCE_PLANE_SGIX 0x817D +#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E +#endif + +#ifndef GL_SGIX_flush_raster +#endif + +#ifndef GL_SGIX_depth_texture +#define GL_DEPTH_COMPONENT16_SGIX 0x81A5 +#define GL_DEPTH_COMPONENT24_SGIX 0x81A6 +#define GL_DEPTH_COMPONENT32_SGIX 0x81A7 +#endif + +#ifndef GL_SGIS_fog_function +#define GL_FOG_FUNC_SGIS 0x812A +#define GL_FOG_FUNC_POINTS_SGIS 0x812B +#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C +#endif + +#ifndef GL_SGIX_fog_offset +#define GL_FOG_OFFSET_SGIX 0x8198 +#define GL_FOG_OFFSET_VALUE_SGIX 0x8199 +#endif + +#ifndef GL_HP_image_transform +#define GL_IMAGE_SCALE_X_HP 0x8155 +#define GL_IMAGE_SCALE_Y_HP 0x8156 +#define GL_IMAGE_TRANSLATE_X_HP 0x8157 +#define GL_IMAGE_TRANSLATE_Y_HP 0x8158 +#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 +#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A +#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B +#define GL_IMAGE_MAG_FILTER_HP 0x815C +#define GL_IMAGE_MIN_FILTER_HP 0x815D +#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E +#define GL_CUBIC_HP 0x815F +#define GL_AVERAGE_HP 0x8160 +#define GL_IMAGE_TRANSFORM_2D_HP 0x8161 +#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 +#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 +#endif + +#ifndef GL_HP_convolution_border_modes +#define GL_IGNORE_BORDER_HP 0x8150 +#define GL_CONSTANT_BORDER_HP 0x8151 +#define GL_REPLICATE_BORDER_HP 0x8153 +#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 +#endif + +#ifndef GL_INGR_palette_buffer +#endif + +#ifndef GL_SGIX_texture_add_env +#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE +#endif + +#ifndef GL_EXT_color_subtable +#endif + +#ifndef GL_PGI_vertex_hints +#define GL_VERTEX_DATA_HINT_PGI 0x1A22A +#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B +#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C +#define GL_MAX_VERTEX_HINT_PGI 0x1A22D +#define GL_COLOR3_BIT_PGI 0x00010000 +#define GL_COLOR4_BIT_PGI 0x00020000 +#define GL_EDGEFLAG_BIT_PGI 0x00040000 +#define GL_INDEX_BIT_PGI 0x00080000 +#define GL_MAT_AMBIENT_BIT_PGI 0x00100000 +#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 +#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 +#define GL_MAT_EMISSION_BIT_PGI 0x00800000 +#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 +#define GL_MAT_SHININESS_BIT_PGI 0x02000000 +#define GL_MAT_SPECULAR_BIT_PGI 0x04000000 +#define GL_NORMAL_BIT_PGI 0x08000000 +#define GL_TEXCOORD1_BIT_PGI 0x10000000 +#define GL_TEXCOORD2_BIT_PGI 0x20000000 +#define GL_TEXCOORD3_BIT_PGI 0x40000000 +#define GL_TEXCOORD4_BIT_PGI 0x80000000 +#define GL_VERTEX23_BIT_PGI 0x00000004 +#define GL_VERTEX4_BIT_PGI 0x00000008 +#endif + +#ifndef GL_PGI_misc_hints +#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 +#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD +#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE +#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 +#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 +#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 +#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C +#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D +#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E +#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F +#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 +#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 +#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 +#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 +#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 +#define GL_FULL_STIPPLE_HINT_PGI 0x1A219 +#define GL_CLIP_NEAR_HINT_PGI 0x1A220 +#define GL_CLIP_FAR_HINT_PGI 0x1A221 +#define GL_WIDE_LINE_HINT_PGI 0x1A222 +#define GL_BACK_NORMALS_HINT_PGI 0x1A223 +#endif + +#ifndef GL_EXT_paletted_texture +#define GL_COLOR_INDEX1_EXT 0x80E2 +#define GL_COLOR_INDEX2_EXT 0x80E3 +#define GL_COLOR_INDEX4_EXT 0x80E4 +#define GL_COLOR_INDEX8_EXT 0x80E5 +#define GL_COLOR_INDEX12_EXT 0x80E6 +#define GL_COLOR_INDEX16_EXT 0x80E7 +#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED +#endif + +#ifndef GL_EXT_clip_volume_hint +#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 +#endif + +#ifndef GL_SGIX_list_priority +#define GL_LIST_PRIORITY_SGIX 0x8182 +#endif + +#ifndef GL_SGIX_ir_instrument1 +#define GL_IR_INSTRUMENT1_SGIX 0x817F +#endif + +#ifndef GL_SGIX_calligraphic_fragment +#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 +#endif + +#ifndef GL_SGIX_texture_lod_bias +#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E +#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F +#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 +#endif + +#ifndef GL_SGIX_shadow_ambient +#define GL_SHADOW_AMBIENT_SGIX 0x80BF +#endif + +#ifndef GL_EXT_index_texture +#endif + +#ifndef GL_EXT_index_material +#define GL_INDEX_MATERIAL_EXT 0x81B8 +#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 +#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA +#endif + +#ifndef GL_EXT_index_func +#define GL_INDEX_TEST_EXT 0x81B5 +#define GL_INDEX_TEST_FUNC_EXT 0x81B6 +#define GL_INDEX_TEST_REF_EXT 0x81B7 +#endif + +#ifndef GL_EXT_index_array_formats +#define GL_IUI_V2F_EXT 0x81AD +#define GL_IUI_V3F_EXT 0x81AE +#define GL_IUI_N3F_V2F_EXT 0x81AF +#define GL_IUI_N3F_V3F_EXT 0x81B0 +#define GL_T2F_IUI_V2F_EXT 0x81B1 +#define GL_T2F_IUI_V3F_EXT 0x81B2 +#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 +#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 +#endif + +#ifndef GL_EXT_compiled_vertex_array +#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 +#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 +#endif + +#ifndef GL_EXT_cull_vertex +#define GL_CULL_VERTEX_EXT 0x81AA +#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB +#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC +#endif + +#ifndef GL_SGIX_ycrcb +#define GL_YCRCB_422_SGIX 0x81BB +#define GL_YCRCB_444_SGIX 0x81BC +#endif + +#ifndef GL_SGIX_fragment_lighting +#define GL_FRAGMENT_LIGHTING_SGIX 0x8400 +#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 +#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 +#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 +#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 +#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 +#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 +#define GL_LIGHT_ENV_MODE_SGIX 0x8407 +#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 +#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 +#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A +#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B +#define GL_FRAGMENT_LIGHT0_SGIX 0x840C +#define GL_FRAGMENT_LIGHT1_SGIX 0x840D +#define GL_FRAGMENT_LIGHT2_SGIX 0x840E +#define GL_FRAGMENT_LIGHT3_SGIX 0x840F +#define GL_FRAGMENT_LIGHT4_SGIX 0x8410 +#define GL_FRAGMENT_LIGHT5_SGIX 0x8411 +#define GL_FRAGMENT_LIGHT6_SGIX 0x8412 +#define GL_FRAGMENT_LIGHT7_SGIX 0x8413 +#endif + +#ifndef GL_IBM_rasterpos_clip +#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 +#endif + +#ifndef GL_HP_texture_lighting +#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 +#define GL_TEXTURE_POST_SPECULAR_HP 0x8168 +#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 +#endif + +#ifndef GL_EXT_draw_range_elements +#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 +#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 +#endif + +#ifndef GL_WIN_phong_shading +#define GL_PHONG_WIN 0x80EA +#define GL_PHONG_HINT_WIN 0x80EB +#endif + +#ifndef GL_WIN_specular_fog +#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC +#endif + +#ifndef GL_EXT_light_texture +#define GL_FRAGMENT_MATERIAL_EXT 0x8349 +#define GL_FRAGMENT_NORMAL_EXT 0x834A +#define GL_FRAGMENT_COLOR_EXT 0x834C +#define GL_ATTENUATION_EXT 0x834D +#define GL_SHADOW_ATTENUATION_EXT 0x834E +#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F +#define GL_TEXTURE_LIGHT_EXT 0x8350 +#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 +#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 +/* reuse GL_FRAGMENT_DEPTH_EXT */ +#endif + +#ifndef GL_SGIX_blend_alpha_minmax +#define GL_ALPHA_MIN_SGIX 0x8320 +#define GL_ALPHA_MAX_SGIX 0x8321 +#endif + +#ifndef GL_SGIX_impact_pixel_texture +#define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184 +#define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185 +#define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186 +#define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187 +#define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188 +#define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189 +#define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A +#endif + +#ifndef GL_EXT_bgra +#define GL_BGR_EXT 0x80E0 +#define GL_BGRA_EXT 0x80E1 +#endif + +#ifndef GL_SGIX_async +#define GL_ASYNC_MARKER_SGIX 0x8329 +#endif + +#ifndef GL_SGIX_async_pixel +#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C +#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D +#define GL_ASYNC_READ_PIXELS_SGIX 0x835E +#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F +#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 +#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 +#endif + +#ifndef GL_SGIX_async_histogram +#define GL_ASYNC_HISTOGRAM_SGIX 0x832C +#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D +#endif + +#ifndef GL_INTEL_texture_scissor +#endif + +#ifndef GL_INTEL_parallel_arrays +#define GL_PARALLEL_ARRAYS_INTEL 0x83F4 +#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 +#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 +#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 +#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 +#endif + +#ifndef GL_HP_occlusion_test +#define GL_OCCLUSION_TEST_HP 0x8165 +#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 +#endif + +#ifndef GL_EXT_pixel_transform +#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 +#define GL_PIXEL_MAG_FILTER_EXT 0x8331 +#define GL_PIXEL_MIN_FILTER_EXT 0x8332 +#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 +#define GL_CUBIC_EXT 0x8334 +#define GL_AVERAGE_EXT 0x8335 +#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 +#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 +#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 +#endif + +#ifndef GL_EXT_pixel_transform_color_table +#endif + +#ifndef GL_EXT_shared_texture_palette +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#endif + +#ifndef GL_EXT_separate_specular_color +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif + +#ifndef GL_EXT_secondary_color +#define GL_COLOR_SUM_EXT 0x8458 +#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D +#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E +#endif + +#ifndef GL_EXT_texture_perturb_normal +#define GL_PERTURB_EXT 0x85AE +#define GL_TEXTURE_NORMAL_EXT 0x85AF +#endif + +#ifndef GL_EXT_multi_draw_arrays +#endif + +#ifndef GL_EXT_fog_coord +#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 +#define GL_FOG_COORDINATE_EXT 0x8451 +#define GL_FRAGMENT_DEPTH_EXT 0x8452 +#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 +#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 +#endif + +#ifndef GL_REND_screen_coordinates +#define GL_SCREEN_COORDINATES_REND 0x8490 +#define GL_INVERTED_SCREEN_W_REND 0x8491 +#endif + +#ifndef GL_EXT_coordinate_frame +#define GL_TANGENT_ARRAY_EXT 0x8439 +#define GL_BINORMAL_ARRAY_EXT 0x843A +#define GL_CURRENT_TANGENT_EXT 0x843B +#define GL_CURRENT_BINORMAL_EXT 0x843C +#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E +#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F +#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 +#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 +#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 +#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 +#define GL_MAP1_TANGENT_EXT 0x8444 +#define GL_MAP2_TANGENT_EXT 0x8445 +#define GL_MAP1_BINORMAL_EXT 0x8446 +#define GL_MAP2_BINORMAL_EXT 0x8447 +#endif + +#ifndef GL_EXT_texture_env_combine +#define GL_COMBINE_EXT 0x8570 +#define GL_COMBINE_RGB_EXT 0x8571 +#define GL_COMBINE_ALPHA_EXT 0x8572 +#define GL_RGB_SCALE_EXT 0x8573 +#define GL_ADD_SIGNED_EXT 0x8574 +#define GL_INTERPOLATE_EXT 0x8575 +#define GL_CONSTANT_EXT 0x8576 +#define GL_PRIMARY_COLOR_EXT 0x8577 +#define GL_PREVIOUS_EXT 0x8578 +#define GL_SOURCE0_RGB_EXT 0x8580 +#define GL_SOURCE1_RGB_EXT 0x8581 +#define GL_SOURCE2_RGB_EXT 0x8582 +#define GL_SOURCE0_ALPHA_EXT 0x8588 +#define GL_SOURCE1_ALPHA_EXT 0x8589 +#define GL_SOURCE2_ALPHA_EXT 0x858A +#define GL_OPERAND0_RGB_EXT 0x8590 +#define GL_OPERAND1_RGB_EXT 0x8591 +#define GL_OPERAND2_RGB_EXT 0x8592 +#define GL_OPERAND0_ALPHA_EXT 0x8598 +#define GL_OPERAND1_ALPHA_EXT 0x8599 +#define GL_OPERAND2_ALPHA_EXT 0x859A +#endif + +#ifndef GL_APPLE_specular_vector +#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 +#endif + +#ifndef GL_APPLE_transform_hint +#define GL_TRANSFORM_HINT_APPLE 0x85B1 +#endif + +#ifndef GL_SGIX_fog_scale +#define GL_FOG_SCALE_SGIX 0x81FC +#define GL_FOG_SCALE_VALUE_SGIX 0x81FD +#endif + +#ifndef GL_SUNX_constant_data +#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 +#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 +#endif + +#ifndef GL_SUN_global_alpha +#define GL_GLOBAL_ALPHA_SUN 0x81D9 +#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA +#endif + +#ifndef GL_SUN_triangle_list +#define GL_RESTART_SUN 0x0001 +#define GL_REPLACE_MIDDLE_SUN 0x0002 +#define GL_REPLACE_OLDEST_SUN 0x0003 +#define GL_TRIANGLE_LIST_SUN 0x81D7 +#define GL_REPLACEMENT_CODE_SUN 0x81D8 +#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 +#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 +#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 +#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 +#define GL_R1UI_V3F_SUN 0x85C4 +#define GL_R1UI_C4UB_V3F_SUN 0x85C5 +#define GL_R1UI_C3F_V3F_SUN 0x85C6 +#define GL_R1UI_N3F_V3F_SUN 0x85C7 +#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 +#define GL_R1UI_T2F_V3F_SUN 0x85C9 +#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA +#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB +#endif + +#ifndef GL_SUN_vertex +#endif + +#ifndef GL_EXT_blend_func_separate +#define GL_BLEND_DST_RGB_EXT 0x80C8 +#define GL_BLEND_SRC_RGB_EXT 0x80C9 +#define GL_BLEND_DST_ALPHA_EXT 0x80CA +#define GL_BLEND_SRC_ALPHA_EXT 0x80CB +#endif + +#ifndef GL_INGR_color_clamp +#define GL_RED_MIN_CLAMP_INGR 0x8560 +#define GL_GREEN_MIN_CLAMP_INGR 0x8561 +#define GL_BLUE_MIN_CLAMP_INGR 0x8562 +#define GL_ALPHA_MIN_CLAMP_INGR 0x8563 +#define GL_RED_MAX_CLAMP_INGR 0x8564 +#define GL_GREEN_MAX_CLAMP_INGR 0x8565 +#define GL_BLUE_MAX_CLAMP_INGR 0x8566 +#define GL_ALPHA_MAX_CLAMP_INGR 0x8567 +#endif + +#ifndef GL_INGR_interlace_read +#define GL_INTERLACE_READ_INGR 0x8568 +#endif + +#ifndef GL_EXT_stencil_wrap +#define GL_INCR_WRAP_EXT 0x8507 +#define GL_DECR_WRAP_EXT 0x8508 +#endif + +#ifndef GL_EXT_422_pixels +#define GL_422_EXT 0x80CC +#define GL_422_REV_EXT 0x80CD +#define GL_422_AVERAGE_EXT 0x80CE +#define GL_422_REV_AVERAGE_EXT 0x80CF +#endif + +#ifndef GL_NV_texgen_reflection +#define GL_NORMAL_MAP_NV 0x8511 +#define GL_REFLECTION_MAP_NV 0x8512 +#endif + +#ifndef GL_EXT_texture_cube_map +#define GL_NORMAL_MAP_EXT 0x8511 +#define GL_REFLECTION_MAP_EXT 0x8512 +#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C +#endif + +#ifndef GL_SUN_convolution_border_modes +#define GL_WRAP_BORDER_SUN 0x81D4 +#endif + +#ifndef GL_EXT_texture_env_add +#endif + +#ifndef GL_EXT_texture_lod_bias +#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD +#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 +#define GL_TEXTURE_LOD_BIAS_EXT 0x8501 +#endif + +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +#ifndef GL_EXT_vertex_weighting +#define GL_MODELVIEW0_STACK_DEPTH_EXT GL_MODELVIEW_STACK_DEPTH +#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 +#define GL_MODELVIEW0_MATRIX_EXT GL_MODELVIEW_MATRIX +#define GL_MODELVIEW1_MATRIX_EXT 0x8506 +#define GL_VERTEX_WEIGHTING_EXT 0x8509 +#define GL_MODELVIEW0_EXT GL_MODELVIEW +#define GL_MODELVIEW1_EXT 0x850A +#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B +#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C +#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D +#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E +#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F +#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 +#endif + +#ifndef GL_NV_light_max_exponent +#define GL_MAX_SHININESS_NV 0x8504 +#define GL_MAX_SPOT_EXPONENT_NV 0x8505 +#endif + +#ifndef GL_NV_vertex_array_range +#define GL_VERTEX_ARRAY_RANGE_NV 0x851D +#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E +#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F +#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 +#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 +#endif + +#ifndef GL_NV_register_combiners +#define GL_REGISTER_COMBINERS_NV 0x8522 +#define GL_VARIABLE_A_NV 0x8523 +#define GL_VARIABLE_B_NV 0x8524 +#define GL_VARIABLE_C_NV 0x8525 +#define GL_VARIABLE_D_NV 0x8526 +#define GL_VARIABLE_E_NV 0x8527 +#define GL_VARIABLE_F_NV 0x8528 +#define GL_VARIABLE_G_NV 0x8529 +#define GL_CONSTANT_COLOR0_NV 0x852A +#define GL_CONSTANT_COLOR1_NV 0x852B +#define GL_PRIMARY_COLOR_NV 0x852C +#define GL_SECONDARY_COLOR_NV 0x852D +#define GL_SPARE0_NV 0x852E +#define GL_SPARE1_NV 0x852F +#define GL_DISCARD_NV 0x8530 +#define GL_E_TIMES_F_NV 0x8531 +#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 +#define GL_UNSIGNED_IDENTITY_NV 0x8536 +#define GL_UNSIGNED_INVERT_NV 0x8537 +#define GL_EXPAND_NORMAL_NV 0x8538 +#define GL_EXPAND_NEGATE_NV 0x8539 +#define GL_HALF_BIAS_NORMAL_NV 0x853A +#define GL_HALF_BIAS_NEGATE_NV 0x853B +#define GL_SIGNED_IDENTITY_NV 0x853C +#define GL_SIGNED_NEGATE_NV 0x853D +#define GL_SCALE_BY_TWO_NV 0x853E +#define GL_SCALE_BY_FOUR_NV 0x853F +#define GL_SCALE_BY_ONE_HALF_NV 0x8540 +#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 +#define GL_COMBINER_INPUT_NV 0x8542 +#define GL_COMBINER_MAPPING_NV 0x8543 +#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 +#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 +#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 +#define GL_COMBINER_MUX_SUM_NV 0x8547 +#define GL_COMBINER_SCALE_NV 0x8548 +#define GL_COMBINER_BIAS_NV 0x8549 +#define GL_COMBINER_AB_OUTPUT_NV 0x854A +#define GL_COMBINER_CD_OUTPUT_NV 0x854B +#define GL_COMBINER_SUM_OUTPUT_NV 0x854C +#define GL_MAX_GENERAL_COMBINERS_NV 0x854D +#define GL_NUM_GENERAL_COMBINERS_NV 0x854E +#define GL_COLOR_SUM_CLAMP_NV 0x854F +#define GL_COMBINER0_NV 0x8550 +#define GL_COMBINER1_NV 0x8551 +#define GL_COMBINER2_NV 0x8552 +#define GL_COMBINER3_NV 0x8553 +#define GL_COMBINER4_NV 0x8554 +#define GL_COMBINER5_NV 0x8555 +#define GL_COMBINER6_NV 0x8556 +#define GL_COMBINER7_NV 0x8557 +/* reuse GL_TEXTURE0_ARB */ +/* reuse GL_TEXTURE1_ARB */ +/* reuse GL_ZERO */ +/* reuse GL_NONE */ +/* reuse GL_FOG */ +#endif + +#ifndef GL_NV_fog_distance +#define GL_FOG_DISTANCE_MODE_NV 0x855A +#define GL_EYE_RADIAL_NV 0x855B +#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C +/* reuse GL_EYE_PLANE */ +#endif + +#ifndef GL_NV_texgen_emboss +#define GL_EMBOSS_LIGHT_NV 0x855D +#define GL_EMBOSS_CONSTANT_NV 0x855E +#define GL_EMBOSS_MAP_NV 0x855F +#endif + +#ifndef GL_NV_blend_square +#endif + +#ifndef GL_NV_texture_env_combine4 +#define GL_COMBINE4_NV 0x8503 +#define GL_SOURCE3_RGB_NV 0x8583 +#define GL_SOURCE3_ALPHA_NV 0x858B +#define GL_OPERAND3_RGB_NV 0x8593 +#define GL_OPERAND3_ALPHA_NV 0x859B +#endif + +#ifndef GL_MESA_resize_buffers +#endif + +#ifndef GL_MESA_window_pos +#endif + +#ifndef GL_EXT_texture_compression_s3tc +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif + +#ifndef GL_IBM_cull_vertex +#define GL_CULL_VERTEX_IBM 103050 +#endif + +#ifndef GL_IBM_multimode_draw_arrays +#endif + +#ifndef GL_IBM_vertex_array_lists +#define GL_VERTEX_ARRAY_LIST_IBM 103070 +#define GL_NORMAL_ARRAY_LIST_IBM 103071 +#define GL_COLOR_ARRAY_LIST_IBM 103072 +#define GL_INDEX_ARRAY_LIST_IBM 103073 +#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 +#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 +#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 +#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 +#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 +#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 +#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 +#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 +#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 +#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 +#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 +#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 +#endif + +#ifndef GL_SGIX_subsample +#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 +#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 +#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 +#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 +#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 +#endif + +#ifndef GL_SGIX_ycrcb_subsample +#endif + +#ifndef GL_SGIX_ycrcba +#define GL_YCRCB_SGIX 0x8318 +#define GL_YCRCBA_SGIX 0x8319 +#endif + +#ifndef GL_SGI_depth_pass_instrument +#define GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310 +#define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311 +#define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312 +#endif + +#ifndef GL_3DFX_texture_compression_FXT1 +#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 +#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 +#endif + +#ifndef GL_3DFX_multisample +#define GL_MULTISAMPLE_3DFX 0x86B2 +#define GL_SAMPLE_BUFFERS_3DFX 0x86B3 +#define GL_SAMPLES_3DFX 0x86B4 +#define GL_MULTISAMPLE_BIT_3DFX 0x20000000 +#endif + +#ifndef GL_3DFX_tbuffer +#endif + +#ifndef GL_EXT_multisample +#define GL_MULTISAMPLE_EXT 0x809D +#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F +#define GL_SAMPLE_MASK_EXT 0x80A0 +#define GL_1PASS_EXT 0x80A1 +#define GL_2PASS_0_EXT 0x80A2 +#define GL_2PASS_1_EXT 0x80A3 +#define GL_4PASS_0_EXT 0x80A4 +#define GL_4PASS_1_EXT 0x80A5 +#define GL_4PASS_2_EXT 0x80A6 +#define GL_4PASS_3_EXT 0x80A7 +#define GL_SAMPLE_BUFFERS_EXT 0x80A8 +#define GL_SAMPLES_EXT 0x80A9 +#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA +#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB +#define GL_SAMPLE_PATTERN_EXT 0x80AC +#define GL_MULTISAMPLE_BIT_EXT 0x20000000 +#endif + +#ifndef GL_SGIX_vertex_preclip +#define GL_VERTEX_PRECLIP_SGIX 0x83EE +#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF +#endif + +#ifndef GL_SGIX_convolution_accuracy +#define GL_CONVOLUTION_HINT_SGIX 0x8316 +#endif + +#ifndef GL_SGIX_resample +#define GL_PACK_RESAMPLE_SGIX 0x842C +#define GL_UNPACK_RESAMPLE_SGIX 0x842D +#define GL_RESAMPLE_REPLICATE_SGIX 0x842E +#define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F +#define GL_RESAMPLE_DECIMATE_SGIX 0x8430 +#endif + +#ifndef GL_SGIS_point_line_texgen +#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 +#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 +#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 +#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 +#define GL_EYE_POINT_SGIS 0x81F4 +#define GL_OBJECT_POINT_SGIS 0x81F5 +#define GL_EYE_LINE_SGIS 0x81F6 +#define GL_OBJECT_LINE_SGIS 0x81F7 +#endif + +#ifndef GL_SGIS_texture_color_mask +#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF +#endif + +#ifndef GL_EXT_texture_env_dot3 +#define GL_DOT3_RGB_EXT 0x8740 +#define GL_DOT3_RGBA_EXT 0x8741 +#endif + +#ifndef GL_ATI_texture_mirror_once +#define GL_MIRROR_CLAMP_ATI 0x8742 +#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 +#endif + +#ifndef GL_NV_fence +#define GL_ALL_COMPLETED_NV 0x84F2 +#define GL_FENCE_STATUS_NV 0x84F3 +#define GL_FENCE_CONDITION_NV 0x84F4 +#endif + +#ifndef GL_IBM_texture_mirrored_repeat +#define GL_MIRRORED_REPEAT_IBM 0x8370 +#endif + +#ifndef GL_NV_evaluators +#define GL_EVAL_2D_NV 0x86C0 +#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 +#define GL_MAP_TESSELLATION_NV 0x86C2 +#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 +#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 +#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 +#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 +#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 +#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 +#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 +#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA +#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB +#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC +#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD +#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE +#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF +#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 +#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 +#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 +#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 +#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 +#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 +#define GL_MAX_MAP_TESSELLATION_NV 0x86D6 +#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 +#endif + +#ifndef GL_NV_packed_depth_stencil +#define GL_DEPTH_STENCIL_NV 0x84F9 +#define GL_UNSIGNED_INT_24_8_NV 0x84FA +#endif + +#ifndef GL_NV_register_combiners2 +#define GL_PER_STAGE_CONSTANTS_NV 0x8535 +#endif + +#ifndef GL_NV_texture_compression_vtc +#endif + +#ifndef GL_NV_texture_rectangle +#define GL_TEXTURE_RECTANGLE_NV 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 +#endif + +#ifndef GL_NV_texture_shader +#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C +#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D +#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E +#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 +#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA +#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB +#define GL_DSDT_MAG_INTENSITY_NV 0x86DC +#define GL_SHADER_CONSISTENT_NV 0x86DD +#define GL_TEXTURE_SHADER_NV 0x86DE +#define GL_SHADER_OPERATION_NV 0x86DF +#define GL_CULL_MODES_NV 0x86E0 +#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 +#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 +#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 +#define GL_OFFSET_TEXTURE_2D_MATRIX_NV GL_OFFSET_TEXTURE_MATRIX_NV +#define GL_OFFSET_TEXTURE_2D_SCALE_NV GL_OFFSET_TEXTURE_SCALE_NV +#define GL_OFFSET_TEXTURE_2D_BIAS_NV GL_OFFSET_TEXTURE_BIAS_NV +#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 +#define GL_CONST_EYE_NV 0x86E5 +#define GL_PASS_THROUGH_NV 0x86E6 +#define GL_CULL_FRAGMENT_NV 0x86E7 +#define GL_OFFSET_TEXTURE_2D_NV 0x86E8 +#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 +#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA +#define GL_DOT_PRODUCT_NV 0x86EC +#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED +#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE +#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 +#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 +#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 +#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 +#define GL_HILO_NV 0x86F4 +#define GL_DSDT_NV 0x86F5 +#define GL_DSDT_MAG_NV 0x86F6 +#define GL_DSDT_MAG_VIB_NV 0x86F7 +#define GL_HILO16_NV 0x86F8 +#define GL_SIGNED_HILO_NV 0x86F9 +#define GL_SIGNED_HILO16_NV 0x86FA +#define GL_SIGNED_RGBA_NV 0x86FB +#define GL_SIGNED_RGBA8_NV 0x86FC +#define GL_SIGNED_RGB_NV 0x86FE +#define GL_SIGNED_RGB8_NV 0x86FF +#define GL_SIGNED_LUMINANCE_NV 0x8701 +#define GL_SIGNED_LUMINANCE8_NV 0x8702 +#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 +#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 +#define GL_SIGNED_ALPHA_NV 0x8705 +#define GL_SIGNED_ALPHA8_NV 0x8706 +#define GL_SIGNED_INTENSITY_NV 0x8707 +#define GL_SIGNED_INTENSITY8_NV 0x8708 +#define GL_DSDT8_NV 0x8709 +#define GL_DSDT8_MAG8_NV 0x870A +#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B +#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C +#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D +#define GL_HI_SCALE_NV 0x870E +#define GL_LO_SCALE_NV 0x870F +#define GL_DS_SCALE_NV 0x8710 +#define GL_DT_SCALE_NV 0x8711 +#define GL_MAGNITUDE_SCALE_NV 0x8712 +#define GL_VIBRANCE_SCALE_NV 0x8713 +#define GL_HI_BIAS_NV 0x8714 +#define GL_LO_BIAS_NV 0x8715 +#define GL_DS_BIAS_NV 0x8716 +#define GL_DT_BIAS_NV 0x8717 +#define GL_MAGNITUDE_BIAS_NV 0x8718 +#define GL_VIBRANCE_BIAS_NV 0x8719 +#define GL_TEXTURE_BORDER_VALUES_NV 0x871A +#define GL_TEXTURE_HI_SIZE_NV 0x871B +#define GL_TEXTURE_LO_SIZE_NV 0x871C +#define GL_TEXTURE_DS_SIZE_NV 0x871D +#define GL_TEXTURE_DT_SIZE_NV 0x871E +#define GL_TEXTURE_MAG_SIZE_NV 0x871F +#endif + +#ifndef GL_NV_texture_shader2 +#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF +#endif + +#ifndef GL_NV_vertex_array_range2 +#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 +#endif + +#ifndef GL_NV_vertex_program +#define GL_VERTEX_PROGRAM_NV 0x8620 +#define GL_VERTEX_STATE_PROGRAM_NV 0x8621 +#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 +#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 +#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 +#define GL_CURRENT_ATTRIB_NV 0x8626 +#define GL_PROGRAM_LENGTH_NV 0x8627 +#define GL_PROGRAM_STRING_NV 0x8628 +#define GL_MODELVIEW_PROJECTION_NV 0x8629 +#define GL_IDENTITY_NV 0x862A +#define GL_INVERSE_NV 0x862B +#define GL_TRANSPOSE_NV 0x862C +#define GL_INVERSE_TRANSPOSE_NV 0x862D +#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E +#define GL_MAX_TRACK_MATRICES_NV 0x862F +#define GL_MATRIX0_NV 0x8630 +#define GL_MATRIX1_NV 0x8631 +#define GL_MATRIX2_NV 0x8632 +#define GL_MATRIX3_NV 0x8633 +#define GL_MATRIX4_NV 0x8634 +#define GL_MATRIX5_NV 0x8635 +#define GL_MATRIX6_NV 0x8636 +#define GL_MATRIX7_NV 0x8637 +#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 +#define GL_CURRENT_MATRIX_NV 0x8641 +#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 +#define GL_PROGRAM_PARAMETER_NV 0x8644 +#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 +#define GL_PROGRAM_TARGET_NV 0x8646 +#define GL_PROGRAM_RESIDENT_NV 0x8647 +#define GL_TRACK_MATRIX_NV 0x8648 +#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 +#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A +#define GL_PROGRAM_ERROR_POSITION_NV 0x864B +#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 +#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 +#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 +#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 +#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 +#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 +#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 +#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 +#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 +#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 +#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A +#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B +#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C +#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D +#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E +#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F +#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 +#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 +#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 +#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 +#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 +#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 +#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 +#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 +#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 +#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 +#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A +#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B +#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C +#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D +#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E +#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F +#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 +#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 +#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 +#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 +#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 +#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 +#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 +#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 +#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 +#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 +#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A +#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B +#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C +#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D +#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E +#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F +#endif + +#ifndef GL_SGIX_texture_coordinate_clamp +#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 +#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A +#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B +#endif + +#ifndef GL_SGIX_scalebias_hint +#define GL_SCALEBIAS_HINT_SGIX 0x8322 +#endif + +#ifndef GL_OML_interlace +#define GL_INTERLACE_OML 0x8980 +#define GL_INTERLACE_READ_OML 0x8981 +#endif + +#ifndef GL_OML_subsample +#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 +#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 +#endif + +#ifndef GL_OML_resample +#define GL_PACK_RESAMPLE_OML 0x8984 +#define GL_UNPACK_RESAMPLE_OML 0x8985 +#define GL_RESAMPLE_REPLICATE_OML 0x8986 +#define GL_RESAMPLE_ZERO_FILL_OML 0x8987 +#define GL_RESAMPLE_AVERAGE_OML 0x8988 +#define GL_RESAMPLE_DECIMATE_OML 0x8989 +#endif + +#ifndef GL_NV_copy_depth_to_color +#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E +#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F +#endif + +#ifndef GL_ATI_envmap_bumpmap +#define GL_BUMP_ROT_MATRIX_ATI 0x8775 +#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 +#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 +#define GL_BUMP_TEX_UNITS_ATI 0x8778 +#define GL_DUDV_ATI 0x8779 +#define GL_DU8DV8_ATI 0x877A +#define GL_BUMP_ENVMAP_ATI 0x877B +#define GL_BUMP_TARGET_ATI 0x877C +#endif + +#ifndef GL_ATI_fragment_shader +#define GL_FRAGMENT_SHADER_ATI 0x8920 +#define GL_REG_0_ATI 0x8921 +#define GL_REG_1_ATI 0x8922 +#define GL_REG_2_ATI 0x8923 +#define GL_REG_3_ATI 0x8924 +#define GL_REG_4_ATI 0x8925 +#define GL_REG_5_ATI 0x8926 +#define GL_REG_6_ATI 0x8927 +#define GL_REG_7_ATI 0x8928 +#define GL_REG_8_ATI 0x8929 +#define GL_REG_9_ATI 0x892A +#define GL_REG_10_ATI 0x892B +#define GL_REG_11_ATI 0x892C +#define GL_REG_12_ATI 0x892D +#define GL_REG_13_ATI 0x892E +#define GL_REG_14_ATI 0x892F +#define GL_REG_15_ATI 0x8930 +#define GL_REG_16_ATI 0x8931 +#define GL_REG_17_ATI 0x8932 +#define GL_REG_18_ATI 0x8933 +#define GL_REG_19_ATI 0x8934 +#define GL_REG_20_ATI 0x8935 +#define GL_REG_21_ATI 0x8936 +#define GL_REG_22_ATI 0x8937 +#define GL_REG_23_ATI 0x8938 +#define GL_REG_24_ATI 0x8939 +#define GL_REG_25_ATI 0x893A +#define GL_REG_26_ATI 0x893B +#define GL_REG_27_ATI 0x893C +#define GL_REG_28_ATI 0x893D +#define GL_REG_29_ATI 0x893E +#define GL_REG_30_ATI 0x893F +#define GL_REG_31_ATI 0x8940 +#define GL_CON_0_ATI 0x8941 +#define GL_CON_1_ATI 0x8942 +#define GL_CON_2_ATI 0x8943 +#define GL_CON_3_ATI 0x8944 +#define GL_CON_4_ATI 0x8945 +#define GL_CON_5_ATI 0x8946 +#define GL_CON_6_ATI 0x8947 +#define GL_CON_7_ATI 0x8948 +#define GL_CON_8_ATI 0x8949 +#define GL_CON_9_ATI 0x894A +#define GL_CON_10_ATI 0x894B +#define GL_CON_11_ATI 0x894C +#define GL_CON_12_ATI 0x894D +#define GL_CON_13_ATI 0x894E +#define GL_CON_14_ATI 0x894F +#define GL_CON_15_ATI 0x8950 +#define GL_CON_16_ATI 0x8951 +#define GL_CON_17_ATI 0x8952 +#define GL_CON_18_ATI 0x8953 +#define GL_CON_19_ATI 0x8954 +#define GL_CON_20_ATI 0x8955 +#define GL_CON_21_ATI 0x8956 +#define GL_CON_22_ATI 0x8957 +#define GL_CON_23_ATI 0x8958 +#define GL_CON_24_ATI 0x8959 +#define GL_CON_25_ATI 0x895A +#define GL_CON_26_ATI 0x895B +#define GL_CON_27_ATI 0x895C +#define GL_CON_28_ATI 0x895D +#define GL_CON_29_ATI 0x895E +#define GL_CON_30_ATI 0x895F +#define GL_CON_31_ATI 0x8960 +#define GL_MOV_ATI 0x8961 +#define GL_ADD_ATI 0x8963 +#define GL_MUL_ATI 0x8964 +#define GL_SUB_ATI 0x8965 +#define GL_DOT3_ATI 0x8966 +#define GL_DOT4_ATI 0x8967 +#define GL_MAD_ATI 0x8968 +#define GL_LERP_ATI 0x8969 +#define GL_CND_ATI 0x896A +#define GL_CND0_ATI 0x896B +#define GL_DOT2_ADD_ATI 0x896C +#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D +#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E +#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F +#define GL_NUM_PASSES_ATI 0x8970 +#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 +#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 +#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 +#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 +#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 +#define GL_SWIZZLE_STR_ATI 0x8976 +#define GL_SWIZZLE_STQ_ATI 0x8977 +#define GL_SWIZZLE_STR_DR_ATI 0x8978 +#define GL_SWIZZLE_STQ_DQ_ATI 0x8979 +#define GL_SWIZZLE_STRQ_ATI 0x897A +#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B +#define GL_RED_BIT_ATI 0x00000001 +#define GL_GREEN_BIT_ATI 0x00000002 +#define GL_BLUE_BIT_ATI 0x00000004 +#define GL_2X_BIT_ATI 0x00000001 +#define GL_4X_BIT_ATI 0x00000002 +#define GL_8X_BIT_ATI 0x00000004 +#define GL_HALF_BIT_ATI 0x00000008 +#define GL_QUARTER_BIT_ATI 0x00000010 +#define GL_EIGHTH_BIT_ATI 0x00000020 +#define GL_SATURATE_BIT_ATI 0x00000040 +#define GL_COMP_BIT_ATI 0x00000002 +#define GL_NEGATE_BIT_ATI 0x00000004 +#define GL_BIAS_BIT_ATI 0x00000008 +#endif + +#ifndef GL_ATI_pn_triangles +#define GL_PN_TRIANGLES_ATI 0x87F0 +#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 +#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 +#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 +#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 +#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 +#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 +#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 +#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 +#endif + +#ifndef GL_ATI_vertex_array_object +#define GL_STATIC_ATI 0x8760 +#define GL_DYNAMIC_ATI 0x8761 +#define GL_PRESERVE_ATI 0x8762 +#define GL_DISCARD_ATI 0x8763 +#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 +#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 +#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 +#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 +#endif + +#ifndef GL_EXT_vertex_shader +#define GL_VERTEX_SHADER_EXT 0x8780 +#define GL_VERTEX_SHADER_BINDING_EXT 0x8781 +#define GL_OP_INDEX_EXT 0x8782 +#define GL_OP_NEGATE_EXT 0x8783 +#define GL_OP_DOT3_EXT 0x8784 +#define GL_OP_DOT4_EXT 0x8785 +#define GL_OP_MUL_EXT 0x8786 +#define GL_OP_ADD_EXT 0x8787 +#define GL_OP_MADD_EXT 0x8788 +#define GL_OP_FRAC_EXT 0x8789 +#define GL_OP_MAX_EXT 0x878A +#define GL_OP_MIN_EXT 0x878B +#define GL_OP_SET_GE_EXT 0x878C +#define GL_OP_SET_LT_EXT 0x878D +#define GL_OP_CLAMP_EXT 0x878E +#define GL_OP_FLOOR_EXT 0x878F +#define GL_OP_ROUND_EXT 0x8790 +#define GL_OP_EXP_BASE_2_EXT 0x8791 +#define GL_OP_LOG_BASE_2_EXT 0x8792 +#define GL_OP_POWER_EXT 0x8793 +#define GL_OP_RECIP_EXT 0x8794 +#define GL_OP_RECIP_SQRT_EXT 0x8795 +#define GL_OP_SUB_EXT 0x8796 +#define GL_OP_CROSS_PRODUCT_EXT 0x8797 +#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 +#define GL_OP_MOV_EXT 0x8799 +#define GL_OUTPUT_VERTEX_EXT 0x879A +#define GL_OUTPUT_COLOR0_EXT 0x879B +#define GL_OUTPUT_COLOR1_EXT 0x879C +#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D +#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E +#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F +#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 +#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 +#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 +#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 +#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 +#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 +#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 +#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 +#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 +#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 +#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA +#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB +#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC +#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD +#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE +#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF +#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 +#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 +#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 +#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 +#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 +#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 +#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 +#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 +#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 +#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 +#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA +#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB +#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC +#define GL_OUTPUT_FOG_EXT 0x87BD +#define GL_SCALAR_EXT 0x87BE +#define GL_VECTOR_EXT 0x87BF +#define GL_MATRIX_EXT 0x87C0 +#define GL_VARIANT_EXT 0x87C1 +#define GL_INVARIANT_EXT 0x87C2 +#define GL_LOCAL_CONSTANT_EXT 0x87C3 +#define GL_LOCAL_EXT 0x87C4 +#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 +#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 +#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 +#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 +#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE +#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF +#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 +#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 +#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 +#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 +#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 +#define GL_X_EXT 0x87D5 +#define GL_Y_EXT 0x87D6 +#define GL_Z_EXT 0x87D7 +#define GL_W_EXT 0x87D8 +#define GL_NEGATIVE_X_EXT 0x87D9 +#define GL_NEGATIVE_Y_EXT 0x87DA +#define GL_NEGATIVE_Z_EXT 0x87DB +#define GL_NEGATIVE_W_EXT 0x87DC +#define GL_ZERO_EXT 0x87DD +#define GL_ONE_EXT 0x87DE +#define GL_NEGATIVE_ONE_EXT 0x87DF +#define GL_NORMALIZED_RANGE_EXT 0x87E0 +#define GL_FULL_RANGE_EXT 0x87E1 +#define GL_CURRENT_VERTEX_EXT 0x87E2 +#define GL_MVP_MATRIX_EXT 0x87E3 +#define GL_VARIANT_VALUE_EXT 0x87E4 +#define GL_VARIANT_DATATYPE_EXT 0x87E5 +#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 +#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 +#define GL_VARIANT_ARRAY_EXT 0x87E8 +#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 +#define GL_INVARIANT_VALUE_EXT 0x87EA +#define GL_INVARIANT_DATATYPE_EXT 0x87EB +#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC +#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED +#endif + +#ifndef GL_ATI_vertex_streams +#define GL_MAX_VERTEX_STREAMS_ATI 0x876B +#define GL_VERTEX_STREAM0_ATI 0x876C +#define GL_VERTEX_STREAM1_ATI 0x876D +#define GL_VERTEX_STREAM2_ATI 0x876E +#define GL_VERTEX_STREAM3_ATI 0x876F +#define GL_VERTEX_STREAM4_ATI 0x8770 +#define GL_VERTEX_STREAM5_ATI 0x8771 +#define GL_VERTEX_STREAM6_ATI 0x8772 +#define GL_VERTEX_STREAM7_ATI 0x8773 +#define GL_VERTEX_SOURCE_ATI 0x8774 +#endif + +#ifndef GL_ATI_element_array +#define GL_ELEMENT_ARRAY_ATI 0x8768 +#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 +#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A +#endif + +#ifndef GL_SUN_mesh_array +#define GL_QUAD_MESH_SUN 0x8614 +#define GL_TRIANGLE_MESH_SUN 0x8615 +#endif + +#ifndef GL_SUN_slice_accum +#define GL_SLICE_ACCUM_SUN 0x85CC +#endif + +#ifndef GL_NV_multisample_filter_hint +#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 +#endif + +#ifndef GL_NV_depth_clamp +#define GL_DEPTH_CLAMP_NV 0x864F +#endif + +#ifndef GL_NV_occlusion_query +#define GL_PIXEL_COUNTER_BITS_NV 0x8864 +#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 +#define GL_PIXEL_COUNT_NV 0x8866 +#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 +#endif + +#ifndef GL_NV_point_sprite +#define GL_POINT_SPRITE_NV 0x8861 +#define GL_COORD_REPLACE_NV 0x8862 +#define GL_POINT_SPRITE_R_MODE_NV 0x8863 +#endif + +#ifndef GL_NV_texture_shader3 +#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 +#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 +#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 +#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 +#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 +#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 +#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 +#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 +#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 +#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 +#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A +#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B +#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C +#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D +#define GL_HILO8_NV 0x885E +#define GL_SIGNED_HILO8_NV 0x885F +#define GL_FORCE_BLUE_TO_ONE_NV 0x8860 +#endif + +#ifndef GL_NV_vertex_program1_1 +#endif + +#ifndef GL_EXT_shadow_funcs +#endif + +#ifndef GL_EXT_stencil_two_side +#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 +#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 +#endif + +#ifndef GL_ATI_text_fragment_shader +#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 +#endif + +#ifndef GL_APPLE_client_storage +#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 +#endif + +#ifndef GL_APPLE_element_array +#define GL_ELEMENT_ARRAY_APPLE 0x8768 +#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8769 +#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x876A +#endif + +#ifndef GL_APPLE_fence +#define GL_DRAW_PIXELS_APPLE 0x8A0A +#define GL_FENCE_APPLE 0x8A0B +#endif + +#ifndef GL_APPLE_vertex_array_object +#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 +#endif + +#ifndef GL_APPLE_vertex_array_range +#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D +#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E +#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F +#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 +#define GL_STORAGE_CACHED_APPLE 0x85BE +#define GL_STORAGE_SHARED_APPLE 0x85BF +#endif + +#ifndef GL_APPLE_ycbcr_422 +#define GL_YCBCR_422_APPLE 0x85B9 +#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#endif + +#ifndef GL_S3_s3tc +#define GL_RGB_S3TC 0x83A0 +#define GL_RGB4_S3TC 0x83A1 +#define GL_RGBA_S3TC 0x83A2 +#define GL_RGBA4_S3TC 0x83A3 +#endif + +#ifndef GL_ATI_draw_buffers +#define GL_MAX_DRAW_BUFFERS_ATI 0x8824 +#define GL_DRAW_BUFFER0_ATI 0x8825 +#define GL_DRAW_BUFFER1_ATI 0x8826 +#define GL_DRAW_BUFFER2_ATI 0x8827 +#define GL_DRAW_BUFFER3_ATI 0x8828 +#define GL_DRAW_BUFFER4_ATI 0x8829 +#define GL_DRAW_BUFFER5_ATI 0x882A +#define GL_DRAW_BUFFER6_ATI 0x882B +#define GL_DRAW_BUFFER7_ATI 0x882C +#define GL_DRAW_BUFFER8_ATI 0x882D +#define GL_DRAW_BUFFER9_ATI 0x882E +#define GL_DRAW_BUFFER10_ATI 0x882F +#define GL_DRAW_BUFFER11_ATI 0x8830 +#define GL_DRAW_BUFFER12_ATI 0x8831 +#define GL_DRAW_BUFFER13_ATI 0x8832 +#define GL_DRAW_BUFFER14_ATI 0x8833 +#define GL_DRAW_BUFFER15_ATI 0x8834 +#endif + +#ifndef GL_ATI_pixel_format_float +#define GL_TYPE_RGBA_FLOAT_ATI 0x8820 +#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 +#endif + +#ifndef GL_ATI_texture_env_combine3 +#define GL_MODULATE_ADD_ATI 0x8744 +#define GL_MODULATE_SIGNED_ADD_ATI 0x8745 +#define GL_MODULATE_SUBTRACT_ATI 0x8746 +#endif + +#ifndef GL_ATI_texture_float +#define GL_RGBA_FLOAT32_ATI 0x8814 +#define GL_RGB_FLOAT32_ATI 0x8815 +#define GL_ALPHA_FLOAT32_ATI 0x8816 +#define GL_INTENSITY_FLOAT32_ATI 0x8817 +#define GL_LUMINANCE_FLOAT32_ATI 0x8818 +#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 +#define GL_RGBA_FLOAT16_ATI 0x881A +#define GL_RGB_FLOAT16_ATI 0x881B +#define GL_ALPHA_FLOAT16_ATI 0x881C +#define GL_INTENSITY_FLOAT16_ATI 0x881D +#define GL_LUMINANCE_FLOAT16_ATI 0x881E +#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F +#endif + +#ifndef GL_NV_float_buffer +#define GL_FLOAT_R_NV 0x8880 +#define GL_FLOAT_RG_NV 0x8881 +#define GL_FLOAT_RGB_NV 0x8882 +#define GL_FLOAT_RGBA_NV 0x8883 +#define GL_FLOAT_R16_NV 0x8884 +#define GL_FLOAT_R32_NV 0x8885 +#define GL_FLOAT_RG16_NV 0x8886 +#define GL_FLOAT_RG32_NV 0x8887 +#define GL_FLOAT_RGB16_NV 0x8888 +#define GL_FLOAT_RGB32_NV 0x8889 +#define GL_FLOAT_RGBA16_NV 0x888A +#define GL_FLOAT_RGBA32_NV 0x888B +#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C +#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D +#define GL_FLOAT_RGBA_MODE_NV 0x888E +#endif + +#ifndef GL_NV_fragment_program +#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 +#define GL_FRAGMENT_PROGRAM_NV 0x8870 +#define GL_MAX_TEXTURE_COORDS_NV 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 +#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 +#define GL_PROGRAM_ERROR_STRING_NV 0x8874 +#endif + +#ifndef GL_NV_half_float +#define GL_HALF_FLOAT_NV 0x140B +#endif + +#ifndef GL_NV_pixel_data_range +#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 +#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 +#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A +#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B +#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C +#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D +#endif + +#ifndef GL_NV_primitive_restart +#define GL_PRIMITIVE_RESTART_NV 0x8558 +#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 +#endif + +#ifndef GL_NV_texture_expand_normal +#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F +#endif + +#ifndef GL_NV_vertex_program2 +#endif + +#ifndef GL_ATI_map_object_buffer +#endif + +#ifndef GL_ATI_separate_stencil +#define GL_STENCIL_BACK_FUNC_ATI 0x8800 +#define GL_STENCIL_BACK_FAIL_ATI 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 +#endif + +#ifndef GL_ATI_vertex_attrib_array_object +#endif + +#ifndef GL_OES_read_format +#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B +#endif + +#ifndef GL_EXT_depth_bounds_test +#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 +#define GL_DEPTH_BOUNDS_EXT 0x8891 +#endif + +#ifndef GL_EXT_texture_mirror_clamp +#define GL_MIRROR_CLAMP_EXT 0x8742 +#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 +#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 +#endif + +#ifndef GL_EXT_blend_equation_separate +#define GL_BLEND_EQUATION_RGB_EXT GL_BLEND_EQUATION +#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D +#endif + +#ifndef GL_MESA_pack_invert +#define GL_PACK_INVERT_MESA 0x8758 +#endif + +#ifndef GL_MESA_ycbcr_texture +#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB +#define GL_YCBCR_MESA 0x8757 +#endif + +#ifndef GL_EXT_pixel_buffer_object +#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF +#endif + +#ifndef GL_NV_fragment_program_option +#endif + +#ifndef GL_NV_fragment_program2 +#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 +#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 +#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 +#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 +#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 +#endif + +#ifndef GL_NV_vertex_program2_option +/* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */ +/* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */ +#endif + +#ifndef GL_NV_vertex_program3 +/* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */ +#endif + +#ifndef GL_EXT_framebuffer_object +#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 +#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 +#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 +#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 +#define GL_FRAMEBUFFER_EXT 0x8D40 +#define GL_RENDERBUFFER_EXT 0x8D41 +#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 +#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 +#define GL_STENCIL_INDEX1_EXT 0x8D46 +#define GL_STENCIL_INDEX4_EXT 0x8D47 +#define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_STENCIL_INDEX16_EXT 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +#endif + +#ifndef GL_GREMEDY_string_marker +#endif + +#ifndef GL_EXT_packed_depth_stencil +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#endif + +#ifndef GL_EXT_stencil_clear_tag +#define GL_STENCIL_TAG_BITS_EXT 0x88F2 +#define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 +#endif + +#ifndef GL_EXT_texture_sRGB +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB8_EXT 0x8C41 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define GL_SLUMINANCE_EXT 0x8C46 +#define GL_SLUMINANCE8_EXT 0x8C47 +#define GL_COMPRESSED_SRGB_EXT 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif + +#ifndef GL_EXT_framebuffer_blit +#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT +#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CAA +#endif + +#ifndef GL_EXT_framebuffer_multisample +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_MAX_SAMPLES_EXT 0x8D57 +#endif + +#ifndef GL_MESAX_texture_stack +#define GL_TEXTURE_1D_STACK_MESAX 0x8759 +#define GL_TEXTURE_2D_STACK_MESAX 0x875A +#define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B +#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C +#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D +#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E +#endif + +#ifndef GL_EXT_timer_query +#define GL_TIME_ELAPSED_EXT 0x88BF +#endif + +#ifndef GL_EXT_gpu_program_parameters +#endif + +#ifndef GL_APPLE_flush_buffer_range +#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 +#define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 +#endif + +#ifndef GL_NV_gpu_program4 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 +#define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 +#define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 +#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 +#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 +#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 +#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 +#endif + +#ifndef GL_NV_geometry_program4 +#define GL_LINES_ADJACENCY_EXT 0x000A +#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B +#define GL_TRIANGLES_ADJACENCY_EXT 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D +#define GL_GEOMETRY_PROGRAM_NV 0x8C26 +#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 +#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 +#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA +#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 +#define GL_PROGRAM_POINT_SIZE_EXT 0x8642 +#endif + +#ifndef GL_EXT_geometry_shader4 +#define GL_GEOMETRY_SHADER_EXT 0x8DD9 +/* reuse GL_GEOMETRY_VERTICES_OUT_EXT */ +/* reuse GL_GEOMETRY_INPUT_TYPE_EXT */ +/* reuse GL_GEOMETRY_OUTPUT_TYPE_EXT */ +/* reuse GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */ +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD +#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE +#define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 +/* reuse GL_LINES_ADJACENCY_EXT */ +/* reuse GL_LINE_STRIP_ADJACENCY_EXT */ +/* reuse GL_TRIANGLES_ADJACENCY_EXT */ +/* reuse GL_TRIANGLE_STRIP_ADJACENCY_EXT */ +/* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT */ +/* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT */ +/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ +/* reuse GL_PROGRAM_POINT_SIZE_EXT */ +#endif + +#ifndef GL_NV_vertex_program4 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD +#endif + +#ifndef GL_EXT_gpu_shader4 +#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 +#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 +#define GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 +#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 +#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 +#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 +#define GL_INT_SAMPLER_1D_EXT 0x8DC9 +#define GL_INT_SAMPLER_2D_EXT 0x8DCA +#define GL_INT_SAMPLER_3D_EXT 0x8DCB +#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC +#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD +#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF +#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#endif + +#ifndef GL_EXT_draw_instanced +#endif + +#ifndef GL_EXT_packed_float +#define GL_R11F_G11F_B10F_EXT 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B +#define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C +#endif + +#ifndef GL_EXT_texture_array +#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 +#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D +#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF +#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E +/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ +#endif + +#ifndef GL_EXT_texture_buffer_object +#define GL_TEXTURE_BUFFER_EXT 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D +#define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E +#endif + +#ifndef GL_EXT_texture_compression_latc +#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 +#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 +#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 +#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 +#endif + +#ifndef GL_EXT_texture_compression_rgtc +#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#endif + +#ifndef GL_EXT_texture_shared_exponent +#define GL_RGB9_E5_EXT 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E +#define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F +#endif + +#ifndef GL_NV_depth_buffer_float +#define GL_DEPTH_COMPONENT32F_NV 0x8DAB +#define GL_DEPTH32F_STENCIL8_NV 0x8DAC +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD +#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF +#endif + +#ifndef GL_NV_fragment_program4 +#endif + +#ifndef GL_NV_framebuffer_multisample_coverage +#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB +#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 +#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 +#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 +#endif + +#ifndef GL_EXT_framebuffer_sRGB +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA +#endif + +#ifndef GL_NV_geometry_shader4 +#endif + +#ifndef GL_NV_parameter_buffer_object +#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 +#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 +#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 +#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 +#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 +#endif + +#ifndef GL_EXT_draw_buffers2 +#endif + +#ifndef GL_NV_transform_feedback +#define GL_BACK_PRIMARY_COLOR_NV 0x8C77 +#define GL_BACK_SECONDARY_COLOR_NV 0x8C78 +#define GL_TEXTURE_COORD_NV 0x8C79 +#define GL_CLIP_DISTANCE_NV 0x8C7A +#define GL_VERTEX_ID_NV 0x8C7B +#define GL_PRIMITIVE_ID_NV 0x8C7C +#define GL_GENERIC_ATTRIB_NV 0x8C7D +#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 +#define GL_ACTIVE_VARYINGS_NV 0x8C81 +#define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 +#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 +#define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 +#define GL_PRIMITIVES_GENERATED_NV 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 +#define GL_RASTERIZER_DISCARD_NV 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_ATTRIBS_NV 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B +#define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C +#define GL_SEPARATE_ATTRIBS_NV 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F +#endif + +#ifndef GL_EXT_bindable_uniform +#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 +#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 +#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 +#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED +#define GL_UNIFORM_BUFFER_EXT 0x8DEE +#define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF +#endif + +#ifndef GL_EXT_texture_integer +#define GL_RGBA32UI_EXT 0x8D70 +#define GL_RGB32UI_EXT 0x8D71 +#define GL_ALPHA32UI_EXT 0x8D72 +#define GL_INTENSITY32UI_EXT 0x8D73 +#define GL_LUMINANCE32UI_EXT 0x8D74 +#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 +#define GL_RGBA16UI_EXT 0x8D76 +#define GL_RGB16UI_EXT 0x8D77 +#define GL_ALPHA16UI_EXT 0x8D78 +#define GL_INTENSITY16UI_EXT 0x8D79 +#define GL_LUMINANCE16UI_EXT 0x8D7A +#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B +#define GL_RGBA8UI_EXT 0x8D7C +#define GL_RGB8UI_EXT 0x8D7D +#define GL_ALPHA8UI_EXT 0x8D7E +#define GL_INTENSITY8UI_EXT 0x8D7F +#define GL_LUMINANCE8UI_EXT 0x8D80 +#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 +#define GL_RGBA32I_EXT 0x8D82 +#define GL_RGB32I_EXT 0x8D83 +#define GL_ALPHA32I_EXT 0x8D84 +#define GL_INTENSITY32I_EXT 0x8D85 +#define GL_LUMINANCE32I_EXT 0x8D86 +#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 +#define GL_RGBA16I_EXT 0x8D88 +#define GL_RGB16I_EXT 0x8D89 +#define GL_ALPHA16I_EXT 0x8D8A +#define GL_INTENSITY16I_EXT 0x8D8B +#define GL_LUMINANCE16I_EXT 0x8D8C +#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D +#define GL_RGBA8I_EXT 0x8D8E +#define GL_RGB8I_EXT 0x8D8F +#define GL_ALPHA8I_EXT 0x8D90 +#define GL_INTENSITY8I_EXT 0x8D91 +#define GL_LUMINANCE8I_EXT 0x8D92 +#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 +#define GL_RED_INTEGER_EXT 0x8D94 +#define GL_GREEN_INTEGER_EXT 0x8D95 +#define GL_BLUE_INTEGER_EXT 0x8D96 +#define GL_ALPHA_INTEGER_EXT 0x8D97 +#define GL_RGB_INTEGER_EXT 0x8D98 +#define GL_RGBA_INTEGER_EXT 0x8D99 +#define GL_BGR_INTEGER_EXT 0x8D9A +#define GL_BGRA_INTEGER_EXT 0x8D9B +#define GL_LUMINANCE_INTEGER_EXT 0x8D9C +#define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D +#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E +#endif + + +/*************************************************************/ + +#include +#ifndef GL_VERSION_2_0 +/* GL type for program/shader text */ +typedef char GLchar; /* native character */ +#endif + +#ifndef GL_VERSION_1_5 +/* GL types for handling large vertex buffer objects */ +typedef ptrdiff_t GLintptr; +typedef ptrdiff_t GLsizeiptr; +#endif + +#ifndef GL_ARB_vertex_buffer_object +/* GL types for handling large vertex buffer objects */ +typedef ptrdiff_t GLintptrARB; +typedef ptrdiff_t GLsizeiptrARB; +#endif + +#ifndef GL_ARB_shader_objects +/* GL types for handling shader object handles and program/shader text */ +typedef char GLcharARB; /* native character */ +typedef unsigned int GLhandleARB; /* shader object handle */ +#endif + +/* GL types for "half" precision (s10e5) float data in host memory */ +#ifndef GL_ARB_half_float_pixel +typedef unsigned short GLhalfARB; +#endif + +#ifndef GL_NV_half_float +typedef unsigned short GLhalfNV; +#endif + +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) +#include +#if defined(__STDC__) +#if defined(__arch64__) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include /* Fallback option */ +#endif +#endif + +#ifndef GL_EXT_timer_query +typedef int64_t GLint64EXT; +typedef uint64_t GLuint64EXT; +#endif + +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendColor (GLclampf, GLclampf, GLclampf, GLclampf); +GLAPI void APIENTRY glBlendEquation (GLenum); +GLAPI void APIENTRY glDrawRangeElements (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *); +GLAPI void APIENTRY glColorTable (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glColorTableParameterfv (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glColorTableParameteriv (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glCopyColorTable (GLenum, GLenum, GLint, GLint, GLsizei); +GLAPI void APIENTRY glGetColorTable (GLenum, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetColorTableParameterfv (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetColorTableParameteriv (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glColorSubTable (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glCopyColorSubTable (GLenum, GLsizei, GLint, GLint, GLsizei); +GLAPI void APIENTRY glConvolutionFilter1D (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glConvolutionFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glConvolutionParameterf (GLenum, GLenum, GLfloat); +GLAPI void APIENTRY glConvolutionParameterfv (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glConvolutionParameteri (GLenum, GLenum, GLint); +GLAPI void APIENTRY glConvolutionParameteriv (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum, GLenum, GLint, GLint, GLsizei); +GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei); +GLAPI void APIENTRY glGetConvolutionFilter (GLenum, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetSeparableFilter (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *); +GLAPI void APIENTRY glSeparableFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *); +GLAPI void APIENTRY glGetHistogram (GLenum, GLboolean, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetHistogramParameterfv (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetHistogramParameteriv (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetMinmax (GLenum, GLboolean, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glHistogram (GLenum, GLsizei, GLenum, GLboolean); +GLAPI void APIENTRY glMinmax (GLenum, GLenum, GLboolean); +GLAPI void APIENTRY glResetHistogram (GLenum); +GLAPI void APIENTRY glResetMinmax (GLenum); +GLAPI void APIENTRY glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glCopyTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); +typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif + +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTexture (GLenum); +GLAPI void APIENTRY glClientActiveTexture (GLenum); +GLAPI void APIENTRY glMultiTexCoord1d (GLenum, GLdouble); +GLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *); +GLAPI void APIENTRY glMultiTexCoord1f (GLenum, GLfloat); +GLAPI void APIENTRY glMultiTexCoord1fv (GLenum, const GLfloat *); +GLAPI void APIENTRY glMultiTexCoord1i (GLenum, GLint); +GLAPI void APIENTRY glMultiTexCoord1iv (GLenum, const GLint *); +GLAPI void APIENTRY glMultiTexCoord1s (GLenum, GLshort); +GLAPI void APIENTRY glMultiTexCoord1sv (GLenum, const GLshort *); +GLAPI void APIENTRY glMultiTexCoord2d (GLenum, GLdouble, GLdouble); +GLAPI void APIENTRY glMultiTexCoord2dv (GLenum, const GLdouble *); +GLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat); +GLAPI void APIENTRY glMultiTexCoord2fv (GLenum, const GLfloat *); +GLAPI void APIENTRY glMultiTexCoord2i (GLenum, GLint, GLint); +GLAPI void APIENTRY glMultiTexCoord2iv (GLenum, const GLint *); +GLAPI void APIENTRY glMultiTexCoord2s (GLenum, GLshort, GLshort); +GLAPI void APIENTRY glMultiTexCoord2sv (GLenum, const GLshort *); +GLAPI void APIENTRY glMultiTexCoord3d (GLenum, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glMultiTexCoord3dv (GLenum, const GLdouble *); +GLAPI void APIENTRY glMultiTexCoord3f (GLenum, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glMultiTexCoord3fv (GLenum, const GLfloat *); +GLAPI void APIENTRY glMultiTexCoord3i (GLenum, GLint, GLint, GLint); +GLAPI void APIENTRY glMultiTexCoord3iv (GLenum, const GLint *); +GLAPI void APIENTRY glMultiTexCoord3s (GLenum, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glMultiTexCoord3sv (GLenum, const GLshort *); +GLAPI void APIENTRY glMultiTexCoord4d (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glMultiTexCoord4dv (GLenum, const GLdouble *); +GLAPI void APIENTRY glMultiTexCoord4f (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glMultiTexCoord4fv (GLenum, const GLfloat *); +GLAPI void APIENTRY glMultiTexCoord4i (GLenum, GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glMultiTexCoord4iv (GLenum, const GLint *); +GLAPI void APIENTRY glMultiTexCoord4s (GLenum, GLshort, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glMultiTexCoord4sv (GLenum, const GLshort *); +GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *); +GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *); +GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *); +GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *); +GLAPI void APIENTRY glSampleCoverage (GLclampf, GLboolean); +GLAPI void APIENTRY glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glGetCompressedTexImage (GLenum, GLint, GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); +#endif + +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparate (GLenum, GLenum, GLenum, GLenum); +GLAPI void APIENTRY glFogCoordf (GLfloat); +GLAPI void APIENTRY glFogCoordfv (const GLfloat *); +GLAPI void APIENTRY glFogCoordd (GLdouble); +GLAPI void APIENTRY glFogCoorddv (const GLdouble *); +GLAPI void APIENTRY glFogCoordPointer (GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glMultiDrawArrays (GLenum, GLint *, GLsizei *, GLsizei); +GLAPI void APIENTRY glMultiDrawElements (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei); +GLAPI void APIENTRY glPointParameterf (GLenum, GLfloat); +GLAPI void APIENTRY glPointParameterfv (GLenum, const GLfloat *); +GLAPI void APIENTRY glPointParameteri (GLenum, GLint); +GLAPI void APIENTRY glPointParameteriv (GLenum, const GLint *); +GLAPI void APIENTRY glSecondaryColor3b (GLbyte, GLbyte, GLbyte); +GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *); +GLAPI void APIENTRY glSecondaryColor3d (GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *); +GLAPI void APIENTRY glSecondaryColor3f (GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *); +GLAPI void APIENTRY glSecondaryColor3i (GLint, GLint, GLint); +GLAPI void APIENTRY glSecondaryColor3iv (const GLint *); +GLAPI void APIENTRY glSecondaryColor3s (GLshort, GLshort, GLshort); +GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *); +GLAPI void APIENTRY glSecondaryColor3ub (GLubyte, GLubyte, GLubyte); +GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *); +GLAPI void APIENTRY glSecondaryColor3ui (GLuint, GLuint, GLuint); +GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *); +GLAPI void APIENTRY glSecondaryColor3us (GLushort, GLushort, GLushort); +GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *); +GLAPI void APIENTRY glSecondaryColorPointer (GLint, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glWindowPos2d (GLdouble, GLdouble); +GLAPI void APIENTRY glWindowPos2dv (const GLdouble *); +GLAPI void APIENTRY glWindowPos2f (GLfloat, GLfloat); +GLAPI void APIENTRY glWindowPos2fv (const GLfloat *); +GLAPI void APIENTRY glWindowPos2i (GLint, GLint); +GLAPI void APIENTRY glWindowPos2iv (const GLint *); +GLAPI void APIENTRY glWindowPos2s (GLshort, GLshort); +GLAPI void APIENTRY glWindowPos2sv (const GLshort *); +GLAPI void APIENTRY glWindowPos3d (GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glWindowPos3dv (const GLdouble *); +GLAPI void APIENTRY glWindowPos3f (GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glWindowPos3fv (const GLfloat *); +GLAPI void APIENTRY glWindowPos3i (GLint, GLint, GLint); +GLAPI void APIENTRY glWindowPos3iv (const GLint *); +GLAPI void APIENTRY glWindowPos3s (GLshort, GLshort, GLshort); +GLAPI void APIENTRY glWindowPos3sv (const GLshort *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); +typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); +typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); +typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); +#endif + +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueries (GLsizei, GLuint *); +GLAPI void APIENTRY glDeleteQueries (GLsizei, const GLuint *); +GLAPI GLboolean APIENTRY glIsQuery (GLuint); +GLAPI void APIENTRY glBeginQuery (GLenum, GLuint); +GLAPI void APIENTRY glEndQuery (GLenum); +GLAPI void APIENTRY glGetQueryiv (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetQueryObjectiv (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetQueryObjectuiv (GLuint, GLenum, GLuint *); +GLAPI void APIENTRY glBindBuffer (GLenum, GLuint); +GLAPI void APIENTRY glDeleteBuffers (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenBuffers (GLsizei, GLuint *); +GLAPI GLboolean APIENTRY glIsBuffer (GLuint); +GLAPI void APIENTRY glBufferData (GLenum, GLsizeiptr, const GLvoid *, GLenum); +GLAPI void APIENTRY glBufferSubData (GLenum, GLintptr, GLsizeiptr, const GLvoid *); +GLAPI void APIENTRY glGetBufferSubData (GLenum, GLintptr, GLsizeiptr, GLvoid *); +GLAPI GLvoid* APIENTRY glMapBuffer (GLenum, GLenum); +GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum); +GLAPI void APIENTRY glGetBufferParameteriv (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetBufferPointerv (GLenum, GLenum, GLvoid* *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params); +#endif + +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparate (GLenum, GLenum); +GLAPI void APIENTRY glDrawBuffers (GLsizei, const GLenum *); +GLAPI void APIENTRY glStencilOpSeparate (GLenum, GLenum, GLenum, GLenum); +GLAPI void APIENTRY glStencilFuncSeparate (GLenum, GLenum, GLint, GLuint); +GLAPI void APIENTRY glStencilMaskSeparate (GLenum, GLuint); +GLAPI void APIENTRY glAttachShader (GLuint, GLuint); +GLAPI void APIENTRY glBindAttribLocation (GLuint, GLuint, const GLchar *); +GLAPI void APIENTRY glCompileShader (GLuint); +GLAPI GLuint APIENTRY glCreateProgram (void); +GLAPI GLuint APIENTRY glCreateShader (GLenum); +GLAPI void APIENTRY glDeleteProgram (GLuint); +GLAPI void APIENTRY glDeleteShader (GLuint); +GLAPI void APIENTRY glDetachShader (GLuint, GLuint); +GLAPI void APIENTRY glDisableVertexAttribArray (GLuint); +GLAPI void APIENTRY glEnableVertexAttribArray (GLuint); +GLAPI void APIENTRY glGetActiveAttrib (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *); +GLAPI void APIENTRY glGetActiveUniform (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *); +GLAPI void APIENTRY glGetAttachedShaders (GLuint, GLsizei, GLsizei *, GLuint *); +GLAPI GLint APIENTRY glGetAttribLocation (GLuint, const GLchar *); +GLAPI void APIENTRY glGetProgramiv (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetProgramInfoLog (GLuint, GLsizei, GLsizei *, GLchar *); +GLAPI void APIENTRY glGetShaderiv (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetShaderInfoLog (GLuint, GLsizei, GLsizei *, GLchar *); +GLAPI void APIENTRY glGetShaderSource (GLuint, GLsizei, GLsizei *, GLchar *); +GLAPI GLint APIENTRY glGetUniformLocation (GLuint, const GLchar *); +GLAPI void APIENTRY glGetUniformfv (GLuint, GLint, GLfloat *); +GLAPI void APIENTRY glGetUniformiv (GLuint, GLint, GLint *); +GLAPI void APIENTRY glGetVertexAttribdv (GLuint, GLenum, GLdouble *); +GLAPI void APIENTRY glGetVertexAttribfv (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetVertexAttribiv (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint, GLenum, GLvoid* *); +GLAPI GLboolean APIENTRY glIsProgram (GLuint); +GLAPI GLboolean APIENTRY glIsShader (GLuint); +GLAPI void APIENTRY glLinkProgram (GLuint); +GLAPI void APIENTRY glShaderSource (GLuint, GLsizei, const GLchar* *, const GLint *); +GLAPI void APIENTRY glUseProgram (GLuint); +GLAPI void APIENTRY glUniform1f (GLint, GLfloat); +GLAPI void APIENTRY glUniform2f (GLint, GLfloat, GLfloat); +GLAPI void APIENTRY glUniform3f (GLint, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glUniform4f (GLint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glUniform1i (GLint, GLint); +GLAPI void APIENTRY glUniform2i (GLint, GLint, GLint); +GLAPI void APIENTRY glUniform3i (GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glUniform4i (GLint, GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glUniform1fv (GLint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glUniform2fv (GLint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glUniform3fv (GLint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glUniform4fv (GLint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glUniform1iv (GLint, GLsizei, const GLint *); +GLAPI void APIENTRY glUniform2iv (GLint, GLsizei, const GLint *); +GLAPI void APIENTRY glUniform3iv (GLint, GLsizei, const GLint *); +GLAPI void APIENTRY glUniform4iv (GLint, GLsizei, const GLint *); +GLAPI void APIENTRY glUniformMatrix2fv (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix3fv (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix4fv (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glValidateProgram (GLuint); +GLAPI void APIENTRY glVertexAttrib1d (GLuint, GLdouble); +GLAPI void APIENTRY glVertexAttrib1dv (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib1f (GLuint, GLfloat); +GLAPI void APIENTRY glVertexAttrib1fv (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib1s (GLuint, GLshort); +GLAPI void APIENTRY glVertexAttrib1sv (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib2d (GLuint, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib2dv (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib2f (GLuint, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib2fv (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib2s (GLuint, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib2sv (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib3d (GLuint, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib3dv (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib3f (GLuint, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib3fv (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib3s (GLuint, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib3sv (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint, const GLbyte *); +GLAPI void APIENTRY glVertexAttrib4Niv (GLuint, const GLint *); +GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib4Nub (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); +GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint, const GLubyte *); +GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint, const GLuint *); +GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint, const GLushort *); +GLAPI void APIENTRY glVertexAttrib4bv (GLuint, const GLbyte *); +GLAPI void APIENTRY glVertexAttrib4d (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib4dv (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib4f (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib4fv (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib4iv (GLuint, const GLint *); +GLAPI void APIENTRY glVertexAttrib4s (GLuint, GLshort, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib4sv (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib4ubv (GLuint, const GLubyte *); +GLAPI void APIENTRY glVertexAttrib4uiv (GLuint, const GLuint *); +GLAPI void APIENTRY glVertexAttrib4usv (GLuint, const GLushort *); +GLAPI void APIENTRY glVertexAttribPointer (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); +typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +#endif + +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformMatrix2x3fv (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix3x2fv (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix2x4fv (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix4x2fv (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix3x4fv (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix4x3fv (GLint, GLsizei, GLboolean, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#endif + +#ifndef GL_ARB_multitexture +#define GL_ARB_multitexture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTextureARB (GLenum); +GLAPI void APIENTRY glClientActiveTextureARB (GLenum); +GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum, GLdouble); +GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum, const GLdouble *); +GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum, GLfloat); +GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum, const GLfloat *); +GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum, GLint); +GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum, const GLint *); +GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum, GLshort); +GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum, const GLshort *); +GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum, GLdouble, GLdouble); +GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum, const GLdouble *); +GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum, GLfloat, GLfloat); +GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum, const GLfloat *); +GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum, GLint, GLint); +GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum, const GLint *); +GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum, GLshort, GLshort); +GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum, const GLshort *); +GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum, const GLdouble *); +GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum, const GLfloat *); +GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum, GLint, GLint, GLint); +GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum, const GLint *); +GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum, const GLshort *); +GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum, const GLdouble *); +GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum, const GLfloat *); +GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum, GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum, const GLint *); +GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum, GLshort, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum, const GLshort *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); +#endif + +#ifndef GL_ARB_transpose_matrix +#define GL_ARB_transpose_matrix 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *); +GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *); +GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *); +GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); +#endif + +#ifndef GL_ARB_multisample +#define GL_ARB_multisample 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleCoverageARB (GLclampf, GLboolean); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert); +#endif + +#ifndef GL_ARB_texture_env_add +#define GL_ARB_texture_env_add 1 +#endif + +#ifndef GL_ARB_texture_cube_map +#define GL_ARB_texture_cube_map 1 +#endif + +#ifndef GL_ARB_texture_compression +#define GL_ARB_texture_compression 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img); +#endif + +#ifndef GL_ARB_texture_border_clamp +#define GL_ARB_texture_border_clamp 1 +#endif + +#ifndef GL_ARB_point_parameters +#define GL_ARB_point_parameters 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfARB (GLenum, GLfloat); +GLAPI void APIENTRY glPointParameterfvARB (GLenum, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); +#endif + +#ifndef GL_ARB_vertex_blend +#define GL_ARB_vertex_blend 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWeightbvARB (GLint, const GLbyte *); +GLAPI void APIENTRY glWeightsvARB (GLint, const GLshort *); +GLAPI void APIENTRY glWeightivARB (GLint, const GLint *); +GLAPI void APIENTRY glWeightfvARB (GLint, const GLfloat *); +GLAPI void APIENTRY glWeightdvARB (GLint, const GLdouble *); +GLAPI void APIENTRY glWeightubvARB (GLint, const GLubyte *); +GLAPI void APIENTRY glWeightusvARB (GLint, const GLushort *); +GLAPI void APIENTRY glWeightuivARB (GLint, const GLuint *); +GLAPI void APIENTRY glWeightPointerARB (GLint, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glVertexBlendARB (GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); +typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); +typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); +typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); +typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); +typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); +typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); +typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); +typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); +#endif + +#ifndef GL_ARB_matrix_palette +#define GL_ARB_matrix_palette 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint); +GLAPI void APIENTRY glMatrixIndexubvARB (GLint, const GLubyte *); +GLAPI void APIENTRY glMatrixIndexusvARB (GLint, const GLushort *); +GLAPI void APIENTRY glMatrixIndexuivARB (GLint, const GLuint *); +GLAPI void APIENTRY glMatrixIndexPointerARB (GLint, GLenum, GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); +typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +#endif + +#ifndef GL_ARB_texture_env_combine +#define GL_ARB_texture_env_combine 1 +#endif + +#ifndef GL_ARB_texture_env_crossbar +#define GL_ARB_texture_env_crossbar 1 +#endif + +#ifndef GL_ARB_texture_env_dot3 +#define GL_ARB_texture_env_dot3 1 +#endif + +#ifndef GL_ARB_texture_mirrored_repeat +#define GL_ARB_texture_mirrored_repeat 1 +#endif + +#ifndef GL_ARB_depth_texture +#define GL_ARB_depth_texture 1 +#endif + +#ifndef GL_ARB_shadow +#define GL_ARB_shadow 1 +#endif + +#ifndef GL_ARB_shadow_ambient +#define GL_ARB_shadow_ambient 1 +#endif + +#ifndef GL_ARB_window_pos +#define GL_ARB_window_pos 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWindowPos2dARB (GLdouble, GLdouble); +GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *); +GLAPI void APIENTRY glWindowPos2fARB (GLfloat, GLfloat); +GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *); +GLAPI void APIENTRY glWindowPos2iARB (GLint, GLint); +GLAPI void APIENTRY glWindowPos2ivARB (const GLint *); +GLAPI void APIENTRY glWindowPos2sARB (GLshort, GLshort); +GLAPI void APIENTRY glWindowPos2svARB (const GLshort *); +GLAPI void APIENTRY glWindowPos3dARB (GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *); +GLAPI void APIENTRY glWindowPos3fARB (GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *); +GLAPI void APIENTRY glWindowPos3iARB (GLint, GLint, GLint); +GLAPI void APIENTRY glWindowPos3ivARB (const GLint *); +GLAPI void APIENTRY glWindowPos3sARB (GLshort, GLshort, GLshort); +GLAPI void APIENTRY glWindowPos3svARB (const GLshort *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); +#endif + +#ifndef GL_ARB_vertex_program +#define GL_ARB_vertex_program 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttrib1dARB (GLuint, GLdouble); +GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib1fARB (GLuint, GLfloat); +GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib1sARB (GLuint, GLshort); +GLAPI void APIENTRY glVertexAttrib1svARB (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib2dARB (GLuint, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib2fARB (GLuint, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib2sARB (GLuint, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib2svARB (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib3dARB (GLuint, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib3fARB (GLuint, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib3sARB (GLuint, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib3svARB (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint, const GLbyte *); +GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint, const GLint *); +GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); +GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint, const GLubyte *); +GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint, const GLuint *); +GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint, const GLushort *); +GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint, const GLbyte *); +GLAPI void APIENTRY glVertexAttrib4dARB (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib4fARB (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint, const GLint *); +GLAPI void APIENTRY glVertexAttrib4sARB (GLuint, GLshort, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib4svARB (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint, const GLubyte *); +GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint, const GLuint *); +GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint, const GLushort *); +GLAPI void APIENTRY glVertexAttribPointerARB (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); +GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint); +GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint); +GLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glBindProgramARB (GLenum, GLuint); +GLAPI void APIENTRY glDeleteProgramsARB (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *); +GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum, GLuint, const GLdouble *); +GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum, GLuint, const GLfloat *); +GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum, GLuint, const GLdouble *); +GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *); +GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum, GLuint, GLdouble *); +GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum, GLuint, GLfloat *); +GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum, GLuint, GLdouble *); +GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum, GLuint, GLfloat *); +GLAPI void APIENTRY glGetProgramivARB (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetProgramStringARB (GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint, GLenum, GLdouble *); +GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetVertexAttribivARB (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint, GLenum, GLvoid* *); +GLAPI GLboolean APIENTRY glIsProgramARB (GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); +typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); +typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); +#endif + +#ifndef GL_ARB_fragment_program +#define GL_ARB_fragment_program 1 +/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */ +#endif + +#ifndef GL_ARB_vertex_buffer_object +#define GL_ARB_vertex_buffer_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindBufferARB (GLenum, GLuint); +GLAPI void APIENTRY glDeleteBuffersARB (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenBuffersARB (GLsizei, GLuint *); +GLAPI GLboolean APIENTRY glIsBufferARB (GLuint); +GLAPI void APIENTRY glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum); +GLAPI void APIENTRY glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *); +GLAPI void APIENTRY glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *); +GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum, GLenum); +GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum); +GLAPI void APIENTRY glGetBufferParameterivARB (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); +typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params); +#endif + +#ifndef GL_ARB_occlusion_query +#define GL_ARB_occlusion_query 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueriesARB (GLsizei, GLuint *); +GLAPI void APIENTRY glDeleteQueriesARB (GLsizei, const GLuint *); +GLAPI GLboolean APIENTRY glIsQueryARB (GLuint); +GLAPI void APIENTRY glBeginQueryARB (GLenum, GLuint); +GLAPI void APIENTRY glEndQueryARB (GLenum); +GLAPI void APIENTRY glGetQueryivARB (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetQueryObjectivARB (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint, GLenum, GLuint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); +#endif + +#ifndef GL_ARB_shader_objects +#define GL_ARB_shader_objects 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB); +GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum); +GLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB); +GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum); +GLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *); +GLAPI void APIENTRY glCompileShaderARB (GLhandleARB); +GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); +GLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB); +GLAPI void APIENTRY glLinkProgramARB (GLhandleARB); +GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB); +GLAPI void APIENTRY glValidateProgramARB (GLhandleARB); +GLAPI void APIENTRY glUniform1fARB (GLint, GLfloat); +GLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat); +GLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glUniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glUniform1iARB (GLint, GLint); +GLAPI void APIENTRY glUniform2iARB (GLint, GLint, GLint); +GLAPI void APIENTRY glUniform3iARB (GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glUniform4iARB (GLint, GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glUniform1fvARB (GLint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glUniform2fvARB (GLint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glUniform3fvARB (GLint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glUniform4fvARB (GLint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glUniform1ivARB (GLint, GLsizei, const GLint *); +GLAPI void APIENTRY glUniform2ivARB (GLint, GLsizei, const GLint *); +GLAPI void APIENTRY glUniform3ivARB (GLint, GLsizei, const GLint *); +GLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *); +GLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *); +GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *); +GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *); +GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); +GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *); +GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *); +GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); +GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *); +GLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *); +GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); +typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); +typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); +typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); +typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); +typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); +typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); +typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); +typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); +#endif + +#ifndef GL_ARB_vertex_shader +#define GL_ARB_vertex_shader 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *); +GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); +GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +#endif + +#ifndef GL_ARB_fragment_shader +#define GL_ARB_fragment_shader 1 +#endif + +#ifndef GL_ARB_shading_language_100 +#define GL_ARB_shading_language_100 1 +#endif + +#ifndef GL_ARB_texture_non_power_of_two +#define GL_ARB_texture_non_power_of_two 1 +#endif + +#ifndef GL_ARB_point_sprite +#define GL_ARB_point_sprite 1 +#endif + +#ifndef GL_ARB_fragment_program_shadow +#define GL_ARB_fragment_program_shadow 1 +#endif + +#ifndef GL_ARB_draw_buffers +#define GL_ARB_draw_buffers 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawBuffersARB (GLsizei, const GLenum *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); +#endif + +#ifndef GL_ARB_texture_rectangle +#define GL_ARB_texture_rectangle 1 +#endif + +#ifndef GL_ARB_color_buffer_float +#define GL_ARB_color_buffer_float 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClampColorARB (GLenum, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); +#endif + +#ifndef GL_ARB_half_float_pixel +#define GL_ARB_half_float_pixel 1 +#endif + +#ifndef GL_ARB_texture_float +#define GL_ARB_texture_float 1 +#endif + +#ifndef GL_ARB_pixel_buffer_object +#define GL_ARB_pixel_buffer_object 1 +#endif + +#ifndef GL_EXT_abgr +#define GL_EXT_abgr 1 +#endif + +#ifndef GL_EXT_blend_color +#define GL_EXT_blend_color 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendColorEXT (GLclampf, GLclampf, GLclampf, GLclampf); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +#endif + +#ifndef GL_EXT_polygon_offset +#define GL_EXT_polygon_offset 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat, GLfloat); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); +#endif + +#ifndef GL_EXT_texture +#define GL_EXT_texture 1 +#endif + +#ifndef GL_EXT_texture3D +#define GL_EXT_texture3D 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage3DEXT (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +#endif + +#ifndef GL_SGIS_texture_filter4 +#define GL_SGIS_texture_filter4 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum, GLenum, GLsizei, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); +typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); +#endif + +#ifndef GL_EXT_subtexture +#define GL_EXT_subtexture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexSubImage1DEXT (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +#endif + +#ifndef GL_EXT_copy_texture +#define GL_EXT_copy_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint); +GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint); +GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei); +GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); +GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif + +#ifndef GL_EXT_histogram +#define GL_EXT_histogram 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetHistogramEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetMinmaxEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glHistogramEXT (GLenum, GLsizei, GLenum, GLboolean); +GLAPI void APIENTRY glMinmaxEXT (GLenum, GLenum, GLboolean); +GLAPI void APIENTRY glResetHistogramEXT (GLenum); +GLAPI void APIENTRY glResetMinmaxEXT (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); +typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); +#endif + +#ifndef GL_EXT_convolution +#define GL_EXT_convolution 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum, GLenum, GLfloat); +GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum, GLenum, GLint); +GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum, GLenum, GLint, GLint, GLsizei); +GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei); +GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *); +GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); +#endif + +#ifndef GL_SGI_color_matrix +#define GL_SGI_color_matrix 1 +#endif + +#ifndef GL_SGI_color_table +#define GL_SGI_color_table 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTableSGI (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glColorTableParameterivSGI (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glCopyColorTableSGI (GLenum, GLenum, GLint, GLint, GLsizei); +GLAPI void APIENTRY glGetColorTableSGI (GLenum, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum, GLenum, GLint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); +#endif + +#ifndef GL_SGIX_pixel_texture +#define GL_SGIX_pixel_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTexGenSGIX (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); +#endif + +#ifndef GL_SGIS_pixel_texture +#define GL_SGIS_pixel_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum, GLint); +GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum, const GLint *); +GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum, GLfloat); +GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum, const GLfloat *); +GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum, GLint *); +GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); +#endif + +#ifndef GL_SGIS_texture4D +#define GL_SGIS_texture4D 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage4DSGIS (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); +#endif + +#ifndef GL_SGI_texture_color_table +#define GL_SGI_texture_color_table 1 +#endif + +#ifndef GL_EXT_cmyka +#define GL_EXT_cmyka 1 +#endif + +#ifndef GL_EXT_texture_object +#define GL_EXT_texture_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei, const GLuint *, GLboolean *); +GLAPI void APIENTRY glBindTextureEXT (GLenum, GLuint); +GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenTexturesEXT (GLsizei, GLuint *); +GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint); +GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei, const GLuint *, const GLclampf *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); +typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); +typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); +#endif + +#ifndef GL_SGIS_detail_texture +#define GL_SGIS_detail_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum, GLsizei, const GLfloat *); +GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); +#endif + +#ifndef GL_SGIS_sharpen_texture +#define GL_SGIS_sharpen_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum, GLsizei, const GLfloat *); +GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); +#endif + +#ifndef GL_EXT_packed_pixels +#define GL_EXT_packed_pixels 1 +#endif + +#ifndef GL_SGIS_texture_lod +#define GL_SGIS_texture_lod 1 +#endif + +#ifndef GL_SGIS_multisample +#define GL_SGIS_multisample 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleMaskSGIS (GLclampf, GLboolean); +GLAPI void APIENTRY glSamplePatternSGIS (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); +#endif + +#ifndef GL_EXT_rescale_normal +#define GL_EXT_rescale_normal 1 +#endif + +#ifndef GL_EXT_vertex_array +#define GL_EXT_vertex_array 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glArrayElementEXT (GLint); +GLAPI void APIENTRY glColorPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); +GLAPI void APIENTRY glDrawArraysEXT (GLenum, GLint, GLsizei); +GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei, GLsizei, const GLboolean *); +GLAPI void APIENTRY glGetPointervEXT (GLenum, GLvoid* *); +GLAPI void APIENTRY glIndexPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *); +GLAPI void APIENTRY glNormalPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *); +GLAPI void APIENTRY glTexCoordPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); +GLAPI void APIENTRY glVertexPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); +typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); +typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params); +typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +#endif + +#ifndef GL_EXT_misc_attribute +#define GL_EXT_misc_attribute 1 +#endif + +#ifndef GL_SGIS_generate_mipmap +#define GL_SGIS_generate_mipmap 1 +#endif + +#ifndef GL_SGIX_clipmap +#define GL_SGIX_clipmap 1 +#endif + +#ifndef GL_SGIX_shadow +#define GL_SGIX_shadow 1 +#endif + +#ifndef GL_SGIS_texture_edge_clamp +#define GL_SGIS_texture_edge_clamp 1 +#endif + +#ifndef GL_SGIS_texture_border_clamp +#define GL_SGIS_texture_border_clamp 1 +#endif + +#ifndef GL_EXT_blend_minmax +#define GL_EXT_blend_minmax 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationEXT (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); +#endif + +#ifndef GL_EXT_blend_subtract +#define GL_EXT_blend_subtract 1 +#endif + +#ifndef GL_EXT_blend_logic_op +#define GL_EXT_blend_logic_op 1 +#endif + +#ifndef GL_SGIX_interlace +#define GL_SGIX_interlace 1 +#endif + +#ifndef GL_SGIX_pixel_tiles +#define GL_SGIX_pixel_tiles 1 +#endif + +#ifndef GL_SGIX_texture_select +#define GL_SGIX_texture_select 1 +#endif + +#ifndef GL_SGIX_sprite +#define GL_SGIX_sprite 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum, GLfloat); +GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum, const GLfloat *); +GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum, GLint); +GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum, const GLint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); +#endif + +#ifndef GL_SGIX_texture_multi_buffer +#define GL_SGIX_texture_multi_buffer 1 +#endif + +#ifndef GL_EXT_point_parameters +#define GL_EXT_point_parameters 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfEXT (GLenum, GLfloat); +GLAPI void APIENTRY glPointParameterfvEXT (GLenum, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); +#endif + +#ifndef GL_SGIS_point_parameters +#define GL_SGIS_point_parameters 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfSGIS (GLenum, GLfloat); +GLAPI void APIENTRY glPointParameterfvSGIS (GLenum, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); +#endif + +#ifndef GL_SGIX_instruments +#define GL_SGIX_instruments 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); +GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei, GLint *); +GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *); +GLAPI void APIENTRY glReadInstrumentsSGIX (GLint); +GLAPI void APIENTRY glStartInstrumentsSGIX (void); +GLAPI void APIENTRY glStopInstrumentsSGIX (GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); +typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); +typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); +typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); +typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); +typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); +#endif + +#ifndef GL_SGIX_texture_scale_bias +#define GL_SGIX_texture_scale_bias 1 +#endif + +#ifndef GL_SGIX_framezoom +#define GL_SGIX_framezoom 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFrameZoomSGIX (GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); +#endif + +#ifndef GL_SGIX_tag_sample_buffer +#define GL_SGIX_tag_sample_buffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTagSampleBufferSGIX (void); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); +#endif + +#ifndef GL_SGIX_polynomial_ffd +#define GL_SGIX_polynomial_ffd 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *); +GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *); +GLAPI void APIENTRY glDeformSGIX (GLbitfield); +GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); +typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); +typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); +#endif + +#ifndef GL_SGIX_reference_plane +#define GL_SGIX_reference_plane 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); +#endif + +#ifndef GL_SGIX_flush_raster +#define GL_SGIX_flush_raster 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushRasterSGIX (void); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); +#endif + +#ifndef GL_SGIX_depth_texture +#define GL_SGIX_depth_texture 1 +#endif + +#ifndef GL_SGIS_fog_function +#define GL_SGIS_fog_function 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFogFuncSGIS (GLsizei, const GLfloat *); +GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); +#endif + +#ifndef GL_SGIX_fog_offset +#define GL_SGIX_fog_offset 1 +#endif + +#ifndef GL_HP_image_transform +#define GL_HP_image_transform 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glImageTransformParameteriHP (GLenum, GLenum, GLint); +GLAPI void APIENTRY glImageTransformParameterfHP (GLenum, GLenum, GLfloat); +GLAPI void APIENTRY glImageTransformParameterivHP (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum, GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); +#endif + +#ifndef GL_HP_convolution_border_modes +#define GL_HP_convolution_border_modes 1 +#endif + +#ifndef GL_SGIX_texture_add_env +#define GL_SGIX_texture_add_env 1 +#endif + +#ifndef GL_EXT_color_subtable +#define GL_EXT_color_subtable 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorSubTableEXT (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum, GLsizei, GLint, GLint, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +#endif + +#ifndef GL_PGI_vertex_hints +#define GL_PGI_vertex_hints 1 +#endif + +#ifndef GL_PGI_misc_hints +#define GL_PGI_misc_hints 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glHintPGI (GLenum, GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); +#endif + +#ifndef GL_EXT_paletted_texture +#define GL_EXT_paletted_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTableEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *); +GLAPI void APIENTRY glGetColorTableEXT (GLenum, GLenum, GLenum, GLvoid *); +GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum, GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +#endif + +#ifndef GL_EXT_clip_volume_hint +#define GL_EXT_clip_volume_hint 1 +#endif + +#ifndef GL_SGIX_list_priority +#define GL_SGIX_list_priority 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetListParameterivSGIX (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glListParameterfSGIX (GLuint, GLenum, GLfloat); +GLAPI void APIENTRY glListParameterfvSGIX (GLuint, GLenum, const GLfloat *); +GLAPI void APIENTRY glListParameteriSGIX (GLuint, GLenum, GLint); +GLAPI void APIENTRY glListParameterivSGIX (GLuint, GLenum, const GLint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); +#endif + +#ifndef GL_SGIX_ir_instrument1 +#define GL_SGIX_ir_instrument1 1 +#endif + +#ifndef GL_SGIX_calligraphic_fragment +#define GL_SGIX_calligraphic_fragment 1 +#endif + +#ifndef GL_SGIX_texture_lod_bias +#define GL_SGIX_texture_lod_bias 1 +#endif + +#ifndef GL_SGIX_shadow_ambient +#define GL_SGIX_shadow_ambient 1 +#endif + +#ifndef GL_EXT_index_texture +#define GL_EXT_index_texture 1 +#endif + +#ifndef GL_EXT_index_material +#define GL_EXT_index_material 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIndexMaterialEXT (GLenum, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); +#endif + +#ifndef GL_EXT_index_func +#define GL_EXT_index_func 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIndexFuncEXT (GLenum, GLclampf); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); +#endif + +#ifndef GL_EXT_index_array_formats +#define GL_EXT_index_array_formats 1 +#endif + +#ifndef GL_EXT_compiled_vertex_array +#define GL_EXT_compiled_vertex_array 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLockArraysEXT (GLint, GLsizei); +GLAPI void APIENTRY glUnlockArraysEXT (void); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); +#endif + +#ifndef GL_EXT_cull_vertex +#define GL_EXT_cull_vertex 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCullParameterdvEXT (GLenum, GLdouble *); +GLAPI void APIENTRY glCullParameterfvEXT (GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); +#endif + +#ifndef GL_SGIX_ycrcb +#define GL_SGIX_ycrcb 1 +#endif + +#ifndef GL_SGIX_fragment_lighting +#define GL_SGIX_fragment_lighting 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum, GLenum); +GLAPI void APIENTRY glFragmentLightfSGIX (GLenum, GLenum, GLfloat); +GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glFragmentLightiSGIX (GLenum, GLenum, GLint); +GLAPI void APIENTRY glFragmentLightivSGIX (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum, GLfloat); +GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum, const GLfloat *); +GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum, GLint); +GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum, const GLint *); +GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum, GLenum, GLfloat); +GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum, GLenum, GLint); +GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glLightEnviSGIX (GLenum, GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); +#endif + +#ifndef GL_IBM_rasterpos_clip +#define GL_IBM_rasterpos_clip 1 +#endif + +#ifndef GL_HP_texture_lighting +#define GL_HP_texture_lighting 1 +#endif + +#ifndef GL_EXT_draw_range_elements +#define GL_EXT_draw_range_elements 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +#endif + +#ifndef GL_WIN_phong_shading +#define GL_WIN_phong_shading 1 +#endif + +#ifndef GL_WIN_specular_fog +#define GL_WIN_specular_fog 1 +#endif + +#ifndef GL_EXT_light_texture +#define GL_EXT_light_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glApplyTextureEXT (GLenum); +GLAPI void APIENTRY glTextureLightEXT (GLenum); +GLAPI void APIENTRY glTextureMaterialEXT (GLenum, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); +#endif + +#ifndef GL_SGIX_blend_alpha_minmax +#define GL_SGIX_blend_alpha_minmax 1 +#endif + +#ifndef GL_EXT_bgra +#define GL_EXT_bgra 1 +#endif + +#ifndef GL_SGIX_async +#define GL_SGIX_async 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint); +GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *); +GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *); +GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei); +GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint, GLsizei); +GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); +typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); +typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); +typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); +typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); +typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); +#endif + +#ifndef GL_SGIX_async_pixel +#define GL_SGIX_async_pixel 1 +#endif + +#ifndef GL_SGIX_async_histogram +#define GL_SGIX_async_histogram 1 +#endif + +#ifndef GL_INTEL_parallel_arrays +#define GL_INTEL_parallel_arrays 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexPointervINTEL (GLint, GLenum, const GLvoid* *); +GLAPI void APIENTRY glNormalPointervINTEL (GLenum, const GLvoid* *); +GLAPI void APIENTRY glColorPointervINTEL (GLint, GLenum, const GLvoid* *); +GLAPI void APIENTRY glTexCoordPointervINTEL (GLint, GLenum, const GLvoid* *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer); +typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); +#endif + +#ifndef GL_HP_occlusion_test +#define GL_HP_occlusion_test 1 +#endif + +#ifndef GL_EXT_pixel_transform +#define GL_EXT_pixel_transform 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum, GLenum, GLint); +GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum, GLenum, GLfloat); +GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum, GLenum, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); +#endif + +#ifndef GL_EXT_pixel_transform_color_table +#define GL_EXT_pixel_transform_color_table 1 +#endif + +#ifndef GL_EXT_shared_texture_palette +#define GL_EXT_shared_texture_palette 1 +#endif + +#ifndef GL_EXT_separate_specular_color +#define GL_EXT_separate_specular_color 1 +#endif + +#ifndef GL_EXT_secondary_color +#define GL_EXT_secondary_color 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte, GLbyte, GLbyte); +GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *); +GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *); +GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *); +GLAPI void APIENTRY glSecondaryColor3iEXT (GLint, GLint, GLint); +GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *); +GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort, GLshort, GLshort); +GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *); +GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte, GLubyte, GLubyte); +GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *); +GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint, GLuint, GLuint); +GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *); +GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort, GLushort, GLushort); +GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *); +GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint, GLenum, GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +#endif + +#ifndef GL_EXT_texture_perturb_normal +#define GL_EXT_texture_perturb_normal 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureNormalEXT (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); +#endif + +#ifndef GL_EXT_multi_draw_arrays +#define GL_EXT_multi_draw_arrays 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei); +GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); +#endif + +#ifndef GL_EXT_fog_coord +#define GL_EXT_fog_coord 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFogCoordfEXT (GLfloat); +GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *); +GLAPI void APIENTRY glFogCoorddEXT (GLdouble); +GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *); +GLAPI void APIENTRY glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); +typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); +typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); +typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +#endif + +#ifndef GL_REND_screen_coordinates +#define GL_REND_screen_coordinates 1 +#endif + +#ifndef GL_EXT_coordinate_frame +#define GL_EXT_coordinate_frame 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTangent3bEXT (GLbyte, GLbyte, GLbyte); +GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *); +GLAPI void APIENTRY glTangent3dEXT (GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *); +GLAPI void APIENTRY glTangent3fEXT (GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *); +GLAPI void APIENTRY glTangent3iEXT (GLint, GLint, GLint); +GLAPI void APIENTRY glTangent3ivEXT (const GLint *); +GLAPI void APIENTRY glTangent3sEXT (GLshort, GLshort, GLshort); +GLAPI void APIENTRY glTangent3svEXT (const GLshort *); +GLAPI void APIENTRY glBinormal3bEXT (GLbyte, GLbyte, GLbyte); +GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *); +GLAPI void APIENTRY glBinormal3dEXT (GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *); +GLAPI void APIENTRY glBinormal3fEXT (GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *); +GLAPI void APIENTRY glBinormal3iEXT (GLint, GLint, GLint); +GLAPI void APIENTRY glBinormal3ivEXT (const GLint *); +GLAPI void APIENTRY glBinormal3sEXT (GLshort, GLshort, GLshort); +GLAPI void APIENTRY glBinormal3svEXT (const GLshort *); +GLAPI void APIENTRY glTangentPointerEXT (GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glBinormalPointerEXT (GLenum, GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); +typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); +typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); +typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); +typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); +typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); +typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); +typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); +typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); +typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); +typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +#endif + +#ifndef GL_EXT_texture_env_combine +#define GL_EXT_texture_env_combine 1 +#endif + +#ifndef GL_APPLE_specular_vector +#define GL_APPLE_specular_vector 1 +#endif + +#ifndef GL_APPLE_transform_hint +#define GL_APPLE_transform_hint 1 +#endif + +#ifndef GL_SGIX_fog_scale +#define GL_SGIX_fog_scale 1 +#endif + +#ifndef GL_SUNX_constant_data +#define GL_SUNX_constant_data 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFinishTextureSUNX (void); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); +#endif + +#ifndef GL_SUN_global_alpha +#define GL_SUN_global_alpha 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte); +GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort); +GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint); +GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat); +GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble); +GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte); +GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort); +GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); +#endif + +#ifndef GL_SUN_triangle_list +#define GL_SUN_triangle_list 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint); +GLAPI void APIENTRY glReplacementCodeusSUN (GLushort); +GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte); +GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *); +GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *); +GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *); +GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum, GLsizei, const GLvoid* *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer); +#endif + +#ifndef GL_SUN_vertex +#define GL_SUN_vertex 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat); +GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *, const GLfloat *); +GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *, const GLfloat *); +GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *, const GLubyte *, const GLfloat *); +GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *, const GLfloat *); +GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *, const GLubyte *, const GLfloat *); +GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +#endif + +#ifndef GL_EXT_blend_func_separate +#define GL_EXT_blend_func_separate 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum, GLenum, GLenum, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#endif + +#ifndef GL_INGR_blend_func_separate +#define GL_INGR_blend_func_separate 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum, GLenum, GLenum, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#endif + +#ifndef GL_INGR_color_clamp +#define GL_INGR_color_clamp 1 +#endif + +#ifndef GL_INGR_interlace_read +#define GL_INGR_interlace_read 1 +#endif + +#ifndef GL_EXT_stencil_wrap +#define GL_EXT_stencil_wrap 1 +#endif + +#ifndef GL_EXT_422_pixels +#define GL_EXT_422_pixels 1 +#endif + +#ifndef GL_NV_texgen_reflection +#define GL_NV_texgen_reflection 1 +#endif + +#ifndef GL_SUN_convolution_border_modes +#define GL_SUN_convolution_border_modes 1 +#endif + +#ifndef GL_EXT_texture_env_add +#define GL_EXT_texture_env_add 1 +#endif + +#ifndef GL_EXT_texture_lod_bias +#define GL_EXT_texture_lod_bias 1 +#endif + +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +#endif + +#ifndef GL_EXT_vertex_weighting +#define GL_EXT_vertex_weighting 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexWeightfEXT (GLfloat); +GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *); +GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei, GLenum, GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); +#endif + +#ifndef GL_NV_light_max_exponent +#define GL_NV_light_max_exponent 1 +#endif + +#ifndef GL_NV_vertex_array_range +#define GL_NV_vertex_array_range 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); +GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer); +#endif + +#ifndef GL_NV_register_combiners +#define GL_NV_register_combiners 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCombinerParameterfvNV (GLenum, const GLfloat *); +GLAPI void APIENTRY glCombinerParameterfNV (GLenum, GLfloat); +GLAPI void APIENTRY glCombinerParameterivNV (GLenum, const GLint *); +GLAPI void APIENTRY glCombinerParameteriNV (GLenum, GLint); +GLAPI void APIENTRY glCombinerInputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum); +GLAPI void APIENTRY glCombinerOutputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean); +GLAPI void APIENTRY glFinalCombinerInputNV (GLenum, GLenum, GLenum, GLenum); +GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum, GLenum, GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum, GLenum, GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum, GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum, GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum, GLenum, GLint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); +#endif + +#ifndef GL_NV_fog_distance +#define GL_NV_fog_distance 1 +#endif + +#ifndef GL_NV_texgen_emboss +#define GL_NV_texgen_emboss 1 +#endif + +#ifndef GL_NV_blend_square +#define GL_NV_blend_square 1 +#endif + +#ifndef GL_NV_texture_env_combine4 +#define GL_NV_texture_env_combine4 1 +#endif + +#ifndef GL_MESA_resize_buffers +#define GL_MESA_resize_buffers 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glResizeBuffersMESA (void); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); +#endif + +#ifndef GL_MESA_window_pos +#define GL_MESA_window_pos 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWindowPos2dMESA (GLdouble, GLdouble); +GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *); +GLAPI void APIENTRY glWindowPos2fMESA (GLfloat, GLfloat); +GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *); +GLAPI void APIENTRY glWindowPos2iMESA (GLint, GLint); +GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *); +GLAPI void APIENTRY glWindowPos2sMESA (GLshort, GLshort); +GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *); +GLAPI void APIENTRY glWindowPos3dMESA (GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *); +GLAPI void APIENTRY glWindowPos3fMESA (GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *); +GLAPI void APIENTRY glWindowPos3iMESA (GLint, GLint, GLint); +GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *); +GLAPI void APIENTRY glWindowPos3sMESA (GLshort, GLshort, GLshort); +GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *); +GLAPI void APIENTRY glWindowPos4dMESA (GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *); +GLAPI void APIENTRY glWindowPos4fMESA (GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *); +GLAPI void APIENTRY glWindowPos4iMESA (GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *); +GLAPI void APIENTRY glWindowPos4sMESA (GLshort, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); +#endif + +#ifndef GL_IBM_cull_vertex +#define GL_IBM_cull_vertex 1 +#endif + +#ifndef GL_IBM_multimode_draw_arrays +#define GL_IBM_multimode_draw_arrays 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *, const GLint *, const GLsizei *, GLsizei, GLint); +GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *, const GLsizei *, GLenum, const GLvoid* const *, GLsizei, GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); +typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); +#endif + +#ifndef GL_IBM_vertex_array_lists +#define GL_IBM_vertex_array_lists 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); +GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); +GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint, const GLboolean* *, GLint); +GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); +GLAPI void APIENTRY glIndexPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); +GLAPI void APIENTRY glNormalPointerListIBM (GLenum, GLint, const GLvoid* *, GLint); +GLAPI void APIENTRY glTexCoordPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); +GLAPI void APIENTRY glVertexPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); +#endif + +#ifndef GL_SGIX_subsample +#define GL_SGIX_subsample 1 +#endif + +#ifndef GL_SGIX_ycrcba +#define GL_SGIX_ycrcba 1 +#endif + +#ifndef GL_SGIX_ycrcb_subsample +#define GL_SGIX_ycrcb_subsample 1 +#endif + +#ifndef GL_SGIX_depth_pass_instrument +#define GL_SGIX_depth_pass_instrument 1 +#endif + +#ifndef GL_3DFX_texture_compression_FXT1 +#define GL_3DFX_texture_compression_FXT1 1 +#endif + +#ifndef GL_3DFX_multisample +#define GL_3DFX_multisample 1 +#endif + +#ifndef GL_3DFX_tbuffer +#define GL_3DFX_tbuffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTbufferMask3DFX (GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); +#endif + +#ifndef GL_EXT_multisample +#define GL_EXT_multisample 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleMaskEXT (GLclampf, GLboolean); +GLAPI void APIENTRY glSamplePatternEXT (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); +#endif + +#ifndef GL_SGIX_vertex_preclip +#define GL_SGIX_vertex_preclip 1 +#endif + +#ifndef GL_SGIX_convolution_accuracy +#define GL_SGIX_convolution_accuracy 1 +#endif + +#ifndef GL_SGIX_resample +#define GL_SGIX_resample 1 +#endif + +#ifndef GL_SGIS_point_line_texgen +#define GL_SGIS_point_line_texgen 1 +#endif + +#ifndef GL_SGIS_texture_color_mask +#define GL_SGIS_texture_color_mask 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean, GLboolean, GLboolean, GLboolean); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +#endif + +#ifndef GL_SGIX_igloo_interface +#define GL_SGIX_igloo_interface 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params); +#endif + +#ifndef GL_EXT_texture_env_dot3 +#define GL_EXT_texture_env_dot3 1 +#endif + +#ifndef GL_ATI_texture_mirror_once +#define GL_ATI_texture_mirror_once 1 +#endif + +#ifndef GL_NV_fence +#define GL_NV_fence 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteFencesNV (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenFencesNV (GLsizei, GLuint *); +GLAPI GLboolean APIENTRY glIsFenceNV (GLuint); +GLAPI GLboolean APIENTRY glTestFenceNV (GLuint); +GLAPI void APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glFinishFenceNV (GLuint); +GLAPI void APIENTRY glSetFenceNV (GLuint, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); +typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); +typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); +#endif + +#ifndef GL_NV_evaluators +#define GL_NV_evaluators 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *); +GLAPI void APIENTRY glMapParameterivNV (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glMapParameterfvNV (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glGetMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *); +GLAPI void APIENTRY glGetMapParameterivNV (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetMapParameterfvNV (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum, GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum, GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glEvalMapsNV (GLenum, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); +typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); +typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); +#endif + +#ifndef GL_NV_packed_depth_stencil +#define GL_NV_packed_depth_stencil 1 +#endif + +#ifndef GL_NV_register_combiners2 +#define GL_NV_register_combiners2 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum, GLenum, const GLfloat *); +GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum, GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); +#endif + +#ifndef GL_NV_texture_compression_vtc +#define GL_NV_texture_compression_vtc 1 +#endif + +#ifndef GL_NV_texture_rectangle +#define GL_NV_texture_rectangle 1 +#endif + +#ifndef GL_NV_texture_shader +#define GL_NV_texture_shader 1 +#endif + +#ifndef GL_NV_texture_shader2 +#define GL_NV_texture_shader2 1 +#endif + +#ifndef GL_NV_vertex_array_range2 +#define GL_NV_vertex_array_range2 1 +#endif + +#ifndef GL_NV_vertex_program +#define GL_NV_vertex_program 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei, const GLuint *, GLboolean *); +GLAPI void APIENTRY glBindProgramNV (GLenum, GLuint); +GLAPI void APIENTRY glDeleteProgramsNV (GLsizei, const GLuint *); +GLAPI void APIENTRY glExecuteProgramNV (GLenum, GLuint, const GLfloat *); +GLAPI void APIENTRY glGenProgramsNV (GLsizei, GLuint *); +GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum, GLuint, GLenum, GLdouble *); +GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum, GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetProgramivNV (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetProgramStringNV (GLuint, GLenum, GLubyte *); +GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum, GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint, GLenum, GLdouble *); +GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetVertexAttribivNV (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint, GLenum, GLvoid* *); +GLAPI GLboolean APIENTRY glIsProgramNV (GLuint); +GLAPI void APIENTRY glLoadProgramNV (GLenum, GLuint, GLsizei, const GLubyte *); +GLAPI void APIENTRY glProgramParameter4dNV (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glProgramParameter4dvNV (GLenum, GLuint, const GLdouble *); +GLAPI void APIENTRY glProgramParameter4fNV (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glProgramParameter4fvNV (GLenum, GLuint, const GLfloat *); +GLAPI void APIENTRY glProgramParameters4dvNV (GLenum, GLuint, GLuint, const GLdouble *); +GLAPI void APIENTRY glProgramParameters4fvNV (GLenum, GLuint, GLuint, const GLfloat *); +GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei, const GLuint *); +GLAPI void APIENTRY glTrackMatrixNV (GLenum, GLuint, GLenum, GLenum); +GLAPI void APIENTRY glVertexAttribPointerNV (GLuint, GLint, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glVertexAttrib1dNV (GLuint, GLdouble); +GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib1fNV (GLuint, GLfloat); +GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib1sNV (GLuint, GLshort); +GLAPI void APIENTRY glVertexAttrib1svNV (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib2dNV (GLuint, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib2fNV (GLuint, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib2sNV (GLuint, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib2svNV (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib3dNV (GLuint, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib3fNV (GLuint, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib3sNV (GLuint, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib3svNV (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib4dNV (GLuint, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint, const GLdouble *); +GLAPI void APIENTRY glVertexAttrib4fNV (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint, const GLfloat *); +GLAPI void APIENTRY glVertexAttrib4sNV (GLuint, GLshort, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glVertexAttrib4svNV (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint, GLubyte, GLubyte, GLubyte, GLubyte); +GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint, const GLubyte *); +GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint, GLsizei, const GLdouble *); +GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glVertexAttribs1svNV (GLuint, GLsizei, const GLshort *); +GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint, GLsizei, const GLdouble *); +GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glVertexAttribs2svNV (GLuint, GLsizei, const GLshort *); +GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint, GLsizei, const GLdouble *); +GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glVertexAttribs3svNV (GLuint, GLsizei, const GLshort *); +GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint, GLsizei, const GLdouble *); +GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glVertexAttribs4svNV (GLuint, GLsizei, const GLshort *); +GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint, GLsizei, const GLubyte *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); +typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); +typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); +typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); +typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLuint count, const GLdouble *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLuint count, const GLfloat *v); +typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); +#endif + +#ifndef GL_SGIX_texture_coordinate_clamp +#define GL_SGIX_texture_coordinate_clamp 1 +#endif + +#ifndef GL_SGIX_scalebias_hint +#define GL_SGIX_scalebias_hint 1 +#endif + +#ifndef GL_OML_interlace +#define GL_OML_interlace 1 +#endif + +#ifndef GL_OML_subsample +#define GL_OML_subsample 1 +#endif + +#ifndef GL_OML_resample +#define GL_OML_resample 1 +#endif + +#ifndef GL_NV_copy_depth_to_color +#define GL_NV_copy_depth_to_color 1 +#endif + +#ifndef GL_ATI_envmap_bumpmap +#define GL_ATI_envmap_bumpmap 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBumpParameterivATI (GLenum, const GLint *); +GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum, const GLfloat *); +GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum, GLint *); +GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); +#endif + +#ifndef GL_ATI_fragment_shader +#define GL_ATI_fragment_shader 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint); +GLAPI void APIENTRY glBindFragmentShaderATI (GLuint); +GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint); +GLAPI void APIENTRY glBeginFragmentShaderATI (void); +GLAPI void APIENTRY glEndFragmentShaderATI (void); +GLAPI void APIENTRY glPassTexCoordATI (GLuint, GLuint, GLenum); +GLAPI void APIENTRY glSampleMapATI (GLuint, GLuint, GLenum); +GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); +typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); +typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); +typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); +typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); +typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); +#endif + +#ifndef GL_ATI_pn_triangles +#define GL_ATI_pn_triangles 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPNTrianglesiATI (GLenum, GLint); +GLAPI void APIENTRY glPNTrianglesfATI (GLenum, GLfloat); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); +#endif + +#ifndef GL_ATI_vertex_array_object +#define GL_ATI_vertex_array_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei, const GLvoid *, GLenum); +GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint); +GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint, GLuint, GLsizei, const GLvoid *, GLenum); +GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetObjectBufferivATI (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glFreeObjectBufferATI (GLuint); +GLAPI void APIENTRY glArrayObjectATI (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint); +GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum, GLenum, GLfloat *); +GLAPI void APIENTRY glGetArrayObjectivATI (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glVariantArrayObjectATI (GLuint, GLenum, GLsizei, GLuint, GLuint); +GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint, GLenum, GLint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); +typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); +#endif + +#ifndef GL_EXT_vertex_shader +#define GL_EXT_vertex_shader 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginVertexShaderEXT (void); +GLAPI void APIENTRY glEndVertexShaderEXT (void); +GLAPI void APIENTRY glBindVertexShaderEXT (GLuint); +GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint); +GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint); +GLAPI void APIENTRY glShaderOp1EXT (GLenum, GLuint, GLuint); +GLAPI void APIENTRY glShaderOp2EXT (GLenum, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glShaderOp3EXT (GLenum, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glSwizzleEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum); +GLAPI void APIENTRY glWriteMaskEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum); +GLAPI void APIENTRY glInsertComponentEXT (GLuint, GLuint, GLuint); +GLAPI void APIENTRY glExtractComponentEXT (GLuint, GLuint, GLuint); +GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum, GLenum, GLenum, GLuint); +GLAPI void APIENTRY glSetInvariantEXT (GLuint, GLenum, const GLvoid *); +GLAPI void APIENTRY glSetLocalConstantEXT (GLuint, GLenum, const GLvoid *); +GLAPI void APIENTRY glVariantbvEXT (GLuint, const GLbyte *); +GLAPI void APIENTRY glVariantsvEXT (GLuint, const GLshort *); +GLAPI void APIENTRY glVariantivEXT (GLuint, const GLint *); +GLAPI void APIENTRY glVariantfvEXT (GLuint, const GLfloat *); +GLAPI void APIENTRY glVariantdvEXT (GLuint, const GLdouble *); +GLAPI void APIENTRY glVariantubvEXT (GLuint, const GLubyte *); +GLAPI void APIENTRY glVariantusvEXT (GLuint, const GLushort *); +GLAPI void APIENTRY glVariantuivEXT (GLuint, const GLuint *); +GLAPI void APIENTRY glVariantPointerEXT (GLuint, GLenum, GLuint, const GLvoid *); +GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint); +GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint); +GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum, GLenum); +GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum, GLenum); +GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum, GLenum, GLenum); +GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum, GLenum); +GLAPI GLuint APIENTRY glBindParameterEXT (GLenum); +GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint, GLenum); +GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint, GLenum, GLboolean *); +GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetVariantPointervEXT (GLuint, GLenum, GLvoid* *); +GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint, GLenum, GLboolean *); +GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint, GLenum, GLboolean *); +GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint, GLenum, GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); +typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); +typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); +typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); +typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); +typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); +typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); +typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); +typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); +typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); +typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); +typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); +typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); +typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); +typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); +typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); +typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); +typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); +typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); +typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); +typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); +typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); +typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); +typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); +typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); +typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); +typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data); +typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +#endif + +#ifndef GL_ATI_vertex_streams +#define GL_ATI_vertex_streams 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexStream1sATI (GLenum, GLshort); +GLAPI void APIENTRY glVertexStream1svATI (GLenum, const GLshort *); +GLAPI void APIENTRY glVertexStream1iATI (GLenum, GLint); +GLAPI void APIENTRY glVertexStream1ivATI (GLenum, const GLint *); +GLAPI void APIENTRY glVertexStream1fATI (GLenum, GLfloat); +GLAPI void APIENTRY glVertexStream1fvATI (GLenum, const GLfloat *); +GLAPI void APIENTRY glVertexStream1dATI (GLenum, GLdouble); +GLAPI void APIENTRY glVertexStream1dvATI (GLenum, const GLdouble *); +GLAPI void APIENTRY glVertexStream2sATI (GLenum, GLshort, GLshort); +GLAPI void APIENTRY glVertexStream2svATI (GLenum, const GLshort *); +GLAPI void APIENTRY glVertexStream2iATI (GLenum, GLint, GLint); +GLAPI void APIENTRY glVertexStream2ivATI (GLenum, const GLint *); +GLAPI void APIENTRY glVertexStream2fATI (GLenum, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexStream2fvATI (GLenum, const GLfloat *); +GLAPI void APIENTRY glVertexStream2dATI (GLenum, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexStream2dvATI (GLenum, const GLdouble *); +GLAPI void APIENTRY glVertexStream3sATI (GLenum, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glVertexStream3svATI (GLenum, const GLshort *); +GLAPI void APIENTRY glVertexStream3iATI (GLenum, GLint, GLint, GLint); +GLAPI void APIENTRY glVertexStream3ivATI (GLenum, const GLint *); +GLAPI void APIENTRY glVertexStream3fATI (GLenum, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexStream3fvATI (GLenum, const GLfloat *); +GLAPI void APIENTRY glVertexStream3dATI (GLenum, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexStream3dvATI (GLenum, const GLdouble *); +GLAPI void APIENTRY glVertexStream4sATI (GLenum, GLshort, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glVertexStream4svATI (GLenum, const GLshort *); +GLAPI void APIENTRY glVertexStream4iATI (GLenum, GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glVertexStream4ivATI (GLenum, const GLint *); +GLAPI void APIENTRY glVertexStream4fATI (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glVertexStream4fvATI (GLenum, const GLfloat *); +GLAPI void APIENTRY glVertexStream4dATI (GLenum, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glVertexStream4dvATI (GLenum, const GLdouble *); +GLAPI void APIENTRY glNormalStream3bATI (GLenum, GLbyte, GLbyte, GLbyte); +GLAPI void APIENTRY glNormalStream3bvATI (GLenum, const GLbyte *); +GLAPI void APIENTRY glNormalStream3sATI (GLenum, GLshort, GLshort, GLshort); +GLAPI void APIENTRY glNormalStream3svATI (GLenum, const GLshort *); +GLAPI void APIENTRY glNormalStream3iATI (GLenum, GLint, GLint, GLint); +GLAPI void APIENTRY glNormalStream3ivATI (GLenum, const GLint *); +GLAPI void APIENTRY glNormalStream3fATI (GLenum, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glNormalStream3fvATI (GLenum, const GLfloat *); +GLAPI void APIENTRY glNormalStream3dATI (GLenum, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glNormalStream3dvATI (GLenum, const GLdouble *); +GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum); +GLAPI void APIENTRY glVertexBlendEnviATI (GLenum, GLint); +GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum, GLfloat); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); +typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); +#endif + +#ifndef GL_ATI_element_array +#define GL_ATI_element_array 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glElementPointerATI (GLenum, const GLvoid *); +GLAPI void APIENTRY glDrawElementArrayATI (GLenum, GLsizei); +GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum, GLuint, GLuint, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); +#endif + +#ifndef GL_SUN_mesh_array +#define GL_SUN_mesh_array 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum, GLint, GLsizei, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); +#endif + +#ifndef GL_SUN_slice_accum +#define GL_SUN_slice_accum 1 +#endif + +#ifndef GL_NV_multisample_filter_hint +#define GL_NV_multisample_filter_hint 1 +#endif + +#ifndef GL_NV_depth_clamp +#define GL_NV_depth_clamp 1 +#endif + +#ifndef GL_NV_occlusion_query +#define GL_NV_occlusion_query 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei, GLuint *); +GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei, const GLuint *); +GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint); +GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint); +GLAPI void APIENTRY glEndOcclusionQueryNV (void); +GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint, GLenum, GLuint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); +typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); +#endif + +#ifndef GL_NV_point_sprite +#define GL_NV_point_sprite 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameteriNV (GLenum, GLint); +GLAPI void APIENTRY glPointParameterivNV (GLenum, const GLint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +#endif + +#ifndef GL_NV_texture_shader3 +#define GL_NV_texture_shader3 1 +#endif + +#ifndef GL_NV_vertex_program1_1 +#define GL_NV_vertex_program1_1 1 +#endif + +#ifndef GL_EXT_shadow_funcs +#define GL_EXT_shadow_funcs 1 +#endif + +#ifndef GL_EXT_stencil_two_side +#define GL_EXT_stencil_two_side 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); +#endif + +#ifndef GL_ATI_text_fragment_shader +#define GL_ATI_text_fragment_shader 1 +#endif + +#ifndef GL_APPLE_client_storage +#define GL_APPLE_client_storage 1 +#endif + +#ifndef GL_APPLE_element_array +#define GL_APPLE_element_array 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glElementPointerAPPLE (GLenum, const GLvoid *); +GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum, GLint, GLsizei); +GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, GLint, GLsizei); +GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum, const GLint *, const GLsizei *, GLsizei); +GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); +#endif + +#ifndef GL_APPLE_fence +#define GL_APPLE_fence 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenFencesAPPLE (GLsizei, GLuint *); +GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei, const GLuint *); +GLAPI void APIENTRY glSetFenceAPPLE (GLuint); +GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint); +GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint); +GLAPI void APIENTRY glFinishFenceAPPLE (GLuint); +GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum, GLuint); +GLAPI void APIENTRY glFinishObjectAPPLE (GLenum, GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); +typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); +typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); +typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); +#endif + +#ifndef GL_APPLE_vertex_array_object +#define GL_APPLE_vertex_array_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint); +GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, GLuint *); +GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); +#endif + +#ifndef GL_APPLE_vertex_array_range +#define GL_APPLE_vertex_array_range 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei, GLvoid *); +GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei, GLvoid *); +GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum, GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); +#endif + +#ifndef GL_APPLE_ycbcr_422 +#define GL_APPLE_ycbcr_422 1 +#endif + +#ifndef GL_S3_s3tc +#define GL_S3_s3tc 1 +#endif + +#ifndef GL_ATI_draw_buffers +#define GL_ATI_draw_buffers 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawBuffersATI (GLsizei, const GLenum *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); +#endif + +#ifndef GL_ATI_pixel_format_float +#define GL_ATI_pixel_format_float 1 +/* This is really a WGL extension, but defines some associated GL enums. + * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string. + */ +#endif + +#ifndef GL_ATI_texture_env_combine3 +#define GL_ATI_texture_env_combine3 1 +#endif + +#ifndef GL_ATI_texture_float +#define GL_ATI_texture_float 1 +#endif + +#ifndef GL_NV_float_buffer +#define GL_NV_float_buffer 1 +#endif + +#ifndef GL_NV_fragment_program +#define GL_NV_fragment_program 1 +/* Some NV_fragment_program entry points are shared with ARB_vertex_program. */ +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint, GLsizei, const GLubyte *, const GLfloat *); +GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint, GLsizei, const GLubyte *, const GLdouble *); +GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint, GLsizei, const GLubyte *, GLfloat *); +GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint, GLsizei, const GLubyte *, GLdouble *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); +typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); +#endif + +#ifndef GL_NV_half_float +#define GL_NV_half_float 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertex2hNV (GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *); +GLAPI void APIENTRY glVertex3hNV (GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *); +GLAPI void APIENTRY glVertex4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *); +GLAPI void APIENTRY glNormal3hNV (GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *); +GLAPI void APIENTRY glColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *); +GLAPI void APIENTRY glColor4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *); +GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV); +GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *); +GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *); +GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *); +GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *); +GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum, GLhalfNV); +GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum, const GLhalfNV *); +GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum, const GLhalfNV *); +GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum, const GLhalfNV *); +GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum, const GLhalfNV *); +GLAPI void APIENTRY glFogCoordhNV (GLhalfNV); +GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *); +GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *); +GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV); +GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *); +GLAPI void APIENTRY glVertexAttrib1hNV (GLuint, GLhalfNV); +GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint, const GLhalfNV *); +GLAPI void APIENTRY glVertexAttrib2hNV (GLuint, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint, const GLhalfNV *); +GLAPI void APIENTRY glVertexAttrib3hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint, const GLhalfNV *); +GLAPI void APIENTRY glVertexAttrib4hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV); +GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint, const GLhalfNV *); +GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint, GLsizei, const GLhalfNV *); +GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint, GLsizei, const GLhalfNV *); +GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint, GLsizei, const GLhalfNV *); +GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint, GLsizei, const GLhalfNV *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); +typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); +typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); +typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); +typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); +typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); +typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); +typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); +typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +#endif + +#ifndef GL_NV_pixel_data_range +#define GL_NV_pixel_data_range 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelDataRangeNV (GLenum, GLsizei, GLvoid *); +GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer); +typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); +#endif + +#ifndef GL_NV_primitive_restart +#define GL_NV_primitive_restart 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPrimitiveRestartNV (void); +GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); +#endif + +#ifndef GL_NV_texture_expand_normal +#define GL_NV_texture_expand_normal 1 +#endif + +#ifndef GL_NV_vertex_program2 +#define GL_NV_vertex_program2 1 +#endif + +#ifndef GL_ATI_map_object_buffer +#define GL_ATI_map_object_buffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint); +GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); +#endif + +#ifndef GL_ATI_separate_stencil +#define GL_ATI_separate_stencil 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilOpSeparateATI (GLenum, GLenum, GLenum, GLenum); +GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum, GLenum, GLint, GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); +#endif + +#ifndef GL_ATI_vertex_attrib_array_object +#define GL_ATI_vertex_attrib_array_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint); +GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint, GLenum, GLfloat *); +GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint, GLenum, GLint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); +#endif + +#ifndef GL_OES_read_format +#define GL_OES_read_format 1 +#endif + +#ifndef GL_EXT_depth_bounds_test +#define GL_EXT_depth_bounds_test 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDepthBoundsEXT (GLclampd, GLclampd); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); +#endif + +#ifndef GL_EXT_texture_mirror_clamp +#define GL_EXT_texture_mirror_clamp 1 +#endif + +#ifndef GL_EXT_blend_equation_separate +#define GL_EXT_blend_equation_separate 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); +#endif + +#ifndef GL_MESA_pack_invert +#define GL_MESA_pack_invert 1 +#endif + +#ifndef GL_MESA_ycbcr_texture +#define GL_MESA_ycbcr_texture 1 +#endif + +#ifndef GL_EXT_pixel_buffer_object +#define GL_EXT_pixel_buffer_object 1 +#endif + +#ifndef GL_NV_fragment_program_option +#define GL_NV_fragment_program_option 1 +#endif + +#ifndef GL_NV_fragment_program2 +#define GL_NV_fragment_program2 1 +#endif + +#ifndef GL_NV_vertex_program2_option +#define GL_NV_vertex_program2_option 1 +#endif + +#ifndef GL_NV_vertex_program3 +#define GL_NV_vertex_program3 1 +#endif + +#ifndef GL_EXT_framebuffer_object +#define GL_EXT_framebuffer_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint); +GLAPI void APIENTRY glBindRenderbufferEXT (GLenum, GLuint); +GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *); +GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei); +GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum, GLenum, GLint *); +GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint); +GLAPI void APIENTRY glBindFramebufferEXT (GLenum, GLuint); +GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *); +GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum); +GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum, GLenum, GLenum, GLuint, GLint); +GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint); +GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLint); +GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint); +GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum, GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGenerateMipmapEXT (GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); +#endif + +#ifndef GL_GREMEDY_string_marker +#define GL_GREMEDY_string_marker 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei, const GLvoid *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); +#endif + +#ifndef GL_EXT_packed_depth_stencil +#define GL_EXT_packed_depth_stencil 1 +#endif + +#ifndef GL_EXT_stencil_clear_tag +#define GL_EXT_stencil_clear_tag 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilClearTagEXT (GLsizei, GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); +#endif + +#ifndef GL_EXT_texture_sRGB +#define GL_EXT_texture_sRGB 1 +#endif + +#ifndef GL_EXT_framebuffer_blit +#define GL_EXT_framebuffer_blit 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlitFramebufferEXT (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif + +#ifndef GL_EXT_framebuffer_multisample +#define GL_EXT_framebuffer_multisample 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#endif + +#ifndef GL_MESAX_texture_stack +#define GL_MESAX_texture_stack 1 +#endif + +#ifndef GL_EXT_timer_query +#define GL_EXT_timer_query 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint, GLenum, GLint64EXT *); +GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint, GLenum, GLuint64EXT *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64EXT *params); +#endif + +#ifndef GL_EXT_gpu_program_parameters +#define GL_EXT_gpu_program_parameters 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum, GLuint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum, GLuint, GLsizei, const GLfloat *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +#endif + +#ifndef GL_APPLE_flush_buffer_range +#define GL_APPLE_flush_buffer_range 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum, GLenum, GLint); +GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum, GLintptr, GLsizeiptr); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); +#endif + +#ifndef GL_NV_gpu_program4 +#define GL_NV_gpu_program4 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum, GLuint, GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum, GLuint, const GLint *); +GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum, GLuint, GLsizei, const GLint *); +GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum, GLuint, const GLuint *); +GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum, GLuint, GLsizei, const GLuint *); +GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum, GLuint, GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum, GLuint, const GLint *); +GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum, GLuint, GLsizei, const GLint *); +GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum, GLuint, const GLuint *); +GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum, GLuint, GLsizei, const GLuint *); +GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum, GLuint, GLint *); +GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum, GLuint, GLuint *); +GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum, GLuint, GLint *); +GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum, GLuint, GLuint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); +#endif + +#ifndef GL_NV_geometry_program4 +#define GL_NV_geometry_program4 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramVertexLimitNV (GLenum, GLint); +GLAPI void APIENTRY glFramebufferTextureEXT (GLenum, GLenum, GLuint, GLint); +GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum, GLenum, GLuint, GLint, GLint); +GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum, GLenum, GLuint, GLint, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#endif + +#ifndef GL_EXT_geometry_shader4 +#define GL_EXT_geometry_shader4 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramParameteriEXT (GLuint, GLenum, GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); +#endif + +#ifndef GL_NV_vertex_program4 +#define GL_NV_vertex_program4 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint, GLint); +GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint, GLint, GLint); +GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint, GLint, GLint, GLint); +GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint, GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint, GLuint); +GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint, GLuint, GLuint); +GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint, const GLint *); +GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint, const GLint *); +GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint, const GLint *); +GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint, const GLint *); +GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint, const GLuint *); +GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint, const GLuint *); +GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint, const GLuint *); +GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint, const GLuint *); +GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint, const GLbyte *); +GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint, const GLshort *); +GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint, const GLubyte *); +GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint, const GLushort *); +GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint, GLint, GLenum, GLsizei, const GLvoid *); +GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint, GLenum, GLint *); +GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint, GLenum, GLuint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); +#endif + +#ifndef GL_EXT_gpu_shader4 +#define GL_EXT_gpu_shader4 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetUniformuivEXT (GLuint, GLint, GLuint *); +GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint, GLuint, const GLchar *); +GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint, const GLchar *); +GLAPI void APIENTRY glUniform1uiEXT (GLint, GLuint); +GLAPI void APIENTRY glUniform2uiEXT (GLint, GLuint, GLuint); +GLAPI void APIENTRY glUniform3uiEXT (GLint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glUniform4uiEXT (GLint, GLuint, GLuint, GLuint, GLuint); +GLAPI void APIENTRY glUniform1uivEXT (GLint, GLsizei, const GLuint *); +GLAPI void APIENTRY glUniform2uivEXT (GLint, GLsizei, const GLuint *); +GLAPI void APIENTRY glUniform3uivEXT (GLint, GLsizei, const GLuint *); +GLAPI void APIENTRY glUniform4uivEXT (GLint, GLsizei, const GLuint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +#endif + +#ifndef GL_EXT_draw_instanced +#define GL_EXT_draw_instanced 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum, GLint, GLsizei, GLsizei); +GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum, GLsizei, GLenum, const GLvoid *, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +#endif + +#ifndef GL_EXT_packed_float +#define GL_EXT_packed_float 1 +#endif + +#ifndef GL_EXT_texture_array +#define GL_EXT_texture_array 1 +#endif + +#ifndef GL_EXT_texture_buffer_object +#define GL_EXT_texture_buffer_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBufferEXT (GLenum, GLenum, GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); +#endif + +#ifndef GL_EXT_texture_compression_latc +#define GL_EXT_texture_compression_latc 1 +#endif + +#ifndef GL_EXT_texture_compression_rgtc +#define GL_EXT_texture_compression_rgtc 1 +#endif + +#ifndef GL_EXT_texture_shared_exponent +#define GL_EXT_texture_shared_exponent 1 +#endif + +#ifndef GL_NV_depth_buffer_float +#define GL_NV_depth_buffer_float 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDepthRangedNV (GLdouble, GLdouble); +GLAPI void APIENTRY glClearDepthdNV (GLdouble); +GLAPI void APIENTRY glDepthBoundsdNV (GLdouble, GLdouble); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); +typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); +#endif + +#ifndef GL_NV_fragment_program4 +#define GL_NV_fragment_program4 1 +#endif + +#ifndef GL_NV_framebuffer_multisample_coverage +#define GL_NV_framebuffer_multisample_coverage 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum, GLsizei, GLsizei, GLenum, GLsizei, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +#endif + +#ifndef GL_EXT_framebuffer_sRGB +#define GL_EXT_framebuffer_sRGB 1 +#endif + +#ifndef GL_NV_geometry_shader4 +#define GL_NV_geometry_shader4 1 +#endif + +#ifndef GL_NV_parameter_buffer_object +#define GL_NV_parameter_buffer_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum, GLuint, GLuint, GLsizei, const GLfloat *); +GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum, GLuint, GLuint, GLsizei, const GLint *); +GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum, GLuint, GLuint, GLsizei, const GLuint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params); +#endif + +#ifndef GL_EXT_draw_buffers2 +#define GL_EXT_draw_buffers2 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint, GLboolean, GLboolean, GLboolean, GLboolean); +GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum, GLuint, GLboolean *); +GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum, GLuint, GLint *); +GLAPI void APIENTRY glEnableIndexedEXT (GLenum, GLuint); +GLAPI void APIENTRY glDisableIndexedEXT (GLenum, GLuint); +GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum, GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); +#endif + +#ifndef GL_NV_transform_feedback +#define GL_NV_transform_feedback 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum); +GLAPI void APIENTRY glEndTransformFeedbackNV (void); +GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint, const GLint *, GLenum); +GLAPI void APIENTRY glBindBufferRangeNV (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr); +GLAPI void APIENTRY glBindBufferOffsetNV (GLenum, GLuint, GLuint, GLintptr); +GLAPI void APIENTRY glBindBufferBaseNV (GLenum, GLuint, GLuint); +GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint, GLsizei, const GLint *, GLenum); +GLAPI void APIENTRY glActiveVaryingNV (GLuint, const GLchar *); +GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint, const GLchar *); +GLAPI void APIENTRY glGetActiveVaryingNV (GLuint, GLuint, GLsizei, GLsizei *, GLsizei *, GLenum *, GLchar *); +GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint, GLuint, GLint *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); +typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); +#endif + +#ifndef GL_EXT_bindable_uniform +#define GL_EXT_bindable_uniform 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformBufferEXT (GLuint, GLint, GLuint); +GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint, GLint); +GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint, GLint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); +typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); +typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); +#endif + +#ifndef GL_EXT_texture_integer +#define GL_EXT_texture_integer 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexParameterIivEXT (GLenum, GLenum, const GLint *); +GLAPI void APIENTRY glTexParameterIuivEXT (GLenum, GLenum, const GLuint *); +GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum, GLenum, GLint *); +GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum, GLenum, GLuint *); +GLAPI void APIENTRY glClearColorIiEXT (GLint, GLint, GLint, GLint); +GLAPI void APIENTRY glClearColorIuiEXT (GLuint, GLuint, GLuint, GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); +typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/j3d-core/src/native/ogl/j3dsys.h b/j3d-core/src/native/ogl/j3dsys.h new file mode 100644 index 0000000..526b140 --- /dev/null +++ b/j3d-core/src/native/ogl/j3dsys.h @@ -0,0 +1,45 @@ +/* + * $RCSfile: j3dsys.h,v $ + * + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision: 1.3 $ + * $Date: 2008/02/28 20:18:01 $ + * $State: Exp $ + */ + +#ifndef _j3dsys_h_ +#define _j3dsys_h_ + +// Suppress VS2005 compiler warning +#if defined(WIN32) +#define _CRT_SECURE_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif + +#if defined(LINUX) +#define _GNU_SOURCE 1 +#endif + +#endif /* _j3dsys_h_ */ diff --git a/j3d-core/src/native/ogl/panoramiXext.h b/j3d-core/src/native/ogl/panoramiXext.h new file mode 100644 index 0000000..0deac63 --- /dev/null +++ b/j3d-core/src/native/ogl/panoramiXext.h @@ -0,0 +1,90 @@ +/* $TOG: panoramiXext.h /main/3 1998/02/13 13:08:51 kaleb $ */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ +/* + * PanoramiX definitions + */ + +/* THIS IS NOT AN X PROJECT TEAM SPECIFICATION */ + +#define PANORAMIX_MAJOR_VERSION 1 /* current version number */ +#define PANORAMIX_MINOR_VERSION 0 + +typedef struct { + Window window; /* PanoramiX window - may not exist */ + int screen; + int State; /* PanroamiXOff, PanoramiXOn */ + int width; /* width of this screen */ + int height; /* height of this screen */ + int ScreenCount; /* real physical number of screens */ + XID eventMask; /* selected events for this client */ +} XPanoramiXInfo; + +extern XPanoramiXInfo *XPanoramiXAllocInfo ( +#if NeedFunctionPrototypes + void +#endif +); + +#define XINERAMA_PLACE_TOP 1 +#define XINERAMA_PLACE_BOTTOM 2 +#define XINERAMA_PLACE_RIGHT 4 +#define XINERAMA_PLACE_LEFT 8 + +#ifndef _XINERAMAINFO_ +#define _XINERAMAINFO_ + +#define XinID int +#define MAXSCREEN 16 +#define DELTA int +#define POINT int + +typedef struct subwid +{ + XinID wid; /* sub window id */ + DELTA dx,dy; /* delta in screen co-ord from virtual zero */ + POINT x,y; /* location of window in screen co-ord */ + DELTA wdx,wdy;/* size of window in screen co-ord */ +}SubWID, *pSubWID; + +typedef struct xineramainfo +{ + XinID wid; /* Window ID of requested virtual window */ + SubWID subs[MAXSCREEN]; /* there will be 16 slots */ +}XineramaInfo, *pXineramaInfo; +#endif + +#ifndef NO_PROTO_HERE +Bool XDgaGetXineramaInfo( +#if NeedFunctionPrototypes +/* this brakes the server +Display *, int, XID, XineramaInfo * +*/ +#endif +); +#endif diff --git a/j3d-core/src/native/ogl/wglext.h b/j3d-core/src/native/ogl/wglext.h new file mode 100644 index 0000000..18804be --- /dev/null +++ b/j3d-core/src/native/ogl/wglext.h @@ -0,0 +1,648 @@ +#ifndef __wglext_h_ +#define __wglext_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2007 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +/*************************************************************/ + +/* Header file version number */ +/* wglext.h last updated 2007/02/09 */ +/* Current version at http://www.opengl.org/registry/ */ +#define WGL_WGLEXT_VERSION 9 + +#ifndef WGL_ARB_buffer_region +#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 +#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 +#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 +#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 +#endif + +#ifndef WGL_ARB_multisample +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#endif + +#ifndef WGL_ARB_extensions_string +#endif + +#ifndef WGL_ARB_pixel_format +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +#endif + +#ifndef WGL_ARB_make_current_read +#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 +#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 +#endif + +#ifndef WGL_ARB_pbuffer +#define WGL_DRAW_TO_PBUFFER_ARB 0x202D +#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E +#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 +#define WGL_PBUFFER_LARGEST_ARB 0x2033 +#define WGL_PBUFFER_WIDTH_ARB 0x2034 +#define WGL_PBUFFER_HEIGHT_ARB 0x2035 +#define WGL_PBUFFER_LOST_ARB 0x2036 +#endif + +#ifndef WGL_ARB_render_texture +#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 +#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 +#define WGL_TEXTURE_FORMAT_ARB 0x2072 +#define WGL_TEXTURE_TARGET_ARB 0x2073 +#define WGL_MIPMAP_TEXTURE_ARB 0x2074 +#define WGL_TEXTURE_RGB_ARB 0x2075 +#define WGL_TEXTURE_RGBA_ARB 0x2076 +#define WGL_NO_TEXTURE_ARB 0x2077 +#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 +#define WGL_TEXTURE_1D_ARB 0x2079 +#define WGL_TEXTURE_2D_ARB 0x207A +#define WGL_MIPMAP_LEVEL_ARB 0x207B +#define WGL_CUBE_MAP_FACE_ARB 0x207C +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 +#define WGL_FRONT_LEFT_ARB 0x2083 +#define WGL_FRONT_RIGHT_ARB 0x2084 +#define WGL_BACK_LEFT_ARB 0x2085 +#define WGL_BACK_RIGHT_ARB 0x2086 +#define WGL_AUX0_ARB 0x2087 +#define WGL_AUX1_ARB 0x2088 +#define WGL_AUX2_ARB 0x2089 +#define WGL_AUX3_ARB 0x208A +#define WGL_AUX4_ARB 0x208B +#define WGL_AUX5_ARB 0x208C +#define WGL_AUX6_ARB 0x208D +#define WGL_AUX7_ARB 0x208E +#define WGL_AUX8_ARB 0x208F +#define WGL_AUX9_ARB 0x2090 +#endif + +#ifndef WGL_ARB_pixel_format_float +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 +#endif + +#ifndef WGL_EXT_make_current_read +#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 +#endif + +#ifndef WGL_EXT_pixel_format +#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 +#define WGL_DRAW_TO_WINDOW_EXT 0x2001 +#define WGL_DRAW_TO_BITMAP_EXT 0x2002 +#define WGL_ACCELERATION_EXT 0x2003 +#define WGL_NEED_PALETTE_EXT 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 +#define WGL_SWAP_METHOD_EXT 0x2007 +#define WGL_NUMBER_OVERLAYS_EXT 0x2008 +#define WGL_NUMBER_UNDERLAYS_EXT 0x2009 +#define WGL_TRANSPARENT_EXT 0x200A +#define WGL_TRANSPARENT_VALUE_EXT 0x200B +#define WGL_SHARE_DEPTH_EXT 0x200C +#define WGL_SHARE_STENCIL_EXT 0x200D +#define WGL_SHARE_ACCUM_EXT 0x200E +#define WGL_SUPPORT_GDI_EXT 0x200F +#define WGL_SUPPORT_OPENGL_EXT 0x2010 +#define WGL_DOUBLE_BUFFER_EXT 0x2011 +#define WGL_STEREO_EXT 0x2012 +#define WGL_PIXEL_TYPE_EXT 0x2013 +#define WGL_COLOR_BITS_EXT 0x2014 +#define WGL_RED_BITS_EXT 0x2015 +#define WGL_RED_SHIFT_EXT 0x2016 +#define WGL_GREEN_BITS_EXT 0x2017 +#define WGL_GREEN_SHIFT_EXT 0x2018 +#define WGL_BLUE_BITS_EXT 0x2019 +#define WGL_BLUE_SHIFT_EXT 0x201A +#define WGL_ALPHA_BITS_EXT 0x201B +#define WGL_ALPHA_SHIFT_EXT 0x201C +#define WGL_ACCUM_BITS_EXT 0x201D +#define WGL_ACCUM_RED_BITS_EXT 0x201E +#define WGL_ACCUM_GREEN_BITS_EXT 0x201F +#define WGL_ACCUM_BLUE_BITS_EXT 0x2020 +#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 +#define WGL_DEPTH_BITS_EXT 0x2022 +#define WGL_STENCIL_BITS_EXT 0x2023 +#define WGL_AUX_BUFFERS_EXT 0x2024 +#define WGL_NO_ACCELERATION_EXT 0x2025 +#define WGL_GENERIC_ACCELERATION_EXT 0x2026 +#define WGL_FULL_ACCELERATION_EXT 0x2027 +#define WGL_SWAP_EXCHANGE_EXT 0x2028 +#define WGL_SWAP_COPY_EXT 0x2029 +#define WGL_SWAP_UNDEFINED_EXT 0x202A +#define WGL_TYPE_RGBA_EXT 0x202B +#define WGL_TYPE_COLORINDEX_EXT 0x202C +#endif + +#ifndef WGL_EXT_pbuffer +#define WGL_DRAW_TO_PBUFFER_EXT 0x202D +#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E +#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 +#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 +#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 +#define WGL_PBUFFER_LARGEST_EXT 0x2033 +#define WGL_PBUFFER_WIDTH_EXT 0x2034 +#define WGL_PBUFFER_HEIGHT_EXT 0x2035 +#endif + +#ifndef WGL_EXT_depth_float +#define WGL_DEPTH_FLOAT_EXT 0x2040 +#endif + +#ifndef WGL_3DFX_multisample +#define WGL_SAMPLE_BUFFERS_3DFX 0x2060 +#define WGL_SAMPLES_3DFX 0x2061 +#endif + +#ifndef WGL_EXT_multisample +#define WGL_SAMPLE_BUFFERS_EXT 0x2041 +#define WGL_SAMPLES_EXT 0x2042 +#endif + +#ifndef WGL_I3D_digital_video_control +#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 +#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 +#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 +#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 +#endif + +#ifndef WGL_I3D_gamma +#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E +#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F +#endif + +#ifndef WGL_I3D_genlock +#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 +#define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045 +#define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046 +#define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047 +#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 +#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 +#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A +#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B +#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C +#endif + +#ifndef WGL_I3D_image_buffer +#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 +#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 +#endif + +#ifndef WGL_I3D_swap_frame_lock +#endif + +#ifndef WGL_NV_render_depth_texture +#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 +#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 +#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 +#define WGL_DEPTH_COMPONENT_NV 0x20A7 +#endif + +#ifndef WGL_NV_render_texture_rectangle +#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 +#define WGL_TEXTURE_RECTANGLE_NV 0x20A2 +#endif + +#ifndef WGL_ATI_pixel_format_float +#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 +#endif + +#ifndef WGL_NV_float_buffer +#define WGL_FLOAT_COMPONENTS_NV 0x20B0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 +#define WGL_TEXTURE_FLOAT_R_NV 0x20B5 +#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 +#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 +#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 +#endif + +#ifndef WGL_3DL_stereo_control +#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 +#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 +#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 +#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 +#endif + +#ifndef WGL_EXT_pixel_format_packed_float +#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 +#endif + +#ifndef WGL_EXT_framebuffer_sRGB +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 +#endif + + +/*************************************************************/ + +#ifndef WGL_ARB_pbuffer +DECLARE_HANDLE(HPBUFFERARB); +#endif +#ifndef WGL_EXT_pbuffer +DECLARE_HANDLE(HPBUFFEREXT); +#endif + +#ifndef WGL_ARB_buffer_region +#define WGL_ARB_buffer_region 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern HANDLE WINAPI wglCreateBufferRegionARB (HDC, int, UINT); +extern VOID WINAPI wglDeleteBufferRegionARB (HANDLE); +extern BOOL WINAPI wglSaveBufferRegionARB (HANDLE, int, int, int, int); +extern BOOL WINAPI wglRestoreBufferRegionARB (HANDLE, int, int, int, int, int, int); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); +typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); +typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); +typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +#endif + +#ifndef WGL_ARB_multisample +#define WGL_ARB_multisample 1 +#endif + +#ifndef WGL_ARB_extensions_string +#define WGL_ARB_extensions_string 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern const char * WINAPI wglGetExtensionsStringARB (HDC); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); +#endif + +#ifndef WGL_ARB_pixel_format +#define WGL_ARB_pixel_format 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglGetPixelFormatAttribivARB (HDC, int, int, UINT, const int *, int *); +extern BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC, int, int, UINT, const int *, FLOAT *); +extern BOOL WINAPI wglChoosePixelFormatARB (HDC, const int *, const FLOAT *, UINT, int *, UINT *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif + +#ifndef WGL_ARB_make_current_read +#define WGL_ARB_make_current_read 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglMakeContextCurrentARB (HDC, HDC, HGLRC); +extern HDC WINAPI wglGetCurrentReadDCARB (void); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); +#endif + +#ifndef WGL_ARB_pbuffer +#define WGL_ARB_pbuffer 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern HPBUFFERARB WINAPI wglCreatePbufferARB (HDC, int, int, int, const int *); +extern HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB); +extern int WINAPI wglReleasePbufferDCARB (HPBUFFERARB, HDC); +extern BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB); +extern BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB, int, int *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); +typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); +typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); +typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); +#endif + +#ifndef WGL_ARB_render_texture +#define WGL_ARB_render_texture 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglBindTexImageARB (HPBUFFERARB, int); +extern BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB, int); +extern BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB, const int *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); +#endif + +#ifndef WGL_ARB_pixel_format_float +#define WGL_ARB_pixel_format_float 1 +#endif + +#ifndef WGL_EXT_display_color_table +#define WGL_EXT_display_color_table 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort); +extern GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *, GLuint); +extern GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort); +extern VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); +typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); +typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); +typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); +#endif + +#ifndef WGL_EXT_extensions_string +#define WGL_EXT_extensions_string 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern const char * WINAPI wglGetExtensionsStringEXT (void); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); +#endif + +#ifndef WGL_EXT_make_current_read +#define WGL_EXT_make_current_read 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglMakeContextCurrentEXT (HDC, HDC, HGLRC); +extern HDC WINAPI wglGetCurrentReadDCEXT (void); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); +#endif + +#ifndef WGL_EXT_pbuffer +#define WGL_EXT_pbuffer 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC, int, int, int, const int *); +extern HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT); +extern int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT, HDC); +extern BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT); +extern BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT, int, int *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); +typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); +typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); +typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); +#endif + +#ifndef WGL_EXT_pixel_format +#define WGL_EXT_pixel_format 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC, int, int, UINT, int *, int *); +extern BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC, int, int, UINT, int *, FLOAT *); +extern BOOL WINAPI wglChoosePixelFormatEXT (HDC, const int *, const FLOAT *, UINT, int *, UINT *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif + +#ifndef WGL_EXT_swap_control +#define WGL_EXT_swap_control 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglSwapIntervalEXT (int); +extern int WINAPI wglGetSwapIntervalEXT (void); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); +typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); +#endif + +#ifndef WGL_EXT_depth_float +#define WGL_EXT_depth_float 1 +#endif + +#ifndef WGL_NV_vertex_array_range +#define WGL_NV_vertex_array_range 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern void* WINAPI wglAllocateMemoryNV (GLsizei, GLfloat, GLfloat, GLfloat); +extern void WINAPI wglFreeMemoryNV (void *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef void* (WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); +#endif + +#ifndef WGL_3DFX_multisample +#define WGL_3DFX_multisample 1 +#endif + +#ifndef WGL_EXT_multisample +#define WGL_EXT_multisample 1 +#endif + +#ifndef WGL_OML_sync_control +#define WGL_OML_sync_control 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglGetSyncValuesOML (HDC, INT64 *, INT64 *, INT64 *); +extern BOOL WINAPI wglGetMscRateOML (HDC, INT32 *, INT32 *); +extern INT64 WINAPI wglSwapBuffersMscOML (HDC, INT64, INT64, INT64); +extern INT64 WINAPI wglSwapLayerBuffersMscOML (HDC, int, INT64, INT64, INT64); +extern BOOL WINAPI wglWaitForMscOML (HDC, INT64, INT64, INT64, INT64 *, INT64 *, INT64 *); +extern BOOL WINAPI wglWaitForSbcOML (HDC, INT64, INT64 *, INT64 *, INT64 *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); +typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#endif + +#ifndef WGL_I3D_digital_video_control +#define WGL_I3D_digital_video_control 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC, int, int *); +extern BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC, int, const int *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +#endif + +#ifndef WGL_I3D_gamma +#define WGL_I3D_gamma 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglGetGammaTableParametersI3D (HDC, int, int *); +extern BOOL WINAPI wglSetGammaTableParametersI3D (HDC, int, const int *); +extern BOOL WINAPI wglGetGammaTableI3D (HDC, int, USHORT *, USHORT *, USHORT *); +extern BOOL WINAPI wglSetGammaTableI3D (HDC, int, const USHORT *, const USHORT *, const USHORT *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#endif + +#ifndef WGL_I3D_genlock +#define WGL_I3D_genlock 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglEnableGenlockI3D (HDC); +extern BOOL WINAPI wglDisableGenlockI3D (HDC); +extern BOOL WINAPI wglIsEnabledGenlockI3D (HDC, BOOL *); +extern BOOL WINAPI wglGenlockSourceI3D (HDC, UINT); +extern BOOL WINAPI wglGetGenlockSourceI3D (HDC, UINT *); +extern BOOL WINAPI wglGenlockSourceEdgeI3D (HDC, UINT); +extern BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC, UINT *); +extern BOOL WINAPI wglGenlockSampleRateI3D (HDC, UINT); +extern BOOL WINAPI wglGetGenlockSampleRateI3D (HDC, UINT *); +extern BOOL WINAPI wglGenlockSourceDelayI3D (HDC, UINT); +extern BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC, UINT *); +extern BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC, UINT *, UINT *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); +typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); +typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#endif + +#ifndef WGL_I3D_image_buffer +#define WGL_I3D_image_buffer 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern LPVOID WINAPI wglCreateImageBufferI3D (HDC, DWORD, UINT); +extern BOOL WINAPI wglDestroyImageBufferI3D (HDC, LPVOID); +extern BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC, const HANDLE *, const LPVOID *, const DWORD *, UINT); +extern BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC, const LPVOID *, UINT); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); +typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); +typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); +#endif + +#ifndef WGL_I3D_swap_frame_lock +#define WGL_I3D_swap_frame_lock 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglEnableFrameLockI3D (void); +extern BOOL WINAPI wglDisableFrameLockI3D (void); +extern BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *); +extern BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); +#endif + +#ifndef WGL_I3D_swap_frame_usage +#define WGL_I3D_swap_frame_usage 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern BOOL WINAPI wglGetFrameUsageI3D (float *); +extern BOOL WINAPI wglBeginFrameTrackingI3D (void); +extern BOOL WINAPI wglEndFrameTrackingI3D (void); +extern BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *, DWORD *, float *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); +typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#endif + +#ifndef WGL_ATI_pixel_format_float +#define WGL_ATI_pixel_format_float 1 +#endif + +#ifndef WGL_NV_float_buffer +#define WGL_NV_float_buffer 1 +#endif + +#ifndef WGL_EXT_pixel_format_packed_float +#define WGL_EXT_pixel_format_packed_float 1 +#endif + +#ifndef WGL_EXT_framebuffer_sRGB +#define WGL_EXT_framebuffer_sRGB 1 +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/j3d-core/www/build-instr.html b/j3d-core/www/build-instr.html new file mode 100644 index 0000000..c3c085d --- /dev/null +++ b/j3d-core/www/build-instr.html @@ -0,0 +1,53 @@ + + + + + CVS download and build instructions + + + +

CVS download and build instructions for j3d-core +

+

To +build the j3d-core +packages, you must checkout the following three +CVS +repositories:
+

+ +

These three top-level directories must be named exactly as +shown above and they must be sibling directories. To ensure this, run +the cvs checkout command for each of the respositories from the same +parent +directory. For example:
+

+
    + cd <cvs-root-dir>
    + cvs checkout vecmath
    + cvs checkout j3d-core
    + cvs checkout j3d-core-utils +
+

After you have downloaded the three CVS repositories, read the +README-FIRST.txt file, then read and follow the +instructions in the README-build.html +files in all three CVS repositories.
+

+

Go to the "CVS client setup" +page for instructions on how to access the j3d-core source code from +CVS. +Click on the "Version Control - CVS" +link to browse the j3d-core source code. Automated CVS change +messages are sent to the cvs 'at' +j3d-core.dev.java.net +list list. Click here to +subscribe to this list.
+

+


+

+ + diff --git a/j3d-core/www/index.html b/j3d-core/www/index.html new file mode 100644 index 0000000..ee6f16a --- /dev/null +++ b/j3d-core/www/index.html @@ -0,0 +1,46 @@ + + + + + Core classes for javax.media.j3d + + +

This project contains the source code +for the javax.media.j3d package.

+

Related projects include: vecmath +(the 3D vector math package), j3d-core-utils (the +3D core utilities), and j3d-examples (the +3D +example programs). The vecmath and j3d-core-utils projects are required +to build j3d-core. Developers should refer to the CVS download +and build +instructions for information on downloading the source code and +building j3d-core.
+

+

For all other project +information, including contributing to the 3D projects and reporting +issues, +please go to the parent java3d +project.

+

NOTE: The issue Tracker in this j3d-core subproject cannot be used +to file or track issues. Please use the Issue Tracker +in the parent java3d +project +to track issues (bugs, feature requests, etc.) for +j3d-core and other 3D sub-projects.
+

+

License

+

The source code for the javax.media.j3d package is licensed +under the GNU +Public License, version 2, with the Classpath Exception. This is the same +license that is used for the OpenJDK project. +

+


+

+ + diff --git a/j3d-core/www/j3d1_3_2/HOW-TO-INSTALL.html b/j3d-core/www/j3d1_3_2/HOW-TO-INSTALL.html new file mode 100644 index 0000000..eda7ad0 --- /dev/null +++ b/j3d-core/www/j3d1_3_2/HOW-TO-INSTALL.html @@ -0,0 +1,32 @@ + + + + + Java 3D 1.3.2 Installation Instructions + + +

Instructions for Installing +Java 3DTM 1.3.2

+

The 1.3.2 version of the Java 3DTM +API runs on JDK version 1.4.2 and higher. It has been released for +the Solaris/Sparc, Linux (both x86 and amd64), and Windows operating +environments. To install this build, go to the "jre" +directory within the jdk and unzip (or unjar) the zip file. For +example, +if your JDK is installed in /usr/java/j2sdk1.5.0, you +would +install this as follows: +

+
    + cd /usr/java/j2sdk1.5.0/jre
    +unzip /path-to-extracted-files/j3d-jre-*.zip
    +
    +
+

You may need to be "root" to do this on Solaris or Linux. +

+

See the release notes for +information about Java 3D 1.3.2 release. +

+ + diff --git a/j3d-core/www/j3d1_3_2/RELEASE-NOTES.html b/j3d-core/www/j3d1_3_2/RELEASE-NOTES.html new file mode 100644 index 0000000..d427ad0 --- /dev/null +++ b/j3d-core/www/j3d1_3_2/RELEASE-NOTES.html @@ -0,0 +1,388 @@ + + + + + + Java 3D 1.3.2 Release Notes + + +

Java 3DTM 1.3.2 Release Notes

+

This file contains important release information for users of the +Java 3DTM API, version 1.3.2. +

+ +

Click here for instructions on +how +to install the developer's release of +Java 3D +version 1.3.2.

+

NOTE: It is recommended that any +previous version of Java 3D be +uninstalled before installing this version. +

+

System Requirements

+

The 1.3.2 version of the Java 3D API has been released for +Solaris/Sparc, Linux (both x86 and amd64), and Windows. +

+

Solaris/Sparc

+

+The 1.3.2 version of Java 3D for Solaris/SPARC requires the +following: +

+
    +
  • JDK 1.4.2 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 8 or later
  • +
  • Frame Buffer with OpenGL support (XVR-500, XVR-1000, XVR-600, +XVR-1200, XVR-4000, Expert3D, Elite3D, Creator3D, and PGX)
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Linux
+

+

The 1.3.2 version of Java 3D for Linux (x86 or amd64) requires +the +following:
+

+
    +
  • JDK 1.4.2 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.2 or later
    +
  • +
+

Windows
+

+

The 1.3.2 version of Java 3D for Windows 2000, and Windows/XP +requires the following:
+

+
    +
  • JDK 1.4.2 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.1 or +later, +available from Microsoft or from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires DirectX 8.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: "java -Dj3d.rend=d3d ClassName" +
    +
+

Changes Since 1.3.1

+

Miscellaneous

+
    +
  • Improved the speed and quality of scene antialiasing (from 2 +samples to possibly 8 samples) if pbuffer is supported
  • +
  • Eliminated memory bloat for IndexedGeometryArrays with +USE_COORD_INDEX_ONLY flags set
  • +
  • MouseWheelEvent now supported in WakeupOnAWTEvent, MouseBehavior, +ViewPlatformAWTBehavior, and OrbitBehavior
  • +
  • Wavefront ".obj" loader now properly handles transparency +attribute +of the model (but not transparency mapping).
  • +
+

Java 3D Sound

+

+Java 3D sound is rendered via the use of a concrete implementation +of +the abstract AudioEngine3DL2 class. In version 1.3.1 we provided two +such implementations that could be used to render 3D sounds: +JavaSoundMixer and HeadspaceMixer. The 1.3.2 release no longer +includes the HeadspaceMixer implementation. Only JavaSoundMixer is +available, and it is disabled by default for users of the +Viewer.createAudioDevice() method (see the j3d.audiodevice property +below). +

+

System Properties

+
    +
  • j3d.rend - Specified the renderer that will be used +for Java 3D. +Recognized values are "ogl" and "d3d" (Windows-only). The default +value is "ogl".
  • +
  • j3d.viewFrustumCulling - If this flag is set to +false, the renderer +view frustum culling is turned off. The default value is true. Note: +Java 3D uses a 2 pass view culling. The first pass is a loose +view culling of the spatial tree, and the second pass is a tight view +frustum culling in the renderer before sending the geometry down to +the low level graphics API. The j3d.viewFrustumCulling property is to +control the renderer view frustum culling, and it will not affect the +first pass view culling.
  • +
  • j3d.transparentOffScreen - If this flag is set to +true the background +of the off screen canvas is set to transparent. The default value is +false.
  • +
  • j3d.usePbuffer - If this flag is set to false +pbuffer will not be use +for off screen rendering. The default value is true.
  • +
  • j3d.audiodevice - Takes the name of a concrete +subclass of +com.sun.j3d.audioengines.AudioEngine3DL2 that will be constructed by +Viewer.createAudioDevice(). The default value is null, which means +that audio is disabled by default for applications that call +Viewer.createAudioDevice(). For more information see the topic +on Java 3D Sound in the Java 3D forum.
  • +
  • j3d.forceReleaseView - If this flag is set to true, +the view is +released after the Canvas3D is removed from the view. Can be used if +you have memory leaks after disposing Canvas3D. Note: Setting this +flag as true disables the bug fix 4267395 in View deactivate(). The +default value is false.
  • +
+

Issues Fixed
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
3lg3d: gets unsatisified link error on various ATI cards
4Speed of OffScreen Canvas3D
5Frequent native exception: Canvas3D.destroyContext
10Canvas Redraw Issue
11Seemingly inconsistent delays in updating attributes
12Frame counter isn't always incremented correctly
13J3DTimer fails on Windows XP with P4 3GHz
14Random NullPException in uninitialized SoundSheduler
15Model Clip planes not correctly set when view changes
16Issue with Runtime instantiation of Canvas3D
18Geometry missing in OnScreenCanvas when OffScreenCanvas is +resized
19Resizing off-screen Canvas3D hangs on Solaris
20Off-screen rendering doesn't work on Linux
21Exception in WakeupOnElapsedFrames behavior stops renderer +from running when it should
23Enhancement to Reduce Memory Bloat in IndexedGeometryArray
26Texture3D not displaying when size over 512X512
27Shapes mistakenly culled when they are visible
28Combine Mode & Missing Texture in OffScreen snapshot on +Win/XP
33Texture updates fail w/ Multitextured BY_REF Geoms
36Vector3d hashCode() method distinguishes between -0.0 and 0.0
38ConfiguredUniverse throws an exception when using Java Web +Start
65WakeupOnAWTEvent does not support MouseWheelEvent
66NullPointerException in renderOffScreenBuffer
71OGL: OffScreen canvas ignore GraphicsConfigTemplate under +windows
72Exception in setOffScreenBuffer when Canvas3D not in View
73Quat4f#interpolate: incorrect when q1*q2<0
74Texture/color math difference (D3D vs OGL)
76OffScreen rendering should use Pbuffer on Windows / OpenGL
77Scene antialiasing is disabled on Windows / OpenGL
80libj3dcore-ogl.so fails to load on Linux systems without +certain GL extensions
81SimpleUniverse.cleanup() doesn't dispose of all threads
83Deadlock when removing Canvas3D and universe
86ModelClip affects Java2D graphics in mixed-mode rendering...
88Ambient Lighting corrupted by Mixed-Mode rendering...
91add new key/s to Canvas3D.queryProperties() for graphics card +info
94glCallList error
95NullPointerException reading PathInterpolator behavior with +SceneGraphFileReader
96ViewSpecificGroup documentation needs clarification
98Random Lockup when adding a Canvas3D to JTabbedPane
99New - Cannot build native bits in j3d-core with Sun Studio 10
100Offscreen Capture crash JVM
101Memory leak in com.sun.j3d.utils.geometry.Primitive
102memory leak:: Canvas3D holds a reference to parent container
103Memory leak:: View deactivate not full enabled
104Java3D based application fail to start on ATI 8.10 driver
105Build for IA64 (Itanium) 64-bit Linux
111Java 3D doesn't recognize OpenGL 2.0
112Calling Virtual Universe seems to hang
+

More Information
+

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_4/api-changes.html b/j3d-core/www/j3d1_4/api-changes.html new file mode 100644 index 0000000..4cdc828 --- /dev/null +++ b/j3d-core/www/j3d1_4/api-changes.html @@ -0,0 +1,14 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Roadmap page of the Java 3D Wiki.

+ + diff --git a/j3d-core/www/j3d1_4/graph-change-listener.html b/j3d-core/www/j3d1_4/graph-change-listener.html new file mode 100644 index 0000000..4cdc828 --- /dev/null +++ b/j3d-core/www/j3d1_4/graph-change-listener.html @@ -0,0 +1,14 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Roadmap page of the Java 3D Wiki.

+ + diff --git a/j3d-core/www/j3d1_4/improvements.html b/j3d-core/www/j3d1_4/improvements.html new file mode 100644 index 0000000..4cdc828 --- /dev/null +++ b/j3d-core/www/j3d1_4/improvements.html @@ -0,0 +1,14 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Roadmap page of the Java 3D Wiki.

+ + diff --git a/j3d-core/www/j3d1_4/lightweight-canvas3d.html b/j3d-core/www/j3d1_4/lightweight-canvas3d.html new file mode 100644 index 0000000..54d0945 --- /dev/null +++ b/j3d-core/www/j3d1_4/lightweight-canvas3d.html @@ -0,0 +1,15 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Wiki page discussing JCanvas3D.
+

+ + diff --git a/j3d-core/www/j3d1_4/multipass.html b/j3d-core/www/j3d1_4/multipass.html new file mode 100644 index 0000000..4cdc828 --- /dev/null +++ b/j3d-core/www/j3d1_4/multipass.html @@ -0,0 +1,14 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Roadmap page of the Java 3D Wiki.

+ + diff --git a/j3d-core/www/j3d1_4/picking.html b/j3d-core/www/j3d1_4/picking.html new file mode 100644 index 0000000..4cdc828 --- /dev/null +++ b/j3d-core/www/j3d1_4/picking.html @@ -0,0 +1,14 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Roadmap page of the Java 3D Wiki.

+ + diff --git a/j3d-core/www/j3d1_4/proposed-changes.html b/j3d-core/www/j3d1_4/proposed-changes.html new file mode 100644 index 0000000..4cdc828 --- /dev/null +++ b/j3d-core/www/j3d1_4/proposed-changes.html @@ -0,0 +1,14 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Roadmap page of the Java 3D Wiki.

+ + diff --git a/j3d-core/www/j3d1_4/render-texture.html b/j3d-core/www/j3d1_4/render-texture.html new file mode 100644 index 0000000..b94723a --- /dev/null +++ b/j3d-core/www/j3d1_4/render-texture.html @@ -0,0 +1,15 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Wiki page discussing Render-to-Texture.
+

+ + diff --git a/j3d-core/www/j3d1_4/shaders.html b/j3d-core/www/j3d1_4/shaders.html new file mode 100644 index 0000000..4cdc828 --- /dev/null +++ b/j3d-core/www/j3d1_4/shaders.html @@ -0,0 +1,14 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Roadmap page of the Java 3D Wiki.

+ + diff --git a/j3d-core/www/j3d1_4/stencil.html b/j3d-core/www/j3d1_4/stencil.html new file mode 100644 index 0000000..4cdc828 --- /dev/null +++ b/j3d-core/www/j3d1_4/stencil.html @@ -0,0 +1,14 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Roadmap page of the Java 3D Wiki.

+ + diff --git a/j3d-core/www/j3d1_4/vsg-op.html b/j3d-core/www/j3d1_4/vsg-op.html new file mode 100644 index 0000000..5047d16 --- /dev/null +++ b/j3d-core/www/j3d1_4/vsg-op.html @@ -0,0 +1,15 @@ + + + + + Obsolete Page + + +

Obsolete Page

+

This page is obsolete. Click here +to go the Java 3D Wiki page discussing ViewSpecificGroupOp.
+

+ + diff --git a/j3d-core/www/j3d1_4_0/HOW-TO-INSTALL-beta4.html b/j3d-core/www/j3d1_4_0/HOW-TO-INSTALL-beta4.html new file mode 100644 index 0000000..c5d14fc --- /dev/null +++ b/j3d-core/www/j3d1_4_0/HOW-TO-INSTALL-beta4.html @@ -0,0 +1,55 @@ + + + + + Java 3D 1.4.0 Installation Instructions + + +

Instructions for Installing +Java 3DTM 1.4.0-beta4

+

The 1.4.0-beta4 version of the Java 3DTM +API runs on JDK version 1.4.2 and higher. It has been released for +the Solaris, Linux, and Windows operating +environments. See the release notes +for more information
+

+

Linux

+

This interrim build of Java 3D runs on JDK version 1.4.2 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Linux/x86 platform and your JDK is +installed +in /usr/java/jdk1.5.0_06, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_06/jre
    +sh /path-to-download-files/java3d-1_4_0-beta4-linux-i586.bin
    +
+

You may need to be "root" to do this on Linux.
+

+

Solaris

+

This interrim build of Java 3D runs on JDK version 1.4.2 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Solaris/sparc platform and your JDK is +installed +in /usr/java/jdk1.5.0_06, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_06/jre
    +sh /path-to-download-files/java3d-1_4_0-beta4-solaris-sparc.bin
    +
+

You may need to be "root" to do this on Solaris.
+

+

Windows

+This interrim build of Java 3D runs on JDK version 1.4.2 and +higher. To install +this build, execute the binary installer that you downloaded, by +double-clicking on the java3d-1_4_0-beta4-windows-i586.exe icon.
+
+ + diff --git a/j3d-core/www/j3d1_4_0/HOW-TO-INSTALL.html b/j3d-core/www/j3d1_4_0/HOW-TO-INSTALL.html new file mode 100644 index 0000000..48e63e8 --- /dev/null +++ b/j3d-core/www/j3d1_4_0/HOW-TO-INSTALL.html @@ -0,0 +1,61 @@ + + + + + Java 3D 1.4.0 Installation Instructions + + +

Instructions for Installing Java 3DTM +1.4.0

+

The 1.4.0 version of the Java 3DTM +API runs on JDK version 1.4.2 and higher. It has been released for +the Solaris, Linux, and Windows operating +environments. See the release notes +for more information.
+

+

Linux

+

This release of Java 3D runs on JDK version 1.4.2 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Linux/x86 platform and your JDK is +installed +in /usr/java/jdk1.5.0_06, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_06/jre
    +sh /path-to-download-files/java3d-1_4_0-linux-i586.bin
    +
+

You may need to be "root" to do this on Linux.
+

+

Solaris

+

This release of Java 3D runs on JDK version 1.4.2 and +higher (JDK 1.5.0 or higher for Solaris/x86). +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Solaris/x86 platform (including amd64) +and your JDK is +installed +in /usr/java/jdk1.5.0_06, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_06/jre
    +sh /path-to-download-files/java3d-1_4_0-solaris-x86.bin
    +
+

You may need to be "root" to do this on Solaris.
+

+

Windows

+

This release of Java 3D runs on JDK version 1.4.2 and +higher. To install +this build, execute the binary installer that you downloaded, by +double-clicking on the java3d-1_4_0-windows-i586.exe icon.
+

+

Alternatively, you can download the java3d-1_4_0-windows-i586.zip +file and manually install +the +necessary files into your JRE. In this case, unzip the file, and follow +the instructions in the unzipped README.txt file.

+ + diff --git a/j3d-core/www/j3d1_4_0/RELEASE-NOTES-beta4.html b/j3d-core/www/j3d1_4_0/RELEASE-NOTES-beta4.html new file mode 100644 index 0000000..892c57d --- /dev/null +++ b/j3d-core/www/j3d1_4_0/RELEASE-NOTES-beta4.html @@ -0,0 +1,493 @@ + + + + + + Java 3D 1.4.0 Release Notes + + +

Java 3DTM 1.4.0-beta4 +Pre-Release Notes

+

NOTE: These release notes +are incomplete.
+

+

This file contains important pre-release information for users of +the +Java 3DTM API, version +1.4.0-beta4. +

+ +

Click here for instructions +on +how +to install this pre-release of +Java 3D +version 1.4.0-beta4.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.4.0-beta4 version of the Java 3D API has been released +for +Solaris (both sparc and x86), Linux (both x86 and amd64), and Windows. +

+

Solaris/Sparc

+

+The 1.4.0-beta4 version of Java 3D for Solaris/SPARC requires the +following: +

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL support (XVR-500, XVR-1000, XVR-600, +XVR-1200, XVR-4000, Expert3D, Elite3D, Creator3D, and PGX)
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris/x86

+

+The 1.4.0-beta4 version of Java 3D for Solaris/x86 requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer
  • +
  • OpenGL XX for Solaris/x86 or later. OpenGL for Solaris can be +obtained at: [WHERE?]
  • +
+

Linux
+

+

The 1.4.0-beta4 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.2 or later
    +
  • +
+

Windows
+

+

The 1.4.0-beta4 version of Java 3D for Windows 2000, and +Windows/XP +requires the following:
+

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.2 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
+

Changes Since 1.3.2

+

New Features

+
    +
  • Pointer to new features...
    +
  • +
+

Miscellaneous

+
    +
  • Improved...
  • +
+

System Properties

+
    +
  • j3d.xxxxx – Description of xxxxx
  • +
+

Issues Fixed
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
17
+

+
DirectX GraphicsConfiguration Issue
67
+
Transparency mode update didn't +get reflected correctly
78
+

+
Rendering stops if there's an exception in the EventDispatch
100
+
Offscreen Capture crash JVM
109
+
Frame Delays in Mixed Mode +Rendering
116
+
Handling of picking on +OrientatedShape3D needs clarification
117
+
Texture subimage is not +optimized for large subimages
124
+
Improve picking performance / +reduce garbage generation
127
+
Geometry Picking fails when +Shapes use Color4
129
+
NPE when removing an opaque +object that used to be transparent
132
+
BufferedImage getData slow, +causing poor Yup perf with updateSubImage
133
+
NullPointerException, PickCanvas +with GEOMETRY_INTERSECT_INFO and BoundingPolytope
134
+
Canvas3D memory leak
135
+
Java3D 1.3.2+ using DirectX 9.0
137
+
Add new depthTestFunction +attribute
138
+
Add method to retrieve +tessellated geometry from 3D font
139
+
add other rasterOp modes.
140
+
Object Leak in PickResult
 141
+
DirectX 9.0c for Java3D 1.4, +including shaders
144
+
ExponentialFog blending factor +depends on canvas size
145
+
Add stencil buffer support
146
+
Additional blending functions in +TransparencyAttributes
163
+
Regression in view frustum +culling
164
+
Cannot load j3dcore-ogl-cg.dll +library in JRE bin directory
167
+
Transform3D reports matrix with +NaN to be affine
169
+
TextureLoader should throw an +exception instead of printing cryptic message to System.err
170
+
TextureLoader should throw +exception when loading image
175
+
OffScreenRendering: Issue with +Updating Texture Size from Behavior
+
181
+
Performance regression: +j3d.optimizeForSpace=false ignored for some geometry
182
+
ShaderProgram not implemented +for immediate mode rendering
183
+
NPE if +CLOSEST_INTERSECTION_POINT is only flag
184
+
Illegal return value if flag +NODE is omitted
185
+
"Missing" essential methods in +IntersectionInfo
186
+
Using new Pick API with +PickSegment often returns null
187
+
NPE for new PickFast PickInfo +when getting geometries
195
+
Finish CgShader vertex +attributes native methods
196
+
Finish CgShader shader +attributes native methods
199
+
New Picking system only return 1 +result per geometry
201
+
D3D : +UnsatisfiedLinkError encountered with closing windows
202
+
Need to upgrade to latest +glext.h header file
203
+
System.currentTimeMillis is too +inaccurate on Windows for fine-grained timing
207
+
Viewer.java throws exception +with leading \n
208
+
Sound nodes cannot be placed +below Switch groups
212
+
PureImmediate test fails to +rotate
217
+
Compile j3d with +"-g:lines,source" to provide line numbers on stack traces
223
+
JVM crashes when execute +IndexedGeometryArray object with Texture coordinates
+

More Information
+

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_4_0/RELEASE-NOTES.html b/j3d-core/www/j3d1_4_0/RELEASE-NOTES.html new file mode 100644 index 0000000..97f15f8 --- /dev/null +++ b/j3d-core/www/j3d1_4_0/RELEASE-NOTES.html @@ -0,0 +1,506 @@ + + + + + + Java 3D 1.4.0 Release Notes + + +

Java 3DTM 1.4.0 Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.4.0. +

+ +

Click here for instructions +on +how +to install this release of +Java 3D +version 1.4.0.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.4.0 version of the Java 3D API has been released +for +Solaris (both sparc and x86), Linux (both x86 and amd64), and Windows +(32-bit). +

+

Solaris/Sparc

+

+The 1.4.0 version of Java 3D for Solaris/SPARC requires the +following: +

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL support (e.g., XVR-1200)
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris/x86

+

+The 1.4.0 version of Java 3D for Solaris/x86 requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
    +
  • +
+

Linux
+

+

The 1.4.0 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.2 or later
    +
  • +
+

Windows
+

+

The 1.4.0 version of Java 3D for Windows 2000, and +Windows/XP (32-bit) +requires the following:
+

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.2 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
+

Changes Since 1.3.2

+

New Features

+

Thw following new features have been added to the 1.4 version of the +Java 3D API. Please refer to the API +documentation, or the JSR-926 +change log for more information.

+
    +
  • Programmable shader support
  • +
  • Changed default values for all read capability bits
  • +
  • Enhanced picking API
    +
  • +
  • Stencil buffer support
    +
  • +
  • New rendering attributes
  • +
  • Other minor features and API changes
    +
  • +
+

System Properties

+

The following system properties were added in Java 3D 1.4.0:
+

+
    +
  • j3d.shadingLanguage – sets the shading language to +use for programmable shaders. Supported values are: "GLSL" or "Cg". The +default value is "GLSL".
    +
  • +
  • j3d.simulatedMultiTexture – If this flag is set to +true, simulation of multi-texturing will be done on systems that don't +have sufficient texture units. The default value is false. This does +not work with programmable shading, and will not be supported in 1.5.0.
    +
  • +
+

Issues Fixed
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
17
+

+
DirectX GraphicsConfiguration Issue
67
+
Transparency mode update didn't +get reflected correctly
78
+

+
Rendering stops if there's an exception in the EventDispatch
100
+
Offscreen Capture crash JVM
109
+
Frame Delays in Mixed Mode +Rendering
116
+
Handling of picking on +OrientatedShape3D needs clarification
117
+
Texture subimage is not +optimized for large subimages
124
+
Improve picking performance / +reduce garbage generation
127
+
Geometry Picking fails when +Shapes use Color4
129
+
NPE when removing an opaque +object that used to be transparent
132
+
BufferedImage getData slow, +causing poor Yup perf with updateSubImage
133
+
NullPointerException, PickCanvas +with GEOMETRY_INTERSECT_INFO and BoundingPolytope
134
+
Canvas3D memory leak
135
+
Java3D 1.3.2+ using DirectX 9.0
137
+
Add new depthTestFunction +attribute
138
+
Add method to retrieve +tessellated geometry from 3D font
139
+
add other rasterOp modes.
140
+
Object Leak in PickResult
 141
+
DirectX 9.0c for Java3D 1.4, +including shaders
144
+
ExponentialFog blending factor +depends on canvas size
145
+
Add stencil buffer support
146
+
Additional blending functions in +TransparencyAttributes
163
+
Regression in view frustum +culling
164
+
Cannot load j3dcore-ogl-cg.dll +library in JRE bin directory
167
+
Transform3D reports matrix with +NaN to be affine
169
+
TextureLoader should throw an +exception instead of printing cryptic message to System.err
170
+
TextureLoader should throw +exception when loading image
175
+
OffScreenRendering: Issue with +Updating Texture Size from Behavior
+
181
+
Performance regression: +j3d.optimizeForSpace=false ignored for some geometry
182
+
ShaderProgram not implemented +for immediate mode rendering
183
+
NPE if +CLOSEST_INTERSECTION_POINT is only flag
184
+
Illegal return value if flag +NODE is omitted
185
+
"Missing" essential methods in +IntersectionInfo
186
+
Using new Pick API with +PickSegment often returns null
187
+
NPE for new PickFast PickInfo +when getting geometries
195
+
Finish CgShader vertex +attributes native methods
196
+
Finish CgShader shader +attributes native methods
199
+
New Picking system only return 1 +result per geometry
201
+
D3D : +UnsatisfiedLinkError encountered with closing windows
202
+
Need to upgrade to latest +glext.h header file
203
+
System.currentTimeMillis is too +inaccurate on Windows for fine-grained timing
207
+
Viewer.java throws exception +with leading \n
208
+
Sound nodes cannot be placed +below Switch groups
212
+
PureImmediate test fails to +rotate
217
+
Compile j3d with +"-g:lines,source" to provide line numbers on stack traces
223
+
JVM crashes when execute +IndexedGeometryArray object with Texture coordinates
+

More Information
+

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_4_0_01/HOW-TO-INSTALL.html b/j3d-core/www/j3d1_4_0_01/HOW-TO-INSTALL.html new file mode 100644 index 0000000..b580721 --- /dev/null +++ b/j3d-core/www/j3d1_4_0_01/HOW-TO-INSTALL.html @@ -0,0 +1,61 @@ + + + + + Java 3D 1.4.0_01 Installation Instructions + + +

Instructions for Installing Java 3DTM +1.4.0_01

+

The 1.4.0_01 version of the Java 3DTM +API runs on JDK version 1.4.2 and higher. It has been released for +the Solaris, Linux, and Windows operating +environments. See the release notes +for more information.
+

+

Linux

+

This release of Java 3D runs on JDK version 1.4.2 and +higher. +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Linux/x86 platform and your JDK is +installed +in /usr/java/jdk1.5.0_06, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_06/jre
    +sh /path-to-download-files/java3d-1_4_0_01-linux-i586.bin
    +
+

You may need to be "root" to do this on Linux.
+

+

Solaris

+

This release of Java 3D runs on JDK version 1.4.2 and +higher (JDK 1.5.0 or higher for Solaris/x86). +To install this build, chdir to the "jre" directory within the jdk +and execute the self-extracting binary that you downloaded. For +example, if you are running on a Solaris/x86 platform (including amd64) +and your JDK is +installed +in /usr/java/jdk1.5.0_06, you would install Java 3D as follows: +

+
    +cd /usr/java/jdk1.5.0_06/jre
    +sh /path-to-download-files/java3d-1_4_0_01-solaris-x86.bin
    +
+

You may need to be "root" to do this on Solaris.
+

+

Windows

+

This release of Java 3D runs on JDK version 1.4.2 and +higher. To install +this build, execute the binary installer that you downloaded, by +double-clicking on the java3d-1_4_0_01-windows-i586.exe icon.
+

+

Alternatively, you can download the java3d-1_4_0_01-windows-i586.zip +file and manually install +the +necessary files into your JRE. In this case, unzip the file, and follow +the instructions in the unzipped README.txt file.

+ + diff --git a/j3d-core/www/j3d1_4_0_01/RELEASE-NOTES.html b/j3d-core/www/j3d1_4_0_01/RELEASE-NOTES.html new file mode 100644 index 0000000..41ba6df --- /dev/null +++ b/j3d-core/www/j3d1_4_0_01/RELEASE-NOTES.html @@ -0,0 +1,569 @@ + + + + + + Java 3D 1.4.0_01 Release Notes + + +

Java 3DTM 1.4.0_01 Release +Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.4.0_01. +

+ +

Click here for instructions +on +how +to install this patch release of +Java 3D +version 1.4.0_01.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.4.0_01 version of the Java 3D API has been released +for +Solaris (both sparc and x86), Linux (both x86 and amd64), and Windows +(32-bit). +

+

Solaris/Sparc

+

+The 1.4.0_01 version of Java 3D for Solaris/SPARC requires the +following: +

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL support (e.g., XVR-1200)
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris/x86

+

+The 1.4.0_01 version of Java 3D for Solaris/x86 requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
    +
  • +
+

Linux
+

+

The 1.4.0_01 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.2 or later
    +
  • +
+

Windows
+

+

The 1.4.0_01 version of Java 3D for Windows 2000, and +Windows/XP (32-bit) +requires the following:
+

+
    +
  • JDK 1.4.2 or later (1.5.0 is recommended) from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.2 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
+

Bugs Fixed in 1.4.0_01 Patch

+

The following bugs (issues) have been fixed in the 1.4.0_01 patch +release.

+ + + + + + + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
160
+

+
AlternateAppearance behaves +differently in J3D 1.3.2 comparing to J3D 1.3.1
+
244
+

+
ClassCastException in Group.setChild
249
+
NullPointerException in +MasterControlThread when adding a Light
+
+

NOTE: the fix for issue 249 (as well as 160) was to disable the +"sole user" optimization, which was originally done to optimize the +updating of +frequently changing appearance attributes in cases where there was only +one Shape3D using a particular Appearance. This optimization came at +the expense of rendering performance in some cases, and was also the +source of several +bugs. Now that this optimization is disabled, rendering +performance and stability should improve for most applications, but +some +applications may notice a slow-down in update performance. For this +reason, we have added a new system property to re-enable the sole-user +optimization.
+

+
    +
  • j3d.allowSoleUser – If this flag is set to +true, the 1.4.0-fcs behavior is restored, causing the sole-user +optimization to be allowed when appropriate. The default value is false.
    +
  • +
+

Changes Since 1.3.2

+

New Features

+

Thw following new features have been added to the 1.4 version of the +Java 3D API. Please refer to the API +documentation, or the JSR-926 +change log for more information.

+
    +
  • Programmable shader support
  • +
  • Changed default values for all read capability bits
  • +
  • Enhanced picking API
    +
  • +
  • Stencil buffer support
    +
  • +
  • New rendering attributes
  • +
  • Other minor features and API changes
    +
  • +
+

System Properties

+

The following system properties were added in Java 3D 1.4.0:
+

+
    +
  • j3d.shadingLanguage – sets the shading language to +use for programmable shaders. Supported values are: "GLSL" or "Cg". The +default value is "GLSL".
    +
  • +
  • j3d.simulatedMultiTexture – If this flag is set to +true, simulation of multi-texturing will be done on systems that don't +have sufficient texture units. The default value is false. This does +not work with programmable shading, and will not be supported in 1.5.0.
    +
  • +
+

Issues Fixed
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
17
+

+
DirectX GraphicsConfiguration Issue
67
+
Transparency mode update didn't +get reflected correctly
78
+

+
Rendering stops if there's an exception in the EventDispatch
100
+
Offscreen Capture crash JVM
109
+
Frame Delays in Mixed Mode +Rendering
116
+
Handling of picking on +OrientatedShape3D needs clarification
117
+
Texture subimage is not +optimized for large subimages
124
+
Improve picking performance / +reduce garbage generation
127
+
Geometry Picking fails when +Shapes use Color4
129
+
NPE when removing an opaque +object that used to be transparent
132
+
BufferedImage getData slow, +causing poor Yup perf with updateSubImage
133
+
NullPointerException, PickCanvas +with GEOMETRY_INTERSECT_INFO and BoundingPolytope
134
+
Canvas3D memory leak
135
+
Java3D 1.3.2+ using DirectX 9.0
137
+
Add new depthTestFunction +attribute
138
+
Add method to retrieve +tessellated geometry from 3D font
139
+
add other rasterOp modes.
140
+
Object Leak in PickResult
 141
+
DirectX 9.0c for Java3D 1.4, +including shaders
144
+
ExponentialFog blending factor +depends on canvas size
145
+
Add stencil buffer support
146
+
Additional blending functions in +TransparencyAttributes
163
+
Regression in view frustum +culling
164
+
Cannot load j3dcore-ogl-cg.dll +library in JRE bin directory
167
+
Transform3D reports matrix with +NaN to be affine
169
+
TextureLoader should throw an +exception instead of printing cryptic message to System.err
170
+
TextureLoader should throw +exception when loading image
175
+
OffScreenRendering: Issue with +Updating Texture Size from Behavior
+
181
+
Performance regression: +j3d.optimizeForSpace=false ignored for some geometry
182
+
ShaderProgram not implemented +for immediate mode rendering
183
+
NPE if +CLOSEST_INTERSECTION_POINT is only flag
184
+
Illegal return value if flag +NODE is omitted
185
+
"Missing" essential methods in +IntersectionInfo
186
+
Using new Pick API with +PickSegment often returns null
187
+
NPE for new PickFast PickInfo +when getting geometries
195
+
Finish CgShader vertex +attributes native methods
196
+
Finish CgShader shader +attributes native methods
199
+
New Picking system only return 1 +result per geometry
201
+
D3D : +UnsatisfiedLinkError encountered with closing windows
202
+
Need to upgrade to latest +glext.h header file
203
+
System.currentTimeMillis is too +inaccurate on Windows for fine-grained timing
207
+
Viewer.java throws exception +with leading \n
208
+
Sound nodes cannot be placed +below Switch groups
212
+
PureImmediate test fails to +rotate
217
+
Compile j3d with +"-g:lines,source" to provide line numbers on stack traces
223
+
JVM crashes when execute +IndexedGeometryArray object with Texture coordinates
+

More Information
+

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_0/RELEASE-NOTES-beta1.html b/j3d-core/www/j3d1_5_0/RELEASE-NOTES-beta1.html new file mode 100644 index 0000000..53c9a71 --- /dev/null +++ b/j3d-core/www/j3d1_5_0/RELEASE-NOTES-beta1.html @@ -0,0 +1,587 @@ + + + + + + Java 3D 1.5.0 Pre-Release Notes + + +

Java 3DTM 1.5.0-beta1 +Pre-Release Notes

+

This file contains important pre-release information for users of +the +Java 3DTM API, version +1.5.0-beta1. +

+ +

Click +here for instructions +on +how +to install this patch release of +Java 3D +version 1.4.0_01.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.0-beta1 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.0-beta1 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support (XVR-600, +XVR-1200, Expert3D, etc.)
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.0-beta1 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.0-beta1 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later
    +
  • +
+

Windows
+

+

The 1.5.0-beta1 version of Java 3D for Windows 2000, and +Windows/XP (x86 or amd64) +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      + The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +

      + The DirectX rendering pipeline is not +available in 1.5.0-beta1. We plan to deliver a beta version in +1.5.0-beta2. +
    +
+

Mac OS X

+

The 1.5.0-beta1 version of Java 3D for Mac OSX (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.0-beta1

+

New Features / Enhancements

+
    +
  • JOGL Rendering Pipeline
    +
  • +
  • Non-power-of-two textures
  • +
  • NIO image buffer support for textures
  • +
  • By-reference support for geometry indices
  • +
  • Rendering error listeners
  • +
  • Vecmath accessors/mutators
  • +
+

Issues Fixed

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
40  Transparency color not correct +on UCIO geometry and OffScreen canvas
75  Memory leak in SetLiveState when +branchGroup remove
85  Optimize the downloading of ARGB +textures
92  ImageComponent2D.setSubImage() +uses incorrect image sizes
93  ImageComponent2D.setSubImage() +does not correctly update the display
113  NPE in updateAlphaInVertexData +on multiple screens
121  Stop using finalize() to clean +up state
123  Reduce or eliminate use of +memory free lists
147  Need Windows/amd64 port of Java +3D
152  NPE in updateNodeComponent
160  AlternateAppearance behaves +defferently in J3D 1.3.2 comparing to J3D 1.3.1
172  Texture.setImage fails to check +ImageComponent sizes when not live
180  Frame-dependent Large Texture +Updates leads to OOM Exception
194  Provide NIOBuffer texture +components
198  Need more shader example programs
209  PolygonAttributes.isCompiled() +returns false after the scenegraph's BranchGroup is compiled.
216  J3DTimer should use +clock_gettime on Linux
219  Add support for Non Power of Two +textures
220  Matrix3d.set(AxisAngle4d) sets +incorrectly if axis vector not normalized
221  UnsatisfiedLinkError if shading +language set to Cg on d3d
224  NPE While Toggling Visibility
225  BY_REF Support for +CoordinateIndices To Reduce Memory Bloat
229  Need to implement JOGL renderer
235  Null Pointer in AttributeBin
240  Canvas3D.queryProperties reports +stencil available even when it is not
241  Texture3D by Reference Fails
244  ClassCastException in +Group.setChild
245  Problem with +ALLOW_RENDERING_ATTRIBUTES_WRITE in Appearance
246  Move compressed geometry code +from core to utils
247  SHADER_ATTRIBUTE_TYPE_ERROR is +fired when ShaderAttributeArray is used (OpenGL and GLSL shaders used)
248  Wrong spec. on the setFlags() +method of com.sun.j3d.utils.pickfast.PickTool
249  NullpointerException in +MasterControlThread when adding a Light
251  Typo, in spec. PickTool.PickAny +and PickTool.PickClosest return is wrong
253  Transform3D's incorrectly +identified as Affine
260  Obsolete graphics library +version kills renderer thread, cannot be detected by app
264  Behaviors that throw an Error +cause the BehaviorScheduler to die
266  Canvas3D should throw NPE by +default for null graphicsConfig
268  Replace native +getNumberOfProcessor() with pure Java equiv?
269  GLSL on nVidia cards: Confict of +a builtin vertex attribute (named gl_Normal) and a bound generic vertex +attribute
275  sleep for +setMinimumFrameCycleTime should not hold lock
279  Intermittent hang in +MasterControl while running lg3d
283  Add Eclipse plugin defs to +manifest
288  Objects in RenderBin free lists +keep reference to user data
308  WakeupOnElapsedTime occasionally +doesn't wake up on elapsed time
311  Broken build for linux on ppc.
313  Geometry Stress Test results in +OOM Error
318  Cannot build on Itanium Linux
320  Shader Appearance update is +asynchronous to transform update
321  bug in +vecmath.Matrix3d.set(AxisAngle a1)
323  Deprecate optional detail +texture functionality
325  This Tuple4d is epsilonEquals to +all others: (NaN, NaN, NaN, NaN)
326  PrintCanvas3D on JOGL pipeline +crashes on Linux and Solaris
327  javadoc for VIew class doesn't +list correct clip policy defaults
328  JOGL pipeline : Geometry fails +to render in Cosmic Birdie
331  Add .cvsignore file to root of +vecmath.
338  Bug in glPushAttrib usage in +NativePipeline
339  Java crashes when using GLSL +shaders
340  Resource leak in +setOffScreenBuffer, NPE in JOGL pipeline
342  Raster.setDstOffset() set the +destination pixel offset in opposite direction
347  OffScreen Canvas3D always +reloads textures, display lists
348  Programmable shaders do not work +for OffScreen Canvas3D
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac +OSX (x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here and go +to the "Early access +test program" section at bottom of the +page to run a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OSX and the native OpenGL pipeline on all +other platforms.
+

+

The JOGL renderer is the default on Mac OSX. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and install it into the JRE along with the Java 3D jar files (or +include it in your PATH/CLASSPATH).
+

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_0/RELEASE-NOTES-beta2.html b/j3d-core/www/j3d1_5_0/RELEASE-NOTES-beta2.html new file mode 100644 index 0000000..0eb6808 --- /dev/null +++ b/j3d-core/www/j3d1_5_0/RELEASE-NOTES-beta2.html @@ -0,0 +1,800 @@ + + + + + + Java 3D 1.5.0 Pre-Release Notes + + +

Java 3DTM 1.5.0-beta2 +Pre-Release Notes

+

This file contains important pre-release information for users of +the +Java 3DTM API, version +1.5.0-beta2. +

+ +

Click +here for instructions +on +how +to install this patch release of +Java 3D +version 1.4.0_01.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.0-beta2 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.0-beta2 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.0-beta2 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.0-beta2 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.0-beta2 version of Java 3D for Windows 2000, and +Windows/XP (x86 or amd64) +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
+

Mac OS X

+

The 1.5.0-beta2 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.0

+

New Features / Enhancements

+ +

Issues Fixed in 1.5.0-beta2
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
84  Rendering pauses after Canvas3D +disposal until AWT event
+
238  Exception in thread +"J3D-MasterControl-1" when setting TextureUnitState to 0-length array
+
252  Offscreen Canvas3D/Screen3D +error reporting (pbuffer allocation)
+
295  Texture3D throws +ArrayIndexOutOfBoundsException when scaleImage
+
312  Exception while detaching +ModelClip from ViewSpecificGroup
+
324  Lockup Java3D program and throw +exception using JOGL renderer
+
336  Unable to redraw when resizing +using JOGL pipeline
+
341  Initializing audio device using +Webstart throws ClassNotFoundException
+
344  Too much time to load image as +Texture
+
349  OffScreen Canvas3D needlessly +forces power-of-two for its buffer
+
351  Need a new mechanism to free D3D +surface
+
352  VC compiler generates warning on +Windows AMD64 build
+
353  GeometryArray Memory Leak
+
355  IndexedXXXStripArray throws NPE +with ByRef Indices
+
356  Exception in RenderBin when +removing a Shape3D with no geometry
+
358  Document that OGL 1.2 is +supported, but at reduced functionality
+
360  SceneGraphStreamWriter.writeBranchGraph +throws exception
+
366  Raster appears without image on +systems without NPOT support
+
367  Clip throws NPE in case of +region = null in a live scene
+
368  Background texture doesn't work +on system with no NPOT support
+
370  Deadlock when calling +Raster.setimage from user thread
+
371  Poor raster quality for systems +that don't support NPOT textures
+
372  ImageComponent.set(BufferedImage) +ignored when used by Raster
+
373  ImageComponent.set(BufferedImage) +ignored when used by Background
+
374  Exception when calling +Background.setImage on live scene graph
+
379  Needs NPOT support documented in +Texture, Texture3D and TextureCubeMap
+
380  NPE when uncheck Show Color +Texture in Dot3 demo
+
+
+

Issues Fixed in 1.5.0-beta1
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
40  Transparency color not correct +on UCIO geometry and OffScreen canvas
75  Memory leak in SetLiveState when +branchGroup remove
85  Optimize the downloading of ARGB +textures
92  ImageComponent2D.setSubImage() +uses incorrect image sizes
93  ImageComponent2D.setSubImage() +does not correctly update the display
113  NPE in updateAlphaInVertexData +on multiple screens
121  Stop using finalize() to clean +up state
123  Reduce or eliminate use of +memory free lists
147  Need Windows/amd64 port of Java +3D
152  NPE in updateNodeComponent
160  AlternateAppearance behaves +defferently in J3D 1.3.2 comparing to J3D 1.3.1
172  Texture.setImage fails to check +ImageComponent sizes when not live
180  Frame-dependent Large Texture +Updates leads to OOM Exception
194  Provide NIOBuffer texture +components
198  Need more shader example programs
209  PolygonAttributes.isCompiled() +returns false after the scenegraph's BranchGroup is compiled.
216  J3DTimer should use +clock_gettime on Linux
219  Add support for Non Power of Two +textures
220  Matrix3d.set(AxisAngle4d) sets +incorrectly if axis vector not normalized
221  UnsatisfiedLinkError if shading +language set to Cg on d3d
224  NPE While Toggling Visibility
225  BY_REF Support for +CoordinateIndices To Reduce Memory Bloat
229  Need to implement JOGL renderer
235  Null Pointer in AttributeBin
240  Canvas3D.queryProperties reports +stencil available even when it is not
241  Texture3D by Reference Fails
244  ClassCastException in +Group.setChild
245  Problem with +ALLOW_RENDERING_ATTRIBUTES_WRITE in Appearance
246  Move compressed geometry code +from core to utils
247  SHADER_ATTRIBUTE_TYPE_ERROR is +fired when ShaderAttributeArray is used (OpenGL and GLSL shaders used)
248  Wrong spec. on the setFlags() +method of com.sun.j3d.utils.pickfast.PickTool
249  NullpointerException in +MasterControlThread when adding a Light
251  Typo, in spec. PickTool.PickAny +and PickTool.PickClosest return is wrong
253  Transform3D's incorrectly +identified as Affine
260  Obsolete graphics library +version kills renderer thread, cannot be detected by app
264  Behaviors that throw an Error +cause the BehaviorScheduler to die
266  Canvas3D should throw NPE by +default for null graphicsConfig
268  Replace native +getNumberOfProcessor() with pure Java equiv?
269  GLSL on nVidia cards: Confict of +a builtin vertex attribute (named gl_Normal) and a bound generic vertex +attribute
275  sleep for +setMinimumFrameCycleTime should not hold lock
279  Intermittent hang in +MasterControl while running lg3d
283  Add Eclipse plugin defs to +manifest
288  Objects in RenderBin free lists +keep reference to user data
308  WakeupOnElapsedTime occasionally +doesn't wake up on elapsed time
311  Broken build for linux on ppc.
313  Geometry Stress Test results in +OOM Error
318  Cannot build on Itanium Linux
320  Shader Appearance update is +asynchronous to transform update
321  bug in +vecmath.Matrix3d.set(AxisAngle a1)
323  Deprecate optional detail +texture functionality
325  This Tuple4d is epsilonEquals to +all others: (NaN, NaN, NaN, NaN)
326  PrintCanvas3D on JOGL pipeline +crashes on Linux and Solaris
327  javadoc for VIew class doesn't +list correct clip policy defaults
328  JOGL pipeline : Geometry fails +to render in Cosmic Birdie
331  Add .cvsignore file to root of +vecmath.
338  Bug in glPushAttrib usage in +NativePipeline
339  Java crashes when using GLSL +shaders
340  Resource leak in +setOffScreenBuffer, NPE in JOGL pipeline
342  Raster.setDstOffset() set the +destination pixel offset in opposite direction
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac +OS X (x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here and go +to the "Early access +test program" section at bottom of the +page to run a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and install it into the JRE along with the Java 3D jar files (or +include it in your PATH/CLASSPATH).
+

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_0/RELEASE-NOTES-pre.html b/j3d-core/www/j3d1_5_0/RELEASE-NOTES-pre.html new file mode 100644 index 0000000..650251e --- /dev/null +++ b/j3d-core/www/j3d1_5_0/RELEASE-NOTES-pre.html @@ -0,0 +1,473 @@ + + + + + + Java 3D 1.5.0 Pre-Release Notes + + +

Java 3DTM 1.5.0-build4 +Pre-Release Notes

+

NOTE: These release notes +are incomplete.
+

+

This file contains important pre-release information for users of +the +Java 3DTM API, version +1.5.0-build4. +

+ +

System Requirements

+

The 1.5.0-build4 version of the Java 3D API has been released +for +Solaris (both sparc and x86), Linux (both x86 and amd64), and Windows. +

+

Solaris/Sparc

+

+The 1.5.0-build4 version of Java 3D for Solaris/SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support (XVR-600, +XVR-1200, Expert3D, etc.)
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris/x86

+

+The 1.5.0-build4 version of Java 3D for Solaris/x86 requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.0-build4 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later
    +
  • +
+

Windows
+

+

The 1.5.0-build4 version of Java 3D for Windows 2000, and +Windows/XP +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
+

JOGL Rendering Pipeline

+

A preliminary version of the JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms. It will also run on Apple Mac +OSX (x86 or PPC)! The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here and go +to the "Early access +test program" section at bottom of the +page to run a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OSX and the native OpenGL pipeline on all +other platforms.
+

+

For those who download and install Java 3D locally, +there isn't a specific Mac build yet. To run Java 3D on the Mac, +just +grab the binary for any other platform (e.g., Windows) and run it. It +won't try to use the DLLs. The JOGL renderer is the default on Mac OSX. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download JOGL +and install it into the JRE along with the Java 3D jar files (or +include it in your PATH/CLASSPATH).
+

+

Most Java 3D features are implemented in the JOGL pipeline, but +the +following are known to be missing:
+

+
    +
  • Off-screen rendering
  • +
  • Cg shading language
    +
  • +
  • Programmable shader vertex attributes
    +
  • +
+

There may be others missing, as well. Any missing function will +print +out a message of the form:
+

+
    + JoglPipeline.createOffScreenBuffer() +
+

UPDATE : 2-Jul-2006

+

The JOGL rendering pipeline should now be feature complete, but not +all code paths have been tested. If you encounter problems, or, more +specifically, see any differences in rendering results between the +native OpenGL pipeline and the JOGL pipeline, please either post on the +Java 3D +forum or +file +a bug.
+

+

Run a daily +build as of 2006-07-02 or later to use the feature complete version +of the JOGL Pipeline. This will be available in 1.5.0-build5.
+

+

Improvements in 1.5.0-build4

+

New Features / Enhancements

+ +

Issues Fixed

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
241
+

+
Texture3D by Reference Fails
+
311
+

+
Broken build for linux on ppc.
+
320
+

+
Shader Appearance update is +asynchronous to transform update
+
321
+

+
bug in +vecmath.Matrix3d.set(AxisAngle a1)
+
+
+

Improvements in 1.5.0-build3

+

New Features / Enhancements

+
    +
  • JOGL Rendering Pipeline
    +
  • +
  • Memory free lists for Java 3D messages, etc., are now +disabled by +default (issue 123). We temporarily added a new system property, +"j3d.useFreeLists", that can be set to true to re-enable memory free +lists. We eventually plan to completely remove the memory free lists.
    +
  • +
+

Issues Fixed

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
123
+

+
Reduce or eliminate use of +memory free lists
+
268
+

+
Replace native +getNumberOfProcessor() with pure Java equiv
+
269
+

+
GLSL on nVidia cards: Conflict +of +a builtin vertex attribute
+
275
+

+
sleep for +setMinimumFrameCycleTime should not hold lock
+
279
+

+
Intermittent hang in +MasterControl while running lg3d
+
288
+

+
Objects in RenderBin free lists +keep reference to user data
+
308
+

+
WakeupOnElapsedTime occasionally +doesn't wake up on elapsed time
+
+
+

Improvements in 1.5.0-build2

+

New Features / Enhancements

+
    +
  • Added preliminary API for NIO texture images
    +
  • +
+

Issues Fixed

+
+ + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
264
+
Behaviors that throw an Error +cause the BehaviorScheduler to die
266
+
Canvas3D should throw NPE by +default for null graphicsConfig
+
+

Improvements in 1.5.0-build1

+

New Features / Enhancements

+
    +
  • Non-power-of-two textures for Texture2D
    +
  • +
+

Issues Fixed

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue
+
 
+
Description
+
160
+
AlternateAppearance behaves +defferently in J3D 1.3.2 comparing to J3D 1.3.1
+
172
+
Texture.setImage fails to check +ImageComponent sizes when not live
216
+
J3DTimer should use +clock_gettime on Linux
221
+
UnsatisfiedLinkError if shading +language set to Cg on d3d
244
+
ClassCastException in +Group.setChild
247
+
SHADER_ATTRIBUTE_TYPE_ERROR is +fired when ShaderAttributeArray is used (GLSL shaders)
248
+
Wrong spec. on the setFlags() +method of com.sun.j3d.utils.pickfast.PickTool
249
+
NullpointerException in +MasterControlThread when adding a Light
+
251
+
Typo in spec: PickTool.PickAny +and PickTool.PickClosest return is wrong
+
+
+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_0/RELEASE-NOTES.html b/j3d-core/www/j3d1_5_0/RELEASE-NOTES.html new file mode 100644 index 0000000..c624b2b --- /dev/null +++ b/j3d-core/www/j3d1_5_0/RELEASE-NOTES.html @@ -0,0 +1,815 @@ + + + + + + Java 3D 1.5.0 Release Notes + + +

Java 3DTM 1.5.0 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.0. +

+ +

Click +here for instructions +on +how +to install this release of +Java 3D +version 1.5.0.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.0 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.0 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.0 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.0 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.0 version of Java 3D for Windows 2000, and +Windows/XP (x86 or amd64) +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000 or Windows/XP
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
+

Mac OS X

+

The 1.5.0 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.0

+

New Features / Enhancements

+ +

Issues Fixed in 1.5.0
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
40  Transparency color not correct +on UCIO geometry and OffScreen canvas
75  Memory leak in SetLiveState when +branchGroup remove
84  Rendering pauses after Canvas3D +disposal until AWT event
85  Optimize the downloading of ARGB +textures
92  ImageComponent2D.setSubImage() +uses incorrect image sizes
93  ImageComponent2D.setSubImage() +does not correctly update the display
113  NPE in updateAlphaInVertexData +on multiple screens
121  Stop using finalize() to clean +up state
123  Reduce or eliminate use of +memory free lists
131  Lightweight Canvas3D
147  Need Windows/amd64 port of Java +3D
152  NPE in updateNodeComponent
160  AlternateAppearance behaves +defferently in J3D 1.3.2 comparing to J3D 1.3.1
162  Textures are randomly incorrect +in multi-screen mode with LG3D
172  Texture.setImage fails to check +ImageComponent sizes when not live
180  Frame-dependent Large Texture +Updates leads to OOM Exception
194  Provide NIOBuffer texture +components
198  Need more shader example programs
209  PolygonAttributes.isCompiled() +returns false after the scenegraph's BranchGroup is compiled.
216  J3DTimer should use +clock_gettime on Linux
219  Add support for Non Power of Two +textures
220  Matrix3d.set(AxisAngle4d) sets +incorrectly if axis vector not normalized
221  UnsatisfiedLinkError if shading +language set to Cg on d3d
224  NPE While Toggling Visibility
225  BY_REF Support for +CoordinateIndices To Reduce Memory Bloat
227  Serialization problem with +vecmath
229  Need to implement JOGL renderer
235  Null Pointer in AttributeBin
238  Exception in thread +J3D-MasterControl-1 when setting TextureUnitState to 0-length array
240  Canvas3D.queryProperties reports +stencil available even when it is not
241  Texture3D by Reference Fails
244  ClassCastException in +Group.setChild
245  Problem with +ALLOW_RENDERING_ATTRIBUTES_WRITE in Appearance
246  Move compressed geometry code +from core to utils
247  SHADER_ATTRIBUTE_TYPE_ERROR is +fired when ShaderAttributeArray is used (OpenGL and GLSL shaders used)
248  Wrong spec. on the setFlags() +method of com.sun.j3d.utils.pickfast.PickTool
249  NullpointerException in +MasterControlThread when adding a Light
251  Typo, in spec. PickTool.PickAny +and PickTool.PickClosest return is wrong
252  Offscreen Canvas3D/Screen3D +error reporting (pbuffer allocation)
253  Transform3D's incorrectly +identified as Affine
260  Obsolete graphics library +version kills renderer thread, cannot be detected by app
264  Behaviors that throw an Error +cause the BehaviorScheduler to die
266  Canvas3D should throw NPE by +default for null graphicsConfig
267  TextureLoader should autodetect +alpha and colours
268  Replace native +getNumberOfProcessor() with pure Java equiv?
269  GLSL on nVidia cards: Confict of +a builtin vertex attribute (named gl_Normal) and a bound generic vertex +attribute
275  sleep for +setMinimumFrameCycleTime should not hold lock
279  Intermittent hang in +MasterControl while running lg3d
283  Add Eclipse plugin defs to +manifest
288  Objects in RenderBin free lists +keep reference to user data
295  Texture3D throws +ArrayIndexOutOfBoundsException when scaleImage
308  WakeupOnElapsedTime occasionally +doesn't wake up on elapsed time
311  Broken build for linux on ppc.
312  Exception while detaching +ModelClip from ViewSpecificGroup
313  Geometry Stress Test results in +OOM Error
318  Cannot build on Itanium Linux
320  Shader Appearance update is +asynchronous to transform update
321  bug in +vecmath.Matrix3d.set(AxisAngle a1)
323  Deprecate optional detail +texture functionality
324  Lockup Java3D program and throw +exception using JOGL renderer
325  This Tuple4d is epsilonEquals to +all others: (NaN, NaN, NaN, NaN)
326  PrintCanvas3D on JOGL pipeline +crashes on Linux and Solaris
327  javadoc for VIew class doesn't +list correct clip policy defaults
328  JOGL pipeline : Geometry fails +to render in Cosmic Birdie
331  Add .cvsignore file to root of +vecmath.
336  Unable to redraw when resizing +using JOGL pipeline
338  Bug in glPushAttrib usage in +NativePipeline
339  Java crashes when using GLSL +shaders
340  Resource leak in +setOffScreenBuffer, NPE in JOGL pipeline
341  Initializing audio device using +Webstart throws ClassNotFoundException
342  Raster.setDstOffset() set the +destination pixel offset in opposite direction
344  Too much time to load image as +Texture
349  OffScreen Canvas3D needlessly +forces power-of-two for its buffer
351  Need a new mechanism to free D3D +surface
352  VC compiler generates warning on +Windows AMD64 build
353  GeometryArray Memory Leak
355  IndexedXXXStripArray throws NPE +with ByRef Indices
356  Exception in RenderBin when +removing a Shape3D with no geometry
358  Document that OGL 1.2 is +supported, but at reduced functionality
360  SceneGraphStreamWriter.writeBranchGraph +throws exception
366  Raster appears without image on +systems without NPOT support
367  Clip throws NPE in case of +region = null in a live scene
368  Background texture doesn't work +on system with no NPOT support
370  Deadlock when calling +Raster.setimage from user thread
371  Poor raster quality for systems +that don't support NPOT textures
372  ImageComponent.set(BufferedImage) +ignored when used by Raster
373  ImageComponent.set(BufferedImage) +ignored when used by Background
374  Exception when calling +Background.setImage on live scene graph
379  Needs NPOT support documented in +Texture, Texture3D and TextureCubeMap
380  NPE when uncheck Show Color +Texture in Dot3 demo
383  JCanvas3D's offscreen Canvas3D +is inverted.
392  Texture loading regression for +optimized RGB PNG files
393  TextureLoader regression on +BufferedImage.TYPE_BYTE_INDEXED
395  JCanvas3D / JOGL: Program freezes
400  Lighting differs with various +renderers
403  AssertionError while changing +(offscreen) Texture size
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac +OS X (x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and install it into the JRE along with the Java 3D jar files (or +include it in your PATH/CLASSPATH).
+

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_1/RELEASE-NOTES-beta1.html b/j3d-core/www/j3d1_5_1/RELEASE-NOTES-beta1.html new file mode 100644 index 0000000..47cfa26 --- /dev/null +++ b/j3d-core/www/j3d1_5_1/RELEASE-NOTES-beta1.html @@ -0,0 +1,517 @@ + + + + + + Java 3D 1.5.1 Pre-Release Notes + + +

Java 3DTM 1.5.1-beta1 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.1-beta1. +

+ +

Click +here for instructions +on +how +to install this release of +Java 3D +version 1.5.1-beta1.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.1-beta1 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.1-beta1 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.1-beta1 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.1-beta1 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.1-beta1 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000, Windows XP, or Windows Vista
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
    + NOTE: The DirectX version of Java 3D is used if a suitable version + of OpenGL cannot be found. Note also that DirectX is chosen by + default on Windows Vista systems with an ATI graphics card (due to + ATI driver bugs). +
+

Mac OS X

+

The 1.5.1-beta1 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.1-beta1

+

Enhancements

+
    +
  • Windows Vista Support
  • +
  • Pack200 Support for Java Web Start Applications
  • +
  • Logging + Framework
  • +
+

Issues Fixed in 1.5.1-beta1
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
126  Use OpenGL automatic mipmap generation
157  Would like a JOALMixer implementation of AudioEngine3DL2
197  Consider supporting pack200 for Java Web Start / JNLP
226  D3D : fail on stress test for the creation and destruction of Canvases
239  Stencil buffer should be cleared at the start of each frame
274  NPE With Simultaneous View and Content Side PickingBehaviors
293  Need better logging for j3d error, warning, assertion messages.
314  Issue with Stenciled Transparent Objects
347  OffScreen Canvas3D always reloads textures, display lists
348  Programmable shaders do not work for OffScreen Canvas3D
357  Memory leak when using textures with multiple views
362  dynamic assignment if Canvas3D to View makes content disappear
364  Canvas3D.setOffScreenBuffer(null) sometimes hangs
378  Shaders are not rendered when Canvas3D is created and destroyed
381  ByRef, yDown, 4BYTE_ABGR throws ArrayIndexOOB Exception
396  Off-screen Canvas3D / D3D: Resizing crashes VM
402  Off-screen Canvas3D throws Exception on BufferedImage of TYPE_4BYTE_ABGR and TYPE_INT_ARGB
408  Poor quality of auto-generated mipmaps
411  Add Primitive flag to reverse Y for tex coords
412  Exception when updating Y_UP BY_REFERENCE image
414  D3D: NPOT textures not properly disabled on card that lacks support
415  Need ability to disable NPOT textures for raster/background
416  JOGL: ClassCastException in Renderer with NioImageBuffer
417  JOGL: Mip-mapped NPOT textures rendered incorrectly
424  JOALMixer requires the default Viewer's setUserHeadToVworldEnable setting to true
425  NullPointerException in automatic mipmap generation
427  Method with constructor name: ObjectFileMaterial
431  disabled PointSound starts playing when scheduling bounds are entered
433  JCanvas3D crashed when using jogl pipe
434  OutOfMemory after creating millions of RenderAtomListInfo objects
437  SceneGraphStreamWriter NPE
435  Memory leak when reusing an Appearance with a single Texture
438  ConfiguredUniverse & SimpleUniverse constructor missing
441  ArrayIndexOutOfBoundsException in IndexedTriangleArrayRetained Intersect
444  Transform updates overly expensive
446  JCanvas3D and focus
447  Enhance Element Traversal To Improve Pick Hits
449  SceneGraphIO can not support ImageComponent2DURL
452  Java 3D should fall back to D3D if OpenGL not available
453  SceneGraphIO does not support SceneGraphObjects name field
455  Need to disable NPOT textures for older cards that claim to support it.
456  NPOT background ( maybe raster) fail to work if HW doesn't support NPOT texture
457  ClassCastException in MasterControl when updating Texture3D
458  Canvas3D stops rendering on window close
461  ClassCastException thrown when using filters with NioImageBuffer
466  NPE when updating lights with multiple views
467  Add Java3D source jar file as a separate or part of the distribution
468  SceneGraphStreamReader/Writer do not close the stream
470  Need informative error message for mismatched NioImageBuffer
471  Performance degradation with shader attribute object setValue()
474  Update javadoc for TextureLoader for ImageException
478  Memory leak in TransparencySortController
479  JOGL: Screen door transparency renders incorrectly on JoglPipeline
480  getBounds should cache results
481  JOALSample: cannot load if only URLString is given in MediaContainer
485  ClassCastException when switching shaders in PhongShadingGLSL example
486  Java 3D hangs on some Windows Vista systems
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac +OS X (x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and install it into the JRE along with the Java 3D jar files (or +include it in your PATH/CLASSPATH).
+

+

NOTE: You must install both Java 3D and JOGL into the JRE, +or else you must install neither Java 3D nor JOGL into the +JRE. If you install Java 3D into the JRE and put JOGL on your +CLASSPATH, the JoglPipeline will fail to find the JOGL classes.

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_1/RELEASE-NOTES-beta2.html b/j3d-core/www/j3d1_5_1/RELEASE-NOTES-beta2.html new file mode 100644 index 0000000..b85c416 --- /dev/null +++ b/j3d-core/www/j3d1_5_1/RELEASE-NOTES-beta2.html @@ -0,0 +1,559 @@ + + + + + + Java 3D 1.5.1 Pre-Release Notes + + +

Java 3DTM 1.5.1-beta2 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.1-beta2. +

+ +

Click +here for instructions +on +how +to install this release of +Java 3D +version 1.5.1-beta2.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.1-beta2 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.1-beta2 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.1-beta2 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.1-beta2 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.1-beta2 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000, Windows XP, or Windows Vista
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
    + NOTE: The DirectX version of Java 3D is used if a suitable version + of OpenGL cannot be found. Note also that DirectX is chosen by + default on Windows Vista systems with an ATI graphics card (due to + ATI driver bugs). +
+

Mac OS X

+

The 1.5.1-beta2 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.1-beta2

+

Enhancements

+
    +
  • Windows Vista Support
  • +
  • Pack200 Support for Java Web Start Applications
  • +
  • Logging + Framework
  • +
  • Added support for JNLPAppletLauncher (will be available shortly)
  • +
+

Issues Fixed in 1.5.1-beta2

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
257  Java3D Applet Launcher support
488  ImageComponent3D bug with by-reference images
489  AutoOffScreenCanvas3D: postSwap() is called twice
490  JOALSample fails to load second sample
491  Refactor platform-specific classes to use non-overlapping class names
492  ImageComponent2D.setSubImage throws IllegalArgumentException
+
+

Issues Fixed in 1.5.1-beta1

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
126  Use OpenGL automatic mipmap generation
157  Would like a JOALMixer implementation of AudioEngine3DL2
197  Consider supporting pack200 for Java Web Start / JNLP
226  D3D : fail on stress test for the creation and destruction of Canvases
239  Stencil buffer should be cleared at the start of each frame
274  NPE With Simultaneous View and Content Side PickingBehaviors
293  Need better logging for j3d error, warning, assertion messages.
314  Issue with Stenciled Transparent Objects
347  OffScreen Canvas3D always reloads textures, display lists
348  Programmable shaders do not work for OffScreen Canvas3D
357  Memory leak when using textures with multiple views
362  dynamic assignment if Canvas3D to View makes content disappear
364  Canvas3D.setOffScreenBuffer(null) sometimes hangs
378  Shaders are not rendered when Canvas3D is created and destroyed
381  ByRef, yDown, 4BYTE_ABGR throws ArrayIndexOOB Exception
396  Off-screen Canvas3D / D3D: Resizing crashes VM
402  Off-screen Canvas3D throws Exception on BufferedImage of TYPE_4BYTE_ABGR and TYPE_INT_ARGB
408  Poor quality of auto-generated mipmaps
411  Add Primitive flag to reverse Y for tex coords
412  Exception when updating Y_UP BY_REFERENCE image
414  D3D: NPOT textures not properly disabled on card that lacks support
415  Need ability to disable NPOT textures for raster/background
416  JOGL: ClassCastException in Renderer with NioImageBuffer
417  JOGL: Mip-mapped NPOT textures rendered incorrectly
424  JOALMixer requires the default Viewer's setUserHeadToVworldEnable setting to true
425  NullPointerException in automatic mipmap generation
427  Method with constructor name: ObjectFileMaterial
431  disabled PointSound starts playing when scheduling bounds are entered
433  JCanvas3D crashed when using jogl pipe
434  OutOfMemory after creating millions of RenderAtomListInfo objects
437  SceneGraphStreamWriter NPE
435  Memory leak when reusing an Appearance with a single Texture
438  ConfiguredUniverse & SimpleUniverse constructor missing
441  ArrayIndexOutOfBoundsException in IndexedTriangleArrayRetained Intersect
444  Transform updates overly expensive
446  JCanvas3D and focus
447  Enhance Element Traversal To Improve Pick Hits
449  SceneGraphIO can not support ImageComponent2DURL
452  Java 3D should fall back to D3D if OpenGL not available
453  SceneGraphIO does not support SceneGraphObjects name field
455  Need to disable NPOT textures for older cards that claim to support it.
456  NPOT background ( maybe raster) fail to work if HW doesn't support NPOT texture
457  ClassCastException in MasterControl when updating Texture3D
458  Canvas3D stops rendering on window close
461  ClassCastException thrown when using filters with NioImageBuffer
466  NPE when updating lights with multiple views
467  Add Java3D source jar file as a separate or part of the distribution
468  SceneGraphStreamReader/Writer do not close the stream
470  Need informative error message for mismatched NioImageBuffer
471  Performance degradation with shader attribute object setValue()
474  Update javadoc for TextureLoader for ImageException
478  Memory leak in TransparencySortController
479  JOGL: Screen door transparency renders incorrectly on JoglPipeline
480  getBounds should cache results
481  JOALSample: cannot load if only URLString is given in MediaContainer
485  ClassCastException when switching shaders in PhongShadingGLSL example
486  Java 3D hangs on some Windows Vista systems
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac +OS X (x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and install it into the JRE along with the Java 3D jar files (or +include it in your PATH/CLASSPATH).
+

+

NOTE: You must install both Java 3D and JOGL into the JRE, +or else you must install neither Java 3D nor JOGL into the +JRE. If you install Java 3D into the JRE and put JOGL on your +CLASSPATH, the JoglPipeline will fail to find the JOGL classes.

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_1/RELEASE-NOTES.html b/j3d-core/www/j3d1_5_1/RELEASE-NOTES.html new file mode 100644 index 0000000..08e29a9 --- /dev/null +++ b/j3d-core/www/j3d1_5_1/RELEASE-NOTES.html @@ -0,0 +1,1543 @@ + + + + + + + + + + + Java 3D 1.5.1 Release Notes + + + + + + +

Java 3DTM +1.5.1 +Release Notes

+ + +

This file contains important release information for users of +the +Java 3DTM +API, version +1.5.1. +

+ + + + + +

Click +here for instructions +on +how +to install this release of +Java 3D +version 1.5.1.

+ + +

NOTE: We +recommend that you uninstall +all previous +versions of Java 3D before +installing this version. +

+ + +

System +Requirements

+ + +

The 1.5.1 version of the Java 3D API has been +released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+ + +

Solaris Sparc

+ + +

+The 1.5.1 version of Java 3D for Solaris SPARC requires +the +following: +

+ + +
    + + +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • + + +
  • Solaris 9 or later
  • + + +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • + + +
  • OpenGL 1.3 for Solaris or later. To find your current +version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris +can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • + + +
+ + +

Solaris x86

+ + +

+The 1.5.1 version of Java 3D for Solaris x86/amd64 +requires +the +following: +

+ + +
    + + +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • + + +
  • Solaris 10 or later
  • + + +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • + + +
+ + +

Linux
+ + +

+ + +

The 1.5.1 version of Java 3D for Linux (x86 or +amd64) +requires +the +following:
+ + +

+ + +
    + + +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • + + +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • + + +
+ + +

Windows
+ + +

+ + +

The 1.5.1 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+ + +

+ + +
    + + +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • + + +
  • Windows 2000, Windows XP, or Windows Vista
  • + + +
  • Support for either OpenGL or DirectX as shown below.
    + + +
  • + + +
+ + +
    + + + OpenGL version
    + + + +
      + + +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 +or +later, +available from your graphics card manufacturer. + +
    + + +
+ + +
    + + + DirectX version
    + + + +
      + + +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" +system +property +to "d3d", +for example: + +
        + + + java -Dj3d.rend=d3d ClassName + +
      + + + +
    + + +
    + + +NOTE: The DirectX version of Java 3D is used if a suitable version of +OpenGL cannot be found. Note also that DirectX is chosen by default on +Windows Vista systems with an ATI graphics card (due to ATI driver +bugs). +
+ + +

Mac OS X

+ + +

The 1.5.1 version of Java 3D for Mac OS X (PPC +or x86) +requires the following:
+ + +

+ + + + + +

Improvements +in 1.5.1

+ + +

Enhancements

+ + +
    + + +
  • Windows Vista Support
  • +
  • Automatic fallback to D3D pipeline if OpenGL unavailable
  • +
  • JOALMixer-based audio engine
  • +
  • Automatic mipmap generation
  • +
  • Pack200 support for Java Web Start applications
  • +
  • Logging +Framework
  • + + +
  • Support for new JNLPAppletLauncher utility (based on JOGLAppletLauncher)
  • + + +
+ + +

Issues Fixed in 1.5.1

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
126  Use OpenGL +automatic mipmap generation
157  Would like a +JOALMixer implementation of AudioEngine3DL2
197  Consider supporting +pack200 for Java Web Start / JNLP
226  D3D : fail on +stress test for the creation and destruction of Canvases
239  Stencil buffer +should be cleared at the start of each frame
257  Java3D Applet +Launcher support
274  NPE With +Simultaneous View and Content Side PickingBehaviors
293  Need better logging +for j3d error, warning, assertion messages.
314  Issue with +Stenciled Transparent Objects
347  OffScreen Canvas3D +always reloads textures, display lists
348  Programmable +shaders do not work for OffScreen Canvas3D
357  Memory leak when +using textures with multiple views
362  dynamic assignment +if Canvas3D to View makes content disappear
364  Canvas3D.setOffScreenBuffer(null) +sometimes hangs
378  Shaders are not +rendered when Canvas3D is created and destroyed
381  ByRef, yDown, +4BYTE_ABGR throws ArrayIndexOOB Exception
396  Off-screen Canvas3D +/ D3D: Resizing crashes VM
402  Off-screen Canvas3D +throws Exception on BufferedImage of TYPE_4BYTE_ABGR and TYPE_INT_ARGB
408  Poor quality of +auto-generated mipmaps
411  Add Primitive flag +to reverse Y for tex coords
412  Exception when +updating Y_UP BY_REFERENCE image
414  D3D: NPOT textures +not properly disabled on card that lacks support
415  Need ability to +disable NPOT textures for raster/background
416  JOGL: +ClassCastException in Renderer with NioImageBuffer
417  JOGL: Mip-mapped +NPOT textures rendered incorrectly
424  JOALMixer requires +the default Viewer's setUserHeadToVworldEnable setting to true
425  NullPointerException +in automatic mipmap generation
427  Method with +constructor name: ObjectFileMaterial
430  Deliver JOALMixer +for JNLP and download bundle
+ + +
431  disabled PointSound +starts playing when scheduling bounds are entered
433  JCanvas3D crashed +when using jogl pipe
434  OutOfMemory after +creating millions of RenderAtomListInfo objects
437  SceneGraphStreamWriter +NPE
435  Memory leak when +reusing an Appearance with a single Texture
438  ConfiguredUniverse +& SimpleUniverse constructor missing
441  ArrayIndexOutOfBoundsException +in IndexedTriangleArrayRetained Intersect
444  Transform updates +overly expensive
446  JCanvas3D and focus
447  Enhance Element +Traversal To Improve Pick Hits
449  SceneGraphIO can +not support ImageComponent2DURL
452  Java 3D should fall +back to D3D if OpenGL not available
453  SceneGraphIO does +not support SceneGraphObjects name field
455  Need to disable +NPOT textures for older cards that claim to support it.
456  NPOT background ( +maybe raster) fail to work if HW doesn't support NPOT texture
457  ClassCastException +in MasterControl when updating Texture3D
458  Canvas3D stops +rendering on window close
461  ClassCastException +thrown when using filters with NioImageBuffer
466  NPE when updating +lights with multiple views
467  Add Java3D source +jar file as a separate or part of the distribution
468  SceneGraphStreamReader/Writer +do not close the stream
470  Need informative +error message for mismatched NioImageBuffer
471  Performance +degradation with shader attribute object setValue()
474  Update javadoc for +TextureLoader for ImageException
478  Memory leak in +TransparencySortController
479  JOGL: Screen door +transparency renders incorrectly on JoglPipeline
480  getBounds should +cache results
481  JOALSample: cannot +load if only URLString is given in MediaContainer
485  ClassCastException +when switching shaders in PhongShadingGLSL example
486  Java 3D hangs on +some Windows Vista systems
488  ImageComponent3D +bug with by-reference images
489  AutoOffScreenCanvas3D: +postSwap() is called twice
490  JOALSample fails to +load second sample
491  Refactor +platform-specific classes to use non-overlapping class names
492  ImageComponent2D.setSubImage +throws IllegalArgumentException
494  Group.moveto(null) +throws a NullPointerException
+ + +
496  Big performance hit +in VirtualUniverse.getNodeId
+ + +
500  Reuse JOAL buffers +where possible
+ + +
+ + +
+ + +

JOGL Rendering +Pipeline

+ + +

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac +OS X (x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here +to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+ + +

+ + +

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+ + +
    + + + java -Dj3d.rend=jogl ClassName +
+ + +

You will need to download +JOGL +and install it into the JRE along with the Java 3D jar files +(or +include it in your PATH/CLASSPATH).
+ + +

+ + +

NOTE: You must install both Java 3D and +JOGL into the JRE, +or else you must install neither Java 3D nor JOGL +into the +JRE. If you install Java 3D into the JRE and put JOGL on your +CLASSPATH, the JoglPipeline will fail to find the JOGL classes.

+ + +

More +Information

+ + +

For the latest information on Java 3D, see the main Java 3D +project page +on +java.net.
+ + +

+ + +

Click here +for a list of open issues.

+ + + + diff --git a/j3d-core/www/j3d1_5_2/RELEASE-NOTES-beta1.html b/j3d-core/www/j3d1_5_2/RELEASE-NOTES-beta1.html new file mode 100644 index 0000000..7b974ee --- /dev/null +++ b/j3d-core/www/j3d1_5_2/RELEASE-NOTES-beta1.html @@ -0,0 +1,325 @@ + + + + + Java 3D 1.5.2 Pre-Release Notes + + +

Java 3DTM 1.5.2-beta1 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.2-beta1. +

+ +

Click +here for instructions +on +how +to install this release of +Java 3D +version 1.5.2-beta1.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.2-beta1 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.2-beta1 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.2-beta1 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.2-beta1 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.2-beta1 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000, Windows XP, or Windows Vista
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
    + NOTE: The DirectX version of Java 3D is used if a suitable version + of OpenGL cannot be found. Note also that DirectX is chosen by + default on Windows Vista systems with an ATI graphics card (due to + ATI driver bugs). +
+

Mac OS X

+

The 1.5.2-beta1 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.2-beta1

+

Enhancements

+
    +
  • Source code license changed to GPL v2 + CLASSPATH
  • +
+

Issues Fixed in 1.5.2-beta1
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
179  OrbitBehavior.setRotationCenter gives spurious view shift
483  NullPointerException when writing Font3D using scenegraph.io
506  NullPointerException: Calling getNominalSensorRotation in WandViewBehavior when internal nominalSensorRotation is null causes a NullPointerException.
513  Down-rev D3D driver can cause JVM to crash
514  NPE in Wonderland : triggered in cached bounds computation
519  IntersectionInfo.getGeometry return null for IndexedArrayGeometry
525  JOALMixer only playing one sample
532  Background geometry BG isn't saved with SceneGraphFileWriter
534  ClassNotFoundException when running applet if Java 3D installed into JRE
538  Machine precision bug in AxisAngle4d and Quat4d
540  ArrayIndexOutOfBoundsException when calling setPickable
541  Bound.closest_point() method creates unused Matrix3d
544  GroupRetained.getBounds() should return BoundingBox?
545  Update docs to discourage installing Java 3D into JRE
548  RFE - Disable getLock() / unLock() on non-alive GeometryArray
555  Muting a PointSound causes a ClassCastException
560  Use D3DCREATE_FPU_PRESERVE flag on D3D pipeline
561  Decrease memory footprint of BoundingBox
562  Error occurs when Canvas3D removed from View
563  Background cloneNode() fails with Background geometry
567  Update license to GPL v2 + CLASSPATH
569  ImageComponent.ALLOW_IMAGE_READ is false
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac OS X +(x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and include it in your PATH/CLASSPATH along with the Java 3D jar files.
+

+

NOTE: Installing the j3d or jogl jars and native libs into the "ext" +directory of the JRE is strongly discouraged. Doing so can cause +conflicts with third-party applications launched via Java Web Start, +and causes confusion later when upgrading the distribution. +

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_2/RELEASE-NOTES-beta2.html b/j3d-core/www/j3d1_5_2/RELEASE-NOTES-beta2.html new file mode 100644 index 0000000..5d678bf --- /dev/null +++ b/j3d-core/www/j3d1_5_2/RELEASE-NOTES-beta2.html @@ -0,0 +1,348 @@ + + + + + Java 3D 1.5.2 Pre-Release Notes + + +

Java 3DTM 1.5.2-beta2 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.2-beta2. +

+ +

Click +here for instructions +on +how +to install this release of +Java 3D +version 1.5.2-beta2.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.2-beta2 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.2-beta2 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.2-beta2 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.2-beta2 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.2-beta2 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000, Windows XP, or Windows Vista
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
    + NOTE: The DirectX version of Java 3D is used if a suitable version + of OpenGL cannot be found. Note also that DirectX is chosen by + default on Windows Vista systems with an ATI graphics card (due to + ATI driver bugs). +
+

Mac OS X

+

The 1.5.2-beta2 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.2-beta2

+

Issues Fixed in 1.5.2-beta2

+
+ + + + + + + + + + + + + + + + + + +
Issue  Description
543  J3DClock does not adjust to clock skew
583  A disposed Graphics2D remains in Canvas3D after removal and addtion
+

Improvements in 1.5.2-beta1

+

Enhancements

+
    +
  • Source code license changed to GPL v2 + CLASSPATH
  • +
+

Issues Fixed in 1.5.2-beta1
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
179  OrbitBehavior.setRotationCenter gives spurious view shift
483  NullPointerException when writing Font3D using scenegraph.io
506  NullPointerException: Calling getNominalSensorRotation in WandViewBehavior when internal nominalSensorRotation is null causes a NullPointerException.
513  Down-rev D3D driver can cause JVM to crash
514  NPE in Wonderland : triggered in cached bounds computation
519  IntersectionInfo.getGeometry return null for IndexedArrayGeometry
525  JOALMixer only playing one sample
532  Background geometry BG isn't saved with SceneGraphFileWriter
534  ClassNotFoundException when running applet if Java 3D installed into JRE
538  Machine precision bug in AxisAngle4d and Quat4d
540  ArrayIndexOutOfBoundsException when calling setPickable
541  Bound.closest_point() method creates unused Matrix3d
544  GroupRetained.getBounds() should return BoundingBox?
545  Update docs to discourage installing Java 3D into JRE
548  RFE - Disable getLock() / unLock() on non-alive GeometryArray
555  Muting a PointSound causes a ClassCastException
560  Use D3DCREATE_FPU_PRESERVE flag on D3D pipeline
561  Decrease memory footprint of BoundingBox
562  Error occurs when Canvas3D removed from View
563  Background cloneNode() fails with Background geometry
567  Update license to GPL v2 + CLASSPATH
569  ImageComponent.ALLOW_IMAGE_READ is false
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac OS X +(x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and include it in your PATH/CLASSPATH along with the Java 3D jar files.
+

+

NOTE: Installing the j3d or jogl jars and native libs into the "ext" +directory of the JRE is strongly discouraged. Doing so can cause +conflicts with third-party applications launched via Java Web Start, +and causes confusion later when upgrading the distribution. +

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/j3d1_5_2/RELEASE-NOTES.html b/j3d-core/www/j3d1_5_2/RELEASE-NOTES.html new file mode 100644 index 0000000..d6f0d4b --- /dev/null +++ b/j3d-core/www/j3d1_5_2/RELEASE-NOTES.html @@ -0,0 +1,344 @@ + + + + + Java 3D 1.5.2 Release Notes + + +

Java 3DTM 1.5.2 +Release Notes

+

This file contains important release information for users of +the +Java 3DTM API, version +1.5.2. +

+ +

Click +here for instructions +on +how +to install this release of +Java 3D +version 1.5.2.

+

NOTE: We recommend that you uninstall all previous versions of Java 3D before +installing this version. +

+

System Requirements

+

The 1.5.2 version of the Java 3D API has been released +for +Solaris (both sparc and x86/amd64), Linux (both x86 and amd64), Windows +(both x86 and amd64), and +Mac OS X (both PPC and x86). +

+

Solaris Sparc

+

+The 1.5.2 version of Java 3D for Solaris SPARC requires the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 9 or later
  • +
  • Frame Buffer with OpenGL 1.3 support or better (XVR-600, +XVR-1200, Expert3D, etc.). A frame buffer with OpenGL 1.2 support will +work, but with reduced texture mapping functionality.
  • +
  • OpenGL 1.3 for Solaris or later. To find your current version, +use: "pkginfo -l SUNWglrt". OpenGL for Solaris can be +obtained at: http://www.sun.com/software/graphics/opengl/
  • +
+

Solaris x86

+

+The 1.5.2 version of Java 3D for Solaris x86/amd64 requires +the +following: +

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Solaris 10 or later
  • +
  • NVIDIA Frame Buffer with OpenGL 1.3 or later
  • +
+

Linux
+

+

The 1.5.2 version of Java 3D for Linux (x86 or amd64) +requires +the +following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Graphics adapter with driver that supports the GLX +extension: GLX +1.3 or later and OpenGL 1.3 or later. A graphics adapter with OpenGL +1.2 support will work, but with reduced texture mapping functionality.
  • +
+

Windows
+

+

The 1.5.2 version of Java 3D for Windows 2000, +Windows XP (x86 or amd64), or Windows Vista +requires the following:
+

+
    +
  • JDK 1.5.0 or later from Sun Microsystems: http://java.sun.com/j2se/
  • +
  • Windows 2000, Windows XP, or Windows Vista
  • +
  • Support for either OpenGL or DirectX as shown below.
    +
  • +
+
    + OpenGL version
    +
      +The (default) OpenGL renderer of Java 3D requires OpenGL 1.3 or +later, +available from your graphics card manufacturer. +
    +
+
    + DirectX version
    +
      +The (optional) DirectX renderer of Java 3D requires +DirectX 9.0 or +later, which is available from Microsoft at: http://www.microsoft.com/windows/directx/ +. The DirectX version of +Java 3D is selected by setting the "j3d.rend" system +property +to "d3d", +for example: +
        + java -Dj3d.rend=d3d ClassName +
      +
    +
    + NOTE: The DirectX version of Java 3D is used if a suitable version + of OpenGL cannot be found. Note also that DirectX is chosen by + default on Windows Vista systems with an ATI graphics card (due to + ATI driver bugs). +
+

Mac OS X

+

The 1.5.2 version of Java 3D for Mac OS X (PPC or x86) +requires the following:
+

+ +

Improvements in 1.5.2

+

Enhancements

+
    +
  • Source code license changed to GPL v2 + CLASSPATH
  • +
+

Issues Fixed in 1.5.2

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Issue  Description
179  OrbitBehavior.setRotationCenter gives spurious view shift
483  NullPointerException when writing Font3D using scenegraph.io
506  NullPointerException: Calling getNominalSensorRotation in WandViewBehavior when internal nominalSensorRotation is null causes a NullPointerException.
510  J3DGraphics2D context lost when canvas changes frame
513  Down-rev D3D driver can cause JVM to crash
514  NPE in Wonderland : triggered in cached bounds computation
519  IntersectionInfo.getGeometry return null for IndexedArrayGeometry
525  JOALMixer only playing one sample
532  Background geometry BG isn't saved with SceneGraphFileWriter
534  ClassNotFoundException when running applet if Java 3D installed into JRE
538  Machine precision bug in AxisAngle4d and Quat4d
540  ArrayIndexOutOfBoundsException when calling setPickable
541  Bound.closest_point() method creates unused Matrix3d
543  J3DClock does not adjust to clock skew
544  GroupRetained.getBounds() should return BoundingBox?
545  Update docs to discourage installing Java 3D into JRE
548  RFE - Disable getLock() / unLock() on non-alive GeometryArray
555  Muting a PointSound causes a ClassCastException
560  Use D3DCREATE_FPU_PRESERVE flag on D3D pipeline
561  Decrease memory footprint of BoundingBox
562  Error occurs when Canvas3D removed from View
563  Background cloneNode() fails with Background geometry
567  Update license to GPL v2 + CLASSPATH
569  ImageComponent.ALLOW_IMAGE_READ is false
583  A disposed Graphics2D remains in Canvas3D after removal and addtion
585  ClassCastException in TransformStructure.java
+
+

JOGL Rendering Pipeline

+

A JOGL rendering pipeline, as described +in issue +229, is now +available on all supported platforms, including Apple Mac OS X +(x86 or PPC). The easiest way to run Java 3D applications +using the JOGL +pipeline is via Java Webstart from your browser (with no setup +required). +Click here to run +a Java 3D example program from your browser via the +JOGL pipeline. These +examples will use JOGL on Mac OS X and the native OpenGL pipeline on +all +other platforms.
+

+

The JOGL renderer is the default on Mac OS X. +You can select the JOGL renderer on other platforms by setting the "j3d.rend" +system +property +to "jogl", +for example: +

+
    + java -Dj3d.rend=jogl ClassName +
+

You will need to download +JOGL +and include it in your PATH/CLASSPATH along with the Java 3D jar files.
+

+

NOTE: Installing the j3d or jogl jars and native libs into the "ext" +directory of the JRE is strongly discouraged. Doing so can cause +conflicts with third-party applications launched via Java Web Start, +and causes confusion later when upgrading the distribution. +

+

More Information

+

For the latest information on Java 3D, see the main Java 3D project page +on +java.net.
+

+

Click here +for a list of open issues.

+ + diff --git a/j3d-core/www/project_tools.html b/j3d-core/www/project_tools.html new file mode 100644 index 0000000..bc57931 --- /dev/null +++ b/j3d-core/www/project_tools.html @@ -0,0 +1,12 @@ + + + + + Project Tools + + + + + + diff --git a/j3d-core-utils/COPYRIGHT.txt b/j3d-core-utils/COPYRIGHT.txt new file mode 100644 index 0000000..b02644e --- /dev/null +++ b/j3d-core-utils/COPYRIGHT.txt @@ -0,0 +1,77 @@ +Copyright (c) 2007 Sun Microsystems, Inc., 4150 Network Circle, Santa +Clara, California 95054, U.S.A. All rights reserved. + +Sun Microsystems, Inc. has intellectual property rights relating to +technology embodied in the product that is described in this +document. In particular, and without limitation, these intellectual +property rights may include one or more of the U.S. patents listed at +http://www.sun.com/patents and one or more additional patents or +pending patent applications in the U.S. and in other countries. + +U.S. Government Rights - Commercial software. Government users are +subject to the Sun Microsystems, Inc. standard license agreement and +applicable provisions of the FAR and its supplements. + +Use is subject to license terms. + +This distribution may include materials developed by third parties. + +Parts of the product may be derived from Berkeley BSD systems, +licensed from the University of California. UNIX is a registered +trademark in the U.S. and in other countries, exclusively licensed +through X/Open Company, Ltd. + +Sun, Sun Microsystems, the Sun logo, Java, Solaris, Java 3D, the 100% +Pure Java logo, the Duke logo and the Java Coffee Cup logo are +trademarks or registered trademarks of Sun Microsystems, Inc. in the +U.S. and other countries. + +This product is covered and controlled by U.S. Export Control laws and +may be subject to the export or import laws in other countries. +Nuclear, missile, chemical biological weapons or nuclear maritime end +uses or end users, whether direct or indirect, are strictly +prohibited. Export or reexport to countries subject to U.S. embargo or +to entities identified on U.S. export exclusion lists, including, but +not limited to, the denied persons and specially designated nationals +lists is strictly prohibited. + +Copyright (c) 2007 Sun Microsystems, Inc., 4150 Network Circle, Santa +Clara, California 95054, Etats-Unis. Tous droits réservés. + +Sun Microsystems, Inc. détient les droits de propriété intellectuels +relatifs à la technologie incorporée dans le produit qui est décrit +dans ce document. En particulier, et ce sans limitation, ces droits de +propriété intellectuelle peuvent inclure un ou plus des brevets +américains listés à l'adresse http://www.sun.com/patents et un ou les +brevets supplémentaires ou les applications de brevet en attente aux +Etats - Unis et dans les autres pays. + +L'utilisation est soumise aux termes de la Licence. + +Cette distribution peut comprendre des composants développés par des +tierces parties. + +Des parties de ce produit pourront être dérivées des systèmes Berkeley +BSD licenciés par l'Université de Californie. UNIX est une marque +déposée aux Etats-Unis et dans d'autres pays et licenciée +exclusivement par X/Open Company, Ltd. + +Sun, Sun Microsystems, le logo Sun, Java, Solaris, Java 3D, le logo +100% Pure Java, le logo Duke et le logo Java Coffee Cup sont des +marques de fabrique ou des marques déposées de Sun Microsystems, +Inc. aux Etats-Unis et dans d'autres pays. + +Ce produit est soumis à la législation américaine en matière de +contrôle des exportations et peut être soumis à la règlementation en +vigueur dans d'autres pays dans le domaine des exportations et +importations. Les utilisations, ou utilisateurs finaux, pour des armes +nucléaires,des missiles, des armes biologiques et chimiques ou du +nucléaire maritime, directement ou indirectement, sont strictement +interdites. Les exportations ou réexportations vers les pays sous +embargo américain, ou vers des entités figurant sur les listes +d'exclusion d'exportation américaines, y compris, mais de manière non +exhaustive, la liste de personnes qui font objet d'un ordre de ne pas +participer, d'une façon directe ou indirecte, aux exportations des +produits ou des services qui sont régis par la législation américaine +en matière de contrôle des exportations et la liste de ressortissants +spécifiquement désignés, sont rigoureusement interdites. diff --git a/j3d-core-utils/LICENSE.txt b/j3d-core-utils/LICENSE.txt new file mode 100644 index 0000000..d85bd8c --- /dev/null +++ b/j3d-core-utils/LICENSE.txt @@ -0,0 +1,35 @@ +Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistribution of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistribution in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +Neither the name of Sun Microsystems, Inc. or the names of +contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +This software is provided "AS IS," without a warranty of any +kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND +WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY +EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL +NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF +USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS +DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR +ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND +REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR +INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +You acknowledge that this software is not designed, licensed or +intended for use in the design, construction, operation or +maintenance of any nuclear facility. diff --git a/j3d-core-utils/README-FIRST.txt b/j3d-core-utils/README-FIRST.txt new file mode 100644 index 0000000..a687e9b --- /dev/null +++ b/j3d-core-utils/README-FIRST.txt @@ -0,0 +1,12 @@ +The source code for the j3d-core-utils project is copyrighted code +that is licensed to individuals or companies who download or otherwise +access the code. + +The copyright notice for this project is in COPYRIGHT.txt + +The source code license information for this project is in LICENSE.txt + +Additional information and license restrictions for third party source +code are found in the THIRDPARTY-LICENSE-*.txt files. + +Instructions for building this project are in README-build.html diff --git a/j3d-core-utils/README-build.html b/j3d-core-utils/README-build.html new file mode 100644 index 0000000..ecd1dab --- /dev/null +++ b/j3d-core-utils/README-build.html @@ -0,0 +1,61 @@ + + + + + + README-build: build instructions for the j3d-core-utils project + + +

Building +j3d-core-utils

+

The j3d-core-utils project is built as part of the j3d-core +project. See the README-build.html +file in the "j3d-core" directory for instructions.
+

+ + diff --git a/j3d-core-utils/THIRDPARTY-LICENSE-DISTANCE.txt b/j3d-core-utils/THIRDPARTY-LICENSE-DISTANCE.txt new file mode 100644 index 0000000..2c86b0a --- /dev/null +++ b/j3d-core-utils/THIRDPARTY-LICENSE-DISTANCE.txt @@ -0,0 +1,104 @@ +The following additional provisions apply to third party software +included as part of this product. + + com/sun/j3d/internal/ + Distance.java + +Copyright (c) 2004 Magic Software, Inc. All Rights Reserved. + +The Wild Magic Library (WML) source code is supplied under the terms of +the license agreement http://www.magic-software.com/License/WildMagic.pdf +and may not be copied or disclosed except in accordance with the terms of +that agreement. + +---------- Text of WildMagic.pdf downloaded 8-Jun-2004 ---------- + +License Agreement for the Wild Magic (Version 2) Software Library +Revision 1: January 28, 2004 + +THIS WILD MAGIC (VERSION 2) SOFTWARE LICENSE AGREEMENT ("Agreement") +is made by and between Magic Software, Inc. ("We/Us/Our"), a North +Carolina corporation, having its principal place of business at 6006 +Meadow Run Court, Chapel Hill, North Carolina 27516 and any person or +legal entity using or accepting any software governed by this +Agreement ("You/Your"). This Agreement shall be effective on the first +day you use or accept software ("The Software") governed by this +Agreement, whichever is earlier. + +THE PARTIES AGREE as follows: + +1. Grant. We grant you a nonexclusive, nontransferable, and perpetual + license to use The Software subject to the terms and conditions of the + Agreement: + + (a) There is no charge to you for this license. + + (b) The Software may be used, edited, modified, copied, and + distributed by you for noncommercial products. + + (c) The Software may be used, edited, modified, copied, and + distributed by you for commercial products provided that such + products are not intended to wrap The Software solely for the + purposes of selling it as if it were your own product. The + intent of this clause is that you use The Software, in part or + in whole, to assist you in building your own original + products. An example of acceptable use is to incorporate the + graphics portion of The Software in a game to be sold to an end + user. An example that violates this clause is to compile a + library from only The Software, bundle it with the headers + files as a Software Development Kit (SDK), then sell that SDK + to others. If there is any doubt about whether you can use The + Software for a commercial product, contact us and explain what + portions you intend to use. We will consider creating a + separate legal document that grants you permission to use those + portions of The Software in your commercial product. + +2. Limitation of Liability. We will have no liability for special, + incidental or consequential damages even if advised of the + possibility of such damages. We will not be liable for any other + damages or loss in any way connected with The Software. + +3. Warranties. We make no warranties at all. The Software is + transferred to you on an as-is basis. You use The Software at your + own peril. You assume all risk of loss for all claims or + controversies, now existing or hereafter, arising out of use of The + Software. We shall have no liability based on a claim that your use + or combination of The Software with products or data not supplied + by us infringes any patent, copyright, or proprietary right. All + other warranties, expressed or implied, including, without + limitation, any warranty of merchantability or fitness for a + particular purpose are hereby excluded. + + +4. Taxes and Duties. You shall pay or reimburse us for federal, state, + provincial, local or other tariffs, duties and taxes not based on + our net income, including all taxes, tariffs, duties, or amounts + levied in lieu thereof, based on charges payable under this + Agreement or based on The Software, its use or any services + performed hereunder, whether such tariffs, duties or taxes are now + or hereafter imposed under the authority of any federal, state, + provincial, local or other jurisdiction. + +5. Entire Agreement, Amendments. This Agreement represents the + complete and exclusive statement of the Agreements between the + parties relating to the licensing of The Software and maintenance + of The Software and supersedes all prior Agreements and + representations between them relating to such + licensing. Modifications to this Agreement shall not be effective + unless in writing and signed by the party against whom enforcement + is sought. The terms of this Agreement shall not be amended or + changed by any purchase order or acknowledgment even if we have + signed such documents. + +6. North Carolina Law, Severability. This Agreement will be governed + by North Carolina law. If any provision of this Agreement shall be + unlawful, void, or for any reason unenforceable, it shall be deemed + severable from and shall in no way affect the validity or + enforceability of the remaining provisions of this Agreement. + +7. Force Majeure. It is herein agreed that neither party to this + Agreement shall be liable for delays for failures in performance + resulting from acts beyond the control of such party. Such acts + include, without limitation, acts of God, strikes, lockouts, riots, + acts of war, epidemics, governmental regulations superimposed after + the fact, fire, power failures, earthquakes or other disasters. diff --git a/j3d-core-utils/THIRDPARTY-LICENSE-FIST.txt b/j3d-core-utils/THIRDPARTY-LICENSE-FIST.txt new file mode 100644 index 0000000..712723e --- /dev/null +++ b/j3d-core-utils/THIRDPARTY-LICENSE-FIST.txt @@ -0,0 +1,23 @@ +The following additional information pertains to third party software +included as part of this product. No additional restrictions are +placed on this source code, except that this attribution must be +distributed with the source code. + + com/sun/j3d/utils/geometry/ + BBox.java, Basic.java, BottleNeck.java, Bridge.java, + Clean.java, Degenerate.java, Desperate.java, Distance.java, + EarClip.java, Heap.java, HeapNode.java, Left.java, + ListNode.java, NoHash.java, Numerics.java, Orientation.java, + PntNode.java, Project.java, Simple.java, Stripifier.java, + StripifierStats.java, Triangle.java, Triangulator.java + +The reference to Fast Industrial Strength Triangulation (FIST) code +in this release by Sun Microsystems is related to Sun's rewrite of +an early version of FIST. FIST was originally created by Martin +Held and Joseph Mitchell at Stony Brook University and is +incorporated by Sun under an agreement with The Research Foundation +of SUNY (RFSUNY). The current version of FIST is available for +commercial use under a license agreement with RFSUNY on behalf of +the authors and Stony Brook University. Please contact the Office +of Technology Licensing at Stony Brook, phone 631-632-9009, for +licensing information. diff --git a/j3d-core-utils/THIRDPARTY-LICENSE-MAINFRAME.txt b/j3d-core-utils/THIRDPARTY-LICENSE-MAINFRAME.txt new file mode 100644 index 0000000..0f15a58 --- /dev/null +++ b/j3d-core-utils/THIRDPARTY-LICENSE-MAINFRAME.txt @@ -0,0 +1,29 @@ +The following additional provisions apply to third party software +included as part of this product. + + com/sun/j3d/utils/applet/ + MainFrame.java - run an Applet as an application in AWT Frame + JMainFrame.java - run an Applet as an application in Swing JFrame + +Copyright (C) 1996 by Jef Poskanzer . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/j3d-core-utils/build.xml b/j3d-core-utils/build.xml new file mode 100644 index 0000000..281879b --- /dev/null +++ b/j3d-core-utils/build.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + NOTE: You must run ant from the j3d-core directory + + + diff --git a/j3d-core-utils/src/classes/ToolsVersion b/j3d-core-utils/src/classes/ToolsVersion new file mode 100644 index 0000000..cbfaf18 --- /dev/null +++ b/j3d-core-utils/src/classes/ToolsVersion @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Specification-Title: +Specification-Version: 1.5 +Specification-Vendor: @SPEC_VENDOR@ +Implementation-Title: 3D Utilities +Implementation-Version: @VERSION_BASE@ +Implementation-Vendor: @IMPL_VENDOR@ +Extension-Name: javax.media.j3d +Implementation-Vendor-Id: @IMPL_VENDOR_ID@ diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/ExceptionStrings.properties b/j3d-core-utils/src/classes/share/com/sun/j3d/ExceptionStrings.properties new file mode 100644 index 0000000..363945c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/ExceptionStrings.properties @@ -0,0 +1,78 @@ +Intersect0=Intersect.rayAndQuad : This quad has less than 4 points! +Intersect1=Intersect.rayAndTriangle : This triangle has less than 3 points! +Intersect3=Intersect.segmentAndQuad : This quad has less than 4 points! +Intersect5=Intersect.segmentAndTriangle:This triange has less than 3 points! +Intersect6=Intersect.segmentAndTriangle : This triange has less than 3 points! +Intersect7=Intersect.pointAndquad : This quad has less than 4 points! +Intersect9=Intersect.pointAndTriangle: This triange has less than 3 points! +Intersect10=Intersect.pointAndTriangle : This triange has less than 3 points! +Intersect11=Intersect.rayAndLine : This line has less than 2 points! +Intersect13=Intersect.segmentAndLine : This line has less than 2 points! +TCBKeyFrame0=TCBKeyFrame: tension value should be between -1 and 1 +TCBKeyFrame1=TCBKeyFrame: bias value should be between -1 and 1 +TCBKeyFrame2=TCBKeyFrame: continuity value should be between -1 and 1 +TCBSplinePathInterpolator0=TCBSplinePathInterpolator: need at least 2 Key Frames for the interpolator +TCBSplinePathInterpolator1=TCBSplinePathInterpolator: first key frame should have knot value of 0.0 +TCBSplinePathInterpolator2=TCBSplinePathInterpolator: last key frame should have knot value of 1.0 +TCBSplinePathInterpolator3=TCBSplinePathInterpolator: Key Frame knot values not in sequence +CubicSplineCurve0=CubicSplineCurve needs at least 4 key frames +KBKeyFrame0=KBKeyFrame: tension value should be between -1 and 1 +KBKeyFrame1=KBKeyFrame: bias value should be between -1 and 1 +KBKeyFrame2=KBKeyFrame: continuity value should be between -1 and 1 +KBSplinePathInterpolator0=KBSplinePathInterpolator: need at least 2 Key Frames for the interpolator +KBSplinePathInterpolator1=KBSplinePathInterpolator: first key frame should have knot value of 0.0 +KBSplinePathInterpolator2=KBSplinePathInterpolator: last key frame should have knot value of 1.0 +KBSplinePathInterpolator3=KBSplinePathInterpolator: Key Frame knot values not in sequence +KBCubicSplineCurve0=KBCubicSplineCurve needs at least 4 key frames +CompressedGeometry0=CompressedGeometry: start+size exceeds geometry length +CompressedGeometry4=CompressedGeometry: target buffer is too small +CompressedGeometry7=CompressedGeometry: cannot directly access data in byReference mode +CompressedGeometry8=CompressedGeometry: must be in byReference mode to use this method +CompressedGeometry9=CompressedGeometry: NIO buffer support is not implemented +GeneralizedStrip0=GeneralizedStrip: strip ended incompletely +GeometryDecompressor0=GeometryDecompressor: start+length > data array size +GeometryDecompressor1=GeometryDecompressor: bad delta normal in compressed buffer +GeometryDecompressorShape3D0=GeometryDecompressorShape3D: bad triangle output type +GeometryDecompressorShape3D1=GeometryDecompressorShape3D: bad buffer data type +GeometryInfo0=Illegal primitive. +GeometryInfo1=Illegal use of deprecated setTextureCoordinateIndices(int[]) +GeometryInfo2=Length of float array not a multiple of dimensionality of texcoords +GeometryInfo3=Coordinate data required. +GeometryInfo4=Color Index list set with no color list set. +GeometryInfo5=Index lists must all be the same length +GeometryInfo6=StripCounts inconsistent with primitive +GeometryInfo7=stripCounts sum inconsistent with number of vertices. +GeometryInfo8=Sum of contourCounts must equal length of stripCounts array. +GeometryInfo9=Data must be one of Point3f, Color3f, Color4f, Vector3f, TexCoord2f, TexCoord3f or TexCoord4f. +GeometryInfo10=Missing Texture Coordinate data list +GeometryInfo11=Normal Index list set with no normal list set. +GeometryInfo12=For triangles, number of vertices must be multiple of 3. +GeometryInfo13=For quads, number of vertices must be multiple of 4. +GeometryInfo14=contourCounts only useful when primitive is POLYGON_ARRAY. +GeometryInfo15=2D texture coordinates not specified. +GeometryInfo16=3D texture coordinates not specified. +GeometryInfo17=4D texture coordinates not specified. +GeometryInfo18=Invalid texture coordinate set index. +GeometryInfo19=Missing Index List. +GeometryInfo20=Non-coordinate index list set in USE_COORD_INDEX_ONLY mode +GeometryInfo21=setTextureCoordinateParams not called +GeometryInfoGenerator0=Unsupported geometry type +Triangulator0=GeometryInfo must have primitive type POLYGON_ARRAY. +ViewingPlatform0=Multiple Viewer support not implemented +ViewingPlatform1=TransformGroup does not exist +DistanceAttenuation0=Distance attenuation array null +VrmlParser0=VRML binary parser disabled +LwsMotion0=Number of motion channels != 9! +LwoSurface0=VSPC problem +LwoParser0=File not of FORM-length-LWOB format +LwsEnvelope0=Number of envelope channels != 1! +SwitchPathInterpolator0=SwitchPathInterpolator: length of knots and numChildren must be equal +FloatValueInterpolator0=FloatValueInterpolator: first knot is not 0.0 +FloatValueInterpolator1=FloatValueInterpolator: last knot is not 1.0 +FloatValueInterpolator2=FloatValueInterpolator: knot values out of order +FloatValueInterpolator3=FloatValueInterpolator: number of knots and values must be equal +JavaSoundMixer0=JavaSoundMixer.prepareSound - bad URL +Behavior0=Cannot call addListener on a Behavior that was not created as a listener. +Stripifier0=Cannot getStripifierStats on a Stripifier object that was not created with the COLLECT_STATS flag. +OrbitBehavior0=Specified function must be one of ROTATE, TRANSLATE or ZOOM. +OrbitBehavior1=Minimum Orbit radius must be > 0.0. diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine.java new file mode 100644 index 0000000..f04ba3c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine.java @@ -0,0 +1,202 @@ +/* + * $RCSfile: AudioEngine.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:02 $ + * $State: Exp $ + */ + +package com.sun.j3d.audioengines; + +import javax.media.j3d.*; + +/** + * The AudioEngine Class defines an audio output device that generates + * sound 'image' from scene graph. + * An AudioEngine object encapsulates the AudioDevice's basic information. + * + *

+ * NOTE: AudioEngine developers should not subclass this class directly. + * Subclass AudioEngine3DL2 instead. + */ +public abstract class AudioEngine implements AudioDevice { + + /* + * This device's UNIX file descriptor + */ + int fileDescriptor; + + /* + * Type of audio output device J3D sound is played over: + * HEADPHONE, MONO_SPEAKER, STEREO_SPEAKERS + */ + int audioPlaybackType = HEADPHONES; + + /* + * Distance from center ear (midpoint between ears) to physical speaker. + * Default reflects distance for headphones. + * For two speakers it is assumed that the speakers are the same + * distance from the listener and that + */ + float distanceToSpeaker = 0.0f; + + /* + * Angle between the vector from center ear parallel to head coordiate + * Z axis and the vector from the center ear to the speaker. + * For two speakers it is assumed that the speakers are placed at the + * same angular offset from the listener. + */ + float angleOffsetToSpeaker = 0.0f; + + /* + * Channels currently available + */ + int channelsAvailable = 8; + + /* + * Total number of Channels ever available + */ + int totalChannels = 8; + + /** + * Construct a new AudioEngine with the specified P.E. + * @param physicalEnvironment the physical environment object where we + * want access to this device. + */ + public AudioEngine(PhysicalEnvironment physicalEnvironment ) { + physicalEnvironment.setAudioDevice(this); + } + + /** + * Code to initialize the device + * @return flag: true is initialized sucessfully, false if error + */ + public abstract boolean initialize(); + + /** + * Code to close the device + * @return flag: true is closed sucessfully, false if error + */ + public abstract boolean close(); + + /* + * Audio Playback Methods + */ + /** + * Set Type of Audio Playback physical transducer(s) sound is output to. + * Valid types are HEADPHONE, MONO_SPEAKER, STEREO_SPEAKERS + * @param type of audio output device + */ + public void setAudioPlaybackType(int type) { + audioPlaybackType = type; + } + + /** + * Get Type of Audio Playback Output Device + * returns audio playback type to which sound is currently output + */ + public int getAudioPlaybackType() { + return audioPlaybackType; + } + + /** + * Set Distance from the Center Ear to a Speaker + * @param distance from the center ear and to the speaker + */ + public void setCenterEarToSpeaker(float distance) { + distanceToSpeaker = distance; + } + + /** + * Get Distance from Ear to Speaker + * returns value set as distance from listener's ear to speaker + */ + public float getCenterEarToSpeaker() { + return distanceToSpeaker; + } + + /** + * Set Angle Offset To Speaker + * @param angle in radian between head coordinate Z axis and vector to speaker */ + public void setAngleOffsetToSpeaker(float angle) { + angleOffsetToSpeaker = angle; + } + + /** + * Get Angle Offset To Speaker + * returns value set as angle between vector to speaker and Z head axis + */ + public float getAngleOffsetToSpeaker() { + return angleOffsetToSpeaker; + } + + /** + * Query total number of channels available for sound rendering + * for this audio device. + * returns number of maximum sound channels you can run with this + * library/device-driver. + */ + public int getTotalChannels() { + // this method should be overridden by a device specific implementation + return (totalChannels); + } + + /** + * Query number of channels currently available for use by the + * returns number of sound channels currently available (number + * not being used by active sounds. + */ + public int getChannelsAvailable() { + return (channelsAvailable); + } + + /** + * Query number of channels that would be used to render a particular + * sound node. + * @param sound refenence to sound node that query to be performed on + * returns number of sound channels used by a specific Sound node + * @deprecated This method is now part of the Sound class + */ + public int getChannelsUsedForSound(Sound sound) { + if (sound != null) + return sound.getNumberOfChannelsUsed(); + else + return -1; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine3D.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine3D.java new file mode 100644 index 0000000..db0d170 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine3D.java @@ -0,0 +1,473 @@ +/* + * $RCSfile: AudioEngine3D.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:02 $ + * $State: Exp $ + */ + +package com.sun.j3d.audioengines; + +import javax.media.j3d.*; +import javax.vecmath.*; +import java.util.ArrayList; + + +/** + * The AudioEngine3D Class defines an audio output device that generates + * sound 'image' from high-level sound parameters passed to it during + * scene graph. + * + *

+ * The methods in this class are meant to be optionally overridden by an + * extended class. This extended class would provice device specific code. + * + *

+ * Error checking on all parameters passed to these methods is already + * explicitly being done by the Java 3D core code that calls these methods. + * + *

+ * NOTE: AudioEngine developers should not subclass this class directly. + * Subclass AudioEngine3DL2 instead. + */ + +public abstract class AudioEngine3D extends AudioEngine implements AudioDevice3D +{ + /* + * Identifiers of sample associated with sound source + * This array grows as the AudioDevice3D implementation requires it larger. + */ + protected ArrayList samples = new ArrayList(64); + + /** + * Current View sound is being rendered + */ + protected View currentView = (View)null; + + /* + * current Aural attribute Parameters + */ + protected AuralParameters attribs = new AuralParameters(); + + /** + * Construct a new AudioEngine with the specified PhysicalEnvironment. + * @param physicalEnvironment the physical environment object where we + * want access to this device. + */ + public AudioEngine3D(PhysicalEnvironment physicalEnvironment ) { + super(physicalEnvironment); + } + + /* + * + * Methods that affect AudioEngine3D fields that are NOT associated + * with a specific sound sample + * + */ + + /** + * Save a reference to the current View object. + * @param reference to current view object + */ + public void setView(View reference) { + currentView = reference; + return; + } + /** + * Get reference to the current View object. + * @return reference to current view object + */ + public View getView() { + return (currentView); + } + + /* + * + * Methods explicitly affect sound rendering and that require + * audio device specific methods that override this class. + * + */ + + /** + * Prepare Sound in device. + * Makes sound assessible to device - in this case attempts to load sound + * Stores sound type and data. + * @param soundType denotes type of sound: Background, Point or Cone + * @param soundData descrition of sound source data + * @return index into sample vector of Sample object for sound + */ + public int prepareSound(int soundType, MediaContainer soundData) { + // This method must be overridden by device specific implementation + return Sample.NULL_SAMPLE; + } + + /** + * Clear Sound. + * Removes/clears associated sound data with this sound source node + * @param index device specific reference number to device driver sample + */ + public abstract void clearSound(int index); + + /** + * Set the transform for local to virtual world coordinate space + * @param index device specific reference number to device driver sample + * @param trans is a reference to virtual world composite transform + */ + public void setVworldXfrm(int index, Transform3D trans) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.vworldXfrm.set(trans); + return; + } + /** + * Start sample playing on audio device + * @param index device specific reference number to device driver sample + * @return status: < 0 denotes an error + */ + public abstract int startSample(int index); + + /** + * Stop sample playing on audio device + * @param index device specific reference number to device driver sample + * @return status: < 0 denotes an error + */ + public abstract int stopSample(int index); + + /** + * Update sample. + * Implies that some parameters affecting rendering have been modified. + * @param index device specific reference number to device driver sample + */ + // TODO: The update method exists on a TEMPORARY basis. + public abstract void updateSample(int index); + + /** + * Mute sample. + * @param index device specific reference number to device driver sample + */ + public abstract void muteSample(int index); + + /** + * Unmute sample. + * @param index device specific reference number to device driver sample + */ + public abstract void unmuteSample(int index); + + /** + * Pause sample. + * @param index device specific reference number to device driver sample + */ + public abstract void pauseSample(int index); + + /** + * Unpause sample. + * @param index device specific reference number to device driver sample + */ + public abstract void unpauseSample(int index); + + /* + * + * Methods that affect fields associated with the sound sample + * and that may cause implicit rendering. + * + */ + /** + * Set gain scale factor applied to sample. + * @param index device specific reference number to device driver sample + * @param scaleFactor floating point multiplier applied to sample amplitude + */ + public void setSampleGain(int index, float scaleFactor) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setGain(scaleFactor); + return; + } + + /** + * Set number of times sample is looped. + * @param index device specific reference number to device driver sample + * @param count number of times sample is repeated + */ + public void setLoop(int index, int count) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setLoopCount(count); + return; + } + + /** + * Set location of sample. + * @param index device specific reference number to device driver sample + * @param position point location in virtual world coordinate of sample + */ + public void setPosition(int index, Point3d position) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setPosition(position); + return; + } + + /* Set elliptical distance attenuation arrays applied to sample amplitude. + * @param index device specific reference number to device driver sample + * @param frontDistance defines an array of distance along the position axis + * thru which ellipses pass + * @param frontAttenuationScaleFactor gain scale factors + * @param backDistance defines an array of distance along the negative axis + * thru which ellipses pass + * @param backAttenuationScaleFactor gain scale factors + */ + public void setDistanceGain(int index, + double[] frontDistance, float[] frontAttenuationScaleFactor, + double[] backDistance, float[] backAttenuationScaleFactor) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setDistanceGain(frontDistance, frontAttenuationScaleFactor, + backDistance, backAttenuationScaleFactor); + return; + } + + /** + * Set direction vector of sample. + * @param index device specific reference number to device driver sample + * @param direction vector in virtual world coordinate. + */ + public void setDirection(int index, Vector3d direction) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setDirection(direction); + return; + } + + /** + * Set angular attenuation arrays affecting angular amplitude attenuation + * and angular distance filtering. + * @param index device specific reference number to device driver sample + * @param filterType denotes type of filtering (on no filtering) applied + * to sample. + * @param angle array containing angular distances from sound axis + * @param attenuationScaleFactor array containing gain scale factor + * @param filterCutoff array containing filter cutoff frequencies. + * The filter values for each tuples can be set to Sound.NO_FILTER. + */ + public void setAngularAttenuation(int index, int filterType, + double[] angle, float[] attenuationScaleFactor, float[] filterCutoff) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setAngularAttenuation(filterType, angle, + attenuationScaleFactor, filterCutoff); + return; + } + + /** + * Set rolloff value for current aural attribute applied to all samples. + * @param rolloff scale factor applied to standard speed of sound. + */ + public void setRolloff(float rolloff) { + attribs.rolloff = rolloff; + return; + } + + /** + * Set reverberation surface reflection coefficient value for current aural + * attribute applied to all samples. + * @param coefficient applied to amplitude of reverbation added at each + * iteration of reverb processing. + */ + public void setReflectionCoefficient(float coefficient) { + attribs.reflectionCoefficient = coefficient; + return; + } + + /** + * Set reverberation delay time for current aural attribute applied to + * all samples. + * @param reverbDelay amount of time in millisecond between each + * iteration of reverb processing. + */ + public void setReverbDelay(float reverbDelay) { + attribs.reverbDelay = reverbDelay; + return; + } + + /** + * Set reverberation order for current aural attribute applied to all + * samples. + * @param reverbOrder number of times reverb process loop is iterated. + */ + public void setReverbOrder(int reverbOrder) { + attribs.reverbOrder = reverbOrder; + return; + } + + /** + * Set distance filter for current aural attribute applied to all samples. + * @param filterType denotes type of filtering (on no filtering) applied + * to all sample based on distance between listener and sound. + * @param dist is an attenuation array of distance and low-pass filter values. + */ + public void setDistanceFilter(int filterType, + double[] dist, float[] filterCutoff) { + attribs.setDistanceFilter(filterType, dist, filterCutoff); + return; + } + + /** + * Set frequency scale factor for current aural attribute applied to all + * samples. + * @param scaleFactor frequency scale factor applied to samples normal + * playback rate. + */ + public void setFrequencyScaleFactor(float scaleFactor) { + attribs.frequencyScaleFactor = scaleFactor; + return; + } + /** + * Set velocity scale factor for current aural attribute applied to all + * samples when Doppler is calculated. + * @param scaleFactor scale factor applied to postional samples' + * listener-to-soundSource velocity. + * playback rate. + */ + public void setVelocityScaleFactor(float scaleFactor) { + attribs.velocityScaleFactor = scaleFactor; + return; + } + + /** + * Get number of channels used by a particular sample on the audio device. + * @param index device specific reference number to device driver sample + * @return number of channels currently being used by this sample. + */ + public int getNumberOfChannelsUsed(int index) { + // This method must be overridden by device specific implementation + Sample sample = (Sample)getSample(index); + if (sample != null) + return (sample.getNumberOfChannelsUsed()); + else + return 0; + } + + /** + * Get number of channels that would be used by a particular sample on + * the audio device given the mute flag passed in as a parameter. + * @param index device specific reference number to device driver sample + * @param muteFlag denotes the mute state to assume while executing this + * query. This mute value does not have to match the current mute state + * of the sample. + * @return number of channels that would be used by this sample if it + * were playing. + */ + public int getNumberOfChannelsUsed(int index, boolean muteFlag) { + // This method must be overridden by device specific implementation + Sample sample = (Sample)getSample(index); + if (sample != null) + return (sample.getNumberOfChannelsUsed()); + else + return 0; + } + + /** + * Get length of time a sample would play if allowed to play to completion. + * @param index device specific reference number to device driver sample + * @return length of sample in milliseconds + */ + public long getSampleDuration(int index) { + Sample sample = (Sample)getSample(index); + if (sample != null) + return (sample.getDuration()); + else + return 0L; + } + + /** + * Get time this sample begun playing on the audio device. + * @param index device specific reference number to device driver sample + * @return system clock time sample started + */ + public long getStartTime(int index) { + Sample sample = (Sample)getSample(index); + if (sample != null) + return (sample.getStartTime()); + else + return 0L; + } + + /** + * Get reference to the array list of samples + * @return reference to samples list + * @deprecated unsafe to get reference to samples list with this method. + * It's better to directly reference samples list within a synchronized + * block which also contains calls to .getSample(index). + */ + protected ArrayList getSampleList() { + return (samples); + } + + public int getSampleListSize() { + return (samples.size()); + } + + /** + * Get specific sample from indexed sample list + * Checks for valid index before attempting to get sample from list. + * @param index device specific reference number to device driver sample + * @return reference to sample; returns null if index out of range. + * + * @since Java 3D 1.2.1 + */ + public Sample getSample(int index) { + synchronized(samples) { + if ((index >= 0) && (index < samples.size())) { + Sample sample = (Sample)samples.get(index); + return (sample); + } + else + return null; + } + } + + /* + * Get reference to current aural attribute parameters associated with + * this audio device. + * @return reference to current aural attribute parameters + */ + public AuralParameters getAuralParameters() { + return (attribs); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine3DL2.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine3DL2.java new file mode 100644 index 0000000..45273fa --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngine3DL2.java @@ -0,0 +1,299 @@ +/* + * $RCSfile: AudioEngine3DL2.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:02 $ + * $State: Exp $ + */ + +package com.sun.j3d.audioengines; + +import javax.media.j3d.*; +import javax.vecmath.*; +import java.util.ArrayList; + + +/** + * The AudioEngine3DL2 Class defines an audio output device that generates + * sound 'image' from high-level sound parameters passed to it during + * scene graph. + * + *

+ * The methods in this class are meant to be optionally overridden by an + * extended class. This extended class would provice device specific code. + * + *

+ * Error checking on all parameters passed to these methods is already + * explicitly being done by the Java 3D core code that calls these methods. + * + *

+ * These methods should NOT be called by any application if the audio engine + * is associated with a Physical Environment used by Java3D Core. + * + * @since Java 3D 1.3 + */ +public abstract class AudioEngine3DL2 extends AudioEngine3D implements AudioDevice3DL2 { + /** + * Construct a new AudioEngine3DL2 with the specified PhysicalEnvironment. + * @param physicalEnvironment the physical environment object where we + * want access to this device. + */ + public AudioEngine3DL2(PhysicalEnvironment physicalEnvironment ) { + super(physicalEnvironment); + } + + /* + * + * Methods that affect AudioEngine3DLD fields that are NOT associated + * with a specific sound sample + * + */ + + /** + * Pauses audio device engine without closing the device and associated + * threads. + * Causes all cached sounds to be paused and all streaming sounds to be + * stopped. + */ + public abstract void pause(); + + /** + * Resumes audio device engine (if previously paused) without + * reinitializing the device. + * Causes all paused cached sounds to be resumed and all streaming + * sounds restarted. + */ + public abstract void resume(); + + /** + * Set overall gain control of all sounds playing on the audio device. + * @param scaleFactor scale factor applied to calculated amplitudes for + * all sounds playing on this device + */ + public abstract void setGain(float scaleFactor); + + /* + * + * Methods explicitly affect a particular sound rendering and that + * require audio device specific methods that override this class. + * + */ + + /** + * Set scale factor applied to sample playback rate for a particular sound + * associated with the audio device. + * Changing the device sample rate affects both the pitch and speed. + * This scale factor is applied to ALL sound types. + * Changes (scales) the playback rate of a sound independent of + * Doppler rate changes. + * @param index device specific reference to device driver sample + * @param scaleFactor non-negative factor applied to calculated + * amplitudes for all sounds playing on this device + * @see Sound#setRateScaleFactor + */ + public void setRateScaleFactor(int index, float scaleFactor) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setRateScaleFactor(scaleFactor); + return; + } + + + /* + * + * Methods explicitly affect aural attributes of the listening space + * used to calculated reverberation during sound rendering. + * These require audio device specific methods that override this class. + * + */ + + /** + * Set late reflection (referred to as 'reverb') attenuation. + * This scale factor is applied to iterative, indistinguishable + * late reflections that constitute the tail of reverberated sound in + * the aural environment. + * This parameter, along with the early reflection coefficient, defines + * the reflective/absorptive characteristic of the surfaces in the + * current listening region. + * @param coefficient late reflection attenuation factor + * @see AuralAttributes#setReverbCoefficient + */ + public void setReverbCoefficient(float coefficient) { + attribs.reverbCoefficient = coefficient; + return; + } + + + /** + * Sets the early reflection delay time. + * In this form, the parameter specifies the delay time between each order + * of reflection (while reverberation is being rendered) explicitly given + * in milliseconds. + * @param reflectionDelay time between each order of early reflection + * @see AuralAttributes#setReflectionDelay + */ + public void setReflectionDelay(float reflectionDelay) { + attribs.reflectionDelay = reflectionDelay; + return; + } + + /** + * Set reverb decay time. + * Defines the reverberation decay curve. + * @param time decay time in milliseconds + * @see AuralAttributes#setDecayTime + */ + public void setDecayTime(float time) { + attribs.decayTime = time; + return; + } + + /** + * Set reverb decay filter. + * This provides for frequencies above the given cutoff frequency to be + * attenuated during reverb decay at a different rate than frequencies + * below this value. Thus, defining a different reverb decay curve for + * frequencies above the cutoff value. + * @param frequencyCutoff value of frequencies in Hertz above which a + * low-pass filter is applied. + * @see AuralAttributes#setDecayFilter + */ + public void setDecayFilter(float frequencyCutoff) { + attribs.decayFrequencyCutoff = frequencyCutoff; + return; + } + + /** + * Set reverb diffusion. + * This defines the echo dispersement (also referred to as 'echo density'). + * The value of this reverb parameter is expressed as a percent of the + * audio device's minimum-to-maximum values. + * @param diffusion percentage expressed within the range of 0.0 and 1.0 + * @see AuralAttributes#setDiffusion + */ + public void setDiffusion(float diffusion) { + attribs.diffusion = diffusion; + return; + } + + /** + * Set reverb density. + * This defines the modal density (also referred to as 'spectral + * coloration'). + * The value of this parameter is expressed as a percent of the audio + * device's minimum-to-maximum values for this reverb parameter. + * @param density reverb density expressed as a percentage, + * within the range of 0.0 and 1.0 + * @see AuralAttributes#setDensity + */ + public void setDensity(float density) { + attribs.density = density; + return; + } + + + /** + * Set the obstruction gain control. This method allows for attenuating + * sound waves traveling between the sound source and the listener + * obstructed by objects. Direct sound signals/waves for obstructed sound + * source are attenuated but not indirect (reflected) waves. + * There is no corresponding Core AuralAttributes method at this time. + * @param index device specific reference to device driver sample + * @param scaleFactor non-negative factor applied to direct sound gain + */ + public void setObstructionGain(int index, float scaleFactor) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setObstructionGain(scaleFactor); + return; + } + + /** + * Set the obstruction filter control. + * This provides for frequencies above the given cutoff frequency + * to be attenuated, during while the gain of an obstruction signal + * is being calculated, at a different rate than frequencies + * below this value. + * There is no corresponding Core AuralAttributes method at this time. + * @param index device specific reference to device driver sample + * @param frequencyCutoff value of frequencies in Hertz above which a + * low-pass filter is applied. + */ + + public void setObstructionFilter(int index, float frequencyCutoff) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setObstructionFilter(frequencyCutoff); + return; + } + + /** + * Set the occlusion gain control. This method allows for attenuating + * sound waves traveling between the sound source and the listener + * occluded by objects. Both direct and indirect sound signals/waves + * for occluded sound sources are attenuated. + * There is no corresponding Core AuralAttributes method at this time. + * @param index device specific reference to device driver sample + * @param scaleFactor non-negative factor applied to direct sound gain + */ + public void setOcclusionGain(int index, float scaleFactor) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setObstructionGain(scaleFactor); + return; + } + + /** + * Set the occlusion filter control. + * This provides for frequencies above the given cutoff frequency + * to be attenuated, during while the gain of an occluded signal + * is being calculated, at a different rate than frequencies below + * this value. + * There is no corresponding Core AuralAttributes method at this time. + * @param index device specific reference to device driver sample + * @param frequencyCutoff value of frequencies in Hertz above which a + * low-pass filter is applied. + */ + public void setOcclusionFilter(int index, float frequencyCutoff) { + Sample sample = (Sample)getSample(index); + if (sample != null) + sample.setObstructionFilter(frequencyCutoff); + return; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngineThread.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngineThread.java new file mode 100644 index 0000000..dfedd9c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AudioEngineThread.java @@ -0,0 +1,275 @@ +/* + * $RCSfile: AudioEngineThread.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:02 $ + * $State: Exp $ + */ + +package com.sun.j3d.audioengines; + +/* + * Audio Engine Thread + */ + +import javax.media.j3d.*; + +/** + * The Thread Class extended for Audio Device engines that must process + * calls dynamically, in 'real-time" to asynchronously change engine + * parameters. + * + *

+ * NOTE: this class is probably not needed for those Audio Device implementations + * that handle all dynamic parameters in the low-level audio library. + */ +public class AudioEngineThread extends Thread { + + // Debug print flag + static final protected boolean debugFlag = false; + + + protected void debugPrint(String message) { + if (debugFlag) + System.out.println(message); + } + + /** + * The classification types. + */ + protected static final int WORK_THREAD = 0x01; + protected static final int UPDATE_THREAD = 0x02; + + /** + * This runMonitor action puts the thread into an initial wait state + */ + protected static final int WAIT = 0; + + /** + * This runMonitor action notifies MasterControl that this thread + * has completed and wait. + */ + protected static final int NOTIFY_AND_WAIT = 1; + + /** + * This runMonitor action tells the thread to run N number of + * iterations. + */ + protected static final int RUN = 2; + + /** + * This runMonitor action tells the thread to stop running + */ + protected static final int STOP = 3; + + /** + * This indicates that this thread has been activated by MC + */ + protected boolean active = false; + + /** + * This indicates that this thread is alive and running + */ + protected boolean running = true; + + + /** + * This indicates that this thread is ready + */ + protected boolean started = false; + + /** + * The time values passed into this thread + */ + protected long referenceTime; + + /** + * Use to assign threadOpts WAIT_ALL_THREADS + */ + protected long lastWaitTimestamp = 0; + + /** + * The type of this thread. It is one of the above constants. + */ + protected int type; + + /** + * The classification of this thread. It is one of the above constants. + */ + protected int classification = WORK_THREAD; + + /** + * The arguments passed in for this thread + */ + protected Object[] args = null; + + /** + * Flag to indicate that user initiate a thread stop + */ + protected boolean userStop = false; + + /** + * Flag to indicate that this thread is waiting to be notify + */ + protected boolean waiting = false; + + /** + * Some variables used to name threads correctly + */ + protected static int numInstances = 0; + protected int instanceNum = -1; + + /** + * This constructor simply assigns the given id. + */ + public AudioEngineThread(ThreadGroup t, String threadName) { + super(t, threadName); + if (debugFlag) + debugPrint("AudioEngineThread.constructor("+threadName +")"); + } + + synchronized int newInstanceNum() { + return (++numInstances); + } + + int getInstanceNum() { + if (instanceNum == -1) + instanceNum = newInstanceNum(); + return instanceNum; + } + + /** + * This method is defined by all slave threads to implement + * one iteration of work. + */ + synchronized public void doWork() { + if (debugFlag) + debugPrint("AudioEngineThread.doWork()"); + } + + /** + * This initializes this thread. Once this method returns, the thread is + * ready to do work. + */ + public void initialize() { + if (debugFlag) + debugPrint("AudioEngineThread.initialize()"); + this.start(); + while (!started) { + try { + Thread.currentThread().sleep(1, 0); + } catch (InterruptedException e) { + } + } + } + + /** + * This causes the threads run method to exit. + */ + public void finish() { + while (!waiting) { + try { + Thread.sleep(10); + } catch (InterruptedException e) {} + } + runMonitor(STOP, 0,null); + } + + /* + * This thread controls the syncing of all the canvases attached to + * this view. + */ + public void run() { + if (debugFlag) + debugPrint("AudioEngineThread.run"); + runMonitor(WAIT, 0, null); + while (running) { + doWork(); + runMonitor(WAIT, 0, null); + } + // resource clean up + shutdown(); + } + + synchronized public void runMonitor(int action, long referenceTime, Object[] args){ + switch (action) { + case WAIT: + if (debugFlag) + debugPrint("AudioEngineThread.runMonitor(WAIT)"); + try { + started = true; + waiting = true; + wait(); + } catch (InterruptedException e) { + System.err.println(e); + } + waiting = false; + break; + case RUN: + if (debugFlag) + debugPrint("AudioEngineThread.runMonitor(RUN)"); + this.referenceTime = referenceTime; + this.args = args; + notify(); + break; + case STOP: + if (debugFlag) + debugPrint("AudioEngineThread.runMonitor(STOP)"); + running = false; + notify(); + break; + } + } + + public void shutdown() { + } + + // default resource clean up method + public void cleanup() { + active = false; + running = true; + started = true; + lastWaitTimestamp = 0; + classification = WORK_THREAD; + args = null; + userStop = false; + referenceTime = 0; + + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AuralParameters.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AuralParameters.java new file mode 100644 index 0000000..71b71d0 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/AuralParameters.java @@ -0,0 +1,197 @@ +/* + * $RCSfile: AuralParameters.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:02 $ + * $State: Exp $ + */ + +package com.sun.j3d.audioengines; + +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * The AuralParameters Class defines a set of fields that define the + * Aural listening environment. Many of the parameters correspond to + * AuralAttribute fields. + * + *

+ * Error checking on all parameters passed to these methods is already + * explicitly being done by the Java 3D core code that calls these methods. + */ + +public class AuralParameters +{ + // Speed of Sound in meters/milliseconds + public static final float SPEED_OF_SOUND = 0.344f; + public static final int NO_FILTERING = -1; + + public float rolloff = 1.0f; + public float reflectionCoefficient = 0.0f; + public float reverbDelay = 40.0f; + public int reverbOrder = 0; + public float frequencyScaleFactor = 1.0f; + public float velocityScaleFactor = 0.0f; + int filterType = NO_FILTERING; + double[] filterDistance = null; + float[] filterCutoff = null; + + /* + * @since Java 3D 1.3 + */ + public float reverbCoefficient = 1.0f; + public float reflectionDelay = 20.0f; + public float decayTime = 1000.0f; + public float decayFrequencyCutoff = 5000.0f; + public float diffusion = 1.0f; // 100% + public float density = 1.0f; // 100% + + /** + * Construct a new AuralParameters object + */ + public AuralParameters() { + frequencyScaleFactor = 1.0f; + velocityScaleFactor = 0.0f; + rolloff = 1.0f; + reflectionCoefficient = 0.0f; + reflectionDelay = 20.0f; + reverbCoefficient = 1.0f; + reverbDelay = 40.0f; + reverbOrder = 0; + filterType = NO_FILTERING; + filterDistance = new double[2]; // start out with array of two + filterCutoff = new float[2]; // start out with array of two + decayTime = 1000.0f; + decayFrequencyCutoff = 5000.0f; + diffusion = 1.0f; // 100% + density = 1.0f; // 100% + } + + public void setDistanceFilter(int filterType, double[] distance, + float[] filterCutoff) { + boolean error = false; + boolean allocate = false; + int attenuationLength = 0; + if (distance == null || filterCutoff == null) { + error = true; + } + else { + attenuationLength = distance.length; + if (attenuationLength == 0 || filterType == NO_FILTERING) { + error = true; + } + } + if (error) { + this.filterType = NO_FILTERING; + this.filterDistance = null; + this.filterCutoff = null; + if (debugFlag) + debugPrint("setDistanceFilter NO_FILTERING"); + return; + } + this.filterType = filterType; + if (debugFlag) + debugPrint("setDistanceFilter type = " + filterType); + if ((filterDistance == null) || (filterCutoff == null)) { + allocate = true; + } + else if (attenuationLength > filterDistance.length) { + allocate = true; + } + if (allocate) { + if (debugFlag) + debugPrint("setDistanceFilter length = " + attenuationLength); + this.filterDistance = new double[attenuationLength]; + this.filterCutoff = new float[attenuationLength]; + } + System.arraycopy(distance, 0, this.filterDistance, 0, + attenuationLength); + System.arraycopy(filterCutoff, 0, this.filterCutoff, 0, + attenuationLength); + + if (debugFlag) { + debugPrint("setDistanceFilter arrays = "); + for (int i=0; i filterDistance.length) + attenuationLength = filterDistance.length; + System.arraycopy(this.filterDistance, 0, distance, 0, + attenuationLength); + System.arraycopy(this.filterCutoff, 0, filterCutoff, 0, + attenuationLength); + return; + } + + // Debug print flags + static final boolean debugFlag = false; + static final boolean internalErrors = false; + + /** + * Debug print method for Sound nodes + */ + protected void debugPrint(String message) { + if (debugFlag) + System.out.println(message); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/Sample.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/Sample.java new file mode 100644 index 0000000..f5104ca --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/Sample.java @@ -0,0 +1,479 @@ +/* + * $RCSfile: Sample.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:02 $ + * $State: Exp $ + */ + +package com.sun.j3d.audioengines; + +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * The Sample class defines the data and methods associated with a sound + * sample played through the AudioDevice. + * This contains all the data fields for non-spatialized and spatialized + * (positional and directional) sound samples. + */ +public class Sample { + + // Debug print flags and methods + static final protected boolean debugFlag = false; + static final protected boolean internalErrors = false; + + protected void debugPrint(String message) { + if (debugFlag) + System.out.println(message); + } + + protected void debugPrintln(String message) { + if (debugFlag) + System.out.println(message); + } + + /** + * Null Sound identifier denotes sound is not created or initialized + */ + public static final int NULL_SAMPLE = -1; + + /** + * sound data associated with sound source + */ + protected MediaContainer soundData = null; + + /** + * sound data associated with sound source + */ + protected int soundType = -1; + + /** + * Overall Scale Factor applied to sound gain. + */ + protected float gain = 1.0f; // Valid values are >= 0.0. + + /** + * Overall Scale Factor applied to sound. + * @since Java 3D 1.3 + */ + protected float rateScaleFactor = 1.0f; // Valid values are >= 0.0. + + /** + * Number of times sound is looped/repeated during play + */ + protected int loopCount = 0; // Range from 0 to POSITIVE_INFINITY(-1) + + + /* + * Duration of sample + * This should match the Sound node constant of same name + */ + public static final int DURATION_UNKNOWN = -1; + protected long duration = DURATION_UNKNOWN; + + protected int numberOfChannels = 0; + protected boolean mute = false; // denotes if sample is muted + // (playing with zero gain) + + /* + * + * Fields associated with positional sound samples + * + */ + /* + * Local to Vworld transform + */ + protected Transform3D vworldXfrm = new Transform3D(); + protected boolean vwXfrmFlag = false; + + /* + * Origin of Sound source in Listener's space. + */ + protected Point3f position = new Point3f(0.0f, 0.0f, 0.0f); + + /* + * Pairs of distances and gain scale factors that define piecewise linear + * gain attenuation between each pair. + */ + protected double[] attenuationDistance = null; + protected float[] attenuationGain = null;; + + /** + * dirty flags denoting what has changed since last rendering + */ + protected int dirtyFlags = 0xFFFF; + + /* + * + * Direction sample fields + * + */ + /** + * The Cone Sound's direction vector. This is the cone axis. + */ + protected Vector3f direction = new Vector3f(0.0f, 0.0f, 1.0f); + + /** + * Pairs of distances and gain scale factors that define piecewise linear + * gain BACK attenuation between each pair. + * These are used for defining elliptical attenuation regions. + */ + protected double[] backAttenuationDistance = null; + protected float[] backAttenuationGain = null; + + /** + * Directional Sound's gain can be attenuated based on the listener's + * location off-angle from the source source direction. + * This can be set by three parameters: + * angular distance in radians + * gain scale factor + * filtering (currently the only filtering supported is lowpass) + */ + protected double[] angularDistance = {0.0, (Math.PI * 0.5)}; + protected float[] angularGain = {1.0f, 0.0f}; + + /** + * Distance Filter + * Each sound source is attenuated by a filter based on it's distance + * from the listener. + * For now the only supported filterType will be LOW_PASS frequency + * cutoff. + * At some time full FIR filtering will be supported. + */ + public static final int NO_FILTERING = -1; + public static final int LOW_PASS = 1; + + protected int angularFilterType = NO_FILTERING; + protected float[] angularFilterCutoff = {Sound.NO_FILTER, Sound.NO_FILTER}; + + /* + * Obstruction and Occlusion parameters + * For now the only type of filtering supported is a low-pass filter + * defined by a frequency cutoff value. + * @since Java 3D 1.3 + */ + protected float obstructionGain = 1.0f; // scale factor + protected int obstructionFilterType = NO_FILTERING; + protected float obstructionFilterCutoff = Sound.NO_FILTER; + protected float occlusionGain = 1.0f; // scale factor + protected int occlusionFilterType = NO_FILTERING; + protected float occlusionFilterCutoff = Sound.NO_FILTER; + + /* + * Construct a new audio device Sample object + */ + public Sample() { + if (debugFlag) + debugPrintln("Sample constructor"); + } + + public long getDuration() { + return 0; + } + + public long getStartTime() { + return 0; + } + + public int getNumberOfChannelsUsed() { + return 0; + } + + public void setDirtyFlags(int flags) { + dirtyFlags = flags; + } + + public int getDirtyFlags() { + return dirtyFlags; + } + + public void setSoundType(int type) { + soundType = type; + } + + public int getSoundType() { + return soundType; + } + + public void setSoundData(MediaContainer ref) { + soundData = ref; + } + + public MediaContainer getSoundData() { + return soundData; + } + + public void setMuteFlag(boolean flag) { + mute = flag; + } + + public boolean getMuteFlag() { + return mute; + } + + public void setVWrldXfrmFlag(boolean flag) { + // this flag is ONLY true if the VirtualWorld Transform is ever set + vwXfrmFlag = flag; + } + + public boolean getVWrldXfrmFlag() { + return vwXfrmFlag; + } + + public void setGain(float scaleFactor) { + gain = scaleFactor; + } + + public float getGain() { + return gain; + } + + public void setLoopCount(int count) { + loopCount = count; + } + + public int getLoopCount() { + return loopCount; + } + + + public void setPosition(Point3d position) { + this.position.set(position); + return; + } + + // TODO: no get method for Position + + + public void setDistanceGain( + double[] frontDistance, float[] frontAttenuationScaleFactor, + double[] backDistance, float[] backAttenuationScaleFactor) { + if (frontDistance != null) { + int size = frontDistance.length; + attenuationDistance = new double[size]; + attenuationGain = new float[size]; + for (int i=0; i=0 if everythings OK +**************/ + return null; // TODO: implement this + + } // reinitAudioInputStream + + + DataLine initDataLine(AudioInputStream ais) { + if (debugFlag) { + debugPrintln("JSChannel: initDataLine(" + ais + ")"); + debugPrintln(" must be overridden"); + } + return null; + } + + long getDuration() { + // TODO: how should this really be done?? + if (debugFlag) + debugPrintln("JSChannel:getDuration"); + + if (ais == null || audioFormat == null ) { + if (debugFlag) + debugPrintln("JSChannel: Internal Error getDuration"); + return (long)Sample.DURATION_UNKNOWN; + } + // Otherwise we'll assume that we can calculate this duration + + // get "duration" of audio stream (wave file) + // TODO: For True STREAMing audio the size is unknown... + long numFrames = ais.getFrameLength(); + if (debugFlag) + debugPrintln(" frame length = " + numFrames); + if (numFrames <= 0) + return (long)Sample.DURATION_UNKNOWN; + + float rateInFrames = audioFormat.getFrameRate(); + rateInHz = audioFormat.getSampleRate(); + if (debugFlag) + debugPrintln(" rate in Frames = " + rateInFrames); + if (numFrames <= 0) + return (long)Sample.DURATION_UNKNOWN; + long duration = (long)((float)numFrames/rateInFrames); + if (debugFlag) + debugPrintln(" duration(based on ais) = " + duration); + return duration; + } + + /** + * Start TWO Samples + */ + boolean startSamples(int loopCount, float leftGain, float rightGain, + int leftDelay, int rightDelay) { + if (debugFlag) + debugPrint("JSChannel: startSamples must be overridden"); + return false; + } // end of start Samples + + /* + * Starts a Sample + */ + boolean startSample(int loopCount, float gain, int delay) { + if (debugFlag) + debugPrint("JSChannel: startSample must be overridden"); + return false; + } // end of start (single) Sample + + int stopSample() { +// This will tell thread to stop reading and writing + // reload with old URL + // reloadSample + if (debugFlag) + debugPrint("JSChannel: stopSample must be overridden"); + startTime = 0; + return 0; + } + + int stopSamples() { +// This will tell thread to stop reading and writing + // TODO: For muting, stop sound but don't clear startTime... + // QUESTION: what does it mean for replaying that .stop "frees memory" + if (debugFlag) + debugPrint("JSChannel: stopSample must be overridden"); +// reloadSample + + startTime = 0; + return 0; + } + + void setSampleGain(float gain) { +// TODO: Must be done in thread + if (debugFlag) + debugPrint("JSChannel: setSampleGain must be overridden"); + } + + void setSampleDelay(int delay) { + if (debugFlag) + debugPrint("JSChannel: setSampleDelay must be overridden"); + /* + * null method + */ + // dynamic changes to sample delay while playing is not implemented + } + + void setSampleReverb(int type, boolean on) { + if (debugFlag) + debugPrint("JSChannel: setSampleReverb must be overridden"); + } + + void setSampleRate() { + if (debugFlag) + debugPrint("JSChannel: setSampleRate must be overridden"); + } + void scaleSampleRate(float scaleFactor) { + /** + * Change rate for Doppler affect or pitch shifting. + * Engine maximum sample rate is 48kHz so clamp to that + * max value. + */ + if (debugFlag) + debugPrintln("JSChannel: scaleSampleRate"); + if (ais == null) { + if (debugFlag) { + debugPrint("JSChannel: Internal Error scaleSampleRate: "); + debugPrintln("ais is null"); + } + return; + } + + AudioFormat audioFormat = ais.getFormat(); + float rate = audioFormat.getSampleRate(); + + double newRate = rate * scaleFactor; + if (newRate > 48000.0) // clamp to 48K max + newRate = 48000.0; +/**** +// NOTE: This doesn't work... +/// audioStream.setSampleRate(newRate); + +// need to set FloatControl.Type(SAMPLE_RATE) to new value somehow... + + if (debugFlag) { + debugPrintln("JSChannel: scaleSampleRate: new rate = " + + rate * scaleFactor); + debugPrintln(" >>>>>>>>>>>>>>> using scaleFactor = " + + scaleFactor); + } +****/ + } + + int pauseSamples() { + /** + * Pause playing samples + */ +// TODO: Notify thread + return 0; + } + + int pauseSample() { + /** + * Pause playing a sample + */ +// TODO: Notify thread + return 0; + } + + int unpauseSamples() { + /** + * Resume playing samples + */ +// TODO: Notify thread + return 0; + } + + int unpauseSample() { + /** + * Resume playing a sample + */ +// TODO: Notify thread + return 0; + } + + void setSampleFiltering(boolean filterFlag, float cutoffFreq) { + /** + * Set or clear low-pass filtering + */ +/**** +// QUESTION: how will this be done if data is written out one channel/sample at + a time?? +****/ + // QUESTION: should filtering of Midi data be performed? +// ais.setFiltering(filterFlag, cutoffFreq); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSClip.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSClip.java new file mode 100755 index 0000000..0fcb14e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSClip.java @@ -0,0 +1,349 @@ +/* + * $RCSfile: JSClip.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:03 $ + * $State: Exp $ + */ + +/* + * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs + * to be rewritten. + */ + +package com.sun.j3d.audioengines.javasound; + +import java.applet.*; +import java.util.*; +import java.lang.String; +import java.net.*; +import java.io.*; +import java.io.InputStream; +import javax.sound.sampled.*; + +/** + * The JSClip Class defines an audio output methods that call JavaSound + * Hae mixer methods. + */ + +class JSClip extends JSChannel { + + Clip line; + +// TODO: separate left and right channel required until I write into +// stereo buffer! + Clip otherChannel = null; + +// TODO: Reverb channel that is centered and not delayed is maintained separately +// until a way to set stereo reverb send (panned and attenuated to give +// the same affect) is implemented + Clip reverbChannel = null; + + + /** + * Create data line for outputting audio input stream. + * for a stream that is a sourceDataline + * @return true is successful in initiallizing DataLine + */ + DataLine initDataLine(AudioInputStream ais) { + if (debugFlag) + debugPrintln("JSClip: initDataLine(" + ais + ")"); + + try { + if (debugFlag) + debugPrintln("JSClip: loadSample - try getting new line "); + /* + * From the AudioInputStream fetch information about the format + * of the audio data - including sampling frequency, number of + * channels, size of samples,... + */ + audioFormat = ais.getFormat(); + + /* + * we can't yet open the device for ALAW/ULAW playback, + * convert ALAW/ULAW to PCM + */ + if ((audioFormat.getEncoding() == AudioFormat.Encoding.ULAW) || + (audioFormat.getEncoding() == AudioFormat.Encoding.ALAW)) { + + AudioFormat tmp = + new AudioFormat( + AudioFormat.Encoding.PCM_SIGNED, + audioFormat.getSampleRate(), + audioFormat.getSampleSizeInBits() * 2, + audioFormat.getChannels(), + audioFormat.getFrameSize() * 2, + audioFormat.getFrameRate(), + true); + ais = AudioSystem.getAudioInputStream(tmp, ais); + audioFormat = tmp; + } + + /* + * ask JavaSound for outline with a format suitable for our + * AudioInputStream. In order to ask for a line, a Info object + * with the desired properties must be constructed. + * Clip is used for outputing buffered data. + * We have to pass the line the AudioFormat object so it knows + * format will be. + * + * TODO: we could give JavaSound a hint about how big the + * internal buffer for the line should be, rather than use the + * default. + */ + DataLine.Info info = new DataLine.Info(Clip.class, + audioFormat); + line = (Clip)AudioSystem.getLine(info); +/***** +// TODO: JSClip can't be a listener (do we need to do this in the thread?) + if (debugFlag) + debugPrintln("JSClip: addLineListener for clip"); + line.addLineListener(this); +******/ + + if (debugFlag) + debugPrintln("JSClip: open sound Clip"); + + // Make line ready to receive data. + line.open(ais); + + // Line can now receive data but still needs to be + // activated (opened) so it will pass data on to the + // audio device. This is done at "startSample" time. + } + catch (Exception e) { + if (debugFlag) { + debugPrint("JSClip: Internal Error loadSample "); + debugPrintln("get stream failed"); + } + e.printStackTrace(); + // TODO: clean up vector elements that were set up for + // failed sample + return null; + } + return (DataLine)line; + } // initDataLine + + /** + * Start TWO Samples + * + * used when two samples are associated with a single Point or Cone + * sound. This method handles starting both samples, rather than + * forcing the caller to make two calls to startSample, so that the + * actual Java Sound start methods called are as immediate (without + * delay between as possible. + */ + boolean startSamples(int loopCount, float leftGain, float rightGain, + int leftDelay, int rightDelay) { + // loop count is ignored for Stream and MIDI + // TODO: loop count isn't implemented for MIDI yet + + // left and rightDelay parameters are in terms of Samples + if (debugFlag) { + debugPrint("JSClip: startSamples "); + debugPrintln("start stream for Left called with "); + debugPrintln(" gain = " + leftGain + + " delay = " + leftDelay); + debugPrintln("start stream for Right called with "); + debugPrintln(" gain = " + rightGain + + " delay = " + rightDelay); + } + + // This is called assuming that the Stream is allocated for a + // Positional sample, but if it is not then fall back to + // starting the single sample associated with this Stream + if (otherChannel == null || reverbChannel == null) + startSample(loopCount, leftGain, leftDelay); + + /* + * ais for Left and Right streams should be same so just get ais + * left stream + */ + if (ais == null) { + if (debugFlag) { + debugPrint("JSClip: Internal Error startSamples: "); + debugPrintln("either left or right ais is null"); + } + return false; + } + Clip leftLine; + Clip rightLine; + leftLine = line; + rightLine = otherChannel; +// left line only for background sounds... +// TODO: +/*********** +for now just care about the left + if (leftLine == null || rightLine == null) { + if (debugFlag) { + debugPrint("JSClip: startSamples Internal Error: "); + debugPrintln("either left or right line null"); + } + return false; + } +************/ + + // we know that were processing TWO channels + double ZERO_EPS = 0.0039; // approx 1/256 - twice MIDI precision + double leftVolume = (double)leftGain; + double rightVolume = (double)rightGain; + +// TODO: if not reading/writing done for Clips then I can't do +// stereo trick (reading mono file and write to stereo buffer) + // Save time sound started, only in left + startTime = System.currentTimeMillis(); + if (debugFlag) + debugPrintln("*****start Stream with new start time " + + startTime); + try { + // QUESTION: Offset clip is done how??? +/******* +// TODO: +offset delayed sound +set volume +set pan?? +set reverb + boolean reverbLeft = false; // off; reverb has it own channel + boolean reverbRight = reverbLeft; + + if (leftDelay < rightDelay) { +XXXX audioLeftStream.start(leftVolume, panLeft, reverbLeft); +XXXX audioRightStream.start(rightVolume, panRight, reverbRight); + } + else { +XXXX audioRightStream.start(rightVolume, panRight, reverbRight); +XXXX audioLeftStream.start(leftVolume, panLeft, reverbLeft); + } +******/ + line.setLoopPoints(0, -1); // Loop the entire sound sample + line.loop(loopCount); // plays clip loopCount + 1 times + line.start(); // start the sound + } + catch (Exception e) { + if (debugFlag) { + debugPrint("JSClip: startSamples "); + debugPrintln("audioInputStream.read failed"); + } + e.printStackTrace(); + startTime = 0; + return false; + } + + if (debugFlag) + debugPrintln("JSClip: startSamples returns"); + return true; + } // end of startSamples + + + /* + * This method is called specifically for BackgroundSounds. + * There is exactly ONE sample (mono or stereo) associated with + * this type of sound. Consequently, delay is not applicable. + * Since the sound has no auralAttributes applied to it reverb + * is not applied to the sample. + */ + boolean startSample(int loopCount, float gain, int delay) { + /* + if (debugFlag) { + debugPrint("JSClip: startSample "); + debugPrintln("start stream called with "); + debugPrintln(" gain = " + gain + ", delay is zero"); + } + + // Since only one sample is processed in startSample, just call + // this more general method passing duplicate information + // We don't really want to do this in the long term. + return startSamples(loopCount, gain, gain, 0, 0); + */ + + // TODO: The following is temporary until we have fully + // functional startSample and startSamples methods + if (debugFlag) + debugPrintln("JSClip.startSample(): starting sound Clip"); + line.setFramePosition(0); // Start playing from the beginning + line.setLoopPoints(0, -1); // Loop the entire sound sample + line.loop(loopCount); + line.start(); + return true; + } // end of start (single) Sample + + int stopSample() { + // This will tell thread to stop reading and writing + // reload with old URL - reloadSample()??? + + if (debugFlag) + debugPrintln("JSClip.stopSample(): stopping sound Clip"); + line.stop(); + + startTime = 0; + return 0; + } + + int stopSamples() { + // This will tell thread to stop reading and writing + // TODO: For muting, stop sound but don't clear startTime... + // QUESTION: what does it mean for replaying that .stop "frees memory" + + // reloadSample + // QUESTION: set stop state WHERE??!! + + if (debugFlag) + debugPrintln("JSClip.stopSample(): stopping sound Clip"); + line.stop(); + + startTime = 0; + return 0; + } + + /* + * called by LineListener class + */ + public void update(LineEvent event) { + if (event.getType().equals(LineEvent.Type.STOP)) { + line.close(); // really a stop?? + } + else if (event.getType().equals(LineEvent.Type.CLOSE)) { + // this forces a system exit in example code + // TODO: what should be done to close line + if (debugFlag) + debugPrint("JSClip.update(CLOSE) entered "); + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSDirectionalSample.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSDirectionalSample.java new file mode 100755 index 0000000..412c9ee --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSDirectionalSample.java @@ -0,0 +1,738 @@ +/* + * $RCSfile: JSDirectionalSample.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:03 $ + * $State: Exp $ + */ + +/* + * DirectionalSample object + * + * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs + * to be rewritten. + */ + +package com.sun.j3d.audioengines.javasound; + +import javax.media.j3d.*; +import com.sun.j3d.audioengines.*; +import javax.vecmath.*; + +/** + * The PostionalSample Class defines the data and methods associated with a + * PointSound sample played through the AudioDevice. + */ + +class JSDirectionalSample extends JSPositionalSample +{ + // The transformed direction of this sound + Vector3f xformDirection = new Vector3f(0.0f, 0.0f, 1.0f); + + public JSDirectionalSample() { + super(); + if (debugFlag) + debugPrintln("JSDirectionalSample constructor"); + } + + void setXformedDirection() { + if (debugFlag) + debugPrint("*** setXformedDirection"); + if (!getVWrldXfrmFlag()) { + if (debugFlag) + debugPrint(" Transform NOT set yet, so dir => xformDir"); + xformDirection.set(direction); + } + else { + if (debugFlag) + debugPrint(" Transform dir => xformDir"); + vworldXfrm.transform(direction, xformDirection); + } + if (debugFlag) + debugPrint(" xform(sound)Direction <= "+xformDirection.x+ + ", " + xformDirection.y + ", " + xformDirection.z); + } + + + /* *********************************** + * + * Intersect ray to head with Ellipse + * + * ***********************************/ + /* + * An ellipse is defined using: + * (1) the ConeSound's direction vector as the major axis of the ellipse; + * (2) the max parameter (a front distance attenuation value) along the + * cone's position axis; and + * (3) the min parameter (a back distance attenuation value) along the + * cone's negative axis + * This method calculates the distance from the sound source to the + * Intersection of the Ellipse with the ray from the sound source to the + * listener's head. + * This method returns the resulting distance. + * If an error occurs, -1.0 is returned. + * + * A calculation are done in 'Cone' space: + * The origin is defined as being the sound source position. + * The ConeSound source axis is the X-axis of this Cone's space. + * Since this ConeSound source defines a prolate spheroid (obtained + * by revolving an ellipsoid about the major axis) we can define the + * Y-axis of this Cone space as being in the same plane as the X-axis + * and the vector from the origin to the head. + * All calculations in Cone space can be generalized in this two- + * dimensional space without loss of precision. + * Location of the head, H, in Cone space can then be defined as: + * H'(x,y) = (cos @, sin @) * | H | + * where @ is the angle between the X-axis and the ray to H. + * Using the equation of the line thru the origin and H', and the + * equation of ellipse defined with min and max, find the + * intersection by solving for x and then y. + * + * (I) The equation of the line thru the origin and H', and the + * | H'(y) - S(y) | + * y - S(y) = | ----------- | * [x - S(x)] + * | H'(x) - S(x) | + * and since S(x,y) is the origin of ConeSpace: + * | H'(y) | + * y = | ----- | x + * | H'(x) | + * + * (II) The equation of ellipse: + * x**2 y**2 + * ---- + ---- = 1 + * a**2 b**2 + * given a is length from origin to ellipse along major, X-axis, and + * b is length from origin to ellipse along minor, Y-axis; + * where a**2 = [(max+min)/2]**2 , since 2a = min+max; + * where b**2 = min*max , since the triangle abc is made is defined by the + * the points: S(x,y), origin, and (0,b), + * thus b**2 = a**2 - S(x,y) = a**2 - ((a-min)**2) = 2a*min - min**2 + * b**2 = ((min+max)*min) - min**2 = min*max. + * so the equation of the ellipse becomes: + * x**2 y**2 + * ---------------- + ------- = 1 + * [(max+min)/2]**2 min*max + * + * Substuting for y from Eq.(I) into Eq.(II) gives + * x**2 [(H'(y)/H'(x))*x]**2 + * ---------------- + -------------------- = 1 + * [(max+min)/2]**2 min*max + * + * issolating x**2 gives + * | 1 [H'(y)/H'(x)]**2 | + * x**2 | ---------------- + ---------------- | = 1 + * | [(max+min)/2]**2 min*max | + * + * + * | 4 [(sin @ * |H|)/(cos @ * |H|)]**2 | + * x**2 | -------------- + -------------------------------- | = 1 + * | [(max+min)]**2 min*max | + * + * | | + * | 1 | + * | | + * x**2 = | --------------------------------------- | + * | | 4 [sin @/cos @]**2 | | + * | | -------------- + ---------------- | | + * | | [(max+min)]**2 min*max | | + * + * substitute tan @ for [sin @/cos @], and take the square root and you have + * the equation for x as calculated below. + * + * Then solve for y by plugging x into Eq.(I). + * + * Return the distance from the origin in Cone space to this intersection + * point: square_root(x**2 + y**2). + * + */ + double intersectEllipse(double max, double min ) { + + if (debugFlag) + debugPrint(" intersectEllipse entered with min/max = " + min + "/" + max); + /* + * First find angle '@' between the X-axis ('A') and the ray to Head ('H'). + * In local coordinates, use Dot Product of those two vectors to get cos @: + * A(u)*H(u) + A(v)*H(v) + A(w)*H(v) + * cos @ = -------------------------------- + * |A|*|H| + * then since domain of @ is { 0 <= @ <= PI }, arccos can be used to get @. + */ + Vector3f xAxis = this.direction; // axis is sound direction vector + // Get the already calculated vector from sound source position to head + Vector3f sourceToHead = this.sourceToCenterEar; + // error check vectors not empty + if (xAxis == null || sourceToHead == null) { + if (debugFlag) + debugPrint( " one or both of the vectors are null" ); + return (-1.0f); // denotes an error occurred + } + + // Dot Product + double dotProduct = (double)( (sourceToHead.dot(xAxis)) / + (sourceToHead.length() * xAxis.length())); + if (debugFlag) + debugPrint( " dot product = " + dotProduct ); + // since theta angle is in the range between 0 and PI, arccos can be used + double theta = (float)(Math.acos(dotProduct)); + if (debugFlag) + debugPrint( " theta = " + theta ); + + /* + * Solve for X using Eq.s (I) and (II) from above. + */ + double minPlusMax = (double)(min + max); + double tangent = Math.tan(theta); + double xSquared = 1.0 / + ( ( 4.0 / (minPlusMax * minPlusMax) ) + + ( (tangent * tangent) / (min * max) ) ); + double x = Math.sqrt(xSquared); + if (debugFlag) + debugPrint( " X = " + x ); + /* + * Solve for y, given the result for x: + * | H'(y) | | sin @ | + * y = | ----- | x = | ----- | x + * | H'(x) | | cos @ | + */ + double y = tangent * x; + if (debugFlag) + debugPrint( " Y = " + y ); + double ySquared = y * y; + + /* + * Now return distance from origin to intersection point (x,y) + */ + float distance = (float)(Math.sqrt(xSquared + ySquared)); + if (debugFlag) + debugPrint( " distance to intersection = " + distance ); + return (distance); + } + + /* ***************** + * + * Find Factor + * + * *****************/ + /* + * Interpolates the correct attenuation scale factor given a 'distance' + * value. This version used both front and back attenuation distance + * and scale factor arrays (if non-null) in its calculation of the + * the distance attenuation. + * If the back attenuation arrays are null then this executes the + * PointSoundRetained version of this method. + * This method finds the intesection of the ray from the sound source + * to the center-ear, with the ellipses defined by the two sets (front + * and back) of distance attenuation arrays. + * This method looks at pairs of intersection distance values to find + * which pair the input distance argument is between: + * [intersectionDistance[index] and intersectionDistance[index+1] + * The index is used to get factorArray[index] and factorArray[index+1]. + * Then the ratio of the 'distance' between this pair of intersection + * values is used to scale the two found factorArray values proportionally. + */ + float findFactor(double distanceToHead, + double[] maxDistanceArray, float[] maxFactorArray, + double[] minDistanceArray, float[] minFactorArray) { + int index, lowIndex, highIndex, indexMid; + double returnValue; + + if (debugFlag) { + debugPrint("JSDirectionalSample.findFactor entered:"); + debugPrint(" distance to head = " + distanceToHead); + } + + if (minDistanceArray == null || minFactorArray == null) { + /* + * Execute the PointSoundRetained version of this method. + * Assume it will check for other error conditions. + */ + return ( this.findFactor(distanceToHead, + maxDistanceArray, maxFactorArray) ); + } + + /* + * Error checking + */ + if (maxDistanceArray == null || maxFactorArray == null) { + if (debugFlag) + debugPrint(" findFactor: arrays null"); + return -1.0f; + } + // Assuming length > 1 already tested in set attenuation arrays methods + int arrayLength = maxDistanceArray.length; + if (arrayLength < 2) { + if (debugFlag) + debugPrint(" findFactor: arrays length < 2"); + return -1.0f; + } + int largestIndex = arrayLength - 1; + /* + * Calculate distanceGain scale factor + */ + /* + * distanceToHead is larger than greatest distance in maxDistanceArray + * so head is beyond the outer-most ellipse. + */ + if (distanceToHead >= maxDistanceArray[largestIndex]) { + if (debugFlag) + debugPrint(" findFactor: distance > " + + maxDistanceArray[largestIndex]); + if (debugFlag) + debugPrint(" maxDistanceArray length = " + + maxDistanceArray.length); + if (debugFlag) + debugPrint(" findFactor returns ****** " + + maxFactorArray[largestIndex] + " ******"); + return maxFactorArray[largestIndex]; + } + + /* + * distanceToHead is smaller than least distance in minDistanceArray + * so head is inside the inner-most ellipse. + */ + if (distanceToHead <= minDistanceArray[0]) { + if (debugFlag) + debugPrint(" findFactor: distance < " + + maxDistanceArray[0]); + if (debugFlag) + debugPrint(" findFactor returns ****** " + + minFactorArray[0] + " ******"); + return minFactorArray[0]; + } + + /* + * distanceToHead is between points within attenuation arrays. + * Use binary halfing of distance attenuation arrays. + */ + { + double[] distanceArray = new double[arrayLength]; + float[] factorArray = new float[arrayLength]; + boolean[] intersectionCalculated = new boolean[arrayLength]; + // initialize intersection calculated array flags to false + for (int i=0; i= 0.0) + intersectionCalculated[lowIndex] = true; + else { + /* + * Error in ellipse intersection calculation. Use + * average of max/min difference for intersection value. + */ + distanceArray[lowIndex] = (minDistanceArray[lowIndex] + + maxDistanceArray[lowIndex])*0.5; + if (internalErrors) + debugPrint( + "Internal Error in intersectEllipse; use " + + distanceArray[lowIndex] + + " for intersection value " ); + // Rather than aborting, just use average and go on... + intersectionCalculated[lowIndex] = true; + } + } // end of if intersection w/ lowIndex not already calculated + + if (!intersectionCalculated[highIndex]) { + distanceArray[highIndex] = this.intersectEllipse( + maxDistanceArray[highIndex],minDistanceArray[highIndex]); + // If return intersection distance is < 0 an error occurred. + if (distanceArray[highIndex] >= 0.0f) + intersectionCalculated[highIndex] = true; + else { + /* + * Error in ellipse intersection calculation. Use + * average of max/min difference for intersection value. + */ + distanceArray[highIndex] = (minDistanceArray[highIndex]+ + maxDistanceArray[highIndex])*0.5f; + if (internalErrors) + debugPrint( + "Internal Error in intersectEllipse; use " + + distanceArray[highIndex] + + " for intersection value " ); + // Rather than aborting, just use average and go on... + intersectionCalculated[highIndex] = true; + } + } // end of if intersection w/ highIndex not already calculated + + /* + * Test for intersection points being the same as head position + * distanceArray[lowIndex] and distanceArray[highIndex], if so + * return factor value directly from array + */ + if (distanceArray[lowIndex] >= distanceToHead) { + if ((lowIndex != 0) && + (distanceToHead < distanceArray[lowIndex])) { + if (internalErrors) + debugPrint( + "Internal Error: binary halving in " + + "findFactor failed; distance < low " + + "index value"); + } + if (debugFlag) { + debugPrint(" distanceArray[lowIndex] >= " + + "distanceToHead" ); + debugPrint( " factorIndex = " + lowIndex); + } + intersectionOnEllipse = true; + factorIndex = lowIndex; + break; + } + else if (distanceArray[highIndex] <= distanceToHead) { + if ((highIndex != largestIndex) && + (distanceToHead > distanceArray[highIndex])) { + if (internalErrors) + debugPrint( + "Internal Error: binary halving in " + + "findFactor failed; distance > high " + + "index value"); + } + if (debugFlag) { + debugPrint(" distanceArray[highIndex] >= " + + "distanceToHead" ); + debugPrint( " factorIndex = " + highIndex); + } + intersectionOnEllipse = true; + factorIndex = highIndex; + break; + } + + if (distanceToHead > distanceArray[lowIndex] && + distanceToHead < distanceArray[highIndex] ) { + indexMid = lowIndex + ((highIndex - lowIndex) / 2); + if (distanceToHead <= distanceArray[indexMid]) + // value of distance in lower "half" of list + highIndex = indexMid; + else // value if distance in upper "half" of list + lowIndex = indexMid; + } + } /* of while */ + + /* + * First check to see if distanceToHead is beyond min or max + * ellipses, or on an ellipse. + * If so, factor is calculated using the distance Ratio + * (distanceToHead - min) / (max-min) + * where max = maxDistanceArray[factorIndex], and + * min = minDistanceArray[factorIndex] + */ + if (intersectionOnEllipse && factorIndex >= 0) { + if (debugFlag) { + debugPrint( " ratio calculated using factorIndex " + + factorIndex); + debugPrint( " d.A. max pair for factorIndex " + + maxDistanceArray[factorIndex] + ", " + + maxFactorArray[factorIndex]); + debugPrint( " d.A. min pair for lowIndex " + + minDistanceArray[factorIndex] + ", " + + minFactorArray[factorIndex]); + } + returnValue = ( + ( (distanceArray[factorIndex] - + minDistanceArray[factorIndex]) / + (maxDistanceArray[factorIndex] - + minDistanceArray[factorIndex]) ) * + (maxFactorArray[factorIndex] - + minFactorArray[factorIndex]) ) + + minFactorArray[factorIndex] ; + if (debugFlag) + debugPrint(" findFactor returns ****** " + + returnValue + " ******"); + return (float)returnValue; + } + + /* Otherwise, for distanceToHead between distance intersection + * values, we need to calculate two factors - one for the + * ellipse defined by lowIndex min/max factor arrays, and + * the other by highIndex min/max factor arrays. Then the + * distance Ratio (defined above) is applied, using these + * two factor values, to get the final return value. + */ + double highFactorValue = 1.0; + double lowFactorValue = 0.0; + highFactorValue = + ( ((distanceArray[highIndex] - minDistanceArray[highIndex]) / + (maxDistanceArray[highIndex]-minDistanceArray[highIndex])) * + (maxFactorArray[highIndex] - minFactorArray[highIndex]) ) + + minFactorArray[highIndex] ; + if (debugFlag) { + debugPrint( " highFactorValue calculated w/ highIndex " + + highIndex); + debugPrint( " d.A. max pair for highIndex " + + maxDistanceArray[highIndex] + ", " + + maxFactorArray[highIndex]); + debugPrint( " d.A. min pair for lowIndex " + + minDistanceArray[highIndex] + ", " + + minFactorArray[highIndex]); + debugPrint( " highFactorValue " + highFactorValue); + } + lowFactorValue = + ( ((distanceArray[lowIndex] - minDistanceArray[lowIndex]) / + (maxDistanceArray[lowIndex] - minDistanceArray[lowIndex])) * + (maxFactorArray[lowIndex] - minFactorArray[lowIndex]) ) + + minFactorArray[lowIndex] ; + if (debugFlag) { + debugPrint( " lowFactorValue calculated w/ lowIndex " + + lowIndex); + debugPrint( " d.A. max pair for lowIndex " + + maxDistanceArray[lowIndex] + ", " + + maxFactorArray[lowIndex]); + debugPrint( " d.A. min pair for lowIndex " + + minDistanceArray[lowIndex] + ", " + + minFactorArray[lowIndex]); + debugPrint( " lowFactorValue " + lowFactorValue); + } + /* + * calculate gain scale factor based on the ratio distance + * between ellipses the distanceToHead lies between. + */ + /* + * ratio: distance from listener to sound source + * between lowIndex and highIndex times + * attenuation value between lowIndex and highIndex + * gives linearly interpolationed attenuation value + */ + if (debugFlag) { + debugPrint( " ratio calculated using distanceArray" + + lowIndex + ", highIndex " + highIndex); + debugPrint( " calculated pair for lowIndex " + + distanceArray[lowIndex]+", "+ lowFactorValue); + debugPrint( " calculated pair for highIndex " + + distanceArray[highIndex]+", "+ highFactorValue ); + } + + returnValue = + ( ( (distanceToHead - distanceArray[lowIndex]) / + (distanceArray[highIndex] - distanceArray[lowIndex]) ) * + (highFactorValue - lowFactorValue) ) + + factorArray[lowIndex] ; + if (debugFlag) + debugPrint(" findFactor returns ******" + + returnValue + " ******"); + return (float)returnValue; + } + + } + + /** + * CalculateDistanceAttenuation + * + * Simply calls ConeSound specific 'findFactor()' with + * both front and back attenuation linear distance and gain scale factor + * arrays. + */ + float calculateDistanceAttenuation(float distance) { + float factor = findFactor(distance, this.attenuationDistance, + this.attenuationGain, this.backAttenuationDistance, + this.backAttenuationGain); + if (factor < 0.0f) + return 1.0f; + else + return factor; + } + /** + * CalculateAngularGain + * + * Simply calls generic (for PointSound) 'findFactor()' with + * a single set of angular attenuation distance and gain scalefactor arrays. + */ + float calculateAngularGain() { + float angle = findAngularOffset(); + float factor = findFactor(angle, this.angularDistance, this.angularGain); + if (factor < 0.0f) + return 1.0f; + else + return factor; + } + + /* ***************** + * + * Find Angular Offset + * + * *****************/ + /* + * Calculates the angle from the sound's direction axis and the ray from + * the sound origin to the listener'center ear. + * For Cone Sounds this value is the arc cosine of dot-product between + * the sound direction vector and the vector (sound position,centerEar) + * all in Virtual World coordinates space. + * Center ear position is in Virtual World coordinates. + * Assumes that calculation done in VWorld Space... + * Assumes that xformPosition is already calculated... + */ + float findAngularOffset() { + Vector3f unitToEar = new Vector3f(); + Vector3f unitDirection = new Vector3f(); + Point3f xformPosition = positions[currentIndex]; + Point3f xformCenterEar = centerEars[currentIndex]; + float dotProduct; + float angle; + /* + * TODO: (Question) is assumption that xformed values available O.K. + * TODO: (Performance) save this angular offset and only recalculate + * if centerEar or sound position have changed. + */ + unitToEar.x = xformCenterEar.x - xformPosition.x; + unitToEar.y = xformCenterEar.y - xformPosition.y; + unitToEar.z = xformCenterEar.z - xformPosition.z; + unitToEar.normalize(); + unitDirection.normalize(this.direction); + dotProduct = unitToEar.dot(unitDirection); + angle = (float)(Math.acos((double)dotProduct)); + if (debugFlag) + debugPrint(" angle from cone direction = " + angle); + return(angle); + } + + /************ + * + * Calculate Filter + * + * *****************/ + /* + * Calculates the low-pass cutoff frequency filter value applied to the + * a sound based on both: + * Distance Filter (from Aural Attributes) based on distance + * between the sound and the listeners position + * Angular Filter (for Directional Sounds) based on the angle + * between a sound's projected direction and the + * vector between the sounds position and center ear. + * The lowest of these two filter is used. + * This filter value is stored into the sample's filterFreq field. + */ + void calculateFilter(float distance, AuralParameters attribs) { + // setting filter cutoff freq to 44.1kHz which, in this + // implementation, is the same as not performing filtering + float distanceFilter = 44100.0f; + float angularFilter = 44100.0f; + int arrayLength = attribs.getDistanceFilterLength(); + int filterType = attribs.getDistanceFilterType(); + + boolean distanceFilterFound = false; + boolean angularFilterFound = false; + if ((filterType == AuralParameters.NO_FILTERING) && arrayLength > 0) { + double[] distanceArray = new double[arrayLength]; + float[] cutoffArray = new float[arrayLength]; + attribs.getDistanceFilter(distanceArray, cutoffArray); + + if (debugFlag) { + debugPrint("distanceArray cutoffArray"); + for (int i=0; i + * NOTE: This class is not yet implemented. + */ + +class JSMidi extends JSChannel { + private static boolean warningReported = false; + + JSMidi() { + // Report a "not implemented" warning message + if (!warningReported) { + System.err.println("***"); + System.err.println("*** WARNING: JavaSoundMixer: MIDI sound not implemented"); + System.err.println("***"); + warningReported = true; + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSPositionalSample.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSPositionalSample.java new file mode 100755 index 0000000..1404345 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSPositionalSample.java @@ -0,0 +1,1339 @@ +/* + * $RCSfile: JSPositionalSample.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:03 $ + * $State: Exp $ + */ + +/* + * Java Sound PositionalSample object + * + * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs + * to be rewritten. + */ + +package com.sun.j3d.audioengines.javasound; + +import javax.media.j3d.*; +import javax.vecmath.*; +import com.sun.j3d.audioengines.*; + +/** + * The PostionalSample Class defines the data and methods associated with a + * PointSound sample played thru the AudioDevice. + */ + +class JSPositionalSample extends JSSample +{ + + // maintain fields for stereo channel rendering + float leftGain = 1.0f; // scale factor + float rightGain = 1.0f; // scale factor + int leftDelay = 0; // left InterauralTimeDifference in millisec + int rightDelay = 0; // right ITD in millisec + // fields for reverb channel + + // debug flag for the verbose Doppler calculation methods + static final + protected boolean dopplerFlag = true; + + /** + * For positional and directional sounds, TWO Hae streams or clips + * are allocated, one each for the left and right channels, played at + * a different (delayed) time and with a different gain value. + */ + int secondIndex = NULL_SAMPLE; + /** + * A third sample for control of reverb of the stream/clip is openned + * and maintained for all directional/positional sounds. + * For now, even if no aural attributes (using reverb) are active, + * a reverb channel is always started with the other two. A sound could + * be started without reverb and then reverb added later, but since there + * is no way to offset properly into all sounds (considering non-cached + * and nconsistent rate-changes during playing) this third sound is + * always allocated and started. + */ + int reverbIndex = NULL_SAMPLE; + + /** + * Save ear positions transformed into VirtualWorld coords from Head coords + * These default positions are used when the real values cannot queried + */ + Point3f xformLeftEar = new Point3f(-0.09f, -0.03f, 0.095f); + Point3f xformRightEar = new Point3f(0.09f, -0.03f, 0.095f); + // Z axis in head space - looking into the screen + Vector3f xformHeadZAxis = new Vector3f(0.0f, 0.0f, -1.0f); // Va + + /** + * Save vectors from source source position to transformed ear parameters + */ + Vector3f sourceToCenterEar = new Vector3f(); // Vh + Vector3f sourceToRightEar = new Vector3f(); // Vf or Vc + Vector3f sourceToLeftEar = new Vector3f(); // Vf or Vc + + boolean averageDistances = false; + long deltaTime = 0; + double sourcePositionChange = -1.0; + double headPositionChange = -1.0; + + /* + * Maintain the last locations of sound and head as well as time the + * sound was last processed. + * Process delta distance and time as part of Doppler calculations. + */ + static int MAX_DISTANCES = 4; + int numDistances = 0; +// TODO: time is based on changes to position!!! only +// TODO: must shap shot when either Position OR ear changes!!! +// TODO: must grab all changes to VIEW parameters (could change ear)!!! +// not just when pointer to View changes!! + long[] times = new long[MAX_DISTANCES]; + Point3f[] positions = new Point3f[MAX_DISTANCES]; // xformed sound source positions + Point3f[] centerEars = new Point3f[MAX_DISTANCES]; // xformed center ear positions + /* + * a set of indices (first, last, and current) are maintained to point + * into the above arrays + */ + int firstIndex = 0; + int lastIndex = 0; + int currentIndex = 0; + + /* + * Allow changes in Doppler rate only small incremental values otherwise + * you hear skips in the pitch of a sound during playback. + * When playback is faster, allow delta changes: + * (diff in Factor for octave (1.0))/(12 1/2-steps))*(1/4) of half-step + * When playback is slower, allow delta changes: + * (diff in Factor for octave (0.5))/(12 1/2-steps))*(1/4) of half-step + */ + double lastRequestedDopplerRateRatio = -1.0f; + double lastActualDopplerRateRatio = -1.0f; + static double maxRatio = 256.0f; // 8 times higher/lower + /* + * denotes movement of sound away or towards listener + */ + static int TOWARDS = 1; + static int NO_CHANGE = 0; + static int AWAY = -1; + + /* + * Process request for Filtering fields + */ + boolean filterFlag = false; + float filterFreq = -1.0f; + + /* + * Construct a new audio device Sample object + */ + public JSPositionalSample() { + super(); + if (debugFlag) + debugPrint("JSPositionalSample constructor"); + // initiallize circular buffer for averaging distance values + for (int i=0; i maxIndex) { + // increment each counter and loop around + averageDistances = true; + currentIndex++; + lastIndex++; + firstIndex++; + currentIndex %= MAX_DISTANCES; + lastIndex %= MAX_DISTANCES; + firstIndex %= MAX_DISTANCES; + } + } + + // Not only do we transform position but delta time is calculated and + // old transformed position is saved + // Average the last MAX_DISTANCES delta time and change in position using + // an array for both and circlularly storing the time and distance values + // into this array. + // Current transformed position and time in stored into maxIndex of their + // respective arrays. + void setXformedPosition() { + Point3f newPosition = new Point3f(); + if (debugFlag) + debugPrint("*** setXformedPosition"); + // xform Position + if (getVWrldXfrmFlag()) { + if (debugFlag) + debugPrint(" Transform set so transform pos"); + vworldXfrm.transform(position, newPosition); + } + else { + if (debugFlag) + debugPrint(" Transform NOT set so pos => xformPos"); + newPosition.set(position); + } + // store position and increment indices ONLY if theres an actual change + if (newPosition.x == positions[currentIndex].x && + newPosition.y == positions[currentIndex].y && + newPosition.z == positions[currentIndex].z ) { + if (debugFlag) + debugPrint(" No change in pos, so don't reset"); + return; + } + + incrementIndices(); + // store new transformed position + times[currentIndex] = System.currentTimeMillis(); + positions[currentIndex].set(newPosition); + if (debugFlag) + debugPrint(" xform(sound)Position -" + + " positions[" + currentIndex + "] = (" + + positions[currentIndex].x + ", " + + positions[currentIndex].y + ", " + + positions[currentIndex].z + ")"); + + // since this is a change to the sound position and not the + // head save the last head position into the current element + if (numDistances > 1) + centerEars[currentIndex].set(centerEars[lastIndex]); + + } + + /** + * Set Doppler effect Rate + * + * Calculate the rate of change in for the head and sound + * between the two time stamps (last two times position or + * VirtualWorld transform was updated). + * First determine if the head and sound source are moving + * towards each other (distance between them is decreasing), + * moving away from each other (distance between them is + * increasing), or no change (distance is the same, not moving + * or moving the same speed/direction). + * The following equation is used for determining the change in frequency - + * If there has been a change in the distance between the head and sound: + * + * f' = f * frequencyScaleFactor * velocityRatio + * + * For no change in the distance bewteen head and sound, velocityRatio is 1: + * + * f' = f + * + * For head and sound moving towards each other, velocityRatio (> 1.0) is: + * + * | speedOfSound*rollOff + velocityOfHead*velocityScaleFactor | + * | ------------------------------------------------------------- | + * | speedOfSound*rollOff - velocityOfSource*velocityScaleFactor | + * + * For head and sound moving away from each other, velocityRatio (< 1.0) is: + * + * | speedOfSound*rollOff - velocityOfHead*velocityScaleFactor | + * | ------------------------------------------------------------- | + * | speedOfSound*rollOff + velocityOfSource*velocityScaleFactor | + * + * where frequencyScaleFactor, rollOff, velocityScaleFactor all come from + * the active AuralAttributes parameters. + * The following special cases must be test for AuralAttribute parameters: + * rolloff + * Value MUST be > zero for any sound to be heard! + * If value is zero, all sounds affected by AuralAttribute region are silent. + * velocityScaleFactor + * Value MUST be > zero for any sound to be heard! + * If value is zero, all sounds affected by AuralAttribute region are paused. + * frequencyScaleFactor + * Value of zero disables Doppler calculations: + * Sfreq' = Sfreq * frequencyScaleFactor + * + * This rate is passed to device drive as a change to playback sample + * rate, in this case the frequency need not be known. + * + * Return value of zero denotes no change + * Return value of -1 denotes ERROR + */ + float calculateDoppler(AuralParameters attribs) { + double sampleRateRatio = 1.0; + double headVelocity = 0.0; // in milliseconds + double soundVelocity = 0.0; // in milliseconds + double distanceSourceToHead = 0.0; // in meters + double lastDistanceSourceToHead = 0.0; // in meters + float speedOfSound = attribs.SPEED_OF_SOUND; + double numerator = 1.0; + double denominator = 1.0; + int direction = NO_CHANGE; // sound movement away or towards listener + + Point3f lastXformPosition; + Point3f lastXformCenterEar; + Point3f xformPosition; + Point3f xformCenterEar; + float averagedSoundDistances = 0.0f; + float averagedEarsDistances = 0.0f; + + /* + * Average the differences between the last MAX_DISTANCE + * sound positions and head positions + */ + if (!averageDistances) { + // TODO: Use some EPSilion to do 'equals' test against + if (dopplerFlag) + debugPrint("JSPositionalSample.calculateDoppler - " + + "not enough distance data collected, " + + "dopplerRatio set to zero"); + // can't calculate change in direction + return 0.0f; // sample rate ratio is zero + } + + lastXformPosition = positions[lastIndex]; + lastXformCenterEar = centerEars[lastIndex]; + xformPosition = positions[currentIndex]; + xformCenterEar = centerEars[currentIndex]; + distanceSourceToHead = xformPosition.distance(xformCenterEar); + lastDistanceSourceToHead = lastXformPosition.distance(lastXformCenterEar); + if (dopplerFlag) { + debugPrint("JSPositionalSample.calculateDoppler - distances: " + + "current,last = " + distanceSourceToHead + ", " + + lastDistanceSourceToHead ); + debugPrint(" " + + "current position = " + + xformPosition.x + ", " + xformPosition.y + + ", " + xformPosition.z); + debugPrint(" " + + "current ear = " + + xformCenterEar.x + ", " + xformCenterEar.y + + ", " + xformCenterEar.z); + debugPrint(" " + + "last position = " + + lastXformPosition.x + ", " + lastXformPosition.y + + ", " + lastXformPosition.z); + debugPrint(" " + + "last ear = " + + lastXformCenterEar.x + ", " + lastXformCenterEar.y + + ", " + lastXformCenterEar.z); + } + if (distanceSourceToHead == lastDistanceSourceToHead) { + // TODO: Use some EPSilion to do 'equals' test against + if (dopplerFlag) + debugPrint("JSPositionalSample.calculateDoppler - " + + "distance diff = 0, dopplerRatio set to zero"); + // can't calculate change in direction + return 0.0f; // sample rate ratio is zero + } + + deltaTime = times[currentIndex] - times[firstIndex]; + for (int i=0; i<(MAX_DISTANCES-1); i++) { + averagedSoundDistances += positions[i+1].distance(positions[i]); + averagedEarsDistances += centerEars[i+1].distance(centerEars[i]); + } + averagedSoundDistances /= (MAX_DISTANCES-1); + averagedEarsDistances /= (MAX_DISTANCES-1); + soundVelocity = averagedSoundDistances/deltaTime; + headVelocity = averagedEarsDistances/deltaTime; + if (dopplerFlag) { + debugPrint(" " + + "delta time = " + deltaTime ); + debugPrint(" " + + "soundPosition delta = " + + xformPosition.distance(lastXformPosition)); + debugPrint(" " + + "soundVelocity = " + soundVelocity); + debugPrint(" " + + "headPosition delta = " + + xformCenterEar.distance(lastXformCenterEar)); + debugPrint(" " + + "headVelocity = " + headVelocity); + } + if (attribs != null) { + + float rolloff = attribs.rolloff; + float velocityScaleFactor = attribs.velocityScaleFactor; + if (rolloff != 1.0f) { + speedOfSound *= rolloff; + if (dopplerFlag) + debugPrint(" " + + "attrib rollof = " + rolloff); + } + if (velocityScaleFactor != 1.0f) { + soundVelocity *= velocityScaleFactor; + headVelocity *= velocityScaleFactor; + if (dopplerFlag) { + debugPrint(" " + + "attrib velocity scale factor = " + + velocityScaleFactor ); + debugPrint(" " + + "new soundVelocity = " + soundVelocity); + debugPrint(" " + + "new headVelocity = " + headVelocity); + } + } + } + if (distanceSourceToHead < lastDistanceSourceToHead) { + // sound and head moving towards each other + if (dopplerFlag) + debugPrint(" " + + "moving towards..."); + direction = TOWARDS; + numerator = speedOfSound + headVelocity; + denominator = speedOfSound - soundVelocity; + } + else { + // sound and head moving away from each other + // note: no change in distance case covered above + if (dopplerFlag) + debugPrint(" " + + "moving away..."); + direction = AWAY; + numerator = speedOfSound - headVelocity; + denominator = speedOfSound + soundVelocity; + } + if (numerator <= 0.0) { + if (dopplerFlag) + debugPrint("JSPositionalSample.calculateDoppler: " + + "BOOM!! - velocity of head > speed of sound"); + return -1.0f; + } + else if (denominator <= 0.0) { + if (dopplerFlag) + debugPrint("JSPositionalSample.calculateDoppler: " + + "BOOM!! - velocity of sound source negative"); + return -1.0f; + } + else { + if (dopplerFlag) + debugPrint("JSPositionalSample.calculateDoppler: " + + "numerator = " + numerator + + ", denominator = " + denominator ); + sampleRateRatio = numerator / denominator; + } + +/******** + IF direction WERE important to calling method... + * Return value greater than 0 denotes direction of sound source is + * towards the listener + * Return value less than 0 denotes direction of sound source is + * away from the listener + if (direction == AWAY) + return -((float)sampleRateRatio); + else + return (float)sampleRateRatio; +*********/ + return (float)sampleRateRatio; + } + + void updateEar(int dirtyFlags, View view) { + if (debugFlag) + debugPrint("*** updateEar fields"); + // xform Ear + Point3f xformCenterEar = new Point3f(); + if (!calculateNewEar(dirtyFlags, view, xformCenterEar)) { + if (debugFlag) + debugPrint("calculateNewEar returned false"); + return; + } + // store ear and increment indices ONLY if there is an actual change + if (xformCenterEar.x == centerEars[currentIndex].x && + xformCenterEar.y == centerEars[currentIndex].y && + xformCenterEar.z == centerEars[currentIndex].z ) { + if (debugFlag) + debugPrint(" No change in ear, so don't reset"); + return; + } + // store xform Ear + incrementIndices(); + times[currentIndex] = System.currentTimeMillis(); + centerEars[currentIndex].set(xformCenterEar); + // since this is a change to the head position and not the sound + // position save the last sound position into the current element + if (numDistances > 1) + positions[currentIndex].set(positions[lastIndex]); + } + + boolean calculateNewEar(int dirtyFlags, View view, Point3f xformCenterEar) { + /* + * Transform ear position (from Head) into Virtual World Coord space + */ + Point3d earPosition = new Point3d(); // temporary double Point + + // TODO: check dirty flags coming in + // For now, recalculate ear positions by forcing earsXformed false + boolean earsXformed = false; + if (!earsXformed) { + if (view != null) { + PhysicalBody body = view.getPhysicalBody(); + if (body != null) { + + // Get Head Coord. to Virtual World transform + // TODO: re-enable this when userHeadToVworld is + // implemented correctly!!! + Transform3D headToVwrld = new Transform3D(); + view.getUserHeadToVworld(headToVwrld); + if (debugFlag) { + debugPrint("user head to Vwrld colum-major:"); + double[] matrix = new double[16]; + headToVwrld.get(matrix); + debugPrint("JSPosSample " + matrix[0]+", " + + matrix[1]+", "+matrix[2]+", "+matrix[3]); + debugPrint("JSPosSample " + matrix[4]+", " + + matrix[5]+", "+matrix[6]+", "+matrix[7]); + debugPrint("JSPosSample " + matrix[8]+", " + + matrix[9]+", "+matrix[10]+", "+matrix[11]); + debugPrint("JSPosSample " + matrix[12]+", " + + matrix[13]+", "+matrix[14]+", "+matrix[15]); + } + + // Get left and right ear positions in Head Coord.s + // Transforms left and right ears to Virtual World coord.s + body.getLeftEarPosition(earPosition); + xformLeftEar.x = (float)earPosition.x; + xformLeftEar.y = (float)earPosition.y; + xformLeftEar.z = (float)earPosition.z; + body.getRightEarPosition(earPosition); + xformRightEar.x = (float)earPosition.x; + xformRightEar.y = (float)earPosition.y; + xformRightEar.z = (float)earPosition.z; + headToVwrld.transform(xformRightEar); + headToVwrld.transform(xformLeftEar); + // Transform head viewing (Z) axis to Virtual World coord.s + xformHeadZAxis.set(0.0f, 0.0f, -1.0f); // Va + headToVwrld.transform(xformHeadZAxis); + + // calculate the new (current) mid-point between the ears + // find the mid point between left and right ear positions + xformCenterEar.x = xformLeftEar.x + + ((xformRightEar.x - xformLeftEar.x)*0.5f); + xformCenterEar.y = xformLeftEar.y + + ((xformRightEar.y - xformLeftEar.y)*0.5f); + xformCenterEar.z = xformLeftEar.z + + ((xformRightEar.z - xformLeftEar.z)*0.5f); + // TODO: when head changes earDirty should be set! + // earDirty = false; + if (debugFlag) { + debugPrint(" earXformed CALCULATED"); + debugPrint(" xformCenterEar = " + + xformCenterEar.x + " " + + xformCenterEar.y + " " + + xformCenterEar.z ); + } + earsXformed = true; + } // end of body NOT null + } // end of view NOT null + } // end of earsDirty + else { + // TODO: use existing transformed ear positions + } + + if (!earsXformed) { + // uses the default head position of (0.0, -0.03, 0.095) + if (debugFlag) + debugPrint(" earXformed NOT calculated"); + } + return earsXformed; + } + + /** + * Render this sample + * + * Calculate the audiodevice parameters necessary to spatially play this + * sound. + */ + public void render(int dirtyFlags, View view, AuralParameters attribs) { + if (debugFlag) + debugPrint("JSPositionalSample.render"); + updateEar(dirtyFlags, view); + + /* + * Time to check velocities and change the playback rate if necessary... + * + * Rolloff value MUST be > zero for any sound to be heard! + * If rolloff is zero, all sounds affected by AuralAttribute region + * are silent. + * FrequencyScaleFactor value MUST be > zero for any sound to be heard! + * since Sfreq' = Sfreq * frequencyScaleFactor. + * If FrequencyScaleFactor is zero, all sounds affected by + * AuralAttribute region are paused. + * VelocityScaleFactor value of zero disables Doppler calculations. + * + * Scale 'Doppler' rate (or lack of Doppler) by frequencyScaleFactor. + */ + float dopplerRatio = 1.0f; + if (attribs != null) { + float rolloff = attribs.rolloff; + float frequencyScaleFactor = attribs.frequencyScaleFactor; + float velocityScaleFactor = attribs.velocityScaleFactor; + if (debugFlag || dopplerFlag) + debugPrint("JSPositionalSample: attribs NOT null"); + if (rolloff <= 0.0f) { + if (debugFlag) + debugPrint(" rolloff = " + rolloff + " <= 0.0" ); + // TODO: Make sound silent + // return ??? + } + else if (frequencyScaleFactor <= 0.0f) { + if (debugFlag) + debugPrint(" freqScaleFactor = " + frequencyScaleFactor + + " <= 0.0" ); + // TODO: Pause sound silent + // return ??? + } + else if (velocityScaleFactor > 0.0f) { + if (debugFlag || dopplerFlag) + debugPrint(" velocityScaleFactor = " + + velocityScaleFactor); +/******* + if (deltaTime > 0) { +*******/ + // Doppler can be calculated after the second time + // updateXformParams() is executed + dopplerRatio = calculateDoppler(attribs); + + if (dopplerRatio == 0.0f) { + // dopplerRatio zeroo denotes no changed + // TODO: But what if frequencyScaleFactor has changed + if (debugFlag) { + debugPrint("JSPositionalSample: render: " + + "dopplerRatio returned zero; no change"); + } + } + else if (dopplerRatio == -1.0f) { + // error returned by calculateDoppler + if (debugFlag) { + debugPrint("JSPositionalSample: render: " + + "dopplerRatio returned = " + + dopplerRatio + "< 0"); + } + // TODO: Make sound silent + // return ??? + } + else if (dopplerRatio > 0.0f) { + // rate could be changed + rateRatio = dopplerRatio * frequencyScaleFactor * + getRateScaleFactor(); + if (debugFlag) { + debugPrint(" scaled by frequencyScaleFactor = " + + frequencyScaleFactor ); + } + } +/****** + } + else { + if (debugFlag) + debugPrint("deltaTime <= 0 - skip Doppler calc"); + } +******/ + } + else { // auralAttributes not null but velocityFactor <= 0 + // Doppler is disabled + rateRatio = frequencyScaleFactor * getRateScaleFactor(); + } + } + /* + * since aural attributes undefined, default values are used, + * thus no Doppler calculated + */ + else { + if (debugFlag || dopplerFlag) + debugPrint("JSPositionalSample: attribs null"); + rateRatio = 1.0f; + } + + this.panSample(attribs); + } + + /* ***************** + * + * Calculate Angular Gain + * + * *****************/ + /* + * Calculates the Gain scale factor applied to the overall gain for + * a sound based on angle between a sound's projected direction and the + * vector between the sounds position and center ear. + * + * For Point Sounds this value is always 1.0f. + */ + float calculateAngularGain() { + return(1.0f); + } + + /* ***************** + * + * Calculate Filter + * + * *****************/ + /* + * Calculates the low-pass cutoff frequency filter value applied to the + * a sound based on both: + * Distance Filter (from Aural Attributes) based on distance + * between the sound and the listeners position + * Angular Filter (for Directional Sounds) based on the angle + * between a sound's projected direction and the + * vector between the sounds position and center ear. + * The lowest of these two filter is used. + * This filter value is stored into the sample's filterFreq field. + */ + void calculateFilter(float distance, AuralParameters attribs) { + // setting filter cutoff freq to 44.1kHz which, in this + // implementation, is the same as not performing filtering + float distanceFilter = 44100.0f; + float angularFilter = 44100.0f; + int arrayLength = attribs.getDistanceFilterLength(); + int filterType = attribs.getDistanceFilterType(); + boolean distanceFilterFound = false; + boolean angularFilterFound = false; + if ((filterType != AuralParameters.NO_FILTERING) && arrayLength > 0) { + double[] distanceArray = new double[arrayLength]; + float[] cutoffArray = new float[arrayLength]; + attribs.getDistanceFilter(distanceArray, cutoffArray); + + if (debugFlag) { + debugPrint("distanceArray cutoffArray"); + for (int i=0; i= distanceArray[largestIndex]) { + if (debugFlag) { + debugPrint(" findFactor: distance > " + + distanceArray[largestIndex]); + debugPrint(" distanceArray length = "+ arrayLength); + } + return factorArray[largestIndex]; + } + else if (distance <= distanceArray[0]) { + if (debugFlag) + debugPrint(" findFactor: distance < " + + distanceArray[0]); + return factorArray[0]; + } + /* + * Distance between points within attenuation array. + * Use binary halfing of distance array + */ + else { + lowIndex = 0; + highIndex = largestIndex; + if (debugFlag) + debugPrint(" while loop to find index: "); + while (lowIndex < (highIndex-1)) { + if (debugFlag) { + debugPrint(" lowIndex " + lowIndex + + ", highIndex " + highIndex); + debugPrint(" d.A. pair for lowIndex " + + distanceArray[lowIndex] + ", " + factorArray[lowIndex] ); + debugPrint(" d.A. pair for highIndex " + + distanceArray[highIndex] + ", " + factorArray[highIndex] ); + } + /* + * we can assume distance is between distance atttenuation vals + * distanceArray[lowIndex] and distanceArray[highIndex] + * calculate gain scale factor based on distance + */ + if (distanceArray[lowIndex] >= distance) { + if (distance < distanceArray[lowIndex]) { + if (internalErrors) + debugPrint("Internal Error: binary halving in " + + " findFactor failed; distance < index value"); + } + if (debugFlag) { + debugPrint( " index == distanceGain " + + lowIndex); + debugPrint(" findFactor returns [LOW=" + + lowIndex + "] " + factorArray[lowIndex]); + } + // take value of scale factor directly from factorArray + return factorArray[lowIndex]; + } + else if (distanceArray[highIndex] <= distance) { + if (distance > distanceArray[highIndex]) { + if (internalErrors) + debugPrint("Internal Error: binary halving in " + + " findFactor failed; distance > index value"); + } + if (debugFlag) { + debugPrint( " index == distanceGain " + + highIndex); + debugPrint(" findFactor returns [HIGH=" + + highIndex + "] " + factorArray[highIndex]); + } + // take value of scale factor directly from factorArray + return factorArray[highIndex]; + } + if (distance > distanceArray[lowIndex] && + distance < distanceArray[highIndex] ) { + indexMid = lowIndex + ((highIndex - lowIndex) / 2); + if (distance <= distanceArray[indexMid]) + // value of distance in lower "half" of list + highIndex = indexMid; + else // value if distance in upper "half" of list + lowIndex = indexMid; + } + } /* of while */ + + /* + * ratio: distance from listener to sound source + * between lowIndex and highIndex times + * attenuation value between lowIndex and highIndex + * gives linearly interpolationed attenuation value + */ + if (debugFlag) { + debugPrint( " ratio calculated using lowIndex " + + lowIndex + ", highIndex " + highIndex); + debugPrint( " d.A. pair for lowIndex " + + distanceArray[lowIndex]+", "+factorArray[lowIndex] ); + debugPrint( " d.A. pair for highIndex " + + distanceArray[highIndex]+", "+factorArray[highIndex] ); + } + + float outputFactor = + ((float)(((distance - distanceArray[lowIndex])/ + (distanceArray[highIndex] - distanceArray[lowIndex]) ) ) * + (factorArray[highIndex] - factorArray[lowIndex]) ) + + factorArray[lowIndex] ; + if (debugFlag) + debugPrint(" findFactor returns " + outputFactor); + return outputFactor; + } + } + + /** + * CalculateDistanceAttenuation + * + * Simply calls generic (for PointSound) 'findFactor()' with + * a single set of attenuation distance and gain scale factor arrays. + */ + float calculateDistanceAttenuation(float distance) { + float factor = 1.0f; + factor = findFactor((double)distance, this.attenuationDistance, + this.attenuationGain); + if (factor >= 0.0) + return (factor); + else + return (1.0f); + } + + /* ****************** + * + * Pan Sample + * + * ******************/ + /* + * Sets pan and delay for a single sample associated with this Sound. + * Front and Back quadrants are treated the same. + */ + void panSample(AuralParameters attribs) { + int quadrant = 1; + float intensityHigh = 1.0f; + float intensityLow = 0.125f; + float intensityDifference = intensityHigh - intensityLow; + + //TODO: time around "average" default head + // int delayHigh = 32; // 32.15 samples = .731 ms + // int delayLow = 0; + + float intensityOffset; // 0.0 -> 1.0 then 1.0 -> 0.0 for full rotation + float halfX; + int id; + int err; + + float nearZero = 0.000001f; + float nearOne = 0.999999f; + float nearNegativeOne = -nearOne; + float halfPi = (float)Math.PI * 0.5f; + /* + * Parameters used for IID and ITD equations. + * Name of parameters (as used in Guide, E.3) are denoted in comments. + */ + float distanceSourceToCenterEar = 0.0f; // Dh + float lastDistanceSourceToCenterEar = 0.0f; + float distanceSourceToRightEar = 0.0f; // Ef or Ec + float distanceSourceToLeftEar = 0.0f; // Ef or Ec + float distanceBetweenEars = 0.18f; // De + float radiusOfHead = 0.0f; // De/2 + float radiusOverDistanceToSource = 0.0f; // De/2 * 1/Dh + + float alpha = 0.0f; // 'alpha' + float sinAlpha = 0.0f; // sin(alpha); + float gamma = 0.0f; // 'gamma' + + // Speed of Sound (unaffected by rolloff) in millisec/meters + float speedOfSound = attribs.SPEED_OF_SOUND; + float invSpeedOfSound = 1.0f / attribs.SPEED_OF_SOUND; + + float sampleRate = 44.1f; // 44 samples/millisec + + boolean rightEarClosest = false; + boolean soundFromBehind = false; + + float distanceGain = 1.0f; + float allGains = this.gain; // product of gain scale factors + + Point3f workingPosition = new Point3f(); + Point3f workingCenterEar = new Point3f(); + + // Asuumes that head and ear positions can be retrieved from universe + + Vector3f mixScale = new Vector3f(); // for mix*Samples code + + // Use transformed position of this sound + workingPosition.set(positions[currentIndex]); + workingCenterEar.set(centerEars[currentIndex]); + if (debugFlag) { + debugPrint("panSample:workingPosition from" + + " positions["+currentIndex+"] -> " + + workingPosition.x + ", " + workingPosition.y + ", " + + workingPosition.z + " for pointSound " + this); + debugPrint("panSample:workingCenterEar " + + workingCenterEar.x + " " + workingCenterEar.y + " " + + workingCenterEar.z); + debugPrint("panSample:xformLeftEar " + + xformLeftEar.x + " " + xformLeftEar.y + " " + + xformLeftEar.z); + debugPrint("panSample:xformRightEar " + + xformRightEar.x + " " + xformRightEar.y + " " + + xformRightEar.z); + } + + // Create the vectors from the sound source to head positions + sourceToCenterEar.x = workingCenterEar.x - workingPosition.x; + sourceToCenterEar.y = workingCenterEar.y - workingPosition.y; + sourceToCenterEar.z = workingCenterEar.z - workingPosition.z; + sourceToRightEar.x = xformRightEar.x - workingPosition.x; + sourceToRightEar.y = xformRightEar.y - workingPosition.y; + sourceToRightEar.z = xformRightEar.z - workingPosition.z; + sourceToLeftEar.x = xformLeftEar.x - workingPosition.x; + sourceToLeftEar.y = xformLeftEar.y - workingPosition.y; + sourceToLeftEar.z = xformLeftEar.z - workingPosition.z; + + /* + * get distances from SoundSource to + * (i) head origin + * (ii) right ear + * (iii) left ear + */ + distanceSourceToCenterEar = workingPosition.distance(workingCenterEar); + distanceSourceToRightEar = workingPosition.distance(xformRightEar); + distanceSourceToLeftEar = workingPosition.distance(xformLeftEar); + distanceBetweenEars = xformRightEar.distance(xformLeftEar); + if (debugFlag) + debugPrint(" distance from left,right ears to source: = (" + + distanceSourceToLeftEar + ", " + distanceSourceToRightEar + ")"); + + radiusOfHead = distanceBetweenEars * 0.5f; + if (debugFlag) + debugPrint(" radius of head = " + radiusOfHead ); + radiusOverDistanceToSource = // De/2 * 1/Dh + radiusOfHead/distanceSourceToCenterEar; + if (debugFlag) + debugPrint(" radius over distance = " + radiusOverDistanceToSource ); + if (debugFlag) { + debugPrint("panSample:source to center ear " + + sourceToCenterEar.x + " " + sourceToCenterEar.y + " " + + sourceToCenterEar.z ); + debugPrint("panSample:xform'd Head ZAxis " + + xformHeadZAxis.x + " " + xformHeadZAxis.y + " " + + xformHeadZAxis.z ); + debugPrint("panSample:length of sourceToCenterEar " + + sourceToCenterEar.length()); + debugPrint("panSample:length of xformHeadZAxis " + + xformHeadZAxis.length()); + } + + // Dot Product + double dotProduct = (double)( + (sourceToCenterEar.dot(xformHeadZAxis))/ + (sourceToCenterEar.length() * xformHeadZAxis.length())); + if (debugFlag) + debugPrint( " dot product = " + dotProduct ); + alpha = (float)(Math.acos(dotProduct)); + if (debugFlag) + debugPrint( " alpha = " + alpha ); + + if (alpha > halfPi) { + if (debugFlag) + debugPrint(" sound from behind"); + soundFromBehind = true; + alpha = (float)Math.PI - alpha; + if (debugFlag) + debugPrint( " PI minus alpha =>" + alpha ); + } + else { + soundFromBehind = false; + if (debugFlag) + debugPrint(" sound from in front"); + } + + gamma = (float)(Math.acos(radiusOverDistanceToSource)); + if (debugFlag) + debugPrint( " gamma " + gamma ); + + rightEarClosest = + (distanceSourceToRightEar>distanceSourceToLeftEar) ? false : true ; + /* + * Determine the quadrant sound is in + */ + if (rightEarClosest) { + if (debugFlag) + debugPrint( " right ear closest"); + if (soundFromBehind) + quadrant = 4; + else + quadrant = 1; + } + else { + if (debugFlag) + debugPrint( " left ear closest"); + if (soundFromBehind) + quadrant = 3; + else + quadrant = 2; + } + sinAlpha = (float)(Math.sin((double)alpha)); + if (sinAlpha < 0.0) sinAlpha = -sinAlpha; + if (debugFlag) + debugPrint( " sin(alpha) " + sinAlpha ); + + /* + * The path from sound source to the farthest ear is always indirect + * (it wraps around part of the head). + * Calculate distance wrapped around the head for farthest ear + */ + float DISTANCE = (float)Math.sqrt((double) + distanceSourceToCenterEar * distanceSourceToCenterEar + + radiusOfHead * radiusOfHead); + if (debugFlag) + debugPrint( " partial distance from edge of head to source = " + + distanceSourceToCenterEar); + if (rightEarClosest) { + distanceSourceToLeftEar = + DISTANCE + radiusOfHead * (halfPi+alpha-gamma); + if (debugFlag) + debugPrint(" new distance from left ear to source = " + + distanceSourceToLeftEar); + } + else { + distanceSourceToRightEar = + DISTANCE + radiusOfHead * (halfPi+alpha-gamma); + if (debugFlag) + debugPrint(" new distance from right ear to source = " + + distanceSourceToRightEar); + } + /* + * The path from the source source to the closest ear could either + * be direct or indirect (wraps around part of the head). + * if sinAlpha >= radiusOverDistance path of sound to closest ear + * is direct, otherwise it is indirect + */ + if (sinAlpha < radiusOverDistanceToSource) { + if (debugFlag) + debugPrint(" closest path is also indirect "); + // Path of sound to closest ear is indirect + + if (rightEarClosest) { + distanceSourceToRightEar = + DISTANCE + radiusOfHead * (halfPi-alpha-gamma); + if (debugFlag) + debugPrint(" new distance from right ear to source = " + + distanceSourceToRightEar); + } + else { + distanceSourceToLeftEar = + DISTANCE + radiusOfHead * (halfPi-alpha-gamma); + if (debugFlag) + debugPrint(" new distance from left ear to source = " + + distanceSourceToLeftEar); + } + } + else { + if (debugFlag) + debugPrint(" closest path is direct "); + if (rightEarClosest) { + if (debugFlag) + debugPrint(" direct distance from right ear to source = " + + distanceSourceToRightEar); + } + else { + if (debugFlag) + debugPrint(" direct distance from left ear to source = " + + distanceSourceToLeftEar); + } + } + + /** + * Short-cut taken. Rather than using actual delays from source + * (where the overall distances would be taken into account in + * determining delay) the difference in the left and right delay + * are applied. + * This approach will be preceptibly wrong for sound sources that + * are very far away from the listener so both ears would have + * large delay. + */ + sampleRate = channel.rateInHz * (0.001f); // rate in milliseconds + if (rightEarClosest) { + rightDelay = 0; + leftDelay = (int)((distanceSourceToLeftEar - distanceSourceToRightEar) * + invSpeedOfSound * sampleRate); + } + else { + leftDelay = 0; + rightDelay = (int)((distanceSourceToRightEar - distanceSourceToLeftEar) * + invSpeedOfSound * sampleRate); + } + + if (debugFlag) { + debugPrint(" using inverted SoS = " + invSpeedOfSound); + debugPrint(" and sample rate = " + sampleRate); + debugPrint(" left and right delay = (" + + leftDelay + ", " + rightDelay + ")"); + } + + // What should the gain be for the different ears??? + // TODO: now using a hack that sets gain based on a unit circle!!! + workingPosition.sub(workingCenterEar); // offset sound pos. by head origin + // normalize; put Sound on unit sphere around head origin + workingPosition.scale(1.0f/distanceSourceToCenterEar); + if (debugFlag) + debugPrint(" workingPosition after unitization " + + workingPosition.x+" "+workingPosition.y+" "+workingPosition.z ); + + /* + * Get the correct distance gain scale factor from attenuation arrays. + * This requires that sourceToCenterEar vector has been calculated. + */ + // TODO: now using distance from center ear to source + // Using distances from each ear to source would be more accurate + distanceGain = calculateDistanceAttenuation(distanceSourceToCenterEar); + + allGains *= distanceGain; + + /* + * Add angular gain (for Cone sound) + */ + if (debugFlag) + debugPrint(" all Gains (without angular gain) " + allGains); + // assume that transfromed Position is already calculated + allGains *= this.calculateAngularGain(); + if (debugFlag) + debugPrint(" (incl. angular gain) " + allGains); + + halfX = workingPosition.x/2.0f; + if (halfX >= 0) + intensityOffset = (intensityDifference * (0.5f - halfX)); + else + intensityOffset = (intensityDifference * (0.5f + halfX)); + + /* + * For now have delay constant for front back sound for now + */ + if (debugFlag) + debugPrint("panSample: quadrant " + quadrant); + switch (quadrant) { + case 1: + // Sound from front, right of center of head + case 4: + // Sound from back, right of center of head + rightGain = allGains * (intensityHigh - intensityOffset); + leftGain = allGains * (intensityLow + intensityOffset); + break; + + case 2: + // Sound from front, left of center of head + case 3: + // Sound from back, right of center of head + leftGain = allGains * (intensityHigh - intensityOffset); + rightGain = allGains * (intensityLow + intensityOffset); + break; + } /* switch */ + if (debugFlag) + debugPrint("panSample: left/rightGain " + leftGain + + ", " + rightGain); + + // Combines distance and angular filter to set this sample's current + // frequency cutoff value + calculateFilter(distanceSourceToCenterEar, attribs); + + } /* panSample() */ + +// NOTE: setGain in audioengines.Sample is used to set/get user suppled factor +// this class uses this single gain value to calculate the left and +// right gain values +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSSample.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSSample.java new file mode 100755 index 0000000..1311d4c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSSample.java @@ -0,0 +1,362 @@ +/* + * $RCSfile: JSSample.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:03 $ + * $State: Exp $ + */ + +/* + * Java Sound Sample object + * + * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs + * to be rewritten. + */ + +package com.sun.j3d.audioengines.javasound; + +import java.net.URL; +import java.io.InputStream; +import javax.media.j3d.*; +import javax.sound.sampled.*; +import com.sun.j3d.audioengines.*; + +/** + * The Sample Class extended for Java Sound Mixer specific audio device. + */ + +class JSSample extends com.sun.j3d.audioengines.Sample +{ + /* + * NOTE: for this device type there is exactly one sample associated + * with each sound. + */ + + /** + * Sound Data Types + * + * Samples can be processed as streaming or buffered data. + * Fully spatializing sound sources may require data to be buffered. + * + * Sound data specified as Streaming is not copied by the AudioDevice + * driver implementation. It is up the application to ensure that + * this data is continuously accessible during sound rendering. + * Futhermore, full sound spatialization may not be possible, for + * all AudioDevice implementations on unbuffered sound data. + */ + static final int STREAMING_AUDIO_DATA = 1; + /** + * Sound data specified as Buffered is copied by the AudioDevice + * driver implementation. + */ + static final int BUFFERED_AUDIO_DATA = 2; + /** + * MIDI data + * TODO: differentiate between STREAMING and BUFFERED MIDI data + * right now all MIDI data is buffered + */ + static final int STREAMING_MIDI_DATA = 3; + static final int BUFFERED_MIDI_DATA = 3; + static final int UNSUPPORTED_DATA_TYPE = -1; + + static final int NULL_SAMPLE = -1; + + /** + * sound data types: BUFFERED (cached) or STREAMING (non-cached) + */ + int dataType = BUFFERED_AUDIO_DATA; + + JSChannel channel = null; + + /** + * Offset pointer within currently playing sample data + */ + long dataOffset = 0; + + /* + * Maintain continuously playing silent sound sources. + */ + long timeDeactivated = 0; + long positionDeactivated = 0; + + long sampleLength = 0; + long loopStartOffset = 0; // for most this will be 0 + long loopLength = 0; // for most this is end sample - sampleLength + long attackLength = 0; // portion of sample before loop section + long releaseLength = 0; // portion of sample after loop section + + float rateRatio = 1.0f; + float currentRateRatio = -1.0f; // last actual rate ratio send to device + float targetRateRatio = -1.0f; + boolean rampRateFlag = false; + + public JSSample() { + super(); + if (debugFlag) + debugPrintln("JSSample constructor"); + } + + // the only public methods are those declared in the audioengines + // package as public + + /* + * This excutes code necessary to set current fields to their current + * correct values before JavaSoundMixer either start or updates the + * sample thru calls to JSThread. + */ + public void render(int dirtyFlags, View view, AuralParameters attribs) { + if (debugFlag) + debugPrint("JSSample.render "); + // if this is starting set gain, delay (for Pos), freq rate ... + // TODO: NOT SURE - leaving this in for now + float freqScaleFactor = attribs.frequencyScaleFactor; + if (attribs != null) { + if (freqScaleFactor <= 0.0f) { + // TODO: Pause Sample + } + else + rateRatio = currentRateRatio * freqScaleFactor; + } + else + rateRatio = currentRateRatio; + } + + /** + * Clears/re-initialize fields associated with sample data for + * this sound, + * and frees any device specific data associated with this sample. + */ + public void clear() { + super.clear(); + if (debugFlag) + debugPrintln("JSSample.clear() entered"); + // TODO: unload sound data at device +// null out samples element that points to this? +// would this cause samples list size to shrink? +// if sample elements are never freed then does this mean +// a have a memory leak? + dataType = UNSUPPORTED_DATA_TYPE; + dataOffset = 0; + timeDeactivated = 0; + positionDeactivated = 0; + sampleLength = 0; + loopStartOffset = 0; + loopLength = 0; + attackLength = 0; + releaseLength = 0; + rateRatio = 1.0f; + channel = null; + if (debugFlag) + debugPrintln("JSSample.clear() exited"); + } + + // @return error true if error occurred + boolean load(MediaContainer soundData) { + /** + * Get the AudioInputStream first. + * MediaContiner passed to method assumed to be a clone of the + * application node with the query capability bits set on. + */ + String path = soundData.getURLString(); + URL url = soundData.getURLObject(); + InputStream inputStream = soundData.getInputStream(); + boolean cacheFlag = soundData.getCacheEnable(); + AudioInputStream ais = null; + DataLine dataLine = null; + + // TODO: How do we determine if the file is a MIDI file??? + // for now set dataType to BUFFERED_ or STREAMING_AUDIO_DATA + // used to test for ais instanceof AudioMidiInputStream || + // ais instanceof AudioRmfInputStream ) + // then set dataType = JSSample.BUFFERED_MIDI_DATA; + // QUESTION: can non-cached MIDI files ever be supported ? + /**************** + // TODO: when we have a way to determine data type use code below + if (dataType==UNSUPPORTED_DATA_TYPE OR error_occurred) + clearSound(index); + if (debugFlag) + debugPrintln("JavaSoundMixer.prepareSound get dataType failed"); + return true; + } + *****************/ + // ...for now just check cacheFlag + if (cacheFlag) + dataType = BUFFERED_AUDIO_DATA; + else + dataType = STREAMING_AUDIO_DATA; + + if ((url == null) && (inputStream == null) && (path == null)) { + if (debugFlag) + debugPrint("JavaSoundMixer.loadSound null data - return error"); + return true; + } + + // get ais + if (path != null) { + // generate url from string, and pass url to driver + if (debugFlag) { + debugPrint("JavaSoundMixer.loadSound with path = " + path); + } + try { + url = new URL(path); + } + catch (Exception e) { + // do not throw an exception while rendering + return true; + } + } + + // get DataLine channel based on data type + if (dataType == BUFFERED_AUDIO_DATA) { + if (debugFlag) + debugPrintln("JSSample.load dataType = BUFFERED "); + channel = new JSClip(); + if (debugFlag) + debugPrintln(" calls JSClip.initAudioInputStream"); + if (url != null) + ais = channel.initAudioInputStream(url, cacheFlag); + else if (inputStream != null) + ais = channel.initAudioInputStream(inputStream, cacheFlag); + if (ais == null) { + if (debugFlag) + debugPrintln("JavaSoundMixer.prepareSound " + + "initAudioInputStream() failed"); + return true; + } + if (debugFlag) + debugPrintln(" calls JSClip.initDataLine"); + dataLine = channel.initDataLine(ais); + } + else if (dataType == STREAMING_AUDIO_DATA) { + if (debugFlag) + debugPrintln("JSSample.load dataType = STREAMING "); + channel = new JSStream(); + if (debugFlag) + debugPrintln(" calls JSStream.initAudioInputStream"); + if (url != null) + ais = channel.initAudioInputStream(url, cacheFlag); + else if (inputStream != null) + ais = channel.initAudioInputStream(inputStream, cacheFlag); + if (ais == null) { + if (debugFlag) + debugPrintln("JavaSoundMixer.prepareSound " + + "initAudioInputStream() failed"); + return true; + } + if (debugFlag) + debugPrintln(" calls JSStream.initDataLine"); + dataLine = channel.initDataLine(ais); + } + else { + if (debugFlag) + debugPrintln("JSSample.load doesn't support MIDI yet"); + } + if (dataLine == null) { + if (debugFlag) + debugPrint("JSSample.load initDataLine failed "); + channel = null; + return true; + } + duration = channel.getDuration(); + if (debugFlag) + debugPrint("JSSample.load channel duration = " + duration); + /* + * Since no error occurred while loading, save all the characteristics + * for the sound in the sample. + */ + setDirtyFlags(0xFFFF); + setSoundType(soundType); + setSoundData(soundData); + + if (debugFlag) + debugPrintln("JSSample.load returned without error"); + return false; + } + + void reset() { + if (debugFlag) + debugPrint("JSSample.reset() exit"); + rateRatio = 1.0f; + } + +// TODO: NEED methods for any field accessed by both JSThread and +// JavaSoundMixer so that we can make these MT safe?? + /* + * Process request for Filtering fields + */ + boolean getFilterFlag() { + return false; + } + float getFilterFreq() { + return -1.0f; + } + + void setCurrentRateRatio(float ratio) { + currentRateRatio = ratio; + } + + float getCurrentRateRatio() { + return currentRateRatio; + } + + void setTargetRateRatio(float ratio) { + targetRateRatio = ratio; + } + + float getTargetRateRatio() { + return targetRateRatio; + } + + void setRampRateFlag(boolean flag) { + rampRateFlag = flag; + } + + boolean getRampRateFlag() { + return rampRateFlag; + } + + void setDataType(int type) { + dataType = type; + } + + int getDataType() { + return dataType; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSStream.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSStream.java new file mode 100755 index 0000000..714f8ea --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSStream.java @@ -0,0 +1,67 @@ +/* + * $RCSfile: JSStream.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:03 $ + * $State: Exp $ + */ + +package com.sun.j3d.audioengines.javasound; + +/** + * The JSStream class defines audio output methods that call the JavaSound + * API methods for streams. + * + *

+ * NOTE: This class is not yet implemented. + */ + +class JSStream extends JSChannel { + private static boolean warningReported = false; + + JSStream() { + // Report a "not implemented" warning message + if (!warningReported) { + System.err.println("***"); + System.err.println("*** WARNING: JavaSoundMixer: Streaming (uncached) audio not implemented"); + System.err.println("***"); + warningReported = true; + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSThread.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSThread.java new file mode 100755 index 0000000..dff9752 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JSThread.java @@ -0,0 +1,855 @@ +/* + * $RCSfile: JSThread.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:03 $ + * $State: Exp $ + */ + +package com.sun.j3d.audioengines.javasound; + +/* + * JavaSound engine Thread + * + * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs + * to be rewritten. When this is done, we may or may not need this class. + */ + +import javax.media.j3d.*; +import com.sun.j3d.audioengines.*; + +/** + * The Thread Class extended for JavaSound Mixer specific audio device + * calls that dynamically, in 'real-time" change engine parameters + * such as volume/gain and sample-rate/frequency(pitch). + */ + +class JSThread extends com.sun.j3d.audioengines.AudioEngineThread { + + /** + * The thread data for this thread + */ + int totalChannels = 0; + /** + * flags denoting if dynamic gain or rate interpolation is to be performed + */ + boolean rampGain = false; + + // global thread flat rampRate set true only when setTargetRate called + // for any sample. but it is cleared only by doWork when no sample + // has a need for the rate to be ramped any further. + boolean rampRate = false; + +/*** TODO: + * + * scalefactors applied to current sample rate to determine delta changes + * in rate (in Hz) + * + float currentGain = 1.0f; + float targetGain = 1.0f; +***********/ + + // reference to engine that created this thread + AudioEngine3D audioEngine = null; + + /** + * This constructor simply assigns the given id. + */ + JSThread(ThreadGroup t, AudioEngine3DL2 engine) { + super(t, "J3D-JavaSoundThread"); + audioEngine = engine; + // TODO: really get total JavaSound channels + totalChannels = 32; + if (debugFlag) + debugPrint("JSThread.constructor("+t+")"); + } + + + + /** + * This method performs one iteration of pending work to do + * + * Wildly "garbled" sounds was caused by unequal changes in delta + * time verses delta distances (resulting in jumps in rate factors + * calculated for Doppler. This work thread is meant to smoothly + * increment/decrement changes in rate (and other future parameters) + * until the target value is reached. + */ + synchronized public void doWork() { + if (debugFlag) + debugPrint("JSThread.doWork()"); +/******* + while (rampRate || rampGain) { +*********/ +/****** DESIGN +// Loop while sound is playing, reget attributes and gains/reverb,... params +// update lowlevel params then read modify then copy to line(s) + +can keep my own loop count for streams??? not really + +*******/ + // QUESTION: will size ever get smaller after get performed??? + int numSamples = audioEngine.getSampleListSize(); + JSSample sample = null; + int numRateRamps = 0; + for (int index = 0; index < numSamples; index++) { + // loop thru samples looking for ones needing rate incremented + sample = (JSSample)audioEngine.getSample(index); + if (sample == null) + continue; + if (sample.getRampRateFlag()) { + if (debugFlag) + debugPrint(" rampRate true"); + boolean endOfRampReached = adjustRate(sample); + sample.setRampRateFlag(!endOfRampReached); + if (!endOfRampReached) + numRateRamps++; + } + // TODO: support changes in gain this way as well + } + if (numRateRamps > 0) { + rampRate = true; +runMonitor(RUN, 0, null); + } + else + rampRate = false; +/********* + try { + Thread.sleep(4); + } catch (InterruptedException e){} +*********/ +/******** + } // while +*********/ + // otherwise do nothing + } + + int getTotalChannels() { + return (totalChannels); + } + + /** + * Gradually change rate scale factor + * + * If the rate change is too great suddenly, it sounds like a + * jump, so we need to change gradually over time. + * Since an octive delta change up is 2.0 but down is 0.5, forced + * "max" rate of change is different for both. + * @return true if target rate value was reached + */ + boolean adjustRate(JSSample sample) { + // QUESTION: what should max delta rate changes be + // Using 1/32 of a half-step (1/12 of an octive)??? + double maxRateChangeDown = 0.00130213; + double maxRateChangeUp = 0.00260417; + + double lastActualRateRatio = sample.getCurrentRateRatio(); + double requestedRateRatio = sample.getTargetRateRatio(); + boolean endOfRamp = false; // flag denotes if target rate reached + if ( lastActualRateRatio > 0 ) { + double sampleRateRatio = requestedRateRatio; // in case diff = 0 + double diff = 0.0; + if (debugFlag) { + debugPrint("JSThread.adjustRate: between " + + lastActualRateRatio + " & " + requestedRateRatio); + } + diff = requestedRateRatio - lastActualRateRatio; + if (diff > 0.0) { // direction of movement is towards listener + // inch up towards the requested target rateRatio + if (diff >= maxRateChangeUp) { + sampleRateRatio = lastActualRateRatio + maxRateChangeUp; + if (debugFlag) { + debugPrint(" adjustRate: " + + "diff >= maxRateChangeUp so "); + debugPrint(" adjustRate: " + + " sampleRateRatio incremented up by max"); + } + endOfRamp = false; // target value not reached + } + /* + * otherwise delta change is within tolerance + * so use requested RateRatio as calculated w/out change + */ + else { + sampleRateRatio = requestedRateRatio; + if (debugFlag) { + debugPrint(" adjustRate: " + + " requestedRateRatio reached"); + } + endOfRamp = true; // reached + } + } + else if (diff < 0.0) { // movement is away from listener + // inch down towards the requested target rateRatio + if ((-diff) >= maxRateChangeDown) { + sampleRateRatio = lastActualRateRatio - maxRateChangeDown; + if (debugFlag) { + debugPrint(" adjustRate: " + + "-(diff) >= maxRateChangeUp so "); + debugPrint(" adjustRate: " + + " sampleRateRatio incremented down by max "); + } + endOfRamp = false; // target value not reached + } + /* + * otherwise negitive delta change is within tolerance so + * use sampleRateRatio as calculated w/out change + */ + else { + sampleRateRatio = requestedRateRatio; + if (debugFlag) { + debugPrint(" adjustRate: " + + " requestedRateRatio reached"); + } + endOfRamp = true; // reached + } + } + else // there is no difference between last set and requested rates + return true; + + this.setSampleRate(sample, (float)sampleRateRatio); + } + else { + // this is the first time thru with a rate change + if (debugFlag) { + debugPrint(" adjustRate: " + + "last requested rateRatio not set yet " + + "so sampleRateRatio left unchanged"); + } + this.setSampleRate(sample, (float)requestedRateRatio); + endOfRamp = false; // target value not reached + } + return endOfRamp; + } // adjustRate + + void setSampleRate(JSSample sample, JSAuralParameters attribs) { +// TODO: + } + + // gain set at start sample time as well + void setSampleGain(JSSample sample, JSAuralParameters attribs) { +/******* + // take fields as already set in sample and updates gain + // called after sample.render performed + if (debugFlag) + debugPrint("JSThread.setSampleGain()"); +leftGain, rightGain + if (debugFlag) { + debugPrint(" " + + "StereoGain during update " + leftGain + + ", " + rightGain); + debugPrint(" " + + "StereoDelay during update " + leftDelay + + ", " + rightDelay); + } + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + boolean muted = sample.getMuteFlag(); + + if (debugFlag) + debugPrint("setStereoGain for sample "+sample+" " + leftGain + + ", " + rightGain); + if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA || + dataType == JSAuralParameters.BUFFERED_AUDIO_DATA ) { + thread.setSampleGain(sample, leftGain); + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + thread.setSampleGain( + ((JSPositionalSample)sample).getSecondIndex(), rightGain); thread.setSampleGain( + ((JSPositionalSample)sample).getReverbIndex(), reverbGain); + } + } + // TODO: JavaSound does not support MIDI song panning yet + else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA || + + dataType == JSAuralParameters.BUFFERED_MIDI_DATA) { + // Stereo samples not used for Midi Song playback + thread.setSampleGain(sample, (leftGain+rightGain) ); + ****** + // -1.0 far left, 0.0 center, 1.0 far right + position = (leftGain - rightGain) / (leftGain + rightGain); + JSMidi.setSamplePan(sample, position); + + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + JSMidi.setSampleGain( + ((JSPositionalSample)sample).getSecondIndex(), rightGain); JSMidi.setSampleGain( + ((JSPositionalSample)sample).getReverbIndex(), reverbGain); + } + ****** + } + else { + if (debugFlag) + debugPrint( "JSThread: Internal Error setSampleGain dataType " + + dataType + " invalid"); + return; + } + ***** + // force specific gain + // go ahead and set gain immediately + this.setSampleGain(sample, scaleFactor); + rampGain = false; // disable ramping of gain +******/ + } + + void setSampleDelay(JSSample sample, JSAuralParameters attribs) { +/****** + // take fields as already set in sample and updates delay + // called after sample.render performed + // adjust by attrib rolloff + float delayTime = attribs.reverbDelay * attribs.rolloff; + + leftDelay = (int)(sample.leftDelay * attribs.rolloff); + rightDelay = (int)(sample.rightDelay * attribs.rolloff); +leftDelay, rightDelay + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + if (debugFlag) + debugPrint("setStereoDelay for sample "+sample+" " + leftDelay + + ", " + rightDelay); + if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) { + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + JSStream.setSampleDelay( + sample, leftDelay); + JSStream.setSampleDelay( + ((JSPositionalSample)sample).getSecondIndex(), rightDelay); + } + else + JSStream.setSampleDelay(sample, 0); + } + else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) { + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + JSClip.setSampleDelay( + sample, leftDelay); + JSClip.setSampleDelay( + ((JSPositionalSample)sample).getSecondIndex(), rightDelay); + } + else + JSClip.setSampleDelay(sample, 0); + } + else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA || + + dataType == JSAuralParameters.BUFFERED_MIDI_DATA) { + ******** + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + JSMidi.setSampleDelay( + sample, leftDelay); + JSMidi.setSampleDelay( + ((JSPositionalSample)sample).getSecondIndex(), rightDelay); + } + else + ******** + JSMidi.setSampleDelay(sample, 0); + } + else { + if (debugFlag) + debugPrint( "JSThread: Internal Error setSampleDelay dataType " + + dataType + " invalid"); + return; + } +******/ + } + + void setTargetGain(JSSample sample, float scaleFactor) { +/********** +// TODO: implement this + // current gain is used as starting scalefactor for ramp +// TEMPORARY: for now just set gain + this.setSampleGain(sample, scaleFactor); + rampGain = false; + rampGain = true; + targetGain = scaleFactor; + runMonitor(RUN, 0, null); +**********/ + } + + void setRate(JSSample sample, float rateScaleFactor) { + // force specific rate + // go ahead and set rate immediately + // take fields as already set in sample and updates rate + // called after sample.render performed + this.setSampleRate(sample, rateScaleFactor); + // disables rate from being gradually increased or decreased + // don't set global thread flat rampRate false just because + // one sample's rate is set to a specific value. + sample.setRampRateFlag(false); + } + + void setTargetRate(JSSample sample, float rateScaleFactor) { + // make gradual change in rate factors up or down to target rate + sample.setRampRateFlag(true); + sample.setTargetRateRatio(rateScaleFactor); + rampRate = true; + runMonitor(RUN, 0, null); + } + +// TODO: should have methods for delay and pan as well + + void setSampleGain(JSSample sample, float gain) { +/*********** +// QUESTION: What needs to be synchronized??? + if (debugFlag) + debugPrint("JSThread.setSampleGain for sample "+sample+" " + gain ); + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + boolean muted = sample.getMuteFlag(); +// TODO: + if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) +{ + com.sun.j3d.audio.J3DHaeStream.setSampleGain(index, gain); + } + else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) { + com.sun.j3d.audio.J3DHaeClip.setSampleGain(index, gain); + } + else { + // dataType==JSAuralParameters.STREAMING_MIDI_DATA + // dataType==JSAuralParameters.BUFFERED_MIDI_DATA + com.sun.j3d.audio.J3DHaeMidi.setSampleGain(index, gain); + } +***************/ + } + + void setSampleRate(JSSample sample, float scaleFactor) { +/********* +// QUESTION: What needs to be synchronized??? + // TODO: use sample.rateRatio?? + if (debugFlag) + debugPrint("JSThread.setSampleRate sample " + + sample + ", scale factor = " + scaleFactor); + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + +// TODO: + if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) { + com.sun.j3d.audio.J3DHaeStream.scaleSampleRate(index, scaleFactor); + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + com.sun.j3d.audio.J3DHaeStream.scaleSampleRate( + ((JSPositionalSample)sample).getSecondIndex(), + scaleFactor); + com.sun.j3d.audio.J3DHaeStream.scaleSampleRate( + ((JSPositionalSample)sample).getReverbIndex(), + scaleFactor); + } + } + else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) { + com.sun.j3d.audio.J3DHaeClip.scaleSampleRate(index, scaleFactor); + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + com.sun.j3d.audio.J3DHaeClip.scaleSampleRate( + ((JSPositionalSample)sample).getSecondIndex(), + scaleFactor); + com.sun.j3d.audio.J3DHaeClip.scaleSampleRate( + ((JSPositionalSample)sample).getReverbIndex(), + scaleFactor); + } + } + else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA || + dataType == JSAuralParameters.BUFFERED_MIDI_DATA) { + com.sun.j3d.audio.J3DHaeMidi.scaleSampleRate(index, scaleFactor); + // TODO: MIDI only supported for Background sounds + } +***********/ + sample.setCurrentRateRatio(scaleFactor); + } + + boolean startSample(JSSample sample) { +/********** +// QUESTION: should this have a return values - error - or not?? + + int returnValue = 0; + AuralParameters attribs = audioEngine.getAuralParameters(); + int soundType = sample.getSoundType(); + boolean muted = sample.getMuteFlag(); + int dataType = sample.getDataType(); + int loopCount = sample.getLoopCount(); + float leftGain = sample.leftGain; + float rightGain = sample.rightGain; + int leftDelay = (int)(sample.leftDelay * attribs.rolloff); + int rightDelay = (int)(sample.rightDelay * attribs.rolloff); + if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) { + if (soundType == AudioDevice3D.BACKGROUND_SOUND) { + returnValue = JSStream.startSample(sample, + loopCount, leftGain); + if (debugFlag) + debugPrint("JSThread " + + "start stream backgroundSound with gain " + leftGain); + } + else { // soundType is POINT_SOUND or CONE_SOUND + // start up main left and right channels for spatial rendered sound + returnValue = JSStream.startSamples(sample, + ((JSPositionalSample)sample).getSecondIndex(), + loopCount, leftGain, rightGain, leftDelay, rightDelay); + // + // start up reverb channel w/out delay even if reverb not on now // + float reverbGain = 0.0f; + if (!muted && auralParams.reverbFlag) { + reverbGain = sample.getGain() * + attribs.reflectionCoefficient; + } + int reverbRtrnVal = JSStream.startSample( + ((JSPositionalSample)sample).getReverbIndex(), loopCount, reverbGain); + if (debugFlag) + debugPrint("JSThread " + + "start stream positionalSound with gain "+ leftGain + + ", " + rightGain); + } + } + + else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) { + if (soundType == AudioDevice3D.BACKGROUND_SOUND) { + returnValue = JSClip.startSample(sample, + loopCount, leftGain ); + if (debugFlag) + debugPrint("JSThread " + + "start buffer backgroundSound with gain " + leftGain); + } + else { // soundType is POINT_SOUND or CONE_SOUND + // start up main left and right channels for spatial rendered sound + returnValue = JSClip.startSamples(sample, + ((JSPositionalSample)sample).getSecondIndex(), + loopCount, leftGain, rightGain, leftDelay, rightDelay); + // + // start up reverb channel w/out delay even if reverb not on now // + float reverbGain = 0.0f; + if (!muted && auralParams.reverbFlag) { + reverbGain = sample.getGain() * + attribs.reflectionCoefficient; + } + int reverbRtrnVal = JSClip.startSample( + ((JSPositionalSample)sample).getReverbIndex(), + loopCount, reverbGain); + + if (debugFlag) + debugPrint("JSThread " + + "start stream positionalSound with gain " + leftGain + + ", " + rightGain); + } + } + else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA || + dataType == JSAuralParameters.BUFFERED_MIDI_DATA) { + if (soundType == AudioDevice3D.BACKGROUND_SOUND) { + returnValue = JSMidi.startSample(sample, + loopCount, leftGain); + if (debugFlag) + debugPrint("JSThread " + + "start Midi backgroundSound with gain " + leftGain); + } + else { // soundType is POINT_SOUND or CONE_SOUND + // start up main left and right channels for spatial rendered sound + returnValue = JSMidi.startSamples(sample, + ((JSPositionalSample)sample).getSecondIndex(), + loopCount, leftGain, rightGain, leftDelay, rightDelay); + ******* + // TODO: positional MIDI sounds not supported. + // The above startSamples really just start on sample + // Don't bother with reverb channel for now. + + // + // start up reverb channel w/out delay even if reverb not on now // + float reverbGain = 0.0f; + if (!muted && auralParams.reverbFlag) { + reverbGain = sample.getGain() * + attribs.reflectionCoefficient; + } + int reverbRtrnVal = JSMidi.startSample( + ((JSPositionalSample)sample).getReverbIndex(), loopCount, reverbGain); + ******* + if (debugFlag) + debugPrint("JSThread " + + "start Midi positionalSound with gain "+ leftGain + + ", " + rightGain); + } + } + + else { + if (debugFlag) + debugPrint( + "JSThread: Internal Error startSample dataType " + + dataType + " invalid"); + return false; + } + // TODO: have to look at return values and conditionally return 'success' +**********/ + return true; + } + + boolean stopSample(JSSample sample) { +/*********** +// QUESTION: should this have a return values - error - or not?? + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + + int returnValue = 0; + if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) { + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSStream.stopSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSStream.stopSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + returnValue = JSStream.stopSample(sample); + } + else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) { + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSClip.stopSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSClip.stopSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + returnValue = JSClip.stopSample(sample); + } + else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA || + dataType == JSAuralParameters.BUFFERED_MIDI_DATA) { + + ***** + // TODO: positional sounds NOT supported yet + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSMidi.stopSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSMidi.stopSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + ***** + returnValue = JSMidi.stopSample(sample); + } + else { + if (debugFlag) + debugPrint( "JSThread: Internal Error stopSample dataType " + + dataType + " invalid"); + return -1; + } + +************/ + return true; + } + + + void pauseSample(JSSample sample) { +/********** + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + int returnValue = 0; + if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) { + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSStream.pauseSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSStream.pauseSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + returnValue = JSStream.pauseSample(sample); + } + else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) { + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSClip.pauseSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSClip.pauseSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + returnValue = JSClip.pauseSample(sample); + } + else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA || + + dataType == JSAuralParameters.BUFFERED_MIDI_DATA) { + ******* + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSMidi.pauseSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSMidi.pauseSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + ***** + returnValue = JSMidi.pauseSample(sample); + } + else { + if (debugFlag) + debugPrint( + "JSThread: Internal Error pauseSample dataType " + + dataType + " invalid"); + } + if (returnValue < 0) { + if (debugFlag) + debugPrint( "JSThread: Internal Error pauseSample " + + "for sample " + sample + " failed"); + } +// QUESTION: return value or not??? + return; +*************/ + } + + void unpauseSample(JSSample sample) { +/************** + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + int returnValue = 0; + if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) { + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSStream.unpauseSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSStream.unpauseSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + returnValue = JSStream.unpauseSample(sample); + } + else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) { + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSClip.unpauseSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSClip.unpauseSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + returnValue = JSClip.unpauseSample(sample); + } + else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA || + + dataType == JSAuralParameters.BUFFERED_MIDI_DATA) { + ********* + // TODO: positional Midi sounds + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + returnValue = JSMidi.unpauseSamples(sample, + ((JSPositionalSample)sample).getSecondIndex()); + returnValue = JSMidi.unpauseSample( + ((JSPositionalSample)sample).getReverbIndex()); + } + else + ********* + returnValue = JSMidi.unpauseSample(sample); + } + else { + if (debugFlag) + debugPrint( + "JSThread: Internal Error unpauseSample dataType " + dataType + " invalid"); + } + if (returnValue < 0) { + if (debugFlag) + debugPrint( "JSThread: Internal Error unpauseSample " + + "for sample " + sample + " failed"); + + } +// QUESTION: return value or not??? + return; +*************/ + } + +// TODO: + void muteSample(JSSample sample) { + // is this already muted? if so don't do anytning + + // This determines if mute is done as a zero gain or + // as a stop, advance restart... + } + +// TODO: + void unmuteSample(JSSample sample) { + if (debugFlag) + debugPrint( "JSThread.unmuteSample not implemented"); + } + + int startStreams() { +// QUESTION: return value or not??? + return 0; + } + int startStream() { +// QUESTION: return value or not??? + return 0; + } + int startClips() { +// QUESTION: return value or not??? + return 0; + } + int startClip() { +// QUESTION: return value or not??? + return 0; + } + + /** + * This initializes this thread. Once this method returns, the thread is + * ready to do work. + */ + public void initialize() { + super.initialize(); + // this.setPriority(Thread.MAX_PRIORITY); + // TODO: init values of fields??? + if (debugFlag) + debugPrint("JSThread.initialize()"); + // TODO: doesn't do anything yet + } + + /** + * Code to close the device + * @return flag: true is closed sucessfully, false if error + */ + boolean close() { + // TODO: for now do nothing + return false; + } + + public void shutdown() { + } + + + + + // default resource clean up method + public void cleanup() { + super.cleanup(); + if (debugFlag) + debugPrint("JSThread.cleanup()"); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JavaSoundMixer.java b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JavaSoundMixer.java new file mode 100755 index 0000000..f31a0eb --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/JavaSoundMixer.java @@ -0,0 +1,959 @@ +/* + * $RCSfile: JavaSoundMixer.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:04 $ + * $State: Exp $ + */ + +/* + * Audio device driver using Java Sound Mixer Engine. + * + * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs + * to be rewritten. + */ + +package com.sun.j3d.audioengines.javasound; + +import java.net.URL; +import java.io.InputStream; +import javax.vecmath.*; +import javax.media.j3d.*; +import com.sun.j3d.audioengines.*; +import java.util.ArrayList; +import java.lang.Thread; + +/** + * The JavaSoundMixer Class defines an audio output device that accesses + * JavaSound functionality stream data. + */ +public class JavaSoundMixer extends AudioEngine3DL2 { + + // Debug print flags and methods + static final boolean debugFlag = false; + static final boolean internalErrors = false; + + void debugPrint(String message) { + if (debugFlag) + System.out.println(message); + } + + void debugPrintln(String message) { + if (debugFlag) + System.out.println(message); + } + + // Determines method to call for added or setting sound into ArrayList + static final int ADD_TO_LIST = 1; + static final int SET_INTO_LIST = 2; + + // current Aural Parameters = Aural Attributes from core + JavaSound + // specific fields, including reverberation parameters. + JSAuralParameters auralParams = null; + + // thread for dynamically changing audio parameters such as volume + // and sample rate. + JSThread thread = null; + + /* + * new fields in extended class + */ + protected float deviceGain = 1.0f; + + protected static final int NOT_PAUSED = 0; + protected static final int PAUSE_PENDING = 1; + protected static final int PAUSED = 2; + protected static final int RESUME_PENDING = 3; + protected int pause = NOT_PAUSED; + + /* + * Construct a new JavaSoundMixer with the specified P.E. + * @param physicalEnvironment the physical environment object where we + * want access to this device. + */ + public JavaSoundMixer(PhysicalEnvironment physicalEnvironment ) { + super(physicalEnvironment); + thread = new JSThread(Thread.currentThread().getThreadGroup(), this); + } + + /** + * Query total number of channels available for sound rendering + * for this audio device. + * Overridden method from AudioEngine. + * @return number of maximum voices play simultaneously on JavaSound Mixer. + */ + public int getTotalChannels() { + if (thread != null) + return thread.getTotalChannels(); + else + return 32; + } + + /** + * Code to initialize the device + * New interface to mixer/engine specific methods + * @return flag: true is initialized sucessfully, false if error + */ + public boolean initialize() { + if (thread == null) { + return false; + } + // init JavaSound dynamic thread + thread.initialize(); + auralParams = new JSAuralParameters(); + if (debugFlag) + debugPrintln("JavaSoundMixer: JSStream.initialize returned true"); + return true; + } + + /** + * Code to close the device. + * New interface to mixer/engine specific methods + * @return flag: true is closed sucessfully, false if error + */ + public boolean close() { + if (thread == null) + return false; + if (thread.close()) { + if (debugFlag) + debugPrintln("JavaSoundMixer: JSStream.close returned true"); + return true; + } + else { + if (debugFlag) + debugPrintln("JavaSoundMixer: JSStream.close returned false"); + return false; + } + } + + + /** + * Code to load sound data into a channel of device mixer. + * Load sound as one or mores sample into the Java Sound Mixer: + * a) as either a STREAM or CLIP based on whether cached is enabled + * b) positional and directional sounds use three samples per + * sound + * Overriden method from AudioEngine3D. + * + * Sound type determines if this is a Background, Point or Cone + * sound source and thus the JSXxxxSample object type + * Call JSXxxxxSample.loadSample() + * If no error + * Get the next free index in the samples list. + * Store a reference to JSXxxxSample object in samples list. + * @return index to the sample in samples list. + */ + public int prepareSound(int soundType, MediaContainer soundData) { + int index = JSSample.NULL_SAMPLE; + int methodType = ADD_TO_LIST; + if (soundData == null) + return JSSample.NULL_SAMPLE; + synchronized(samples) { + // for now force to just add to end of samples list + int samplesSize = samples.size(); + index = samplesSize; + samples.ensureCapacity(index+1); + boolean error = false; + + if (soundType == AudioDevice3D.CONE_SOUND) { + if (debugFlag) + debugPrintln("JavaSoundMixer.prepareSound type=CONE"); + JSDirectionalSample dirSample = new JSDirectionalSample(); + error = dirSample.load(soundData); + if (error) + return JSSample.NULL_SAMPLE; + if (methodType == SET_INTO_LIST) + samples.set(index, dirSample); + else + samples.add(index, dirSample); + /* + * Since no error occurred while loading, save all the + * characterstics for the sound in the sample. + */ + dirSample.setDirtyFlags(0xFFFF); + dirSample.setSoundType(soundType); + dirSample.setSoundData(soundData); + + } + else if (soundType == AudioDevice3D.POINT_SOUND) { + if (debugFlag) + debugPrintln("JavaSoundMixer.prepareSound type=POINT"); + JSPositionalSample posSample = new JSPositionalSample(); + error = posSample.load(soundData); + if (error) + return JSSample.NULL_SAMPLE; + if (methodType == SET_INTO_LIST) + samples.set(index, posSample); + else + samples.add(index, posSample); + posSample.setDirtyFlags(0xFFFF); + posSample.setSoundType(soundType); + posSample.setSoundData(soundData); + } + else { // soundType == AudioDevice3D.BACKGROUND_SOUND + if (debugFlag) + debugPrintln("JavaSoundMixer.prepareSound type=BACKGROUND"); + JSSample sample = null; + sample = new JSSample(); + error = sample.load(soundData); + if (error) + return JSSample.NULL_SAMPLE; + if (methodType == SET_INTO_LIST) + samples.set(index, sample); + else + samples.add(index, sample); + sample.setDirtyFlags(0xFFFF); + sample.setSoundType(soundType); + sample.setSoundData(soundData); + } + } + + if (debugFlag) { + debugPrint(" prepareSound type = "+soundType); + debugPrintln("JavaSoundMixer.prepareSound returned "+index); + } + return index; + } + + /** + * Clears the fields associated with sample data for this sound. + * Overriden method from AudioEngine3D. + */ + public void clearSound(int index) { + // TODO: call JSXXXX clear method + JSSample sample = null; + if ( (sample = (JSSample)getSample(index)) == null) + return; + sample.clear(); + synchronized(samples) { + samples.set(index, null); + } + } + + /** + * Save a reference to the local to virtual world coordinate space + * Overriden method from AudioEngine3D. + */ + public void setVworldXfrm(int index, Transform3D trans) { + if (debugFlag) + debugPrintln("JavaSoundMixer: setVworldXfrm for index " + index); + super.setVworldXfrm(index, trans); + if (debugFlag) { + double[] matrix = new double[16]; + trans.get(matrix); + debugPrintln("JavaSoundMixer column-major transform "); + debugPrintln("JavaSoundMixer " + matrix[0]+", "+matrix[1]+ + ", "+matrix[2]+", "+matrix[3]); + debugPrintln("JavaSoundMixer " + matrix[4]+", "+matrix[5]+ + ", "+matrix[6]+", "+matrix[7]); + debugPrintln("JavaSoundMixer " + matrix[8]+", "+matrix[9]+ + ", "+matrix[10]+", "+matrix[11]); + debugPrintln("JavaSoundMixer " + matrix[12]+", "+matrix[13]+ + ", "+matrix[14]+", "+matrix[15]); + } + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return; + int soundType = sample.getSoundType(); + + if (soundType == AudioDevice3D.CONE_SOUND) { + JSDirectionalSample dirSample = null; + if ((dirSample = (JSDirectionalSample)getSample(index)) == null) + return; + dirSample.setXformedDirection(); + dirSample.setXformedPosition(); + // flag that VirtualWorld transform set + dirSample.setVWrldXfrmFlag(true); + } + else if (soundType == AudioDevice3D.POINT_SOUND) { + JSPositionalSample posSample = null; + if ((posSample = (JSPositionalSample)getSample(index)) == null) + return; + posSample.setXformedPosition(); + // flag that VirtualWorld transform set + posSample.setVWrldXfrmFlag(true); + } + return; + } + /* + * Overriden method from AudioEngine3D. + */ + public void setPosition(int index, Point3d position) { + if (debugFlag) + debugPrintln("JavaSoundMixer: setPosition for index " + index); + super.setPosition(index, position); + JSPositionalSample posSample = null; + if ((posSample = (JSPositionalSample)getSample(index)) == null) + return; + int soundType = posSample.getSoundType(); + if ( (soundType == AudioDevice3D.POINT_SOUND) || + (soundType == AudioDevice3D.CONE_SOUND) ) { + posSample.setXformedPosition(); + } + return; + } + + /* + * Overriden method from AudioEngine3D. + */ + public void setDirection(int index, Vector3d direction) { + if (debugFlag) + debugPrintln("JavaSoundMixer: setDirection for index " + index); + super.setDirection(index, direction); + JSDirectionalSample dirSample = null; + if ((dirSample = (JSDirectionalSample)getSample(index)) == null) + return; + int soundType = dirSample.getSoundType(); + if (soundType == AudioDevice3D.CONE_SOUND) { + dirSample.setXformedDirection(); + } + return; + } + + /* + * Overriden method from AudioEngine3D. + */ + public void setReflectionCoefficient(float coefficient) { + super.setReflectionCoefficient(coefficient); + auralParams.reverbDirty |= JSAuralParameters.REFLECTION_COEFF_CHANGED; + return; + } + + /* + * Overriden method from AudioEngine3D. + */ + public void setReverbDelay(float reverbDelay) { + super.setReverbDelay(reverbDelay); + auralParams.reverbDirty |= JSAuralParameters.REVERB_DELAY_CHANGED; + return; + } + + /* + * Overriden method from AudioEngine3D. + */ + public void setReverbOrder(int reverbOrder) { + super.setReverbOrder(reverbOrder); + auralParams.reverbDirty |= JSAuralParameters.REVERB_ORDER_CHANGED; + return; + } + + /* + * QUESTION: if this is used, for now, exclusively, to start a Background + * or any single sampled Sounds, why are there if-else cases to handle + * Point and Cone sounds?? + * + * For now background sounds are not reverberated + * + * Overriden method from AudioEngine3D. + */ + public int startSample(int index) { + // TODO: Rewrite this function + + if (debugFlag) + debugPrintln("JavaSoundMixer: STARTSample for index " + index); + + JSSample sample = null; + if ( ( (sample = (JSSample)getSample(index)) == null) || + thread == null ) + return JSSample.NULL_SAMPLE; + + int soundType = sample.getSoundType(); + boolean muted = sample.getMuteFlag(); + if (muted) { + if (debugFlag) + debugPrintln(" MUTEd start"); + thread.muteSample(sample); + if (soundType != AudioDevice3D.BACKGROUND_SOUND) + setFilter(index, false, Sound.NO_FILTER); + } + else { + sample.render(sample.getDirtyFlags(), getView(), auralParams); + this.scaleSampleRate(index, sample.rateRatio); + // filtering + if (soundType != AudioDevice3D.BACKGROUND_SOUND) + setFilter(index, sample.getFilterFlag(), sample.getFilterFreq()); + } + + boolean startSuccessful; + startSuccessful = thread.startSample(sample); + + sample.channel.startSample(sample.getLoopCount(), sample.getGain(), 0); + + if (!startSuccessful) { + if (internalErrors) + debugPrintln( + "JavaSoundMixer: Internal Error startSample for index " + + index + " failed"); + return JSSample.NULL_SAMPLE; + } + else { + if (debugFlag) + debugPrintln(" startSample worked, " + + "returning " + startSuccessful); + // NOTE: Set AuralParameters AFTER sound started + // Setting AuralParameters before you start sound doesn't work + if (!muted) { + if (auralParams.reverbDirty > 0) { + if (debugFlag) { + debugPrintln("startSample: reverb settings are:"); + debugPrintln(" coeff = "+ + auralParams.reflectionCoefficient + + ", delay = " + auralParams.reverbDelay + + ", order = " + auralParams.reverbOrder); + } + float delayTime = auralParams.reverbDelay * auralParams.rolloff; + calcReverb(sample); + } + // NOTE: it apprears that reverb has to be reset in + // JavaSound engine when sound re-started?? + // force reset of reverb parameters when sound is started + setReverb(sample); + } + return index; + } + } + + /* + * Overriden method from AudioEngine3D. + */ + public int stopSample(int index) { + // TODO: Rewrite this function + + if (debugFlag) + debugPrintln("JavaSoundMixer: STOPSample for index " + index); + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return -1; + + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + + boolean stopSuccessful = true; + stopSuccessful = thread.stopSample(sample); + + sample.channel.stopSample(); + + if (!stopSuccessful) { + if (internalErrors) + debugPrintln( "JavaSoundMixer: Internal Error stopSample(s) for index " + + index + " failed"); + return -1; + } + else { + // set fields in sample to reset for future start + sample.reset(); + if (debugFlag) + debugPrintln("JavaSoundMixer: stopSample for index " + + index + " worked, returning " + stopSuccessful); + return 0; + } + } + + /* + * Overriden method from AudioEngine3D. + */ + public void pauseSample(int index) { + if (debugFlag) + debugPrintln("JavaSoundMixer: PAUSESample for index " + index); + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return; + // check thread != null + thread.pauseSample(sample); + } + + /* + * Overriden method from AudioEngine3D. + */ + public void unpauseSample(int index) { + if (debugFlag) + debugPrintln("JavaSoundMixer: UNPAUSESample for index " + index); + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return; + thread.unpauseSample(sample); + } + + /* + * Force thread to update sample. + * Overriden method from AudioEngine3D. + */ + + public void updateSample(int index) { + if (debugFlag) + debugPrintln("JavaSoundMixer: UPDATESample for index " + index); + JSSample sample = null; + if ( ( (sample = (JSSample)getSample(index)) == null) || + thread == null ) + return; + + int soundType = sample.getSoundType(); + boolean muted = sample.getMuteFlag(); + + if (muted) { + if (soundType != AudioDevice3D.BACKGROUND_SOUND) + setFilter(index, false, Sound.NO_FILTER); + thread.muteSample(sample); + if (debugFlag) + debugPrintln(" Mute during update"); + } + else { + // If reverb parameters changed resend to audio device + if (auralParams.reverbDirty > 0) { + if (debugFlag) { + debugPrintln("updateSample: reverb settings are:"); + debugPrintln(" coeff = " + auralParams.reflectionCoefficient+ + ", delay = " + auralParams.reverbDelay + + ", order = " + auralParams.reverbOrder); + } + float delayTime = auralParams.reverbDelay * auralParams.rolloff; + calcReverb(sample); + } + // TODO: Only re-set reverb if values different + // For now force reset to ensure that reverb is currently correct + setReverb(sample); // ensure reverb is current/correct + + // TODO: For now sum left & rightGains for reverb gain + float reverbGain = 0.0f; + if (!muted && auralParams.reverbFlag) { + reverbGain = sample.getGain() * auralParams.reflectionCoefficient; + } + + sample.render(sample.getDirtyFlags(), getView(), auralParams); + + // filtering + if (soundType != AudioDevice3D.BACKGROUND_SOUND) + setFilter(index, sample.getFilterFlag(), sample.getFilterFreq()); + thread.setSampleGain(sample, auralParams); + thread.setSampleRate(sample, auralParams); + thread.setSampleDelay(sample, auralParams); + } + return; + } + + /* + * Overriden method from AudioEngine3D. + */ + public void muteSample(int index) { + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return; + + if (debugFlag) + debugPrintln("JavaSoundMixer: muteSample"); + sample.setMuteFlag(true); + thread.muteSample(sample); + return; + } + + /* + * Overriden method from AudioEngine3D. + */ + public void unmuteSample(int index) { + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return; + + if (debugFlag) + debugPrintln("JavaSoundMixer: unmuteSample"); + sample.setMuteFlag(false); + + // since while mute the reverb type and state was not updated... + // Reverb has to be recalculated when sound is unmuted . + auralParams.reverbDirty = 0xFFFF; // force an update of reverb params + sample.setDirtyFlags(0xFFFF); // heavy weight forcing of gain/delay update + + // TODO: force an update of ALL parameters that could have changed + // while muting disabled... + + thread.unmuteSample(sample); + return; + } + + /* + * Overriden method from AudioEngine3D. + */ + public long getSampleDuration(int index) { + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return Sample.DURATION_UNKNOWN; + long duration; + + if (sample != null) + duration = sample.getDuration(); + else + duration = Sample.DURATION_UNKNOWN; + if (debugFlag) + debugPrintln(" return duration " + duration); + return duration; + } + + /* + * Overriden method from AudioEngine3D. + */ + public int getNumberOfChannelsUsed(int index) { + /* + * Calls same method with different signature containing the + * sample's mute flag passed as the 2nd parameter. + */ + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return 0; + else + return getNumberOfChannelsUsed(index, sample.getMuteFlag()); + } + + /** + * Overriden method from AudioEngine3D. + */ + public int getNumberOfChannelsUsed(int index, boolean muted) { + /* + * The JavaSoundMixer implementation uses THREE channels to render + * the stereo image of each Point and Cone Sounds: + * Two for rendering the right and left portions of the rendered + * spatialized sound image - panned hard right or left respectively. + * This implementation uses one channel to render Background sounds + * whether the sample is mono or stereo. + * + * TODO: When muted is implemented, that flag should be check + * so that zero is returned. + */ + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return 0; + + int soundType = sample.getSoundType(); + int dataType = sample.getDataType(); + + // TODO: for now positional Midi sound used only 1 sample + if (dataType == JSSample.STREAMING_MIDI_DATA || + dataType == JSSample.BUFFERED_MIDI_DATA) + return 1; + + if (soundType == BACKGROUND_SOUND) + return 1; + else // for Point and Cone sounds + return 3; + } + + /* + * Overriden method from AudioEngine3D. + */ + public long getStartTime(int index) { + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return 0L; + if (sample.channel == null) + return 0L; + return (long)sample.channel.startTime; + } + + /* + * Methods called during rendering + */ + void scaleSampleRate(int index, float scaleFactor) { + if (debugFlag) + debugPrintln("JavaSoundMixer: scaleSampleRate index " + + index + ", scale factor = " + scaleFactor); + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null || + thread == null) + return; + int dataType = sample.getDataType(); + if (debugFlag) + debugPrintln(" scaleSampleRate.dataType = " + dataType + + "using sample " + sample + " from samples[" + + index +"]"); + int soundType = sample.getSoundType(); + + if (dataType == JSSample.STREAMING_AUDIO_DATA || + dataType == JSSample.BUFFERED_AUDIO_DATA) { + thread.setSampleRate(sample, scaleFactor); + /********** + // TODO: + if (soundType != AudioDevice3D.BACKGROUND_SOUND) { + thread.setSampleRate( ((JSPositionalSample)sample).getSecondIndex(), + scaleFactor); + thread.setSampleRate(((JSPositionalSample)sample).getReverbIndex(), + scaleFactor); + } + **********/ + } + else if (dataType == JSSample.STREAMING_MIDI_DATA || + dataType == JSSample.BUFFERED_MIDI_DATA) { + thread.setSampleRate(sample, scaleFactor); + /********** + if (soundType != AudioDevice3D.BACKGROUND_SOUND) { + thread.setSampleRate(((JSPositionalSample)sample).getSecondIndex(), + scaleFactor); + thread.setSampleRate(((JSPositionalSample)sample).getReverbIndex(), + scaleFactor); + } + **********/ + } + else { + if (internalErrors) + debugPrintln( + "JavaSoundMixer: Internal Error scaleSampleRate dataType " + + dataType + " invalid"); + } + } + + /* + * Methods called during rendering + */ + void calcReverb(JSSample sample) { + /* + * Java Sound reverb parameters are a subset of Java 3D parameters + */ + int dataType = sample.getDataType(); + int soundType = sample.getSoundType(); + float decay = auralParams.decayTime; + float delay = auralParams.reverbDelay * auralParams.rolloff; + float reflection = auralParams.reflectionCoefficient; + int order = auralParams.reverbOrder; + /* + * Remember Coeff change is choosen over Order change if BOTH made + * otherwise the last one changed take precidence. + */ + if (auralParams.reflectionCoefficient == 0.0f || + auralParams.reverbCoefficient == 0.0f) + auralParams.reverbFlag = false; + else { + auralParams.reverbFlag = true; + if (order > 0) { + // clamp reverb decay time to order*delay + float clampedTime = order * delay; + if ( clampedTime < decay) + decay = clampedTime; + } + if (delay < 100.0f) { + // "small" reverberant space + if (decay <= 1500.0f) + auralParams.reverbType = 2; + else + auralParams.reverbType = 4; + } + else if (delay < 500.0f) { + // "medium" reverberant space + if (decay <= 1500.0f) + auralParams.reverbType = 3; + else + auralParams.reverbType = 6; + } + else { // delay >= 500.0f + // "large" reverberant space + if (decay <= 1500.0f) + auralParams.reverbType = 6; + else + auralParams.reverbType = 5; + } + } + + if (debugFlag) + debugPrintln("JavaSoundMixer: setReverb for " + + sample + ", type = " + auralParams.reverbType + ", flag = " + auralParams.reverbFlag); + + auralParams.reverbDirty = 0; // clear the attribute reverb dirty flags + } + + /* + * Interal method for setting reverb parameters called during rendering. + * This not called by SoundScheduler. + */ + void setReverb(JSSample sample) { + /* + * Only third sample of multisample sounds has reverb parameters set. + * For now, only positional and directional sounds are reverberated. + */ + int soundType = sample.getSoundType(); + int dataType = sample.getDataType(); + + // QUESTION: Should reverb be applied to background sounds? + if ( (soundType == AudioDevice3D.CONE_SOUND) || + (soundType == AudioDevice3D.POINT_SOUND) ) { + if (debugFlag) + debugPrintln("setReverb called with type, on = " + + auralParams.reverbType + ", " + auralParams.reverbFlag); + if (sample == null) + return; + JSPositionalSample posSample = (JSPositionalSample)sample; + if (posSample.channel == null) + return; + + /********** + // NOTE: no support for reverb channel yet... + int reverbIndex = posSample.getReverbIndex(); + **********/ + if (dataType == JSSample.STREAMING_AUDIO_DATA) { + JSStream stream = (JSStream)posSample.channel; + stream.setSampleReverb(auralParams.reverbType, auralParams.reverbFlag); + } + else if (dataType == JSSample.BUFFERED_AUDIO_DATA) { + JSClip clip = (JSClip)posSample.channel; + clip.setSampleReverb(auralParams.reverbType, auralParams.reverbFlag); + } + /********** + // TODO: + else if (dataType == JSSample.STREAMING_MIDI_DATA || + dataType == JSSample.BUFFERED_MIDI_DATA) { + JSMidi.setSampleReverb(reverbIndex, + auralParams.reverbType, auralParams.reverbFlag); + } + **********/ + else { + if (internalErrors) + debugPrintln( "JavaSoundMixer: Internal Error setReverb " + + "dataType " + dataType + " invalid"); + } + } + } + + // TEMPORARY: Override of method due to bug in Java Sound + public void setLoop(int index, int count) { + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return; + int dataType = sample.getDataType(); + + // WORKAROUND: + // Bug in Java Sound engine hangs when INFINITE_LOOP count + // for Audio Wave data. Leave count unchanged for Midi data. + if (dataType==JSSample.STREAMING_AUDIO_DATA || + dataType==JSSample.BUFFERED_AUDIO_DATA) { + if (count == Sound.INFINITE_LOOPS) { + // LoopCount of 'loop Infinitely' forced to largest positive int + count = 0x7FFFFFF; + } + } + super.setLoop(index, count); + return; + } + + // Perform device specific filtering + // Assumes that this is called for positional and directional sounds + // not background sounds, so there are at lease two samples assigned + // per sound. + // TODO: remove assumption from method + void setFilter(int index, boolean filterFlag, float filterFreq) { + JSPositionalSample posSample = null; + if ((posSample = (JSPositionalSample)getSample(index)) == null) + return; + if (posSample.channel == null) + return; + int dataType = posSample.getDataType(); + + // Filtering can NOT be performed on MIDI Songs + if (dataType == JSSample.STREAMING_MIDI_DATA || + dataType == JSSample.BUFFERED_MIDI_DATA) { + return; + } + + /**** + // TODO: multiple clips per channel + int secondIndex = posSample.getSecondIndex(); + *****/ + if (dataType == JSSample.BUFFERED_AUDIO_DATA) { + JSClip clip = (JSClip)posSample.channel; + clip.setSampleFiltering(filterFlag,filterFreq); + /***** + JSClip.setSampleFiltering(econdIndex, filterFlag, filterFreq); + ******/ + } + else { // dataType == JSSample.STREAMING_AUDIO_DATA + JSStream stream = (JSStream)posSample.channel; + stream.setSampleFiltering(filterFlag,filterFreq); + /***** + JSStream.setSampleFiltering(secondIndex, ilterFlag, filterFreq); + ******/ + } + // QUESTION: should reverb channel be filtered??? + + if (debugFlag) { + debugPrintln("JavaSoundMixer:setFilter " + + "of non-backgroundSound by (" + + filterFlag + ", " + filterFreq + ")"); + } + } + // + // Set overall gain for device + // @since Java 3D 1.3 + // + public void setGain(float scaleFactor) { + float oldDeviceGain = deviceGain; + float gainFactor = scaleFactor/oldDeviceGain; + // TODO: for each sample, change gain by gainFactor + deviceGain = scaleFactor; // set given scalefactor as new device gain + return; + } + + /* + * Set sample specific sample rate scale factor gain + * @since Java 3D 1.3 + */ + public void setRateScaleFactor(int index, float rateScaleFactor) { + JSSample sample = null; + if ((sample = (JSSample)getSample(index)) == null) + return; + sample.setRateScaleFactor(rateScaleFactor); + this.scaleSampleRate(index, rateScaleFactor); + } + + /** + * Pauses audio device engine without closing the device and associated + * threads. + * Causes all cached sounds to be paused and all streaming sounds to be + * stopped. + */ + public void pause() { + pause = PAUSE_PENDING; + // TODO: pause all sounds + return; + } + /** + * Resumes audio device engine (if previously paused) without reinitializing * the device. + * Causes all paused cached sounds to be resumed and all streaming sounds + * restarted. + */ + public void resume() { + pause = RESUME_PENDING; + // TODO: unpause all sounds + return; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/package.html new file mode 100644 index 0000000..5897bc9 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/javasound/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.audioengines.javasound + + +

Provides a JavaSound-based implementation of a Java 3D audio device.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/package.html new file mode 100644 index 0000000..59b80b4 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/audioengines/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.audioengines + + +

Provides abstract classes for creating Java 3D audio devices.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/JCanvas3D.java b/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/JCanvas3D.java new file mode 100644 index 0000000..74c245b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/JCanvas3D.java @@ -0,0 +1,980 @@ +/* + * $RCSfile: JCanvas3D.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.10 $ + * $Date: 2007/04/11 02:08:56 $ + * $State: Exp $ + */ + +package com.sun.j3d.exp.swing; + +import com.sun.j3d.exp.swing.impl.AutoOffScreenCanvas3D; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.GraphicsConfigTemplate; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; +import javax.media.j3d.Canvas3D; +import javax.media.j3d.GraphicsConfigTemplate3D; +import javax.swing.JPanel; +import javax.swing.event.AncestorListener; + + +/** + * This class provides a lightweight capability to Java 3D. The component + * handles bidirectional messaging between swing and Java 3D so that repaint + * ordonned by swing are sent to the universe if necessary and refreshes from + * the universe are painted accordingly. In order to get responsive interfaces + * during layout changes, the canvas has a feature (disabled by default) that + * lets true resizes occur only after a timer expires. Images between real + * resizes can eventually be slightly wrong and pixelated, but their display + * will be stutterless.
+ * Lightweight canvas also handles redirection to heavyweight canvas for the + * following events:
+ * - InputMethodEvent
+ * - KeyEvent
+ * - FocusEvent
+ * - ComponentKeyEvent
+ * - MouseWheelEvent
+ * - MouseEvent
+ * - MouseMotionEvent
+ *
+ *
+ * When Swing is waiting for a canvas to be retrieved and that canvas is in + * rendering stage,a loop takes place, which includes small calls to wait(). + * The canvas status is tested for readiness before and after the wait(). If + * the canvas is not ready to be retrieved after the wait(), counter is + * decremented and control is given back to awt thread, which will repaint old + * buffer. If the loop goes over a certain amount of iterations, the canvas is + * declared 'crashed' and won't be updated anymore. This was done so that a + * crashed canvas/universe does not remove control over your GUI and does not + * leave you with a frozen application. In current implementation, the delay + * before a canvas is declared crashed is of :
+ * 30 Math.max(20.0, getView().getMinimumFrameCycleTime() ) + * + * @author Frederic 'pepe' Barachant + * + * @see getLightweightComponent() + * @see setResizeValidationDelay() + * @see setResizeMode() + * + * @since Java 3D 1.5 + */ +public class JCanvas3D extends JPanel implements AncestorListener { + /** + * Resizing the canvas or component will be done immediately. This + * operation might take some time and make the application look sluggish. + * + * @see setResizeMode() + */ + public final static int RESIZE_IMMEDIATELY = 0; + + /** + * Resizing the canvas or component will be done if no resizing + * occurs after expiration of a certain delay. Rendering will be + * eventually stretched or deformed. It can be useful on certain + * applications where smooth update of UI during layout is needed or + * desired. + * + * @see setResizeMode() + */ + public final static int RESIZE_DELAYED = 1; + + //TODO: FBA: this had been taken from javax.media.j3d.Screen3D. When/IF proper dpi handling comes one day, that part will have to be changed also for consistency + /** size of a pixel */ + private static double METERS_PER_PIXEL = 0.0254 / 90.0; + + /** the template to be used for this canvas */ + private GraphicsConfigTemplate3D template; + + /** the graphics configuration used for this canvas */ + private GraphicsConfiguration graphicsConfig; + + /** The canvas that is linked to the component. */ + private InternalCanvas3D canvas; + + /** flag indicating that the JCanvas3D has been added to a container */ + private boolean hasBeenAdded = false; + + /** The resize mode currently being used. */ + int resizeMode; + + /** + * the idle delay that will trigger a real resize. ('idle' being + * the lack of resizing action from the user) + */ + int resizeValidationDelay; + + /** the device to be used by this canvas */ + private GraphicsDevice device; + + //TODO: FBA: the constructor below should be callable. Code should be changed so that it is possible, in order for the canvas to be useable into netbeans. + //TODO: FBA: create a netbeans module that installs J3D as a library and the JCanvas3D as a new item in a new J3D category of the swing palette (take from the java.net swash project) + + /** + * Constructs and initializes a new JCanvas3D object that Java 3D + * can render into. The screen device is obtained from + * GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(), + * which might not be the one you should use if you are in a multiscreen environment. + * The JCanvas3D is constructed using the following default parameters:
+ * resize mode : RESIZE_IMMEDIATELY
+ * validation delay : 100ms
+ * double buffer enable : false
+ * stereo enable : false
+ */ + public JCanvas3D() { + this(null, GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice()); + } + + /** + * Constructs and initializes a new Canvas3D object that Java 3D + * can render into, using the specified graphics device. + * + * @param device the screen graphics device that will be used to construct + * a GraphicsConfiguration. + */ + public JCanvas3D(GraphicsDevice device) { + this(null, device); + } + + /** + * Constructs and initializes a new Canvas3D object that Java 3D + * can render into, using the specified template. + * The screen device is obtained from + * GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(), + * which might not be the one you should use if you are + * in a multiscreen environment. + * + * @param template The template that will be used to construct a + * GraphicsConfiguration. The stereo and doublebuffer properties + * are forced to UNNECESSARY. + */ + public JCanvas3D(GraphicsConfigTemplate3D template) { + this(template, GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice()); + } + + /** + * Constructs and initializes a new Canvas3D object that Java 3D + * can render into, using the specified template and graphics device. + * + * @param template The template that will be used to construct a + * GraphicsConfiguration. The stereo and doublebuffer properties + * are forced to UNNECESSARY. + * @param device the screen graphics device that will be used to construct + * a GraphicsConfiguration in conjunction with the template. + */ + public JCanvas3D(GraphicsConfigTemplate3D template, GraphicsDevice device) { + this.device = device; + this.template = new GraphicsConfigTemplate3D(); + + if (template != null) { + // Clone template (it would be easier if GCT3D were cloneable) + this.template.setRedSize(template.getRedSize()); + this.template.setGreenSize(template.getGreenSize()); + this.template.setBlueSize(template.getBlueSize()); + this.template.setDepthSize(template.getDepthSize()); + this.template.setSceneAntialiasing(template.getSceneAntialiasing()); + this.template.setStencilSize(template.getStencilSize()); +// this.template.setDoubleBuffer(template.getDoubleBuffer()); +// this.template.setStereo(template.getStereo()); + } + + // Force double-buffer and stereo to UNNECESSARY + this.template.setStereo(GraphicsConfigTemplate.UNNECESSARY); + this.template.setDoubleBuffer(GraphicsConfigTemplate.UNNECESSARY); + + graphicsConfig = this.device.getBestConfiguration(this.template); + + addAncestorListener(this); + setDoubleBuffered(false); + setResizeMode(RESIZE_IMMEDIATELY); + setResizeValidationDelay(100); + + // so that key events and such can be received. + setFocusable(true); + } + + /** + * {@inheritDoc} + * + * @param event {@inheritDoc} + */ + public void ancestorAdded(javax.swing.event.AncestorEvent event) { + // if ( true == isVisible( ) ) // check if the component itself is visible. + { + Dimension sz = getSize(); + + if (0 == sz.width) { + sz.width = 100; + } + + if (0 == sz.height) { + sz.height = 100; + } + + createCanvas(sz.width, sz.height); + canvas.addNotifyFlag = true; // make it so that i can call addNotify() without being rejected. + canvas.addNotify(); + hasBeenAdded = true; + } + } + + /** + * {@inheritDoc} + * + * @param event {@inheritDoc} + */ + public void ancestorMoved(javax.swing.event.AncestorEvent event) { + } + + /** + * {@inheritDoc} + * + * @param event {@inheritDoc} + */ + public void ancestorRemoved(javax.swing.event.AncestorEvent event) { + hasBeenAdded = false; + canvas.removeNotify(); + } + + /** + * Computes the physical dimensions of the screen in space. + */ + private void computePhysicalDimensions() { + // Fix to Issue : 433 - JCanvas3D crashed when using jogl pipe. + Rectangle screenRect = this.graphicsConfig.getBounds(); + int screenWidth = (int) screenRect.getWidth(); + int screenHeight = (int) screenRect.getHeight(); + canvas.getScreen3D().setSize(screenWidth, screenHeight); + canvas.getScreen3D() + .setPhysicalScreenWidth(((double) screenWidth) * METERS_PER_PIXEL); + canvas.getScreen3D() + .setPhysicalScreenHeight(((double) screenHeight) * METERS_PER_PIXEL); + } + + /** + * Creates a heavyweight canvas and initializes it, or changes the + * size of the current one if present. Current heavyweight canvas is + * changed only if size is different from the actual one. No canvas is + * created if this component has no parent, that is, was not added to a + * container. + * + * @param width the width of the canvas to create. + * @param height the height of the canvas to create. + */ + void createCanvas(int width, int height) { + if (getParent() == null) { + return; + } + + if (null != canvas) { + // i had a canvas, i need to check if i really need to change it + if ((width != canvas.getWidth()) || (height != canvas.getHeight())) { + if ((null != canvas.getOffScreenBuffer()) && + (null != canvas.getOffScreenBuffer().getImage())) { + canvas.getOffScreenBuffer().getImage().flush(); // flushing so that eventual resources are freed. + } + } else { + return; + } + } else { + // no canvas, i have to create it. + canvas = new InternalCanvas3D(this.graphicsConfig, this); + } + + createOffScreenBuffer(width, height); // whatever happened right above, i need to create the offscreen buffer. + } + + /** + * Creates an offscreen buffer to be attached to the heavyweight + * buffer. Buffer is created 'byreference' + * + * @param width the width of the buffer. + * @param height the height of the buffer. + */ + private void createOffScreenBuffer(int width, int height) { + computePhysicalDimensions(); + + // this.canvas.setDoubleBufferEnable( false ); + java.awt.image.BufferedImage bImage = new java.awt.image.BufferedImage(width, + height, java.awt.image.BufferedImage.TYPE_INT_ARGB); + javax.media.j3d.ImageComponent2D image = new javax.media.j3d.ImageComponent2D(javax.media.j3d.ImageComponent2D.FORMAT_RGBA8, + bImage, true, false ); + image.setCapability(image.ALLOW_IMAGE_READ); + image.setCapability(image.ALLOW_IMAGE_WRITE); + + this.canvas.stopRenderer(); + + // offscreenrendering might occur even if the renderer is stopped. For that reason, i'm waiting for an hypothetical offscreen render to finish before setting offscreen rendering. + // Otherwise, rendering will stop with an exception. + this.canvas.waitForOffScreenRendering(); + + this.canvas.setOffScreenBuffer(image); + this.canvas.startRenderer(); + } + + /** + * Returns the offscreen heavyweight canvas of that lightweight + * component. + * + * @return the heavyweight canvas that lies in the deepness of this + * Component. + */ + public Canvas3D getOffscreenCanvas3D() { + if (null == this.canvas) { + createCanvas(getWidth(), getHeight()); + } + + return this.canvas; + } + + /** + * Retrieves the resize mode for that component. + * + * @return the resize mode, which can be one of RESIZE_IMMEDIATELY or + * RESIZE_DELAYED + */ + public int getResizeMode() { + return resizeMode; + } + + /** + * Retrieves the validation delay for that canvas, whatever the + * resize mode is set to. + * + * @return the validation delay. + */ + public int getResizeValidationDelay() { + return resizeValidationDelay; + } + + /** + * Paints the result of the rendering. If the rendered buffer is + * not useable (render thread being between [code]postRender()[/code] and + * [code]postSwap()[/code]), it will wait for it to be ready. Otherwise it + * will directly paint the previous buffer. + * + * @param g {@inheritDoc} + */ + public void paintComponent(java.awt.Graphics g) { + super.paintComponent(g); //paint background + + // Wait for and display image if JCanvas3D was added to an ancestor + if (hasBeenAdded) { + if ((false == canvas.canvasCrashed) && + (true == canvas.isRendererRunning())) { + // System.err.println("paintComponentWaitforSwap"); + canvas.waitForSwap(); + + // System.err.println("wait is over"); + } + + if (null != canvas.bi) { + // can eventually be null if the canvas did not send the result in the desired timeframe + // for first render. In that case, we don't paint and keep the background as-is. + g.drawImage(canvas.bi, 0, 0, getWidth(), getHeight(), null); + } + } + } + + /** + * Redirects event to canvas and to superclass. + * + * @param e {@inheritDoc} + */ + protected void processComponentKeyEvent(java.awt.event.KeyEvent e) { + super.processComponentKeyEvent(e); + + Object src = e.getSource(); + e.setSource(canvas); + canvas.processComponentEvent(e); + e.setSource(src); + } + + /** + * Redirects event to canvas and to superclass. + * + * @param e {@inheritDoc} + */ + protected void processFocusEvent(java.awt.event.FocusEvent e) { + super.processFocusEvent(e); + + Object src = e.getSource(); + e.setSource(canvas); + canvas.processFocusEvent(e); + e.setSource(src); + } + + /** + * Redirects event to canvas and to superclass. + * + * @param e {@inheritDoc} + */ + protected void processInputMethodEvent(java.awt.event.InputMethodEvent e) { + super.processInputMethodEvent(e); + + Object src = e.getSource(); + e.setSource(canvas); + canvas.processInputMethodEvent(e); + e.setSource(src); + } + + /** + * Redirects event to canvas and to superclass. + * + * @param e {@inheritDoc} + */ + protected void processKeyEvent(java.awt.event.KeyEvent e) { + super.processKeyEvent(e); + + Object src = e.getSource(); + e.setSource(canvas); + canvas.processKeyEvent(e); + e.setSource(src); + } + + /** + * Redirects event to canvas and to superclass. + * + * @param e {@inheritDoc} + */ + protected void processMouseEvent(java.awt.event.MouseEvent e) { + super.processMouseEvent(e); + + Object src = e.getSource(); + e.setSource(canvas); + canvas.processMouseEvent(e); + e.setSource(src); + } + + /** + * Redirects event to canvas and to superclass. + * + * @param e {@inheritDoc} + */ + protected void processMouseMotionEvent(java.awt.event.MouseEvent e) { + super.processMouseMotionEvent(e); + + Object src = e.getSource(); + e.setSource(canvas); + canvas.processMouseMotionEvent(e); + e.setSource(src); + } + + /** + * Redirects event to canvas and to superclass. + * + * @param e {@inheritDoc} + */ + protected void processMouseWheelEvent(java.awt.event.MouseWheelEvent e) { + super.processMouseWheelEvent(e); + + Object src = e.getSource(); + e.setSource(canvas); + canvas.processMouseWheelEvent(e); + e.setSource(src); + } + + /** + * {@inheritDoc} + * + * @param x {@inheritDoc} + * @param y {@inheritDoc} + * @param width {@inheritDoc} + * @param height {@inheritDoc} + */ + public void setBounds(int x, int y, int width, int height) { + super.setBounds(x, y, width, height); + + if ((null == canvas) || (null == canvas.getOffScreenBuffer()) || + (JCanvas3D.RESIZE_IMMEDIATELY == getResizeMode())) //whatever the resize mode, i create on first setbounds(). (not doing so would create a deadlock in DELAYED mode when trying to do the first paint + { + createCanvas(width, height); + } else if ((JCanvas3D.RESIZE_DELAYED == getResizeMode()) && + ((null != canvas.getParent()) && + (true == canvas.getParent().isVisible()))) { + if ((null == canvas.resizeThread) || + (false == canvas.resizeThread.isAlive())) { + canvas.resizeThread = new ResizeThread(width, height, + getResizeValidationDelay(), this); + canvas.resizeThread.start(); + } else { + canvas.resizeThread.setWidth(width); + canvas.resizeThread.setHeight(height); + } + } + } + + /** + * Sets resize mode to be used on this component. Resize mode + * permits to have smoother canvas resizes. The time taken by a canvas to + * be resized can be pretty long: renderer has to stop, current render has + * to end, everything has to be initialized again, and after all that has + * been done, renderer is started again, then the image is displayed once + * rendered. Resize mode uses a timer to make those steps only after the + * last refresh request occured. 'Latest refresh' is determined by the + * amount of time between now and the last time you asked for a size + * change. If that time expires, a real resize is done. In between, the + * same size is rendered, but the drawn image is scaled down/up. This has + * some drawbacks, as the image can appear blocked, imprecise, distorted, + * incomplete for that while, but most of the time only some of the + * drawbacks will be users will see nothing. Default delay is set to + * 100ms, which is low enough for common human not to be able to really + * see that the rendered image is scaled. + * + * @param resizeMode can be one of RESIZE_IMMEDIATELY or RESIZE_DELAYED + * @see #RESIZE_IMMEDIATELY + * @see #RESIZE_DELAYED + */ + public void setResizeMode(int resizeMode) { + this.resizeMode = resizeMode; + } + + /** + * Sets the validation delay for the component. The validation + * delay is the maximum time allowed for the canvas resizing to occur + * using rendered buffer scaling. Once that delay expired, the canvas is + * resized at the lowest level possible, thus in the rendering pipeline. + * Note: Changing this field is only useful if resize mode is set to + * RESIZE_IMMEDIATELY or RESIZE_DELAYED + * + * @param resizeValidationDelay the delay before a real resize would occur. + * @see #RESIZE_IMMEDIATELY + * @see #RESIZE_DELAYED + */ + public void setResizeValidationDelay(int resizeValidationDelay) { + this.resizeValidationDelay = resizeValidationDelay; + } + + /** + * This class is the internal Canvas3D that is used and sent to + * Java 3D. It is remote controlled through JCanvas3D and is modified to be + * able to tell the lightweight component when refreshes are needed. + */ + static class InternalCanvas3D extends Canvas3D + implements AutoOffScreenCanvas3D { + + // These two constants define the maximum amount of time + // to wait for the readback of the off-screen buffer to complete. + // The total time is MAX_WAIT_LOOPS * MAX_WAIT_TIME msec. + private static final int MAX_WAIT_LOOPS = 5; + private static final long MAX_WAIT_TIME = 100; + + /** + * the bufferedImage that will be displayed as the result + * of the computations. + */ + BufferedImage bi = null; + + /** + * This is the lightweight canvas that is linked to that + * offscreen canvas. + */ + JCanvas3D lwCanvas; + + /** + * If delayed resizing is selected, a thread handling + * resising will be started. + */ + ResizeThread resizeThread; + + /** + * flag used to sort a call to addnotify() from user and + * from the lightweight component. Lightweight component calls + * addNotify() so that the rendering begins and uses normal routines, + * but this is a method that user must not call. + */ + boolean addNotifyFlag; + + /** + * flag indicating that the canvas crashed in a way or an + * other, making swing to wait for the swap for much too long. + */ + protected boolean canvasCrashed; + + /** + * flag used to know when image can be painted or not. This + * is to avoid component potentially displaying a buffer with an + * unfinished blit. There is already a flag (imageReady) in Canvas3D + * that does this but it can't be used because of restrictions. This + * flag is not really fine grained, being set from end of postRender() + * to end of postSwap() + */ + boolean imageReadyBis; + + /** + * Flag to indicate that the component is waiting for the + * canvas to acomplish its swap, and that the component has to be + * notified when done. + */ + boolean waitingForSwap; + + /** + * Creates a new instance of JCanvas3D. Resize mode is set + * to RESIZE_IMMEDIATELY and validation delay to 100ms. + * + * @param graphicsConfiguration The graphics configuration to be used. + * @param lwCanvas the lightweight canvas that is linked to that + * heavyweight canvas. + */ + public InternalCanvas3D(GraphicsConfiguration graphicsConfiguration, + JCanvas3D lwCanvas) { + super(graphicsConfiguration, true); + this.lwCanvas = lwCanvas; + imageReadyBis = false; + waitingForSwap = false; + addNotifyFlag = false; + } + + /** + * {@inheritDoc} + */ + public void addNotify() { + if (false == addNotifyFlag) { + throw new UnsupportedOperationException("CHANGE ME"); + } else { + addNotifyFlag = false; + super.addNotify(); + } + } + + /** + * Normally, returns the parent of that component. As the + * canvas ought to never be added to any component, it has no parent. + * Java 3D expects it to have a parent for some operations, so we in + * fact cheat it by returning the parent of the lightweight component. + * + * @return the parent of the lightweight component, if any. Returns + * null if the component is not created or if it has no + * parent. + */ + public java.awt.Container getParent() { + if (null == this.lwCanvas) { + return null; + } + + return this.lwCanvas.getParent(); + } + + /** + * Blocks the retrieval of the render buffer. + */ + public void postRender() { + imageReadyBis = false; + } + + /** + * Retrieves the buffer from canvas, if possible, and + * calls/notifies component to be repainted, if necessary. + */ + synchronized public void postSwap() { + if (true == isRendererRunning()) { // as weird as it can look, there can be postswaps without rendered running. (?!!) Anyway, in that case we should not refresh. + bi = getOffScreenBuffer().getImage(); + imageReadyBis = true; + + if (false == waitingForSwap) { + // System.err.println("repaint " + System.currentTimeMillis()); + this.lwCanvas.repaint(); + } else { + notify(); + } + } else { + // System.err.println("SWAP WITHOUT RENDERER RUNNING"); + } + } + + /** + * Overriden so that the JComponent can access it. + * + * @param e {@inheritDoc} + */ + protected void processComponentEvent(java.awt.event.ComponentEvent e) { + super.processComponentEvent(e); + } + + /** + * Overriden so that the JComponent can access it. + * + * @param e {@inheritDoc} + */ + protected void processFocusEvent(java.awt.event.FocusEvent e) { + super.processFocusEvent(e); + } + + /** + * Overriden so that the JComponent can access it. + * + * @param e {@inheritDoc} + */ + protected void processInputMethodEvent( + java.awt.event.InputMethodEvent e) { + super.processInputMethodEvent(e); + } + + /** + * Overriden so that the JComponent can access it. + * + * @param e {@inheritDoc} + */ + protected void processKeyEvent(java.awt.event.KeyEvent e) { + super.processKeyEvent(e); + } + + /** + * Overriden so that the JComponent can access it. + * + * @param e {@inheritDoc} + */ + protected void processMouseEvent(java.awt.event.MouseEvent e) { + super.processMouseEvent(e); + } + + /** + * Overriden so that the JComponent can access it. + * + * @param e {@inheritDoc} + */ + protected void processMouseMotionEvent(java.awt.event.MouseEvent e) { + super.processMouseMotionEvent(e); + } + + /** + * Overriden so that the JComponent can access it. + * + * @param e {@inheritDoc} + */ + protected void processMouseWheelEvent(java.awt.event.MouseWheelEvent e) { + super.processMouseWheelEvent(e); + } + + /** + * If the Canvas is in a state that forbids the retrieving + * of the buffer, wait a bit before trying again. + */ + synchronized void waitForSwap() { + int counter = MAX_WAIT_LOOPS; + while (false == imageReadyBis) { + try { + waitingForSwap = true; + wait(MAX_WAIT_TIME); + waitingForSwap = false; + + if (!imageReadyBis && --counter <= 0) { + //if i've waited too long for the canvas to be there, let us declare it crashed. + System.err.println("CANVAS CRASHED!!!"); + canvasCrashed = true; + return; + } + } catch (InterruptedException ex) { + System.err.println(ex); + } + } + } + + } + + /** + * This Runnable is the class used when the canvas has to be + * resized. + */ + static class ResizeSwingRunnable implements Runnable { + /** The component that is displaying the canvas */ + JCanvas3D canvas; + + /** latest height that was requested */ + int height; + + /** latest width that was requested */ + int width; + + /** + * Creates a new ResizeSwingRunnable object. + */ + private ResizeSwingRunnable() { + } + + /** + * Creates a new ResizeSwingRunnable object. + * + * @param canvas the canvas to check + * @param width the width that is requested + * @param height the height that is requested + */ + public ResizeSwingRunnable(JCanvas3D canvas, int width, int height) { + this.canvas = canvas; + this.width = width; + this.height = height; + } + + /** + * {@inheritDoc} + */ + public void run() { + canvas.createCanvas(width, height); + } + } + + /** + * This Thread handles the resizing changes and handles the timer + * up to the moment when the resizing has to really occur. + */ + static class ResizeThread extends Thread { + //TODO: refactor so that it can handle a list of canvases, delays and start delay date, and change to a singleton. Actually, each JCanvas3D that would have to resize would spawn its own thread, which ought to be seen as "a bad thing" + /** the canvas that has to be checked */ + JCanvas3D canvas; + + /** A flag indicating that since last check, size got changed again and the delay has to be reset */ + boolean sizeChanged; + + /** the delay that has to occur between last size change and real resize */ + int delay; + + /** latest height that was requested */ + int height; + + /** latest width that was requested */ + int width; + + /** + * Creates a new ResizeThread object. + */ + private ResizeThread() { + } + + /** + * Creates a new ResizeThread object. + * + * @param width initial width change + * @param height initial height change + * @param delay delay to be used + * @param canvas the canvas that has to be checked + */ + public ResizeThread(int width, int height, int delay, JCanvas3D canvas) { + this.width = width; + this.height = height; + this.delay = delay; + this.sizeChanged = true; + this.canvas = canvas; + } + + /** + * returns the latest height that is being requested for change + * + * @return latest height requested + */ + public int getHeight() { + return height; + } + + /** + * returns the latest width that is being requested for change + * + * @return latest width requested + */ + public int getWidth() { + return width; + } + + /** + * {@inheritDoc} + */ + public void run() { + try { + while (true == sizeChanged) // the double loop is made so that if a change of size arrives while the canvas is already resizing, the same thread can keep up with subsequent resizes. + { // the effect of the double loop is to simplify some subtle race conditions at higher level. + + while (true == sizeChanged) { + sizeChanged = false; + Thread.sleep(delay); // while the thread sleeps, value can change. if value changes, flag will be true, and i'll have to wait again. if size does not change during the sleep, thread will quit and size will change. + //TODO: should i force a resize after a definite delay occured, so it does not stay zoomed too long ? + } + + try { + EventQueue.invokeAndWait(new ResizeSwingRunnable( + canvas, width, height)); + } catch (InterruptedException ie) { + } catch (InvocationTargetException ite) { + } + } + } catch (InterruptedException ie) { + //if i get interrupted, this is not important, i'll quit method. + } + } + + /** + * sets height. this has the effect of resetting the timeout. + * + * @param height the new height. + * + * @throws RuntimeException DOCUMENT ME! + */ + public void setHeight(int height) { + if (isAlive()) { + this.height = height; + sizeChanged = true; + } else { + throw new RuntimeException( + "Resizing order arrived to a dead resizing thread. Spawn a new one."); + } + } + + /** + * Sets width. This has the effect of resetting the timeout. + * + * @param width the new width. + * + * @throws RuntimeException DOCUMENT ME! + */ + public void setWidth(int width) { + if (isAlive()) { + this.width = width; + sizeChanged = true; + } else { + throw new RuntimeException( + "Resizing order arrived to a dead resizing thread. Spawn a new one."); + } + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/impl/AutoOffScreenCanvas3D.java b/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/impl/AutoOffScreenCanvas3D.java new file mode 100644 index 0000000..2b46021 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/impl/AutoOffScreenCanvas3D.java @@ -0,0 +1,60 @@ +/* + * $RCSfile: AutoOffScreenCanvas3D.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:04 $ + * $State: Exp $ + */ + +package com.sun.j3d.exp.swing.impl; + +/** + * Tagging interface for Java 3D off-screen Canvas3D objects that are + * automatically rendered. This is used internally by the JCanvas3D + * implementation. + *

+ * NOTE: this is an experimental interface, which is not intended for use + * by applications. + * + * @author pepe + * + * @since Java 3D 1.5 + */ +public interface AutoOffScreenCanvas3D { +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/package.html new file mode 100644 index 0000000..e1cff44 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/exp/swing/package.html @@ -0,0 +1,13 @@ + + + + + com.sun.j3d.exp.swing + + +

EXPERIMENTAL: Provides a lightweight JCanvas3D class. +Note that the API in this package is highly experimental and +subject to change at any time.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/BufferWrapper.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/BufferWrapper.java new file mode 100755 index 0000000..69aa6e9 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/BufferWrapper.java @@ -0,0 +1,186 @@ +/* + * $RCSfile: BufferWrapper.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +package com.sun.j3d.internal; + +import javax.media.j3d.J3DBuffer; +import java.nio.Buffer; + +/** + * NIO Buffers are new in Java 1.4 but we need to run on 1.3 + * as well, so this class was created to hide the NIO classes + * from non-1.4 Java 3D users. + * + *

+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2 + * community source release on java.net. We should be able to get rid + * of this class. + */ + +public abstract class BufferWrapper { + + /** + * Value returned from getBufferType(), this indicates + * that the BufferWrapper contains a null buffer. + */ + public static final int TYPE_NULL = 0; + + /** + * Value returned from getBufferType(), this indicates + * that the BufferWrapper does not hold data of type + * byte, float, or double. + */ + public static final int TYPE_UNKNOWN = 1; + + /** + * Value returned from getBufferType(), this indicates + * that the BufferWrapper contains a java.nio.ByteBuffer. + */ + public static final int TYPE_BYTE = 2; + + /** + * Value returned from getBufferType(), this indicates + * that the BufferWrapper contains a java.nio.FloatBuffer. + */ + public static final int TYPE_FLOAT = 3; + + /** + * Value returned from getBufferType(), this indicates + * that the BufferWrapper contains a java.nio.DoubleBuffer. + */ + public static final int TYPE_DOUBLE = 4; + + /** + * Never used - this class is abstract. + */ + public BufferWrapper() { + } + + /** + * Must be implemented by sublasses. + */ + abstract Buffer getBuffer(); + + /** + * @return Buffer as object of type Object. + */ + public Object getBufferAsObject() { + return getBuffer(); + } + + // Wrapper for all relevant Buffer methods. + + /** + * @return This buffer's capacity (set at initialization in + * allocateDirect() ). + * @see ByteBufferWrapper#allocateDirect + */ + public int capacity() { + return getBuffer().capacity(); + } + + /** + * @return This buffer's limit. + */ + public int limit() { + return getBuffer().limit(); + } + + /** + * @return This buffer's position. + */ + public int position() { + return getBuffer().position(); + } + + /** + * Sets this buffer's position. + * @return This buffer. + */ + public BufferWrapper position(int newPosition){ + getBuffer().position(newPosition); + return this; + } + + /** + * Resets this buffer's position to the previously marked + * position. + * @return This buffer. + */ + public BufferWrapper rewind() { + getBuffer().rewind(); + return this; + } + + /** + * @return An integer indicating the type of data held in + * this buffer. + * @see #TYPE_NULL + * @see #TYPE_BYTE + * @see #TYPE_FLOAT + * @see #TYPE_DOUBLE + * @see #TYPE_UNKNOWN + */ + public static int getBufferType(J3DBuffer b) { + int bufferType; + Buffer buffer = b.getBuffer(); + + if (buffer == null) { + bufferType = TYPE_NULL; + } + else if (buffer instanceof java.nio.ByteBuffer) { + bufferType = TYPE_BYTE; + } + else if (buffer instanceof java.nio.FloatBuffer) { + bufferType = TYPE_FLOAT; + } + else if (buffer instanceof java.nio.DoubleBuffer) { + bufferType = TYPE_DOUBLE; + } + else { + bufferType = TYPE_UNKNOWN; + } + return bufferType; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/ByteBufferWrapper.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/ByteBufferWrapper.java new file mode 100755 index 0000000..371e8fb --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/ByteBufferWrapper.java @@ -0,0 +1,197 @@ +/* + * $RCSfile: ByteBufferWrapper.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +package com.sun.j3d.internal; + +import javax.media.j3d.J3DBuffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * NIO Buffers are new in Java 1.4 but we need to run on 1.3 + * as well, so this class was created to hide the NIO classes + * from non-1.4 Java 3D users. + * + *

+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2 + * community source release on java.net. We should be able to get rid + * of this class. + */ + +public class ByteBufferWrapper extends BufferWrapper { + + private ByteBuffer buffer = null; + + /** + * Constructor initializes buffer with a + * java.nio.ByteBuffer object. + */ + public ByteBufferWrapper(ByteBuffer buffer) { + this.buffer = buffer; + } + + /** + * Constructor initializes buffer with a + * javax.media.j3d.J3DBuffer object. + */ + public ByteBufferWrapper(J3DBuffer b) { + buffer = (ByteBuffer)(b.getBuffer()); + } + + /** + * Allocate a direct ByteBuffer with the given capacity. + * @return New ByteBufferWrapper containing the + * new buffer. + */ + public static ByteBufferWrapper allocateDirect(int capacity) { + ByteBuffer bb = ByteBuffer.allocateDirect(capacity); + return new ByteBufferWrapper(bb); + } + + /** + * Returns the java.nio.Buffer contained within this + * ByteBufferWrapper. + */ + public java.nio.Buffer getBuffer() { + return this.buffer; + } + + // Wrapper for all relevant ByteBuffer methods. + + /** + * @return A boolean indicating whether the java.nio.Buffer + * object contained within this ByteBuffer is direct or + * indirect. + */ + public boolean isDirect() { + return buffer.isDirect(); + } + + /** + * Reads the byte at this buffer's current position, + * and then increments the position. + */ + public byte get() { + return buffer.get(); + } + + /** + * Reads the byte at the given offset into the buffer. + */ + public byte get(int index) { + return buffer.get(index); + } + + /** + * Bulk get method. Transfers dst.length + * bytes from + * the buffer to the destination array and increments the + * buffer's position by dst.length. + */ + public ByteBufferWrapper get(byte[] dst) { + buffer.get(dst); + return this; + } + + /** + * Bulk get method. Transfers length bytes + * from the buffer starting at position offset into + * the destination array. + */ + public ByteBufferWrapper get(byte[] dst, int offset, int length) { + buffer.get(dst, offset, length); + return this; + } + + /** + * Returns the byte order of this buffer. + */ + public ByteOrderWrapper order() { + if ( buffer.order()==ByteOrder.BIG_ENDIAN ) return ByteOrderWrapper.BIG_ENDIAN; + else return ByteOrderWrapper.LITTLE_ENDIAN; + } + + /** + * Modifies this buffer's byte order. + */ + public ByteBufferWrapper order(ByteOrderWrapper bo) + { + if ( bo == ByteOrderWrapper.BIG_ENDIAN ) buffer.order( ByteOrder.BIG_ENDIAN ); + else buffer.order( ByteOrder.LITTLE_ENDIAN ); + return this; + } + + /** + * Creates a view of this ByteBufferWrapper as a + * FloatBufferWrapper. Uses the correct + */ + public FloatBufferWrapper asFloatBuffer() { + return new FloatBufferWrapper( buffer.asFloatBuffer() ); + } + + /** + * Creates a view of this ByteBufferWrapper as a + * DoubleBufferWrapper. + */ + public DoubleBufferWrapper asDoubleBuffer() { + return new DoubleBufferWrapper( buffer.asDoubleBuffer() ); + } + + /** + * Bulk put method. Transfers src.length + * bytes into the buffer at the current position. + */ + public ByteBufferWrapper put(byte[] src) { + buffer.put(src); + return this; + } + + /** + * Creates and returns a J3DBuffer object containing the + * buffer in this ByteBufferWrapper object. + */ + public J3DBuffer getJ3DBuffer() { + return new J3DBuffer( buffer ); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/ByteOrderWrapper.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/ByteOrderWrapper.java new file mode 100755 index 0000000..a8715b2 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/ByteOrderWrapper.java @@ -0,0 +1,101 @@ +/* + * $RCSfile: ByteOrderWrapper.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +package com.sun.j3d.internal; + +import javax.media.j3d.J3DBuffer; +import java.nio.Buffer; +import java.nio.ByteOrder; + +/** + * NIO Buffers are new in Java 1.4 but we need to run on 1.3 + * as well, so this class was created to hide the NIO classes + * from non-1.4 Java 3D users. + * + *

+ * Typesafe enum for byte orders. + * + *

+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2 + * community source release on java.net. We should be able to get rid + * of this class. + */ + +public final class ByteOrderWrapper { + + private final String enum_name; + + /** + * Private constructor is only called from static initializers + * in this class. + */ + private ByteOrderWrapper(String name) { + enum_name = name; + } + + /** + * Static initializer creates object of this type. + */ + public static final ByteOrderWrapper BIG_ENDIAN = + new ByteOrderWrapper("BIG_ENDIAN"); + + /** + * Static initializer creates object of this type. + */ + public static final ByteOrderWrapper LITTLE_ENDIAN = + new ByteOrderWrapper("LITTLE_ENDIAN"); + + public String toString() { + return enum_name; + } + + /** + * Returns the native byte order of the host system. + */ + public static ByteOrderWrapper nativeOrder() { + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { + return ByteOrderWrapper.BIG_ENDIAN; + } else return ByteOrderWrapper.LITTLE_ENDIAN; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/Distance.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/Distance.java new file mode 100644 index 0000000..f714197 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/Distance.java @@ -0,0 +1,1096 @@ +/* + * $RCSfile: Distance.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +// -------------------------------------------------- +// +// Distance routines, ported from: +// +// Magic Software, Inc. +// http://www.magic-software.com +// http://www.wild-magic.com +// Copyright (c) 2004. All Rights Reserved +// +// The Wild Magic Library (WML) source code is supplied under the terms of +// the license agreement http://www.magic-software.com/License/WildMagic.pdf +// and may not be copied or disclosed except in accordance with the terms of +// that agreement. +// +// -------------------------------------------------- + +package com.sun.j3d.internal; + +import javax.vecmath.*; + +/** + * Utility class used to calculate distance. Contains static methods + * used by picking method to determine intersections. + */ + +public class Distance { + /* Threshold factor to determine if two lines are parallel */ + static final double FUZZ = 1E-5; + + /* Utility method, for easy switch between distance and squared distance */ + private static final double DIST (double in) { + // return Math.sqrt (Math.abs (in)); + return Math.abs (in); + } + + /** + * Minimum ray to segment distance. + * + * @param rayorig Origin of the ray + * @param raydir Direction of the ray + * @param segstart Segment start point + * @param segend Segment end point + * @return the square of the minimum distance from the ray to the segment + */ + static public double rayToSegment (Point3d rayorig, + Vector3d raydir, + Point3d segstart, + Point3d segend) { + return rayToSegment (rayorig, raydir, segstart, segend, null, null, null); + } + + /** + * Minimum ray to segment distance. Returns the square of the distance. + * + * @param rayorig Origin of the ray + * + * @param raydir Direction of the ray + * + * @param segstart Segment start point + * + * @param segend Segment end point + * + * @param rayint If non-null, will be filled with the coordinates of + * the point corresponding to the minimum distance on the ray. + * + * @param segint If non-null, will be filled with the coordinates of + * the point corresponding to the minimum distance on the segment. + * + * @param param An array of two doubles, will be filled with the + * parametric factors used to find the point of shortest distance on + * each primitive (ray = O +sD, with O=origin and + * D=direction). param[0] will contain the parameter for the ray, + * and param[1] the parameter for the segment. + * + * @return the square of the minimum distance from the ray to the + * segment + */ + static public double rayToSegment (Point3d rayorig, + Vector3d raydir, + Point3d segstart, + Point3d segend, + Point3d rayint, + Point3d segint, + double[] param) { + double s, t; + + Vector3d diff = new Vector3d(); + diff.sub (rayorig,segstart); + Vector3d segdir = new Vector3d(); + segdir.sub (segend, segstart); + /* + System.out.println (rayorig + "\n" + raydir + "\n" + segstart + "\n" + + segdir); + */ + double A = raydir.dot (raydir);//Dot(ray.m,ray.m); + double B = -raydir.dot (segdir);//-Dot(ray.m,seg.m); + double C = segdir.dot (segdir);//Dot(seg.m,seg.m); + double D = raydir.dot (diff);//Dot(ray.m,diff); + double E; // -Dot(seg.m,diff), defer until needed + double F = diff.dot (diff);//Dot(diff,diff); + double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0 + + double tmp; + + if (det >= FUZZ) { + // ray and segment are not parallel + E = -segdir.dot (diff);//-Dot(seg.m,diff); + s = B*E-C*D; + t = B*D-A*E; + + if (s >= 0) { + if (t >= 0) { + if (t <= det) { // region 0 + // minimum at interior points of ray and segment + double invDet = 1.0f/det; + s *= invDet; + t *= invDet; + if (rayint!=null) rayint.scaleAdd (s, raydir, rayorig); + if (segint!=null) segint.scaleAdd (t, segdir, segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F); + } + else { // region 1 + + t = 1; + if (D >= 0) { + s = 0; + if (rayint!=null) rayint.set (rayorig); + if (segint!=null) segint.set (segend); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + s = -D/A; + if (rayint!=null) rayint.scaleAdd (s, raydir, rayorig); + if (segint!=null) segint.set (segend); + if (param != null) { param[0] = s; param[1] = t; } + return DIST((D+2*B)*s+C+2*E+F); + } + } + } + else { // region 5 + t = 0; + if (D >= 0) { + s = 0; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else { + s = -D/A; + if (rayint != null) rayint.scaleAdd (s, raydir, rayorig); + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + } + } + else { + if (t <= 0) { // region 4 + if (D < 0) { + s = -D/A; + t = 0; + if (rayint != null) rayint.scaleAdd (s, raydir, rayorig); + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + else { + s = 0; + if (E >= 0) { + t = 0; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else if (-E >= C) { + t = 1; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segend); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + t = -E/C; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.scaleAdd (t, segdir, segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + } + } + else if (t <= det) { // region 3 + s = 0; + if (E >= 0) { + t = 0; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else if (-E >= C) { + t = 1; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segend); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + t = -E/C; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.scaleAdd (t, segdir, segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + } + else { // region 2 + tmp = B+D; + if (tmp < 0) { + s = -tmp/A; + t = 1; + if (rayint != null) rayint.scaleAdd (s, raydir, rayorig); + if (segint != null) segint.set (segend); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(tmp*s+C+2*E+F); + } + else { + s = 0; + if (E >= 0) { + t = 0; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else if (-E >= C) { + t = 1; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segend); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + t = -E/C; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.scaleAdd (t, segdir, segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + } + } + } + } + else { + // ray and segment are parallel + if (B > 0) { + // opposite direction vectors + t = 0; + if (D >= 0) { + s = 0; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else { + s = -D/A; + if (rayint != null) rayint.scaleAdd (s, raydir, rayorig); + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + } + else { + // same direction vectors + E = segdir.dot (diff);//-Dot(seg.m,diff); + t = 1; + tmp = B+D; + if (tmp >= 0) { + s = 0; + if (rayint != null) rayint.set (rayorig); + if (segint != null) segint.set (segend); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + s = -tmp/A; + if (rayint != null) rayint.scaleAdd (s, raydir, rayorig); + if (segint != null) segint.set (segend); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(tmp*s+C+2*E+F); + } + } + } + } + + /** + * Minimum ray to ray distance. Returns the square of the distance. + * + * @param ray0orig Origin of ray 0 + * @param ray0dir Direction of ray 0 + * @param ray1orig Origin of ray 1 + * @param ray1dir Direction of ray 1 + * @return the square of the minimum distance from the ray to the segment + */ + static public double rayToRay (Point3d ray0orig, + Vector3d ray0dir, + Point3d ray1orig, + Vector3d ray1dir) { + return rayToRay (ray0orig, ray0dir, ray1orig, ray1dir, null, null, null); + } + + /** + * Minimum ray to ray distance. Returns the square of the distance. + * + * @param ray0orig Origin of ray 0 + * + * @param ray0dir Direction of ray 0 + * + * @param ray1orig Origin of ray 1 + * + * @param ray1dir Direction of ray 1 + * + * @param ray0int If non-null, will be filled with the coordinates + * of the point corresponding to the minimum distance on ray 0. + * + * @param ray1int If non-null, will be filled with the coordinates + * of the point corresponding to the minimum distance on ray 1. + * + * @param param An array of two doubles, will be filled with the + * parametric factors used to find the point of shortest distance on + * each primitive (ray = O +sD, with O=origin and + * D=direction). param[0] will contain the parameter for ray0, and + * param[1] the parameter for ray1. + * + * @return the square of the minimum distance from the ray to the segment + */ + static public double rayToRay (Point3d ray0orig, + Vector3d ray0dir, + Point3d ray1orig, + Vector3d ray1dir, + Point3d ray0int, + Point3d ray1int, + double[] param) { + + double s, t; + + Vector3d diff = new Vector3d(); + diff.sub (ray0orig, ray1orig); + + double A = ray0dir.dot (ray0dir); //Dot(ray0.m,ray0.m); + double B = -ray0dir.dot (ray1dir); //-Dot(ray0.m,ray1.m); + double C = ray1dir.dot (ray1dir); //Dot(ray1.m,ray1.m); + double D = ray0dir.dot (diff); //Dot(ray0.m,diff); + double E; // -Dot(ray1.m,diff), defer until needed + double F = diff.dot (diff); //Dot(diff,diff); + double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0 + /* + System.out.println (ray0orig + "\n" + ray0dir + "\n" + + ray1orig + "\n" + ray1dir); + System.out.println (A + " " + B + " " + C + " " + D + " " + F + " " + det); + */ + if (det >= FUZZ) { + // rays are not parallel + E = -ray1dir.dot (diff); //-Dot(ray1.m,diff); + s = B*E-C*D; + t = B*D-A*E; + + if (s >= 0) { + if (t >= 0) { // region 0 (interior) + // minimum at two interior points of rays + double invDet = 1.0f/det; + s *= invDet; + t *= invDet; + if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig); + if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F); + } + else { // region 3 (side) + t = 0; + if (D >= 0) { + s = 0; + if (ray0int != null) ray0int.set (ray0orig); + if (ray1int != null) ray1int.set (ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else { + s = -D/A; + if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig); + if (ray1int != null) ray1int.set (ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + } + } + else { + if (t >= 0) { // region 1 (side) + s = 0; + if (E >= 0) { + t = 0; + if (ray0int != null) ray0int.set (ray0orig); + if (ray1int != null) ray1int.set (ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else { + t = -E/C; + if (ray0int != null) ray0int.set (ray0orig); + if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + } + else { // region 2 (corner) + if (D < 0) { + s = -D/A; + t = 0; + if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig); + if (ray1int != null) ray1int.set (ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + else { + s = 0; + if (E >= 0) { + t = 0; + if (ray0int != null) ray0int.set (ray0orig); + if (ray1int != null) ray1int.set (ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else { + t = -E/C; + if (ray0int != null) ray0int.set (ray0orig); + if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + } + } + } + } + else { + // rays are parallel + if (B > 0) { + // opposite direction vectors + t = 0; + if (D >= 0) { + s = 0; + if (ray0int != null) ray0int.set (ray0orig); + if (ray1int != null) ray1int.set (ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else { + s = -D/A; + if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig); + if (ray1int != null) ray1int.set (ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + } + else { + // same direction vectors + if (D >= 0) { + E = ray1dir.dot (diff); //-Dot(ray1.m,diff); + s = 0; + t = -E/C; + if (ray0int != null) ray0int.set (ray0orig); + if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + else { + s = -D/A; + t = 0; + if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig); + if (ray1int != null) ray1int.set (ray1orig); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + } + } + } + + /** + * Minimum pt to ray distance. Returns the square of the distance. + * @param pt The point + * @param rayorig Origin of the ray + * @param raydir Direction of the ray + * @return the square of the minimum distance between the point and the ray + */ + static public double pointToRay (Point3d pt, + Point3d rayorig, + Vector3d raydir) { + return pointToRay (pt, rayorig, raydir, null, null); + } + + /** + * Minimum pt to ray distance. Returns the square of the distance. + * + * @param pt The point + * + * @param rayorig Origin of the ray + * + * @param raydir Direction of the ray + * + * @param rayint If non-null, will be filled with the coordinates of + * the point corresponding to the minimum distance on the ray. + * + * @param param An array of one double, will be filled with the + * parametric factors used to find the point of shortest distance on + * the ray (ray = O +sD, with O=origin and D=direction). param[0] + * will contain the parameter for the ray. + * + * @return the square of the minimum distance between the point and the ray + */ + static public double pointToRay (Point3d pt, + Point3d rayorig, + Vector3d raydir, + Point3d rayint, + double[] param) { + + double t; + + Vector3d diff = new Vector3d(); + diff.sub (pt, rayorig); + t = raydir.dot (diff); //Dot(ray.m,diff); + + if (t <= 0.0) { + t = 0.0; // behind start of ray + if (rayint != null) rayint.set (rayorig); + if (param != null) { param[0] = t; } + } else { + t /= raydir.dot (raydir); //Dot(ray.m,ray.m); + diff.scaleAdd (-t, raydir, diff); // diff = diff - t*ray.m; + if (rayint != null) rayint.scaleAdd (t, raydir, rayorig); + if (param != null) { param[0] = t; } + } + return diff.dot(diff); + } + + /** + * Minimum pt to segment distance. Returns the square of the distance. + */ + static public double pointToSegment (Point3d pt, + Point3d segstart, + Point3d segend) { + return pointToSegment (pt, segstart, segend, null, null); + } + + /** + * Minimum pt to segment distance. Returns the square of the distance. + */ + static public double pointToSegment (Point3d pt, + Point3d segstart, + Point3d segend, + Point3d segint, + double[] param) { + + double t; + Vector3d segdir = new Vector3d (); + segdir.sub (segend, segstart); + Vector3d diff = new Vector3d(); + diff.sub (pt,segstart); + t = segdir.dot (diff); //Dot(seg.m,diff); + + if (t <= 0.0) { + t = 0.0f; + if (segint != null) segint.set (segstart); + if (param != null) { param[0] = t; } + } + else { + double mDotm = segdir.dot (segdir); //Dot(seg.m,seg.m); + if (t >= mDotm) { + t = 1.0f; + diff.sub (segdir); + if (segint != null) segint.set (segend); + if (param != null) { param[0] = t; } + } + else { + t /= mDotm; + diff.scaleAdd (-t, segdir, diff); //diff = diff - t*seg.m; + if (segint != null) segint.scaleAdd (t, segdir, segstart); + if (param != null) { param[0] = t; } + } + } + return diff.dot(diff); //DIST(diff); + } + + + /** + * Minimum segment to segment distance. Returns the square of the distance. + * @param seg0start the start of segment 0 + * @param seg0end the end of segment 0 + * @param seg1start the start of segment 1 + * @param seg1end the end of segment 1 + * @return the square of the minimum distance from segment to segment + */ + static public double segmentToSegment (Point3d seg0start, + Point3d seg0end, + Point3d seg1start, + Point3d seg1end) { + return segmentToSegment (seg0start, seg0end, seg1start, seg1end, + null, null, null); + } + + /** + * Minimum segment to segment distance. Returns the square of the distance. + * + * @param seg0start the start of segment 0 + * + * @param seg0end the end of segment 0 + * + * @param seg1start the start of segment 1 + * + * @param seg1end the end of segment 1 + * + * @param seg0int If non-null, will be filled with the coordinates + * of the point corresponding to the minimum distance on segment 0. + * + * @param seg1int If non-null, will be filled with the coordinates + * of the point corresponding to the minimum distance on segment 1. + * + * @param param An array of two doubles, will be filled with the + * parametric factors used to find the point of shortest distance on + * each primitive (segment = O +sD, with O=origin and + * D=direction). param[0] will contain the parameter for segment 0, + * and param[1] the parameter for segment 1. + * + * @return the square of the minimum distance from segment to segment + */ + static public double segmentToSegment (Point3d seg0start, + Point3d seg0end, + Point3d seg1start, + Point3d seg1end, + Point3d seg0int, + Point3d seg1int, + double[] param) { + double s,t; + + Vector3d diff = new Vector3d(); + diff.sub (seg0start,seg1start); + + Vector3d seg0dir = new Vector3d(); + seg0dir.sub (seg0end, seg0start); + Vector3d seg1dir = new Vector3d(); + seg1dir.sub (seg1end, seg1start); + + double A = seg0dir.dot (seg0dir); //Dot(seg0dir,seg0dir); + double B = -seg0dir.dot (seg1dir); //-Dot(seg0dir,seg1dir); + double C = seg1dir.dot (seg1dir); //Dot(seg1dir,seg1dir); + double D = seg0dir.dot (diff); //Dot(seg0dir,diff); + double E; // -Dot(seg1dir,diff), defer until needed + double F = diff.dot (diff); //Dot(diff,diff); + double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0 + + double tmp; + + if (det >= FUZZ) { + // line segments are not parallel + E = -seg1dir.dot (diff); //-Dot(seg1dir,diff); + s = B*E-C*D; + t = B*D-A*E; + + if (s >= 0) { + if (s <= det) { + if (t >= 0) { + if (t <= det) { // region 0 (interior) + // minimum at two interior points of 3D lines + double invDet = 1.0f/det; + s *= invDet; + t *= invDet; + if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F); + } + else { // region 3 (side) + t = 1; + tmp = B+D; + if (tmp >= 0) { + s = 0; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else if (-tmp >= A) { + s = 1; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+C+F+2*(E+tmp)); + } + else { + s = -tmp/A; + if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(tmp*s+C+2*E+F); + } + } + } + else { // region 7 (side) + t = 0; + if (D >= 0) { + s = 0; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else if (-D >= A) { + s = 1; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+2*D+F); + } + else { + s = -D/A; + if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + } + } + else { + if (t >= 0) { + if (t <= det) { // region 1 (side) + s = 1; + tmp = B+E; + if (tmp >= 0) { + t = 0; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+2*D+F); + } + else if (-tmp >= C) { + t = 1; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+C+F+2*(D+tmp)); + } + else { + t = -tmp/C; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(tmp*t+A+2*D+F); + } + } + else { // region 2 (corner) + tmp = B+D; + if (-tmp <= A) { + t = 1; + if (tmp >= 0) { + s = 0; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + s = -tmp/A; + if (seg0int!=null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int!=null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(tmp*s+C+2*E+F); + } + } + else { + s = 1; + tmp = B+E; + if (tmp >= 0) { + t = 0; + if (seg0int!=null) seg0int.set (seg0end); + if (seg1int!=null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+2*D+F); + } + else if (-tmp >= C) { + t = 1; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+C+F+2*(D+tmp)); + } + else { + t = -tmp/C; + if (seg0int!=null) seg0int.set (seg0end); + if (seg1int!=null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(tmp*t+A+2*D+F); + } + } + } + } + else { // region 8 (corner) + if (-D < A) { + t = 0; + if (D >= 0) { + s = 0; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else { + s = -D/A; + if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + } + else { + s = 1; + tmp = B+E; + if (tmp >= 0) { + t = 0; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+2*D+F); + } + else if (-tmp >= C) { + t = 1; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+C+F+2*(D+tmp)); + } + else { + t = -tmp/C; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(tmp*t+A+2*D+F); + } + } + } + } + } + else { + if (t >= 0) { + if (t <= det) { // region 5 (side) + s = 0; + if (E >= 0) { + t = 0; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else if (-E >= C) { + t = 1; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + t = -E/C; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + } + else { // region 4 (corner) + tmp = B+D; + if (tmp < 0) { + t = 1; + if (-tmp >= A) { + s = 1; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+C+F+2*(E+tmp)); + } + else { + s = -tmp/A; + if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(tmp*s+C+2*E+F); + } + } + else { + s = 0; + if (E >= 0) { + t = 0; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else if (-E >= C) { + t = 1; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + t = -E/C; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + } + } + } + else { // region 6 (corner) + if (D < 0) { + t = 0; + if (-D >= A) { + s = 1; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+2*D+F); + } + else { + s = -D/A; + if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + } + else { + s = 0; + if (E >= 0) { + t = 0; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else if (-E >= C) { + t = 1; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + t = -E/C; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(E*t+F); + } + } + } + } + } + else { + // line segments are parallel + if (B > 0) { + // direction vectors form an obtuse angle + if (D >= 0) { + s = 0; + t = 0; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F); + } + else if (-D <= A) { + s = -D/A; + t = 0; + if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + else { + E = -seg1dir.dot (diff); //-Dot(seg1dir,diff); + s = 1; + tmp = A+D; + if (-tmp >= B) { + t = 1; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+C+F+2*(B+D+E)); + } + else { + t = -tmp/B; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+2*D+F+t*(C*t+2*(B+E))); + } + } + } + else { + // direction vectors form an acute angle + if (-D >= A) { + s = 1; + t = 0; + if (seg0int != null) seg0int.set (seg0end); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(A+2*D+F); + } + else if (D <= 0) { + s = -D/A; + t = 0; + if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start); + if (seg1int != null) seg1int.set (seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(D*s+F); + } + else { + E = -seg1dir.dot (diff); //-Dot(seg1dir,diff); + s = 0; + if (D >= -B) { + t = 1; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.set (seg1end); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(C+2*E+F); + } + else { + t = -D/B; + if (seg0int != null) seg0int.set (seg0start); + if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start); + if (param != null) { param[0] = s; param[1] = t; } + return DIST(F+t*(2*E+C*t)); + } + } + } + } + } +} + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/DoubleBufferWrapper.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/DoubleBufferWrapper.java new file mode 100755 index 0000000..402f6c2 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/DoubleBufferWrapper.java @@ -0,0 +1,153 @@ +/* + * $RCSfile: DoubleBufferWrapper.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +package com.sun.j3d.internal; + +import javax.media.j3d.J3DBuffer; +import java.nio.DoubleBuffer; + +/** + * NIO Buffers are new in Java 1.4 but we need to run on 1.3 + * as well, so this class was created to hide the NIO classes + * from non-1.4 Java 3D users. + * + *

+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2 + * community source release on java.net. We should be able to get rid + * of this class. + */ + +public class DoubleBufferWrapper extends BufferWrapper { + + private DoubleBuffer buffer = null; + + /** + * Constructor initializes buffer with a + * java.nio.DoubleBuffer object. + */ + public DoubleBufferWrapper(DoubleBuffer buffer) { + this.buffer = buffer; + } + + /** + * Constructor initializes buffer with a + * javax.media.j3d.J3DBuffer object. + */ + public DoubleBufferWrapper(J3DBuffer b) { + buffer = (DoubleBuffer)(b.getBuffer()); + } + + /** + * Returns the java.nio.Buffer contained within this + * DoubleBufferWrapper. + */ + public java.nio.Buffer getBuffer() { + return this.buffer; + } + + // Wrapper for all relevant DoubleBuffer methods. + + /** + * @return A boolean indicating whether the java.nio.Buffer + * object contained within this DoubleBuffer is direct or + * indirect. + */ + public boolean isDirect() { + return buffer.isDirect(); + } + + /** + * Reads the double at this buffer's current position, + * and then increments the position. + */ + public double get() { + return buffer.get(); + } + + /** + * Reads the double at the given offset into the buffer. + */ + public double get(int index) { + return buffer.get(index); + } + + /** + * Bulk get method. Transfers dst.length + * doubles from + * the buffer to the destination array and increments the + * buffer's position by dst.length. + */ + public DoubleBufferWrapper get(double[] dst) { + buffer.get(dst); + return this; + } + + /** + * Bulk get method. Transfers length doubles + * from the buffer starting at position offset into + * the destination array. + */ + public DoubleBufferWrapper get(double[] dst, int offset, int length){ + buffer.get(dst, offset, length); + return this; + } + + /** + * Bulk put method. Transfers src.length + * doubles into the buffer at the current position. + */ + public DoubleBufferWrapper put(double[] src) { + buffer.put(src); + return this; + } + + /** + * Creates and returns a J3DBuffer object containing the + * buffer in this DoubleBufferWrapper object. + */ + public J3DBuffer getJ3DBuffer() { + return new J3DBuffer( buffer ); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/FastVector.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/FastVector.java new file mode 100644 index 0000000..8383d93 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/FastVector.java @@ -0,0 +1,143 @@ +/* + * $RCSfile: FastVector.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +package com.sun.j3d.internal; + +/** + * The FastVector object is a growable array of ints. It's much faster + * than the Java Vector class because it isn't synchronized. This class + * was created because it is needed in several places by graphics + * utilities. + */ +public class FastVector { + + private int data[]; + private int capacity; + private int increment; + private int size; + + /** + * Add an element to the end of the array. + */ + public void addElement(int element) + { + if (size >= capacity) { + capacity += (increment == 0) ? capacity : increment; + int newData[] = new int[capacity]; + System.arraycopy(data, 0, newData, 0, size); + data = newData; + } + data[size++] = element; + } // End of addElement + + + + /** + * Get number of ints currently stored in the array; + */ + public int getSize() + { + return size; + } // End of getSize + + + + /** + * Get access to array data + */ + public int[] getData() + { + return data; + } // End of getData + + + + /** + * Constructor. + * @param initialCapacity Number of ints the object can hold + * without reallocating the array. + * @param capacityIncrement Once the array has grown beyond + * its capacity, how much larger the reallocated array should be. + */ + public FastVector(int initialCapacity, int capacityIncrement) + { + data = new int[initialCapacity]; + capacity = initialCapacity; + increment = capacityIncrement; + size = 0; + } // End of FastVector(int, int) + + + + /** + * Constructor. + * When the array runs out of space, its size is doubled. + * @param initialCapacity Number of ints the object can hold + * without reallocating the array. + */ + public FastVector(int initialCapacity) + { + data = new int[initialCapacity]; + capacity = initialCapacity; + increment = 0; + size = 0; + } // End of FastVector(int) + + + + /** + * Constructor. + * The array is constructed with initial capacity of one integer. + * When the array runs out of space, its size is doubled. + */ + public FastVector() + { + data = new int[1]; + capacity = 1; + increment = 0; + size = 0; + } // End of FastVector() +} // End of class FastVector + +// End of file FastVector.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/FloatBufferWrapper.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/FloatBufferWrapper.java new file mode 100755 index 0000000..0d535ae --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/FloatBufferWrapper.java @@ -0,0 +1,152 @@ +/* + * $RCSfile: FloatBufferWrapper.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +package com.sun.j3d.internal; + +import javax.media.j3d.J3DBuffer; +import java.nio.FloatBuffer; + +/** + * NIO Buffers are new in Java 1.4 but we need to run on 1.3 + * as well, so this class was created to hide the NIO classes + * from non-1.4 Java 3D users. + * + *

+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2 + * community source release on java.net. We should be able to get rid + * of this class. + */ + +public class FloatBufferWrapper extends BufferWrapper { + + private FloatBuffer buffer = null; + + /** + * Constructor initializes buffer with a + * java.nio.FloatBuffer object. + */ + public FloatBufferWrapper(FloatBuffer buffer) { + this.buffer = buffer; + } + + /** + * Constructor initializes buffer with a + * javax.media.j3d.J3DBuffer object. + */ + public FloatBufferWrapper(javax.media.j3d.J3DBuffer b) { + this.buffer = (FloatBuffer)(b.getBuffer()); + } + + /** + * Returns the java.nio.Buffer contained within this + * FloatBufferWrapper. + */ + public java.nio.Buffer getBuffer() { + return this.buffer; + } + + // Wrapper for all relevant FloatBuffer methods. + + /** + * @return A boolean indicating whether the java.nio.Buffer + * object contained within this FloatBuffer is direct or + * indirect. + */ + public boolean isDirect() { + return buffer.isDirect(); + } + + /** + * Reads the float at this buffer's current position, + * and then increments the position. + */ + public float get() { + return buffer.get(); + } + + /** + * Reads the float at the given offset into the buffer. + */ + public float get(int index) { + return buffer.get(index); + } + + /** + * Bulk get method. Transfers dst.length + * floats from + * the buffer to the destination array and increments the + * buffer's position by dst.length. + */ + public FloatBufferWrapper get(float[] dst) { + buffer.get(dst); + return this; + } + + /** + * Bulk get method. Transfers length floats + * from the buffer starting at position offset into + * the destination array. + */ + public FloatBufferWrapper get(float[] dst, int offset, int length){ + buffer.get(dst, offset, length); + return this; + } + + /** + * Bulk put method. Transfers src.length + * floats into the buffer at the current position. + */ + public FloatBufferWrapper put(float[] src) { + buffer.put(src); + return this; + } + + /** + * Creates and returns a J3DBuffer object containing the + * buffer in this FloatBufferWrapper object. + */ + public J3DBuffer getJ3DBuffer() { + return new J3DBuffer( buffer ); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/HashCodeUtil.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/HashCodeUtil.java new file mode 100644 index 0000000..c3c0536 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/HashCodeUtil.java @@ -0,0 +1,116 @@ +/* + * $RCSfile: HashCodeUtil.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +package com.sun.j3d.internal; + +/** + * Utility class used when computing the hash code for + * objects containing float or double values. This fixes Issue 36. + */ +public class HashCodeUtil { + /** + * Returns the representation of the specified floating-point + * value according to the IEEE 754 floating-point "single format" + * bit layout, after first mapping -0.0 to 0.0. This method is + * identical to Float.floatToIntBits(float) except that an integer + * value of 0 is returned for a floating-point value of + * -0.0f. This is done for the purpose of computing a hash code + * that satisfies the contract of hashCode() and equals(). The + * equals() method in some Java 3D classes does a pair-wise + * "==" test on each floating-point field in the class. Since + * 0.0f == -0.0f returns true, we must also return the + * same hash code for two objects, one of which has a field with a + * value of -0.0f and the other of which has a cooresponding field + * with a value of 0.0f. + * + * @param f an input floating-point number + * @return the integer bits representing that floating-point + * number, after first mapping -0.0f to 0.0f + */ + public static int floatToIntBits(float f) { + // Check for +0 or -0 + if (f == 0.0f) { + return 0; + } + else { + return Float.floatToIntBits(f); + } + } + + /** + * Returns the representation of the specified floating-point + * value according to the IEEE 754 floating-point "double format" + * bit layout, after first mapping -0.0 to 0.0. This method is + * identical to Double.doubleToLongBits(double) except that an + * integer value of 0L is returned for a floating-point value of + * -0.0. This is done for the purpose of computing a hash code + * that satisfies the contract of hashCode() and equals(). The + * equals() method in some Java 3D classes does a pair-wise + * "==" test on each floating-point field in the class. Since + * 0.0 == -0.0 returns true, we must also return the + * same hash code for two objects, one of which has a field with a + * value of -0.0 and the other of which has a cooresponding field + * with a value of 0.0. + * + * @param d an input double precision floating-point number + * @return the integer bits representing that floating-point + * number, after first mapping -0.0f to 0.0f + */ + public static long doubleToLongBits(double d) { + // Check for +0 or -0 + if (d == 0.0) { + return 0L; + } + else { + return Double.doubleToLongBits(d); + } + } + + + /** + * Do not construct an instance of this class. + */ + private HashCodeUtil() { + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/internal/J3dUtilsI18N.java b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/J3dUtilsI18N.java new file mode 100644 index 0000000..1bb0628 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/internal/J3dUtilsI18N.java @@ -0,0 +1,63 @@ +/* + * $RCSfile: J3dUtilsI18N.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:05 $ + * $State: Exp $ + */ + +package com.sun.j3d.internal; + +import java.io.*; +import java.util.*; + + +public class J3dUtilsI18N { + static public String getString(String key) { + String s; + try { + s = (String) ResourceBundle.getBundle("com.sun.j3d.ExceptionStrings").getString(key); + } + catch (MissingResourceException e) { + System.err.println("J3dUtilsI18N: Error looking up: " + key); + s = key; + } + return s; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/IncorrectFormatException.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/IncorrectFormatException.java new file mode 100644 index 0000000..bbc4b4e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/IncorrectFormatException.java @@ -0,0 +1,62 @@ +/* + * $RCSfile: IncorrectFormatException.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:06 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders; + + +/** + * Exception used to indicate that a file of the incorrect + * type was passed to a loader. + */ +public class IncorrectFormatException extends RuntimeException { + + public IncorrectFormatException() { + super(); + } + + public IncorrectFormatException(String s) { + super(s); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/Loader.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/Loader.java new file mode 100644 index 0000000..0c0ca7d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/Loader.java @@ -0,0 +1,176 @@ +/* + * $RCSfile: Loader.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:06 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders; + +import java.net.URL; +import java.io.Reader; +import java.io.FileNotFoundException; + +/** + * The Loader interface is used to specify the location + * and elements of a file format to load. + * The interface is used to give loaders of various + * file formats a common public interface. Ideally + * the Scene interface will be implemented to give + * the user a consistent interface to extract the + * data. + * + * @see com.sun.j3d.loaders.Scene + */ +public interface Loader { + + // These are the values to be used in constructing the + // load flags for the loader. Users should OR the selected + // values together to construct an aggregate flag integer + // (see the setFlags() method). Users wishing to load all + // data in a file should use the LOAD_ALL specifier. + + /** This flag enables the loading of light objects into the scene.*/ + public static final int LOAD_LIGHT_NODES = 1; + + /** This flag enables the loading of fog objects into the scene.*/ + public static final int LOAD_FOG_NODES = 2; + + /** This flag enables the loading of background objects into the scene.*/ + public static final int LOAD_BACKGROUND_NODES = 4; + + /** This flag enables the loading of behaviors into the scene.*/ + public static final int LOAD_BEHAVIOR_NODES = 8; + + /** This flag enables the loading of view (camera) objects into + * the scene.*/ + public static final int LOAD_VIEW_GROUPS = 16; + + /** This flag enables the loading of sound objects into the scene.*/ + public static final int LOAD_SOUND_NODES = 32; + + /** This flag enables the loading of all objects into the scene.*/ + public static final int LOAD_ALL = 0xffffffff; + + + // Loading methods + + /** + * This method loads the named file and returns the Scene + * containing the scene. Any data files referenced by this + * file should be located in the same place as the named file; + * otherwise users should specify an alternate base path with + * the setBasePath(String) method. + */ + public Scene load(String fileName) throws FileNotFoundException, + IncorrectFormatException, ParsingErrorException; + + /** + * This method loads the named file and returns the Scene + * containing the scene. Any data files referenced by the Reader + * should be located in the same place as the named file; otherwise, + * users should specify an alternate base path with the setBaseUrl(URL) + * method. + */ + public Scene load(URL url) throws FileNotFoundException, + IncorrectFormatException, ParsingErrorException; + + /** + * This method loads the Reader and returns the Scene + * containing the scene. Any data files referenced by the Reader should + * be located in the user's current working directory. + */ + public Scene load(Reader reader) + throws FileNotFoundException, IncorrectFormatException, + ParsingErrorException; + + + // Variable get/set methods + + /** + * This method sets the base URL name for data files associated with + * the file passed into the load(URL) method. + * The basePath should be null by default, which is an indicator + * to the loader that it should look for any associated files starting + * from the same directory as the file passed into the load(URL) method. + */ + public void setBaseUrl(URL url); + + /** + * This method sets the base path name for data files associated with + * the file passed into the load(String) method. + * The basePath should be null by default, which is an indicator + * to the loader that it should look for any associated files starting + * from the same directory as the file passed into the load(String) + * method. + */ + public void setBasePath(String pathName); + + /** + * Returns the current base URL setting. By default this is null, + * implying the loader should look for associated files starting + * from the same directory as the file passed into the load(URL) method. + */ + public URL getBaseUrl(); + + /** + * Returns the current base path setting. By default this is null, + * implying the loader should look for associated files starting + * from the same directory as the file passed into the load(String) + * method. + */ + public String getBasePath(); + + /** + * This method sets the load flags for the file. The flags should + * equal 0 by default (which tells the loader to only load geometry). + * To enable the loading of any particular scene elements, pass + * in a logical OR of the LOAD values specified above. + */ + public void setFlags(int flags); + + /** + * Returns the current loading flags setting. + */ + public int getFlags(); +} + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/LoaderBase.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/LoaderBase.java new file mode 100644 index 0000000..88ef49f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/LoaderBase.java @@ -0,0 +1,147 @@ +/* + * $RCSfile: LoaderBase.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:06 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders; + +import java.net.URL; +import java.io.Reader; + +/** + * This class implements the Loader interface. To use + * a file loader would extend this class. + */ +public abstract class LoaderBase implements Loader { + + /** Stores the types of objects that the user wishes to load.*/ + protected int loadFlags = 0; + + /** Stores the baseUrl for data files associated with the URL + * passed into load(URL).*/ + protected URL baseUrl = null; + + /** Stores the basePath for data files associated with the file + * passed into load(String).*/ + protected String basePath = null; + + // Constructors + + /** + * Constructs a Loader with default values for all variables. + */ + public LoaderBase() { + } + + /** + * Constructs a Loader with the specified flags word. + */ + public LoaderBase(int flags) { + loadFlags = flags; + } + + + // Variable get/set methods + + /** + * This method sets the base URL name for data files associated with + * the file. The baseUrl should be null by default, which is an indicator + * to the loader that it should look for any associated files starting + * from the same place as the URL passed into the load(URL) method. + * Note: Users of setBaseUrl() would then use load(URL) + * as opposed to load(String). + */ + public void setBaseUrl(URL url) { + baseUrl = url; + } + + /** + * This method sets the base path name for data files associated with + * the file. The basePath should be null by default, which is an indicator + * to the loader that it should look for any associated files starting + * from the same directory as the file passed into the load(String) + * method. + * Note: Users of setBasePath() would then use load(String) + * as opposed to load(URL). + */ + public void setBasePath(String pathName) { + basePath = pathName; + } + + /** + * Returns the current base URL setting. + */ + public URL getBaseUrl() { + return baseUrl; + } + + /** + * Returns the current base path setting. + */ + public String getBasePath() { + return basePath; + } + + /** + * This method sets the load flags for the file. The flags should + * equal 0 by default (which tells the loader to only load geometry). + */ + public void setFlags(int flags) { + loadFlags = flags; + } + + /** + * Returns the current loading flags setting. + */ + public int getFlags() { + return loadFlags; + } + +} + + + + + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/ParsingErrorException.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/ParsingErrorException.java new file mode 100644 index 0000000..c456aaa --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/ParsingErrorException.java @@ -0,0 +1,62 @@ +/* + * $RCSfile: ParsingErrorException.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:06 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders; + + +/** + * Exception used to indicate that the loader encountered + * a problem parsing the specified file. + */ +public class ParsingErrorException extends RuntimeException { + + public ParsingErrorException() { + super(); + } + + public ParsingErrorException(String s) { + super(s); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/Scene.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/Scene.java new file mode 100644 index 0000000..0c3e967 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/Scene.java @@ -0,0 +1,148 @@ +/* + * $RCSfile: Scene.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:06 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders; + +import java.util.Hashtable; + +import javax.media.j3d.Behavior; +import javax.media.j3d.BranchGroup; +import javax.media.j3d.TransformGroup; +import javax.media.j3d.Light; +import javax.media.j3d.Background; +import javax.media.j3d.Fog; +import javax.media.j3d.Sound; + + +/** + * The Scene interface is a set of methods used to extract + * Java 3D scene graph information from a file loader utility. + * The interface is used to give loaders of various + * file formats a common public interface. + */ +public interface Scene { + + + /** + * This method returns the BranchGroup containing the overall + * scene loaded by the loader. All enabled items will be loaded + * into this scene except for Behaviors (the Behavior group must be + * retrieved separately so that users can choose whether and when + * to activate behaviors). + */ + public BranchGroup getSceneGroup(); + + /** + * This method returns an array of all View Groups defined in the file. + * Each View Group is a TransformGroup that is already placed within + * the scene that is returned in the getSceneGroup() call. This + * TransformGroup holds the position/orientation of the view + * as defined by the file. A user might request these references to + * the groups in order to look at the data stored there or + * to place ViewPlatforms within these groups and allow the + * View to activate these ViewPlatforms so that the user would + * see the scene from the viewpoints defined in the file. + */ + public TransformGroup[] getViewGroups(); + + /** + * This method returns an array of floats with the horizontal field + * of view. The entries in the array will correspond to those in the + * array returned by the method getViewGroups. The entries from these + * two arrays together provide all the information needed to recreate + * the viewing parameters associated with a scene graph. + */ + public float[] getHorizontalFOVs(); + + /** + * This method returns an array of all Lights defined in the file. + * If no lights are defined, null is returned. + */ + public Light[] getLightNodes(); + + /** + * This method returns a Hashtable which contains a list of all named + * objects in the file and their associated scene graph objects. The + * naming scheme for file objects is file-type dependent, but may include + * such names as the DEF names of Vrml or filenames of objects (as + * in Lightwave 3D). If no named objects are defined, null is returned. + */ + public Hashtable getNamedObjects(); + + /** + * This method returns an array of all Background nodes defined in the + * file. IF no Background nodes are defined, null is returned. + */ + public Background[] getBackgroundNodes(); + + /** + * This method returns an array of all Fog nodes defined in the + * file. If no fog nodes are defined, null is returned. + */ + public Fog[] getFogNodes(); + + /** + * This method returns an array of all the behavior nodes + * in the scene. If no Behavior nodes are defined, null is returned. + */ + public Behavior[] getBehaviorNodes(); + + /** + * This method returns an array of all of the Sound nodes defined + * in the file. If no Sound nodes are defined, null is returned. + */ + public Sound[] getSoundNodes(); + + /** + * This method returns the text description of the file. If no + * such description exists, this method should return null. + */ + public String getDescription(); + +} + + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/SceneBase.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/SceneBase.java new file mode 100644 index 0000000..518091f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/SceneBase.java @@ -0,0 +1,311 @@ +/* + * $RCSfile: SceneBase.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:06 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders; + +import java.lang.Float; + +import java.util.Hashtable; +import java.util.Vector; +import java.util.Enumeration; + +import javax.media.j3d.Behavior; +import javax.media.j3d.BranchGroup; +import javax.media.j3d.TransformGroup; +import javax.media.j3d.Light; +import javax.media.j3d.Background; +import javax.media.j3d.Fog; +import javax.media.j3d.Sound; + + +/** + * This class implements the Scene interface and extends it to incorporate + * utilities that could be used by loaders. There should be little need + * for future loaders to subclass this, or to implement Scene directly, + * as the functionality of a SceneBase is fairly straightforward. This + * class is responsible for both the storage and retrieval of data from + * the Scene. The storage methods (used only by Loader writers) are all + * of the add* routines. The retrieval methods (used primarily by Loader + * users) are all of the get* routines. + */ +public class SceneBase implements Scene { + + BranchGroup sceneGroup = null; + BranchGroup behaviorGroup = null; + Hashtable namedObjects = new Hashtable(); + String description = null; + + Vector viewVector = new Vector(); + Vector hfovVector = new Vector(); + Vector behaviorVector = new Vector(); + Vector lightVector = new Vector(); + Vector fogVector = new Vector(); + Vector backgroundVector = new Vector(); + Vector soundVector = new Vector(); + + // Add methods + + /** + * Sets the sceneGroup to be the group that is passed in. + */ + public void setSceneGroup(BranchGroup scene) { + sceneGroup = scene; + } + + /** + * Adds the given group to the list of view groups. + */ + public void addViewGroup(TransformGroup tg) { + viewVector.addElement(tg); + } + + /** + * Adds the given field of view value to the list of field of view values. + */ + public void addHorizontalFOV(float hfov) { + hfovVector.addElement(new Float(hfov)); + } + + /** + * Adds the given behavior to a list of behaviors + */ + public void addBehaviorNode(Behavior b) { + behaviorVector.addElement(b); + } + + /** + * Adds the given Light node to the list of lights. + */ + public void addLightNode(Light light) { + lightVector.addElement(light); + } + + /** + * Adds the given Background node to the list of backgrounds. + */ + public void addBackgroundNode(Background background) { + backgroundVector.addElement(background); + } + + /** + * Adds the given Sound node to the list of sounds. + */ + public void addSoundNode(Sound sound) { + soundVector.addElement(sound); + } + + /** + * Adds the given Fog node to the list of fog nodes. + */ + public void addFogNode(Fog fog) { + fogVector.addElement(fog); + } + + /** + * Sets the text description of the scene to the passed in String. + */ + public void addDescription(String descriptionString) { + description = descriptionString; + } + + /** + * Adds the given String/Object pair to the table of named objects. + */ + public void addNamedObject(String name, Object object) { + if (namedObjects.get(name) == null) + namedObjects.put(name, object); + else { + // key already exists - append a unique integer to end of name + int nameIndex = 1; + boolean done = false; + while (!done) { + // Iterate starting from "[1]" until we find a unique key + String tempName = name + "[" + nameIndex + "]"; + if (namedObjects.get(tempName) == null) { + namedObjects.put(tempName, object); + done = true; + } + nameIndex++; + } + } + } + + /** + * This method returns the BranchGroup containing the overall + * scene loaded by the loader. + */ + public BranchGroup getSceneGroup() { + return sceneGroup; + } + + + /** + * This method returns an array of all View Groups defined in the file. + * A View Group is defined as a TransformGroup which contains a + * ViewPlatform. The TransformGroup holds the position/orientation + * information for the given ViewPlatform and the ViewPlatform + * holds an view-specific information, such as Field of View. + */ + public TransformGroup[] getViewGroups() { + if (viewVector.isEmpty()) + return null; + TransformGroup[] viewGroups = new TransformGroup[viewVector.size()]; + viewVector.copyInto(viewGroups); + return viewGroups; + } + + /** + * This method returns an array of floats that contains the horizontal + * field of view values for each corresponding entry in the array of + * view groups returned by the method getViewGroups. + */ + public float[] getHorizontalFOVs() { + if (hfovVector.isEmpty()) + return null; + + int arraySize = hfovVector.size(); + float[] hfovs = new float[arraySize]; + Float[] tmpFovs = new Float[hfovVector.size()]; + hfovVector.copyInto(tmpFovs); + + // copy to array of floats and delete Floats + for (int i=0; i 0) { + System.out.print(theOutput); + } + } + + void println(int outputType, String theOutput) { + if ((outputType & validOutput) > 0) + System.out.println(theOutput); + } + +} + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/EnvelopeHandler.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/EnvelopeHandler.java new file mode 100644 index 0000000..1b378a1 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/EnvelopeHandler.java @@ -0,0 +1,133 @@ +/* + * $RCSfile: EnvelopeHandler.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:06 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.io.StreamTokenizer; +import java.io.IOException; +import java.lang.reflect.Constructor; +import com.sun.j3d.loaders.ParsingErrorException; +import java.lang.ClassNotFoundException; +import java.lang.InstantiationException; +import java.lang.IllegalAccessException; +import java.lang.reflect.InvocationTargetException; + + +/** + * This class is used in implementing Envelope objects (of which there + * is currently only one - LightIntensity). + * The class is called whenever the parser has encountered + * a token which could have an envelope description. If the + * token simply has a numeric value, this value is stored. + * If, instead, there is an envelope, then the class creates + * the envelope class and parses that information. + */ + +class EnvelopeHandler extends TextfileParser { + + float theValue = 0; + boolean hasValue = false; + boolean hasEnvelope = true; + LwsEnvelope theEnvelope = null; + + /** + * Constructor: This constructor is used if there is no existing + * implementation for this type of envelope. The real constructor + * is called with the generic LwsEnvelope class name, which will + * allow s to parse and ignore the envelope data + */ + EnvelopeHandler(StreamTokenizer st, + int totalFrames, float totalTime) { + this(st, totalFrames, totalTime, + "com.sun.j3d.utils.loaders.lw3d.LwsEnvelope"); + } + + /** + * Constructor: This constructor is called with the name of a class + * that can handle the encountered envelope. This is done so that this + * EnvelopeHandler class can generically call the given class to handle + * the envelope, whether it results in parsing/ignoring the data or + * in actually using the data + */ + EnvelopeHandler(StreamTokenizer st, + int totalFrames, + float totalTime, + String envClassName) throws ParsingErrorException { + try { + theValue = (float)getNumber(st); + hasValue = true; + } + catch (NumberFormatException e) { + if (st.ttype == '(') { + st.pushBack(); + // This code creates a new instance for the given class name + try { + Class envClass = Class.forName(envClassName); + Constructor constructors[] = envClass.getConstructors(); + Constructor con = constructors[0]; + Object args[] = new Object[3]; + args[0] = (Object)st; + args[1] = (Object)(new Integer(totalFrames)); + args[2] = (Object)(new Float(totalTime)); + try { + theEnvelope = (LwsEnvelope)con.newInstance(args); + hasEnvelope = true; + } + catch (InstantiationException e3) { + // Ignore + } + catch (IllegalAccessException e3) { + // Ignore + } + catch (InvocationTargetException e3) { + // Ignore + } + } + catch (ClassNotFoundException e2) { + // Ignore + } + } + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/FloatValueInterpolator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/FloatValueInterpolator.java new file mode 100644 index 0000000..5c70311 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/FloatValueInterpolator.java @@ -0,0 +1,171 @@ +/* + * $RCSfile: FloatValueInterpolator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:07 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import javax.vecmath.*; +import java.util.BitSet; +import java.util.Enumeration; + +import javax.media.j3d.Alpha; +import javax.media.j3d.Node; +import javax.media.j3d.NodeReferenceTable; +import javax.media.j3d.SceneGraphObject; +import javax.media.j3d.Interpolator; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * This class acts as an interpolator between values specified in a + * floating point array, based on knot values (keyframes) specified in a + * knots array. + */ +abstract class FloatValueInterpolator extends Interpolator { + + private float knots[]; + private int knotsLength; + protected int currentKnotIndex; + protected float currentInterpolationRatio; + protected float values[]; + protected float currentValue; + + /** + * Constructs a new FloatValueInterpolator object. + * @param alpha the alpha object for this interpolator + * @param knots an array of knot values that specify a spline + */ + FloatValueInterpolator(Alpha alpha, float k[], float v[]) { + + super(alpha); + + // Check that first knot = 0.0f + knotsLength = k.length; + if (k[0] < -0.0001 || k[0] > 0.0001) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("FloatValueInterpolator0")); + } + + // Check that last knot = 1.0f + if ((k[knotsLength-1] - 1.0f) < -0.0001 || + (k[knotsLength-1] - 1.0f) > 0.0001) { + + throw new IllegalArgumentException(J3dUtilsI18N.getString("FloatValueInterpolator1")); + } + + // Check to see that knots are in ascending order and copy them + this.knots = new float[knotsLength]; + for (int i = 0; i < knotsLength; i++) { + if ((i > 0) && (k[i] < k[i-1])) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("FloatValueInterpolator2")); + } + this.knots[i] = k[i]; + } + + // check to see that we have the same number of values as knots + if (knotsLength != v.length) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("FloatValueInterpolator3")); + } + + // copy the values + this.values = new float[knotsLength]; + for(int i = 0; i < knotsLength; i++) { + this.values[i] = v[i]; + } + + } + + /** + * This method sets the value at the specified index for + * this interpolator. + * @param index the index to be changed + * @param position the new value at index + */ + void setValue(int index, float value) { + this.values[index] = value; + } + + /** + * This method retrieves the value at the specified index. + * @param index the index of the value requested + * @return the interpolator's value at the index + */ + float getValue(int index) { + return this.values[index]; + } + + /** + * This method computes the bounding knot indices and interpolation value + * "currentValue" given the current value of alpha, the knots[] array and + * the array of values. + * If the index is 0 and there will be no interpolation, both the + * index variable and the interpolation variable are set to 0. + * Otherwise, currentKnotIndex is set to the lower index of the + * two bounding knot points and the currentInterpolationRatio + * variable is set to the ratio of the alpha value between these + * two bounding knot points. + */ + protected void computePathInterpolation() { + float alphaValue = (this.getAlpha()).value(); + + for (int i = 0; i < knotsLength; i++) { + if ((i == 0 && alphaValue <= knots[i]) || + (i > 0 && alphaValue >= knots[i-1] && alphaValue <= knots[i])) { + + if (i==0) { + currentInterpolationRatio = 0f; + currentKnotIndex = 0; + currentValue = values[0]; + } + else { + currentInterpolationRatio = + (alphaValue - knots[i-1])/(knots[i] - knots[i-1]); + currentKnotIndex = i - 1; + currentValue = values[i-1] + + currentInterpolationRatio * (values[i] - values[i-1]); + } + break; + } + } + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ImageScaler.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ImageScaler.java new file mode 100644 index 0000000..e511938 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ImageScaler.java @@ -0,0 +1,148 @@ +/* + * $RCSfile: ImageScaler.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:07 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; + +/** + * This class resizes an image to be the nearest power of 2 wide and high. + * This facility now exists inside of the TextureLoader class, so + * ImageScaler should be eliminated at some point. + */ + +class ImageScaler { + + int origW, origH; + Image origImage; + + ImageScaler(Image image, int w, int h) { + origImage = image; + origW = w; + origH = h; + } + + ImageScaler(BufferedImage image) { + origImage = image; + origW = image.getWidth(); + origH = image.getHeight(); + } + + /** + * Utility method to return closes poser of 2 to the given integer + */ + int getClosestPowerOf2(int value) { + + if (value < 1) + return value; + + int powerValue = 1; + for (int i = 1; i < 20; ++i) { + powerValue *= 2; + if (value < powerValue) { + // Found max bound of power, determine which is closest + int minBound = powerValue/2; + if ((powerValue - value) > + (value - minBound)) + return minBound; + else + return powerValue; + } + } + // shouldn't reach here... + return 1; + } + + /** + * Returns an Image that has been scaled from the original image to + * the closest power of 2 + */ + Image getScaledImage() { + int newWidth = getClosestPowerOf2(origW); + int newHeight = getClosestPowerOf2(origH); + + // If the image is already a power of 2 wide/tall, no need to scale + if (newWidth == origW && + newHeight == origH) + return origImage; + + Image scaledImage = null; + + if (origImage instanceof BufferedImage) { + // If BufferedImage, then we have some work to do + BufferedImage origImageB = (BufferedImage)origImage; + scaledImage = + new BufferedImage(newWidth, + newHeight, + origImageB.getType()); + BufferedImage scaledImageB = (BufferedImage)scaledImage; + float widthScale = (float)origW/(float)newWidth; + float heightScale = (float)origH/(float)newHeight; + int origPixels[] = ((DataBufferInt)origImageB.getRaster().getDataBuffer()).getData(); + int newPixels[] = ((DataBufferInt)scaledImageB.getRaster().getDataBuffer()).getData(); + for (int row = 0; row < newHeight; ++row) { + for (int column = 0; column < newWidth; ++column) { + int oldRow = Math.min(origH-1, + (int)((float)(row)* + heightScale + .5f)); + int oldColumn = + Math.min(origW-1, + (int)((float)column*widthScale + .5f)); + newPixels[row*newWidth + column] = + origPixels[oldRow*origW + oldColumn]; + } + } + } + else { + // If regular Image, then the work is done for us + scaledImage = origImage.getScaledInstance(newWidth, + newHeight, + Image.SCALE_DEFAULT); + } + return scaledImage; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/J3dLwoParser.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/J3dLwoParser.java new file mode 100644 index 0000000..433d6d8 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/J3dLwoParser.java @@ -0,0 +1,601 @@ +/* + * $RCSfile: J3dLwoParser.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:07 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.awt.Component; +import java.awt.Image; +import java.util.Enumeration; +import java.util.Vector; +import com.sun.j3d.utils.geometry.GeometryInfo; +import com.sun.j3d.utils.geometry.NormalGenerator; +import com.sun.j3d.utils.geometry.Stripifier; +import com.sun.j3d.utils.image.TextureLoader; +import com.sun.j3d.loaders.IncorrectFormatException; +import java.io.FileNotFoundException; + +import javax.media.j3d.*; +import javax.vecmath.*; + +import java.net.*; + + +/** + * This class is responsible for turning Lightwave geometry data into + * Java3D geometry. It is a subclass of LwoObject and calls that + * superclass when first instantiated to parse the binary file and turn it + * into intermediate data structures. J3dLwoParser then goes through + * those data structures and turns them into Java3D objects. For each + * ShapeHolder object created by the parent class, this class retrieves + * the geometry data and associated surface data, creates the + * appropriate Geometry object (usually IndexedTriangleFanArray, + * unless the object is points or lines), including calculating normals for + * the polygons and sets up the Appearance according to the surface + * parameters (including calculating texture coordinates if necessary). + */ + +class J3dLwoParser extends LwoParser { + + float normalCoordsArray[]; + int normalIndicesArray[]; + Shape3D objectShape; + Color3f color, diffuseColor, specularColor, emissiveColor; + float shininess; + Vector objectShapeList = new Vector(); + + /** + * Constructor: Calls LwoObject to parse file and create data structures + */ + J3dLwoParser(String fileName, + int debugVals) throws FileNotFoundException { + super(fileName, debugVals); + } + + J3dLwoParser(URL url, int debugVals) + throws FileNotFoundException { + super(url, debugVals); + } + + void getSurf(int length) throws FileNotFoundException { + super.getSurf(length); + } + + + /** + * Turns LwoObject's data structures (created from the binary geometry + * file) into Java3d objects + */ + void createJava3dGeometry() throws IncorrectFormatException { + + GeometryArray object; + LwoTexture texture; + + for (Enumeration e = shapeList.elements(); + e.hasMoreElements() ;) { + int vertexFormat = javax.media.j3d.GeometryArray.COORDINATES; + ShapeHolder shape = (ShapeHolder)e.nextElement(); + debugOutputLn(LINE_TRACE, "about to create Arrays for Shape"); + debugOutputLn(VALUES, "shape = " + shape); + shape.createArrays(true); + int vertexCount = shape.coordsArray.length/3; + int indexCount = 0; + if (shape.facetIndices != null) + indexCount = shape.facetIndices.length; + debugOutputLn(VALUES, "numSurf = " + shape.numSurf); + // Find the right surface. Note: surfaces are indexed by + // name. So take this surf number, look up the name of that + // surface in surfaceNameList, then take that name and + // find the matching LwoSurface + String surfName = + (String)surfNameList.elementAt(shape.numSurf - 1); + LwoSurface surf = null; + for (int surfNum = 0; + surfNum < surfaceList.size(); + ++surfNum) { + LwoSurface tempSurf = + (LwoSurface)surfaceList.elementAt(surfNum); + String tempSurfName = tempSurf.surfName; + if (surfName.equals(tempSurfName)) { + surf = tempSurf; + break; + } + } + if (surf == null) { + throw new IncorrectFormatException( + "bad surf for surfnum/name = " + shape.numSurf + ", " + + surfName); + } + debugOutputLn(VALUES, "surf = " + surf); + + // Get the LwoTexture object (if any) for the surface + texture = surf.getTexture(); + + Appearance appearance = new Appearance(); + if (shape.facetSizes[0] == 1) { + // This case happens if the objects are points + // Note that points are colored, not lit + object = new + javax.media.j3d.PointArray(vertexCount, vertexFormat); + object.setCoordinates(0, shape.coordsArray); + ColoringAttributes colorAtt = + new ColoringAttributes(surf.getColor(), + ColoringAttributes.FASTEST); + PointAttributes pointStyle = new PointAttributes(); + pointStyle.setPointSize(1); + + appearance.setColoringAttributes(colorAtt); + appearance.setPointAttributes(pointStyle); + } + else if (shape.facetSizes[0] == 2) { + // This case happens if the objects are lines + // Note that lines are colored, not lit + debugOutputLn(LINE_TRACE, "Creating IndexedLineArray"); + object = new javax.media.j3d.LineArray(vertexCount, + vertexFormat); + object.setCoordinates(0, shape.coordsArray); + ColoringAttributes colorAtt = + new ColoringAttributes(surf.getColor(), + ColoringAttributes.FASTEST); + appearance.setColoringAttributes(colorAtt); + } + else { + // This is the case for any polygonal objects + debugOutputLn(LINE_TRACE, "Creating IndexedTriFanArray"); + // create triFanArray + vertexFormat |= javax.media.j3d.GeometryArray.NORMALS; + + debugOutputLn(LINE_TRACE, "about to process vertices/indices, facetIndices = " + + shape.facetIndices); + if (shape.facetIndices != null) { + float[] textureCoords = null; + int[] textureIndices = null; + + debugOutputLn(LINE_TRACE, "setting vertexCount, normind = " + shape.normalIndices); + // If these are null we're going direct (non-indexed) + debugOutputLn(LINE_TRACE, "vtxcount, format, indcount = " + + vertexCount + ", " + vertexFormat + + ", " + indexCount); + if (texture != null) { + // There's a texture here - need to create the appropriate arrays + // and calculate texture coordinates for the object + vertexFormat |= GeometryArray.TEXTURE_COORDINATE_2; + textureCoords = new float[vertexCount * 2]; + textureIndices = new int[shape.facetIndices.length]; + calculateTextureCoords(texture, shape.coordsArray, + shape.facetIndices, + textureCoords, textureIndices); + debugOutputLn(LINE_TRACE, "textureCoords:"); + debugOutputLn(LINE_TRACE, "texture Coords, Indices.length = " + textureCoords.length + ", " + textureIndices.length); + } + debugOutputLn(LINE_TRACE, "about to create GeometryInfo"); + + // Use the GeometryInfo utility to calculate smooth normals + GeometryInfo gi = + new GeometryInfo(GeometryInfo.TRIANGLE_FAN_ARRAY); + gi.setCoordinates(shape.coordsArray); + gi.setCoordinateIndices(shape.facetIndices); + gi.setStripCounts(shape.facetSizes); + if (texture != null) { + gi.setTextureCoordinateParams(1, 2); + gi.setTextureCoordinates(0, textureCoords); + gi.setTextureCoordinateIndices(0, textureIndices); + } + gi.recomputeIndices(); + NormalGenerator ng = + new NormalGenerator(surf.getCreaseAngle()); + ng.generateNormals(gi); + Stripifier st = new Stripifier(); + st.stripify(gi); + object = gi.getGeometryArray(true, true, false); + debugOutputLn(LINE_TRACE, "done."); + } + else { + // This case is called if LwoObject did not create facet + // indices. This code is not currently used because facet + // indices are always created for polygonal objects + debugOutputLn(LINE_TRACE, + "about to create trifanarray with " + + "vertexCount, facetSizes.len = " + + vertexCount + ", " + + shape.facetSizes.length); + object = new + javax.media.j3d.TriangleFanArray(vertexCount, + vertexFormat, + shape.facetSizes); + object.setCoordinates(0, shape.coordsArray); + object.setNormals(0, shape.normalCoords); + debugOutputLn(VALUES, "passed in normalCoords, length = " + + shape.normalCoords.length); + } + debugOutputLn(LINE_TRACE, "created fan array"); + + // Setup Appearance given the surface parameters + Material material = new Material(surf.getColor(), + surf.getEmissiveColor(), + surf.getDiffuseColor(), + surf.getSpecularColor(), + surf.getShininess()); + material.setLightingEnable(true); + appearance.setMaterial(material); + if (surf.getTransparency() != 0f) { + TransparencyAttributes ta = new TransparencyAttributes(); + ta.setTransparency(surf.getTransparency()); + ta.setTransparencyMode(ta.BLENDED); + appearance.setTransparencyAttributes(ta); + } + if (texture != null) { + debugOutputLn(LINE_TRACE, "texture != null, enable texturing"); + Texture tex = texture.getTexture(); + tex.setEnable(true); + appearance.setTexture(tex); + TextureAttributes ta = new TextureAttributes(); + if (texture.getType().equals("DTEX")) + ta.setTextureMode(TextureAttributes.MODULATE); + else if (texture.getType().equals("CTEX")) + ta.setTextureMode(TextureAttributes.DECAL); + appearance.setTextureAttributes(ta); + } + else { + debugOutputLn(LINE_TRACE, "texture == null, no texture to use"); + } + } + debugOutputLn(LINE_TRACE, "done creating object"); + + // This does gc + shape.nullify(); + + objectShape = new Shape3D(object); + + // Combine the appearance and geometry + objectShape.setAppearance(appearance); + objectShapeList.addElement(objectShape); + } + } + + /** + * Calculate texture coordinates for the geometry given the texture + * map properties specified in the LwoTexture object + */ + void calculateTextureCoords(LwoTexture texture, + float verts[], int indices[], + float[] textureCoords, int[] textureIndices) { + + /* + the actual math in these coord calculations comes directly from + Newtek - they posted sample code to help compute tex coords based + on the type of mapping: + + Here are some simplified code fragments showing how LightWave + computes UV coordinates from X, Y, and Z. If the resulting + UV coordinates are not in the range from 0 to 1, the + appropriate integer should be added to them to bring them into + that range (the fract function should have accomplished + this by subtracting the floor of each number from itself). + Then they can be multiplied by the width and height (in pixels) + of an image map to determine which pixel to look up. The + texture size, center, and tiling parameters are taken right + off the texture control panel. + + + x -= xTextureCenter; + y -= yTextureCenter; + z -= zTextureCenter; + if (textureType == TT_PLANAR) { + s = (textureAxis == TA_X) ? z / zTextureSize + .5 : + x / xTextureSize + .5; + t = (textureAxis == TA_Y) ? -z / zTextureSize + .5 : + -y / yTextureSize + .5; + u = fract(s); + v = fract(t); + } + else if (type == TT_CYLINDRICAL) { + if (textureAxis == TA_X) { + xyztoh(z,x,-y,&lon); + t = -x / xTextureSize + .5; + } + else if (textureAxis == TA_Y) { + xyztoh(-x,y,z,&lon); + t = -y / yTextureSize + .5; + } + else { + xyztoh(-x,z,-y,&lon); + t = -z / zTextureSize + .5; + } + lon = 1.0 - lon / TWOPI; + if (widthTiling != 1.0) + lon = fract(lon) * widthTiling; + u = fract(lon); + v = fract(t); + } + else if (type == TT_SPHERICAL) { + if (textureAxis == TA_X) + xyztohp(z,x,-y,&lon,&lat); + else if (textureAxis == TA_Y) + xyztohp(-x,y,z,&lon,&lat); + else + xyztohp(-x,z,-y,&lon,&lat); + lon = 1.0 - lon / TWOPI; + lat = .5 - lat / PI; + if (widthTiling != 1.0) + lon = fract(lon) * widthTiling; + if (heightTiling != 1.0) + lat = fract(lat) * heightTiling; + u = fract(lon); + v = fract(lat); + } + + support functions: + + void xyztoh(float x,float y,float z,float *h) + { + if (x == 0.0 && z == 0.0) + *h = 0.0; + else { + if (z == 0.0) + *h = (x < 0.0) ? HALFPI : -HALFPI; + else if (z < 0.0) + *h = -atan(x / z) + PI; + else + *h = -atan(x / z); + } + } + + void xyztohp(float x,float y,float z,float *h,float *p) + { + if (x == 0.0 && z == 0.0) { + *h = 0.0; + if (y != 0.0) + *p = (y < 0.0) ? -HALFPI : HALFPI; + else + *p = 0.0; + } + else { + if (z == 0.0) + *h = (x < 0.0) ? HALFPI : -HALFPI; + else if (z < 0.0) + *h = -atan(x / z) + PI; + else + *h = -atan(x / z); + x = sqrt(x * x + z * z); + if (x == 0.0) + *p = (y < 0.0) ? -HALFPI : HALFPI; + else + *p = atan(y / x); + } + } + */ + + debugOutputLn(TRACE, "calculateTextureCoords()"); + // Compute texture coord stuff + float sx = 0, sz = 0, ty = 0, tz = 0; + double s, t; + int textureAxis = texture.getTextureAxis(); + Vector3f textureSize = texture.getTextureSize(); + Vector3f textureCenter = texture.getTextureCenter(); + + String mappingType = texture.getMappingType(); + if (mappingType.startsWith("Cylindrical")) + calculateCylindricalTextureCoords(textureAxis, textureSize, + textureCenter, textureCoords, + textureIndices, + verts, indices); + else if (mappingType.startsWith("Spherical")) + calculateSphericalTextureCoords(textureAxis, + textureCenter, textureCoords, + textureIndices, + verts, indices); + else if (mappingType.startsWith("Planar")) + calculatePlanarTextureCoords(textureAxis, textureSize, + textureCenter, textureCoords, + textureIndices, + verts, indices); + + } + + /** See the comments in calculateTextureCoordinates*/ + double xyztoh(float x,float y,float z) { + if (x == 0.0 && z == 0.0) + return 0.0; + else { + if (z == 0.0) + return (x < 0.0) ? Math.PI/2.0 : -Math.PI/2.0; + else if (z < 0.0) + return -Math.atan(x / z) + Math.PI; + else + return -Math.atan(x / z); + } + } + + /** See the comments in calculateTextureCoordinates*/ + double xyztop(float x,float y,float z) { + double p; + + if (x == 0.0 && z == 0.0) { + if (y != 0.0) + p = (y < 0.0) ? -Math.PI/2 : Math.PI/2; + else + p = 0.0; + } + else { + x = (float)Math.sqrt(x * x + z * z); + if (x == 0.0) + p = (y < 0.0) ? -Math.PI/2 : Math.PI/2; + else + p = Math.atan(y / x); + } + return p; + } + + + /** See the comments in calculateTextureCoordinates*/ + void calculateSphericalTextureCoords(int textureAxis, + Vector3f textureCenter, + float textureCoords[], + int textureIndices[], + float verts[], int indices[]) { + debugOutputLn(TRACE, "calculateSphericalTextureCoords"); + double s, t; + + + for (int i = 0; i < indices.length; ++i) { + float x = verts[3*indices[i]] - textureCenter.x; + float y = verts[3*indices[i]+1] - textureCenter.y; + float z = -(verts[3*indices[i]+2] + textureCenter.z); + if (textureAxis == 1){ // X Axis + s = xyztoh(z, x, -y); + t = xyztop(z,x,-y); + } + else if (textureAxis == 2) { // Y Axis + s = xyztoh(-x,y,z); + t = xyztop(-x,y,z); + } + else { // Z Axis + s = xyztoh(-x,z,-y); + t = xyztop(-x,z,-y); + } + s = 1.0 - s / (2*Math.PI); + t = -(.5 - t / Math.PI); + textureCoords[indices[i]*2] = (float)s; + textureCoords[indices[i]*2 + 1] = (float)t; + textureIndices[i] = indices[i]; + } + } + + /** See the comments in calculateTextureCoordinates*/ + void calculateCylindricalTextureCoords(int textureAxis, + Vector3f textureSize, + Vector3f textureCenter, + float textureCoords[], + int textureIndices[], + float verts[], int indices[]) { + debugOutputLn(TRACE, "calculateCylindricalTextureCoords"); + debugOutputLn(VALUES, "axis, size, center, tc, ti, v, i = " + + textureAxis + ", " + + textureSize + ", " + + textureCenter + ", " + + textureCoords + ", " + + textureIndices + ", " + + verts + ", " + + indices); + double s, t; + + debugOutputLn(VALUES, "Cyl Texture Coords:"); + for (int i = 0; i < indices.length; ++i) { + float x = verts[3*indices[i]] - textureCenter.x; + float y = verts[3*indices[i]+1] - textureCenter.y; + float z = -(verts[3*indices[i]+2] + textureCenter.z); + // Negate z value because we invert geom z's to swap handedness + if (textureAxis == 1) { // X axis + s = xyztoh(z,x,-y); + t = x / textureSize.x + .5; + } + else if (textureAxis == 2) { // Y Axis + s = xyztoh(-x,y,z); + t = y / textureSize.y + .5; + } + else { + s = xyztoh(-x,z,-y); + t = z / textureSize.z + .5; + } + s = 1.0 - s / (2*Math.PI); + textureCoords[indices[i]*2] = (float)s; + textureCoords[indices[i]*2 + 1] = (float)t; + textureIndices[i] = indices[i]; + debugOutputLn(VALUES, "x, y, z = " + + x + ", " + y + ", " + z + " " + + "s, t = " + s + ", " + t); + } + } + + /** See the comments in calculateTextureCoordinates*/ + void calculatePlanarTextureCoords(int textureAxis, Vector3f textureSize, + Vector3f textureCenter, + float textureCoords[], + int textureIndices[], + float verts[], int indices[]) { + debugOutputLn(TRACE, "calculatePlanarTextureCoords"); + debugOutputLn(VALUES, "size, center, axis = " + + textureSize + textureCenter + ", " + textureAxis); + float sx = 0, sz = 0, ty = 0, tz = 0; + double s, t; + + if (textureAxis == 1) { // X Axis + sz = -1.0f / textureSize.z; // Negate because we negate z in geom + ty = 1.0f / textureSize.y; + } + else if (textureAxis == 2) { // Y Axis + sx = 1.0f / textureSize.x; + tz = -1.0f / textureSize.z; // Negate because we negate z in geom + } + else { // Z Axis + sx = 1.0f / textureSize.x; + ty = 1.0f / textureSize.y; + } + + debugOutputLn(VALUES, "Planar Texture Coords:"); + for (int i = 0; i < indices.length; ++i) { + float x = verts[3*indices[i]] - textureCenter.x; + float y = verts[3*indices[i]+1] - textureCenter.y; + float z = verts[3*indices[i]+2] + textureCenter.z; + s = x*sx + z*sz + .5; + t = y*ty + z*tz + .5; + textureCoords[indices[i]*2] = (float)s; + textureCoords[indices[i]*2 + 1] = (float)t; + textureIndices[i] = indices[i]; + debugOutputLn(VALUES, "x, y, z = " + + x + ", " + y + ", " + z + " " + + "s, t = " + s + ", " + t); + } + } + + + Shape3D getJava3dShape() { + return objectShape; + } + + Vector getJava3dShapeList() { + return objectShapeList; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LWOBFileReader.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LWOBFileReader.java new file mode 100644 index 0000000..8dc18be --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LWOBFileReader.java @@ -0,0 +1,266 @@ +/* + * $RCSfile: LWOBFileReader.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:07 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import com.sun.j3d.loaders.ParsingErrorException; + + +class LWOBFileReader extends BufferedInputStream { + + + + // Debugging constants + final static int TRACE = DebugOutput.TRACE; + final static int VALUES = DebugOutput.VALUES; + final static int MISC = DebugOutput.MISC; + final static int LINE_TRACE = DebugOutput.LINE_TRACE; + final static int NONE = DebugOutput.NONE; + final static int EXCEPTION = DebugOutput.EXCEPTION; + + protected DebugOutput debugPrinter; + + protected String theFilename; + + protected int marker; + + + + protected void debugOutputLn(int outputType, String theOutput) { + if (theOutput.equals("")) + debugPrinter.println(outputType, theOutput); + else + debugPrinter.println(outputType, + getClass().getName() + "::" + theOutput); + } // End of debugOutputLn + + + + // Return a string consisting of the next 4 bytes in the file + public String getToken() throws ParsingErrorException { + byte tokenBuffer[] = new byte[4]; + try { + int readResult = read(tokenBuffer, 0, 4); + if (readResult == -1) { + debugOutputLn(LINE_TRACE, "no token - returning null"); + return null; + } + return new String(tokenBuffer); + } + catch (IOException e) { + debugOutputLn(EXCEPTION, "getToken: " + e); + throw new ParsingErrorException(e.getMessage()); + } + } + + + + /** + * Skip ahead amount bytes in the file + */ + public void skipLength(int amount) throws ParsingErrorException { + try { + skip((long)amount); + marker += amount; + } + catch (IOException e) { + debugOutputLn(EXCEPTION, "skipLength: " + e); + throw new ParsingErrorException(e.getMessage()); + } + } + + + + /** + * Read four bytes from the file and return their integer value + */ + public int getInt() throws ParsingErrorException { + try { + int x = 0; + for (int i = 0 ; i < 4 ; i++) { + int readResult = read(); + if (readResult == -1) + throw new ParsingErrorException("Unexpected EOF"); + x = (x << 8) | readResult; + } + return x; + } + catch (IOException e) { + debugOutputLn(EXCEPTION, "getInt: " + e); + throw new ParsingErrorException(e.getMessage()); + } + } + + + + /** + * Read four bytes from the file and return their float value + */ + public float getFloat() throws ParsingErrorException { + return Float.intBitsToFloat(getInt()); + } // End of getFloat + + + + /** + * Returns the name of the file associated with this stream + */ + public String getFilename() { + return theFilename; + } // End of getFilename + + + + /** + * Returns a string read from the file. The string is assumed to + * end with '0'. + */ + public String getString() throws ParsingErrorException { + byte buf[] = new byte[512]; + try { + byte b; + int len = 0; + do { + b = (byte)read(); + buf[len++] = b; + } while (b != 0); + // Have to read an even number of bytes + if (len % 2 != 0) read(); + } + catch (IOException e) { + debugOutputLn(EXCEPTION, "getString: " + e); + throw new ParsingErrorException(e.getMessage()); + } + return new String(buf); + } // End of getString + + + + /** + * Reads an array of xyz values. + */ + public void getVerts(float ar[], int num) throws ParsingErrorException { + for (int i = 0 ; i < num ; i++) { + ar[i * 3 + 0] = getFloat(); + ar[i * 3 + 1] = getFloat(); + ar[i * 3 + 2] = -getFloat(); + } + } // End of getVerts + + + + /** + * Reads two bytes from the file and returns their integer value. + */ + public int getShortInt() throws ParsingErrorException { + int i = 0; + try { + i = read(); + i = (i << 8) | read(); + // Sign extension + if ((i & 0x8000) != 0) i |= 0xffff0000; + } + catch (IOException e) { + debugOutputLn(EXCEPTION, "getShortInt: " + e); + throw new ParsingErrorException(e.getMessage()); + } + return i; + } // End of getShortInt + + + + /** + * Returns the current position in the file + */ + public int getMarker() { + // protected field inherited from BufferedInputStream + return marker; + } // End of getMarker + + + + public int read() throws IOException { + marker++; + return super.read(); + } // End of read() + + + + public int read(byte[] buffer, int offset, int count) throws IOException { + int ret = super.read(buffer, offset, count); + if (ret != -1) marker += ret; + return ret; + } // End of read(byte[], int, int) + + + + /** + * Constructor. + */ + public LWOBFileReader(String filename) throws FileNotFoundException { + super(new FileInputStream(filename)); + + // Add constants on this line to get more debug output + debugPrinter = new DebugOutput(127); + + marker = 0; + } // End of constructor + + public LWOBFileReader(java.net.URL url) throws java.io.IOException { + super(url.openStream()); + + // add constants on this line to get more debug output + debugPrinter = new DebugOutput(127); + + marker = 0; + } + +} // End of file LWOBFileReader diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LightIntensityPathInterpolator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LightIntensityPathInterpolator.java new file mode 100644 index 0000000..cc11cbe --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LightIntensityPathInterpolator.java @@ -0,0 +1,101 @@ +/* + * $RCSfile: LightIntensityPathInterpolator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:07 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.util.*; + +import javax.media.j3d.Alpha; +import javax.media.j3d.Light; + +/** + * This Interpolator object modifies the intensity of a Light object + * according to the keyframes in a light intensity envelope + */ +class LightIntensityPathInterpolator extends FloatValueInterpolator { + + LwLightObject theLight; + + LightIntensityPathInterpolator(Alpha alpha, + float knots[], + float values[], + Object target) { + + super(alpha, knots, values); + theLight = (LwLightObject)target; + } + + /** + * This method is invoked by the behavior scheduler every frame. It maps + * the alpha value that corresponds to the current time into the + * appropriate light intensity for that time as obtained by interpolating + * between the light intensity values for each knot point that were passed + * to this class. + * @param criteria enumeration of criteria that have triggered this wakeup + */ + + public void processStimulus(Enumeration criteria) { + // Handle stimulus + + if (this.getAlpha() != null) { + + // Let FloatValueInterpolator calculate the correct + // interpolated value + computePathInterpolation(); + + // Set light intensity to the value calculated by + // FloatValueInterpolator + if (theLight != null) + theLight.setIntensity(currentValue); + + if ((this.getAlpha()).finished()) + return; + } + + wakeupOn(defaultWakeupCriterion); + + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/Lw3dLoader.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/Lw3dLoader.java new file mode 100644 index 0000000..06ffc2b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/Lw3dLoader.java @@ -0,0 +1,706 @@ +/* + * $RCSfile: Lw3dLoader.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:07 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + +import com.sun.j3d.loaders.*; +import java.awt.Component; +import java.io.*; +import java.util.Vector; +import java.util.Enumeration; +import java.net.URL; +import java.net.MalformedURLException; + +import javax.media.j3d.*; +import javax.vecmath.Color3f; +import javax.vecmath.Point3d; + + +/** + * This class implements the Loader API and allows users to load + * Lightwave 3D scene files. In order to load properly, the object + * files referred to in the scene files and the image files referred + * to by the object files must all be specified with path and filenames + * that are valid with respect to the directory in which the application + * is being executed. + */ + +public class Lw3dLoader extends TextfileParser implements Loader { + + Vector objectList; + Vector lightList; + BranchGroup sceneGroupNode; + Color3f ambientColor; + LwsCamera camera = null; + LwsFog fog = null; + LwsBackground background = null; + int loadFlags = 0; + int loadBehaviors = 0; + Vector sceneBehaviors; + SceneBase scene = null; + String basePath = null; + String internalBasePath = null; + URL baseUrl = null; + String internalBaseUrl = null; // store url base as String + static final int FILE_TYPE_NONE = 0; + static final int FILE_TYPE_URL = 1; + static final int FILE_TYPE_FILENAME = 2; + static final int FILE_TYPE_READER = 4; + int fileType = FILE_TYPE_NONE; + + /** + * Default constructor. Sets up default values for some variables. + */ + public Lw3dLoader() { + + ambientColor = new Color3f(0f, 0f, 0f); + objectList = new Vector(); + lightList = new Vector(); + debugPrinter.setValidOutput(0x0); + + } + + /** + * This constructor takes a flags word that specifies which types of + * scenefile items should be loaded into the scene. The possible + * values are specified in the com.sun.j3d.loaders.Loader class. + */ + public Lw3dLoader(int flags) { + + this(); + loadFlags = flags; + loadBehaviors = (loadFlags & Loader.LOAD_BEHAVIOR_NODES); + + } + + /** + * This method loads the named file and returns the Scene + * containing the scene. Any data files referenced by the Reader + * should be located in the same place as the named file; otherwise, + * users should specify an alternate base path with the setBaseUrl(URL) + * method. + */ + public Scene load(URL url) throws FileNotFoundException, + IncorrectFormatException, ParsingErrorException { + + fileType = FILE_TYPE_URL; + setInternalBaseUrl(url); + InputStreamReader reader; + try { + reader = new InputStreamReader( + new BufferedInputStream(url.openStream())); + } + catch (IOException e) { + throw new FileNotFoundException(e.getMessage()); + } + Scene returnScene = load(reader); + fileType = FILE_TYPE_NONE; + return returnScene; + } + + /** + * This method loads the named file and returns the Scene + * containing the scene. Any data files referenced by this + * file should be located in the same place as the named file; + * otherwise users should specify an alternate base path with + * the setBasePath(String) method. + */ + public Scene load(String fileName) throws FileNotFoundException, + IncorrectFormatException, ParsingErrorException { + + fileType = FILE_TYPE_FILENAME; + setInternalBasePath(fileName); + Reader reader = new BufferedReader(new FileReader(fileName)); + Scene returnScene = load(reader); + fileType = FILE_TYPE_NONE; + return returnScene; + } + + /** + * This method loads the Reader and returns the Scene + * containing the scene. Any data files referenced by the Reader should + * be located in the user's current working directory. + */ + public Scene load(Reader reader) throws FileNotFoundException, + IncorrectFormatException, ParsingErrorException { + + if (fileType == FILE_TYPE_NONE) + fileType = FILE_TYPE_READER; + StreamTokenizer tokenizer = new StreamTokenizer(reader); + setupTokenizer(tokenizer); + + getAndCheckString(tokenizer, "LWSC"); + getNumber(tokenizer); + getAndCheckString(tokenizer, "FirstFrame"); + int firstFrame = (int)getNumber(tokenizer); + getAndCheckString(tokenizer, "LastFrame"); + int finalFrame = (int)getNumber(tokenizer); + skipUntilString(tokenizer, "FramesPerSecond"); + double fps = getNumber(tokenizer); + float totalTime = (float)(finalFrame - firstFrame)/(float)fps; + boolean done = false; + while (!done) { + int token; + try { + token = tokenizer.nextToken(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + switch (tokenizer.ttype) { + case StreamTokenizer.TT_EOF: + done = true; + break; + case StreamTokenizer.TT_WORD: + debugOutputLn(VALUES, " String = " + tokenizer.sval); + if (tokenizer.sval.equals("AddNullObject")) { + LwsObject obj = + new LwsObject(tokenizer, false, + firstFrame, + finalFrame, totalTime, + this, + debugPrinter.getValidOutput()); + obj.createJava3dObject(null, loadBehaviors); + objectList.addElement(obj); + } + else if (tokenizer.sval.equals("LoadObject")) { + String filename = getString(tokenizer); + tokenizer.pushBack(); // push filename token back + debugOutputLn(TIME, "loading " + filename + " at " + + System.currentTimeMillis()); + LwsObject obj = new LwsObject(tokenizer, true, + firstFrame, + finalFrame, totalTime, + this, + debugPrinter.getValidOutput()); + debugOutputLn(TIME, "done loading at " + + System.currentTimeMillis()); + LwsObject cloneObject = null; + for (Enumeration e = objectList.elements() ; + e.hasMoreElements() ;) { + LwsObject tmpObj = (LwsObject)e.nextElement(); + if (tmpObj.fileName != null && + tmpObj.fileName.equals(filename)) { + cloneObject = tmpObj; + break; + } + } + obj.createJava3dObject(cloneObject, loadBehaviors); + objectList.addElement(obj); + } + else if (tokenizer.sval.equals("AmbientColor")) { + ambientColor.x = (float)getNumber(tokenizer)/255f; + ambientColor.y = (float)getNumber(tokenizer)/255f; + ambientColor.z = (float)getNumber(tokenizer)/255f; + } + else if (tokenizer.sval.equals("AmbIntensity")) { + // TODO: must be able to handle envelopes here + float intensity = (float)getNumber(tokenizer); + ambientColor.x *= intensity; + ambientColor.y *= intensity; + ambientColor.z *= intensity; + } + else if (tokenizer.sval.equals("AddLight")) { + LwsLight light = + new LwsLight(tokenizer, + finalFrame, totalTime, + debugPrinter.getValidOutput()); + light.createJava3dObject(loadBehaviors); + lightList.addElement(light); + } + else if (tokenizer.sval.equals("ShowCamera")) { + camera = new LwsCamera(tokenizer, firstFrame, + finalFrame, totalTime, + debugPrinter.getValidOutput()); + camera.createJava3dObject(loadBehaviors); + } + else if (tokenizer.sval.equals("FogType")) { + int fogType = (int)getNumber(tokenizer); + if (fogType != 0) { + fog = new LwsFog(tokenizer, + debugPrinter.getValidOutput()); + fog.createJava3dObject(); + } + } + else if (tokenizer.sval.equals("SolidBackdrop")) { + background = + new LwsBackground(tokenizer, + debugPrinter.getValidOutput()); + background.createJava3dObject(); + } + break; + default: + debugOutputLn(VALUES, " Unknown ttype, token = " + + tokenizer.ttype + ", " + token); + break; + } + } + + // Set up scene groups and parent objects appropriately + sceneGroupNode = new BranchGroup(); + sceneBehaviors = new Vector(); + parentObjects(); + constructScene(); + + return scene; + + } + + + /** + * This method creates the Scene (actually SceneBase) data structure + * and adds all appropriate items to it. This is the data structure + * that the user will get back from the load() call and inquire to + * get data from the scene. + */ + void constructScene() { + + // Construct Scene data structure + scene = new SceneBase(); + + if ((loadFlags & Loader.LOAD_LIGHT_NODES) != 0) { + addLights(); + addAmbient(); + } + + if ((loadFlags & Loader.LOAD_FOG_NODES) != 0) + addFog(); + + if ((loadFlags & Loader.LOAD_BACKGROUND_NODES) != 0) + addBackground(); + + if ((loadFlags & Loader.LOAD_VIEW_GROUPS) != 0) + addCamera(); + + if (loadBehaviors != 0) + addBehaviors(); + + scene.setSceneGroup(sceneGroupNode); + + // now add named objects to the scenes name table + for (Enumeration e = objectList.elements(); e.hasMoreElements() ;) { + + LwsObject obj = (LwsObject)e.nextElement(); + if (obj.fileName != null) + scene.addNamedObject(obj.fileName,(Object)obj.getObjectNode()); + else if (obj.objName != null) + scene.addNamedObject(obj.objName,(Object)obj.getObjectNode()); + + } + } + + + /** + * Creates a url for internal use. This method is not currently + * used (url's are ignored for this loader; only filenames work) + */ + void setInternalBaseUrl(URL url) { +// System.out.println("setInternalBaseUrl url = " + url); + java.util.StringTokenizer stok = + new java.util.StringTokenizer(url.toString(), +// java.io.File.separator); + "\\/"); + int tocount = stok.countTokens()-1; + StringBuffer sb = new StringBuffer(80); + for(int ji = 0; ji < tocount ; ji++) { + String a = stok.nextToken(); + if((ji == 0) && //(!a.equals("file:"))) { + (!a.regionMatches(true, 0, "file:", 0, 5))) { + sb.append(a); + // urls use / on windows also +// sb.append(java.io.File.separator); +// sb.append(java.io.File.separator); + sb.append('/'); + sb.append('/'); + } else { + sb.append(a); + // urls use / on windows also +// sb.append( java.io.File.separator ); + sb.append('/'); + } + } + internalBaseUrl = sb.toString(); +// System.out.println("internalBaseUrl = " + internalBaseUrl); + } + + /** + * Standardizes the filename for use in the loader + */ + void setInternalBasePath(String fileName) { + java.util.StringTokenizer stok = + new java.util.StringTokenizer(fileName, + java.io.File.separator); + int tocount = stok.countTokens()-1; + StringBuffer sb = new StringBuffer(80); + if (fileName!= null && + fileName.startsWith(java.io.File.separator)) + sb.append(java.io.File.separator); + for(int ji = 0; ji < tocount ; ji++) { + String a = stok.nextToken(); + sb.append(a); + sb.append( java.io.File.separator ); + } + internalBasePath = sb.toString(); + } + + String getInternalBasePath() { + return internalBasePath; + } + + String getInternalBaseUrl() { + return internalBaseUrl; + } + + int getFileType() { + return fileType; + } + + /** + * This method parents all objects in the scene appropriately. If + * the scen file specifies a Parent node for the object, then the + * object is parented to that node. If not, then the object is + * parented to the scene's root. + */ + void parentObjects() { + debugOutputLn(TRACE, "parentObjects()"); + for (Enumeration e = objectList.elements(); e.hasMoreElements(); ) { + + LwsObject obj = (LwsObject)e.nextElement(); + if (obj.getParent() != -1) { + + LwsObject parent = (LwsObject) + objectList.elementAt(obj.getParent() - 1); + parent.addChild(obj); + debugOutputLn(VALUES, "added child successfully"); + + } else { + + if (obj.getObjectNode() != null) + sceneGroupNode.addChild(obj.getObjectNode()); + + } + + // Collect all behaviors + if (loadBehaviors != 0) { + if (!(obj.getObjectBehaviors()).isEmpty()) { + sceneBehaviors.addAll(obj.getObjectBehaviors()); + + } + } + } + + debugOutputLn(LINE_TRACE, "Done with parentObjects()"); + + } + + + /** + * This method sets the base URL name for data files + * associated with the file passed into the load(URL) method. + * The basePath should be null by default, which is an + * indicator to the loader that it should look for any + * associated files starting from the same directory as the + * file passed into the load(URL) method. + */ + public void setBaseUrl(URL url) { + baseUrl = url; + } + + /** + * This method sets the base path to be used when searching for all + * data files within a Lightwave scene. + */ + public void setBasePath(String pathName) { + // This routine standardizes path names so that all pathnames + // will have standard file separators, they'll end in a separator + // character, and if the user passes in null or "" (meaning to + // set the current directory as the base path), this will become + // "./" (or ".\") + basePath = pathName; + if (basePath == null || basePath == "") + basePath = "." + java.io.File.separator; + basePath = basePath.replace('/', java.io.File.separatorChar); + basePath = basePath.replace('\\', java.io.File.separatorChar); + if (!basePath.endsWith(java.io.File.separator)) + basePath = basePath + java.io.File.separator; + } + + /** + * Returns the current base URL setting. + */ + public URL getBaseUrl() { + return baseUrl; + } + + /** + * Returns the current base path setting. + */ + public String getBasePath() { + return basePath; + } + + /** + * This method sets the load flags for the file. The flags should + * equal 0 by default (which tells the loader to only load geometry). + */ + public void setFlags(int flags) { + loadFlags = flags; + } + + /** + * Returns the current loading flags setting. + */ + public int getFlags() { + return loadFlags; + } + + + + /** + * getObject() iterates through the objectList checking the given + * name against the fileName and objectName of each object in turn. + * For the filename, it carves off the pathname and just checks the + * final name (e.g., "missile.lwo"). + * If name has []'s at the end, it will use the number inside those + * brackets to pick which object out of an ordered set it will + * send back (objectList is created in the order that objects + * exist in the file, so this order should correspond to the order + * specified by the user). If no []'s exist, just pass back the + * first one encountered that matches. + */ + public TransformGroup getObject(String name) { + debugOutputLn(TRACE, "getObject()"); + int indexNumber = -1; + int currentObjectCount = 0; + String subobjectName = name; + if (name.indexOf("[") != -1) { + // caller wants specifically numbered subjbect; get that number + int bracketsIndex = name.indexOf("["); + subobjectName = name.substring(0, bracketsIndex); + String bracketsString = name.substring(bracketsIndex); + int bracketEndIndex = bracketsString.indexOf("]"); + String indexString = bracketsString.substring(1, bracketEndIndex); + indexNumber = (new Integer(indexString)).intValue(); + } + for (Enumeration e = objectList.elements() ; + e.hasMoreElements() ;) { + LwsObject tempObj = (LwsObject)e.nextElement(); + debugOutputLn(VALUES, "tempObj, file, objname = " + + tempObj + tempObj.fileName + + tempObj.objName); + if ((tempObj.fileName != null && + tempObj.fileName.indexOf(subobjectName) != -1) || + (tempObj.objName != null && + tempObj.objName.indexOf(subobjectName) != -1)) { + if (indexNumber < 0 || + indexNumber == currentObjectCount) + return tempObj.getObjectNode(); + else + currentObjectCount++; + } + } + debugOutputLn(VALUES, " no luck - wanted " + + name + " returning null"); + return null; + } + + + /** + * This method sets up the StreamTokenizer for the scene file. Note + * that we're not parsing numbers as numbers because the tokenizer + * does not interpret scientific notation correctly. + */ + void setupTokenizer(StreamTokenizer tokenizer) { + tokenizer.resetSyntax(); + tokenizer.wordChars('a', 'z'); + tokenizer.wordChars('A', 'Z'); + tokenizer.wordChars(128 + 32, 255); + tokenizer.whitespaceChars(0, ' '); + tokenizer.commentChar('/'); + tokenizer.quoteChar('"'); + tokenizer.quoteChar('\''); + tokenizer.wordChars('0', '9'); + tokenizer.wordChars('.', '.'); + tokenizer.wordChars('-', '-'); + tokenizer.wordChars('/', '/'); + tokenizer.wordChars('\\', '\\'); + tokenizer.wordChars('_', '_'); + tokenizer.wordChars('&', '&'); + tokenizer.ordinaryChar('('); + tokenizer.ordinaryChar(')'); + tokenizer.whitespaceChars('\r', '\r'); + + // add ':' as wordchar so urls will work + tokenizer.wordChars(':', ':'); + // add '~' as wordchar for urls + tokenizer.wordChars('~', '~'); + } + + /** + * Adds Ambient lighting effects to the scene + */ + void addAmbient() { + AmbientLight aLgt = new AmbientLight(ambientColor); + BoundingSphere bounds = + new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0); + aLgt.setInfluencingBounds(bounds); + sceneGroupNode.addChild(aLgt); + // scope ambient light to the lw3d scene + aLgt.addScope(sceneGroupNode); + scene.addLightNode(aLgt); + } + + /** + * Add any defined lights to the java3d scene + */ + void addLights() { + // Add lights to the scene + for (Enumeration e1 = lightList.elements(); e1.hasMoreElements(); ) { + + debugOutputLn(LINE_TRACE, "adding light to scene group"); + LwsLight light = (LwsLight)e1.nextElement(); + + if (light.getObjectNode() != null) { + // scope light to the lw3d scene + light.getLight().addScope(sceneGroupNode); + + if (light.getParent() != -1) { + LwsObject parent = (LwsObject) + objectList.elementAt(light.getParent() - 1); + parent.addChild(light); + } + else { // No parent - add to scene group + sceneGroupNode.addChild(light.getObjectNode()); + + } + + // collect behaviors if LOAD_BEHAVIOR_NODES is set + if (loadBehaviors != 0) { + if (!(light.getObjectBehaviors()).isEmpty()) + sceneBehaviors.addAll(light.getObjectBehaviors()); + + } + + scene.addLightNode(light.getLight()); + } + else + debugOutputLn(LINE_TRACE, "light object null?"); + } + } + + /** + * Adds the Camera's transform group to the scene, either by parenting + * it to the appropriate object or by adding it to the scene root. + * To use this camera data, users can request the camera/view data + * for the scene and can then insert a ViewPlatform in the transform group. + */ + void addCamera() { + // Add camera effects to scene. + if (camera != null) { + if (camera.getParent() != -1) { + debugOutputLn(VALUES, "camera parent = " + + camera.getParent()); + LwsObject parent = (LwsObject) + objectList.elementAt(camera.getParent() - 1); + parent.addChild(camera); + debugOutputLn(VALUES, "added child successfully"); + } + else { + sceneGroupNode.addChild(camera.getObjectNode()); + + } + + // collect behaviors if LOAD_BEHAVIOR_NODES is set + if (loadBehaviors != 0) { + if (!(camera.getObjectBehaviors()).isEmpty()) + sceneBehaviors.addAll(camera.getObjectBehaviors()); + } + + scene.addViewGroup(camera.getObjectNode()); + } + } + + /** + * Add appropriate fog effects to the scene + */ + void addFog() { + if (fog != null) { + Fog fogNode = fog.getObjectNode(); + if (fogNode != null) { + sceneGroupNode.addChild(fogNode); + scene.addFogNode(fogNode); + } + } + } + + /** + * Add the behaviors to the scene + */ + void addBehaviors() { + if (!sceneBehaviors.isEmpty()) { + Enumeration e = sceneBehaviors.elements(); + while (e.hasMoreElements()) { + scene.addBehaviorNode((Behavior)e.nextElement()); + } + } + } + + /** + * Add appropriate background effects to the scene. Note that the java3d + * background may not have all of the information of the lw3d background, + * as the loader does not currently process items such as gradients between + * the horizon and sky colors + */ + void addBackground() { + if (background != null) { + Background bgNode = background.getObjectNode(); + if (bgNode != null) { + sceneGroupNode.addChild(bgNode); + scene.addBackgroundNode(bgNode); + } + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwLightObject.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwLightObject.java new file mode 100644 index 0000000..a346185 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwLightObject.java @@ -0,0 +1,100 @@ +/* + * $RCSfile: LwLightObject.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:07 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import javax.vecmath.Color3f; +import javax.media.j3d.Light; + + +/** + * This class is used to set the Light Intensity value according to the + * keyframe value of the envelope for that light. The class is used in + * conjunction with LightIntensityPathInterpolator, which uses this + * class as the target of its interpolations. + */ + +class LwLightObject { + + float intensity; + Color3f color; + Light theLight; + + LwLightObject(Light theLight, float intensity, Color3f color) { + this.intensity = intensity; + this.color = color; + this.theLight = theLight; + } + + void setIntensity(float intensity) { + Color3f newLightColor = new Color3f(color.x * intensity, + color.y * intensity, + color.z * intensity); + if (theLight != null) + theLight.setColor(newLightColor); + this.intensity = intensity; + } + + void setColor(Color3f color) { + Color3f newLightColor = new Color3f(color.x * intensity, + color.y * intensity, + color.z * intensity); + if (theLight != null) + theLight.setColor(newLightColor); + this.color = color; + } + + void setLight(Light l) { + theLight = l; + Color3f newLightColor = new Color3f(color.x * intensity, + color.y * intensity, + color.z * intensity); + if (theLight != null) + theLight.setColor(newLightColor); + } +} + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoParser.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoParser.java new file mode 100644 index 0000000..478c9b2 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoParser.java @@ -0,0 +1,424 @@ +/* + * $RCSfile: LwoParser.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:07 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Vector; +import java.util.Date; +import java.util.Enumeration; +import com.sun.j3d.loaders.lw3d.LWOBFileReader; +import com.sun.j3d.internal.J3dUtilsI18N; +import java.net.*; +import com.sun.j3d.loaders.ParsingErrorException; +import com.sun.j3d.loaders.IncorrectFormatException; + + +/** + * This class is responsible for parsing a binary Object file and storing + * the data. This class is not called directly, but is the parent class of + * J3dLwoObject. The subclass calls this class to parse the file, then it + * turns the resulting data into Java3D objects. LwoObject instantiates + * an LWOBFileReader object to parse the data. Then the class creates a + * list of ShapeHolder objects to hold all of the vertex/facet data and + * surface references and creates a list of LwoSurface objects to hold + * the data for each surface.
+ * Rather than describe in detail how the file is parsed for each method, + * I advise the user of this code to understand the lw3d file format + * specs, which are pretty clear. + */ + +class LwoParser extends ParserObject { + + LWOBFileReader theReader; + int currLength; + float coordsArray[]; + float normalCoordsArray[]; + int facetIndicesArray[]; + int facetSizesArray[]; + int normalIndicesArray[]; + int red = 255, green = 255, blue = 255; + float diffuse = 0.0f, specular = 0.0f, transparency = 0.0f, luminosity = 0.0f; + int gloss = 128; + Vector surfNameList = null; + Vector surfaceList = new Vector(200); + Vector shapeList = new Vector(200); + + /** + * Constructor: Creates file reader and calls parseFile() to actually + * read the file and grab the data + */ + LwoParser(String fileName, int debugVals) + throws FileNotFoundException { + + super(debugVals); + debugOutputLn(TRACE, "parser()"); + long start = System.currentTimeMillis(); + theReader = new LWOBFileReader(fileName); + debugOutputLn(TIME, " file opened in " + + (System.currentTimeMillis() - start)); + parseFile(); + } + + LwoParser(URL url, int debugVals) + throws FileNotFoundException { + super(debugVals); + debugOutputLn(TRACE, "parser()"); + try { + long start = System.currentTimeMillis(); + theReader = new LWOBFileReader(url); + debugOutputLn(TIME, " file opened in " + + (System.currentTimeMillis() - start)); + } + catch (IOException ex) { + throw new FileNotFoundException(url.toString()); + } + parseFile(); + } + + + /** + * Detail polygons are currently not implemented by this loader. Their + * structure in geometry files is a bit complex, so there's this separate + * method for simply parsing through and ignoring the data for detail + * polygons + */ + int skipDetailPolygons(int numPolys) throws ParsingErrorException { + debugOutputLn(TRACE, "skipDetailPolygons(), numPolys = " + numPolys); + int lengthRead = 0; + int vert; + + try { + for (int polyNum = 0; polyNum < numPolys; ++polyNum) { + debugOutputLn(VALUES, "polyNum = " + polyNum); + int numVerts = theReader.getShortInt(); + theReader.skip(numVerts * 2 + 2); // skip indices plus surf + lengthRead += (numVerts * 2) + 4; // increment counter + } + } + catch (IOException e) { + debugOutputLn(EXCEPTION, "Exception in reading detail polys: " + e); + throw new ParsingErrorException(e.getMessage()); + } + return lengthRead; + } + + /** + * Returns already-existing ShapeHolder if one exists with the same + * surface and the same geometry type (point, line, or poly) + */ + ShapeHolder getAppropriateShape(int numSurf, int numVerts) { + for (Enumeration e = shapeList.elements(); + e.hasMoreElements() ;) { + ShapeHolder shape = (ShapeHolder)e.nextElement(); + if (shape.numSurf == numSurf) + if (shape.numVerts == numVerts || + (shape.numVerts > 3 && + numVerts > 3)) + return shape; + } + return null; + } + + + /** + * Parse the file for all the data for a POLS object (polygon + * description) + */ + void getPols(int length) { + debugOutputLn(TRACE, "getPols(len), len = " + length); + int vert; + int lengthRead = 0; + int prevNumVerts = -1; + int prevNumSurf = 0; + Vector facetSizesList; + int facetIndicesArray[]; + facetSizesList = + new Vector(length/6); // worst case size (every poly one vert) + // Note that our array sizes are hardcoded because we don't + // know until we're done how large they will be + facetIndicesArray = new int[length/2]; + ShapeHolder shape = new ShapeHolder(debugPrinter.getValidOutput()); + debugOutputLn(VALUES, "new shape = " + shape); + shape.coordsArray = coordsArray; + shape.facetSizesList = facetSizesList; + //shape.facetIndicesList = facetIndicesList; + shape.facetIndicesArray = facetIndicesArray; + shapeList.addElement(shape); + + //long startTime = (new Date()).getTime(); + boolean firstTime = true; + while (lengthRead < length) { + int numVerts = theReader.getShortInt(); + lengthRead += 2; + int intArray[] = new int[numVerts]; + for (int i = 0; i < numVerts; ++i) { + intArray[i] = theReader.getShortInt(); + lengthRead += 2; + } + + int numSurf = theReader.getShortInt(); + lengthRead += 2; + long startTimeBuff = 0, startTimeList = 0; + if (!firstTime && + (numSurf != prevNumSurf || + ((numVerts != prevNumVerts) && + ((prevNumVerts < 3) || + (numVerts < 3))))) { + // If above true, then start new shape + shape = getAppropriateShape(numSurf, numVerts); + if (shape == null) { + //debugOutputLn(LINE_TRACE, "Starting new shape"); + facetSizesList = new Vector(length/6); + facetIndicesArray = new int[length/2]; + shape = new ShapeHolder(debugPrinter.getValidOutput()); + shape.coordsArray = coordsArray; + shape.facetSizesList = facetSizesList; + //shape.facetIndicesList = facetIndicesList; + shape.facetIndicesArray = facetIndicesArray; + shape.numSurf = numSurf; + shape.numVerts = numVerts; + shapeList.addElement(shape); + } + else { + facetSizesList = shape.facetSizesList; + facetIndicesArray = shape.facetIndicesArray; + } + } + else { + shape.numSurf = numSurf; + shape.numVerts = numVerts; + } + prevNumVerts = numVerts; + prevNumSurf = numSurf; + facetSizesList.addElement(new Integer(numVerts)); + + int currPtr = 0; + System.arraycopy(intArray, 0, + facetIndicesArray, shape.currentNumIndices, + numVerts); + shape.currentNumIndices += numVerts; + if (numSurf < 0) { // neg number means detail poly + int numPolys = theReader.getShortInt(); + lengthRead += skipDetailPolygons(numPolys); + shape.numSurf = ~shape.numSurf & 0xffff; + if (shape.numSurf == 0) + shape.numSurf = 1; // Can't have surface = 0 + } + firstTime = false; + } + } + + /** + * Parses file to get the names of all surfaces. Each polygon will + * be associated with a particular surface number, which is the index + * number of these names + */ + void getSrfs(int length) { + String surfName = new String(); + surfNameList = new Vector(length/2); // worst case size (each name 2 chars long) + int lengthRead = 0; + int stopMarker = theReader.getMarker() + length; + + int surfIndex = 0; + while (theReader.getMarker() < stopMarker) { + debugOutputLn(VALUES, "marker, stop = " + + theReader.getMarker() + ", " + stopMarker); + debugOutputLn(LINE_TRACE, "About to call getString"); + surfName = theReader.getString(); + debugOutputLn(VALUES, "Surfname = " + surfName); + surfNameList.addElement(surfName); + } + } + + /** + * Parses file to get all vertices + */ + void getPnts(int length) throws ParsingErrorException { + int numVerts = length / 12; + float x, y, z; + + coordsArray = new float[numVerts*3]; + theReader.getVerts(coordsArray, numVerts); + } + + /** + * Creates new LwoSurface object that parses file and gets all + * surface parameters for a particular surface + */ + void getSurf(int length) throws FileNotFoundException { + debugOutputLn(TRACE, "getSurf()"); + + // Create LwoSurface object to read and hold each surface, then + // store that surface in a vector of all surfaces. + + LwoSurface surf = new LwoSurface(theReader, length, + debugPrinter.getValidOutput()); + surfaceList.addElement(surf); + } + + + /** + * parses entire file. + * return -1 on error or 0 on completion + */ + int parseFile() throws FileNotFoundException, IncorrectFormatException { + debugOutputLn(TRACE, "parseFile()"); + int length = 0; + int lengthRead = 0; + int fileLength = 100000; + + long loopStartTime = System.currentTimeMillis(); + // Every parsing unit begins with a four character string + String tokenString = theReader.getToken(); + + while (!(tokenString == null) && + lengthRead < fileLength) { + long startTime = System.currentTimeMillis(); + // Based on value of tokenString, go to correct parsing method + length = theReader.getInt(); + + lengthRead += 4; + //debugOutputLn(VALUES, "length, lengthRead, fileLength = " + + // length + ", " + lengthRead + ", " + fileLength); + //debugOutputLn(VALUES, "LWOB marker is at: " + theReader.getMarker()); + + if (tokenString.equals("FORM")) { + //debugOutputLn(LINE_TRACE, "got a form"); + fileLength = length + 4; + length = 0; + tokenString = theReader.getToken(); + lengthRead += 4; + if (!tokenString.equals("LWOB")) + throw new IncorrectFormatException( + "File not of FORM-length-LWOB format"); + } + else if (tokenString.equals("PNTS")) { + //debugOutputLn(LINE_TRACE, "PNTS"); + getPnts(length); + debugOutputLn(TIME, "done with " + tokenString + " in " + + (System.currentTimeMillis() - startTime)); + } + else if (tokenString.equals("POLS")) { + //debugOutputLn(LINE_TRACE, "POLS"); + getPols(length); + debugOutputLn(TIME, "done with " + tokenString + " in " + + (System.currentTimeMillis() - startTime)); + } + else if (tokenString.equals("SRFS")) { + //debugOutputLn(LINE_TRACE, "SRFS"); + getSrfs(length); + debugOutputLn(TIME, "done with " + tokenString + " in " + + (System.currentTimeMillis() - startTime)); + } + else if (tokenString.equals("CRVS")) { + //debugOutputLn(LINE_TRACE, "CRVS"); + theReader.skipLength(length); + //debugOutputLn(TIME, "done with " + tokenString + " in " + + // (System.currentTimeMillis() - startTime)); + } + else if (tokenString.equals("PCHS")) { + //debugOutputLn(LINE_TRACE, "PCHS"); + theReader.skipLength(length); + //debugOutputLn(TIME, "done with " + tokenString + " in " + + // (System.currentTimeMillis() - startTime)); + } + else if (tokenString.equals("SURF")) { + //debugOutputLn(LINE_TRACE, "SURF"); + getSurf(length); + //debugOutputLn(VALUES, "Done with SURF, marker = " + theReader.getMarker()); + debugOutputLn(TIME, "done with " + tokenString + " in " + + (System.currentTimeMillis() - startTime)); + } + else if (tokenString.equals("LWOB")) { + //debugOutputLn(LINE_TRACE, "LWOB"); + } + else { + //debugOutputLn(LINE_TRACE, "Unknown object = " + tokenString); + theReader.skipLength(length); + //debugOutputLn(TIME, "done with " + tokenString + " in " + + // (System.currentTimeMillis() - startTime)); + } + lengthRead += length; + if (lengthRead < fileLength) { + //debugOutputLn(VALUES, "end of parseFile, length, lengthRead = " + + // length + ", " + lengthRead); + tokenString = theReader.getToken(); + lengthRead += 4; + //debugOutputLn(VALUES, "just got tokenString = " + tokenString); + } + } + debugOutputLn(TIME, "done with parseFile in " + + (System.currentTimeMillis() - loopStartTime)); + return 0; + } + + /** + * This method is used only for testing + */ + static void main(String[] args) { + String fileName; + if (args.length == 0) + fileName = "cube.obj"; + else + fileName = args[0]; + + try { + LwoParser theParser = new LwoParser(fileName, 0); + } + catch (FileNotFoundException e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + } +} + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoSurface.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoSurface.java new file mode 100644 index 0000000..09c6872 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoSurface.java @@ -0,0 +1,316 @@ +/* + * $RCSfile: LwoSurface.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.awt.Image; +import java.io.IOException; +import java.util.Vector; +import java.util.Enumeration; +import javax.vecmath.Color3f; +import javax.vecmath.Vector3f; +import com.sun.j3d.loaders.lw3d.LWOBFileReader; +import com.sun.j3d.internal.J3dUtilsI18N; +import java.io.FileNotFoundException; +import com.sun.j3d.loaders.IncorrectFormatException; +import com.sun.j3d.loaders.ParsingErrorException; + + +/** + * This class is responsible for retrieving the surface parameters for a + * particular surface from a binary Object file and turning that data + * into Java3D data. These surface parameters include + * diffuse/specular/emissive properties, color, shininess, transparency, + * and textures. For textures, this class instantiates a LwoTexture object + * to parse that data and turn it into Java3D texture data. + */ + +class LwoSurface extends ParserObject { + + LWOBFileReader theReader; + int red = 255, green = 255, blue = 255; + float diffuse = 0.0f, specular = 0.0f, transparency = 0.0f, luminosity = 0.0f; + float creaseAngle = 0.0f; + int gloss = 128; + Color3f color, diffuseColor, specularColor, emissiveColor; + float shininess; + Image theImage = null; + Vector3f textureCenter = null, textureSize = null; + int textureAxis; + String surfName; + Vector textureList = new Vector(); + + /** + * Constructor that parses surface data from the binary file + * and creates the necessary Java3d objects + */ + LwoSurface(LWOBFileReader reader, int length, int debugVals) + throws FileNotFoundException { + + super(debugVals); + debugOutputLn(TRACE, "LwoSurface()"); + theReader = reader; + getSurf(length); + setJ3dColors(); + } + + /** + * Creates Java3d color objects from the lw3d surface data + */ + void setJ3dColors() { + color = new Color3f((float)red/(float)255, + (float)green/(float)255, + (float)blue/(float)255); + diffuseColor = new Color3f(diffuse*color.x, + diffuse*color.y, + diffuse*color.z); + specularColor = new Color3f(specular*color.x, + specular*color.y, + specular*color.z); + emissiveColor = new Color3f(luminosity*color.x, + luminosity*color.y, + luminosity*color.z); + shininess = (float)(128.0 * ((float)gloss/1024.0)); + } + + Color3f getColor() { + return color; + } + + Color3f getDiffuseColor() { + return diffuseColor; + } + + Color3f getSpecularColor() { + return specularColor; + } + + Color3f getEmissiveColor() { + return emissiveColor; + } + + float getShininess() { + return shininess; + } + + float getCreaseAngle() { + return creaseAngle; + } + + /** + * Returns the LwoTexture for the surface, if any is defined. Note that + * lw3d allows users to define multiple textures for any surface, which + * is not possible through Java3d. Therefore, we just grab the first + * texture in any list of textures for a surface + */ + LwoTexture getTexture() { + debugOutputLn(TRACE, "getTexture()"); + try { + if (textureList.isEmpty()) { + return null; + } + else { + return (LwoTexture)textureList.elementAt(0); + } + } + catch (ArrayIndexOutOfBoundsException e) { + debugOutputLn(EXCEPTION, + "getTexture(), exception returning first element: " + e); + return null; + } + } + + String getSurfName() { + return surfName; + } + + float getTransparency() { + return transparency; + } + + /** + * Parses the binary file and gets all data for this surface + */ + void getSurf(int length) + throws FileNotFoundException, IncorrectFormatException, + ParsingErrorException { + + debugOutputLn(TRACE, "getSurf()"); + + // These "got*" booleans are to help use read the best version of + // the data - the float values for these parameters should take + // precedence over the other format + boolean gotLuminosityFloat = false; + boolean gotTransparencyFloat = false; + boolean gotDiffuseFloat = false; + boolean gotSpecularFloat = false; + int surfStopMarker = theReader.getMarker() + length; + surfName = theReader.getString(); + String tokenString = theReader.getToken(); + while (!(tokenString == null) && + theReader.getMarker() < surfStopMarker) { + debugOutputLn(VALUES, " tokenString = " + tokenString); + debugOutputLn(VALUES, " marker, stop = " + + theReader.getMarker() + ", " + surfStopMarker); + String textureToken = null; + int fieldLength = theReader.getShortInt(); + debugOutputLn(VALUES, " fl = " + fieldLength); + + if (tokenString.equals("COLR")) { + debugOutputLn(LINE_TRACE, " COLR"); + try { + red = theReader.read(); + green = theReader.read(); + blue = theReader.read(); + theReader.read(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + if (fieldLength != 4) + throw new IncorrectFormatException( + J3dUtilsI18N.getString("LwoSurface0")); + } + else if (tokenString.equals("FLAG")) { + debugOutputLn(LINE_TRACE, " FLAG"); + theReader.skipLength(fieldLength); + } + else if (tokenString.equals("VLUM")) { + debugOutputLn(LINE_TRACE, " VLUM"); + luminosity = theReader.getFloat(); + gotLuminosityFloat = true; + } + else if (tokenString.equals("LUMI")) { + debugOutputLn(LINE_TRACE, " LUMI"); + if (gotLuminosityFloat) + theReader.skipLength(fieldLength); + else + luminosity = (float)(theReader.getShortInt())/255; + } + else if (tokenString.equals("VDIF")) { + debugOutputLn(LINE_TRACE, " VDIF"); + if (fieldLength != 4) + throw new IncorrectFormatException("VDIF problem"); + diffuse = theReader.getFloat(); + gotDiffuseFloat = true; + debugOutputLn(VALUES, "diff = " + diffuse); + } + else if (tokenString.equals("DIFF")) { + debugOutputLn(LINE_TRACE, " DIFF"); + if (gotDiffuseFloat) + theReader.skipLength(fieldLength); + else + diffuse = (float)theReader.getShortInt()/255; + } + else if (tokenString.equals("VTRN")) { + debugOutputLn(LINE_TRACE, " VTRN"); + transparency = theReader.getFloat(); + gotTransparencyFloat = true; + } + else if (tokenString.equals("TRAN")) { + debugOutputLn(LINE_TRACE, " TRAN"); + if (gotTransparencyFloat) + theReader.skipLength(fieldLength); + else + transparency = (float)theReader.getShortInt()/255; + } + else if (tokenString.equals("VSPC")) { + debugOutputLn(LINE_TRACE, " VSPC"); + specular = theReader.getFloat(); + gotSpecularFloat = true; + debugOutputLn(VALUES, "spec = " + specular); + } + else if (tokenString.equals("SPEC")) { + debugOutputLn(LINE_TRACE, " SPEC"); + if (gotSpecularFloat) + theReader.skipLength(fieldLength); + else { + if (fieldLength == 4) // Bug in some LW versions + specular = (float)theReader.getInt()/255; + else + specular = (float)theReader.getShortInt()/255; + } + } + else if (tokenString.equals("GLOS")) { + debugOutputLn(LINE_TRACE, " GLOS"); + if (fieldLength == 4) + gloss = theReader.getInt(); + else + gloss = theReader.getShortInt(); + } + else if (tokenString.equals("SMAN")) { + debugOutputLn(LINE_TRACE, " SMAN"); + creaseAngle = theReader.getFloat(); + } + else if (tokenString.endsWith("TEX")) { + // Textures are complex - hand off this bit to the + // LwoTexture class + LwoTexture texture = + new LwoTexture(theReader, + surfStopMarker - theReader.getMarker(), + tokenString, + debugPrinter.getValidOutput()); + textureToken = texture.getNextToken(); + if (texture.isHandled()) + textureList.addElement(texture); + debugOutputLn(WARNING, "val = " + tokenString); + } + else { + debugOutputLn(WARNING, + "unrecognized token: " + tokenString); + theReader.skipLength(fieldLength); + } + if (theReader.getMarker() < surfStopMarker) { + if (textureToken == null) + tokenString = theReader.getToken(); + else + tokenString = textureToken; + } + } + } + +} + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoTexture.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoTexture.java new file mode 100644 index 0000000..bc3cb1c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwoTexture.java @@ -0,0 +1,284 @@ +/* + * $RCSfile: LwoTexture.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.awt.Component; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.FileReader; +import java.io.File; +import java.io.IOException; +import java.util.Vector; +import java.util.Enumeration; +import java.util.Hashtable; +import javax.vecmath.Color3f; +import javax.vecmath.Vector3f; +import com.sun.j3d.utils.image.TextureLoader; +import javax.media.j3d.Texture; +import javax.media.j3d.Texture2D; +import javax.media.j3d.ImageComponent; +import javax.media.j3d.ImageComponent2D; +import com.sun.j3d.loaders.lw3d.LWOBFileReader; +import java.io.FileNotFoundException; +import com.sun.j3d.loaders.ParsingErrorException; + +/** + * This class is responsible for parsing the binary data in an Object file + * that describes a texture for a particular surface and turning that data + * into Java3D texture data. If the texture is coming from a file (which + * is the only type of texture handled by the loader currently; other + * types of texture definitions are ignored), then this class instantiates + * a TargaReader object to read the data in that file. Once all of the + * data has been read, the class creates a Java3D Texture object by first + * scaling the image using the ImageScaler class (since all textures must + * have width/height = power of 2; Note: this functionality is now built + * into the TextureLoader class, so it could be removed from this loader) + * and then creating a Texture with that image. + */ + +class LwoTexture extends ParserObject { + + LWOBFileReader theReader; + int red = 255, green = 255, blue = 255; + Color3f color, diffuseColor, specularColor, emissiveColor; + Image theImage = null; + String imageFile = null; + Vector3f textureSize = new Vector3f(1f, 1f, 1f);; + Vector3f textureCenter = new Vector3f(0f, 0f, 0f); + int textureAxis; + int flags = 0; + String type; + String mappingType; + String nextToken = null; + static Hashtable imageTable = new Hashtable(); + static Hashtable textureTable = new Hashtable(); + + /** + * Constructor: calls readTexture() to parse the file and retrieve + * texture parameters + */ + LwoTexture(LWOBFileReader reader, int length, String typename, + int debugVals) throws FileNotFoundException { + super(debugVals); + debugOutputLn(TRACE, "Constructor"); + theReader = reader; + type = typename; + readTexture(length); + } + + String getNextToken() { + return nextToken; + } + + /** + * The loader currently only handles CTEX and DTEX texture types + * (These either represent the surface color like a decal (CTEX) + * or modify the diffuse color (DTEX) + */ + boolean isHandled() { + if ((type.equals("CTEX") || + type.equals("DTEX")) && + theImage != null) + return true; + debugOutputLn(LINE_TRACE, "failed isHandled(), type, theImage = " + + type + ", " + theImage); + return false; + } + + /** + * Return the actual Texture object associated with the current image. + * If we've already created a texture for this image, return that; + * otherwise create a new Texture + */ + Texture getTexture() { + debugOutputLn(TRACE, "getTexture()"); + if (theImage == null) + return null; + Texture2D t2d = (Texture2D)textureTable.get(theImage); + if (t2d == null) { + ImageScaler scaler = new ImageScaler((BufferedImage)theImage); + BufferedImage scaledImage = (BufferedImage)scaler.getScaledImage(); + TextureLoader tl = new TextureLoader(scaledImage); + t2d = (Texture2D)tl.getTexture(); + textureTable.put(theImage, t2d); + } + + return t2d; + } + + String getType() { + return type; + } + + Color3f getColor() { + return color; + } + + Image getImage() { + return theImage; + } + + Vector3f getTextureSize() { + return textureSize; + } + + int getTextureAxis() { + return textureAxis; + } + + Vector3f getTextureCenter() { + return textureCenter; + } + + String getMappingType() { + return mappingType; + } + + /** + * Parse the binary file to retrieve all texture parameters for this + * surface. If/when we encounter a TIMG parameter, which contains the + * filename of an image, then create a new TargaReader object to + * read that image file + */ + void readTexture(int length) + throws FileNotFoundException, ParsingErrorException { + + debugOutputLn(TRACE, "readTexture()"); + + int surfStopMarker = theReader.getMarker() + length; + mappingType = theReader.getString(); + debugOutputLn(VALUES, "mappingType = " + mappingType); + String tokenString = theReader.getToken(); + while (!(tokenString == null) && theReader.getMarker() < surfStopMarker) { + + debugOutputLn(VALUES, " tokenString = " + tokenString); + debugOutputLn(VALUES, " marker, stop = " + theReader.getMarker() + ", " + surfStopMarker); + + if (tokenString.endsWith("TEX") || + (!tokenString.startsWith("T") || tokenString.equals("TRAN"))) { + nextToken = tokenString; + return; + } + + int fieldLength = theReader.getShortInt(); + debugOutputLn(VALUES, " fl = " + fieldLength); + + if (tokenString.equals("TFLG")) { + debugOutputLn(WARNING, "Not yet handling: " + tokenString); + flags = theReader.getShortInt(); + textureAxis = flags & 0x07; + debugOutputLn(WARNING, "val = " + flags); + } + else if (tokenString.equals("TCLR")) { + debugOutputLn(WARNING, "Not yet handling: " + tokenString); + try { + red = theReader.read(); + green = theReader.read(); + blue = theReader.read(); + theReader.read(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + debugOutputLn(WARNING, "val = " + red + ", " + green + + ", " + blue); + } + else if (tokenString.equals("TIMG")) { + debugOutputLn(WARNING, "Not yet handling: " + tokenString); + imageFile = theReader.getString(); + debugOutputLn(VALUES, "imageFile = " + imageFile); + if (imageFile.indexOf("none") == -1) { + if ((theImage = + (Image)imageTable.get(imageFile)) == null) { + try { + TargaReader tr = + new TargaReader(imageFile, + debugPrinter.getValidOutput()); + theImage = tr.getImage(); + imageTable.put(imageFile, theImage); + } + catch (FileNotFoundException e) { + // Ignore texture if can't find it + debugOutputLn(WARNING, "Image File skipped: " + + imageFile); + } + } + } + debugOutputLn(WARNING, "val = __" + imageFile + "__"); + } + else if (tokenString.equals("TWRP")) { + debugOutputLn(WARNING, "Not yet handling: " + tokenString); + int widthWrap = theReader.getShortInt(); + int heightWrap = theReader.getShortInt(); + debugOutputLn(WARNING, "val = " + widthWrap + ", " + + heightWrap); + } + else if (tokenString.equals("TCTR")) { + debugOutputLn(WARNING, "Not yet handling: " + tokenString); + textureCenter.x = theReader.getFloat(); + textureCenter.y = theReader.getFloat(); + textureCenter.z = theReader.getFloat(); + debugOutputLn(WARNING, "val = " + textureCenter); + } + else if (tokenString.equals("TSIZ")) { + debugOutputLn(WARNING, "Not yet handling: " + tokenString); + textureSize.x = theReader.getFloat(); + textureSize.y = theReader.getFloat(); + textureSize.z = theReader.getFloat(); + debugOutputLn(WARNING, "val = " + textureSize); + } + else { + debugOutputLn(WARNING, + "unrecognized token: " + tokenString); + theReader.skipLength(fieldLength); + } + if (theReader.getMarker() < surfStopMarker) { + tokenString = theReader.getToken(); + } + } + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsBackground.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsBackground.java new file mode 100644 index 0000000..bb8d495 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsBackground.java @@ -0,0 +1,163 @@ +/* + * $RCSfile: LwsBackground.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.util.Enumeration; +import com.sun.j3d.loaders.ParsingErrorException; + + +/** + * This class creates a Background object (solid color only, no geometry) + * according to some of the data stored in a Scene file. Note: Lightwave + * defines much more complex backgrounds that the loader currently + * handles. It should be possible to se Background Geometry to handle + * most of these cases, if there's time and will to work on the problem. + */ + +class LwsBackground extends TextfileParser { + + // data from the file + int solidBackdrop; + Color3f color, zenithColor, skyColor, groundColor, nadirColor; + Background backgroundObject = null; + + + /** + * Constructor: parses stream and retrieves all Background-related data + */ + LwsBackground(StreamTokenizer st, int debugVals) + throws ParsingErrorException { + + debugPrinter.setValidOutput(debugVals); + debugOutput(TRACE, "LwsBackground()"); + color = new Color3f(0f, 0f, 0f); + zenithColor = new Color3f(0f, 0f, 0f); + skyColor = new Color3f(0f, 0f, 0f); + groundColor = new Color3f(0f, 0f, 0f); + nadirColor = new Color3f(0f, 0f, 0f); + + solidBackdrop = (int)getNumber(st); + while (!isCurrentToken(st, "FogType")) { + debugOutputLn(LINE_TRACE, "currentToken = " + st.sval); + + if (isCurrentToken(st, "BackdropColor")) { + color.x = (float)getNumber(st)/255f; + color.y = (float)getNumber(st)/255f; + color.z = (float)getNumber(st)/255f; + } + else if (isCurrentToken(st, "NadirColor")) { + nadirColor.x = (float)getNumber(st)/255f; + nadirColor.y = (float)getNumber(st)/255f; + nadirColor.z = (float)getNumber(st)/255f; + } + else if (isCurrentToken(st, "SkyColor")) { + skyColor.x = (float)getNumber(st)/255f; + skyColor.y = (float)getNumber(st)/255f; + skyColor.z = (float)getNumber(st)/255f; + } + else if (isCurrentToken(st, "GroundColor")) { + groundColor.x = (float)getNumber(st)/255f; + groundColor.y = (float)getNumber(st)/255f; + groundColor.z = (float)getNumber(st)/255f; + } + else if (isCurrentToken(st, "NadirColor")) { + nadirColor.x = (float)getNumber(st)/255f; + nadirColor.y = (float)getNumber(st)/255f; + nadirColor.z = (float)getNumber(st)/255f; + } + try { + st.nextToken(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + st.pushBack(); // push token back on stack + } + + /** + * Creates Java3d objects from the background data. Note that there + * are plenty of lw3d background attributes that the loader currently + * ignores. Some of these may best be handled by creating background + * geometry rather than a solid background color + */ + void createJava3dObject() { + // TODO: there are various attributes of + // backdrops that we're not currently handling. In + // particular, if the file calls for a gradient background + // (solidBackdrop == 0), we ignore the request and just + // create a solid background from the sky color instead. + // We should be able to do something with the + // various colors specified, perhaps by creating + // background geometry with the appropriate vertex + // colors? + + if (solidBackdrop != 0) { + backgroundObject = new Background(color); + debugOutput(VALUES, "Background color = " + color); + } + else { + backgroundObject = new Background(skyColor); + debugOutput(VALUES, "Background color = " + skyColor); + } + BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0); + backgroundObject.setApplicationBounds(bounds); + } + + Background getObjectNode() { + return backgroundObject; + } + + void printVals() { + debugOutputLn(VALUES, " BACKGROUND vals: "); + } + + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsCamera.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsCamera.java new file mode 100644 index 0000000..6daad29 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsCamera.java @@ -0,0 +1,179 @@ +/* + * $RCSfile: LwsCamera.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.*; +import java.util.Vector; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.util.Enumeration; +import com.sun.j3d.loaders.ParsingErrorException; + +/** + * This class parses the data in a Scene file related to the camera and + * creates Java3D TransformGroup that holds the data for positioning + * and orienting the view according to the camera specifications. + */ + +class LwsCamera extends TextfileParser implements LwsPrimitive { + + // data from the file + String fileName; + String objName; + LwsMotion motion; + int parent; + TransformGroup objectTransform; + Vector objectBehavior; + + /** + * Constructor: parses camera info and creates LwsMotion object for + * keyframe data + */ + LwsCamera(StreamTokenizer st, int firstFrame, + int totalFrames, float totalTime, + int debugVals) throws ParsingErrorException { + debugPrinter.setValidOutput(debugVals); + parent = -1; + getNumber(st); // Skip ShowCamera parameters + getNumber(st); + getAndCheckString(st, "CameraMotion"); + motion = new LwsMotion(st, firstFrame, totalFrames, totalTime, + debugPrinter.getValidOutput()); + + // TODO: buggy way to stop processing the camera. Should actually + // process required/optional fields in order and stop when there's + // no more. + + while (!isCurrentToken(st, "DepthOfField")) { + debugOutputLn(LINE_TRACE, "currentToken = " + st.sval); + + if (isCurrentToken(st, "ParentObject")) { + parent = (int)getNumber(st); + } + try { + st.nextToken(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + getNumber(st); // skip shadow type parameter + } + + /** + * Returns parent of the camera object + */ + int getParent() { + return parent; + } + + /** + * Creates Java3D items from the camera data. These objects consist + * of: a TransformGroup to hold the view platform, and the behaviors + * (if any) that act upon the view's TransformGroup. + */ + void createJava3dObject(int loadBehaviors) + { + Matrix4d mat = new Matrix4d(); + mat.setIdentity(); + // Set the node's transform matrix according to the first frame + // of the object's motion + LwsFrame firstFrame = motion.getFirstFrame(); + firstFrame.setMatrix(mat); + debugOutputLn(VALUES, " Camera Matrix = \n" + mat); + Transform3D t1 = new Transform3D(); + Matrix4d m = new Matrix4d(); + double scale = .1; + m.setColumn(0, scale, 0, 0, 0); // setScale not yet implemented + m.setColumn(1, 0, scale, 0, 0); + m.setColumn(2, 0, 0, scale, 0); + m.setColumn(3, 0, 0, 0, 1); + Transform3D scaleTrans = new Transform3D(m); + TransformGroup scaleGroup = new TransformGroup(scaleTrans); + scaleGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + scaleGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); + // mat.mul(m); + t1.set(mat); + objectTransform = new TransformGroup(t1); + objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + objectBehavior = new Vector();; + if (loadBehaviors != 0) { + motion.createJava3dBehaviors(objectTransform); + Behavior b = motion.getBehaviors(); + if (b != null) + objectBehavior.addElement(b); + } + } + + /** + * Returns TransformGroup of camera + */ + public TransformGroup getObjectNode() + { + return objectTransform; + } + + /** + * Returns animation behaviors for camera + */ + public Vector getObjectBehaviors() + { + debugOutputLn(TRACE, "getObjectBehaviors()"); + return objectBehavior; + } + + /** + * This is a debuggin utility, not currently activated. It prints + * out the camera values + */ + void printVals() + { + System.out.println(" objName = " + objName); + motion.printVals(); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelope.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelope.java new file mode 100644 index 0000000..4fea6a2 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelope.java @@ -0,0 +1,160 @@ +/* + * $RCSfile: LwsEnvelope.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.io.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; +import com.sun.j3d.loaders.ParsingErrorException; +import com.sun.j3d.loaders.IncorrectFormatException; + +/** + * This class is a superclass for any implementation of envelopes; the + * only subclass currently is LwsEnvelopeLightIntensity. LwsEnvelope + * parses the data in a Scene file and extracts the envelope data. + */ + +class LwsEnvelope extends TextfileParser { + + // data from the file + String name; + LwsEnvelopeFrame frames[]; + int numFrames; + int numChannels; + boolean loop; + float totalTime; + int totalFrames; + Behavior behaviors; + + /** + * Constructor: calls getEnvelope() to parse the stream for the + * envelope data + */ + LwsEnvelope(StreamTokenizer st, int frames, float time) { + numFrames = 0; + totalTime = time; + totalFrames = frames; + name = getName(st); + getEnvelope(st); + } + + /** + * Parses the stream to retrieve all envelope data. Creates + * LwsEnvelopeFrame objects for each keyframe of the envelope + * (these frames differ slightly from LwsFrame objects because + * envelopes contain slightly different data) + */ + void getEnvelope(StreamTokenizer st) + throws IncorrectFormatException, ParsingErrorException + { + debugOutputLn(TRACE, "getEnvelope()"); + numChannels = (int)getNumber(st); + if (numChannels != 1) { + throw new IncorrectFormatException( + J3dUtilsI18N.getString("LwsEnvelope0")); + } + debugOutputLn(LINE_TRACE, "got channels"); + + numFrames = (int)getNumber(st); + frames = new LwsEnvelopeFrame[numFrames]; + debugOutputLn(VALUES, "got frames" + numFrames); + + for (int i = 0; i < numFrames; ++i) { + frames[i] = new LwsEnvelopeFrame(st); + } + debugOutput(LINE_TRACE, "got all frames"); + + try { + st.nextToken(); + while (!isCurrentToken(st, "EndBehavior")) { + // There is an undocumented "FrameOffset" in some files + st.nextToken(); + } + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + int repeatVal = (int)getNumber(st); + if (repeatVal == 1) + loop = false; + else + loop = true; + } + + /** + * This superclass does nothing here - if the loader understands + * how to deal with a particular type of envelope, it will use + * a subclass of LwsEnvelope that will override this method + */ + void createJava3dBehaviors(TransformGroup target) { + behaviors = null; + } + + Behavior getBehaviors() { + return behaviors; + } + + + LwsEnvelopeFrame getFirstFrame() { + if (numFrames > 0) + return frames[0]; + else + return null; + } + + + void printVals() { + debugOutputLn(VALUES, " name = " + name); + debugOutputLn(VALUES, " numChannels = " + numChannels); + debugOutputLn(VALUES, " numFrames = " + numFrames); + debugOutputLn(VALUES, " loop = " + loop); + for (int i = 0; i < numFrames; ++i) { + debugOutputLn(VALUES, " FRAME " + i); + frames[i].printVals(); + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeFrame.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeFrame.java new file mode 100644 index 0000000..3a76a04 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeFrame.java @@ -0,0 +1,105 @@ +/* + * $RCSfile: LwsEnvelopeFrame.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.*; +import javax.vecmath.Matrix4d; +import javax.vecmath.Vector3d; +import javax.vecmath.Point3f; + +/** + * This class represents one keyframe in an envelope sequence. + */ + +class LwsEnvelopeFrame extends TextfileParser { + + // data from the file + double value; + double frameNumber; + int linearValue; + double tension, continuity, bias; + + + /** + * Constructor: parses stream and stores data for one keyframe of + * an envelope sequence + */ + LwsEnvelopeFrame(StreamTokenizer st) { + value = getNumber(st); + debugOutputLn(VALUES, "value = " + value); + frameNumber = (int)getNumber(st); + linearValue = (int)getNumber(st); + debugOutputLn(VALUES, "framenum, linear " + frameNumber + " , " + linearValue); + tension = getNumber(st); + continuity = getNumber(st); + bias = getNumber(st); + debugOutputLn(VALUES, "tension, cont, bias = " + tension + ", " + continuity + ", " + bias); + //System.out.println(" FRAME VALS"); + //printVals(); + } + + + double getValue() { + return value; + } + + + double getFrameNum() { + return frameNumber; + } + + + void printVals() { + debugOutputLn(VALUES, " value = " + value); + debugOutputLn(VALUES, " frameNum = " + frameNumber); + debugOutputLn(VALUES, " lin = " + linearValue); + debugOutputLn(VALUES, " tension = " + tension); + debugOutputLn(VALUES, " continuity = " + continuity); + debugOutputLn(VALUES, " bias = " + bias); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeLightIntensity.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeLightIntensity.java new file mode 100644 index 0000000..e02ca70 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeLightIntensity.java @@ -0,0 +1,153 @@ +/* + * $RCSfile: LwsEnvelopeLightIntensity.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import javax.media.j3d.TransformGroup; + + +/** + * This class creates a LightIntensityPathInterpolator object from the + * keyframe-based envelope specified in a Scene file. + */ + +class LwsEnvelopeLightIntensity extends LwsEnvelope { + + + /** + * Constructor: Calls superclass, which will parse the stream + * and store the envelope data + */ + LwsEnvelopeLightIntensity(StreamTokenizer st, + int frames, float time) { + super(st, frames, time); + } + + /** + * Creates Java3d behaviors given the stored envelope data. The + * Behavior created is a LightIntensityPathInterpolator + */ + void createJava3dBehaviors(Object target) { + if (numFrames <= 1) + behaviors = null; + else { + long alphaAtOne = 0; + int loopCount; + if (loop) + loopCount = -1; + else + loopCount = 1; + // Note: hardcoded to always loop... + loopCount = -1; + debugOutputLn(VALUES, "totalTime = " + totalTime); + debugOutputLn(VALUES, "loopCount = " + loopCount); + float animTime = 1000.0f * totalTime * + (float)(frames[numFrames-1].getFrameNum()/(float)totalFrames); + debugOutputLn(VALUES, " anim time: " + animTime); + debugOutputLn(VALUES, " totalFrames = " + totalFrames); + debugOutputLn(VALUES, " lastFrame = " + + frames[numFrames-1].getFrameNum()); + if (!loop) + alphaAtOne = (long)(1000.0*totalTime - animTime); + Alpha theAlpha = + new Alpha(loopCount, Alpha.INCREASING_ENABLE, + 0, 0, (long)animTime, 0, + alphaAtOne, 0, 0, 0); + float knots[] = new float[numFrames]; + float values[] = new float[numFrames]; + for (int i=0; i < numFrames; ++i) { + values[i] = (float)frames[i].getValue(); + knots[i] = (float)(frames[i].getFrameNum())/ + (float)(frames[numFrames-1].getFrameNum()); + debugOutputLn(VALUES, "value, knot = " + + values[i] + ", " + knots[i]); + } + LightIntensityPathInterpolator l = new + LightIntensityPathInterpolator(theAlpha, + knots, + values, + target); + if (l != null) { + behaviors = l; + BoundingSphere bounds = + new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0); + behaviors.setSchedulingBounds(bounds); + ((TransformGroup)target).setCapability + (TransformGroup.ALLOW_TRANSFORM_WRITE); + ((TransformGroup)target).addChild(behaviors); + } + } + } + + + Behavior getBehaviors() { + return behaviors; + } + + + LwsEnvelopeFrame getFirstFrame() { + if (numFrames > 0) + return frames[0]; + else + return null; + } + + + void printVals() { + debugOutputLn(VALUES, " name = " + name); + debugOutputLn(VALUES, " numChannels = " + numChannels); + debugOutputLn(VALUES, " numFrames = " + numFrames); + debugOutputLn(VALUES, " loop = " + loop); + for (int i = 0; i < numFrames; ++i) { + debugOutputLn(VALUES, " FRAME " + i); + frames[i].printVals(); + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFog.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFog.java new file mode 100644 index 0000000..5952426 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFog.java @@ -0,0 +1,143 @@ +/* + * $RCSfile: LwsFog.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.util.Enumeration; +import com.sun.j3d.loaders.ParsingErrorException; + + +/** + * This class creates a Fog object from the data in a Scene file. + */ + +class LwsFog extends TextfileParser { + + // data from the file + float minDist, maxDist, minAmount, maxAmount; + int backdropFog; + Color3f color; + int type; + Fog fogObject = null; + + /** + * Constructor: parses stream and stores fog data + */ + LwsFog(StreamTokenizer st, int debugVals) throws ParsingErrorException { + debugPrinter.setValidOutput(debugVals); + debugOutput(TRACE, "LwsFog()"); + color = new Color3f(0f, 0f, 0f); + + while (!isCurrentToken(st, "DitherIntensity")) { + debugOutputLn(LINE_TRACE, "currentToken = " + st.sval); + + if (isCurrentToken(st, "FogMinDist")) { + minDist = (float)getNumber(st); + } + else if (isCurrentToken(st, "FogMaxDist")) { + maxDist = (float)getNumber(st); + } + else if (isCurrentToken(st, "FogMinAmount")) { + minAmount = (float)getNumber(st); + } + else if (isCurrentToken(st, "FogMaxAmount")) { + maxAmount = (float)getNumber(st); + } + else if (isCurrentToken(st, "BackdropFog")) { + backdropFog = (int)getNumber(st); + } + else if (isCurrentToken(st, "FogColor")) { + color.x = (float)getNumber(st)/255f; + color.y = (float)getNumber(st)/255f; + color.z = (float)getNumber(st)/255f; + } + try { + st.nextToken(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + st.pushBack(); // push token back on stack + } + + /** + * Creates Java3d Fog object given the fog parameters in the file. + * Note that various fog parameters in lw3d are not currently handled. + */ + void createJava3dObject() { + // TODO: there are various attributes of lw fog that + // we're not currently handing, including non-linear fog + // (need to understand the two different types - these may + // map onto java3d's expontential fog node), non-solid + // backdrop colors (how to handle this?), min/max amount + // (j3d only handles 0 -> 1 case) + + fogObject = new LinearFog(color, minDist, maxDist); + debugOutputLn(VALUES, + "just set linearFog with color, minDist, maxDist = " + + color + ", " + + minDist + ", " + + maxDist); + BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0); + fogObject.setInfluencingBounds(bounds); + } + + Fog getObjectNode() + { + return fogObject; + } + + void printVals() + { + debugOutputLn(VALUES, " FOG vals: "); + } + + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFrame.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFrame.java new file mode 100644 index 0000000..106f716 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFrame.java @@ -0,0 +1,341 @@ +/* + * $RCSfile: LwsFrame.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.*; +import javax.vecmath.Matrix4d; +import javax.vecmath.Vector3d; +import javax.vecmath.Point3f; + +/** + * This class is responsible for parsing the data in a Scene file + * associated with a single keyframe. This data includes the position, + * orientation, and scaling information, in addition to the frame number + * of that keyframe and some spline controls which are currently + * ignored. + */ + +class LwsFrame extends TextfileParser { + + // data from the file + double x, y, z; + double heading, pitch, bank; + double xScale, yScale, zScale; + double frameNumber; + int linearValue; + double tension, continuity, bias; + + /** + * Constructor: parses and stores all data associated with a particular + * keyframe + */ + LwsFrame(StreamTokenizer st) { + x = getNumber(st); + y = getNumber(st); + z = -getNumber(st); + debugOutputLn(VALUES, "x, y, z " + x + ", " + y + ", " + z); + heading = getNumber(st); + pitch = getNumber(st); + bank = getNumber(st); + debugOutputLn(VALUES, "(degrees) h, p, b = " + heading + ", " + pitch + ", " + bank); + heading *= (Math.PI / 180.0); // Java3d works with radians + pitch *= (Math.PI / 180.0); + bank *= (Math.PI / 180.0); + debugOutputLn(VALUES, "(radians) h, p, b = " + heading + ", " + pitch + ", " + bank); + debugOutputLn(LINE_TRACE, "got pos and ori"); + xScale = getNumber(st); + yScale = getNumber(st); + zScale = getNumber(st); + debugOutputLn(VALUES, "xs, ys, zs " + xScale +", " + yScale + ", " + zScale); + frameNumber = (int)getNumber(st); + // Note: The following spline controls are ignored + linearValue = (int)getNumber(st); + debugOutputLn(VALUES, "framenum, linear " + frameNumber + " , " + linearValue); + tension = getNumber(st); + continuity = getNumber(st); + bias = getNumber(st); + debugOutputLn(VALUES, "tension, cont, bias = " + tension + ", " + continuity + ", " + bias); + } + + + + /** + * Construct new frame that's in-between two given frames + * Ratio gives the interpolation value for how far in-between + * the new frame should be (0.5 is half-way, etc) + */ + LwsFrame(LwsFrame prevFrame, LwsFrame nextFrame, double ratio) { + + x = prevFrame.x + (nextFrame.x - prevFrame.x) * ratio; + y = prevFrame.y + (nextFrame.y - prevFrame.y) * ratio; + z = prevFrame.z + (nextFrame.z - prevFrame.z) * ratio; + + heading = prevFrame.heading + + (nextFrame.heading - prevFrame.heading) * ratio; + pitch = prevFrame.pitch + + (nextFrame.pitch - prevFrame.pitch) * ratio; + bank = prevFrame.bank + + (nextFrame.bank - prevFrame.bank) * ratio; + xScale = prevFrame.xScale + + (nextFrame.xScale - prevFrame.xScale) * ratio; + yScale = prevFrame.yScale + + (nextFrame.yScale - prevFrame.yScale) * ratio; + zScale = prevFrame.zScale + + (nextFrame.zScale - prevFrame.zScale) * ratio; + frameNumber = prevFrame.frameNumber + + (nextFrame.frameNumber - prevFrame.frameNumber) * ratio; + + // The following are not interpolated + linearValue = prevFrame.linearValue; + tension = prevFrame.tension; + continuity = prevFrame.continuity; + bias = prevFrame.bias; + } + + /** + * Using hermite interpolation construct a new frame that's + * in-between two given frames. We also need to be given a + * frame before the first frame and a frame after the second + * frame. The calling function will make sure that we get the + * four appropriate frames. + * + * Ratio gives the interpolation value for how far in-between + * the new frame should be. (.5 is half-way, etc.) + */ + LwsFrame(LwsFrame prevFrame, LwsFrame frame1, + LwsFrame frame2, LwsFrame nextFrame, double u, + double adj0, double adj1) { + + double h1, h2, h3, h4; + double dd0a, dd0b, ds1a, ds1b; + + // pre-compute spline coefficients + double u2, u3, z1; + u2 = u * u; + u3 = u2 *u; + z1 = 3.0f *u2 - u3 - u3; + h1 = 1.0f - z1; + h2 = z1; + h3 = u3 - u2 - u2 + u; + h4 = u3 - u2; + + dd0a = (1.0f - frame1.tension) * (1.0f + frame1.continuity) + * (1.0f + frame1.bias); + + dd0b = (1.0f - frame1.tension) * (1.0f - frame1.continuity) + * (1.0f - frame1.bias); + + ds1a = (1.0f - frame2.tension) * (1.0f - frame2.continuity) + * (1.0f + frame2.bias); + + ds1b = (1.0f - frame2.tension) * (1.0f + frame2.continuity) + * (1.0f - frame2.bias); + + double[] v = new double[4]; + + // interpolate x, y, z + v[0] = prevFrame.x; v[1] = frame1.x; + v[2] = frame2.x; v[3] = nextFrame.x; + x = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b, + adj0, adj1, h1, h2, h3, h4); + v[0] = prevFrame.y; v[1] = frame1.y; + v[2] = frame2.y; v[3] = nextFrame.y; + y = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b, + adj0, adj1, h1, h2, h3, h4); + v[0] = prevFrame.z; v[1] = frame1.z; + v[2] = frame2.z; v[3] = nextFrame.z; + z = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b, + adj0, adj1, h1, h2, h3, h4); + + // interpolate heading pitch and bank + v[0] = prevFrame.heading; v[1] = frame1.heading; + v[2] = frame2.heading ; v[3] = nextFrame.heading; + heading = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b, + adj0, adj1, h1, h2, h3, h4); + + v[0] = prevFrame.pitch; v[1] = frame1.pitch; + v[2] = frame2.pitch; v[3] = nextFrame.pitch; + pitch = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b, + adj0, adj1, h1, h2, h3, h4); + + v[0] = prevFrame.bank; v[1] = frame1.bank; + v[2] = frame2.bank; v[3] = nextFrame.bank; + bank = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b, + adj0, adj1, h1, h2, h3, h4); + + // interpolate scale - scale interpolation is assumed to be linear + xScale = frame1.xScale + (frame2.xScale - frame1.xScale) * u; + yScale = frame1.yScale + (frame2.yScale - frame1.yScale) * u; + zScale = frame1.zScale + (frame2.zScale - frame1.zScale) * u; + + // interpolate frame number + frameNumber = frame1.frameNumber + + (frame2.frameNumber - frame1.frameNumber) * u; + + // The following are not interpolated + linearValue = frame2.linearValue; + + // We need to keep the spline smooth between knot points + tension = 0.0; + continuity = 0.0; + bias = 0.0; + } + + + double computeInterpolation(double[] value, double dd0a, + double dd0b, double ds1a, + double ds1b, double adj0, + double adj1, double h1, + double h2, double h3, double h4) { + + double dd0, ds1; + double delta = value[2] - value[1] ; + double result; + + // if adj != 0 + if (adj0 < -0.0001 || adj0 > 0.0001) + dd0 = adj0 * (dd0a * (value[1] - value[0]) + dd0b * delta); + else + dd0 = 0.5f * (dd0a + dd0b) * delta; + + // if adj != 0 + if (adj1 < -0.0001 || adj1 > 0.0001) + ds1 = adj1 * (ds1a * delta + ds1b * (value[3] - value[2])); + else + ds1 = 0.5f * (ds1a + ds1b) * delta; + + result = value[1] * h1 + value[2] * h2 + dd0 * h3 + ds1 * h4; + + return (result); + } + + double getHeading() { + return heading; + } + + double getPitch() { + return pitch; + } + + double getBank() { + return bank; + } + + /** + * Sets the given matrix to contain the position, orientation, and + * scale values for the keyframe + */ + void setMatrix(Matrix4d mat) { + setRotationMatrix(mat); + mat.setTranslation(new Vector3d(x, y, z)); + Matrix4d m = new Matrix4d(); + m.setColumn(0, xScale, 0, 0, 0); // setScale not yet implemented + m.setColumn(1, 0, yScale, 0, 0); + m.setColumn(2, 0, 0, zScale, 0); + m.setColumn(3, 0, 0, 0, 1); + mat.mul(m); + } + + /** + * Sets the given matrix to contain the orientation for this keyframe + */ + void setRotationMatrix(Matrix4d mat) + { + debugOutputLn(TRACE, "setRotMat()"); + debugOutputLn(VALUES, " p, h, b = " + + pitch + ", " + + heading + ", " + + bank); + Matrix4d pitchMat = new Matrix4d(); + pitchMat.rotX(-pitch); + Matrix4d bankMat = new Matrix4d(); + bankMat.rotZ(bank); + mat.rotY(-heading); + mat.mul(pitchMat); + mat.mul(bankMat); + debugOutputLn(VALUES, "setRotMat(), mat = " + mat); + } + + Point3f getPosition() { + return (new Point3f((float)x, (float)y, (float)z)); + } + + Point3f getScale() { + // Make sure we don't have zero scale components + if ((xScale < -0.0001 || xScale > 0.0001) && + (yScale < -0.0001 || yScale > 0.0001) && + (zScale < -0.0001 || zScale > 0.0001)) { + return (new Point3f((float)xScale, (float)yScale, (float)zScale)); + } else { + return (new Point3f(1.0f, 1.0f, 1.0f)); + } + } + + double getFrameNum() { + return frameNumber; + } + + void printVals() { + debugOutputLn(VALUES, " x = " + x); + debugOutputLn(VALUES, " y = " + y); + debugOutputLn(VALUES, " z = " + z); + debugOutputLn(VALUES, " xScale = " + xScale); + debugOutputLn(VALUES, " yScale = " + yScale); + debugOutputLn(VALUES, " zScale = " + zScale); + debugOutputLn(VALUES, " heading = " + heading); + debugOutputLn(VALUES, " pitch = " + pitch); + debugOutputLn(VALUES, " bank = " + bank); + debugOutputLn(VALUES, " frameNum = " + frameNumber); + debugOutputLn(VALUES, " lin = " + linearValue); + debugOutputLn(VALUES, " tension = " + tension); + debugOutputLn(VALUES, " continuity = " + continuity); + debugOutputLn(VALUES, " bias = " + bias); + } + +} + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsLight.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsLight.java new file mode 100644 index 0000000..4c02995 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsLight.java @@ -0,0 +1,269 @@ +/* + * $RCSfile: LwsLight.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:08 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.io.*; +import java.util.Vector; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.util.Enumeration; +import com.sun.j3d.loaders.ParsingErrorException; + +/** + * This class creates a light object from the data in a Scene file. It + * instantiates an LwsMotion object to create any associated + * animations. + */ + +class LwsLight extends TextfileParser implements LwsPrimitive { + + // data from the file + String fileName; + String objName; + LwsMotion motion; + int parent; + TransformGroup objectTransform; + Vector objectBehavior; + Color3f color; + int type; + Point3f attenuation = new Point3f(1.0f, 0.0f, 0.0f); + float spotConeAngle = (float)(Math.PI); + // Meta object, used for holding light and + LwLightObject lwLight; + // light parameters + LwsEnvelopeLightIntensity intensityEnvelope = null; + Light light = null; + final static int DIRECTIONAL = 0, POINT = 1, SPOT = 2; + + /** + * Constructor: parses stream and creates data structures for all + * light parameters currently handled by the loader + */ + LwsLight(StreamTokenizer st, int totalFrames, float totalTime, + int debugVals) throws ParsingErrorException { + + debugPrinter.setValidOutput(debugVals); + + debugOutput(TRACE, "LwsLight()"); + color = new Color3f(1f, 1f, 1f); + lwLight = new LwLightObject(null, 0.0f, null); + + parent = -1; + debugOutputLn(LINE_TRACE, "about to get LightName"); + getAndCheckString(st, "LightName"); + debugOutputLn(LINE_TRACE, "about to get LightName value"); + objName = getName(st); + debugOutputLn(LINE_TRACE, "got LightName"); + skip(st, "ShowLight", 2); + debugOutputLn(LINE_TRACE, "got ShowLight"); + getAndCheckString(st, "LightMotion"); + debugOutputLn(LINE_TRACE, "got LightMotion"); + motion = new LwsMotion(st, totalFrames, totalTime); + debugOutputLn(LINE_TRACE, "got motions"); + + // TODO: buggy way to stop processing the light. Should actually + // process required/optional fields in order and stop when there's + // no more. However, spec says "ShadowCasing" but the files say + // "ShadowType". + + while (!isCurrentToken(st, "ShowCamera") && + !isCurrentToken(st, "AddLight")) { + // TODO: + // Things that we're not yet processing (and should): + // - EdgeAngle: for spotlights, this is the angle which + // contains the linear falloff toward the edge of the + // ConeAngle. This doesn't directly map to J3d's + // "concentration" value, so it's left out for now. + + debugOutputLn(LINE_TRACE, "currentToken = " + st.sval); + + if (isCurrentToken(st, "ParentObject")) { + parent = (int)getNumber(st); + } + else if (isCurrentToken(st, "LightColor")) { + color.x = (float)getNumber(st)/255f; + color.y = (float)getNumber(st)/255f; + color.z = (float)getNumber(st)/255f; + lwLight.setColor(color); + } + else if (isCurrentToken(st, "LgtIntensity")) { + // TODO: must be able to handle envelopes here + String className = getClass().getName(); + int classIndex = className.lastIndexOf('.'); + String packageName; + if (classIndex < 0) + packageName = ""; + else + packageName = className.substring(0, classIndex) + "."; + EnvelopeHandler env = + new EnvelopeHandler(st, totalFrames, totalTime, + packageName + "LwsEnvelopeLightIntensity"); + if (env.hasValue) { + float intensity = (float)env.theValue; + color.x *= intensity; + color.y *= intensity; + color.z *= intensity; + lwLight.setIntensity(intensity); + } + else { + intensityEnvelope = + (LwsEnvelopeLightIntensity)env.theEnvelope; + } + } + else if (isCurrentToken(st, "LightType")) { + type = (int)getNumber(st); + } + else if (isCurrentToken(st, "Falloff")) { + float falloff = (float)getNumber(st); + attenuation.y = 1.0f/(1.0f - falloff) - 1.0f; + } + else if (isCurrentToken(st, "ConeAngle")) { + spotConeAngle = (float)getNumber(st) * (float)(Math.PI / 180.0); + } + try { + st.nextToken(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + st.pushBack(); // push "ShowCamera" or "AddLight" back on stack + } + + int getParent() { + return parent; + } + + /** + * Create Java3D objects from the data we got from the file + */ + void createJava3dObject(int loadBehaviors) { + Matrix4d mat = new Matrix4d(); + mat.setIdentity(); + // Set the node's transform matrix according to the first frame + // of the object's motion + LwsFrame firstFrame = motion.getFirstFrame(); + firstFrame.setMatrix(mat); + debugOutputLn(VALUES, "Light transform = " + mat); + Transform3D t1 = new Transform3D(); + t1.set(mat); + objectTransform = new TransformGroup(t1); + objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + Vector3f defaultDir = new Vector3f(0f, 0f, -1f); + Point3f defaultPos = new Point3f(0f, 0f, 0f); + + switch (type) { + case DIRECTIONAL: + light = new DirectionalLight(color, defaultDir); + break; + case POINT: + light = new PointLight(color, defaultPos, attenuation); + break; + case SPOT: + // Note: spotConeAngle in lw3d is half that of Java3d... + light = new SpotLight(color, defaultPos, attenuation, defaultDir, + 2 * spotConeAngle, 0.0f); + break; + default: + // Shouldn't get here + break; + } + + light.setCapability(Light.ALLOW_COLOR_WRITE); + if (light != null) { + lwLight.setLight(light); + BoundingSphere bounds = + new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0); + light.setInfluencingBounds(bounds); + objectTransform.addChild(light); + + // load behaviors if we have to + objectBehavior = new Vector(); + if (loadBehaviors != 0) { + Behavior b; + b = null; + motion.createJava3dBehaviors(objectTransform); + b = motion.getBehaviors(); + if (b != null) + objectBehavior.addElement(b); + + if (intensityEnvelope != null) { + b = null; + intensityEnvelope.createJava3dBehaviors(lwLight); + b = intensityEnvelope.getBehaviors(); + if (b != null) + objectBehavior.addElement(b); + } + } + } + } + + public TransformGroup getObjectNode() + { + return objectTransform; + } + + Light getLight() { + return light; + } + + public Vector getObjectBehaviors() + { + debugOutputLn(TRACE, "getObjectBehaviors()"); + return objectBehavior; + } + + + void printVals() + { + debugOutputLn(VALUES, " LIGHT vals: "); + debugOutputLn(VALUES, " objName = " + objName); + motion.printVals(); + } + + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsMotion.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsMotion.java new file mode 100644 index 0000000..bada8e3 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsMotion.java @@ -0,0 +1,688 @@ +/* + * $RCSfile: LwsMotion.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.io.*; +import java.util.Enumeration; +import java.util.Vector; +import javax.media.j3d.*; +import javax.vecmath.*; +import com.sun.j3d.utils.behaviors.interpolators.*; +import com.sun.j3d.internal.J3dUtilsI18N; +import com.sun.j3d.loaders.ParsingErrorException; +import com.sun.j3d.loaders.IncorrectFormatException; + +/** + * This class is responsible for parsing the data in a Scene file related to + * an object's animation and constructing the appropriate Java3D + * Behavior objects. For each keyframe defined for the animation in the + * Lightwave file, this class creates a LwsFrame object to parse that + * keyframe data and create the appropriate data structures. Then for + * each of those LwsFrame objects created, LwsMotion creates a knot + * value for a PathInterpolator and fills in the appropriate field. Finally, + * the class creates a RotPosScalePathInterpolator with all of the data + * from the animation. There are also some utility functions in this + * class for dealing with special cases of animations, such as animations + * that begin after the first frame of the scene and animations that + * define frames in a way that Java3D cannot easily interpret. + */ + +class LwsMotion extends TextfileParser { + + // data from the file + String motionName; + LwsFrame frames[]; + int numFrames; + int numChannels; + boolean loop; + float totalTime; + int firstFrame; + int totalFrames; + Behavior behaviors; + + /** + * Constructor + */ + LwsMotion(StreamTokenizer st, int frames, float time) { + this(st, 0, frames, time, EXCEPTION); + + } + + /** + * Constructor: takes tokenizer, 1st frame of this animation, total + * number of frames, total time of animation, and the debug settings + */ + LwsMotion(StreamTokenizer st, int firstFrame, + int frames, float time, int debugVals) + throws ParsingErrorException, IncorrectFormatException { + + debugPrinter.setValidOutput(debugVals); + numFrames = 0; + totalTime = time; + this.firstFrame = firstFrame; + totalFrames = frames; + debugOutputLn(LINE_TRACE, "about to get motion name"); + motionName = getName(st); + debugOutputLn(LINE_TRACE, "about to get motion"); + getMotion(st); + } + + /** + * This method parses the tokenizer and creates the data structures + * that hold the data from that file. For each separate keyframe, + * this method calls LwsFrame to parse and interpret that data. + */ + void getMotion(StreamTokenizer st) + throws ParsingErrorException, IncorrectFormatException + { + debugOutputLn(TRACE, "getMotion()"); + numChannels = (int)getNumber(st); + if (numChannels != 9) { + throw new IncorrectFormatException( + J3dUtilsI18N.getString("LwsMotion0")); + } + debugOutputLn(LINE_TRACE, "got channels"); + + numFrames = (int)getNumber(st); + frames = new LwsFrame[numFrames]; + debugOutputLn(VALUES, "got frames" + numFrames); + + for (int i = 0; i < numFrames; ++i) { + frames[i] = new LwsFrame(st); + } + + debugOutput(LINE_TRACE, "got all frames"); + + getAndCheckString(st, "EndBehavior"); + int repeatVal = (int)getNumber(st); + if (repeatVal == 1) + loop = false; + else + loop = true; + + // need to make sure frame info is in sycn with j3d + // fixFrames(); + } + + /** + * The previous version of this method looked for sucessive frames with + * the same rotation value (mod 2PI). If it found such frames, it would + * divide that interval into 4 separate frames. + * This fix is not sufficient for various rotation cases, though. For + * instance, if the rotation difference between two frames is more than + * 2PI, the rotation will not case a flag to be fixed and the resulting + * rotation will only be between the delta of the two rotations, mod 2PI. + * The real fix should behave as follows: + * - Iterate through all sucessive frames + * - For any two frames that have rotation components that differ by more + * than PI/2 (one quarter rotation - no reason for this, but let's pick a + * small value to give our resulting path interpolations a better chance + * of behaving correctly), figure out how many frames we need to create to + * get increments of <= PI/2 between each frame. + * - Create these new frames + * - Set the odl frames pointer to the new frames structures. + */ + + void fixFrames() { + + boolean addedFrames = false; + Vector newFramesList = new Vector(); + double halfPI = (float)(Math.PI/2); + LwsFrame finalFrame = null; + + for (int i = 1 ; i < numFrames; ++i) { + LwsFrame prevFrame; + LwsFrame lastFrame = frames[i-1]; + LwsFrame thisFrame = frames[i]; + LwsFrame nextFrame; + + finalFrame = thisFrame; + newFramesList.add(lastFrame); + + double largestAngleDifference = 0; + double thisAngle = thisFrame.getHeading(); + double lastAngle = lastFrame.getHeading(); + double angleDifference = Math.abs(thisAngle - lastAngle); + if (angleDifference > largestAngleDifference) + largestAngleDifference = angleDifference; + + thisAngle = thisFrame.getPitch(); + lastAngle = lastFrame.getPitch(); + angleDifference = Math.abs(thisAngle - lastAngle); + if (angleDifference > largestAngleDifference) + largestAngleDifference = angleDifference; + + thisAngle = thisFrame.getBank(); + lastAngle = lastFrame.getBank(); + angleDifference = Math.abs(thisAngle - lastAngle); + if (angleDifference > largestAngleDifference) + largestAngleDifference = angleDifference; + + if (largestAngleDifference > halfPI) { + // Angles too big - create new frames + addedFrames = true; + int numNewFrames = (int)(largestAngleDifference/halfPI); + double increment = 1.0/(double)(numNewFrames+1); + double currentRatio = increment; + + double totalf = frames[numFrames-1].getFrameNum(); + double tlength = (thisFrame.getFrameNum() - + lastFrame.getFrameNum())/totalf; + double adj0; + double adj1; + + // get the previous and next frames + if ((i-1) < 1) { + prevFrame = frames[i-1]; + adj0 = 0.0; + } else { + prevFrame = frames[i-2]; + adj0 = tlength/((thisFrame.getFrameNum() - + prevFrame.getFrameNum())/totalf); + } + + if ((i+1) < numFrames) { + nextFrame = frames[i+1]; + adj1 = tlength/((nextFrame.getFrameNum()- + lastFrame.getFrameNum())/totalf); + } else { + nextFrame = frames[i]; + adj1 = 1.0; + } + + for (int j = 0; j < numNewFrames; ++j) { + + LwsFrame newFrame; + + // if linear interpolation + if (thisFrame.linearValue == 1) { + newFrame = new LwsFrame(lastFrame, + thisFrame, currentRatio); + + // if spline interpolation + } else { + newFrame = new LwsFrame(prevFrame, lastFrame, + thisFrame, nextFrame, + currentRatio, adj0, adj1); + } + + currentRatio += increment; + newFramesList.add(newFrame); + } + } + } + + // Now add in final frame + if (finalFrame != null) + newFramesList.add(finalFrame); + if (addedFrames) { + + // Recreate frames array from newFramesList + LwsFrame newFrames[] = new LwsFrame[newFramesList.size()]; + Enumeration elements = newFramesList.elements(); + int index = 0; + while (elements.hasMoreElements()) { + newFrames[index++] = (LwsFrame)elements.nextElement(); + } + frames = newFrames; + numFrames = frames.length; + for (int i = 0; i < numFrames; ++i) { + debugOutputLn(VALUES, "frame " + i + " = " + frames[i]); + frames[i].printVals(); + } + } + } + + /** + * Utility for getting integer mod value + */ + int intMod(int divisee, int divisor) { + int tmpDiv = divisee; + int tmpDivisor = divisor; + if (tmpDiv < 0) + tmpDiv = -tmpDiv; + if (tmpDivisor < 0) + tmpDivisor = -tmpDivisor; + while (tmpDiv > tmpDivisor) { + tmpDiv -= tmpDivisor; + } + return tmpDiv; + } + + /** + * Class that associates a particular frame with its effective frame + * number (which accounts for animations that start after frame 1) + */ + class FrameHolder { + double frameNumber; + LwsFrame frame; + + FrameHolder(LwsFrame theFrame, double number) { + frame = theFrame; + frameNumber = number; + } + } + + + /** + * This method was added to account for animations that start after + * the first frame (e.g., Juggler.lws starts at frame 30). We need + * to alter some of the information for the frames in this "frame subset" + */ + void playWithFrameTimes(Vector framesVector) { + debugOutputLn(TRACE, "playWithFrameTimes: firstFrame = " + + firstFrame); + if (firstFrame == 1) { + return; + } + else if (frames[numFrames-1].getFrameNum() < totalFrames) { + // First, create a vector that holds all LwsFrame's in frame + // increasing order (where order is started at firstFrame Modulo + // this motion's last frame + int motionLastFrame = + (int)(frames[numFrames-1].getFrameNum() + .4999999); + int newFirstFrame = intMod(firstFrame, motionLastFrame); + int newLastFrame = intMod(totalFrames, motionLastFrame); + int index = 0; + while (index < numFrames) { + if (frames[index].getFrameNum() >= newFirstFrame) + break; + ++index; + } + int startIndex = index; + if (frames[startIndex].getFrameNum() > firstFrame && + startIndex > 0) + startIndex--; // Actually, should interpolate + index = startIndex; + if (newFirstFrame < newLastFrame) { + while (index < numFrames && + frames[index].getFrameNum() <= newLastFrame) { + FrameHolder frameHolder = + new FrameHolder(frames[index], + frames[index].getFrameNum() - + newFirstFrame); + framesVector.addElement(frameHolder); + ++index; + } + } + else { + double currentNewFrameNumber = -1.0; + while (index < numFrames) { + currentNewFrameNumber = frames[index].getFrameNum() - + newFirstFrame; + FrameHolder frameHolder = + new FrameHolder(frames[index], + currentNewFrameNumber); + framesVector.addElement(frameHolder); + ++index; + } + index = 0; + while (index <= startIndex && + frames[index].getFrameNum() <= newLastFrame) { + if (index == 0) { + LwsFrame newFrame = + new LwsFrame(frames[index], + frames[index+1], + 1.0/(frames[index+1].getFrameNum() - + frames[index].getFrameNum())); + FrameHolder frameHolder = + new FrameHolder(newFrame, + newFrame.getFrameNum() + + currentNewFrameNumber); + framesVector.addElement(frameHolder); + } + else { + FrameHolder frameHolder = + new FrameHolder(frames[index], + frames[index].getFrameNum() + + currentNewFrameNumber); + framesVector.addElement(frameHolder); + } + ++index; + } + } + } + else { + int index = 0; + while (index < numFrames) { + if (frames[index].getFrameNum() >= firstFrame) + break; + ++index; + } + int startIndex = index; + if (frames[startIndex].getFrameNum() > firstFrame && + startIndex > 0) { + // Interpolate to first frame + double ratio = (double)firstFrame / + (frames[startIndex].getFrameNum() - + frames[startIndex-1].getFrameNum()); + LwsFrame newFrame = new LwsFrame(frames[startIndex-1], + frames[startIndex], + ratio); + FrameHolder frameHolder = + new FrameHolder(newFrame, newFrame.getFrameNum() - + firstFrame); + framesVector.addElement(frameHolder); + } + index = startIndex; + while (index < numFrames && + frames[index].getFrameNum() <= totalFrames) { + FrameHolder frameHolder = + new FrameHolder(frames[index], + frames[index].getFrameNum() - + firstFrame); + framesVector.addElement(frameHolder); + ++index; + } + if (frames[index-1].getFrameNum() < totalFrames) { + // Interpolate to last frame + double ratio = (double)(totalFrames - + frames[index-1].getFrameNum()) / + (frames[index].getFrameNum() - + frames[index-1].getFrameNum()); + LwsFrame newFrame = new LwsFrame(frames[index-1], + frames[index], + ratio); + FrameHolder frameHolder = + new FrameHolder(newFrame, totalFrames - firstFrame); + framesVector.addElement(frameHolder); + } + } + } + + /** + * Normally, we just create j3d behaviors from the frames. But if the + * animation's first frame is after frame number one, then we have to + * shuffle things around to account for playing/looping on this subset + * of the total frames of the animation + */ + void createJava3dBehaviorsForFramesSubset(TransformGroup target) { + + debugOutputLn(TRACE, "createJava3dBehaviorsForFramesSubset"); + Vector frameHolders = new Vector(); + playWithFrameTimes(frameHolders); + long alphaAtOne = 0; + + // determine looping + int loopCount; + if (loop) + loopCount = -1; + else + loopCount = 1; + loopCount = -1; + + int numFrames = frameHolders.size(); + + debugOutputLn(VALUES, "totalTime = " + totalTime); + debugOutputLn(VALUES, "loopCount = " + loopCount); + + FrameHolder lastFrameHolder = + (FrameHolder)frameHolders.elementAt(frameHolders.size() - 1); + LwsFrame lastFrame = lastFrameHolder.frame; + float animTime = 1000.0f * totalTime * + (float)(lastFrameHolder.frameNumber/(float)(totalFrames - + firstFrame)); + debugOutputLn(VALUES, " anim time: " + animTime); + debugOutputLn(VALUES, " totalFrames = " + totalFrames); + + if (!loop) + alphaAtOne = (long)(1000.0*totalTime - animTime); + Alpha theAlpha = + new Alpha(loopCount, Alpha.INCREASING_ENABLE, + 0, 0, (long)animTime, 0, + alphaAtOne, 0, 0, 0); + + float knots[] = new float[numFrames]; + Point3f[] positions = new Point3f[numFrames]; + Quat4f[] quats = new Quat4f[numFrames]; + Point3f[] scales = new Point3f[numFrames]; + Transform3D yAxis = new Transform3D(); + Matrix4d mat = new Matrix4d(); + KBKeyFrame[] keyFrames = new KBKeyFrame[numFrames]; + + for (int i=0; i < numFrames; ++i) { + + FrameHolder frameHolder = (FrameHolder)frameHolders.elementAt(i); + LwsFrame frame = frameHolder.frame; + + // copy position + positions[i] = frame.getPosition(); + + // copy scale + // Used to hardcode no-scale: scales[i] = 1.0f, 1.0f, 1.0f; + // Note that we can't do non-uniform scaling in the current Path + // interpolators. The interpolator just uses the x scale. + // getScale makes sure that we don't have any zero scale component + scales[i] = frame.getScale(); + + // copy rotation information + frame.setRotationMatrix(mat); + debugOutputLn(VALUES, "LwsMotion::createj3dbeh, mat = " + mat); + quats[i] = new Quat4f(); + quats[i].set(mat); + debugOutputLn(VALUES, " and quat = " + quats[i]); + + // calculate knot points from frame numbers + if (i == 0) + knots[i] = 0.0f; + else + knots[i] = (float)(frameHolder.frameNumber)/ + (float)(lastFrameHolder.frameNumber); + + // Create KB key frames + keyFrames[i] = new KBKeyFrame(knots[i], frame.linearValue, + positions[i], + (float)frame.heading, + (float)frame.pitch, + (float)frame.bank, + scales[i], + (float)frame.tension, + (float)frame.continuity, + (float)frame.bias); + + debugOutputLn(VALUES, "pos, knots, quat = " + + positions[i] + knots[i] + quats[i]); + } + + // Pass the KeyFrames to the interpolator an let it do its thing + KBRotPosScaleSplinePathInterpolator b = new + KBRotPosScaleSplinePathInterpolator(theAlpha, + target, + yAxis, + keyFrames); + if (b != null) { + behaviors = b; + BoundingSphere bounds = + new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0); + b.setSchedulingBounds(bounds); + target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + target.addChild(behaviors); + } + } + + /** + * Create j3d behaviors for the data stored in this animation. This is + * done by creating a RotPosScalePathInterpolator object that contains + * all of the position, orientation, scale data for each keyframe. + */ + void createJava3dBehaviors(TransformGroup target) { + + if (numFrames <= 1) + behaviors = null; + else { + if (firstFrame > 1) { + createJava3dBehaviorsForFramesSubset(target); + return; + } + + long alphaAtOne = 0; + + // determine looping + int loopCount; + if (loop) + loopCount = -1; + else + loopCount = 1; + loopCount = -1; + + debugOutputLn(VALUES, "totalTime = " + totalTime); + debugOutputLn(VALUES, "loopCount = " + loopCount); + + float animTime = 1000.0f * totalTime * + (float)(frames[numFrames-1].getFrameNum()/(float)totalFrames); + + debugOutputLn(VALUES, " anim time: " + animTime); + debugOutputLn(VALUES, " totalFrames = " + totalFrames); + debugOutputLn(VALUES, " lastFrame = " + + frames[numFrames-1].getFrameNum()); + + if (!loop) + alphaAtOne = (long)(1000.0*totalTime - animTime); + Alpha theAlpha = + new Alpha(loopCount, Alpha.INCREASING_ENABLE, + 0, 0, (long)animTime, 0, + alphaAtOne, 0, 0, 0); + + float knots[] = new float[numFrames]; + Point3f[] positions = new Point3f[numFrames]; + Quat4f[] quats = new Quat4f[numFrames]; + Point3f[] scales = new Point3f[numFrames]; + Transform3D yAxis = new Transform3D(); + Matrix4d mat = new Matrix4d(); + KBKeyFrame[] keyFrames = new KBKeyFrame[numFrames]; + + for (int i=0; i < numFrames; ++i) { + + // copy position + positions[i] = frames[i].getPosition(); + + // copy scale + // Used to hardcode no-scale: scales[i] = 1.0f, 1.0f, 1.0f; + // Note that we can't do non-uniform scaling in the current Path + // interpolators. The interpolator just uses the x scale. + // getScale makes sure that we don't have any 0 scale component + scales[i] = frames[i].getScale(); + + // copy rotation information + frames[i].setRotationMatrix(mat); + debugOutputLn(VALUES, "LwsMotion::createj3dbeh, mat = " + mat); + quats[i] = new Quat4f(); + quats[i].set(mat); + debugOutputLn(VALUES, " and quat = " + quats[i]); + + // calculate knot points from frame numbers + if (i == 0) + knots[i] = 0.0f; + else + knots[i] = (float)(frames[i].getFrameNum())/ + (float)(frames[numFrames-1].getFrameNum()); + + // Create KB key frames + keyFrames[i] = new KBKeyFrame(knots[i],frames[i].linearValue, + positions[i], + (float)frames[i].heading, + (float)frames[i].pitch, + (float)frames[i].bank, + scales[i], + (float)frames[i].tension, + (float)frames[i].continuity, + (float)frames[i].bias); + + + debugOutputLn(VALUES, "pos, knots, quat = " + + positions[i] + knots[i] + quats[i]); + } + + // Pass the KeyFrames to the interpolator an let it do its thing + KBRotPosScaleSplinePathInterpolator b = new + KBRotPosScaleSplinePathInterpolator(theAlpha, + target, + yAxis, + keyFrames); + if (b != null) { + behaviors = b; + BoundingSphere bounds = + new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0); + b.setSchedulingBounds(bounds); + target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + target.addChild(behaviors); + } + } + + } + + /** + * Returns the Behavior object created for this animation + */ + Behavior getBehaviors() { + return behaviors; + } + + /** + * Returns the first LwsFrame object (which contains the initial + * setup for a given object) + */ + LwsFrame getFirstFrame() { + if (numFrames > 0) + return frames[0]; + else + return null; + } + + /** + * Utility function for printing values + */ + void printVals() { + debugOutputLn(VALUES, " motionName = " + motionName); + debugOutputLn(VALUES, " numChannels = " + numChannels); + debugOutputLn(VALUES, " numFrames = " + numFrames); + debugOutputLn(VALUES, " loop = " + loop); + for (int i = 0; i < numFrames; ++i) { + debugOutputLn(VALUES, " FRAME " + i); + frames[i].printVals(); + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsObject.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsObject.java new file mode 100644 index 0000000..eb9a1e7 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsObject.java @@ -0,0 +1,570 @@ +/* + * $RCSfile: LwsObject.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + +import java.awt.Component; +import java.io.*; +import java.util.Vector; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; +import com.sun.j3d.utils.geometry.ColorCube; +import com.sun.j3d.loaders.ParsingErrorException; +import com.sun.j3d.loaders.IncorrectFormatException; +import java.net.MalformedURLException; + +import java.net.*; + +/** + * An LwsObject is passed a handle to the text file that contains the scene + * and is responsible for parsing a particular section of that file that + * describes a single object. This section defines the type of object + * (either a group or some geometry specified by an Object file) and + * some keyframe data that describes the an animation of the + * orientation/position/scale of the object. For geometry objects, this + * class instantiates a J3dLwoParser object to parse the binary data file. + * For the keyframe data, the class instantiates an LwsMotion object to + * parse and store that data. + */ + +class LwsObject extends TextfileParser implements LwsPrimitive { + + // data from the file + String fileName; + String objName; + LwsMotion motion; + int parent; + TransformGroup objectTransform; + Vector objectBehavior; + Vector shapeList = null; + boolean hasPivot = false; + TransformGroup pivotTransGroup = null; + + URL urlName; + String protocol; + int fileType; + + /** + * Constructor: parses object section of this scene file and + * creates all appropriate data structures to hold the information + * @param st StreamTokenizer for scene file + * @param loadObject boolean specifying that object is not a lw3d Null + * object + * @param firstFrame int holding the first frame of the scene's animation + * @param totalFrames int holding the total number of frames in the scene + * @param totalTime float holding the total time of the animation + * @param loader Lw3dLoader loader object that was created by user + * @param debugVals in holding current debug flags + */ + LwsObject(StreamTokenizer st, boolean loadObject, + int firstFrame, int totalFrames, float totalTime, + Lw3dLoader loader, int debugVals) + throws java.io.FileNotFoundException, + ParsingErrorException { + debugPrinter.setValidOutput(debugVals); + parent = -1; + + fileType = loader.getFileType(); + + try { + if (loadObject) { + // If this is true, then the object is actually described + // in an external geometry file. Get that filename + fileName = getString(st); + String path = null; + switch (loader.getFileType()) { + case Lw3dLoader.FILE_TYPE_FILENAME: + // No other case is current implemented in this loader + path = loader.getBasePath(); + if (path == null) + path = loader.getInternalBasePath(); + if (path != null) { + // It's not sufficient to just use the base path. + // Lightwave scene files tend to embed path names + // to object files that are only correct if you + // start from a certain directory. For example, a + // scene file in data/ may point to an object in + // data/Objects - but in this case + // getInternalBasePath() would be data/, so you'd + // look for the object in data/data/Objects... + // To attempt to overcome this confusing state of + // affairs, let's check path/filename + // first, then iterate all the way up the path + // until there are no more members of path. This + // will ensure that we'll at least pick up data + // files if they exist off of one of the parent + // directories of wherever the scene file is + // stored. + // No, I don't really like this solution, but I don't + // know of a better general approach for now... + + fileName = getQualifiedFilename(path, fileName); + } + break; + case Lw3dLoader.FILE_TYPE_URL: + path = ""; + URL pathUrl = loader.getBaseUrl(); + if (pathUrl != null) { + path = pathUrl.toString(); + // store the protocol + protocol = pathUrl.getProtocol(); + } + else { + path = loader.getInternalBaseUrl(); + // store the protocol + protocol = (new URL(path)).getProtocol(); + } + + urlName = getQualifiedURL(path, fileName); + break; + } + } + else + // else the object is a lw3d Null object; essentially a group + // which contains other objects + objName = getString(st); + skip(st, "ShowObject", 2); + debugOutputLn(LINE_TRACE, + "skipped showobject, about to get objectmotion"); + getAndCheckString(st, "ObjectMotion"); + debugOutputLn(LINE_TRACE, "got string " + st.sval); + // Create an LwsMotion object to parse the animation data + motion = new LwsMotion(st, firstFrame, totalFrames, + totalTime, debugVals); + debugOutputLn(LINE_TRACE, "got motion"); + boolean hasParent = false; // keeps bones prim from reassigning par + + // TODO: This isn't the greatest way to stop parsing an object + // (keying on the ShowOptions parameter), but it seems to be valid + // for the current lw3d format + while (!isCurrentToken(st, "ShadowOptions")) { + if (!hasParent && + isCurrentToken(st, "ParentObject")) { + parent = (int)getNumber(st); + hasParent = true; + } + else if (isCurrentToken(st, "PivotPoint")) { + // PivotPoint objects are tricky - they make the object + // rotate about this new point instead of the default + // So setup transform groups such that this happens + // correctly. + hasPivot = true; + float x = (float)getNumber(st); + float y = (float)getNumber(st); + float z = (float)getNumber(st); + Vector3f pivotPoint = new Vector3f(-x, -y, z); + Transform3D pivotTransform = new Transform3D(); + pivotTransform.set(pivotPoint); + pivotTransGroup = new TransformGroup(pivotTransform); + pivotTransGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + } + + else if (isCurrentToken(st, "ObjDissolve")) { + // Just handle it for now, don't care about value + EnvelopeHandler env = + new EnvelopeHandler(st, totalFrames, totalTime); + } + st.nextToken(); + } + getNumber(st); // skip shadow options parameter + debugOutputLn(LINE_TRACE, "done with LwsObject constructor"); + } + catch (MalformedURLException e) { + throw new FileNotFoundException(e.getMessage()); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + catch (NumberFormatException e) { + throw new ParsingErrorException("Expected a number, got " + + e.getMessage()); + } + } + + /** + * This method takes the given path and filename and checks whether + * that file exists. If not, it chops off the last part of pathname + * and recurse to try again. This has the effect of searching all the + * way up a given pathname for the existence of the file anywhere + * along that path. This is somewhat of a hack to get around the + * constraining way that Lightwave uses to define its data object + * locations in its scene files. + * + * If the filename is absolute, it will use the path information from + * the filename first, then the path information from the lws file. + * If the file can not be found in these locations, the local directory + * will be searched. + * In addition, it will look for filenames converted to lowercase to + * make it easier to use between Windows and Unix. + */ + + String getQualifiedFilename(String pathname, String filename) + throws java.io.FileNotFoundException { + + int index; + String pathname2 = ""; + + // System.out.println ("pathname:"+pathname+" filename:"+filename); + + // Do we have an absolute filename ? + if (filename.indexOf (File.separator) == 0) { + if ((index = filename.lastIndexOf (File.separator)) != -1) { + pathname2 = filename.substring (0, index+1); + filename = filename.substring (index+1); + } + else { + return null; // something out of the ordinary happened + } + } + + // See if we can find the file + // --------------------------- + + // Try pathname from absolute filename + try { + if (new File(pathname2 + filename).exists()) { + return (pathname2 + filename); + } + } + catch (NullPointerException ex) { + ex.printStackTrace(); + } + // Try lowercase filename + if (new File(pathname2 + filename.toLowerCase()).exists()) { + return (pathname2 + filename.toLowerCase()); + } + + // Try original pathname + if (new File(pathname + filename).exists()) { + return (pathname + filename); + } + // Try lowercase filename + if (new File(pathname + filename.toLowerCase()).exists()) { + return (pathname + filename.toLowerCase()); + } + + // Finally, let's check the local directory + if (new File(filename).exists()) { + return (filename); + } + // Try lowercase filename + if (new File(filename.toLowerCase()).exists()) { + return (filename.toLowerCase()); + } + + // Conditions that determine when we give up on the recursive search + if ((pathname.equals(File.separator)) || + (pathname == null) || + (pathname.equals(""))) { + + throw new java.io.FileNotFoundException(filename); + } + + // Try to find the file in the upper directories + // Chop off the last directory from pathname and recurse + StringBuffer newPathName = new StringBuffer(128); + StringTokenizer st = new StringTokenizer(pathname, File.separator); + int tokenCount = st.countTokens() - 1; + if (pathname.startsWith(java.io.File.separator)) + newPathName.append(File.separator); + for (int i = 0; i < tokenCount; ++i) { + String directory = st.nextToken(); + newPathName.append(directory); + newPathName.append(File.separator); + } + + String newPath = newPathName.toString(); + return getQualifiedFilename(newPath, filename); + } + + URL getQualifiedURL(String path, String file) + throws MalformedURLException { + + URL url = null; + + // try the path and the file -- this is the lightwave spec + try { + // create url + url = new URL(path + file); + // see if file exists + url.getContent(); + // return url if no exception is thrown + return url; + } + catch (IOException e) { + // Ignore - try something different + } + + // try a couple other options, but trying to open connections is slow, + // so don't try as many options as getQualifiedFilename + + // try absolute path + try { + url = new URL(file); + url.getContent(); + } + catch (IOException ex) { + // Ignore - try something different + } + + // try the absolute path with the protocol + try { + url = new URL(protocol + ":" + file); + url.getContent(); + return url; + } + catch (IOException ex) { + // Nothing else to try so give up + throw new MalformedURLException(path + file); + } + } + + /** + * Returns parent object + */ + int getParent() { + return parent; + } + + /** + * Adds the given child to the transform of this node (its parent). + */ + void addChild(LwsPrimitive child) { + debugOutputLn(TRACE, "addChild()"); + if (objectTransform != null) { + debugOutputLn(LINE_TRACE, "objectTransform = " + objectTransform); + if (child.getObjectNode() != null) { + debugOutputLn(LINE_TRACE, "child has object node"); + if (hasPivot) + pivotTransGroup.addChild(child.getObjectNode()); + else + objectTransform.addChild(child.getObjectNode()); + } +/* + if (child.getObjectBehaviors() != null) { + debugOutputLn(LINE_TRACE, "child has behaviors"); + Group bg = child.getObjectBehaviors(); + debugOutputLn(VALUES, " child behaviors = " + bg); + // TODO: should remove intermediate group nodes + objectBehavior.addChild(bg); + } +*/ + } + } + + /** + * Creates Java3d objects from the data stored for this object. + * The objects created consist of: A TransformGroup that holds the + * transform specified by the first keyframe, a Behavior that acts + * on the TransformGroup if there are more than 1 keyframes, and + * some geometry (created by J3dLwoParser) from an external geometry + * file (if the object wasn't an lw3d Null object (group)). + */ + void createJava3dObject(LwsObject cloneObject, int loadBehaviors) + throws IncorrectFormatException, ParsingErrorException, + FileNotFoundException + { + String seqToken = new String("_sequence_"); + Matrix4d mat = new Matrix4d(); + mat.setIdentity(); + // Set the node's transform matrix according to the first frame + // of the object's motion + LwsFrame firstFrame = motion.getFirstFrame(); + firstFrame.setMatrix(mat); + Transform3D t1 = new Transform3D(); + t1.set(mat); + objectTransform = new TransformGroup(t1); + objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + + // This following bit is a hack and should probably be removed. + // It was put in here in order to handle the "Tloop" functionality + // of holosketch, which was needed for the 1998 Javaone conference + // (the HighNoon demo, in particular). Having the code here, or + // using it, means that some object file names are tagged as special + // because they contain the phrase "_sequence_", which tells this + // object file reader that that object file is, in fact, a + // sequence file. It then creates a SequenceReader object to + // read that file and create an animation from the objects defined + // in that file. + // See SequenceReader.java for more information on this. + // By the way, a better/fuller implementation of this functionality + // would involve investigating a standard Plug-In for Lightwave + // that allows the writing out of sequence files from Bones data. + // i think it would be better to base any Tloop stuff on that + // standard than on some proprietary hack of our own. + + if (fileName != null && fileName.indexOf(seqToken) != -1) { // Tloop + + int index = fileName.indexOf(seqToken); + index += seqToken.length(); + String seqFilename = fileName.substring(index); + int endIndex = seqFilename.indexOf(".lwo"); + if (endIndex != -1) + seqFilename = seqFilename.substring(0, endIndex); + if ((new File(seqFilename)).exists()) { + SequenceReader sr = + new SequenceReader(seqFilename, + motion.totalTime, + (int)motion.totalFrames); + sr.printLines(); + sr.createJava3dObjects(debugPrinter.getValidOutput(), + loadBehaviors); + Group g = sr.getObjectNode(); + if (g != null) + objectTransform.addChild(g); + + // Sequence reader's getObjectBehaviors creates new Vector + objectBehavior = sr.getObjectBehaviors(); + + return; + } + } + + // Okay, now that that hack is out of the way, let's get on with + // "normal" Lightwave object files. + if (fileName != null || urlName != null) { + // If this object refers to an obj file, load it and create + // geometry from it. + if (cloneObject == null) { + debugOutputLn(VALUES, + "About to load binary file for " + fileName); + // Create a J3dLwoParser object to parse the geometry file + // and create the appropriate geometry + J3dLwoParser objParser = null; + switch (fileType) { + case Lw3dLoader.FILE_TYPE_FILENAME: + objParser = + new J3dLwoParser(fileName, + debugPrinter.getValidOutput()); + break; + case Lw3dLoader.FILE_TYPE_URL: + objParser = new J3dLwoParser(urlName, + debugPrinter.getValidOutput()); + break; + } + objParser.createJava3dGeometry(); + // pivot points change the parent transform + if (hasPivot) { + objectTransform.addChild(pivotTransGroup); + } + if (objParser.getJava3dShapeList() != null) { + shapeList = objParser.getJava3dShapeList(); + for (Enumeration e = shapeList.elements() ; + e.hasMoreElements() ;) { + if (!hasPivot || pivotTransGroup == null) + objectTransform.addChild((Shape3D)e.nextElement()); + else + pivotTransGroup.addChild((Shape3D)e.nextElement()); + } + } + } + else { + // Already read that file: Clone original object + debugOutputLn(LINE_TRACE, "Cloning shapes"); + Vector cloneShapeList = cloneObject.getShapeList(); + for (Enumeration e = cloneShapeList.elements() ; + e.hasMoreElements() ;) { + debugOutputLn(LINE_TRACE, " shape clone"); + Shape3D shape = (Shape3D)e.nextElement(); + Shape3D cloneShape = (Shape3D)shape.cloneTree(); + objectTransform.addChild(cloneShape); + } + } + } + + // Create j3d behaviors for the object's animation + objectBehavior = new Vector(); + if (loadBehaviors != 0) { + motion.createJava3dBehaviors(objectTransform); + Behavior b = motion.getBehaviors(); + if (b != null) + objectBehavior.addElement(b); + } + } + + /** + * Return list of Shape3D objects for this object file. This is used + * when cloning objects (if the scene file requests the same object file + * more than once, that object will be cloned instead of recreated each + * time). + */ + Vector getShapeList() { + return shapeList; + } + + /** + * Return the TransformGroup that holds this object file + */ + public TransformGroup getObjectNode() { + return objectTransform; + } + + /** + * Return the Group that holds this object's behaviors. The behaviors + * are grouped separately from the geometry so that they can be handled + * differently by the parent application. + */ + public Vector getObjectBehaviors() + { + debugOutputLn(TRACE, "getObjectBehaviors()"); + return objectBehavior; + } + + + /** + * Utiliy function to print some of the object values. Used in + * debugging. + */ + void printVals() + { + debugOutputLn(VALUES, " OBJECT vals: "); + debugOutputLn(VALUES, " fileName = " + fileName); + debugOutputLn(VALUES, " objName = " + objName); + motion.printVals(); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsPrimitive.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsPrimitive.java new file mode 100644 index 0000000..a1fdebe --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/LwsPrimitive.java @@ -0,0 +1,68 @@ +/* + * $RCSfile: LwsPrimitive.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + + + +import java.util.Vector; +import javax.media.j3d.Group; +import javax.media.j3d.TransformGroup; + +/** + * This is an interface which is implemented by LwsObject, + * LwsFog, LwsBackground, LwsLight, etc. It provides a generic method + * for objects to access some of the common data in these classes. + */ + +interface LwsPrimitive { + + // interface from which other Lws types (Object, Camera, etc.) + // inherit methods + + public Vector getObjectBehaviors(); + + public TransformGroup getObjectNode(); + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ParserObject.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ParserObject.java new file mode 100644 index 0000000..554e2c6 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ParserObject.java @@ -0,0 +1,91 @@ +/* + * $RCSfile: ParserObject.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +/** + * This class is a superclass of the binary parsing classes. It provides + * some basic debugging utilities. + */ + +class ParserObject { + + + final static int TRACE = DebugOutput.TRACE, VALUES = DebugOutput.VALUES; + final static int MISC = DebugOutput.MISC, LINE_TRACE = DebugOutput.LINE_TRACE; + final static int NONE = DebugOutput.NONE, EXCEPTION = DebugOutput.EXCEPTION; + final static int TIME = DebugOutput.TIME, WARNING = DebugOutput.WARNING; + + protected DebugOutput debugPrinter; + + + ParserObject() { + debugPrinter = new DebugOutput(EXCEPTION); + } + + ParserObject(int debugVals) { + this(); + debugPrinter.setValidOutput(debugVals); + } + + + protected void debugOutputLn(int outputType, String theOutput) { + if (theOutput.equals("")) + debugPrinter.println(outputType, theOutput); + else + debugPrinter.println(outputType, + getClass().getName() + "::" + theOutput); + } + + protected void debugOutput(int outputType, String theOutput) { + debugPrinter.print(outputType, theOutput); + } + + + +} + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceLine.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceLine.java new file mode 100644 index 0000000..e3b2456 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceLine.java @@ -0,0 +1,269 @@ +/* + * $RCSfile: SequenceLine.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.awt.Component; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.StreamTokenizer; +import java.io.IOException; +import javax.media.j3d.*; +import javax.vecmath.Point3d; + +import com.sun.j3d.loaders.IncorrectFormatException; +import com.sun.j3d.loaders.ParsingErrorException; +import java.io.FileNotFoundException; + +/** + * This class was created to handle "sequence files", which allow + * holosketch-type Tloop sequences to be loaded through the lw3d loader. + * The class reads a sequence file line by line and uses SequenceLine to + * load the file specified in each line.
+ * Idea behind the Tloop process:
+ * Artist creates "tloops" (animations with each keyframe's + * geometry saved out explicitly) where the geometries are spaced + * one frame apart. Then I can automatically create a SwitchValueInterpolator + * based on this spacing. If the number of frames in the sequence is + * greater than the number of frames in the tloop, then it will automatically + * loop until the end of the sequence.
+ * Process:
+ * 1) Artist creates an animation of a null group that has a child with some + * special name, such as "bucket_sequence_bucketsequence.txt.lwo", which tells + * the lw3d loader that it should look for a sequence file by the name of + * bucketsequence.txt. What happens to this object is irrelevant (as far as + * the loader is concerned); all animation information is taken from its + * parent instead.
+ * 2) Artist saves out the geometry of the bucket at whatever frames she wants + * to. If she's saving a tloop (a sequence of frames), she should save them + * under the names xxx.lwo, where xxx is the 3-digit sequence number + * (000, 001, 002, etc.).
+ * 3) Artist creates the sequence file, which lists all saved geometry files + * (except sequences - these can be referred to simply by the first file + * (...000.lwo)), along with their associated start/end frames. She also lists + * the number of files in the sequence, although this parameter is implied + * anyway, through the existence of the sequence files and their naming + * convention. Maybe we should trash this guy.
+ * 4) In the lw3d loader, when LwsObject encounters an object with the + * filename "..._sequence_.lwo", it searches for filename. If + * found, it parses the file (using the SequenceReader class) to retrieve + * all parameters.
+ * 5) Each SequenceLine creates a Java3D group containing its objects. This + * is either a plain-old-Group (if there is only one object) or a Switch group + * with a SwitchValueInterpolator.
+ * 6) SequenceReader constructs a Switch group and adds all SequenceLine groups + * to this new group. It also creates a SwitchPathInterpolator (child of + * PathInterolator) that contsructs an Alpha based on the startFrame values of + * each SequenceLine. It creates a group and adds the SwitchPathInterpolator + * plus any SequenceLine SwitchValueInterpolators to this group.
+ * 7) LwsObject adds the SequenceReader Switch group to its objectTransform. + * It does a getBehaviors() from SequenceReader and adds the result (the + * SwitchPathInterpolator group) to its objectBehaviors group.
+ * 8) Done. + */ + +class SequenceLine { + + int startFrame; + int endFrame; + String fileName; + + Group geometryGroup = null; + Behavior behaviors; + int numFrames; + float totalTime; + int totalFrames; + + // storedRefList keeps references to already loaded objects + static Hashtable storedRefList = new Hashtable(); + + SequenceLine(StreamTokenizer st, float time, int frames) + throws ParsingErrorException { + try { + totalTime = time; + totalFrames = frames; + startFrame = (int)st.nval; + st.nextToken(); + endFrame = (int)st.nval; + st.nextToken(); + fileName = st.sval; + numFrames = endFrame - startFrame + 1; + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + + /** + * Creates a SwitchValueInterpolator which is used to switch between + * the objects specified for the sequence. This is done for files + * that end in "000", meaning that there are a sequence of files + * with that same base name that should specify every frame of a + * sequence for an object. The Switch node is used to hold all of the + * files and the Switch Behavior node is used to activate switching + * at the right time and to the right object. + */ + private void createSwitchBehavior(Switch target) { + + int loopCount = -1; + float animTime = 1000.0f * totalTime * + (float)(target.numChildren())/(float)totalFrames; + float startTime = 1000f * totalTime * + (float)startFrame/(float)totalFrames; + Alpha theAlpha = + new Alpha(-1, (long)startTime, 0, (long)animTime, 0, 0); + + SwitchValueInterpolator b=new SwitchValueInterpolator(theAlpha,target); + behaviors = b; + BoundingSphere bounds = + new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0); + b.setSchedulingBounds(bounds); + target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + target.addChild(behaviors); + + } + + /** + * Create Java3d objects from the data in the sequence line. This + * means that for a tloop file (ends in "000"), we're going to create + * the appropriate geometry for each file, put them all in a Switch + * node, then create a SwitchValueInterpolator to swap between the + * frames of the tloop. If it's not a tloop, then we're just going to + * create the geometry for that file. + */ + void createJava3dObjects(int debugVals, int loadBehaviors) + throws IncorrectFormatException, FileNotFoundException { + if (fileName.indexOf("000") != -1) { // Tloop + int index = fileName.indexOf("000"); + String fileNameBase = fileName.substring(0, index); + Switch s = new Switch(); + s.setCapability(Switch.ALLOW_SWITCH_READ); + s.setCapability(Switch.ALLOW_SWITCH_WRITE); + String tempFileName = fileName; + int fileNum = 0; + while ((new File(tempFileName)).exists()) { + if (storedRefList.get(tempFileName) != null) { + // System.out.println("retrieve stored version of " + + // tempFileName); + SharedGroup storedGroup = + (SharedGroup)storedRefList.get(tempFileName); + Link newLink = new Link(storedGroup); + s.addChild(newLink); + } + else { + // System.out.println("reading " + tempFileName); + J3dLwoParser objParser = new J3dLwoParser(tempFileName, + debugVals); + objParser.createJava3dGeometry(); + TransformGroup t = new TransformGroup(); + SharedGroup newSharedGroup = new SharedGroup(); + storedRefList.put(tempFileName, newSharedGroup); + newSharedGroup.addChild(t); + Link newLink = new Link(newSharedGroup); + s.addChild(newLink); + if (objParser.getJava3dShapeList() != null) { + for (Enumeration e = + objParser.getJava3dShapeList().elements() ; + e.hasMoreElements() ;) { + t.addChild((Shape3D)e.nextElement()); + } + } + } + ++fileNum; + String fileNumString = String.valueOf(fileNum); + if (fileNum < 10) + fileNumString = "00" + fileNumString; + else if (fileNum < 100) + fileNumString = "0" + fileNumString; + tempFileName = fileNameBase + fileNumString + ".lwo"; + } + behaviors = null; + if (loadBehaviors != 0) { + createSwitchBehavior(s); + } + geometryGroup = (Group)s; + } + else {// Not a tloop, just a file + geometryGroup = new Group(); + if (storedRefList.get(fileName) != null) { + // System.out.println("getting old ref to " + fileName); + SharedGroup storedGroup = + (SharedGroup)storedRefList.get(fileName); + Link newLink = new Link(storedGroup); + geometryGroup.addChild(newLink); + } + else { + // System.out.println("reading " + fileName); + J3dLwoParser objParser = new J3dLwoParser(fileName, + debugVals); + objParser.createJava3dGeometry(); + TransformGroup t = new TransformGroup(); + if (objParser.getJava3dShapeList() != null) { + for (Enumeration e = objParser.getJava3dShapeList().elements() ; + e.hasMoreElements() ;) { + t.addChild((Shape3D)e.nextElement()); + } + } + SharedGroup newSharedGroup = new SharedGroup(); + newSharedGroup.addChild(t); + Link newLink = new Link(newSharedGroup); + geometryGroup.addChild(newLink); + storedRefList.put(fileName, newSharedGroup); + } + } + } + + Group getGeometry() { + return geometryGroup; + } + + Behavior getBehavior() { + return behaviors; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceReader.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceReader.java new file mode 100644 index 0000000..4e777e4 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceReader.java @@ -0,0 +1,172 @@ +/* + * $RCSfile: SequenceReader.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.awt.Component; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.StreamTokenizer; +import java.io.IOException; +import javax.media.j3d.*; +import javax.vecmath.Point3d; + +import com.sun.j3d.loaders.IncorrectFormatException; +import com.sun.j3d.loaders.ParsingErrorException; +import java.io.FileNotFoundException; + +/** + * This class was created to read a special file format devised for + * JavaOne '98 that allowed Tloop functionality inside of Lightwave. It + * would be best to find a more standard solution, including using some + * plug-in for lw3d that I've heard of that allows artists to automatically + * save out the geometry for a file at every frame. + */ + +class SequenceReader { + + + Vector sequenceLines; + float totalTime; + int totalFrames; + + TransformGroup objectTransform; + Vector behaviorVector; + + /** + * Constructor: parses a sequence file and creates a new SequenceLine + * object to read in every line of the file + */ + SequenceReader(String filename, float time, int frames) + throws ParsingErrorException { + totalTime = time; + totalFrames = frames; + sequenceLines = new Vector(); + try { + // System.out.println("reading sequence from " + filename); + StreamTokenizer st = new StreamTokenizer(new BufferedReader( + new FileReader(filename))); + st.wordChars('_', '_'); + st.wordChars('/', '/'); + int type = st.nextToken(); + while (st.ttype != StreamTokenizer.TT_EOF) { + sequenceLines.addElement(new SequenceLine(st, + totalTime, + totalFrames)); + st.nextToken(); + } + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + + /** + * Creates Java3D objects from the data defined in the sequence + * file. Calls each sequenceLine object to create its own + * j3d objects, then puts all of those objects in a single Switch + * node. Finally, it creates a SwitchPathInterpolator object which + * handles switching between each object/s defined by each line + */ + void createJava3dObjects(int debugVals, int loadBehaviors) + throws FileNotFoundException { + + objectTransform = new TransformGroup(); + behaviorVector = new Vector(); + Enumeration e = sequenceLines.elements(); + Switch switchNode = new Switch(); + switchNode.setCapability(Switch.ALLOW_SWITCH_READ); + switchNode.setCapability(Switch.ALLOW_SWITCH_WRITE); + objectTransform.addChild(switchNode); + while (e.hasMoreElements()) { + SequenceLine line = (SequenceLine)e.nextElement(); + line.createJava3dObjects(debugVals, loadBehaviors); + if (line.getGeometry() != null) + switchNode.addChild(line.getGeometry()); + //objectTransform.addChild(line.getGeometry()); + if (line.getBehavior() != null) { + behaviorVector.addElement(line.getBehavior()); + } + } + float knots[] = new float[sequenceLines.size() + 1]; + for (int i = 0; i < knots.length-1; ++i) { + SequenceLine sl = (SequenceLine)sequenceLines.elementAt(i); + knots[i] = (float)sl.startFrame/(float)totalFrames; + } + knots[knots.length-1] = 1.0f; + Alpha theAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, + 0, 0, (long)(1000f * totalTime), 0, + 0, 0, 0, 0); + + SwitchPathInterpolator switchPath = + new SwitchPathInterpolator(theAlpha, + knots, + switchNode); + BoundingSphere bounds = + new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0); + switchPath.setSchedulingBounds(bounds); + switchNode.addChild(switchPath); + behaviorVector.addElement(switchPath); + } + + TransformGroup getObjectNode() { + return objectTransform; + } + + Vector getObjectBehaviors() { + return behaviorVector; + } + + void printLines() { + Enumeration e = sequenceLines.elements(); + while (e.hasMoreElements()) { + SequenceLine line = (SequenceLine)e.nextElement(); + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ShapeHolder.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ShapeHolder.java new file mode 100644 index 0000000..d32260c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/ShapeHolder.java @@ -0,0 +1,267 @@ +/* + * $RCSfile: ShapeHolder.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.util.Vector; +import javax.vecmath.Vector3f; + + +/** + * This class holds all of the vertex/facet/normal/surface-reference + * data for a particular object. It has utilities to calculate facet normals, + * but this is no longer in use since using the new GeomInfo utilities. + */ + +class ShapeHolder extends ParserObject { + + + Vector facetSizesList; + Vector facetIndicesList; + int facetIndicesArray[]; + int currentNumIndices = 0; + int numSurf; + int numVerts; + int facetIndices[]; + int facetSizes[]; + int normalIndices[]; + float normalCoords[]; + float coordsArray[]; + + ShapeHolder() { + } + + ShapeHolder(int debugVals) { + super(debugVals); + } + + + /** + * Print out (to stdout) the geometry data (coords, indices, + * and facet sizes). This is a debugging utility. + */ + void printGeometryData(LwoSurface surface) { + int i, j; + int indicesIndex = 0; + System.out.println("\nPolygon Data:"); + System.out.println(" Surface color = " + surface.color); + System.out.println(" Surface diffuse = " + surface.diffuseColor); + for (i = 0; i < facetSizes.length; ++i) { + int polySize = facetSizes[i]; + System.out.println("Facet of size " + polySize); + for (j = 0; j < polySize; ++j) { + int coordIndex = 3 * facetIndices[indicesIndex++]; + System.out.println("x, y, z = " + + coordsArray[coordIndex] + ", " + + coordsArray[coordIndex+1] + ", " + + coordsArray[coordIndex+2]); + } + } + } + + /** + * Constructs geometry arrays given a winding rule (it turns out that + * lw3d winding is opposite of j3d winding, so this is always set to + * true in J3dLwoParser) + */ + void createArrays(boolean reverseWinding) { + debugOutputLn(TRACE, "createArrays()"); + // debugOutputLn(VALUES, "facetIndices, faceSizesList = " + + // facetIndicesList + facetSizesList); + //debugOutputLn(VALUES, "ind and sizes size " + + // facetIndicesList.size() + ", " + + // facetSizesList.size()); + //facetIndices = + // new int[facetIndicesList.size()]; + facetIndices = new int[currentNumIndices]; + if (reverseWinding) { + int facetBeginIndex = 0; + for (int facetIndex = 0; + facetIndex < facetSizesList.size(); + ++facetIndex) { + int currFaceSize = + ((Integer)facetSizesList.elementAt(facetIndex)).intValue(); + int tempFace[] = new int[currFaceSize]; + for (int j = 0; j < currFaceSize; ++j) { + facetIndices[facetBeginIndex + j] = + facetIndicesArray[facetBeginIndex + + currFaceSize - j - 1]; + } + facetBeginIndex += currFaceSize; + } + + } + else { + for (int i = 0; i < facetIndices.length; ++i) { + facetIndices[i] = facetIndicesArray[i]; + } + } + + debugOutputLn(LINE_TRACE, "facetIndices.len and coordsArray.len = " + + facetIndices.length + ", " + coordsArray.length); + if (((Integer)facetSizesList.elementAt(0)).intValue() < 3) { + // if we're dealing with point/line primitives, then let's abandon + // the indexed route and simply construct a new coordsArray + // that holds the direct values we need for a GeometryArray + // object + debugOutputLn(LINE_TRACE, "Using direct geometry because " + + "facetIndices is of size " + + facetIndices.length + + " and coordsArray is of length "+ + coordsArray.length); + float newCoordsArray[] = new float[facetIndices.length * 3]; + int newCoordsIndex = 0; + for (int i = 0; i < facetIndices.length; ++i) { + newCoordsArray[newCoordsIndex++] = + coordsArray[facetIndices[i]*3]; + newCoordsArray[newCoordsIndex++] = + coordsArray[facetIndices[i]*3+1]; + newCoordsArray[newCoordsIndex++] = + coordsArray[facetIndices[i]*3+2]; + } + coordsArray = newCoordsArray; + facetIndices = null; + } + + facetSizes = + new int[facetSizesList.size()]; + for (int i = 0; i < facetSizes.length; ++i) { + facetSizes[i] = + ((Integer)facetSizesList.elementAt(i)).intValue(); + } + + facetSizesList = null; // Force garbage collection on Vectors + facetIndicesList = null; + facetIndicesArray = null; + } + + /** + * Force gc on all array objects + */ + void nullify() { + facetSizesList = null; // Force garbage collection on everything + facetIndicesList = null; + facetIndicesArray = null; + facetSizes = null; + facetIndices = null; + normalCoords = null; + normalIndices = null; + } + + /** + * This method calculates facet normals for the geometry. It is no + * longer used, as we're now using the GeometryInfo utility to calculate + * smooth normals + */ + void calcNormals() { + debugOutputLn(TRACE, "calcNormals()"); + debugOutputLn(LINE_TRACE, "coordsLength, facetsizes.len = " + + coordsArray.length + ", " + facetSizes.length); + if (facetSizes[0] > 2) { + // points and lines don't need normals, polys do + if (facetIndices != null) { + normalIndices = new int[facetIndices.length]; + normalCoords = new float[facetIndices.length * 3]; + } + else { + normalCoords = new float[coordsArray.length]; + } + debugOutputLn(LINE_TRACE, "normalCoords, incides len = " + + normalCoords.length + ", " + + ((facetIndices == null) ? 0 : normalIndices.length)); + int facetIndex = 0; + int tempIndex = -1; + for (int i = 0; i < facetSizes.length; i += 1) { + Vector3f norm; + int currFacetSize = facetSizes[i]; + //debugOutputLn(LINE_TRACE, " i, facetIndex, currSize = " + + // i + ", " + facetIndex + ", " + currFacetSize); + if (currFacetSize < 3) { + // This shouldn't occur + norm = new Vector3f(0f, 0f, 1f); + } + else { + Vector3f v1, v2; + int index1, index2, index3; + if (facetIndices != null) { + index1 = facetIndices[facetIndex]; + index2 = facetIndices[facetIndex+1]; + index3 = facetIndices[facetIndex+2]; + //debugOutputLn(VALUES, " index123 = " + + // index1 + ", " + index2 + ", " + index3); + } + else { + index1 = facetIndex; + index2 = facetIndex+1; + index3 = facetIndex+2; + } + v1 = new + Vector3f(coordsArray[index2*3] - coordsArray[index1*3], + coordsArray[index2*3+1] - coordsArray[index1*3+1], + coordsArray[index2*3+2] - coordsArray[index1*3+2]); + v2 = new + Vector3f(coordsArray[index3*3] - coordsArray[index1*3], + coordsArray[index3*3+1] - coordsArray[index1*3+1], + coordsArray[index3*3+2] - coordsArray[index1*3+2]); + //debugOutputLn(VALUES, "v1, v2 = " + v1 + v2); + norm = new Vector3f(); + norm.cross(v1, v2); + norm.normalize(norm); + } + + for (int j = 0; j < currFacetSize; ++j) { + int normIndex = facetIndex + j; + normalCoords[normIndex*3] = norm.x; + normalCoords[normIndex*3+1] = norm.y; + normalCoords[normIndex*3+2] = norm.z; + if (facetIndices != null) + normalIndices[normIndex] = normIndex; + } + facetIndex += currFacetSize; + } + } + debugOutputLn(TRACE, "done with calcNormals()"); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SwitchPathInterpolator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SwitchPathInterpolator.java new file mode 100644 index 0000000..8245538 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/SwitchPathInterpolator.java @@ -0,0 +1,129 @@ +/* + * $RCSfile: SwitchPathInterpolator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + + package com.sun.j3d.loaders.lw3d; + + +import javax.vecmath.*; +import java.util.BitSet; +import java.util.Enumeration; + +import javax.media.j3d.Alpha; +import javax.media.j3d.Node; +import javax.media.j3d.NodeReferenceTable; +import javax.media.j3d.SceneGraphObject; +import javax.media.j3d.Switch; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * This class was used in conjunction with SequenceReader to create + * Tloop functionality inside of Lightwave files. This behavior handles + * the switching between objects defined in separate lines of a + * sequence file. That is, each line in a sequence file has the name + * of an object (or an object sequence, if the name ends in "000") + * and details the start and end frames that that object should be active. + * This class determines which object/s defined in the file should be active + * at any given time during the animation. + */ + +class SwitchPathInterpolator extends FloatValueInterpolator { + + Switch target; + int firstSwitchIndex; + int lastSwitchIndex; + int currentChild; + int childCount; + + /** + * Constructs a new SwitchPathInterpolator object. + * @param alpha the alpha object for this interpolator + * @param knots an array of knot values that specify a spline + */ + SwitchPathInterpolator(Alpha alpha, float knots[], Switch target) { + + super(alpha, knots, new float[knots.length]); + + if (knots.length != (target.numChildren() + 1)) + throw new IllegalArgumentException(J3dUtilsI18N.getString("SwitchPathInterpolator0")); + + this.target = target; + firstSwitchIndex = 0; + lastSwitchIndex = target.numChildren() - 1; + childCount = lastSwitchIndex + 1; + } + + /** + * This method sets the correct child for the Switch node according + * to alpha + * @param criteria enumeration of criteria that have triggered this wakeup + */ + + public void processStimulus(Enumeration criteria) { + + int child; + + // Handle stimulus + if (this.getAlpha() != null) { + + // Let PathInterpolator calculate the correct + // interpolated knot point + computePathInterpolation(); + + if (currentKnotIndex > 0) + child = currentKnotIndex - 1; + else + child = 0; + + if (target.getWhichChild() != child) { + target.setWhichChild(child); + } + + if ((this.getAlpha()).finished()) + return; + } + + wakeupOn(defaultWakeupCriterion); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/TargaReader.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/TargaReader.java new file mode 100644 index 0000000..573d8c9 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/TargaReader.java @@ -0,0 +1,199 @@ +/* + * $RCSfile: TargaReader.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.applet.Applet; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.MediaTracker; +import java.awt.Frame; +import java.awt.Image; +import java.awt.image.MemoryImageSource; +import java.awt.Toolkit; +import java.io.FileNotFoundException; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import com.sun.j3d.loaders.IncorrectFormatException; +import com.sun.j3d.loaders.ParsingErrorException; +import java.io.IOException; + +/** + * This class parses a standard Targa file and retrieves the image stored + * therein, storing the pixel data in a BufferedImage. + */ + +class TargaReader extends ParserObject { + + BufferedInputStream bufferedReader; + Image theImage = null; + + /** + * Constructor: creates file reader and calls parseFile() to do the real + * work + */ + TargaReader(String fileName, int debugVals) throws FileNotFoundException { + super(debugVals); + debugOutputLn(TRACE, "constructor"); + bufferedReader = new BufferedInputStream( + new DataInputStream(new FileInputStream(fileName))); + if (bufferedReader != null) + parseFile(); + } + + /** + * Returns the image that was created from parsing the targa file (null + * if the file reading failed) + */ + Image getImage() { + return theImage; + } + + /** + * This method parses the file and stores the pixel data in a + * BufferedImage. The basic file format is: + * Byte Description + * + * 0 Image ID Length + * 1 Colormap type + * 2 Image Type + * 3-4 Colormap spec: 1st entry index + * 5-6 Colormap spec: length + * 7 Colormap spec: entry size + * 8-9 X-origin of lower-left corner + * 10-11 Y-origin of lower-left corner + * 12-13 Image width + * 14-15 Image height + * 16 Pixel depth + * 17 00(origin)(alpha) + * first 2 bytes 0, next 2 starting corner, + * last four number of overlay bits per pixel + * 18- Image ID + * ?? Colormap data + * ?? Image Data + * ?? Developer Area + * ?? Extension Area + * ?? File Footer + * + * We're going to make some assumptions about the format of files we're + * asked to load. In particular, we're not going to do any colormpa-based + * images: the images need to be either 24-bit or 32-bit true color. + * We're also going to ignore vaiours parameters in the header block, since + * they complicate life and don't appear to be used in Lightwave image + * files. In particular, the following fields will be ignored: + * Image ID, colormap info, xy origins, and alpha/overlay bits. + */ + + void parseFile() + throws IncorrectFormatException, ParsingErrorException { + try { + int idLength = bufferedReader.read(); + int colormapPresent = bufferedReader.read(); + int imageType = bufferedReader.read(); + bufferedReader.skip(9); // skipping camp and xy origin data + int width = bufferedReader.read() | bufferedReader.read() << 8; + int height = bufferedReader.read() | bufferedReader.read() << 8; + int depth = bufferedReader.read(); + int flags = bufferedReader.read(); + boolean bottomToTop = ((flags & 0x20) == 0); + boolean leftToRight = ((flags & 0x10) == 0); + bufferedReader.skip(idLength); + + // Check on the file parameters to see whether we should punt + if ((colormapPresent == 1) || + imageType != 2 || + (depth != 24 && + depth != 32)) { + // Punt + throw new IncorrectFormatException( + "This format is not readable by the Lightwave " + + "loader. Only 24- or 32-bit true-color " + + "uncompressed Targa images will work"); + } + + // Image format must be okay for us to read + BufferedImage bImage = + new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + int[] imageBits = + ((DataBufferInt)bImage.getRaster().getDataBuffer()).getData(); + + int row; + int column; + + for (int i = 0; i < height; ++i) { + if (bottomToTop) + row = (height - i - 1); + else + row = i; + for (int j = 0; j < width; ++j) { + + if (leftToRight) + column = j; + else + column = (width - j - 1); + + int blue = bufferedReader.read(); + int green = bufferedReader.read(); + int red = bufferedReader.read(); + int alpha = 0xff; + if (depth == 32) + alpha = bufferedReader.read(); + imageBits[row*width + column] = alpha << 24 | + red << 16 | + green << 8 | + blue; + } + } + theImage = bImage; + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/TextfileParser.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/TextfileParser.java new file mode 100644 index 0000000..b05a0cd --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/TextfileParser.java @@ -0,0 +1,245 @@ +/* + * $RCSfile: TextfileParser.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.lw3d; + +import java.io.*; +import com.sun.j3d.loaders.ParsingErrorException; + +/** + * This class is a superclass for most of the Lws* Scene-file parsing + * classes. It provides some debugging utilities, as well as utilities for + * reading the types of data common to this loader. + */ + +class TextfileParser { + + // class variables + static int WORD = StreamTokenizer.TT_WORD; + static int NUMBER = StreamTokenizer.TT_NUMBER; + int currentLevel = 3; + final static int TRACE = DebugOutput.TRACE, VALUES = DebugOutput.VALUES; + final static int MISC = DebugOutput.MISC, LINE_TRACE = DebugOutput.LINE_TRACE; + final static int NONE = DebugOutput.NONE, EXCEPTION = DebugOutput.EXCEPTION; + final static int TIME = DebugOutput.TIME; + protected DebugOutput debugPrinter; + char lineSeparatorChar = 0; + + TextfileParser() { + debugPrinter = new DebugOutput(EXCEPTION); + String lineSeparator = System.getProperty("line.separator"); + lineSeparatorChar = lineSeparator.charAt(0); + debugOutputLn(VALUES, "lineSeparatorChar = " + (int)lineSeparatorChar); + } + + + protected void debugOutputLn(int outputType, String theOutput) { + if (theOutput.equals("")) + debugPrinter.println(outputType, theOutput); + else { + debugPrinter.println(outputType, + getClass().getName() + "::" + theOutput); + } + } + + protected void debugOutput(int outputType, String theOutput) { + debugPrinter.print(outputType, theOutput); + } + + /** + * Utility method to advance the tokenizer until we see the given + * string. This is used to skip by various parameters that we + * currently ignore in the loader. + */ + void skipUntilString(StreamTokenizer st, String theString) + throws ParsingErrorException { + boolean done = false; + try { + while (!done) { + st.nextToken(); + if (st.ttype == WORD && + st.sval.equals(theString)) + done = true; + } + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + + + /** + * Returns number from the tokenizer. Note that we don't recognize + * numbers in the tokenizer automatically because numbers might be in + * scientific notation, which isn't processed correctly by + * StreamTokenizer + */ + double getNumber(StreamTokenizer st) + throws ParsingErrorException, NumberFormatException { + try { + int token = st.nextToken(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + checkType(st, WORD); + return ((Double.valueOf(st.sval)).doubleValue()); + } + + /** + * Returns String from the tokenizer + */ + String getString(StreamTokenizer st) throws ParsingErrorException { + try { + st.nextToken(); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + checkType(st, WORD); + return (st.sval); + } + + /** + * Returns a "name" from the stream. This is different from simply a + * String because the name could contain whitespace characters + * (such as "object 1" or "objectname (sequence)") that would confuse + * the string parser. So we just grab all characters until EOL and + * concatenate them together to form the name + */ + String getName(StreamTokenizer st) throws ParsingErrorException { + String theName = ""; + st.ordinaryChar(lineSeparatorChar); + st.ordinaryChar('\n'); + st.ordinaryChar('\r'); + try { + st.nextToken(); + while (st.ttype != lineSeparatorChar && + st.ttype != '\r' && + st.ttype != '\n') { + if (st.ttype != '(' && + st.ttype != ')') + theName += st.sval; + st.nextToken(); + } + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + st.whitespaceChars(lineSeparatorChar, lineSeparatorChar); + st.whitespaceChars('\n', '\n'); + st.whitespaceChars('\r', '\r'); + debugOutputLn(VALUES, "name = " + theName); + return theName; + } + + /** + * Gets the next token and ensures that it is the string we were + * expecting to see + */ + void getAndCheckString(StreamTokenizer st, String expectedValue) + throws ParsingErrorException { + try { + st.nextToken(); + checkString(st, expectedValue); + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + + /** + * Error checking routine - makes sure the current token is the string + * we were expecting + */ + void checkString(StreamTokenizer st, String theString) throws + ParsingErrorException { + if (!(st.ttype == StreamTokenizer.TT_WORD) || + !st.sval.equals(theString)) + throw new ParsingErrorException( + "Bad String Token (wanted " + theString + ", got " + st.sval + + ": " + st.toString()); + } + + /** + * Error checking routine - makes sure the current token is of the right + * type + */ + void checkType(StreamTokenizer st, int theType) + throws ParsingErrorException { + if (!(st.ttype == theType)) + throw new ParsingErrorException( + "Bad Type Token, Expected " + theType + " and received" + + st.ttype); + } + + /** + * Utility routine - gets next token, checks it against our expectation, + * then skips a given number of tokens. This can be used to parse + * through (and ignore) certain parameter/value sets in the files + */ + void skip(StreamTokenizer st, String tokenString, int skipVals) + throws ParsingErrorException { + try { + st.nextToken(); + checkString(st, tokenString); + for (int i = 0; i < skipVals; ++i) { + st.nextToken(); + } + } + catch (IOException e) { + throw new ParsingErrorException(e.getMessage()); + } + } + + /** + * Utility method- used to check whether the current token is equal + * to the given string + */ + boolean isCurrentToken(StreamTokenizer st, String tokenString) { + if (st.ttype == WORD) + return (st.sval.equals(tokenString)); + return false; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/package.html new file mode 100644 index 0000000..e87c100 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/lw3d/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.loaders.lw3d + + +

Provides a Java 3D loader for Lightwave 3D scene files.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/DefaultMaterials.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/DefaultMaterials.java new file mode 100644 index 0000000..994f5d7 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/DefaultMaterials.java @@ -0,0 +1,952 @@ +/* + * $RCSfile: DefaultMaterials.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:10 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.objectfile; + +/** + * This class provides default materials for the object file loader + */ +class DefaultMaterials { + /** + * String that describes the default materials. + */ + static final String materials = + "newmtl amber\n" + + "Ka 0.0531 0.0531 0.0531\n" + + "Kd 0.5755 0.2678 0.0000\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl amber_trans\n" + + "Ka 0.0531 0.0531 0.0531\n" + + "Kd 0.5755 0.2678 0.0000\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "d 0.8400\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl charcoal\n" + + "Ka 0.0082 0.0082 0.0082\n" + + "Kd 0.0041 0.0041 0.0041\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl lavendar\n" + + "Ka 0.1281 0.0857 0.2122\n" + + "Kd 0.2187 0.0906 0.3469\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl navy_blue\n" + + "Ka 0.0000 0.0000 0.0490\n" + + "Kd 0.0000 0.0000 0.0531\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl pale_green\n" + + "Ka 0.0444 0.0898 0.0447\n" + + "Kd 0.0712 0.3796 0.0490\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl pale_pink\n" + + "Ka 0.0898 0.0444 0.0444\n" + + "Kd 0.6531 0.2053 0.4160\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl pale_yellow\n" + + "Ka 0.3606 0.3755 0.0935\n" + + "Kd 0.6898 0.6211 0.1999\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl peach\n" + + "Ka 0.3143 0.1187 0.0167\n" + + "Kd 0.6367 0.1829 0.0156\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl periwinkle\n" + + "Ka 0.0000 0.0000 0.1184\n" + + "Kd 0.0000 0.0396 0.8286\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl redwood\n" + + "Ka 0.0204 0.0027 0.0000\n" + + "Kd 0.2571 0.0330 0.0000\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl smoked_glass\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 0.0041 0.0041 0.0041\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "d 0.9800\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl aqua_filter\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 0.3743 0.6694 0.5791\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "d 0.9800\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl yellow_green\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 0.1875 0.4082 0.0017\n" + + "Ks 0.1878 0.1878 0.1878\n" + + "illum 2\n" + + "Ns 91.4700\n" + + "\n" + + "newmtl bluetint\n" + + "Ka 0.1100 0.4238 0.5388\n" + + "Kd 0.0468 0.7115 0.9551\n" + + "Ks 0.3184 0.3184 0.3184\n" + + "illum 9\n" + + "d 0.5700\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl plasma\n" + + "Ka 0.4082 0.0816 0.2129\n" + + "Kd 1.0000 0.0776 0.4478\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 9\n" + + "d 0.7500\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl emerald\n" + + "Ka 0.0470 1.0000 0.0000\n" + + "Kd 0.0470 1.0000 0.0000\n" + + "Ks 0.2000 0.2000 0.2000\n" + + "illum 9\n" + + "d 0.7500\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl ruby\n" + + "Ka 1.0000 0.0000 0.0000\n" + + "Kd 1.0000 0.0000 0.0000\n" + + "Ks 0.2000 0.2000 0.2000\n" + + "illum 9\n" + + "d 0.7500\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl sapphire\n" + + "Ka 0.0235 0.0000 1.0000\n" + + "Kd 0.0235 0.0000 1.0000\n" + + "Ks 0.2000 0.2000 0.2000\n" + + "illum 9\n" + + "d 0.7500\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl white\n" + + "Ka 0.4000 0.4000 0.4000\n" + + "Kd 1.0000 1.0000 1.0000\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl red\n" + + "Ka 0.4449 0.0000 0.0000\n" + + "Kd 0.7714 0.0000 0.0000\n" + + "Ks 0.8857 0.0000 0.0000\n" + + "illum 2\n" + + "Ns 136.4300\n" + + "\n" + + "newmtl blue_pure\n" + + "Ka 0.0000 0.0000 0.5000\n" + + "Kd 0.0000 0.0000 1.0000\n" + + "Ks 0.0000 0.0000 0.5000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl lime\n" + + "Ka 0.0000 0.5000 0.0000\n" + + "Kd 0.0000 1.0000 0.0000\n" + + "Ks 0.0000 0.5000 0.0000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl green\n" + + "Ka 0.0000 0.2500 0.0000\n" + + "Kd 0.0000 0.2500 0.0000\n" + + "Ks 0.0000 0.2500 0.0000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl yellow\n" + + "Ka 1.0000 0.6667 0.0000\n" + + "Kd 1.0000 0.6667 0.0000\n" + + "Ks 1.0000 0.6667 0.0000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl purple\n" + + "Ka 0.5000 0.0000 1.0000\n" + + "Kd 0.5000 0.0000 1.0000\n" + + "Ks 0.5000 0.0000 1.0000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl orange\n" + + "Ka 1.0000 0.1667 0.0000\n" + + "Kd 1.0000 0.1667 0.0000\n" + + "Ks 1.0000 0.1667 0.0000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl grey\n" + + "Ka 0.5000 0.5000 0.5000\n" + + "Kd 0.1837 0.1837 0.1837\n" + + "Ks 0.5000 0.5000 0.5000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl rubber\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 0.0100 0.0100 0.0100\n" + + "Ks 0.1000 0.1000 0.1000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl flaqua\n" + + "Ka 0.0000 0.4000 0.4000\n" + + "Kd 0.0000 0.5000 0.5000\n" + + "illum 1\n" + + "\n" + + "newmtl flblack\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 0.0041 0.0041 0.0041\n" + + "illum 1\n" + + "\n" + + "newmtl flblue_pure\n" + + "Ka 0.0000 0.0000 0.5592\n" + + "Kd 0.0000 0.0000 0.7102\n" + + "illum 1\n" + + "\n" + + "newmtl flgrey\n" + + "Ka 0.2163 0.2163 0.2163\n" + + "Kd 0.5000 0.5000 0.5000\n" + + "illum 1\n" + + "\n" + + "newmtl fllime\n" + + "Ka 0.0000 0.3673 0.0000\n" + + "Kd 0.0000 1.0000 0.0000\n" + + "illum 1\n" + + "\n" + + "newmtl florange\n" + + "Ka 0.6857 0.1143 0.0000\n" + + "Kd 1.0000 0.1667 0.0000\n" + + "illum 1\n" + + "\n" + + "newmtl flpurple\n" + + "Ka 0.2368 0.0000 0.4735\n" + + "Kd 0.3755 0.0000 0.7510\n" + + "illum 1\n" + + "\n" + + "newmtl flred\n" + + "Ka 0.4000 0.0000 0.0000\n" + + "Kd 1.0000 0.0000 0.0000\n" + + "illum 1\n" + + "\n" + + "newmtl flyellow\n" + + "Ka 0.7388 0.4925 0.0000\n" + + "Kd 1.0000 0.6667 0.0000\n" + + "illum 1\n" + + "\n" + + "newmtl pink\n" + + "Ka 0.9469 0.0078 0.2845\n" + + "Kd 0.9878 0.1695 0.6702\n" + + "Ks 0.7429 0.2972 0.2972\n" + + "illum 2\n" + + "Ns 106.2000\n" + + "\n" + + "newmtl flbrown\n" + + "Ka 0.0571 0.0066 0.0011\n" + + "Kd 0.1102 0.0120 0.0013\n" + + "illum 1\n" + + "\n" + + "newmtl brown\n" + + "Ka 0.1020 0.0185 0.0013\n" + + "Kd 0.0857 0.0147 0.0000\n" + + "Ks 0.1633 0.0240 0.0000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl glass\n" + + "Ka 1.0000 1.0000 1.0000\n" + + "Kd 0.4873 0.4919 0.5306\n" + + "Ks 0.6406 0.6939 0.9020\n" + + "illum 2\n" + + "Ns 200.0000\n" + + "\n" + + "newmtl flesh\n" + + "Ka 0.4612 0.3638 0.2993\n" + + "Kd 0.5265 0.4127 0.3374\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl aqua\n" + + "Ka 0.0000 0.4000 0.4000\n" + + "Kd 0.0000 0.5000 0.5000\n" + + "Ks 0.5673 0.5673 0.5673\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl black\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 0.0020 0.0020 0.0020\n" + + "Ks 0.5184 0.5184 0.5184\n" + + "illum 2\n" + + "Ns 157.3600\n" + + "\n" + + "newmtl silver\n" + + "Ka 0.9551 0.9551 0.9551\n" + + "Kd 0.6163 0.6163 0.6163\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl dkblue_pure\n" + + "Ka 0.0000 0.0000 0.0449\n" + + "Kd 0.0000 0.0000 0.1347\n" + + "Ks 0.0000 0.0000 0.5673\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl fldkblue_pure\n" + + "Ka 0.0000 0.0000 0.0449\n" + + "Kd 0.0000 0.0000 0.1347\n" + + "illum 1\n" + + "\n" + + "newmtl dkgreen\n" + + "Ka 0.0000 0.0122 0.0000\n" + + "Kd 0.0058 0.0245 0.0000\n" + + "Ks 0.0000 0.0490 0.0000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl dkgrey\n" + + "Ka 0.0490 0.0490 0.0490\n" + + "Kd 0.0490 0.0490 0.0490\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl ltbrown\n" + + "Ka 0.1306 0.0538 0.0250\n" + + "Kd 0.2776 0.1143 0.0531\n" + + "Ks 0.3000 0.1235 0.0574\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl fldkgreen\n" + + "Ka 0.0000 0.0122 0.0000\n" + + "Kd 0.0058 0.0245 0.0000\n" + + "illum 1\n" + + "\n" + + "newmtl flltbrown\n" + + "Ka 0.1306 0.0538 0.0250\n" + + "Kd 0.2776 0.1143 0.0531\n" + + "illum 1\n" + + "\n" + + "newmtl tan\n" + + "Ka 0.4000 0.3121 0.1202\n" + + "Kd 0.6612 0.5221 0.2186\n" + + "Ks 0.5020 0.4118 0.2152\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl fltan\n" + + "Ka 0.4000 0.3121 0.1202\n" + + "Kd 0.6612 0.4567 0.1295\n" + + "illum 1\n" + + "\n" + + "newmtl brzskin\n" + + "Ka 0.4408 0.2694 0.1592\n" + + "Kd 0.3796 0.2898 0.2122\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 25.0000\n" + + "\n" + + "newmtl lips\n" + + "Ka 0.4408 0.2694 0.1592\n" + + "Kd 0.9265 0.2612 0.2898\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 25.0000\n" + + "\n" + + "newmtl redorange\n" + + "Ka 0.3918 0.0576 0.0000\n" + + "Kd 0.7551 0.0185 0.0000\n" + + "Ks 0.4694 0.3224 0.1667\n" + + "illum 2\n" + + "Ns 132.5600\n" + + "\n" + + "newmtl blutan\n" + + "Ka 0.4408 0.2694 0.1592\n" + + "Kd 0.0776 0.2571 0.2041\n" + + "Ks 0.1467 0.1469 0.0965\n" + + "illum 2\n" + + "Ns 25.0000\n" + + "\n" + + "newmtl bluteal\n" + + "Ka 0.0041 0.1123 0.1224\n" + + "Kd 0.0776 0.2571 0.2041\n" + + "Ks 0.1467 0.1469 0.0965\n" + + "illum 2\n" + + "Ns 25.0000\n" + + "\n" + + "newmtl pinktan\n" + + "Ka 0.4408 0.2694 0.1592\n" + + "Kd 0.6857 0.2571 0.2163\n" + + "Ks 0.1467 0.1469 0.0965\n" + + "illum 2\n" + + "Ns 25.0000\n" + + "\n" + + "newmtl brnhair\n" + + "Ka 0.0612 0.0174 0.0066\n" + + "Kd 0.0898 0.0302 0.0110\n" + + "Ks 0.1306 0.0819 0.0352\n" + + "illum 2\n" + + "Ns 60.4700\n" + + "\n" + + "newmtl blondhair\n" + + "Ka 0.4449 0.2632 0.0509\n" + + "Kd 0.5714 0.3283 0.0443\n" + + "Ks 0.7755 0.4602 0.0918\n" + + "illum 2\n" + + "Ns 4.6500\n" + + "\n" + + "newmtl flblonde\n" + + "Ka 0.4449 0.2632 0.0509\n" + + "Kd 0.5714 0.3283 0.0443\n" + + "illum 1\n" + + "\n" + + "newmtl yelloworng\n" + + "Ka 0.5837 0.1715 0.0000\n" + + "Kd 0.8857 0.2490 0.0000\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl bone\n" + + "Ka 0.3061 0.1654 0.0650\n" + + "Kd 0.9000 0.7626 0.4261\n" + + "Ks 0.8939 0.7609 0.5509\n" + + "illum 2\n" + + "Ns 200.0000\n" + + "\n" + + "newmtl teeth\n" + + "Ka 0.6408 0.5554 0.3845\n" + + "Kd 0.9837 0.7959 0.4694\n" + + "illum 1\n" + + "\n" + + "newmtl brass\n" + + "Ka 0.2490 0.1102 0.0000\n" + + "Kd 0.4776 0.1959 0.0000\n" + + "Ks 0.5796 0.5796 0.5796\n" + + "illum 2\n" + + "Ns 134.8800\n" + + "\n" + + "newmtl dkred\n" + + "Ka 0.0939 0.0000 0.0000\n" + + "Kd 0.2286 0.0000 0.0000\n" + + "Ks 0.2490 0.0000 0.0000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl taupe\n" + + "Ka 0.1061 0.0709 0.0637\n" + + "Kd 0.2041 0.1227 0.1058\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 84.5000\n" + + "\n" + + "newmtl dkteal\n" + + "Ka 0.0000 0.0245 0.0163\n" + + "Kd 0.0000 0.0653 0.0449\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 55.0400\n" + + "\n" + + "newmtl dkdkgrey\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 0.0122 0.0122 0.0122\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl dkblue\n" + + "Ka 0.0000 0.0029 0.0408\n" + + "Kd 0.0000 0.0041 0.0571\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl gold\n" + + "Ka 0.7224 0.1416 0.0000\n" + + "Kd 1.0000 0.4898 0.0000\n" + + "Ks 0.7184 0.3695 0.3695\n" + + "illum 2\n" + + "Ns 123.2600\n" + + "\n" + + "newmtl redbrick\n" + + "Ka 0.1102 0.0067 0.0067\n" + + "Kd 0.3306 0.0398 0.0081\n" + + "illum 1\n" + + "\n" + + "newmtl flmustard\n" + + "Ka 0.4245 0.2508 0.0000\n" + + "Kd 0.8898 0.3531 0.0073\n" + + "illum 1\n" + + "\n" + + "newmtl flpinegreen\n" + + "Ka 0.0367 0.0612 0.0204\n" + + "Kd 0.1061 0.2163 0.0857\n" + + "illum 1\n" + + "\n" + + "newmtl fldkred\n" + + "Ka 0.0939 0.0000 0.0000\n" + + "Kd 0.2286 0.0082 0.0082\n" + + "illum 1\n" + + "\n" + + "newmtl fldkgreen2\n" + + "Ka 0.0025 0.0122 0.0014\n" + + "Kd 0.0245 0.0694 0.0041\n" + + "illum 1\n" + + "\n" + + "newmtl flmintgreen\n" + + "Ka 0.0408 0.1429 0.0571\n" + + "Kd 0.1306 0.2898 0.1673\n" + + "illum 1\n" + + "\n" + + "newmtl olivegreen\n" + + "Ka 0.0167 0.0245 0.0000\n" + + "Kd 0.0250 0.0367 0.0000\n" + + "Ks 0.2257 0.2776 0.1167\n" + + "illum 2\n" + + "Ns 97.6700\n" + + "\n" + + "newmtl skin\n" + + "Ka 0.2286 0.0187 0.0187\n" + + "Kd 0.1102 0.0328 0.0139\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 17.8300\n" + + "\n" + + "newmtl redbrown\n" + + "Ka 0.1469 0.0031 0.0000\n" + + "Kd 0.2816 0.0060 0.0000\n" + + "Ks 0.3714 0.3714 0.3714\n" + + "illum 2\n" + + "Ns 141.0900\n" + + "\n" + + "newmtl deepgreen\n" + + "Ka 0.0000 0.0050 0.0000\n" + + "Kd 0.0000 0.0204 0.0050\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 113.1800\n" + + "\n" + + "newmtl flltolivegreen\n" + + "Ka 0.0167 0.0245 0.0000\n" + + "Kd 0.0393 0.0531 0.0100\n" + + "illum 1\n" + + "\n" + + "newmtl jetflame\n" + + "Ka 0.7714 0.0000 0.0000\n" + + "Kd 0.9510 0.4939 0.0980\n" + + "Ks 0.8531 0.5222 0.0000\n" + + "illum 2\n" + + "Ns 132.5600\n" + + "\n" + + "newmtl brownskn\n" + + "Ka 0.0122 0.0041 0.0000\n" + + "Kd 0.0204 0.0082 0.0000\n" + + "Ks 0.0735 0.0508 0.0321\n" + + "illum 2\n" + + "Ns 20.1600\n" + + "\n" + + "newmtl greenskn\n" + + "Ka 0.0816 0.0449 0.0000\n" + + "Kd 0.0000 0.0735 0.0000\n" + + "Ks 0.0490 0.1224 0.0898\n" + + "illum 3\n" + + "Ns 46.5100\n" + + "sharpness 146.5100\n" + + "\n" + + "newmtl ltgrey\n" + + "Ka 0.5000 0.5000 0.5000\n" + + "Kd 0.3837 0.3837 0.3837\n" + + "Ks 0.5000 0.5000 0.5000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl bronze\n" + + "Ka 0.0449 0.0204 0.0000\n" + + "Kd 0.0653 0.0367 0.0122\n" + + "Ks 0.0776 0.0408 0.0000\n" + + "illum 3\n" + + "Ns 137.2100\n" + + "sharpness 125.5800\n" + + "\n" + + "newmtl bone1\n" + + "Ka 0.6408 0.5554 0.3845\n" + + "Kd 0.9837 0.7959 0.4694\n" + + "illum 1\n" + + "\n" + + "newmtl flwhite1\n" + + "Ka 0.9306 0.9306 0.9306\n" + + "Kd 1.0000 1.0000 1.0000\n" + + "illum 1\n" + + "\n" + + "newmtl flwhite\n" + + "Ka 0.6449 0.6116 0.5447\n" + + "Kd 0.9837 0.9309 0.8392\n" + + "Ks 0.8082 0.7290 0.5708\n" + + "illum 2\n" + + "Ns 200.0000\n" + + "\n" + + "newmtl shadow\n" + + "Kd 0.0350 0.0248 0.0194\n" + + "illum 0\n" + + "d 0.7500\n" + + "\n" + + "newmtl fldkolivegreen\n" + + "Ka 0.0056 0.0082 0.0000\n" + + "Kd 0.0151 0.0204 0.0038\n" + + "illum 1\n" + + "\n" + + "newmtl fldkdkgrey\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 0.0122 0.0122 0.0122\n" + + "illum 1\n" + + "\n" + + "newmtl lcdgreen\n" + + "Ka 0.4000 0.4000 0.4000\n" + + "Kd 0.5878 1.0000 0.5061\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl brownlips\n" + + "Ka 0.1143 0.0694 0.0245\n" + + "Kd 0.1429 0.0653 0.0408\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 25.0000\n" + + "\n" + + "newmtl muscle\n" + + "Ka 0.2122 0.0077 0.0154\n" + + "Kd 0.4204 0.0721 0.0856\n" + + "Ks 0.1184 0.1184 0.1184\n" + + "illum 2\n" + + "Ns 25.5800\n" + + "\n" + + "newmtl flltgrey\n" + + "Ka 0.5224 0.5224 0.5224\n" + + "Kd 0.8245 0.8245 0.8245\n" + + "illum 1\n" + + "\n" + + "newmtl offwhite.warm\n" + + "Ka 0.5184 0.4501 0.3703\n" + + "Kd 0.8367 0.6898 0.4490\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl offwhite.cool\n" + + "Ka 0.5184 0.4501 0.3703\n" + + "Kd 0.8367 0.6812 0.5703\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl yellowbrt\n" + + "Ka 0.4000 0.4000 0.4000\n" + + "Kd 1.0000 0.7837 0.0000\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl chappie\n" + + "Ka 0.4000 0.4000 0.4000\n" + + "Kd 0.5837 0.1796 0.0367\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl archwhite\n" + + "Ka 0.2816 0.2816 0.2816\n" + + "Kd 0.9959 0.9959 0.9959\n" + + "illum 1\n" + + "\n" + + "newmtl archwhite2\n" + + "Ka 0.2816 0.2816 0.2816\n" + + "Kd 0.8408 0.8408 0.8408\n" + + "illum 1\n" + + "\n" + + "newmtl lighttan\n" + + "Ka 0.0980 0.0536 0.0220\n" + + "Kd 0.7020 0.4210 0.2206\n" + + "Ks 0.8286 0.8057 0.5851\n" + + "illum 2\n" + + "Ns 177.5200\n" + + "\n" + + "newmtl lighttan2\n" + + "Ka 0.0980 0.0492 0.0144\n" + + "Kd 0.3143 0.1870 0.0962\n" + + "Ks 0.8286 0.8057 0.5851\n" + + "illum 2\n" + + "Ns 177.5200\n" + + "\n" + + "newmtl lighttan3\n" + + "Ka 0.0980 0.0492 0.0144\n" + + "Kd 0.1796 0.0829 0.0139\n" + + "Ks 0.8286 0.8057 0.5851\n" + + "illum 2\n" + + "Ns 177.5200\n" + + "\n" + + "newmtl lightyellow\n" + + "Ka 0.5061 0.1983 0.0000\n" + + "Kd 1.0000 0.9542 0.3388\n" + + "Ks 1.0000 0.9060 0.0000\n" + + "illum 2\n" + + "Ns 177.5200\n" + + "\n" + + "newmtl lighttannew\n" + + "Ka 0.0980 0.0492 0.0144\n" + + "Kd 0.7878 0.6070 0.3216\n" + + "Ks 0.8286 0.8057 0.5851\n" + + "illum 2\n" + + "Ns 177.5200\n" + + "\n" + + "newmtl default\n" + + "Ka 0.4000 0.4000 0.4000\n" + + "Kd 0.7102 0.7020 0.6531\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 128.0000\n" + + "\n" + + "newmtl ship2\n" + + "Ka 0.0000 0.0000 0.0000\n" + + "Kd 1.0000 1.0000 1.0000\n" + + "Ks 0.1143 0.1143 0.1143\n" + + "illum 2\n" + + "Ns 60.0000\n" + + "\n" + + "newmtl dkpurple\n" + + "Ka 0.0082 0.0000 0.0163\n" + + "Kd 0.0245 0.0000 0.0490\n" + + "Ks 0.1266 0.0000 0.2531\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl dkorange\n" + + "Ka 0.4041 0.0123 0.0000\n" + + "Kd 0.7143 0.0350 0.0000\n" + + "Ks 0.7102 0.0870 0.0000\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl mintgrn\n" + + "Ka 0.0101 0.1959 0.0335\n" + + "Kd 0.0245 0.4776 0.0816\n" + + "Ks 0.0245 0.4776 0.0816\n" + + "illum 2\n" + + "Ns 65.8900\n" + + "\n" + + "newmtl fgreen\n" + + "Ka 0.0000 0.0449 0.0000\n" + + "Kd 0.0000 0.0449 0.0004\n" + + "Ks 0.0062 0.0694 0.0000\n" + + "illum 2\n" + + "Ns 106.2000\n" + + "\n" + + "newmtl glassblutint\n" + + "Ka 0.4000 0.4000 0.4000\n" + + "Kd 0.5551 0.8000 0.7730\n" + + "Ks 0.7969 0.9714 0.9223\n" + + "illum 4\n" + + "d 0.3300\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl bflesh\n" + + "Ka 0.0122 0.0122 0.0122\n" + + "Kd 0.0245 0.0081 0.0021\n" + + "Ks 0.0531 0.0460 0.0153\n" + + "illum 2\n" + + "Ns 20.1600\n" + + "\n" + + "newmtl meh\n" + + "Ka 0.4000 0.4000 0.4000\n" + + "Kd 0.5551 0.8000 0.7730\n" + + "Ks 0.7969 0.9714 0.9223\n" + + "illum 4\n" + + "d 0.7500\n" + + "Ns 183.7200\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl violet\n" + + "Ka 0.0083 0.0000 0.1265\n" + + "Kd 0.0287 0.0269 0.1347\n" + + "Ks 0.2267 0.4537 0.6612\n" + + "illum 2\n" + + "Ns 96.9000\n" + + "\n" + + "newmtl iris\n" + + "Ka 0.3061 0.0556 0.0037\n" + + "Kd 0.0000 0.0572 0.3184\n" + + "Ks 0.8041 0.6782 0.1477\n" + + "illum 2\n" + + "Ns 188.3700\n" + + "\n" + + "newmtl blugrn\n" + + "Ka 0.4408 0.4144 0.1592\n" + + "Kd 0.0811 0.6408 0.2775\n" + + "Ks 0.1467 0.1469 0.0965\n" + + "illum 2\n" + + "Ns 25.0000\n" + + "\n" + + "newmtl glasstransparent\n" + + "Ka 0.2163 0.2163 0.2163\n" + + "Kd 0.4694 0.4694 0.4694\n" + + "Ks 0.6082 0.6082 0.6082\n" + + "illum 4\n" + + "d 0.7500\n" + + "Ns 200.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl fleshtransparent\n" + + "Ka 0.4000 0.2253 0.2253\n" + + "Kd 0.6898 0.2942 0.1295\n" + + "Ks 0.7388 0.4614 0.4614\n" + + "illum 4\n" + + "d 0.7500\n" + + "Ns 6.2000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl fldkgrey\n" + + "Ka 0.0449 0.0449 0.0449\n" + + "Kd 0.0939 0.0939 0.0939\n" + + "illum 1\n" + + "\n" + + "newmtl sky_blue\n" + + "Ka 0.1363 0.2264 0.4122\n" + + "Kd 0.1241 0.5931 0.8000\n" + + "Ks 0.0490 0.0490 0.0490\n" + + "illum 2\n" + + "Ns 13.9500\n" + + "\n" + + "newmtl fldkpurple\n" + + "Ka 0.0443 0.0257 0.0776\n" + + "Kd 0.1612 0.0000 0.3347\n" + + "Ks 0.0000 0.0000 0.0000\n" + + "illum 2\n" + + "Ns 13.9500\n" + + "\n" + + "newmtl dkbrown\n" + + "Ka 0.0143 0.0062 0.0027\n" + + "Kd 0.0087 0.0038 0.0016\n" + + "Ks 0.2370 0.2147 0.1821\n" + + "illum 3\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl bone2\n" + + "Ka 0.6408 0.5388 0.3348\n" + + "Kd 0.9837 0.8620 0.6504\n" + + "illum 1\n" + + "\n" + + "newmtl bluegrey\n" + + "Ka 0.4000 0.4000 0.4000\n" + + "Kd 0.1881 0.2786 0.2898\n" + + "Ks 0.3000 0.3000 0.3000\n" + + "illum 2\n" + + "Ns 14.7300\n" + + "\n" + + "newmtl metal\n" + + "Ka 0.9102 0.8956 0.1932\n" + + "Kd 0.9000 0.7626 0.4261\n" + + "Ks 0.8939 0.8840 0.8683\n" + + "illum 2\n" + + "Ns 200.0000\n" + + "\n" + + "newmtl sand_stone\n" + + "Ka 0.1299 0.1177 0.0998\n" + + "Kd 0.1256 0.1138 0.0965\n" + + "Ks 0.2370 0.2147 0.1821\n" + + "illum 3\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n" + + "\n" + + "newmtl hair\n" + + "Ka 0.0013 0.0012 0.0010\n" + + "Kd 0.0008 0.0007 0.0006\n" + + "Ks 0.0000 0.0000 0.0000\n" + + "illum 3\n" + + "Ns 60.0000\n" + + "sharpness 60.0000\n"; +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFile.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFile.java new file mode 100644 index 0000000..129c843 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFile.java @@ -0,0 +1,1334 @@ +/* + * $RCSfile: ObjectFile.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:10 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.objectfile; + +import com.sun.j3d.loaders.Scene; +import com.sun.j3d.loaders.SceneBase; +import com.sun.j3d.loaders.Loader; +import com.sun.j3d.loaders.IncorrectFormatException; +import com.sun.j3d.loaders.ParsingErrorException; +import com.sun.j3d.loaders.objectfile.ObjectFileParser; +import com.sun.j3d.loaders.objectfile.ObjectFileMaterials; +import com.sun.j3d.utils.geometry.GeometryInfo; +import com.sun.j3d.utils.geometry.NormalGenerator; +import com.sun.j3d.utils.geometry.Stripifier; +import java.io.FileNotFoundException; +import java.io.StreamTokenizer; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.BufferedInputStream; +import java.io.FileReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.HashMap; +import java.util.StringTokenizer; +import javax.media.j3d.*; +import javax.vecmath.Color3f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; +import javax.vecmath.TexCoord2f; +import java.net.MalformedURLException; + + + +/** + * The ObjectFile class implements the Loader interface for the Wavefront + * .obj file format, a standard 3D object file format created for use with + * Wavefront's Advanced Visualizer (tm) and available for purchase from + * Viewpoint DataLabs, as well as other 3D model companies. Object Files + * are text based + * files supporting both polygonal and free-form geometry (curves + * and surfaces). The Java 3D .obj file loader supports a subset of the + * file format, but it is enough to load almost all commonly available + * Object Files. Free-form geometry is not supported.

+ * + * The Object File tokens currently supported by this loader are:

+ * v float float float

+ *
A single vertex's geometric position in space. The first vertex + * listed in the file has index 1, + * and subsequent vertices are numbered sequentially.

+ * vn float float float

+ *
A normal. The first normal in the file is index 1, and + * subsequent normals are numbered sequentially.

+ * vt float float

+ *
A texture coordinate. The first texture coordinate in the file is + * index 1, and subsequent normals are numbered sequentially.

+ * f int int int . . .

+ *
or

+ * f int/int int/int int/int . . .

+ *
or

+ * f int/int/int int/int/int int/int/int . . .

+ *
A polygonal face. The numbers are indexes into the arrays of + * vertex positions, texture coordinates, and normals respectively. + * There is no maximum number of vertices that a single polygon may + * contain. The .obj file specification says that each face must + * be flat and convex, but if the TRIANGULATE flag is sent to the + * ObjectFile constructor, each face will be triangulated by the + * Java 3D Triangulator, and therefore may be concave. + * A number may be omitted if, for example, texture coordinates are + * not being defined in the model. Numbers are normally positive + * indexes, but may also be negative. An index of -1 means the last + * member added to the respective array, -2 is the one before that, + * and so on.

+ * g name

+ *
Faces defined after this token will be added to the named group. + * These geometry groups are returned as separated Shape3D objects + * attached to the parent SceneGroup. Each named Shape3D will also + * be in the Hashtable returned by Scene.getNamedObjects(). It is + * legal to add faces to a group, switch to another group, and then + * add more faces to the original group by reissuing the same name + * with the g token. If faces are added to the model before the g + * token is seen, the faces are put into the default group called + * "default."

+ * s int

+ *
or

+ * s off

+ *
If the vn token is not used in the file to specify vertex normals + * for the model, this token may be used to put faces into groups + * for normal calculation ("smoothing groups") in the same manner as + * the 'g' token + * is used to group faces geometrically. Faces in the same smoothing + * group will have their normals calculated as if they are part of + * the same smooth surface. To do this, we use the Java 3D NormalGenerator + * utility with the creaseAngle parameter set to PI (180 degrees - + * smooth shading, no creases) or to whatever the user has set the + * creaseAngle. Faces in group 0 or 'off' use a + * creaseAngle of zero, meaning there is no smoothing (the normal + * of the face is used at all vertices giving the surface a faceted + * look; there will be a + * crease, or "Hard Edge," between each face in group zero). There is + * also an implied hard edge between each smoothing group, where they + * meet each other.

+ *

+ * If neither the vn nor the s token is used in the file, then normals + * are calculated using the creaseAngle set in the contructor. + * Normals are calculated on each geometry + * group separately, meaning there will be a hard edge between each + * geometry group.

+ *

+ * usemtl name

+ *
The current (and subsequent) geometry groups (specified with + * the 'g' token) have applied + * to them the named material property. The following set of material + * properties are available by default:

+ *
+ *     amber           amber_trans       aqua            aqua_filter
+ *     archwhite       archwhite2        bflesh          black
+ *     blondhair       blue_pure         bluegrey        bluetint
+ *     blugrn          blutan            bluteal         bone
+ *     bone1           bone2             brass           brnhair
+ *     bronze          brown             brownlips       brownskn
+ *     brzskin         chappie           charcoal        deepgreen
+ *     default         dkblue            dkblue_pure     dkbrown
+ *     dkdkgrey        dkgreen           dkgrey          dkorange
+ *     dkpurple        dkred             dkteal          emerald
+ *     fgreen          flaqua            flblack         flblonde
+ *     flblue_pure     flbrown           fldkblue_pure   fldkdkgrey
+ *     fldkgreen       fldkgreen2        fldkgrey        fldkolivegreen
+ *     fldkpurple      fldkred           flesh           fleshtransparent
+ *     flgrey          fllime            flltbrown       flltgrey
+ *     flltolivegreen  flmintgreen       flmustard       florange
+ *     flpinegreen     flpurple          flred           fltan
+ *     flwhite         flwhite1          flyellow        glass
+ *     glassblutint    glasstransparent  gold            green
+ *     greenskn        grey              hair            iris
+ *     jetflame        lavendar          lcdgreen        lighttan
+ *     lighttan2       lighttan3         lighttannew     lightyellow
+ *     lime            lips              ltbrown         ltgrey
+ *     meh             metal             mintgrn         muscle
+ *     navy_blue       offwhite.cool     offwhite.warm   olivegreen
+ *     orange          pale_green        pale_pink       pale_yellow
+ *     peach           periwinkle        pink            pinktan
+ *     plasma          purple            red             redbrick
+ *     redbrown        redorange         redwood         rubber
+ *     ruby            sand_stone        sapphire        shadow
+ *     ship2           silver            skin            sky_blue
+ *     smoked_glass    tan               taupe           teeth
+ *     violet          white             yellow          yellow_green
+ *     yellowbrt       yelloworng
+ *   
+ * mtllib filename

+ *
Load material properties from the named file. Materials + * with the same name as the predefined materials above will override + * the default value. Any directory path information in (filename) + * is ignored. The .mtl files are assumed to be in the same directory + * as the .obj file. If they are in a different directory, use + * Loader.setBasePath() (or Loader.setBaseUrl() ). The format of the + * material properties files + * are as follows:

+ * newmtl name

+ *
Start the definition of a new named material property.

+ * Ka float float float

+ *
Ambient color.

+ * Kd float float float

+ *
Diffuse color.

+ * Ks float float float

+ *
Specular color.

+ * illum (0, 1, or 2)

+ *
0 to disable lighting, 1 for ambient & diffuse only (specular + * color set to black), 2 for full lighting.

+ * Ns float

+ *
Shininess (clamped to 1.0 - 128.0).

+ * map_Kd filename

+ *
Texture map. Supports .rgb, .rgba, .int, .inta, .sgi, and + * .bw files in addition to those supported by + * TextureLoader. + *

+ */ + +public class ObjectFile implements Loader { + // 0=Input file assumed good + // 1=Input file checked for inconsistencies + // 2=path names + // 4=flags + // 8=Timing Info + // 16=Tokens + // 32=Token details (use with 16) + // 64=limits of model coordinates + private static final int DEBUG = 0; + + /** + * Flag sent to constructor. The object's vertices will be changed + * so that the object is centered at (0,0,0) and the coordinate + * positions are all in the range of (-1,-1,-1) to (1,1,1). + */ + public static final int RESIZE = LOAD_SOUND_NODES << 1; + + /** + * Flag sent to constructor. The Shape3D object will be created + * by using the GeometryInfo POLYGON_ARRAY primitive, causing + * them to be Triangulated by GeometryInfo. Use + * this if you suspect concave or other non-behaving polygons + * in your model. + */ + public static final int TRIANGULATE = RESIZE << 1; + + /** + * Flag sent to constructor. Use if the vertices in your .obj + * file were specified with clockwise winding (Java 3D wants + * counter-clockwise) so you see the back of the polygons and + * not the front. Calls GeometryInfo.reverse(). + */ + public static final int REVERSE = TRIANGULATE << 1; + + /** + * Flag sent to contructor. After normals are generated the data + * will be analyzed to find triangle strips. Use this if your + * hardware supports accelerated rendering of strips. + */ + public static final int STRIPIFY = REVERSE << 1; + + private static final char BACKSLASH = '\\'; + + private int flags; + private String basePath = null; + private URL baseUrl = null; + private boolean fromUrl = false; + private float radians; + + // First, lists of points are read from the .obj file into these arrays. . . + private ArrayList coordList; // Holds Point3f + private ArrayList texList; // Holds TexCoord2f + private ArrayList normList; // Holds Vector3f + + // . . . and index lists are read into these arrays. + private ArrayList coordIdxList; // Holds Integer index into coordList + private ArrayList texIdxList; // Holds Integer index into texList + private ArrayList normIdxList; // Holds Integer index into normList + + // The length of each face is stored in this array. + private ArrayList stripCounts; // Holds Integer + + // Each face's Geometry Group membership is kept here. . . + private HashMap groups; // key=Integer index into stripCounts + // value=String name of group + private String curGroup; + + // . . . and Smoothing Group membership is kept here + private HashMap sGroups; // key=Integer index into stripCounts + // value=String name of group + private String curSgroup; + + // The name of each group's "usemtl" material property is kept here + private HashMap groupMaterials; // key=String name of Group + // value=String name of material + + + // After reading the entire file, the faces are converted into triangles. + // The Geometry Group information is converted into these structures. . . + private HashMap triGroups; // key=String name of group + // value=ArrayList of Integer + // indices into coordIdxList + private ArrayList curTriGroup; + + // . . . and Smoothing Group info is converted into these. + private HashMap triSgroups; // key=String name of group + // value=ArrayList of Integer + // indices into coordIdxList + private ArrayList curTriSgroup; + + + // Finally, coordList, texList, and normList are converted to arrays for + // use with GeometryInfo + private Point3f coordArray[] = null; + private Vector3f normArray[] = null; + private TexCoord2f texArray[] = null; + + // Used for debugging + private long time; + + private ObjectFileMaterials materials = null; + + + void readVertex(ObjectFileParser st) throws ParsingErrorException { + Point3f p = new Point3f(); + + st.getNumber(); + p.x = (float)st.nval; + st.getNumber(); + p.y = (float)st.nval; + st.getNumber(); + p.z = (float)st.nval; + + if ((DEBUG & 32) != 0) + System.out.println(" (" + p.x + "," + p.y + "," + p.z + ")"); + + st.skipToNextLine(); + + // Add this vertex to the array + coordList.add(p); + } // End of readVertex + + + /** + * readNormal + */ + void readNormal(ObjectFileParser st) throws ParsingErrorException { + Vector3f p = new Vector3f(); + + st.getNumber(); + p.x = (float)st.nval; + st.getNumber(); + p.y = (float)st.nval; + st.getNumber(); + p.z = (float)st.nval; + + if ((DEBUG & 32) != 0) + System.out.println(" (" + p.x + "," + p.y + "," + p.z + ")"); + + st.skipToNextLine(); + + // Add this vertex to the array + normList.add(p); + } // End of readNormal + + + /** + * readTexture + */ + void readTexture(ObjectFileParser st) throws ParsingErrorException { + TexCoord2f p = new TexCoord2f(); + + st.getNumber(); + p.x = (float)st.nval; + st.getNumber(); + p.y = (float)st.nval; + + if ((DEBUG & 32) != 0) + System.out.println(" (" + p.x + "," + p.y + ")"); + + st.skipToNextLine(); + + // Add this vertex to the array + texList.add(p); + } // End of readTexture + + + /** + * readFace + * + * Adds the indices of the current face to the arrays. + * + * ViewPoint files can have up to three arrays: Vertex Positions, + * Texture Coordinates, and Vertex Normals. Each vertex can + * contain indices into all three arrays. + */ + void readFace(ObjectFileParser st) throws ParsingErrorException { + int vertIndex, texIndex = 0, normIndex = 0; + int count = 0; + + // There are n vertices on each line. Each vertex is comprised + // of 1-3 numbers separated by slashes ('/'). The slashes may + // be omitted if there's only one number. + + st.getToken(); + + while (st.ttype != st.TT_EOL) { + // First token is always a number (or EOL) + st.pushBack(); + st.getNumber(); + vertIndex = (int)st.nval - 1; + if (vertIndex < 0) vertIndex += coordList.size() + 1; + coordIdxList.add(new Integer(vertIndex)); + + // Next token is a slash, a number, or EOL. Continue on slash + st.getToken(); + if (st.ttype == '/') { + + // If there's a number after the first slash, read it + st.getToken(); + if (st.ttype == st.TT_WORD) { + // It's a number + st.pushBack(); + st.getNumber(); + texIndex = (int)st.nval - 1; + if (texIndex < 0) texIndex += texList.size() + 1; + texIdxList.add(new Integer(texIndex)); + st.getToken(); + } + + // Next token is a slash, a number, or EOL. Continue on slash + if (st.ttype == '/') { + + // There has to be a number after the 2nd slash + st.getNumber(); + normIndex = (int)st.nval - 1; + if (normIndex < 0) normIndex += normList.size() + 1; + normIdxList.add(new Integer(normIndex)); + st.getToken(); + } + } + if ((DEBUG & 32) != 0) { + System.out.println(" " + vertIndex + '/' + texIndex + + '/' + normIndex); + } + count++; + } + + Integer faceNum = new Integer(stripCounts.size()); + stripCounts.add(new Integer(count)); + + // Add face to current groups + groups.put(faceNum, curGroup); + if (curSgroup != null) sGroups.put(faceNum, curSgroup); + + // In case we exited early + st.skipToNextLine(); + } // End of readFace + + + /** + * readPartName + */ + void readPartName(ObjectFileParser st) { + st.getToken(); + + // Find the Material Property of the current group + String curMat = (String)groupMaterials.get(curGroup); + + // New faces will be added to the curGroup + if (st.ttype != ObjectFileParser.TT_WORD) curGroup = "default"; + else curGroup = st.sval; + if ((DEBUG & 32) != 0) System.out.println(" Changed to group " + curGroup); + + // See if this group has Material Properties yet + if (groupMaterials.get(curGroup) == null) { + // It doesn't - carry over from last group + groupMaterials.put(curGroup, curMat); + } + + st.skipToNextLine(); + } // End of readPartName + + + /** + * readMaterialName + */ + void readMaterialName(ObjectFileParser st) throws ParsingErrorException { + st.getToken(); + if (st.ttype == ObjectFileParser.TT_WORD) { + groupMaterials.put(curGroup, new String(st.sval)); + if ((DEBUG & 32) != 0) { + System.out.println(" Material Property " + st.sval + + " assigned to group " + curGroup); + } + } + st.skipToNextLine(); + } // End of readMaterialName + + + /** + * loadMaterialFile + * + * Both types of slashes are returned as tokens from our parser, + * so we go through the line token by token and keep just the + * last token on the line. This should be the filename without + * any directory info. + */ + void loadMaterialFile(ObjectFileParser st) throws ParsingErrorException { + String s = null; + + // Filenames are case sensitive + st.lowerCaseMode(false); + + // Get name of material file (skip path) + do { + st.getToken(); + if (st.ttype == ObjectFileParser.TT_WORD) s = st.sval; + } while (st.ttype != ObjectFileParser.TT_EOL); + + materials.readMaterialFile(fromUrl, + fromUrl ? baseUrl.toString() : basePath, s); + + st.lowerCaseMode(true); + st.skipToNextLine(); + } // End of loadMaterialFile + + + /** + * readSmoothingGroup + */ + void readSmoothingGroup(ObjectFileParser st) throws ParsingErrorException { + st.getToken(); + if (st.ttype != ObjectFileParser.TT_WORD) { + st.skipToNextLine(); + return; + } + if (st.sval.equals("off")) curSgroup = "0"; + else curSgroup = st.sval; + if ((DEBUG & 32) != 0) System.out.println(" Smoothing group " + curSgroup); + st.skipToNextLine(); + } // End of readSmoothingGroup + + + /** + * readFile + * + * Read the model data from the file. + */ + void readFile(ObjectFileParser st) throws ParsingErrorException { + int t; + + st.getToken(); + while (st.ttype != ObjectFileParser.TT_EOF) { + + // Print out one token for each line + if ((DEBUG & 16) != 0) { + System.out.print("Token "); + if (st.ttype == ObjectFileParser.TT_EOL) System.out.println("EOL"); + else if (st.ttype == ObjectFileParser.TT_WORD) + System.out.println(st.sval); + else System.out.println((char)st.ttype); + } + + if (st.ttype == ObjectFileParser.TT_WORD) { + if (st.sval.equals("v")) { + readVertex(st); + } else if (st.sval.equals("vn")) { + readNormal(st); + } else if (st.sval.equals("vt")) { + readTexture(st); + } else if (st.sval.equals("f")) { + readFace(st); + } else if (st.sval.equals("fo")) { // Not sure what the dif is + readFace(st); + } else if (st.sval.equals("g")) { + readPartName(st); + } else if (st.sval.equals("s")) { + readSmoothingGroup(st); + } else if (st.sval.equals("p")) { + st.skipToNextLine(); + } else if (st.sval.equals("l")) { + st.skipToNextLine(); + } else if (st.sval.equals("mtllib")) { + loadMaterialFile(st); + } else if (st.sval.equals("usemtl")) { + readMaterialName(st); + } else if (st.sval.equals("maplib")) { + st.skipToNextLine(); + } else if (st.sval.equals("usemap")) { + st.skipToNextLine(); + } else { + throw new ParsingErrorException( + "Unrecognized token, line " + st.lineno()); + } + } + + st.skipToNextLine(); + + // Get next token + st.getToken(); + } + } // End of readFile + + + /** + * Constructor. + * + * @param flags The constants from above or from + * com.sun.j3d.loaders.Loader, possibly "or'ed" (|) together. + * @param radians Ignored if the vn token is present in the model (user + * normals supplied). Otherwise, crease angle to use within smoothing + * groups, or within geometry groups if the s token isn't present either. + */ + public ObjectFile(int flags, float radians) { + setFlags(flags); + this.radians = radians; + } // End of ObjectFile(int, float) + + + /** + * Constructor. Crease Angle set to default of + * 44 degrees (see NormalGenerator utility for details). + * @param flags The constants from above or from + * com.sun.j3d.loaders.Loader, possibly "or'ed" (|) together. + */ + public ObjectFile(int flags) { + this(flags, -1.0f); + } // End of ObjectFile(int) + + + /** + * Default constructor. Crease Angle set to default of + * 44 degrees (see NormalGenerator utility for details). Flags + * set to zero (0). + */ + public ObjectFile() { + this(0, -1.0f); + } // End of ObjectFile() + + + /** + * Takes a file name and sets the base path to the directory + * containing that file. + */ + private void setBasePathFromFilename(String fileName) { + if (fileName.lastIndexOf(java.io.File.separator) == -1) { + // No path given - current directory + setBasePath("." + java.io.File.separator); + } else { + setBasePath( + fileName.substring(0, fileName.lastIndexOf(java.io.File.separator))); + } + } // End of setBasePathFromFilename + + + /** + * The Object File is loaded from the .obj file specified by + * the filename. + * To attach the model to your scene, call getSceneGroup() on + * the Scene object passed back, and attach the returned + * BranchGroup to your scene graph. For an example, see + * j3d-examples/ObjLoad/ObjLoad.java. + */ + public Scene load(String filename) throws FileNotFoundException, + IncorrectFormatException, + ParsingErrorException { + + setBasePathFromFilename(filename); + + Reader reader = new BufferedReader(new FileReader(filename)); + return load(reader); + } // End of load(String) + + + private void setBaseUrlFromUrl(URL url) throws FileNotFoundException { + String u = url.toString(); + String s; + if (u.lastIndexOf('/') == -1) { + s = url.getProtocol() + ":"; + } else { + s = u.substring(0, u.lastIndexOf('/') + 1); + } + try { + baseUrl = new URL(s); + } + catch (MalformedURLException e) { + throw new FileNotFoundException(e.getMessage()); + } + } // End of setBaseUrlFromUrl + + + /** + * The object file is loaded off of the web. + * To attach the model to your scene, call getSceneGroup() on + * the Scene object passed back, and attach the returned + * BranchGroup to your scene graph. For an example, see + * j3d-examples/ObjLoad/ObjLoad.java. + */ + public Scene load(URL url) throws FileNotFoundException, + IncorrectFormatException, + ParsingErrorException { + BufferedReader reader; + + if (baseUrl == null) setBaseUrlFromUrl(url); + + try { + reader = new BufferedReader(new InputStreamReader(url.openStream())); + } + catch (IOException e) { + throw new FileNotFoundException(e.getMessage()); + } + fromUrl = true; + return load(reader); + } // End of load(URL) + + + /** + * getLimits + * + * Returns an array of Point3f which form a bounding box around the + * object. Element 0 is the low value, element 1 is the high value. + * See normalize() below for an example of how to use this method. + */ + private Point3f[] getLimits() { + Point3f cur_vtx = new Point3f(); + + // Find the limits of the model + Point3f[] limit = new Point3f[2]; + limit[0] = new Point3f(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE); + limit[1] = new Point3f(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE); + for (int i = 0 ; i < coordList.size() ; i++) { + + cur_vtx = (Point3f)coordList.get(i); + + // Keep track of limits for normalization + if (cur_vtx.x < limit[0].x) limit[0].x = cur_vtx.x; + if (cur_vtx.x > limit[1].x) limit[1].x = cur_vtx.x; + if (cur_vtx.y < limit[0].y) limit[0].y = cur_vtx.y; + if (cur_vtx.y > limit[1].y) limit[1].y = cur_vtx.y; + if (cur_vtx.z < limit[0].z) limit[0].z = cur_vtx.z; + if (cur_vtx.z > limit[1].z) limit[1].z = cur_vtx.z; + } + + if ((DEBUG & 64) != 0) { + System.out.println("Model range: (" + + limit[0].x + "," + limit[0].y + "," + limit[0].z + ") to (" + + limit[1].x + "," + limit[1].y + "," + limit[1].z + ")"); + } + + return limit; + } // End of getLimits + + + + /** + * Center the object and make it (-1,-1,-1) to (1,1,1). + */ + private void resize() { + int i, j; + Point3f cur_vtx = new Point3f(); + float biggest_dif; + + Point3f[] limit = getLimits(); + + // Move object so it's centered on (0,0,0) + Vector3f offset = new Vector3f(-0.5f * (limit[0].x + limit[1].x), + -0.5f * (limit[0].y + limit[1].y), + -0.5f * (limit[0].z + limit[1].z)); + + if ((DEBUG & 64) != 0) { + System.out.println("Offset amount: (" + + offset.x + "," + offset.y + "," + offset.z + ")"); + } + + // Find the divide-by value for the normalization + biggest_dif = limit[1].x - limit[0].x; + if (biggest_dif < limit[1].y - limit[0].y) + biggest_dif = limit[1].y - limit[0].y; + if (biggest_dif < limit[1].z - limit[0].z) + biggest_dif = limit[1].z - limit[0].z; + biggest_dif /= 2.0f; + + for (i = 0 ; i < coordList.size() ; i++) { + + cur_vtx = (Point3f)coordList.get(i); + + cur_vtx.add(cur_vtx, offset); + + cur_vtx.x /= biggest_dif; + cur_vtx.y /= biggest_dif; + cur_vtx.z /= biggest_dif; + + // coordList.setElementAt(cur_vtx, i); + } + } // End of resize + + + private int[] objectToIntArray(ArrayList inList) { + int outList[] = new int[inList.size()]; + for (int i = 0 ; i < inList.size() ; i++) { + outList[i] = ((Integer)inList.get(i)).intValue(); + } + return outList; + } // End of objectToIntArray + + + private Point3f[] objectToPoint3Array(ArrayList inList) { + Point3f outList[] = new Point3f[inList.size()]; + for (int i = 0 ; i < inList.size() ; i++) { + outList[i] = (Point3f)inList.get(i); + } + return outList; + } // End of objectToPoint3Array + + + + private TexCoord2f[] objectToTexCoord2Array(ArrayList inList) { + TexCoord2f outList[] = new TexCoord2f[inList.size()]; + for (int i = 0 ; i < inList.size() ; i++) { + outList[i] = (TexCoord2f)inList.get(i); + } + return outList; + } // End of objectToTexCoord2Array + + + private Vector3f[] objectToVectorArray(ArrayList inList) { + Vector3f outList[] = new Vector3f[inList.size()]; + for (int i = 0 ; i < inList.size() ; i++) { + outList[i] = (Vector3f)inList.get(i); + } + return outList; + } // End of objectToVectorArray + + + /** + * Each group is a list of indices into the model's index lists, + * indicating the starting index of each triangle in the group. + * This method converts those data structures + * into an integer array to use with GeometryInfo. + */ + private int[] groupIndices(ArrayList sourceList, ArrayList group) { + int indices[] = new int[group.size() * 3]; + for (int i = 0 ; i < group.size() ; i++) { + int j = ((Integer)group.get(i)).intValue(); + indices[i * 3 + 0] = ((Integer)sourceList.get(j + 0)).intValue(); + indices[i * 3 + 1] = ((Integer)sourceList.get(j + 1)).intValue(); + indices[i * 3 + 2] = ((Integer)sourceList.get(j + 2)).intValue(); + } + return indices; + } // end of groupIndices + + + /** + * smoothingGroupNormals + * + * Smoothing groups are groups of faces who should be grouped + * together for normal calculation purposes. The faces are + * put into a GeometryInfo object and normals are calculated + * with a 180 degree creaseAngle (no creases) or whatever the + * user has specified. The normals + * are then copied out of the GeometryInfo and back into + * ObjectFile data structures. + */ + private void smoothingGroupNormals() { + NormalGenerator ng = + new NormalGenerator(radians == -1.0f ? Math.PI : radians); + NormalGenerator ng0 = new NormalGenerator(0.0); + normList.clear(); + normIdxList = null; + int newNormIdxArray[] = new int[coordIdxList.size()]; + + Iterator e = triSgroups.keySet().iterator(); + while (e.hasNext()) { + String curname = (String)e.next(); + ArrayList triList = (ArrayList)triSgroups.get(curname); + + // Check for group with no faces + if (triList.size() > 0) { + + GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY); + + gi.setCoordinateIndices(groupIndices(coordIdxList, triList)); + gi.setCoordinates(coordArray); + + if (curname.equals("0")) ng0.generateNormals(gi); + else ng.generateNormals(gi); + + // Get the generated normals and indices + Vector3f genNorms[] = gi.getNormals(); + int genNormIndices[] = gi.getNormalIndices(); + + // Now we need to copy the generated normals into ObjectFile + // data structures (normList and normIdxList). The variable + // normIdx is the index of the index of the normal currently + // being put into the list. It takes some calculation to + // figure out the new index and where to put it. + int normIdx = 0; + // Repeat for each triangle in the smoothing group + for (int i = 0 ; i < triList.size() ; i++) { + + // Get the coordIdxList index of the first index in this face + int idx = ((Integer)triList.get(i)).intValue(); + + // Repeat for each vertex in the triangle + for (int j = 0 ; j < 3 ; j++) { + + // Put the new normal's index into the index list + newNormIdxArray[idx + j] = normList.size(); + + // Add the vertex's normal to the normal list + normList.add(genNorms[genNormIndices[normIdx++]]); + } + } + } + } + normIdxList = new ArrayList(coordIdxList.size()); + for (int i = 0 ; i < coordIdxList.size() ; i++) { + normIdxList.add(new Integer(newNormIdxArray[i])); + } + normArray = objectToVectorArray(normList); + } // end of smoothingGroupNormals + + + /** + * Each face is converted to triangles. As each face is converted, + * we look up which geometry group and smoothing group the face + * belongs to. The generated triangles are added to each of these + * groups, which are also being converted to a new triangle based format. + * + * We need to convert to triangles before normals are generated + * because of smoothing groups. The faces in a smoothing group + * are copied into a GeometryInfo to have their normals calculated, + * and then the normals are copied out of the GeometryInfo using + * GeometryInfo.getNormalIndices. As part of Normal generation, + * the geometry gets converted to Triangles. So we need to convert + * to triangles *before* Normal generation so that the normals we + * read out of the GeometryInfo match up with the vertex data + * that we sent in. If we sent in TRIANGLE_FAN data, the normal + * generator would convert it to triangles and we'd read out + * normals formatted for Triangle data. This would not match up + * with our original Fan data, so we couldn't tell which normals + * go with which vertices. + */ + private void convertToTriangles() { + boolean triangulate = (flags & TRIANGULATE) != 0; + boolean textures = !texList.isEmpty() && !texIdxList.isEmpty() && + (texIdxList.size() == coordIdxList.size()); + boolean normals = !normList.isEmpty() && !normIdxList.isEmpty() && + (normIdxList.size() == coordIdxList.size()); + int numFaces = stripCounts.size(); + boolean haveSgroups = curSgroup != null; + + triGroups = new HashMap(50); + if (haveSgroups) triSgroups = new HashMap(50); + + ArrayList newCoordIdxList = null; + ArrayList newTexIdxList = null; + ArrayList newNormIdxList = null; + + if (triangulate) { + GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY); + gi.setStripCounts(objectToIntArray(stripCounts)); + gi.setCoordinates(coordArray); + gi.setCoordinateIndices(objectToIntArray(coordIdxList)); + if (textures) { + gi.setTextureCoordinateParams(1, 2); + gi.setTextureCoordinates(0, texArray); + gi.setTextureCoordinateIndices(0, objectToIntArray(texIdxList)); + } + if (normals) { + gi.setNormals(normArray); + gi.setNormalIndices(objectToIntArray(normIdxList)); + } + gi.convertToIndexedTriangles(); + + // Data is now indexed triangles. Next step is to take the data + // out of the GeometryInfo and put into internal data structures + + int coordIndicesArray[] = gi.getCoordinateIndices(); + + // Fix for #4366060 + // Make sure triangulated geometry has the correct number of triangles + int tris = 0; + for (int i = 0 ; i < numFaces ; i++) + tris += ((Integer)stripCounts.get(i)).intValue() - 2; + + if (coordIndicesArray.length != (tris * 3)) { + // Model contains bad polygons that didn't triangulate into the + // correct number of triangles. Fall back to "simple" triangulation + triangulate = false; + } else { + + int texIndicesArray[] = gi.getTextureCoordinateIndices(); + int normIndicesArray[] = gi.getNormalIndices(); + + // Convert index arrays to internal ArrayList format + coordIdxList.clear(); + texIdxList.clear(); + normIdxList.clear(); + for (int i = 0 ; i < coordIndicesArray.length ; i++) { + coordIdxList.add(new Integer(coordIndicesArray[i])); + if (textures) texIdxList.add(new Integer(texIndicesArray[i])); + if (normals) normIdxList.add(new Integer(normIndicesArray[i])); + } + } + } + + if (!triangulate) { + newCoordIdxList = new ArrayList(); + if (textures) newTexIdxList = new ArrayList(); + if (normals) newNormIdxList = new ArrayList(); + } + + // Repeat for each face in the model - add the triangles from each + // face to the Geometry and Smoothing Groups + int baseVertex = 0; + for (int f = 0 ; f < numFaces ; f++) { + int faceSize = ((Integer)stripCounts.get(f)).intValue(); + + // Find out the name of the group to which this face belongs + Integer curFace = new Integer(f); + curGroup = (String)groups.get(curFace); + + // Change to a new geometry group, create if it doesn't exist + curTriGroup = (ArrayList)triGroups.get(curGroup); + if (curTriGroup == null) { + curTriGroup = new ArrayList(); + triGroups.put(curGroup, curTriGroup); + } + + // Change to a new smoothing group, create if it doesn't exist + if (haveSgroups) { + curSgroup = (String)sGroups.get(curFace); + if (curSgroup == null) { + // Weird case - this face has no smoothing group. Happens if the + // first 's' token comes after some faces have already been defined. + // Assume they wanted no smoothing for these faces + curSgroup = "0"; + } + curTriSgroup = (ArrayList)triSgroups.get(curSgroup); + if (curTriSgroup == null) { + curTriSgroup = new ArrayList(); + triSgroups.put(curSgroup, curTriSgroup); + } + } + + if (triangulate) { + + // Each polygon of n vertices is now n-2 triangles + for (int t = 0 ; t < faceSize - 2 ; t++) { + + // The groups just remember the first vertex of each triangle + Integer triBaseVertex = new Integer(baseVertex); + curTriGroup.add(triBaseVertex); + if (haveSgroups) curTriSgroup.add(triBaseVertex); + + baseVertex += 3; + } + } else { + // Triangulate simply + for (int v = 0 ; v < faceSize - 2 ; v++) { + // Add this triangle to the geometry group and the smoothing group + Integer triBaseVertex = new Integer(newCoordIdxList.size()); + curTriGroup.add(triBaseVertex); + if (haveSgroups) curTriSgroup.add(triBaseVertex); + + newCoordIdxList.add(coordIdxList.get(baseVertex)); + newCoordIdxList.add(coordIdxList.get(baseVertex + v + 1)); + newCoordIdxList.add(coordIdxList.get(baseVertex + v + 2)); + + if (textures) { + newTexIdxList.add(texIdxList.get(baseVertex)); + newTexIdxList.add(texIdxList.get(baseVertex + v + 1)); + newTexIdxList.add(texIdxList.get(baseVertex + v + 2)); + } + + if (normals) { + newNormIdxList.add(normIdxList.get(baseVertex)); + newNormIdxList.add(normIdxList.get(baseVertex + v + 1)); + newNormIdxList.add(normIdxList.get(baseVertex + v + 2)); + } + } + baseVertex += faceSize; + } + } + + // No need to keep these around + stripCounts = null; + groups = null; + sGroups = null; + + if (!triangulate) { + coordIdxList = newCoordIdxList; + texIdxList = newTexIdxList; + normIdxList = newNormIdxList; + } + } // End of convertToTriangles + + + private SceneBase makeScene() { + // Create Scene to pass back + SceneBase scene = new SceneBase(); + BranchGroup group = new BranchGroup(); + scene.setSceneGroup(group); + + boolean gen_norms = normList.isEmpty() || normIdxList.isEmpty() || + (normIdxList.size() != coordIdxList.size()); + boolean do_tex = !texList.isEmpty() && !texIdxList.isEmpty() && + (texIdxList.size() == coordIdxList.size()); + + // Convert ArrayLists to arrays + coordArray = objectToPoint3Array(coordList); + if (!gen_norms) normArray = objectToVectorArray(normList); + if (do_tex) texArray = objectToTexCoord2Array(texList); + + convertToTriangles(); + + if ((DEBUG & 8) != 0) { + time = System.currentTimeMillis() - time; + System.out.println("Convert to triangles: " + time + " ms"); + time = System.currentTimeMillis(); + } + + if ((gen_norms) && (curSgroup != null)) { + smoothingGroupNormals(); + gen_norms = false; + if ((DEBUG & 8) != 0) { + time = System.currentTimeMillis() - time; + System.out.println("Smoothing group normals: " + time + " ms"); + time = System.currentTimeMillis(); + } + } + + NormalGenerator ng = null; + if (gen_norms) ng = new NormalGenerator(radians); + + Stripifier strippy = null; + if ((flags & STRIPIFY) != 0) strippy = new Stripifier(); + + long t1 = 0, t2 = 0, t3 = 0, t4 = 0; + + // Each "Group" of faces in the model will be one Shape3D + Iterator e = triGroups.keySet().iterator(); + while (e.hasNext()) { + + String curname = (String)e.next(); + ArrayList triList = (ArrayList)triGroups.get(curname); + + // Check for group with no faces + if (triList.size() > 0) { + + GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY); + + gi.setCoordinateIndices(groupIndices(coordIdxList, triList)); + gi.setCoordinates(coordArray); + + if (do_tex) { + gi.setTextureCoordinateParams(1, 2); + gi.setTextureCoordinates(0, texArray); + gi.setTextureCoordinateIndices(0, groupIndices(texIdxList, triList)); + } + + if ((DEBUG & 8) != 0) time = System.currentTimeMillis(); + if (gen_norms) { + if ((flags & REVERSE) != 0) gi.reverse(); + ng.generateNormals(gi); + if ((DEBUG & 8) != 0) { + t2 += System.currentTimeMillis() - time; + System.out.println("Generate normals: " + t2 + " ms"); + time = System.currentTimeMillis(); + } + } else { + gi.setNormalIndices(groupIndices(normIdxList, triList)); + gi.setNormals(normArray); + if ((flags & REVERSE) != 0) gi.reverse(); + } + + if ((flags & STRIPIFY) != 0) { + strippy.stripify(gi); + if ((DEBUG & 8) != 0) { + t3 += System.currentTimeMillis() - time; + System.out.println("Stripify: " + t3 + " ms"); + time = System.currentTimeMillis(); + } + } + + // Put geometry into Shape3d + Shape3D shape = new Shape3D(); + + shape.setGeometry(gi.getGeometryArray(true, true, false)); + + String matName = (String)groupMaterials.get(curname); + materials.assignMaterial(matName, shape); + + group.addChild(shape); + scene.addNamedObject(curname, shape); + + if ((DEBUG & 8) != 0) { + t4 += System.currentTimeMillis() - time; + System.out.println("Shape 3D: " + t4 + " ms"); + time = System.currentTimeMillis(); + } + } + } + + return scene; + } // end of makeScene + + + /** + * The Object File is loaded from the already opened file. + * To attach the model to your scene, call getSceneGroup() on + * the Scene object passed back, and attach the returned + * BranchGroup to your scene graph. For an example, see + * j3d-examples/ObjLoad/ObjLoad.java. + */ + public Scene load(Reader reader) throws FileNotFoundException, + IncorrectFormatException, + ParsingErrorException { + // ObjectFileParser does lexical analysis + ObjectFileParser st = new ObjectFileParser(reader); + + coordList = new ArrayList(); + texList = new ArrayList(); + normList = new ArrayList(); + coordIdxList = new ArrayList(); + texIdxList = new ArrayList(); + normIdxList = new ArrayList(); + groups = new HashMap(50); + curGroup = "default"; + sGroups = new HashMap(50); + curSgroup = null; + stripCounts = new ArrayList(); + groupMaterials = new HashMap(50); + groupMaterials.put(curGroup, "default"); + materials = new ObjectFileMaterials(); + + time = 0L; + if ((DEBUG & 8) != 0) { + time = System.currentTimeMillis(); + } + + readFile(st); + + if ((DEBUG & 8) != 0) { + time = System.currentTimeMillis() - time; + System.out.println("Read file: " + time + " ms"); + time = System.currentTimeMillis(); + } + + if ((flags & RESIZE) != 0) resize(); + + return makeScene(); + } // End of load(Reader) + + + /** + * For an .obj file loaded from a URL, set the URL where associated files + * (like material properties files) will be found. + * Only needs to be called to set it to a different URL + * from that containing the .obj file. + */ + public void setBaseUrl(URL url) { + baseUrl = url; + } // End of setBaseUrl + + + /** + * Return the URL where files associated with this .obj file (like + * material properties files) will be found. + */ + public URL getBaseUrl() { + return baseUrl; + } // End of getBaseUrl + + + /** + * Set the path where files associated with this .obj file are + * located. + * Only needs to be called to set it to a different directory + * from that containing the .obj file. + */ + public void setBasePath(String pathName) { + basePath = pathName; + if (basePath == null || basePath == "") + basePath = "." + java.io.File.separator; + basePath = basePath.replace('/', java.io.File.separatorChar); + basePath = basePath.replace('\\', java.io.File.separatorChar); + if (!basePath.endsWith(java.io.File.separator)) + basePath = basePath + java.io.File.separator; + } // End of setBasePath + + + /** + * Return the path where files associated with this .obj file (like material + * files) are located. + */ + public String getBasePath() { + return basePath; + } // End of getBasePath + + + /** + * Set parameters for loading the model. + * Flags defined in Loader.java are ignored by the ObjectFile Loader + * because the .obj file format doesn't include lights, fog, background, + * behaviors, views, or sounds. However, several flags are defined + * specifically for use with the ObjectFile Loader (see above). + */ + public void setFlags(int flags) { + this.flags = flags; + if ((DEBUG & 4) != 0) System.out.println("Flags = " + flags); + } // End of setFlags + + + /** + * Get the parameters currently defined for loading the model. + * Flags defined in Loader.java are ignored by the ObjectFile Loader + * because the .obj file format doesn't include lights, fog, background, + * behaviors, views, or sounds. However, several flags are defined + * specifically for use with the ObjectFile Loader (see above). + */ + public int getFlags() { + return flags; + } // End of getFlags + +} // End of class ObjectFile + +// End of file ObjectFile.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFileMaterials.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFileMaterials.java new file mode 100644 index 0000000..8c9147b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFileMaterials.java @@ -0,0 +1,425 @@ +/* + * $RCSfile: ObjectFileMaterials.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/02/09 17:20:10 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.objectfile; + +import javax.media.j3d.Appearance; +import javax.media.j3d.Material; +import javax.media.j3d.Shape3D; +import javax.vecmath.Color3f; +import com.sun.j3d.loaders.ParsingErrorException; +import com.sun.j3d.loaders.IncorrectFormatException; +import java.io.FileNotFoundException; +import java.io.StringReader; +import java.io.Reader; +import java.io.FileReader; +import java.io.BufferedReader; +import java.io.BufferedInputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.FileInputStream; +import java.util.HashMap; +import com.sun.j3d.loaders.objectfile.DefaultMaterials; +import java.net.URL; +import java.net.MalformedURLException; +import java.awt.Toolkit; +import java.awt.Image; +import java.awt.image.BufferedImage; +import javax.media.j3d.Texture2D; +import java.awt.image.ImageObserver; +import java.awt.image.PixelGrabber; +import java.awt.image.DataBufferInt; +import javax.media.j3d.ImageComponent2D; +import javax.media.j3d.TexCoordGeneration; +import java.security.AccessController; +import java.security.PrivilegedAction; +import javax.media.j3d.GeometryArray; +import com.sun.j3d.utils.image.TextureLoader; +import javax.media.j3d.TransparencyAttributes; + + +class ObjectFileMaterials implements ImageObserver { + // DEBUG + // 1 = Name of materials + // 16 = Tokens + private static final int DEBUG = 0; + + private String curName = null; + private ObjectFileMaterial cur = null; + + private HashMap materials; // key=String name of material + // value=ObjectFileMaterial + + private String basePath; + private boolean fromUrl; + + private class ObjectFileMaterial { + + public Color3f Ka; + public Color3f Kd; + public Color3f Ks; + public int illum; + public float Ns; + public Texture2D t; + public boolean transparent; + public float transparencyLevel; + + } + + + void assignMaterial(String matName, Shape3D shape) { + ObjectFileMaterial p = null; + + if ((DEBUG & 1) != 0) System.out.println("Color " + matName); + + Material m = new Material(); + p = (ObjectFileMaterial)materials.get(matName); + Appearance a = new Appearance(); + + if (p != null) { + // Set ambient & diffuse color + if (p.Ka != null) m.setAmbientColor(p.Ka); + if (p.Kd != null) m.setDiffuseColor(p.Kd); + + // Set specular color + if ((p.Ks != null) && (p.illum != 1)) m.setSpecularColor(p.Ks); + else if (p.illum == 1) m.setSpecularColor(0.0f, 0.0f, 0.0f); + + if (p.illum >= 1) m.setLightingEnable(true); + else if (p.illum == 0) m.setLightingEnable(false); + + if (p.Ns != -1.0f) m.setShininess(p.Ns); + + if (p.t != null) { + a.setTexture(p.t); + // Create Texture Coordinates if not already present + if ((((GeometryArray)shape.getGeometry()).getVertexFormat() & + GeometryArray.TEXTURE_COORDINATE_2) == 0) { + TexCoordGeneration tcg = new TexCoordGeneration(); + a.setTexCoordGeneration(tcg); + } + } + + if (p.transparent) + a.setTransparencyAttributes( + new TransparencyAttributes(TransparencyAttributes.NICEST, + p.transparencyLevel)); + } + a.setMaterial(m); + if ((DEBUG & 1) != 0) System.out.println(m); + shape.setAppearance(a); + } // End of assignMaterial + + + private void readName(ObjectFileParser st) throws ParsingErrorException { + st.getToken(); + + if (st.ttype == ObjectFileParser.TT_WORD) { + + if (curName != null) materials.put(curName, cur); + curName = new String(st.sval); + cur = new ObjectFileMaterial(); + } + st.skipToNextLine(); + } // End of readName + + + private void readAmbient(ObjectFileParser st) throws ParsingErrorException { + Color3f p = new Color3f(); + + st.getNumber(); + p.x = (float)st.nval; + st.getNumber(); + p.y = (float)st.nval; + st.getNumber(); + p.z = (float)st.nval; + + cur.Ka = p; + + st.skipToNextLine(); + } // End of readAmbient + + + private void readDiffuse(ObjectFileParser st) throws ParsingErrorException { + Color3f p = new Color3f(); + + st.getNumber(); + p.x = (float)st.nval; + st.getNumber(); + p.y = (float)st.nval; + st.getNumber(); + p.z = (float)st.nval; + + cur.Kd = p; + + st.skipToNextLine(); + } // End of readDiffuse + + + private void readSpecular(ObjectFileParser st) throws ParsingErrorException { + Color3f p = new Color3f(); + + st.getNumber(); + p.x = (float)st.nval; + st.getNumber(); + p.y = (float)st.nval; + st.getNumber(); + p.z = (float)st.nval; + + cur.Ks = p; + + st.skipToNextLine(); + } // End of readSpecular + + + private void readIllum(ObjectFileParser st) throws ParsingErrorException { + + st.getNumber(); + cur.illum = (int)st.nval; + + st.skipToNextLine(); + } // End of readSpecular + + private void readTransparency(ObjectFileParser st) throws ParsingErrorException { + + st.getNumber(); + cur.transparencyLevel = (float)st.nval; + if ( cur.transparencyLevel < 1.0f ){ + cur.transparent = true; + } + st.skipToNextLine(); + } // End of readTransparency + + private void readShininess(ObjectFileParser st) throws ParsingErrorException { + float f; + + st.getNumber(); + cur.Ns = (float)st.nval; + if (cur.Ns < 1.0f) cur.Ns = 1.0f; + else if (cur.Ns > 128.0f) cur.Ns = 128.0f; + + st.skipToNextLine(); + } // End of readSpecular + + + public void readMapKd(ObjectFileParser st) { + // Filenames are case sensitive + st.lowerCaseMode(false); + + // Get name of texture file (skip path) + String tFile = null; + do { + st.getToken(); + if (st.ttype == ObjectFileParser.TT_WORD) tFile = st.sval; + } while (st.ttype != ObjectFileParser.TT_EOL); + + st.lowerCaseMode(true); + + if (tFile != null) { + // Check for filename with no extension + if (tFile.lastIndexOf('.') != -1) { + try { + // Convert filename to lower case for extension comparisons + String suffix = + tFile.substring(tFile.lastIndexOf('.') + 1).toLowerCase(); + + TextureLoader t = null; + + if ((suffix.equals("int")) || (suffix.equals("inta")) || + (suffix.equals("rgb")) || (suffix.equals("rgba")) || + (suffix.equals("bw")) || (suffix.equals("sgi"))) { + RgbFile f; + if (fromUrl) { + f = new RgbFile(new URL(basePath + tFile).openStream()); + } else { + f = new RgbFile(new FileInputStream(basePath + tFile)); + } + BufferedImage bi = f.getImage(); + + boolean luminance = suffix.equals("int") || suffix.equals("inta"); + boolean alpha = suffix.equals("inta") || suffix.equals("rgba"); + cur.transparent = alpha; + + String s = null; + if (luminance && alpha) s = "LUM8_ALPHA8"; + else if (luminance) s = "LUMINANCE"; + else if (alpha) s = "RGBA"; + else s = "RGB"; + + t = new TextureLoader(bi, s, TextureLoader.GENERATE_MIPMAP); + } else { + // For all other file types, use the TextureLoader + if (fromUrl) { + t = new TextureLoader(new URL(basePath + tFile), "RGB", + TextureLoader.GENERATE_MIPMAP, null); + } else { + t = new TextureLoader(basePath + tFile, "RGB", + TextureLoader.GENERATE_MIPMAP, null); + } + } + Texture2D texture = (Texture2D)t.getTexture(); + if (texture != null) cur.t = texture; + } + catch (FileNotFoundException e) { + // Texture won't get loaded if file can't be found + } + catch (MalformedURLException e) { + // Texture won't get loaded if file can't be found + } + catch (IOException e) { + // Texture won't get loaded if file can't be found + } + } + } + st.skipToNextLine(); + } // End of readMapKd + + + private void readFile(ObjectFileParser st) throws ParsingErrorException { + int t; + st.getToken(); + while (st.ttype != ObjectFileParser.TT_EOF) { + + // Print out one token for each line + if ((DEBUG & 16) != 0) { + System.out.print("Token "); + if (st.ttype == ObjectFileParser.TT_EOL) System.out.println("EOL"); + else if (st.ttype == ObjectFileParser.TT_WORD) + System.out.println(st.sval); + else System.out.println((char)st.ttype); + } + + if (st.ttype == ObjectFileParser.TT_WORD) { + if (st.sval.equals("newmtl")) { + readName(st); + } else if (st.sval.equals("ka")) { + readAmbient(st); + } else if (st.sval.equals("kd")) { + readDiffuse(st); + } else if (st.sval.equals("ks")) { + readSpecular(st); + } else if (st.sval.equals("illum")) { + readIllum(st); + } else if (st.sval.equals("d")) { + readTransparency(st); + } else if (st.sval.equals("ns")) { + readShininess(st); + } else if (st.sval.equals("tf")) { + st.skipToNextLine(); + } else if (st.sval.equals("sharpness")) { + st.skipToNextLine(); + } else if (st.sval.equals("map_kd")) { + readMapKd(st); + } else if (st.sval.equals("map_ka")) { + st.skipToNextLine(); + } else if (st.sval.equals("map_ks")) { + st.skipToNextLine(); + } else if (st.sval.equals("map_ns")) { + st.skipToNextLine(); + } else if (st.sval.equals("bump")) { + st.skipToNextLine(); + } + } + + st.skipToNextLine(); + + // Get next token + st.getToken(); + } + if (curName != null) materials.put(curName, cur); + } // End of readFile + + + void readMaterialFile(boolean fromUrl, String basePath, String fileName) + throws ParsingErrorException { + + Reader reader; + + this.basePath = basePath; + this.fromUrl = fromUrl; + + try { + if (fromUrl) { + reader = (Reader) + (new InputStreamReader( + new BufferedInputStream( + (new URL(basePath + fileName).openStream())))); + } else { + reader = new BufferedReader(new FileReader(basePath + fileName)); + } + } + catch (IOException e) { + // couldn't find it - ignore mtllib + return; + } + if ((DEBUG & 1) != 0) + System.out.println("Material file: " + basePath + fileName); + + ObjectFileParser st = new ObjectFileParser(reader); + readFile(st); + } // End of readMaterialFile + + + ObjectFileMaterials() throws ParsingErrorException { + Reader reader = new StringReader(DefaultMaterials.materials); + + ObjectFileParser st = new ObjectFileParser(reader); + materials = new HashMap(50); + readFile(st); + } // End of ObjectFileMaterials + + + /** + * Implement the ImageObserver interface. Needed to load jpeg and gif + * files using the Toolkit. + */ + public boolean imageUpdate(Image img, int flags, + int x, int y, int w, int h) { + + return (flags & (ALLBITS | ABORT)) == 0; + } // End of imageUpdate + +} // End of class ObjectFileMaterials + +// End of file ObjectFileMaterials.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFileParser.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFileParser.java new file mode 100644 index 0000000..1bc16e4 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/ObjectFileParser.java @@ -0,0 +1,179 @@ +/* + * $RCSfile: ObjectFileParser.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:10 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.objectfile; + +import java.io.StreamTokenizer; +import java.io.IOException; +import java.io.Reader; +import com.sun.j3d.loaders.ParsingErrorException; + +class ObjectFileParser extends StreamTokenizer { + + private static final char BACKSLASH = '\\'; + + + /** + * setup + * + * Sets up StreamTokenizer for reading ViewPoint .obj file format. + */ + void setup() { + resetSyntax(); + eolIsSignificant(true); + lowerCaseMode(true); + + // All printable ascii characters + wordChars('!', '~'); + + // Comment from ! to end of line + commentChar('!'); + + whitespaceChars(' ', ' '); + whitespaceChars('\n', '\n'); + whitespaceChars('\r', '\r'); + whitespaceChars('\t', '\t'); + + // These characters returned as tokens + ordinaryChar('#'); + ordinaryChar('/'); + ordinaryChar(BACKSLASH); + } // End of setup + + + /** + * getToken + * + * Gets the next token from the stream. Puts one of the four + * constants (TT_WORD, TT_NUMBER, TT_EOL, or TT_EOF) or the token value + * for single character tokens into ttype. Handles backslash + * continuation of lines. + */ + void getToken() throws ParsingErrorException { + int t; + boolean done = false; + + try { + do { + t = nextToken(); + if (t == BACKSLASH) { + t = nextToken(); + if (ttype != TT_EOL) done = true; + } else done = true; + } while (!done); + } + catch (IOException e) { + throw new ParsingErrorException( + "IO error on line " + lineno() + ": " + e.getMessage()); + } + } // End of getToken + + + void printToken() { + switch (ttype) { + case TT_EOL: + System.out.println("Token EOL"); + break; + case TT_EOF: + System.out.println("Token EOF"); + break; + case TT_WORD: + System.out.println("Token TT_WORD: " + sval); + break; + case '/': + System.out.println("Token /"); + break; + case BACKSLASH: + System.out.println("Token " + BACKSLASH); + break; + case '#': + System.out.println("Token #"); + break; + } + } // end of printToken + + + /** + * skipToNextLine + * + * Skips all tokens on the rest of this line. Doesn't do anything if + * We're already at the end of a line + */ + void skipToNextLine() throws ParsingErrorException { + while (ttype != TT_EOL) { + getToken(); + } + } // end of skipToNextLine + + + /** + * getNumber + * + * Gets a number from the stream. Note that we don't recognize + * numbers in the tokenizer automatically because numbers might be in + * scientific notation, which isn't processed correctly by + * StreamTokenizer. The number is returned in nval. + */ + void getNumber() throws ParsingErrorException { + int t; + + try { + getToken(); + if (ttype != TT_WORD) + throw new ParsingErrorException("Expected number on line " + lineno()); + nval = (Double.valueOf(sval)).doubleValue(); + } + catch (NumberFormatException e) { + throw new ParsingErrorException(e.getMessage()); + } + } // end of getNumber + + + // ObjectFileParser constructor + ObjectFileParser(Reader r) { + super(r); + setup(); + } // end of ObjectFileParser + +} // End of file ObjectFileParser.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/RgbFile.java b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/RgbFile.java new file mode 100644 index 0000000..693769f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/RgbFile.java @@ -0,0 +1,202 @@ +/* + * $RCSfile: RgbFile.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:10 $ + * $State: Exp $ + */ + +package com.sun.j3d.loaders.objectfile; + +import java.io.BufferedInputStream; +import java.io.FileNotFoundException; +import java.io.FileInputStream; +import java.io.InputStream; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.ComponentColorModel; +import java.awt.image.WritableRaster; +import java.awt.color.ColorSpace; +import java.awt.Transparency; + +class RgbFile extends BufferedInputStream { + + // Header data + short dimension; + short xSize; + short ySize; + short zSize; + + String filename; + + private static final int DEBUG = 0; + + + short getShort() throws IOException { + int t1 = (short)read(); + if (t1 == -1) throw new IOException("Unexpected EOF"); + int t2 = (short)read(); + if (t2 == -1) throw new IOException("Unexpected EOF"); + return (short)((t1 << 8) | t2); + } // End of getShort() + + + byte getByte() throws IOException { + int t = read(); + if (t == -1) throw new IOException("Unexpected EOF"); + return (byte)t; + } // End of getByte + + + int getInt() throws IOException { + int ret = 0; + for (int i = 0 ; i < 4 ; i++) { + int t = read(); + if (t == -1) throw new IOException("Unexpected EOF"); + ret = (ret << 8) | t; + } + return ret; + } // end of getInt + + + public BufferedImage getImage() throws IOException { + short magic = getShort(); + + if (magic != 474) throw new IOException("Unrecognized file format."); + + byte storage = getByte(); + + if (storage != 0) + throw new IOException("RLE Compressed files not supported"); + + byte bpc = getByte(); + dimension = getShort(); + xSize = getShort(); + ySize = getShort(); + zSize = getShort(); + int pixMin = getInt(); + int pixMax = getInt(); + skip(84l); + int colorMap = getInt(); + + if ((DEBUG & 1) != 0) { + System.out.println(filename + ":"); + System.out.println(" bpc = " + bpc); + System.out.println(" dimension = " + dimension); + System.out.println(" xSize = " + xSize); + System.out.println(" ySize = " + ySize); + System.out.println(" zSize = " + zSize); + System.out.println(" pixMin = " + pixMin); + System.out.println(" pixMax = " + pixMax); + System.out.println(" colorMap = " + colorMap); + } + + if ((pixMin != 0) || (pixMax != 0xff) || (colorMap != 0) || (bpc != 1)) + throw new IOException("Unsupported options in file"); + + skip(404l); + + ComponentColorModel cm = null; + if (zSize == 1) { + // Black and White image + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + + int[] nBits = {8}; + cm = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + + } else if (zSize == 2) { + // Black and White image with alpha + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + + int[] nBits = {8, 8}; + cm = new ComponentColorModel(cs, nBits, true, false, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + + } else if (zSize == 3) { + // RGB Image + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + + int[] nBits = {8, 8, 8}; + cm = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + + } else if (zSize == 4) { + // RGBA Image + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + + int[] nBits = {8, 8, 8, 8}; + cm = new ComponentColorModel(cs, nBits, true, false, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + } else { + throw new IOException("Unsupported options in file"); + } + + WritableRaster r = cm.createCompatibleWritableRaster(xSize, ySize); + BufferedImage bi = new BufferedImage(cm, r, false, null); + + int t; + byte image[] = ((DataBufferByte)r.getDataBuffer()).getData(); + for (short z = 0 ; z < zSize ; z++) { + for (int y = ySize - 1 ; y >= 0 ; y--) { + for (short x = 0 ; x < xSize ; x++) { + t = read(); + if (t == -1) throw new IOException("Unexpected EOF"); + image[y * (xSize * zSize) + (x * zSize) + z] = (byte)t; + } + } + } + + return bi; + } // End of getImage + + + public RgbFile(InputStream s) { + super(s); + } // End of RgbFile(URL) + +} // End of class RgbFile + +// End of file RgbFile.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/package.html new file mode 100644 index 0000000..1171815 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/objectfile/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.loaders.objectfile + + +

Provides a Java 3D loader for Wavefront .obj files.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/package.html new file mode 100644 index 0000000..6b38d00 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/loaders/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.loaders + + +

Provides interfaces and abstract classes for writing Java 3D loaders.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/JMainFrame.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/JMainFrame.java new file mode 100644 index 0000000..34dc1f3 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/JMainFrame.java @@ -0,0 +1,347 @@ +/* + * $RCSfile: JMainFrame.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:10 $ + * $State: Exp $ + */ + +// JMainFrame - run an Applet as an application +// +// Copyright (C) 1996 by Jef Poskanzer . All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ + +// --------------------------------------------------------------------- + +package com.sun.j3d.utils.applet; + +import java.applet.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; +import java.io.*; +import java.net.*; +import javax.swing.*; +import java.util.*; + +public class JMainFrame extends JFrame + implements Runnable, AppletStub, AppletContext { + + private String[] args = null; + private static int instances = 0; + private String name; + private Applet applet; + private Label label = null; + private Dimension appletSize; + + private static final String PARAM_PROP_PREFIX = "parameter."; + + public JMainFrame(Applet applet, String[] args, int width, int height) { + build(applet, args, width, height); + } + public JMainFrame(Applet applet, String[] args) { + build(applet, args, -1, -1); + } + + public JMainFrame(Applet applet, int width, int height) { + build(applet, null, width, height); + } + + private void build(Applet applet, String[] args, int width, int height) { + ++instances; + this.applet = applet; + this.args = args; + applet.setStub( this ); + name = applet.getClass().getName(); + setTitle( name ); + + // Set up properties. + Properties props = System.getProperties(); + props.put( "browser", "Acme.MainFrame" ); + props.put( "browser.version", "11jul96" ); + props.put( "browser.vendor", "Acme Laboratories" ); + props.put( "browser.vendor.url", "http://www.acme.com/" ); + + // Turn args into parameters by way of the properties list. + if ( args != null ) + parseArgs( args, props ); + + // If width and height are specified in the parameters, override + // the compiled-in values. + String widthStr = getParameter( "width" ); + if ( widthStr != null ) + width = Integer.parseInt( widthStr ); + String heightStr = getParameter( "height" ); + if ( heightStr != null ) + height = Integer.parseInt( heightStr ); + + // Were width and height specified somewhere? + if ( width == -1 || height == -1 ) { + System.err.println( "Width and height must be specified." ); + return; + } + + // Lay out components. + Container contentPane = getContentPane(); + contentPane.add(applet, BorderLayout.CENTER); + + // Set up size. + pack(); + validate(); + appletSize = applet.getSize(); + applet.setSize( width, height ); + setVisible(true); + + /* + Added WindowListener inner class to detect close events. + */ + SecurityManager sm = System.getSecurityManager(); + boolean doExit = true; + if (sm != null) { + try { + sm.checkExit(0); + } catch (SecurityException e) { + doExit = false; + } + } + + final boolean _doExit = doExit; + + // WindowListener inner class to detect close events. + addWindowListener(new WindowAdapter() + { + public void windowClosing(WindowEvent winEvent) + { + if (JMainFrame.this.applet != null) { + JMainFrame.this.applet.destroy(); + } + hide(); + try { + dispose(); + } catch (IllegalStateException e) {} + + if (_doExit) { + System.exit(0); + } + + } + }); + + // Start a separate thread to call the applet's init() and start() + // methods, in case they take a long time. + (new Thread( this )).start(); + + } + + // Turn command-line arguments into Applet parameters, by way of the + // properties list. + private static void parseArgs( String[] args, Properties props ) { + for ( int i = 0; i < args.length; ++i ) { + String arg = args[i]; + int ind = arg.indexOf( '=' ); + if ( ind == -1 ) + props.put( PARAM_PROP_PREFIX + arg.toLowerCase(), "" ); + else + props.put( + PARAM_PROP_PREFIX + arg.substring( 0, ind ).toLowerCase(), + arg.substring( ind + 1 ) ); + } + } + + // Methods from Runnable. + + /// Separate thread to call the applet's init() and start() methods. + public void run() { + showStatus( name + " initializing..." ); + applet.init(); + validate(); + showStatus( name + " starting..." ); + applet.start(); + validate(); + showStatus( name + " running..." ); + } + + // Methods from AppletStub. + + public boolean isActive() { + return true; + } + + public URL getDocumentBase() { + // Returns the current directory. + String dir = System.getProperty( "user.dir" ); + String urlDir = dir.replace( File.separatorChar, '/' ); + try { + return new URL( "file:" + urlDir + "/"); + } + catch ( MalformedURLException e ) { + return null; + } + } + + public URL getCodeBase() { + // Hack: loop through each item in CLASSPATH, checking if + // the appropriately named .class file exists there. But + // this doesn't account for .zip files. + String path = System.getProperty( "java.class.path" ); + Enumeration st = new StringTokenizer( path, ":" ); + while ( st.hasMoreElements() ) { + String dir = (String) st.nextElement(); + String filename = dir + File.separatorChar + name + ".class"; + File file = new File( filename ); + if ( file.exists() ) { + String urlDir = dir.replace( File.separatorChar, '/' ); + try { + return new URL( "file:" + urlDir + "/" ); + } + catch ( MalformedURLException e ) { + return null; + } + } + } + return null; + } + + public String getParameter( String name ) { + // Return a parameter via the munged names in the properties list. + return System.getProperty( PARAM_PROP_PREFIX + name.toLowerCase() ); + } + + public void appletResize( int width, int height ) { + // Change the frame's size by the same amount that the applet's + // size is changing. + Dimension frameSize = getSize(); + frameSize.width += width - appletSize.width; + frameSize.height += height - appletSize.height; + setSize( frameSize ); + appletSize = applet.getSize(); + } + + public AppletContext getAppletContext() { + return this; + } + + + // Methods from AppletContext. + + public AudioClip getAudioClip( URL url ) { + // This is an internal undocumented routine. However, it + // also provides needed functionality not otherwise available. + // I suspect that in a future release, JavaSoft will add an + // audio content handler which encapsulates this, and then + // we can just do a getContent just like for images. + return new sun.applet.AppletAudioClip( url ); + } + + public Image getImage( URL url ) { + Toolkit tk = Toolkit.getDefaultToolkit(); + try { + ImageProducer prod = (ImageProducer) url.getContent(); + return tk.createImage( prod ); + } + catch ( IOException e ) { + return null; + } + } + + public Applet getApplet( String name ) { + // Returns this Applet or nothing. + if ( name.equals( this.name ) ) + return applet; + return null; + } + + public Enumeration getApplets() { + // Just yields this applet. + Vector v = new Vector(); + v.addElement( applet ); + return v.elements(); + } + + public void showDocument( URL url ) { + // Ignore. + } + + public void showDocument( URL url, String target ) { + // Ignore. + } + + public void showStatus( String status ) { + if ( label != null ) + label.setText( status ); + } + + public void setStream( String key, java.io.InputStream stream ) { + throw new RuntimeException("Not Implemented"); + // TODO implement setStream method + } + + public java.io.InputStream getStream( String key ) { + throw new RuntimeException("Not Implemented"); + // TODO implement getStream method + } + + public java.util.Iterator getStreamKeys() { + throw new RuntimeException("Not Implemented"); + // TODO implement getStreamKeys method + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/MainFrame.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/MainFrame.java new file mode 100644 index 0000000..53000e0 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/MainFrame.java @@ -0,0 +1,397 @@ +/* + * $RCSfile: MainFrame.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:10 $ + * $State: Exp $ + */ + +// MainFrame - run an Applet as an application +// +// Copyright (C) 1996 by Jef Poskanzer . All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ + +// --------------------------------------------------------------------- + +package com.sun.j3d.utils.applet; + +import java.applet.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; +import java.net.*; +import java.io.*; +import java.util.*; + +/// Run an Applet as an application. +//

+// Using this class you can add a trivial main program to any Applet +// and run it directly, as well as from a browser or the appletviewer. +// And unlike some versions of this concept, MainFrame implements both +// images and sound. +//

+// Sample main program: +//

+// public static void main( String[] args )
+//     {
+//     new Acme.MainFrame( new ThisApplet(), args, 400, 400 );
+//     }
+// 
+// The only methods you need to know about are the constructors. +//

+// You can specify Applet parameters on the command line, as name=value. +// For instance, the equivalent of: +//

+// <PARAM NAME="pause" VALUE="200">
+// 
+// would just be: +//
+// pause=200
+// 
+// You can also specify three special parameters: +//
+// width=N          Width of the Applet.
+// height=N         Height of the Applet.
+// barebones=true   Leave off the menu bar and status area.
+// 
+//

+// Fetch the software.
+// Fetch the entire Acme package. + +public class MainFrame extends Frame implements + Runnable, AppletStub, AppletContext +{ + + private String[] args = null; + private static int instances = 0; + private String name; + private boolean barebones = true; + private Applet applet; + private Label label = null; + private Dimension appletSize; + + private static final String PARAM_PROP_PREFIX = "parameter."; + + /// Constructor with everything specified. + public MainFrame(Applet applet, String[] args, + int width, int height) { + build(applet, args, width, height); + } + + /// Constructor with no default width/height. + public MainFrame(Applet applet, String[] args ) { + build(applet, args, -1, -1); + } + + /// Constructor with no arg parsing. + public MainFrame(Applet applet, int width, int height) { + build( applet, null, width, height ); + } + + // Internal constructor routine. + private void build( Applet applet, String[] args, + int width, int height) { + ++instances; + this.applet = applet; + this.args = args; + applet.setStub( this ); + name = applet.getClass().getName(); + setTitle( name ); + + // Set up properties. + Properties props = System.getProperties(); + props.put( "browser", "Acme.MainFrame" ); + props.put( "browser.version", "11jul96" ); + props.put( "browser.vendor", "Acme Laboratories" ); + props.put( "browser.vendor.url", "http://www.acme.com/" ); + + // Turn args into parameters by way of the properties list. + if ( args != null ) + parseArgs( args, props ); + + // If width and height are specified in the parameters, override + // the compiled-in values. + String widthStr = getParameter( "width" ); + if ( widthStr != null ) { + width = Integer.parseInt( widthStr ); + } + + String heightStr = getParameter( "height" ); + if ( heightStr != null ) { + height = Integer.parseInt( heightStr ); + } + + // Were width and height specified somewhere? + if ((width == -1) || (height == -1)) { + System.err.println( "Width and height must be specified." ); + return; + } + + // Do we want to run bare-bones? + String bonesStr = getParameter( "barebones" ); + if ((bonesStr != null) && bonesStr.equals( "true" )) { + barebones = true; + } + + // Lay out components. + setLayout( new BorderLayout() ); + add( "Center", applet ); + + // Set up size. + pack(); + validate(); + appletSize = applet.getSize(); + applet.setSize( width, height ); + setVisible(true); + + + /* + Added WindowListener inner class to detect close events. + */ + SecurityManager sm = System.getSecurityManager(); + boolean doExit = true; + + if (sm != null) { + try { + sm.checkExit(0); + } catch (SecurityException e) { + doExit = false; + } + } + + final boolean _doExit = doExit; + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent winEvent) { + if (MainFrame.this.applet != null) { + MainFrame.this.applet.destroy(); + } + Window w = winEvent.getWindow(); + w.hide(); + try { + w.dispose(); + } catch (IllegalStateException e) {} + + if (_doExit) { + System.exit(0); + } + } + }); + + // Start a separate thread to call the applet's init() and start() + // methods, in case they take a long time. + (new Thread( this )).start(); + } + + // Turn command-line arguments into Applet parameters, by way of the + // properties list. + private static void parseArgs( String[] args, Properties props) { + String arg; + + for (int i = 0; i < args.length; ++i) { + arg = args[i]; + int ind = arg.indexOf( '=' ); + if ( ind == -1 ) { + props.put(PARAM_PROP_PREFIX + arg.toLowerCase(), "" ); + } else { + props.put(PARAM_PROP_PREFIX + arg.substring( 0, ind ).toLowerCase(), + arg.substring( ind + 1 ) ); + } + } + } + + // Methods from Runnable. + + /// Separate thread to call the applet's init() and start() methods. + public void run() { + showStatus( name + " initializing..." ); + applet.init(); + validate(); + showStatus( name + " starting..." ); + applet.start(); + validate(); + showStatus( name + " running..." ); + } + + + // Methods from AppletStub. + public boolean isActive() { + return true; + } + + public URL getDocumentBase() { + // Returns the current directory. + String dir = System.getProperty( "user.dir" ); + String urlDir = dir.replace( File.separatorChar, '/' ); + try { + return new URL( "file:" + urlDir + "/"); + } catch ( MalformedURLException e ) { + return null; + } + } + + public URL getCodeBase() { + // Hack: loop through each item in CLASSPATH, checking if + // the appropriately named .class file exists there. But + // this doesn't account for .zip files. + String path = System.getProperty( "java.class.path" ); + Enumeration st = new StringTokenizer( path, ":" ); + while ( st.hasMoreElements() ) { + String dir = (String) st.nextElement(); + String filename = dir + File.separatorChar + name + ".class"; + File file = new File( filename ); + if (file.exists()) { + String urlDir = dir.replace( File.separatorChar, '/' ); + try { + return new URL( "file:" + urlDir + "/" ); + } catch (MalformedURLException e) { + return null; + } + } + } + return null; + } + + public String getParameter(String name) { + // Return a parameter via the munged names in the properties list. + return System.getProperty( PARAM_PROP_PREFIX + name.toLowerCase() ); + } + + public void appletResize(int width, int height) { + // Change the frame's size by the same amount that the applet's + // size is changing. + Dimension frameSize = getSize(); + frameSize.width += width - appletSize.width; + frameSize.height += height - appletSize.height; + setSize( frameSize ); + appletSize = applet.getSize(); + } + + public AppletContext getAppletContext() { + return this; + } + + + // Methods from AppletContext. + public AudioClip getAudioClip( URL url ) { + // This is an internal undocumented routine. However, it + // also provides needed functionality not otherwise available. + // I suspect that in a future release, JavaSoft will add an + // audio content handler which encapsulates this, and then + // we can just do a getContent just like for images. + return new sun.applet.AppletAudioClip( url ); + } + + public Image getImage( URL url ) { + Toolkit tk = Toolkit.getDefaultToolkit(); + try { + ImageProducer prod = (ImageProducer) url.getContent(); + return tk.createImage( prod ); + } catch ( IOException e ) { + return null; + } + } + + public Applet getApplet(String name) { + // Returns this Applet or nothing. + if (name.equals( this.name )) { + return applet; + } + return null; + } + + public Enumeration getApplets() { + // Just yields this applet. + Vector v = new Vector(); + v.addElement( applet ); + return v.elements(); + } + + public void showDocument( URL url ) { + // Ignore. + } + + public void showDocument( URL url, String target ) { + // Ignore. + } + + public void showStatus( String status ) { + if (label != null) { + label.setText(status); + } + } + + public void setStream( String key, java.io.InputStream stream ) { + throw new RuntimeException("Not Implemented"); + // TODO implement setStream method + } + + public java.io.InputStream getStream( String key ) { + throw new RuntimeException("Not Implemented"); + // TODO implement getStream method + } + + public java.util.Iterator getStreamKeys() { + throw new RuntimeException("Not Implemented"); + // TODO implement getStreamKeys method + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/package.html new file mode 100644 index 0000000..3e0334e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/applet/package.html @@ -0,0 +1,12 @@ + + + + + com.sun.j3d.utils.applet + + +

Provides utility classes for running applets as stand-alone +applications.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/audio/DistanceAttenuation.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/audio/DistanceAttenuation.java new file mode 100644 index 0000000..d7069c3 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/audio/DistanceAttenuation.java @@ -0,0 +1,134 @@ +/* + * $RCSfile: DistanceAttenuation.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:11 $ + * $State: Exp $ + */ + + /* + * Sound Distance Attenuation utilities + * + * Various methods to create PointSound and ConeSound distance attenuation + * arrays. + */ + +package com.sun.j3d.utils.audio; + +import java.io.* ; +import javax.vecmath.* ; +import java.lang.String; +import javax.media.j3d.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +public class DistanceAttenuation +{ + // private fields + + // public fields + /** + * Equation types + */ + static final int DOUBLE_DISTANCE_HALF_GAIN = 1; + + // methods + /** + * Fill a Distance Attenuation array + * + * recommend that the distance attenuation Point2f array is defined to + * be allocated to be 10 for DOUBLE_DISTANCE_HALF_GAIN - since 1/(2^10) + * exceeds 1/1000 scale that is agreed to be affective zero gain + * + * First method assumes that: + * type is half gain for every double of distance + * inner radius is 0.0 but region between 0th and 1st elements is constant + * since gains for these two elements are the same + * min gain approches zero. + */ + public void fillDistanceAttenuation( + float unitDistance, float unitGain, + Point2f[] distanceAttenuation ) { + if (distanceAttenuation == null) + throw new SoundException(J3dUtilsI18N.getString("DistanceAttenuation0")); + + int length = distanceAttenuation.length; + distanceAttenuation[0].x = 0.0f; + distanceAttenuation[0].y = unitGain; + float nextDistance = unitDistance; + float nextGain = unitGain; + + for (int i=1; i + + + + com.sun.j3d.utils.audio + + +

Provides audio utility classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineCurve.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineCurve.java new file mode 100644 index 0000000..26944b1 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineCurve.java @@ -0,0 +1,175 @@ +/* + * $RCSfile: CubicSplineCurve.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:11 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * CubicSplineCurve is a container class that holds a number of + * cubicSplineSegments + * + * @since Java3D 1.1 + */ + +public class CubicSplineCurve { + + private float totalCurveLength; + private CubicSplineSegment[] cubicSplineSegment; + public int numSegments; + + + /** + * Default constructor + */ + CubicSplineCurve () { + numSegments = 0; + totalCurveLength = 0f; + } + + /** + * This method takes a list of key frames and creates spline segments + * from it. It requires at least four key frames to be passed to it. + * Given n key frames, it creates n-3 CubicSplineSegments. + * @param keys the list of key frames that specify the motion path + */ + + CubicSplineCurve (TCBKeyFrame keys[]) { + + int keyLength = keys.length; + // Require at least 4 key frames for cubic spline curve + if (keyLength < 4) + throw new IllegalArgumentException(J3dUtilsI18N.getString("CubicSplineCurve0")); + + numSegments = keyLength - 3; + this.cubicSplineSegment = new CubicSplineSegment[numSegments]; + + // intialize and calculate coefficients for each segment + int k0 = 0; int k1 = 1; int k2 = 2; int k3 = 3; + for (; k0 < numSegments; k0++, k1++, k2++, k3++) { + this.cubicSplineSegment[k0] = new CubicSplineSegment + (keys[k0], keys[k1], keys[k2], keys[k3]); + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method takes a list of spline segments creates the + * CubicSplineCurve. + * @param the list of segments that comprise the complete motion path + */ + + CubicSplineCurve (CubicSplineSegment s[]) { + + cubicSplineSegment = new CubicSplineSegment[s.length]; + numSegments = cubicSplineSegment.length; + for (int i = 0; i < numSegments; i++) { + this.cubicSplineSegment[i] = s[i]; + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method takes a list of spline segments to replace the existing + * set of CubicSplineSegments that comprise the current CubicSplineCurve + * motion path. + * @param s the list of segments that comprise the complete motion path + */ + + public void setSegments (CubicSplineSegment s[]) { + + cubicSplineSegment = new CubicSplineSegment[s.length]; + numSegments = cubicSplineSegment.length; + for (int i = 0; i < numSegments; i++) { + this.cubicSplineSegment[i] = s[i]; + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method returns the CubicSplineSegments pointed to by index + * @param index the index of the CubicSplineSegment required + * @return index the CubicSplineSegment pointed to by index + */ + public CubicSplineSegment getSegment (int index) { + + return this.cubicSplineSegment[index]; + + } + + + // computes the total length of the curve + private void computeTotalCurveLength () { + + totalCurveLength = 0f; + for (int i = 0; i < numSegments; i++) { + totalCurveLength += cubicSplineSegment[i].length; + } + + } + + /** + * This method returns the total length of the entire CubicSplineCurve + * motion path. + * + * @return the length of the CubicSplineCurve motion path + */ + + public float getTotalCurveLength () { + + return this.totalCurveLength; + + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineSegment.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineSegment.java new file mode 100644 index 0000000..6468687 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineSegment.java @@ -0,0 +1,543 @@ +/* + * $RCSfile: CubicSplineSegment.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:11 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; + + +/** + * The CubicSplineSegment class creates the representation of a + * TCB (Kochanek-Bartels Spline). This class takes 4 key frames as + * its input (using TCBKeyFrame). If interpolating between the ith + * and (i+1)th key frame then the four key frames that need to + * be specified are the (i-1)th, ith, (i+1)th + * and (i+2)th keyframes in order. The CubicSegmentClass + * then pre-computes the hermite interpolation basis coefficients if the + * (i+1)th frame has the linear flag set to zero. These are used to + * calculate the interpolated position, scale and quaternions when they + * requested by the user using the getInterpolated* methods. If the the + * (i+1)th frame's linear flag is set to 1 then the class uses + * linear interpolation to calculate the interpolated position, sccale and + * quaternions it returns through the getInterpolated* methods. + * + * @since Java3D 1.1 + */ + +public class CubicSplineSegment { + + // Legendre polynomial information for Gaussian quadrature of speed + // for the domain [0,u], 0 <= u <= 1. + + // Legendre roots mapped to (root+1)/2 + static final double modRoot[] = + { + 0.046910077, + 0.230765345, + 0.5, + 0.769234655, + 0.953089922 + }; + + // original coefficients divided by 2 + static final double modCoeff[] = + { + 0.118463442, + 0.239314335, + 0.284444444, + 0.239314335, + 0.118463442 + }; + + // Key Frames + TCBKeyFrame[] keyFrame = new TCBKeyFrame[4]; + + // H.C + Point3f c0, c1, c2, c3; // coefficients for position + Point3f e0, e1, e2, e3; // coefficients for scale + + // variables for destination derivative + float one_minus_t_in; + float one_minus_c_in; + float one_minus_b_in; + float one_plus_c_in; + float one_plus_b_in; + float ddb; + float dda; + + // variables for source derivative + float one_minus_t_out; + float one_minus_c_out; + float one_minus_b_out; + float one_plus_c_out; + float one_plus_b_out; + float dsb; + float dsa; + + // Length of the spline segment + float length; + + // interpolation type + int linear; + + /** + * Default constructor + */ + CubicSplineSegment () { + + length = 0; + + } + + /** + * Creates a cubic spline segment between two key frames using the + * key frames provided. If creating a spline between the ith frame and + * the (i+1)th frame then send down the (i - 1)th, + * ith , (i+1)th and the (i+2)th key + * frames. + * + * @param kf0 (i - 1)th Key Frame + * @param kf1 ith Key Frame + * @param kf2 (i + 1)th Key Frame + * @param kf3 (i + 2)th Key Frame + */ + + CubicSplineSegment (TCBKeyFrame kf0, TCBKeyFrame kf1, TCBKeyFrame kf2, + TCBKeyFrame kf3) { + + // Copy KeyFrame information + keyFrame[0] = new TCBKeyFrame(kf0); + keyFrame[1] = new TCBKeyFrame(kf1); + keyFrame[2] = new TCBKeyFrame(kf2); + keyFrame[3] = new TCBKeyFrame(kf3); + + // if linear interpolation is requested then just set linear flag + // if spline interpolation is needed then compute spline coefficients + if (kf2.linear == 1) { + this.linear = 1; + } else { + this.linear = 0; + computeCommonCoefficients (kf0, kf1, kf2, kf3); + computeHermiteCoefficients (kf0, kf1, kf2, kf3); + } + + length = computeLength (1.0f); + // System.out.println ("Segment length = " + length); + + } + + // compute the common coefficients + private void computeCommonCoefficients (TCBKeyFrame kf0, + TCBKeyFrame kf1, + TCBKeyFrame kf2, + TCBKeyFrame kf3) { + + // variables for destination derivative + float one_minus_t_in = 1.0f - kf1.tension; + float one_minus_c_in = 1.0f - kf1.continuity; + float one_minus_b_in = 1.0f - kf1.bias; + float one_plus_c_in = 1.0f + kf1.continuity; + float one_plus_b_in = 1.0f + kf1.bias; + + // coefficients for the incoming Tangent + ddb = one_minus_t_in * one_minus_c_in * one_minus_b_in; + dda = one_minus_t_in * one_plus_c_in * one_plus_b_in; + + // variables for source derivative + float one_minus_t_out = 1.0f - kf2.tension; + float one_minus_c_out = 1.0f - kf2.continuity; + float one_minus_b_out = 1.0f - kf2.bias; + float one_plus_c_out = 1.0f + kf2.continuity; + float one_plus_b_out = 1.0f + kf2.bias; + + // coefficients for the outgoing Tangent + dsb = one_minus_t_in * one_plus_c_in * one_minus_b_in; + dsa = one_minus_t_in * one_minus_c_in * one_plus_b_in; + } + + + // compute the hermite interpolation basis coefficients + private void computeHermiteCoefficients (TCBKeyFrame kf0, + TCBKeyFrame kf1, + TCBKeyFrame kf2, + TCBKeyFrame kf3) { + + + Point3f deltaP = new Point3f(); + Point3f deltaS = new Point3f(); + + // Find the difference in position and scale + deltaP.x = kf2.position.x - kf1.position.x; + deltaP.y = kf2.position.y - kf1.position.y; + deltaP.z = kf2.position.z - kf1.position.z; + + deltaS.x = kf2.scale.x - kf1.scale.x; + deltaS.y = kf2.scale.y - kf1.scale.y; + deltaS.z = kf2.scale.z - kf1.scale.z; + + // Incoming Tangent + Point3f dd_pos = new Point3f(); + Point3f dd_scale = new Point3f(); + + // If this is the first keyframe of the animation + if (kf0.knot == kf1.knot) { + + float ddab = 0.5f * (dda + ddb); + + // Position + dd_pos.x = ddab * deltaP.x; + dd_pos.y = ddab * deltaP.y; + dd_pos.z = ddab * deltaP.z; + + // Scale + dd_scale.x = ddab * deltaS.x; + dd_scale.y = ddab * deltaS.y; + dd_scale.z = ddab * deltaS.z; + + } else { + + float adj0 = (kf1.knot - kf0.knot)/(kf2.knot - kf0.knot); + + // Position + dd_pos.x = adj0 * + ((ddb * deltaP.x) + (dda * (kf1.position.x - kf0.position.x))); + dd_pos.y = adj0 * + ((ddb * deltaP.y) + (dda * (kf1.position.y - kf0.position.y))); + dd_pos.z = adj0 * + ((ddb * deltaP.z) + (dda * (kf1.position.z - kf0.position.z))); + + // Scale + dd_scale.x = adj0 * + ((ddb * deltaS.x) + (dda * (kf1.scale.x - kf0.scale.x))); + dd_scale.y = adj0 * + ((ddb * deltaS.y) + (dda * (kf1.scale.y - kf0.scale.y))); + dd_scale.z = adj0 * + ((ddb * deltaS.z) + (dda * (kf1.scale.z - kf0.scale.z))); + } + + // Outgoing Tangent + Point3f ds_pos = new Point3f(); + Point3f ds_scale = new Point3f(); + + // If this is the last keyframe of the animation + if (kf2.knot == kf3.knot) { + + float dsab = 0.5f * (dsa + dsb); + + // Position + ds_pos.x = dsab * deltaP.x; + ds_pos.y = dsab * deltaP.y; + ds_pos.z = dsab * deltaP.z; + + // Scale + ds_scale.x = dsab * deltaS.x; + ds_scale.y = dsab * deltaS.y; + ds_scale.z = dsab * deltaS.z; + + } else { + + float adj1 = (kf2.knot - kf1.knot)/(kf3.knot - kf1.knot); + + // Position + ds_pos.x = adj1 * + ((dsb * (kf3.position.x - kf2.position.x)) + (dsa * deltaP.x)); + ds_pos.y = adj1 * + ((dsb * (kf3.position.y - kf2.position.y)) + (dsa * deltaP.y)); + ds_pos.z = adj1 * + ((dsb * (kf3.position.z - kf2.position.z)) + (dsa * deltaP.z)); + + // Scale + ds_scale.x = adj1 * + ((dsb * (kf3.scale.x - kf2.scale.x)) + (dsa * deltaS.x)); + ds_scale.y = adj1 * + ((dsb * (kf3.scale.y - kf2.scale.y)) + (dsa * deltaS.y)); + ds_scale.z = adj1 * + ((dsb * (kf3.scale.z - kf2.scale.z)) + (dsa * deltaS.z)); + } + + // Calculate the coefficients of the polynomial for position + c0 = new Point3f(); + c0.x = kf1.position.x; + c0.y = kf1.position.y; + c0.z = kf1.position.z; + + c1 = new Point3f(); + c1.x = dd_pos.x; + c1.y = dd_pos.y; + c1.z = dd_pos.z; + + c2 = new Point3f(); + c2.x = 3*deltaP.x - 2*dd_pos.x - ds_pos.x; + c2.y = 3*deltaP.y - 2*dd_pos.y - ds_pos.y; + c2.z = 3*deltaP.z - 2*dd_pos.z - ds_pos.z; + + c3 = new Point3f(); + c3.x = -2*deltaP.x + dd_pos.x + ds_pos.x; + c3.y = -2*deltaP.y + dd_pos.y + ds_pos.y; + c3.z = -2*deltaP.z + dd_pos.z + ds_pos.z; + + // Calculate the coefficients of the polynomial for scale + e0 = new Point3f(); + e0.x = kf1.scale.x; + e0.y = kf1.scale.y; + e0.z = kf1.scale.z; + + e1 = new Point3f(); + e1.x = dd_scale.x; + e1.y = dd_scale.y; + e1.z = dd_scale.z; + + e2 = new Point3f(); + e2.x = 3*deltaS.x - 2*dd_scale.x - ds_scale.x; + e2.y = 3*deltaS.y - 2*dd_scale.y - ds_scale.y; + e2.z = 3*deltaS.z - 2*dd_scale.z - ds_scale.z; + + e3 = new Point3f(); + e3.x = -2*deltaS.x + dd_scale.x + ds_scale.x; + e3.y = -2*deltaS.y + dd_scale.y + ds_scale.y; + e3.z = -2*deltaS.z + dd_scale.z + ds_scale.z; + } + + + /** + * Computes the length of the curve at a given point between + * key frames. + * @param u specifies the point between keyframes where 0 <= u <= 1. + */ + + public float computeLength (float u) { + + float result = 0f; + + // if linear interpolation + if (linear == 1) { + result = u*keyFrame[2].position.distance(keyFrame[1].position); + } else { + // Need to transform domain [0,u] to [-1,1]. If 0 <= x <= u + // and -1 <= t <= 1, then x = u*(t+1)/2. + int degree = 5; + for (int i = 0; i < degree; i++) + result += (float)modCoeff[i]*computeSpeed(u*(float)modRoot[i]); + result *= u; + } + + return result; + } + + // Velocity along curve + private float computeSpeed (float u) { + Point3f v = new Point3f(); + + v.x = c1.x + u * (2 * c2.x + 3 * u * c3.x); + v.y = c1.y + u * (2 * c2.y + 3 * u * c3.y); + v.z = c1.z + u * (2 * c2.z + 3 * u * c3.z); + + return (float)(Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z)); + } + + + /** + * Computes the interpolated quaternion along the curve at + * a given point between key frames. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newQuat returns the value of the interpolated quaternion + */ + + public void getInterpolatedQuaternion (float u, Quat4f newQuat) { + + // if linear interpolation + if (this.linear == 1) { + double quatDot; + + quatDot = keyFrame[1].quat.x * keyFrame[2].quat.x + + keyFrame[1].quat.y * keyFrame[2].quat.y + + keyFrame[1].quat.z * keyFrame[2].quat.z + + keyFrame[1].quat.w * keyFrame[2].quat.w; + + if (quatDot < 0) { + newQuat.x = keyFrame[1].quat.x + + (-keyFrame[2].quat.x - keyFrame[1].quat.x) * u; + newQuat.y = keyFrame[1].quat.y + + (-keyFrame[2].quat.y - keyFrame[1].quat.y) * u; + newQuat.z = keyFrame[1].quat.z + + (-keyFrame[2].quat.z - keyFrame[1].quat.z) * u; + newQuat.w = keyFrame[1].quat.w + + (-keyFrame[2].quat.w - keyFrame[1].quat.w) * u; + } else { + newQuat.x = keyFrame[1].quat.x + + (keyFrame[2].quat.x - keyFrame[1].quat.x) * u; + newQuat.y = keyFrame[1].quat.y + + (keyFrame[2].quat.y - keyFrame[1].quat.y) * u; + newQuat.z = keyFrame[1].quat.z + + (keyFrame[2].quat.z - keyFrame[1].quat.z) * u; + newQuat.w = keyFrame[1].quat.w + + (keyFrame[2].quat.w - keyFrame[1].quat.w) * u; + } + + } else { + + // TODO: + // Currently we just use the great circle spherical interpolation + // for quaternions irrespective of the linear flag. Eventually + // we might want to do cubic interpolation of quaternions + newQuat.interpolate (keyFrame[1].quat, keyFrame[2].quat, u); + } + + } + + + + /** + * Computes the interpolated scale along the curve at a given point + * between key frames and returns a Point3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newScale returns the interpolated x,y,z scale value in a Point3f + */ + + public void getInterpolatedScale (float u, Point3f newScale) { + + // if linear interpolation + if (this.linear == 1) { + + newScale.x = keyFrame[1].scale.x + + ((keyFrame[2].scale.x - keyFrame[1].scale.x) * u); + newScale.y = keyFrame[1].scale.y + + ((keyFrame[2].scale.y - keyFrame[1].scale.y) * u); + newScale.z = keyFrame[1].scale.z + + ((keyFrame[2].scale.z - keyFrame[1].scale.z) * u); + + } else { + + newScale.x = e0.x + u * (e1.x + u * (e2.x + u * e3.x)); + newScale.y = e0.y + u * (e1.y + u * (e2.y + u * e3.y)); + newScale.z = e0.z + u * (e1.z + u * (e2.z + u * e3.z)); + + } + } + + + /** + * Computes the interpolated position along the curve at a given point + * between key frames and returns a Point3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newPos returns the interpolated x,y,z position in a Point3f + */ + + public void getInterpolatedPosition (float u, Point3f newPos) { + + // if linear interpolation + if (this.linear == 1) { + newPos.x = keyFrame[1].position.x + + ((keyFrame[2].position.x - keyFrame[1].position.x) * u); + newPos.y = keyFrame[1].position.y + + ((keyFrame[2].position.y - keyFrame[1].position.y) * u); + newPos.z = keyFrame[1].position.z + + ((keyFrame[2].position.z - keyFrame[1].position.z) * u); + } else { + + newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); + newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); + newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); + + } + } + + + /** + * Computes the interpolated position along the curve at a given point + * between key frames and returns a Vector3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newPos returns the interpolated x,y,z position in a Vector3f. + */ + + public void getInterpolatedPositionVector (float u, Vector3f newPos) { + // if linear interpolation + if (this.linear == 1) { + newPos.x = keyFrame[1].position.x + + ((keyFrame[2].position.x - keyFrame[1].position.x) * u); + newPos.y = keyFrame[1].position.y + + ((keyFrame[2].position.y - keyFrame[1].position.y) * u); + newPos.z = keyFrame[1].position.z + + ((keyFrame[2].position.z - keyFrame[1].position.z) * u); + } else { + + newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); + newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); + newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); + + } + } + + /** + * Computes the ratio of the length of the spline from the ith + * key frame to the position specified by u to the length of the entire + * spline segment from the ith key frame to the (i+1) + * th key frame. When the (i+1)th key frame's linear + * value is equal to 1, this is meaninful otherwise it should return u. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return the interpolated ratio + */ + + public float getInterpolatedValue (float u) { + return (computeLength(u)/this.length); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineCurve.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineCurve.java new file mode 100644 index 0000000..0649cdb --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineCurve.java @@ -0,0 +1,174 @@ +/* + * $RCSfile: KBCubicSplineCurve.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:11 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * KBCubicSplineCurve is a container class that holds a number of + * KBCubicSplineSegments + * + * @since Java3D 1.2 + */ + +public class KBCubicSplineCurve { + + private float totalCurveLength; + private KBCubicSplineSegment[] cubicSplineSegment; + public int numSegments; + + + // default constructor + KBCubicSplineCurve () { + numSegments = 0; + totalCurveLength = 0f; + } + + /** + * This method takes a list of key frames and creates spline segments + * from it. It requires at least four key frames to be passed to it. + * Given n key frames, it creates n-3 KBCubicSplineSegments. + * @param the list of key frames that specify the motion path + */ + + KBCubicSplineCurve (KBKeyFrame keys[]) { + + int keyLength = keys.length; + // Require at least 4 key frames for cubic spline curve + if (keyLength < 4) + throw new + IllegalArgumentException(J3dUtilsI18N.getString("KBCubicSplineCurve0")); + + numSegments = keyLength - 3; + this.cubicSplineSegment = new KBCubicSplineSegment[numSegments]; + + // intialize and calculate coefficients for each segment + int k0 = 0; int k1 = 1; int k2 = 2; int k3 = 3; + for (; k0 < numSegments; k0++, k1++, k2++, k3++) { + this.cubicSplineSegment[k0] = new KBCubicSplineSegment + (keys[k0], keys[k1], keys[k2], keys[k3]); + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method takes a list of spline segments creates the + * KBCubicSplineCurve. + * @param the list of segments that comprise the complete motion path + */ + + KBCubicSplineCurve (KBCubicSplineSegment s[]) { + + cubicSplineSegment = new KBCubicSplineSegment[s.length]; + numSegments = cubicSplineSegment.length; + for (int i = 0; i < numSegments; i++) { + this.cubicSplineSegment[i] = s[i]; + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method takes a list of spline segments to replace the existing + * set of KBCubicSplineSegments that comprise the current + * KBCubicSplineCurve motion path. + * @param s the list of segments that comprise the complete motion path + */ + + public void setSegments (KBCubicSplineSegment s[]) { + + cubicSplineSegment = new KBCubicSplineSegment[s.length]; + numSegments = cubicSplineSegment.length; + for (int i = 0; i < numSegments; i++) { + this.cubicSplineSegment[i] = s[i]; + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method returns the KBCubicSplineSegments pointed to by index + * @param index the index of the KBCubicSplineSegment required + * @return the KBCubicSplineSegment pointed to by index + */ + public KBCubicSplineSegment getSegment (int index) { + + return this.cubicSplineSegment[index]; + + } + + + // computes the total length of the curve + private void computeTotalCurveLength () { + + totalCurveLength = 0f; + for (int i = 0; i < numSegments; i++) { + totalCurveLength += cubicSplineSegment[i].length; + } + + } + + /** + * This method returns the total length of the entire KBCubicSplineCurve + * motion path. + * + * @return the length of the KBCubicSplineCurve motion path + */ + + public float getTotalCurveLength () { + + return this.totalCurveLength; + + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineSegment.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineSegment.java new file mode 100644 index 0000000..0e5359e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineSegment.java @@ -0,0 +1,630 @@ +/* + * $RCSfile: KBCubicSplineSegment.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:11 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; + + +/** + * The KBCubicSplineSegment class creates the representation of a + * Kochanek-Bartel's (also known as the TCB or Tension-Continuity-Bias + * Spline. This class takes 4 key frames as its input (using KBKeyFrame). + * If interpolating between the ith and (i+1)th key + * frame then the four key frames that need to be specified are the + * (i-1)th, ith, (i+1)th + * and (i+2)th keyframes in order. The KBCubicSegmentClass + * then pre-computes the hermite interpolation basis coefficients if the + * (i+1)th frame has the linear flag set to zero. These are used to + * calculate the interpolated position, scale and quaternions when they + * requested by the user using the getInterpolated* methods. If the the + * (i+1)th frame's linear flag is set to 1 then the class uses + * linear interpolation to calculate the interpolated position, scale, heading + * pitch and bank it returns through the getInterpolated* methods. + * + * @since Java3D 1.2 + */ +public class KBCubicSplineSegment { + + // Legendre polynomial information for Gaussian quadrature of speed + // for the domain [0,u], 0 <= u <= 1. + + // Legendre roots mapped to (root+1)/2 + static final double modRoot[] = + { + 0.046910077, + 0.230765345, + 0.5, + 0.769234655, + 0.953089922 + }; + + // original coefficients divided by 2 + static final double modCoeff[] = + { + 0.118463442, + 0.239314335, + 0.284444444, + 0.239314335, + 0.118463442 + }; + + // Key Frames + KBKeyFrame[] keyFrame = new KBKeyFrame[4]; + + // H.C + Point3f c0, c1, c2, c3; // coefficients for position + Point3f e0, e1, e2, e3; // coefficients for scale + float h0, h1, h2, h3; // coefficients for heading + float p0, p1, p2, p3; // coefficients for pitch + float b0, b1, b2, b3; // coefficients for bank + + // variables for destination derivative + float one_minus_t_in; + float one_minus_c_in; + float one_minus_b_in; + float one_plus_c_in; + float one_plus_b_in; + float ddb; + float dda; + + // variables for source derivative + float one_minus_t_out; + float one_minus_c_out; + float one_minus_b_out; + float one_plus_c_out; + float one_plus_b_out; + float dsb; + float dsa; + + // Length of the spline segment + float length; + + // interpolation type + int linear; + + // Default constructor + KBCubicSplineSegment () { + + length = 0; + + } + + /** + * Creates a cubic spline segment between two key frames using the + * key frames provided. If creating a spline between the ith frame and + * the (i+1)th frame then send down the (i - 1)th, + * ith , (i+1)th and the (i+2)th key + * frames. + * + * @param kf0 (i - 1)th Key Frame + * @param kf1 ith Key Frame + * @param kf2 (i + 1)th Key Frame + * @param kf3 (i + 2)th Key Frame + */ + + KBCubicSplineSegment (KBKeyFrame kf0, KBKeyFrame kf1, KBKeyFrame kf2, + KBKeyFrame kf3) { + + // Copy KeyFrame information + keyFrame[0] = new KBKeyFrame(kf0); + keyFrame[1] = new KBKeyFrame(kf1); + keyFrame[2] = new KBKeyFrame(kf2); + keyFrame[3] = new KBKeyFrame(kf3); + + // if linear interpolation is requested then just set linear flag + // if spline interpolation is needed then compute spline coefficients + if (kf2.linear == 1) { + this.linear = 1; + } else { + this.linear = 0; + computeCommonCoefficients (kf0, kf1, kf2, kf3); + computeHermiteCoefficients (kf0, kf1, kf2, kf3); + } + + length = computeLength (1.0f); + // System.out.println ("Segment length = " + length); + + } + + // compute the common coefficients + private void computeCommonCoefficients (KBKeyFrame kf0, + KBKeyFrame kf1, + KBKeyFrame kf2, + KBKeyFrame kf3) { + + // variables for destination derivative + float one_minus_t_in = 1.0f - kf1.tension; + float one_minus_c_in = 1.0f - kf1.continuity; + float one_minus_b_in = 1.0f - kf1.bias; + float one_plus_c_in = 1.0f + kf1.continuity; + float one_plus_b_in = 1.0f + kf1.bias; + + // coefficients for the incoming Tangent + ddb = one_minus_t_in * one_minus_c_in * one_minus_b_in; + dda = one_minus_t_in * one_plus_c_in * one_plus_b_in; + + // variables for source derivative + float one_minus_t_out = 1.0f - kf2.tension; + float one_minus_c_out = 1.0f - kf2.continuity; + float one_minus_b_out = 1.0f - kf2.bias; + float one_plus_c_out = 1.0f + kf2.continuity; + float one_plus_b_out = 1.0f + kf2.bias; + + // coefficients for the outgoing Tangent + dsb = one_minus_t_in * one_plus_c_in * one_minus_b_in; + dsa = one_minus_t_in * one_minus_c_in * one_plus_b_in; + } + + + // compute the hermite interpolation basis coefficients + private void computeHermiteCoefficients (KBKeyFrame kf0, + KBKeyFrame kf1, + KBKeyFrame kf2, + KBKeyFrame kf3) { + + + Point3f deltaP = new Point3f(); + Point3f deltaS = new Point3f(); + float deltaH; + float deltaT; + float deltaB; + + // Find the difference in position and scale + deltaP.x = kf2.position.x - kf1.position.x; + deltaP.y = kf2.position.y - kf1.position.y; + deltaP.z = kf2.position.z - kf1.position.z; + + deltaS.x = kf2.scale.x - kf1.scale.x; + deltaS.y = kf2.scale.y - kf1.scale.y; + deltaS.z = kf2.scale.z - kf1.scale.z; + + // Find the difference in heading, pitch, and bank + deltaH = kf2.heading - kf1.heading; + deltaT = kf2.pitch - kf1.pitch; + deltaB = kf2.bank - kf1.bank; + + // Incoming Tangent + Point3f dd_pos = new Point3f(); + Point3f dd_scale = new Point3f(); + float dd_heading, dd_pitch, dd_bank; + + // If this is the first keyframe of the animation + if (kf0.knot == kf1.knot) { + + float ddab = 0.5f * (dda + ddb); + + // Position + dd_pos.x = ddab * deltaP.x; + dd_pos.y = ddab * deltaP.y; + dd_pos.z = ddab * deltaP.z; + + // Scale + dd_scale.x = ddab * deltaS.x; + dd_scale.y = ddab * deltaS.y; + dd_scale.z = ddab * deltaS.z; + + // Heading, Pitch and Bank + dd_heading = ddab * deltaH; + dd_pitch = ddab * deltaT; + dd_bank = ddab * deltaB; + + } else { + + float adj0 = (kf1.knot - kf0.knot)/(kf2.knot - kf0.knot); + + // Position + dd_pos.x = adj0 * + ((ddb * deltaP.x) + (dda * (kf1.position.x - kf0.position.x))); + dd_pos.y = adj0 * + ((ddb * deltaP.y) + (dda * (kf1.position.y - kf0.position.y))); + dd_pos.z = adj0 * + ((ddb * deltaP.z) + (dda * (kf1.position.z - kf0.position.z))); + + // Scale + dd_scale.x = adj0 * + ((ddb * deltaS.x) + (dda * (kf1.scale.x - kf0.scale.x))); + dd_scale.y = adj0 * + ((ddb * deltaS.y) + (dda * (kf1.scale.y - kf0.scale.y))); + dd_scale.z = adj0 * + ((ddb * deltaS.z) + (dda * (kf1.scale.z - kf0.scale.z))); + + // Heading, Pitch and Bank + dd_heading = adj0 * + ((ddb * deltaH) + (dda * (kf1.heading - kf0.heading))); + dd_pitch = adj0 * + ((ddb * deltaT) + (dda * (kf1.pitch - kf0.pitch))); + dd_bank = adj0 * + ((ddb * deltaB) + (dda * (kf1.bank - kf0.bank))); + } + + // Outgoing Tangent + Point3f ds_pos = new Point3f(); + Point3f ds_scale = new Point3f(); + float ds_heading, ds_pitch, ds_bank; + + // If this is the last keyframe of the animation + if (kf2.knot == kf3.knot) { + + float dsab = 0.5f * (dsa + dsb); + + // Position + ds_pos.x = dsab * deltaP.x; + ds_pos.y = dsab * deltaP.y; + ds_pos.z = dsab * deltaP.z; + + // Scale + ds_scale.x = dsab * deltaS.x; + ds_scale.y = dsab * deltaS.y; + ds_scale.z = dsab * deltaS.z; + + // Heading, Pitch and Bank + ds_heading = dsab * deltaH; + ds_pitch = dsab * deltaT; + ds_bank = dsab * deltaB; + + } else { + + float adj1 = (kf2.knot - kf1.knot)/(kf3.knot - kf1.knot); + + // Position + ds_pos.x = adj1 * + ((dsb * (kf3.position.x - kf2.position.x)) + (dsa * deltaP.x)); + ds_pos.y = adj1 * + ((dsb * (kf3.position.y - kf2.position.y)) + (dsa * deltaP.y)); + ds_pos.z = adj1 * + ((dsb * (kf3.position.z - kf2.position.z)) + (dsa * deltaP.z)); + + // Scale + ds_scale.x = adj1 * + ((dsb * (kf3.scale.x - kf2.scale.x)) + (dsa * deltaS.x)); + ds_scale.y = adj1 * + ((dsb * (kf3.scale.y - kf2.scale.y)) + (dsa * deltaS.y)); + ds_scale.z = adj1 * + ((dsb * (kf3.scale.z - kf2.scale.z)) + (dsa * deltaS.z)); + + // Heading, Pitch and Bank + ds_heading = adj1 * + ((dsb * (kf3.heading - kf2.heading)) + (dsa * deltaH)); + ds_pitch = adj1 * + ((dsb * (kf3.pitch - kf2.pitch)) + (dsa * deltaT)); + ds_bank = adj1 * + ((dsb * (kf3.bank - kf2.bank)) + (dsa * deltaB)); + } + + // Calculate the coefficients of the polynomial for position + c0 = new Point3f(); + c0.x = kf1.position.x; + c0.y = kf1.position.y; + c0.z = kf1.position.z; + + c1 = new Point3f(); + c1.x = dd_pos.x; + c1.y = dd_pos.y; + c1.z = dd_pos.z; + + c2 = new Point3f(); + c2.x = 3*deltaP.x - 2*dd_pos.x - ds_pos.x; + c2.y = 3*deltaP.y - 2*dd_pos.y - ds_pos.y; + c2.z = 3*deltaP.z - 2*dd_pos.z - ds_pos.z; + + c3 = new Point3f(); + c3.x = -2*deltaP.x + dd_pos.x + ds_pos.x; + c3.y = -2*deltaP.y + dd_pos.y + ds_pos.y; + c3.z = -2*deltaP.z + dd_pos.z + ds_pos.z; + + // Calculate the coefficients of the polynomial for scale + e0 = new Point3f(); + e0.x = kf1.scale.x; + e0.y = kf1.scale.y; + e0.z = kf1.scale.z; + + e1 = new Point3f(); + e1.x = dd_scale.x; + e1.y = dd_scale.y; + e1.z = dd_scale.z; + + e2 = new Point3f(); + e2.x = 3*deltaS.x - 2*dd_scale.x - ds_scale.x; + e2.y = 3*deltaS.y - 2*dd_scale.y - ds_scale.y; + e2.z = 3*deltaS.z - 2*dd_scale.z - ds_scale.z; + + e3 = new Point3f(); + e3.x = -2*deltaS.x + dd_scale.x + ds_scale.x; + e3.y = -2*deltaS.y + dd_scale.y + ds_scale.y; + e3.z = -2*deltaS.z + dd_scale.z + ds_scale.z; + + // Calculate the coefficients of the polynomial for heading, pitch + // and bank + h0 = kf1.heading; + p0 = kf1.pitch; + b0 = kf1.bank; + + h1 = dd_heading; + p1 = dd_pitch; + b1 = dd_bank; + + h2 = 3*deltaH - 2*dd_heading - ds_heading; + p2 = 3*deltaT - 2*dd_pitch - ds_pitch; + b2 = 3*deltaB - 2*dd_bank - ds_bank; + + h3 = -2*deltaH + dd_heading + ds_heading; + p3 = -2*deltaT + dd_pitch + ds_pitch; + b3 = -2*deltaB + dd_bank + ds_bank; + } + + + /** + * Computes the length of the curve at a given point between + * key frames. + * @param u specifies the point between keyframes where 0 <= u <= 1. + */ + + public float computeLength (float u) { + + float result = 0f; + + // if linear interpolation + if (linear == 1) { + result = u*keyFrame[2].position.distance(keyFrame[1].position); + } else { + // Need to transform domain [0,u] to [-1,1]. If 0 <= x <= u + // and -1 <= t <= 1, then x = u*(t+1)/2. + int degree = 5; + for (int i = 0; i < degree; i++) + result += (float)modCoeff[i]*computeSpeed(u*(float)modRoot[i]); + result *= u; + } + + return result; + } + + // Velocity along curve + private float computeSpeed (float u) { + Point3f v = new Point3f(); + + v.x = c1.x + u * (2 * c2.x + 3 * u * c3.x); + v.y = c1.y + u * (2 * c2.y + 3 * u * c3.y); + v.z = c1.z + u * (2 * c2.z + 3 * u * c3.z); + + return (float)(Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z)); + } + + + /** + * Computes the interpolated scale along the curve at a given point + * between key frames and returns a Point3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newScale returns the interpolated x,y,z scale value in a Point3f + */ + + public void getInterpolatedScale (float u, Point3f newScale) { + + // if linear interpolation + if (this.linear == 1) { + + newScale.x = keyFrame[1].scale.x + + ((keyFrame[2].scale.x - keyFrame[1].scale.x) * u); + newScale.y = keyFrame[1].scale.y + + ((keyFrame[2].scale.y - keyFrame[1].scale.y) * u); + newScale.z = keyFrame[1].scale.z + + ((keyFrame[2].scale.z - keyFrame[1].scale.z) * u); + + } else { + + newScale.x = e0.x + u * (e1.x + u * (e2.x + u * e3.x)); + newScale.y = e0.y + u * (e1.y + u * (e2.y + u * e3.y)); + newScale.z = e0.z + u * (e1.z + u * (e2.z + u * e3.z)); + + } + } + + + /** + * Computes the interpolated position along the curve at a given point + * between key frames and returns a Point3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newPos returns the interpolated x,y,z position in a Point3f + */ + + public void getInterpolatedPosition (float u, Point3f newPos) { + + // if linear interpolation + if (this.linear == 1) { + newPos.x = keyFrame[1].position.x + + ((keyFrame[2].position.x - keyFrame[1].position.x) * u); + newPos.y = keyFrame[1].position.y + + ((keyFrame[2].position.y - keyFrame[1].position.y) * u); + newPos.z = keyFrame[1].position.z + + ((keyFrame[2].position.z - keyFrame[1].position.z) * u); + } else { + + newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); + newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); + newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); + + } + } + + + /** + * Computes the interpolated position along the curve at a given point + * between key frames and returns a Vector3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newPos returns the interpolated x,y,z position in a Vector3f. + */ + + public void getInterpolatedPositionVector (float u, Vector3f newPos) { + // if linear interpolation + if (this.linear == 1) { + newPos.x = keyFrame[1].position.x + + ((keyFrame[2].position.x - keyFrame[1].position.x) * u); + newPos.y = keyFrame[1].position.y + + ((keyFrame[2].position.y - keyFrame[1].position.y) * u); + newPos.z = keyFrame[1].position.z + + ((keyFrame[2].position.z - keyFrame[1].position.z) * u); + } else { + + newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); + newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); + newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); + + } + } + + /** + * Computes the interpolated heading along the curve at a given point + * between key frames and returns the interpolated value as a float + * This routine uses linear interpolation if the (i+1)th + * key frame's linear value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return returns the interpolated heading value + */ + + public float getInterpolatedHeading (float u) { + + float newHeading; + + // if linear interpolation + if (this.linear == 1) { + + newHeading = keyFrame[1].heading + + ((keyFrame[2].heading - keyFrame[1].heading) * u); + } else { + + newHeading = h0 + u * (h1 + u * (h2 + u * h3)); + + } + + return newHeading; + } + + + /** + * Computes the interpolated pitch along the curve at a given point + * between key frames and returns the interpolated value as a float + * This routine uses linear interpolation if the (i+1)th + * key frame's linear value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return returns the interpolated pitch value + */ + + public float getInterpolatedPitch (float u) { + + float newPitch; + + // if linear interpolation + if (this.linear == 1) { + + newPitch = keyFrame[1].pitch + + ((keyFrame[2].pitch - keyFrame[1].pitch) * u); + } else { + + newPitch = p0 + u * (p1 + u * (p2 + u * p3)); + + } + + return newPitch; + } + + /** + * Computes the interpolated bank along the curve at a given point + * between key frames and returns the interpolated value as a float + * This routine uses linear interpolation if the (i+1)th + * key frame's linear value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return returns the interpolated bank value + */ + + public float getInterpolatedBank (float u) { + + float newBank; + + // if linear interpolation + if (this.linear == 1) { + + newBank = keyFrame[1].bank + + ((keyFrame[2].bank - keyFrame[1].bank) * u); + } else { + + newBank = b0 + u * (b1 + u * (b2 + u * b3)); + + } + + return newBank; + } + + + /** + * Computes the ratio of the length of the spline from the ith + * key frame to the position specified by u to the length of the entire + * spline segment from the ith key frame to the (i+1) + * th key frame. When the (i+1)th key frame's linear + * value is equal to 1, this is meaninful otherwise it should return u. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return the interpolated ratio + */ + + public float getInterpolatedValue (float u) { + return (computeLength(u)/this.length); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBKeyFrame.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBKeyFrame.java new file mode 100644 index 0000000..78e6b70 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBKeyFrame.java @@ -0,0 +1,150 @@ +/* + * $RCSfile: KBKeyFrame.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:11 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * This class represents a Key Frame that can be used for Kochanek-Bartels + * (also called TCB or Tension-Continuity-Bias Splines) spline interpolation. + * + * @since Java3D 1.2 + */ +public class KBKeyFrame { + + // Position, Rotation and Scale + public Point3f position; + public float heading; + public float pitch; + public float bank; + public Point3f scale; + + // Tension, Continuity & Bias + public float tension; + public float continuity; + public float bias; + + // Sample Time + public float knot; + + // Interpolation type (linear = 0 -> spline interpolation) + public int linear; + + // default constructor + KBKeyFrame () { + tension = continuity = bias = 0.0f; + } + + public KBKeyFrame (KBKeyFrame kf) { + this(kf.knot, kf.linear, kf.position, kf.heading, kf.pitch, kf.bank, + kf.scale, kf.tension, kf.continuity, kf.bias); + + } + + + /** + * Creates a key frame using the given inputs. + * + * @param k knot value for this key frame + * @param l the linear flag (0 - Spline Interp, 1, Linear Interp + * @param pos the position at the key frame + * @param hd the heading value at the key frame + * @param pi the pitch value at the key frame + * @param bk the bank value at the key frame + * @param s the scales at the key frame + * @param t tension (-1.0 < t < 1.0) + * @param c continuity (-1.0 < c < 1.0) + * @param b bias (-1.0 < b < 1.0) + */ + public KBKeyFrame (float k, int l, Point3f pos, float hd, float pi, + float bk, Point3f s, float t, float c, float b) { + + knot = k; + linear = l; + position = new Point3f(pos); + heading = hd; + pitch = pi; + bank = bk; + scale = new Point3f(s); + + // Check for valid tension continuity and bias values + if (t < -1.0f || t > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame0")); + } + + if (b < -1.0f || b > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame1")); + } + + if (c < -1.0f || c > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame2")); + } + + // copy valid tension, continuity and bias values + tension = t; + continuity = c; + bias = b; + } + + /** + * Prints information comtained in this key frame + * @param tag string tag for identifying debug message + */ + public void debugPrint (String tag) { + System.out.println ("\n" + tag); + System.out.println (" knot = " + knot); + System.out.println (" linear = " + linear); + System.out.println (" position(x,y,z) = " + position.x + " " + + position.y + " " + position.z); + + System.out.println (" tension = " + tension); + System.out.println (" continuity = " + continuity); + System.out.println (" bias = " + bias); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java new file mode 100644 index 0000000..ef042dd --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java @@ -0,0 +1,313 @@ +/* + * $RCSfile: KBRotPosScaleSplinePathInterpolator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:11 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; + + +/** + * KBRotPosScaleSplinePathInterpolator; A rotation and position path + * interpolation behavior node using Kochanek-Bartels cubic splines + * (also known as TCB or Tension-Continuity-Bias Splines). + * + * @since Java3D 1.2 + */ + +/** + * KBRotPosScaleSplinePathInterpolator behavior. This class defines a + * behavior that varies the rotational, translational, and scale components + * of its target TransformGroup by using the Kochanek-Bartels cubic spline + * interpolation to interpolate among a series of key frames + * (using the value generated by the specified Alpha object). The + * interpolated position, orientation, and scale are used to generate + * a transform in the local coordinate system of this interpolator. + */ + +public class KBRotPosScaleSplinePathInterpolator + extends KBSplinePathInterpolator { + + private Transform3D rotation = new Transform3D(); + + private Matrix4d pitchMat = new Matrix4d(); // pitch matrix + private Matrix4d bankMat = new Matrix4d(); // bank matrix + private Matrix4d tMat = new Matrix4d(); // transformation matrix + private Matrix4d sMat = new Matrix4d(); // scale matrix + //Quat4f iQuat = new Quat4f(); // interpolated quaternion + private Vector3f iPos = new Vector3f(); // interpolated position + private Point3f iScale = new Point3f(); // interpolated scale + float iHeading, iPitch, iBank; // interpolated heading, + // pitch and bank + + KBCubicSplineCurve cubicSplineCurve = new KBCubicSplineCurve(); + KBCubicSplineSegment cubicSplineSegments[]; + int numSegments; + int currentSegmentIndex; + KBCubicSplineSegment currentSegment; + + // non-public, default constructor used by cloneNode + KBRotPosScaleSplinePathInterpolator() { + } + + /** + * Constructs a new KBRotPosScaleSplinePathInterpolator object that + * varies the rotation, translation, and scale of the target + * TransformGroup's transform. At least 2 key frames are required for + * this interpolator. The first key + * frame's knot must have a value of 0.0 and the last knot must have a + * value of 1.0. An intermediate key frame with index k must have a + * knot value strictly greater than the knot value of a key frame with + * index less than k. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this interpolator + * @param axisOfTransform the transform that specifies the local + * coordinate system in which this interpolator operates. + * @param keys an array of key frames that defien the motion path + */ + public KBRotPosScaleSplinePathInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + KBKeyFrame keys[]) { + super(alpha,target, axisOfTransform, keys); + + // Create a spline curve using the derived key frames + cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames); + numSegments = cubicSplineCurve.numSegments; + + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.setTransformAxis(Transform3D) + */ + public void setAxisOfRotPosScale(Transform3D axisOfRotPosScale) { + setTransformAxis(axisOfRotPosScale); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.getTransformAxis() + */ + public Transform3D getAxisOfRotPosScale() { + return getTransformAxis(); + } + + /** + * Set the key frame at the specified index to keyFrame + * @param index Index of the key frame to change + * @param keyFrame The new key frame + */ + public void setKeyFrame( int index, KBKeyFrame keyFrame ) { + super.setKeyFrame( index, keyFrame ); + + // TODO Optimize this + // Create a spline curve using the derived key frames + cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames); + numSegments = cubicSplineCurve.numSegments; + } + + /** + * Set all the key frames + * @param keyFrame The new key frames + */ + public void setKeyFrames( KBKeyFrame[] keyFrame ) { + super.setKeyFrames( keyFrame ); + + // Create a spline curve using the derived key frames + cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames); + numSegments = cubicSplineCurve.numSegments; + } + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + // compute the current value of u from alpha and the + // determine lower and upper knot points + computePathInterpolation( alphaValue ); + + // Determine the segment within which we will be interpolating + currentSegmentIndex = this.lowerKnot - 1; + + // if we are at the start of the curve + if (currentSegmentIndex == 0 && currentU == 0f) { + + iHeading = keyFrames[1].heading; + iPitch = keyFrames[1].pitch; + iBank = keyFrames[1].bank; + iPos.set(keyFrames[1].position); + iScale.set(keyFrames[1].scale); + + // if we are at the end of the curve + } else if (currentSegmentIndex == (numSegments-1) && + currentU == 1.0) { + + iHeading = keyFrames[upperKnot].heading; + iPitch = keyFrames[upperKnot].pitch; + iBank = keyFrames[upperKnot].bank; + iPos.set(keyFrames[upperKnot].position); + iScale.set(keyFrames[upperKnot].scale); + + // if we are somewhere in between the curve + } else { + + // Get a reference to the current spline segment i.e. the + // one bounded by lowerKnot and upperKnot + currentSegment + = cubicSplineCurve.getSegment(currentSegmentIndex); + + // interpolate quaternions + iHeading = currentSegment.getInterpolatedHeading (currentU); + iPitch = currentSegment.getInterpolatedPitch (currentU); + iBank = currentSegment.getInterpolatedBank (currentU); + + // interpolate position + currentSegment.getInterpolatedPositionVector(currentU,iPos); + + // interpolate position + currentSegment.getInterpolatedScale(currentU,iScale); + + } + + // Generate a transformation matrix in tMat using interpolated + // heading, pitch and bank + pitchMat.setIdentity(); + pitchMat.rotX(-iPitch); + bankMat.setIdentity(); + bankMat.rotZ(iBank); + tMat.setIdentity(); + tMat.rotY(-iHeading); + tMat.mul(pitchMat); + tMat.mul(bankMat); + + // TODO: Handle Non-Uniform scale + // Currently this interpolator does not handle non uniform scale + // We cheat by just taking the x scale component + + // Scale the transformation matrix + sMat.set((double)iScale.x); + tMat.mul(sMat); + + // Set the translation components. + tMat.m03 = iPos.x; + tMat.m13 = iPos.y; + tMat.m23 = iPos.z; + rotation.set(tMat); + + // construct a Transform3D from: axis * rotation * axisInverse + transform.mul(axis, rotation); + transform.mul(transform, axisInverse); + } + + /** + * Copies KBRotPosScaleSplinePathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + KBRotPosScaleSplinePathInterpolator spline = + new KBRotPosScaleSplinePathInterpolator(); + + spline.duplicateNode(this, forceDuplicate); + return spline; + } + + /** + * Copies KBRotPosScaleSplinePathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + super.duplicateNode(originalNode, forceDuplicate); + + KBRotPosScaleSplinePathInterpolator interpolator = + (KBRotPosScaleSplinePathInterpolator)originalNode; + setAxisOfRotPosScale(interpolator.axis); + target = interpolator.target; + cubicSplineCurve = new KBCubicSplineCurve(interpolator.keyFrames); + numSegments = cubicSplineCurve.numSegments; + } +} + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java new file mode 100644 index 0000000..8221635 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java @@ -0,0 +1,301 @@ +/* + * $RCSfile: KBSplinePathInterpolator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:12 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * KBSplinePathInterpolator behavior. This class defines the base class for + * all Kochanek-Bartels (also known as TCB or Tension-Continuity-Bias) + * Spline Path Interpolators. + * + * @since Java3D 1.2 + */ + +public abstract class KBSplinePathInterpolator extends TransformInterpolator { + + private int keysLength; + /** + * An array of KBKeyFrame for interpolator + */ + protected KBKeyFrame[] keyFrames; + + /** + * This value is the distance between knots + * value which can be used in further calculations by the subclass. + */ + protected float currentU; + + /** + * The lower knot + */ + protected int lowerKnot; + /** + * The upper knot + */ + protected int upperKnot; + + /** + * Constructs a KBSplinePathInterpolator node with a null alpha value and + * a null target of TransformGroup + * + * @since Java 3D 1.3 + */ + KBSplinePathInterpolator() { + } + + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * KBSplinePathInterpolator(Alpha, TransformGroup, TCBKeyFrame[]) + */ + public KBSplinePathInterpolator(Alpha alpha, KBKeyFrame keys[]) { + this(alpha, null, keys); + } + + /** + * Constructs a new KBSplinePathInterpolator object that interpolates + * between keyframes with specified alpha, target and an default + * axisOfTranform set to identity. + * It takes at least two key frames. The first key + * frame's knot must have a value of 0.0 and the last knot must have a + * value of 1.0. An intermediate key frame with index k must have a + * knot value strictly greater than the knot value of a key frame with + * index less than k. Once this constructor has all the valid key frames + * it creates its own list of key fames that duplicates the first key frame + * at the beginning of the list and the last key frame at the end of the + * list. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this interpolator + * @param keys an array of KBKeyFrame. Requires at least two key frames. + * + * @since Java 3D 1.3 + */ + public KBSplinePathInterpolator(Alpha alpha, TransformGroup target, KBKeyFrame keys[]) { + super(alpha, target); + processKeyFrames( keys ); + } + + /** + * Constructs a new KBSplinePathInterpolator object that interpolates + * between keyframes with specified alpha, target and axisOfTransform. + * It takes at least two key frames. The first key + * frame's knot must have a value of 0.0 and the last knot must have a + * value of 1.0. An intermediate key frame with index k must have a + * knot value strictly greater than the knot value of a key frame with + * index less than k. Once this constructor has all the valid key frames + * it creates its own list of key fames that duplicates the first key frame + * at the beginning of the list and the last key frame at the end of the + * list. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this interpolator + * @param axisOfTransform the transform that defines the local coordinate + * @param keys an array of KBKeyFrame. Requires at least two key frames + * + * @since Java 3D 1.3 + */ + public KBSplinePathInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + KBKeyFrame keys[]) { + super(alpha, target, axisOfTransform); + processKeyFrames( keys ); + } + + /** + * Process the new array of key frames + */ + private void processKeyFrames( KBKeyFrame[] keys ) { + + // Make sure that we have at least two key frames + keysLength = keys.length; + if (keysLength < 2) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator0")); + + } + + // Make sure that the first key frame's knot is equal to 0.0 + if (keys[0].knot < -0.0001 || keys[0].knot > 0.0001) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator1")); + } + + // Make sure that the last key frames knot is equal to 1.0 + if (keys[keysLength-1].knot -1.0 < -0.0001 || keys[keysLength-1].knot -1.0 > 0.0001) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator2")); + } + + // Make sure that all the knots are in sequence + for (int i = 0; i < keysLength; i++) { + if (i>0 && keys[i].knot < keys[i-1].knot) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator3")); + } + } + + // Make space for a leading and trailing key frame in addition to + // the keys passed in + keyFrames = new KBKeyFrame[keysLength+2]; + keyFrames[0] = new KBKeyFrame(); + keyFrames[0] = keys[0]; + for (int i = 1; i < keysLength+1; i++) { + keyFrames[i] = keys[i-1]; + } + keyFrames[keysLength+1] = new KBKeyFrame(); + keyFrames[keysLength+1] = keys[keysLength-1]; + + // Make key frame length reflect the 2 added key frames + keysLength += 2; + } + + /** + * This method retrieves the length of the key frame array. + * @return the number of key frames + */ + public int getArrayLength(){ + return keysLength-2; + } + + /** + * This method retrieves the key frame at the specified index. + * @param index the index of the key frame requested + * @return the key frame at the associated index + */ + public KBKeyFrame getKeyFrame (int index) { + + // We add 1 to index because we have added a leading keyFrame + return this.keyFrames[index+1]; + } + + /** + * Set the key frame at the specified index to keyFrame + * @param index Index of the key frame to change + * @param keyFrame The new key frame + * @since Java 3D 1.3 + */ + public void setKeyFrame( int index, KBKeyFrame keyFrame ) { + this.keyFrames[index+1] = keyFrame; + } + + /** + * Set allthe key frames + * @param keyFrames The new key frame + * @since Java 3D 1.3 + */ + public void setKeyFrames( KBKeyFrame[] keyFrames ) { + processKeyFrames( keyFrames ); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * computePathInterpolation(float) + */ + protected void computePathInterpolation() { + computePathInterpolation(this.getAlpha().value()); + } + + /** + * This method computes the bounding knot indices and interpolation value + * "CurrentU" given the current value of the knots[] array and the + * specified alpha value + * @param alphaValue alpha value between 0.0 and 1.0 + * + * @since Java 3D 1.3 + */ + protected void computePathInterpolation( float alphaValue ) { + + // skip knots till we find the two we fall between + int i = 1; + int len = keysLength - 2; + while ((alphaValue > keyFrames[i].knot) && (i < len)) { + i++; + } + + if (i == 1) { + currentU = 0f; + lowerKnot = 1; + upperKnot = 2; + } else { + currentU = (alphaValue - keyFrames[i-1].knot)/ + (keyFrames[i].knot - keyFrames[i-1].knot); + lowerKnot = i-1; + upperKnot = i; + } + } + + /** + * Copies all KBSplinePathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + super.duplicateNode(originalNode, forceDuplicate); + KBSplinePathInterpolator originalSpline = + (KBSplinePathInterpolator) originalNode; + setAlpha(originalSpline.getAlpha()); + keysLength = originalSpline.keysLength; + keyFrames = new KBKeyFrame[keysLength]; + System.arraycopy(originalSpline.keyFrames, 0, + keyFrames, 0, keysLength); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java new file mode 100644 index 0000000..127e36d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java @@ -0,0 +1,247 @@ +/* + * $RCSfile: RotPosScaleTCBSplinePathInterpolator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:12 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; + + +/** + * RotPosScaleTCBSplinePathInterpolator behavior. This class defines a + * behavior that varies the rotational, translational, and scale components + * of its target TransformGroup by using the Kochanek-Bartels cubic spline + * interpolation to interpolate among a series of key frames + * (using the value generated by the specified Alpha object). The + * interpolated position, orientation, and scale are used to generate + * a transform in the local coordinate system of this interpolator. + * + * @since Java3D 1.1 + */ + +public class RotPosScaleTCBSplinePathInterpolator +extends TCBSplinePathInterpolator { + + private Transform3D rotation = new Transform3D(); + private Matrix4d tMat = new Matrix4d(); + private Matrix4d sMat = new Matrix4d(); + private Quat4f iQuat = new Quat4f(); // interpolated quaternion + private Vector3f iPos = new Vector3f(); // interpolated position + private Point3f iScale = new Point3f(); // interpolated scale + + CubicSplineCurve cubicSplineCurve = new CubicSplineCurve(); + CubicSplineSegment cubicSplineSegments[]; + int numSegments; + int currentSegmentIndex; + CubicSplineSegment currentSegment; + + // non-public, default constructor used by cloneNode + RotPosScaleTCBSplinePathInterpolator() { + } + + /** + * Constructs a new RotPosScaleTCBSplinePathInterpolator object that + * varies the rotation, translation, and scale of the target + * TransformGroup's transform. At least 2 key frames are required for + * this interpolator. The first key + * frame's knot must have a value of 0.0 and the last knot must have a + * value of 1.0. An intermediate key frame with index k must have a + * knot value strictly greater than the knot value of a key frame with + * index less than k. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this interpolator + * @param axisOfTransform the transform that specifies the local + * coordinate system in which this interpolator operates. + * @param keys an array of key frames that defien the motion path + */ + public RotPosScaleTCBSplinePathInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + TCBKeyFrame keys[]) { + super(alpha, target, axisOfTransform, keys); + // Create a spline curve using the derived key frames + cubicSplineCurve = new CubicSplineCurve(this.keyFrames); + numSegments = cubicSplineCurve.numSegments; + + } + + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.setTransformAxis(Transform3D) + */ + public void setAxisOfRotPosScale(Transform3D axisOfRotPosScale) { + setTransformAxis(axisOfRotPosScale); + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TransformInterpolator.getTransformAxis() + */ + public Transform3D getAxisOfRotPosScale() { + return getTransformAxis(); + } + + /** + * Computes the new transform for this interpolator for a given + * alpha value. + * + * @param alphaValue alpha value between 0.0 and 1.0 + * @param transform object that receives the computed transform for + * the specified alpha value + * + * @since Java 3D 1.3 + */ + public void computeTransform(float alphaValue, Transform3D transform) { + + // compute the current value of u from alpha and the + // determine lower and upper knot points + computePathInterpolation(alphaValue); + + // Determine the segment within which we will be interpolating + currentSegmentIndex = this.lowerKnot - 1; + + // if we are at the start of the curve + if (currentSegmentIndex == 0 && currentU == 0f) { + + iQuat.set(keyFrames[1].quat); + iPos.set(keyFrames[1].position); + iScale.set(keyFrames[1].scale); + + // if we are at the end of the curve + } else if (currentSegmentIndex == (numSegments-1) && + currentU == 1.0) { + + iQuat.set(keyFrames[upperKnot].quat); + iPos.set(keyFrames[upperKnot].position); + iScale.set(keyFrames[upperKnot].scale); + + // if we are somewhere in between the curve + } else { + + // Get a reference to the current spline segment i.e. the + // one bounded by lowerKnot and upperKnot + currentSegment + = cubicSplineCurve.getSegment(currentSegmentIndex); + + // interpolate quaternions + currentSegment.getInterpolatedQuaternion(currentU,iQuat); + + // interpolate position + currentSegment.getInterpolatedPositionVector(currentU,iPos); + + // interpolate position + currentSegment.getInterpolatedScale(currentU,iScale); + + } + + // Alway normalize the quaternion + iQuat.normalize(); + tMat.set(iQuat); + + // Set the translation components. + tMat.m03 = iPos.x; + tMat.m13 = iPos.y; + tMat.m23 = iPos.z; + rotation.set(tMat); + + // construct a Transform3D from: axis * rotation * axisInverse + transform.mul(axis, rotation); + transform.setScale(new Vector3d(iScale)); + transform.mul(transform, axisInverse); + + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + RotPosScaleTCBSplinePathInterpolator spline = + new RotPosScaleTCBSplinePathInterpolator(); + spline.duplicateNode(this, forceDuplicate); + return spline; + } + + /** + * Copies RotPosScaleTCBSplinePathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + super.duplicateNode(originalNode, forceDuplicate); + RotPosScaleTCBSplinePathInterpolator interpolator = + (RotPosScaleTCBSplinePathInterpolator)originalNode; + + cubicSplineCurve = new CubicSplineCurve(interpolator.keyFrames); + numSegments = cubicSplineCurve.numSegments; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBKeyFrame.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBKeyFrame.java new file mode 100644 index 0000000..dfb5fad --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBKeyFrame.java @@ -0,0 +1,144 @@ +/* + * $RCSfile: TCBKeyFrame.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:12 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * This class represents a Key Frame that can be used for Kochanek-Bartels + * (TCB) spline interpolation. + * + * @since Java3D 1.1 + */ + +public class TCBKeyFrame { + + // Position, Rotation and Scale + public Point3f position; + public Quat4f quat; + public Point3f scale; + + // Tension, Continuity & Bias + public float tension; + public float continuity; + public float bias; + + // Sample Time + public float knot; + + // Interpolation type (linear = 0 -> spline interpolation) + public int linear; + + // default constructor + TCBKeyFrame () { + tension = continuity = bias = 0.0f; + } + + public TCBKeyFrame (TCBKeyFrame kf) { + this(kf.knot, kf.linear, kf.position, kf.quat, kf.scale, + kf.tension, kf.continuity, kf.bias); + + } + + /** + * Creates a key frame using the given inputs. + * + * @param k knot value for this key frame + * @param l the linear flag (0 - Spline Interp, 1, Linear Interp + * @param pos the position at the key frame + * @param q the rotations at the key frame + * @param s the scales at the key frame + * @param t tension (-1.0 < t < 1.0) + * @param c continuity (-1.0 < c < 1.0) + * @param b bias (-1.0 < b < 1.0) + */ + public TCBKeyFrame (float k, int l, Point3f pos, Quat4f q, Point3f s, + float t, float c, float b) { + + knot = k; + linear = l; + position = new Point3f(pos); + quat = new Quat4f(q); + scale = new Point3f(s); + + // Check for valid tension continuity and bias values + if (t < -1.0f || t > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame0")); + } + + if (b < -1.0f || b > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame1")); + } + + if (c < -1.0f || c > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame2")); + } + + // copy valid tension, continuity and bias values + tension = t; + continuity = c; + bias = b; + } + + /** + * Prints information comtained in this key frame + * @param tag string tag for identifying debug message + */ + public void debugPrint (String tag) { + System.out.println ("\n" + tag); + System.out.println (" knot = " + knot); + System.out.println (" linear = " + linear); + System.out.println (" position(x,y,z) = " + position.x + " " + + position.y + " " + position.z); + + System.out.println (" tension = " + tension); + System.out.println (" continuity = " + continuity); + System.out.println (" bias = " + bias); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java new file mode 100644 index 0000000..0fde176 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java @@ -0,0 +1,278 @@ +/* + * $RCSfile: TCBSplinePathInterpolator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:12 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.interpolators; + +import javax.media.j3d.*; +import java.util.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * TCBSplinePathInterpolator behavior. This class defines the base class for + * all TCB (Kochanek-Bartels) Spline Path Interpolators. + * + * @since Java3D 1.1 + */ + +public abstract class TCBSplinePathInterpolator extends TransformInterpolator { + + private int keysLength; + + /** + * An array of KBKeyFrame for interpolator + */ + protected TCBKeyFrame[] keyFrames; + + /** + * This value is the distance between knots + * value which can be used in further calculations by the subclass. + */ + protected float currentU; + + /** + * The lower knot + */ + protected int lowerKnot; + + /** + * The upper knot + */ + protected int upperKnot; + + /** + * Constructs a TCBSplinePathInterpolator node with a null alpha value and + * a null target of TransformGroup + * + * @since Java 3D 1.3 + */ + + TCBSplinePathInterpolator() { + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * TCBSplinePathInterpolator(Alpha, TransformGroup, TCBKeyFrame[]) + */ + public TCBSplinePathInterpolator(Alpha alpha, TCBKeyFrame keys[]) { + this(alpha, null, keys); + } + + /** + * Constructs a new TCBSplinePathInterpolator object that interpolates + * between keyframes with specified alpha, target and default axisOfTransform + * set to identity. It takes at least two key frames. The first key + * frame's knot must have a value of 0.0 and the last knot must have a + * value of 1.0. An intermediate key frame with index k must have a + * knot value strictly greater than the knot value of a key frame with + * index less than k. Once this constructor has all the valid key frames + * it creates its own list of key fames that duplicates the first key frame + * at the beginning of the list and the last key frame at the end of the + * list. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node effected by this TCBSplinePathInterpolator + * @param keys an array of TCBKeyFrame. Requires at least two key frames. + * + * @since Java 3D 1.3 + */ + public TCBSplinePathInterpolator(Alpha alpha, TransformGroup target, TCBKeyFrame keys[]) { + super(alpha, target); + processKeyFrames(keys); + } + + /** + * Constructs a new TCBSplinePathInterpolator object that interpolates + * between keyframes with specified alpha, target and axisOfTransform. + * It takes at least two key frames. The first key + * frame's knot must have a value of 0.0 and the last knot must have a + * value of 1.0. An intermediate key frame with index k must have a + * knot value strictly greater than the knot value of a key frame with + * index less than k. Once this constructor has all the valid key frames + * it creates its own list of key fames that duplicates the first key frame + * at the beginning of the list and the last key frame at the end of the + * list. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node effected by this TCBSplinePathInterpolator + * @param axisOfTransform the transform that defines the local coordinate + * @param keys an array of TCBKeyFrame. Requires at least two key frames. + * + * @since Java 3D 1.3 + */ + public TCBSplinePathInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfTransform, + TCBKeyFrame keys[]) { + super(alpha, target, axisOfTransform); + processKeyFrames(keys); + } + + /** + * Process the new array of key frames + */ + private void processKeyFrames( TCBKeyFrame keys[] ){ + + // Make sure that we have at least two key frames + keysLength = keys.length; + if (keysLength < 2) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator0")); + + } + + // Make sure that the first key frame's knot is equal to 0.0 + if (keys[0].knot < -0.0001 || keys[0].knot > 0.0001) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator1")); + } + + // Make sure that the last key frames knot is equal to 1.0 + if (keys[keysLength-1].knot -1.0 < -0.0001 || keys[keysLength-1].knot -1.0 > 0.0001) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator2")); + } + + // Make sure that all the knots are in sequence + for (int i = 0; i < keysLength; i++) { + if (i>0 && keys[i].knot < keys[i-1].knot) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator3")); + } + } + + // Make space for a leading and trailing key frame in addition to + // the keys passed in + keyFrames = new TCBKeyFrame[keysLength+2]; + keyFrames[0] = new TCBKeyFrame(); + keyFrames[0] = keys[0]; + for (int i = 1; i < keysLength+1; i++) { + keyFrames[i] = keys[i-1]; + } + keyFrames[keysLength+1] = new TCBKeyFrame(); + keyFrames[keysLength+1] = keys[keysLength-1]; + + // Make key frame length reflect the 2 added key frames + keysLength += 2; + } + + /** + * This method retrieves the length of the key frame array. + * @return the number of key frames + */ + public int getArrayLength(){ + return keysLength-2; + } + + /** + * This method retrieves the key frame at the specified index. + * @param index the index of the key frame requested + * @return the key frame at the associated index + */ + public TCBKeyFrame getKeyFrame (int index) { + + // We add 1 to index because we have added a leading keyFrame + return this.keyFrames[index+1]; + } + + /** + * This method computes the bounding knot indices and interpolation value + * "CurrentU" given the specified value of alpha and the knots[] array. + * @param alphaValue alpha value between 0.0 and 1.0 + * + * @since Java 3D 1.3 + */ + protected void computePathInterpolation(float alphaValue) { + + // skip knots till we find the two we fall between + int i = 1; + int len = keysLength - 2; + while ((alphaValue > keyFrames[i].knot) && (i < len)) { + i++; + } + + if (i == 1) { + currentU = 0f; + lowerKnot = 1; + upperKnot = 2; + } else { + currentU = (alphaValue - keyFrames[i-1].knot)/ + (keyFrames[i].knot - keyFrames[i-1].knot); + lowerKnot = i-1; + upperKnot = i; + } + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + * computePathInterpolation(float) + */ + protected void computePathInterpolation() { + float value = (this.getAlpha()).value(); + computePathInterpolation(value); + } + + /** + * Copies all TCBSplinePathInterpolator information from + * originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method.

+ * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + super.duplicateNode(originalNode, forceDuplicate); + TCBSplinePathInterpolator originalSpline = (TCBSplinePathInterpolator) originalNode; + setAlpha(originalSpline.getAlpha()); + keysLength = originalSpline.keysLength; + keyFrames = new TCBKeyFrame[keysLength]; + System.arraycopy(originalSpline.keyFrames, 0, + keyFrames, 0, keysLength); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/package.html new file mode 100644 index 0000000..7f18f4a --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.behaviors.interpolators + + +

Provides spline-based interpolation behaviors.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigator.java new file mode 100644 index 0000000..50a05c2 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigator.java @@ -0,0 +1,499 @@ +/* + * $RCSfile: KeyNavigator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:12 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.keyboard; + +import java.io.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.awt.event.*; + +/** + * This is the KeyNavigator class. It accumulates AWT key events (key + * press and key release) and computes a new transform based on the + * accumulated events and elapsed time. + */ +public class KeyNavigator { + + private Vector3d navVec; + private long time; + + private Vector3d fwdAcc; + private Vector3d bwdAcc; + private Vector3d leftAcc; + private Vector3d rightAcc; + private Vector3d upAcc; + private Vector3d downAcc; + + private Vector3d fwdDrag; + private Vector3d bwdDrag; + private Vector3d leftDrag; + private Vector3d rightDrag; + private Vector3d upDrag; + private Vector3d downDrag; + + private double fwdVMax; + private double bwdVMax; + private double leftVMax; + private double rightVMax; + private double upVMax; + private double downVMax; + + private float leftRotAngle; + private float rightRotAngle; + private float upRotAngle; + private float downRotAngle; + + private double mmx; + + private Vector3d a = new Vector3d(); + private Vector3d dv = new Vector3d(); + private Point3d dp = new Point3d(); + private Quat4d udQuat = new Quat4d(); + private Quat4d lrQuat = new Quat4d(); + private Vector3d vpPos = new Vector3d(); + private double vpScale; + private Quat4d vpQuat = new Quat4d(); + private Matrix4d vpMatrix = new Matrix4d(); + private Transform3D vpTrans = new Transform3D(); + private Matrix4d mat = new Matrix4d(); + private Vector3d nda = new Vector3d(); + private Vector3d temp = new Vector3d(); + private Transform3D nominal = new Transform3D(); + private TransformGroup targetTG; + + private static final int UP_ARROW = (1<<0); + private static final int DOWN_ARROW = (1<<1); + private static final int LEFT_ARROW = (1<<2); + private static final int RIGHT_ARROW = (1<<3); + private static final int PLUS_SIGN = (1<<4); + private static final int MINUS_SIGN = (1<<5); + private static final int PAGE_UP = (1<<6); + private static final int PAGE_DOWN = (1<<7); + private static final int HOME_DIR = (1<<8); + private static final int HOME_NOMINAL = (1<<9); + + private static final int SHIFT = (1<<10); + private static final int ALT = (1<<11); + private static final int META = (1<<12); + + private static final int KEY_UP = (1<<13); + private static final int KEY_DOWN = (1<<14); + + private int key_state = 0; + private int modifier_key_state = 0; + + + /** + * Constructs a new key navigator object that operates on the specified + * transform group. All parameters are set to their default, idle state. + * @param targetTG the target transform group + */ + public KeyNavigator(TransformGroup targetTG) { + this.targetTG = targetTG; + targetTG.getTransform(nominal); + + mmx = 128.0; + navVec = new Vector3d(0.0,0.0,0.0); + + fwdAcc = new Vector3d( 0.0, 0.0,-mmx); + bwdAcc = new Vector3d( 0.0, 0.0, mmx); + leftAcc = new Vector3d(-mmx, 0.0, 0.0); + rightAcc = new Vector3d( mmx, 0.0, 0.0); + upAcc = new Vector3d( 0.0, mmx, 0.0); + downAcc = new Vector3d( 0.0,-mmx, 0.0); + + fwdDrag = new Vector3d( 0.0, 0.0, mmx); + bwdDrag = new Vector3d( 0.0, 0.0,-mmx); + leftDrag = new Vector3d( mmx, 0.0, 0.0); + rightDrag = new Vector3d(-mmx, 0.0, 0.0); + upDrag = new Vector3d( 0.0,-mmx, 0.0); + downDrag = new Vector3d( 0.0, mmx, 0.0); + + fwdVMax = -mmx; + bwdVMax = mmx; + leftVMax = -mmx; + rightVMax = mmx; + upVMax = mmx; + downVMax = -mmx; + + leftRotAngle = (float) (-Math.PI*2.0/3.0); + rightRotAngle = (float) (Math.PI*2.0/3.0); + upRotAngle = (float) (Math.PI*2.0/3.0); + downRotAngle = (float) (-Math.PI*2.0/3.0); + + // Create Timer here. + time = System.currentTimeMillis(); + + } + + + private long getDeltaTime() { + long newTime = System.currentTimeMillis(); + long deltaTime = newTime - time; + time = newTime; + if (deltaTime > 2000) return 0; + else return deltaTime; + } + + /* Generate a quaterion as a rotation of radians av about 0/x 1/y 2/z axis */ + private void genRotQuat(double av, int axis, Quat4d q) { + double b; + + q.x = q.y = q.z = 0.0; + q.w = Math.cos(av/2.0); + + b = 1.0 - q.w*q.w; + + if (b > 0.0) + b = Math.sqrt(b); + else + return; + + if (av < 0.0) + b = -b; + if (axis == 0) + q.x = b; + else if (axis == 1) + q.y = b; + else + q.z = b; + + } + + private void accKeyAdd(Vector3d a, Vector3d da, Vector3d drag, double scaleVel) { + + /* Scaling of acceleration due to modification keys */ + nda.scale(scaleVel, da); + /* Addition of sufficent acceleration to counteract drag */ + nda.sub(drag); + + /* Summing into overall acceleration */ + a.add(nda); + + } + + + /** + * Computes a new transform for the next frame based on + * the current transform, accumulated keyboard inputs, and + * elapsed time. This new transform is written into the target + * transform group. + * This method should be called once per frame. + */ + public void integrateTransformChanges() { + double scaleVel, scaleRot, scaleScale, pre; + double udAng, lrAng, r; + + // Get the current View Platform transform into a transform3D object. + targetTG.getTransform(vpTrans); + // Extract the position, quaterion, and scale from the transform3D. + vpScale = vpTrans.get(vpQuat, vpPos); + + + double deltaTime = (double) getDeltaTime(); + deltaTime *= 0.001; + + /* Calculate scale due to modification keys */ + if ((modifier_key_state & SHIFT) != 0 && + (modifier_key_state & META) == 0) { + scaleVel = 3.0; scaleRot = 2.0; scaleScale = 4.0; + } + else if ((modifier_key_state & SHIFT) == 0 && + (modifier_key_state & META) != 0) { + scaleVel = 0.1; scaleRot = 0.1; scaleScale = 0.1; + } + else if ((modifier_key_state & SHIFT) != 0 && + (modifier_key_state & META) != 0) { + scaleVel = 0.3; scaleRot = 0.5; scaleScale = 0.1; + } + else { + scaleRot = scaleVel = 1.0; scaleScale = 4.0; + } + + /* + * Processing of rectiliear motion keys. + */ + + a.x = a.y = a.z = 0.0; /* acceleration initially 0 */ + + /* Acceleration due to keys being down */ + if ((key_state & UP_ARROW) != 0 && (key_state & DOWN_ARROW) == 0) + accKeyAdd(a, fwdAcc, fwdDrag, scaleVel); + else + if ((key_state & UP_ARROW) == 0 && (key_state & DOWN_ARROW) != 0) + accKeyAdd(a, bwdAcc, bwdDrag, scaleVel); + + if (((modifier_key_state & ALT) != 0) && + (key_state & LEFT_ARROW) != 0 && (key_state & RIGHT_ARROW) == 0) { + accKeyAdd(a, leftAcc, leftDrag, scaleVel); + } else + if (((modifier_key_state & ALT) != 0) && + (key_state & LEFT_ARROW) == 0 && (key_state & RIGHT_ARROW) != 0) + accKeyAdd(a, rightAcc, rightDrag, scaleVel); + + if (((modifier_key_state & ALT) != 0) && + (key_state & PAGE_UP) != 0 && (key_state & PAGE_DOWN) == 0) + accKeyAdd(a, upAcc, upDrag, scaleVel); + else + if (((modifier_key_state & ALT) != 0) && + (key_state & PAGE_UP) == 0 && (key_state & PAGE_DOWN) != 0) + accKeyAdd(a, downAcc, downDrag, scaleVel); + + + /* + * Drag due to new or existing motion + */ + pre = navVec.z + a.z * deltaTime; + if (pre < 0.0) { + if (pre + fwdDrag.z * deltaTime < 0.0) + a.add(fwdDrag); + else + a.z -= pre/deltaTime; + } else if (pre > 0.0) { + if (pre + bwdDrag.z * deltaTime > 0.0) + a.add(bwdDrag); + else + a.z -= pre/deltaTime; + } + + pre = navVec.x + a.x * deltaTime; + if (pre < 0.0) { + if (pre + leftDrag.x * deltaTime < 0.0) + a.add(leftDrag); + else + a.x -= pre/deltaTime; + } else if (pre > 0.0) { + if (pre + rightDrag.x * deltaTime > 0.0) + a.add(rightDrag); + else + a.x -= pre/deltaTime; + } + + pre = navVec.y + a.y * deltaTime; + if (pre < 0.0) { + if (pre + downDrag.y * deltaTime < 0.0) + a.add(downDrag); + else + a.y -= pre/deltaTime; + } else if (pre > 0.0) { + if (pre + upDrag.y * deltaTime > 0.0) + a.add(upDrag); + else + a.y -= pre/deltaTime; + } + + /* Integration of acceleration to velocity */ + dv.scale(deltaTime, a); + navVec.add(dv); + + /* Speed limits */ + if (navVec.z < scaleVel * fwdVMax) navVec.z = scaleVel * fwdVMax; + if (navVec.z > scaleVel * bwdVMax) navVec.z = scaleVel * bwdVMax; + if (navVec.x < scaleVel * leftVMax) navVec.x = scaleVel * leftVMax; + if (navVec.x > scaleVel * rightVMax) navVec.x = scaleVel* rightVMax; + if (navVec.y > scaleVel * upVMax) navVec.y = scaleVel * upVMax; + if (navVec.y < scaleVel * downVMax) navVec.y = scaleVel * downVMax; + + /* Integration of velocity to distance */ + dp.scale(deltaTime, navVec); + + /* Scale our motion to the current avatar scale */ + // 1.0 eventually needs to be a more complex value (see hs). + // r = workplace_coexistence_to_vworld_ori.scale/ + // one_to_one_coexistence_to_vworld_ori.scale; + r = vpScale/1.0; + dp.scale(r, dp); + + /* + * Processing of rotation motion keys. + */ + udAng = lrAng = 0.0; + + /* Rotation due to keys being down */ + if (((modifier_key_state & ALT) == 0) && + (key_state & LEFT_ARROW) != 0 && (key_state & RIGHT_ARROW) == 0) + lrAng = (double) leftRotAngle; + else if (((modifier_key_state & ALT) == 0) && + (key_state & LEFT_ARROW) == 0 && (key_state & RIGHT_ARROW) != 0) + lrAng = (double) rightRotAngle; + + if (((modifier_key_state & ALT) == 0) && + (key_state & PAGE_UP) != 0 && (key_state & PAGE_DOWN) == 0) + udAng = (double) upRotAngle; + else if (((modifier_key_state & ALT) == 0) && + (key_state & PAGE_UP) == 0 && (key_state & PAGE_DOWN) != 0) + udAng = (double) downRotAngle; + + lrAng *= scaleRot; + udAng *= scaleRot; + + /* Scaling of angle change to delta time */ + lrAng *= deltaTime; + udAng *= deltaTime; + + + /* Addition to existing orientation */ + // vr_quat_inverse(&workplace_coexistence_to_vworld_ori.quat, &vpQuat); + // vpQuat gotten at top of method. + vpQuat.inverse(); + + if(lrAng != 0.0) { + genRotQuat(lrAng, 1, lrQuat); + vpQuat.mul(lrQuat, vpQuat); + } + + if(udAng != 0.0) { + genRotQuat(udAng, 0, udQuat); + vpQuat.mul(udQuat, vpQuat); + } + + /* Rotation of distance vector */ + vpQuat.inverse(); + vpQuat.normalize(); /* Improvment over HoloSketch */ + mat.set(vpQuat); + mat.transform(dp); + + /* Processing of scale */ + if ((key_state & PLUS_SIGN) != 0) { + vpScale *= (1.0 + (scaleScale*deltaTime)); + if (vpScale > 10e+14) vpScale = 1.0; + } else if ((key_state & MINUS_SIGN) != 0) { + vpScale /= (1.0 + (scaleScale*deltaTime)); + if (vpScale < 10e-14) vpScale = 1.0; + } + + // add dp into current vp position. + vpPos.add(dp); + + if ((key_state & HOME_NOMINAL) != 0) { + resetVelocity(); + // Extract the position, quaterion, and scale from the nominal + // transform + vpScale = nominal.get(vpQuat, vpPos); + } + + + /* Final update of view platform */ + // Put the transform back into the transform group. + vpTrans.set(vpQuat, vpPos, vpScale); + targetTG.setTransform(vpTrans); + } + + + /** + * Resets the keyboard navigation velocity to 0. + */ + private void resetVelocity() { + navVec.x = navVec.y = navVec.z = 0.0; + } + + + /** + * Processed a keyboard event. This routine should be called + * every time a KEY_PRESSED or KEY_RELEASED event is received. + * @param keyEvent the AWT key event + */ + public void processKeyEvent(KeyEvent keyEvent) { + int keyCode = keyEvent.getKeyCode(); + int keyChar = keyEvent.getKeyChar(); + +//System.err.println("keyCode " + keyCode + " keyChar " + keyChar); + + if (keyEvent.getID() == KeyEvent.KEY_RELEASED) { + if (keyChar == '+') key_state &= ~PLUS_SIGN; + else + switch (keyCode) { + case KeyEvent.VK_UP: key_state &= ~UP_ARROW; break; + case KeyEvent.VK_DOWN: key_state &= ~DOWN_ARROW; break; + case KeyEvent.VK_LEFT: key_state &= ~LEFT_ARROW; break; + case KeyEvent.VK_RIGHT: key_state &= ~RIGHT_ARROW; break; + case KeyEvent.VK_PAGE_UP: key_state &= ~PAGE_UP; break; + case KeyEvent.VK_PAGE_DOWN: key_state &= ~PAGE_DOWN; break; + case KeyEvent.VK_EQUALS: key_state &= ~HOME_NOMINAL;break; + default: switch(keyChar) { + case '-': key_state &= ~MINUS_SIGN; break; + } + } + } else if (keyEvent.getID() == KeyEvent.KEY_PRESSED) { + if (keyChar == '+') key_state |= PLUS_SIGN; + switch (keyCode) { + case KeyEvent.VK_UP: key_state |= UP_ARROW; break; + case KeyEvent.VK_DOWN: key_state |= DOWN_ARROW; break; + case KeyEvent.VK_LEFT: key_state |= LEFT_ARROW; break; + case KeyEvent.VK_RIGHT: key_state |= RIGHT_ARROW; break; + case KeyEvent.VK_PAGE_UP: key_state |= PAGE_UP; break; + case KeyEvent.VK_PAGE_DOWN: key_state |= PAGE_DOWN; break; + case KeyEvent.VK_EQUALS: key_state |= HOME_NOMINAL;break; + default: switch(keyChar) { + case '-': key_state |= MINUS_SIGN; break; + } + } + } + + /* Check modifier keys */ + if (keyEvent.isShiftDown()) + modifier_key_state |= SHIFT; + else + modifier_key_state &= ~SHIFT; + + if (keyEvent.isMetaDown()) + modifier_key_state |= META; + else + modifier_key_state &= ~META; + + if (keyEvent.isAltDown()) + modifier_key_state |= ALT; + else + modifier_key_state &= ~ALT; + +//System.err.println("keyCode " + keyEvent.getKeyCode() + " modifiers " + keyEvent.getModifiers()); +//System.err.println("SHIFT_MASK " + keyEvent.SHIFT_MASK); +//System.err.println("CTRL_MASK " + keyEvent.CTRL_MASK); +//System.err.println("META_MASK " + keyEvent.META_MASK); +//System.err.println("ALT_MASK " + keyEvent.ALT_MASK); + + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java new file mode 100644 index 0000000..53b43c9 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java @@ -0,0 +1,216 @@ +/* + * $RCSfile: KeyNavigatorBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:12 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.keyboard; + +import java.awt.event.*; +import java.awt.AWTEvent; +import java.util.Enumeration; +import java.awt.Component; +import java.util.LinkedList; +import javax.vecmath.*; +import javax.media.j3d.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * This class is a simple behavior that invokes the KeyNavigator + * to modify the view platform transform. + */ +public class KeyNavigatorBehavior extends Behavior implements KeyListener { + private WakeupCriterion w1 = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED); + private WakeupCriterion w2 = new WakeupOnAWTEvent(KeyEvent.KEY_RELEASED); + private WakeupOnElapsedFrames w3 = new WakeupOnElapsedFrames(0); + private WakeupCriterion[] warray = { w1, w2, w3 }; + private WakeupCondition w = new WakeupOr(warray); + private KeyEvent eventKey; + private KeyNavigator keyNavigator; + private boolean listener = false; + + private LinkedList eventq; + + + /** + * Override Behavior's initialize method to setup wakeup criteria. + */ + public void initialize() { + // Establish initial wakeup criteria + if (listener) { + w1 = new WakeupOnBehaviorPost(this, KeyEvent.KEY_PRESSED); + w2 = new WakeupOnBehaviorPost(this, KeyEvent.KEY_RELEASED); + warray[0] = w1; + warray[1] = w2; + w = new WakeupOr(warray); + eventq = new LinkedList(); + } + wakeupOn(w); + } + + /** + * Override Behavior's stimulus method to handle the event. + */ + public void processStimulus(Enumeration criteria) { + WakeupOnAWTEvent ev; + WakeupCriterion genericEvt; + AWTEvent[] events; + boolean sawFrame = false; + + while (criteria.hasMoreElements()) { + genericEvt = (WakeupCriterion) criteria.nextElement(); + if (genericEvt instanceof WakeupOnAWTEvent) { + ev = (WakeupOnAWTEvent) genericEvt; + events = ev.getAWTEvent(); + processAWTEvent(events); + } else if (genericEvt instanceof WakeupOnElapsedFrames && + eventKey != null) { + sawFrame = true; + } else if ((genericEvt instanceof WakeupOnBehaviorPost)) { + while(true) { + // access to the queue must be synchronized + synchronized (eventq) { + if (eventq.isEmpty()) break; + eventKey = (KeyEvent)eventq.remove(0); + if (eventKey.getID() == KeyEvent.KEY_PRESSED || + eventKey.getID() == KeyEvent.KEY_RELEASED) { + keyNavigator.processKeyEvent(eventKey); + } + } + } + } + } + if (sawFrame) + keyNavigator.integrateTransformChanges(); + + // Set wakeup criteria for next time + wakeupOn(w); + } + + /** + * Process a keyboard event + */ + private void processAWTEvent(AWTEvent[] events) { + for (int loop = 0; loop < events.length; loop++) { + if (events[loop] instanceof KeyEvent) { + eventKey = (KeyEvent) events[loop]; + // change the transformation; for example to zoom + if (eventKey.getID() == KeyEvent.KEY_PRESSED || + eventKey.getID() == KeyEvent.KEY_RELEASED) { + //System.out.println("Keyboard is hit! " + eventKey); + keyNavigator.processKeyEvent(eventKey); + } + } + } + } + + /** + * Adds this behavior as a KeyListener to the specified component. + * This method can only be called if + * the behavior was created with one of the constructors that takes + * a Component as a parameter. + * @param c The component to add the KeyListener to. + * @exception IllegalStateException if the behavior was not created + * as a listener + * @since Java 3D 1.2.1 + */ + public void addListener(Component c) { + if (!listener) { + throw new IllegalStateException(J3dUtilsI18N.getString("Behavior0")); + } + c.addKeyListener(this); + } + + /** + * Constructs a new key navigator behavior node that operates + * on the specified transform group. + * @param targetTG the target transform group + */ + public KeyNavigatorBehavior(TransformGroup targetTG) { + keyNavigator = new KeyNavigator(targetTG); + } + + /** + * Constructs a key navigator behavior that uses AWT listeners + * and behavior posts rather than WakeupOnAWTEvent. The behavior + * is added to the specified Component and works on the given + * TransformGroup. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The component to add the KeyListener to. + * @param targetTG The target transform group. + * @since Java 3D 1.2.1 + */ + public KeyNavigatorBehavior(Component c, TransformGroup targetTG) { + this(targetTG); + if (c != null) { + c.addKeyListener(this); + } + listener = true; + } + + public void keyPressed(KeyEvent evt) { +// System.out.println("keyPressed"); + + // add new event to the queue + // must be MT safe + synchronized (eventq) { + eventq.add(evt); + // only need to post if this is the only event in the queue + if (eventq.size() == 1) postId(KeyEvent.KEY_PRESSED); + } + } + + public void keyReleased(KeyEvent evt) { +// System.out.println("keyReleased"); + + // add new event to the queue + // must be MT safe + synchronized (eventq) { + eventq.add(evt); + // only need to post if this is the only event in the queue + if (eventq.size() == 1) postId(KeyEvent.KEY_RELEASED); + } + } + + public void keyTyped(KeyEvent evt) {} + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/package.html new file mode 100644 index 0000000..b22646e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.behaviors.keyboard + + +

Provides keyboard navigation utility classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehavior.java new file mode 100644 index 0000000..c0a18d3 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehavior.java @@ -0,0 +1,356 @@ +/* + * $RCSfile: MouseBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/02/09 17:20:12 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.mouse; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; + + +/** + * Base class for all mouse manipulators (see MouseRotate, MouseZoom + * and MouseTranslate for + * examples of how to extend this base class). + */ + +public abstract class MouseBehavior extends Behavior + implements MouseListener, MouseMotionListener, MouseWheelListener { + + private boolean listener = false; + + protected WakeupCriterion[] mouseEvents; + protected WakeupOr mouseCriterion; + protected int x, y; + protected int x_last, y_last; + protected TransformGroup transformGroup; + protected Transform3D transformX; + protected Transform3D transformY; + protected Transform3D currXform; + protected boolean buttonPress = false; + protected boolean reset = false; + protected boolean invert = false; + protected boolean wakeUp = false; + protected int flags = 0; + + // to queue the mouse events + protected LinkedList mouseq; + + // true if this behavior is enable + protected boolean enable = true; + + /** + * Set this flag if you want to manually wakeup the behavior. + */ + public static final int MANUAL_WAKEUP = 0x1; + + /** + * Set this flag if you want to invert the inputs. This is useful when + * the transform for the view platform is being changed instead of the + * transform for the object. + */ + public static final int INVERT_INPUT = 0x2; + + /** + * Creates a mouse behavior object with a given transform group. + * @param transformGroup The transform group to be manipulated. + */ + public MouseBehavior(TransformGroup transformGroup) { + super(); + // need to remove old behavior from group + this.transformGroup = transformGroup; + currXform = new Transform3D(); + transformX = new Transform3D(); + transformY = new Transform3D(); + reset = true; + } + + /** + * Initializes standard fields. Note that this behavior still + * needs a transform group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param format flags + */ + public MouseBehavior(int format) { + super(); + flags = format; + currXform = new Transform3D(); + transformX = new Transform3D(); + transformY = new Transform3D(); + reset = true; + } + + /** + * Creates a mouse behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * A null component can be passed to specify the behaviors should use + * listeners. Components can then be added to the behavior with the + * addListener(Component c) method. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.2.1 + */ + public MouseBehavior(Component c, TransformGroup transformGroup) { + this(transformGroup); + if (c != null) { + c.addMouseListener(this); + c.addMouseMotionListener(this); + c.addMouseWheelListener(this); + } + listener = true; + } + + /** + * Creates a mouse behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param format interesting flags (wakeup conditions). + * @since Java 3D 1.2.1 + */ + public MouseBehavior(Component c, int format) { + this(format); + if (c != null) { + c.addMouseListener(this); + c.addMouseMotionListener(this); + c.addMouseWheelListener(this); + } + listener = true; + } + + /** + * Swap a new transformGroup replacing the old one. This allows + * manipulators to operate on different nodes. + * + * @param transformGroup The *new* transform group to be manipulated. + */ + public void setTransformGroup(TransformGroup transformGroup){ + // need to remove old behavior from group + this.transformGroup = transformGroup; + currXform = new Transform3D(); + transformX = new Transform3D(); + transformY = new Transform3D(); + reset = true; + } + + /** + * Return the transformGroup on which this node is operating + */ + public TransformGroup getTransformGroup() { + return this.transformGroup; + } + + /** Initializes the behavior. + */ + + public void initialize() { + mouseEvents = new WakeupCriterion[4]; + + if (!listener) { + mouseEvents[0] = new WakeupOnAWTEvent(MouseEvent.MOUSE_DRAGGED); + mouseEvents[1] = new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED); + mouseEvents[2] = new WakeupOnAWTEvent(MouseEvent.MOUSE_RELEASED); + mouseEvents[3] = new WakeupOnAWTEvent(MouseEvent.MOUSE_WHEEL); + } + else { + mouseEvents[0] = new WakeupOnBehaviorPost(this, + MouseEvent.MOUSE_DRAGGED); + mouseEvents[1] = new WakeupOnBehaviorPost(this, + MouseEvent.MOUSE_PRESSED); + mouseEvents[2] = new WakeupOnBehaviorPost(this, + MouseEvent.MOUSE_RELEASED); + mouseEvents[3] = new WakeupOnBehaviorPost(this, + MouseEvent.MOUSE_WHEEL); + mouseq = new LinkedList(); + } + mouseCriterion = new WakeupOr(mouseEvents); + wakeupOn (mouseCriterion); + x = 0; + y = 0; + x_last = 0; + y_last = 0; + } + + /** + * Manually wake up the behavior. If MANUAL_WAKEUP flag was set upon + * creation, you must wake up this behavior each time it is handled. + */ + + public void wakeup() + { + wakeUp = true; + } + + /** + * Handles mouse events + */ + public void processMouseEvent(MouseEvent evt) { + if (evt.getID()==MouseEvent.MOUSE_PRESSED) { + buttonPress = true; + return; + } + else if (evt.getID()==MouseEvent.MOUSE_RELEASED){ + buttonPress = false; + wakeUp = false; + } + /* + else if (evt.getID() == MouseEvent.MOUSE_MOVED) { + // Process mouse move event + } + else if (evt.getID() == MouseEvent.MOUSE_WHEEL) { + // Process mouse wheel event + } + */ + } + + /** + * All mouse manipulators must implement this. + */ + public abstract void processStimulus (Enumeration criteria); + + /** + * Adds this behavior as a MouseListener, mouseWheelListener and MouseMotionListener to + * the specified component. This method can only be called if + * the behavior was created with one of the constructors that takes + * a Component as a parameter. + * @param c The component to add the MouseListener, MouseWheelListener and + * MouseMotionListener to. + * @exception IllegalStateException if the behavior was not created + * as a listener + * @since Java 3D 1.2.1 + */ + public void addListener(Component c) { + if (!listener) { + throw new IllegalStateException(J3dUtilsI18N.getString("Behavior0")); + } + c.addMouseListener(this); + c.addMouseMotionListener(this); + c.addMouseWheelListener(this); + } + + public void mouseClicked(MouseEvent e) {} + public void mouseEntered(MouseEvent e) {} + public void mouseExited(MouseEvent e) {} + + public void mousePressed(MouseEvent e) { +// System.out.println("mousePressed"); + + // add new event to the queue + // must be MT safe + if (enable) { + synchronized (mouseq) { + mouseq.add(e); + // only need to post if this is the only event in the queue + if (mouseq.size() == 1) + postId(MouseEvent.MOUSE_PRESSED); + } + } + } + + public void mouseReleased(MouseEvent e) { +// System.out.println("mouseReleased"); + + // add new event to the queue + // must be MT safe + if (enable) { + synchronized (mouseq) { + mouseq.add(e); + // only need to post if this is the only event in the queue + if (mouseq.size() == 1) + postId(MouseEvent.MOUSE_RELEASED); + } + } + } + + public void mouseDragged(MouseEvent e) { +// System.out.println("mouseDragged"); + + // add new event to the to the queue + // must be MT safe. + if (enable) { + synchronized (mouseq) { + mouseq.add(e); + // only need to post if this is the only event in the queue + if (mouseq.size() == 1) + postId(MouseEvent.MOUSE_DRAGGED); + } + } + } + + public void mouseMoved(MouseEvent e) {} + + public void setEnable(boolean state) { + super.setEnable(state); + this.enable = state; + if (!enable && (mouseq != null)) { + mouseq.clear(); + } + } + + public void mouseWheelMoved(MouseWheelEvent e){ + System.out.println("MouseBehavior : mouseWheel enable = " + enable ); + + // add new event to the to the queue + // must be MT safe. + if (enable) { + synchronized (mouseq) { + mouseq.add(e); + // only need to post if this is the only event in the queue + if (mouseq.size() == 1) + postId(MouseEvent.MOUSE_WHEEL); + } + } + } +} + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehaviorCallback.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehaviorCallback.java new file mode 100644 index 0000000..4cec159 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehaviorCallback.java @@ -0,0 +1,73 @@ +/* + * $RCSfile: MouseBehaviorCallback.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:13 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.mouse; + +import javax.media.j3d.Transform3D; + +/** + * The MouseBehaviorCallback interface allows a class to be notified + * when the transform is changed by one of the MouseBehaviors. The + * class that is interested in transform changes implements this + * interface, and the object created with that class is registered + * with the desired subclass of MouseBehavior using the + * setupCallback method. When the transform changes, the + * registered object's transformChanged method is + * invoked. + */ + +public interface MouseBehaviorCallback { + + public final static int ROTATE=0; + public final static int TRANSLATE=1; + public final static int ZOOM=2; + + /** + * Classes implementing this interface that are registered with + * one of the MouseBehaviors will be called every time the + * behavior updates the Transform + * @param type will be one of ROTATE, TRANSLATE or ZOOM + */ + public void transformChanged( int type, Transform3D transform ); +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseRotate.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseRotate.java new file mode 100644 index 0000000..ec55e88 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseRotate.java @@ -0,0 +1,315 @@ +/* + * $RCSfile: MouseRotate.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:13 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.mouse; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * MouseRotate is a Java3D behavior object that lets users control the + * rotation of an object via a mouse. + *

+ * To use this utility, first create a transform group that this + * rotate behavior will operate on. Then, + *

+ * 
+ *   MouseRotate behavior = new MouseRotate();
+ *   behavior.setTransformGroup(objTrans);
+ *   objTrans.addChild(behavior);
+ *   behavior.setSchedulingBounds(bounds);
+ *
+ *
+ * The above code will add the rotate behavior to the transform + * group. The user can rotate any object attached to the objTrans. + */ + +public class MouseRotate extends MouseBehavior { + double x_angle, y_angle; + double x_factor = .03; + double y_factor = .03; + + private MouseBehaviorCallback callback = null; + + /** + * Creates a rotate behavior given the transform group. + * @param transformGroup The transformGroup to operate on. + */ + public MouseRotate(TransformGroup transformGroup) { + super(transformGroup); + } + + /** + * Creates a default mouse rotate behavior. + **/ + public MouseRotate() { + super(0); + } + + /** + * Creates a rotate behavior. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param flags interesting flags (wakeup conditions). + */ + public MouseRotate(int flags) { + super(flags); + } + + /** + * Creates a rotate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The Component to add the MouseListener + * and MouseMotionListener to. + * @since Java 3D 1.2.1 + */ + public MouseRotate(Component c) { + super(c, 0); + } + + /** + * Creates a rotate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * A null component can be passed to specify the behavior should use + * listeners. Components can then be added to the behavior with the + * addListener(Component c) method. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.2.1 + */ + public MouseRotate(Component c, TransformGroup transformGroup) { + super(c, transformGroup); + } + + /** + * Creates a rotate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added to + * the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param flags interesting flags (wakeup conditions). + * @since Java 3D 1.2.1 + */ + public MouseRotate(Component c, int flags) { + super(c, flags); + } + + public void initialize() { + super.initialize(); + x_angle = 0; + y_angle = 0; + if ((flags & INVERT_INPUT) == INVERT_INPUT) { + invert = true; + x_factor *= -1; + y_factor *= -1; + } + } + + /** + * Return the x-axis movement multipler. + **/ + public double getXFactor() { + return x_factor; + } + + /** + * Return the y-axis movement multipler. + **/ + public double getYFactor() { + return y_factor; + } + + + /** + * Set the x-axis amd y-axis movement multipler with factor. + **/ + public void setFactor( double factor) { + x_factor = y_factor = factor; + } + + /** + * Set the x-axis amd y-axis movement multipler with xFactor and yFactor + * respectively. + **/ + public void setFactor( double xFactor, double yFactor) { + x_factor = xFactor; + y_factor = yFactor; + } + + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; +// int id; +// int dx, dy; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + // access to the queue must be synchronized + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolidate MOUSE_DRAG events + while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_DRAGGED)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn (mouseCriterion); + } + + void doProcess(MouseEvent evt) { + int id; + int dx, dy; + + processMouseEvent(evt); + if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || + ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))) { + id = evt.getID(); + if ((id == MouseEvent.MOUSE_DRAGGED) && + !evt.isMetaDown() && ! evt.isAltDown()){ + x = evt.getX(); + y = evt.getY(); + + dx = x - x_last; + dy = y - y_last; + + if (!reset){ + x_angle = dy * y_factor; + y_angle = dx * x_factor; + + transformX.rotX(x_angle); + transformY.rotY(y_angle); + + transformGroup.getTransform(currXform); + + Matrix4d mat = new Matrix4d(); + // Remember old matrix + currXform.get(mat); + + // Translate to origin + currXform.setTranslation(new Vector3d(0.0,0.0,0.0)); + if (invert) { + currXform.mul(currXform, transformX); + currXform.mul(currXform, transformY); + } else { + currXform.mul(transformX, currXform); + currXform.mul(transformY, currXform); + } + + // Set old translation back + Vector3d translation = new + Vector3d(mat.m03, mat.m13, mat.m23); + currXform.setTranslation(translation); + + // Update xform + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + if (callback!=null) + callback.transformChanged( MouseBehaviorCallback.ROTATE, + currXform ); + } + else { + reset = false; + } + + x_last = x; + y_last = y; + } + else if (id == MouseEvent.MOUSE_PRESSED) { + x_last = evt.getX(); + y_last = evt.getY(); + } + } + } + + /** + * Users can overload this method which is called every time + * the Behavior updates the transform + * + * Default implementation does nothing + */ + public void transformChanged( Transform3D transform ) { + } + + + /** + * The transformChanged method in the callback class will + * be called every time the transform is updated + */ + public void setupCallback( MouseBehaviorCallback callback ) { + this.callback = callback; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseTranslate.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseTranslate.java new file mode 100644 index 0000000..74e8e56 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseTranslate.java @@ -0,0 +1,290 @@ +/* + * $RCSfile: MouseTranslate.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:13 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.mouse; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * MouseTranslate is a Java3D behavior object that lets users control the + * translation (X, Y) of an object via a mouse drag motion with the third + * mouse button (alt-click on PC). See MouseRotate for similar usage info. + */ + +public class MouseTranslate extends MouseBehavior { + + double x_factor = .02; + double y_factor = .02; + Vector3d translation = new Vector3d(); + + private MouseBehaviorCallback callback = null; + + /** + * Creates a mouse translate behavior given the transform group. + * @param transformGroup The transformGroup to operate on. + */ + public MouseTranslate(TransformGroup transformGroup) { + super(transformGroup); + } + + /** + * Creates a default translate behavior. + */ + public MouseTranslate(){ + super(0); + } + + /** + * Creates a translate behavior. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param flags + */ + public MouseTranslate(int flags) { + super(flags); + } + + /** + * Creates a translate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The Component to add the MouseListener + * and MouseMotionListener to. + * @since Java 3D 1.2.1 + */ + public MouseTranslate(Component c) { + super(c, 0); + } + + /** + * Creates a translate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * A null component can be passed to specify the behavior should use + * listeners. Components can then be added to the behavior with the + * addListener(Component c) method. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.2.1 + */ + public MouseTranslate(Component c, TransformGroup transformGroup) { + super(c, transformGroup); + } + + /** + * Creates a translate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added to + * the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param flags interesting flags (wakeup conditions). + * @since Java 3D 1.2.1 + */ + public MouseTranslate(Component c, int flags) { + super(c, flags); + } + + public void initialize() { + super.initialize(); + if ((flags & INVERT_INPUT) == INVERT_INPUT) { + invert = true; + x_factor *= -1; + y_factor *= -1; + } + } + + /** + * Return the x-axis movement multipler. + **/ + public double getXFactor() { + return x_factor; + } + + /** + * Return the y-axis movement multipler. + **/ + public double getYFactor() { + return y_factor; + } + + /** + * Set the x-axis amd y-axis movement multipler with factor. + **/ + public void setFactor( double factor) { + x_factor = y_factor = factor; + } + + /** + * Set the x-axis amd y-axis movement multipler with xFactor and yFactor + * respectively. + **/ + public void setFactor( double xFactor, double yFactor) { + x_factor = xFactor; + y_factor = yFactor; + } + + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; +// int id; +// int dx, dy; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + // access to the queue must be synchronized + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolodate MOUSE_DRAG events + while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_DRAGGED)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn(mouseCriterion); + } + + void doProcess(MouseEvent evt) { + int id; + int dx, dy; + + processMouseEvent(evt); + + if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || + ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){ + id = evt.getID(); + if ((id == MouseEvent.MOUSE_DRAGGED) && + !evt.isAltDown() && evt.isMetaDown()) { + + x = evt.getX(); + y = evt.getY(); + + dx = x - x_last; + dy = y - y_last; + + if ((!reset) && ((Math.abs(dy) < 50) && (Math.abs(dx) < 50))) { + //System.out.println("dx " + dx + " dy " + dy); + transformGroup.getTransform(currXform); + + translation.x = dx*x_factor; + translation.y = -dy*y_factor; + + transformX.set(translation); + + if (invert) { + currXform.mul(currXform, transformX); + } else { + currXform.mul(transformX, currXform); + } + + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + if (callback!=null) + callback.transformChanged( MouseBehaviorCallback.TRANSLATE, + currXform ); + + } + else { + reset = false; + } + x_last = x; + y_last = y; + } + else if (id == MouseEvent.MOUSE_PRESSED) { + x_last = evt.getX(); + y_last = evt.getY(); + } + } + } + + /** + * Users can overload this method which is called every time + * the Behavior updates the transform + * + * Default implementation does nothing + */ + public void transformChanged( Transform3D transform ) { + } + + /** + * The transformChanged method in the callback class will + * be called every time the transform is updated + */ + public void setupCallback( MouseBehaviorCallback callback ) { + this.callback = callback; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseWheelZoom.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseWheelZoom.java new file mode 100644 index 0000000..fe98cfc --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseWheelZoom.java @@ -0,0 +1,254 @@ +/* + * $RCSfile: MouseWheelZoom.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:13 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.mouse; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + + +/** + * MouseWheelZoom is a Java3D behavior object that lets users control the + * Z axis translation of an object via mouse wheel. + * @since Java 3D 1.3.2 + */ + +public class MouseWheelZoom extends MouseBehavior { + + double z_factor = .1; + Vector3d translation = new Vector3d(); + + private MouseBehaviorCallback callback = null; + + /** + * Creates a zoom behavior given the transform group. + * @param transformGroup The transformGroup to operate on. + */ + public MouseWheelZoom(TransformGroup transformGroup) { + super(transformGroup); + } + + /** + * Creates a default mouse zoom behavior. + **/ + public MouseWheelZoom() { + super(0); + } + + /** + * Creates a zoom behavior. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param flags + */ + public MouseWheelZoom(int flags) { + super(flags); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The Component to add the MouseListener + * and MouseMotionListener to. + * @since Java 3D 1.3.2 + */ + public MouseWheelZoom(Component c) { + super(c, 0); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.3.2 + */ + public MouseWheelZoom(Component c, TransformGroup transformGroup) { + super(c, transformGroup); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param flags interesting flags (wakeup conditions). + * @since Java 3D 1.3.2 + */ + public MouseWheelZoom(Component c, int flags) { + super(c, flags); + } + + public void initialize() { + super.initialize(); + if ((flags & INVERT_INPUT) == INVERT_INPUT) { + z_factor *= -1; + invert = true; + } + } + + /** + * Return the y-axis movement multipler. + **/ + public double getFactor() { + return z_factor; + } + + /** + * Set the wheel units movement multipler with factor. + **/ + public void setFactor( double factor) { + z_factor = factor; + } + + + public void processStimulus(Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolidate MOUSE_WHEEL events + while((evt.getID() == MouseEvent.MOUSE_WHEEL) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_WHEEL)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn(mouseCriterion); + } + + void doProcess(MouseEvent evt) { + int units = 0; + + processMouseEvent(evt); + + if ((evt.getID() == MouseEvent.MOUSE_WHEEL)) { + MouseWheelEvent wheelEvent = (MouseWheelEvent)evt; + if (wheelEvent.getScrollType() == wheelEvent.WHEEL_UNIT_SCROLL ) { + units = wheelEvent.getUnitsToScroll(); + } + + if (!reset) { + transformGroup.getTransform(currXform); + + translation.z = units*z_factor; + + transformX.set(translation); + + if (invert) { + currXform.mul(currXform, transformX); + } else { + currXform.mul(transformX, currXform); + } + + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + if (callback!=null) + callback.transformChanged( MouseBehaviorCallback.ZOOM, + currXform ); + + } + else { + reset = false; + } + } + } + + + /** + * Users can overload this method which is called every time + * the Behavior updates the transform + * + * Default implementation does nothing + */ + public void transformChanged( Transform3D transform ) { + } + + /** + * The transformChanged method in the callback class will + * be called every time the transform is updated + */ + public void setupCallback( MouseBehaviorCallback callback ){ + this.callback = callback; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseZoom.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseZoom.java new file mode 100644 index 0000000..89a2004 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseZoom.java @@ -0,0 +1,271 @@ +/* + * $RCSfile: MouseZoom.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:13 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.mouse; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + + +/** + * MouseZoom is a Java3D behavior object that lets users control the + * Z axis translation of an object via a mouse drag motion with the second + * mouse button. See MouseRotate for similar usage info. + */ + +public class MouseZoom extends MouseBehavior { + + double z_factor = .04; + Vector3d translation = new Vector3d(); + + private MouseBehaviorCallback callback = null; + + /** + * Creates a zoom behavior given the transform group. + * @param transformGroup The transformGroup to operate on. + */ + public MouseZoom(TransformGroup transformGroup) { + super(transformGroup); + } + + /** + * Creates a default mouse zoom behavior. + **/ + public MouseZoom(){ + super(0); + } + + /** + * Creates a zoom behavior. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param flags + */ + public MouseZoom(int flags) { + super(flags); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The Component to add the MouseListener + * and MouseMotionListener to. + * @since Java 3D 1.2.1 + */ + public MouseZoom(Component c) { + super(c, 0); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.2.1 + */ + public MouseZoom(Component c, TransformGroup transformGroup) { + super(c, transformGroup); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param flags interesting flags (wakeup conditions). + * @since Java 3D 1.2.1 + */ + public MouseZoom(Component c, int flags) { + super(c, flags); + } + + public void initialize() { + super.initialize(); + if ((flags & INVERT_INPUT) == INVERT_INPUT) { + z_factor *= -1; + invert = true; + } + } + + /** + * Return the y-axis movement multipler. + **/ + public double getFactor() { + return z_factor; + } + + /** + * Set the y-axis movement multipler with factor. + **/ + public void setFactor( double factor) { + z_factor = factor; + } + + + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; +// int id; +// int dx, dy; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolodate MOUSE_DRAG events + while((evt.getID() == MouseEvent.MOUSE_DRAGGED) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_DRAGGED)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn (mouseCriterion); + } + + void doProcess(MouseEvent evt) { + int id; + int dx, dy; + + processMouseEvent(evt); + + if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || + ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){ + id = evt.getID(); + if ((id == MouseEvent.MOUSE_DRAGGED) && + evt.isAltDown() && !evt.isMetaDown()){ + + x = evt.getX(); + y = evt.getY(); + + dx = x - x_last; + dy = y - y_last; + + if (!reset){ + transformGroup.getTransform(currXform); + + translation.z = dy*z_factor; + + transformX.set(translation); + + if (invert) { + currXform.mul(currXform, transformX); + } else { + currXform.mul(transformX, currXform); + } + + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + if (callback!=null) + callback.transformChanged( MouseBehaviorCallback.ZOOM, + currXform ); + + } + else { + reset = false; + } + + x_last = x; + y_last = y; + } + else if (id == MouseEvent.MOUSE_PRESSED) { + x_last = evt.getX(); + y_last = evt.getY(); + } + } + } + + + /** + * Users can overload this method which is called every time + * the Behavior updates the transform + * + * Default implementation does nothing + */ + public void transformChanged( Transform3D transform ) { + } + + /** + * The transformChanged method in the callback class will + * be called every time the transform is updated + */ + public void setupCallback( MouseBehaviorCallback callback ) { + this.callback = callback; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/package.html new file mode 100644 index 0000000..d943a49 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/mouse/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.behaviors.mouse + + +

Provides mouse navigation utility classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/Intersect.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/Intersect.java new file mode 100644 index 0000000..eba1faa --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/Intersect.java @@ -0,0 +1,1297 @@ +/* + * $RCSfile: Intersect.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:13 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.picking; + +import javax.media.j3d.*; +import javax.vecmath.*; +import java.lang.Math; +import com.sun.j3d.internal.J3dUtilsI18N; + +/* + * Contains static methods to aid in the intersection test between + * various PickShape classes and geometry primitives (such as quad, + * triangle, line and point). + */ + + +/** + * @deprecated As of Java 3D version 1.2, this class is no + * longer needed + */ + +public class Intersect +{ + + /** + * Determines if the PickRay and quadrilateral + * objects intersect. + * The quadrilateral is defined as coordinates[index] to + * coordinates[index+3]. + * + * @param ray The ray to use in the intersection test. + * @param coordinates An array holding the quadrilateral data. + * @param index An array index that designates the starting position + * in the array of the quadrilateral to test. + * @param dist On return dist[0] will be set to the distance between ray's + * origin and the point of intersection, if it exists. + * The dist array should be allocated by the user. + * @return true if the ray intersects the quad, + * false if the ray does not intersect the object. + */ + public static boolean rayAndQuad( PickRay ray, Point3d coordinates[], + int index, double dist[] ) { + + if((coordinates.length - index) < 4) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect0")); + + Point3d pnts[] = new Point3d[4]; + + for(int i=0; i<4; i++) + pnts[i] = coordinates[index+i]; + + return rayAndPoly(pnts, ray, dist); + + } + + /** + * Return true if triangle intersects with ray and the distance, from + * the origin of ray to the intersection point, is stored in dist[0]. + * The triangle is defined by coordinates[index] to coordinates[index+2] + * coordinates[index+2]. + * + * @param ray The ray to use in the intersection test. + * @param coordinates An array holding the triangle data. + * @param index An array index that designates the starting position + * in the array of the triangle to test. + * @param dist On return dist[0] will be set to the distance between ray's origin and the + * point of intersection, if it exists. The dist array should be + * allocated by the user. + * @return true if the ray intersects the triangle, + * false if the ray does not intersect the object. + */ + public static boolean rayAndTriangle( PickRay ray, Point3d coordinates[], + int index, double dist[] ) { + + if((coordinates.length - index) < 3) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect1")); + + Point3d pnts[] = new Point3d[3]; + + for(int i=0; i<3; i++) + pnts[i] = coordinates[index+i]; + + return rayAndPoly(pnts, ray, dist); + + } + + /** + * Return true if triangle intersects with ray and the distance, from + * the origin of ray to the intersection point, is stored in dist[0]. + * The triangle is defined by coordinates[index] to coordinates[index+2] + * + * @param ray The ray that is used in intersection test. + * @param coordinates an array of vertices. + * @param index the vertex index + * @param dist On return dist[0] will be set to the distance between ray's origin and the point intersection, if + * exist. + * @return true if ray intersects triangle, else return false. + */ + + public static boolean rayAndTriangle( PickRay ray, Point3f coordinates[], + int index, double dist[] ) { + + if((coordinates.length - index) < 3) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect1")); + + Point3d pnts[] = new Point3d[3]; + + for(int i=0; i<3; i++) + pnts[i] = new Point3d(coordinates[index+i]); + + return rayAndPoly(pnts, ray, dist); + + } + + + /** + * Caluates the intersection between a PickSegment + * object and a quadrilateral. + * The quad is defined as coordinates[index] to coordinates[index+3] + * + * @param segment The segment to use in the intersection test. + * @param coordinates An array holding the quadrilateral data. + * @param index An array index that designates the starting position + * in the array of the quadrilateral to test. + * @param dist On return dist[0] will be set to the distance between the start of the segment + * and the point of intersection, if it exists. The dist array + * should be allocated by the user. + * @return true if the segment intersects the quad, + * false if the segment does not intersect the object. + */ + public static boolean segmentAndQuad( PickSegment segment, + Point3d coordinates[], + int index, double dist[] ) { + if((coordinates.length - index) < 4) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect3")); + + Point3d pnts[] = new Point3d[4]; + + for(int i=0; i<4; i++) + pnts[i] = coordinates[index+i]; + + return segmentAndPoly(pnts, segment, dist); + + } + + /** + * Return true if quad intersects with segment and the distance, from + * the start of segment to the intersection point, is stored in dist[0]. + * The quad is defined by coordinates[index] to coordinates[index+3] + * + * @param segment The segment that is used in intersection test. + * @param coordinates an array of vertices. + * @param index the vertex index + * @param dist On return dist[0] will be set to the distance between segment's start and the point + * intersection, if exist. + * @return true if segment intersects quad, else return false. + */ + + public static boolean segmentAndQuad( PickSegment segment, Point3f coordinates[], + int index, double dist[] ) { + if((coordinates.length - index) < 4) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect3")); + + Point3d pnts[] = new Point3d[4]; + + for(int i=0; i<4; i++) + pnts[i] = new Point3d(coordinates[index+i]); + + return segmentAndPoly(pnts, segment, dist); + + } + + /** + * Caluates the intersection between a PickSegment + * object and a triangle. + * The triangle is defined as coordinates[index] to coordinates[index+2] + * + * @param segment The segment to use in the intersection test. + * @param coordinates An array holding the triangle data. + * @param index An array index that designates the starting position + * in the array of the triangle to test. + * @param dist On return dist[0] contains the distance between the start of the segment + * and the point of intersection, if it exists. The dist array + * should be allocated by the user. + * @return true if the segment intersects the triangle, + * false if the segment does not intersect the object. + */ + public static boolean segmentAndTriangle( PickSegment segment, + Point3d coordinates[], + int index, + double dist[] ) { + if((coordinates.length - index) < 3) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect5")); + + Point3d pnts[] = new Point3d[3]; + + for(int i=0; i<3; i++) + pnts[i] = coordinates[index+i]; + + return segmentAndPoly(pnts, segment, dist); + + } + + /** + * Return true if triangle intersects with segment and the distance, from + * the start of segment to the intersection point, is stored in dist[0]. + * The triangle is defined by coordinates[index] to coordinates[index+2] + * + * @param segment The segment that is used in intersection test. + * @param coordinates an array of vertices. + * @param index the vertex index + * @param dist On return dist[0] will be set to the distance between segment's start and the point + * intersection, if exist. + * @return true if segment intersects triangle, else return false. + */ + + public static boolean segmentAndTriangle( PickSegment segment, + Point3f coordinates[], int index, + double dist[] ) { + if((coordinates.length - index) < 3) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect6")); + + Point3d pnts[] = new Point3d[3]; + + for(int i=0; i<3; i++) + pnts[i] = new Point3d(coordinates[index+i]); + + return segmentAndPoly(pnts, segment, dist); + + } + + /** + * Caluates the intersection between a PickPoint + * object and a quadrilateral. + * The quad is defined as coordinates[index] to + * coordinates[index+3]. + * + * @param point The point to use in the intersection test. + * @param coordinates An array holding the quadrilateral data. + * @param index An array index that designates the starting position + * in the array of the quadrilateral to test. + * @return true if the point intersects the quad, + * false if the point does not intersect the object. + */ + private static boolean pointAndQuad( PickPoint point, + Point3d coordinates[], + int index) { + + if((coordinates.length - index) < 4) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect7")); + + Point3d pnts[] = new Point3d[4]; + + for(int i=0; i<4; i++) + pnts[i] = coordinates[index+i]; + + return pointAndPoly( pnts, point); + + } + + /** + * Return true if quad intersects with point. + * The triangle is defined by coordinates[index] to coordinates[index+3] + * + * @param point The point that is used in intersection test. + * @param coordinates an array of vertices. + * @param index the vertex index + * @return true if point intersects quad, else return false. + */ + + private static boolean pointAndQuad( PickPoint point, Point3f coordinates[], + int index) { + + if((coordinates.length - index) < 4) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect7")); + + Point3d pnts[] = new Point3d[4]; + + for(int i=0; i<4; i++) + pnts[i] = new Point3d(coordinates[index+i]); + + return pointAndPoly( pnts, point); + + } + + /** + * Caluates the intersection between a PickPoint + * object and a triangle. + * The triangle is defined by coordinates[index] to + * coordinates[index+2]. + * + * @param point The point to use in the intersection test. + * @param coordinates An array holding the triangle data. + * @param index An array index that designates the starting position + * in the array of the triangle to test. + * @return true if the point intersects the triangle, + * false if the point does not intersect the object. + */ + private static boolean pointAndTriangle( PickPoint point, + Point3d coordinates[], + int index) { + + if((coordinates.length - index) < 3) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect9")); + + Point3d pnts[] = new Point3d[3]; + + for(int i=0; i<3; i++) + pnts[i] = coordinates[index+i]; + + return pointAndPoly( pnts, point); + + } + + /** + * Return true if triangle intersects with point. + * The triangle is defined by coordinates[index] to coordinates[index+2] + * + * @param point The point that is used in intersection test. + * @param coordinates an array of vertices. + * @param index the vertex index + * @return true if point intersects triangle, else return false. + */ + + private static boolean pointAndTriangle( PickPoint point, Point3f coordinates[], + int index) { + + if((coordinates.length - index) < 3) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect10")); + + Point3d pnts[] = new Point3d[3]; + + for(int i=0; i<3; i++) + pnts[i] = new Point3d(coordinates[index+i]); + + return pointAndPoly( pnts, point); + + } + + /** + * Determines if the PickRay and Point3d + * objects intersect. + * + * @param ray The ray that is used in the intersection test. + * @param pnt The point that is used in intersection test. + * @param dist On return dist[0] will be set to the distance between ray's origin and the point + * of intersection, if it exists. The dist array + * should be allocated by the user. + * @return true if the ray intersects the point, + * false if the ray does not intersect the object. + */ + public static boolean rayAndPoint( PickRay ray, Point3d pnt, + double dist[] ) { + + Point3d origin = new Point3d(); + Vector3d direction = new Vector3d(); + + ray.get(origin, direction); + + return rayAndPoint(pnt, origin, direction, dist); + } + + /** + * Return true if point intersects with ray and the distance, from + * the origin of ray to the intersection point, is stored in dist[0]. + * + * @param ray The ray that is used in intersection test. + * @param pnt The point that is used in intersection test. + * @param dist On return dist[0] contains the distance between ray's origin and the point + * intersection, if exist. + * @return true if ray intersects point, else return false. + */ + + public static boolean rayAndPoint( PickRay ray, Point3f pnt, double dist[] ) { + + Point3d origin = new Point3d(); + Vector3d direction = new Vector3d(); + + ray.get(origin, direction); + + return rayAndPoint(new Point3d(pnt), origin, direction, dist); + } + + /** + * Determines if the PickSegment and Point3d + * objects intersect. + * + * @param segment The segment that is used in the intersection test. + * @param pnt The point that is used in intersection test. + * @param dist On return dist[0] contains the distance between segment's origin and the point + * of intersection, if it exists. The dist array + * should be allocated by the user. + * @return true if the segment intersects the point, + * false if the segment does not intersect the object. + */ + public static boolean segmentAndPoint( PickSegment segment, Point3d pnt, + double dist[] ) { + + Point3d start = new Point3d(); + Point3d end = new Point3d(); + Vector3d direction = new Vector3d(); + + segment.get(start, end); + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + if((rayAndPoint(pnt, start, direction, dist)==true) && (dist[0] <= 1.0)) + return true; + + return false; + } + + /** + * Return true if point intersects with segment and the distance, from + * the start of segment to the intersection point, is stored in dist[0]. + * + * @param segment The segment that is used in intersection test. + * @param pnt The point that is used in intersection test. + * @param dist On return dist[0] contains the distance between segment's start and the point + * intersection, if exist. + * @return true if segment intersects point, else return false. + */ + + public static boolean segmentAndPoint( PickSegment segment, Point3f pnt, + double dist[] ) { + + Point3d start = new Point3d(); + Point3d end = new Point3d(); + Vector3d direction = new Vector3d(); + + segment.get(start, end); + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + if((rayAndPoint(new Point3d(pnt), start, direction, dist)==true) + && (dist[0] <= 1.0)) + return true; + + return false; + } + + /** + * Determines if the PickPoint and Point3d + * objects intersect. + * + * @param point The PickPoint that is used in the intersection test. + * @param pnt The Point3d that is used in intersection test. + * @return true if the PickPoint and Point3d objects + * intersect, false if the do not intersect. + */ + public static boolean pointAndPoint( PickPoint point, Point3d pnt) { + + Point3d location = new Point3d(); + + point.get(location); + + if ((location.x == pnt.x) && (location.y == pnt.y) && + (location.z == pnt.z)) + return true; + + return false; + } + + /** + * Return true if pnt intersects with point. + * + * @param point The point that is used in intersection test. + * @param pnt The point that is used in intersection test. + * @return true if point intersects pnt, else return false. + */ + + public static boolean pointAndPoint( PickPoint point, Point3f pnt) { + + Point3d location = new Point3d(); + + point.get(location); + + if(((float) location.x == pnt.x) && ((float) location.y == pnt.y) + && ((float) location.z == pnt.z)) + return true; + + return false; + } + + /** + * Determines if the PickRay and Line + * objects intersect. + * The line is defined as coordinates[index] to + * coordinates[index+1]. + * + * @param ray The ray that is used in the intersection test. + * @param coordinates An array holding the line data. + * @param dist On return dist[0] contains the distance between ray's origin and the point of + * intersection, if it exists. The dist array + * should be allocated by the user. + * @return true if the ray intersects the line, + * false if the ray does not intersect the object. + */ + public static boolean rayAndLine(PickRay ray, Point3d coordinates[], + int index, + double dist[] ) { + Point3d origin = new Point3d(); + Vector3d direction = new Vector3d(); + + if((coordinates.length - index) < 2) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect11")); + + ray.get(origin, direction); + Point3d start = coordinates[index++]; + Point3d end = coordinates[index]; + + return lineAndRay( start, end, origin, direction, dist ); + + } + + /** + * Return true if line intersects with ray and the distance, from + * the origin of ray to the intersection point, is stored in dist[0]. + * The line is defined by coordinates[index] to coordinates[index+1] + * + * @param ray The ray that is used in intersection test. + * @param coordinates an array of vertices. + * @param index the vertex index + * @param dist On return dist[0] contains the distance between ray's origin and the point intersection, if + * exist. + * @return true if ray intersects line, else return false. + */ + + public static boolean rayAndLine(PickRay ray, Point3f coordinates[], int index, + double dist[] ) { + Point3d origin = new Point3d(); + Vector3d direction = new Vector3d(); + + if((coordinates.length - index) < 2) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect11")); + + ray.get(origin, direction); + Point3d start = new Point3d(coordinates[index++]); + Point3d end = new Point3d(coordinates[index]); + + return lineAndRay( start, end, origin, direction, dist ); + + } + + /** + * Determines if the PickSegment and Line + * objects intersect. + * The line is defined as coordinates[index] to + * coordinates[index+1]. + * + * @param segment The segment that is used in the intersection test. + * @param coordinates An array holding the line data. + * @param dist On return dist[0] contains the distance between segment's origin and the point of + * intersection, if it exists. The dist array + * should be allocated by the user. + * @return true if the segment intersects the line, + * false if the segment does not intersect the object. + */ + public static boolean segmentAndLine(PickSegment segment, + Point3d coordinates[], + int index, double dist[] ) { + + Point3d start = new Point3d(); + Point3d end = new Point3d(); + Vector3d direction = new Vector3d(); + + if((coordinates.length - index) < 2) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect13")); + + segment.get(start, end); + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + Point3d startpnt = coordinates[index++]; + Point3d endpnt = coordinates[index]; + + if(lineAndRay(startpnt, endpnt, start, direction, dist)==true) + if(dist[0] <= 1.0) + return true; + + return false; + } + + /** + * Return true if line intersects with segment and the distance, from + * the start of segment to the intersection point, is stored in dist[0]. + * The line is defined by coordinates[index] to coordinates[index+1] + * + * @param segment The segment that is used in intersection test. + * @param coordinates an array of vertices. + * @param index the vertex index + * @param dist On return dist[0] contains the distance between segment's start and the point + * intersection, if exist. + * @return true if segment intersects line, else return false. + */ + + public static boolean segmentAndLine(PickSegment segment, Point3f coordinates[], + int index, double dist[] ) { + + Point3d start = new Point3d(); + Point3d end = new Point3d(); + Vector3d direction = new Vector3d(); + + if((coordinates.length - index) < 2) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect13")); + + segment.get(start, end); + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + Point3d startpnt = new Point3d(coordinates[index++]); + Point3d endpnt = new Point3d(coordinates[index]); + + if(lineAndRay(startpnt, endpnt, start, direction, dist)==true) + if(dist[0] <= 1.0) + return true; + + return false; + } + + /** + * Determines if the PickPoint and Line + * objects intersect. + * The line is defined as coordinates[index] to + * coordinates[index+1]. + * + * @param point The point that is used in the intersection test. + * @param coordinates An array holding the line data. + * @return true if the the point intersects the line, + * false if the the point does not intersect the object. + */ + public static boolean pointAndLine(PickPoint point, Point3d coordinates[], + int index ) { + + if((coordinates.length - index) < 2) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect13")); + + double dist[] = new double[1]; + Point3d start = coordinates[index++]; + Point3d end = coordinates[index]; + Point3d location = new Point3d(); + Vector3d direction = new Vector3d(); + + point.get(location); + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + if ((rayAndPoint(location, start, direction, dist)==true) && + (dist[0] <= 1.0)) + return true; + + return false; + + } + + /** + * Return true if line intersects with point. + * The line is defined by coordinates[index] to coordinates[index+1] + * + * @param point The point that is used in intersection test. + * @param coordinates an array of vertices. + * @param index the vertex index + * @return true if point intersects line, else return false. + */ + + public static boolean pointAndLine(PickPoint point, Point3f coordinates[], + int index ) { + + if((coordinates.length - index) < 2) + throw new RuntimeException(J3dUtilsI18N.getString("Intersect13")); + + double dist[] = new double[1]; + Point3d start = new Point3d(coordinates[index++]); + Point3d end = new Point3d(coordinates[index]); + Point3d location = new Point3d(); + Vector3d direction = new Vector3d(); + + point.get(location); + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + if((rayAndPoint(location, start, direction, dist)==true) && (dist[0] <= 1.0)) + return true; + + return false; + + } + + /** + * Return true if point is on the inside of halfspace test. The + * halfspace is + * partition by the plane of triangle or quad. + * */ + + private static boolean pointAndPoly( Point3d coordinates[], PickPoint point) { + + Vector3d vec0 = new Vector3d(); // Edge vector from point 0 to point 1; + Vector3d vec1 = new Vector3d(); // Edge vector from point 0 to point 2 or 3; + Vector3d pNrm = new Vector3d(); + double absNrmX, absNrmY, absNrmZ, pD = 0.0; + Vector3d tempV3d = new Vector3d(); + double pNrmDotrDir = 0.0; + + double tempD; + + int i, j; + + // Compute plane normal. + for(i=0; i 0.0) + break; + } + + for(j=i; j 0.0) + break; + } + + if(j == (coordinates.length-1)) { + // System.out.println("(1) Degenerated polygon."); + return false; // Degenerated polygon. + } + + /* + System.out.println("Ray orgin : " + ray.origin + " dir " + ray.direction); + System.out.println("Triangle/Quad :"); + for(i=0; i1.0)) // Before or after the end points of line. + return false; + + tmp1 = ori.z + s * dir.z; + tmp2 = start.z + t * lDir.z; + + if((tmp1 < (tmp2 - Double.MIN_VALUE)) || (tmp1 > (tmp2 + Double.MIN_VALUE))) + return false; + + dist[0] = s; + return true; + } + + private static boolean rayAndPoint( Point3d pnt, Point3d ori, + Vector3d dir, double dist[] ) { + int flag = 0; + double temp; + + if(dir.x != 0.0) { + flag = 0; + dist[0] = (pnt.x - ori.x)/dir.x; + } + else if(dir.y != 0.0) { + if(pnt.x != ori.x) + return false; + flag = 1; + dist[0] = (pnt.y - ori.y)/dir.y; + } + else if(dir.z != 0.0) { + if((pnt.x != ori.x)||(pnt.y != ori.y)) + return false; + flag = 2; + dist[0] = (pnt.z - ori.z)/dir.z; + + } + else + return false; + + if(dist[0] < 0.0) + return false; + + if(flag == 0) { + temp = ori.y + dist[0] * dir.y; + if((pnt.y < (temp - Double.MIN_VALUE)) || (pnt.y > (temp + Double.MIN_VALUE))) + return false; + } + + if(flag < 2) { + temp = ori.z + dist[0] * dir.z; + if((pnt.z < (temp - Double.MIN_VALUE)) || (pnt.z > (temp + Double.MIN_VALUE))) + return false; + } + + return true; + + } + + private static boolean rayAndPoly( Point3d coordinates[], + PickRay ray, double dist[] ) { + + Vector3d vec0 = new Vector3d(); // Edge vector from point 0 to point 1; + Vector3d vec1 = new Vector3d(); // Edge vector from point 0 to point 2 or 3; + Vector3d pNrm = new Vector3d(); + double absNrmX, absNrmY, absNrmZ, pD = 0.0; + Vector3d tempV3d = new Vector3d(); + double pNrmDotrDir = 0.0; + int axis, nc, sh, nsh; + Point3d origin = new Point3d(); + Vector3d direction = new Vector3d(); + + Point3d iPnt = new Point3d(); // Point of intersection. + + double uCoor[] = new double[4]; // Only need to support up to quad. + double vCoor[] = new double[4]; + double tempD; + + int i, j; + + // Compute plane normal. + for(i=0; i 0.0) + break; + } + + for(j=i; j 0.0) + break; + } + + if(j == (coordinates.length-1)) { + // System.out.println("(1) Degenerated polygon."); + return false; // Degenerated polygon. + } + + /* + System.out.println("Triangle/Quad :"); + for(i=0; i absNrmY) + axis = 0; + else + axis = 1; + + if(axis == 0) { + if(absNrmX < absNrmZ) + axis = 2; + } + else if(axis == 1) { + if(absNrmY < absNrmZ) + axis = 2; + } + + // System.out.println("Normal " + pNrm + " axis " + axis ); + + for(i=0; i 0.0) && (uCoor[j] > 0.0)) { + // This line must cross U+. + nc++; + } + else if((uCoor[i] > 0.0) || (uCoor[j] > 0.0)) { + // This line might cross U+. We need to compute intersection on U azis. + tempD = uCoor[i]-vCoor[i]*(uCoor[j]-uCoor[i])/(vCoor[j]-vCoor[i]); + if(tempD > 0) + // This line cross U+. + nc++; + } + sh = nsh; + } // sh != nsh + } + + // System.out.println("nc " + nc); + + if((nc%2) == 1) { + + // calculate the distance + dist[0] *= direction.length(); + + // System.out.println("Ray Intersected!"); + /* + System.out.println("Ray orgin : " + origin + " dir " + direction); + System.out.println("Triangle/Quad :"); + for(i=0; i 0.0) + break; + } + + for(j=i; j 0.0) + break; + } + + if(j == (coordinates.length-1)) { + // System.out.println("(1) Degenerated polygon."); + return false; // Degenerated polygon. + } + + /* + System.out.println("Triangle/Quad :"); + for(i=0; i 1.0 )) { + // System.out.println("Segment intersects the plane behind the start or exceed end."); + return false; + } + + // Now, one thing for sure the segment intersect the plane. + // Find the intersection point. + iPnt.x = start.x + direction.x * dist[0]; + iPnt.y = start.y + direction.y * dist[0]; + iPnt.z = start.z + direction.z * dist[0]; + + // System.out.println("dist " + dist[0] + " iPnt : " + iPnt); + + // Project 3d points onto 2d plane and apply Jordan curve theorem. + // Note : Area of polygon is not preserve in this projection, but + // it doesn't matter here. + + // Find the axis of projection. + absNrmX = Math.abs(pNrm.x); + absNrmY = Math.abs(pNrm.y); + absNrmZ = Math.abs(pNrm.z); + + if(absNrmX > absNrmY) + axis = 0; + else + axis = 1; + + if(axis == 0) { + if(absNrmX < absNrmZ) + axis = 2; + } + else if(axis == 1) { + if(absNrmY < absNrmZ) + axis = 2; + } + + // System.out.println("Normal " + pNrm + " axis " + axis ); + + for(i=0; i 0.0) && (uCoor[j] > 0.0)) { + // This line must cross U+. + nc++; + } + else if((uCoor[i] > 0.0) || (uCoor[j] > 0.0)) { + // This line might cross U+. We need to compute intersection on U azis. + tempD = uCoor[i]-vCoor[i]*(uCoor[j]-uCoor[i])/(vCoor[j]-vCoor[i]); + if(tempD > 0) + // This line cross U+. + nc++; + } + sh = nsh; + } // sh != nsh + } + + // System.out.println("nc " + nc); + + if((nc%2) == 1) { + + // calculate the distance + dist[0] *= direction.length(); + + // System.out.println("Segment Intersected!"); + /* + System.out.println("Segment orgin : " + start + " dir " + direction); + System.out.println("Triangle/Quad :"); + for(i=0; icom.sun.j3d.utils.picking.behaviors.PickMouseBehavior + * + * @see com.sun.j3d.utils.picking.behaviors.PickMouseBehavior + */ + +public abstract class PickMouseBehavior extends Behavior { + + /** + * Portion of the scene graph to operate picking on. + */ + protected PickObject pickScene; + + protected WakeupCriterion[] conditions; + protected WakeupOr wakeupCondition; + protected boolean buttonPress = false; + + protected TransformGroup currGrp; + protected static final boolean debug = false; + protected MouseEvent mevent; + + /** + * Creates a PickMouseBehavior given current canvas, root of the tree to + * operate on, and the bounds. + */ + public PickMouseBehavior(Canvas3D canvas, BranchGroup root, Bounds bounds){ + super(); + currGrp = new TransformGroup(); + currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); + root.addChild(currGrp); + pickScene = new PickObject(canvas, root); + } + + public void initialize() { + + conditions = new WakeupCriterion[2]; + conditions[0] = new WakeupOnAWTEvent(Event.MOUSE_MOVE); + conditions[1] = new WakeupOnAWTEvent(Event.MOUSE_DOWN); + wakeupCondition = new WakeupOr(conditions); + + wakeupOn(wakeupCondition); + } + + private void processMouseEvent(MouseEvent evt) { + buttonPress = false; + + if (evt.getID()==MouseEvent.MOUSE_PRESSED | + evt.getID()==MouseEvent.MOUSE_CLICKED) { + buttonPress = true; + return; + } + else if (evt.getID() == MouseEvent.MOUSE_MOVED) { + // Process mouse move event + } + } + + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] evt = null; + int xpos = 0, ypos = 0; + + while(criteria.hasMoreElements()) { + wakeup = (WakeupCriterion)criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) + evt = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + } + + if (evt[0] instanceof MouseEvent){ + mevent = (MouseEvent) evt[0]; + + if (debug) + System.out.println("got mouse event"); + processMouseEvent((MouseEvent)evt[0]); + xpos = mevent.getPoint().x; + ypos = mevent.getPoint().y; + } + + if (debug) + System.out.println("mouse position " + xpos + " " + ypos); + + if (buttonPress){ + updateScene(xpos, ypos); + } + wakeupOn (wakeupCondition); + } + + /** Subclasses shall implement this update function + */ + public abstract void updateScene(int xpos, int ypos); +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickObject.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickObject.java new file mode 100644 index 0000000..238307e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickObject.java @@ -0,0 +1,841 @@ +/* + * $RCSfile: PickObject.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:13 $ + * $State: Exp $ + */ + +/* +New Base level methods: + +ISSUE : + How about PickPoint and PickSegment ? + +DONE : + PickShape generatePickRay(int x, int y) + + SceneGraphPath[] pickAll(int x, int y) + SceneGraphPath[] pickAllSorted(int x, int y) + SceneGraphPath pickAny(int x, int y) + SceneGraphPath pickClosest(int x, int y) + + Node getPickedNode(SceneGraphPath, flag) + Node getPickedNode(SceneGraphPath, flag, int count) + where flag can be any combo of: + Group, Morph, Primitive, Shape3D, + TransformGroup, Switch + + +TODO : + SceneGraphPath[] pickGeomAll(int x, int y) + SceneGraphPath[] pickGeomAllSorted(int x, int y) + SceneGraphPath pickGeomAny(int x, int y) + SceneGraphPath pickGeomClosest(int x, int y) + + bool intersect(SceneGraphPath, PickShape) + + + Eventually: + getClosestVtx(ScenGraphPath, PickShape) + + +Misc: + Mouse should stay on top of object it is dragging + + */ + +package com.sun.j3d.utils.behaviors.picking; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import com.sun.j3d.utils.geometry.Primitive; +import javax.vecmath.*; + +/* + * Contains methods to aid in picking. A PickObject is created + * for a given Canvas3D and a BranchGroup. SceneGraphObjects + * under the specified BranchGroup can then be checked to determine + * if they have been picked. + */ + +/** + * @deprecated As of Java 3D version 1.2, replaced by + * com.sun.j3d.utils.picking.PickCanvas + * + * @see com.sun.j3d.utils.picking.PickCanvas + */ + +public class PickObject extends Object { + + // Have to rethink what to support. Is this complete. + + /** + * A flag to indicate to the pickNode method to return a + * Shape3D node from + * a given SceneGraphPath. + * + * @see PickObject#pickNode + */ + public static final int SHAPE3D = 0x1; + + /** + * A flag to indicate to the pickNode method to return a + * Morph node from + * a given SceneGraphPath. + * + * @see PickObject#pickNode + */ + public static final int MORPH = 0x2; + + /** + * A flag to indicate to the pickNode method to return a + * Primitive node + * from a given SceneGraphPath. + * + * @see PickObject#pickNode + */ + public static final int PRIMITIVE = 0x4; + + /** + * A flag to indicate to the pickNode method to return a + * Link node from + * a given SceneGraphPath. + * + * @see PickObject#pickNode + */ + public static final int LINK = 0x8; + + /** + * A flag to indicate to the pickNode method to return a + * Group node from + * a given SceneGraphPath. + * + * @see PickObject#pickNode + */ + public static final int GROUP = 0x10; + + /** + * A flag to indicate to the pickNode method to return a + * TransformGroup + * node from a given SceneGraphPath. + * + * @see PickObject#pickNode + */ + public static final int TRANSFORM_GROUP = 0x20; + + /** + * A flag to indicate to the pickNode method to return a + * BranchGroup + * node from a given SceneGraphPath. + * + * @see PickObject#pickNode + */ + public static final int BRANCH_GROUP = 0x40; + + /** + * A flag to indicate to the pickNode method to return a + * Switch node from + * a given SceneGraphPath. + * + * @see PickObject#pickNode + */ + public static final int SWITCH = 0x80; + + + /** + * Set this flag if you want to pick by geometry. + */ + public static final int USE_GEOMETRY = 0x100; + + + /** + * Set this flag if you want to pick by bounds. + */ + public static final int USE_BOUNDS = 0x200; + + BranchGroup pickRoot; + Canvas3D canvas; + Point3d origin = new Point3d(); + Vector3d direction = new Vector3d(); + PickRay pickRay = new PickRay(); + SceneGraphPath sceneGraphPath = null; + SceneGraphPath sceneGraphPathArr[] = null; + int pickBy; // To pick by Bounds or Geometry. + + static final boolean debug = false; + + /** + * Creates a PickObject. + * @param c Current J3D canvas. + * @param root The portion of the scenegraph for which picking is to occur + * on. It has to be a BranchGroup. + * + * @see BranchGroup + * @see Canvas3D + */ + public PickObject(Canvas3D c, BranchGroup root) + { + pickRoot = root; + canvas = c; + } + + /** + * Creates a PickRay that starts at the viewer position and points into + * the scene in the direction of (xpos, ypos) specified in window space. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @return A PickShape object that is the constructed PickRay. + */ + public PickShape generatePickRay(int xpos, int ypos) + { + + Transform3D motion=new Transform3D(); + Point3d eyePosn = new Point3d(); + Point3d mousePosn = new Point3d(); + Vector3d mouseVec=new Vector3d(); + + canvas.getCenterEyeInImagePlate(eyePosn); + canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn); + if (canvas.getView().getProjectionPolicy() == + View.PARALLEL_PROJECTION) { + // Correct for the parallel projection: keep the eye's z + // coordinate, but make x,y be the same as the mouse, this + // simulates the eye being at "infinity" + eyePosn.x = mousePosn.x; + eyePosn.y = mousePosn.y; + } + + canvas.getImagePlateToVworld(motion); + + if (debug) { + System.out.println("mouse position " + xpos + " " + ypos); + System.out.println("before, mouse " + mousePosn + " eye " + eyePosn); + } + + motion.transform(eyePosn); + motion.transform(mousePosn); + mouseVec.sub(mousePosn, eyePosn); + mouseVec.normalize(); + + if (debug) { + System.out.println(motion + "\n"); + System.out.println("after, mouse " + mousePosn + " eye " + eyePosn + + " mouseVec " + mouseVec); + } + + pickRay.set(eyePosn, mouseVec); + + return (PickShape) pickRay; + + } + + /** + * Returns an array referencing all the items that are pickable below the + * BranchGroup (specified in the PickObject constructor) that + * intersect with a ray that starts at the + * viewer position and points into the scene in the direction of (xpos, ypos) + * specified in window space. The resultant array is unordered. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @return The array of SceneGraphPath objects that contain Objects that + * were picked + * If no pickable object is found null is returned.. + * + * @see SceneGraphPath + */ + public SceneGraphPath[] pickAll(int xpos, int ypos) + { + pickRay = (PickRay) generatePickRay(xpos, ypos); + sceneGraphPathArr = pickRoot.pickAll(pickRay); + return sceneGraphPathArr; + } + + /** + * Returns a sorted array of references to all the Pickable items below the + * BranchGroup (specified in the PickObject constructor) that + * intersect with the ray that starts at the viewer + * position and points into the scene in the direction of (xpos, ypos) + * in the window space. + * Element [0] references the item closest to viewer. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @return A sorted arrayof SceneGraphPath objects that contain Objects that + * were picked. The array is sorted from closest to farthest from the + * viewer + * If no pickable object is found null is returned.. + * + * @see SceneGraphPath + */ + public SceneGraphPath[] pickAllSorted(int xpos, int ypos) + { + pickRay = (PickRay) generatePickRay(xpos, ypos); + sceneGraphPathArr = pickRoot.pickAllSorted(pickRay); + return sceneGraphPathArr; + } + + /** + * Returns a reference to any item that is Pickable below the specified + * BranchGroup (specified in the PickObject constructor) which + * intersects with the ray that starts at the viewer + * position and points into the scene in the direction of (xpos, ypos) in + * window space. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @return A SceneGraphPath of an object that was picked. This is not + * guarenteed to return the same result for multiple picks + * If no pickable object is found null is returned.. + * + * @see SceneGraphPath + */ + public SceneGraphPath pickAny(int xpos, int ypos) + { + pickRay = (PickRay) generatePickRay(xpos, ypos); + sceneGraphPath = pickRoot.pickAny(pickRay); + return sceneGraphPath; + } + + /** + * Returns a reference to the item that is closest to the viewer and is + * Pickable below the BranchGroup (specified in the PickObject + * constructor) which intersects with the ray that starts at + * the viewer position and points into the scene in the direction of + * (xpos, ypos) in the window space. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @return A SceneGraphPath which contains the closest pickable object. + * If no pickable object is found, null is returned. + * + * @see SceneGraphPath + */ + public SceneGraphPath pickClosest(int xpos, int ypos) + { + pickRay = (PickRay) generatePickRay(xpos, ypos); + sceneGraphPath = pickRoot.pickClosest(pickRay); + return sceneGraphPath; + } + + + /** + * Returns an array referencing all the items that are pickable below the + * BranchGroup (specified in the PickObject constructor) that + * intersect with a ray that starts at the + * viewer position and points into the scene in the direction of (xpos, ypos) + * specified in window space. The resultant array is unordered. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @param flag Specifys picking by Geometry or Bounds. + * @return The array of SceneGraphPath objects that contain Objects that + * were picked + * If no pickable object is found null is returned.. + * + * @see SceneGraphPath + */ + public SceneGraphPath[] pickAll(int xpos, int ypos, int flag) + { + + if(flag == USE_BOUNDS) { + return pickAll(xpos, ypos); + } + else if(flag == USE_GEOMETRY) { + return pickGeomAll(xpos, ypos); + } + else + return null; + } + + /** + * Returns a sorted array of references to all the Pickable items below the + * BranchGroup (specified in the PickObject constructor) that + * intersect with the ray that starts at the viewer + * position and points into the scene in the direction of (xpos, ypos) + * in the window space. + * Element [0] references the item closest to viewer. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @param flag Specifys picking by Geometry or Bounds. + * @return A sorted arrayof SceneGraphPath objects that contain Objects that + * were picked. The array is sorted from closest to farthest from the + * viewer + * If no pickable object is found null is returned.. + * + * @see SceneGraphPath + */ + public SceneGraphPath[] pickAllSorted(int xpos, int ypos, int flag) + { + + if(flag == USE_BOUNDS) { + return pickAllSorted(xpos, ypos); + } + else if(flag == USE_GEOMETRY) { + return pickGeomAllSorted(xpos, ypos); + } + else + return null; + + } + + /** + * Returns a reference to any item that is Pickable below the specified + * BranchGroup (specified in the PickObject constructor) which + * intersects with the ray that starts at the viewer + * position and points into the scene in the direction of (xpos, ypos) in + * window space. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @param flag Specifys picking by Geometry or Bounds. + * @return A SceneGraphPath of an object that was picked. This is not + * guarenteed to return the same result for multiple picks + * If no pickable object is found null is returned.. + * + * @see SceneGraphPath + */ + public SceneGraphPath pickAny(int xpos, int ypos, int flag) + { + + if(flag == USE_BOUNDS) { + return pickAny(xpos, ypos); + } + else if(flag == USE_GEOMETRY) { + return pickGeomAny(xpos, ypos); + } + else + return null; + } + + /** + * Returns a reference to the item that is closest to the viewer and is + * Pickable below the BranchGroup (specified in the PickObject + * constructor) which intersects with the ray that starts at + * the viewer position and points into the scene in the direction of + * (xpos, ypos) in the window space. + * + * @param xpos The value along the x-axis. + * @param ypos The value along the y-axis. + * @param flag Specifys picking by Geometry or Bounds. + * @return A SceneGraphPath which contains the closest pickable object. + * If no pickable object is found, null is returned. + * + * @see SceneGraphPath + */ + public SceneGraphPath pickClosest(int xpos, int ypos, int flag) + { + + if(flag == USE_BOUNDS) { + return pickClosest(xpos, ypos); + } + else if(flag == USE_GEOMETRY) { + return pickGeomClosest(xpos, ypos); + } + else + return null; + } + + private SceneGraphPath[] pickGeomAll(int xpos, int ypos) + { + Node obj; + int i, cnt=0; + + pickRay = (PickRay) generatePickRay(xpos, ypos); + sceneGraphPathArr = pickRoot.pickAll(pickRay); + + if(sceneGraphPathArr == null) + return null; + + boolean found[] = new boolean[sceneGraphPathArr.length]; + + for(i=0; inull is returned. + */ + public Node pickNode(SceneGraphPath sgPath, int flags) + { + + if (sgPath != null) { + Node pickedNode = sgPath.getObject(); + + if ((pickedNode instanceof Shape3D) && ((flags & SHAPE3D) != 0)){ + if (debug) System.out.println("Shape3D found"); + return pickedNode; + } + else if ((pickedNode instanceof Morph) && ((flags & MORPH) != 0)){ + if (debug) System.out.println("Morph found"); + return pickedNode; + } + else { + for (int j=sgPath.nodeCount()-1; j>=0; j--){ + pickedNode = sgPath.getNode(j); + if (debug) System.out.println("looking at node " + pickedNode); + + if ((pickedNode instanceof Primitive) && + ((flags & PRIMITIVE) != 0)){ + if (debug) System.out.println("Primitive found"); + return pickedNode; + } + else if ((pickedNode instanceof Link) && ((flags & LINK) != 0)){ + if (debug) System.out.println("Link found"); + return pickedNode; + } + else if ((pickedNode instanceof Switch) && ((flags & SWITCH) != 0)){ + if (debug) System.out.println("Switch found"); + return pickedNode; + } + else if ((pickedNode instanceof TransformGroup) && + ((flags & TRANSFORM_GROUP) != 0)){ + if (debug) System.out.println("xform group found"); + return pickedNode; + } + else if ((pickedNode instanceof BranchGroup) && + ((flags & BRANCH_GROUP) != 0)){ + if (debug) System.out.println("Branch group found"); + return pickedNode; + } + else if ((pickedNode instanceof Group) && ((flags & GROUP) != 0)){ + if (debug) System.out.println("Group found"); + return pickedNode; + } + } + + if (pickedNode == null) + if (debug) System.out.println("ERROR: null SceneGraphPath"); + } + + } + + return null; + + } + + + /** + * Returns a reference to a Pickable Node that + * is of the specified type + * that is contained in the specified SceneGraphPath. + * The Node returned is the nth occurrence + * of a Node that is of the specified type. + * + * @param sgPath the SceneGraphPath to be traversed. + * @param flags the Node types interested. + * @param occurrence the occurrence of a Node that + * matches the specified type to return. An occurrence of + * 1 means to return the first occurrence of that object type (the object + * closest to the Locale). + * @return the nth occurrence of a Node + * of type flags, starting from the Locale. If no pickable object is + * found, null is returned. + */ + public Node pickNode(SceneGraphPath sgPath, int flags, int occurrence) + { + int curCnt=0; + + if (sgPath != null) { + Node pickedNode = sgPath.getObject(); + + // Shape3D and Morph are leaf nodes and have no children. It doesn't + // make sense to do occurrence check here. We'll just return it for now. + if ((pickedNode instanceof Shape3D) && ((flags & SHAPE3D) != 0)){ + if (debug) System.out.println("Shape3D found"); + return pickedNode; + } else if ((pickedNode instanceof Morph) && ((flags & MORPH) != 0)){ + if (debug) System.out.println("Morph found"); + return pickedNode; + } + else { + for (int j = 0; j < sgPath.nodeCount(); j++){ + pickedNode = sgPath.getNode(j); + if (debug) System.out.println("looking at node " + pickedNode); + + if ((pickedNode instanceof Group) && ((flags & GROUP) != 0)){ + if (debug) System.out.println("Group found"); + curCnt++; + if(curCnt == occurrence) + return pickedNode; + } + else if ((pickedNode instanceof BranchGroup) && + ((flags & BRANCH_GROUP) != 0)){ + if (debug) System.out.println("Branch group found"); + curCnt++; + if(curCnt == occurrence) + return pickedNode; + } + else if ((pickedNode instanceof TransformGroup) && + ((flags & TRANSFORM_GROUP) != 0)){ + if (debug) System.out.println("xform group found"); + curCnt++; + if(curCnt == occurrence) + return pickedNode; + } + else if ((pickedNode instanceof Primitive) && + ((flags & PRIMITIVE) != 0)){ + if (debug) System.out.println("Primitive found"); + curCnt++; + if(curCnt == occurrence) + return pickedNode; + } + else if ((pickedNode instanceof Link) && ((flags & LINK) != 0)){ + if (debug) System.out.println("Link found"); + curCnt++; + if(curCnt == occurrence) + return pickedNode; + } + } + + if (pickedNode == null) + if (debug) System.out.println("ERROR: null SceneGraphPath"); + } + + } + + return null; + + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickRotateBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickRotateBehavior.java new file mode 100644 index 0000000..16cec0e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickRotateBehavior.java @@ -0,0 +1,194 @@ +/* + * $RCSfile: PickRotateBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:14 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.picking; + +import com.sun.j3d.utils.behaviors.mouse.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/* + * A mouse behavior that allows user to pick and drag scene graph objects. + * Common usage: + *

+ * 1. Create your scene graph. + *

+ * 2. Create this behavior with root and canvas. + *

+ *

+ *	PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds);
+ *      root.addChild(behavior);
+ * 
+ *

+ * The above behavior will monitor for any picking events on + * the scene graph (below root node) and handle mouse drags on pick hits. + * Note the root node can also be a subgraph node of the scene graph (rather + * than the topmost). + */ + +/** + * @deprecated As of Java 3D version 1.2, replaced by + * com.sun.j3d.utils.picking.behaviors.PickRotateBehavior + * + * @see com.sun.j3d.utils.picking.behaviors.PickRotateBehavior + */ + +public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseRotate drag; + int pickMode = PickObject.USE_BOUNDS; + private PickingCallback callback=null; + private TransformGroup currentTG; + + /** + * Creates a pick/rotate behavior that waits for user mouse events for + * the scene graph. This method has its pickMode set to BOUNDS picking. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP); + drag.setTransformGroup(currGrp); + currGrp.addChild(drag); + drag.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/rotate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY. + * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in + * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set. + **/ + + public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds, + int pickMode){ + super(canvas, root, bounds); + drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP); + drag.setTransformGroup(currGrp); + currGrp.addChild(drag); + drag.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.pickMode = pickMode; + } + + /** + * Sets the pickMode component of this PickRotateBehavior to the value of + * the passed pickMode. + * @param pickMode the pickMode to be copied. + **/ + + + public void setPickMode(int pickMode) { + this.pickMode = pickMode; + } + + /** + * Return the pickMode component of this PickRotateBehavior. + **/ + + public int getPickMode() { + return pickMode; + } + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + public void updateScene(int xpos, int ypos){ + TransformGroup tg = null; + + if (!mevent.isMetaDown() && !mevent.isAltDown()){ + + // tg = (TransformGroup) pickScene.pickNode(pickScene.pickClosest(xpos, ypos), + // PickObject.TRANSFORM_GROUP); + + tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos,pickMode), + PickObject.TRANSFORM_GROUP); + // Make sure the selection exists and is movable. + if ((tg != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){ + drag.setTransformGroup(tg); + drag.wakeup(); + currentTG = tg; + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + } + } + + /** + * Callback method from MouseRotate + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.ROTATE, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + drag.setupCallback( null ); + else + drag.setupCallback( this ); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickTranslateBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickTranslateBehavior.java new file mode 100644 index 0000000..98d8584 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickTranslateBehavior.java @@ -0,0 +1,178 @@ +/* + * $RCSfile: PickTranslateBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:14 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.picking; + +import com.sun.j3d.utils.behaviors.mouse.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +// A mouse behavior that allows user to pick and translate scene graph objects. +// Common usage: 1. Create your scene graph. 2. Create this behavior with +// the root and canvas. See PickRotateBehavior for more details. + +/** + * @deprecated As of Java 3D version 1.2, replaced by + * com.sun.j3d.utils.picking.behaviors.PickTranslateBehavior + * + * @see com.sun.j3d.utils.picking.behaviors.PickTranslateBehavior + */ + +public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseTranslate translate; + int pickMode = PickObject.USE_BOUNDS; + private PickingCallback callback = null; + private TransformGroup currentTG; + + /** + * Creates a pick/translate behavior that waits for user mouse events for + * the scene graph. This method has its pickMode set to BOUNDS picking. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP); + translate.setTransformGroup(currGrp); + currGrp.addChild(translate); + translate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/translate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY. + * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in + * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set. + **/ + + public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds, + int pickMode){ + super(canvas, root, bounds); + translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP); + translate.setTransformGroup(currGrp); + currGrp.addChild(translate); + translate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.pickMode = pickMode; + } + + /** + * Sets the pickMode component of this PickTranslateBehavior to the value of + * the passed pickMode. + * @param pickMode the pickMode to be copied. + **/ + + public void setPickMode(int pickMode) { + this.pickMode = pickMode; + } + + /** + * Return the pickMode component of this PickTranslaeBehavior. + **/ + + public int getPickMode() { + return pickMode; + } + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + public void updateScene(int xpos, int ypos){ + TransformGroup tg = null; + + if (!mevent.isAltDown() && mevent.isMetaDown()){ + + tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos, pickMode), + PickObject.TRANSFORM_GROUP); + //Check for valid selection. + if ((tg != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){ + + translate.setTransformGroup(tg); + translate.wakeup(); + currentTG = tg; + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + } + + } + + /** + * Callback method from MouseTranslate + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.TRANSLATE, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + translate.setupCallback( null ); + else + translate.setupCallback( this ); + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickZoomBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickZoomBehavior.java new file mode 100644 index 0000000..45711eb --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickZoomBehavior.java @@ -0,0 +1,180 @@ +/* + * $RCSfile: PickZoomBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:14 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.picking; + +import com.sun.j3d.utils.behaviors.mouse.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + + +// A mouse behavior that allows user to pick and zoom scene graph objects. +// Common usage: 1. Create your scene graph. 2. Create this behavior with +// the root and canvas. See PickRotateBehavior for more details. + +/** + * @deprecated As of Java 3D version 1.2, replaced by + * com.sun.j3d.utils.picking.behaviors.PickZoomBehavior + * + * @see com.sun.j3d.utils.picking.behaviors.PickZoomBehavior + */ + +public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseZoom zoom; + int pickMode = PickObject.USE_BOUNDS; + private PickingCallback callback = null; + private TransformGroup currentTG; + + /** + * Creates a pick/zoom behavior that waits for user mouse events for + * the scene graph. This method has its pickMode set to BOUNDS picking. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP); + zoom.setTransformGroup(currGrp); + currGrp.addChild(zoom); + zoom.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/zoom behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY. + * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in + * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set. + **/ + + public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds, + int pickMode){ + super(canvas, root, bounds); + zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP); + zoom.setTransformGroup(currGrp); + currGrp.addChild(zoom); + zoom.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.pickMode = pickMode; + } + + /** + * Sets the pickMode component of this PickZoomBehavior to the value of + * the passed pickMode. + * @param pickMode the pickMode to be copied. + **/ + + public void setPickMode(int pickMode) { + this.pickMode = pickMode; + } + + + /** + * Return the pickMode component of this PickZoomBehavior. + **/ + + public int getPickMode() { + return pickMode; + } + + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + + public void updateScene(int xpos, int ypos){ + TransformGroup tg = null; + + if (mevent.isAltDown() && !mevent.isMetaDown()){ + + tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos, pickMode), + PickObject.TRANSFORM_GROUP); + + // Check for valid selection + if ((tg != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){ + zoom.setTransformGroup(tg); + zoom.wakeup(); + currentTG = tg; + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + } + } + + /** + * Callback method from MouseZoom + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.ZOOM, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + zoom.setupCallback( null ); + else + zoom.setupCallback( this ); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickingCallback.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickingCallback.java new file mode 100644 index 0000000..8801d4e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickingCallback.java @@ -0,0 +1,73 @@ +/* + * $RCSfile: PickingCallback.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:14 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.picking; + +import javax.media.j3d.TransformGroup; + +/** + * @deprecated As of Java 3D version 1.2, replaced by + * com.sun.j3d.utils.picking.behaviors.PickingCallback + * + * @see com.sun.j3d.utils.picking.behaviors.PickingCallback + */ + +public interface PickingCallback { + + public final static int ROTATE=0; + public final static int TRANSLATE=1; + public final static int ZOOM=2; + + /** + * The user made a selection but nothing was + * actually picked + */ + public final static int NO_PICK=3; + + /** + * Called by the Pick Behavior with which this callback + * is registered each time the Picked object is moved + */ + public void transformChanged( int type, TransformGroup tg ); +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/package.html new file mode 100644 index 0000000..b5d0b77 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/picking/package.html @@ -0,0 +1,13 @@ + + + + + com.sun.j3d.utils.behaviors.picking + + +

Deprecated: Use com.sun.j3d.utils.pickfast.behaviors +instead.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/Mouse6DPointerBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/Mouse6DPointerBehavior.java new file mode 100644 index 0000000..cff288b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/Mouse6DPointerBehavior.java @@ -0,0 +1,195 @@ +/* + * $RCSfile: Mouse6DPointerBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:14 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.sensor ; + +import java.util.Enumeration ; +import javax.media.j3d.* ; +import javax.vecmath.Point3d ; +import javax.vecmath.Vector3f ; + +/** + * This class provides basic behavior for a 6DOF mouse sensor. It + * generates a visible 3D cursor echo in the virtual world which tracks the + * position and orientation of the 6DOF mouse in the physical world. It + * can be extended to provide other functions by accessing its + * SensorEventAgent. + * + * @see SensorEventAgent + * @since Java 3D 1.3 + */ +public class Mouse6DPointerBehavior extends Behavior { + private Sensor sensor = null ; + private SensorEventAgent eventAgent = null ; + private TransformGroup echoTransformGroup = null ; + private WakeupCondition conditions = new WakeupOnElapsedFrames(0) ; + + /** + * Constructs the behavior with a default echo. To make the echo visible, + * call getEcho() to retrieve the TransformGroup that parents the echo + * geometry, and then add that TransformGroup to the scene graph. + *

+ * The default echo is a solid 6-pointed star where each point is aligned + * with the axes of the local coordinate system of the sensor, and with + * the center of the star at the location of the sensor hotspot. + * + * @param sensor a 6 degree of freedom Sensor which generates position + * and orientation relative to the tracker base. + * @param size the physical width of the echo in centimeters. + * @param enableLighting a boolean indicating whether the echo geometry + * should have lighting enabled. + */ + public Mouse6DPointerBehavior(Sensor sensor, double size, + boolean enableLighting) { + + this.sensor = sensor ; + echoTransformGroup = new TransformGroup() ; + echoTransformGroup.setCapability + (TransformGroup.ALLOW_TRANSFORM_WRITE) ; + + Point3d hotspot = new Point3d() ; + sensor.getHotspot(hotspot) ; + + Transform3D t3d = new Transform3D() ; + Vector3f v3f = new Vector3f(hotspot) ; + t3d.set(v3f) ; + + Shape3D echo = + new SensorGnomonEcho(t3d, 0.001*size, 0.005*size, enableLighting) ; + echoTransformGroup.addChild(echo) ; + + eventAgent = new SensorEventAgent(this) ; + eventAgent.addSensorReadListener(sensor, new EchoReadListener()) ; + } + + /** + * Constructs the behavior with an echo parented by the specified + * TransformGroup. + * + * @param sensor a 6 degree of freedom Sensor which generates position + * and orientation relative to the tracker base. + * @param tg a TransformGroup with a child defining the visible echo + * which will track the Sensor position and orientation; the Transform3D + * associated with the TransformGroup will be updated in order to effect + * the behavior, so it must have the ALLOW_TRANSFORM_WRITE capability + * set before the scene graph is set live + */ + public Mouse6DPointerBehavior(Sensor sensor, TransformGroup tg) { + this.sensor = sensor ; + echoTransformGroup = tg ; + eventAgent = new SensorEventAgent(this) ; + eventAgent.addSensorReadListener(sensor, new EchoReadListener()) ; + } + + /** + * Gets the sensor used by this behavior. + * + * @return the sensor used by this behavior + */ + public Sensor getSensor() { + return sensor ; + } + + /** + * Gets the echo used by this behavior. + * + * @return the TransformGroup parenting this behavior's echo geometry + */ + public TransformGroup getEcho() { + return echoTransformGroup ; + } + + /** + * Gets the SensorEventAgent used by this behavior. This can be used to + * add customized event bindings to this behavior. + * + * @return the SensorEventAgent + */ + public SensorEventAgent getSensorEventAgent() { + return eventAgent ; + } + + /** + * Initializes the behavior. + * NOTE: Applications should not call this method. It is called by the + * Java 3D behavior scheduler. + */ + public void initialize() { + wakeupOn(conditions) ; + } + + /** + * Processes a stimulus meant for this behavior. + * NOTE: Applications should not call this method. It is called by the + * Java 3D behavior scheduler. + */ + public void processStimulus(Enumeration criteria) { + eventAgent.dispatchEvents() ; + wakeupOn(conditions) ; + } + + /** + * This member class updates the echo transform in response to sensor + * reads. + */ + public class EchoReadListener implements SensorReadListener { + private Transform3D t3d = new Transform3D() ; + + public void read(SensorEvent e) { + // Get the Transform3D that transforms points from local sensor + // coordinates to virtual world coordinates, based on the primary + // view associated with this Behavior. This view is defined to be + // the first View attached to a live ViewPlatform. + // + // Note that this will display frame lag if another behavior such + // as OrbitBehavior is used to manipulate the view transform while + // the echo is visible. In order to eliminate frame lag the + // behavior driving the view transform must also compute the echo + // transform as well. See the WandViewBehavior utility for the + // appropriate techniques. + getView().getSensorToVworld(e.getSensor(), t3d) ; + echoTransformGroup.setTransform(t3d) ; + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorBeamEcho.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorBeamEcho.java new file mode 100644 index 0000000..cf5a6d7 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorBeamEcho.java @@ -0,0 +1,231 @@ +/* + * $RCSfile: SensorBeamEcho.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:14 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.sensor ; + +import javax.media.j3d.Shape3D ; +import javax.media.j3d.Material ; +import javax.media.j3d.Appearance ; +import javax.media.j3d.Transform3D ; +import javax.media.j3d.GeometryArray ; +import javax.media.j3d.TriangleStripArray ; +import javax.media.j3d.TransparencyAttributes; +import javax.vecmath.AxisAngle4f ; +import javax.vecmath.Point3d ; +import javax.vecmath.Point3f ; +import javax.vecmath.Vector3f ; + +/** + * A Shape3D representing a beam pointing from the origin of a + * sensor's local coordinate system to its hotspot. + * + * @since Java 3D 1.3 + */ +public class SensorBeamEcho extends Shape3D { + /** + * Creates a SensorBeamEcho. Read and write capabilities are granted + * for the Appearance, Material, TransparencyAttributes, and + * TransparencyAttributes mode and value. + * + * @param hotspot location of the sensor's hotspot in the sensor's + * local coordinate system; this must not be (0, 0, 0) + * @param baseWidth width of the beam in meters + * @param enableLighting boolean indicating whether normals should be + * generated and lighting enabled + * @exception IllegalArgumentException if hotspot is (0, 0, 0) + */ + public SensorBeamEcho(Point3d hotspot, double baseWidth, + boolean enableLighting) { + super() ; + + if (hotspot.distance(new Point3d()) == 0.0) + throw new IllegalArgumentException + ("\nBeam echo can't have hotspot at origin") ; + + Vector3f axis = new Vector3f((float)hotspot.x, + (float)hotspot.y, + (float)hotspot.z) ; + + Vector3f axis1 = new Vector3f() ; + axis1.normalize(axis) ; + + // Choose an arbitrary vector normal to the beam axis. + Vector3f normal = new Vector3f(0.0f, 1.0f, 0.0f) ; + normal.cross(axis1, normal) ; + if (normal.lengthSquared() < 0.5f) { + normal.set(0.0f, 0.0f, 1.0f) ; + normal.cross(axis1, normal) ; + } + normal.normalize() ; + + // Create cap vertices and normals. + int divisions = 18 ; + Point3f[] cap0 = new Point3f[divisions] ; + Point3f[] cap1 = new Point3f[divisions] ; + Vector3f[] capNormals = new Vector3f[divisions] ; + Vector3f cap0Normal = new Vector3f(axis1) ; + Vector3f cap1Normal = new Vector3f(axis1) ; + cap0Normal.negate() ; + + AxisAngle4f aa4f = new AxisAngle4f + (axis1, -(float)Math.PI/((float)divisions/2.0f)) ; + Transform3D t3d = new Transform3D() ; + t3d.set(aa4f) ; + + float halfWidth = (float)baseWidth / 2.0f ; + for (int i = 0 ; i < divisions ; i++) { + capNormals[i] = new Vector3f(normal) ; + cap0[i] = new Point3f(normal) ; + cap0[i].scale(halfWidth) ; + cap1[i] = new Point3f(cap0[i]) ; + cap1[i].add(axis) ; + t3d.transform(normal) ; + } + + // The beam cylinder is created with 3 triangle strips. The first + // strip contains the side facets (2 + 2*divisions vertices), and + // the other two strips are the caps (divisions vertices each). + int vertexCount = 2 + (4 * divisions) ; + Point3f[] vertices = new Point3f[vertexCount] ; + Vector3f[] normals = new Vector3f[vertexCount] ; + + // Side facets. + for (int i = 0 ; i < divisions ; i++) { + vertices[i*2] = cap0[i] ; + vertices[(i*2) + 1] = cap1[i] ; + + normals[i*2] = capNormals[i] ; + normals[(i*2) + 1] = capNormals[i] ; + } + + vertices[divisions*2] = cap0[0] ; + vertices[(divisions*2) + 1] = cap1[0] ; + + normals[divisions*2] = capNormals[0] ; + normals[(divisions*2) + 1] = capNormals[0] ; + + // Strips for caps created by criss-crossing the interior. + int v = (divisions+1) * 2 ; + vertices[v] = cap0[0] ; + normals[v++] = cap0Normal ; + + int j = 1 ; + int k = divisions - 1 ; + while (j <= k) { + vertices[v] = cap0[j++] ; + normals[v++] = cap0Normal ; + if (j > k) break ; + vertices[v] = cap0[k--] ; + normals[v++] = cap0Normal ; + } + + vertices[v] = cap1[0] ; + normals[v++] = cap1Normal ; + + j = 1 ; + k = divisions - 1 ; + while (j <= k) { + vertices[v] = cap1[k--] ; + normals[v++] = cap1Normal ; + if (j > k) break ; + vertices[v] = cap1[j++] ; + normals[v++] = cap1Normal ; + } + + // Create the TriangleStripArray. + int vertexFormat ; + Material m = new Material() ; + m.setCapability(Material.ALLOW_COMPONENT_READ) ; + m.setCapability(Material.ALLOW_COMPONENT_WRITE) ; + + if (enableLighting) { + vertexFormat = + GeometryArray.COORDINATES | GeometryArray.NORMALS ; + m.setLightingEnable(true) ; + } + else { + vertexFormat = GeometryArray.COORDINATES ; + m.setLightingEnable(false) ; + } + + int[] stripCounts = new int[3] ; + stripCounts[0] = 2 + (2 * divisions) ; + stripCounts[1] = divisions ; + stripCounts[2] = divisions ; + + TriangleStripArray tsa = + new TriangleStripArray(vertexCount, + vertexFormat, stripCounts) ; + + tsa.setCoordinates(0, vertices) ; + if (enableLighting) + tsa.setNormals(0, normals) ; + + Appearance a = new Appearance() ; + a.setMaterial(m) ; + a.setCapability(Appearance.ALLOW_MATERIAL_READ) ; + a.setCapability(Appearance.ALLOW_MATERIAL_WRITE) ; + + TransparencyAttributes ta = new TransparencyAttributes() ; + ta.setCapability(TransparencyAttributes.ALLOW_MODE_READ) ; + ta.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE) ; + ta.setCapability(TransparencyAttributes.ALLOW_VALUE_READ) ; + ta.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE) ; + ta.setCapability + (TransparencyAttributes.ALLOW_BLEND_FUNCTION_READ) ; + ta.setCapability + (TransparencyAttributes.ALLOW_BLEND_FUNCTION_WRITE) ; + + a.setTransparencyAttributes(ta) ; + a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ) ; + a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE) ; + + setGeometry(tsa) ; + setAppearance(a) ; + + setCapability(ALLOW_APPEARANCE_READ) ; + setCapability(ALLOW_APPEARANCE_WRITE) ; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorButtonListener.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorButtonListener.java new file mode 100644 index 0000000..be53472 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorButtonListener.java @@ -0,0 +1,94 @@ +/* + * $RCSfile: SensorButtonListener.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:14 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.sensor ; + +/** + * This defines the interface for handling a sensor's button events in + * conjunction with a SensorEventAgent instance. + *

+ * The events passed to this listener's methods are ephemeral; they + * are only valid until the listener has returned. If a listener needs to + * retain the event it must be copied using the + * SensorEvent(SensorEvent) constructor. + * + * @see SensorEvent + * @see SensorEventAgent + * @see SensorReadListener + * @since Java 3D 1.3 + */ +public interface SensorButtonListener { + /** + * This method is called when a sensor's button is pressed. + * + * @param e the sensor event + */ + public void pressed(SensorEvent e) ; + + /** + * This method is called when a sensor's button is released. + * + * @param e the sensor event + */ + public void released(SensorEvent e) ; + + /** + * This method is called with each invocation of the + * dispatchEvents method of SensorEventAgent + * if any button bound to the listener is down and has not changed + * state since the last invocation. The sensor value has not + * necessarily changed from the last drag event. + * + * @param e the sensor event + */ + public void dragged(SensorEvent e) ; + + /** + * This method is currently not used by SensorEventAgent, + * but is included here for future possible development. Its + * implementations should remain empty for the present. + */ + public void clicked(SensorEvent e) ; +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEvent.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEvent.java new file mode 100644 index 0000000..92aa004 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEvent.java @@ -0,0 +1,336 @@ +/* + * $RCSfile: SensorEvent.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:14 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.sensor ; + +import javax.media.j3d.Sensor ; +import javax.media.j3d.Transform3D ; + +/** + * This class defines the event object that is created by a + * SensorEventAgent and passed to registered + * SensorReadListener and SensorButtonListener + * implementations. + *

+ * The events passed to the listeners are ephemeral; they are only + * valid until the listener has returned. This is done to avoid + * allocating large numbers of mostly temporary objects, especially for + * behaviors that wake up every frame. If a listener needs to retain the + * event it must be copied using the SensorEvent(SensorEvent) + * constructor. + * + * @see SensorEventAgent + * @see SensorButtonListener + * @see SensorReadListener + * @since Java 3D 1.3 + */ +public class SensorEvent { + /** + * A button pressed event. + */ + public static final int PRESSED = 1 ; + + /** + * A button released event. + */ + public static final int RELEASED = 2 ; + + /** + * A button dragged event. + */ + public static final int DRAGGED = 3 ; + + /** + * A sensor read event. + */ + public static final int READ = 4 ; + + /** + * The value that is returned by getButton when no + * buttons have changed state. + */ + public static final int NOBUTTON = -1 ; + + private int id = 0 ; + private Object source = null ; + private Sensor sensor = null ; + private int button = NOBUTTON ; + private int[] buttonState = null ; + private Transform3D sensorRead = null ; + private long time = 0 ; + private long lastTime = 0 ; + private boolean ephemeral = false ; + + /** + * Creates a new SensorEvent. + * + * @param source a reference to the originating object which + * instantiated the SensorEventAgent, usually a + * Behavior; may be null + * @param id event type + * @param sensor a reference to the provoking sensor + * @param sensorRead the sensor's read value at the time of the event + * @param buttonState the state of the sensor's buttons at the time of + * the event, where a 1 in the array indicates that the button at that + * index is down, and a 0 indicates that button is up; may be null + * @param button index of the button that changed state, from 0 to + * (buttonCount - 1), or the value NOBUTTON + * @param time the time in nanoseconds at which the + * dispatchEvents method of + * SensorEventAgent was called to generate this event, + * usually from the processStimulus method of a Behavior + * @param lastTime the time in nanoseconds at which the + * dispatchEvents method of + * SensorEventAgent was last called to generate + * events, usually from the processStimulus method of a + * Behavior; may be used to measure frame time in + * behaviors that wake up every frame + */ + public SensorEvent(Object source, int id, Sensor sensor, + Transform3D sensorRead, int[] buttonState, + int button, long time, long lastTime) { + + this.source = source ; + this.id = id ; + this.sensor = sensor ; + this.button = button ; + this.time = time ; + this.lastTime = lastTime ; + if (sensorRead == null) + throw new NullPointerException("sensorRead can't be null") ; + this.sensorRead = new Transform3D(sensorRead) ; + if (buttonState != null) { + this.buttonState = new int[buttonState.length] ; + for (int i = 0 ; i < buttonState.length ; i++) + this.buttonState[i] = buttonState[i] ; + } + this.ephemeral = false ; + } + + /** + * Creates a new ephemeral SensorEvent. In order + * to avoid creating large numbers of sensor event objects, the events + * passed to the button and read listeners by the + * dispatchEvents method of SensorEventAgent + * are valid only until the listener returns. If the event needs to + * be retained then they must be copied with the + * SensorEvent(SensorEvent) constructor. + */ + public SensorEvent() { + this.ephemeral = true ; + } + + /** + * Creates a copy of the given SensorEvent. Listeners + * must use this constructor to copy events that need to be retained. + * NOTE: The Sensor and Object references + * returned by getSensor and getSource + * remain references to the original objects. + * + * @param e the event to be copied + */ + public SensorEvent(SensorEvent e) { + this.source = e.source ; + this.id = e.id ; + this.sensor = e.sensor ; + this.button = e.button ; + this.time = e.time ; + this.lastTime = e.lastTime ; + if (e.sensorRead == null) + throw new NullPointerException("sensorRead can't be null") ; + this.sensorRead = new Transform3D(e.sensorRead) ; + if (e.buttonState != null) { + this.buttonState = new int[e.buttonState.length] ; + for (int i = 0 ; i < e.buttonState.length ; i++) + this.buttonState[i] = e.buttonState[i] ; + } + this.ephemeral = false ; + } + + /** + * Sets the fields of an ephemeral event. No objects are copied. An + * IllegalStateException will be thrown if this event + * is not ephemeral. + * + * @param source a reference to the originating object which + * instantiated the SensorEventAgent, usually a + * Behavior; may be null + * @param id event type + * @param sensor a reference to the provoking sensor + * @param sensorRead the sensor's read value at the time of the event + * @param buttonState the state of the sensor's buttons at the time of + * the event; a 1 in the array indicates that the button at that + * index is down, while a 0 indicates that button is up + * @param button index of the button that changed state, from 0 to + * (buttonCount - 1), or the value NOBUTTON + * @param time the time in nanoseconds at which the + * dispatchEvents method of + * SensorEventAgent was called to generate this event, + * usually from the processStimulus method of a Behavior + * @param lastTime the time in nanoseconds at which the + * dispatchEvents method of + * SensorEventAgent was last called to generate + * events, usually from the processStimulus method of a + * Behavior; may be used to measure frame time in + * behaviors that wake up every frame + */ + public void set(Object source, int id, Sensor sensor, + Transform3D sensorRead, int[] buttonState, + int button, long time, long lastTime) { + + if (!ephemeral) + throw new IllegalStateException + ("Can't set the fields of non-ephemeral events") ; + + this.source = source ; + this.id = id ; + this.sensor = sensor ; + if (sensorRead == null) + throw new NullPointerException("sensorRead can't be null") ; + this.sensorRead = sensorRead ; + this.buttonState = buttonState ; + this.button = button ; + this.time = time ; + this.lastTime = lastTime ; + } + + /** + * Gets a reference to the originating object which instantiated the + * SensorEventAgent, usually a Behavior; may + * be null. + * @return the originating object + */ + public Object getSource() { + return source ; + } + + /** + * Gets the event type. + * @return the event id + */ + public int getID() { + return id ; + } + + + /** + * Gets a reference to the provoking sensor. + * @return the provoking sensor + */ + public Sensor getSensor() { + return sensor ; + } + + /** + * Gets the time in nanoseconds at which the + * dispatchEvents method of SensorEventAgent + * was called to generate this event, usually from the + * processStimulus method of a Behavior. + * @return time in nanoseconds + */ + public long getTime() { + return time ; + } + + /** + * Gets the time in nanoseconds at which the + * dispatchEvents method of SensorEventAgent + * was last called to generate events, usually from the + * processStimulus method of a Behavior; may + * be used to measure frame time in behaviors that wake up every + * frame. + * @return last time in nanoseconds + */ + public long getLastTime() { + return lastTime ; + } + + /** + * Copies the sensor's read value at the time of the event into the + * given Transform3D. + * + * @param t the transform to receive the sensor read + */ + public void getSensorRead(Transform3D t) { + t.set(sensorRead) ; + } + + /** + * Gets the index of the button that changed state when passed to a + * pressed or released callback. The index + * may range from 0 to (sensor.getSensorButtonCount() - + * 1). The value returned is NOBUTTON for events + * passed to a read or dragged callback. + * @return the button index + */ + public int getButton() { + return button ; + } + + /** + * Copies the state of the sensor's buttons at the time of the event + * into the given array. A 1 in the array indicates that the button + * at that index is down, while a 0 indicates that button is up. + * @param buttonState the state of the sensor buttons + */ + public void getButtonState(int[] buttonState) { + if (buttonState.length != this.buttonState.length) + throw new ArrayIndexOutOfBoundsException + ("buttonState array is the wrong length") ; + + for (int i = 0 ; i < buttonState.length ; i++) + buttonState[i] = this.buttonState[i] ; + } + + /** + * Returns true if this event is ephemeral and is valid only + * until the listener returns. A copy of the event can be created by + * passing it to the SensorEvent(SensorEvent) + * constructor. + */ + public boolean isEphemeral() { + return ephemeral ; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEventAgent.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEventAgent.java new file mode 100644 index 0000000..cf4dd88 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEventAgent.java @@ -0,0 +1,715 @@ +/* + * $RCSfile: SensorEventAgent.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:15 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.sensor ; + +import java.util.Iterator ; +import java.util.List ; +import java.util.ArrayList ; +import javax.media.j3d.Sensor ; +import javax.media.j3d.Transform3D ; +import com.sun.j3d.utils.timer.J3DTimer ; + +/** + * This class works in conjunction with the SensorButtonListener + * and SensorReadListener interfaces to support an event-driven + * model of sensor interaction. Java 3D defines sensors as delivering + * continuous input data which must be polled to retrieve their values, but in + * practice it is often convenient to structure application code to respond to + * events such as button state transitions. + *

+ * Listeners registered with this class are invoked when its + * dispatchEvents method is called. This is usually called from + * the processStimulus method of a Behavior, but may + * also be called directly from the pollAndProcessInput method of + * an event-driven implementation of InputDevice. In either case + * the device is still polled by the Java 3D input device scheduling thread to + * get its current values; however, in the former, dispatchEvents + * is called from the behavior scheduler thread regardless of whether any new + * events are available, while in the latter, the InputDevice + * implementation may choose to call dispatchEvents only if new + * events are actually generated. + *

+ * Button events are generated by changes in sensor button state, from pressed + * to released and vice versa. Button state changes are examined with each + * invocation of the dispatchEvents method. Events are + * distributed to interested parties through the button listener interface + * using the pressed and released callbacks. + *

+ * The dragged method is not necessarily called in response to a + * motion event generated by a sensor. dispatchEvents will call + * dragged whenever any button assigned to the listener is down + * and has not changed state since the last time it was called. If + * dispatchEvents is called in the processStimulus + * of a Behavior, then dragged may be called even if + * the sensor value has not changed. This is as a consequence of the core + * Java 3D API definition of sensors as continuous devices. + *

+ * Like dragged, the read method of + * SensorReadListener is not necessarily invoked in response to a + * real event. It is called by dispatchEvents whenever a button + * listener has not been called for that sensor. This usually means that no + * buttons are down, but clients are free to leave a button listener null, or + * to explicitly bind a null button listener to a button so that button's + * events are ignored. The sensor value has not necessarily changed since the + * last read callback. + *

+ * A mutual exclusion policy can be applied between button + * listeners when they are grouped in an array mapped to the sensor's + * buttons. If multiple sensor buttons are held down at the same time, + * then a listener in the array is invoked only for the button that was + * depressed first. The read callback is separated from the + * pressed, released, and dragged + * callbacks in a separate interface in order to support this policy. + *

+ * The events passed to the listeners are ephemeral; they are only + * valid until the listener has returned. This is done to avoid + * allocating large numbers of mostly temporary objects, especially for + * behaviors that wake up every frame. If a listener needs to retain the + * event it must be copied using the SensorEvent(SensorEvent) + * constructor. + *

+ * It is safe to add and remove listeners in response to a callback. + * + * @see SensorEvent + * @see SensorButtonListener + * @see SensorReadListener + * @since Java 3D 1.3 + */ +public class SensorEventAgent { + private long t0 = 0 ; + private Object source = null ; + private SensorEvent e = new SensorEvent() ; + + // List of SensorBinding objects and corresponding array. + private List bindingsList = new ArrayList() ; + private SensorBinding[] bindings = new SensorBinding[0] ; + + // Indicates that lists must be converted to arrays. Need to do this + // to allow listeners to add and remove themselves or other listeners + // safely during event dispatch. + private boolean listsDirty = false ; + + /** + * Create a SensorEventAgent to generate and dispatch + * sensor events to registered listeners. + * + * @param source reference to the originating object for inclusion in + * generated SensorEvents; intended to refer to the + * instantiating Behavior but may be any reference, or null + */ + public SensorEventAgent(Object source) { + this.source = source ; + } + + /** + * This class contains all the button and read listeners registered + * with a sensor. + */ + private static class SensorBinding { + Sensor sensor = null ; + int[] buttons = null ; + Transform3D read = null ; + + // List of SensorButtonBinding objects and corresponding array. + List buttonBindingsList = new ArrayList() ; + SensorButtonBinding[] buttonBindings = new SensorButtonBinding[0] ; + + // List of SensorReadListener objects and corresponding array. + List readBindingsList = new ArrayList() ; + SensorReadListener[] readBindings = new SensorReadListener[0] ; + + SensorBinding(Sensor sensor) { + this.sensor = sensor ; + buttons = new int[sensor.getSensorButtonCount()] ; + read = new Transform3D() ; + } + + void updateArrays() { + buttonBindings = + (SensorButtonBinding[])buttonBindingsList.toArray + (new SensorButtonBinding[buttonBindingsList.size()]) ; + readBindings = + (SensorReadListener[])readBindingsList.toArray + (new SensorReadListener[readBindingsList.size()]) ; + } + + public String toString() { + String s = new String() ; + s = "sensor " + sensor + "\nbutton listener arrays:\n" ; + for (int i = 0 ; i < buttonBindingsList.size() ; i++) + s = s + ((SensorButtonBinding)buttonBindingsList.get(i)) ; + s = s + "read listeners:\n" ; + for (int i = 0 ; i < readBindingsList.size() ; i++) + s = s + " " + + ((SensorReadListener)readBindingsList.get(i)) + "\n" ; + return s ; + } + } + + /** + * This class contains an array of SensorButtonListener + * implementations, one for each sensor button. This array is used to + * support a mutual exclusion callback policy. There may be multiple + * instances of this class associated with a single sensor. + */ + private static class SensorButtonBinding { + int buttonsHandled = 0 ; + boolean[] prevButtons = null ; + boolean multiButton = false ; + SensorButtonListener[] listeners = null ; + + SensorButtonBinding(SensorButtonListener[] listeners, + boolean multiButtonEnable) { + + prevButtons = new boolean[listeners.length] ; + this.listeners = new SensorButtonListener[listeners.length] ; + + for (int i = 0 ; i < listeners.length ; i++) { + prevButtons[i] = false ; + this.listeners[i] = listeners[i] ; + } + + this.multiButton = multiButtonEnable ; + } + + public String toString() { + String s = new String() ; + s = " length " + listeners.length + + ", mutual exclusion " + (!multiButton) + "\n" ; + for (int i = 0 ; i < listeners.length ; i++) + s = s + " " + + (listeners[i] == null? + "null" : listeners[i].toString()) + "\n" ; + return s ; + } + } + + /** + * Look up the sensor listeners bound to the given sensor. + */ + private SensorBinding getSensorBinding(Sensor sensor) { + for (int i = 0 ; i < bindingsList.size() ; i++) { + SensorBinding sb = (SensorBinding)bindingsList.get(i) ; + if (sb.sensor == sensor) + return sb ; + } + return null ; + } + + /** + * Creates a binding of the specified sensor button to the given + * SensorButtonListener implementation. + * + * @param sensor the sensor with the button to be bound + * @param button the index of the button to be bound on the specified + * sensor; may range from 0 to + * (sensor.getSensorButtonCount() - 1) + * @param buttonListener the SensorButtonListener + * implementation that will be invoked for the sensor's button + */ + public synchronized void addSensorButtonListener + (Sensor sensor, int button, SensorButtonListener buttonListener) { + + if (sensor == null) + throw new NullPointerException("\nsensor is null") ; + + if (button >= sensor.getSensorButtonCount()) + throw new ArrayIndexOutOfBoundsException + ("\nbutton " + button + " >= sensor button count " + + sensor.getSensorButtonCount()) ; + + SensorBinding sb = getSensorBinding(sensor) ; + if (sb == null) { + sb = new SensorBinding(sensor) ; + bindingsList.add(sb) ; + } + + SensorButtonListener[] listeners = + new SensorButtonListener[sb.buttons.length] ; + + // Assign only the specified button; others remain null. + listeners[button] = buttonListener ; + SensorButtonBinding sbb = + new SensorButtonBinding(listeners, true) ; + + sb.buttonBindingsList.add(sbb) ; + listsDirty = true ; + } + + /** + * Creates a binding from all the buttons on the specified sensor to + * the given SensorButtonListener implementation. If + * multiple sensor buttons are held down at the same time, the press + * and release callbacks are called for each button in the order that + * they occur. This allows actions to be bound to combinations of + * button presses, but is also convenient for listeners that don't + * care which button was pressed. + * + * @param sensor the sensor to be bound + * @param buttonListener the SensorButtonListener + * implementation that will be called for all button events + */ + public synchronized void addSensorButtonListener + (Sensor sensor, SensorButtonListener buttonListener) { + + if (sensor == null) + throw new NullPointerException("\nsensor is null") ; + + SensorBinding sb = getSensorBinding(sensor) ; + if (sb == null) { + sb = new SensorBinding(sensor) ; + bindingsList.add(sb) ; + } + + SensorButtonListener[] listeners = + new SensorButtonListener[sb.buttons.length] ; + + // All buttons are bound to the same listener. + for (int i = 0 ; i < sb.buttons.length ; i++) + listeners[i] = buttonListener ; + + SensorButtonBinding sbb = + new SensorButtonBinding(listeners, true) ; + + sb.buttonBindingsList.add(sbb) ; + listsDirty = true ; + } + + /** + * Creates a binding of the specified sensor to the given array of + * SensorButtonListener implementations. The array index + * of the listener indicates the index of the sensor button to which + * it will be bound. + *

+ * This method enforces a mutually exclusive callback policy + * among the listeners specified in the array. If multiple sensor + * buttons are held down at the same time, callbacks are invoked only + * for the button that was depressed first. + * + * @param sensor the sensor to be bound + * @param buttonListeners array of implementations of + * SensorButtonListener; array entries may be null or + * duplicates but the array length must equal the sensor's button + * count + */ + public synchronized void addSensorButtonListeners + (Sensor sensor, SensorButtonListener[] buttonListeners) { + + if (sensor == null) + throw new NullPointerException("\nsensor is null") ; + + SensorBinding sb = getSensorBinding(sensor) ; + if (sb == null) { + sb = new SensorBinding(sensor) ; + bindingsList.add(sb) ; + } + + if (sb.buttons.length != buttonListeners.length) + throw new IllegalArgumentException + ("\nbuttonListeners length " + buttonListeners.length + + " must equal sensor button count " + sb.buttons.length) ; + + SensorButtonBinding sbb = + new SensorButtonBinding(buttonListeners, false) ; + + sb.buttonBindingsList.add(sbb) ; + listsDirty = true ; + } + + /** + * Gets the SensorButtonListener implementations bound to + * the given sensor and button. + * + * @param sensor the sensor of interest + * @param button the button of interest + * @return array of SensorButtonListener implementations + * bound to the given sensor and button, or null + */ + public SensorButtonListener[] getSensorButtonListeners(Sensor sensor, + int button) { + if (sensor == null) + throw new NullPointerException("\nsensor is null") ; + + if (button >= sensor.getSensorButtonCount()) + throw new ArrayIndexOutOfBoundsException + ("\nbutton " + button + " >= sensor button count " + + sensor.getSensorButtonCount()) ; + + SensorBinding sb = getSensorBinding(sensor) ; + if (sb == null) + return null ; + + ArrayList listeners = new ArrayList() ; + for (int i = 0 ; i < sb.buttonBindingsList.size() ; i++) { + SensorButtonBinding sbb = + (SensorButtonBinding)sb.buttonBindingsList.get(i) ; + + if (sbb.listeners[button] != null) + listeners.add(sbb.listeners[button]) ; + } + + if (listeners.size() == 0) + return null ; + else + return (SensorButtonListener[])listeners.toArray + (new SensorButtonListener[listeners.size()]) ; + } + + /** + * Remove the SensorButtonListener from the given SensorBinding. + */ + private void removeSensorButtonListener + (SensorBinding sb, SensorButtonListener listener) { + + Iterator i = sb.buttonBindingsList.iterator() ; + while (i.hasNext()) { + int instanceCount = 0 ; + SensorButtonBinding sbb = (SensorButtonBinding)i.next() ; + + for (int j = 0 ; j < sbb.listeners.length ; j++) { + if (sbb.listeners[j] == listener) + sbb.listeners[j] = null ; + else if (sbb.listeners[j] != null) + instanceCount++ ; + } + if (instanceCount == 0) { + i.remove() ; + } + } + listsDirty = true ; + } + + /** + * Remove the given SensorButtonListener binding from the + * specified sensor. + * + * @param sensor the sensor from which to remove the listener + * @param listener the listener to be removed + */ + public synchronized void removeSensorButtonListener + (Sensor sensor, SensorButtonListener listener) { + + if (sensor == null) + throw new NullPointerException("\nsensor is null") ; + + SensorBinding sb = getSensorBinding(sensor) ; + if (sb == null) + return ; + + removeSensorButtonListener(sb, listener) ; + if (sb.buttonBindingsList.size() == 0 && + sb.readBindingsList.size() == 0) + removeSensorBinding(sensor) ; + + listsDirty = true ; + } + + /** + * Remove the given SensorButtonListener from all sensors. + * + * @param listener the listener to remove + */ + public synchronized void removeSensorButtonListener + (SensorButtonListener listener) { + + Iterator i = bindingsList.iterator() ; + while (i.hasNext()) { + SensorBinding sb = (SensorBinding)i.next() ; + removeSensorButtonListener(sb, listener) ; + + if (sb.buttonBindingsList.size() == 0 && + sb.readBindingsList.size() == 0) { + i.remove() ; + } + } + listsDirty = true ; + } + + /** + * Creates a binding of the specified sensor to the given + * SensorReadListener. The read listener is invoked + * every time dispatchEvents is called and a button + * listener is not invoked. + * + * @param sensor the sensor to be bound + * @param readListener the SensorReadListener + * implementation + */ + public synchronized void addSensorReadListener + (Sensor sensor, SensorReadListener readListener) { + + if (sensor == null) + throw new NullPointerException("\nsensor is null") ; + + SensorBinding sb = getSensorBinding(sensor) ; + if (sb == null) { + sb = new SensorBinding(sensor) ; + bindingsList.add(sb) ; + } + sb.readBindingsList.add(readListener) ; + listsDirty = true ; + } + + /** + * Gets the SensorReadListeners bound to the specified + * sensor. + * + * @param sensor the sensor of interest + * @return array of SensorReadListeners bound to the + * given sensor, or null + */ + public SensorReadListener[] getSensorReadListeners(Sensor sensor) { + if (sensor == null) + throw new NullPointerException("\nsensor is null") ; + + SensorBinding sb = getSensorBinding(sensor) ; + if (sb == null) + return null ; + else if (sb.readBindingsList.size() == 0) + return null ; + else + return (SensorReadListener[])sb.readBindingsList.toArray + (new SensorReadListener[sb.readBindingsList.size()]) ; + } + + /** + * Remove the SensorReadListener from the given SensorBinding. + */ + private void removeSensorReadListener + (SensorBinding sb, SensorReadListener listener) { + + Iterator i = sb.readBindingsList.iterator() ; + while (i.hasNext()) { + if (((SensorReadListener)i.next()) == listener) + i.remove() ; + } + listsDirty = true ; + } + + /** + * Remove the given SensorReadListener binding from the + * specified sensor. + * + * @param sensor the sensor from which to remove the listener + * @param listener the listener to be removed + */ + public synchronized void removeSensorReadListener + (Sensor sensor, SensorReadListener listener) { + + if (sensor == null) + throw new NullPointerException("\nsensor is null") ; + + SensorBinding sb = getSensorBinding(sensor) ; + if (sb == null) + return ; + + removeSensorReadListener(sb, listener) ; + if (sb.buttonBindingsList.size() == 0 && + sb.readBindingsList.size() == 0) + removeSensorBinding(sensor) ; + + listsDirty = true ; + } + + /** + * Remove the given SensorReadListener from all sensors. + * + * @param listener the listener to remove + */ + public synchronized void removeSensorReadListener + (SensorReadListener listener) { + + Iterator i = bindingsList.iterator() ; + while (i.hasNext()) { + SensorBinding sb = (SensorBinding)i.next() ; + removeSensorReadListener(sb, listener) ; + + if (sb.buttonBindingsList.size() == 0 && + sb.readBindingsList.size() == 0) { + i.remove() ; + } + } + listsDirty = true ; + } + + /** + * Remove all sensor listeners bound to the given sensor. + */ + public synchronized void removeSensorBinding(Sensor sensor) { + Iterator i = bindingsList.iterator() ; + while (i.hasNext()) { + SensorBinding sb = (SensorBinding)i.next() ; + if (sb.sensor == sensor) { + i.remove() ; + break ; + } + } + listsDirty = true ; + } + + /** + * Returns an array of references to all sensors that have been bound + * to listeners. + * @return an array of sensors, or null if no sensors have been bound + */ + public Sensor[] getSensors() { + if (bindingsList.size() == 0) + return null ; + + Sensor[] s = new Sensor[bindingsList.size()] ; + for (int i = 0 ; i < bindingsList.size() ; i++) + s[i] = ((SensorBinding)bindingsList.get(i)).sensor ; + + return s ; + } + + /** + * Copies binding lists to arrays for event dispatch. This allows + * listeners to add or remove themselves or other listeners safely. + */ + private synchronized void updateArrays() { + bindings = (SensorBinding[])bindingsList.toArray + (new SensorBinding[bindingsList.size()]) ; + + for (int i = 0 ; i < bindings.length ; i++) { + bindings[i].updateArrays() ; + } + } + + /** + * Reads all sensor button state and dispatches events to registered + * button and read listeners. This method is intended to be called from + * the processStimulus implementation of a + * Behavior or the pollAndProcessInput method of + * an event-driven implementation of InputDevice. + */ + public void dispatchEvents() { + long t1 = t0 ; + t0 = J3DTimer.getValue() ; + + if (listsDirty) { + updateArrays() ; + listsDirty = false ; + } + + // Loop through all sensor bindings. + for (int k = 0 ; k < bindings.length ; k++) { + SensorBinding sb = bindings[k] ; + Sensor s = sb.sensor ; + Transform3D read = sb.read ; + int[] buttons = sb.buttons ; + int dragButton = 0 ; + boolean callReadListeners = true ; + boolean callDraggedListener = false ; + + // Get this sensor's readings. + s.getRead(read) ; + s.lastButtons(buttons) ; + + // Dispatch button listeners. + for (int j = 0 ; j < sb.buttonBindings.length ; j++) { + SensorButtonBinding sbb = sb.buttonBindings[j] ; + for (int i = 0 ; i < buttons.length ; i++) { + if (sbb.listeners[i] == null) + continue ; + + // Check for button release. + if (sbb.prevButtons[i]) { + if (buttons[i] == 0) { + e.set(source, SensorEvent.RELEASED, s, read, + buttons, i, t0, t1) ; + sbb.listeners[i].released(e) ; + sbb.prevButtons[i] = false ; + sbb.buttonsHandled-- ; + } + else { + callDraggedListener = true ; + dragButton = i ; + } + callReadListeners = false ; + } + // Check for button press. + // Ignore multiple button presses if not enabled; + // otherwise, one listener is bound to all buttons. + else if (buttons[i] == 1) { + if (sbb.buttonsHandled == 0 || sbb.multiButton) { + e.set(source, SensorEvent.PRESSED, s, read, + buttons, i, t0, t1) ; + sbb.listeners[i].pressed(e) ; + sbb.prevButtons[i] = true ; + sbb.buttonsHandled++ ; + callReadListeners = false ; + } + } + } + if (callDraggedListener) { + // One drag event even if multiple buttons down. + // Called after all pressed() and released() calls. + e.set(source, SensorEvent.DRAGGED, s, read, buttons, + SensorEvent.NOBUTTON, t0, t1) ; + sbb.listeners[dragButton].dragged(e) ; + } + } + // Dispatch read listeners. + if (callReadListeners) { + e.set(source, SensorEvent.READ, s, read, + buttons, SensorEvent.NOBUTTON, t0, t1) ; + for (int r = 0 ; r < sb.readBindings.length ; r++) { + sb.readBindings[r].read(e) ; + } + } + } + } + + public String toString() { + String s = "SensorEventAgent@" + Integer.toHexString(hashCode()) ; + s += "\nsensor bindings:\n\n" ; + for (int i = 0 ; i < bindingsList.size() ; i++) { + s += ((SensorBinding)bindingsList.get(i)).toString() + "\n" ; + } + return s ; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorGnomonEcho.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorGnomonEcho.java new file mode 100644 index 0000000..9a4f8db --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorGnomonEcho.java @@ -0,0 +1,225 @@ +/* + * $RCSfile: SensorGnomonEcho.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:15 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.sensor ; + +import javax.media.j3d.Shape3D ; +import javax.media.j3d.Material ; +import javax.media.j3d.Appearance ; +import javax.media.j3d.Transform3D ; +import javax.media.j3d.GeometryArray ; +import javax.media.j3d.TriangleArray ; +import javax.media.j3d.TransparencyAttributes; +import javax.vecmath.Point3f ; +import javax.vecmath.Vector3f ; + +/** + * A Shape3D representing a gnomon pointing along each coordinate + * axis. The base of the gnomon is a cube, and the coordinate axes are + * represented by pyramids attached to each face of the cube. + * + * @since Java 3D 1.3 + */ +public class SensorGnomonEcho extends Shape3D { + /** + * Constructs a SensorGnomonEcho. Read and write capabilities are + * granted for the Appearance, Material, TransparencyAttributes, + * and TransparencyAttributes mode and value. + * + * @param transform translation and/or rotation to apply to the gnomon + * geometry; this should be the position and orientation of the sensor + * hotspot in the sensor's local coordinate system + * @param baseWidth width of each edge of the base cube in meters + * @param axisLength distance in meters from the gnomon center to + * the apex of the pyramid attached to each face of the base cube + * @param enableLighting boolean indicating whether normals should be + * generated and lighting enabled + */ + public SensorGnomonEcho(Transform3D transform, + double baseWidth, + double axisLength, + boolean enableLighting) { + super() ; + + int FRONT = 0 ; + int BACK = 1 ; + int LEFT = 2 ; + int RIGHT = 3 ; + int TOP = 4 ; + int BOTTOM = 5 ; + Point3f[] axes = new Point3f[6] ; + float length = (float)axisLength ; + + axes[FRONT] = new Point3f(0f, 0f, length) ; + axes[BACK] = new Point3f(0f, 0f, -length) ; + axes[LEFT] = new Point3f(-length, 0f, 0f) ; + axes[RIGHT] = new Point3f( length, 0f, 0f) ; + axes[TOP] = new Point3f(0f, length, 0f) ; + axes[BOTTOM] = new Point3f(0f, -length, 0f) ; + + if (transform != null) + for (int i = FRONT ; i <= BOTTOM ; i++) + transform.transform(axes[i]) ; + + float offset = (float)baseWidth / 2.0f ; + Point3f[][] cube = new Point3f[6][4] ; + + cube[FRONT][0] = new Point3f(-offset, -offset, offset) ; + cube[FRONT][1] = new Point3f( offset, -offset, offset) ; + cube[FRONT][2] = new Point3f( offset, offset, offset) ; + cube[FRONT][3] = new Point3f(-offset, offset, offset) ; + + cube[BACK][0] = new Point3f( offset, -offset, -offset) ; + cube[BACK][1] = new Point3f(-offset, -offset, -offset) ; + cube[BACK][2] = new Point3f(-offset, offset, -offset) ; + cube[BACK][3] = new Point3f( offset, offset, -offset) ; + + if (transform != null) + for (int i = FRONT ; i <= BACK ; i++) + for (int j = 0 ; j < 4 ; j++) + transform.transform(cube[i][j]) ; + + cube[LEFT][0] = cube[BACK][1] ; + cube[LEFT][1] = cube[FRONT][0] ; + cube[LEFT][2] = cube[FRONT][3] ; + cube[LEFT][3] = cube[BACK][2] ; + + cube[RIGHT][0] = cube[FRONT][1] ; + cube[RIGHT][1] = cube[BACK][0] ; + cube[RIGHT][2] = cube[BACK][3] ; + cube[RIGHT][3] = cube[FRONT][2] ; + + cube[TOP][0] = cube[FRONT][3] ; + cube[TOP][1] = cube[FRONT][2] ; + cube[TOP][2] = cube[BACK][3] ; + cube[TOP][3] = cube[BACK][2] ; + + cube[BOTTOM][0] = cube[BACK][1] ; + cube[BOTTOM][1] = cube[BACK][0] ; + cube[BOTTOM][2] = cube[FRONT][1] ; + cube[BOTTOM][3] = cube[FRONT][0] ; + + int v = 0 ; + Point3f[] vertices = new Point3f[72] ; + + for (int i = 0 ; i < 6 ; i++) { + vertices[v++] = cube[i][0] ; + vertices[v++] = cube[i][1] ; + vertices[v++] = axes[i] ; + vertices[v++] = cube[i][1] ; + vertices[v++] = cube[i][2] ; + vertices[v++] = axes[i] ; + vertices[v++] = cube[i][2] ; + vertices[v++] = cube[i][3] ; + vertices[v++] = axes[i] ; + vertices[v++] = cube[i][3] ; + vertices[v++] = cube[i][0] ; + vertices[v++] = axes[i] ; + } + + int vertexFormat ; + Material m = new Material() ; + m.setCapability(Material.ALLOW_COMPONENT_READ) ; + m.setCapability(Material.ALLOW_COMPONENT_WRITE) ; + + if (enableLighting) { + vertexFormat = + GeometryArray.COORDINATES | GeometryArray.NORMALS ; + m.setLightingEnable(true) ; + } + else { + vertexFormat = GeometryArray.COORDINATES ; + m.setLightingEnable(false) ; + } + + TriangleArray ta = new TriangleArray(72, vertexFormat) ; + ta.setCoordinates(0, vertices) ; + + if (enableLighting) { + Vector3f v0 = new Vector3f() ; + Vector3f v1 = new Vector3f() ; + Vector3f[] normals = new Vector3f[72] ; + + for (int i = 0 ; i < 72 ; i += 3) { + v0.sub(vertices[i+1], vertices[i]) ; + v1.sub(vertices[i+2], vertices[i]) ; + + Vector3f n = new Vector3f() ; + n.cross(v0, v1) ; + n.normalize() ; + + normals[i] = n ; + normals[i+1] = n ; + normals[i+2] = n ; + } + ta.setNormals(0, normals) ; + } + + Appearance a = new Appearance() ; + a.setMaterial(m) ; + a.setCapability(Appearance.ALLOW_MATERIAL_READ) ; + a.setCapability(Appearance.ALLOW_MATERIAL_WRITE) ; + + TransparencyAttributes tra = new TransparencyAttributes() ; + tra.setCapability(TransparencyAttributes.ALLOW_MODE_READ) ; + tra.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE) ; + tra.setCapability(TransparencyAttributes.ALLOW_VALUE_READ) ; + tra.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE) ; + ta.setCapability + (TransparencyAttributes.ALLOW_BLEND_FUNCTION_READ) ; + ta.setCapability + (TransparencyAttributes.ALLOW_BLEND_FUNCTION_WRITE) ; + + a.setTransparencyAttributes(tra) ; + a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ) ; + a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE) ; + + setGeometry(ta) ; + setAppearance(a) ; + + setCapability(ALLOW_APPEARANCE_READ) ; + setCapability(ALLOW_APPEARANCE_WRITE) ; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorInputAdaptor.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorInputAdaptor.java new file mode 100644 index 0000000..70a705f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorInputAdaptor.java @@ -0,0 +1,71 @@ +/* + * $RCSfile: SensorInputAdaptor.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:15 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.sensor ; + +/** + * The adaptor which receives sensor button and read events. The methods + * in this class are empty; the ones of interest should be overridden by + * classes extending this adaptor. + * + * @since Java 3D 1.3 + */ +public class SensorInputAdaptor + implements SensorButtonListener, SensorReadListener { + + public void pressed(SensorEvent e) { + } + + public void released(SensorEvent e) { + } + + public void dragged(SensorEvent e) { + } + + public void clicked(SensorEvent e) { + } + + public void read(SensorEvent e) { + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorReadListener.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorReadListener.java new file mode 100644 index 0000000..c57f589 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorReadListener.java @@ -0,0 +1,72 @@ +/* + * $RCSfile: SensorReadListener.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:15 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.sensor ; + +/** + * This defines the interface for handling a sensor's read events in + * conjuction with a SensorEventAgent instance. + *

+ * The events passed to this listener's methods are ephemeral; they + * are only valid until the listener has returned. If a listener needs to + * retain the event it must be copied using the + * SensorEvent(SensorEvent) constructor. + * + * @see SensorEvent + * @see SensorEventAgent + * @see SensorButtonListener + * @since Java 3D 1.3 + */ +public interface SensorReadListener { + /** + * This method is called each time the dispatchEvents + * method of SensorEventAgent is called and none of a + * sensor's buttons have been handled by a button listener. The + * sensor read value has not necessarily changed since the last read + * event. + * + * @param e the sensor event + */ + public void read(SensorEvent e) ; +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/package.html new file mode 100644 index 0000000..25c9b13 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/sensor/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.behaviors.sensor + + +

Provides 6DOF sensor behavior classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/OrbitBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/OrbitBehavior.java new file mode 100644 index 0000000..e0f0f30 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/OrbitBehavior.java @@ -0,0 +1,1079 @@ +/* + * $RCSfile: OrbitBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/10/08 23:08:02 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.vp; + +import java.awt.event.MouseEvent; +import java.awt.AWTEvent; + +import javax.media.j3d.Transform3D; +import javax.media.j3d.Canvas3D; + +import javax.vecmath.Vector3d; +import javax.vecmath.Point3d; +import javax.vecmath.Matrix3d; + +import com.sun.j3d.utils.universe.ViewingPlatform; + +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * Moves the View around a point of interest when the mouse is dragged with + * a mouse button pressed. Includes rotation, zoom, and translation + * actions. Zooming can also be obtained by using mouse wheel. + *

+ * This behavior must be added to the ViewingPlatform + * using the ViewingPlatform.setViewPlatformBehavior method. + *

+ * The rotate action rotates the ViewPlatform around the point of interest + * when the mouse is moved with the main mouse button pressed. The + * rotation is in the direction of the mouse movement, with a default + * rotation of 0.01 radians for each pixel of mouse movement. + *

+ * The zoom action moves the ViewPlatform closer to or further from the + * point of interest when the mouse is moved with the middle mouse button + * pressed (or Alt-main mouse button on systems without a middle mouse button). + * The default zoom action is to translate the ViewPlatform 0.01 units for each + * pixel of mouse movement. Moving the mouse up moves the ViewPlatform closer, + * moving the mouse down moves the ViewPlatform further away. + *

+ * By default, the zoom action allows the ViewPlatform to move through + * the center of rotation to orbit at a negative radius. + * The STOP_ZOOM constructor flag will stop the ViewPlatform at + * a minimum radius from the center. The default minimum radius is 0.0 + * and can be set using the setMinRadius method. + *

+ * The PROPORTIONAL_ZOOM constructor flag changes the zoom action + * to move the ViewPlatform proportional to its distance from the center + * of rotation. For this mode, the default action is to move the ViewPlatform + * by 1% of its distance from the center of rotation for each pixel of + * mouse movement. + *

+ * The translate action translates the ViewPlatform when the mouse is moved + * with the right mouse button pressed (Shift-main mouse button on systems + * without a right mouse button). The translation is in the direction of the + * mouse movement, with a default translation of 0.01 units for each pixel + * of mouse movement. + *

+ * The sensitivity of the actions can be scaled using the + * setActionFactor() methods which scale + * the default movement by the factor. The rotate and translate actions + * have separate factors for x and y. + *

+ * The actions can be reversed using the REVERSE_ACTION + * constructor flags. The default action moves the ViewPlatform around the + * objects in the scene. The REVERSE_ACTION flags can + * make the objects in the scene appear to be moving in the direction + * of the mouse movement. + *

+ * The actions can be disabled by either using the + * DISABLE_ACTION constructor flags or the + * setActionEnable methods. + *

+ * The default center of rotation is (0, 0, 0) and can be set using the + * setRotationCenter() method. + * + * @since Java 3D 1.2.1 + */ +public class OrbitBehavior extends ViewPlatformAWTBehavior { + + private Transform3D longditudeTransform = new Transform3D(); + private Transform3D latitudeTransform = new Transform3D(); + private Transform3D rotateTransform = new Transform3D(); + + // needed for integrateTransforms but don't want to new every time + private Transform3D temp1 = new Transform3D(); + private Transform3D temp2 = new Transform3D(); + private Transform3D translation = new Transform3D(); + private Vector3d transVector = new Vector3d(); + private Vector3d distanceVector = new Vector3d(); + private Vector3d centerVector = new Vector3d(); + private Vector3d invertCenterVector = new Vector3d(); + + private double longditude = 0.0; + private double latitude = 0.0; + private double startDistanceFromCenter = 20.0; + private double distanceFromCenter = 20.0; + private Point3d rotationCenter = new Point3d(); + private Matrix3d rotMatrix = new Matrix3d(); + private Transform3D currentXfm = new Transform3D(); + + private int mouseX = 0; + private int mouseY = 0; + + private double rotXFactor = 1.0; + private double rotYFactor = 1.0; + private double transXFactor = 1.0; + private double transYFactor = 1.0; + private double zoomFactor = 1.0; + + private double xtrans = 0.0; + private double ytrans = 0.0; + private double ztrans = 0.0; + + private boolean zoomEnabled = true; + private boolean rotateEnabled = true; + private boolean translateEnabled = true; + private boolean reverseRotate = false; + private boolean reverseTrans = false; + private boolean reverseZoom = false; + private boolean stopZoom = false; + private boolean proportionalZoom = false; + private double minRadius = 0.0; + private int leftButton = ROTATE; + private int rightButton = TRANSLATE; + private int middleButton = ZOOM; + + // the factor to be applied to wheel zooming so that it does not + // look much different with mouse movement zooming. + // This is a totally subjective factor. + private float wheelZoomFactor = 50.0f; + + /** + * Constructor flag to reverse the rotate behavior + */ + public static final int REVERSE_ROTATE = 0x010; + + /** + * Constructor flag to reverse the translate behavior + */ + public static final int REVERSE_TRANSLATE = 0x020; + + /** + * Constructor flag to reverse the zoom behavior + */ + public static final int REVERSE_ZOOM = 0x040; + + /** + * Constructor flag to reverse all the behaviors + */ + public static final int REVERSE_ALL = (REVERSE_ROTATE | REVERSE_TRANSLATE | + REVERSE_ZOOM); + + /** + * Constructor flag that indicates zoom should stop when it reaches + * the minimum orbit radius set by setMinRadius(). The minimus + * radius default is 0.0. + */ + public static final int STOP_ZOOM = 0x100; + + /** + * Constructor flag to disable rotate + */ + public static final int DISABLE_ROTATE = 0x200; + + /** + * Constructor flag to disable translate + */ + public static final int DISABLE_TRANSLATE = 0x400; + + /** + * Constructor flag to disable zoom + */ + public static final int DISABLE_ZOOM = 0x800; + + /** + * Constructor flag to use proportional zoom, which determines + * how much you zoom based on view's distance from the center of + * rotation. The percentage of distance that the viewer zooms + * is determined by the zoom factor. + */ + public static final int PROPORTIONAL_ZOOM = 0x1000; + + /** + * Used to set the fuction for a mouse button to Rotate + */ + private static final int ROTATE = 0; + + /** + * Used to set the function for a mouse button to Translate + */ + private static final int TRANSLATE = 1; + + /** + * Used to set the function for a mouse button to Zoom + */ + private static final int ZOOM = 2; + + private static final double NOMINAL_ZOOM_FACTOR = .01; + private static final double NOMINAL_PZOOM_FACTOR = 1.0; + private static final double NOMINAL_ROT_FACTOR = .01; + private static final double NOMINAL_TRANS_FACTOR = .01; + + private double rotXMul = NOMINAL_ROT_FACTOR * rotXFactor; + private double rotYMul = NOMINAL_ROT_FACTOR * rotYFactor; + private double transXMul = NOMINAL_TRANS_FACTOR * transXFactor; + private double transYMul = NOMINAL_TRANS_FACTOR * transYFactor; + private double zoomMul = NOMINAL_ZOOM_FACTOR * zoomFactor; + + /** + * Parameterless constructor for this behavior. This is intended for use + * by ConfiguredUniverse, which requires such a constructor for + * configurable behaviors. The Canvas3D used to listen for mouse and + * mouse motion events is obtained from the superclass + * setViewingPlatform() method. + * @since Java 3D 1.3 + */ + public OrbitBehavior() { + super(MOUSE_LISTENER | MOUSE_MOTION_LISTENER | MOUSE_WHEEL_LISTENER); + } + + /** + * Creates a new OrbitBehavior + * + * @param c The Canvas3D to add the behavior to + */ + public OrbitBehavior(Canvas3D c) { + this(c, 0 ); + } + + /** + * Creates a new OrbitBehavior + * + * @param c The Canvas3D to add the behavior to + * @param flags The option flags + */ + public OrbitBehavior(Canvas3D c, int flags) { + super(c, MOUSE_LISTENER | MOUSE_MOTION_LISTENER | MOUSE_WHEEL_LISTENER | flags ); + + if ((flags & DISABLE_ROTATE) != 0) rotateEnabled = false; + if ((flags & DISABLE_ZOOM) != 0) zoomEnabled = false; + if ((flags & DISABLE_TRANSLATE) != 0) translateEnabled = false; + if ((flags & REVERSE_TRANSLATE) != 0) reverseTrans = true; + if ((flags & REVERSE_ROTATE) != 0) reverseRotate = true; + if ((flags & REVERSE_ZOOM) != 0) reverseZoom = true; + if ((flags & STOP_ZOOM) != 0) stopZoom = true; + if ((flags & PROPORTIONAL_ZOOM) !=0) { + proportionalZoom = true; + zoomMul = NOMINAL_PZOOM_FACTOR * zoomFactor; + } + } + + protected synchronized void processAWTEvents( final AWTEvent[] events ) { + motion = false; + for(int i=0; i + minRadius) { + distanceFromCenter -= (zoomMul*ychange* + distanceFromCenter/100.0); + } + else { + distanceFromCenter = minRadius; + } + } + else { + if ((distanceFromCenter + + (zoomMul*ychange*distanceFromCenter/100.0)) + > minRadius) { + distanceFromCenter += (zoomMul*ychange* + distanceFromCenter/100.0); + } + else { + distanceFromCenter = minRadius; + } + } + } + else { + if (stopZoom) { + if (reverseZoom) { + if ((distanceFromCenter - ychange*zoomMul) > minRadius) { + distanceFromCenter -= ychange*zoomMul; + } + else { + distanceFromCenter = minRadius; + } + } + else { + if ((distanceFromCenter + ychange*zoomMul) > minRadius) { + distanceFromCenter += ychange * zoomMul; + } + else { + distanceFromCenter = minRadius; + } + } + } + else { + if (reverseZoom) { + distanceFromCenter -= ychange*zoomMul; + } + else { + distanceFromCenter += ychange*zoomMul; + } + } + } + } + + + + /** + * Sets the ViewingPlatform for this behavior. This method is + * called by the ViewingPlatform. + * If a sub-calls overrides this method, it must call + * super.setViewingPlatform(vp). + * NOTE: Applications should not call this method. + */ + @Override + public void setViewingPlatform(ViewingPlatform vp) { + super.setViewingPlatform( vp ); + + if (vp!=null) { + resetView(); + integrateTransforms(); + } + } + + /** + * Reset the orientation and distance of this behavior to the current + * values in the ViewPlatform Transform Group + */ + private void resetView() { + Vector3d centerToView = new Vector3d(); + + targetTG.getTransform( targetTransform ); + + targetTransform.get( rotMatrix, transVector ); + centerToView.sub( transVector, rotationCenter ); + distanceFromCenter = centerToView.length(); + startDistanceFromCenter = distanceFromCenter; + + targetTransform.get( rotMatrix ); + rotateTransform.set( rotMatrix ); + + // compute the initial x/y/z offset + temp1.set(centerToView); + rotateTransform.invert(); + rotateTransform.mul(temp1); + rotateTransform.get(centerToView); + xtrans = centerToView.x; + ytrans = centerToView.y; + ztrans = centerToView.z; + + // reset rotMatrix + rotateTransform.set( rotMatrix ); + } + + protected synchronized void integrateTransforms() { + // Check if the transform has been changed by another + // behavior + targetTG.getTransform(currentXfm) ; + if (! targetTransform.equals(currentXfm)) + resetView() ; + + longditudeTransform.rotY( longditude ); + latitudeTransform.rotX( latitude ); + rotateTransform.mul(rotateTransform, latitudeTransform); + rotateTransform.mul(rotateTransform, longditudeTransform); + + distanceVector.z = distanceFromCenter - startDistanceFromCenter; + + temp1.set(distanceVector); + temp1.mul(rotateTransform, temp1); + + // want to look at rotationCenter + transVector.x = rotationCenter.x + xtrans; + transVector.y = rotationCenter.y + ytrans; + transVector.z = rotationCenter.z + ztrans; + + translation.set(transVector); + targetTransform.mul(temp1, translation); + + // handle rotationCenter + temp1.set(centerVector); + temp1.mul(targetTransform); + + invertCenterVector.x = -centerVector.x; + invertCenterVector.y = -centerVector.y; + invertCenterVector.z = -centerVector.z; + + temp2.set(invertCenterVector); + targetTransform.mul(temp1, temp2); + + targetTG.setTransform(targetTransform); + + // reset yaw and pitch angles + longditude = 0.0; + latitude = 0.0; + } + + /** + * Sets the center around which the View rotates. + * The default is (0,0,0). + * @param center The Point3d to set the center of rotation to + */ + public synchronized void setRotationCenter(Point3d center) { + Point3d centerDelta = new Point3d(); + centerDelta.sub(centerVector, center); + Transform3D invRot = new Transform3D(rotateTransform); + invRot.invert(); + invRot.transform(centerDelta); + xtrans += centerDelta.x; + ytrans += centerDelta.y; + ztrans += centerDelta.z; + rotationCenter.x = center.x; + rotationCenter.y = center.y; + rotationCenter.z = center.z; + centerVector.set(rotationCenter); + } + + /** + * Property which sets the center around which the View rotates. + * Used by ConfiguredUniverse. + * @param center array of length 1 containing an instance of Point3d + * @since Java 3D 1.3 + */ + public void RotationCenter(Object[] center) { + if (! (center.length == 1 && center[0] instanceof Point3d)) + throw new IllegalArgumentException + ("RotationCenter must be a single Point3d"); + + setRotationCenter((Point3d)center[0]); + } + + /** + * Places the value of the center around which the View rotates + * into the Point3d. + * @param center The Point3d + */ + public void getRotationCenter(Point3d center) { + center.x = rotationCenter.x; + center.y = rotationCenter.y; + center.z = rotationCenter.z; + } + + // TODO + // Need to add key factors for Rotate, Translate and Zoom + // Method calls should just update MAX_KEY_ANGLE, KEY_TRANSLATE and + // KEY_ZOOM + // + // Methods also need to correctly set sign of variables depending on + // the Reverse settings. + + /** + * Sets the rotation x and y factors. The factors are used to determine + * how many radians to rotate the view for each pixel of mouse movement. + * The view is rotated factor * 0.01 radians for each pixel of mouse + * movement. The default factor is 1.0. + * @param xfactor The x movement multiplier + * @param yfactor The y movement multiplier + **/ + public synchronized void setRotFactors(double xfactor, double yfactor) { + rotXFactor = xfactor; + rotYFactor = yfactor; + rotXMul = NOMINAL_ROT_FACTOR * xfactor; + rotYMul = NOMINAL_ROT_FACTOR * yfactor; + } + + /** + * Property which sets the rotation x and y factors. + * Used by ConfiguredUniverse. + * @param factors array of length 2 containing instances of Double + * @since Java 3D 1.3 + */ + public void RotFactors(Object[] factors) { + if (! (factors.length == 2 && + factors[0] instanceof Double && factors[1] instanceof Double)) + throw new IllegalArgumentException + ("RotFactors must be two Doubles"); + + setRotFactors(((Double)factors[0]).doubleValue(), + ((Double)factors[1]).doubleValue()); + } + + /** + * Sets the rotation x factor. The factors are used to determine + * how many radians to rotate the view for each pixel of mouse movement. + * The view is rotated factor * 0.01 radians for each pixel of mouse + * movement. The default factor is 1.0. + * @param xfactor The x movement multiplier + **/ + public synchronized void setRotXFactor(double xfactor) { + rotXFactor = xfactor; + rotXMul = NOMINAL_ROT_FACTOR * xfactor; + } + + /** + * Property which sets the rotation x factor. + * Used by ConfiguredUniverse. + * @param xFactor array of length 1 containing instance of Double + * @since Java 3D 1.3 + */ + public void RotXFactor(Object[] xFactor) { + if (! (xFactor.length == 1 && xFactor[0] instanceof Double)) + throw new IllegalArgumentException("RotXFactor must be a Double"); + + setRotXFactor(((Double)xFactor[0]).doubleValue()); + } + + /** + * Sets the rotation y factor. The factors are used to determine + * how many radians to rotate the view for each pixel of mouse movement. + * The view is rotated factor * 0.01 radians for each pixel of mouse + * movement. The default factor is 1.0. + * @param yfactor The y movement multiplier + **/ + public synchronized void setRotYFactor(double yfactor) { + rotYFactor = yfactor; + rotYMul = NOMINAL_ROT_FACTOR * yfactor; + } + + /** + * Property which sets the rotation y factor. + * Used by ConfiguredUniverse. + * @param yFactor array of length 1 containing instance of Double + * @since Java 3D 1.3 + */ + public void RotYFactor(Object[] yFactor) { + if (! (yFactor.length == 1 && yFactor[0] instanceof Double)) + throw new IllegalArgumentException("RotYFactor must be a Double"); + + setRotYFactor(((Double)yFactor[0]).doubleValue()); + } + + /** + * Sets the translation x and y factors. The factors are used to determine + * how many units to translate the view for each pixel of mouse movement. + * The view is translated factor * 0.01 units for each pixel of mouse + * movement. The default factor is 1.0. + * @param xfactor The x movement multiplier + * @param yfactor The y movement multiplier + **/ + public synchronized void setTransFactors(double xfactor, + double yfactor) { + transXFactor = xfactor; + transYFactor = yfactor; + transXMul = NOMINAL_TRANS_FACTOR * xfactor; + transYMul = NOMINAL_TRANS_FACTOR * yfactor; + } + + /** + * Property which sets the translation x and y factors. + * Used by ConfiguredUniverse. + * @param factors array of length 2 containing instances of Double + * @since Java 3D 1.3 + */ + public void TransFactors(Object[] factors) { + if (! (factors.length == 2 && + factors[0] instanceof Double && factors[1] instanceof Double)) + throw new IllegalArgumentException + ("TransFactors must be two Doubles"); + + setTransFactors(((Double)factors[0]).doubleValue(), + ((Double)factors[1]).doubleValue()); + } + + /** + * Sets the translation x factor. The factors are used to determine + * how many units to translate the view for each pixel of mouse movement. + * The view is translated factor * 0.01 units for each pixel of mouse + * movement. The default factor is 1.0. + * @param xfactor The x movement multiplier + **/ + public synchronized void setTransXFactor(double xfactor) { + transXFactor = xfactor; + transXMul = NOMINAL_TRANS_FACTOR * xfactor; + } + + /** + * Property which sets the translation x factor. + * Used by ConfiguredUniverse. + * @param xFactor array of length 1 containing instance of Double + * @since Java 3D 1.3 + */ + public void TransXFactor(Object[] xFactor) { + if (! (xFactor.length == 1 && xFactor[0] instanceof Double)) + throw new IllegalArgumentException("TransXFactor must be a Double"); + + setTransXFactor(((Double)xFactor[0]).doubleValue()); + } + + /** + * Sets the translation y factor. The factors are used to determine + * how many units to translate the view for each pixel of mouse movement. + * The view is translated factor * 0.01 units for each pixel of mouse + * movement. The default factor is 1.0. + * @param yfactor The y movement multiplier + **/ + public synchronized void setTransYFactor(double yfactor) { + transYFactor = yfactor; + transYMul = NOMINAL_TRANS_FACTOR * yfactor; + } + + /** + * Property which sets the translation y factor. + * Used by ConfiguredUniverse. + * @param yFactor array of length 1 containing instance of Double + * @since Java 3D 1.3 + */ + public void TransYFactor(Object[] yFactor) { + if (! (yFactor.length == 1 && yFactor[0] instanceof Double)) + throw new IllegalArgumentException("TransYFactor must be a Double"); + + setTransYFactor(((Double)yFactor[0]).doubleValue()); + } + + /** + * Sets the zoom factor. The factor is used to determine how many + * units to zoom the view for each pixel of mouse movement. + * The view is zoomed factor * 0.01 units for each pixel of mouse + * movement. For proportional zoom, the view is zoomed factor * 1% + * of the distance from the center of rotation for each pixel of + * mouse movement. The default factor is 1.0. + * @param zfactor The movement multiplier + */ + public synchronized void setZoomFactor(double zfactor) { + zoomFactor = zfactor; + if (proportionalZoom) { + zoomMul = NOMINAL_PZOOM_FACTOR * zfactor; + } + else { + zoomMul = NOMINAL_ZOOM_FACTOR * zfactor; + } + } + + /** + * Property which sets the zoom factor. + * Used by ConfiguredUniverse. + * @param zFactor array of length 1 containing instance of Double + * @since Java 3D 1.3 + */ + public void ZoomFactor(Object[] zFactor) { + if (! (zFactor.length == 1 && zFactor[0] instanceof Double)) + throw new IllegalArgumentException("ZoomFactor must be a Double"); + + setZoomFactor(((Double)zFactor[0]).doubleValue()); + } + + /** + * Returns the x rotation movement multiplier + * @return The movement multiplier for x rotation + */ + public double getRotXFactor() { + return rotXFactor; + } + + /** + * Returns the y rotation movement multiplier + * @return The movement multiplier for y rotation + */ + public double getRotYFactor() { + return rotYFactor; + } + + /** + * Returns the x translation movement multiplier + * @return The movement multiplier for x translation + */ + public double getTransXFactor() { + return transXFactor; + } + + /** + * Returns the y translation movement multiplier + * @return The movement multiplier for y translation + */ + public double getTransYFactor() { + return transYFactor; + } + + /** + * Returns the zoom movement multiplier + * @return The movement multiplier for zoom + */ + public double getZoomFactor() { + return zoomFactor; + } + + /** + * Enables or disables rotation. The default is true. + * @param enabled true or false to enable or disable rotate + */ + public synchronized void setRotateEnable(boolean enabled) { + rotateEnabled = enabled; + } + + /** + * Property which enables or disables rotation. + * Used by ConfiguredUniverse. + * @param enabled array of length 1 containing instance of Boolean + * @since Java 3D 1.3 + */ + public void RotateEnable(Object[] enabled) { + if (! (enabled.length == 1 && enabled[0] instanceof Boolean)) + throw new IllegalArgumentException("RotateEnable must be Boolean"); + + setRotateEnable(((Boolean)enabled[0]).booleanValue()); + } + + /** + * Enables or disables zoom. The default is true. + * @param enabled true or false to enable or disable zoom + */ + public synchronized void setZoomEnable(boolean enabled) { + zoomEnabled = enabled; + } + + /** + * Property which enables or disables zoom. + * Used by ConfiguredUniverse. + * @param enabled array of length 1 containing instance of Boolean + * @since Java 3D 1.3 + */ + public void ZoomEnable(Object[] enabled) { + if (! (enabled.length == 1 && enabled[0] instanceof Boolean)) + throw new IllegalArgumentException("ZoomEnable must be Boolean"); + + setZoomEnable(((Boolean)enabled[0]).booleanValue()); + } + + /** + * Enables or disables translate. The default is true. + * @param enabled true or false to enable or disable translate + */ + public synchronized void setTranslateEnable(boolean enabled) { + translateEnabled = enabled; + } + + /** + * Property which enables or disables translate. + * Used by ConfiguredUniverse. + * @param enabled array of length 1 containing instance of Boolean + * @since Java 3D 1.3 + */ + public void TranslateEnable(Object[] enabled) { + if (! (enabled.length == 1 && enabled[0] instanceof Boolean)) + throw new IllegalArgumentException + ("TranslateEnable must be Boolean"); + + setTranslateEnable(((Boolean)enabled[0]).booleanValue()); + } + + /** + * Retrieves the state of rotate enabled + * @return the rotate enable state + */ + public boolean getRotateEnable() { + return rotateEnabled; + } + + /** + * Retrieves the state of zoom enabled + * @return the zoom enable state + */ + public boolean getZoomEnable() { + return zoomEnabled; + } + + /** + * Retrieves the state of translate enabled + * @return the translate enable state + */ + public boolean getTranslateEnable() { + return translateEnabled; + } + + boolean rotate(MouseEvent evt) { + if (rotateEnabled) { + if ((leftButton == ROTATE) && + (!evt.isAltDown() && !evt.isMetaDown())) { + return true; + } + if ((middleButton == ROTATE) && + (evt.isAltDown() && !evt.isMetaDown())) { + return true; + } + if ((rightButton == ROTATE) && + (!evt.isAltDown() && evt.isMetaDown())) { + return true; + } + } + return false; + } + + boolean zoom(MouseEvent evt) { + if (zoomEnabled) { + if (evt instanceof java.awt.event.MouseWheelEvent) { + return true; + } + if ((leftButton == ZOOM) && + (!evt.isAltDown() && !evt.isMetaDown())) { + return true; + } + if ((middleButton == ZOOM) && + (evt.isAltDown() && !evt.isMetaDown())) { + return true; + } + if ((rightButton == ZOOM) && + (!evt.isAltDown() && evt.isMetaDown())) { + return true; + } + } + return false; + } + + boolean translate(MouseEvent evt) { + if (translateEnabled) { + if ((leftButton == TRANSLATE) && + (!evt.isAltDown() && !evt.isMetaDown())) { + return true; + } + if ((middleButton == TRANSLATE) && + (evt.isAltDown() && !evt.isMetaDown())) { + return true; + } + if ((rightButton == TRANSLATE) && + (!evt.isAltDown() && evt.isMetaDown())) { + return true; + } + } + return false; + } + + /** + * Sets the minimum radius for the OrbitBehavior. The zoom will + * stop at this distance from the center of rotation. The default + * is 0.0. The minimum will have no affect if the STOP_ZOOM constructor + * flag is not set. + * @param r the minimum radius + * @exception IllegalArgumentException if the radius is less than 0.0 + */ + public synchronized void setMinRadius(double r) { + if (r < 0.0) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("OrbitBehavior1")); + } + minRadius = r; + } + + /** + * Property which sets the minimum radius for the OrbitBehavior. + * Used by ConfiguredUniverse. + * @param r array of length 1 containing instance of Double + * @since Java 3D 1.3 + */ + public void MinRadius(Object[] r) { + if (! (r.length == 1 && r[0] instanceof Double)) + throw new IllegalArgumentException("MinRadius must be a Double"); + + setMinRadius(((Double)r[0]).doubleValue()); + } + + /** + * Returns the minimum orbit radius. The zoom will stop at this distance + * from the center of rotation if the STOP_ZOOM constructor flag is set. + * @return the minimum radius + */ + public double getMinRadius() { + return minRadius; + } + + /** + * Set reverse translate behavior. The default is false. + * @param state if true, reverse translate behavior + * @since Java 3D 1.3 + */ + public void setReverseTranslate(boolean state) { + reverseTrans = state; + } + + /** + * Property which sets reverse translate behavior. + * Used by ConfiguredUniverse. + * @param state array of length 1 containing instance of Boolean + * @since Java 3D 1.3 + */ + public void ReverseTranslate(Object[] state) { + if (! (state.length == 1 && state[0] instanceof Boolean)) + throw new IllegalArgumentException + ("ReverseTranslate must be Boolean"); + + setReverseTranslate(((Boolean)state[0]).booleanValue()); + } + + /** + * Set reverse rotate behavior. The default is false. + * @param state if true, reverse rotate behavior + * @since Java 3D 1.3 + */ + public void setReverseRotate(boolean state) { + reverseRotate = state; + } + + /** + * Property which sets reverse rotate behavior. + * Used by ConfiguredUniverse. + * @param state array of length 1 containing instance of Boolean + * @since Java 3D 1.3 + */ + public void ReverseRotate(Object[] state) { + if (! (state.length == 1 && state[0] instanceof Boolean)) + throw new IllegalArgumentException("ReverseRotate must be Boolean"); + + setReverseRotate(((Boolean)state[0]).booleanValue()); + } + + /** + * Set reverse zoom behavior. The default is false. + * @param state if true, reverse zoom behavior + * @since Java 3D 1.3 + */ + public void setReverseZoom(boolean state) { + reverseZoom = state; + } + + /** + * Property which sets reverse zoom behavior. + * Used by ConfiguredUniverse. + * @param state array of length 1 containing instance of Boolean + * @since Java 3D 1.3 + */ + public void ReverseZoom(Object[] state) { + if (! (state.length == 1 && state[0] instanceof Boolean)) + throw new IllegalArgumentException("ReverseZoom must be Boolean"); + + setReverseZoom(((Boolean)state[0]).booleanValue()); + } + + /** + * Set proportional zoom behavior. The default is false. + * @param state if true, use proportional zoom behavior + * @since Java 3D 1.3 + */ + public synchronized void setProportionalZoom(boolean state) { + proportionalZoom = state; + + if (state) { + zoomMul = NOMINAL_PZOOM_FACTOR * zoomFactor; + } + else { + zoomMul = NOMINAL_ZOOM_FACTOR * zoomFactor; + } + } + + /** + * Property which sets proportional zoom behavior. + * Used by ConfiguredUniverse. + * @param state array of length 1 containing instance of Boolean + * @since Java 3D 1.3 + */ + public void ProportionalZoom(Object[] state) { + if (! (state.length == 1 && state[0] instanceof Boolean)) + throw new IllegalArgumentException + ("ProportionalZoom must be Boolean"); + + setProportionalZoom(((Boolean)state[0]).booleanValue()); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformAWTBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformAWTBehavior.java new file mode 100644 index 0000000..ce1f79d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformAWTBehavior.java @@ -0,0 +1,417 @@ +/* + * $RCSfile: ViewPlatformAWTBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:15 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.vp; + +import java.awt.event.ComponentEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseWheelListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.KeyListener; +import java.awt.event.KeyEvent; +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Cursor; +import javax.swing.SwingUtilities; +import java.util.ArrayList; + +import javax.media.j3d.WakeupOnBehaviorPost; +import javax.media.j3d.WakeupOnElapsedFrames; +import javax.media.j3d.WakeupOr; +import javax.media.j3d.WakeupCriterion; +import javax.media.j3d.WakeupCondition; +import javax.media.j3d.TransformGroup; +import javax.media.j3d.Transform3D; +import javax.media.j3d.View; +import javax.media.j3d.Canvas3D; + +import javax.vecmath.Vector3f; +import com.sun.j3d.utils.universe.*; + + +/** + * Abstract class which implements much of the event tracking and + * state updating in a thread safe manner. + * + * AWT Events are captured and placed in a queue. + * + * While there are pending events or motion the behavior will wake + * up every frame, call processAWTEvents and integrateTransforms. + * + * @since Java 3D 1.2.1 + */ +public abstract class ViewPlatformAWTBehavior extends ViewPlatformBehavior +implements MouseListener, MouseMotionListener, KeyListener, MouseWheelListener { + + private final static boolean DEBUG = false; + + /** + * Behavior PostId used in this behavior + */ + protected final static int POST_ID = 9998; + + /** + * The different criterion for the behavior to wakeup + */ + protected WakeupOnElapsedFrames frameWakeup; + + /** + * The Or of the different criterion for the behavior to wakeup + */ + protected WakeupOnBehaviorPost postWakeup; + + /** + * The target Transform3D for this behavior + */ + protected Transform3D targetTransform = new Transform3D(); + + /** + * Boolean for whether the mouse is in motion + */ + protected boolean motion = false; + + /** + * Flag indicating Behavior should listen for Mouse Events + */ + public final static int MOUSE_LISTENER = 0x01; + + /** + * Flag indicating Behavior should listen for Mouse Motion Events + */ + public final static int MOUSE_MOTION_LISTENER = 0x02; + + /** + * Flag indicating Behavior should listen for Key Events + */ + public final static int KEY_LISTENER = 0x04; + + /** + * Flag indicating Behavior should listen for MouseWheel Events + */ + public final static int MOUSE_WHEEL_LISTENER = 0x08; + + /** + * The Canvas3Ds from which this Behavior gets AWT events + */ + protected Canvas3D canvases[]; + + private ArrayList eventQueue = new ArrayList(); + private int listenerFlags = 0; + private boolean firstEvent = false; + + /** + * Parameterless constructor for this behavior, intended for use by + * subclasses instantiated through ConfiguredUniverse. Such a constructor + * is required for configurable behaviors. + * @since Java 3D 1.3 + */ + protected ViewPlatformAWTBehavior() { + super(); + } + + /** + * Construct a behavior which listens for events specified by the given + * flags, intended for use by subclasses instantiated through + * ConfiguredUniverse. + * + * @param listenerFlags Indicates which listener should be registered, + * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER + * @since Java 3D 1.3 + */ + protected ViewPlatformAWTBehavior(int listenerFlags) { + super(); + setListenerFlags(listenerFlags); + } + + /** + * Constructs a new ViewPlatformAWTBehavior. + * + * @param c The Canvas3D on which to listen for events. If this is null a + * NullPointerException will be thrown. + * @param listenerFlags Indicates which listener should be registered, + * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER + */ + public ViewPlatformAWTBehavior(Canvas3D c, int listenerFlags ) { + super(); + + if (c == null) + throw new NullPointerException(); + + canvases = new Canvas3D[] { c }; + setListenerFlags(listenerFlags); + } + + /** + * Sets listener flags for this behavior. + * + * @param listenerFlags Indicates which listener should be registered, + * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER + * @since Java 3D 1.3 + */ + protected void setListenerFlags(int listenerFlags) { + this.listenerFlags = listenerFlags; + } + + /** + * Initializes the behavior. + * NOTE: Applications should not call this method. It is called by the + * Java 3D behavior scheduler. + */ + public void initialize() { + frameWakeup = new WakeupOnElapsedFrames( 0 ); + postWakeup = new WakeupOnBehaviorPost( this, POST_ID ); + + wakeupOn(postWakeup); + } + + /** + * Process a stimulus meant for this behavior. + * NOTE: Applications should not call this method. It is called by the + * Java 3D behavior scheduler. + */ + public void processStimulus( java.util.Enumeration behEnum ) { + boolean hadPost = false; + + while(behEnum.hasMoreElements()) { + WakeupCondition wakeup = (WakeupCondition)behEnum.nextElement(); + if (wakeup instanceof WakeupOnBehaviorPost) { + hadPost = true; + } else if (wakeup instanceof WakeupOnElapsedFrames) { + AWTEvent[] events = null; + // access to event queue must be synchronized + synchronized(eventQueue) { + events = (AWTEvent[])eventQueue.toArray( new AWTEvent[eventQueue.size()] ); + eventQueue.clear(); + } + processAWTEvents(events); + + if (motion) + integrateTransforms(); + } + } + + if (motion || hadPost) { + // wake up on behavior posts and elapsed frames if in motion + wakeupOn( frameWakeup ); + } else { + // only wake up on behavior posts if not in motion + wakeupOn( postWakeup ); + } + } + + /** + * Overload setEnable from Behavior. + * + * Adds/Removes the AWT listeners depending on the requested + * state. + */ + public void setEnable( boolean state ) { + if (state==getEnable()) + return; + + super.setEnable(state); + + if (canvases != null) { + enableListeners(state); + } + } + + private void enableListeners( boolean enable ) { + if (enable) { + firstEvent = true ; + if ( (listenerFlags & MOUSE_LISTENER)!=0) + for(int i=0; inot call this method. + */ + public void setViewingPlatform(ViewingPlatform vp) { + super.setViewingPlatform( vp ); + + if (vp==null) { + enableListeners( false ); + } else { + if (canvases != null) { + // May be switching canvases here. + enableListeners(false); + } + + // Use the canvases associated with viewer[0]; if no viewer is + // available yet, see if a canvas was provided with a constructor. + Viewer[] viewers = vp.getViewers(); + + if (viewers != null && viewers[0] != null) + canvases = viewers[0].getCanvas3Ds(); + + if (canvases == null || canvases[0] == null) + throw new IllegalStateException("No canvases available"); + + if (getEnable()) { + enableListeners(true); + } + } + } + + /** + * This is called once per frame if there are any AWT events to + * process. + * + * The motion variable will be true when the method + * is called. If it is true when the method returns integrateTransforms + * will be called immediately. + * + * The AWTEvents are presented in the array in the order in which they + * arrived from AWT. + */ + protected abstract void processAWTEvents( final java.awt.AWTEvent[] events ); + + /** + * Called once per frame (if the view is moving) to calculate the new + * view platform transform + */ + protected abstract void integrateTransforms(); + + /** + * Queue AWTEvents in a thread safe manner. + * + * If subclasses override this method they must call + * super.queueAWTEvent(e) + */ + protected void queueAWTEvent( AWTEvent e ) { + // add new event to the queue + // must be MT safe + synchronized (eventQueue) { + eventQueue.add(e); + // Only need to post if this is the only event in the queue. + // There have been reports that the first event after + // setViewingPlatform() is sometimes missed, so check the + // firstEvent flag as well. + if (firstEvent || eventQueue.size() == 1) { + firstEvent = false; + postId( POST_ID ); + } + } + } + + public void mouseClicked(final MouseEvent e) { + queueAWTEvent( e ); + } + + public void mouseEntered(final MouseEvent e) { + queueAWTEvent( e ); + } + + public void mouseExited(final MouseEvent e) { + queueAWTEvent( e ); + } + + public void mousePressed(final MouseEvent e) { + queueAWTEvent( e ); + } + + public void mouseReleased(final MouseEvent e) { + queueAWTEvent( e ); + } + + public void mouseDragged(final MouseEvent e) { + queueAWTEvent( e ); + } + + public void mouseMoved(final MouseEvent e) { + queueAWTEvent( e ); + } + + public void keyReleased(final java.awt.event.KeyEvent e) { + queueAWTEvent( e ); + } + + public void keyPressed(final java.awt.event.KeyEvent e) { + queueAWTEvent( e ); + } + + public void keyTyped(final java.awt.event.KeyEvent e) { + queueAWTEvent( e ); + } + + public void mouseWheelMoved( final java.awt.event.MouseWheelEvent e) { + queueAWTEvent( e ); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformBehavior.java new file mode 100644 index 0000000..726490f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformBehavior.java @@ -0,0 +1,137 @@ +/* + * $RCSfile: ViewPlatformBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:15 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.vp; + +import javax.vecmath.*; +import javax.media.j3d.*; +import com.sun.j3d.utils.universe.*; + +/** + * Abstract class for ViewPlatformBehaviors. A ViewPlatformBehavior must + * be added to the ViewingPlatform with the + * ViewingPlatform.addViewPlatformBehavior() method. The ViewPlatformBehavior + * will operate on the ViewPlatform transform (the TransformGroup return by + * ViewingPlatform.getViewPlatformTransform()). + * @since Java 3D 1.2.1 + */ +abstract public class ViewPlatformBehavior extends Behavior { + + /** + * The ViewingPlatform for this behavior. + */ + protected ViewingPlatform vp; + + /** + * The target TransformGroup for this behavior. + */ + protected TransformGroup targetTG; + + /** + * The "home" transform for this behavior. This is a transform used to + * position and orient the ViewingPlatform to a known point of interest. + * + * @since Java 3D 1.3 + */ + protected Transform3D homeTransform = null; + + /** + * Sets the ViewingPlatform for this behavior. This method is called by + * the ViewingPlatform. If a sub-calls overrides this method, it must + * call super.setViewingPlatform(vp).

+ * + * NOTE: Applications should not call this method. + * + * @param vp the target ViewingPlatform for this behavior + */ + public void setViewingPlatform(ViewingPlatform vp) { + this.vp = vp; + + if (vp!=null) + targetTG = vp.getViewPlatformTransform(); + else + targetTG = null; + } + + /** + * Returns the ViewingPlatform for this behavior + * @return the ViewingPlatform for this behavior + */ + public ViewingPlatform getViewingPlatform() { + return vp; + } + + /** + * Copies the given Transform3D into the "home" transform, used to + * position and reorient the ViewingPlatform to a known point of interest. + * + * @param home source transform to be copied + * @since Java 3D 1.3 + */ + public void setHomeTransform(Transform3D home) { + if (homeTransform == null) + homeTransform = new Transform3D(home); + else + homeTransform.set(home); + } + + /** + * Returns the behaviors "home" transform. + * + * @param home transform to be returned + * @since Java 3D 1.3 + */ + public void getHomeTransform(Transform3D home ) { + home.set( homeTransform ); + } + + /** + * Positions and reorients the ViewingPlatform to its "home" transform. + * @since Java 3D 1.3 + */ + public void goHome() { + if (targetTG != null && homeTransform != null) + targetTG.setTransform(homeTransform); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/WandViewBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/WandViewBehavior.java new file mode 100644 index 0000000..df74936 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/WandViewBehavior.java @@ -0,0 +1,3847 @@ +/* + * $RCSfile: WandViewBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/10/08 23:54:09 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.behaviors.vp ; + +import java.util.* ; +import javax.vecmath.* ; +import javax.media.j3d.* ; +import com.sun.j3d.utils.universe.* ; +import com.sun.j3d.utils.behaviors.sensor.* ; + +/** + * Manipulates view platform transforms using a motion-tracked wand or mouse + * equipped with a six degree of freedom (6DOF) sensor. An optional two axis + * (2D) valuator sensor is also directly supported. Default operation is set + * up to enable both direct manipulation of the view transform and translation + * back and forth along the direction the 6DOF sensor is pointing; rotation + * is handled by the 2D valuator if available. An arbitrary number of sensors + * and action bindings can be customized by accessing this behavior's + * SensorEventAgent directly. + *

+ * This behavior can be instantiated from the configuration file read by + * ConfiguredUniverse and fully configured using the + * ViewPlatformBehaviorProperties command to set the properties + * described below, but neither ConfiguredUniverse nor + * SimpleUniverse are required by this behavior. Conventional + * set and get accessors are provided for + * configuring this behavior directly; these methods have the same names as + * the properties but are prefixed with get and set. + * Property values are spelled with mixed case strings while the corresponding + * constant field names for the conventional accessors are spelled with upper + * case strings and underscores. + *

+ * {@link #Sensor6D Sensor6D} is the 6DOF sensor to use. This can also be set + * directly with the appropriate constructor. This sensor must generate 6 + * degree of freedom position and orientation reads relative to the tracker + * base in physical units. By default this behavior provides an echo for the + * 6DOF sensor which indicates its position and orientation in the virtual + * world; the echo attributes can be set by the {@link #EchoType EchoType}, + * {@link #EchoSize EchoSize}, {@link #EchoColor EchoColor}, and {@link + * #EchoTransparency EchoTransparency} properties. See also the {@link + * #NominalSensorRotation NominalSensorRotation} property, and the + * setHotSpot method of the Sensor class. + *

+ * {@link #Sensor2D Sensor2D} is an optional 2D valuator to use in conjunction + * with the 6DOF sensor. This can be set directly with the appropriate + * constructor. The valuator should generate X and Y reads ranging from [-1.0 + * .. +1.0], with a nominal (deadzone) value of 0.0. The default + * configuration expects to find these values along the translation components + * of the read matrix, at indices 3 and 7, but these indices can be also be + * specified by the {@link #MatrixIndices2D MatrixIndices2D} property. + *

+ * {@link #ButtonAction6D ButtonAction6D} sets an action for a specific button + * on a 6DOF sensor. The actions available are: + *

    + *
  • + * GrabView - Directly manipulates the view platform by moving + * it in inverse response to the sensor's position and orientation, + * producing the effect of attaching the virtual world to the sensor's + * movements. If a button is available then this action is bound to button 0 + * by default. + *
  • + *
  • + * TranslateForward - Translates the view platform forward along + * the direction the sensor is pointing; the virtual world appears to move + * towards the sensor. The default is button 1 if two buttons are available. + * Related properties are {@link #TranslationSpeed TranslationSpeed}, {@link + * #AccelerationTime AccelerationTime}, {@link #ConstantSpeedTime + * ConstantSpeedTime}, and {@link #FastSpeedFactor FastSpeedFactor}. + *
  • + *
  • + * TranslateBackward - Translates the view platform backwards + * along the direction the sensor is pointing; the virtual world appears to + * move away from the sensor. The default is button 2 if three buttons are + * available. + *
  • + *
  • + * RotateCCW - Rotates the view platform counter-clockwise about + * a Y axis; the virtual world appears to rotate clockwise. This action is + * not assigned by default. Related properties are {@link #RotationSpeed + * RotationSpeed}, {@link #RotationCoords RotationCoords}, {@link + * #TransformCenterSource TransformCenterSource}, {@link #TransformCenter + * TransformCenter}, and AccelerationTime. + *
  • + *
  • + * RotateCW - Rotates the view platform clockwise about a Y axis; + * the virtual world appears to rotate counter-clockwise. This action is not + * assigned by default. + *
  • + *
  • + * ScaleUp - Scales the view platform larger so that the virtual + * world appears to grow smaller. This action is not assigned by default. + * Related properties are {@link #ScaleSpeed ScaleSpeed}, + * TransformCenterSource, TransformCenter, and + * AccelerationTime. + *
  • + *
  • + * ScaleDown - Scales the view platform smaller so that the + * virtual world appears to grow larger. This action is not assigned by + * default. + *
  • + *
+ *

+ * {@link #ReadAction2D ReadAction2D} sets the action bound to 2D valuator + * reads; that is, non-zero values generated by the device when no buttons + * have been pressed. If the value is (0.0, 0.0) or below the threshold value + * set by {@link #Threshold2D Threshold2D}, then this behavior does nothing; + * otherwise, the following actions can be performed: + *

    + *
  • + * Rotation - Rotates the view platform. This is the default 2D + * valuator action set by this behavior. Related properties are + * RotationSpeed, RotationCoords, + * TransformCenterSource, and TransformCenter. + *
  • + *
  • + * Translation - Translates the view platform. The translation + * occurs relative to the X and Z basis vectors of either the 6DOF sensor or + * the view platform if one is not available. The maximum speed is equal to + * the product of the TranslationSpeed and + * FastSpeedFactor property values. + *
  • + *
  • + * Scale - Scales the view platform smaller with positive Y + * values and larger with negative Y values. The effect is to increase the + * apparent size of the virtual world when pushing the valuator forwards and + * to decrease it when pushing backwards. Related properties are + * ScaleSpeed, TransformCenterSource, and + * TransformCenter. + *
  • + *
+ *

+ * {@link #ButtonAction2D ButtonAction2D} sets an action for a specific button + * on the 2D valuator. The available actions are the same as for + * ReadAction2D. No actions are bound by default to the 2D + * valuator buttons. + *

+ * The view transform may be reset to its home transform by pressing a number + * of buttons simultaneously on the 6DOF sensor. The minimum number of + * buttons that must be pressed is set by {@link #ResetViewButtonCount6D + * ResetViewButtonCount6D}. This value must be greater than one; the default + * is three. This action may be disabled by setting the property value to + * None. The corresponding property for the 2D valuator is {@link + * #ResetViewButtonCount2D ResetViewButtonCount2D}, with a default value of + * None. Note, however, that the reset view action will be ineffectual if an + * action which always modifies the view transform is bound to reads on the + * sensor used to reset the view, since the reset transform will get + * overwritten by the read action. + *

+ * The special value None can in general be assigned to any + * button or read action to prevent any defaults from being bound to it. + * + * @see ConfiguredUniverse + * @see SensorEventAgent + * @since Java 3D 1.3 + */ +public class WandViewBehavior extends ViewPlatformBehavior { + /** + * Indicates a null configuration choice. + */ + public static final int NONE = 0 ; + + /** + * Indicates that a 6DOF sensor button action should be bound + * to grabbing the view. The default is button 0. + */ + public static final int GRAB_VIEW = 1 ; + + /** + * Indicates that a 6DOF sensor button action should be bound + * to translating the view forward. The default is button 1. + */ + public static final int TRANSLATE_FORWARD = 2 ; + + /** + * Indicates that a 6DOF sensor button action should be bound + * to translating the view backward. The default is button 2. + */ + public static final int TRANSLATE_BACKWARD = 3 ; + + /** + * Indicates that a 6DOF sensor button action should be bound + * to rotate the view plaform counter-clockwise about a Y axis. + */ + public static final int ROTATE_CCW = 4 ; + + /** + * Indicates that a 6DOF sensor button action should be bound + * to rotate the view platform clockwise about a Y axis. + */ + public static final int ROTATE_CW = 5 ; + + /** + * Indicates that a 6DOF sensor button action should be bound + * to scaling the view platform larger. + */ + public static final int SCALE_UP = 6 ; + + /** + * Indicates that a 6DOF sensor button action should be bound + * to scaling the view platform smaller. + */ + public static final int SCALE_DOWN = 7 ; + + /** + * Indicates that a 2D sensor button or read action should be bound + * to translation. + */ + public static final int TRANSLATION = 8 ; + + /** + * Indicates that a 2D sensor button or read action should be bound + * to scaling. + */ + public static final int SCALE = 9 ; + + /** + * Indicates that a 2D sensor button or read action should be bound + * to rotation. The default is to bind rotation to the 2D sensor reads. + */ + public static final int ROTATION = 10 ; + + /** + * Indicates that translation, rotation, or scaling speeds are + * per frame. + */ + public static final int PER_FRAME = 11 ; + + /** + * Use to indicate that translation, rotation, or scaling speeds are per + * second. This is the default. + */ + public static final int PER_SECOND = 12 ; + + /** + * Indicates that translation speed is in virtual world units. + */ + public static final int VIRTUAL_UNITS = 13 ; + + /** + * Indicates that translation speed is in physical world units + * (meters per second or per frame). This is the default. + */ + public static final int PHYSICAL_METERS = 14 ; + + /** + * Indicates that rotation speed should be in radians. + */ + public static final int RADIANS = 15 ; + + /** + * Indicates that rotation speed should be in degrees. This is the + * default. + */ + public static final int DEGREES = 16 ; + + /** + * Indicates that rotation should occur in view platform + * coordinates. + */ + public static final int VIEW_PLATFORM = 17 ; + + /** + * Indicates that rotation should occur in head coordinates. + */ + public static final int HEAD = 18 ; + + /** + * Indicates that rotation should occur in sensor coordinates. + * This is the default. + */ + public static final int SENSOR = 19 ; + + /** + * Indicates that rotation or scale should be about a fixed point + * in virtual world coordinates. + */ + public static final int VWORLD_FIXED = 20 ; + + /** + * Indicates that rotation or scale should be about a 6DOF sensor + * hotspot. This is the default. + */ + public static final int HOTSPOT = 21 ; + + /** + * Indicates that the 6DOF sensor read action should be bound to + * displaying the sensor's echo in the virtual world. This is the + * default. + */ + public static final int ECHO = 22 ; + + /** + * Indicates that the echo type is a gnomon displaying the + * directions of the sensor's local coordinate system axes at the location + * of the sensor's hotspot. + */ + public static final int GNOMON = 23 ; + + /** + * Indicates that the echo type is a beam extending from the + * origin of the sensor's local coordinate system to its hotspot. + */ + public static final int BEAM = 24 ; + + /** + * Indicates that a button listener or read listener has not been + * set for a particular target. This allows this behavior to use that + * target for a default listener. + */ + private static final int UNSET = -1 ; + + private View view = null ; + private SensorEventAgent eventAgent = null ; + private String sensor6DName = null ; + private String sensor2DName = null ; + private Shape3D echoGeometry = null ; + private BranchGroup echoBranchGroup = null ; + private TransformGroup echoTransformGroup = null ; + private SensorReadListener echoReadListener6D = null ; + private boolean echoBranchGroupAttached = false ; + private WakeupCondition wakeupConditions = new WakeupOnElapsedFrames(0) ; + private boolean configured = false ; + + // The rest of these private fields are all configurable through + // ConfiguredUniverse. + private Sensor sensor6D = null ; + private Sensor sensor2D = null ; + private int x2D = 3 ; + private int y2D = 7 ; + private double threshold2D = 0.0 ; + + private int readAction6D = UNSET ; + private int readAction2D = UNSET ; + + private ArrayList buttonActions6D = new ArrayList() ; + private ArrayList buttonActions2D = new ArrayList() ; + + private double translationSpeed = 0.1 ; + private int translationUnits = PHYSICAL_METERS ; + private int translationTimeBase = PER_SECOND ; + private double accelerationTime = 1.0 ; + private double constantSpeedTime = 8.0 ; + private double fastSpeedFactor = 10.0 ; + + private double rotationSpeed = 180.0 ; + private int rotationUnits = DEGREES ; + private int rotationTimeBase = PER_SECOND ; + private int rotationCoords = SENSOR ; + + private double scaleSpeed = 2.0 ; + private int scaleTimeBase = PER_SECOND ; + + private int transformCenterSource = HOTSPOT ; + private Point3d transformCenter = new Point3d(0.0, 0.0, 0.0) ; + + private int resetViewButtonCount6D = 3 ; + private int resetViewButtonCount2D = NONE ; + + private int echoType = GNOMON ; + private double echoSize = 0.01 ; + private Color3f echoColor = null ; + private float echoTransparency = 0.0f ; + private Transform3D nominalSensorRotation = null ; + + /** + * Parameterless constructor for this behavior. This is called when this + * behavior is instantiated from a configuration file. + *

+ * Syntax:
(NewViewPlatformBehavior <name> + * com.sun.j3d.utils.behaviors.vp.WandViewBehavior) + */ + public WandViewBehavior() { + // Create an event agent. + eventAgent = new SensorEventAgent(this) ; + + // Set a default SchedulingBounds. + setSchedulingBounds(new BoundingSphere(new Point3d(0.0, 0.0, 0.0), + Double.POSITIVE_INFINITY)) ; + } + + /** + * Creates a new instance with the specified sensors and echo parameters. + * At least one sensor must be non-null. + *

+ * This constructor should only be used if either + * SimpleUniverse or ConfiguredUniverse is used + * to set up the view side of the scene graph, or if it is otherwise to be + * attached to a ViewingPlatform. If this behavior is not + * instantiated from a configuration file then it must then be explicitly + * attached to a ViewingPlatform instance with the + * ViewingPlatform.setViewPlatformBehavior method. + * + * @param sensor6D a six degree of freedom sensor which generates reads + * relative to the tracker base in physical units; may be + * null + * @param sensor2D 2D valuator which generates X and Y reads ranging from + * [-1.0 .. +1.0]; may be null + * @param echoType either GNOMON, BEAM, or + * NONE for the 6DOF sensor echo + * @param echoSize the width of the 6DOF sensor echo in physical meters; + * ignored if echoType is NONE + */ + public WandViewBehavior(Sensor sensor6D, Sensor sensor2D, + int echoType, double echoSize) { + this() ; + this.sensor6D = sensor6D ; + this.sensor2D = sensor2D ; + this.echoType = echoType ; + this.echoSize = echoSize ; + } + + /** + * Creates a new instance with the specified sensors and a 6DOF sensor + * echo parented by the specified TransformGroup. At least + * one sensor must be non-null. + *

+ * This constructor should only be used if either + * SimpleUniverse or ConfiguredUniverse is used + * to set up the view side of the scene graph, or if it is otherwise to be + * attached to a ViewingPlatform. If this behavior is not + * instantiated from a configuration file then it must then be explicitly + * attached to a ViewingPlatform instance with the + * ViewingPlatform.setViewPlatformBehavior method. + *

+ * If the echo TransformGroup is non-null, it + * will be added to a new BranchGroup and attached to the + * ViewingPlatform, where its transform will be updated in + * response to the sensor reads. Capabilities to allow writing its + * transform and to read, write, and extend its children will be set. The + * echo geometry is assumed to incorporate the position and orientation of + * the 6DOF sensor hotspot. + * + * @param sensor6D a six degree of freedom sensor which generates reads + * relative to the tracker base in physical units; may be + * null + * @param sensor2D 2D valuator which generates X and Y reads ranging from + * [-1.0 .. +1.0]; may be null + * @param echo a TransformGroup containing the visible echo + * which will track the 6DOF sensor's position and orientation, or + * null for no echo + */ + public WandViewBehavior(Sensor sensor6D, Sensor sensor2D, + TransformGroup echo) { + this() ; + this.sensor6D = sensor6D ; + this.sensor2D = sensor2D ; + if (echo != null) { + echo.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) ; + echo.setCapability(Group.ALLOW_CHILDREN_READ) ; + echo.setCapability(Group.ALLOW_CHILDREN_WRITE) ; + echo.setCapability(Group.ALLOW_CHILDREN_EXTEND) ; + } + this.echoTransformGroup = echo ; + } + + /** + * Creates a new instance with the specified sensors and a 6DOF sensor + * echo parented by the specified TransformGroup. At least + * one sensor must be non-null. + *

+ * This constructor should only be used if SimpleUniverse or + * ConfiguredUniverse is not used to set up the view + * side of the scene graph. The application must set up the view side + * itself and supply references to the View and the + * TransformGroup containing the view platform transform. + * ViewingPlatform.setViewPlatformBehavior must not + * be called, and this behavior must be explicitly added to the virtual + * universe by the application. + *

+ * If the echo TransformGroup is non-null, it + * will only be used to update its associated transform with the position + * and orientation of a 6DOF sensor (if supplied). The application is + * responsible for adding the echo to the virtual universe. The echo + * geometry is assumed to incorporate the position and orientation of the + * 6DOF sensor hotspot. + * + * @param sensor6D a six degree of freedom sensor which generates reads + * relative to the tracker base in physical units; may be + * null + * @param sensor2D 2D valuator which generates X and Y reads ranging from + * [-1.0 .. +1.0]; may be null + * @param view a reference to the View attached to the + * ViewPlatform to be manipulated by this behavior + * @param viewTransform a TransformGroup containing the view + * platform transform; appropriate capabilities to update the transform + * must be set + * @param homeTransform a Transform3D containing the + * view transform to be used when the view is reset; may be + * null for identity + * @param echo a TransformGroup containing the visible echo + * which will track the 6DOF sensor's position and orientation, or + * null for no echo; appropriate capabilities to update the + * transform must be set + */ + public WandViewBehavior(Sensor sensor6D, Sensor sensor2D, + View view, TransformGroup viewTransform, + Transform3D homeTransform, TransformGroup echo) { + this() ; + this.sensor6D = sensor6D ; + this.sensor2D = sensor2D ; + this.view = view ; + this.targetTG = viewTransform ; + this.echoTransformGroup = echo ; + + if (homeTransform == null) + setHomeTransform(new Transform3D()) ; + else + setHomeTransform(homeTransform) ; + } + + /** + * Initializes and configures this behavior. + * NOTE: Applications should not call this method. It is called by + * the Java 3D behavior scheduler. + */ + public void initialize() { + // Don't configure the sensors and echo after the first time. + if (!configured) { + configureSensorActions() ; + + // Configure an echo only if a ViewingPlatform is in use. + if (vp != null) { + if (echoTransformGroup == null && + sensor6D != null && readAction6D == ECHO) { + configureEcho() ; + } + if (echoTransformGroup != null) { + echoBranchGroup = new BranchGroup() ; + echoBranchGroup.setCapability + (BranchGroup.ALLOW_DETACH) ; + echoBranchGroup.setCapability + (BranchGroup.ALLOW_CHILDREN_READ) ; + echoBranchGroup.setCapability + (BranchGroup.ALLOW_CHILDREN_WRITE) ; + + echoBranchGroup.addChild(echoTransformGroup) ; + echoBranchGroup.compile() ; + } + attachEcho() ; + } + configured = true ; + } + wakeupOn(wakeupConditions) ; + } + + /** + * Processes a stimulus meant for this behavior. + * NOTE: Applications should not call this method. It is called by + * the Java 3D behavior scheduler. + */ + public void processStimulus(Enumeration criteria) { + // Invoke the sensor event dispatcher. + eventAgent.dispatchEvents() ; + + // Wake up on the next frame. + wakeupOn(wakeupConditions) ; + } + + /** + * Enables or disables this behavior. The default state is enabled. + * @param enable true or false to enable or disable this behavior + */ + public void setEnable(boolean enable) { + if (enable == getEnable()) { + return ; + } + else if (enable) { + attachEcho() ; + } + else { + detachEcho() ; + } + super.setEnable(enable) ; + } + + /** + * Sets the ViewingPlatform for this behavior. If a subclass + * overrides this method, it must call + * super.setViewingPlatform(vp). NOTE: Applications should + * not call this method. It is called by the + * ViewingPlatform. + */ + public void setViewingPlatform(ViewingPlatform vp) { + super.setViewingPlatform(vp) ; + if (vp == null) { + detachEcho() ; + return ; + } + + Viewer[] viewers = vp.getViewers() ; + if (viewers != null) { + // Get the View from the first Viewer attached to the + // ViewingPlatform. Multiple Viewers are not supported. + if (viewers.length != 0 && viewers[0] != null) + view = viewers[0].getView() ; + + if (viewers.length > 1) + throw new RuntimeException("multiple Viewers not supported") ; + } + if (view == null) { + // Fallback to the first View attached to a live ViewPlatform. + view = getView() ; + } + if (view == null) { + // This behavior requires a view. Bail. + throw new RuntimeException("a view is not available") ; + } + + // Get the top-most TransformGroup in the ViewingPlatform. + // ViewPlatformBehavior retrieves the bottom-most which won't work + // if there are multiple TransformGroups. + targetTG = vp.getMultiTransformGroup().getTransformGroup(0) ; + + // Should be an API for checking if homeTransform is null. + if (homeTransform == null) + setHomeTransform(new Transform3D()) ; + + attachEcho() ; + } + + /** + * Attaches the echo BranchGroup to the ViewingPlatform if appropriate. + */ + private void attachEcho() { + if (vp != null && + echoBranchGroup != null && !echoBranchGroupAttached) { + vp.addChild(echoBranchGroup) ; + echoBranchGroupAttached = true ; + } + } + + /** + * Detaches the echo BranchGroup from the ViewingPlatform if appropriate. + */ + private void detachEcho() { + if (echoBranchGroup != null && echoBranchGroupAttached) { + echoBranchGroup.detach() ; + echoBranchGroupAttached = false ; + } + } + + /** + * Creates the sensor listeners for a 6DOF sensor and/or a 2D valuator + * sensor using the predefined button and read listeners and the + * configured action bindings. + *

+ * This is invoked the first time initialize is called. This + * method can be overridden by subclasses to modify the configured + * bindings or introduce other configuration parameters. + */ + protected void configureSensorActions() { + SensorButtonListener[] sbls ; + int buttonCount, buttonActionCount ; + + SimpleUniverse universe = null ; + if (vp != null) universe = vp.getUniverse() ; + if (universe != null && universe instanceof ConfiguredUniverse) { + // Check if sensors were instantiated from a config file. + Map sensorMap = ((ConfiguredUniverse)universe).getNamedSensors() ; + + if (sensor2D == null && sensor2DName != null) { + sensor2D = (Sensor)sensorMap.get(sensor2DName) ; + if (sensor2D == null) + throw new IllegalArgumentException + ("\nsensor " + sensor2DName + " not found") ; + } + + if (sensor6D == null && sensor6DName != null) { + sensor6D = (Sensor)sensorMap.get(sensor6DName) ; + if (sensor6D == null) + throw new IllegalArgumentException + ("\nsensor " + sensor6DName + " not found") ; + } + } + + if (sensor6D != null) { + // Assign default read action. + if (readAction6D == UNSET) + readAction6D = ECHO ; + + // Register the read listener. + if (readAction6D == ECHO) { + echoReadListener6D = new EchoReadListener6D() ; + eventAgent.addSensorReadListener + (sensor6D, echoReadListener6D) ; + } + + // Check for button range. + buttonCount = sensor6D.getSensorButtonCount() ; + buttonActionCount = buttonActions6D.size() ; + if (buttonActionCount > buttonCount) + throw new IllegalArgumentException + ("\nbutton index " + (buttonActionCount-1) + + " >= number of buttons (" + buttonCount +")") ; + + // Assign default button actions. + if (buttonCount > 2 && + (buttonActionCount < 3 || buttonActions6D.get(2) == null)) + setButtonAction6D(2, TRANSLATE_BACKWARD) ; + if (buttonCount > 1 && + (buttonActionCount < 2 || buttonActions6D.get(1) == null)) + setButtonAction6D(1, TRANSLATE_FORWARD) ; + if (buttonCount > 0 && + (buttonActionCount < 1 || buttonActions6D.get(0) == null)) + setButtonAction6D(0, GRAB_VIEW) ; + + buttonActionCount = buttonActions6D.size() ; + if (buttonActionCount > 0) { + // Set up the button listener array. + sbls = new SensorButtonListener[buttonCount] ; + for (int i = 0 ; i < buttonActionCount ; i++) { + Integer button = (Integer)buttonActions6D.get(i) ; + if (button != null) { + int action = button.intValue() ; + if (action == NONE) + sbls[i] = null ; + else if (action == GRAB_VIEW) + sbls[i] = new GrabViewListener6D() ; + else if (action == TRANSLATE_FORWARD) + sbls[i] = new TranslationListener6D(false) ; + else if (action == TRANSLATE_BACKWARD) + sbls[i] = new TranslationListener6D(true) ; + else if (action == ROTATE_CCW) + sbls[i] = new RotationListener6D(false) ; + else if (action == ROTATE_CW) + sbls[i] = new RotationListener6D(true) ; + else if (action == SCALE_UP) + sbls[i] = new ScaleListener6D(false) ; + else if (action == SCALE_DOWN) + sbls[i] = new ScaleListener6D(true) ; + } + } + // Register the button listeners. + eventAgent.addSensorButtonListeners(sensor6D, sbls) ; + } + + // Check for reset view action. + if (resetViewButtonCount6D != NONE) { + SensorInputAdaptor r = + new ResetViewListener(sensor6D, resetViewButtonCount6D) ; + eventAgent.addSensorButtonListener(sensor6D, r) ; + eventAgent.addSensorReadListener(sensor6D, r) ; + } + } + + if (sensor2D != null) { + // Assign default read action + if (readAction2D == UNSET) + readAction2D = ROTATION ; + + // Register the read listener. + if (readAction2D == ROTATION) { + SensorReadListener r = + new RotationListener2D(sensor2D, sensor6D) ; + eventAgent.addSensorReadListener(sensor2D, r) ; + } + else if (readAction2D == TRANSLATION) { + SensorReadListener r = + new TranslationListener2D(sensor2D, sensor6D) ; + eventAgent.addSensorReadListener(sensor2D, r) ; + } + else if (readAction2D == SCALE) { + SensorReadListener r = + new ScaleListener2D(sensor2D, sensor6D) ; + eventAgent.addSensorReadListener(sensor2D, r) ; + } + + // Check for button range. + buttonCount = sensor2D.getSensorButtonCount() ; + buttonActionCount = buttonActions2D.size() ; + if (buttonActionCount > buttonCount) + throw new IllegalArgumentException + ("\nbutton index " + (buttonActionCount-1) + + " >= number of buttons (" + buttonCount +")") ; + + // No default button actions are defined for the 2D sensor. + if (buttonActionCount > 0) { + // Set up the button listener array. + sbls = new SensorButtonListener[buttonCount] ; + for (int i = 0 ; i < buttonActionCount ; i++) { + Integer button = (Integer)buttonActions2D.get(i) ; + if (button != null) { + int action = button.intValue() ; + if (action == NONE) + sbls[i] = null ; + else if (action == ROTATION) + sbls[i] = new RotationListener2D + (sensor2D, sensor6D) ; + else if (action == TRANSLATION) + sbls[i] = new TranslationListener2D + (sensor2D, sensor6D) ; + else if (action == SCALE) + sbls[i] = new ScaleListener2D + (sensor2D, sensor6D) ; + } + } + // Register the button listeners. + eventAgent.addSensorButtonListeners(sensor2D, sbls) ; + } + + // Check for reset view action. + if (resetViewButtonCount2D != NONE) { + SensorInputAdaptor r = + new ResetViewListener(sensor2D, resetViewButtonCount2D) ; + eventAgent.addSensorButtonListener(sensor2D, r) ; + eventAgent.addSensorReadListener(sensor2D, r) ; + } + } + } + + /** + * Creates a 6DOF sensor echo according to configuration parameters. This + * is done only if a 6DOF sensor has been specified, the 6DOF sensor read + * action has been set to echo the sensor position, the echo transform + * group has not already been set, and a ViewingPlatform is in use. This + * is invoked the first time initialize is called to set this + * behavior live, but before the echo transform group is added to a + * BranchGroup and made live. This method can be overridden + * to support other echo geometry. + */ + protected void configureEcho() { + Point3d hotspot = new Point3d() ; + sensor6D.getHotspot(hotspot) ; + + if (echoType == GNOMON) { + Transform3D gnomonTransform = new Transform3D() ; + if (nominalSensorRotation != null) { + gnomonTransform.set(nominalSensorRotation) ; + gnomonTransform.invert() ; + } + gnomonTransform.setTranslation(new Vector3d(hotspot)) ; + echoGeometry = new SensorGnomonEcho + (gnomonTransform, 0.1 * echoSize, 0.5 * echoSize, true) ; + } + else if (echoType == BEAM) { + echoGeometry = new SensorBeamEcho(hotspot, echoSize, true) ; + } + + if (echoGeometry != null) { + Appearance a = echoGeometry.getAppearance() ; + if (echoColor != null) { + Material m = a.getMaterial() ; + m.setDiffuseColor(echoColor) ; + } + if (echoTransparency != 0.0f) { + TransparencyAttributes ta = a.getTransparencyAttributes() ; + ta.setTransparencyMode(TransparencyAttributes.BLENDED) ; + ta.setTransparency(echoTransparency) ; + // Use order independent additive blend for gnomon. + if (echoGeometry instanceof SensorGnomonEcho) + ta.setDstBlendFunction(TransparencyAttributes.BLEND_ONE) ; + } + echoTransformGroup = new TransformGroup() ; + echoTransformGroup.setCapability + (TransformGroup.ALLOW_TRANSFORM_WRITE) ; + echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_READ) ; + echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_WRITE) ; + echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND) ; + echoTransformGroup.addChild(echoGeometry) ; + } + } + + /** + * A base class for implementing some of this behavior's listeners. + */ + public class ListenerBase extends SensorInputAdaptor { + /** + * The initial transform from view platform coordinates to virtual + * world coordinates, set by initAction. + */ + protected Transform3D viewPlatformToVworld = new Transform3D() ; + + /** + * The initial transform from tracker base coordinates to virtual + * world coordinates, set by initAction. + */ + protected Transform3D trackerToVworld = new Transform3D() ; + + /** + * The initial transform from sensor coordinates to virtual + * world coordinates, set by initAction. + */ + protected Transform3D sensorToVworld = new Transform3D() ; + + /** + * The initial transform from sensor coordinates to tracker base + * coordinates, set by initAction. + */ + protected Transform3D sensorToTracker = new Transform3D() ; + + // Private fields. + private Transform3D trackerToSensor = new Transform3D() ; + private boolean active = false ; + + // Misc. temporary objects. + private double[] s3Tmp = new double[3] ; + private double[] m16Tmp = new double[16] ; + private Vector3d v3dTmp = new Vector3d() ; + private Transform3D t3dTmp = new Transform3D() ; + + /** + * Initializes the listener action. Subclasses must call this before + * starting the action, either from pressed or when a 2D + * valuator exits the deadzone threshold. + * + * @param s reference to a 6DOF sensor if used by the listener; may + * be null + */ + protected void initAction(Sensor s) { + targetTG.getTransform(viewPlatformToVworld) ; + active = true ; + if (s == null) return ; + + // Kludge to get the static trackerToVworld for this + // frame. This is computed from the two separate sensor reads + // below, which are close enough to identical to work. The + // Java 3D View class needs a getTrackerBaseToVworld() method + // (see Java 3D RFE 4676808). + s.getRead(sensorToTracker) ; + view.getSensorToVworld(s, sensorToVworld) ; + + trackerToSensor.invert(sensorToTracker) ; + trackerToVworld.mul(sensorToVworld, trackerToSensor) ; + } + + /** + * Ends the action. Subclasses must be call this from + * released or when a 2D valuator enters the deadzone + * threshold. + * + * @param s reference to a 6DOF sensor if used by the listener; may + * be null + */ + protected void endAction(Sensor s) { + active = false ; + } + + /** + * Returns true if the listener is currently active; that is, if + * initAction has been called but not yet + * endAction. + * + * @return true if the listener is active, false otherwise + */ + protected boolean isActive() { + return active ; + } + + public void pressed(SensorEvent e) { + initAction(e.getSensor()) ; + } + + public void released(SensorEvent e) { + endAction(e.getSensor()) ; + } + + /** + * Gets the physical to virtual scale. + */ + protected double getPhysicalToVirtualScale() { + view.getCanvas3D(0).getImagePlateToVworld(t3dTmp) ; + t3dTmp.get(m16Tmp) ; + return Math.sqrt(m16Tmp[0]*m16Tmp[0] + + m16Tmp[1]*m16Tmp[1] + + m16Tmp[2]*m16Tmp[2]) ; + } + + /** + * Gets the scale from physical units to view platform units. + */ + protected double getPhysicalToViewPlatformScale() { + double vpToVirtualScale ; + + targetTG.getTransform(t3dTmp) ; + t3dTmp.get(m16Tmp) ; + vpToVirtualScale = Math.sqrt(m16Tmp[0]*m16Tmp[0] + + m16Tmp[1]*m16Tmp[1] + + m16Tmp[2]*m16Tmp[2]) ; + + return getPhysicalToVirtualScale() / vpToVirtualScale ; + } + + /** + * Translates a coordinate system. + * + * @param transform the coordinate system to be translated + * @param translation the vector by which to translate + */ + protected void translateTransform(Transform3D transform, + Vector3d translation) { + transform.get(v3dTmp) ; + v3dTmp.add(translation) ; + transform.setTranslation(v3dTmp) ; + } + + /** + * Transforms the target coordinate system about a center point. + * This can be used for rotation and scaling. + * + * @param target the coordinate system to transform + * @param center the center point about which to transform + * @param transform the transform to apply + */ + protected void transformAboutCenter + (Transform3D target, Point3d center, Transform3D transform) { + + // Translate to the center. + target.get(v3dTmp) ; + v3dTmp.sub(center) ; + target.setTranslation(v3dTmp) ; + + // Apply the transform. + target.mul(transform, target) ; + + // Translate back. + target.get(v3dTmp) ; + v3dTmp.add(center) ; + target.setTranslation(v3dTmp) ; + } + + /** + * Equalizes the scale factors in the view tranform, which must be + * congruent. If successful, the ViewingPlatform + * TransformGroup is updated; otherwise, its transform is reset + * to the home transform. This should be called if multiple + * incremental scale factors are applied to the view transform. + * + * @param viewPlatformToVworld the view transform + */ + protected void conditionViewScale(Transform3D viewPlatformToVworld) { + viewPlatformToVworld.normalize() ; + viewPlatformToVworld.get(m16Tmp) ; + + s3Tmp[0] = m16Tmp[0]*m16Tmp[0] + + m16Tmp[4]*m16Tmp[4] + m16Tmp[8]*m16Tmp[8] ; + s3Tmp[1] = m16Tmp[1]*m16Tmp[1] + + m16Tmp[5]*m16Tmp[5] + m16Tmp[9]*m16Tmp[9] ; + s3Tmp[2] = m16Tmp[2]*m16Tmp[2] + + m16Tmp[6]*m16Tmp[6] + m16Tmp[10]*m16Tmp[10] ; + + if (s3Tmp[0] == s3Tmp[1] && s3Tmp[0] == s3Tmp[2]) + return ; + + s3Tmp[0] = Math.sqrt(s3Tmp[0]) ; + s3Tmp[1] = Math.sqrt(s3Tmp[1]) ; + s3Tmp[2] = Math.sqrt(s3Tmp[2]) ; + + int closestToOne = 0 ; + if (Math.abs(s3Tmp[1] - 1.0) < Math.abs(s3Tmp[0] - 1.0)) + closestToOne = 1 ; + if (Math.abs(s3Tmp[2] - 1.0) < Math.abs(s3Tmp[closestToOne] - 1.0)) + closestToOne = 2 ; + + double scale ; + for (int i = 0 ; i < 3 ; i++) { + if (i == closestToOne) continue ; + scale = s3Tmp[closestToOne] / s3Tmp[i] ; + m16Tmp[i+0] *= scale ; + m16Tmp[i+4] *= scale ; + m16Tmp[i+8] *= scale ; + } + + // Set the view transform and bail out if unsuccessful. + viewPlatformToVworld.set(m16Tmp) ; + if ((viewPlatformToVworld.getType() & Transform3D.CONGRUENT) == 0) + goHome() ; + else + targetTG.setTransform(viewPlatformToVworld) ; + } + } + + /** + * Implements a 6DOF sensor button listener to directly manipulate the + * view platform transform. The view platform moves in inverse response + * to the sensor's position and orientation to give the effect of + * attaching the virtual world to the sensor's echo. + * @see #setButtonAction6D + */ + public class GrabViewListener6D extends ListenerBase { + private Transform3D t3d = new Transform3D() ; + private Transform3D initialVworldToSensor = new Transform3D() ; + + public void pressed(SensorEvent e) { + initAction(e.getSensor()) ; + + // Save the inverse of the initial sensorToVworld. + initialVworldToSensor.invert(sensorToVworld) ; + } + + public void dragged(SensorEvent e) { + // Get sensor read relative to the static view at the time of the + // button-down. + Sensor s = e.getSensor() ; + s.getRead(sensorToTracker) ; + sensorToVworld.mul(trackerToVworld, sensorToTracker) ; + + // Solve for T, where T x initialSensorToVworld = sensorToVworld + t3d.mul(sensorToVworld, initialVworldToSensor) ; + + // Move T to the view side by inverting it, and then applying it + // to the static view transform. + t3d.invert() ; + t3d.mul(viewPlatformToVworld) ; + targetTG.setTransform(t3d) ; + } + } + + /** + * Implements a 6DOF sensor button listener that translates the view + * platform along the direction the sensor is pointing. + * @see #setButtonAction6D + * @see #setTranslationSpeed + * @see #setAccelerationTime + * @see #setConstantSpeedTime + * @see #setFastSpeedFactor + */ + public class TranslationListener6D extends ListenerBase { + private long buttonDownTime ; + private double speedScaled ; + private double interval0 ; + private double interval1 ; + private double interval2 ; + private Vector3d v3d = new Vector3d() ; + + /** + * Construct a new translation button listener for a 6DOF sensor. + * + * @param reverse if true, translate the view platform backwards; + * otherwise, translate the view platform forwards + */ + public TranslationListener6D(boolean reverse) { + // Compute translation speed intervals. + interval0 = accelerationTime ; + interval1 = interval0 + constantSpeedTime ; + interval2 = interval1 + accelerationTime ; + + // Apply virtual to physical scale if needed. + if (translationUnits == VIRTUAL_UNITS) + speedScaled = translationSpeed / getPhysicalToVirtualScale() ; + else + speedScaled = translationSpeed ; + + if (reverse) { + speedScaled = -speedScaled ; + } + } + + public void pressed(SensorEvent e) { + initAction(e.getSensor()) ; + buttonDownTime = e.getTime() ; + } + + public void dragged(SensorEvent e) { + long time = e.getTime() ; + long lastTime = e.getLastTime() ; + double currSpeed, transTime ; + double frameTime = 1.0 ; + if (translationTimeBase == PER_SECOND) + frameTime = (time - lastTime) / 1e9 ; + + // Compute speed based on acceleration intervals. + transTime = (time - buttonDownTime) / 1e9 ; + if (transTime <= interval0) { + currSpeed = (transTime / accelerationTime) * speedScaled ; + } + else if (transTime > interval1 && transTime < interval2) { + currSpeed = ((((transTime-interval1) / accelerationTime) * + (fastSpeedFactor-1.0)) + 1.0) * speedScaled ; + } + else if (transTime >= interval2) { + currSpeed = fastSpeedFactor * speedScaled ; + } + else { + currSpeed = speedScaled ; + } + + // Transform the translation direction (0, 0, -1). + v3d.set(0.0, 0.0, -1.0) ; + if (nominalSensorRotation != null) + nominalSensorRotation.transform(v3d) ; + + // To avoid echo frame lag, compute sensorToVworld based on + // computed trackerToVworld. getSensorToVworld() isn't + // current for this frame. + Sensor s = e.getSensor() ; + s.getRead(sensorToTracker) ; + sensorToVworld.mul(trackerToVworld, sensorToTracker) ; + sensorToVworld.transform(v3d) ; + + // Translate the view platform. + v3d.scale(frameTime * currSpeed) ; + translateTransform(viewPlatformToVworld, v3d) ; + targetTG.setTransform(viewPlatformToVworld) ; + + // Translate trackerToVworld. + translateTransform(trackerToVworld, v3d) ; + + if (readAction6D == ECHO) { + // Translate sensor echo to compensate for the new view + // platform movement. + translateTransform(sensorToVworld, v3d) ; + updateEcho(s, sensorToVworld) ; + } + } + } + + /** + * Implements a 6DOF sensor button listener that rotates the view platform + * about a Y axis. This axis can be relative to the sensor, user head, or + * view platform. The rotation center can be the sensor hotspot or a + * fixed point in virtual world coordinates. + * + * @see #setButtonAction6D + * @see #setRotationCoords + * @see #setTransformCenterSource + * @see #setTransformCenter + * @see #setRotationSpeed + * @see #setAccelerationTime + */ + public class RotationListener6D extends ListenerBase { + private boolean reverse ; + private long buttonDownTime ; + private Vector3d axis = new Vector3d() ; + private Point3d center = new Point3d() ; + private Transform3D t3d = new Transform3D() ; + private AxisAngle4d aa4d = new AxisAngle4d() ; + private Transform3D headToVworld = new Transform3D() ; + private double speedScaled ; + + protected void initAction(Sensor s) { + super.initAction(s) ; + if (rotationCoords == HEAD) { + view.setUserHeadToVworldEnable(true) ; + } + } + + protected void endAction(Sensor s) { + super.endAction(s) ; + viewPlatformToVworld.normalize() ; + targetTG.setTransform(viewPlatformToVworld) ; + if (rotationCoords == HEAD) { + view.setUserHeadToVworldEnable(false) ; + } + } + + /** + * Construct a new rotation button listener for a 6DOF sensor. + * + * @param reverse if true, rotate clockwise; otherwise, rotate + * counter-clockwise + */ + public RotationListener6D(boolean reverse) { + this.reverse = reverse ; + if (rotationUnits == DEGREES) + speedScaled = rotationSpeed * Math.PI / 180.0 ; + else + speedScaled = rotationSpeed ; + } + + public void pressed(SensorEvent e) { + initAction(e.getSensor()) ; + buttonDownTime = e.getTime() ; + } + + public void dragged(SensorEvent e) { + long time = e.getTime() ; + long lastTime = e.getLastTime() ; + double currSpeed, transTime ; + double frameTime = 1.0 ; + if (rotationTimeBase == PER_SECOND) + frameTime = (time - lastTime) / 1e9 ; + + // Compute speed based on acceleration interval. + transTime = (time - buttonDownTime) / 1e9 ; + if (transTime <= accelerationTime) { + currSpeed = (transTime / accelerationTime) * speedScaled ; + } + else { + currSpeed = speedScaled ; + } + + // Set the rotation axis. + if (reverse) + axis.set(0.0, -1.0, 0.0) ; + else + axis.set(0.0, 1.0, 0.0) ; + + // To avoid echo frame lag, compute sensorToVworld based on + // computed trackerToVworld. getSensorToVworld() isn't current + // for this frame. + Sensor s = e.getSensor() ; + s.getRead(sensorToTracker) ; + sensorToVworld.mul(trackerToVworld, sensorToTracker) ; + + // Transform rotation axis into target coordinate system. + if (rotationCoords == SENSOR) { + if (nominalSensorRotation != null) + nominalSensorRotation.transform(axis) ; + + sensorToVworld.transform(axis) ; + } + else if (rotationCoords == HEAD) { + view.getUserHeadToVworld(headToVworld) ; + headToVworld.transform(axis) ; + } + else { + viewPlatformToVworld.transform(axis) ; + } + + // Get the rotation center. + if (transformCenterSource == HOTSPOT) { + s.getHotspot(center) ; + sensorToVworld.transform(center) ; + } + else { + center.set(transformCenter) ; + } + + // Construct origin-based rotation about axis. + aa4d.set(axis, currSpeed * frameTime) ; + t3d.set(aa4d) ; + + // Apply the rotation to the view platform. + transformAboutCenter(viewPlatformToVworld, center, t3d) ; + targetTG.setTransform(viewPlatformToVworld) ; + + // Apply the rotation to trackerToVworld. + transformAboutCenter(trackerToVworld, center, t3d) ; + + if (readAction6D == ECHO) { + // Transform sensor echo to compensate for the new view + // platform movement. + transformAboutCenter(sensorToVworld, center, t3d) ; + updateEcho(s, sensorToVworld) ; + } + } + } + + /** + * Implements a 6DOF sensor button listener that scales the view platform. + * The center of scaling can be the sensor hotspot or a fixed location in + * virtual world coordinates. + * + * @see #setButtonAction6D + * @see #setTransformCenterSource + * @see #setTransformCenter + * @see #setScaleSpeed + * @see #setAccelerationTime + */ + public class ScaleListener6D extends ListenerBase { + private double direction ; + private long buttonDownTime ; + private Point3d center = new Point3d() ; + private Transform3D t3d = new Transform3D() ; + + protected void endAction(Sensor s) { + super.endAction(s) ; + conditionViewScale(viewPlatformToVworld) ; + } + + /** + * Construct a new scale button listener for a 6DOF sensor. + * + * @param reverse if true, scale the view platform smaller; otherwise, + * scale the view platform larger + */ + public ScaleListener6D(boolean reverse) { + if (reverse) + direction = -1.0 ; + else + direction = 1.0 ; + } + + public void pressed(SensorEvent e) { + initAction(e.getSensor()) ; + buttonDownTime = e.getTime() ; + } + + public void dragged(SensorEvent e) { + long time = e.getTime() ; + long lastTime = e.getLastTime() ; + double scale, exp, transTime ; + double frameTime = 1.0 ; + if (scaleTimeBase == PER_SECOND) + frameTime = (time - lastTime) / 1e9 ; + + // Compute speed based on acceleration interval. + transTime = (time - buttonDownTime) / 1e9 ; + if (transTime <= accelerationTime) { + exp = (transTime / accelerationTime) * frameTime * direction ; + } + else { + exp = frameTime * direction ; + } + scale = Math.pow(scaleSpeed, exp) ; + + // To avoid echo frame lag, compute sensorToVworld based on + // computed trackerToVworld. getSensorToVworld() isn't current + // for this frame. + Sensor s = e.getSensor() ; + s.getRead(sensorToTracker) ; + sensorToVworld.mul(trackerToVworld, sensorToTracker) ; + + // Get the scale center. + if (transformCenterSource == HOTSPOT) { + s.getHotspot(center) ; + sensorToVworld.transform(center) ; + } + else { + center.set(transformCenter) ; + } + + // Apply the scale to the view platform. + t3d.set(scale) ; + transformAboutCenter(viewPlatformToVworld, center, t3d) ; + + // Incremental scaling at the extremes can lead to numerical + // instability, so catch BadTransformException to prevent the + // behavior thread from being killed. Using a cumulative scale + // matrix avoids this problem to a better extent, but causes the + // 6DOF sensor hotspot center to jitter excessively. + try { + targetTG.setTransform(viewPlatformToVworld) ; + } + catch (BadTransformException bt) { + conditionViewScale(viewPlatformToVworld) ; + } + + // Apply the scale to trackerToVworld. + transformAboutCenter(trackerToVworld, center, t3d) ; + + if (readAction6D == ECHO) { + // Scale sensor echo to compensate for the new view + // platform scale. + transformAboutCenter(sensorToVworld, center, t3d) ; + updateEcho(s, sensorToVworld) ; + } + } + } + + /** + * Implements a 6DOF sensor read listener that updates the orientation and + * position of the sensor's echo in the virtual world. + * + * @see #setEchoType + * @see #setEchoSize + * @see #setReadAction6D + * @see SensorGnomonEcho + * @see SensorBeamEcho + */ + public class EchoReadListener6D implements SensorReadListener { + private Transform3D sensorToVworld = new Transform3D() ; + + public void read(SensorEvent e) { + Sensor s = e.getSensor() ; + view.getSensorToVworld(s, sensorToVworld) ; + updateEcho(s, sensorToVworld) ; + } + } + + /** + * Implements a 2D valuator listener that rotates the view platform. The + * X and Y values from the valuator should have a continuous range from + * -1.0 to +1.0, although the rotation speed can be scaled to compensate + * for a different range. The X and Y values are found in the sensor's + * read matrix at the indices specified by + * setMatrixIndices2D, with defaults of 3 and 7 respectively. + *

+ * The rotation direction is controlled by the direction the 2D valuator + * is pushed, and the rotation speed is scaled by the magnitude of the 2D + * valuator read values. + *

+ * This listener will work in conjunction with a 6DOF sensor if supplied + * in the constructor. If a 6DOF sensor is provided and + * setRotationCoords has been called with the value + * SENSOR, then the rotation is applied in the 6DOF sensor's + * coordinate system; otherwise the rotation is applied either in head + * coordinates or in view platform coordinates. If a 6DOF sensor is + * provided and setTransformCenterSource has been called with + * the value HOTSPOT, then rotation is about the 6DOF + * sensor's hotspot; otherwise, the rotation center is the value set by + * setTransformCenter. + * + * @see #setReadAction2D + * @see #setButtonAction2D + * @see #setRotationCoords + * @see #setTransformCenterSource + * @see #setTransformCenter + * @see #setRotationSpeed + * @see #setThreshold2D + * @see #setMatrixIndices2D + */ + public class RotationListener2D extends ListenerBase { + private Sensor sensor2D, sensor6D ; + private double[] m = new double[16] ; + private Vector3d axis = new Vector3d() ; + private Point3d center = new Point3d() ; + private Transform3D t3d = new Transform3D() ; + private AxisAngle4d aa4d = new AxisAngle4d() ; + private Transform3D sensor2DRead = new Transform3D() ; + private Transform3D headToVworld = new Transform3D() ; + private double speedScaled ; + + protected void initAction(Sensor s) { + super.initAction(s) ; + if (rotationCoords == HEAD) { + view.setUserHeadToVworldEnable(true) ; + } + if (s != null && readAction6D == ECHO) { + // Disable the 6DOF echo. It will be updated in this action. + eventAgent.removeSensorReadListener(s, echoReadListener6D) ; + } + } + + protected void endAction(Sensor s) { + super.endAction(s) ; + viewPlatformToVworld.normalize() ; + targetTG.setTransform(viewPlatformToVworld) ; + if (rotationCoords == HEAD) { + view.setUserHeadToVworldEnable(false) ; + } + if (s != null && readAction6D == ECHO) { + eventAgent.addSensorReadListener(s, echoReadListener6D) ; + } + } + + /** + * Construct an instance of this class with the specified sensors. + * + * @param sensor2D the 2D valuator whose X and Y values drive the + * rotation + * @param sensor6D the 6DOF sensor to use if the rotation coordinate + * system is set to SENSOR or the rotation center source + * is HOTSPOT; may be null + */ + public RotationListener2D(Sensor sensor2D, Sensor sensor6D) { + this.sensor2D = sensor2D ; + this.sensor6D = sensor6D ; + + if (rotationUnits == DEGREES) + speedScaled = rotationSpeed * Math.PI / 180.0 ; + else + speedScaled = rotationSpeed ; + } + + public void read(SensorEvent e) { + sensor2D.getRead(sensor2DRead) ; + sensor2DRead.get(m) ; + + if (m[x2D] > threshold2D || m[x2D] < -threshold2D || + m[y2D] > threshold2D || m[y2D] < -threshold2D) { + // Initialize action on threshold crossing. + if (!isActive()) initAction(sensor6D) ; + + // m[x2D] is the X valuator value and m[y2D] is the Y valuator + // value. Use these to construct the rotation axis. + double length = Math.sqrt(m[x2D]*m[x2D] + m[y2D]*m[y2D]) ; + double iLength = 1.0/length ; + axis.set(m[y2D]*iLength, -m[x2D]*iLength, 0.0) ; + + if (sensor6D != null) { + // To avoid echo frame lag, compute sensorToVworld based + // on computed trackerToVworld. getSensorToVworld() isn't + // current for this frame. + sensor6D.getRead(sensorToTracker) ; + sensorToVworld.mul(trackerToVworld, sensorToTracker) ; + } + + // Transform rotation axis into target coordinate system. + if (sensor6D != null && rotationCoords == SENSOR) { + if (nominalSensorRotation != null) + nominalSensorRotation.transform(axis) ; + + sensorToVworld.transform(axis) ; + } + else if (rotationCoords == HEAD) { + view.getUserHeadToVworld(headToVworld) ; + headToVworld.transform(axis) ; + } + else { + viewPlatformToVworld.transform(axis) ; + } + + // Get the rotation center. + if (transformCenterSource == HOTSPOT && sensor6D != null) { + sensor6D.getHotspot(center) ; + sensorToVworld.transform(center) ; + } + else { + center.set(transformCenter) ; + } + + double frameTime = 1.0 ; + if (rotationTimeBase == PER_SECOND) + frameTime = (e.getTime() - e.getLastTime()) / 1e9 ; + + // Construct origin-based rotation about axis. + aa4d.set(axis, speedScaled * frameTime * length) ; + t3d.set(aa4d) ; + + // Apply the rotation to the view platform. + transformAboutCenter(viewPlatformToVworld, center, t3d) ; + targetTG.setTransform(viewPlatformToVworld) ; + + if (sensor6D != null) { + // Apply the rotation to trackerToVworld. + transformAboutCenter(trackerToVworld, center, t3d) ; + } + + if (sensor6D != null && readAction6D == ECHO) { + // Transform sensor echo to compensate for the new view + // platform movement. + transformAboutCenter(sensorToVworld, center, t3d) ; + updateEcho(sensor6D, sensorToVworld) ; + } + } + else { + // Initialize action on next threshold crossing. + if (isActive()) endAction(sensor6D) ; + } + } + + public void pressed(SensorEvent e) { + initAction(sensor6D) ; + } + + public void released(SensorEvent e) { + if (isActive()) endAction(sensor6D) ; + } + + public void dragged(SensorEvent e) { + read(e) ; + } + } + + /** + * Implements a 2D valuator listener that translates the view platform. + * The X and Y values from the valuator should have a continuous range + * from -1.0 to +1.0, although the translation speed can be scaled to + * compensate for a different range. The X and Y values are found in the + * sensor's read matrix at the indices specified by + * setMatrixIndices2D, with defaults of 3 and 7 respectively. + *

+ * The translation direction is controlled by the direction the 2D + * valuator is pushed, and the speed is the translation speed scaled by + * the fast speed factor and the magnitude of the 2D valuator reads. + *

+ * This listener will work in conjunction with a 6DOF sensor if supplied + * in the constructor. If a 6DOF sensor is provided then the translation + * occurs along the basis vectors of the 6DOF sensor's coordinate system; + * otherwise, the translation occurs along the view platform's basis + * vectors. + * + * @see #setReadAction2D + * @see #setButtonAction2D + * @see #setTranslationSpeed + * @see #setFastSpeedFactor + * @see #setThreshold2D + * @see #setMatrixIndices2D + */ + public class TranslationListener2D extends ListenerBase { + private Sensor sensor2D, sensor6D ; + private double[] m = new double[16] ; + private Vector3d v3d = new Vector3d() ; + private Transform3D sensor2DRead = new Transform3D() ; + private double speedScaled ; + + protected void initAction(Sensor s) { + super.initAction(s) ; + if (s != null && readAction6D == ECHO) { + // Disable the 6DOF echo. It will be updated in this action. + eventAgent.removeSensorReadListener(s, echoReadListener6D) ; + } + } + + protected void endAction(Sensor s) { + super.endAction(s) ; + if (s != null && readAction6D == ECHO) { + // Enable the 6DOF sensor echo. + eventAgent.addSensorReadListener(s, echoReadListener6D) ; + } + } + + /** + * Construct an instance of this class using the specified sensors. + * + * @param sensor2D 2D valuator sensor for translation + * @param sensor6D 6DOF sensor for translation direction; may be + * null + */ + public TranslationListener2D(Sensor sensor2D, Sensor sensor6D) { + this.sensor2D = sensor2D ; + this.sensor6D = sensor6D ; + + // Apply virtual to physical scale if needed. + if (translationUnits == VIRTUAL_UNITS) + speedScaled = translationSpeed * + fastSpeedFactor / getPhysicalToVirtualScale() ; + else + speedScaled = translationSpeed * fastSpeedFactor ; + + // Apply physical to view platform scale if needed. + if (sensor6D == null) + speedScaled *= getPhysicalToViewPlatformScale() ; + } + + public void read(SensorEvent e) { + sensor2D.getRead(sensor2DRead) ; + sensor2DRead.get(m) ; + + if (m[x2D] > threshold2D || m[x2D] < -threshold2D || + m[y2D] > threshold2D || m[y2D] < -threshold2D) { + // Initialize action on threshold crossing. + if (!isActive()) initAction(sensor6D) ; + + // m[x2D] is the X valuator value and m[y2D] is the Y valuator + // value. Use these to construct the translation vector. + double length = Math.sqrt(m[x2D]*m[x2D] + m[y2D]*m[y2D]) ; + double iLength = 1.0/length ; + v3d.set(m[x2D]*iLength, 0.0, -m[y2D]*iLength) ; + + // Transform translation vector into target coordinate system. + if (sensor6D != null) { + if (nominalSensorRotation != null) + nominalSensorRotation.transform(v3d) ; + + // To avoid echo frame lag, compute sensorToVworld based + // on computed trackerToVworld. getSensorToVworld() isn't + // current for this frame. + sensor6D.getRead(sensorToTracker) ; + sensorToVworld.mul(trackerToVworld, sensorToTracker) ; + sensorToVworld.transform(v3d) ; + } + else { + viewPlatformToVworld.transform(v3d) ; + } + + double frameTime = 1.0 ; + if (translationTimeBase == PER_SECOND) + frameTime = (e.getTime() - e.getLastTime()) / 1e9 ; + + v3d.scale(frameTime * speedScaled * length) ; + + // Translate the view platform. + translateTransform(viewPlatformToVworld, v3d) ; + targetTG.setTransform(viewPlatformToVworld) ; + + if (sensor6D != null) { + // Apply the translation to trackerToVworld. + translateTransform(trackerToVworld, v3d) ; + } + + if (sensor6D != null && readAction6D == ECHO) { + // Translate sensor echo to compensate for the new view + // platform movement. + translateTransform(sensorToVworld, v3d) ; + updateEcho(sensor6D, sensorToVworld) ; + } + } + else { + // Initialize action on next threshold crossing. + if (isActive()) endAction(sensor6D) ; + } + } + + public void pressed(SensorEvent e) { + initAction(sensor6D) ; + } + + public void released(SensorEvent e) { + if (isActive()) endAction(sensor6D) ; + } + + public void dragged(SensorEvent e) { + read(e) ; + } + } + + /** + * Implements a 2D valuator listener that scales the view platform. + * Pushing the valuator forwards gives the appearance of the virtual world + * increasing in size, while pushing the valuator backwards makes the + * virtual world appear to shrink. The X and Y values from the valuator + * should have a continuous range from -1.0 to +1.0, although the scale + * speed can be adjusted to compensate for a different range. + *

+ * This listener will work in conjunction with a 6DOF sensor if supplied + * in the constructor. If setTransformCenterSource has been + * called with the value HOTSPOT, then scaling is about the + * 6DOF sensor's hotspot; otherwise, the scaling center is the value set + * by setTransformCenter. + * + * @see #setReadAction2D + * @see #setButtonAction2D + * @see #setScaleSpeed + * @see #setTransformCenter + * @see #setThreshold2D + * @see #setMatrixIndices2D + */ + public class ScaleListener2D extends ListenerBase { + private Sensor sensor2D, sensor6D ; + private double[] m = new double[16] ; + private Point3d center = new Point3d() ; + private Transform3D t3d = new Transform3D() ; + private Transform3D sensor2DRead = new Transform3D() ; + + protected void initAction(Sensor s) { + super.initAction(s) ; + if (s != null && readAction6D == ECHO) { + // Disable the 6DOF echo. It will be updated in this action. + eventAgent.removeSensorReadListener(s, echoReadListener6D) ; + } + } + + protected void endAction(Sensor s) { + super.endAction(s) ; + conditionViewScale(viewPlatformToVworld) ; + if (s != null && readAction6D == ECHO) { + // Enable the 6DOF sensor echo. + eventAgent.addSensorReadListener(s, echoReadListener6D) ; + } + } + + /** + * Construct an instance of this class with the specified sensors. + * + * @param sensor2D the 2D valuator whose Y value drive the scaling + * @param sensor6D the 6DOF sensor to use if the rotation/scale center + * source is HOTSPOT; may be null + */ + public ScaleListener2D(Sensor sensor2D, Sensor sensor6D) { + this.sensor2D = sensor2D ; + this.sensor6D = sensor6D ; + } + + public void read(SensorEvent e) { + sensor2D.getRead(sensor2DRead) ; + sensor2DRead.get(m) ; + + if (m[y2D] > threshold2D || m[y2D] < -threshold2D) { + // Initialize action on threshold crossing. + if (!isActive()) initAction(sensor6D) ; + + if (sensor6D != null) { + // To avoid echo frame lag, compute sensorToVworld based + // on computed trackerToVworld. getSensorToVworld() isn't + // current for this frame. + sensor6D.getRead(sensorToTracker) ; + sensorToVworld.mul(trackerToVworld, sensorToTracker) ; + } + + // Get the scale center. + if (sensor6D != null && transformCenterSource == HOTSPOT) { + sensor6D.getHotspot(center) ; + sensorToVworld.transform(center) ; + } + else { + center.set(transformCenter) ; + } + + // Compute incremental scale for this frame. + double frameTime = 1.0 ; + if (scaleTimeBase == PER_SECOND) + frameTime = (e.getTime() - e.getLastTime()) / 1e9 ; + + // Map range: [-1.0 .. 0 .. 1.0] to: + // [scaleSpeed**frameTime .. 1 .. 1.0/(scaleSpeed**frameTime)] + double scale = Math.pow(scaleSpeed, (-m[y2D]*frameTime)) ; + + // Apply the scale to the view platform. + t3d.set(scale) ; + transformAboutCenter(viewPlatformToVworld, center, t3d) ; + + // Incremental scaling at the extremes can lead to numerical + // instability, so catch BadTransformException to prevent the + // behavior thread from being killed. Using a cumulative + // scale matrix avoids this problem to a better extent, but + // causes the 6DOF sensor hotspot center to jitter + // excessively. + try { + targetTG.setTransform(viewPlatformToVworld) ; + } + catch (BadTransformException bt) { + conditionViewScale(viewPlatformToVworld) ; + } + + if (sensor6D != null) { + // Apply the scale to trackerToVworld. + transformAboutCenter(trackerToVworld, center, t3d) ; + } + + if (sensor6D != null && readAction6D == ECHO) { + // Scale sensor echo to compensate for the new view + // platform scale. + transformAboutCenter(sensorToVworld, center, t3d) ; + updateEcho(sensor6D, sensorToVworld) ; + } + } + else { + // Initialize action on next threshold crossing. + if (isActive()) endAction(sensor6D) ; + } + } + + public void pressed(SensorEvent e) { + initAction(sensor6D) ; + } + + public void released(SensorEvent e) { + if (isActive()) endAction(sensor6D) ; + } + + public void dragged(SensorEvent e) { + read(e) ; + } + } + + /** + * Resets the view back to the home transform when a specified number of + * buttons are down simultaneously. + * + * @see #setResetViewButtonCount6D + * @see ViewPlatformBehavior#setHomeTransform + * ViewPlatformBehavior.setHomeTransform + */ + public class ResetViewListener extends SensorInputAdaptor { + private int resetCount ; + private int[] buttonState = null ; + private boolean goHomeNextRead = false ; + + /** + * Creates a sensor listener that resets the view when the specified + * number of buttons are down simultaneously. + * + * @param s the sensor to listen to + * @param count the number of buttons that must be down simultaneously + */ + public ResetViewListener(Sensor s, int count) { + resetCount = count ; + buttonState = new int[s.getSensorButtonCount()] ; + } + + public void pressed(SensorEvent e) { + int count = 0 ; + e.getButtonState(buttonState) ; + for (int i = 0 ; i < buttonState.length ; i++) + if (buttonState[i] == 1) count++ ; + + if (count >= resetCount) + // Ineffectual to reset immediately while other listeners may + // be setting the view transform. + goHomeNextRead = true ; + } + + public void read(SensorEvent e) { + if (goHomeNextRead) { + goHome() ; + goHomeNextRead = false ; + } + } + } + + /** + * Updates the echo position and orientation. The echo is placed at the + * sensor hotspot position if applicable. This implementation assumes the + * hotspot position and orientation have been incorporated into the echo + * geometry. + * + * @param sensor the sensor to be echoed + * @param sensorToVworld transform from sensor coordinates to virtual + * world coordinates + * @see #setEchoType + * @see #setEchoSize + * @see #setReadAction6D + * @see SensorGnomonEcho + * @see SensorBeamEcho + */ + protected void updateEcho(Sensor sensor, Transform3D sensorToVworld) { + echoTransformGroup.setTransform(sensorToVworld) ; + } + + /** + * Property which sets a 6DOF sensor for manipulating the view platform. + * This sensor must generate 6 degree of freedom orientation and position + * data in physical meters relative to the sensor's tracker base. + *

+ * This property is set in the configuration file. The first command form + * assumes that a ViewingPlatform is being used and that the + * sensor name can be looked up from a ConfiguredUniverse + * reference retrieved from ViewingPlatform.getUniverse. The + * second form is preferred and accepts the Sensor reference directly. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * Sensor6D <sensorName>) + *

+ * Alternative Syntax:
(ViewPlatformBehaviorProperty + * <name> Sensor6D (Sensor <sensorName>)) + * + * @param sensor array of length 1 containing a String or + * a Sensor + */ + public void Sensor6D(Object[] sensor) { + if (sensor.length != 1) + throw new IllegalArgumentException + ("Sensor6D requires a single name or Sensor instance") ; + + if (sensor[0] instanceof String) + sensor6DName = (String)sensor[0] ; + else if (sensor[0] instanceof Sensor) + sensor6D = (Sensor)sensor[0] ; + else + throw new IllegalArgumentException + ("Sensor6D must be a name or a Sensor instance") ; + } + + /** + * Returns a reference to the 6DOF sensor used for manipulating the view + * platform. + * + * @return the 6DOF sensor + */ + public Sensor getSensor6D() { + return sensor6D ; + } + + /** + * Property which sets a 2D sensor for manipulating the view platform. + * This is intended to support devices which incorporate a separate 2D + * valuator along with the 6DOF sensor. The X and Y values from the + * valuator should have a continuous range from -1.0 to +1.0, although + * rotation, translation, and scaling speeds can be scaled to compensate + * for a different range. The X and Y values are found in the sensor's + * read matrix at the indices specified by the + * MatrixIndices2D property, with defaults of 3 and 7 + * (the X and Y translation components) respectively. + *

+ * This property is set in the configuration file. The first command form + * assumes that a ViewingPlatform is being used and that the + * sensor name can be looked up from a ConfiguredUniverse + * reference retrieved from ViewingPlatform.getUniverse. The + * second form is preferred and accepts the Sensor reference directly. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * Sensor2D <sensorName>) + *

+ * Alternative Syntax:
(ViewPlatformBehaviorProperty + * <name> Sensor2D (Sensor <sensorName>)) + * + * @param sensor array of length 1 containing a String or + * a Sensor + */ + public void Sensor2D(Object[] sensor) { + if (sensor.length != 1) + throw new IllegalArgumentException + ("Sensor2D requires a single name or Sensor instance") ; + + if (sensor[0] instanceof String) + sensor2DName = (String)sensor[0] ; + else if (sensor[0] instanceof Sensor) + sensor2D = (Sensor)sensor[0] ; + else + throw new IllegalArgumentException + ("Sensor2D must be a name or a Sensor instance") ; + } + + /** + * Returns a reference to the 2D valuator used for manipulating the view + * platform. + * + * @return the 2D valuator + */ + public Sensor getSensor2D() { + return sensor2D ; + } + + /** + * Property which sets a button action for the 6DOF sensor. The choices + * are TranslateForward, TranslateBackward, + * GrabView, RotateCCW, RotateCW, + * ScaleUp, ScaleDown, or None. By + * default, button 0 is bound to GrabView, button 1 is bound + * to TranslateForward, and button 2 is bound to + * TranslateBackward. If there are fewer than three buttons + * available, then the default button actions with the lower button + * indices have precedence. A value of None indicates that + * no default action is to be associated with the specified button. + *

+ * TranslateForward moves the view platform forward along the + * direction the sensor is pointing. TranslateBackward does + * the same, in the opposite direction. GrabView directly + * manipulates the view by moving it in inverse response to the sensor's + * position and orientation. RotateCCW and + * RotateCW rotate about a Y axis, while ScaleUp + * and ScaleDown scale the view platform larger and smaller. + *

+ * Specifying a button index that is greater than that available with the + * 6DOF sensor will result in an ArrayOutOfBoundsException + * when the behavior is initialized or attached to a + * ViewingPlatform. + *

+ * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * ButtonAction6D <button index> + * [GrabView | TranslateForward | TranslateBackward | RotateCCW | + * RotateCW | ScaleUp | ScaleDown | None]) + * + * @param action array of length 2 containing a Double and a + * String. + * @see #setButtonAction6D + * @see #Sensor6D Sensor6D + * @see #TranslationSpeed TranslationSpeed + * @see #AccelerationTime AccelerationTime + * @see #ConstantSpeedTime ConstantSpeedTime + * @see #FastSpeedFactor FastSpeedFactor + * @see #RotationSpeed RotationSpeed + * @see #RotationCoords RotationCoords + * @see #ScaleSpeed ScaleSpeed + * @see #TransformCenterSource TransformCenterSource + * @see #TransformCenter TransformCenter + * @see GrabViewListener6D + * @see TranslationListener6D + * @see RotationListener6D + * @see ScaleListener6D + */ + public void ButtonAction6D(Object[] action) { + if (! (action.length == 2 && + action[0] instanceof Double && action[1] instanceof String)) + throw new IllegalArgumentException + ("\nButtonAction6D must be a number and a string") ; + + int button = ((Double)action[0]).intValue() ; + String actionString = (String)action[1] ; + + if (actionString.equals("GrabView")) + setButtonAction6D(button, GRAB_VIEW) ; + else if (actionString.equals("TranslateForward")) + setButtonAction6D(button, TRANSLATE_FORWARD) ; + else if (actionString.equals("TranslateBackward")) + setButtonAction6D(button, TRANSLATE_BACKWARD) ; + else if (actionString.equals("RotateCCW")) + setButtonAction6D(button, ROTATE_CCW) ; + else if (actionString.equals("RotateCW")) + setButtonAction6D(button, ROTATE_CW) ; + else if (actionString.equals("ScaleUp")) + setButtonAction6D(button, SCALE_UP) ; + else if (actionString.equals("ScaleDown")) + setButtonAction6D(button, SCALE_DOWN) ; + else if (actionString.equals("None")) + setButtonAction6D(button, NONE) ; + else + throw new IllegalArgumentException + ("\nButtonAction6D must be GrabView, TranslateForward, " + + "TranslateBackward, RotateCCW, RotateCW, ScaleUp, " + + "ScaleDown, or None") ; + } + + /** + * Sets a button action for the 6DOF sensor. The choices are + * TRANSLATE_FORWARD, TRANSLATE_BACKWARD, + * GRAB_VIEW, ROTATE_CCW, + * ROTATE_CW, SCALE_UP, SCALE_DOWN, + * or NONE. By default, button 0 is bound to + * GRAB_VIEW, button 1 is bound to + * TRANSLATE_FORWARD, and button 2 is bound to + * TRANSLATE_BACKWARD. If there are fewer than three buttons + * available, then the default button actions with the lower button + * indices have precedence. A value of NONE indicates that + * no default action is to be associated with the specified button. + *

+ * TRANSLATE_FORWARD moves the view platform forward along + * the direction the sensor is pointing. TRANSLATE_BACKWARD + * does the same, in the opposite direction. GRAB_VIEW + * directly manipulates the view by moving it in inverse response to the + * sensor's position and orientation. ROTATE_CCW and + * ROTATE_CW rotate about a Y axis, while + * SCALE_UP and SCALE_DOWN scale the view + * platform larger and smaller. + *

+ * Specifying a button index that is greater that that available with the + * 6DOF sensor will result in an ArrayOutOfBoundsException + * when the behavior is initialized or attached to a + * ViewingPlatform. + *

+ * This method only configures the button listeners pre-defined by + * this behavior. For complete control over the button actions, access + * the SensorEventAgent used by this behavior directly. + * + * @param button index of the button to bind + * @param action either TRANSLATE_FORWARD, + * TRANSLATE_BACKWARD, GRAB_VIEW, + * ROTATE_CCW, ROTATE_CW, SCALE_UP, + * SCALE_DOWN, or NONE + * @see #setTranslationSpeed + * @see #setAccelerationTime + * @see #setConstantSpeedTime + * @see #setFastSpeedFactor + * @see #setRotationSpeed + * @see #setRotationCoords + * @see #setScaleSpeed + * @see #setTransformCenterSource + * @see #setTransformCenter + * @see #getSensorEventAgent + * @see GrabViewListener6D + * @see TranslationListener6D + * @see RotationListener6D + * @see ScaleListener6D + */ + public synchronized void setButtonAction6D(int button, int action) { + if (! (action == TRANSLATE_FORWARD || action == TRANSLATE_BACKWARD || + action == GRAB_VIEW || action == ROTATE_CCW || + action == ROTATE_CW || action == SCALE_UP || + action == SCALE_DOWN || action == NONE)) + throw new IllegalArgumentException + ("\naction must be TRANSLATE_FORWARD, TRANSLATE_BACKWARD, " + + "GRAB_VIEW, ROTATE_CCW, ROTATE_CW, SCALE_UP, SCALE_DOWN, " + + "or NONE") ; + + while (button >= buttonActions6D.size()) { + buttonActions6D.add(null) ; + } + buttonActions6D.set(button, new Integer(action)) ; + } + + + /** + * Gets the action associated with the specified button on the 6DOF sensor. + * + * @return the action associated with the button + */ + public int getButtonAction6D(int button) { + if (button >= buttonActions6D.size()) + return NONE ; + + Integer i = (Integer)buttonActions6D.get(button) ; + if (i == null) + return NONE ; + else + return i.intValue() ; + } + + /** + * Property which sets the action to be bound to 2D valuator reads. This + * action will be performed on each frame whenever no button actions have + * been invoked and the valuator read value is greater than the threshold + * range specified by the Threshold2D property. + *

+ * The X and Y values from the valuator should have a continuous range + * from -1.0 to +1.0, although speeds can be scaled to compensate for a + * different range. The X and Y values are found in the sensor's read + * matrix at the indices specified by MatrixIndices2D, with + * defaults of 3 and 7 respectively. + *

+ * The default property value of Rotation rotates the view + * platform in the direction the valuator is pushed. The rotation + * coordinate system is set by the RotationCoords property, + * with a default of Sensor. The rotation occurs about a + * point in the virtual world set by the + * TransformCenterSource and TransformCenter + * properties, with the default set to rotate about the hotspot of a 6DOF + * sensor, if one is available, or about the origin of the virtual world + * if not. The rotation speed is scaled by the valuator read value up to + * the maximum speed set with the RotationSpeed property; the + * default is 180 degrees per second. + *

+ * A property value of Translation moves the view platform in + * the direction the valuator is pushed. The translation occurs along the + * X and Z basis vectors of either a 6DOF sensor or the view platform if a + * 6DOF sensor is not specified. The translation speed is scaled by the + * valuator read value up to a maximum set by the product of the + * TranslationSpeed and FastSpeedFactor property + * values. + *

+ * If this property value is to Scale, then the view platform + * is scaled smaller or larger when the valuator is pushed forward or + * backward. The scaling occurs about a point in the virtual world set by + * the TransformCenterSource and TransformCenter + * properties. The scaling speed is set with the ScaleSpeed + * property, with a default scale factor of 2.0 per second at the extreme + * negative range of -1.0, and a factor of 0.5 per second at the extreme + * positive range of +1.0. + *

+ * A value of None prevents Rotation from being + * bound to the 2D valuator reads. + *

+ * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * ReadAction2D [Rotation | Translation | Scale | None]) + * + * @param action array of length 1 containing a String + * @see #setReadAction2D + * @see #RotationCoords RotationCoords + * @see #RotationSpeed RotationSpeed + * @see #TransformCenterSource TransformCenterSource + * @see #TransformCenter TransformCenter + * @see #TranslationSpeed TranslationSpeed + * @see #FastSpeedFactor FastSpeedFactor + * @see #ScaleSpeed ScaleSpeed + * @see #MatrixIndices2D MatrixIndices2D + * @see RotationListener2D + * @see TranslationListener2D + * @see ScaleListener2D + */ + public void ReadAction2D(Object[] action) { + if (! (action.length == 1 && action[0] instanceof String)) + throw new IllegalArgumentException + ("\nReadAction2D must be a String") ; + + String actionString = (String)action[0] ; + + if (actionString.equals("Rotation")) + setReadAction2D(ROTATION) ; + else if (actionString.equals("Translation")) + setReadAction2D(TRANSLATION) ; + else if (actionString.equals("Scale")) + setReadAction2D(SCALE) ; + else if (actionString.equals("None")) + setReadAction2D(NONE) ; + else + throw new IllegalArgumentException + ("\nReadAction2D must be Rotation, Translation, Scale, " + + "or None") ; + } + + /** + * Sets the action to be bound to 2D valuator reads. This action will be + * performed on each frame whenever no button actions have been invoked + * and the valuator read value is greater than the threshold range + * specified by setThreshold2D. + *

+ * The X and Y values from the valuator should have a continuous range + * from -1.0 to +1.0, although speeds can be scaled to compensate for a + * different range. The X and Y values are found in the sensor's read + * matrix at the indices specified by the setMatrixIndices2D + * method, with defaults of 3 and 7 respectively. + *

+ * The default action of ROTATION rotates the view platform + * in the direction the valuator is pushed. The rotation coordinate + * system is set by setRotationCoords, with a default of + * SENSOR. The rotation occurs about a point in the virtual + * world set by setTransformCenterSource and + * setTransformCenter, with the default set to rotate about + * the hotspot of a 6DOF sensor, if one is available, or about the origin + * of the virtual world if not. The rotation speed is scaled by the + * valuator read value up to the maximum speed set with + * setRotationSpeed; the default is 180 degrees per second. + *

+ * A value of TRANSLATION moves the view platform in the + * direction the valuator is pushed. The translation occurs along the X + * and Z basis vectors of either a 6DOF sensor or the view platform if a + * 6DOF sensor is not specified. The translation speed is scaled by the + * valuator read value up to a maximum set by the product of the + * setTranslationSpeed and setFastSpeedFactor + * values. + *

+ * If the value is to SCALE, then the view platform is scaled + * smaller or larger when the valuator is pushed forward or backward. The + * scaling occurs about a point in the virtual world set by + * setTransformCenterSource and + * setTransformCenter. The scaling speed is set with + * setScaleSpeed, with a default scale factor of 2.0 per + * second at the extreme negative range of -1.0, and a factor of 0.5 per + * second at the extreme positive range of +1.0. + *

+ * A value of NONE prevents ROTATION from being + * bound by default to the 2D valuator reads. + *

+ * This method only configures the read listeners pre-defined by + * this behavior. For complete control over the read actions, access + * the SensorEventAgent used by this behavior directly. + * + * @param action either ROTATION, TRANSLATION, + * SCALE, or NONE + * @see #setRotationCoords + * @see #setRotationSpeed + * @see #setTransformCenterSource + * @see #setTransformCenter + * @see #setTranslationSpeed + * @see #setFastSpeedFactor + * @see #setScaleSpeed + * @see #setMatrixIndices2D + * @see #getSensorEventAgent + * @see RotationListener2D + * @see TranslationListener2D + * @see ScaleListener2D + */ + public void setReadAction2D(int action) { + if (! (action == ROTATION || action == TRANSLATION || + action == SCALE || action == NONE)) + throw new IllegalArgumentException + ("\nReadAction2D must be ROTATION, TRANSLATION, SCALE, " + + "or NONE") ; + + this.readAction2D = action ; + } + + /** + * Gets the configured 2D valuator read action. + * + * @return the action associated with the sensor read + */ + public int getReadAction2D() { + if (readAction2D == UNSET) + return NONE ; + else + return readAction2D ; + } + + /** + * Property which sets a button action for the 2D valuator. The possible + * values are Rotation, Translation, + * Scale, or None, with a default of + * None. These actions are the same as those for + * ReadAction2D. + *

+ * Specifying a button index that is greater that that available with the + * 2D valuator will result in an ArrayOutOfBoundsException + * when the behavior is initialized or attached to a + * ViewingPlatform. + *

+ * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * ButtonAction2D <button index> + * [Rotation | Translation | Scale | None]) + * + * @param action array of length 2 containing a Double and a + * String. + * @see #setButtonAction2D + * @see #ReadAction2D ReadAction2D + * @see #RotationCoords RotationCoords + * @see #RotationSpeed RotationSpeed + * @see #TransformCenterSource TransformCenterSource + * @see #TransformCenter TransformCenter + * @see #TranslationSpeed TranslationSpeed + * @see #FastSpeedFactor FastSpeedFactor + * @see #ScaleSpeed ScaleSpeed + * @see #MatrixIndices2D MatrixIndices2D + * @see RotationListener2D + * @see TranslationListener2D + * @see ScaleListener2D + */ + public void ButtonAction2D(Object[] action) { + if (! (action.length == 2 && + action[0] instanceof Double && action[1] instanceof String)) + throw new IllegalArgumentException + ("\nButtonAction2D must be a number and a string") ; + + int button = ((Double)action[0]).intValue() ; + String actionString = (String)action[1] ; + + if (actionString.equals("Rotation")) + setButtonAction2D(button, ROTATION) ; + else if (actionString.equals("Translation")) + setButtonAction2D(button, TRANSLATION) ; + else if (actionString.equals("Scale")) + setButtonAction2D(button, SCALE) ; + else if (actionString.equals("None")) + setButtonAction2D(button, NONE) ; + else + throw new IllegalArgumentException + ("\nButtonAction2D must be Rotation, Translation, Scale " + + "or None") ; + } + + /** + * Sets a button action for the 2D valuator. The possible values are + * ROTATION, TRANSLATION, SCALE, or + * NONE, with a default of NONE. These actions + * are the same as those for setReadAction2D. + *

+ * Specifying a button index that is greater that that available with the + * 2D valuator will result in an ArrayOutOfBoundsException + * when the behavior is initialized or attached to a + * ViewingPlatform. + *

+ * This method only configures the button listeners pre-defined by + * this behavior. For complete control over the button actions, access + * the SensorEventAgent used by this behavior directly. + * + * @param button index of the button to bind + * @param action either ROTATION, TRANSLATION, + * SCALE, or NONE + * @see #setReadAction2D + * @see #setRotationCoords + * @see #setRotationSpeed + * @see #setTransformCenterSource + * @see #setTransformCenter + * @see #setTranslationSpeed + * @see #setFastSpeedFactor + * @see #setScaleSpeed + * @see #setMatrixIndices2D + * @see #getSensorEventAgent + * @see RotationListener2D + * @see TranslationListener2D + * @see ScaleListener2D + */ + public synchronized void setButtonAction2D(int button, int action) { + if (! (action == ROTATION || action == TRANSLATION || + action == SCALE || action == NONE)) + throw new IllegalArgumentException + ("\naction must be ROTATION, TRANSLATION, SCALE, or NONE") ; + + while (button >= buttonActions2D.size()) { + buttonActions2D.add(null) ; + } + buttonActions2D.set(button, new Integer(action)) ; + } + + + /** + * Gets the action associated with the specified button on the 2D valuator. + * + * @return the action associated with the button + */ + public int getButtonAction2D(int button) { + if (button >= buttonActions2D.size()) + return NONE ; + + Integer i = (Integer)buttonActions2D.get(button) ; + if (i == null) + return NONE ; + else + return i.intValue() ; + } + + /** + * Property which sets the action to be bound to 6DOF sensor reads. This + * action will be performed every frame whenever a button action has not + * been invoked. + *

+ * The default is Echo, which displays a geometric + * representation of the sensor's current position and orientation in the + * virtual world. A value of None indicates that no default + * action is to be applied to the sensor's read. + *

+ * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * ReadAction6D [Echo | None]) + * + * @param action array of length 1 containing a String + * @see #setReadAction6D + * @see EchoReadListener6D + */ + public void ReadAction6D(Object[] action) { + if (! (action.length == 1 && action[0] instanceof String)) + throw new IllegalArgumentException + ("\nReadAction6D must be a String") ; + + String actionString = (String)action[0] ; + + if (actionString.equals("Echo")) + setReadAction6D(ECHO) ; + else if (actionString.equals("None")) + setReadAction6D(NONE) ; + else + throw new IllegalArgumentException + ("\nReadAction6D must be Echo or None") ; + } + + /** + * Sets the action to be bound to 6DOF sensor reads. This action will be + * performed every frame whenever a button action has not been invoked. + *

+ * The default is ECHO, which displays a geometric + * representation of the sensor's current position and orientation in the + * virtual world. A value of NONE indicates that no default + * action is to be associated with the sensor's read. + *

+ * This method only configures the read listeners pre-defined by + * this behavior. For complete control over the read actions, access + * the SensorEventAgent used by this behavior directly. + * + * @param action either ECHO or NONE + * @see EchoReadListener6D + * @see #getSensorEventAgent + */ + public void setReadAction6D(int action) { + if (! (action == ECHO || action == NONE)) + throw new IllegalArgumentException + ("\naction must be ECHO or NONE") ; + + this.readAction6D = action ; + } + + /** + * Gets the configured 6DOF sensor read action. + * + * @return the configured 6DOF sensor read action + */ + public int getReadAction6D() { + if (readAction6D == UNSET) + return NONE ; + else + return readAction6D ; + } + + /** + * Property which sets the normal translation speed. The default is 0.1 + * meters/second in physical units. This property is set in the + * configuration file read by ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * TranslationSpeed <speed> [PhysicalMeters | VirtualUnits] + * [PerFrame | PerSecond]) + * + * @param speed array of length 3; first element is a Double + * for the speed, the second is a String for the units, and + * the third is a String for the time base + * @see #setTranslationSpeed + */ + public void TranslationSpeed(Object[] speed) { + if (! (speed.length == 3 && speed[0] instanceof Double && + speed[1] instanceof String && speed[2] instanceof String)) + throw new IllegalArgumentException + ("\nTranslationSpeed must be number, units, and time base") ; + + double v = ((Double)speed[0]).doubleValue() ; + String unitsString = (String)speed[1] ; + String timeBaseString = (String)speed[2] ; + int units, timeBase ; + + if (unitsString.equals("PhysicalMeters")) + units = PHYSICAL_METERS ; + else if (unitsString.equals("VirtualUnits")) + units = VIRTUAL_UNITS ; + else + throw new IllegalArgumentException + ("\nTranslationSpeed units must be " + + "PhysicalMeters or VirtualUnits") ; + + if (timeBaseString.equals("PerFrame")) + timeBase = PER_FRAME ; + else if (timeBaseString.equals("PerSecond")) + timeBase = PER_SECOND ; + else + throw new IllegalArgumentException + ("\ntime base must be PerFrame or PerSecond") ; + + setTranslationSpeed(v, units, timeBase) ; + } + + /** + * Sets the normal translation speed. The default is 0.1 physical + * meters/second. + * + * @param speed how fast to translate + * @param units either PHYSICAL_METERS or + * VIRTUAL_UNITS + * @param timeBase either PER_SECOND or + * PER_FRAME + */ + public void setTranslationSpeed(double speed, int units, int timeBase) { + this.translationSpeed = speed ; + + if (units == PHYSICAL_METERS || units == VIRTUAL_UNITS) + this.translationUnits = units ; + else + throw new IllegalArgumentException + ("\ntranslation speed units must be " + + "PHYSICAL_METERS or VIRTUAL_UNITS") ; + + if (timeBase == PER_FRAME || timeBase == PER_SECOND) + this.translationTimeBase = timeBase ; + else + throw new IllegalArgumentException + ("\ntranslation time base must be PER_FRAME or PER_SECOND") ; + } + + /** + * Gets the normal speed at which to translate the view platform. + * + * @return the normal translation speed + */ + public double getTranslationSpeed() { + return translationSpeed ; + } + + /** + * Gets the translation speed units. + * + * @return the translation units + */ + public int getTranslationUnits() { + return translationUnits ; + } + + /** + * Gets the time base for translation speed. + * + * @return the translation time base + */ + public int getTranslationTimeBase() { + return translationTimeBase ; + } + + /** + * Property which sets the time interval for accelerating to the + * translation, rotation, or scale speeds and for transitioning between + * the normal and fast translation speeds. The default is 1 second. This + * property is set in the configuration file read by + * ConfiguredUniverse.

+ * + * Syntax:
(ViewPlatformBehaviorProperty <name> + * AccelerationTime <seconds>) + * + * @param time array of length 1 containing a Double + * @see #setAccelerationTime + */ + public void AccelerationTime(Object[] time) { + if (! (time.length == 1 && time[0] instanceof Double)) + throw new IllegalArgumentException + ("\nAccelerationTime must be a number") ; + + setAccelerationTime(((Double)time[0]).doubleValue()) ; + } + + /** + * Sets the time interval for accelerating to the translation, rotation, + * or scale speeds and for transitioning between the normal and fast + * translation speeds. The default is 1 second. + * + * @param time number of seconds to accelerate to normal or fast speed + */ + public void setAccelerationTime(double time) { + this.accelerationTime = time ; + } + + /** + * Gets the time interval for accelerating to normal speed and for + * transitioning between the normal and fast translation speeds. + * + * @return the acceleration time + */ + public double getAccelerationTime() { + return accelerationTime ; + } + + /** + * Property which sets the time interval for which the translation occurs + * at the normal speed. The default is 8 seconds. This property is set + * in the configuration file read by ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * ConstantSpeedTime <seconds>) + * + * @param time array of length 1 containing a Double + * @see #setConstantSpeedTime + */ + public void ConstantSpeedTime(Object[] time) { + if (! (time.length == 1 && time[0] instanceof Double)) + throw new IllegalArgumentException + ("\nConstantSpeedTime must be a number") ; + + setConstantSpeedTime(((Double)time[0]).doubleValue()) ; + } + + /** + * Sets the time interval for which the translation occurs at the normal + * speed. The default is 8 seconds. + * + * @param time number of seconds to translate at a constant speed + */ + public void setConstantSpeedTime(double time) { + this.constantSpeedTime = time ; + } + + /** + * Gets the time interval for which the translation occurs at the + * normal speed. + * + * @return the constant speed time + */ + public double getConstantSpeedTime() { + return constantSpeedTime ; + } + + /** + * Property which sets the fast translation speed factor. The default is + * 10 times the normal speed. This property is set in the configuration + * file read by ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * FastSpeedFactor <factor>) + * + * @param factor array of length 1 containing a Double + * @see #setFastSpeedFactor + */ + public void FastSpeedFactor(Object[] factor) { + if (! (factor.length == 1 && factor[0] instanceof Double)) + throw new IllegalArgumentException + ("\nFastSpeedFactor must be a number") ; + + setFastSpeedFactor(((Double)factor[0]).doubleValue()) ; + } + + /** + * Sets the fast translation speed factor. The default is 10 times the + * normal speed. + * + * @param factor scale by which the normal translation speed is multiplied + */ + public void setFastSpeedFactor(double factor) { + this.fastSpeedFactor = factor ; + } + + /** + * Gets the factor by which the normal translation speed is multiplied + * after the constant speed time interval. + * + * @return the fast speed factor + */ + public double getFastSpeedFactor() { + return fastSpeedFactor ; + } + + /** + * Property which sets the threshold for 2D valuator reads. The default + * is 0.0. It can be set higher to handle noisy valuators. This property + * is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * Threshold2D <threshold>) + * + * @param threshold array of length 1 containing a Double + * @see #setThreshold2D + */ + public void Threshold2D(Object[] threshold) { + if (! (threshold.length == 1 && threshold[0] instanceof Double)) + throw new IllegalArgumentException + ("\nThreshold2D must be a number") ; + + setThreshold2D(((Double)threshold[0]).doubleValue()) ; + } + + /** + * Sets the threshold for 2D valuator reads. The default is 0.0. It can + * be set higher to handle noisy valuators. + * + * @param threshold if the absolute values of both the X and Y valuator + * reads are less than this value then the values are ignored + */ + public void setThreshold2D(double threshold) { + this.threshold2D = threshold ; + } + + /** + * Gets the 2D valuator threshold. + * + * @return the threshold value + */ + public double getThreshold2D() { + return threshold2D ; + } + + /** + * Property which specifies where to find the X and Y values in the matrix + * read generated by a 2D valuator. The defaults are along the + * translation components of the matrix, at indices 3 and 7. This + * property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * MatrixIndices2D <X index> <Y index>) + * + * @param indices array of length 2 containing Doubles + * @see #setMatrixIndices2D + */ + public void MatrixIndices2D(Object[] indices) { + if (! (indices.length == 2 && + indices[0] instanceof Double && indices[1] instanceof Double)) + throw new IllegalArgumentException + ("\nMatrixIndices2D must be a numbers") ; + + setMatrixIndices2D(((Double)indices[0]).intValue(), + ((Double)indices[1]).intValue()) ; + } + + /** + * Specifies where to find the X and Y values in the matrix read generated + * by a 2D valuator. The defaults are along the translation components of + * the matrix, at indices 3 and 7. + * + * @param xIndex index of the X valuator value + * @param yIndex index of the Y valuator value + */ + public void setMatrixIndices2D(int xIndex, int yIndex) { + this.x2D = xIndex ; + this.y2D = yIndex ; + } + + /** + * Gets the index where the X value of a 2D valuator read matrix can be + * found. + * + * @return the X index in the read matrix + */ + public int getMatrixXIndex2D() { + return x2D ; + } + + /** + * Gets the index where the Y value of a 2D valuator read matrix can be + * found. + * + * @return the Y index in the read matrix + */ + public int getMatrixYIndex2D() { + return y2D ; + } + + /** + * Property which sets the rotation speed. The default is 180 + * degrees/second. This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * RotationSpeed <speed> [Degrees | Radians] + * [PerFrame | PerSecond]) + * + * @param speed array of length 3; first element is a Double + * for the speed, the second is a String for the units, and + * the third is a String for the time base + * @see #setRotationSpeed + */ + public void RotationSpeed(Object[] speed) { + if (! (speed.length == 3 && speed[0] instanceof Double && + speed[1] instanceof String && speed[2] instanceof String)) + throw new IllegalArgumentException + ("\nRotationSpeed must be number, units, and time base") ; + + double v = ((Double)speed[0]).doubleValue() ; + String unitsString = (String)speed[1] ; + String timeBaseString = (String)speed[2] ; + int units, timeBase ; + + if (unitsString.equals("Degrees")) + units = DEGREES ; + else if (unitsString.equals("Radians")) + units = RADIANS ; + else + throw new IllegalArgumentException + ("\nRotationSpeed units must be Degrees or Radians") ; + + if (timeBaseString.equals("PerFrame")) + timeBase = PER_FRAME ; + else if (timeBaseString.equals("PerSecond")) + timeBase = PER_SECOND ; + else + throw new IllegalArgumentException + ("\nRotationSpeed time base must be PerFrame or PerSecond") ; + + setRotationSpeed(v, units, timeBase) ; + } + + /** + * Sets the rotation speed. The default is 180 degrees/second. + * + * @param speed how fast to rotate + * @param units either DEGREES or RADIANS + * @param timeBase either PER_SECOND or PER_FRAME + */ + public void setRotationSpeed(double speed, int units, int timeBase) { + this.rotationSpeed = speed ; + + if (units == DEGREES || units == RADIANS) + this.rotationUnits = units ; + else + throw new IllegalArgumentException + ("\nrotation speed units must be DEGREES or RADIANS") ; + + if (timeBase == PER_FRAME || timeBase == PER_SECOND) + this.rotationTimeBase = timeBase ; + else + throw new IllegalArgumentException + ("\nrotation time base must be PER_FRAME or PER_SECOND") ; + } + + /** + * Gets the rotation speed. + * + * @return the rotation speed + */ + public double getRotationSpeed() { + return rotationSpeed ; + } + + /** + * Gets the rotation speed units + * + * @return the rotation units + */ + public int getRotationUnits() { + return rotationUnits ; + } + + /** + * Gets the time base for rotation speed. + * + * @return the rotation time base + */ + public int getRotationTimeBase() { + return rotationTimeBase ; + } + + /** + * Property which sets the rotation coordinate system. The default is + * Sensor, which means that the rotation axis is parallel to + * the XY plane of the current orientation of a specified 6DOF sensor. A + * value of ViewPlatform means the rotation axis is parallel + * to the XY plane of the view platform. The latter is also the fallback + * if a 6DOF sensor is not specified. If the value is Head, + * then the rotation occurs in head coordinates. + *

+ * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * RotationCoords [Sensor | ViewPlatform | Head]) + * + * @param coords array of length 1 containing a String + * @see #setRotationCoords + */ + public void RotationCoords(Object[] coords) { + if (! (coords.length == 1 && coords[0] instanceof String)) + throw new IllegalArgumentException + ("\nRotationCoords must be a String") ; + + String coordsString = (String)coords[0] ; + + if (coordsString.equals("Sensor")) + setRotationCoords(SENSOR) ; + else if (coordsString.equals("ViewPlatform")) + setRotationCoords(VIEW_PLATFORM) ; + else if (coordsString.equals("Head")) + setRotationCoords(HEAD) ; + else + throw new IllegalArgumentException + ("\nRotationCoords must be Sensor, ViewPlatform, or Head") ; + } + + /** + * Sets the rotation coordinate system. The default is + * SENSOR, which means that the rotation axis is parallel to + * the XY plane of the current orientation of a specified 6DOF sensor. A + * value of VIEW_PLATFORM means the rotation axis is parallel + * to the XY plane of the view platform. The latter is also the fallback + * if a 6DOF sensor is not specified. If the value is HEAD, + * then rotation occurs in head coordinates. + * + * @param coords either SENSOR, VIEW_PLATFORM, or + * HEAD + */ + public void setRotationCoords(int coords) { + if (! (coords == SENSOR || coords == VIEW_PLATFORM || coords == HEAD)) + throw new IllegalArgumentException + ("\nrotation coordinates be SENSOR, VIEW_PLATFORM, or HEAD") ; + + this.rotationCoords = coords ; + } + + /** + * Gets the rotation coordinate system. + * + * @return the rotation coordinate system + */ + public int getRotationCoords() { + return rotationCoords ; + } + + /** + * Property which sets the scaling speed. The default is 2.0 per second, + * which means magnification doubles the apparent size of the virtual + * world every second, and minification halves the apparent size of the + * virtual world every second. + *

+ * The scaling applied with each frame is Math.pow(scaleSpeed, + * frameTime), where frameTime is the time in seconds + * that the last frame took to render if the time base is + * PerSecond, or 1.0 if the time base is + * PerFrame. If scaling is performed with the 2D valuator, + * then the valuator's Y value as specified by + * MatrixIndices2D is an additional scale applied to the + * exponent. If scaling is performed by the 6DOF sensor, then the scale + * speed can be inverted with a negative exponent by using the appropriate + * listener constructor flag. + *

+ * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * ScaleSpeed <speed> [PerFrame | PerSecond]) + * + * @param speed array of length 2; first element is a Double + * for the speed, and the second is a String for the time + * base + * @see #setScaleSpeed + */ + public void ScaleSpeed(Object[] speed) { + if (! (speed.length == 2 && + speed[0] instanceof Double && speed[1] instanceof String)) + throw new IllegalArgumentException + ("\nScalingSpeed must be a number and a string") ; + + double v = ((Double)speed[0]).doubleValue() ; + String timeBaseString = (String)speed[2] ; + int timeBase ; + + if (timeBaseString.equals("PerFrame")) + timeBase = PER_FRAME ; + else if (timeBaseString.equals("PerSecond")) + timeBase = PER_SECOND ; + else + throw new IllegalArgumentException + ("\nScalingSpeed time base must be PerFrame or PerSecond") ; + + setScaleSpeed(v, timeBase) ; + } + + /** + * Sets the scaling speed. The default is 2.0 per second, which means + * magnification doubles the apparent size of the virtual world every + * second, and minification halves the apparent size of the virtual world + * every second. + *

+ * The scaling applied with each frame is Math.pow(scaleSpeed, + * frameTime), where frameTime is the time in seconds + * that the last frame took to render if the time base is + * PER_SECOND, or 1.0 if the time base is + * PER_FRAME. If scaling is performed with the 2D valuator, + * then the valuator's Y value as specified by + * setMatrixIndices2D is an additional scale applied to the + * exponent. If scaling is performed by the 6DOF sensor, then the scale + * speed can be inverted with a negative exponent by using the appropriate + * listener constructor flag. + * + * @param speed specifies the scale speed + * @param timeBase either PER_SECOND or PER_FRAME + */ + public void setScaleSpeed(double speed, int timeBase) { + this.scaleSpeed = speed ; + + if (timeBase == PER_FRAME || timeBase == PER_SECOND) + this.scaleTimeBase = timeBase ; + else + throw new IllegalArgumentException + ("\nscaling time base must be PER_FRAME or PER_SECOND") ; + } + + /** + * Gets the scaling speed. + * + * @return the scaling speed + */ + public double getScaleSpeed() { + return scaleSpeed ; + } + + /** + * Gets the time base for scaling speed. + * + * @return the scaling time base + */ + public int getScaleTimeBase() { + return scaleTimeBase ; + } + + /** + * Property which sets the source of the center of rotation and scale. + * The default is Hotspot, which means the center of rotation + * or scale is a 6DOF sensor's current hotspot location. The alternative + * is VworldFixed, which uses the fixed virtual world + * coordinates specified by the TransformCenter property as + * the center. The latter is also the fallback if a 6DOF sensor is not + * specified. This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * TransformCenterSource [Hotspot | VworldFixed]) + * + * @param source array of length 1 containing a String + * @see #setTransformCenterSource + */ + public void TransformCenterSource(Object[] source) { + if (! (source.length == 1 && source[0] instanceof String)) + throw new IllegalArgumentException + ("\nTransformCenterSource must be a String") ; + + String sourceString = (String)source[0] ; + + if (sourceString.equals("Hotspot")) + setTransformCenterSource(HOTSPOT) ; + else if (sourceString.equals("VworldFixed")) + setTransformCenterSource(VWORLD_FIXED) ; + else + throw new IllegalArgumentException + ("\nTransformCenterSource must be Hotspot or " + + "VworldFixed") ; + } + + /** + * Sets the source of the center of rotation and scale. The default is + * HOTSPOT, which means the center of rotation or scale is a + * 6DOF sensor's current hotspot location. The alternative is + * VWORLD_FIXED, which uses the fixed virtual world + * coordinates specified by setTransformCenter as the center. + * The latter is also the fallback if a 6DOF sensor is not specified. + *

+ * The transform center source can be dynamically updated while the + * behavior is running. + * + * @param source either HOTSPOT or VWORLD_FIXED + */ + public void setTransformCenterSource(int source) { + if (! (source == HOTSPOT || source == VWORLD_FIXED)) + throw new IllegalArgumentException + ("\nrotation/scale center source must be HOTSPOT or " + + "VWORLD_FIXED") ; + + this.transformCenterSource = source ; + } + + /** + * Gets the rotation/scale center source. + * + * @return the rotation/scale center source + */ + public int getTransformCenterSource() { + return transformCenterSource ; + } + + /** + * Property which sets the center of rotation and scale if the + * TransformCenterSource property is VworldFixed + * or if a 6DOF sensor is not specified. The default is (0.0, 0.0, 0.0) + * in virtual world coordinates. This property is set in the + * configuration file read by ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * TransformCenter <Point3d>) + * + * @param center array of length 1 containing a Point3d + * @see #setTransformCenter + */ + public void TransformCenter(Object[] center) { + if (! (center.length == 1 && center[0] instanceof Point3d)) + throw new IllegalArgumentException + ("\nTransformCenter must be a Point3d") ; + + setTransformCenter((Point3d)center[0]) ; + } + + /** + * Sets the center of rotation and scale if + * setTransformCenterSource is called with + * VWORLD_FIXED or if a 6DOF sensor is not specified. The + * default is (0.0, 0.0, 0.0) in virtual world coordinates. + *

+ * The transform center can be dynamically updated while the behavior is + * running. + * + * @param center point in virtual world coordinates about which to rotate + * and scale + */ + public void setTransformCenter(Point3d center) { + this.transformCenter.set(center) ; + } + + /** + * Gets the rotation/scale center in virtual world coordinates. + * @param center Point3d to receive a copy of the + * rotation/scale center + */ + public void getTransformCenter(Point3d center) { + center.set(transformCenter) ; + } + + /** + * Property which sets the nominal sensor rotation. The default is the + * identity transform. + *

+ * This behavior assumes that when a hand-held wand is pointed directly at + * a screen in an upright position, then its 6DOF sensor's local + * coordinate system axes (its basis vectors) are nominally aligned with + * the image plate basis vectors; specifically, that the sensor's -Z axis + * points toward the screen, the +Y axis points up, and the +X axis points + * to the right. The translation and rotation listeners provided by this + * behavior assume this orientation to determine the transforms to be + * applied to the view platform; for example, translation applies along + * the sensor Z axis, while rotation applies about axes defined in the + * sensor XY plane. + *

+ * This nominal alignment may not hold true depending upon how the sensor + * is mounted and how the specific InputDevice supporting the + * sensor handles its orientation. The NominalSensorRotation + * property can be used to correct the alignment by specifying the + * rotation needed to transform vectors from the nominal sensor coordinate + * system, aligned with the image plate coordinate system as described + * above, to the sensor's actual local coordinate system. + *

+ * NOTE: the nominal sensor transform applies only to the + * translation directions and rotation axes created by the listeners + * defined in this behavior; for compatibility with the core Java 3D API, + * sensor reads and the sensor hotspot location are still expressed in the + * sensor's local coordinate system. + *

+ * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * NominalSensorRotation [<Matrix4d> | + * <Matrix3d>]) + * + * @param matrix array of length 1 containing a Matrix4d or + * Matrix3d + * @see #setNominalSensorRotation + */ + public void NominalSensorRotation(Object[] matrix) { + if (! (matrix.length == 1 && (matrix[0] instanceof Matrix3d || + matrix[0] instanceof Matrix4d))) + throw new IllegalArgumentException + ("\nNominalSensorRotation must be a Matrix3d or Matrix4d") ; + + Transform3D t3d = new Transform3D() ; + + if (matrix[0] instanceof Matrix3d) + t3d.set((Matrix3d)matrix[0]) ; + else + t3d.set((Matrix4d)matrix[0]) ; + + setNominalSensorRotation(t3d) ; + } + + /** + * Sets the nominal sensor transform. The default is the identity + * transform. + *

+ * This behavior assumes that when a hand-held wand is pointed directly at + * a screen in an upright position, then its 6DOF sensor's local + * coordinate system axes (its basis vectors) are nominally aligned with + * the image plate basis vectors; specifically, that the sensor's -Z axis + * points toward the screen, the +Y axis points up, and the +X axis points + * to the right. The translation and rotation listeners provided by this + * behavior assume this orientation to determine the transforms to be + * applied to the view platform, in that translation applies along the + * sensor Z axis, and rotation applies about axes defined in the sensor XY + * plane. + *

+ * This nominal alignment may not hold true depending upon how the sensor + * is mounted and how the specific InputDevice supporting the + * sensor handles its orientation. setNominalSensorRotation + * can be called to correct the alignment by specifying the rotation + * needed to transform vectors from the nominal sensor coordinate system, + * aligned with the image plate coordinate system as described above, to + * the sensor's actual local coordinate system. + *

+ * NOTE: the nominal sensor transform applies only to the + * translation directions and rotation axes created by the listeners + * defined in this behavior; for compatibility with the core Java 3D API, + * sensor reads and the sensor hotspot location are still expressed in the + * sensor's local coordinate system. + * + * @param transform Rotates vectors from the nominal sensor coordinate + * system system to the sensor's local coordinate system; only the + * rotational components are used. May be set null for + * identity. + */ + public void setNominalSensorRotation(Transform3D transform) { + if (transform == null) { + nominalSensorRotation = null ; + return ; + } + + if (nominalSensorRotation == null) + nominalSensorRotation = new Transform3D() ; + + // Set transform and make sure it is a rotation only. + nominalSensorRotation.set(transform) ; + nominalSensorRotation.setTranslation(new Vector3d()) ; + } + + /** + * Gets the nominal sensor transform. + * + * @param t3d Transform3D to receive a copy of the + * nominal sensor transform + */ + public void getNominalSensorRotation(Transform3D t3d) { + if (nominalSensorRotation != null) { + t3d.set(nominalSensorRotation); + } else { + t3d.setIdentity(); + } + } + + /** + * Property which sets the number of buttons to be pressed simultaneously + * on the 6DOF sensor in order to reset the view back to the home + * transform. The value must be greater than 1; the default is 3. A + * value of None disables this action. This property is set + * in the configuration file read by ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * ResetViewButtonCount6D [<count> | None]) + * + * @param count array of length 1 containing a Double or + * String + * @see #setResetViewButtonCount6D + * @see ViewPlatformBehavior#setHomeTransform + * ViewPlatformBehavior.setHomeTransform + */ + public void ResetViewButtonCount6D(Object[] count) { + if (! (count.length == 1 && + (count[0] instanceof Double || count[0] instanceof String))) + throw new IllegalArgumentException + ("\nResetViewButtonCount6D must be a number or None") ; + + if (count[0] instanceof String) { + String s = (String)count[0] ; + if (s.equals("None")) + setResetViewButtonCount6D(NONE) ; + else + throw new IllegalArgumentException + ("\nResetViewButtonCount6D string value must be None") ; + } + else { + setResetViewButtonCount6D(((Double)count[0]).intValue()) ; + } + } + + /** + * Sets the number of buttons to be pressed simultaneously + * on the 6DOF sensor in order to reset the view back to the home + * transform. The value must be greater than 1; the default is 3. A + * value of NONE disables this action. + * + * @param count either NONE or button count > 1 + * @see ViewPlatformBehavior#setHomeTransform + * ViewPlatformBehavior.setHomeTransform + */ + public void setResetViewButtonCount6D(int count) { + if (count == NONE || count > 1) { + resetViewButtonCount6D = count ; + } + else { + throw new IllegalArgumentException + ("reset view button count must be > 1") ; + } + } + + /** + * Gets the number of buttons to be pressed simultaneously on the 6DOF + * sensor in order to reset the view back to the home transform. A value + * of NONE indicates this action is disabled. + * + * @return the number of buttons to press simultaneously for a view reset + */ + public int getResetViewButtonCount6D() { + return resetViewButtonCount6D ; + } + + /** + * Property which sets the number of buttons to be pressed simultaneously + * on the 2D valuator in order to reset the view back to the home + * transform. The value must be greater than 1; the default is + * None. A value of None disables this action. + * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * ResetViewButtonCount2D [<count> | None]) + * + * @param count array of length 1 containing a Double or + * String + * @see #setResetViewButtonCount2D + * @see ViewPlatformBehavior#setHomeTransform + * ViewPlatformBehavior.setHomeTransform + */ + public void ResetViewButtonCount2D(Object[] count) { + if (! (count.length == 1 && + (count[0] instanceof Double || count[0] instanceof String))) + throw new IllegalArgumentException + ("\nResetViewButtonCount2D must be a number or None") ; + + if (count[0] instanceof String) { + String s = (String)count[0] ; + if (s.equals("None")) + setResetViewButtonCount2D(NONE) ; + else + throw new IllegalArgumentException + ("\nResetViewButtonCount2D string value must be None") ; + } + else { + setResetViewButtonCount2D(((Double)count[0]).intValue()) ; + } + } + + /** + * Sets the number of buttons to be pressed simultaneously on the 2D + * valuator in order to reset the view back to the home transform. The + * value must be greater than 1; the default is NONE. A + * value of NONE disables this action. + * + * @param count either NONE or button count > 1 + * @see ViewPlatformBehavior#setHomeTransform + * ViewPlatformBehavior.setHomeTransform + */ + public void setResetViewButtonCount2D(int count) { + if (count == NONE || count > 1) { + resetViewButtonCount2D = count ; + } + else { + throw new IllegalArgumentException + ("reset view button count must be > 1") ; + } + } + + /** + * Gets the number of buttons to be pressed simultaneously on the 2D + * valuator in order to reset the view back to the home transform. A value + * of NONE indicates this action is disabled. + * + * @return the number of buttons to press simultaneously for a view reset + */ + public int getResetViewButtonCount2D() { + return resetViewButtonCount2D ; + } + + /** + * Property which sets the 6DOF sensor echo type. The default is + * Gnomon, which displays an object with points indicating + * the direction of each of the sensor's coordinate system axes at the + * location of the sensor's hotspot. The alternative is + * Beam, which displays a beam from the sensor's origin to + * the location of the sensor's hotspot; the hotspot must not be (0, 0, 0) + * or an IllegalArgumentException will result. The width of + * each of these echo types is specified by the EchoSize + * property. The EchoType property is set in the + * configuration file read by ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * EchoType [Gnomon | Beam | None]) + * + * @param type array of length 1 containing a String + * @see #setEchoType + */ + public void EchoType(Object[] type) { + if (! (type.length == 1 && type[0] instanceof String)) + throw new IllegalArgumentException + ("\nEchoType must be a String") ; + + String typeString = (String)type[0] ; + + if (typeString.equals("Gnomon")) + setEchoType(GNOMON) ; + else if (typeString.equals("Beam")) + setEchoType(BEAM) ; + else if (typeString.equals("None")) + setEchoType(NONE) ; + else + throw new IllegalArgumentException + ("\nEchoType must be Gnomon, Beam, or None") ; + } + + /** + * Sets the 6DOF sensor echo type. The default is GNOMON, + * which displays an object with points indicating the direction of each + * of the sensor's coordinate axes at the location of the sensor's + * hotspot. The alternative is BEAM, which displays a beam + * from the sensor's origin to the location of the sensor's hotspot; the + * hotspot must not be (0, 0, 0) or an + * IllegalArgumentException will result. The width of each + * of these echo types is specified by setEchoSize. + * + * @param type GNOMON, BEAM, or + * NONE are recognized + */ + public void setEchoType(int type) { + this.echoType = type ; + } + + /** + * Gets the echo type. + * + * @return the echo type + */ + public int getEchoType() { + return echoType ; + } + + /** + * Property which sets the size of the 6DOF sensor echo in physical + * meters. This is used for the width of the gnomon and beam echoes. The + * default is 1 centimeter. This property is set in the configuration + * file read by ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * EchoSize <size>) + * + * @param echoSize array of length 1 containing a Double + * @see #setEchoSize + */ + public void EchoSize(Object[] echoSize) { + if (! (echoSize.length == 1 && echoSize[0] instanceof Double)) + throw new IllegalArgumentException + ("\nEchoSize must be a Double") ; + + setEchoSize(((Double)echoSize[0]).doubleValue()) ; + } + + /** + * Sets the size of the 6DOF sensor echo in physical meters. This is used + * for the width of the gnomon and beam echoes. The default is 1 + * centimeter. + * + * @param echoSize the size in meters + */ + public void setEchoSize(double echoSize) { + this.echoSize = echoSize ; + } + + /** + * Gets the size of the 6DOF sensor echo in meters. + * + * @return the echo size + */ + public double getEchoSize() { + return echoSize ; + } + + /** + * Property which sets the color of the 6DOF sensor echo. The default is + * white. This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * EchoColor <red> <green> <blue>) + * + * @param color array of length 3 containing Doubles + * @see #setEchoColor + */ + public void EchoColor(Object[] color) { + if (! (color.length == 3 && color[0] instanceof Double && + color[1] instanceof Double && color[2] instanceof Double)) + throw new IllegalArgumentException + ("\nEchoColor must be 3 numbers for red, green, and blue") ; + + setEchoColor(new Color3f(((Double)color[0]).floatValue(), + ((Double)color[1]).floatValue(), + ((Double)color[2]).floatValue())) ; + } + + /** + * Sets the color of the 6DOF sensor echo. The default is white. This + * can be called to set the color before or after the echo geometry is + * created. + * + * @param color the echo color + */ + public void setEchoColor(Color3f color) { + if (echoColor == null) + echoColor = new Color3f(color) ; + else + echoColor.set(color) ; + + if (echoGeometry != null) { + Appearance a = echoGeometry.getAppearance() ; + Material m = a.getMaterial() ; + m.setDiffuseColor(echoColor) ; + } + } + + /** + * Gets the 6DOF sensor echo color. + * + * @param color the Color3f into which to copy the echo color + */ + public void getEchoColor(Color3f color) { + if (echoColor == null) + color.set(1.0f, 1.0f, 1.0f) ; + else + color.set(echoColor) ; + } + + /** + * Property which sets the 6DOF sensor echo transparency. The default is + * opaque. A value of 0.0 is fully opaque and 1.0 is fully transparent. + * This property is set in the configuration file read by + * ConfiguredUniverse. + *

+ * Syntax:
(ViewPlatformBehaviorProperty <name> + * EchoTransparency <transparency>) + * + * @param transparency array of length 1 containing a Double + * @see #setEchoTransparency + */ + public void EchoTransparency(Object[] transparency) { + if (! (transparency.length == 1 && transparency[0] instanceof Double)) + throw new IllegalArgumentException + ("\nEchoTransparency must be a number") ; + + setEchoTransparency(((Double)transparency[0]).floatValue()) ; + } + + /** + * Sets the 6DOF sensor echo transparency. The default is opaque. A + * value of 0.0 is fully opaque and 1.0 is fully transparent. This can be + * called to set the transparency before or after the echo geometry is + * created. + * + * @param transparency the transparency value + */ + public void setEchoTransparency(float transparency) { + echoTransparency = transparency ; + + if (echoGeometry != null) { + Appearance a = echoGeometry.getAppearance() ; + TransparencyAttributes ta = a.getTransparencyAttributes() ; + if (echoTransparency == 0.0f) { + ta.setTransparencyMode(TransparencyAttributes.NONE) ; + ta.setTransparency(0.0f) ; + } + else { + ta.setTransparencyMode(TransparencyAttributes.BLENDED) ; + ta.setTransparency(echoTransparency) ; + // Use order independent additive blend for gnomon. + if (echoGeometry instanceof SensorGnomonEcho) + ta.setDstBlendFunction(TransparencyAttributes.BLEND_ONE) ; + } + } + } + + /** + * Gets the 6DOF sensor echo transparency value. + * + * @return the transparency value + */ + public float getEchoTransparency() { + return echoTransparency ; + } + + /** + * Sets the transform group containing a 6DOF sensor's echo geometry. + * This is used to specify a custom echo. Its transform will be + * manipulated to represent the position and orientation of the 6DOF + * sensor. Capabilities to allow writing its transform and to read, + * write, and extend its children will be set. + *

+ * This method must be called before the behavior is made live in order to + * have an effect. + * + * @param echo the TransformGroup containing the + * echo geometry + */ + public void setEchoTransformGroup(TransformGroup echo) { + echo.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) ; + echo.setCapability(Group.ALLOW_CHILDREN_READ) ; + echo.setCapability(Group.ALLOW_CHILDREN_WRITE) ; + echo.setCapability(Group.ALLOW_CHILDREN_EXTEND) ; + this.echoTransformGroup = echo ; + } + + /** + * Gets the transform group containing a 6DOF sensor's echo geometry. + * Capabilities to write its transform and read, write, and extend its + * children are granted. + * + * @return the echo's transform group + */ + public TransformGroup getEchoTransformGroup() { + return echoTransformGroup ; + } + + /** + * Gets the Shape3D defining the 6DOF sensor's echo geometry + * and appearance. The returned Shape3D allows appearance + * read and write. If a custom echo was supplied by providing the echo + * transform group directly then the return value will be + * null. + * + * @return the echo geometry, or null if a custom echo was + * supplied + */ + public Shape3D getEchoGeometry() { + return echoGeometry ; + } + + /** + * Gets the SensorEventAgent used by this behavior. Sensor + * event generation is delegated to this agent. This can be accessed to + * manipulate the sensor button and read action bindings directly. + * + * @return the sensor event agent + */ + public SensorEventAgent getSensorEventAgent() { + return eventAgent ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/package.html new file mode 100644 index 0000000..4900193 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/behaviors/vp/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.behaviors.vp + + +

Provides ViewPlatform navigation utility classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CommandStream.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CommandStream.java new file mode 100644 index 0000000..befc092 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CommandStream.java @@ -0,0 +1,265 @@ +/* + * $RCSfile: CommandStream.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:16 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +/** + * This class is used to build the bit-level compression command stream which + * is the final result of the compression process. It defines the bit + * representations of the compression commands and provides a mechanism for + * the interleaving and forwarding of command headers and bodies required by + * the geometry compression specification. + */ +class CommandStream { + // Geometry compression commands. + static final int SET_NORM = 0xC0 ; + static final int SET_COLOR = 0x80 ; + static final int VERTEX = 0x40 ; + static final int MESH_B_R = 0x20 ; + static final int SET_STATE = 0x18 ; + static final int SET_TABLE = 0x10 ; + static final int V_NO_OP = 0x01 ; + + // Huffman table indices. + static final int POSITION_TABLE = 0 ; + static final int COLOR_TABLE = 1 ; + static final int NORMAL_TABLE = 2 ; + + // The buffer of compressed data and the current offset. + private byte bytes[] ; + private int byteOffset ; + private int bitOffset ; + + // Last command body for header forwarding. + private long lastBody ; + private int lastBodyLength ; + + /** + * Create an empty CommandStream with a default initial size. + */ + CommandStream() { + this(65536) ; + } + + /** + * Create an empty CommandStream with the given initial size. + * + * @param initSize initial capacity of CommandStream in bytes + */ + CommandStream(int initSize) { + bytes = new byte[initSize] ; + clear() ; + } + + /** + * Mark the CommandStream as empty so that its storage will be reused. + */ + void clear() { + // Initialize the first byte to 0. + // Subsequent bytes are cleared as they are written. + bytes[0] = 0 ; + + // Reset the number of valid bits. + bitOffset = 0 ; + byteOffset = 0 ; + + // The first command header is always followed by the body of an + // implicit variable length no-op to start the header-forwarding + // interleave required by hardware decompressor implementations. The + // only necessary bits are 5 bits of length set to zeros to indicate a + // fill of zero length. + lastBody = 0 ; + lastBodyLength = 5 ; + } + + /** + * Add a compression command to this instance.

+ * + * A compression command includes an 8-bit header and can range up to 72 + * bits in length. The command with the maximum length is a 2-bit color + * command with a 6-bit tag in the header, followed by four 16-bit color + * components of data.

+ * + * A subcommand is either a position, normal, or color, though in practice + * a position subcommand can only be part of a vertex command. Normal and + * color subcommands can be parts of separate global normal and color + * commands as well as parts of a vertex command.

+ * + * A subcommand includes a 6-bit header. Its length is 2 bits less than + * the length of the corresponding command. + * + * @param header contains compression command header bits, right-justified + * within the bits of the int + * @param headerLength number of bits in header, either 8 for commands or + * 6 for subcommands + * @param body contains the body of the compression command, + * right-justified within the bits of the long + * @param bodyLength number of bits in the body + */ + void addCommand(int header, int headerLength, long body, int bodyLength) { + addByte(header, headerLength) ; + addLong(lastBody, lastBodyLength) ; + + lastBody = body ; + lastBodyLength = bodyLength ; + } + + // + // Add the rightmost bitCount bits of b to the end of the command stream. + // + private void addByte(int b, int bitCount) { + int bitsEmpty = 8 - bitOffset ; + b &= (int)CompressionStreamElement.lengthMask[bitCount] ; + + if (bitCount <= bitsEmpty) { + bytes[byteOffset] |= (b << (bitsEmpty - bitCount)) ; + bitOffset += bitCount ; + return ; + } + + if (bytes.length == byteOffset + 1) { + byte newBytes[] = new byte[bytes.length * 2] ; + System.arraycopy(bytes, 0, newBytes, 0, bytes.length) ; + bytes = newBytes ; + } + + bitOffset = bitCount - bitsEmpty ; + bytes[byteOffset] |= (b >>> bitOffset) ; + + byteOffset++ ; + bytes[byteOffset] = (byte)(b << (8 - bitOffset)) ; + } + + // + // Add the rightmost bitCount bits of l to the end of the command stream. + // + private void addLong(long l, int bitCount) { + int byteCount = bitCount / 8 ; + int excessBits = bitCount - byteCount * 8 ; + + if (excessBits > 0) + addByte((int)(l >>> (byteCount * 8)), excessBits) ; + + while (byteCount > 0) { + addByte((int)((l >>> ((byteCount - 1) * 8)) & 0xff), 8) ; + byteCount-- ; + } + } + + /** + * Add a no-op and the last command body. Pad out with additional no-ops + * to a 64-bit boundary if necessary. A call to this method is required + * in order to create a valid compression command stream. + */ + void end() { + int excessBytes, padBits ; + + // Add the 1st no-op and the last body. + addByte(V_NO_OP, 8) ; + addLong(lastBody, lastBodyLength) ; + + excessBytes = (byteOffset + 1) % 8 ; + if (excessBytes == 0 && bitOffset == 8) + // No padding necessary. + return ; + + // Need to add padding with a 2nd no-op. + addByte(V_NO_OP, 8) ; + excessBytes = (byteOffset + 1) % 8 ; + + if (excessBytes == 0) + padBits = 8 - bitOffset ; + else { + int fillBytes = 8 - excessBytes ; + padBits = (8 * fillBytes) + (8 - bitOffset) ; + } + + // The minimum length for a no-op command body is 5 bits. + if (padBits < 5) + // Have to cross the next 64-bit boundary. + padBits += 64 ; + + // The maximum length of a no-op body is a 5-bit length + 31 bits of + // fill for a total of 36. + if (padBits < 37) { + // Pad with the body of the 1st no-op. + addLong((padBits - 5) << (padBits - 5), padBits) ; + return ; + } + + // The number of bits to pad at this point is [37..68]. Knock off 24 + // bits with the body of the 1st no-op to reduce the number of pad + // bits to [13..44], which can be filled with 1 more no-op. + addLong(19 << 19, 24) ; + padBits -= 24 ; + + // Add a 3rd no-op. + addByte(V_NO_OP, 8) ; + padBits -= 8 ; + + // Complete padding with the body of the 2nd no-op. + addLong((padBits - 5) << (padBits - 5), padBits) ; + } + + /** + * Get the number of bytes in the compression command stream. + * + * @return size of compressed data in bytes + */ + int getByteCount() { + if (byteOffset + bitOffset == 0) + return 0 ; + else + return byteOffset + 1 ; + } + + /** + * Get the bytes composing the compression command stream. + * + * @return reference to array of bytes containing the compressed data + */ + byte[] getBytes() { + return bytes ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressedGeometryFile.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressedGeometryFile.java new file mode 100644 index 0000000..85648f7 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressedGeometryFile.java @@ -0,0 +1,1013 @@ +/* + * $RCSfile: CompressedGeometryFile.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:16 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import javax.media.j3d.CompressedGeometry; +import javax.media.j3d.CompressedGeometryHeader; + +// +// The compressed geometry file format supported by this class has a 32 +// byte header followed by multiple compressed geometry objects. +// +// Each object consists of a block of compressed data and an 8-byte +// individual block header describing its contents. +// +// The file ends with a directory data structure used for random access, +// containing a 64-bit offset for each object in the order in which it +// appears in the file. This is also used to find the size of the largest +// object in the file and must be present. +// + +/** + * This class provides methods to read and write compressed geometry resource + * files. These files usually end with the .cg extension and support + * sequential as well as random access to multiple compressed geometry + * objects. + * + * @deprecated As of Java 3D 1.5, replaced by + * com.sun.j3d.utils.geometry.compression.{@link com.sun.j3d.utils.geometry.compression.CompressedGeometryFile}. + */ +public class CompressedGeometryFile { + private static final boolean print = false ; + private static final boolean benchmark = false ; + + /** + * The magic number which identifies the compressed geometry file type. + */ + static final int MAGIC_NUMBER = 0xbaddfab4 ; + + /** + * Byte offset of the magic number from start of file. + */ + static final int MAGIC_NUMBER_OFFSET = 0 ; + + /** + * Byte offset of the major version number from start of file. + */ + static final int MAJOR_VERSION_OFFSET = 4 ; + + /** + * Byte offset of the minor version number from start of file. + */ + static final int MINOR_VERSION_OFFSET = 8 ; + + /** + * Byte offset of the minor minor version number from start of file. + */ + static final int MINOR_MINOR_VERSION_OFFSET = 12 ; + + /** + * Byte offset of the number of objects from start of file. + */ + static final int OBJECT_COUNT_OFFSET = 16 ; + + /** + * Byte offset of the directory offset from start of file. + * This offset is long word aligned since the directory offset is a long. + */ + static final int DIRECTORY_OFFSET_OFFSET = 24 ; + + /** + * File header total size in bytes. + */ + static final int HEADER_SIZE = 32 ; + + /** + * Byte offset of the object size from start of individual compressed + * geometry block. + */ + static final int OBJECT_SIZE_OFFSET = 0 ; + + /** + * Byte offset of the compressed geometry data descriptor from start of + * individual compressed geometry block. + */ + static final int GEOM_DATA_OFFSET = 4 ; + + /** + * Bits in compressed geometry data descriptor which encode the buffer type. + */ + static final int TYPE_MASK = 0x03 ; + + /** + * Bit in compressed geometry data descriptor encoding presence of normals. + */ + static final int NORMAL_PRESENT_MASK = 0x04 ; + + /** + * Bit in compressed geometry data descriptor encoding presence of colors. + */ + static final int COLOR_PRESENT_MASK = 0x08 ; + + /** + * Bit in compressed geometry data descriptor encoding presence of alphas. + */ + static final int ALPHA_PRESENT_MASK = 0x10 ; + + /** + * Value in compressed geometry data descriptor for a point buffer type. + */ + static final int TYPE_POINT = 1 ; + + /** + * Value in compressed geometry data descriptor for a line buffer type. + */ + static final int TYPE_LINE = 2 ; + + /** + * Value in compressed geometry data descriptor for a triangle buffer type. + */ + static final int TYPE_TRIANGLE = 3 ; + + /** + * Block header total size in bytes. + */ + static final int BLOCK_HEADER_SIZE = 8 ; + + // The name of the compressed geometry resource file. + String fileName = null ; + + // The major, minor, and subminor version number of the most recent + // compressor used to compress any of the objects in the compressed + // geometry resource file. + int majorVersionNumber ; + int minorVersionNumber ; + int minorMinorVersionNumber ; + + // The number of objects in the compressed geometry resource file. + int objectCount ; + + // The index of the current object in the file. + int objectIndex = 0 ; + + // The random access file associated with this instance. + RandomAccessFile cgFile = null ; + + // The magic number identifying the file type. + int magicNumber ; + + // These fields are set from each individual block of compressed geometry. + byte cgBuffer[] ; + int geomSize ; + int geomStart ; + int geomDataType ; + + // The directory of object offsets is read from the end of the file. + long directory[] ; + long directoryOffset ; + + // The object sizes are computed from the directory offsets. These are + // used to allocate a buffer large enough to hold the largest object and + // to determine how many consecutive objects can be read into that buffer. + int objectSizes[] ; + int bufferObjectStart ; + int bufferObjectCount ; + int bufferNextObjectCount ; + int bufferNextObjectOffset ; + + // The shared compressed geometry header object. + CompressedGeometryHeader cgh ; + + // Flag indicating file update. + boolean fileUpdate = false ; + + /** + * Construct a new CompressedGeometryFile instance associated with the + * specified file. An attempt is made to open the file with read-only + * access; if this fails then a FileNotFoundException is thrown. + * + * @param file path to the compressed geometry resource file + * @exception FileNotFoundException if file doesn't exist or + * cannot be read + * @exception IllegalArgumentException if the file is not a compressed + * geometry resource file + * @exception IOException if there is a header or directory read error + */ + public CompressedGeometryFile(String file) throws IOException { + this(file, false) ; + } + + /** + * Construct a new CompressedGeometryFile instance associated with the + * specified file. + * + * @param file path to the compressed geometry resource file + * @param rw if true, opens the file for read and write access or attempts + * to create one if it doesn't exist; if false, opens the file with + * read-only access + * @exception FileNotFoundException if file doesn't exist or + * access permissions disallow access + * @exception IllegalArgumentException if the file is not a compressed + * geometry resource file + * @exception IOException if there is a header or directory read error + */ + public CompressedGeometryFile(String file, boolean rw) throws IOException { + // Open the file and read the file header. + open(file, rw) ; + + // Copy the file name. + fileName = new String(file) ; + + // Set up the file fields. + initialize() ; + } + + /** + * Construct a new CompressedGeometryFile instance associated with a + * currently open RandomAccessFile. + * + * @param file currently open RandomAccessFile + * @exception IllegalArgumentException if the file is not a compressed + * geometry resource file + * @exception IOException if there is a header or directory read error + */ + public CompressedGeometryFile(RandomAccessFile file) throws IOException { + // Copy the file reference. + cgFile = file ; + + // Set up the file fields. + initialize() ; + } + + /** + * Delete all compressed objects from this instance. This method may only + * be called after successfully creating a CompressedGeometryFile instance + * with read-write access, so a corrupted or otherwise invalid resource + * must be removed manually before it can be rewritten. The close() + * method must be called sometime after invoking clear() in order to write + * out the new directory structure. + * + * @exception IOException if clear fails + */ + public void clear() throws IOException { + // Truncate the file. + cgFile.setLength(0) ; + + // Set up the file fields. + initialize() ; + } + + /** + * Return a string containing the file name associated with this instance + * or null if there is none. + * + * @return file name associated with this instance or null if there is + * none + */ + public String getFileName() { + return fileName ; + } + + /** + * Return the major version number of the most recent compressor used to + * compress any of the objects in this instance. + * + * @return major version number + */ + public int getMajorVersionNumber() { + return majorVersionNumber ; + } + + /** + * Return the minor version number of the most recent compressor used to + * compress any of the objects in this instance. + * + * @return minor version number + */ + public int getMinorVersionNumber() { + return minorVersionNumber ; + } + + /** + * Return the subminor version number of the most recent compressor used to + * compress any of the objects in this instance. + * + * @return subminor version number + */ + public int getMinorMinorVersionNumber() { + return minorMinorVersionNumber ; + } + + /** + * Return the number of compressed objects in this instance. + * + * @return number of compressed objects + */ + public int getObjectCount() { + return objectCount ; + } + + /** + * Return the current object index associated with this instance. This is + * the index of the object that would be returned by an immediately + * following call to the readNext() method. Its initial value is 0; -1 + * is returned if the last object has been read. + * + * @return current object index, or -1 if at end + */ + public int getCurrentIndex() { + if (objectIndex == objectCount) + return -1 ; + else + return objectIndex ; + } + + /** + * Read the next compressed geometry object in the instance. This is + * initially the first object (index 0) in the instance; otherwise, it is + * whatever object is next after the last one read. The current object + * index is incremented by 1 after the read. When the last object is read + * the index becomes invalid and an immediately subsequent call to + * readNext() returns null. + * + * @return a CompressedGeometry node component, or null if the last object + * has been read + * @exception IOException if read fails + */ + public CompressedGeometry readNext() throws IOException { + return readNext(cgBuffer.length) ; + } + + /** + * Read all compressed geometry objects contained in the instance. The + * current object index becomes invalid; an immediately following call + * to readNext() will return null. + * + * @return an array of CompressedGeometry node components. + * @exception IOException if read fails + */ + public CompressedGeometry[] read() throws IOException { + long startTime = 0 ; + CompressedGeometry cg[] = new CompressedGeometry[objectCount] ; + + if (benchmark) + startTime = System.currentTimeMillis() ; + + objectIndex = 0 ; + setFilePointer(directory[0]) ; + bufferNextObjectCount = 0 ; + + for (int i = 0 ; i < objectCount ; i++) + cg[i] = readNext(cgBuffer.length) ; + + if (benchmark) { + long t = System.currentTimeMillis() - startTime ; + System.out.println("read " + objectCount + + " objects " + cgFile.length() + + " bytes in " + (t/1000f) + " sec.") ; + System.out.println((cgFile.length()/(float)t) + " Kbytes/sec.") ; + } + + return cg ; + } + + /** + * Read the compressed geometry object at the specified index. The + * current object index is set to the subsequent object unless the last + * object has been read, in which case the index becomes invalid and an + * immediately following call to readNext() will return null. + * + * @param index compressed geometry object to read + * @return a CompressedGeometry node component + * @exception IndexOutOfBoundsException if object index is + * out of range + * @exception IOException if read fails + */ + public CompressedGeometry read(int index) throws IOException { + objectIndex = index ; + + if (objectIndex < 0) { + throw new IndexOutOfBoundsException + ("\nobject index must be >= 0") ; + } + if (objectIndex >= objectCount) { + throw new IndexOutOfBoundsException + ("\nobject index must be < " + objectCount) ; + } + + // Check if object is in cache. + if ((objectIndex >= bufferObjectStart) && + (objectIndex < bufferObjectStart + bufferObjectCount)) { + if (print) System.out.println("\ngetting object from cache\n") ; + + bufferNextObjectOffset = (int) + (directory[objectIndex] - directory[bufferObjectStart]) ; + + bufferNextObjectCount = + bufferObjectCount - (objectIndex - bufferObjectStart) ; + + return readNext() ; + + } else { + // Move file pointer to correct offset. + setFilePointer(directory[objectIndex]) ; + + // Force a read from current offset. Disable cache read-ahead + // since cache hits are unlikely with random access. + bufferNextObjectCount = 0 ; + return readNext(objectSizes[objectIndex]) ; + } + } + + + /** + * Add a compressed geometry node component to the end of the instance. + * The current object index becomes invalid; an immediately following call + * to readNext() will return null. The close() method must be called at + * some later time in order to create a valid compressed geometry file. + * + * @param cg a compressed geometry node component + * @exception CapabilityNotSetException if unable to get compressed + * geometry data from the node component + * @exception IOException if write fails + */ + public void write(CompressedGeometry cg) throws IOException { + CompressedGeometryHeader cgh = new CompressedGeometryHeader() ; + cg.getCompressedGeometryHeader(cgh) ; + + // Update the read/write buffer size if necessary. + if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) { + cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ; + if (print) System.out.println("\ncgBuffer: reallocated " + + (cgh.size+BLOCK_HEADER_SIZE) + + " bytes") ; + } + + cg.getCompressedGeometry(cgBuffer) ; + write(cgh, cgBuffer) ; + } + + /** + * Add a buffer of compressed geometry data to the end of the + * resource. The current object index becomes invalid; an immediately + * following call to readNext() will return null. The close() method must + * be called at some later time in order to create a valid compressed + * geometry file. + * + * @param cgh a CompressedGeometryHeader object describing the data. + * @param geometry the compressed geometry data + * @exception IOException if write fails + */ + public void write(CompressedGeometryHeader cgh, byte geometry[]) + throws IOException { + + // Update the read/write buffer size if necessary. It won't be used + // in this method, but should be big enough to read any object in + // the file, including the one to be written. + if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) { + cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ; + if (print) System.out.println("\ncgBuffer: reallocated " + + (cgh.size+BLOCK_HEADER_SIZE) + + " bytes") ; + } + + // Assuming backward compatibility, the version number of the file + // should be the maximum of all individual compressed object versions. + if ((cgh.majorVersionNumber > majorVersionNumber) + || + ((cgh.majorVersionNumber == majorVersionNumber) && + (cgh.minorVersionNumber > minorVersionNumber)) + || + ((cgh.majorVersionNumber == majorVersionNumber) && + (cgh.minorVersionNumber == minorVersionNumber) && + (cgh.minorMinorVersionNumber > minorMinorVersionNumber))) { + + majorVersionNumber = cgh.majorVersionNumber ; + minorVersionNumber = cgh.minorVersionNumber ; + minorMinorVersionNumber = cgh.minorMinorVersionNumber ; + + this.cgh.majorVersionNumber = cgh.majorVersionNumber ; + this.cgh.minorVersionNumber = cgh.minorVersionNumber ; + this.cgh.minorMinorVersionNumber = cgh.minorMinorVersionNumber ; + } + + // Get the buffer type and see what vertex components are present. + int geomDataType = 0 ; + + switch (cgh.bufferType) { + case CompressedGeometryHeader.POINT_BUFFER: + geomDataType = TYPE_POINT ; + break ; + case CompressedGeometryHeader.LINE_BUFFER: + geomDataType = TYPE_LINE ; + break ; + case CompressedGeometryHeader.TRIANGLE_BUFFER: + geomDataType = TYPE_TRIANGLE ; + break ; + } + + if ((cgh.bufferDataPresent & + CompressedGeometryHeader.NORMAL_IN_BUFFER) != 0) + geomDataType |= NORMAL_PRESENT_MASK ; + + if ((cgh.bufferDataPresent & + CompressedGeometryHeader.COLOR_IN_BUFFER) != 0) + geomDataType |= COLOR_PRESENT_MASK ; + + if ((cgh.bufferDataPresent & + CompressedGeometryHeader.ALPHA_IN_BUFFER) != 0) + geomDataType |= ALPHA_PRESENT_MASK ; + + // Allocate new directory and object size arrays if necessary. + if (objectCount == directory.length) { + long newDirectory[] = new long[2*objectCount] ; + int newObjectSizes[] = new int[2*objectCount] ; + + System.arraycopy(directory, 0, + newDirectory, 0, objectCount) ; + System.arraycopy(objectSizes, 0, + newObjectSizes, 0, objectCount) ; + + directory = newDirectory ; + objectSizes = newObjectSizes ; + + if (print) + System.out.println("\ndirectory and size arrays: reallocated " + + (2*objectCount) + " entries") ; + } + + // Update directory and object size array. + directory[objectCount] = directoryOffset ; + objectSizes[objectCount] = cgh.size + BLOCK_HEADER_SIZE ; + objectCount++ ; + + // Seek to the directory and overwrite from there. + setFilePointer(directoryOffset) ; + cgFile.writeInt(cgh.size) ; + cgFile.writeInt(geomDataType) ; + cgFile.write(geometry, 0, cgh.size) ; + if (print) + System.out.println("\nwrote " + cgh.size + + " byte compressed object to " + fileName + + "\nfile offset " + directoryOffset) ; + + // Update the directory offset. + directoryOffset += cgh.size + BLOCK_HEADER_SIZE ; + + // Return end-of-file on next read. + objectIndex = objectCount ; + + // Flag file update so close() will write out the directory. + fileUpdate = true ; + } + + /** + * Release the resources associated with this instance. + * Write out final header and directory if contents were updated. + * This method must be called in order to create a valid compressed + * geometry resource file if any updates were made. + */ + public void close() { + if (cgFile != null) { + try { + if (fileUpdate) { + writeFileDirectory() ; + writeFileHeader() ; + } + cgFile.close() ; + } + catch (IOException e) { + // Don't propagate this exception. + System.out.println("\nException: " + e.getMessage()) ; + System.out.println("failed to close " + fileName) ; + } + } + cgFile = null ; + cgBuffer = null ; + directory = null ; + objectSizes = null ; + } + + + // + // Open the file. Specifying a non-existent file creates a new one if + // access permissions allow. + // + void open(String fname, boolean rw) + throws FileNotFoundException, IOException { + + cgFile = null ; + String mode ; + + if (rw) + mode = "rw" ; + else + mode = "r" ; + + try { + cgFile = new RandomAccessFile(fname, mode) ; + if (print) System.out.println("\n" + fname + + ": opened mode " + mode) ; + } + catch (FileNotFoundException e) { + // N.B. this exception is also thrown on access permission errors + throw new FileNotFoundException(e.getMessage() + "\n" + fname + + ": open mode " + mode + " failed") ; + } + } + + // + // Seek to the specified offset in the file. + // + void setFilePointer(long offset) throws IOException { + cgFile.seek(offset) ; + + // Reset number of objects that can be read sequentially from cache. + bufferNextObjectCount = 0 ; + } + + // + // Initialize directory, object size array, read/write buffer, and the + // shared compressed geometry header. + // + void initialize() throws IOException { + int maxSize = 0 ; + + if (cgFile.length() == 0) { + // New file for writing: allocate nominal initial sizes for arrays. + objectCount = 0 ; + cgBuffer = new byte[32768] ; + directory = new long[16] ; + objectSizes = new int[directory.length] ; + + // Set fields as if they have been read. + magicNumber = MAGIC_NUMBER ; + majorVersionNumber = 1 ; + minorVersionNumber = 0 ; + minorMinorVersionNumber = 0 ; + directoryOffset = HEADER_SIZE ; + + // Write the file header. + writeFileHeader() ; + + } else { + // Read the file header. + readFileHeader() ; + + // Check file type. + if (magicNumber != MAGIC_NUMBER) { + close() ; + throw new IllegalArgumentException + ("\n" + fileName + " is not a compressed geometry file") ; + } + + // Read the directory and determine object sizes. + directory = new long[objectCount] ; + readDirectory(directoryOffset, directory) ; + + objectSizes = new int[objectCount] ; + for (int i = 0 ; i < objectCount-1 ; i++) { + objectSizes[i] = (int)(directory[i+1] - directory[i]) ; + if (objectSizes[i] > maxSize) maxSize = objectSizes[i] ; + } + + if (objectCount > 0) { + objectSizes[objectCount-1] = + (int)(directoryOffset - directory[objectCount-1]) ; + + if (objectSizes[objectCount-1] > maxSize) + maxSize = objectSizes[objectCount-1] ; + } + + // Allocate a buffer big enough to read the largest object. + cgBuffer = new byte[maxSize] ; + + // Move to the first object. + setFilePointer(HEADER_SIZE) ; + } + + // Set up common parts of the compressed geometry object header. + cgh = new CompressedGeometryHeader() ; + cgh.majorVersionNumber = this.majorVersionNumber ; + cgh.minorVersionNumber = this.minorVersionNumber ; + cgh.minorMinorVersionNumber = this.minorMinorVersionNumber ; + + if (print) { + System.out.println(fileName + ": " + objectCount + " objects") ; + System.out.println("magic number 0x" + + Integer.toHexString(magicNumber) + + ", version number " + majorVersionNumber + + "." + minorVersionNumber + + "." + minorMinorVersionNumber) ; + System.out.println("largest object is " + maxSize + " bytes") ; + } + } + + // + // Read the file header. + // + void readFileHeader() throws IOException { + byte header[] = new byte[HEADER_SIZE] ; + + try { + setFilePointer(0) ; + if (cgFile.read(header) != HEADER_SIZE) { + close() ; + throw new IOException("failed header read") ; + } + } + catch (IOException e) { + if (cgFile != null) { + close() ; + } + throw e ; + } + + magicNumber = + ((header[MAGIC_NUMBER_OFFSET+0] & 0xff) << 24) | + ((header[MAGIC_NUMBER_OFFSET+1] & 0xff) << 16) | + ((header[MAGIC_NUMBER_OFFSET+2] & 0xff) << 8) | + ((header[MAGIC_NUMBER_OFFSET+3] & 0xff)) ; + + majorVersionNumber = + ((header[MAJOR_VERSION_OFFSET+0] & 0xff) << 24) | + ((header[MAJOR_VERSION_OFFSET+1] & 0xff) << 16) | + ((header[MAJOR_VERSION_OFFSET+2] & 0xff) << 8) | + ((header[MAJOR_VERSION_OFFSET+3] & 0xff)) ; + + minorVersionNumber = + ((header[MINOR_VERSION_OFFSET+0] & 0xff) << 24) | + ((header[MINOR_VERSION_OFFSET+1] & 0xff) << 16) | + ((header[MINOR_VERSION_OFFSET+2] & 0xff) << 8) | + ((header[MINOR_VERSION_OFFSET+3] & 0xff)) ; + + minorMinorVersionNumber = + ((header[MINOR_MINOR_VERSION_OFFSET+0] & 0xff) << 24) | + ((header[MINOR_MINOR_VERSION_OFFSET+1] & 0xff) << 16) | + ((header[MINOR_MINOR_VERSION_OFFSET+2] & 0xff) << 8) | + ((header[MINOR_MINOR_VERSION_OFFSET+3] & 0xff)) ; + + objectCount = + ((header[OBJECT_COUNT_OFFSET+0] & 0xff) << 24) | + ((header[OBJECT_COUNT_OFFSET+1] & 0xff) << 16) | + ((header[OBJECT_COUNT_OFFSET+2] & 0xff) << 8) | + ((header[OBJECT_COUNT_OFFSET+3] & 0xff)) ; + + directoryOffset = + ((long)(header[DIRECTORY_OFFSET_OFFSET+0] & 0xff) << 56) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+1] & 0xff) << 48) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+2] & 0xff) << 40) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+3] & 0xff) << 32) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+4] & 0xff) << 24) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+5] & 0xff) << 16) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+6] & 0xff) << 8) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+7] & 0xff)) ; + } + + // + // Write the file header based on current field values. + // + void writeFileHeader() throws IOException { + setFilePointer(0) ; + try { + cgFile.writeInt(MAGIC_NUMBER) ; + cgFile.writeInt(majorVersionNumber) ; + cgFile.writeInt(minorVersionNumber) ; + cgFile.writeInt(minorMinorVersionNumber) ; + cgFile.writeInt(objectCount) ; + cgFile.writeInt(0) ; // long word alignment + cgFile.writeLong(directoryOffset) ; + if (print) + System.out.println("wrote file header for " + fileName) ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\ncould not write file header for " + fileName) ; + } + } + + // + // Read the directory of compressed geometry object offsets. + // + void readDirectory(long offset, long[] directory) + throws IOException { + + byte buff[] = new byte[directory.length * 8] ; + setFilePointer(offset) ; + + try { + cgFile.read(buff) ; + if (print) + System.out.println("read " + buff.length + " byte directory") ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\nfailed to read " + buff.length + + " byte directory, offset " + offset + " in file " + fileName) ; + } + + for (int i = 0 ; i < directory.length ; i++) { + directory[i] = + ((long)(buff[i*8+0] & 0xff) << 56) | + ((long)(buff[i*8+1] & 0xff) << 48) | + ((long)(buff[i*8+2] & 0xff) << 40) | + ((long)(buff[i*8+3] & 0xff) << 32) | + ((long)(buff[i*8+4] & 0xff) << 24) | + ((long)(buff[i*8+5] & 0xff) << 16) | + ((long)(buff[i*8+6] & 0xff) << 8) | + ((long)(buff[i*8+7] & 0xff)) ; + } + } + + // + // Write the file directory. + // + void writeFileDirectory() throws IOException { + setFilePointer(directoryOffset) ; + + int directoryAlign = (int)(directoryOffset % 8) ; + if (directoryAlign != 0) { + // Align to long word before writing directory of long offsets. + byte bytes[] = new byte[8-directoryAlign] ; + + try { + cgFile.write(bytes) ; + if (print) + System.out.println ("wrote " + (8-directoryAlign) + + " bytes long alignment") ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\ncould not write " + directoryAlign + + " bytes to long word align directory for " + fileName) ; + } + directoryOffset += 8-directoryAlign ; + } + + try { + for (int i = 0 ; i < objectCount ; i++) + cgFile.writeLong(directory[i]) ; + + if (print) + System.out.println("wrote file directory for " + fileName) ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\ncould not write directory for " + fileName) ; + } + } + + // + // Get the next compressed object in the file, either from the read-ahead + // cache or from the file itself. + // + CompressedGeometry readNext(int bufferReadLimit) + throws IOException { + if (objectIndex == objectCount) + return null ; + + if (bufferNextObjectCount == 0) { + // No valid objects are in the cache. + int curSize = 0 ; + bufferObjectCount = 0 ; + + // See how much we have room to read. + for (int i = objectIndex ; i < objectCount ; i++) { + if (curSize + objectSizes[i] > bufferReadLimit) break ; + curSize += objectSizes[i] ; + bufferObjectCount++ ; + } + + // Try to read that amount. + try { + int n = cgFile.read(cgBuffer, 0, curSize) ; + if (print) + System.out.println("\nread " + n + + " bytes from " + fileName) ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\nfailed to read " + curSize + + " bytes, object " + objectIndex + " in file " + fileName) ; + } + + // Point at the first object in the buffer. + bufferObjectStart = objectIndex ; + bufferNextObjectCount = bufferObjectCount ; + bufferNextObjectOffset = 0 ; + } + + // Get block header info. + geomSize = + ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+0]&0xff)<<24) | + ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+1]&0xff)<<16) | + ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+2]&0xff)<< 8) | + ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+3]&0xff)) ; + + geomDataType = + ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+0]&0xff) << 24) | + ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+1]&0xff) << 16) | + ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+2]&0xff) << 8) | + ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+3]&0xff)) ; + + // Get offset of compressed geometry data from start of buffer. + geomStart = bufferNextObjectOffset + BLOCK_HEADER_SIZE ; + + if (print) { + System.out.println("\nobject " + objectIndex + + "\nfile offset " + directory[objectIndex] + + ", buffer offset " + bufferNextObjectOffset) ; + System.out.println("size " + geomSize + " bytes, " + + "data descriptor 0x" + + Integer.toHexString(geomDataType)) ; + } + + // Update cache info. + bufferNextObjectOffset += objectSizes[objectIndex] ; + bufferNextObjectCount-- ; + objectIndex++ ; + + return newCG(geomSize, geomStart, geomDataType) ; + } + + + // + // Construct and return a compressed geometry node. + // + CompressedGeometry newCG(int geomSize, + int geomStart, + int geomDataType) { + cgh.size = geomSize ; + cgh.start = geomStart ; + + if ((geomDataType & TYPE_MASK) == TYPE_POINT) + cgh.bufferType = CompressedGeometryHeader.POINT_BUFFER ; + else if ((geomDataType & TYPE_MASK) == TYPE_LINE) + cgh.bufferType = CompressedGeometryHeader.LINE_BUFFER ; + else if ((geomDataType & TYPE_MASK) == TYPE_TRIANGLE) + cgh.bufferType = CompressedGeometryHeader.TRIANGLE_BUFFER ; + + cgh.bufferDataPresent = 0 ; + + if ((geomDataType & NORMAL_PRESENT_MASK) != 0) + cgh.bufferDataPresent |= + CompressedGeometryHeader.NORMAL_IN_BUFFER ; + + if ((geomDataType & COLOR_PRESENT_MASK) != 0) + cgh.bufferDataPresent |= + CompressedGeometryHeader.COLOR_IN_BUFFER ; + + if ((geomDataType & ALPHA_PRESENT_MASK) != 0) + cgh.bufferDataPresent |= + CompressedGeometryHeader.ALPHA_IN_BUFFER ; + + return new CompressedGeometry(cgh, cgBuffer) ; + } + + /** + * Release file resources when this object is garbage collected. + */ + protected void finalize() { + close() ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStream.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStream.java new file mode 100644 index 0000000..34ce199 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStream.java @@ -0,0 +1,2325 @@ +/* + * $RCSfile: CompressionStream.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:16 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import com.sun.j3d.internal.BufferWrapper; +import com.sun.j3d.internal.ByteBufferWrapper; +import com.sun.j3d.internal.DoubleBufferWrapper; +import com.sun.j3d.internal.FloatBufferWrapper; +import com.sun.j3d.utils.geometry.GeometryInfo; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import javax.media.j3d.Appearance; +import javax.media.j3d.CompressedGeometryHeader; +import javax.media.j3d.Geometry; +import javax.media.j3d.GeometryArray; +import javax.media.j3d.GeometryStripArray; +import javax.media.j3d.IndexedGeometryArray; +import javax.media.j3d.IndexedGeometryStripArray; +import javax.media.j3d.IndexedLineArray; +import javax.media.j3d.IndexedLineStripArray; +import javax.media.j3d.IndexedQuadArray; +import javax.media.j3d.IndexedTriangleArray; +import javax.media.j3d.IndexedTriangleFanArray; +import javax.media.j3d.IndexedTriangleStripArray; +import javax.media.j3d.J3DBuffer; +import javax.media.j3d.LineArray; +import javax.media.j3d.LineStripArray; +import javax.media.j3d.Material; +import javax.media.j3d.QuadArray; +import javax.media.j3d.Shape3D; +import javax.media.j3d.TriangleArray; +import javax.media.j3d.TriangleFanArray; +import javax.media.j3d.TriangleStripArray; +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; +import javax.vecmath.Point3d; +import javax.vecmath.Point3f; +import javax.vecmath.Point3i; +import javax.vecmath.Vector3f; + +/** + * This class is used as input to a geometry compressor. It collects elements + * such as vertices, normals, colors, mesh references, and quantization + * parameters in an ordered stream. This stream is then traversed during + * the compression process and used to build the compressed output buffer. + * + * @see GeometryCompressor + * + * @deprecated As of Java 3D 1.5, replaced by + * com.sun.j3d.utils.geometry.compression.{@link com.sun.j3d.utils.geometry.compression.CompressionStream}. + */ +public class CompressionStream { + // + // NOTE: For now, copies are made of all GeometryArray vertex components + // even when by-reference access is available. + // + // TODO: Retrofit all CompressionStreamElements and MeshBuffer to handle + // offsets to vertex data array references so that vertex components don't + // have to be copied. New CompressionStreamElements could be defined to + // set the current array reference during the quantization pass, or the + // reference could be included in every CompressionStreamElement along + // with the data offsets. + // + // TODO: Quantize on-the-fly when adding GeometryArray vertex data so that + // CompressionStreamElements don't need references to the original float, + // double, or byte data. Quantization is currently a separate pass since + // the 1st pass adds vertex data and gets the total object bounds, but + // this can be computed by merging the bounds of each GeometryArray + // compressed into a single object. The 2nd pass quantization is still + // needed for vertex data which isn't retrieved from a GeometryArray; for + // example, apps that might use the addVertex() methods directly instead + // of addGeometryArray(). + // + // TODO: To further optimize memory, create new subclasses of + // CompressionStream{Color, Normal} for bundled attributes and add them as + // explicit stream elements. Then CompressionStreamVertex won't need to + // carry references to them. This memory savings might be negated by the + // extra overhead of adding more elements to the stream, however. + // + // TODO: Keep the absolute quantized values in the mesh buffer mirror so + // that unmeshed CompressionStreamElements don't need to carry them. + // + // TODO: Support texture coordinate compression even though Level II is + // not supported by any hardware decompressor on any graphics card. + // Software decompression is still useful for applications interested in + // minimizing file space, transmission time, and object loading time. + // + private static final boolean debug = false ; + private static final boolean benchmark = false ; + + // Mesh buffer normal substitution is unavailable in Level I. + private static final boolean noMeshNormalSubstitution = true ; + + /** + * This flag indicates that a vertex starts a new triangle or line strip. + */ + static final int RESTART = 1 ; + + /** + * This flag indicates that the next triangle in the strip is defined by + * replacing the middle vertex of the previous triangle in the strip. + * Equivalent to REPLACE_OLDEST for line strips. + */ + static final int REPLACE_MIDDLE = 2 ; + + /** + * This flag indicates that the next triangle in the strip is defined by + * replacing the oldest vertex of the previous triangle in the strip. + * Equivalent to REPLACE_MIDDLE for line strips. + */ + static final int REPLACE_OLDEST = 3 ; + + /** + * This flag indicates that a vertex is to be pushed into the mesh buffer. + */ + static final int MESH_PUSH = 1 ; + + /** + * This flag indicates that a vertex does not use the mesh buffer. + */ + static final int NO_MESH_PUSH = 0 ; + + /** + * Byte to float scale factor for scaling byte color components. + */ + static final float ByteToFloatScale = 1.0f/255.0f; + + /** + * Type of this stream, either CompressedGeometryHeader.POINT_BUFFER, + * CompressedGeometryHeader.LINE_BUFFER, or + * CompressedGeometryHeader.TRIANGLE_BUFFER + */ + int streamType ; + + /** + * A mask indicating which components are present in each vertex, as + * defined by GeometryArray. + */ + int vertexComponents ; + + /** + * Boolean indicating colors are bundled with the vertices. + */ + boolean vertexColors ; + + /** + * Boolean indicating RGB colors are bundled with the vertices. + */ + boolean vertexColor3 ; + + /** + * Boolean indicating RGBA colors are bundled with the vertices. + */ + boolean vertexColor4 ; + + /** + * Boolean indicating normals are bundled with the vertices. + */ + boolean vertexNormals ; + + /** + * Boolean indicating texture coordinates are present. + */ + boolean vertexTextures ; + + /** + * Boolean indicating that 2D texture coordinates are used. + * Currently only used to skip over textures in interleaved data. + */ + boolean vertexTexture2 ; + + /** + * Boolean indicating that 3D texture coordinates are used. + * Currently only used to skip over textures in interleaved data. + */ + boolean vertexTexture3 ; + + /** + * Boolean indicating that 4D texture coordinates are used. + * Currently only used to skip over textures in interleaved data. + */ + boolean vertexTexture4 ; + + /** + * Axes-aligned box enclosing all vertices in model coordinates. + */ + Point3d mcBounds[] = new Point3d[2] ; + + /** + * Axes-aligned box enclosing all vertices in normalized coordinates. + */ + Point3d ncBounds[] = new Point3d[2] ; + + /** + * Axes-aligned box enclosing all vertices in quantized coordinates. + */ + Point3i qcBounds[] = new Point3i[2] ; + + /** + * Center for normalizing positions to the unit cube. + */ + double center[] = new double[3] ; + + /** + * Maximum position range along the 3 axes. + */ + double positionRangeMaximum ; + + /** + * Scale for normalizing positions to the unit cube. + */ + double scale ; + + /** + * Current position component (X, Y, and Z) quantization value. This can + * range from 1 to 16 bits and has a default of 16.

+ * + * At 1 bit of quantization it is not possible to express positive + * absolute or delta positions. + */ + int positionQuant ; + + /** + * Current color component (R, G, B, A) quantization value. This can + * range from 2 to 16 bits and has a default of 9.

+ * + * A color component is represented with a signed fixed-point value in + * order to be able express negative deltas; the default of 9 bits + * corresponds to the 8-bit color component range of the graphics hardware + * commonly available. Colors must be non-negative, so the lower limit of + * quantization is 2 bits. + */ + int colorQuant ; + + /** + * Current normal component (U and V) quantization value. This can range + * from 0 to 6 bits and has a default of 6.

+ * + * At 0 bits of quantization normals are represented only as 6 bit + * sextant/octant pairs and 14 specially encoded normals (the 6 axis + * normals and the 8 octant midpoint normals); since U and V can only be 0 + * at the minimum quantization, the totally number of unique normals is + * 12 + 14 = 26. + */ + int normalQuant ; + + /** + * Flag indicating position quantization change. + */ + boolean positionQuantChanged ; + + /** + * Flag indicating color quantization change. + */ + boolean colorQuantChanged ; + + /** + * Flag indicating normal quantization change. + */ + boolean normalQuantChanged ; + + /** + * Last quantized position. + */ + int lastPosition[] = new int[3] ; + + /** + * Last quantized color. + */ + int lastColor[] = new int[4] ; + + /** + * Last quantized normal's sextant. + */ + int lastSextant ; + + /** + * Last quantized normal's octant. + */ + int lastOctant ; + + /** + * Last quantized normal's U encoding parameter. + */ + int lastU ; + + /** + * Last quantized normal's V encoding parameter. + */ + int lastV ; + + /** + * Flag indicating last normal used a special encoding. + */ + boolean lastSpecialNormal ; + + /** + * Flag indicating the first position in this stream. + */ + boolean firstPosition ; + + /** + * Flag indicating the first color in this stream. + */ + boolean firstColor ; + + /** + * Flag indicating the first normal in this stream. + */ + boolean firstNormal ; + + /** + * The total number of bytes used to create the uncompressed geometric + * elements in this stream, useful for performance analysis. This + * excludes mesh buffer references. + */ + int byteCount ; + + /** + * The number of vertices created for this stream, excluding mesh buffer + * references. + */ + int vertexCount ; + + /** + * The number of mesh buffer references created for this stream. + */ + int meshReferenceCount ; + + /** + * Mesh buffer mirror used for computing deltas during quantization pass + * and a limited meshing algorithm for unstripped data. + */ + MeshBuffer meshBuffer = new MeshBuffer() ; + + + // Collection which holds the elements of this stream. + private Collection stream ; + + // True if preceding stream elements were colors or normals. Used to flag + // color and normal mesh buffer substitution when computing deltas during + // quantization pass. + private boolean lastElementColor = false ; + private boolean lastLastElementColor = false ; + private boolean lastElementNormal = false ; + private boolean lastLastElementNormal = false ; + + // Some convenient temporary holding variables. + private Point3f p3f = new Point3f() ; + private Color3f c3f = new Color3f() ; + private Color4f c4f = new Color4f() ; + private Vector3f n3f = new Vector3f() ; + + + // Private constructor for common initializations. + private CompressionStream() { + this.stream = new LinkedList() ; + + byteCount = 0 ; + vertexCount = 0 ; + meshReferenceCount = 0 ; + + mcBounds[0] = new Point3d(Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY) ; + mcBounds[1] = new Point3d(Double.NEGATIVE_INFINITY, + Double.NEGATIVE_INFINITY, + Double.NEGATIVE_INFINITY) ; + + qcBounds[0] = new Point3i(Integer.MAX_VALUE, + Integer.MAX_VALUE, + Integer.MAX_VALUE) ; + qcBounds[1] = new Point3i(Integer.MIN_VALUE, + Integer.MIN_VALUE, + Integer.MIN_VALUE) ; + + /* normalized bounds computed from quantized bounds */ + ncBounds[0] = new Point3d() ; + ncBounds[1] = new Point3d() ; + } + + /** + * Creates a new CompressionStream for the specified geometry type and + * vertex format.

+ * + * @param streamType type of data in this stream, either + * CompressedGeometryHeader.POINT_BUFFER, + * CompressedGeometryHeader.LINE_BUFFER, or + * CompressedGeometryHeader.TRIANGLE_BUFFER + * + * @param vertexComponents a mask indicating which components are present + * in each vertex, as defined by GeometryArray: COORDINATES, NORMALS, and + * COLOR_3 or COLOR_4. + * + * @see GeometryCompressor + * @see GeometryArray + */ + CompressionStream(int streamType, int vertexComponents) { + this() ; + this.streamType = streamType ; + this.vertexComponents = getVertexComponents(vertexComponents) ; + } + + // See what vertex geometry components are present. The byReference, + // interleaved, useNIOBuffer, and useCoordIndexOnly flags are not + // examined. + private int getVertexComponents(int vertexFormat) { + int components = 0 ; + + vertexColors = vertexColor3 = vertexColor4 = vertexNormals = + vertexTextures = vertexTexture2 = vertexTexture3 = vertexTexture4 = + false ; + + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + vertexNormals = true ; + components &= GeometryArray.NORMALS ; + if (debug) System.out.println("vertexNormals") ; + } + + if ((vertexFormat & GeometryArray.COLOR_3) != 0) { + vertexColors = true ; + + if ((vertexFormat & GeometryArray.COLOR_4) != 0) { + vertexColor4 = true ; + components &= GeometryArray.COLOR_4 ; + if (debug) System.out.println("vertexColor4") ; + } + else { + vertexColor3 = true ; + components &= GeometryArray.COLOR_3 ; + if (debug) System.out.println("vertexColor3") ; + } + } + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + vertexTextures = true ; + vertexTexture2 = true ; + components &= GeometryArray.TEXTURE_COORDINATE_2 ; + if (debug) System.out.println("vertexTexture2") ; + } + else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + vertexTextures = true ; + vertexTexture3 = true ; + components &= GeometryArray.TEXTURE_COORDINATE_3 ; + if (debug) System.out.println("vertexTexture3") ; + } + else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + vertexTextures = true ; + vertexTexture4 = true ; + components &= GeometryArray.TEXTURE_COORDINATE_4 ; + if (debug) System.out.println("vertexTexture4") ; + } + + if (vertexTextures) + // Throw exception for now until texture is supported. + throw new UnsupportedOperationException + ("\ncompression of texture coordinates is not supported") ; + + return components ; + } + + // Get the streamType associated with a GeometryArray instance. + private int getStreamType(GeometryArray ga) { + if (ga instanceof TriangleStripArray || + ga instanceof IndexedTriangleStripArray || + ga instanceof TriangleFanArray || + ga instanceof IndexedTriangleFanArray || + ga instanceof TriangleArray || + ga instanceof IndexedTriangleArray || + ga instanceof QuadArray || + ga instanceof IndexedQuadArray) + + return CompressedGeometryHeader.TRIANGLE_BUFFER ; + + else if (ga instanceof LineArray || + ga instanceof IndexedLineArray || + ga instanceof LineStripArray || + ga instanceof IndexedLineStripArray) + + return CompressedGeometryHeader.LINE_BUFFER ; + + else + return CompressedGeometryHeader.POINT_BUFFER ; + } + + /** + * Iterates across all compression stream elements and applies + * quantization parameters, encoding consecutive vertices as delta values + * whenever possible. Each geometric element is mapped to a HuffmanNode + * object containing its resulting bit length, right shift (trailing 0 + * count), and absolute or relative status.

+ * + * Positions are normalized to span a unit cube via an offset and a + * uniform scale factor that maps the midpoint of the object extents along + * each dimension to the origin, and the longest dimension of the object to + * the open interval (-1.0 .. +1.0). The geometric endpoints along that + * dimension are both one quantum away from unity; for example, at a + * position quantization of 6 bits, an object would be normalized so that + * its most negative dimension is at (-1 + 1/64) and the most positive is + * at (1 - 1/64).

+ * + * Normals are assumed to be of unit length. Color components are clamped + * to the [0..1) range, where the right endpoint is one quantum less + * than 1.0.

+ * + * @param huffmanTable Table which will map geometric compression stream + * elements to HuffmanNode objects describing each element's data + * representation. This table can then be processed with Huffman's + * algorithm to optimize the bit length of descriptor tags according to + * the number of geometric elements mapped to each tag. + */ + void quantize(HuffmanTable huffmanTable) { + // Set up default initial quantization parameters. The position and + // color parameters specify the number of bits for each X, Y, Z, R, G, + // B, or A component. The normal quantization parameter specifies the + // number of bits for each U and V component. + positionQuant = 16 ; + colorQuant = 9 ; + normalQuant = 6 ; + + // Compute position center and scaling for normalization to the unit + // cube. This is a volume bounded by the open intervals (-1..1) on + // each axis. + center[0] = (mcBounds[1].x + mcBounds[0].x) / 2.0 ; + center[1] = (mcBounds[1].y + mcBounds[0].y) / 2.0 ; + center[2] = (mcBounds[1].z + mcBounds[0].z) / 2.0 ; + + double xRange = mcBounds[1].x - mcBounds[0].x ; + double yRange = mcBounds[1].y - mcBounds[0].y ; + double zRange = mcBounds[1].z - mcBounds[0].z ; + + if (xRange > yRange) + positionRangeMaximum = xRange ; + else + positionRangeMaximum = yRange ; + + if (zRange > positionRangeMaximum) + positionRangeMaximum = zRange ; + + // Adjust the range of the unit cube to match the default + // quantization. + // + // This scale factor along with the center values computed above will + // produce 16-bit integer representations of the floating point + // position coordinates ranging symmetrically about 0 from -32767 to + // +32767. -32768 is not used and the normalized floating point + // position coordinates of -1.0 as well as +1.0 will not be + // represented. + // + // Applications which wish to seamlessly stitch together compressed + // objects will need to be aware that the range of normalized + // positions will be one quantum away from the [-1..1] endpoints of + // the unit cube and should adjust scale factors accordingly. + scale = (2.0 / positionRangeMaximum) * (32767.0 / 32768.0) ; + + // Flag quantization change. + positionQuantChanged = colorQuantChanged = normalQuantChanged = true ; + + // Flag first position, color, and normal. + firstPosition = firstColor = firstNormal = true ; + + // Apply quantization. + Iterator i = stream.iterator() ; + while (i.hasNext()) { + Object o = i.next() ; + + if (o instanceof CompressionStreamElement) { + ((CompressionStreamElement)o).quantize(this, huffmanTable) ; + + // Keep track of whether last two elements were colors or + // normals for mesh buffer component substitution semantics. + lastLastElementColor = lastElementColor ; + lastLastElementNormal = lastElementNormal ; + lastElementColor = lastElementNormal = false ; + + if (o instanceof CompressionStreamColor) + lastElementColor = true ; + else if (o instanceof CompressionStreamNormal) + lastElementNormal = true ; + } + } + + // Compute the bounds in normalized coordinates. + ncBounds[0].x = (double)qcBounds[0].x / 32768.0 ; + ncBounds[0].y = (double)qcBounds[0].y / 32768.0 ; + ncBounds[0].z = (double)qcBounds[0].z / 32768.0 ; + + ncBounds[1].x = (double)qcBounds[1].x / 32768.0 ; + ncBounds[1].y = (double)qcBounds[1].y / 32768.0 ; + ncBounds[1].z = (double)qcBounds[1].z / 32768.0 ; + } + + /** + * Iterates across all compression stream elements and builds the + * compressed geometry command stream output.

+ * + * @param huffmanTable Table which maps geometric elements in this stream + * to tags describing the encoding parameters (length, shift, and + * absolute/relative status) to be used for their representations in the + * compressed output. All tags must be 6 bits or less in length, and the + * sum of the number of bits in the tag plus the number of bits in the + * data it describes must be at least 6 bits in length. + * + * @param outputBuffer CommandStream to use for collecting the compressed + * bits. + */ + void outputCommands(HuffmanTable huffmanTable, CommandStream outputBuffer) { + // + // The first command output is setState to indicate what data is + // bundled with each vertex. Although the semantics of geometry + // decompression allow setState to appear anywhere in the stream, this + // cannot be handled by the current Java 3D software decompressor, + // which internally decompresses an entire compressed buffer into a + // single retained object sharing a single consistent vertex format. + // This limitation may be removed in subsequent releases of Java 3D. + // + int bnv = (vertexNormals? 1 : 0) ; + int bcv = ((vertexColor3 || vertexColor4)? 1 : 0) ; + int cap = (vertexColor4? 1 : 0) ; + + int command = CommandStream.SET_STATE | bnv ; + long data = (bcv << 2) | (cap << 1) ; + + // Output the setState command. + outputBuffer.addCommand(command, 8, data, 3) ; + + // Output the Huffman table commands. + huffmanTable.outputCommands(outputBuffer) ; + + // Output each compression stream element's data. + Iterator i = stream.iterator() ; + while (i.hasNext()) { + Object o = i.next() ; + if (o instanceof CompressionStreamElement) + ((CompressionStreamElement)o).outputCommand(huffmanTable, + outputBuffer) ; + } + + // Finish the header-forwarding interleave and long-word align. + outputBuffer.end() ; + } + + /** + * Retrieve the total size of the uncompressed geometric data in bytes, + * excluding mesh buffer references. + * @return uncompressed byte count + */ + int getByteCount() { + return byteCount ; + } + + /** + * Retrieve the the number of vertices created for this stream, excluding + * mesh buffer references. + * @return vertex count + */ + int getVertexCount() { + return vertexCount ; + } + + /** + * Retrieve the number of mesh buffer references created for this stream. + * @return mesh buffer reference count + */ + int getMeshReferenceCount() { + return meshReferenceCount ; + } + + /** + * Stream element that sets position quantization during quantize pass. + */ + private class PositionQuant extends CompressionStreamElement { + int value ; + + PositionQuant(int value) { + this.value = value ; + } + + void quantize(CompressionStream s, HuffmanTable t) { + positionQuant = value ; + positionQuantChanged = true ; + + // Adjust range of unit cube scaling to match quantization. + scale = (2.0 / positionRangeMaximum) * + (((double)((1 << (value-1)) - 1))/((double)(1 << (value-1)))) ; + } + + public String toString() { + return "positionQuant: " + value ; + } + } + + /** + * Stream element that sets normal quantization during quantize pass. + */ + private class NormalQuant extends CompressionStreamElement { + int value ; + + NormalQuant(int value) { + this.value = value ; + } + + void quantize(CompressionStream s, HuffmanTable t) { + normalQuant = value ; + normalQuantChanged = true ; + } + + public String toString() { + return "normalQuant: " + value ; + } + } + + /** + * Stream element that sets color quantization during quantize pass. + */ + private class ColorQuant extends CompressionStreamElement { + int value ; + + ColorQuant(int value) { + this.value = value ; + } + + void quantize(CompressionStream s, HuffmanTable t) { + colorQuant = value ; + colorQuantChanged = true ; + } + + public String toString() { + return "colorQuant: " + value ; + } + } + + /** + * Stream element that references the mesh buffer. + */ + private class MeshReference extends CompressionStreamElement { + int stripFlag, meshIndex ; + + MeshReference(int stripFlag, int meshIndex) { + this.stripFlag = stripFlag ; + this.meshIndex = meshIndex ; + meshReferenceCount++ ; + } + + void quantize(CompressionStream s, HuffmanTable t) { + // Retrieve the vertex from the mesh buffer mirror and set up the + // data needed for the next stream element to compute its deltas. + CompressionStreamVertex v = meshBuffer.getVertex(meshIndex) ; + lastPosition[0] = v.xAbsolute ; + lastPosition[1] = v.yAbsolute ; + lastPosition[2] = v.zAbsolute ; + + // Set up last color data if it exists and previous elements + // don't override it. + if (v.color != null && !lastElementColor && + !(lastElementNormal && lastLastElementColor)) { + lastColor[0] = v.color.rAbsolute ; + lastColor[1] = v.color.gAbsolute ; + lastColor[2] = v.color.bAbsolute ; + lastColor[3] = v.color.aAbsolute ; + } + + // Set up last normal data if it exists and previous element + // doesn't override it. + if (v.normal != null && !lastElementNormal && + !(lastElementColor && lastLastElementNormal)) { + lastSextant = v.normal.sextant ; + lastOctant = v.normal.octant ; + lastU = v.normal.uAbsolute ; + lastV = v.normal.vAbsolute ; + lastSpecialNormal = v.normal.specialNormal ; + } + } + + void outputCommand(HuffmanTable t, CommandStream outputBuffer) { + int command = CommandStream.MESH_B_R ; + long data = stripFlag & 0x1 ; + + command |= (((meshIndex & 0xf) << 1) | (stripFlag >> 1)) ; + outputBuffer.addCommand(command, 8, data, 1) ; + } + + public String toString() { + return + "meshReference: stripFlag " + stripFlag + + " meshIndex " + meshIndex ; + } + } + + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, int stripFlag) { + stream.add(new CompressionStreamVertex(this, pos, + (Vector3f)null, (Color3f)null, + stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Vector3f norm, int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, (Color3f)null, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Color3f color, int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Color4f color, int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Vector3f norm, Color3f color, + int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Vector3f norm, Color4f color, + int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, (Color3f)null, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Vector3f norm, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, (Color3f)null, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Color3f color, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Color4f color, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Vector3f norm, Color3f color, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, color, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Vector3f norm, Color4f color, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, color, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data, either Color3f or Color4f, determined by + * current vertex format + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Vector3f norm, + Object color, int stripFlag, int meshFlag) { + + if (vertexColor3) + stream.add(new CompressionStreamVertex + (this, pos, norm, (Color3f)color, stripFlag, meshFlag)) ; + else + stream.add(new CompressionStreamVertex + (this, pos, norm, (Color4f)color, stripFlag, meshFlag)) ; + } + + /** + * Add a mesh buffer reference to this stream. + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshIndex index of vertex to retrieve from the mesh buffer + */ + void addMeshReference(int stripFlag, int meshIndex) { + stream.add(new MeshReference(stripFlag, meshIndex)) ; + } + + /** + * Copy the given color to the end of this stream and use it as a global + * state change that applies to all subsequent vertices. + */ + void addColor(Color3f c3f) { + stream.add(new CompressionStreamColor(this, c3f)) ; + } + + /** + * Copy the given color to the end of this stream and use it as a global + * state change that applies to all subsequent vertices. + */ + void addColor(Color4f c4f) { + stream.add(new CompressionStreamColor(this, c4f)) ; + } + + /** + * Copy the given normal to the end of this stream and use it as a global + * state change that applies to all subsequent vertices. + */ + void addNormal(Vector3f n) { + stream.add(new CompressionStreamNormal(this, n)) ; + } + + /** + * Add a new position quantization value to the end of this stream that + * will apply to all subsequent vertex positions. + * + * @param value number of bits to quantize each position's X, Y, + * and Z components, ranging from 1 to 16 with a default of 16 + */ + void addPositionQuantization(int value) { + stream.add(new PositionQuant(value)) ; + } + + /** + * Add a new color quantization value to the end of this stream that will + * apply to all subsequent colors. + * + * @param value number of bits to quantize each color's R, G, B, and + * alpha components, ranging from 2 to 16 with a default of 9 + */ + void addColorQuantization(int value) { + stream.add(new ColorQuant(value)) ; + } + + /** + * Add a new normal quantization value to the end of this stream that will + * apply to all subsequent normals. This value specifies the number of + * bits for each normal's U and V components. + * + * @param value number of bits for quantizing U and V, ranging from 0 to + * 6 with a default of 6 + */ + void addNormalQuantization(int value) { + stream.add(new NormalQuant(value)) ; + } + + /** + * Interface to access GeometryArray vertex components and add them to the + * compression stream. + * + * A processVertex() implementation retrieves vertex components using the + * appropriate access semantics of a particular GeometryArray, and adds + * them to the compression stream. + * + * The implementation always pushes vertices into the mesh buffer unless + * they match ones already there; if they do, it generates mesh buffer + * references instead. This reduces the number of vertices when + * non-stripped abutting facets are added to the stream. + * + * Note: Level II geometry compression semantics allow the mesh buffer + * normals to be substituted with the value of an immediately + * preceding SetNormal command, but this is unavailable in Level I. + * + * @param index vertex offset from the beginning of its data array + * @param stripFlag RESTART, REPLACE_MIDDLE, or REPLACE_OLDEST + */ + private interface GeometryAccessor { + void processVertex(int index, int stripFlag) ; + } + + /** + * This class implements the GeometryAccessor interface for geometry + * arrays accessed with by-copy semantics. + */ + private class ByCopyGeometry implements GeometryAccessor { + Point3f[] positions = null ; + Vector3f[] normals = null ; + Color3f[] colors3 = null ; + Color4f[] colors4 = null ; + + ByCopyGeometry(GeometryArray ga) { + this(ga, ga.getInitialVertexIndex(), ga.getValidVertexCount()) ; + } + + ByCopyGeometry(GeometryArray ga, + int firstVertex, int validVertexCount) { + int i ; + positions = new Point3f[validVertexCount] ; + for (i = 0 ; i < validVertexCount ; i++) + positions[i] = new Point3f() ; + + ga.getCoordinates(firstVertex, positions) ; + + if (vertexNormals) { + normals = new Vector3f[validVertexCount] ; + for (i = 0 ; i < validVertexCount ; i++) + normals[i] = new Vector3f() ; + + ga.getNormals(firstVertex, normals) ; + } + + if (vertexColor3) { + colors3 = new Color3f[validVertexCount] ; + for (i = 0 ; i < validVertexCount ; i++) + colors3[i] = new Color3f() ; + + ga.getColors(firstVertex, colors3) ; + } + else if (vertexColor4) { + colors4 = new Color4f[validVertexCount] ; + for (i = 0 ; i < validVertexCount ; i++) + colors4[i] = new Color4f() ; + + ga.getColors(firstVertex, colors4) ; + } + } + + public void processVertex(int v, int stripFlag) { + Point3f p = positions[v] ; + int r = meshBuffer.getMeshReference(p) ; + + if ((r == meshBuffer.NOT_FOUND) || + (vertexNormals && noMeshNormalSubstitution && + (! normals[v].equals(meshBuffer.getNormal(r))))) { + + Vector3f n = vertexNormals? normals[v] : null ; + Object c = vertexColor3? (Object)colors3[v] : + vertexColor4? (Object)colors4[v] : null ; + + addVertex(p, n, c, stripFlag, MESH_PUSH) ; + meshBuffer.push(p, c, n) ; + } + else { + if (vertexNormals && !noMeshNormalSubstitution && + (! normals[v].equals(meshBuffer.getNormal(r)))) + addNormal(normals[v]) ; + + if (vertexColor3 && + (! colors3[v].equals(meshBuffer.getColor3(r)))) + addColor(colors3[v]) ; + + else if (vertexColor4 && + (! colors4[v].equals(meshBuffer.getColor4(r)))) + addColor(colors4[v]) ; + + addMeshReference(stripFlag, r) ; + } + } + } + + /** + * Class which holds index array references for a geometry array. + */ + private static class IndexArrays { + int colorIndices[] = null ; + int normalIndices[] = null ; + int positionIndices[] = null ; + } + + /** + * Retrieves index array references for the specified IndexedGeometryArray. + * Index arrays are copied starting from initialIndexIndex. + */ + private void getIndexArrays(GeometryArray ga, IndexArrays ia) { + IndexedGeometryArray iga = (IndexedGeometryArray)ga ; + + int initialIndexIndex = iga.getInitialIndexIndex() ; + int indexCount = iga.getValidIndexCount() ; + int vertexFormat = iga.getVertexFormat() ; + + boolean useCoordIndexOnly = false ; + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if (debug) System.out.println("useCoordIndexOnly") ; + useCoordIndexOnly = true ; + } + + ia.positionIndices = new int[indexCount] ; + iga.getCoordinateIndices(initialIndexIndex, ia.positionIndices) ; + + if (vertexNormals) { + if (useCoordIndexOnly) { + ia.normalIndices = ia.positionIndices ; + } + else { + ia.normalIndices = new int[indexCount] ; + iga.getNormalIndices(initialIndexIndex, ia.normalIndices) ; + } + } + if (vertexColor3 || vertexColor4) { + if (useCoordIndexOnly) { + ia.colorIndices = ia.positionIndices ; + } + else { + ia.colorIndices = new int[indexCount] ; + iga.getColorIndices(initialIndexIndex, ia.colorIndices) ; + } + } + } + + /** + * Class which holds indices for a specific vertex of an + * IndexedGeometryArray. + */ + private static class VertexIndices { + int pi, ni, ci ; + } + + /** + * Retrieves vertex indices for a specific vertex in an + * IndexedGeometryArray. + */ + private void getVertexIndices(int v, IndexArrays ia, VertexIndices vi) { + vi.pi = ia.positionIndices[v] ; + if (vertexNormals) + vi.ni = ia.normalIndices[v] ; + if (vertexColors) + vi.ci = ia.colorIndices[v] ; + } + + /** + * This class implements the GeometryAccessor interface for indexed + * geometry arrays accessed with by-copy semantics. + */ + private class IndexedByCopyGeometry extends ByCopyGeometry { + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedByCopyGeometry(GeometryArray ga) { + super(ga, 0, ga.getVertexCount()) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + int r = meshBuffer.getMeshReference(vi.pi) ; + + if ((r == meshBuffer.NOT_FOUND) || + (vertexNormals && noMeshNormalSubstitution && + (vi.ni != meshBuffer.getNormalIndex(r)))) { + + Point3f p = positions[vi.pi] ; + Vector3f n = vertexNormals? normals[vi.ni] : null ; + Object c = vertexColor3? (Object)colors3[vi.ci] : + vertexColor4? (Object)colors4[vi.ci] : null ; + + addVertex(p, n, c, stripFlag, MESH_PUSH) ; + meshBuffer.push(vi.pi, vi.ci, vi.ni) ; + } + else { + if (vertexNormals && !noMeshNormalSubstitution && + vi.ni != meshBuffer.getNormalIndex(r)) + addNormal(normals[vi.ni]) ; + + if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r)) + addColor(colors3[vi.ci]) ; + + else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r)) + addColor(colors4[vi.ci]) ; + + addMeshReference(stripFlag, r) ; + } + } + } + + // + // NOTE: For now, copies are made of all GeometryArray vertex components + // even when by-reference access is available. + // + private static class VertexCopy { + Object c = null ; + Point3f p = null ; + Vector3f n = null ; + Color3f c3 = null ; + Color4f c4 = null ; + } + + private void processVertexCopy(VertexCopy vc, int stripFlag) { + int r = meshBuffer.getMeshReference(vc.p) ; + + if ((r == meshBuffer.NOT_FOUND) || + (vertexNormals && noMeshNormalSubstitution && + (! vc.n.equals(meshBuffer.getNormal(r))))) { + + addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ; + meshBuffer.push(vc.p, vc.c, vc.n) ; + } + else { + if (vertexNormals && !noMeshNormalSubstitution && + (! vc.n.equals(meshBuffer.getNormal(r)))) + addNormal(vc.n) ; + + if (vertexColor3 && (! vc.c3.equals(meshBuffer.getColor3(r)))) + addColor(vc.c3) ; + + else if (vertexColor4 && (! vc.c4.equals(meshBuffer.getColor4(r)))) + addColor(vc.c4) ; + + addMeshReference(stripFlag, r) ; + } + } + + private void processIndexedVertexCopy(VertexCopy vc, + VertexIndices vi, + int stripFlag) { + + int r = meshBuffer.getMeshReference(vi.pi) ; + + if ((r == meshBuffer.NOT_FOUND) || + (vertexNormals && noMeshNormalSubstitution && + (vi.ni != meshBuffer.getNormalIndex(r)))) { + + addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ; + meshBuffer.push(vi.pi, vi.ci, vi.ni) ; + } + else { + if (vertexNormals && !noMeshNormalSubstitution && + vi.ni != meshBuffer.getNormalIndex(r)) + addNormal(vc.n) ; + + if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r)) + addColor(vc.c3) ; + + else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r)) + addColor(vc.c4) ; + + addMeshReference(stripFlag, r) ; + } + } + + /** + * This abstract class implements the GeometryAccessor interface for + * concrete subclasses which handle float and NIO interleaved geometry + * arrays. + */ + private abstract class InterleavedGeometry implements GeometryAccessor { + VertexCopy vc = new VertexCopy() ; + + int vstride = 0 ; + int coffset = 0 ; + int noffset = 0 ; + int poffset = 0 ; + int tstride = 0 ; + int tcount = 0 ; + + InterleavedGeometry(GeometryArray ga) { + if (vertexTextures) { + if (vertexTexture2) tstride = 2 ; + else if (vertexTexture3) tstride = 3 ; + else if (vertexTexture4) tstride = 4 ; + + tcount = ga.getTexCoordSetCount() ; + vstride += tcount * tstride ; + } + + if (vertexColors) { + coffset = vstride ; + if (vertexColor3) vstride += 3 ; + else vstride += 4 ; + } + + if (vertexNormals) { + noffset = vstride ; + vstride += 3 ; + } + + poffset = vstride ; + vstride += 3 ; + } + + abstract void copyVertex(int pi, int ni, int ci, VertexCopy vc) ; + + public void processVertex(int v, int stripFlag) { + copyVertex(v, v, v, vc) ; + processVertexCopy(vc, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for float + * interleaved geometry arrays. + */ + private class InterleavedGeometryFloat extends InterleavedGeometry { + float[] vdata = null ; + + InterleavedGeometryFloat(GeometryArray ga) { + super(ga) ; + vdata = ga.getInterleavedVertices() ; + } + + void copyVertex(int pi, int ni, int ci, VertexCopy vc) { + int voffset ; + voffset = pi * vstride ; + vc.p = new Point3f(vdata[voffset + poffset + 0], + vdata[voffset + poffset + 1], + vdata[voffset + poffset + 2]) ; + + if (vertexNormals) { + voffset = ni * vstride ; + vc.n = new Vector3f(vdata[voffset + noffset + 0], + vdata[voffset + noffset + 1], + vdata[voffset + noffset + 2]) ; + } + if (vertexColor3) { + voffset = ci * vstride ; + vc.c3 = new Color3f(vdata[voffset + coffset + 0], + vdata[voffset + coffset + 1], + vdata[voffset + coffset + 2]) ; + vc.c = vc.c3 ; + } + else if (vertexColor4) { + voffset = ci * vstride ; + vc.c4 = new Color4f(vdata[voffset + coffset + 0], + vdata[voffset + coffset + 1], + vdata[voffset + coffset + 2], + vdata[voffset + coffset + 3]) ; + vc.c = vc.c4 ; + } + } + } + + /** + * This class implements the GeometryAccessor interface for indexed + * interleaved geometry arrays. + */ + private class IndexedInterleavedGeometryFloat + extends InterleavedGeometryFloat { + + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedInterleavedGeometryFloat(GeometryArray ga) { + super(ga) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + copyVertex(vi.pi, vi.ni, vi.ci, vc) ; + processIndexedVertexCopy(vc, vi, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for + * interleaved NIO geometry arrays. + */ + private class InterleavedGeometryNIO extends InterleavedGeometry { + FloatBufferWrapper fbw = null ; + + InterleavedGeometryNIO(GeometryArray ga) { + super(ga) ; + J3DBuffer buffer = ga.getInterleavedVertexBuffer() ; + if (BufferWrapper.getBufferType(buffer) == + BufferWrapper.TYPE_FLOAT) { + fbw = new FloatBufferWrapper(buffer) ; + } + else { + throw new IllegalArgumentException + ("\ninterleaved vertex buffer must be FloatBuffer") ; + } + } + + void copyVertex(int pi, int ni, int ci, VertexCopy vc) { + int voffset ; + voffset = pi * vstride ; + vc.p = new Point3f(fbw.get(voffset + poffset + 0), + fbw.get(voffset + poffset + 1), + fbw.get(voffset + poffset + 2)) ; + + if (vertexNormals) { + voffset = ni * vstride ; + vc.n = new Vector3f(fbw.get(voffset + noffset + 0), + fbw.get(voffset + noffset + 1), + fbw.get(voffset + noffset + 2)) ; + } + if (vertexColor3) { + voffset = ci * vstride ; + vc.c3 = new Color3f(fbw.get(voffset + coffset + 0), + fbw.get(voffset + coffset + 1), + fbw.get(voffset + coffset + 2)) ; + vc.c = vc.c3 ; + } + else if (vertexColor4) { + voffset = ci * vstride ; + vc.c4 = new Color4f(fbw.get(voffset + coffset + 0), + fbw.get(voffset + coffset + 1), + fbw.get(voffset + coffset + 2), + fbw.get(voffset + coffset + 3)) ; + vc.c = vc.c4 ; + } + } + } + + /** + * This class implements the GeometryAccessor interface for indexed + * interleaved NIO geometry arrays. + */ + private class IndexedInterleavedGeometryNIO extends InterleavedGeometryNIO { + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedInterleavedGeometryNIO(GeometryArray ga) { + super(ga) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + copyVertex(vi.pi, vi.ni, vi.ci, vc) ; + processIndexedVertexCopy(vc, vi, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for + * non-interleaved geometry arrays accessed with by-reference semantics. + */ + private class ByRefGeometry implements GeometryAccessor { + VertexCopy vc = new VertexCopy() ; + + byte[] colorsB = null ; + float[] colorsF = null ; + float[] normals = null ; + float[] positionsF = null ; + double[] positionsD = null ; + + int initialPositionIndex = 0 ; + int initialNormalIndex = 0 ; + int initialColorIndex = 0 ; + + ByRefGeometry(GeometryArray ga) { + positionsF = ga.getCoordRefFloat() ; + if (debug && positionsF != null) + System.out.println("float positions") ; + + positionsD = ga.getCoordRefDouble() ; + if (debug && positionsD != null) + System.out.println("double positions") ; + + if (positionsF == null && positionsD == null) + throw new UnsupportedOperationException + ("\nby-reference access to Point3{d,f} arrays") ; + + initialPositionIndex = ga.getInitialCoordIndex() ; + + if (vertexColors) { + colorsB = ga.getColorRefByte() ; + if (debug && colorsB != null) + System.out.println("byte colors") ; + + colorsF = ga.getColorRefFloat() ; + if (debug && colorsF != null) + System.out.println("float colors") ; + + if (colorsB == null && colorsF == null) + throw new UnsupportedOperationException + ("\nby-reference access to Color{3b,3f,4b,4f} arrays") ; + + initialColorIndex = ga.getInitialColorIndex() ; + } + + if (vertexNormals) { + normals = ga.getNormalRefFloat() ; + if (debug && normals != null) + System.out.println("float normals") ; + + if (normals == null) + throw new UnsupportedOperationException + ("\nby-reference access to Normal3f array") ; + + initialNormalIndex = ga.getInitialNormalIndex() ; + } + } + + void copyVertex(int pi, int ni, int ci, VertexCopy vc) { + pi *= 3 ; + if (positionsF != null) { + vc.p = new Point3f(positionsF[pi + 0], + positionsF[pi + 1], + positionsF[pi + 2]) ; + } + else { + vc.p = new Point3f((float)positionsD[pi + 0], + (float)positionsD[pi + 1], + (float)positionsD[pi + 2]) ; + } + + ni *= 3 ; + if (vertexNormals) { + vc.n = new Vector3f(normals[ni + 0], + normals[ni + 1], + normals[ni + 2]) ; + } + + if (vertexColor3) { + ci *= 3 ; + if (colorsB != null) { + vc.c3 = new Color3f + ((colorsB[ci + 0] & 0xff) * ByteToFloatScale, + (colorsB[ci + 1] & 0xff) * ByteToFloatScale, + (colorsB[ci + 2] & 0xff) * ByteToFloatScale) ; + } + else { + vc.c3 = new Color3f(colorsF[ci + 0], + colorsF[ci + 1], + colorsF[ci + 2]) ; + } + vc.c = vc.c3 ; + } + else if (vertexColor4) { + ci *= 4 ; + if (colorsB != null) { + vc.c4 = new Color4f + ((colorsB[ci + 0] & 0xff) * ByteToFloatScale, + (colorsB[ci + 1] & 0xff) * ByteToFloatScale, + (colorsB[ci + 2] & 0xff) * ByteToFloatScale, + (colorsB[ci + 3] & 0xff) * ByteToFloatScale) ; + } + else { + vc.c4 = new Color4f(colorsF[ci + 0], + colorsF[ci + 1], + colorsF[ci + 2], + colorsF[ci + 3]) ; + } + vc.c = vc.c4 ; + } + } + + public void processVertex(int v, int stripFlag) { + copyVertex(v + initialPositionIndex, + v + initialNormalIndex, + v + initialColorIndex, vc) ; + + processVertexCopy(vc, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for indexed + * non-interleaved geometry arrays accessed with by-reference semantics. + */ + private class IndexedByRefGeometry extends ByRefGeometry { + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedByRefGeometry(GeometryArray ga) { + super(ga) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + copyVertex(vi.pi, vi.ni, vi.ci, vc) ; + processIndexedVertexCopy(vc, vi, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for + * non-interleaved geometry arrays accessed with NIO. + */ + private class ByRefGeometryNIO implements GeometryAccessor { + VertexCopy vc = new VertexCopy() ; + + ByteBufferWrapper colorsB = null ; + FloatBufferWrapper colorsF = null ; + FloatBufferWrapper normals = null ; + FloatBufferWrapper positionsF = null ; + DoubleBufferWrapper positionsD = null ; + + int initialPositionIndex = 0 ; + int initialNormalIndex = 0 ; + int initialColorIndex = 0 ; + + ByRefGeometryNIO(GeometryArray ga) { + J3DBuffer buffer ; + buffer = ga.getCoordRefBuffer() ; + initialPositionIndex = ga.getInitialCoordIndex() ; + + switch (BufferWrapper.getBufferType(buffer)) { + case BufferWrapper.TYPE_FLOAT: + positionsF = new FloatBufferWrapper(buffer) ; + if (debug) System.out.println("float positions buffer") ; + break ; + case BufferWrapper.TYPE_DOUBLE: + positionsD = new DoubleBufferWrapper(buffer) ; + if (debug) System.out.println("double positions buffer") ; + break ; + default: + throw new IllegalArgumentException + ("\nposition buffer must be FloatBuffer or DoubleBuffer") ; + } + + if (vertexColors) { + buffer = ga.getColorRefBuffer() ; + initialColorIndex = ga.getInitialColorIndex() ; + + switch (BufferWrapper.getBufferType(buffer)) { + case BufferWrapper.TYPE_BYTE: + colorsB = new ByteBufferWrapper(buffer) ; + if (debug) System.out.println("byte colors buffer") ; + break ; + case BufferWrapper.TYPE_FLOAT: + colorsF = new FloatBufferWrapper(buffer) ; + if (debug) System.out.println("float colors buffer") ; + break ; + default: + throw new IllegalArgumentException + ("\ncolor buffer must be ByteBuffer or FloatBuffer") ; + } + } + + if (vertexNormals) { + buffer = ga.getNormalRefBuffer() ; + initialNormalIndex = ga.getInitialNormalIndex() ; + + switch (BufferWrapper.getBufferType(buffer)) { + case BufferWrapper.TYPE_FLOAT: + normals = new FloatBufferWrapper(buffer) ; + if (debug) System.out.println("float normals buffer") ; + break ; + default: + throw new IllegalArgumentException + ("\nnormal buffer must be FloatBuffer") ; + } + } + } + + void copyVertex(int pi, int ni, int ci, VertexCopy vc) { + pi *= 3 ; + if (positionsF != null) { + vc.p = new Point3f(positionsF.get(pi + 0), + positionsF.get(pi + 1), + positionsF.get(pi + 2)) ; + } + else { + vc.p = new Point3f((float)positionsD.get(pi + 0), + (float)positionsD.get(pi + 1), + (float)positionsD.get(pi + 2)) ; + } + + ni *= 3 ; + if (vertexNormals) { + vc.n = new Vector3f(normals.get(ni + 0), + normals.get(ni + 1), + normals.get(ni + 2)) ; + } + + if (vertexColor3) { + ci *= 3 ; + if (colorsB != null) { + vc.c3 = new Color3f + ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale) ; + } + else { + vc.c3 = new Color3f(colorsF.get(ci + 0), + colorsF.get(ci + 1), + colorsF.get(ci + 2)) ; + } + vc.c = vc.c3 ; + } + else if (vertexColor4) { + ci *= 4 ; + if (colorsB != null) { + vc.c4 = new Color4f + ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 3) & 0xff) * ByteToFloatScale) ; + } + else { + vc.c4 = new Color4f(colorsF.get(ci + 0), + colorsF.get(ci + 1), + colorsF.get(ci + 2), + colorsF.get(ci + 3)) ; + } + vc.c = vc.c4 ; + } + } + + public void processVertex(int v, int stripFlag) { + copyVertex(v + initialPositionIndex, + v + initialNormalIndex, + v + initialColorIndex, vc) ; + + processVertexCopy(vc, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for + * non-interleaved indexed geometry arrays accessed with NIO. + */ + private class IndexedByRefGeometryNIO extends ByRefGeometryNIO { + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedByRefGeometryNIO(GeometryArray ga) { + super(ga) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + copyVertex(vi.pi, vi.ni, vi.ci, vc) ; + processIndexedVertexCopy(vc, vi, stripFlag) ; + } + } + + /** + * Convert a GeometryArray to compression stream elements and add them to + * this stream. + * + * @param ga GeometryArray to convert + * @exception IllegalArgumentException if GeometryArray has a + * dimensionality or vertex format inconsistent with the CompressionStream + */ + void addGeometryArray(GeometryArray ga) { + int firstVertex = 0 ; + int validVertexCount = 0 ; + int vertexFormat = ga.getVertexFormat() ; + GeometryAccessor geometryAccessor = null ; + + if (streamType != getStreamType(ga)) + throw new IllegalArgumentException + ("GeometryArray has inconsistent dimensionality") ; + + if (vertexComponents != getVertexComponents(vertexFormat)) + throw new IllegalArgumentException + ("GeometryArray has inconsistent vertex components") ; + + // Set up for vertex data access semantics. + boolean NIO = (vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 ; + boolean byRef = (vertexFormat & GeometryArray.BY_REFERENCE) != 0 ; + boolean interleaved = (vertexFormat & GeometryArray.INTERLEAVED) != 0 ; + boolean indexedGeometry = ga instanceof IndexedGeometryArray ; + + if (indexedGeometry) { + if (debug) System.out.println("indexed") ; + // Index arrays will be copied such that valid indices start at + // offset 0 in the copied arrays. + firstVertex = 0 ; + validVertexCount = ((IndexedGeometryArray)ga).getValidIndexCount() ; + } + + if (!byRef) { + if (debug) System.out.println("by-copy") ; + if (indexedGeometry) { + geometryAccessor = new IndexedByCopyGeometry(ga) ; + } + else { + firstVertex = 0 ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new ByCopyGeometry(ga) ; + } + } + else if (interleaved && NIO) { + if (debug) System.out.println("interleaved NIO") ; + if (indexedGeometry) { + geometryAccessor = new IndexedInterleavedGeometryNIO(ga) ; + } + else { + firstVertex = ga.getInitialVertexIndex() ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new InterleavedGeometryNIO(ga) ; + } + } + else if (interleaved && !NIO) { + if (debug) System.out.println("interleaved") ; + if (indexedGeometry) { + geometryAccessor = new IndexedInterleavedGeometryFloat(ga) ; + } + else { + firstVertex = ga.getInitialVertexIndex() ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new InterleavedGeometryFloat(ga) ; + } + } + else if (!interleaved && NIO) { + if (debug) System.out.println("non-interleaved NIO") ; + if (indexedGeometry) { + geometryAccessor = new IndexedByRefGeometryNIO(ga) ; + } + else { + firstVertex = 0 ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new ByRefGeometryNIO(ga) ; + } + } + else if (!interleaved && !NIO) { + if (debug) System.out.println("non-interleaved by-ref") ; + if (indexedGeometry) { + geometryAccessor = new IndexedByRefGeometry(ga) ; + } + else { + firstVertex = 0 ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new ByRefGeometry(ga) ; + } + } + + // Set up for topology. + int stripCount = 0 ; + int stripCounts[] = null ; + int constantStripLength = 0 ; + int replaceCode = RESTART ; + boolean strips = false ; + boolean implicitStrips = false ; + + if (ga instanceof TriangleStripArray || + ga instanceof IndexedTriangleStripArray || + ga instanceof LineStripArray || + ga instanceof IndexedLineStripArray) { + + strips = true ; + replaceCode = REPLACE_OLDEST ; + if (debug) System.out.println("strips") ; + } + else if (ga instanceof TriangleFanArray || + ga instanceof IndexedTriangleFanArray) { + + strips = true ; + replaceCode = REPLACE_MIDDLE ; + if (debug) System.out.println("fans") ; + } + else if (ga instanceof QuadArray || + ga instanceof IndexedQuadArray) { + + // Handled as fan arrays with 4 vertices per fan. + implicitStrips = true ; + constantStripLength = 4 ; + replaceCode = REPLACE_MIDDLE ; + if (debug) System.out.println("quads") ; + } + + // Get strip counts. + if (strips) { + if (indexedGeometry) { + IndexedGeometryStripArray igsa ; + igsa = (IndexedGeometryStripArray)ga ; + + stripCount = igsa.getNumStrips() ; + stripCounts = new int[stripCount] ; + igsa.getStripIndexCounts(stripCounts) ; + + } else { + GeometryStripArray gsa ; + gsa = (GeometryStripArray)ga ; + + stripCount = gsa.getNumStrips() ; + stripCounts = new int[stripCount] ; + gsa.getStripVertexCounts(stripCounts) ; + } + } + + // Build the compression stream for this shape's geometry. + int v = firstVertex ; + if (strips) { + for (int i = 0 ; i < stripCount ; i++) { + geometryAccessor.processVertex(v++, RESTART) ; + for (int j = 1 ; j < stripCounts[i] ; j++) { + geometryAccessor.processVertex(v++, replaceCode) ; + } + } + } + else if (implicitStrips) { + while (v < firstVertex + validVertexCount) { + geometryAccessor.processVertex(v++, RESTART) ; + for (int j = 1 ; j < constantStripLength ; j++) { + geometryAccessor.processVertex(v++, replaceCode) ; + } + } + } + else { + while (v < firstVertex + validVertexCount) { + geometryAccessor.processVertex(v++, RESTART) ; + } + } + } + + /** + * Print the stream to standard output. + */ + void print() { + System.out.println("\nstream has " + stream.size() + " entries") ; + System.out.println("uncompressed size " + byteCount + " bytes") ; + System.out.println("upper position bound: " + mcBounds[1].toString()) ; + System.out.println("lower position bound: " + mcBounds[0].toString()) ; + System.out.println("X, Y, Z centers (" + + ((float)center[0]) + " " + + ((float)center[1]) + " " + + ((float)center[2]) + ")\n" + + "scale " + ((float)scale) + "\n") ; + + Iterator i = stream.iterator() ; + while (i.hasNext()) { + System.out.println(i.next().toString() + "\n") ; + } + } + + + //////////////////////////////////////////////////////////////////////////// + // // + // The following constructors and methods are currently the only public // + // members of this class. All other members are subject to revision. // + // // + //////////////////////////////////////////////////////////////////////////// + + /** + * Creates a CompressionStream from an array of Shape3D scene graph + * objects. These Shape3D objects may only consist of a GeometryArray + * component and an optional Appearance component. The resulting stream + * may be used as input to the GeometryCompressor methods.

+ * + * Each Shape3D in the array must be of the same dimensionality (point, + * line, or surface) and have the same vertex format as the others. + * Texture coordinates are ignored.

+ * + * If a color is specified in the material attributes for a Shape3D then + * that color is added to the CompressionStream as the current global + * color. Subsequent colors as well as any colors bundled with vertices + * will override it. Only the material diffuse colors are used; all other + * appearance attributes are ignored.

+ * + * @param positionQuant + * number of bits to quantize each position's X, Y, + * and Z components, ranging from 1 to 16 + * + * @param colorQuant + * number of bits to quantize each color's R, G, B, and + * alpha components, ranging from 2 to 16 + * + * @param normalQuant + * number of bits for quantizing each normal's U and V components, ranging + * from 0 to 6 + * + * @param shapes + * an array of Shape3D scene graph objects containing + * GeometryArray objects, all with the same vertex format and + * dimensionality + * + * @exception IllegalArgumentException if any Shape3D has an inconsistent + * dimensionality or vertex format, or if any Shape3D contains a geometry + * component that is not a GeometryArray + * + * @see Shape3D + * @see GeometryArray + * @see GeometryCompressor + */ + public CompressionStream(int positionQuant, int colorQuant, + int normalQuant, Shape3D shapes[]) { + this() ; + if (debug) System.out.println("CompressionStream(Shape3D[]):") ; + + if (shapes == null) + throw new IllegalArgumentException("null Shape3D array") ; + + if (shapes.length == 0) + throw new IllegalArgumentException("zero-length Shape3D array") ; + + if (shapes[0] == null) + throw new IllegalArgumentException("Shape3D at index 0 is null") ; + + long startTime = 0 ; + if (benchmark) startTime = System.currentTimeMillis() ; + + Geometry g = shapes[0].getGeometry() ; + if (! (g instanceof GeometryArray)) + throw new IllegalArgumentException + ("Shape3D at index 0 is not a GeometryArray") ; + + GeometryArray ga = (GeometryArray)g ; + this.streamType = getStreamType(ga) ; + this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ; + + // Add global quantization parameters to the start of the stream. + addPositionQuantization(positionQuant) ; + addColorQuantization(colorQuant) ; + addNormalQuantization(normalQuant) ; + + // Loop through all shapes. + for (int s = 0 ; s < shapes.length ; s++) { + if (debug) System.out.println("\nShape3D " + s + ":") ; + + g = shapes[s].getGeometry() ; + if (! (g instanceof GeometryArray)) + throw new IllegalArgumentException + ("Shape3D at index " + s + " is not a GeometryArray") ; + + // Check for material color and add it to the stream if it exists. + Appearance a = shapes[s].getAppearance() ; + if (a != null) { + Material m = a.getMaterial() ; + if (m != null) { + m.getDiffuseColor(c3f) ; + if (vertexColor4) { + c4f.set(c3f.x, c3f.y, c3f.z, 1.0f) ; + addColor(c4f) ; + } else + addColor(c3f) ; + } + } + + // Add the geometry array to the stream. + addGeometryArray((GeometryArray)g) ; + } + + if (benchmark) { + long t = System.currentTimeMillis() - startTime ; + System.out.println + ("\nCompressionStream:\n" + shapes.length + " shapes in " + + (t / 1000f) + " sec") ; + } + } + + /** + * Creates a CompressionStream from an array of Shape3D scene graph + * objects. These Shape3D objects may only consist of a GeometryArray + * component and an optional Appearance component. The resulting stream + * may be used as input to the GeometryCompressor methods.

+ * + * Each Shape3D in the array must be of the same dimensionality (point, + * line, or surface) and have the same vertex format as the others. + * Texture coordinates are ignored.

+ * + * If a color is specified in the material attributes for a Shape3D then + * that color is added to the CompressionStream as the current global + * color. Subsequent colors as well as any colors bundled with vertices + * will override it. Only the material diffuse colors are used; all other + * appearance attributes are ignored.

+ * + * Defaults of 16, 9, and 6 bits are used as the quantization values for + * positions, colors, and normals respectively. These are the maximum + * resolution values defined for positions and normals; the default of 9 + * for color is the equivalent of the 8 bits of RGBA component resolution + * commonly available in graphics frame buffers.

+ * + * @param shapes + * an array of Shape3D scene graph objects containing + * GeometryArray objects, all with the same vertex format and + * dimensionality. + * + * @exception IllegalArgumentException if any Shape3D has an inconsistent + * dimensionality or vertex format, or if any Shape3D contains a geometry + * component that is not a GeometryArray + * + * @see Shape3D + * @see GeometryArray + * @see GeometryCompressor + */ + public CompressionStream(Shape3D shapes[]) { + this(16, 9, 6, shapes) ; + } + + /** + * Creates a CompressionStream from an array of GeometryInfo objects. The + * resulting stream may be used as input to the GeometryCompressor + * methods.

+ * + * Each GeometryInfo in the array must be of the same dimensionality + * (point, line, or surface) and have the same vertex format as the + * others. Texture coordinates are ignored.

+ * + * @param positionQuant + * number of bits to quantize each position's X, Y, + * and Z components, ranging from 1 to 16 + * + * @param colorQuant + * number of bits to quantize each color's R, G, B, and + * alpha components, ranging from 2 to 16 + * + * @param normalQuant + * number of bits for quantizing each normal's U and V components, ranging + * from 0 to 6 + * + * @param geometry + * an array of GeometryInfo objects, all with the same + * vertex format and dimensionality + * + * @exception IllegalArgumentException if any GeometryInfo object has an + * inconsistent dimensionality or vertex format + * + * @see GeometryInfo + * @see GeometryCompressor + */ + public CompressionStream(int positionQuant, int colorQuant, + int normalQuant, GeometryInfo geometry[]) { + this() ; + if (debug) System.out.println("CompressionStream(GeometryInfo[])") ; + + if (geometry == null) + throw new IllegalArgumentException("null GeometryInfo array") ; + + if (geometry.length == 0) + throw new IllegalArgumentException + ("zero-length GeometryInfo array") ; + + if (geometry[0] == null) + throw new IllegalArgumentException + ("GeometryInfo at index 0 is null") ; + + long startTime = 0 ; + if (benchmark) startTime = System.currentTimeMillis() ; + + GeometryArray ga = geometry[0].getGeometryArray() ; + this.streamType = getStreamType(ga) ; + this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ; + + // Add global quantization parameters to the start of the stream. + addPositionQuantization(positionQuant) ; + addColorQuantization(colorQuant) ; + addNormalQuantization(normalQuant) ; + + // Loop through all GeometryInfo objects and add them to the stream. + for (int i = 0 ; i < geometry.length ; i++) { + if (debug) System.out.println("\nGeometryInfo " + i + ":") ; + addGeometryArray(geometry[i].getGeometryArray()) ; + } + + if (benchmark) { + long t = System.currentTimeMillis() - startTime ; + System.out.println + ("\nCompressionStream:\n" + geometry.length + + " GeometryInfo objects in " + (t / 1000f) + " sec") ; + } + } + + /** + * Creates a CompressionStream from an array of GeometryInfo objects. The + * resulting stream may be used as input to the GeometryCompressor + * methods.

+ * + * Each GeometryInfo in the array must be of the same dimensionality + * (point, line, or surface) and have the same vertex format as the + * others. Texture coordinates are ignored.

+ * + * Defaults of 16, 9, and 6 bits are used as the quantization values for + * positions, colors, and normals respectively. These are the maximum + * resolution values defined for positions and normals; the default of 9 + * for color is the equivalent of the 8 bits of RGBA component resolution + * commonly available in graphics frame buffers.

+ * + * @param geometry + * an array of GeometryInfo objects, all with the same + * vertex format and dimensionality + * + * @exception IllegalArgumentException if any GeometryInfo object has an + * inconsistent dimensionality or vertex format + * + * @see GeometryInfo + * @see GeometryCompressor + */ + public CompressionStream(GeometryInfo geometry[]) { + this(16, 9, 6, geometry) ; + } + + /** + * Get the original bounds of the coordinate data, in modeling coordinates. + * Coordinate data is positioned and scaled to a normalized cube after + * compression. + * + * @return Point3d array of length 2, where the 1st Point3d is the lower + * bounds and the 2nd Point3d is the upper bounds. + * @since Java 3D 1.3 + */ + public Point3d[] getModelBounds() { + Point3d[] bounds = new Point3d[2] ; + bounds[0] = new Point3d(mcBounds[0]) ; + bounds[1] = new Point3d(mcBounds[1]) ; + return bounds ; + } + + /** + * Get the bounds of the compressed object in normalized coordinates. + * These have an maximum bounds by [-1.0 .. +1.0] across each axis. + * + * @return Point3d array of length 2, where the 1st Point3d is the lower + * bounds and the 2nd Point3d is the upper bounds. + * @since Java 3D 1.3 + */ + public Point3d[] getNormalizedBounds() { + Point3d[] bounds = new Point3d[2] ; + bounds[0] = new Point3d(ncBounds[0]) ; + bounds[1] = new Point3d(ncBounds[1]) ; + return bounds ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamColor.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamColor.java new file mode 100644 index 0000000..eaffb43 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamColor.java @@ -0,0 +1,272 @@ +/* + * $RCSfile: CompressionStreamColor.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:16 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; + +/** + * This class represents a color in a compression stream. It maintains both + * floating-point and quantized representations. This color may be bundled + * with a vertex or exist separately as a global color. + */ +class CompressionStreamColor extends CompressionStreamElement { + private int R, G, B, A ; + private boolean color3 ; + private boolean color4 ; + private float colorR, colorG, colorB, colorA ; + + int rAbsolute, gAbsolute, bAbsolute, aAbsolute ; + + /** + * Create a CompressionStreamColor. + * + * @param stream CompressionStream associated with this element + * @param color3 floating-point representation to be encoded + */ + CompressionStreamColor(CompressionStream stream, Color3f c3) { + this.color4 = false ; + this.color3 = true ; + colorR = c3.x ; + colorG = c3.y ; + colorB = c3.z ; + colorA = 0.0f ; + stream.byteCount += 12 ; + } + + /** + * Create a CompressionStreamColor. + * + * @param stream CompressionStream associated with this element + * @param color4 floating-point representation to be encoded + */ + CompressionStreamColor(CompressionStream stream, Color4f c4) { + this.color3 = false ; + this.color4 = true ; + colorR = c4.x ; + colorG = c4.y ; + colorB = c4.z ; + colorA = c4.w ; + stream.byteCount += 16 ; + } + + /** + * Quantize a floating point color to fixed point integer components of + * the specified number of bits. The bit length can range from a maximum + * of 16 to a minimum of 2 bits since negative colors are not defined.

+ * + * The bit length is the total number of bits in the signed version of the + * fixed point representation of the input color, which is assumed to + * be normalized into the [0..1) range. With the maximum bit length of + * 16, 15 bits of positive colors can be represented; a bit length of 9 is + * needed to get the 8 bit positive color size in common use.

+ * + * @param stream CompressionStream associated with this element + * @param table HuffmanTable for collecting data about the quantized + * representation of this element + */ + void quantize(CompressionStream stream, HuffmanTable huffmanTable) { + // Clamp quantization. + int quant = + (stream.colorQuant < 2? 2 : + (stream.colorQuant > 16? 16 : stream.colorQuant)) ; + + absolute = false ; + if (stream.firstColor || stream.colorQuantChanged) { + absolute = true ; + stream.lastColor[0] = 0 ; + stream.lastColor[1] = 0 ; + stream.lastColor[2] = 0 ; + stream.lastColor[3] = 0 ; + stream.firstColor = false ; + stream.colorQuantChanged = false ; + } + + // Convert the floating point position to s.15 2's complement. + if (color3) { + R = (int)(colorR * 32768.0) ; + G = (int)(colorG * 32768.0) ; + B = (int)(colorB * 32768.0) ; + A = 0 ; + } else if (color4) { + R = (int)(colorR * 32768.0) ; + G = (int)(colorG * 32768.0) ; + B = (int)(colorB * 32768.0) ; + A = (int)(colorA * 32768.0) ; + } + + // Clamp color components. + R = (R > 32767? 32767: (R < 0? 0: R)) ; + G = (G > 32767? 32767: (G < 0? 0: G)) ; + B = (B > 32767? 32767: (B < 0? 0: B)) ; + A = (A > 32767? 32767: (A < 0? 0: A)) ; + + // Compute quantized values. + R &= quantizationMask[quant] ; + G &= quantizationMask[quant] ; + B &= quantizationMask[quant] ; + A &= quantizationMask[quant] ; + + // Copy and retain absolute color for mesh buffer lookup. + rAbsolute = R ; + gAbsolute = G ; + bAbsolute = B ; + aAbsolute = A ; + + // Compute deltas. + R -= stream.lastColor[0] ; + G -= stream.lastColor[1] ; + B -= stream.lastColor[2] ; + A -= stream.lastColor[3] ; + + // Update last values. + stream.lastColor[0] += R ; + stream.lastColor[1] += G ; + stream.lastColor[2] += B ; + stream.lastColor[3] += A ; + + // Compute length and shift common to all components. + if (color3) + computeLengthShift(R, G, B) ; + + else if (color4) + computeLengthShift(R, G, B, A) ; + + // 0-length components are allowed only for normals. + if (length == 0) + length = 1 ; + + // Add this element to the Huffman table associated with this stream. + huffmanTable.addColorEntry(length, shift, absolute) ; + } + + /** + * Output a setColor command. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputCommand(HuffmanTable table, CommandStream output) { + outputColor(table, output, CommandStream.SET_COLOR, 8) ; + } + + /** + * Output a color subcommand. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputSubcommand(HuffmanTable table, CommandStream output) { + + outputColor(table, output, 0, 6) ; + } + + // + // Output the final compressed bits to the output command stream. + // + private void outputColor(HuffmanTable table, CommandStream output, + int header, int headerLength) { + HuffmanNode t ; + + // Look up the Huffman token for this compression stream element. + t = table.getColorEntry(length, shift, absolute) ; + + // Construct the color subcommand components. The maximum length of a + // color subcommand is 70 bits (a tag with a length of 6 followed by 4 + // components of 16 bits each). The subcommand is therefore + // constructed initially using just the first 3 components, with the + // 4th component added later after the tag has been shifted into the + // subcommand header. + int componentLength = t.dataLength - t.shift ; + int subcommandLength = t.tagLength + (3 * componentLength) ; + + R = (R >> t.shift) & (int)lengthMask[componentLength] ; + G = (G >> t.shift) & (int)lengthMask[componentLength] ; + B = (B >> t.shift) & (int)lengthMask[componentLength] ; + + long colorSubcommand = + (((long)t.tag) << (3 * componentLength)) | + (((long)R) << (2 * componentLength)) | + (((long)G) << (1 * componentLength)) | + (((long)B) << (0 * componentLength)) ; + + if (subcommandLength < 6) { + // The header will have some empty bits. The Huffman tag + // computation will prevent this if necessary. + header |= (int)(colorSubcommand << (6 - subcommandLength)) ; + subcommandLength = 0 ; + } + else { + // Move the 1st 6 bits of the subcommand into the header. + header |= (int)(colorSubcommand >>> (subcommandLength - 6)) ; + subcommandLength -= 6 ; + } + + // Add alpha if present. + if (color4) { + A = (A >> t.shift) & (int)lengthMask[componentLength] ; + colorSubcommand = (colorSubcommand << componentLength) | A ; + subcommandLength += componentLength ; + } + + // Add the header and body to the output buffer. + output.addCommand(header, headerLength, + colorSubcommand, subcommandLength) ; + } + + public String toString() { + String d = absolute? "" : "delta " ; + String c = (colorR + " " + colorG + " " + colorB + + (color4? (" " + colorA): "")) ; + + return + "color: " + c + "\n" + + " fixed point " + d + + R + " " + G + " " + B + "\n" + + " length " + length + " shift " + shift + + (absolute? " absolute" : " relative") ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamElement.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamElement.java new file mode 100644 index 0000000..ff0448d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamElement.java @@ -0,0 +1,359 @@ +/* + * $RCSfile: CompressionStreamElement.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:16 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +/** + * Instances of this class are used as elements in a CompressionStream. + * @see CompressionStream + */ +abstract class CompressionStreamElement { + /** + * Bit length of quantized geometric components. + */ + int length ; + + /** + * Number of trailing zeros in quantized geometric components. + */ + int shift ; + + /** + * If false, geometric component values are represented as differences + * from those of the preceding element in the stream. + */ + boolean absolute ; + + /** + * Array with elements that can be used as masks to apply a quantization + * to the number of bits indicated by the referencing index [0..16]. + */ + static final int quantizationMask[] = { + 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, + 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, + 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, + 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, + 0xFFFFFFFF + } ; + + /** + * Array with elements that can be used as masks to retain the number of + * trailing bits of data indicated by the referencing index [0..64]. Used + * to clear the leading sign bits of fixed-point 2's complement numbers + * and in building the compressed output stream. + */ + static final long lengthMask[] = { + 0x0000000000000000L, 0x0000000000000001L, + 0x0000000000000003L, 0x0000000000000007L, + 0x000000000000000FL, 0x000000000000001FL, + 0x000000000000003FL, 0x000000000000007FL, + 0x00000000000000FFL, 0x00000000000001FFL, + 0x00000000000003FFL, 0x00000000000007FFL, + 0x0000000000000FFFL, 0x0000000000001FFFL, + 0x0000000000003FFFL, 0x0000000000007FFFL, + 0x000000000000FFFFL, 0x000000000001FFFFL, + 0x000000000003FFFFL, 0x000000000007FFFFL, + 0x00000000000FFFFFL, 0x00000000001FFFFFL, + 0x00000000003FFFFFL, 0x00000000007FFFFFL, + 0x0000000000FFFFFFL, 0x0000000001FFFFFFL, + 0x0000000003FFFFFFL, 0x0000000007FFFFFFL, + 0x000000000FFFFFFFL, 0x000000001FFFFFFFL, + 0x000000003FFFFFFFL, 0x000000007FFFFFFFL, + 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL, + 0x00000003FFFFFFFFL, 0x00000007FFFFFFFFL, + 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL, + 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL, + 0x000000FFFFFFFFFFL, 0x000001FFFFFFFFFFL, + 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL, + 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL, + 0x00003FFFFFFFFFFFL, 0x00007FFFFFFFFFFFL, + 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL, + 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL, + 0x000FFFFFFFFFFFFFL, 0x001FFFFFFFFFFFFFL, + 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL, + 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL, + 0x03FFFFFFFFFFFFFFL, 0x07FFFFFFFFFFFFFFL, + 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL, + 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL, + 0xFFFFFFFFFFFFFFFFL + } ; + + + /** + * Computes the quantized representation of this stream element. + * + * @param stream CompressionStream associated with this element + * @param table HuffmanTable for collecting data about the quantized + * representation of this element + */ + abstract void quantize(CompressionStream stream, HuffmanTable table) ; + + /** + * Outputs the compressed bits representing this stream element. + * Some instances of CompressionStreamElement don't require an + * implementation and will inherit the stub provided here. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputCommand(HuffmanTable table, CommandStream output) { + } + + /** + * Finds the minimum bits needed to represent the given 16-bit signed 2's + * complement integer. For positive integers, this include the first + * 1 starting from the left, plus a 0 sign bit; for negative integers, + * this includes the first 0 starting from the left, plus a 1 sign bit. + * 0 is a special case returning 0; however, 0-length components are valid + * ONLY for normals. + * + * The decompressor uses the data length to determine how many bits of + * sign extension to add to the data coming in from the compressed stream + * in order to create a 16-bit signed 2's complement integer. E.g., a data + * length of 12 indicates that 16-12=4 bits of sign are to be extended.

+ * + * @param number a signed 2's complement integer representable in 16 bits + * or less + * @return minimum number of bits to represent the number + */ + private static final int getLength(int number) { + if (number == 0) + return 0 ; + + else if ((number & 0x8000) > 0) { + // negative numbers + if ((number & 0x4000) == 0) return 16 ; + if ((number & 0x2000) == 0) return 15 ; + if ((number & 0x1000) == 0) return 14 ; + if ((number & 0x0800) == 0) return 13 ; + if ((number & 0x0400) == 0) return 12 ; + if ((number & 0x0200) == 0) return 11 ; + if ((number & 0x0100) == 0) return 10 ; + if ((number & 0x0080) == 0) return 9 ; + if ((number & 0x0040) == 0) return 8 ; + if ((number & 0x0020) == 0) return 7 ; + if ((number & 0x0010) == 0) return 6 ; + if ((number & 0x0008) == 0) return 5 ; + if ((number & 0x0004) == 0) return 4 ; + if ((number & 0x0002) == 0) return 3 ; + if ((number & 0x0001) == 0) return 2 ; + + return 1 ; + + } else { + // positive numbers + if ((number & 0x4000) > 0) return 16 ; + if ((number & 0x2000) > 0) return 15 ; + if ((number & 0x1000) > 0) return 14 ; + if ((number & 0x0800) > 0) return 13 ; + if ((number & 0x0400) > 0) return 12 ; + if ((number & 0x0200) > 0) return 11 ; + if ((number & 0x0100) > 0) return 10 ; + if ((number & 0x0080) > 0) return 9 ; + if ((number & 0x0040) > 0) return 8 ; + if ((number & 0x0020) > 0) return 7 ; + if ((number & 0x0010) > 0) return 6 ; + if ((number & 0x0008) > 0) return 5 ; + if ((number & 0x0004) > 0) return 4 ; + if ((number & 0x0002) > 0) return 3 ; + + return 2 ; + } + } + + /** + * Finds the rightmost 1 bit in the given 16-bit integer. This value is + * used by the decompressor to indicate the number of trailing zeros to be + * added to the end of the data coming in from the compressed stream, + * accomplished by left shifting the data by the indicated amount. + * 0 is a special case returning 0.

+ * + * @param number an integer representable in 16 bits or less + * @return number of trailing zeros + */ + private static final int getShift(int number) { + if (number == 0) return 0 ; + + if ((number & 0x0001) > 0) return 0 ; + if ((number & 0x0002) > 0) return 1 ; + if ((number & 0x0004) > 0) return 2 ; + if ((number & 0x0008) > 0) return 3 ; + if ((number & 0x0010) > 0) return 4 ; + if ((number & 0x0020) > 0) return 5 ; + if ((number & 0x0040) > 0) return 6 ; + if ((number & 0x0080) > 0) return 7 ; + if ((number & 0x0100) > 0) return 8 ; + if ((number & 0x0200) > 0) return 9 ; + if ((number & 0x0400) > 0) return 10 ; + if ((number & 0x0800) > 0) return 11 ; + if ((number & 0x1000) > 0) return 12 ; + if ((number & 0x2000) > 0) return 13 ; + if ((number & 0x4000) > 0) return 14 ; + + return 15 ; + } + + /** + * Computes common length and shift of 2 numbers. + */ + final void computeLengthShift(int n0, int n1) { + int s0 = n0 & 0x8000 ; + int s1 = n1 & 0x8000 ; + + // equal sign optimization + if (s0 == s1) + if (s0 == 0) + this.length = getLength(n0 | n1) ; + else + this.length = getLength(n0 & n1) ; + else + this.length = getMaximum(getLength(n0), getLength(n1)) ; + + this.shift = getShift(n0 | n1) ; + } + + + /** + * Computes common length and shift of 3 numbers. + */ + final void computeLengthShift(int n0, int n1, int n2) { + int s0 = n0 & 0x8000 ; + int s1 = n1 & 0x8000 ; + int s2 = n2 & 0x8000 ; + + // equal sign optimization + if (s0 == s1) + if (s1 == s2) + if (s2 == 0) + this.length = getLength(n0 | n1 | n2) ; + else + this.length = getLength(n0 & n1 & n2) ; + else + if (s1 == 0) + this.length = getMaximum(getLength(n0 | n1), + getLength(n2)) ; + else + this.length = getMaximum(getLength(n0 & n1), + getLength(n2)) ; + else + if (s1 == s2) + if (s2 == 0) + this.length = getMaximum(getLength(n1 | n2), + getLength(n0)) ; + else + this.length = getMaximum(getLength(n1 & n2), + getLength(n0)) ; + else + if (s0 == 0) + this.length = getMaximum(getLength(n0 | n2), + getLength(n1)) ; + else + this.length = getMaximum(getLength(n0 & n2), + getLength(n1)) ; + + this.shift = getShift(n0 | n1 | n2) ; + } + + + /** + * Computes common length and shift of 4 numbers. + */ + final void computeLengthShift(int n0, int n1, int n2, int n3) { + this.length = getMaximum(getLength(n0), getLength(n1), + getLength(n2), getLength(n3)) ; + + this.shift = getShift(n0 | n1 | n2 | n3) ; + } + + + /** + * Finds the maximum of two integers. + */ + private static final int getMaximum(int x, int y) { + if (x > y) + return x ; + else + return y ; + } + + /** + * Finds the maximum of three integers. + */ + private static final int getMaximum(int x, int y, int z) { + if (x > y) + if (x > z) + return x ; + else + return z ; + else + if (y > z) + return y ; + else + return z ; + } + + /** + * Finds the maximum of four integers. + */ + private static final int getMaximum(int x, int y, int z, int w) { + int n0, n1 ; + + if (x > y) + n0 = x ; + else + n0 = y ; + + if (z > w) + n1 = z ; + else + n1 = w ; + + if (n0 > n1) + return n0 ; + else + return n1 ; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamNormal.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamNormal.java new file mode 100644 index 0000000..465f114 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamNormal.java @@ -0,0 +1,674 @@ +/* + * $RCSfile: CompressionStreamNormal.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:16 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import javax.vecmath.Vector3f; + +/** + * This class represents a normal in a compression stream. It maintains both + * floating-point and quantized representations. This normal may be bundled + * with a vertex or exist separately as a global normal. + */ +class CompressionStreamNormal extends CompressionStreamElement { + private int u, v ; + private int specialOctant, specialSextant ; + private float normalX, normalY, normalZ ; + + int octant, sextant ; + boolean specialNormal ; + int uAbsolute, vAbsolute ; + + /** + * Create a CompressionStreamNormal. + * + * @param stream CompressionStream associated with this element + * @param normal floating-point representation to be encoded + */ + CompressionStreamNormal(CompressionStream stream, Vector3f normal) { + this.normalX = normal.x ; + this.normalY = normal.y ; + this.normalZ = normal.z ; + stream.byteCount += 12 ; + } + + // + // Normal Encoding Parameterization + // + // A floating point normal is quantized to a desired number of bits by + // comparing it to candidate entries in a table of every possible normal + // at that quantization and finding the closest match. This table of + // normals is indexed by the following encoding: + // + // First, points on a unit radius sphere are parameterized by two angles, + // th and psi, using usual spherical coordinates. th is the angle about + // the y axis, psi is the inclination to the plane containing the point. + // The mapping between rectangular and spherical coordinates is: + // + // x = cos(th)*cos(psi) + // y = sin(psi) + // z = sin(th)*cos(psi) + // + // Points on sphere are folded first by octant, and then by sort order + // of xyz into one of six sextants. All the table encoding takes place in + // the positive octant, in the region bounded by the half spaces: + // + // x >= z + // z >= y + // y >= 0 + // + // This triangular shaped patch runs from 0 to 45 degrees in th, and + // from 0 to as much as 0.615479709 (MAX_Y_ANG) in psi. The xyz bounds + // of the patch is: + // + // (1, 0, 0) (1/sqrt(2), 0, 1/sqrt(2)) (1/sqrt(3), 1/sqrt(3), 1/sqrt(3)) + // + // When dicing this space up into discrete points, the choice for y is + // linear quantization in psi. This means that if the y range is to be + // divided up into n segments, the angle of segment j is: + // + // psi(j) = MAX_Y_ANG*(j/n) + // + // The y height of the patch (in arc length) is *not* the same as the xz + // dimension. However, the subdivision quantization needs to treat xz and + // y equally. To achieve this, the th angles are re-parameterized as + // reflected psi angles. That is, the i-th point's th is: + // + // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*(i/n))) + // + // To go the other direction, the angle th corresponds to the real index r + // (in the same 0-n range as i): + // + // r(th) = n*atan(sin(th))/MAX_Y_ANG + // + // Rounded to the nearest integer, this gives the closest integer index i + // to the xz angle th. Because the triangle has a straight edge on the + // line x=z, it is more intuitive to index the xz angles in reverse + // order. Thus the two equations above are replaced by: + // + // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*((n-i)/n))) + // + // r(th) = n*(1 - atan(sin(th))/MAX_Y_ANG) + // + // Each level of quantization subdivides the triangular patch twice as + // densely. The case in which only the three vertices of the triangle are + // present is the first logical stage of representation, but because of + // how the table is encoded the first usable case starts one level of + // sub-division later. This three point level has an n of 2 by the above + // conventions. + // + private static final int MAX_UV_BITS = 6 ; + private static final int MAX_UV_ENTRIES = 64 ; + + private static final double cgNormals[][][][] = + new double[MAX_UV_BITS+1][MAX_UV_ENTRIES+1][MAX_UV_ENTRIES+1][3] ; + + private static final double MAX_Y_ANG = 0.615479709 ; + private static final double UNITY_14 = 16384.0 ; + + private static void computeNormals() { + int inx, iny, inz, n ; + double th, psi, qnx, qny, qnz ; + + for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) { + n = 1 << quant ; + + for (int j = 0 ; j <= n ; j++) { + for (int i = 0 ; i <= n ; i++) { + if (i+j > n) continue ; + + psi = MAX_Y_ANG*(j/((double) n)) ; + th = Math.asin(Math.tan(MAX_Y_ANG*((n-i)/((double) n)))) ; + + qnx = Math.cos(th)*Math.cos(psi) ; + qny = Math.sin(psi) ; + qnz = Math.sin(th)*Math.cos(psi) ; + + // The normal table uses 16-bit components and must be + // able to represent both +1.0 and -1.0, so convert the + // floating point normal components to fixed point with 14 + // fractional bits, a unity bit, and a sign bit (s1.14). + // Set them back to get the float equivalent. + qnx = qnx*UNITY_14 ; inx = (int)qnx ; + qnx = inx ; qnx = qnx/UNITY_14 ; + + qny = qny*UNITY_14 ; iny = (int)qny ; + qny = iny ; qny = qny/UNITY_14 ; + + qnz = qnz*UNITY_14 ; inz = (int)qnz ; + qnz = inz ; qnz = qnz/UNITY_14 ; + + cgNormals[quant][j][i][0] = qnx ; + cgNormals[quant][j][i][1] = qny ; + cgNormals[quant][j][i][2] = qnz ; + } + } + } + } + + // + // An inverse sine table is used for each quantization level to take the Y + // component of a normal (which is the sine of the inclination angle) and + // obtain the closest quantized Y angle. + // + // At any level of compression, there are a fixed number of different Y + // angles (between 0 and MAX_Y_ANG). The inverse table is built to have + // slightly more than twice as many entries as y angles at any particular + // level; this ensures that the inverse look-up will get within one angle + // of the right one. The size of the table should be as small as + // possible, but with its delta sine still smaller than the delta sine + // between the last two angles to be encoded. + // + // Example: the inverse sine table has a maximum angle of 0.615479709. At + // the maximum resolution of 6 bits there are 65 discrete angles used, + // but twice as many are needed for thresholding between angles, so the + // delta angle is 0.615479709/128. The difference then between the last + // two angles to be encoded is: + // sin(0.615479709*128.0/128.0) - sin(0.615479709*127.0/128.0) = 0.003932730 + // + // Using 8 significent bits below the binary point, fixed point can + // represent sines in increments of 0.003906250, just slightly smaller. + // However, because the maximum Y angle sine is 0.577350269, only 148 + // instead of 256 table entries are needed. + // + private static final short inverseSine[][] = new short[MAX_UV_BITS+1][] ; + + // UNITY_14 * sin(MAX_Y_ANGLE) + private static final short MAX_SIN_14BIT = 9459 ; + + private static void computeInverseSineTables() { + int intSin, deltaSin, intAngle ; + double floatSin, floatAngle ; + short sin14[] = new short[MAX_UV_ENTRIES+1] ; + + // Build table of sines in s1.14 fixed point for each of the + // discrete angles used at maximum resolution. + for (int i = 0 ; i <= MAX_UV_ENTRIES ; i++) { + sin14[i] = (short)(UNITY_14*Math.sin(i*MAX_Y_ANG/MAX_UV_ENTRIES)) ; + } + + for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) { + switch (quant) { + default: + case 6: + // Delta angle: MAX_Y_ANGLE/128.0 + // Bits below binary point for fixed point delta sine: 8 + // Integer delta sine: 64 + // Inverse sine table size: 148 entries + deltaSin = 1 << (14 - 8) ; + break ; + case 5: + // Delta angle: MAX_Y_ANGLE/64.0 + // Bits below binary point for fixed point delta sine: 7 + // Integer delta sine: 128 + // Inverse sine table size: 74 entries + deltaSin = 1 << (14 - 7) ; + break ; + case 4: + // Delta angle: MAX_Y_ANGLE/32.0 + // Bits below binary point for fixed point delta sine: 6 + // Integer delta sine: 256 + // Inverse sine table size: 37 entries + deltaSin = 1 << (14 - 6) ; + break ; + case 3: + // Delta angle: MAX_Y_ANGLE/16.0 + // Bits below binary point for fixed point delta sine: 5 + // Integer delta sine: 512 + // Inverse sine table size: 19 entries + deltaSin = 1 << (14 - 5) ; + break ; + case 2: + // Delta angle: MAX_Y_ANGLE/8.0 + // Bits below binary point for fixed point delta sine: 4 + // Integer delta sine: 1024 + // Inverse sine table size: 10 entries + deltaSin = 1 << (14 - 4) ; + break ; + case 1: + // Delta angle: MAX_Y_ANGLE/4.0 + // Bits below binary point for fixed point delta sine: 3 + // Integer delta sine: 2048 + // Inverse sine table size: 5 entries + deltaSin = 1 << (14 - 3) ; + break ; + case 0: + // Delta angle: MAX_Y_ANGLE/2.0 + // Bits below binary point for fixed point delta sine: 2 + // Integer delta sine: 4096 + // Inverse sine table size: 3 entries + deltaSin = 1 << (14 - 2) ; + break ; + } + + inverseSine[quant] = new short[(MAX_SIN_14BIT/deltaSin) + 1] ; + + intSin = 0 ; + for (int i = 0 ; i < inverseSine[quant].length ; i++) { + // Compute float representation of integer sine with desired + // number of fractional bits by effectively right shifting 14. + floatSin = intSin/UNITY_14 ; + + // Compute the angle with this sine value and quantize it. + floatAngle = Math.asin(floatSin) ; + intAngle = (int)((floatAngle/MAX_Y_ANG) * (1 << quant)) ; + + // Choose the closest of the three nearest quantized values + // intAngle-1, intAngle, and intAngle+1. + if (intAngle > 0) { + if (Math.abs(sin14[intAngle << (6-quant)] - intSin) > + Math.abs(sin14[(intAngle-1) << (6-quant)] - intSin)) + intAngle = intAngle-1 ; + } + + if (intAngle < (1 << quant)) { + if (Math.abs(sin14[intAngle << (6-quant)] - intSin) > + Math.abs(sin14[(intAngle+1) << (6-quant)] - intSin)) + intAngle = intAngle+1 ; + } + + inverseSine[quant][i] = (short)intAngle ; + intSin += deltaSin ; + } + } + } + + /** + * Compute static tables needed for normal quantization. + */ + static { + computeNormals() ; + computeInverseSineTables() ; + } + + /** + * Quantize the floating point normal to a 6-bit octant/sextant plus u,v + * components of [0..6] bits. Full resolution is 18 bits and the minimum + * is 6 bits. + * + * @param stream CompressionStream associated with this element + * @param table HuffmanTable for collecting data about the quantized + * representation of this element + */ + void quantize(CompressionStream stream, HuffmanTable huffmanTable) { + double nx, ny, nz, t ; + + // Clamp UV quantization. + int quant = + (stream.normalQuant < 0? 0 : + (stream.normalQuant > 6? 6 : stream.normalQuant)) ; + + nx = normalX ; + ny = normalY ; + nz = normalZ ; + + octant = 0 ; + sextant = 0 ; + u = 0 ; + v = 0 ; + + // Normalize the fixed point normal to the positive signed octant. + if (nx < 0.0) { + octant |= 4 ; + nx = -nx ; + } + if (ny < 0.0) { + octant |= 2 ; + ny = -ny ; + } + if (nz < 0.0) { + octant |= 1 ; + nz = -nz ; + } + + // Normalize the fixed point normal to the proper sextant of the octant. + if (nx < ny) { + sextant |= 1 ; + t = nx ; + nx = ny ; + ny = t ; + } + if (nz < ny) { + sextant |= 2 ; + t = ny ; + ny = nz ; + nz = t ; + } + if (nx < nz) { + sextant |= 4 ; + t = nx ; + nx = nz ; + nz = t ; + } + + // Convert the floating point y component to s1.14 fixed point. + int yInt = (int)(ny * UNITY_14) ; + + // The y component of the normal is the sine of the y angle. Quantize + // the y angle by using the fixed point y component as an index into + // the inverse sine table of the correct size for the quantization + // level. (12 - quant) bits of the s1.14 y normal component are + // rolled off with a right shift; the remaining bits then match the + // number of bits used to represent the delta sine of the table. + int yIndex = inverseSine[quant][yInt >> (12-quant)] ; + + // Search the two xz rows near y for the best match. + int ii = 0 ; + int jj = 0 ; + int n = 1 << quant ; + double dot, bestDot = -1 ; + + for (int j = yIndex-1 ; j < yIndex+1 && j <= n ; j++) { + if (j < 0) + continue ; + + for (int i = 0 ; i <= n ; i++) { + if (i+j > n) + continue ; + + dot = nx * cgNormals[quant][j][i][0] + + ny * cgNormals[quant][j][i][1] + + nz * cgNormals[quant][j][i][2] ; + + if (dot > bestDot) { + bestDot = dot ; + ii = i ; + jj = j ; + } + } + } + + // Convert u and v to standard grid form. + u = ii << (6 - quant) ; + v = jj << (6 - quant) ; + + // Check for special normals and specially encode them. + specialNormal = false ; + if (u == 64 && v == 0) { + // six coordinate axes case + if (sextant == 0 || sextant == 2) { + // +/- x-axis + specialSextant = 0x6 ; + specialOctant = ((octant & 4) != 0)? 0x2 : 0 ; + + } else if (sextant == 3 || sextant == 1) { + // +/- y-axis + specialSextant = 0x6 ; + specialOctant = 4 | (((octant & 2) != 0)? 0x2 : 0) ; + + } else if (sextant == 5 || sextant == 4) { + // +/- z-axis + specialSextant = 0x7 ; + specialOctant = ((octant & 1) != 0)? 0x2 : 0 ; + } + specialNormal = true ; + u = v = 0 ; + + } else if (u == 0 && v == 64) { + // eight mid point case + specialSextant = 6 | (octant >> 2) ; + specialOctant = ((octant & 0x3) << 1) | 1 ; + specialNormal = true ; + u = v = 0 ; + } + + // Compute deltas if possible. + // Use the non-normalized ii and jj indices. + int du = 0 ; + int dv = 0 ; + int uv64 = 64 >> (6 - quant) ; + + absolute = false ; + if (stream.firstNormal || stream.normalQuantChanged || + stream.lastSpecialNormal || specialNormal) { + // The first normal by definition is absolute, and normals cannot + // be represented as deltas to or from special normals, nor from + // normals with a different quantization. + absolute = true ; + stream.firstNormal = false ; + stream.normalQuantChanged = false ; + + } else if (stream.lastOctant == octant && + stream.lastSextant == sextant) { + // Deltas are always allowed within the same sextant/octant. + du = ii - stream.lastU ; + dv = jj - stream.lastV ; + + } else if (stream.lastOctant != octant && + stream.lastSextant == sextant && + (((sextant == 1 || sextant == 5) && + (stream.lastOctant & 3) == (octant & 3)) || + ((sextant == 0 || sextant == 4) && + (stream.lastOctant & 5) == (octant & 5)) || + ((sextant == 2 || sextant == 3) && + (stream.lastOctant & 6) == (octant & 6)))) { + // If the sextants are the same, the octants can differ only when + // they are bordering each other on the same edge that the + // sextant has. + du = ii - stream.lastU ; + dv = -jj - stream.lastV ; + + // Can't delta by less than -64. + if (dv < -uv64) absolute = true ; + + // Can't delta doubly defined points. + if (jj == 0) absolute = true ; + + } else if (stream.lastOctant == octant && + stream.lastSextant != sextant && + ((sextant == 0 && stream.lastSextant == 4) || + (sextant == 4 && stream.lastSextant == 0) || + (sextant == 1 && stream.lastSextant == 5) || + (sextant == 5 && stream.lastSextant == 1) || + (sextant == 2 && stream.lastSextant == 3) || + (sextant == 3 && stream.lastSextant == 2))) { + // If the octants are the same, the sextants must border on + // the i side (this case) or the j side (next case). + du = -ii - stream.lastU ; + dv = jj - stream.lastV ; + + // Can't delta by less than -64. + if (du < -uv64) absolute = true ; + + // Can't delta doubly defined points. + if (ii == 0) absolute = true ; + + } else if (stream.lastOctant == octant && + stream.lastSextant != sextant && + ((sextant == 0 && stream.lastSextant == 2) || + (sextant == 2 && stream.lastSextant == 0) || + (sextant == 1 && stream.lastSextant == 3) || + (sextant == 3 && stream.lastSextant == 1) || + (sextant == 4 && stream.lastSextant == 5) || + (sextant == 5 && stream.lastSextant == 4))) { + // If the octants are the same, the sextants must border on + // the j side (this case) or the i side (previous case). + if (((ii + jj ) != uv64) && (ii != 0) && (jj != 0)) { + du = uv64 - ii - stream.lastU ; + dv = uv64 - jj - stream.lastV ; + + // Can't delta by greater than +63. + if ((du >= uv64) || (dv >= uv64)) + absolute = true ; + } else + // Can't delta doubly defined points. + absolute = true ; + + } else + // Can't delta this normal. + absolute = true ; + + if (absolute == false) { + // Convert du and dv to standard grid form. + u = du << (6 - quant) ; + v = dv << (6 - quant) ; + } + + // Compute length and shift common to all components. + computeLengthShift(u, v) ; + + if (absolute && length > 6) { + // Absolute normal u, v components are unsigned 6-bit integers, so + // truncate the 0 sign bit for values > 0x001f. + length = 6 ; + } + + // Add this element to the Huffman table associated with this stream. + huffmanTable.addNormalEntry(length, shift, absolute) ; + + // Save current normal as last. + stream.lastSextant = sextant ; + stream.lastOctant = octant ; + stream.lastU = ii ; + stream.lastV = jj ; + stream.lastSpecialNormal = specialNormal ; + + // Copy and retain absolute normal for mesh buffer lookup. + uAbsolute = ii ; + vAbsolute = jj ; + } + + /** + * Output a setNormal command. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputCommand(HuffmanTable table, CommandStream output) { + outputNormal(table, output, CommandStream.SET_NORM, 8) ; + } + + /** + * Output a normal subcommand. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputSubcommand(HuffmanTable table, CommandStream output) { + outputNormal(table, output, 0, 6) ; + } + + // + // Output the final compressed bits to the output command stream. + // + private void outputNormal(HuffmanTable table, CommandStream output, + int header, int headerLength) { + + HuffmanNode t ; + + // Look up the Huffman token for this compression stream element. + t = table.getNormalEntry(length, shift, absolute) ; + + // Construct the normal subcommand. + int componentLength = t.dataLength - t.shift ; + int subcommandLength = 0 ; + long normalSubcommand = 0 ; + + if (absolute) { + // A 3-bit sextant and a 3-bit octant are always present. + subcommandLength = t.tagLength + 6 ; + + if (specialNormal) + // Use the specially-encoded sextant and octant. + normalSubcommand = + (t.tag << 6) | (specialSextant << 3) | specialOctant ; + else + // Use the general encoding rule. + normalSubcommand = + (t.tag << 6) | (sextant << 3) | octant ; + } else { + // The tag is immediately followed by the u and v delta components. + subcommandLength = t.tagLength ; + normalSubcommand = t.tag ; + } + + // Add the u and v values to the subcommand. + subcommandLength += (2 * componentLength) ; + + u = (u >> t.shift) & (int)lengthMask[componentLength] ; + v = (v >> t.shift) & (int)lengthMask[componentLength] ; + + normalSubcommand = + (normalSubcommand << (2 * componentLength)) | + (u << (1 * componentLength)) | + (v << (0 * componentLength)) ; + + if (subcommandLength < 6) { + // The header will have some empty bits. The Huffman tag + // computation will prevent this if necessary. + header |= (int)(normalSubcommand << (6 - subcommandLength)) ; + subcommandLength = 0 ; + } + else { + // Move the 1st 6 bits of the subcommand into the header. + header |= (int)(normalSubcommand >>> (subcommandLength - 6)) ; + subcommandLength -= 6 ; + } + + // Add the header and body to the output buffer. + output.addCommand(header, headerLength, + normalSubcommand, subcommandLength) ; + } + + public String toString() { + String fixed ; + + if (specialNormal) + fixed = " special normal, sextant " + specialSextant + + " octant " + specialOctant ; + + else if (absolute) + fixed = " sextant " + sextant + " octant " + octant + + " u " + u + " v " + v ; + else + fixed = " du " + u + " dv " + v ; + + return + "normal: " + normalX + " " + normalY + " " + normalZ + "\n" + + fixed + "\n" + " length " + length + " shift " + shift + + (absolute? " absolute" : " relative") ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamVertex.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamVertex.java new file mode 100644 index 0000000..b1618b5 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamVertex.java @@ -0,0 +1,322 @@ +/* + * $RCSfile: CompressionStreamVertex.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:16 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +/** + * This class represents a vertex in a compression stream. It maintains both + * floating-point and quantized representations of the vertex position along + * with meshing and vertex replacement flags for line and surface + * primitives. If normals or colors are bundled with geometry vertices then + * instances of this class will also contain references to normal or color + * stream elements. + */ +class CompressionStreamVertex extends CompressionStreamElement { + private int X, Y, Z ; + private int meshFlag ; + private int stripFlag ; + private float floatX, floatY, floatZ ; + + int xAbsolute, yAbsolute, zAbsolute ; + CompressionStreamColor color = null ; + CompressionStreamNormal normal = null ; + + /** + * Create a CompressionStreamVertex with the given parameters. + * + * @param stream CompressionStream associated with this vertex + * @param p position + * @param n normal bundled with this vertex or null if not bundled + * @param c color bundled with this vertex or null if not bundled + * @param stripFlag CompressionStream.RESTART, + * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE + * @param meshFlag CompressionStream.MESH_PUSH or + * CompressionStream.NO_MESH_PUSH + */ + CompressionStreamVertex(CompressionStream stream, + Point3f p, Vector3f n, Color3f c, + int stripFlag, int meshFlag) { + + this(stream, p, n, stripFlag, meshFlag) ; + + if (stream.vertexColor3) + color = new CompressionStreamColor(stream, c) ; + } + + /** + * Create a CompressionStreamVertex with the given parameters. + * + * @param stream CompressionStream associated with this vertex + * @param p position + * @param n normal bundled with this vertex or null if not bundled + * @param c color bundled with this vertex or null if not bundled + * @param stripFlag CompressionStream.RESTART, + * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE + * @param meshFlag CompressionStream.MESH_PUSH or + * CompressionStream.NO_MESH_PUSH + */ + CompressionStreamVertex(CompressionStream stream, + Point3f p, Vector3f n, Color4f c, + int stripFlag, int meshFlag) { + + this(stream, p, n, stripFlag, meshFlag) ; + + if (stream.vertexColor4) + color = new CompressionStreamColor(stream, c) ; + } + + /** + * Create a CompressionStreamVertex with the given parameters. + * + * @param stream CompressionStream associated with this vertex + * @param p position + * @param n normal bundled with this vertex or null if not bundled + * @param stripFlag CompressionStream.RESTART, + * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE + * @param meshFlag CompressionStream.MESH_PUSH or + * CompressionStream.NO_MESH_PUSH + */ + CompressionStreamVertex(CompressionStream stream, Point3f p, Vector3f n, + int stripFlag, int meshFlag) { + + this.stripFlag = stripFlag ; + this.meshFlag = meshFlag ; + this.floatX = p.x ; + this.floatY = p.y ; + this.floatZ = p.z ; + + stream.byteCount += 12 ; + stream.vertexCount++ ; + + if (p.x < stream.mcBounds[0].x) stream.mcBounds[0].x = p.x ; + if (p.y < stream.mcBounds[0].y) stream.mcBounds[0].y = p.y ; + if (p.z < stream.mcBounds[0].z) stream.mcBounds[0].z = p.z ; + + if (p.x > stream.mcBounds[1].x) stream.mcBounds[1].x = p.x ; + if (p.y > stream.mcBounds[1].y) stream.mcBounds[1].y = p.y ; + if (p.z > stream.mcBounds[1].z) stream.mcBounds[1].z = p.z ; + + if (stream.vertexNormals) + normal = new CompressionStreamNormal(stream, n) ; + } + + /** + * Quantize the floating point position to fixed point integer components + * of the specified number of bits. The bit length can range from 1 to 16. + * + * @param stream CompressionStream associated with this element + * @param table HuffmanTable for collecting data about the quantized + * representation of this element + */ + void quantize(CompressionStream stream, HuffmanTable huffmanTable) { + double px, py, pz ; + + // Clamp quantization. + int quant = + (stream.positionQuant < 1? 1 : + (stream.positionQuant > 16? 16 : stream.positionQuant)) ; + + absolute = false ; + if (stream.firstPosition || stream.positionQuantChanged) { + absolute = true ; + stream.lastPosition[0] = 0 ; + stream.lastPosition[1] = 0 ; + stream.lastPosition[2] = 0 ; + stream.firstPosition = false ; + stream.positionQuantChanged = false ; + } + + // Normalize position to the unit cube. This is bounded by the open + // intervals (-1..1) on each axis. + px = (floatX - stream.center[0]) * stream.scale ; + py = (floatY - stream.center[1]) * stream.scale ; + pz = (floatZ - stream.center[2]) * stream.scale ; + + // Convert the floating point position to s.15 2's complement. + // ~1.0 -> 32767 (0x00007fff) [ ~1.0 = 32767.0/32768.0] + // ~-1.0 -> -32767 (0xffff8001) [~-1.0 = -32767.0/32768.0] + X = (int)(px * 32768.0) ; + Y = (int)(py * 32768.0) ; + Z = (int)(pz * 32768.0) ; + + // Compute quantized values. + X &= quantizationMask[quant] ; + Y &= quantizationMask[quant] ; + Z &= quantizationMask[quant] ; + + // Update quantized bounds. + if (X < stream.qcBounds[0].x) stream.qcBounds[0].x = X ; + if (Y < stream.qcBounds[0].y) stream.qcBounds[0].y = Y ; + if (Z < stream.qcBounds[0].z) stream.qcBounds[0].z = Z ; + + if (X > stream.qcBounds[1].x) stream.qcBounds[1].x = X ; + if (Y > stream.qcBounds[1].y) stream.qcBounds[1].y = Y ; + if (Z > stream.qcBounds[1].z) stream.qcBounds[1].z = Z ; + + // Copy and retain absolute position for mesh buffer lookup. + xAbsolute = X ; + yAbsolute = Y ; + zAbsolute = Z ; + + // Compute deltas. + X -= stream.lastPosition[0] ; + Y -= stream.lastPosition[1] ; + Z -= stream.lastPosition[2] ; + + // Update last values. + stream.lastPosition[0] += X ; + stream.lastPosition[1] += Y ; + stream.lastPosition[2] += Z ; + + // Deltas which exceed the range of 16-bit signed 2's complement + // numbers are handled by sign-extension of the 16th bit in order to + // effect a 16-bit wrap-around. + X = (X << 16) >> 16 ; + Y = (Y << 16) >> 16 ; + Z = (Z << 16) >> 16 ; + + // Compute length and shift common to all components. + computeLengthShift(X, Y, Z) ; + + // 0-length components are allowed only for normals. + if (length == 0) + length = 1 ; + + // Add this element to the Huffman table associated with this stream. + huffmanTable.addPositionEntry(length, shift, absolute) ; + + // Quantize any bundled color or normal. + if (color != null) + color.quantize(stream, huffmanTable) ; + + if (normal != null) + normal.quantize(stream, huffmanTable) ; + + // Push this vertex into the mesh buffer mirror, if necessary, so it + // can be retrieved for computing deltas when mesh buffer references + // are subsequently encountered during the quantization pass. + if (meshFlag == stream.MESH_PUSH) + stream.meshBuffer.push(this) ; + } + + /** + * Output the final compressed bits to the compression command stream. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputCommand(HuffmanTable huffmanTable, CommandStream outputBuffer) { + + HuffmanNode t ; + int command = CommandStream.VERTEX ; + + // Look up the Huffman token for this compression stream element. The + // values of length and shift found there will override the + // corresponding fields in this element, which represent best-case + // compression without regard to tag length. + t = huffmanTable.getPositionEntry(length, shift, absolute) ; + + // Construct the position subcommand. + int componentLength = t.dataLength - t.shift ; + int subcommandLength = t.tagLength + (3 * componentLength) ; + + X = (X >> t.shift) & (int)lengthMask[componentLength] ; + Y = (Y >> t.shift) & (int)lengthMask[componentLength] ; + Z = (Z >> t.shift) & (int)lengthMask[componentLength] ; + + long positionSubcommand = + (((long)t.tag) << (3 * componentLength)) | + (((long)X) << (2 * componentLength)) | + (((long)Y) << (1 * componentLength)) | + (((long)Z) << (0 * componentLength)) ; + + if (subcommandLength < 6) { + // The header will have some empty bits. The Huffman tag + // computation will prevent this if necessary. + command |= (int)(positionSubcommand << (6 - subcommandLength)) ; + subcommandLength = 0 ; + } + else { + // Move the 1st 6 bits of the subcommand into the header. + command |= (int)(positionSubcommand >>> (subcommandLength - 6)) ; + subcommandLength -= 6 ; + } + + // Construct the vertex command body. + long body = + (((long)stripFlag) << (subcommandLength + 1)) | + (((long)meshFlag) << (subcommandLength + 0)) | + (positionSubcommand & lengthMask[subcommandLength]) ; + + // Add the vertex command to the output buffer. + outputBuffer.addCommand(command, 8, body, subcommandLength + 3) ; + + // Output any normal and color subcommands. + if (normal != null) + normal.outputSubcommand(huffmanTable, outputBuffer) ; + + if (color != null) + color.outputSubcommand(huffmanTable, outputBuffer) ; + } + + public String toString() { + String d = absolute? "" : "delta " ; + String c = (color == null? "": "\n\n " + color.toString()) ; + String n = (normal == null? "": "\n\n " + normal.toString()) ; + + return + "position: " + floatX + " " + floatY + " " + floatZ + "\n" + + "fixed point " + d + + X + " " + Y + " " + Z + "\n" + + "length " + length + " shift " + shift + + (absolute? " absolute" : " relative") + "\n" + + "strip flag " + stripFlag + " mesh flag " + meshFlag + + c + n ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/GeometryCompressor.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/GeometryCompressor.java new file mode 100644 index 0000000..9fe3d54 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/GeometryCompressor.java @@ -0,0 +1,206 @@ +/* + * $RCSfile: GeometryCompressor.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:16 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import java.io.IOException; +import javax.media.j3d.CompressedGeometry; +import javax.media.j3d.CompressedGeometryHeader; +import javax.vecmath.Point3d; + +/** + * A GeometryCompressor takes a stream of geometric elements and + * quantization parameters (the CompressionStream object) and + * compresses it into a stream of commands as defined by appendix B + * of the Java 3D specification. The resulting data may be output + * in the form of a CompressedGeometry node component or appended + * to a CompressedGeometryFile. + * + * @see CompressionStream + * @see CompressedGeometry + * @see CompressedGeometryFile + * + * @deprecated As of Java 3D 1.5, replaced by + * com.sun.j3d.utils.geometry.compression.{@link com.sun.j3d.utils.geometry.compression.GeometryCompressor}. + */ +public class GeometryCompressor { + private static final boolean benchmark = false ; + private static final boolean printStream = false ; + private static final boolean printHuffman = false ; + + private HuffmanTable huffmanTable ; + private CommandStream outputBuffer ; + private CompressedGeometryHeader cgHeader ; + private long startTime ; + + public GeometryCompressor() { + // Create a compressed geometry header. + cgHeader = new CompressedGeometryHeader() ; + + // v1.0.0 - pre-FCS + // v1.0.1 - fixed winding order, FCS version (J3D 1.1.2) + // v1.0.2 - normal component length maximum 6, LII hardware (J3D 1.2) + cgHeader.majorVersionNumber = 1 ; + cgHeader.minorVersionNumber = 0 ; + cgHeader.minorMinorVersionNumber = 2 ; + } + + /** + * Compress a stream into a CompressedGeometry node component. + * + * @param stream CompressionStream containing the geometry to be compressed + * @return a CompressedGeometry node component + */ + public CompressedGeometry compress(CompressionStream stream) { + CompressedGeometry cg ; + + compressStream(stream) ; + cg = new CompressedGeometry(cgHeader, outputBuffer.getBytes()) ; + + outputBuffer.clear() ; + return cg ; + } + + /** + * Compress a stream and append the output to a CompressedGeometryFile. + * The resource remains open for subsequent updates; its close() method + * must be called to create a valid compressed geometry resource file. + * + * @param stream CompressionStream containing the geometry to be compressed + * @param f a currently open CompressedGeometryFile with write access + * @exception IOException if write fails + */ + public void compress(CompressionStream stream, CompressedGeometryFile f) + throws IOException { + + compressStream(stream) ; + f.write(cgHeader, outputBuffer.getBytes()) ; + + outputBuffer.clear() ; + } + + // + // Compress the stream and put the results in the output buffer. + // Set up the CompressedGeometryHeader object. + // + private void compressStream(CompressionStream stream) { + if (benchmark) startTime = System.currentTimeMillis() ; + + // Create the Huffman table. + huffmanTable = new HuffmanTable() ; + + // Quantize the stream, compute deltas between consecutive elements if + // possible, and histogram the data length distribution. + stream.quantize(huffmanTable) ; + + // Compute tags for stream tokens. + huffmanTable.computeTags() ; + + // Create the output buffer and assemble the compressed output. + outputBuffer = new CommandStream(stream.getByteCount() / 3) ; + stream.outputCommands(huffmanTable, outputBuffer) ; + + // Print any desired info. + if (benchmark) printBench(stream) ; + if (printStream) stream.print() ; + if (printHuffman) huffmanTable.print() ; + + // Set up the compressed geometry header object. + cgHeader.bufferType = stream.streamType ; + cgHeader.bufferDataPresent = 0 ; + cgHeader.lowerBound = new Point3d(stream.ncBounds[0]) ; + cgHeader.upperBound = new Point3d(stream.ncBounds[1]) ; + + if (stream.vertexNormals) + cgHeader.bufferDataPresent |= + CompressedGeometryHeader.NORMAL_IN_BUFFER ; + + if (stream.vertexColor3 || stream.vertexColor4) + cgHeader.bufferDataPresent |= + CompressedGeometryHeader.COLOR_IN_BUFFER ; + + if (stream.vertexColor4) + cgHeader.bufferDataPresent |= + CompressedGeometryHeader.ALPHA_IN_BUFFER ; + + cgHeader.start = 0 ; + cgHeader.size = outputBuffer.getByteCount() ; + + // Clear the huffman table for next use. + huffmanTable.clear() ; + } + + private void printBench(CompressionStream stream) { + long t = System.currentTimeMillis() - startTime ; + int vertexCount = stream.getVertexCount() ; + int meshReferenceCount = stream.getMeshReferenceCount() ; + int totalVertices = meshReferenceCount + vertexCount ; + float meshPercent = 100f * meshReferenceCount/(float)totalVertices ; + + float compressionRatio = + stream.getByteCount() / ((float)outputBuffer.getByteCount()) ; + + int vertexBytes = + 12 + (stream.vertexColor3 ? 12 : 0) + + (stream.vertexColor4 ? 16 : 0) + (stream.vertexNormals ? 12 : 0) ; + + float compressedVertexBytes = + outputBuffer.getByteCount() / (float)totalVertices ; + + System.out.println + ("\nGeometryCompressor:\n" + totalVertices + " total vertices\n" + + vertexCount + " streamed vertices\n" + meshReferenceCount + + " mesh buffer references (" + meshPercent + "%)\n" + + stream.getByteCount() + " bytes streamed geometry compressed to " + + outputBuffer.getByteCount() + " in " + (t/1000f) + " sec\n" + + (stream.getByteCount()/(float)t) + " kbytes/sec, " + + "stream compression ratio " + compressionRatio + "\n\n" + + vertexBytes + " original bytes per vertex, " + + compressedVertexBytes + " compressed bytes per vertex\n" + + "total vertex compression ratio " + + (vertexBytes / (float)compressedVertexBytes) + "\n\n" + + "lower bound " + stream.ncBounds[0].toString() +"\n" + + "upper bound " + stream.ncBounds[1].toString()) ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/HuffmanNode.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/HuffmanNode.java new file mode 100644 index 0000000..ccf3fae --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/HuffmanNode.java @@ -0,0 +1,225 @@ +/* + * $RCSfile: HuffmanNode.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:17 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import java.util.Collection; +import java.util.Comparator; + +/** + * Instances of this class are used as the nodes of binary trees representing + * mappings of tags to compression stream elements. Tags are descriptors + * inserted into the compression command stream that specify the encoding of + * immediately succeeding data elements.

+ * + * The tag assignments in such a tree are computed from the paths taken from + * the root to the leaf nodes. Each leaf node represents the particular way + * one or more compression stream elements wound up being encoded with respect + * to various combinations of data lengths, shifts, and absolute/relative + * status.

+ * + * Huffman's algorithm for constructing binary trees with minimal weighted + * path lengths can be used to optimize the bit lengths of the tags with + * respect to the frequency of occurrence of their associated data encodings + * in the compression stream. The weighted path length is the sum of the + * frequencies of all the leaf nodes times their path lengths to the root of + * the tree.

+ * + * The length of the longest tag determines the size of the table mapping tags + * to data representations. The geometry compression specification limits the + * size of the table to 64 entries, so tags cannot be longer than 6 bits. The + * depth of the tree is reduced through a process of increasing the data + * lengths of less frequently occuring nodes so they can be merged with other + * more frequent nodes. + */ +class HuffmanNode { + int tag, tagLength ; + int shift, dataLength ; + boolean absolute ; + + private int frequency ; + private HuffmanNode child0, child1, mergeNode ; + private boolean merged, unmergeable, cleared ; + + void clear() { + tag = -1 ; + tagLength = -1 ; + + shift = -1 ; + dataLength = -1 ; + absolute = false ; + + child0 = null ; + child1 = null ; + mergeNode = null ; + + frequency = 0 ; + merged = false ; + unmergeable = false ; + cleared = true ; + } + + HuffmanNode() { + clear() ; + } + + HuffmanNode(int length, int shift, boolean absolute) { + this() ; + set(length, shift, absolute) ; + } + + final void set(int length, int shift, boolean absolute) { + this.dataLength = length ; + this.shift = shift ; + this.absolute = absolute ; + this.cleared = false ; + } + + final boolean cleared() { + return cleared ; + } + + final void addCount() { + frequency++ ; + } + + final boolean hasCount() { + return frequency > 0 ; + } + + final boolean tokenEquals(HuffmanNode node) { + return + this.absolute == node.absolute && + this.dataLength == node.dataLength && + this.shift == node.shift ; + } + + void addChildren(HuffmanNode child0, HuffmanNode child1) { + this.child0 = child0 ; + this.child1 = child1 ; + this.frequency = child0.frequency + child1.frequency ; + } + + void collectLeaves(int tag, int tagLength, Collection collection) { + if (child0 == null) { + this.tag = tag ; + this.tagLength = tagLength ; + collection.add(this) ; + } else { + child0.collectLeaves((tag << 1) | 0, tagLength + 1, collection) ; + child1.collectLeaves((tag << 1) | 1, tagLength + 1, collection) ; + } + } + + boolean mergeInto(HuffmanNode node) { + if (this.absolute == node.absolute) { + if (this.dataLength > node.dataLength) + node.dataLength = this.dataLength ; + + if (this.shift < node.shift) + node.shift = this.shift ; + + node.frequency += this.frequency ; + this.mergeNode = node ; + this.merged = true ; + return true ; + + } else + return false ; + } + + int incrementLength() { + if (shift > 0) + shift-- ; + else + dataLength++ ; + + return dataLength - shift ; + } + + final boolean merged() { + return merged ; + } + + final HuffmanNode getMergeNode() { + return mergeNode ; + } + + void setUnmergeable() { + unmergeable = true ; + } + + final boolean unmergeable() { + return unmergeable ; + } + + public String toString() { + return + "shift " + shift + " data length " + dataLength + + (absolute? " absolute " : " relative ") + + "\ntag 0x" + Integer.toHexString(tag) + " tag length " + tagLength + + "\nfrequency: " + frequency ; + } + + /** + * Sorts nodes in ascending order by frequency. + */ + static class FrequencyComparator implements Comparator { + public final int compare(Object o1, Object o2) { + return ((HuffmanNode)o1).frequency - ((HuffmanNode)o2).frequency ; + } + } + + /** + * Sorts nodes in descending order by tag bit length. + */ + static class TagLengthComparator implements Comparator { + public final int compare(Object o1, Object o2) { + return ((HuffmanNode)o2).tagLength - ((HuffmanNode)o1).tagLength ; + } + } + + static FrequencyComparator frequencyComparator = new FrequencyComparator() ; + static TagLengthComparator tagLengthComparator = new TagLengthComparator() ; +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/HuffmanTable.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/HuffmanTable.java new file mode 100644 index 0000000..7820a68 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/HuffmanTable.java @@ -0,0 +1,483 @@ +/* + * $RCSfile: HuffmanTable.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:17 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.ListIterator; + +/** + * This class maintains a map from compression stream elements (tokens) onto + * HuffmanNode objects. A HuffmanNode contains a tag describing the + * associated token's data length, right shift value, and absolute/relative + * status.

+ * + * The tags are computed using Huffman's algorithm to build a binary tree with + * a minimal total weighted path length. The frequency of each token is + * used as its node's weight when building the tree. The path length from the + * root to the token's node then indicates the bit length that should be used + * for that token's tag in order to minimize the total size of the compressed + * stream. + */ +class HuffmanTable { + private static final int MAX_TAG_LENGTH = 6 ; + + private HuffmanNode positions[] ; + private HuffmanNode normals[] ; + private HuffmanNode colors[] ; + + /** + * Create a new HuffmanTable with entries for all possible position, + * normal, and color tokens. + */ + HuffmanTable() { + // + // Position and color components can have data lengths up to 16 + // bits, with right shifts up to 15 bits. The position and color + // lookup tables are therefore 2*17*16=544 entries in length to + // account for all possible combinations of data lengths, shifts, + // and relative or absolute status. + // + colors = new HuffmanNode[544] ; + positions = new HuffmanNode[544] ; + + // + // Delta normals can have uv components up to 7 bits in length with + // right shifts up to 6 bits. Absolute normals can have uv components + // up to 6 bits in length with right shifts up to 5 bits. The normal + // lookup table is therefore 2*8*7=112 entries in length. + // + normals = new HuffmanNode[112] ; + } + + private final int getPositionIndex(int len, int shift, boolean absolute) { + return (absolute? 1:0)*272 + len*16 + shift ; + } + + private final int getNormalIndex(int length, int shift, boolean absolute) { + return (absolute? 1:0)*56 + length*7 + shift ; + } + + private final int getColorIndex(int length, int shift, boolean absolute) { + return getPositionIndex(length, shift, absolute) ; + } + + + /** + * Add a position entry with the given length, shift, and absolute + * status. + * + * @param length number of bits in each X, Y, and Z component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous vertex in the compression stream + */ + void addPositionEntry(int length, int shift, boolean absolute) { + addEntry(positions, getPositionIndex(length, shift, absolute), + length, shift, absolute) ; + } + + /** + * Get the position entry associated with the specified length, shift, and + * absolute status. This will contain a tag indicating the actual + * encoding to be used in the compression command stream, not necessarily + * the same as the original length and shift with which the the entry was + * created. + * + * @param length number of bits in each X, Y, and Z component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous vertex in the compression stream + * @return HuffmanNode mapped to the specified parameters + */ + HuffmanNode getPositionEntry(int length, int shift, boolean absolute) { + return getEntry(positions, getPositionIndex(length, shift, absolute)) ; + } + + /** + * Add a color entry with the given length, shift, and absolute + * status. + * + * @param length number of bits in each R, G, B, and A component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous color in the compression stream + */ + void addColorEntry(int length, int shift, boolean absolute) { + addEntry(colors, getColorIndex(length, shift, absolute), + length, shift, absolute) ; + } + + /** + * Get the color entry associated with the specified length, shift, and + * absolute status. This will contain a tag indicating the actual + * encoding to be used in the compression command stream, not necessarily + * the same as the original length and shift with which the the entry was + * created. + * + * @param length number of bits in each R, G, B, and A component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous color in the compression stream + * @return HuffmanNode mapped to the specified parameters + */ + HuffmanNode getColorEntry(int length, int shift, boolean absolute) { + return getEntry(colors, getColorIndex(length, shift, absolute)) ; + } + + /** + * Add a normal entry with the given length, shift, and absolute + * status. + * + * @param length number of bits in each U and V component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous normal in the compression stream + */ + void addNormalEntry(int length, int shift, boolean absolute) { + addEntry(normals, getNormalIndex(length, shift, absolute), + length, shift, absolute) ; + } + + /** + * Get the normal entry associated with the specified length, shift, and + * absolute status. This will contain a tag indicating the actual + * encoding to be used in the compression command stream, not necessarily + * the same as the original length and shift with which the the entry was + * created. + * + * @param length number of bits in each U and V component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous normal in the compression stream + * @return HuffmanNode mapped to the specified parameters + */ + HuffmanNode getNormalEntry(int length, int shift, boolean absolute) { + return getEntry(normals, getNormalIndex(length, shift, absolute)) ; + } + + + private void addEntry(HuffmanNode table[], int index, + int length, int shift, boolean absolute) { + + if (table[index] == null) + table[index] = new HuffmanNode(length, shift, absolute) ; + + else if (table[index].cleared()) + table[index].set(length, shift, absolute) ; + + table[index].addCount() ; + } + + private HuffmanNode getEntry(HuffmanNode table[], int index) { + HuffmanNode t = table[index] ; + + while (t.merged()) + t = t.getMergeNode() ; + + return t ; + } + + private void getEntries(HuffmanNode table[], Collection c) { + for (int i = 0 ; i < table.length ; i++) + if (table[i] != null && !table[i].cleared() && + table[i].hasCount() && !table[i].merged()) + c.add(table[i]) ; + } + + + /** + * Clear this HuffmanTable instance. + */ + void clear() { + for (int i = 0 ; i < positions.length ; i++) + if (positions[i] != null) + positions[i].clear() ; + + for (int i = 0 ; i < colors.length ; i++) + if (colors[i] != null) + colors[i].clear() ; + + for (int i = 0 ; i < normals.length ; i++) + if (normals[i] != null) + normals[i].clear() ; + } + + /** + * Compute optimized tags for each position, color, and normal entry. + */ + void computeTags() { + LinkedList nodeList = new LinkedList() ; + getEntries(positions, nodeList) ; + computeTags(nodeList, 3) ; + + nodeList.clear() ; + getEntries(colors, nodeList) ; + computeTags(nodeList, 3) ; + + nodeList.clear() ; + getEntries(normals, nodeList) ; + computeTags(nodeList, 2) ; + } + + // + // Compute tags for a list of Huffman tokens. + // + private void computeTags(LinkedList nodes, int minComponentCount) { + HuffmanNode node0, node1, node2 ; + + // Return if there's nothing to do. + if (nodes.isEmpty()) + return ; + + while (true) { + // Sort the nodes in ascending order by frequency. + Collections.sort(nodes, HuffmanNode.frequencyComparator) ; + + // Apply Huffman's algorithm to construct a binary tree with a + // minimum total weighted path length. + node0 = (HuffmanNode)nodes.removeFirst() ; + while (nodes.size() > 0) { + node1 = (HuffmanNode)nodes.removeFirst() ; + node2 = new HuffmanNode() ; + + node2.addChildren(node0, node1) ; + addNodeInOrder(nodes, node2, HuffmanNode.frequencyComparator) ; + + node0 = (HuffmanNode)nodes.removeFirst() ; + } + + // node0 is the root of the resulting binary tree. Traverse it + // assigning tags and lengths to the leaf nodes. The leaves are + // collected into the now empty node list. + node0.collectLeaves(0, 0, nodes) ; + + // Sort the nodes in descending order by tag length. + Collections.sort(nodes, HuffmanNode.tagLengthComparator) ; + + // Check for tag length overrun. + if (((HuffmanNode)nodes.getFirst()).tagLength > MAX_TAG_LENGTH) { + // Tokens need to be merged and the tree rebuilt with the new + // combined frequencies. + merge(nodes) ; + + } else { + // Increase tag length + data length if they're too small. + expand(nodes, minComponentCount) ; + break ; + } + } + } + + // + // Merge a token with a long tag into some other token. The merged token + // will be removed from the list along with any duplicate node the merge + // created, reducing the size of the list by 1 or 2 elements until only + // unmergeable tokens are left. + // + private void merge(LinkedList nodes) { + ListIterator i = nodes.listIterator(0) ; + HuffmanNode node0, node1, node2 ; + int index = 0 ; + + while (i.hasNext()) { + // Get the node with the longest possibly mergeable tag. + node0 = (HuffmanNode)i.next() ; + if (node0.unmergeable()) continue ; + + // Try to find a node that can be merged with node0. This is any + // node that matches its absolute/relative status. + i.remove() ; + while (i.hasNext()) { + node1 = (HuffmanNode)i.next() ; + if (node0.mergeInto(node1)) { + // Search for a duplicate of the possibly modified node1 + // and merge into it so that node weights remain valid. + // If a duplicate exists it must be further in the list, + // otherwise node0 would have merged into it. + i.remove() ; + while (i.hasNext()) { + node2 = (HuffmanNode)i.next() ; + if (node1.tokenEquals(node2)) { + node1.mergeInto(node2) ; + return ; + } + } + // node1 has no duplicate, so return it to the list. + i.add(node1) ; + return ; + } + } + + // node0 can't be merged with any other node; it must be the only + // relative or absolute node in the list. Mark it as unmergeable + // to avoid unnecessary searches on subsequent calls to merge() + // and return it to the list. + node0.setUnmergeable() ; + i.add(node0) ; + + // Restart the iteration. + i = nodes.listIterator(0) ; + } + } + + // + // Empty bits within a compression command header are not allowed. If + // the tag length plus the total data length is less than 6 bits then + // the token's length must be increased. + // + private void expand(LinkedList nodes, int minComponentCount) { + Iterator i = nodes.iterator() ; + + while (i.hasNext()) { + HuffmanNode n = (HuffmanNode)i.next() ; + + while (n.tagLength + + (minComponentCount * (n.dataLength - n.shift)) < 6) { + + n.incrementLength() ; + } + } + } + + // + // Insert a node into the correct place in a sorted list of nodes. + // + private void addNodeInOrder(LinkedList l, HuffmanNode node, Comparator c) { + ListIterator i = l.listIterator(0) ; + + while (i.hasNext()) { + HuffmanNode n = (HuffmanNode)i.next() ; + if (c.compare(n, node) > 0) { + n = (HuffmanNode)i.previous() ; + break ; + } + } + i.add(node) ; + } + + /** + * Create compression stream commands for decompressors to use to set up + * their decompression tables. + * + * @param output CommandStream which receives the compression commands + */ + void outputCommands(CommandStream output) { + LinkedList nodeList = new LinkedList() ; + getEntries(positions, nodeList) ; + outputCommands(nodeList, output, CommandStream.POSITION_TABLE) ; + + nodeList.clear() ; + getEntries(colors, nodeList) ; + outputCommands(nodeList, output, CommandStream.COLOR_TABLE) ; + + nodeList.clear() ; + getEntries(normals, nodeList) ; + outputCommands(nodeList, output, CommandStream.NORMAL_TABLE) ; + } + + // + // Output a setTable command for each unique token. + // + private void outputCommands(Collection nodes, + CommandStream output, int tableId) { + + Iterator i = nodes.iterator() ; + while (i.hasNext()) { + HuffmanNode n = (HuffmanNode)i.next() ; + int addressRange = (1 << n.tagLength) | n.tag ; + int dataLength = (n.dataLength == 16? 0 : n.dataLength) ; + + int command = + CommandStream.SET_TABLE | (tableId << 1) | (addressRange >> 6) ; + + long body = + ((addressRange & 0x3f) << 9) | (dataLength << 5) | + (n.absolute? 0x10 : 0) | n.shift ; + + output.addCommand(command, 8, body, 15) ; + } + } + + /** + * Print a collection of HuffmanNode objects to standard out. + * + * @param header descriptive string + * @param nodes Collection of HuffmanNode objects to print + */ + void print(String header, Collection nodes) { + System.out.println(header + "\nentries: " + nodes.size() + "\n") ; + + Iterator i = nodes.iterator() ; + while(i.hasNext()) { + HuffmanNode n = (HuffmanNode)i.next() ; + System.out.println(n.toString() + "\n") ; + } + } + + /** + * Print the contents of this instance to standard out. + */ + void print() { + LinkedList nodeList = new LinkedList() ; + + getEntries(positions, nodeList) ; + Collections.sort(nodeList, HuffmanNode.frequencyComparator) ; + print("\nposition tokens and tags", nodeList) ; + + nodeList.clear() ; + getEntries(colors, nodeList) ; + Collections.sort(nodeList, HuffmanNode.frequencyComparator) ; + print("\ncolor tokens and tags", nodeList) ; + + nodeList.clear() ; + getEntries(normals, nodeList) ; + Collections.sort(nodeList, HuffmanNode.frequencyComparator) ; + print("\nnormal tokens and tags", nodeList) ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/MeshBuffer.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/MeshBuffer.java new file mode 100644 index 0000000..484cfcd --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/MeshBuffer.java @@ -0,0 +1,242 @@ +/* + * $RCSfile: MeshBuffer.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:17 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.compression; + +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +/** + * This class mirrors the vertex mesh buffer stack supported by the geometry + * compression semantics. + */ +class MeshBuffer { + // + // The fixed-length mesh buffer stack is represented by circular buffers. + // Three stack representations are provided: vertices, positions, and + // indices. + // + // The vertex representation stores references to CompressionStreamVertex + // objects. The position representation stores references to Point3f, + // Vector3f, Color3f, and Color4f objects, while the index representation + // stores indices into externally maintained arrays of those objects. All + // these representations may be used independently and all provide access + // to the stored references via a mesh buffer index. + // + // In addition, the position and index representations provide lookup + // mechanisms to check if positions or indices exist in the mesh buffer + // and return their mesh buffer indices if they do. This is used to + // implement a limited meshing algorithm which reduces the number of + // vertices when non-stripped abutting facets are added to a compression + // stream. + // + static final int NOT_FOUND = -1 ; + + private static final int SIZE = 16 ; + private static final int NAN_HASH = + new Point3f(Float.NaN, Float.NaN, Float.NaN).hashCode() ; + + private int topIndex = SIZE - 1 ; + private int positionIndices[] = new int[SIZE] ; + private int normalIndices[] = new int[SIZE] ; + private int colorIndices[] = new int[SIZE] ; + + private int topPosition = SIZE - 1 ; + private int positionHashCodes[] = new int[SIZE] ; + private Point3f positions[] = new Point3f[SIZE] ; + private Vector3f normals[] = new Vector3f[SIZE] ; + private Color3f colors3[] = new Color3f[SIZE] ; + private Color4f colors4[] = new Color4f[SIZE] ; + + private int topVertex = SIZE - 1 ; + private CompressionStreamVertex vertices[] = + new CompressionStreamVertex[SIZE] ; + + MeshBuffer() { + for (int i = 0 ; i < SIZE ; i++) { + positionHashCodes[i] = NAN_HASH ; + + positionIndices[i] = NOT_FOUND ; + normalIndices[i] = NOT_FOUND ; + colorIndices[i] = NOT_FOUND ; + } + } + + private static int nextTop(int top) { + // The stack top references an element in the fixed-length backing + // array in which the stack is stored. Stack elements below it have + // decreasing indices into the backing array until element 0, at which + // point the indices wrap to the end of the backing array and back to + // the top. + // + // A push is accomplished by incrementing the stack top in a circular + // buffer and storing the data into the new stack element it + // references. The bottom of the stack is the element with the next + // higher index from the top in the backing array, and is overwritten + // with each new push. + return (top + 1) % SIZE ; + } + + private static int flipOffset(int top, int offset) { + // Flips an offset relative to the beginning of the backing array to + // an offset from the top of the stack. Also works in reverse, from + // an offset from the top of the stack to an offset from the beginning + // of the backing array. + if (offset > top) offset -= SIZE ; + return top - offset ; + } + + // + // Mesh buffer vertex stack. This is currently only used for vertex + // lookup during the quantization pass in order to compute delta values; + // no mesh reference lookup is necessary. + // + void push(CompressionStreamVertex v) { + topVertex = nextTop(topVertex) ; + vertices[topVertex] = v ; + } + + CompressionStreamVertex getVertex(int meshReference) { + return vertices[flipOffset(topVertex, meshReference)] ; + } + + + // + // Mesh buffer index stack and index reference lookup support. + // + void push(int positionIndex, int normalIndex) { + topIndex = nextTop(topIndex) ; + + positionIndices[topIndex] = positionIndex ; + normalIndices[topIndex] = normalIndex ; + } + + void push(int positionIndex, int colorIndex, int normalIndex) { + push(positionIndex, normalIndex) ; + colorIndices[topIndex] = colorIndex ; + } + + int getMeshReference(int positionIndex) { + int index ; + for (index = 0 ; index < SIZE ; index++) + if (positionIndices[index] == positionIndex) + break ; + + if (index == SIZE) return NOT_FOUND ; + return flipOffset(topIndex, index) ; + } + + int getPositionIndex(int meshReference) { + return positionIndices[flipOffset(topIndex, meshReference)] ; + } + + int getColorIndex(int meshReference) { + return colorIndices[flipOffset(topIndex, meshReference)] ; + } + + int getNormalIndex(int meshReference) { + return normalIndices[flipOffset(topIndex, meshReference)] ; + } + + + // + // Mesh buffer position stack and position reference lookup support. + // + void push(Point3f position, Vector3f normal) { + topPosition = nextTop(topPosition) ; + + positionHashCodes[topPosition] = position.hashCode() ; + positions[topPosition] = position ; + normals[topPosition] = normal ; + } + + void push(Point3f position, Color3f color, Vector3f normal) { + push(position, normal) ; + colors3[topPosition] = color ; + } + + void push(Point3f position, Color4f color, Vector3f normal) { + push(position, normal) ; + colors4[topPosition] = color ; + } + + void push(Point3f position, Object color, Vector3f normal) { + push(position, normal) ; + if (color instanceof Color3f) + colors3[topPosition] = (Color3f)color ; + else + colors4[topPosition] = (Color4f)color ; + } + + int getMeshReference(Point3f position) { + int index ; + int hashCode = position.hashCode() ; + + for (index = 0 ; index < SIZE ; index++) + if (positionHashCodes[index] == hashCode) + if (positions[index].equals(position)) + break ; + + if (index == SIZE) return NOT_FOUND ; + return flipOffset(topPosition, index) ; + } + + Point3f getPosition(int meshReference) { + return positions[flipOffset(topPosition, meshReference)] ; + } + + Color3f getColor3(int meshReference) { + return colors3[flipOffset(topPosition, meshReference)] ; + } + + Color4f getColor4(int meshReference) { + return colors4[flipOffset(topPosition, meshReference)] ; + } + + Vector3f getNormal(int meshReference) { + return normals[flipOffset(topPosition, meshReference)] ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/package.html new file mode 100644 index 0000000..628453b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/compression/package.html @@ -0,0 +1,13 @@ + + + + + com.sun.j3d.utils.compression + + +

Deprecated: Use com.sun.j3d.utils.geometry.compression +instead.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/BBox.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/BBox.java new file mode 100644 index 0000000..e1c1ece --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/BBox.java @@ -0,0 +1,128 @@ +/* + * $RCSfile: BBox.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:17 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +/** + * Bounding Box class for Triangulator. + */ +class BBox { + int imin; /* lexicographically smallest point, determines min-x */ + int imax; /* lexicographically largest point, determines max-x */ + double ymin; /* minimum y-coordinate */ + double ymax; /* maximum y-coordinate */ + + /** + * This constructor computes the bounding box of a line segment whose end + * points i, j are sorted according to x-coordinates. + */ + BBox(Triangulator triRef, int i, int j) { + // assert(InPointsList(i)); + // assert(InPointsList(j)); + + imin = Math.min(i, j); + imax = Math.max(i, j); + ymin = Math.min(triRef.points[imin].y, triRef.points[imax].y); + ymax = Math.max(triRef.points[imin].y, triRef.points[imax].y); + } + + + boolean pntInBBox(Triangulator triRef, int i) { + return (((imax < i) ? false : + ((imin > i) ? false : + ((ymax < triRef.points[i].y) ? false : + ((ymin > triRef.points[i].y) ? false : true))))); + } + + + + boolean BBoxOverlap(BBox bb) { + return (((imax < (bb).imin) ? false : + ((imin > (bb).imax) ? false : + ((ymax < (bb).ymin) ? false : + ((ymin > (bb).ymax) ? false : true))))); + } + + boolean BBoxContained(BBox bb) { + return ((imin <= (bb).imin) && (imax >= (bb).imax) && + (ymin <= (bb).ymin) && (ymax >= (bb).ymax)); + } + + + boolean BBoxIdenticalLeaf(BBox bb) { + return ((imin == (bb).imin) && (imax == (bb).imax)); + } + + + void BBoxUnion(BBox bb1, BBox bb3) { + (bb3).imin = Math.min(imin, (bb1).imin); + (bb3).imax = Math.max(imax, (bb1).imax); + (bb3).ymin = Math.min(ymin, (bb1).ymin); + (bb3).ymax = Math.max(ymax, (bb1).ymax); + } + + + double BBoxArea(Triangulator triRef) { + return (triRef.points[imax].x - triRef.points[imin].x) * (ymax - ymin); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Basic.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Basic.java new file mode 100644 index 0000000..24fa0a6 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Basic.java @@ -0,0 +1,168 @@ +/* + * $RCSfile: Basic.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:17 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class Basic { + + static final double D_RND_MAX = 2147483647.0; + + + static double detExp(double u_x, double u_y, double u_z, + double v_x, double v_y, double v_z, + double w_x, double w_y, double w_z) { + + return ((u_x) * ((v_y) * (w_z) - (v_z) * (w_y)) - + (u_y) * ((v_x) * (w_z) - (v_z) * (w_x)) + + (u_z) * ((v_x) * (w_y) - (v_y) * (w_x))); + } + + + static double det3D(Tuple3f u, Tuple3f v, Tuple3f w) { + return ((u).x * ((v).y * (w).z - (v).z * (w).y) - + (u).y * ((v).x * (w).z - (v).z * (w).x) + + (u).z * ((v).x * (w).y - (v).y * (w).x)); + } + + + static double det2D(Tuple2f u, Tuple2f v, Tuple2f w) { + return (((u).x - (v).x) * ((v).y - (w).y) + ((v).y - (u).y) * ((v).x - (w).x)); + } + + + static double length2(Tuple3f u) { + return (((u).x * (u).x) + ((u).y * (u).y) + ((u).z * (u).z)); + } + + static double lengthL1(Tuple3f u) { + return (Math.abs((u).x) + Math.abs((u).y) + Math.abs((u).z)); + } + + static double lengthL2(Tuple3f u) { + return Math.sqrt(((u).x * (u).x) + ((u).y * (u).y) + ((u).z * (u).z)); + } + + + static double dotProduct(Tuple3f u, Tuple3f v) { + return (((u).x * (v).x) + ((u).y * (v).y) + ((u).z * (v).z)); + } + + + static double dotProduct2D(Tuple2f u, Tuple2f v) { + return (((u).x * (v).x) + ((u).y * (v).y)); + } + + + static void vectorProduct(Tuple3f p, Tuple3f q, Tuple3f r) { + (r).x = (p).y * (q).z - (q).y * (p).z; + (r).y = (q).x * (p).z - (p).x * (q).z; + (r).z = (p).x * (q).y - (q).x * (p).y; + } + + + static void vectorAdd( Tuple3f p, Tuple3f q, Tuple3f r) { + (r).x = (p).x + (q).x; + (r).y = (p).y + (q).y; + (r).z = (p).z + (q).z; + } + + static void vectorSub( Tuple3f p, Tuple3f q, Tuple3f r) { + (r).x = (p).x - (q).x; + (r).y = (p).y - (q).y; + (r).z = (p).z - (q).z; + } + + + static void vectorAdd2D( Tuple2f p, Tuple2f q, Tuple2f r) { + (r).x = (p).x + (q).x; + (r).y = (p).y + (q).y; + } + + + static void vectorSub2D( Tuple2f p, Tuple2f q, Tuple2f r) { + (r).x = (p).x - (q).x; + (r).y = (p).y - (q).y; + } + + static void invertVector(Tuple3f p) { + (p).x = -(p).x; + (p).y = -(p).y; + (p).z = -(p).z; + } + + static void divScalar(double scalar, Tuple3f u) { + (u).x /= scalar; + (u).y /= scalar; + (u).z /= scalar; + } + + static void multScalar2D(double scalar, Tuple2f u) { + (u).x *= scalar; + (u).y *= scalar; + } + + + static int signEps(double x, double eps) { + return ((x <= eps) ? ((x < -eps) ? -1 : 0) : 1); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/BottleNeck.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/BottleNeck.java new file mode 100644 index 0000000..c742746 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/BottleNeck.java @@ -0,0 +1,167 @@ +/* + * $RCSfile: BottleNeck.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:17 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class BottleNeck { + + static boolean checkArea(Triangulator triRef, int ind4, int ind5) { + int ind1, ind2; + int i0, i1, i2; + double area = 0.0, area1 = 0, area2 = 0.0; + + i0 = triRef.fetchData(ind4); + ind1 = triRef.fetchNextData(ind4); + i1 = triRef.fetchData(ind1); + + while (ind1 != ind5) { + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + area =Numerics.stableDet2D(triRef, i0, i1, i2); + area1 += area; + ind1 = ind2; + i1 = i2; + } + + if (Numerics.le(area1, triRef.ZERO)) return false; + + ind1 = triRef.fetchNextData(ind5); + i1 = triRef.fetchData(ind1); + while (ind1 != ind4) { + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + area = Numerics.stableDet2D(triRef, i0, i1, i2); + area2 += area; + ind1 = ind2; + i1 = i2; + } + + if (Numerics.le(area2, triRef.ZERO)) return false; + else return true; + } + + + // Yet another check needed in order to handle degenerate cases! + static boolean checkBottleNeck(Triangulator triRef, + int i1, int i2, int i3, int ind4) { + int ind5; + int i4, i5; + boolean flag; + + i4 = i1; + + ind5 = triRef.fetchPrevData(ind4); + i5 = triRef.fetchData(ind5); + if ((i5 != i2) && (i5 != i3)) { + flag = Numerics.pntInTriangle(triRef, i1, i2, i3, i5); + if (flag) return true; + } + + if (i2 <= i3) { + if (i4 <= i5) flag = Numerics.segIntersect(triRef, i2, i3, i4, i5, -1); + else flag = Numerics.segIntersect(triRef, i2, i3, i5, i4, -1); + } + else { + if (i4 <= i5) flag = Numerics.segIntersect(triRef, i3, i2, i4, i5, -1); + else flag = Numerics.segIntersect(triRef, i3, i2, i5, i4, -1); + } + if (flag) return true; + + ind5 = triRef.fetchNextData(ind4); + i5 = triRef.fetchData(ind5); + + if ((i5 != i2) && (i5 != i3)) { + flag = Numerics.pntInTriangle(triRef, i1, i2, i3, i5); + if (flag) return true; + } + + if (i2 <= i3) { + if (i4 <= i5) flag = Numerics.segIntersect(triRef, i2, i3, i4, i5, -1); + else flag = Numerics.segIntersect(triRef, i2, i3, i5, i4, -1); + } + else { + if (i4 <= i5) flag = Numerics.segIntersect(triRef, i3, i2, i4, i5, -1); + else flag = Numerics.segIntersect(triRef, i3, i2, i5, i4, -1); + } + + if (flag) return true; + + ind5 = triRef.fetchNextData(ind4); + i5 = triRef.fetchData(ind5); + while (ind5 != ind4) { + if (i4 == i5) { + if (checkArea(triRef, ind4, ind5)) return true; + } + ind5 = triRef.fetchNextData(ind5); + i5 = triRef.fetchData(ind5); + } + + return false; + } +} + + + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Box.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Box.java new file mode 100644 index 0000000..ec93808 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Box.java @@ -0,0 +1,482 @@ +/* + * $RCSfile: Box.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/04/24 18:50:59 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * Box is a geometry primitive created with a given length, width, and height. + * It is centered at the origin. By default, it lies within the bounding + * box, [-1,-1,-1] and [1,1,1]. + * + * When a texture is applied to a box, it is map CCW like on a Cylinder. + * A texture is mapped CCW from the back of the + * body. The top and bottom faces are mapped such that the texture appears + * front facing when the faces are rotated 90 toward the viewer. + *

+ * By default all primitives with the same parameters share their + * geometry (e.g., you can have 50 shperes in your scene, but the + * geometry is stored only once). A change to one primitive will + * effect all shared nodes. Another implication of this + * implementation is that the capabilities of the geometry are shared, + * and once one of the shared nodes is live, the capabilities cannot + * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to + * share geometry among primitives with the same parameters. + */ + +public class Box extends Primitive { + + /** + * Used to designate the front side of the box when using + * getShape(). + * + * @see Box#getShape + */ + public static final int FRONT = 0; + + /** + * Used to designate the back side of the box when using + * getShape(). + * + * @see Box#getShape + */ + public static final int BACK = 1; + + /** + * Used to designate the right side of the box when using + * getShape(). + * + * @see Box#getShape + */ + public static final int RIGHT = 2; + + /** + * Used to designate the left side of the box when using + * getShape(). + * + * @see Box#getShape + */ + public static final int LEFT = 3; + + /** + * Used to designate the top side of the box when using + * getShape(). + * + * @see Box#getShape + */ + public static final int TOP = 4; + + /** + * Used to designate the bottom side of the box when using + * getShape(). + * + * @see Box#getShape + */ + public static final int BOTTOM = 5; + + float xDim, yDim, zDim; + + int numTexUnit = 1; + + /** + * Constructs a default box of 1.0 in all dimensions. + * Normals are generated by default, texture coordinates are not. + */ + + public Box() + { + this(1.0f, 1.0f, 1.0f, GENERATE_NORMALS, null); + } + + /** + * Constructs a box of a given dimension and appearance. + * Normals are generated by default, texture coordinates are not. + * + * @param xdim X-dimension size. + * @param ydim Y-dimension size. + * @param zdim Z-dimension size. + * @param ap Appearance + */ + + public Box(float xdim, float ydim, float zdim, Appearance ap) + { + this(xdim, ydim, zdim, GENERATE_NORMALS, ap); + } + + /** + * Constructs a box of a given dimension, flags, and appearance. + * + * @param xdim X-dimension size. + * @param ydim Y-dimension size. + * @param zdim Z-dimension size. + * @param primflags primitive flags. + * @param ap Appearance + */ + + public Box(float xdim, float ydim, float zdim, int primflags, + Appearance ap, int numTexUnit) { + int i; + double sign; + + xDim = xdim; + yDim = ydim; + zDim = zdim; + flags = primflags; + numTexUnit = numTexUnit; + boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0; + + //Depending on whether normal inward bit is set. + if ((flags & GENERATE_NORMALS_INWARD) != 0) + sign = -1.0; + else sign = 1.0; + + +// TransformGroup objTrans = new TransformGroup(); +// objTrans.setCapability(ALLOW_CHILDREN_READ); +// this.addChild(objTrans); + + Shape3D shape[] = new Shape3D[6]; + + GeomBuffer cache = null; + + for (i = FRONT; i <= BOTTOM; i++){ + + cache = getCachedGeometry(Primitive.BOX, xdim, ydim, zdim, i, i, + primflags); + if (cache != null) { +// System.out.println("using cached geometry i = " + i); + shape[i] = new Shape3D(cache.getComputedGeometry()); + numVerts += cache.getNumVerts(); + numTris += cache.getNumTris(); + } + else { + + GeomBuffer gbuf = new GeomBuffer(4, numTexUnit); + + gbuf.begin(GeomBuffer.QUAD_STRIP); + for (int j = 0; j < 2; j++){ + gbuf.normal3d( (double) normals[i].x*sign, + (double) normals[i].y*sign, + (double) normals[i].z*sign); + if (texCoordYUp) { + gbuf.texCoord2d(tcoords[i*8 + j*2], 1.0 - tcoords[i*8 + j*2 + 1]); + } + else { + gbuf.texCoord2d(tcoords[i*8 + j*2], tcoords[i*8 + j*2 + 1]); + } + + gbuf.vertex3d( (double) verts[i*12 + j*3]*xdim, + (double) verts[i*12+ j*3 + 1]*ydim, + (double) verts[i*12+ j*3 + 2]*zdim ); + } + for (int j = 3; j > 1; j--){ + gbuf.normal3d( (double) normals[i].x*sign, + (double) normals[i].y*sign, + (double) normals[i].z*sign); + if (texCoordYUp) { + gbuf.texCoord2d(tcoords[i*8 + j*2], 1.0 - tcoords[i*8 + j*2 + 1]); + } + else { + gbuf.texCoord2d(tcoords[i*8 + j*2], tcoords[i*8 + j*2 + 1]); + } + gbuf.vertex3d( (double) verts[i*12 + j*3]*xdim, + (double) verts[i*12+ j*3 + 1]*ydim, + (double) verts[i*12+ j*3 + 2]*zdim ); + } + gbuf.end(); + shape[i] = new Shape3D(gbuf.getGeom(flags)); + numVerts = gbuf.getNumVerts(); + numTris = gbuf.getNumTris(); + + if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { + cacheGeometry(Primitive.BOX, xdim, ydim, zdim, i, i, + primflags, gbuf); + } + } + + if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) { + (shape[i]).setCapability(Shape3D.ALLOW_APPEARANCE_READ); + (shape[i]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + } + + if ((flags & ENABLE_GEOMETRY_PICKING) != 0) { + (shape[i]).setCapability(Shape3D.ALLOW_GEOMETRY_READ); + } + +// objTrans.addChild(shape[i]); + this.addChild(shape[i]); + } + + if (ap == null){ + setAppearance(); + } + else setAppearance(ap); + } + + public Box(float xdim, float ydim, float zdim, int primflags, + Appearance ap) { + this(xdim, ydim, zdim, primflags, ap, 1); + } + + /** + * Gets one of the faces (Shape3D) from the box that contains the + * geometry and appearance. This allows users to modify the + * appearance or geometry of individual parts. + * @param partId The part to return. + * @return The Shape3D object associated with the partID. If an + * invalid partId is passed in, null is returned. + */ + + public Shape3D getShape(int partId) { + if ((partId >= FRONT) && (partId <= BOTTOM)) +// return (Shape3D)(((Group)getChild(0)).getChild(partId)); + return (Shape3D)getChild(partId); + return null; + } + + /** + * Sets appearance of the box. This will set each face of the + * box to the same appearance. To set each face's appearance + * separately, use getShape(partId) to get the + * individual shape and call shape.setAppearance(ap). + */ + + public void setAppearance(Appearance ap){ +// ((Shape3D)((Group)getChild(0)).getChild(TOP)).setAppearance(ap); +// ((Shape3D)((Group)getChild(0)).getChild(LEFT)).setAppearance(ap); +// ((Shape3D)((Group)getChild(0)).getChild(RIGHT)).setAppearance(ap); +// ((Shape3D)((Group)getChild(0)).getChild(FRONT)).setAppearance(ap); +// ((Shape3D)((Group)getChild(0)).getChild(BACK)).setAppearance(ap); +// ((Shape3D)((Group)getChild(0)).getChild(BOTTOM)).setAppearance(ap); + ((Shape3D)getChild(TOP)).setAppearance(ap); + ((Shape3D)getChild(LEFT)).setAppearance(ap); + ((Shape3D)getChild(RIGHT)).setAppearance(ap); + ((Shape3D)getChild(FRONT)).setAppearance(ap); + ((Shape3D)getChild(BACK)).setAppearance(ap); + ((Shape3D)getChild(BOTTOM)).setAppearance(ap); + } + + /** + * Gets the appearance of the specified part of the box. + * + * @param partId identifier for a given subpart of the box + * + * @return The appearance object associated with the partID. If an + * invalid partId is passed in, null is returned. + * + * @since Java 3D 1.2.1 + */ + public Appearance getAppearance(int partId) { + if (partId > BOTTOM || partId < FRONT) return null; + return getShape(partId).getAppearance(); + } + + + private static final float[] verts = { + // front face + 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, +-1.0f, 1.0f, 1.0f, +-1.0f, -1.0f, 1.0f, + // back face +-1.0f, -1.0f, -1.0f, +-1.0f, 1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + // right face + 1.0f, -1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + // left face +-1.0f, -1.0f, 1.0f, +-1.0f, 1.0f, 1.0f, +-1.0f, 1.0f, -1.0f, +-1.0f, -1.0f, -1.0f, + // top face + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, +-1.0f, 1.0f, -1.0f, +-1.0f, 1.0f, 1.0f, + // bottom face +-1.0f, -1.0f, 1.0f, +-1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, 1.0f, + }; + + private static final double[] tcoords = { + // front + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0, + // back + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0, + //right + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0, + // left + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0, + // top + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0, + // bottom + 0.0, 1.0, + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0 + }; + + + private static final Vector3f[] normals = { + new Vector3f( 0.0f, 0.0f, 1.0f), // front face + new Vector3f( 0.0f, 0.0f, -1.0f), // back face + new Vector3f( 1.0f, 0.0f, 0.0f), // right face + new Vector3f(-1.0f, 0.0f, 0.0f), // left face + new Vector3f( 0.0f, 1.0f, 0.0f), // top face + new Vector3f( 0.0f, -1.0f, 0.0f), // bottom face + }; + + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * cloneNode should be overridden by any user subclassed + * objects. All subclasses must have their cloneNode + * method consist of the following lines: + *

+     *     public Node cloneNode(boolean forceDuplicate) {
+     *         UserSubClass usc = new UserSubClass();
+     *         usc.duplicateNode(this, forceDuplicate);
+     *         return usc;
+     *     }
+     * 
+ * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Box b = new Box(xDim, yDim, zDim, flags, getAppearance()); + b.duplicateNode(this, forceDuplicate); + return b; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + super.duplicateNode(originalNode, forceDuplicate); + } + + /** + * Returns the X-dimension size of the Box + * + * @since Java 3D 1.2.1 + */ + public float getXdimension() { + return xDim; + } + + /** + * Returns the Y-dimension size of the Box + * + * @since Java 3D 1.2.1 + */ + public float getYdimension() { + return yDim; + } + + /** + * Returns the Z-dimension size of the Box + * + * @since Java 3D 1.2.1 + */ + public float getZdimension() { + return zDim; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Bridge.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Bridge.java new file mode 100644 index 0000000..2d1aea1 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Bridge.java @@ -0,0 +1,398 @@ +/* + * $RCSfile: Bridge.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:17 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class Bridge { + + static void constructBridges(Triangulator triRef, int loopMin, int loopMax) { + int i, j, numDist, numLeftMost; + + int[] i0 = new int[1]; + int[] ind0 = new int[1]; + int[] i1 = new int[1]; + int[] ind1 = new int[1]; + + int[] iTmp = new int[1]; + int[] indTmp = new int[1]; + + if(triRef.noHashingEdges != true) + System.out.println("Bridge:constructBridges noHashingEdges is false"); + if(loopMax <= loopMin) + System.out.println("Bridge:constructBridges loopMax<=loopMin"); + if(loopMin < 0) + System.out.println("Bridge:constructBridges loopMin<0"); + if(loopMax > triRef.numLoops) + System.out.println("Bridge:constructBridges loopMax>triRef.numLoops"); + + numLeftMost = loopMax - loopMin - 1; + + if (numLeftMost > triRef.maxNumLeftMost) { + triRef.maxNumLeftMost = numLeftMost; + triRef.leftMost = new Left[numLeftMost]; + } + + // For each contour, find the left-most vertex. (we will use the fact + // that the vertices appear in sorted order!) + findLeftMostVertex(triRef, triRef.loops[loopMin], ind0, i0); + j = 0; + for (i = loopMin + 1; i < loopMax; ++i) { + findLeftMostVertex(triRef, triRef.loops[i], indTmp, iTmp); + triRef.leftMost[j] = new Left(); + triRef.leftMost[j].ind = indTmp[0]; + triRef.leftMost[j].index = iTmp[0]; + + ++j; + } + + // sort the inner contours according to their left-most vertex + sortLeft(triRef.leftMost, numLeftMost); + + // construct bridges. every bridge will eminate at the left-most point of + // its corresponding inner loop. + numDist = triRef.numPoints + 2 * triRef.numLoops; + triRef.maxNumDist = numDist; + triRef.distances = new Distance[numDist]; + for (int k = 0; k < triRef.maxNumDist; k++) + triRef.distances[k] = new Distance(); + + + for (j = 0; j < numLeftMost; ++j) { + if (!findBridge(triRef, ind0[0], i0[0], triRef.leftMost[j].index, ind1, i1)) { + // if (verbose) + // fprintf(stderr, "\n\n***** yikes! the loops intersect! *****\n"); + } + if (i1[0] == triRef.leftMost[j].index) + // the left-most node of the hole coincides with a node of the + // boundary + simpleBridge(triRef, ind1[0], triRef.leftMost[j].ind); + else + // two bridge edges need to be inserted + insertBridge(triRef, ind1[0], i1[0], triRef.leftMost[j].ind, + triRef.leftMost[j].index); + } + + } + + + /** + * We try to find a vertex i1 on the loop which contains i such that i1 + * is close to start, and such that i1, start is a valid diagonal. + */ + static boolean findBridge(Triangulator triRef, int ind, int i, int start, + int[] ind1, int[] i1) { + int i0, i2, j, numDist = 0; + int ind0, ind2; + BBox bb; + Distance old[] = null; + boolean convex, coneOk; + + // sort the points according to their distance from start. + ind1[0] = ind; + i1[0] = i; + if (i1[0] == start) return true; + if (numDist >= triRef.maxNumDist) { + // System.out.println("(1) Expanding distances array ..."); + triRef.maxNumDist += triRef.INC_DIST_BK; + old = triRef.distances; + triRef.distances = new Distance[triRef.maxNumDist]; + System.arraycopy(old, 0, triRef.distances, 0, old.length); + for (int k = old.length; k < triRef.maxNumDist; k++) + triRef.distances[k] = new Distance(); + } + + triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[start], + triRef.points[i1[0]]); + triRef.distances[numDist].ind = ind1[0]; + ++numDist; + + + ind1[0] = triRef.fetchNextData(ind1[0]); + i1[0] = triRef.fetchData(ind1[0]); + while (ind1[0] != ind) { + if (i1[0] == start) return true; + if (numDist >= triRef.maxNumDist) { + // System.out.println("(2) Expanding distances array ..."); + triRef.maxNumDist += triRef.INC_DIST_BK; + old = triRef.distances; + triRef.distances = new Distance[triRef.maxNumDist]; + System.arraycopy(old, 0, triRef.distances, 0, old.length); + for (int k = old.length; k < triRef.maxNumDist; k++) + triRef.distances[k] = new Distance(); + } + + triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[start], + triRef.points[i1[0]]); + triRef.distances[numDist].ind = ind1[0]; + ++numDist; + ind1[0] = triRef.fetchNextData(ind1[0]); + i1[0] = triRef.fetchData(ind1[0]); + } + + // qsort(distances, num_dist, sizeof(distance), &d_comp); + sortDistance(triRef.distances, numDist); + + // find a valid diagonal. note that no node with index i1 > start can + // be feasible! + for (j = 0; j < numDist; ++j) { + ind1[0] = triRef.distances[j].ind; + i1[0] = triRef.fetchData(ind1[0]); + if (i1[0] <= start) { + ind0 = triRef.fetchPrevData(ind1[0]); + i0 = triRef.fetchData(ind0); + ind2 = triRef.fetchNextData(ind1[0]); + i2 = triRef.fetchData(ind2); + convex = triRef.getAngle(ind1[0]) > 0; + + coneOk = Numerics.isInCone(triRef, i0, i1[0], i2, start, convex); + if (coneOk) { + bb = new BBox(triRef, i1[0], start); + if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1[0], -1)) + return true; + } + } + } + + // the left-most point of the hole does not lie within the outer + // boundary! what is the best bridge in this case??? I make a + // brute-force decision... perhaps this should be refined during a + // revision of the code... + for (j = 0; j < numDist; ++j) { + ind1[0] = triRef.distances[j].ind; + i1[0] = triRef.fetchData(ind1[0]); + ind0 = triRef.fetchPrevData(ind1[0]); + i0 = triRef.fetchData(ind0); + ind2 = triRef.fetchNextData(ind1[0]); + i2 = triRef.fetchData(ind2); + bb = new BBox(triRef, i1[0], start); + if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1[0], -1)) + return true; + } + + // still no diagonal??? yikes! oh well, this polygon is messed up badly! + ind1[0] = ind; + i1[0] = i; + + return false; + } + + + static void findLeftMostVertex(Triangulator triRef, int ind, int[] leftInd, + int[] leftI) { + int ind1, i1; + + ind1 = ind; + i1 = triRef.fetchData(ind1); + leftInd[0] = ind1; + leftI[0] = i1; + ind1 = triRef.fetchNextData(ind1); + i1 = triRef.fetchData(ind1); + while (ind1 != ind) { + if (i1 < leftI[0]) { + leftInd[0] = ind1; + leftI[0] = i1; + } + else if (i1 == leftI[0]) { + if (triRef.getAngle(ind1) < 0) { + leftInd[0] = ind1; + leftI[0] = i1; + } + } + ind1 = triRef.fetchNextData(ind1); + i1 = triRef.fetchData(ind1); + } + + } + + static void simpleBridge(Triangulator triRef, int ind1, int ind2) { + int prev, next; + int i1, i2, prv, nxt; + int angle; + + + // change the links + triRef.rotateLinks(ind1, ind2); + + // reset the angles + i1 = triRef.fetchData(ind1); + next = triRef.fetchNextData(ind1); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind1); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1); + triRef.setAngle(ind1, angle); + + i2 = triRef.fetchData(ind2); + next = triRef.fetchNextData(ind2); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind2); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i2, nxt, ind2); + triRef.setAngle(ind2, angle); + + } + + + static void insertBridge(Triangulator triRef, int ind1, int i1, + int ind3, int i3) { + int ind2, ind4, prev, next; + int prv, nxt, angle; + int vcntIndex; + + // duplicate nodes in order to form end points of the bridge edges + ind2 = triRef.makeNode(i1); + triRef.insertAfter(ind1, ind2); + + // Need to get the original data, before setting it. + + vcntIndex = triRef.list[ind1].getCommonIndex(); + + triRef.list[ind2].setCommonIndex(vcntIndex); + + + ind4 = triRef.makeNode(i3); + triRef.insertAfter(ind3, ind4); + + vcntIndex = triRef.list[ind3].getCommonIndex(); + triRef.list[ind4].setCommonIndex(vcntIndex); + + // insert the bridge edges into the boundary loops + triRef.splitSplice(ind1, ind2, ind3, ind4); + + // reset the angles + next = triRef.fetchNextData(ind1); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind1); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1); + triRef.setAngle(ind1, angle); + + next = triRef.fetchNextData(ind2); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind2); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind2); + triRef.setAngle(ind2, angle); + + next = triRef.fetchNextData(ind3); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind3); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind3); + triRef.setAngle(ind3, angle); + + next = triRef.fetchNextData(ind4); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind4); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind4); + triRef.setAngle(ind4, angle); + + } + + + static int l_comp(Left a, Left b) { + if (a.index < b.index) return -1; + else if (a.index > b.index) return 1; + else return 0; + } + + static int d_comp(Distance a, Distance b) { + if (a.dist < b.dist) return -1; + else if (a.dist > b.dist) return 1; + else return 0; + } + + + static void sortLeft(Left[] lefts, int numPts) { + int i,j; + Left swap = new Left(); + + for (i = 0; i < numPts; i++){ + for (j = i + 1; j < numPts; j++){ + if (l_comp(lefts[i], lefts[j]) > 0){ + swap.copy(lefts[i]); + lefts[i].copy(lefts[j]); + lefts[j].copy(swap); + } + } + } + } + + + static void sortDistance(Distance[] distances, int numPts) { + int i,j; + Distance swap = new Distance(); + + for (i = 0; i < numPts; i++){ + for (j = i + 1; j < numPts; j++){ + if (d_comp(distances[i], distances[j]) > 0){ + swap.copy(distances[i]); + distances[i].copy(distances[j]); + distances[j].copy(swap); + } + } + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Clean.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Clean.java new file mode 100644 index 0000000..5c5a39c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Clean.java @@ -0,0 +1,193 @@ +/* + * $RCSfile: Clean.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:18 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class Clean { + + static void initPUnsorted(Triangulator triRef, int number) { + if (number > triRef.maxNumPUnsorted) { + triRef.maxNumPUnsorted = number; + triRef.pUnsorted = new Point2f[triRef.maxNumPUnsorted]; + for(int i = 0; i 0){ + swap.set(points[i]); + points[i].set(points[j]); + points[j].set(swap); + } + } + } + /* + for (i = 0; i < numPts; i++) { + System.out.println("pt " + points[i]); + } + */ + } + + static int findPInd(Point2f sorted[], int numPts, Point2f pnt) { + int i; + + for (i = 0; i < numPts; i++){ + if ((pnt.x == sorted[i].x) && + (pnt.y == sorted[i].y)){ + return i; + } + } + return -1; + } + + static int pComp(Point2f a, Point2f b) { + if (a.x < b.x) + return -1; + else if (a.x > b.x) + return 1; + else { + if (a.y < b.y) + return -1; + else if (a.y > b.y) + return 1; + else + return 0; + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/ColorCube.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/ColorCube.java new file mode 100644 index 0000000..4c2d5d5 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/ColorCube.java @@ -0,0 +1,175 @@ +/* + * $RCSfile: ColorCube.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:18 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import javax.media.j3d.*; + +/** + * Simple color-per-vertex cube with a different color for each face + */ +public class ColorCube extends Shape3D { + private static final float[] verts = { + // front face + 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 1.0f, + // back face + -1.0f, -1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + // right face + 1.0f, -1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + // left face + -1.0f, -1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, + // top face + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, 1.0f, + // bottom face + -1.0f, -1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, 1.0f, + }; + + private static final float[] colors = { + // front face (red) + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + // back face (green) + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + // right face (blue) + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + // left face (yellow) + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + // top face (magenta) + 1.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 1.0f, + // bottom face (cyan) + 0.0f, 1.0f, 1.0f, + 0.0f, 1.0f, 1.0f, + 0.0f, 1.0f, 1.0f, + 0.0f, 1.0f, 1.0f, + }; + + double scale; + + /** + * Constructs a color cube with unit scale. The corners of the + * color cube are [-1,-1,-1] and [1,1,1]. + */ + public ColorCube() { + QuadArray cube = new QuadArray(24, QuadArray.COORDINATES | + QuadArray.COLOR_3); + + cube.setCoordinates(0, verts); + cube.setColors(0, colors); + + this.setGeometry(cube); + + scale = 1.0; + } + + + /** + * Constructs a color cube with the specified scale. The corners of the + * color cube are [-scale,-scale,-scale] and [scale,scale,scale]. + * @param scale the scale of the cube + */ + public ColorCube(double scale) { + QuadArray cube = new QuadArray(24, QuadArray.COORDINATES | + QuadArray.COLOR_3); + + float scaledVerts[] = new float[verts.length]; + for (int i = 0; i < verts.length; i++) + scaledVerts[i] = verts[i] * (float)scale; + + cube.setCoordinates(0, scaledVerts); + cube.setColors(0, colors); + + this.setGeometry(cube); + + this.scale = scale; + } + + /** + * @deprecated ColorCube now extends shape so it is no longer necessary + * to call this method. + */ + public Shape3D getShape() { + return this; + } + + /** + * Returns the scale of the Cube + * + * @since Java 3D 1.2.1 + */ + public double getScale() { + return scale; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Cone.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Cone.java new file mode 100644 index 0000000..dfe4e35 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Cone.java @@ -0,0 +1,429 @@ +/* + * $RCSfile: Cone.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/04/24 18:50:59 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.*; +import java.io.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * Cone is a geometry primitive defined with a radius and a height. + * It is a capped cone centered at the origin with its central axis + * aligned along the Y-axis. The center of the cone is defined to be + * the center of its bounding box (rather than its centroid). + *

+ * If the GENERATE_TEXTURE_COORDS flag is set, the texture coordinates + * are generated such that the texture gets mapped onto the cone similarly + * to how it gets mapped onto a cylinder, the difference being the top + * cap is nonexistent. + *

+ * By default all primitives with the same parameters share their + * geometry (e.g., you can have 50 shperes in your scene, but the + * geometry is stored only once). A change to one primitive will + * effect all shared nodes. Another implication of this + * implementation is that the capabilities of the geometry are shared, + * and once one of the shared nodes is live, the capabilities cannot + * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to + * share geometry among primitives with the same parameters. + */ +public class Cone extends Primitive { + float radius, height; + int xdivisions, ydivisions; + static final int MID_REZ_DIV_X = 15; + static final int MID_REZ_DIV_Y = 1; + + /** + * Designates the body of the cone. Used by getShape. + * + * @see Cone#getShape + */ + public static final int BODY = 0; + + /** + * Designates the end-cap of the cone. Used by getShape. + * + * @see Cone#getShape + */ + public static final int CAP = 1; + + /** + * Constructs a default Cone of radius of 1.0 and height + * of 2.0. Resolution defaults to 15 divisions along X and axis + * and 1 along the Y axis. Normals are generated, texture + * coordinates are not. + */ + public Cone(){ + this(1.0f, 2.0f, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null); + } + + /** + * + * Constructs a default Cone of a given radius and height. Normals + * are generated, texture coordinates are not. + * @param radius Radius + * @param height Height + */ + public Cone (float radius, float height) + { + this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null); + } + + /** + * + * Constructs a default cone of a given radius, height, + * and appearance. Normals are generated, texture coordinates are not. + * @param radius Radius + * @param height Height + * @param ap Appearance + * + * @since Java 3D 1.2.1 + */ + public Cone (float radius, float height, Appearance ap) + { + this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap); + } + + /** + * + * Constructs a default cone of a given radius, height, + * primitive flags, and appearance. + * @param radius Radius + * @param height Height + * @param primflags Primitive flags + * @param ap Appearance + */ + public Cone (float radius, float height, int primflags, Appearance ap) + { + this(radius, height, primflags, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap); + } + + /** + * Obtains the Shape3D node associated with one of the parts of the + * cone (the body or the cap). This allows users to modify the appearance + * or geometry of individual parts. + * @param partId The part to return (BODY or CAP). + * @return The Shape3D object associated with the partId. If an + * invalid partId is passed in, null is returned. + */ + public Shape3D getShape(int partId){ + if (partId > CAP || partId < BODY) return null; + return (Shape3D)getChild(partId); + } + + + /** + * Sets appearance of the cone. This will set each part of the + * cone (cap & body) to the same appearance. To set each + * part's appearance separately, use getShape(partId) to get the + * individual shape and call shape.setAppearance(ap). + */ + public void setAppearance(Appearance ap){ + ((Shape3D)getChild(BODY)).setAppearance(ap); + ((Shape3D)getChild(CAP)).setAppearance(ap); + } + + /** + * Gets the appearance of the specified part of the cone. + * + * @param partId identifier for a given subpart of the cone + * + * @return The appearance object associated with the partID. If an + * invalid partId is passed in, null is returned. + * + * @since Java 3D 1.2.1 + */ + public Appearance getAppearance(int partId) { + if (partId > CAP || partId < BODY) return null; + return getShape(partId).getAppearance(); + } + + + /** + * Constructs a customized Cone of a given radius, height, flags, + * resolution (X and Y dimensions), and appearance. The + * resolution is defined in terms of number of subdivisions + * along the object's X axis (width) and Y axis (height). More divisions + * lead to finer tesselated objects. + *

+ * If appearance is null, the default white appearance will be used. + * @param radius Radius + * @param height Height + * @param xdivision Number of divisions along X direction. + * @param ydivision Number of divisions along the height of cone. + * @param primflags flags + * @param ap Appearance + */ + + public Cone(float radius, float height, int primflags, + int xdivision, int ydivision, + Appearance ap) + { + super(); + + Shape3D shape[] = new Shape3D[2]; + this.radius = radius; + this.height = height; + xdivisions = xdivision; + ydivisions = ydivision; + flags = primflags; + boolean outside = (flags & GENERATE_NORMALS_INWARD) == 0; + boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0; + Quadrics q = new Quadrics(); + GeomBuffer gbuf = null; + + GeomBuffer cache = getCachedGeometry(Primitive.CONE, + radius, 0.0f, height, + xdivision, ydivision, primflags); + if (cache != null){ +// System.out.println("using cached geometry"); + shape[BODY] = new Shape3D(cache.getComputedGeometry()); + numVerts += cache.getNumVerts(); + numTris += cache.getNumTris(); + } + else { + // the body of the cone consists of the top of the cone and if + // ydivisions is greater than 1, the body of the cone. + gbuf = q.coneTop((double)(height/2.0 - height/ydivisions), + (double)(radius/ydivisions), height/ydivisions, + xdivisions, 1.0-1.0/(double)ydivisions, + outside, texCoordYUp); + shape[BODY] = new Shape3D(gbuf.getGeom(flags)); + numVerts += gbuf.getNumVerts(); + numTris += gbuf.getNumTris(); + if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { + cacheGeometry(Primitive.CONE, + radius, 0.0f, height, + xdivision, ydivision, primflags, gbuf); + } + } + + // only need to add a body if the ydivisions is greater than 1 + if (ydivisions > 1) { + cache = getCachedGeometry(Primitive.CONE_DIVISIONS, radius, 0.0f, + height, xdivision, ydivision, primflags); + if (cache != null) { +// System.out.println("using cached divisions"); + shape[BODY].addGeometry(cache.getComputedGeometry()); + numVerts += cache.getNumVerts(); + numTris += cache.getNumTris(); + } + else { + gbuf = q.coneBody(-(double)(height/2.0), + (double)(height/2.0-height/ydivisions), + (double)radius, (double)(radius/ydivisions), + xdivisions, ydivisions-1, 1.0/(double)ydivisions, + outside, texCoordYUp); + shape[BODY].addGeometry(gbuf.getGeom(flags)); + numVerts += gbuf.getNumVerts(); + numTris += gbuf.getNumTris(); + if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { + cacheGeometry(Primitive.CONE_DIVISIONS, radius, 0.0f, height, + xdivision, ydivision, primflags, gbuf); + } + } + } + + if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) { + (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_READ); + (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + } + + if ((flags & ENABLE_GEOMETRY_PICKING) != 0) { + (shape[BODY]).setCapability(Shape3D.ALLOW_GEOMETRY_READ); + } + + this.addChild(shape[BODY]); + + // Create bottom cap. + cache = getCachedGeometry(Primitive.BOTTOM_DISK, radius, + radius, -height/2.0f, xdivision, xdivision, + primflags); + if (cache != null) { +// System.out.println("using cached bottom"); + shape[CAP] = new Shape3D(cache.getComputedGeometry()); + numVerts += cache.getNumVerts(); + numTris += cache.getNumTris(); + } + else { + gbuf = q.disk((double)radius, xdivision, -(double)height/2.0, + !outside, texCoordYUp); + shape[CAP] = new Shape3D(gbuf.getGeom(flags)); + numVerts += gbuf.getNumVerts(); + numTris += gbuf.getNumTris(); + if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { + cacheGeometry(Primitive.BOTTOM_DISK, radius, radius, -height/2.0f, + xdivision, xdivision, primflags, gbuf); + } + } + + if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) { + (shape[CAP]).setCapability(Shape3D.ALLOW_APPEARANCE_READ); + (shape[CAP]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + } + + if ((flags & ENABLE_GEOMETRY_PICKING) != 0) { + (shape[CAP]).setCapability(Shape3D.ALLOW_GEOMETRY_READ); + } + +// Transform3D t2 = new Transform3D(); + + // Flip it to match up the texture coords. +/* This causes the bottom not to match up for odd xdivision values + objectMat = new Matrix4d(); + objectMat.setIdentity(); + rotMat = new Matrix4d(); + rotMat.setIdentity(); + rotMat.rotZ(Math.PI); + objectMat.mul(objectMat, rotMat); + t2.set(objectMat); +*/ + + this.addChild(shape[CAP]); + + if (ap == null){ + setAppearance(); + } + else setAppearance(ap); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * cloneNode should be overridden by any user subclassed + * objects. All subclasses must have their cloneNode + * method consist of the following lines: + *

+     *     public Node cloneNode(boolean forceDuplicate) {
+     *         UserSubClass usc = new UserSubClass();
+     *         usc.duplicateNode(this, forceDuplicate);
+     *         return usc;
+     *     }
+     * 
+ * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Cone c = new Cone(radius, height, flags, xdivisions, + ydivisions, getAppearance()); + c.duplicateNode(this, forceDuplicate); + return c; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + super.duplicateNode(originalNode, forceDuplicate); + } + + /** + * Returns the radius of the cone + * + * @since Java 3D 1.2.1 + */ + public float getRadius() { + return radius; + } + + /** + * Returns the height of the cone + * + * @since Java 3D 1.2.1 + */ + public float getHeight() { + return height; + } + + /** + * Returns the number divisions along the X direction + * + * @since Java 3D 1.2.1 + */ + public int getXdivisions() { + return xdivisions; + } + + /** + * Returns the number of divisions along the height of the cone + * + * @since Java 3D 1.2.1 + */ + public int getYdivisions() { + return ydivisions; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Cylinder.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Cylinder.java new file mode 100644 index 0000000..45e8aae --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Cylinder.java @@ -0,0 +1,422 @@ +/* + * $RCSfile: Cylinder.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/04/24 18:50:59 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.*; +import java.io.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * Cylinder is a geometry primitive defined with a radius and a height. + * It is a capped cylinder centered at the origin with its central axis + * aligned along the Y-axis. + *

+ * When a texture is applied to a cylinder, the texture is applied to the + * caps and the body different. A texture is mapped CCW from the back of the + * body. The top and bottom caps are mapped such that the texture appears + * front facing when the caps are rotated 90 degrees toward the viewer. + *

+ * By default all primitives with the same parameters share their + * geometry (e.g., you can have 50 shperes in your scene, but the + * geometry is stored only once). A change to one primitive will + * effect all shared nodes. Another implication of this + * implementation is that the capabilities of the geometry are shared, + * and once one of the shared nodes is live, the capabilities cannot + * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to + * share geometry among primitives with the same parameters. + */ + +public class Cylinder extends Primitive{ + float radius, height; + int xdivisions, ydivisions; + + static final int MID_REZ_DIV_X = 15; + static final int MID_REZ_DIV_Y = 1; + + /** + * Designates the body of the cylinder. Used by getShape. + * + * @see Cylinder#getShape + */ + public static final int BODY = 0; + + /** + * Designates the top end-cap of the cylinder. + * Used by getShape. + * + * @see Cylinder#getShape + */ + public static final int TOP = 1; + + /** + * Designates the bottom end-cap of the cylinder. + * Used by getShape. + * + * @see Cylinder#getShape + */ + public static final int BOTTOM = 2; + + /** + * Constructs a default cylinder of radius of 1.0 and height + * of 2.0. Normals are generated by default, texture + * coordinates are not. Resolution defaults to 15 divisions + * along X axis and 1 along the Y axis. + */ + public Cylinder() { + this(1.0f, 2.0f, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null); + } + + /** + * Constructs a default cylinder of a given radius and height. + * Normals are generated by default, texture coordinates are not. + * @param radius Radius + * @param height Height + */ + public Cylinder (float radius, float height) { + this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, + null); + } + + /** + * Constructs a default cylinder of a given radius, height, and + * appearance. Normals are generated by default, texture + * coordinates are not. + * @param radius Radius + * @param height Height + * @param ap Appearance + */ + public Cylinder (float radius, float height, Appearance ap) + { + this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, + ap); + } + + /** + * + * Constructs a default cylinder of a given radius, height, + * primitive flags and appearance. + * @param radius Radius + * @param height Height + * @param primflags Flags + * @param ap Appearance + */ + public Cylinder (float radius, float height, int primflags, Appearance ap) + { + this(radius, height, primflags, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap); + } + + /** + * Obtains the Shape3D node associated with a given part of the cylinder. + * This allows users to modify the appearance or geometry + * of individual parts. + * @param partId The part to return (BODY, TOP, or BOTTOM). + * @return The Shape3D object associated with the partID. If an + * invalid partId is passed in, null is returned. + */ + public Shape3D getShape(int partId){ + if (partId > BOTTOM || partId < BODY) return null; + return (Shape3D)getChild(partId); + } + + /** Sets appearance of the cylinder. This will set each part of the + * cylinder (TOP,BOTTOM,BODY) to the same appearance. To set each + * part's appearance separately, use getShape(partId) to get the + * individual shape and call shape.setAppearance(ap). + */ + public void setAppearance(Appearance ap) { + ((Shape3D)getChild(BODY)).setAppearance(ap); + ((Shape3D)getChild(TOP)).setAppearance(ap); + ((Shape3D)getChild(BOTTOM)).setAppearance(ap); + } + + /** + * Gets the appearance of the specified part of the cylinder. + * + * @param partId identifier for a given subpart of the cylinder + * + * @return The appearance object associated with the partID. If an + * invalid partId is passed in, null is returned. + * + * @since Java 3D 1.2.1 + */ + public Appearance getAppearance(int partId) { + if (partId > BOTTOM || partId < BODY) return null; + return getShape(partId).getAppearance(); + } + + + /** + * Constructs a customized cylinder of a given radius, height, + * resolution (X and Y dimensions), and appearance. The + * resolution is defined in terms of number of subdivisions + * along the object's X axis (width) and Y axis (height). More divisions + * lead to more finely tesselated objects. + * @param radius Radius + * @param height Height + * @param xdivision Number of divisions along X direction. + * @param ydivision Number of divisions along height of cylinder. + * @param primflags Primitive flags. + * @param ap Appearance + */ + public Cylinder(float radius, float height, int primflags, + int xdivision, int ydivision, Appearance ap) { + super(); + + this.radius = radius; + this.height = height; + this.xdivisions = xdivision; + this.ydivisions = ydivision; + flags = primflags; + boolean outside = (flags & GENERATE_NORMALS_INWARD) == 0; + boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0; + // Create many body of the cylinder. + Quadrics q = new Quadrics(); + GeomBuffer gbuf = null; + Shape3D shape[] = new Shape3D[3]; + + GeomBuffer cache = getCachedGeometry(Primitive.CYLINDER, + (float)BODY, radius, height, + xdivision, ydivision, primflags); + if (cache != null){ +// System.out.println("using cached geometry"); + shape[BODY] = new Shape3D(cache.getComputedGeometry()); + numVerts += cache.getNumVerts(); + numTris += cache.getNumTris(); + } + else { + gbuf = q.cylinder((double)height, (double)radius, + xdivision, ydivision, outside, texCoordYUp); + shape[BODY] = new Shape3D(gbuf.getGeom(flags)); + numVerts += gbuf.getNumVerts(); + numTris += gbuf.getNumTris(); + if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) + cacheGeometry(Primitive.CYLINDER, + (float)BODY, radius, height, + xdivision, ydivision, primflags, gbuf); + } + + if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) { + (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_READ); + (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + } + + if ((flags & ENABLE_GEOMETRY_PICKING) != 0) { + (shape[BODY]).setCapability(Shape3D.ALLOW_GEOMETRY_READ); + } + + this.addChild(shape[BODY]); + + // Create top of cylinder + cache = getCachedGeometry(Primitive.TOP_DISK, radius, radius, + height/2.0f, xdivision, xdivision, primflags); + if (cache != null) { +// System.out.println("using cached top"); + shape[TOP] = new Shape3D(cache.getComputedGeometry()); + numVerts += cache.getNumVerts(); + numTris += cache.getNumTris(); + } + else { + gbuf = q.disk((double)radius, xdivision, height/2.0, + outside, texCoordYUp); + shape[TOP] = new Shape3D(gbuf.getGeom(flags)); + numVerts += gbuf.getNumVerts(); + numTris += gbuf.getNumTris(); + if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { + cacheGeometry(Primitive.TOP_DISK, radius, radius, + height/2.0f, xdivision, xdivision, + primflags, gbuf); + } + } + + if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) { + (shape[TOP]).setCapability(Shape3D.ALLOW_APPEARANCE_READ); + (shape[TOP]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + } + + if ((flags & ENABLE_GEOMETRY_PICKING) != 0) { + (shape[TOP]).setCapability(Shape3D.ALLOW_GEOMETRY_READ); + } + + this.addChild(shape[TOP]); + + // Create bottom + cache = getCachedGeometry(Primitive.BOTTOM_DISK, radius, radius, + -height/2.0f, xdivision, xdivision, + primflags); + if (cache != null) { +// System.out.println("using cached bottom"); + shape[BOTTOM] = new Shape3D(cache.getComputedGeometry()); + numVerts += cache.getNumVerts(); + numTris += cache.getNumTris(); + } + else { + gbuf = q.disk((double)radius, xdivision, -height/2.0, !outside, texCoordYUp); + shape[BOTTOM] = new Shape3D(gbuf.getGeom(flags)); + numVerts += gbuf.getNumVerts(); + numTris += gbuf.getNumTris(); + if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) { + cacheGeometry(Primitive.BOTTOM_DISK, radius, radius, + -height/2.0f, xdivision, xdivision, + primflags, gbuf); + } + } + + if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) { + (shape[BOTTOM]).setCapability(Shape3D.ALLOW_APPEARANCE_READ); + (shape[BOTTOM]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + } + + if ((flags & ENABLE_GEOMETRY_PICKING) != 0) { + (shape[BOTTOM]).setCapability(Shape3D.ALLOW_GEOMETRY_READ); + } + + this.addChild(shape[BOTTOM]); + + // Set Appearance + if (ap == null){ + setAppearance(); + } + else setAppearance(ap); + } + + /** + * Used to create a new instance of the node. This routine is called + * by cloneTree to duplicate the current node. + * cloneNode should be overridden by any user subclassed + * objects. All subclasses must have their cloneNode + * method consist of the following lines: + *

+     *     public Node cloneNode(boolean forceDuplicate) {
+     *         UserSubClass usc = new UserSubClass();
+     *         usc.duplicateNode(this, forceDuplicate);
+     *         return usc;
+     *     }
+     * 
+ * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Cylinder c = new Cylinder(radius, height, flags, xdivisions, + ydivisions, getAppearance()); + c.duplicateNode(this, forceDuplicate); + return c; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + super.duplicateNode(originalNode, forceDuplicate); + } + + /** + * Returns the radius of the cylinder + * + * @since Java 3D 1.2.1 + */ + public float getRadius() { + return radius; + } + + /** + * Returns the height of the cylinder + * + * @since Java 3D 1.2.1 + */ + public float getHeight() { + return height; + } + + /** + * Returns the number divisions along the X direction + * + * @since Java 3D 1.2.1 + */ + public int getXdivisions() { + return xdivisions; + } + + /** + * Returns the number of divisions along the height of the cylinder + * + * @since Java 3D 1.2.1 + */ + public int getYdivisions() { + return ydivisions; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Degenerate.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Degenerate.java new file mode 100644 index 0000000..5d83a0b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Degenerate.java @@ -0,0 +1,170 @@ +/* + * $RCSfile: Degenerate.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:18 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class Degenerate { + + /** + * This function checks whether the triangle i1, i2, i3 is an ear, where + * the vertex i4 lies on at least one of the two edges i1, i2 or i3, i1. + * basically, we can cut the polygon at i4 into two pieces. the polygon + * touches at i4 back to back if following the next-pointers in one + * subpolygon and following the prev-pointers in the other subpolygon yields + * the same orientation for both subpolygons. otherwise, i4 forms a + * bottle neck of the polygon, and i1, i2, i3 is no valid ear. + * + * Note that this function may come up with the incorrect answer if the + * polygon has self-intersections. + */ + static boolean handleDegeneracies(Triangulator triRef, int i1, int ind1, int i2, + int i3, int i4, int ind4) { + int i0, i5; + int type[] = new int[1]; + int ind0, ind2, ind5; + boolean flag; + double area = 0.0, area1 = 0, area2 = 0.0; + + /* assert(InPointsList(i1)); + assert(InPointsList(i2)); + assert(InPointsList(i3)); + assert(InPointsList(i4)); + */ + + // first check whether the successor or predecessor of i4 is inside the + // triangle, or whether any of the two edges incident at i4 intersects + // i2, i3. + ind5 = triRef.fetchPrevData(ind4); + i5 = triRef.fetchData(ind5); + + // assert(ind4 != ind5); + //assert(InPointsList(i5)); + if ((i5 != i2) && (i5 != i3)) { + flag = Numerics.vtxInTriangle(triRef, i1, i2, i3, i5, type); + if (flag && (type[0] == 0)) return true; + if (i2 <= i3) { + if (i4 <= i5) + flag = Numerics.segIntersect(triRef, i2, i3, i4, i5, -1); + else + flag = Numerics.segIntersect(triRef, i2, i3, i5, i4, -1); + } + else { + if (i4 <= i5) + flag = Numerics.segIntersect(triRef, i3, i2, i4, i5, -1); + else + flag = Numerics.segIntersect(triRef, i3, i2, i5, i4, -1); + } + if (flag) + return true; + } + + ind5 = triRef.fetchNextData(ind4); + i5 = triRef.fetchData(ind5); + // assert(ind4 != ind5); + // assert(InPointsList(i5)); + if ((i5 != i2) && (i5 != i3)) { + flag = Numerics.vtxInTriangle(triRef, i1, i2, i3, i5, type); + if (flag && (type[0] == 0)) return true; + if (i2 <= i3) { + if (i4 <= i5) flag = Numerics.segIntersect(triRef, i2, i3, i4, i5, -1); + else flag = Numerics.segIntersect(triRef, i2, i3, i5, i4, -1); + } + else { + if (i4 <= i5) flag = Numerics.segIntersect(triRef, i3, i2, i4, i5, -1); + else flag = Numerics.segIntersect(triRef, i3, i2, i5, i4, -1); + } + if (flag) return true; + } + + i0 = i1; + ind0 = ind1; + ind1 = triRef.fetchNextData(ind1); + i1 = triRef.fetchData(ind1); + while (ind1 != ind4) { + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + area = Numerics.stableDet2D(triRef, i0, i1, i2); + area1 += area; + ind1 = ind2; + i1 = i2; + } + + ind1 = triRef.fetchPrevData(ind0); + i1 = triRef.fetchData(ind1); + while (ind1 != ind4) { + ind2 = triRef.fetchPrevData(ind1); + i2 = triRef.fetchData(ind2); + area = Numerics.stableDet2D(triRef, i0, i1, i2); + area2 += area; + ind1 = ind2; + i1 = i2; + } + + if (Numerics.le(area1, triRef.ZERO) && Numerics.le(area2, triRef.ZERO)) + return false; + else if (Numerics.ge(area1, triRef.ZERO) && Numerics.ge(area2, triRef.ZERO)) + return false; + else + return true; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Desperate.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Desperate.java new file mode 100644 index 0000000..5f26a28 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Desperate.java @@ -0,0 +1,431 @@ +/* + * $RCSfile: Desperate.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:18 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class Desperate { + + /** + * the functions in this file try to ensure that we always end up with + * something that (topologically) is a triangulation. + * + * the more desperate we get, the more aggressive means we choose for making + * diagonals "valid". + */ + static boolean desperate(Triangulator triRef, int ind, int i, boolean[] splitted) { + int[] i1 = new int[1]; + int[] i2 = new int[1]; + int[] i3 = new int[1]; + int[] i4 = new int[1]; + int[] ind1 = new int[1]; + int[] ind2 = new int[1]; + int[] ind3 = new int[1]; + int[] ind4 = new int[1]; + + splitted[0] = false; + + // check whether there exist consecutive vertices i1, i2, i3, i4 such + // that i1, i2 and i3, i4 intersect + if (existsCrossOver(triRef, ind, ind1, i1, ind2, i2, ind3, i3, ind4, i4)) { + // insert two new diagonals around the cross-over without checking + // whether they are intersection-free + handleCrossOver(triRef, ind1[0], i1[0], ind2[0], i2[0], ind3[0], i3[0], + ind4[0], i4[0]); + return false; + } + + NoHash.prepareNoHashEdges(triRef, i, i+1); + + // check whether there exists a valid diagonal that splits the polygon + // into two parts + if (existsSplit(triRef, ind, ind1, i1, ind2, i2)) { + // break up the polygon by inserting this diagonal (which can't be an + // ear -- otherwise, we would not have ended up in this part of the + // code). then, let's treat the two polygons separately. hopefully, + // this will help to handle self-overlapping polygons in the "correct" + // way. + handleSplit(triRef, ind1[0], i1[0], ind2[0], i2[0]); + splitted[0] = true; + return false; + } + + return true; + } + + + static boolean existsCrossOver(Triangulator triRef, int ind, int[] ind1, int[] i1, + int[] ind2, int[] i2, int[] ind3, int[] i3, + int[] ind4, int[] i4) { + BBox bb1, bb2; + + ind1[0] = ind; + i1[0] = triRef.fetchData(ind1[0]); + ind2[0] = triRef.fetchNextData(ind1[0]); + i2[0] = triRef.fetchData(ind2[0]); + ind3[0] = triRef.fetchNextData(ind2[0]); + i3[0] = triRef.fetchData(ind3[0]); + ind4[0] = triRef.fetchNextData(ind3[0]); + i4[0] = triRef.fetchData(ind4[0]); + + do { + bb1 = new BBox(triRef, i1[0], i2[0]); + bb2 = new BBox(triRef, i3[0], i4[0]); + if (bb1.BBoxOverlap(bb2)) { + if (Numerics.segIntersect(triRef, bb1.imin, bb1.imax, bb2.imin, bb2.imax, -1)) + return true; + } + ind1[0] = ind2[0]; + i1[0] = i2[0]; + ind2[0] = ind3[0]; + i2[0] = i3[0]; + ind3[0] = ind4[0]; + i3[0] = i4[0]; + ind4[0] = triRef.fetchNextData(ind3[0]); + i4[0] = triRef.fetchData(ind4[0]); + + } while (ind1[0] != ind); + + return false; + } + + + static void handleCrossOver(Triangulator triRef, int ind1, int i1, int ind2, + int i2, int ind3, int i3, int ind4, int i4) { + double ratio1, ratio4; + boolean first; + int angle1, angle4; + + // which pair of triangles shall I insert?? we can use either i1, i2, i3 + // and i1, i3, i4, or we can use i2, i3, i4 and i1, i2, i4... + angle1 = triRef.getAngle(ind1); + angle4 = triRef.getAngle(ind4); + if (angle1 < angle4) first = true; + else if (angle1 > angle4) first = false; + else if (triRef.earsSorted) { + ratio1 = Numerics.getRatio(triRef, i3, i4, i1); + ratio4 = Numerics.getRatio(triRef, i1, i2, i4); + if (ratio4 < ratio1) first = false; + else first = true; + } + else { + first = true; + } + + if (first) { + // first clip i1, i2, i3, then clip i1, i3, i4 + triRef.deleteLinks(ind2); + // StoreTriangle(GetOriginal(ind1), GetOriginal(ind2), GetOriginal(ind3)); + triRef.storeTriangle(ind1, ind2, ind3); + triRef.setAngle(ind3, 1); + Heap.insertIntoHeap(triRef, 0.0, ind3, ind1, ind4); + } + else { + // first clip i2, i3, i4, then clip i1, i2, i4 + triRef.deleteLinks(ind3); + //StoreTriangle(GetOriginal(ind2), GetOriginal(ind3), GetOriginal(ind4)); + triRef.storeTriangle(ind2, ind3, ind4); + triRef.setAngle(ind2, 1); + Heap.insertIntoHeap(triRef, 0.0, ind2, ind1, ind4); + } + } + + + static boolean letsHope(Triangulator triRef, int ind) { + int ind0, ind1, ind2; + int i0, i1, i2; + + // let's clip the first convex corner. of course, we know that this is no + // ear in an ideal world. but this polygon isn't ideal, either! + ind1 = ind; + i1 = triRef.fetchData(ind1); + + do { + if (triRef.getAngle(ind1) > 0) { + ind0 = triRef.fetchPrevData(ind1); + i0 = triRef.fetchData(ind0); + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + Heap.insertIntoHeap(triRef, 0.0, ind1, ind0, ind2); + return true; + } + ind1 = triRef.fetchNextData(ind1); + i1 = triRef.fetchData(ind1); + } while (ind1 != ind); + + // no convex corners? so, let's cheat! this code won't stop without some + // triangulation... ;-) g-i-g-o? right! perhaps, this is what you + // call a robust code?! + triRef.setAngle(ind, 1); + ind0 = triRef.fetchPrevData(ind); + i0 = triRef.fetchData(ind0); + ind2 = triRef.fetchNextData(ind); + i2 = triRef.fetchData(ind2); + Heap.insertIntoHeap(triRef, 0.0, ind, ind0, ind2); + i1 = triRef.fetchData(ind); + + return true; + + // see, we never have to return "false"... + /* + return false; + */ + } + + + static boolean existsSplit(Triangulator triRef, int ind, int[] ind1, int[] i1, + int[] ind2, int[] i2) { + int ind3, ind4, ind5; + int i3, i4, i5; + + if (triRef.numPoints > triRef.maxNumDist) { + // System.out.println("Desperate: Expanding distances array ..."); + triRef.maxNumDist = triRef.numPoints; + triRef.distances = new Distance[triRef.maxNumDist]; + for (int k = 0; k < triRef.maxNumDist; k++) + triRef.distances[k] = new Distance(); + } + ind1[0] = ind; + i1[0] = triRef.fetchData(ind1[0]); + ind4 = triRef.fetchNextData(ind1[0]); + i4 = triRef.fetchData(ind4); + // assert(*ind1 != ind4); + ind5 = triRef.fetchNextData(ind4); + i5 = triRef.fetchData(ind5); + // assert(*ind1 != *ind2); + ind3 = triRef.fetchPrevData(ind1[0]); + i3 = triRef.fetchData(ind3); + // assert(*ind2 != ind3); + if (foundSplit(triRef, ind5, i5, ind3, ind1[0], i1[0], i3, i4, ind2, i2)) + return true; + i3 = i1[0]; + ind1[0] = ind4; + i1[0] = i4; + ind4 = ind5; + i4 = i5; + ind5 = triRef.fetchNextData(ind4); + i5 = triRef.fetchData(ind5); + + while (ind5 != ind) { + if (foundSplit(triRef, ind5, i5, ind, ind1[0], i1[0], i3, i4, ind2, i2)) + return true; + i3 = i1[0]; + ind1[0] = ind4; + i1[0] = i4; + ind4 = ind5; + i4 = i5; + ind5 = triRef.fetchNextData(ind4); + i5 = triRef.fetchData(ind5); + } + + return false; + } + + + /** + * This function computes the winding number of a polygon with respect to a + * point p. no care is taken to handle cases where p lies on the + * boundary of the polygon. (this is no issue in our application, as we will + * always compute the winding number with respect to the mid-point of a + * valid diagonal.) + */ + static int windingNumber(Triangulator triRef, int ind, Point2f p) { + double angle; + int ind2; + int i1, i2, number; + + i1 = triRef.fetchData(ind); + ind2 = triRef.fetchNextData(ind); + i2 = triRef.fetchData(ind2); + angle = Numerics.angle(triRef, p, triRef.points[i1], triRef.points[i2]); + while (ind2 != ind) { + i1 = i2; + ind2 = triRef.fetchNextData(ind2); + i2 = triRef.fetchData(ind2); + angle += Numerics.angle(triRef, p, triRef.points[i1], triRef.points[i2]); + } + + angle += Math.PI; + number = (int)(angle / (Math.PI*2.0)); + + return number; + } + + + + + static boolean foundSplit(Triangulator triRef, int ind5, int i5, int ind, int ind1, + int i1, int i3, int i4, int[] ind2, int[] i2) { + Point2f center; + int numDist = 0; + int j, i6, i7; + int ind6, ind7; + BBox bb; + boolean convex, coneOk; + + // Sort the points according to their distance from i1 + do { + // assert(numDist < triRef.maxNumDist); + triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[i1], + triRef.points[i5]); + triRef.distances[numDist].ind = ind5; + ++numDist; + ind5 = triRef.fetchNextData(ind5); + i5 = triRef.fetchData(ind5); + } while (ind5 != ind); + + Bridge.sortDistance(triRef.distances, numDist); + + // find a valid diagonal. + for (j = 0; j < numDist; ++j) { + ind2[0] = triRef.distances[j].ind; + i2[0] = triRef.fetchData(ind2[0]); + if (i1 != i2[0]) { + ind6 = triRef.fetchPrevData(ind2[0]); + i6 = triRef.fetchData(ind6); + ind7 = triRef.fetchNextData(ind2[0]); + i7 = triRef.fetchData(ind7); + + convex = triRef.getAngle(ind2[0]) > 0; + coneOk = Numerics.isInCone(triRef, i6, i2[0], i7, i1, convex); + if (coneOk) { + convex = triRef.getAngle(ind1) > 0; + coneOk = Numerics.isInCone(triRef, i3, i1, i4, i2[0], convex); + if (coneOk) { + bb = new BBox(triRef, i1, i2[0]); + if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1, -1)) { + // check whether this is a good diagonal; we do not want a + // diagonal that may create figure-8's! + center = new Point2f(); + Basic.vectorAdd2D(triRef.points[i1], triRef.points[i2[0]], center); + Basic.multScalar2D(0.5, center); + if (windingNumber(triRef, ind, center) == 1) return true; + } + } + } + } + } + + return false; + } + + + static void handleSplit(Triangulator triRef, int ind1, int i1, int ind3, int i3) { + int ind2, ind4, prev, next; + int prv, nxt, angle; + int vIndex, comIndex = -1; + + // duplicate nodes in order to form end points of the new diagonal + ind2 = triRef.makeNode(i1); + triRef.insertAfter(ind1, ind2); + + // Need to get the original data, before setting it. + + comIndex = triRef.list[ind1].getCommonIndex(); + + triRef.list[ind2].setCommonIndex(comIndex); + + ind4 = triRef.makeNode(i3); + triRef.insertAfter(ind3, ind4); + + comIndex = triRef.list[ind3].getCommonIndex(); + triRef.list[ind4].setCommonIndex(comIndex); + + // insert the diagonal into the boundary loop, thus splitting the loop + // into two loops + triRef.splitSplice(ind1, ind2, ind3, ind4); + + // store pointers to the two new loops + triRef.storeChain(ind1); + triRef.storeChain(ind3); + + // reset the angles + next = triRef.fetchNextData(ind1); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind1); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1); + triRef.setAngle(ind1, angle); + + next = triRef.fetchNextData(ind2); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind2); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind2); + triRef.setAngle(ind2, angle); + + next = triRef.fetchNextData(ind3); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind3); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind3); + triRef.setAngle(ind3, angle); + + next = triRef.fetchNextData(ind4); + nxt = triRef.fetchData(next); + prev = triRef.fetchPrevData(ind4); + prv = triRef.fetchData(prev); + angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind4); + triRef.setAngle(ind4, angle); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Distance.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Distance.java new file mode 100644 index 0000000..ad2e6bc --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Distance.java @@ -0,0 +1,73 @@ +/* + * $RCSfile: Distance.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:18 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +class Distance extends Object { + int ind; + double dist; + + Distance() { + } + + void copy(Distance d) { + ind = d.ind; + dist = d.dist; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/EarClip.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/EarClip.java new file mode 100644 index 0000000..151e9ce --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/EarClip.java @@ -0,0 +1,348 @@ +/* + * $RCSfile: EarClip.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:18 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class EarClip { + + /** + * Classifies all the internal angles of the loop referenced by ind. + * the following classification is used: + * 0 ... if angle is 180 degrees + * 1 ... if angle between 0 and 180 degrees + * 2 ... if angle is 0 degrees + * -1 ... if angle between 180 and 360 degrees + * -2 ... if angle is 360 degrees + */ + static void classifyAngles(Triangulator triRef, int ind) { + int ind0, ind1, ind2; + int i0, i1, i2; + int angle; + + ind1 = ind; + i1 = triRef.fetchData(ind1); + ind0 = triRef.fetchPrevData(ind1); + i0 = triRef.fetchData(ind0); + + do { + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + angle = Numerics.isConvexAngle(triRef, i0, i1, i2, ind1); + triRef.setAngle(ind1, angle); + i0 = i1; + i1 = i2; + ind1 = ind2; + } while (ind1 != ind); + + } + + + static void classifyEars(Triangulator triRef, int ind) { + int ind1; + int i1; + int[] ind0, ind2; + double[] ratio; + + ind0 = new int[1]; + ind2 = new int[1]; + ratio = new double[1]; + + Heap.initHeap(triRef); + + ind1 = ind; + i1 = triRef.fetchData(ind1); + + do { + if ((triRef.getAngle(ind1) > 0) && + isEar(triRef, ind1, ind0, ind2, ratio)) { + + Heap.dumpOnHeap(triRef, ratio[0], ind1, ind0[0], ind2[0]); + } + ind1 = triRef.fetchNextData(ind1); + i1 = triRef.fetchData(ind1); + } while (ind1 != ind); + + // Not using sorted_ear so don't have to do MakeHeap(); + // MakeHeap(); + + // Heap.printHeapData(triRef); + + } + + + /** + * This function checks whether a diagonal is valid, that is, whether it is + * locally within the polygon, and whether it does not intersect any other + * segment of the polygon. also, some degenerate cases get a special + * handling. + */ + static boolean isEar(Triangulator triRef, int ind2, int[] ind1, int[] ind3, + double[] ratio) { + int i0, i1, i2, i3, i4; + int ind0, ind4; + BBox bb; + boolean convex, coneOk; + + i2 = triRef.fetchData(ind2); + ind3[0] = triRef.fetchNextData(ind2); + i3 = triRef.fetchData(ind3[0]); + ind4 = triRef.fetchNextData(ind3[0]); + i4 = triRef.fetchData(ind4); + ind1[0] = triRef.fetchPrevData(ind2); + i1 = triRef.fetchData(ind1[0]); + ind0 = triRef.fetchPrevData(ind1[0]); + i0 = triRef.fetchData(ind0); + + /* + System.out.println("isEar : i0 " + i0 + " i1 " + i1 + " i2 " + i2 + + " i3 " + i3 + " i4 " + i4); + */ + + if ((i1 == i3) || (i1 == i2) || (i2 == i3) || (triRef.getAngle(ind2) == 2)) { + // oops, this is not a simple polygon! + ratio[0] = 0.0; + return true; + } + + if (i0 == i3) { + // again, this is not a simple polygon! + if ((triRef.getAngle(ind0) < 0) || (triRef.getAngle(ind3[0]) < 0)) { + ratio[0] = 0.0; + return true; + } + else + return false; + } + + if (i1 == i4) { + // again, this is not a simple polygon! + if ((triRef.getAngle(ind1[0]) < 0) || (triRef.getAngle(ind4) < 0)) { + ratio[0] = 0.0; + return true; + } + else + return false; + } + + // check whether the new diagonal i1, i3 locally is within the polygon + convex = triRef.getAngle(ind1[0]) > 0; + coneOk = Numerics.isInCone(triRef, i0, i1, i2, i3, convex); + // System.out.println("isEar :(1) convex " + convex + " coneOk " + coneOk ); + + if (!coneOk) return false; + convex = triRef.getAngle(ind3[0]) > 0; + coneOk = Numerics.isInCone(triRef, i2, i3, i4, i1, convex); + // System.out.println("isEar :(2) convex " + convex + " coneOk " + coneOk ); + + if (coneOk) { + // check whether this diagonal is a valid diagonal. this translates to + // checking either condition CE1 or CE2 (see my paper). If CE1 is to + // to be checked, then we use a BV-tree or a grid. Otherwise, we use + // "buckets" (i.e., a grid) or no hashing at all. + bb = new BBox(triRef, i1, i3); + // use CE2 + no_hashing + if(!NoHash.noHashIntersectionExists(triRef, i2, ind2, i3, i1, bb)) { + if (triRef.earsSorted) { + // determine the quality of the triangle + ratio[0] = Numerics.getRatio(triRef, i1, i3, i2); + } + else { + ratio[0] = 1.0; + } + return true; + } + } + + // System.out.println("isEar : false"); + return false; + } + + + + /** + * This is the main function that drives the ear-clipping. it obtains an ear + * from set of ears maintained in a priority queue, clips this ear, and + * updates all data structures appropriately. (ears are arranged in the + * priority queue (i.e., heap) according to a quality criterion that tries + * to avoid skinny triangles.) + */ + static boolean clipEar(Triangulator triRef, boolean[] done) { + + int ind0, ind1, ind3, ind4; + + int i0, i1, i2, i3, i4; + int angle1, angle3; + + double ratio[] = new double[1]; + int index0[] = new int[1]; + int index1[] = new int[1]; + int index2[] = new int[1]; + int index3[] = new int[1]; + int index4[] = new int[1]; + int ind2[] = new int[1]; + + int testCnt = 0; + + // Heap.printHeapData(triRef); + + do { + + // System.out.println("In clipEarloop " + testCnt++); + + if (!Heap.deleteFromHeap(triRef, ind2, index1, index3)) + // no ear exists?! + return false; + + // get the successors and predecessors in the list of nodes and check + // whether the ear still is part of the boundary + ind1 = triRef.fetchPrevData(ind2[0]); + i1 = triRef.fetchData(ind1); + ind3 = triRef.fetchNextData(ind2[0]); + i3 = triRef.fetchData(ind3); + + } while ((index1[0] != ind1) || (index3[0] != ind3)); + + //System.out.println("Out of clipEarloop "); + + i2 = triRef.fetchData(ind2[0]); + + // delete the clipped ear from the list of nodes, and update the bv-tree + triRef.deleteLinks(ind2[0]); + + // store the ear in a list of ears which have already been clipped + // StoreTriangle(GetOriginal(ind1), GetOriginal(ind2), GetOriginal(ind3)); + triRef.storeTriangle(ind1, ind2[0], ind3); + + /* */ + /* update the angle classification at ind1 and ind3 */ + /* */ + ind0 = triRef.fetchPrevData(ind1); + i0 = triRef.fetchData(ind0); + if (ind0 == ind3) { + // nothing left + done[0] = true; + return true; + } + angle1 = Numerics.isConvexAngle(triRef, i0, i1, i3, ind1); + + ind4 = triRef.fetchNextData(ind3); + i4 = triRef.fetchData(ind4); + + angle3 = Numerics.isConvexAngle(triRef, i1, i3, i4, ind3); + + if (i1 != i3) { + if ((angle1 >= 0) && (triRef.getAngle(ind1) < 0)) + NoHash.deleteReflexVertex(triRef, ind1); + if ((angle3 >= 0) && (triRef.getAngle(ind3) < 0)) + NoHash.deleteReflexVertex(triRef, ind3); + } + else { + if ((angle1 >= 0) && (triRef.getAngle(ind1) < 0)) + NoHash.deleteReflexVertex(triRef, ind1); + else if ((angle3 >= 0) && (triRef.getAngle(ind3) < 0)) + NoHash.deleteReflexVertex(triRef, ind3); + + } + + triRef.setAngle(ind1, angle1); + triRef.setAngle(ind3, angle3); + + // check whether either of ind1 and ind3 is an ear. (the "ratio" is + // the length of the triangle's longest side divided by the length of the + // height normal onto this side; it is used as a quality criterion.) + if (angle1 > 0) { + if (isEar(triRef, ind1, index0, index2, ratio)) { + // insert the new ear into the priority queue of ears + Heap.insertIntoHeap(triRef, ratio[0], ind1, index0[0], index2[0]); + } + } + + if (angle3 > 0) { + if(isEar(triRef, ind3, index2, index4, ratio)) { + Heap.insertIntoHeap(triRef, ratio[0], ind3, index2[0], index4[0]); + } + } + + // check whether the triangulation is finished. + ind0 = triRef.fetchPrevData(ind1); + i0 = triRef.fetchData(ind0); + ind4 = triRef.fetchNextData(ind3); + i4 = triRef.fetchData(ind4); + if (ind0 == ind4) { + // only one triangle left -- clip it! + triRef.storeTriangle(ind1, ind3, ind4); + done[0] = true; + } + else { + done[0] = false; + } + + return true; + } + +} + + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Edge.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Edge.java new file mode 100644 index 0000000..4047354 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Edge.java @@ -0,0 +1,89 @@ +/* + * $RCSfile: Edge.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:18 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +// Class created so that the two vertex indices that make up an +// edge can be hashed. +class Edge { + + public int v1; + public int v2; + private static final int HASHCONST = 0xEDCBA987; + + public int hashCode() + { + return ((v1 * HASHCONST) << 2) ^ (v2 * HASHCONST); + } // end of Edge.hashCode + + public boolean equals(Object x) + { + if (!(x instanceof Edge)) return false; + Edge e = (Edge)x; + return (v1 == e.v1) && (v2 == e.v2); + } // End of Edge.equals + + public String toString() + { + return "(" + v1 + ", " + v2 + ")"; + } // End of toString + + public Edge(int a, int b) + { + v1 = a; + v2 = b; + } + + public Edge(Edge e) + { + v1 = e.v1; + v2 = e.v2; + } + + public Edge() + { + } +} // end of class Edge + +// End of file Edge.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/EdgeTable.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/EdgeTable.java new file mode 100644 index 0000000..dc92c82 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/EdgeTable.java @@ -0,0 +1,116 @@ +/* + * $RCSfile: EdgeTable.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:18 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; +import com.sun.j3d.utils.geometry.Edge; + +class EdgeTable { + + private HashMap edgeTable; + private static final int DEBUG = 0; + + + + Integer get(int a, int b) + { + return (Integer)edgeTable.get(new Edge(a, b)); + } // End of get() + + + Integer get(Edge e) + { + return (Integer)edgeTable.get(e); + } // End of get() + + + + // This function creates a table used to connect the triangles. + // Here's how it works. If a triangle is made of indices 12, + // 40, and 51, then edge(12, 40) gets 51, edge(40, 51) gets 12, + // and edge(51, 12) gets 40. This lets us quickly move from + // triangle to triangle without saving a lot of extra data. + EdgeTable(int triangleIndices[]) + { + // We'll have one edge for each vertex + edgeTable = new HashMap(triangleIndices.length * 2); + + // Fill in table + Edge e; + for (int t = 0 ; t < triangleIndices.length ; t += 3) { + // Put all 3 edges of triangle into table + for (int v = 0 ; v < 3 ; v++) { + e = new Edge(triangleIndices[t + v], + triangleIndices[t + ((v + 1) % 3)]); + + if (edgeTable.get(e) != null) { + if ((DEBUG & 1) != 0) { + System.out.println("EdgeTable Error: duplicate edge (" + + triangleIndices[t + v] + ", " + + triangleIndices[t + ((v + 1) % 3)] + ")."); + } + } else { + // Store index of 3rd vertex (across from edge) + edgeTable.put(e, new Integer(t + ((v + 2) % 3))); + } + } + } + + if ((DEBUG & 1) != 0) { + System.out.println("Edge Table:"); + Iterator list = edgeTable.keySet().iterator(); + while (list.hasNext()) { + Edge edge = (Edge)list.next(); + System.out.println(" (" + edge.v1 + ", " + edge.v2 + ") = " + + get(edge.v1, edge.v2)); + } + } + } // End of constructor EdgeTable + +} // End of class EdgeTable + +// End of file EdgeTable.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeomBuffer.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeomBuffer.java new file mode 100644 index 0000000..506a2d3 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeomBuffer.java @@ -0,0 +1,560 @@ +/* + * $RCSfile: GeomBuffer.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/04/24 18:50:59 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.*; +import java.io.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.math.*; + +/** + * GeomBuffer allows OpenGL-like input of geometry data. It outputs + * Java 3D geometry array objects. This utility is to simplify porting + * of OpenGL programs to Java 3D. + *

+ * Here is a sample code that use this utility to create some quads. + *

+ * 
+ *     GeomBuffer gbuf = new GeomBuffer(100);
+ *     gbuf.begin(GeomBuffer.QUADS);
+ *
+ *     for (int i = 0; i < 5; i++){
+ *       gbuf.normal3d(0.0, 1.0, 0.0);
+ *       gbuf.vertex3d(1.0, 1.0, 0.0);
+ * 
+ *       gbuf.normal3d(0.0, 1.0, 0.0);
+ *       gbuf.vertex3d(0.0, 1.0, 0.0);
+ * 
+ *       gbuf.normal3d(0.0, 1.0, 0.0);
+ *       gbuf.vertex3d(0.0, 0.0, 0.0);
+ * 
+ *       gbuf.normal3d(0.0, 1.0, 0.0);
+ *       gbuf.vertex3d(1.0, 0.0, 0.0);
+ *     }
+ *     gbuf.end();
+ *     Shape3D shape = new Shape3D(gbuf.getGeom(GeomBuffer.GENERATE_NORMALS));
+ * 
+ * Notice, that you only need to specify some upperbound on the number of + * points you'll use at the beginning (100 in this case). + *

+ * Currently, you are limited to one primitive type per geom buffer. Future + * versions will add support for mixed primitive types. + * + **/ + +class GeomBuffer extends Object{ + + //Supported Primitives + static final int QUAD_STRIP = 0x01; + static final int TRIANGLES = 0x02; + static final int QUADS = 0x04; + static final int TRIANGLE_FAN = 0x10; + static final int TRIANGLE_STRIP = 0x20; + + private int flags; + + Point3f[] pts = null; + Vector3f[] normals = null; + TexCoord2f[] tcoords = null; + int currVertCnt; + int currPrimCnt; + int[] currPrimType = null, + currPrimStartVertex = null, + currPrimEndVertex = null; + GeometryArray geometry; + int numVerts = 0; + int numTris = 0; + int numTexUnit = 1; + int texCoordSetMap[] = null; + + + static final int debug = 0; + + /** Creates a geometry buffer of given number of vertices + * @param numVerts total number of vertices to allocate by this buffer. + * This is an upper bound estimate. + */ + GeomBuffer(int numVerts, int numTexUnit) + { + this.numTexUnit = numTexUnit; + pts = new Point3f[numVerts]; + normals = new Vector3f[numVerts]; + tcoords = new TexCoord2f[numVerts]; + // max primitives is numV/3 + currPrimType = new int[numVerts/3]; + currPrimStartVertex = new int[numVerts/3]; + currPrimEndVertex = new int[numVerts/3]; + currVertCnt = 0; + currPrimCnt = 0; + + texCoordSetMap = new int[numTexUnit]; + for (int i = 0; i < numTexUnit; i++) + texCoordSetMap[i] = 0; + + } + + GeomBuffer(int numVerts) + { + this(numVerts, 1); + } + + /* + * Returns a Java 3D geometry array from the geometry buffer. You need to + * call begin, vertex3d, end, etc. before calling this, of course. + * + * @param format vertex format. + */ + + GeometryArray getGeom(int format) + { + GeometryArray obj = null; + flags = format; + + numTris = 0; + + //Switch based on first primitive. + switch (currPrimType[0]){ + case TRIANGLES: + obj = processTriangles(); + break; + case QUADS: + obj = processQuads(); + break; + case QUAD_STRIP: + case TRIANGLE_STRIP: + obj = processQuadStrips(); + break; + case TRIANGLE_FAN: + obj = processTriangleFan(); + break; + } + if ((obj != null) && ((flags & Primitive.ENABLE_GEOMETRY_PICKING) != 0)) { + obj.setCapability(Geometry.ALLOW_INTERSECT); + obj.setCapability(GeometryArray.ALLOW_FORMAT_READ); + obj.setCapability(GeometryArray.ALLOW_COUNT_READ); + obj.setCapability(GeometryArray.ALLOW_COORDINATE_READ); + } + return obj; + } + + + /** + * Begins a new primitive given the primitive type. + * + * @param prim the primitive type (listed above). + * + **/ + + void begin(int prim) + { + if (debug >= 1) System.out.println("quad"); + currPrimType[currPrimCnt] = prim; + currPrimStartVertex[currPrimCnt] = currVertCnt; + } + + + /** + * End of primitive. + * + * + **/ + void end() + { + if (debug >= 1) System.out.println("end"); + currPrimEndVertex[currPrimCnt] = currVertCnt; + currPrimCnt++; + } + + void vertex3d(double x, double y, double z) + { + + if (debug >= 2) System.out.println("v " + x + " " + + y + " " + + z); + pts[currVertCnt] = new Point3f((float)x, (float)y, (float)z); + currVertCnt++; + } + + void normal3d(double x, double y, double z) + { + if (debug >= 2) System.out.println("n " + x + " " + + y + " " + z); + double sum = x*x+y*y+z*z; + if (Math.abs(sum - 1.0) > 0.001){ + if (debug >= 2) System.out.println("normalizing"); + double root = Math.sqrt(sum); + if (root > 0.000001) { + x /= root; + y /= root; + z /= root; + } else { + y = z = 0.0; x = 1.0; + } + } + normals[currVertCnt] = new Vector3f((float)x, (float)y, (float)z); + } + + void texCoord2d(double s, double t) + { + if (debug >= 2) System.out.println("t " + + s + " " + + t); + tcoords[currVertCnt] = new TexCoord2f((float)s, (float)t); + } + + // Return a reference to the texture coordinates of this geom buffer. + TexCoord2f[] getTexCoords() { + return tcoords; + } + + /** + * Returns the Java 3D geometry gotten from calling getGeom. + * + **/ + + GeometryArray getComputedGeometry() + { + return geometry; + } + + int getNumTris() + { + return numTris; + } + + int getNumVerts() + { + return numVerts; + } + + + private GeometryArray processQuadStrips() + { + GeometryArray obj = null; + int i; + int totalVerts = 0; + + // Calculate how many vertices needed to hold all of the individual quads + int stripCounts[] = new int[currPrimCnt]; + for (i = 0; i < currPrimCnt; i++){ + stripCounts[i] = currPrimEndVertex[i] - currPrimStartVertex[i]; + totalVerts += stripCounts[i]; + } + + if (debug >= 1) System.out.println("totalVerts " + totalVerts); + + int tsaFlags = TriangleStripArray.COORDINATES; + if ((flags & Primitive.GENERATE_NORMALS) != 0) + tsaFlags |= TriangleStripArray.NORMALS; + if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) + tsaFlags |= TriangleStripArray.TEXTURE_COORDINATE_2; + + // Create GeometryArray to pass back + obj = new TriangleStripArray(totalVerts, tsaFlags, + 1, texCoordSetMap, stripCounts); + + // Allocate space to store new vertex info + Point3f[] newpts = new Point3f[totalVerts]; + Vector3f[] newnormals = new Vector3f[totalVerts]; + TexCoord2f[] newtcoords = new TexCoord2f[totalVerts]; + int currVert = 0; + + // Repeat for each Quad Strip + for (i = 0; i < currPrimCnt; i++){ + // Output order for these quad arrays same as java 3d triangle strips + for (int j = currPrimStartVertex[i] ; j < currPrimEndVertex[i] ; j++){ + outVertex(newpts, newnormals, newtcoords, currVert++, + pts, normals, tcoords, j); + } + + } + + numVerts = currVert; + numTris += totalVerts - currPrimCnt * 2; + + obj.setCoordinates(0, newpts); + if ((flags & Primitive.GENERATE_NORMALS) != 0) + obj.setNormals(0, newnormals); + if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) + obj.setTextureCoordinates(0, 0, newtcoords); + + geometry = obj; + return obj; + } + + private GeometryArray processQuads() + { + GeometryArray obj = null; + int i; + int totalVerts = 0; + + for (i = 0; i < currPrimCnt; i++){ + totalVerts += currPrimEndVertex[i] - currPrimStartVertex[i]; + } + + if (debug >= 1) System.out.println("totalVerts " + totalVerts); + + if (((flags & Primitive.GENERATE_NORMALS) != 0) && + ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){ + obj = new QuadArray(totalVerts, + QuadArray.COORDINATES | + QuadArray.NORMALS | + QuadArray.TEXTURE_COORDINATE_2, + 1, texCoordSetMap); + } + else + if (((flags & Primitive.GENERATE_NORMALS) == 0) && + ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){ + obj = new QuadArray(totalVerts, + QuadArray.COORDINATES | + QuadArray.TEXTURE_COORDINATE_2, + 1, texCoordSetMap); + } + else + if (((flags & Primitive.GENERATE_NORMALS) != 0) && + ((flags & Primitive.GENERATE_TEXTURE_COORDS) == 0)){ + obj = new QuadArray(totalVerts, + QuadArray.COORDINATES | + QuadArray.NORMALS); + } + else { + obj = new QuadArray(totalVerts, + QuadArray.COORDINATES); + } + + Point3f[] newpts = new Point3f[totalVerts]; + Vector3f[] newnormals = new Vector3f[totalVerts]; + TexCoord2f[] newtcoords = new TexCoord2f[totalVerts]; + int currVert = 0; + + if (debug > 1) System.out.println("total prims " + currPrimCnt); + + for (i = 0; i < currPrimCnt; i++){ + if (debug > 1) System.out.println("start " + currPrimStartVertex[i] + + " end " + currPrimEndVertex[i]); + for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i] - 3;j+=4){ + outVertex(newpts, newnormals, newtcoords, currVert++, + pts, normals, tcoords, j); + outVertex(newpts, newnormals, newtcoords, currVert++, + pts, normals, tcoords, j + 1); + outVertex(newpts, newnormals, newtcoords, currVert++, + pts, normals, tcoords, j + 2); + outVertex(newpts, newnormals, newtcoords, currVert++, + pts, normals, tcoords, j + 3); + numTris += 2; + } + } + numVerts = currVert; + + obj.setCoordinates(0, newpts); + if ((flags & Primitive.GENERATE_NORMALS) != 0) + obj.setNormals(0, newnormals); + if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) + obj.setTextureCoordinates(0, 0, newtcoords); + + geometry = obj; + return obj; + } + + private GeometryArray processTriangles() + { + GeometryArray obj = null; + int i; + int totalVerts = 0; + + for (i = 0; i < currPrimCnt; i++){ + totalVerts += currPrimEndVertex[i] - currPrimStartVertex[i]; + } + + if (debug >= 1) System.out.println("totalVerts " + totalVerts); + + if (((flags & Primitive.GENERATE_NORMALS) != 0) && + ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){ + obj = new TriangleArray(totalVerts, + TriangleArray.COORDINATES | + TriangleArray.NORMALS | + TriangleArray.TEXTURE_COORDINATE_2, + 1, texCoordSetMap); + } + else + if (((flags & Primitive.GENERATE_NORMALS) == 0) && + ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){ + obj = new TriangleArray(totalVerts, + TriangleArray.COORDINATES | + TriangleArray.TEXTURE_COORDINATE_2, + 1, texCoordSetMap); + } + else + if (((flags & Primitive.GENERATE_NORMALS) != 0) && + ((flags & Primitive.GENERATE_TEXTURE_COORDS) == 0)){ + obj = new TriangleArray(totalVerts, + TriangleArray.COORDINATES | + TriangleArray.NORMALS); + } + else { + obj = new TriangleArray(totalVerts, + TriangleArray.COORDINATES); + } + + Point3f[] newpts = new Point3f[totalVerts]; + Vector3f[] newnormals = new Vector3f[totalVerts]; + TexCoord2f[] newtcoords = new TexCoord2f[totalVerts]; + int currVert = 0; + + for (i = 0; i < currPrimCnt; i++){ + for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i] - 2;j+=3){ + outVertex(newpts, newnormals, newtcoords, currVert++, + pts, normals, tcoords, j); + outVertex(newpts, newnormals, newtcoords, currVert++, + pts, normals, tcoords, j + 1); + outVertex(newpts, newnormals, newtcoords, currVert++, + pts, normals, tcoords, j + 2); + numTris += 1; + } + } + numVerts = currVert; + + obj.setCoordinates(0, newpts); + if ((flags & Primitive.GENERATE_NORMALS) != 0) + obj.setNormals(0, newnormals); + if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) + obj.setTextureCoordinates(0, 0, newtcoords); + + geometry = obj; + return obj; + } + + + private GeometryArray processTriangleFan() { + if (debug > 0) System.out.println("processTriangleFan"); + + GeometryArray obj = null; + int i; + int totalVerts = 0; + + int stripCounts[] = new int[currPrimCnt]; + + // figure out how many vertices we need to hold the individual fans + for (i = 0; i < currPrimCnt; i++) { + stripCounts[i] = currPrimEndVertex[i] - currPrimStartVertex[i]; + totalVerts += stripCounts[i]; + } + + // figure out what flags we need + int tfFlags = TriangleFanArray.COORDINATES; + if ((flags & Primitive.GENERATE_NORMALS) != 0) { + tfFlags |= TriangleFanArray.NORMALS; + } + if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) { + tfFlags |= TriangleFanArray.TEXTURE_COORDINATE_2; + } + + // create the TriangleFanArray + obj = new TriangleFanArray(totalVerts, tfFlags, 1, texCoordSetMap, + stripCounts); + + // allocate space for vertex info + Point3f[] newpts = new Point3f[totalVerts]; + Vector3f[] newnormals = new Vector3f[totalVerts]; + TexCoord2f[] newtcoords = new TexCoord2f[totalVerts]; + + int currVert = 0; + + // repeat for each fan + for (i = 0; i < currPrimCnt; i++) { + for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i]; j++) { + outVertex(newpts, newnormals, newtcoords, currVert++, pts, + normals, tcoords, j); + } + } + + for (i = 0; i < newpts.length; i++) { + if (debug > 1) System.out.println("i = " + i + " " + newpts[i]); + } + + numVerts = currVert; + numTris = totalVerts - currPrimCnt * 2; + + // set the coordinates on the GeometryArray + obj.setCoordinates(0, newpts); + + // set the normals and tex coords if necessary + if ((flags & Primitive.GENERATE_NORMALS) != 0) { + obj.setNormals(0, newnormals); + } + if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) { + obj.setTextureCoordinates(0, 0, newtcoords); + } + geometry = obj; + return obj; + } + + + + void outVertex(Point3f[] dpts, Vector3f[] dnormals, TexCoord2f[] dtcoords, + int dloc, + Point3f[] spts, Vector3f[] snormals, TexCoord2f[] stcoords, + int sloc) + { + if (debug >= 1) System.out.println("v " + spts[sloc].x + " " + + spts[sloc].y + " " + + spts[sloc].z); + + // PSP: Do we really need new points here? + + dpts[dloc] = new Point3f(spts[sloc]); + + if ((flags & Primitive.GENERATE_NORMALS) != 0){ + dnormals[dloc] = new Vector3f(snormals[sloc]); + } + if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0){ + if (debug >= 2) System.out.println("final out tcoord"); + dtcoords[dloc] = new TexCoord2f(stcoords[sloc]); + } + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfo.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfo.java new file mode 100644 index 0000000..9c78f09 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfo.java @@ -0,0 +1,2826 @@ +/* + * $RCSfile: GeometryInfo.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:19 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.Triangulator; +import java.io.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import com.sun.j3d.internal.J3dUtilsI18N; +import java.util.HashMap; +import com.sun.j3d.utils.geometry.GeometryInfoGenerator; +import com.sun.j3d.internal.BufferWrapper; +import com.sun.j3d.internal.ByteBufferWrapper; +import com.sun.j3d.internal.FloatBufferWrapper; +import com.sun.j3d.internal.DoubleBufferWrapper; +import com.sun.j3d.internal.ByteOrderWrapper; +import javax.media.j3d.J3DBuffer; + +/** + * The GeometryInfo object holds data for processing by the Java3D geometry + * utility tools.

+ * + * The NormalGenerator adds normals to geometry without normals.

+ * + * The Stripifier combines adjacent triangles into triangle strips for + * more efficent rendering.

+ * + * Also, the GeometryCompressor can take a set of GeometryInfo objects in a + * CompressionSteam and generate a CompressedGeometry object from the + * geometry.

+ * Geometry is loaded into a GeometryInfo in a manner similar to the + * + * GeometryArray methods. The constructor for the GeometryInfo takes a flag + * that specifies the kind of data being loaded. The vertex data is + * specified using methods that are similar to the GeometryArray methods, but + * with fewer variations.

+ * The major difference between GeometryInfo and GeometryArray is + * that the number of vertices, vertex format, and other data are specified + * implictly, rather than as part of the constructor. The number of verticies + * comes from the number of coordinates passed to the setCoordinates() + * method. The format comes from the set of data components that are + * specified. For example, calling the setCoordinates(), setColors3() and + * setTextureCoordinatesParames(1, 2) methods implies a + * format of COORDINATES | COLOR_3 + * | TEXTURE_COORDINATE_2. Indexed representation is specified by calling + * the methods that specify the indices, for example + * setCoordinateIndices().

+ * Stripped primitives are loaded using the TRIANGLE_FAN_ARRAY or + * TRIANGLE_STRIP_ARRAY flags to the constructor. The setStripCounts() + * method specifies the length of each strip.

+ * A set of complex polygons is loaded using the POLYGON_ARRAY + * flag to the constructor. The setStripCounts() method specifies the length + * of each contour of the polygons. The setContourCounts() method specifies + * the number of countours in each polygon. For example, a triangle with a + * triangular hole would have strip counts [3, 3] (indicating two contours of + * three points) and contour counts [2] (indicating a single polygon with two + * contours).

+ * GeometryInfo itelf contains some simple utilities, such as + * calculating indices for non-indexed data ("indexifying") and getting rid + * of unused data in your indexed geometry ("compacting").

+ * The geometry utility tools modify the contents of the + * GeometryInfo. After processing, the resulting geometry can be extracted + * from the GeometryInfo by calling getGeometryArray(). If multiple tools + * are used, the order of processing should be: generate normals, then + * stripify. For example, to convert a general mesh of polygons without + * normals into an optimized mesh call: + *

+ * GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY); + * // initialize the geometry info here + * // generate normals + * NormalGenerator ng = new NormalGenerator(); + * ng.generateNormals(gi); + * // stripify + * Stripifier st = new Stripifier(); + * st.stripify(gi); + * GeometryArray result = gi.getGeometryArray(); + *
+ * + * @see NormalGenerator + * @see Stripifier + * @see com.sun.j3d.utils.compression.CompressionStream + * @see com.sun.j3d.utils.compression.GeometryCompressor + * @see javax.media.j3d.GeometryArray + */ + +public class GeometryInfo { + + /** + * Send to the constructor to inform that the data will be arranged so + * that each set of three vertices form an independent triangle + */ + public static final int TRIANGLE_ARRAY = 1; + + /** + * Send to the constructor to inform that the data will be arranged so + * that each set of four vertices form an independent quad + */ + public static final int QUAD_ARRAY = 2; + + /** + * Send to the constructor to inform that the data will be arranged so + * that the stripCounts array indicates how many vertices to use + * for each triangle fan. + */ + public static final int TRIANGLE_FAN_ARRAY = 3; + + /** + * Send to the constructor to inform that the data will be arranged so + * that the stripCounts array indicates how many vertices to use + * for each triangle strip. + */ + public static final int TRIANGLE_STRIP_ARRAY = 4; + + /** + * Send to the constructor to inform that the data is arranged as + * possibly multi-contour, possible non-planar polygons. + * The stripCounts array indicates how many vertices to use + * for each contour, and the contourCounts array indicates how many + * stripCounts entries to use for each polygon. The first + * contour is the bounding polygon, and subsequent contours are + * "holes." If contourCounts is left null, the default is + * one contour per polygon. + */ + public static final int POLYGON_ARRAY = 5; + + private int prim; + + // 1 Show indexification details + private static final int DEBUG = 0; + + private Point3f coordinates[] = null; + private Color3f colors3[] = null; + private Color4f colors4[] = null; + private Vector3f normals[] = null; + private Object texCoordSets[][] = null; + + private int coordinateIndices[] = null; + private int colorIndices[] = null; + private int normalIndices[] = null; + private int texCoordIndexSets[][] = null; + + private int[] texCoordSetMap = null; + private int texCoordSetCount = 0; + private int texCoordDim = 0; + + private int stripCounts[] = null; + private int contourCounts[] = null; + + private Triangulator tr = null; + private NormalGenerator ng = null; + + private int oldPrim = 0; + private int oldStripCounts[] = null; + + private boolean coordOnly = false; + + + + /** + * Constructor. + * Creates an empty GeometryInfo object. + * @param primitive Tells the GeometryInfo object the type of + * primitive data to be stored + * in it, so it will know the format of the data. It can be one of + * TRIANGLE_ARRAY, + * QUAD_ARRAY, TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY. + */ + public GeometryInfo(int primitive) + { + if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) { + prim = primitive; + } else { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo0")); + } + } // End of GeometryInfo(int) + + + + /** + * Contructor. Populates the GeometryInfo with the geometry from + * the GeometryArray.

+ * If the GeometryArray uses the Initial and + * Valid GeometryArray methods ( + * setInitialVertexIndex() and setValidVertexCount() + * and their cousins) then only the needed geometry + * is copied into the GeometryInfo. + */ + public GeometryInfo(GeometryArray ga) + { + GeometryInfoGenerator.create(this, ga); + } // End of GeometryInfo(GeometryArray) + + + + /** + * Removes all data from the GeometryInfo and resets the primitive. + * After a call to reset(), the GeometryInfo object will be just like + * it was when it was newly constructed. + * @param primitive Either TRIANGLE_ARRAY, QUAD_ARRAY, + * TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY. + * Tells the GeometryInfo object the type of primitive data to be stored + * in it, so it will know the format of the data. + */ + public void reset(int primitive) + { + if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) { + prim = primitive; + } else { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo0")); + } + + coordinates = null; + colors3 = null; + colors4 = null; + normals = null; + + coordinateIndices = null; + colorIndices = null; + normalIndices = null; + + stripCounts = null; + contourCounts = null; + + oldPrim = 0; + oldStripCounts = null; + + texCoordDim = 0; + texCoordSetCount = 0; + texCoordSets = null; + texCoordIndexSets = null; + texCoordSetMap = null; + + coordOnly = false; + + } // End of reset(int) + + + + /** + * Removes all data from this GeometryInfo and populates it with + * the geometry from the GeometryArray. + */ + public void reset(GeometryArray ga) + { + GeometryInfoGenerator.create(this, ga); + } // End of reset(GeometryArray) + + + + // This method takes an indexed quad array and expands it to + // a list of indexed triangles. It is used for the Coordinate + // indices as well as the color and texture indices. + private int[] expandQuad(int indices[]) + { + int triangles[] = new int[indices.length / 4 * 6]; + + for (int i = 0 ; i < indices.length / 4 ; i++ ) { + triangles[i * 6 + 0] = indices[i * 4]; + triangles[i * 6 + 1] = indices[i * 4 + 1]; + triangles[i * 6 + 2] = indices[i * 4 + 2]; + triangles[i * 6 + 3] = indices[i * 4]; + triangles[i * 6 + 4] = indices[i * 4 + 2]; + triangles[i * 6 + 5] = indices[i * 4 + 3]; + } + + return triangles; + } // End of expandQuad + + + + // This method takes an indexed triangle fan and expands it to + // a list of indexed triangles. It is used for the Coordinate + // indices as well as the color and texture indices. + private int[] expandTriFan(int numTris, int indices[]) + { + int triangles[] = new int[numTris * 3]; + int p = 0; + int base = 0; + for (int f = 0 ; f < stripCounts.length ; f++) { + for (int t = 0 ; t < stripCounts[f] - 2 ; t++) { + triangles[p++] = indices[base]; + triangles[p++] = indices[base + t + 1]; + triangles[p++] = indices[base + t + 2]; + } + base += stripCounts[f]; + } + return triangles; + } // End of expandTriFan + + + + // This method takes an indexed triangle strip and expands it to + // a list of indexed triangles. It is used for the Coordinate + // indices as well as the color and texture indices. + private int[] expandTriStrip(int numTris, int indices[]) + { + int triangles[] = new int[numTris * 3]; + + int p = 0; + int base = 0; + for (int s = 0 ; s < stripCounts.length ; s++) { + for (int t = 0 ; t < stripCounts[s] - 2 ; t++) { + + // Use a ping-ponging algorithm to reverse order on every other + // triangle to preserve winding + if (t % 2 == 0) { + triangles[p++] = indices[base + t + 0]; + triangles[p++] = indices[base + t + 1]; + triangles[p++] = indices[base + t + 2]; + } else { + triangles[p++] = indices[base + t + 0]; + triangles[p++] = indices[base + t + 2]; + triangles[p++] = indices[base + t + 1]; + } + } + base += stripCounts[s]; + } + + return triangles; + } // End of expandTriStrip + + + + // Used by the NormalGenerator utility. Informs the GeometryInfo object + // to remember its current primitive and stripCounts arrays so that + // they can be used to convert the object back to its original + // primitive + void rememberOldPrim() + { + oldPrim = prim; + oldStripCounts = stripCounts; + } // End of rememberOldPrim + + + + // The NormalGenerator needs to know the original primitive for + // facet normal generation for quads + int getOldPrim() + { + return oldPrim; + } // End of getOldPrim + + + + // Used by the Utility libraries other than the NormalGenerator. + // Informs the GeometryInfo object that the geometry need not + // be converted back to the original primitive before returning. + // For example, if a list of Fans is sent, converted to Triangles + // for normal generation, and then stripified by the Stripifyer, + // we want to make sure that GeometryInfo doesn't convert the + // geometry *back* to fans before creating the output GeometryArray. + void forgetOldPrim() + { + oldPrim = 0; + oldStripCounts = null; + } // End of forgetOldPrim + + + + // We have changed the user's data from their original primitive + // type to TRIANGLE_ARRAY. If this method is being called, it + // means we need to change it back (to try and hide from the user + // the fact that we've converted). This usually happens when + // the user has used GeometryInfo for generating normals, but + // they are not Stripifying or Triangulating. The function is + // called from getGeometryArray before creating the output data. + private void changeBackToOldPrim() + { + if (oldPrim != 0) { + convertToIndexedTriangles(); + if (ng == null) ng = new NormalGenerator(); + ng.convertBackToOldPrim(this, oldPrim, oldStripCounts); + oldPrim = 0; + oldStripCounts = null; + } + } // End of changeBackToOldPrim + + + + /** + * Convert the GeometryInfo object to have primitive type TRIANGLE_ARRAY + * and be indexed. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public void convertToIndexedTriangles() + { + int triangles = 0; + + // This calls checkForBadData + indexify(); + + if (prim == TRIANGLE_ARRAY) return; + + switch(prim) { + + case QUAD_ARRAY: + + coordinateIndices = expandQuad(coordinateIndices); + if (colorIndices != null) colorIndices = expandQuad(colorIndices); + if (normalIndices != null) + normalIndices = expandQuad(normalIndices); + for (int i = 0 ; i < texCoordSetCount ; i++) + texCoordIndexSets[i] = expandQuad(texCoordIndexSets[i]); + break; + + case TRIANGLE_FAN_ARRAY: + // Count how many triangles are in the object + for (int i = 0 ; i < stripCounts.length ; i++) { + triangles += stripCounts[i] - 2; + } + + coordinateIndices = expandTriFan(triangles, coordinateIndices); + if (colorIndices != null) + colorIndices = expandTriFan(triangles, colorIndices); + if (normalIndices != null) + normalIndices = expandTriFan(triangles, normalIndices); + for (int i = 0 ; i < texCoordSetCount ; i++) + texCoordIndexSets[i] = expandTriFan(triangles, + texCoordIndexSets[i]); + break; + + case TRIANGLE_STRIP_ARRAY: + // Count how many triangles are in the object + for (int i = 0 ; i < stripCounts.length ; i++) { + triangles += stripCounts[i] - 2; + } + + coordinateIndices = expandTriStrip(triangles, coordinateIndices); + if (colorIndices != null) + colorIndices = expandTriStrip(triangles, colorIndices); + if (normalIndices != null) + normalIndices = expandTriStrip(triangles, normalIndices); + for (int i = 0 ; i < texCoordSetCount ; i++) + texCoordIndexSets[i] = expandTriStrip(triangles, + texCoordIndexSets[i]); + break; + + case POLYGON_ARRAY: + if (tr == null) tr = new Triangulator(); + tr.triangulate(this); + break; + } + + prim = TRIANGLE_ARRAY; + stripCounts = null; + } // End of convertToIndexedTriangles + + + + /** + * Get the current primitive. Some of the utilities may change the + * primitive type of the data stored in the GeometryInfo object + * (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY). + */ + public int getPrimitive() + { + return prim; + } // End of getPrimitive() + + + + /** + * Set the current primitive. Some of the utilities may change the + * primitive type of the data stored in the GeometryInfo object + * (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY). + * But the user can't change the primitive type - it is set in the + * constructor. Therefore, this method has package scope. + */ + void setPrimitive(int primitive) + { + if ((prim >= TRIANGLE_ARRAY) && (prim <= POLYGON_ARRAY)) { + prim = primitive; + } else { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo0")); + } + } // End of setPrimitive() + + + + /** + * Sets the coordinates array. + * No data copying is done because a reference to user data is used. + */ + public void setCoordinates(Point3f coordinates[]) + { + this.coordinates = coordinates; + } // End of setCoordinates + + + + /** + * Sets the coordinates array. + * The points are copied into the GeometryInfo object. + */ + public void setCoordinates(Point3d coordinates[]) + { + if (coordinates == null) this.coordinates = null; + else { + this.coordinates = new Point3f[coordinates.length]; + for (int i = 0 ; i < coordinates.length ; i++) { + this.coordinates[i] = new Point3f( + (float)(coordinates[i].x), + (float)(coordinates[i].y), + (float)(coordinates[i].z)); + } + } + } // End of setCoordinates + + + + /** + * Sets the coordinates array. + * The points are copied into the GeometryInfo object. + */ + public void setCoordinates(float coordinates[]) + { + if (coordinates == null) this.coordinates = null; + else { + this.coordinates = new Point3f[coordinates.length / 3]; + for (int i = 0 ; i < this.coordinates.length ; i++) { + this.coordinates[i] = new Point3f(coordinates[i * 3], + coordinates[i * 3 + 1], + coordinates[i * 3 + 2]); + } + } + } // End of setCoordinates + + + + /** + * Sets the coordinates array. + * The points are copied into the GeometryInfo object. + */ + public void setCoordinates(double coordinates[]) + { + if (coordinates == null) this.coordinates = null; + else { + this.coordinates = new Point3f[coordinates.length / 3]; + for (int i = 0 ; i < coordinates.length / 3 ; i++) { + this.coordinates[i] = new Point3f((float)coordinates[i * 3], + (float)coordinates[i * 3 + 1], + (float)coordinates[i * 3 + 2]); + } + } + } // End of setCoordinates + + + + /** + * Retrieves a reference to the coordinate array. + */ + public Point3f[] getCoordinates() + { + return coordinates; + } // End of getCoordinates + + + + /** + * Sets the colors array. + * No data copying is done because a reference to + * user data is used. + */ + public void setColors(Color3f colors[]) + { + colors3 = colors; + colors4 = null; + } // End of setColors + + + + /** + * Sets the colors array. + * No data copying is done because a reference to + * user data is used. + */ + public void setColors(Color4f colors[]) + { + colors3 = null; + colors4 = colors; + } // End of setColors + + + + /** + * Sets the colors array. + * The points are copied into the GeometryInfo object. + */ + public void setColors(Color3b colors[]) + { + if (colors == null) { + colors3 = null; + colors4 = null; + } else { + colors3 = new Color3f[colors.length]; + colors4 = null; + for (int i = 0 ; i < colors.length ; i++) { + colors3[i] = new Color3f((float) (colors[i].x & 0xff) / 255.0f, + (float) (colors[i].y & 0xff) / 255.0f, + (float) (colors[i].z & 0xff) / 255.0f); + } + } + } // End of setColors + + + + /** + * Sets the colors array. + * The points are copied into the GeometryInfo object. + */ + public void setColors(Color4b colors[]) + { + if (colors == null) { + colors3 = null; + colors4 = null; + } else { + colors3 = null; + colors4 = new Color4f[colors.length]; + for (int i = 0 ; i < colors.length ; i++) { + colors4[i] = new Color4f((float) (colors[i].x & 0xff) / 255.0f, + (float) (colors[i].y & 0xff) / 255.0f, + (float) (colors[i].z & 0xff) / 255.0f, + (float) (colors[i].w & 0xff) / 255.0f); + } + } + } // End of setColors + + + + /** + * Sets the colors array. + * The points are copied into the GeometryInfo object, assuming + * 3 components (R, G, and B) per vertex. + */ + public void setColors3(float colors[]) + { + if (colors == null) { + colors3 = null; + colors4 = null; + } else { + colors3 = new Color3f[colors.length / 3]; + colors4 = null; + for (int i = 0 ; i < colors.length / 3 ; i++) { + colors3[i] = new Color3f(colors[i * 3], + colors[i * 3 + 1], + colors[i * 3 + 2]); + } + } + } // End of setColors3 + + + + /** + * Sets the colors array. + * The points are copied into the GeometryInfo object, assuming + * 4 components (R, G, B, and A) per vertex. + */ + public void setColors4(float colors[]) + { + if (colors == null) { + colors3 = null; + colors4 = null; + } else { + colors3 = null; + colors4 = new Color4f[colors.length / 4]; + for (int i = 0 ; i < colors.length / 4 ; i++) { + colors4[i] = new Color4f(colors[i * 4], + colors[i * 4 + 1], + colors[i * 4 + 2], + colors[i * 4 + 3]); + } + } + } // End of setColors4 + + + + /** + * Sets the colors array. + * The points are copied into the GeometryInfo object, assuming + * 3 components (R, G, and B) per vertex. + */ + public void setColors3(byte colors[]) + { + if (colors == null) { + colors3 = null; + colors4 = null; + } else { + colors3 = new Color3f[colors.length / 3]; + colors4 = null; + for (int i = 0 ; i < colors.length / 3 ; i++) { + colors3[i] = + new Color3f((float)(colors[i * 3] & 0xff) / 255.0f, + (float)(colors[i * 3 + 1] & 0xff) / 255.0f, + (float)(colors[i * 3 + 2] & 0xff) / 255.0f); + } + } + } // End of setColors3 + + + + /** + * Sets the colors array. + * The points are copied into the GeometryInfo object, assuming + * 4 components (R, G, B, and A) per vertex. + */ + public void setColors4(byte colors[]) + { + if (colors == null) { + colors3 = null; + colors4 = null; + } else { + colors3 = null; + colors4 = new Color4f[colors.length / 4]; + for (int i = 0 ; i < colors.length / 4 ; i++) { + colors4[i] = + new Color4f((float)(colors[i * 4] & 0xff) / 255.0f, + (float)(colors[i * 4 + 1] & 0xff) / 255.0f, + (float)(colors[i * 4 + 2] & 0xff) / 255.0f, + (float)(colors[i * 4 + 3] & 0xff) / 255.0f); + } + } + } // End of setColors4 + + + + /** + * Retrieves a reference to the colors array. Will be either + * Color3f[] or Color4f[] depending on + * the type of the input data. Call + * getNumColorComponents() to find out which version is returned. + */ + public Object[] getColors() + { + if (colors3 != null) return colors3; + else return colors4; + } // End of getColors + + + + /** + * Returns the number of color data components stored per vertex + * in the current GeometryInfo object (3 for RGB or 4 for RGBA). + * If no colors are currently defined, 0 is returned. + */ + public int getNumColorComponents() + { + if (colors3 != null) return 3; + else if (colors4 != null) return 4; + else return 0; + } // End of getNumColorComponents + + + + /** + * Sets the normals array. + * No data copying is done because a reference to + * user data is used. + */ + public void setNormals(Vector3f normals[]) + { + this.normals = normals; + } // End of setNormals + + + + /** + * Sets the normals array. + * The points are copied into the GeometryInfo object. + */ + public void setNormals(float normals[]) + { + if (normals == null) this.normals = null; + else { + this.normals = new Vector3f[normals.length / 3]; + for (int i = 0 ; i < this.normals.length ; i++) { + this.normals[i] = new Vector3f(normals[i * 3], + normals[i * 3 + 1], + normals[i * 3 + 2]); + } + } + } // End of setNormals(float[]) + + + + /** + * Retrieves a reference to the normal array. + */ + public Vector3f[] getNormals() + { + return normals; + } // End of getNormals + + + + /** + * This method is used to specify the number of texture coordinate sets + * and the dimensionality of the texture coordinates. + * The number of texture coordinate sets must be specified to the GeometryInfo + * class before any of the sets are specified. The dimensionality of the + * texture coordinates may be 2, 3, or 4, corresponding to 2D, 3D, or 4D + * texture coordinates respectively.(All sets must have the same + * dimensionality.) The default is zero, 2D texture coordinate sets. + * This method should be called before any texture coordinate sets are + * specified because calling this method will delete all previously + * specified texture coordinate and texture coordinate index arrays + * associated with this GeometryInfo. For example: + *

+   *	geomInfo.setTextureCoordinateParams(2, 3);
+   *	geomInfo.setTextureCoordinates(0, tex0);
+   *	geomInfo.setTextureCoordinates(1, tex1);
+   *	geomInfo.setTextureCoordinateParams(1, 2);
+   *	geomInfo.getTexCoordSetCount();
+   * 
+ * The second call to setTextureCoordinateParams will erase all + * the texture coordinate arrays, so the subsequent call to + * getTexCoordSetCount will return 1. + * @param numSets The number of texture coordinate sets that will be + * specified for this GeometryInfo object. + * @param dim The dimensionality of the texture coordinates. Has to be 2, 3 + * or 4. + * @throws IllegalArgumentException if the dimensionality of the texture + * coordinates is not one of 2, 3 or 4. + */ + public void setTextureCoordinateParams(int numSets, int dim) + { + if (dim == 2) { + texCoordSets = new TexCoord2f[numSets][]; + } else if (dim == 3) { + texCoordSets = new TexCoord3f[numSets][]; + } else if (dim == 4) { + texCoordSets = new TexCoord4f[numSets][]; + } else { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo9")); + } + texCoordIndexSets = new int[numSets][]; + texCoordDim = dim; + texCoordSetCount = numSets; + } // End of setTextureCoordinateParams + + + + /** + * Returns the number of texture coordinate sets in this GeometryInfo. + * This value is set with setTextureCoordinateParams(). + * If setTextureCoordinateParams() + * has not been called, 0 is returned unless one of the deprecated + * texture coordinate methods has been called. Calling one of the + * deprecated texture coordinate methods sets the count to 1. + * The deprecated texture coordinate methods are those that don't + * take texCoordSet as the first parameter. + * @return the number of texture coordinate sets in this + * GeometryInfo. + */ + public int getTexCoordSetCount() { + return texCoordSetCount; + } + + + + /** + * Returns the number of texture coordinate components that are stored + * per vertex. Returns 2 for ST (2D), 3 for STR (3D), + * or 4 for STRQ (4D), aslo known as the "dimensionality" of the + * coordinates. This value is set with + * setTextureCoordinateParams(). If setTextureCoordinateParams() + * has not been called, 0 is returned unless one of the deprecated + * texture coordinate methods has been called. Calling one of the + * deprecated texture coordinate methods sets the dimensionality + * explicitly (if you called setTextureCoordinates(Point2f[]) then + * 2 is returned). + * The deprecated texture coordinate methods are those that don't + * take texCoordSet as the first parameter. + */ + public int getNumTexCoordComponents() + { + return texCoordDim; + } // End of getNumTexCoordComponents + + + + /** + * Sets the mapping between texture coordinate sets and texture units. + * See the + * + * GeometryArray constructor for further details. + *

Note: If the texCoordSetMap is not set, multi-texturing is + * turned off. Only the texture coordinate set at index 0 (if set) will be + * used. Any other sets specified by the GeometryInfo.setTextureCoordinate* + * methods will be ignored. + */ + public void setTexCoordSetMap(int map[]) { + texCoordSetMap = map; + } + + + + /** + * Returns a reference to the texture coordinate set map. + * See the + * + * GeometryArray constructor for further details. + */ + public int[] getTexCoordSetMap() { + return texCoordSetMap; + } + + + + /** + * Sets the 2D texture coordinates for the specified set. + * No data copying is done - a reference to user data is used. + * @param texCoordSet The texture coordinate set for which these + * coordinates are being specified. + * @param texCoords Array of 2D texture coordinates. + * @throws IllegalArgumentException if texCoordSet < 0 or + * texCoordSet >= texCoordSetCount, + * or the texture coordinate parameters were not previously set by + * calling setTextureCoordinateParams(texCoordSetCount, 2). + */ + public void setTextureCoordinates(int texCoordSet, TexCoord2f texCoords[]) + { + if (texCoordDim != 2) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo15")); + if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0)) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo18")); + + texCoordSets[texCoordSet] = texCoords; + } // End of setTextureCoordinates(int, TexCoord3f[]) + + + + /** + * Sets the TextureCoordinates array by copying the data + * into the GeometryInfo object. + * This method sets the number of texture coordinate sets to 1, + * sets the dimensionality of the texture coordinates to 2, + * and sets the coordinates for texture coordinate set 0. + * @deprecated As of Java 3D 1.3 replaced by + * setTextureCoordinates(int texCoordSet, TexCoord2f coords[]) + */ + public void setTextureCoordinates(Point2f texCoords[]) + { + texCoordSetCount = 1; + texCoordDim = 2; + texCoordSets = new TexCoord2f[1][]; + if (texCoords != null) { + TexCoord2f[] tex = new TexCoord2f[texCoords.length]; + for (int i = 0 ; i < texCoords.length ; i++) + tex[i] = new TexCoord2f(texCoords[i]); + texCoordSets[0] = tex; + } + } // End of setTextureCoordinates(Point2f[]) + + + + /** + * Sets the texture coordinates array for the specified set. + * No data copying is done - a reference to user data is used. + * @param texCoordSet The texture coordinate set for which these coordinates + * are being specified. + * @param texCoords Array of 3D texture coordinates. + * @throws IllegalArgumentException if texCoordSet < 0 or + * texCoordSet >= texCoordSetCount, + * or the texture coordinate parameters were not previously set by + * calling setTextureCoordinateParams(texCoordSetCount, 3). + */ + public void setTextureCoordinates(int texCoordSet, TexCoord3f texCoords[]) + { + if (texCoordDim != 3) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo16")); + if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0)) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo18")); + + texCoordSets[texCoordSet] = texCoords; + } // End of setTextureCoordinates(int, TexCoord3f[]) + + + + /** + * Sets the TextureCoordinates array by copying the data + * into the GeometryInfo object. + * This method sets the number of texture coordinate sets to 1, + * sets the dimensionality of the texture coordinates to 3, + * and sets the coordinates for texture coordinate set 0. + * @deprecated As of Java 3D 1.3 replaced by + * setTextureCoordinates(int texCoordSet, TexCoord3f coords[]) + */ + public void setTextureCoordinates(Point3f texCoords[]) + { + texCoordSetCount = 1; + texCoordDim = 3; + texCoordSets = new TexCoord3f[1][]; + if (texCoords != null) { + TexCoord3f[] tex = new TexCoord3f[texCoords.length]; + for (int i = 0 ; i < texCoords.length ; i++) + tex[i] = new TexCoord3f(texCoords[i]); + texCoordSets[0] = tex; + } + } // End of setTextureCoordinates(Point3f[]) + + + + /** + * Sets the texture coordinates array for the specified set. + * No data copying is done - a reference to user data is used. + * @param texCoordSet The texture coordinate set for which these coordinates + * are being specified. + * @param texCoords Array of 4D texture coordinates. + * @throws IllegalArgumentException if texCoordSet < 0 or + * texCoordSet >= texCoordSetCount, + * or the texture coordinate parameters were not previously set by + * calling setTextureCoordinateParams(texCoordSetCount, 4). + */ + public void setTextureCoordinates(int texCoordSet, TexCoord4f texCoords[]) { + if (texCoordDim != 4) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo17")); + if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0)) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo18")); + + texCoordSets[texCoordSet] = texCoords; + } // End of setTextureCoordinates(int, TexCoord4f[]) + + + + /** + * Sets the texture coordinates array by copying the data into the + * GeometryInfo object. The number of sets and dimensionality of + * the sets must have been set previously with + * setTextureCoordinateParams(texCoordSetCount, dim). + * @param texCoordSet The texture coordinate set for which these coordinates + * are being specified. + * @param texCoords The float array of texture coordinates. For n texture + * coordinates with dimensionality d, there must be d*n floats in the array. + * @throws IllegalArgumentException if texCoordSet < 0 or + * texCoordSet >= texCoordSetCount, + * or the texture coordinate parameters were not previously set by + * calling setTextureCoordinateParams. + */ + public void setTextureCoordinates(int texCoordSet, float texCoords[]) + { + if ((texCoords.length % texCoordDim) != 0) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo2")); + + // Copy the texCoords into this GeometryInfo object + if (texCoordDim == 2) { + TexCoord2f tcoords[] = new TexCoord2f[texCoords.length / 2]; + for (int i = 0 ; i < tcoords.length ; i++) + tcoords[i] = new TexCoord2f(texCoords[i * 2], + texCoords[i * 2 + 1]); + setTextureCoordinates(texCoordSet, tcoords); + } else if (texCoordDim == 3) { + TexCoord3f tcoords[] = new TexCoord3f[texCoords.length / 3]; + for (int i = 0 ; i < tcoords.length ; i++) + tcoords[i] = new TexCoord3f(texCoords[i * 3], + texCoords[i * 3 + 1], + texCoords[i * 3 + 2]); + setTextureCoordinates(texCoordSet, tcoords); + } else if (texCoordDim == 4) { + TexCoord4f tcoords[] = new TexCoord4f[texCoords.length / 4]; + for (int i = 0 ; i < tcoords.length ; i++) + tcoords[i] = new TexCoord4f(texCoords[i * 4], + texCoords[i * 4 + 1], + texCoords[i * 4 + 2], + texCoords[i * 4 + 3]); + setTextureCoordinates(texCoordSet, tcoords); + } else { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo21")); + } + } // End of setTextureCoordinates(int, float[]) + + + + /** + * Sets the texture coordinates array by copying the data + * into the GeometryInfo object, assuming two numbers + * (S and T) per vertex. + * This method sets the number of texture coordinate sets to 1, + * sets the dimensionality of the texture coordinates to 2, + * and sets the coordinates for texture coordinate set 0. + * @deprecated As of Java 3D 1.3 replaced by + * setTextureCoordinates(int texCoordSet, float texCoords[]) + */ + public void setTextureCoordinates2(float texCoords[]) + { + texCoordSetCount = 1; + texCoordDim = 2; + texCoordSets = new TexCoord2f[1][]; + setTextureCoordinates(0, texCoords); + } // End of setTextureCoordinates2(float[]) + + + + /** + * Sets the TextureCoordinates array by copying the data + * into the GeometryInfo object, assuming three numbers + * (S, T, & R) per vertex. + * This method sets the number of texture coordinate sets to 1, + * sets the dimensionality of the texture coordinates to 3, + * and sets the coordinates for texture coordinate set 0. + * @deprecated As of Java 3D 1.3 replaced by + * setTextureCoordinates(int texCoordSet, float texCoords[]) + */ + public void setTextureCoordinates3(float texCoords[]) + { + texCoordSetCount = 1; + texCoordDim = 3; + texCoordSets = new TexCoord3f[1][]; + setTextureCoordinates(0, texCoords); + } // End of setTextureCoordinates3(float[]) + + + + /** + * Returns a reference to the indicated texture coordinate array. + * The return type will be TexCoord2f[], TexCoord3f[] + * , or TexCoord4f[] depending on the + * current dimensionality of the texture coordinates in the GeometryInfo + * object. Use getNumTexCoordComponents() to find out which + * version is returned. + * @param texCoordSet The index of the texture coordinate set to + * retrieve. + * @return An array of texture coordinates at the specified index + * @throws IllegalArgumentException If texCoordSet < 0 + * or texCoordSet >= texCoordSetCount + */ + public Object[] getTextureCoordinates(int texCoordSet) + { + if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0)) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo18")); + return texCoordSets[texCoordSet]; + } // End of getTextureCoordinates(int) + + + + /** + * Retrieves a reference to texture coordinate set 0. + * The return type will be TexCoord2f[], TexCoord3f[] + * , or TexCoord4f[] depending on the + * current dimensionality of the texture coordinates in the GeometryInfo + * object. Use getNumTexCoordComponents() to find out which + * version is returned. Equivalent to getTextureCoordinates(0). + * @return An array of texture coordinates for set 0. + * @deprecated As of Java 3D 1.3 replaced by + * getTextureCoordinates(int texCoordSet) + */ + public Object[] getTextureCoordinates() + { + return texCoordSets[0]; + } // End of getTextureCoordinates() + + + + /** + * Sets the array of indices into the Coordinate array. + * No data copying is done - a reference to user data is used. + */ + public void setCoordinateIndices(int coordinateIndices[]) + { + this.coordinateIndices = coordinateIndices; + } // End of setCoordinateIndices + + + + /** + * Retrieves a reference to the array of indices into the + * coordinate array.

+ * + * This method should be considered for advanced users only. + * Novice users should just use getGeometryArray() to retrieve + * their data so that the internal format of GeometryInfo is + * of no concern.

+ * + * Depending on which of the utility routines you've called + * on your GeometryInfo object, the results may not be what you + * expect. If you've called the Stripifier, your GeometryInfo + * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY + * and your data will be formatted accordingly. Similarly, if + * you've called the Triangulator, your data is in indexed + * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator + * utility will convert your data to indexed TRIANGLE_ARRAY also, + * but if you call getGeometryArray without calling the Stripifier or + * Triangulator, your data will be converted back to the original + * primitive type when creating the GeometryArray object to pass + * back. However, if your creaseAngle was not Math.PI (no creases - + * smooth shading), then the introduction of + * creases into your model may have split primitives, lengthening + * the StripCounts and index arrays from your original data. + */ + public int[] getCoordinateIndices() + { + return coordinateIndices; + } // End of getCoordinateIndices + + + + /** + * Sets the array of indices into the Color array. + * No data copying is done - a reference to user data is used. + */ + public void setColorIndices(int colorIndices[]) + { + this.colorIndices = colorIndices; + } // End of setColorIndices + + + + /** + * Retrieves a reference to the array of indices into the + * color array.

+ * + * This method should be considered for advanced users only. + * Novice users should just use getGeometryArray() to retrieve + * their data so that the internal format of GeometryInfo is + * of no concern.

+ * + * Depending on which of the utility routines you've called + * on your GeometryInfo object, the results may not be what you + * expect. If you've called the Stripifier, your GeometryInfo + * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY + * and your data will be formatted accordingly. Similarly, if + * you've called the Triangulator, your data is in indexed + * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator + * utility will convert your data to indexed TRIANGLE_ARRAY also, + * but if you call getGeometryArray without calling the Stripifier or + * Triangulator, your data will be converted back to the original + * primitive type when creating the GeometryArray object to pass + * back. However, if your creaseAngle was not Math.PI (no creases - + * smooth shading), then the introduction of + * creases into your model may have split primitives, lengthening + * the StripCounts and index arrays from your original data. + */ + public int[] getColorIndices() + { + return colorIndices; + } // End of getColorIndices + + + + /** + * Sets the array of indices into the Normal array. + * No data copying is done - a reference to user data is used. + */ + public void setNormalIndices(int normalIndices[]) + { + this.normalIndices = normalIndices; + + } // End of setNormalIndices + + + + /** + * Retrieves a reference to the array of indices into the + * Normal array.

+ * + * This method should be considered for advanced users only. + * Novice users should just use getGeometryArray() to retrieve + * their data so that the internal format of GeometryInfo is + * of no concern.

+ * + * Depending on which of the utility routines you've called + * on your GeometryInfo object, the results may not be what you + * expect. If you've called the Stripifier, your GeometryInfo + * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY + * and your data will be formatted accordingly. Similarly, if + * you've called the Triangulator, your data is in indexed + * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator + * utility will convert your data to indexed TRIANGLE_ARRAY also, + * but if you call getGeometryArray without calling the Stripifier or + * Triangulator, your data will be converted back to the original + * primitive type when creating the GeometryArray object to pass + * back. However, if your creaseAngle was not Math.PI (no creases - + * smooth shading), then the introduction of + * creases into your model may have split primitives, lengthening + * the StripCounts and index arrays from your original data. + */ + public int[] getNormalIndices() + { + return normalIndices; + } // End of getNormalIndices + + + + /** + * Sets one of the texture coordinate index arrays. + * No data copying is done - a reference to user data is used. + * @param texCoordSet The texture coordinate set for which these coordinate + * indices are being specified. + * @param texIndices The integer array of indices into the specified texture + * coordinate set + * @throws IllegalArgumentException If texCoordSet < 0 or + * texCoordSet >= texCoordSetCount. + */ + public void setTextureCoordinateIndices(int texCoordSet, int texIndices[]) + { + if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0)) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo18")); + + // Texture coordinates are indexed + texCoordIndexSets[texCoordSet] = texIndices; + } // End of setTextureCoordinateIndices(int, int[]) + + + + /** + * Sets the array of indices into texture coordinate set 0. Do not + * call this method if you are using more than one set of texture + * coordinates. + * No data is copied - a reference to the user data is used. + * @deprecated As of Java 3D 1.3 replaced by + * setTextureCoordinateIndices(int texCoordSet, int indices[]) + * @throws IllegalArgumentException If texCoordSetCount > 1. + */ + public void setTextureCoordinateIndices(int texIndices[]) + { + if (texCoordSetCount > 1) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo1")); + texCoordIndexSets = new int[1][]; + texCoordIndexSets[0] = texIndices; + } // End of setTextureCoordinateIndices(int[]) + + + + /** + * Retrieves a reference to the specified array of texture + * coordinate indices.

+ * + * This method should be considered for advanced users only. + * Novice users should just use getGeometryArray() to retrieve + * their data so that the internal format of GeometryInfo is + * of no concern.

+ * + * Depending on which of the utility routines you've called + * on your GeometryInfo object, the results may not be what you + * expect. If you've called the Stripifier, your GeometryInfo + * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY + * and your data will be formatted accordingly. Similarly, if + * you've called the Triangulator, your data is in indexed + * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator + * utility will convert your data to indexed TRIANGLE_ARRAY also, + * but if you call getGeometryArray without calling the Stripifier or + * Triangulator, your data will be converted back to the original + * primitive type when creating the GeometryArray object to pass + * back. However, if your creaseAngle was not Math.PI (no creases - + * smooth shading), then the introduction of + * creases into your model may have split primitives, lengthening + * the StripCounts and index arrays from your original data. + * @param texCoordSet The texture coordinate index set to be + * retrieved. + * @return Integer array of the texture coordinate indices for the specified + * set. + */ + public int[] getTextureCoordinateIndices(int texCoordSet) { + return texCoordIndexSets[texCoordSet]; + } + + + /** + * Returns a reference to texture coordinate index set 0. + * Equivalent to + * getTextureCoordinateIndices(0). + * @deprecated As of Java 3D 1.3 replaced by + * int[] getTextureCoordinateIndices(int texCoordSet) + * @return Integer array of the texture coordinate indices for set 0 + */ + public int[] getTextureCoordinateIndices() + { + if (texCoordIndexSets == null) return null; + return texCoordIndexSets[0]; + } // End of getTextureCoordinateIndices() + + + + /** + * Sets the array of strip counts. If index lists have been set for + * this GeomteryInfo object then the data is indexed and the stripCounts + * are like stripIndexCounts. If no index lists have been set then + * the data is non-indexed and the stripCounts are like + * stripVertexCounts. + * @see GeometryStripArray#GeometryStripArray(int, int, + * int[] stripVertexCounts) + * @see IndexedGeometryStripArray#IndexedGeometryStripArray(int, int, int, + * int[] stripIndexCounts) + */ + public void setStripCounts(int stripCounts[]) + { + this.stripCounts = stripCounts; + } // End of setStripCounts + + + + /** + * Retrieves a reference to the array of stripCounts.

+ * + * This method should be considered for advanced users only. + * Novice users should just use getGeometryArray() to retrieve + * their data so that the internal format of GeometryInfo is + * of no concern.

+ * + * Depending on which of the utility routines you've called + * on your GeometryInfo object, the results may not be what you + * expect. If you've called the Stripifier, your GeometryInfo + * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY + * and your data will be formatted accordingly. Similarly, if + * you've called the Triangulator, your data is in indexed + * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator + * utility will convert your data to indexed TRIANGLE_ARRAY also, + * but if you call getGeometryArray without calling the Stripifier or + * Triangulator, your data will be converted back to the original + * primitive type when creating the GeometryArray object to pass + * back. However, if your creaseAngle was not Math.PI (no creases - + * smooth shading), then the introduction of + * creases into your model may have split primitives, lengthening + * the StripCounts and index arrays from your original data. + */ + public int[] getStripCounts() + { + return stripCounts; + } // End of getStripCounts + + + + /** + * Sets the list of contour counts. Only used with the POLYGON_ARRAY + * primitive. Polygons can be made of several vertex lists + * called contours. The first list is the polygon, and + * subsequent lists are "holes" that are removed from the + * polygon. All of the holes must be contained entirely + * within the polygon. + */ + public void setContourCounts(int contourCounts[]) + { + this.contourCounts = contourCounts; + } // End of setContourCounts + + + + /** + * Retrieves a reference to the array of contourCounts. + */ + public int[] getContourCounts() + { + return contourCounts; + } // End of getContourCounts + + + + /* + * This routine will return an index list for any array of objects. + */ + int[] getListIndices(Object list[]) + { + // Create list of indices to return + int indices[] = new int[list.length]; + + // Create hash table with initial capacity equal to the number + // of components (assuming about half will be duplicates) + HashMap table = new HashMap(list.length); + + Integer idx; + for (int i = 0 ; i < list.length ; i++) { + + // Find index associated with this object + idx = (Integer)table.get(list[i]); + + if (idx == null) { + // We haven't seen this object before + indices[i] = i; + + // Put into hash table and remember the index + table.put(list[i], new Integer(i)); + + } else { + // We've seen this object + indices[i] = idx.intValue(); + } + } + + return indices; + } // End of getListIndices + + + + // Class to hash 'size' integers + private class IndexRow { + int[] val; + int size; + private static final int HASHCONST = 0xBABEFACE; + + public int hashCode() + { + int bits = 0; + for (int i = 0 ; i < size ; i++) { + bits ^= (bits * HASHCONST) << 2; + } + return bits; + } // End of IndexRow.hashCode + + public boolean equals(Object obj) + { + for (int i = 0 ; i < size ; i++) { + if (((IndexRow)obj).get(i) != val[i]) return false; + } + return true; + } // End of IndexRow.equals() + + public int get(int index) + { + return val[index]; + } // End of IndexRow.get + + public void set(int index, int value) + { + val[index] = value; + } // End of IndexRow.set + + IndexRow(int numColumns) + { + size = numColumns; + val = new int[size]; + } // End of IndexRow constructor + } // End of class IndexRow + + + + /** + * Create index lists for all data lists. + * Identical data entries are guaranteed to + * use the same index value. Does not remove unused data values + * from the object - call compact() to do this. + * @param useCoordIndexOnly Reformat the data into the + * GeometryArray.USE_COORD_INDEX_ONLY format where there is only + * one index list. If the data is already in the USE_COORD_INDEX_ONLY + * format, sending false (or calling indexify()) will change + * it to the normal indexed format. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public void indexify(boolean useCoordIndexOnly) + { + checkForBadData(); + + if (useCoordIndexOnly) { + // Return if already in this format + if (coordOnly) return; + + // Start from normal indexed format + indexify(false); + + // Reformat data to USE_COORD_INDEX_ONLY format + // Need to make an index into the index lists using each + // row of indexes as one value + + // First, find out how many index lists there are; + int numLists = 1; // Always have coordinates + if (colorIndices != null) numLists++; + if (normalIndices != null) numLists++; + numLists += texCoordSetCount; + + // Make single array containing all indices + int n = coordinateIndices.length; + IndexRow[] ir = new IndexRow[n]; + int j; + for (int i = 0 ; i < n ; i++) { + ir[i] = new IndexRow(numLists); + j = 0; + ir[i].set(j++, coordinateIndices[i]); + if (colorIndices != null) ir[i].set(j++, colorIndices[i]); + if (normalIndices != null) ir[i].set(j++, normalIndices[i]); + for (int k = 0 ; k < texCoordSetCount ; k++) { + ir[i].set(j++, texCoordIndexSets[k][i]); + } + } + + // Get index into that array + int[] coordOnlyIndices = getListIndices(ir); + + // Get rid of duplicate rows + int newInd[] = new int[coordOnlyIndices.length]; + ir = (IndexRow[])compactData(coordOnlyIndices, ir, newInd); + coordOnlyIndices = newInd; + + // Reformat data lists to correspond to new index + + // Allocate arrays to hold reformatted data + Point3f[] newCoords = new Point3f[ir.length]; + Color3f[] newColors3 = null; + Color4f[] newColors4 = null; + Vector3f[] newNormals = null; + Object newTexCoordSets[][] = null; + if (colors3 != null) newColors3 = new Color3f[ir.length]; + else if (colors4 != null) newColors4 = new Color4f[ir.length]; + if (normals != null) newNormals = new Vector3f[ir.length]; + for (int i = 0 ; i < texCoordSetCount ; i++) { + if (texCoordDim == 2) { + if (i == 0) newTexCoordSets = new TexCoord2f[texCoordSetCount][]; + newTexCoordSets[i] = new TexCoord2f[ir.length]; + } else if (texCoordDim == 3) { + if (i == 0) newTexCoordSets = new TexCoord3f[texCoordSetCount][]; + newTexCoordSets[i] = new TexCoord3f[ir.length]; + } else if (texCoordDim == 4) { + if (i == 0) newTexCoordSets = new TexCoord4f[texCoordSetCount][]; + newTexCoordSets[i] = new TexCoord4f[ir.length]; + } + } + + // Copy data into new arrays + n = ir.length; + for (int i = 0 ; i < n ; i++) { + j = 0; + newCoords[i] = coordinates[(ir[i]).get(j++)]; + if (colors3 != null) { + newColors3[i] = colors3[(ir[i]).get(j++)]; + } else if (colors4 != null) { + newColors4[i] = colors4[(ir[i]).get(j++)]; + } + if (normals != null) newNormals[i] = normals[(ir[i]).get(j++)]; + for (int k = 0 ; k < texCoordSetCount ; k++) { + newTexCoordSets[k][i] = texCoordSets[k][(ir[i]).get(j++)]; + } + } + + // Replace old arrays with new arrays + coordinates = newCoords; + colors3 = newColors3; + colors4 = newColors4; + normals = newNormals; + texCoordSets = newTexCoordSets; + coordinateIndices = coordOnlyIndices; + colorIndices = null; + normalIndices = null; + texCoordIndexSets = new int[texCoordSetCount][]; + + coordOnly = true; + } else if (coordOnly) { + // Need to change from useCoordIndexOnly format to normal + // indexed format. Should make a more efficient implementation + // later. + + int n = coordinateIndices.length; + if ((colors3 != null) || (colors4 != null)) { + colorIndices = new int[n]; + for (int i = 0 ; i < n ; i++) colorIndices[i] = coordinateIndices[i]; + } + if (normals != null) { + normalIndices = new int[n]; + for (int i = 0 ; i < n ; i++) normalIndices[i] = coordinateIndices[i]; + } + texCoordIndexSets = new int[texCoordSetCount][]; + for (int i = 0 ; i < texCoordSetCount ; i++) { + texCoordIndexSets[i] = new int[n]; + for (int j = 0 ; j < n ; j++) { + texCoordIndexSets[i][j] = coordinateIndices[j]; + } + } + coordOnly = false; + } else { + + // No need to indexify if already indexed + if (coordinateIndices != null) return; + + coordinateIndices = getListIndices(coordinates); + + if (colors3 != null) colorIndices = getListIndices(colors3); + else if (colors4 != null) colorIndices = getListIndices(colors4); + + if (normals != null) normalIndices = getListIndices(normals); + + texCoordIndexSets = new int[texCoordSetCount][]; + for(int i = 0 ; i < texCoordSetCount ; i++) { + texCoordIndexSets[i] = getListIndices(texCoordSets[i]); + } + + coordOnly = false; + } + + if ((DEBUG & 1) == 1) { + System.out.println("Coordinate Array:"); + for (int i = 0 ; i < coordinates.length ; i++) { + System.out.println(" " + i + " " + coordinates[i] + + " " + coordinates[i].hashCode()); + } + System.out.println("Index array:"); + for (int i = 0 ; i < coordinateIndices.length ; i++) { + System.out.println(" " + i + " " + coordinateIndices[i]); + } + } + + } // End of indexify + + + + public void indexify() + { + indexify(false); + } // End of indexify() + + + + /** + * Allocates an array of the same type as the input type. This allows us to + * use a generic compactData method. + * + * @param data Array of coordinate, color, normal or texture coordinate data + * The data can be in one of the following formats - Point3f, Color3f, + * Color4f, TexCoord2f, TexCoord3f, TexCoord4f. + * + * @param num The size of the array to be allocated + * + * @return An array of size num of the same type as the input type + * + * @exception IllegalArgumentException if the input array is not one of the + * types listed above. + */ + Object[] allocateArray(Object data[], int num) { + Object newData[] = null; + if (data instanceof javax.vecmath.Point3f[]) { + newData = new Point3f[num]; + } else if (data instanceof javax.vecmath.Vector3f[]) { + newData = new Vector3f[num]; + } else if (data instanceof javax.vecmath.Color3f[]) { + newData = new Color3f[num]; + } else if (data instanceof javax.vecmath.Color4f[]) { + newData = new Color4f[num]; + } else if (data instanceof javax.vecmath.TexCoord2f[]) { + newData = new TexCoord2f[num]; + } else if (data instanceof javax.vecmath.TexCoord3f[]) { + newData = new TexCoord3f[num]; + } else if (data instanceof javax.vecmath.TexCoord4f[]) { + newData = new TexCoord4f[num]; + } else if (data instanceof IndexRow[]) { + // Hack so we can use compactData for coordIndexOnly + newData = new IndexRow[num]; + } else throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo9")); + return newData; + } // End of allocateArray + + + + /** + * Generic method that compacts (ie removes unreferenced/duplicate data) + * any type of indexed data. + * Used to compact coordinate, color, normal and texture coordinate data. + * @param indices Array of indices + * @param data Array of coordinate, color, normal or texture coordinate data + * The data can be in one of the following formats - Point3f, Color3f, + * Color4f, TexCoord2f, TexCoord3f, TexCoord4f. + * @param newInd The new array of indexes after the data has been compacted. + * This must be allocated by the calling method. On return, this array will + * contain the new index data. The size of this array must be equal to + * indices.length + * @return Array of the data with unreferenced and duplicate entries removed. + * The return type will be the same as the type that was passed in data. + */ + // TODO: Remove duplicate entries in data lists. + private Object[] compactData(int indices[], Object data[], int newInd[]) { + Object newData[] = null; + /* + * This is a three step process. + * First, find out how many unique indexes are used. This + * will be the size of the new data array. + */ + int numUnique = 0; + int translationTable[] = new int[data.length]; + for (int i = 0 ; i < indices.length ; i++) { + if (translationTable[indices[i]] == 0) { + + numUnique++; + translationTable[indices[i]] = 1; + } + } + /* + * Second, build the new data list. Remember the new indexes so + * we can use the table to translate the old indexes to the new + */ + newData = allocateArray(data, numUnique); + int newIdx = 0; + for (int i = 0 ; i < translationTable.length ; i++) { + if (translationTable[i] != 0) { + newData[newIdx] = data[i]; + translationTable[i] = newIdx++; + } + } + /* + * Third, make the new index list + */ + for (int i = 0 ; i < indices.length ; i++) { + newInd[i] = translationTable[indices[i]]; + } + return newData; + } // End of compactData + + + + /** + * Remove unused data from an indexed dataset. + * Indexed data may contain data entries that are never referenced by + * the dataset. This routine will remove those entries where + * appropriate and renumber the indices to match the new values. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public void compact() + { + checkForBadData(); + + // Only usable on indexed data + if (coordinateIndices == null) return; + + // USE_COORD_INDEX_ONLY never has unused data + if (coordOnly) return; + + int newInd[] = new int[coordinateIndices.length]; + coordinates = + (Point3f[])compactData(coordinateIndices, coordinates, newInd); + coordinateIndices = newInd; + + if (colorIndices != null) { + newInd = new int[colorIndices.length]; + if (colors3 != null) + colors3 = (Color3f[])compactData(colorIndices, colors3, newInd); + else if (colors4 != null) + colors4 = (Color4f[])compactData(colorIndices, colors4, newInd); + colorIndices = newInd; + } + + if (normalIndices != null) { + newInd = new int[normalIndices.length]; + normals = (Vector3f[])compactData(normalIndices, normals, newInd); + normalIndices = newInd; + } + + for (int i = 0 ; i < texCoordSetCount ; i++) { + newInd = new int[texCoordIndexSets[i].length]; + texCoordSets[i] = compactData(texCoordIndexSets[i], + texCoordSets[i], newInd); + texCoordIndexSets[i] = newInd; + } + } // End of compact + + + + /** + * Check the data to make sure everything's consistent. + */ + private void checkForBadData() { + boolean badData = false; + + // + // Coordinates are required + // + if (coordinates == null) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo3")); + } + + // + // Check for indices with no data + // + if ((colors3 == null) && (colors4 == null) && (colorIndices != null)) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo4")); + if ((normals == null) && (normalIndices != null)) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo11")); + + // + // Make sure all TextureCoordinate data is set (indices or not) + // + for (int i = 0 ; i < texCoordSetCount ; i++) { + if (texCoordSets[i] == null) + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo10")); + } + + // + // Check for Missing Index lists + // + boolean texInds = false; // Indicates whether we have texcoord indices + if (texCoordIndexSets != null) { + for (int i = 0 ; i < texCoordSetCount ; i++) { + if (texCoordIndexSets[i] != null) texInds = true; + } + } + if ((coordinateIndices != null) || + (colorIndices != null) || + (normalIndices != null) || + texInds) { + // At least one index list is present, so they all must be + // present (unless coordOnly) + if (coordinateIndices == null) badData = true; + else if (coordOnly) { + if ((colorIndices != null) || + (normalIndices != null) || + (texInds == true)) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo20")); + } + } else if (((colors3 != null) || (colors4 != null)) && + (colorIndices == null)) badData = true; + else if ((normals != null) && (normalIndices == null)) badData = true; + else if ((texCoordSetCount > 0) && !texInds) badData = true; + if (badData) throw new + IllegalArgumentException(J3dUtilsI18N.getString("GeometryInfo19")); + } + + // + // Make sure index lists are all the same length + // + if ((coordinateIndices != null) && (!coordOnly)) { + if (((colors3 != null) || (colors4 != null)) && + (colorIndices.length != coordinateIndices.length)) + badData = true; + else if ((normals != null) && + (normalIndices.length != coordinateIndices.length)) + badData = true; + else { + //Check all texCoord indices have the same length + for (int i = 0 ; i < texCoordSetCount ; i++) { + if (texCoordIndexSets[i].length != coordinateIndices.length) { + badData = true; + break; + } + } + } + if (badData) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo5")); + } + } + + // + // For stripped primitives, make sure we have strip counts + // + if ((prim == TRIANGLE_STRIP_ARRAY) || + (prim == TRIANGLE_FAN_ARRAY) || + (prim == POLYGON_ARRAY)) { + if (stripCounts == null) badData = true; + } else if (stripCounts != null) badData = true; + if (badData) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo6")); + } + + // Find out how much data we have + int count; + if (coordinateIndices == null) count = coordinates.length; + else count = coordinateIndices.length; + + // + // Make sure sum of strip counts equals indexCount (or vertexCount) + // and check to make sure triangles and quads have the right number + // of vertices + // + if ((prim == TRIANGLE_STRIP_ARRAY) || + (prim == TRIANGLE_FAN_ARRAY) || + (prim == POLYGON_ARRAY)) { + int sum = 0; + for (int i = 0 ; i < stripCounts.length ; i++) { + sum += stripCounts[i]; + } + if (sum != count) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo7")); + } + } else if (prim == TRIANGLE_ARRAY) { + if (count % 3 != 0) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo12")); + } + } else if (prim == QUAD_ARRAY) { + if (count % 4 != 0) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo13")); + } + } + + // + // For polygons, make sure the contours add up. + // + if (prim == POLYGON_ARRAY) { + if (contourCounts != null) { + int c = 0; + for (int i = 0 ; i < contourCounts.length ; i++) + c += contourCounts[i]; + if (c != stripCounts.length) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo8")); + } + } + } else { + if (contourCounts != null) { + throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfo14")); + } + } + } // End of checkForBadData + + + + /** + * Get rid of index lists by reorganizing data into an un-indexed + * format. Does nothing if no index lists are set. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public void unindexify() { + checkForBadData(); + if (coordinateIndices != null) { + // Switch from USE_COORD_INDEX_ONLY format + if (coordOnly) indexify(false); + + coordinates = + (Point3f[])unindexifyData(coordinates, coordinateIndices); + coordinateIndices = null; + + if (colors3 != null) { + colors3 = (Color3f[])unindexifyData(colors3, colorIndices); + } else if (colors4 != null) { + colors4 = (Color4f[])unindexifyData(colors4, colorIndices); + } + colorIndices = null; + + if (normals != null) { + normals = (Vector3f[])unindexifyData(normals, normalIndices); + normalIndices = null; + } + + for (int i = 0 ; i < texCoordSetCount ; i++) + texCoordSets[i] = unindexifyData(texCoordSets[i], + texCoordIndexSets[i]); + texCoordIndexSets = new int[texCoordSetCount][]; + } + } // End of unindexify + + + + /** + * Generic unindexify method. Can unindex data in any of the following + * formats Point3f, Color3f, Color4f, Vector3f, TexCoord2f, TexCoord3f, + * TexCoord4f. + */ + private Object[] unindexifyData(Object data[], int index[]) + { + Object newData[] = allocateArray(data, index.length); + for (int i = 0 ; i < index.length ; i++) { + newData[i] = data[index[i]]; + } + return newData; + } // End of unindexifyData + + + + /** + * Calculate vertexFormat based on data. + */ + private int getVertexFormat() + { + int vertexFormat = GeometryArray.COORDINATES; + + if (colors3 != null) vertexFormat |= GeometryArray.COLOR_3; + else if (colors4 != null) vertexFormat |= GeometryArray.COLOR_4; + + if (normals != null) vertexFormat |= GeometryArray.NORMALS; + + if (texCoordDim == 2) + vertexFormat |= GeometryArray.TEXTURE_COORDINATE_2; + else if (texCoordDim == 3) + vertexFormat |= GeometryArray.TEXTURE_COORDINATE_3; + else if (texCoordDim == 4) + vertexFormat |= GeometryArray.TEXTURE_COORDINATE_4; + + return vertexFormat; + } // End of getVertexFormat + + + + /** + * Calculate vertexCount based on data + */ + private int getVertexCount() + { + int vertexCount = coordinates.length; + + if (colors3 != null) { + if (colors3.length > vertexCount) vertexCount = colors3.length; + } else if (colors4 != null) { + if (colors4.length > vertexCount) vertexCount = colors4.length; + } + + if (normals != null) { + if (normals.length > vertexCount) vertexCount = normals.length; + } + + // Find max length tex coord set + for (int i = 0 ; i < texCoordSetCount ; i++) { + if (texCoordSets[i].length > vertexCount) + vertexCount = texCoordSets[i].length; + } + + return vertexCount; + } // End of getVertexCount + + + + /** + * Converts an array of Tuple2f, Tuple3f, or Tuple4f values into + * an array of floats. Assumes array is not null. Returns null + * if array is not Tuple2f, Tuple3f, or Tuple4f. Used by fillIn() + * for BY_REFERENCE not INTERLEAVED geometry. + */ + private float[] vecmathToFloat(Object[] ar) + { + if (ar[0] instanceof Tuple2f) { + float[] p = new float[ar.length * 2]; + Tuple2f[] a = (Tuple2f[])ar; + for (int i = 0 ; i < ar.length ; i++) { + p[i * 2] = a[i].x; + p[i * 2 + 1] = a[i].y; + } + return p; + } else if (ar[0] instanceof Tuple3f) { + float[] p = new float[ar.length * 3]; + Tuple3f[] a = (Tuple3f[])ar; + for (int i = 0 ; i < ar.length ; i++) { + p[i * 3] = a[i].x; + p[i * 3 + 1] = a[i].y; + p[i * 3 + 2] = a[i].z; + } + return p; + } else if (ar[0] instanceof Tuple4f) { + float[] p = new float[ar.length * 4]; + Tuple4f[] a = (Tuple4f[])ar; + for (int i = 0 ; i < ar.length ; i++) { + p[i * 4] = a[i].x; + p[i * 4 + 1] = a[i].y; + p[i * 4 + 2] = a[i].z; + p[i * 4 + 3] = a[i].w; + } + return p; + } + return null; + } // End of vecmathToFloat + + + + /** + * Fill in the GeometryArray object. Used by getGeometryArray and + * getIndexedGeometryArray. checkForBadData has already been called. + */ + private void fillIn(GeometryArray ga, boolean byRef, boolean interleaved, + boolean nio) + { + if (interleaved) { + // Calculate number of words per vertex + int wpv = 3; // Always have coordinate data + if (normals != null) wpv += 3; + if (colors3 != null) wpv += 3; + else if (colors4 != null) wpv += 4; + wpv += (texCoordSetCount * texCoordDim); + + // Build array of interleaved data + float[] d = new float[wpv * coordinates.length]; + + // Fill in the array + int offset = 0; + for (int i = 0 ; i < coordinates.length ; i++) { + if (texCoordDim == 2) { + for (int j = 0 ; j < texCoordSetCount ; j++) { + d[offset++] = ((TexCoord2f)texCoordSets[j][i]).x; + d[offset++] = ((TexCoord2f)texCoordSets[j][i]).y; + } + } else if (texCoordDim == 3) { + for (int j = 0 ; j < texCoordSetCount ; j++) { + d[offset++] = ((TexCoord3f)texCoordSets[j][i]).x; + d[offset++] = ((TexCoord3f)texCoordSets[j][i]).y; + d[offset++] = ((TexCoord3f)texCoordSets[j][i]).z; + } + } else if (texCoordDim == 4) { + for (int j = 0 ; j < texCoordSetCount ; j++) { + d[offset++] = ((TexCoord4f)texCoordSets[j][i]).x; + d[offset++] = ((TexCoord4f)texCoordSets[j][i]).y; + d[offset++] = ((TexCoord4f)texCoordSets[j][i]).z; + d[offset++] = ((TexCoord4f)texCoordSets[j][i]).w; + } + } + + if (colors3 != null) { + d[offset++] = colors3[i].x; + d[offset++] = colors3[i].y; + d[offset++] = colors3[i].z; + } else if (colors4 != null) { + d[offset++] = colors4[i].x; + d[offset++] = colors4[i].y; + d[offset++] = colors4[i].z; + d[offset++] = colors4[i].w; + } + + if (normals != null) { + d[offset++] = normals[i].x; + d[offset++] = normals[i].y; + d[offset++] = normals[i].z; + } + + d[offset++] = coordinates[i].x; + d[offset++] = coordinates[i].y; + d[offset++] = coordinates[i].z; + } + // Register reference to array of interleaved data + if (nio) { + ByteBufferWrapper b = ByteBufferWrapper.allocateDirect(d.length * 4); + FloatBufferWrapper f = + b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer(); + f.put(d); + ga.setInterleavedVertexBuffer(f.getJ3DBuffer()); + } else ga.setInterleavedVertices(d); + } else if (nio) { + + ByteBufferWrapper b = + ByteBufferWrapper.allocateDirect(coordinates.length * 4 * 3); + FloatBufferWrapper f = + b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer(); + f.put(vecmathToFloat(coordinates)); + ga.setCoordRefBuffer(f.getJ3DBuffer()); + + if (colors3 != null) { + b = ByteBufferWrapper.allocateDirect(colors3.length * 4 * 3); + f = b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer(); + f.put(vecmathToFloat(colors3)); + ga.setColorRefBuffer(f.getJ3DBuffer()); + } else if (colors4 != null) { + b = ByteBufferWrapper.allocateDirect(colors4.length * 4 * 4); + f = b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer(); + f.put(vecmathToFloat(colors4)); + ga.setColorRefBuffer(f.getJ3DBuffer()); + } + + if (normals != null) { + b = ByteBufferWrapper.allocateDirect(normals.length * 4 * 3); + f = b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer(); + f.put(vecmathToFloat(normals)); + ga.setNormalRefBuffer(f.getJ3DBuffer()); + } + + for (int i = 0 ; i < texCoordSetCount ; i++) { + b = ByteBufferWrapper.allocateDirect( + texCoordSets[i].length * 4 * texCoordDim); + f = b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer(); + f.put(vecmathToFloat(texCoordSets[i])); + ga.setTexCoordRefBuffer(i, f.getJ3DBuffer()); + } + } else if (byRef) { + // Need to copy the data into float arrays - GeometryArray + // prefers them over the vecmath types + ga.setCoordRefFloat(vecmathToFloat(coordinates)); + if (colors3 != null) ga.setColorRefFloat(vecmathToFloat(colors3)); + else if (colors4 != null) ga.setColorRefFloat(vecmathToFloat(colors4)); + if (normals != null) ga.setNormalRefFloat(vecmathToFloat(normals)); + for (int i = 0 ; i < texCoordSetCount ; i++) { + ga.setTexCoordRefFloat(i, vecmathToFloat(texCoordSets[i])); + } + } else { + ga.setCoordinates(0, coordinates); + if (colors3 != null) ga.setColors(0, colors3); + else if (colors4 != null) ga.setColors(0, colors4); + if (normals != null) ga.setNormals(0, normals); + for (int i = 0 ; i < texCoordSetCount ; i++) { + if (texCoordDim == 2) { + ga.setTextureCoordinates(i, 0, (TexCoord2f[])texCoordSets[i]); + } else if (texCoordDim == 3) { + ga.setTextureCoordinates(i, 0, (TexCoord3f[])texCoordSets[i]); + } else if (texCoordDim == 4) { + ga.setTextureCoordinates(i, 0, (TexCoord4f[])texCoordSets[i]); + } + } + } + + if (coordinateIndices != null) { + IndexedGeometryArray iga = null; + iga = (IndexedGeometryArray)ga; + iga.setCoordinateIndices(0, coordinateIndices); + if (!coordOnly) { + if (colorIndices != null) iga.setColorIndices(0, colorIndices); + if (normalIndices != null) iga.setNormalIndices(0, normalIndices); + for (int i = 0 ; i < texCoordSetCount ; i++) + iga.setTextureCoordinateIndices(i, 0, texCoordIndexSets[i]); + } + } + } // End of fillIn + + + + /** + * Redo indexes to guarantee connection information. + * Use this routine if your original data is in indexed format, but + * you don't trust that the indexing is correct. After this + * routine it is guaranteed that two points with the same + * position will have the same coordinate index (for example). + * Try this if you see + * glitches in your normals or stripification, to rule out + * bad indexing as the source of the problem. Works with normal + * indexed format or USE_COORD_INDEX_ONLY format. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public void recomputeIndices() + { + boolean remember = coordOnly; + + // Can make more efficient implementation later + unindexify(); + indexify(remember); + } // End of recomputeIndices + + + + /** + * Reverse the order of an array of ints (computer class homework + * problem). + */ + private void reverseList(int list[]) + { + int t; + + if (list == null) return; + + for (int i = 0 ; i < list.length / 2 ; i++) { + t = list[i]; + list[i] = list[list.length - i - 1]; + list[list.length - i - 1] = t; + } + } // End of reverseList + + + + /** + * Reverse the order of all lists. If your polygons are formatted with + * clockwise winding, you will always see the back and never the front. + * (Java 3D always wants vertices specified with a counter-clockwise + * winding.) + * This method will (in effect) reverse the winding of your data by + * inverting all of the index lists and the stripCounts + * and contourCounts lists. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public void reverse() + { + indexify(); + reverseList(stripCounts); + reverseList(oldStripCounts); + reverseList(contourCounts); + reverseList(coordinateIndices); + reverseList(colorIndices); + reverseList(normalIndices); + for (int i = 0 ; i < texCoordSetCount ; i++) + reverseList(texCoordIndexSets[i]); + } // End of reverse + + + + /** + * Returns true if the data in this GeometryInfo is currently + * formatted in the USE_COORD_INDEX_ONLY format where a single + * index list is used to index into all data lists. + * @see GeometryInfo#indexify(boolean) + * @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean, + * boolean, boolean) + */ + public boolean getUseCoordIndexOnly() + { + return coordOnly; + } // End of getUseCoordIndexOnly + + + + /** + * Tells the GeometryInfo that its data is formatted in the + * USE_COORD_INDEX_ONLY format with a single index list + * (the coordinate index list) that indexes into all data + * lists (coordinates, normals, colors, and texture + * coordinates). NOTE: this will not convert the data + * for you. This method is for when you are sending in + * data useng the setCoordinates, setNormals, setColors, + * and/or setTextureCoordinates methods, and you are only + * setting one index using setCoordinateIndices(). If + * you want GeometryInfo to convert your data to the + * USE_COORD_INDEX_ONLY format, use indexify(true) or + * getIndexedGeometryArray with the useCoordIndexOnly + * parameter set to true. + * @see GeometryInfo#indexify(boolean) + * @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean, + * boolean, boolean) + */ + public void setUseCoordIndexOnly(boolean useCoordIndexOnly) + { + coordOnly = useCoordIndexOnly; + } // End of setUseCoordIndexOnly + + + + /** + * Creates and returns a non-indexed Java 3D GeometryArray object + * based on the data in the GeometryInfo object. This object is + * suitable to be attached to a Shape3D node for rendering. + * @param byRef Use geometry BY_REFERENCE + * @param interleaved Use INTERLEAVED geometry. Implies byRef is + * true as well. + * @param nio Create GeometryArray using java.nio.Buffer for + * geometry arrays. Only usable on JDK 1.4 or higher. Implies + * byRef is true as well. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public GeometryArray getGeometryArray(boolean byRef, boolean interleaved, + boolean nio) + { + checkForBadData(); + + if (prim == POLYGON_ARRAY) { + if (tr == null) tr = new Triangulator(); + tr.triangulate(this); + } else changeBackToOldPrim(); + + unindexify(); + + int vertexFormat = getVertexFormat(); + if (nio) vertexFormat |= (GeometryArray.BY_REFERENCE | + GeometryArray.USE_NIO_BUFFER); + if (interleaved) vertexFormat |= (GeometryArray.BY_REFERENCE | + GeometryArray.INTERLEAVED); + if (byRef) vertexFormat |= GeometryArray.BY_REFERENCE; + + int vertexCount = coordinates.length; + + // If the texCoordSetMap hasn't been set, assume one set of + // texture coordinates only and one texture state unit + if ((texCoordSetCount > 0) && (texCoordSetMap == null)) { + texCoordSetCount = 1; + texCoordSetMap = new int[1]; + texCoordSetMap[0] = 0; + } + + // Create the GeometryArray object + GeometryArray ga = null; + switch (prim) { + case TRIANGLE_ARRAY: + TriangleArray ta = new TriangleArray(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap); + ga = (GeometryArray)ta; + break; + + case QUAD_ARRAY: + QuadArray qa = new QuadArray(vertexCount, vertexFormat, + texCoordSetCount, texCoordSetMap); + ga = (GeometryArray)qa; + break; + + case TRIANGLE_STRIP_ARRAY: + TriangleStripArray tsa = new TriangleStripArray(vertexCount, + vertexFormat, texCoordSetCount, texCoordSetMap, + stripCounts); + ga = (GeometryArray)tsa; + break; + + case TRIANGLE_FAN_ARRAY: + TriangleFanArray tfa = new TriangleFanArray(vertexCount, + vertexFormat, texCoordSetCount, texCoordSetMap, + stripCounts); + ga = (GeometryArray)tfa; + break; + } + + fillIn(ga, byRef, interleaved, nio); + + return ga; + } // End of getGeometryArray(int, int) + + + + /** + * Creates and returns a non-indexed Java 3D GeometryArray object + * based on the data in the GeometryInfo object. This object is + * suitable to be attached to a Shape3D node for rendering. + * The geometry is not created using data BY_REFERENCE, + * INTERLEAVED, or USE_NIO_BUFFER. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public GeometryArray getGeometryArray() + { + return getGeometryArray(false, false, false); + } // End of getGeometryArray() + + + + /** + * Creates and returns a IndexedGeometryArray + * based on the data in the GeometryInfo object. This object is + * suitable to be attached to a Shape3D node for rendering. + * @param compact Remove Coordinates, Colors, Normals, and + * TextureCoordinates that aren't referenced by any indices. + * @param byRef Create the IndexedGeometryArray using geometry + * BY_REFERENCE. + * @param interleaved Use INTERLEAVED geometry. Implies byRef is + * true as well. + * @param nio Create GeometryArray using java.nio.Buffer for + * geometry arrays. Only usable on JDK 1.4 or higher. Implies + * byRef is true as well. + * @param useCoordIndexOnly Create the IndexedGeometryArray using + * USE_COORD_INDEX_ONLY. Values from the coordinate index array + * are used as a single set of indices into all vertex + * component arrays (coord, color, normal, and texCoord). + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public IndexedGeometryArray getIndexedGeometryArray(boolean compact, + boolean byRef, + boolean interleaved, + boolean useCoordIndexOnly, + boolean nio) + { + indexify(useCoordIndexOnly); + + if (compact) compact(); + + if (prim == POLYGON_ARRAY) { + if (tr == null) tr = new Triangulator(); + tr.triangulate(this); + } else changeBackToOldPrim(); + + if (useCoordIndexOnly && coordOnly == false) { + // Check to see if we can optimize for USE_COORD_INDEX_ONLY + int i, j; + boolean canUseCoordIndexOnly = true; + + if (coordinateIndices != null) { + // See if all the array lengths are the same + if (colorIndices != null && + colorIndices.length != coordinateIndices.length) { + canUseCoordIndexOnly = false; + } + if (normalIndices != null && + normalIndices.length != coordinateIndices.length) { + canUseCoordIndexOnly = false; + } + for (i = 0 ; i < texCoordSetCount ; i++) { + if (texCoordIndexSets[i] != null && + texCoordIndexSets[i].length != coordinateIndices.length) { + canUseCoordIndexOnly = false; + break; + } + } + if (canUseCoordIndexOnly && + ((colorIndices != null) || + (normalIndices != null) || + (texCoordSetCount > 0))) { + // All array lengths are the same. Check their contents + + for (i=0; i 0) && (texCoordSetMap == null)) { + texCoordSetCount = 1; + texCoordSetMap = new int[1]; + texCoordSetMap[0] = 0; + } + + // + // Create the IndexedGeometryArray object + // + + IndexedGeometryArray ga = null; + + switch (prim) { + case TRIANGLE_ARRAY: + IndexedTriangleArray ta = new IndexedTriangleArray(vertexCount, + vertexFormat, texCoordSetCount, texCoordSetMap, + coordinateIndices.length); + ga = (IndexedGeometryArray)ta; + break; + + case QUAD_ARRAY: + IndexedQuadArray qa = new IndexedQuadArray(vertexCount, + vertexFormat, texCoordSetCount, texCoordSetMap, + coordinateIndices.length); + ga = (IndexedGeometryArray)qa; + break; + case TRIANGLE_STRIP_ARRAY: + IndexedTriangleStripArray tsa = new IndexedTriangleStripArray( + vertexCount, vertexFormat, texCoordSetCount, + texCoordSetMap, coordinateIndices.length, stripCounts); + ga = (IndexedGeometryArray)tsa; + break; + + case TRIANGLE_FAN_ARRAY: + IndexedTriangleFanArray tfa = new IndexedTriangleFanArray( + vertexCount, vertexFormat, texCoordSetCount, + texCoordSetMap, coordinateIndices.length, stripCounts); + ga = (IndexedGeometryArray)tfa; + break; + } + + // Fill in the GeometryArray object + fillIn(ga, byRef, interleaved, nio); + + return ga; + } // End of getIndexedGeometryArray(bool, bool, bool, bool, bool) + + + + /** + * Creates and returns an IndexedGeometryArray + * based on the data in the GeometryInfo object. This object is + * suitable to be attached to a Shape3D node for rendering. + * Equivalent to getIndexedGeometryArray(compact, false, + * false, false, false). + * @param compact Remove Coordinates, Colors, Normals, and + * TextureCoordinates that aren't referenced by any indices. + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public IndexedGeometryArray getIndexedGeometryArray(boolean compact) + { + return getIndexedGeometryArray(compact, false, false, false, false); + } // End of getIndexedGeometryArray(boolean) + + + + /** + * Creates and returns an IndexedGeometryArray + * based on the data in the GeometryInfo object. This object is + * suitable to be attached to a Shape3D node for rendering. + * Equivalent to getIndexedGeometryArray(false, false, + * false, false, false). + * @throws IllegalArgumentException if coordinate data is missing, + * if the index lists aren't all the + * same length, if an index list is set and the corresponding data + * list isn't set, if a data list is set and the corresponding + * index list is unset (unless all index lists are unset or in + * USE_COORD_INDEX_ONLY format), + * if StripCounts or ContourCounts is inconsistent with the current + * primitive, if the sum of the contourCounts array doesn't equal + * the length of the StripCounts array, or if the number of vertices + * isn't a multiple of three (for triangles) or four (for quads). + */ + public IndexedGeometryArray getIndexedGeometryArray() + { + return getIndexedGeometryArray(false, false, false, false, false); + } // End of getIndexedGeometryArray() + +} // End of class GeometryInfo + +// End of file GeometryInfo.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfoGenerator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfoGenerator.java new file mode 100644 index 0000000..19a6f3e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfoGenerator.java @@ -0,0 +1,857 @@ +/* + * $RCSfile: GeometryInfoGenerator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:19 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import javax.media.j3d.GeometryArray; +import javax.media.j3d.GeometryStripArray; +import javax.media.j3d.TriangleFanArray; +import javax.media.j3d.TriangleStripArray; +import javax.media.j3d.TriangleArray; +import javax.media.j3d.QuadArray; +import javax.media.j3d.IndexedGeometryArray; +import javax.media.j3d.IndexedGeometryStripArray; +import javax.media.j3d.IndexedQuadArray; +import javax.media.j3d.IndexedTriangleArray; +import javax.media.j3d.IndexedTriangleFanArray; +import javax.media.j3d.IndexedTriangleStripArray; +import javax.vecmath.*; +import com.sun.j3d.utils.geometry.GeometryInfo; +import com.sun.j3d.internal.J3dUtilsI18N; +import com.sun.j3d.internal.BufferWrapper; +import com.sun.j3d.internal.ByteBufferWrapper; +import com.sun.j3d.internal.FloatBufferWrapper; +import com.sun.j3d.internal.DoubleBufferWrapper; +import javax.media.j3d.J3DBuffer; + + + +/** + * Populate a GeometryInfo object from the Geometry provided. Used + * by GeometryInfo. + */ +class GeometryInfoGenerator extends Object { + + public static void create(GeometryInfo geomInfo, GeometryArray geomArray) + { + if (geomArray instanceof GeometryStripArray) + create(geomInfo, (GeometryStripArray)geomArray); + else if (geomArray instanceof TriangleArray) { + geomInfo.reset(GeometryInfo.TRIANGLE_ARRAY); + processGeometryArray(geomInfo, geomArray); + } else if (geomArray instanceof QuadArray) { + geomInfo.reset(GeometryInfo.QUAD_ARRAY); + processGeometryArray(geomInfo, geomArray); + } else if (geomArray instanceof IndexedGeometryArray) + create(geomInfo, (IndexedGeometryArray)geomArray); + else throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfoGenerator0")); + } // End of create(GeometryInfo, GeometryArray) + + + + private static void create(GeometryInfo geomInfo, + GeometryStripArray geomArray) + { + if (geomArray instanceof TriangleFanArray) { + geomInfo.reset(GeometryInfo.TRIANGLE_FAN_ARRAY); + } else if (geomArray instanceof TriangleStripArray) { + geomInfo.reset(GeometryInfo.TRIANGLE_STRIP_ARRAY); + } else throw new IllegalArgumentException( + J3dUtilsI18N.getString("GeometryInfoGenerator0")); + + processGeometryArray(geomInfo, geomArray); + processStripArray(geomInfo, geomArray); + } // End of create(GeometryInfo, GeometryStripArray) + + + + private static void create(GeometryInfo geomInfo, + IndexedGeometryArray geomArray) + { + if (geomArray instanceof IndexedQuadArray) { + geomInfo.reset(GeometryInfo.QUAD_ARRAY); + } else if (geomArray instanceof IndexedTriangleArray) { + geomInfo.reset(GeometryInfo.TRIANGLE_ARRAY); + } else if (geomArray instanceof IndexedTriangleFanArray) { + geomInfo.reset(GeometryInfo.TRIANGLE_FAN_ARRAY); + processIndexStripArray(geomInfo, (IndexedGeometryStripArray)geomArray); + } else if (geomArray instanceof IndexedTriangleStripArray) { + geomInfo.reset(GeometryInfo.TRIANGLE_STRIP_ARRAY); + processIndexStripArray(geomInfo, (IndexedGeometryStripArray)geomArray); + } + + processGeometryArray(geomInfo, geomArray); + processIndexedArray(geomInfo, geomArray); + } // End of create(GeometryInfo, IndexedGeometryArray) + + + + private static void processGeometryArray(GeometryInfo geomInfo, + GeometryArray geomArray) + { + int i, j; + int vertexFormat = geomArray.getVertexFormat(); + int texSets = geomArray.getTexCoordSetCount(); + int valid; + + // Calculate validVertexCount + if (geomArray instanceof GeometryStripArray) { + // Does not include IndexedGeometryStripArray + GeometryStripArray gsa = (GeometryStripArray)geomArray; + int[] strips = new int[gsa.getNumStrips()]; + gsa.getStripVertexCounts(strips); + valid = 0; + for (i = 0 ; i < strips.length ; i++) { + valid += strips[i]; + } + } else if (geomArray instanceof IndexedGeometryArray) { + valid = geomArray.getVertexCount(); + } else valid = geomArray.getValidVertexCount(); + + if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) { + + // Calculate words_per_vertex (wpv) + int wpv = 3; // Always have coordinate data + if ((vertexFormat & GeometryArray.NORMALS) != 0) wpv += 3; + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) + wpv += 4; + else if ((vertexFormat & GeometryArray.COLOR_3) != 0) wpv += 3; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) + wpv += 2 * texSets; + else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) + wpv += 3 * texSets; + else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) + wpv += 4 * texSets; + + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialVertexIndex(); + } else initial = 0; + + float[] d; + if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { + J3DBuffer b = geomArray.getInterleavedVertexBuffer(); + FloatBufferWrapper w = new FloatBufferWrapper(b); + d = new float[w.limit()]; + w.position( 0 ); + w.get(d); + } else d = geomArray.getInterleavedVertices(); + + int offset = 0; + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + geomInfo.setTextureCoordinateParams(texSets, 2); + int[] map = new int[geomArray.getTexCoordSetMapLength()]; + geomArray.getTexCoordSetMap(map); + geomInfo.setTexCoordSetMap(map); + for (i = 0 ; i < texSets ; i++) { + TexCoord2f[] tex = new TexCoord2f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord2f(d[wpv * (j + initial) + offset], + d[wpv * (j + initial) + offset + 1]); + } + geomInfo.setTextureCoordinates(i, tex); + offset += 2; + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + geomInfo.setTextureCoordinateParams(texSets, 3); + int[] map = new int[geomArray.getTexCoordSetMapLength()]; + geomArray.getTexCoordSetMap(map); + geomInfo.setTexCoordSetMap(map); + for (i = 0 ; i < texSets ; i++) { + TexCoord3f[] tex = new TexCoord3f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord3f(d[wpv * (j + initial) + offset], + d[wpv * (j + initial) + offset + 1], + d[wpv * (j + initial) + offset + 2]); + } + geomInfo.setTextureCoordinates(i, tex); + offset += 3; + } + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + geomInfo.setTextureCoordinateParams(texSets, 4); + int[] map = new int[geomArray.getTexCoordSetMapLength()]; + geomArray.getTexCoordSetMap(map); + geomInfo.setTexCoordSetMap(map); + for (i = 0 ; i < texSets ; i++) { + TexCoord4f[] tex = new TexCoord4f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord4f(d[wpv * (j + initial) + offset], + d[wpv * (j + initial) + offset + 1], + d[wpv * (j + initial) + offset + 2], + d[wpv * (j + initial) + offset + 3]); + } + geomInfo.setTextureCoordinates(i, tex); + offset += 4; + } + } + + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + Color4f[] color = new Color4f[valid]; + for (i = 0 ; i < valid ; i++) { + color[i] = new Color4f(d[wpv * (i + initial) + offset], + d[wpv * (i + initial) + offset + 1], + d[wpv * (i + initial) + offset + 2], + d[wpv * (i + initial) + offset + 3]); + } + geomInfo.setColors(color); + offset += 4; + } else if ((vertexFormat & GeometryArray.COLOR_3) != 0) { + Color3f[] color = new Color3f[valid]; + for (i = 0 ; i < valid ; i++) { + color[i] = new Color3f(d[wpv * (i + initial) + offset], + d[wpv * (i + initial) + offset + 1], + d[wpv * (i + initial) + offset + 2]); + } + geomInfo.setColors(color); + offset += 3; + } + + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + Vector3f[] normals = new Vector3f[valid]; + for (i = 0 ; i < valid ; i++) { + normals[i] = new Vector3f(d[wpv * (i + initial) + offset], + d[wpv * (i + initial) + offset + 1], + d[wpv * (i + initial) + offset + 2]); + } + geomInfo.setNormals(normals); + offset += 3; + } + + Point3f[] coords = new Point3f[valid]; + for (i = 0 ; i < valid ; i++) { + coords[i] = new Point3f(d[wpv * (i + initial) + offset], + d[wpv * (i + initial) + offset + 1], + d[wpv * (i + initial) + offset + 2]); + } + geomInfo.setCoordinates(coords); + } else { + // Data is not INTERLEAVED + boolean byRef = ((vertexFormat & GeometryArray.BY_REFERENCE) != 0 ); + boolean nio = ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 ); + + Point3f[] coords = null; + if (byRef) { + + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialCoordIndex(); + } else initial = 0; + + if ( nio ) { + J3DBuffer buf = geomArray.getCoordRefBuffer(); + + switch (BufferWrapper.getBufferType(buf)) { + + case BufferWrapper.TYPE_FLOAT: { + FloatBufferWrapper bb = new FloatBufferWrapper(buf); + float[] c = new float[valid * 3]; + bb.position(initial * 3); + bb.get(c, 0, valid * 3); + coords = new Point3f[valid]; + for (i = 0 ; i < valid ; i++) { + coords[i] = new Point3f(c[i * 3 + 0], + c[i * 3 + 1], + c[i * 3 + 2]); + } + } + break; + + case BufferWrapper.TYPE_DOUBLE: { + DoubleBufferWrapper bb = new DoubleBufferWrapper( buf ); + double[] c = new double[valid * 3]; + bb.position(initial * 3); + bb.get(c, 0, valid * 3); + coords = new Point3f[valid]; + for (i = 0 ; i < valid ; i++) { + coords[i] = new Point3f((float)(c[i * 3 + 0]), + (float)(c[i * 3 + 1]), + (float)(c[i * 3 + 2])); + } + } + break; + } + } else if (geomArray.getCoordRef3f() != null) { + if (initial != 0) { + Point3f[] c = geomArray.getCoordRef3f(); + coords = new Point3f[valid]; + for (i = 0 ; i < valid ; i++) { + coords[i] = new Point3f(c[i + initial]); + } + } else coords = geomArray.getCoordRef3f(); + } else if (geomArray.getCoordRef3d() != null) { + Point3d[] c = geomArray.getCoordRef3d(); + coords = new Point3f[valid]; + for (i = 0 ; i < valid ; i++) { + coords[i] = new Point3f(c[i + initial]); + } + } else if (geomArray.getCoordRefFloat() != null) { + float[] c = geomArray.getCoordRefFloat(); + coords = new Point3f[valid]; + for (i = 0 ; i < valid ; i++) { + coords[i] = new Point3f(c[(i + initial) * 3], + c[(i + initial) * 3 + 1], + c[(i + initial) * 3 + 2]); + } + } else if (geomArray.getCoordRefDouble() != null) { + double[] c = geomArray.getCoordRefDouble(); + coords = new Point3f[valid]; + for (i = 0 ; i < valid ; i++) { + coords[i] = new Point3f((float)(c[(i + initial) * 3]), + (float)(c[(i + initial) * 3 + 1]), + (float)(c[(i + initial) * 3 + 2])); + } + } + // No coordinate data - let GeometryInfo handle this. + } else { + // Not BY_REFERENCE + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialVertexIndex(); + } else initial = 0; + coords = new Point3f[valid]; + for (i = 0 ; i < valid ; i++) coords[i] = new Point3f(); + geomArray.getCoordinates(initial, coords); + } + geomInfo.setCoordinates(coords); + + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + Vector3f[] normals = null; + if (byRef) { + + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialNormalIndex(); + } else initial = 0; + + if ( nio ) { + J3DBuffer buf = geomArray.getNormalRefBuffer(); + + if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) { + FloatBufferWrapper bb = new FloatBufferWrapper(buf); + float[] c = new float[valid * 3]; + bb.position(initial * 3); + bb.get(c, 0, valid * 3); + normals = new Vector3f[valid]; + for (i = 0 ; i < valid ; i++) { + normals[i] = new Vector3f(c[i * 3 + 0], + c[i * 3 + 1], + c[i * 3 + 2]); + } + } + // Normals were set in vertexFormat but none were set - OK + } else if (geomArray.getNormalRef3f() != null) { + if (initial != 0) { + Vector3f[] n = geomArray.getNormalRef3f(); + normals = new Vector3f[valid]; + for (i = 0 ; i < valid ; i++) { + normals[i] = new Vector3f(n[i + initial]); + } + } else normals = geomArray.getNormalRef3f(); + } else if (geomArray.getNormalRefFloat() != null) { + float[] n = geomArray.getNormalRefFloat(); + normals = new Vector3f[valid]; + for (i = 0 ; i < valid ; i++) { + normals[i] = new Vector3f(n[(i + initial) * 3], + n[(i + initial) * 3 + 1], + n[(i + initial) * 3 + 2]); + } + } + // Normals were set in vertexFormat but none were set - OK + } else { + // Not BY_REFERENCE + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialVertexIndex(); + } else initial = 0; + normals = new Vector3f[valid]; + for (i = 0 ; i < valid ; i++) normals[i] = new Vector3f(); + geomArray.getNormals(initial, normals); + } + geomInfo.setNormals(normals); + } + + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + Color4f[] colors = null; + if (byRef) { + + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialColorIndex(); + } else initial = 0; + + if ( nio ) { + J3DBuffer buf = geomArray.getColorRefBuffer(); + + switch (BufferWrapper.getBufferType(buf)) { + + case BufferWrapper.TYPE_FLOAT: { + FloatBufferWrapper bb = new FloatBufferWrapper(buf); + float[] c = new float[valid * 4]; + bb.position(initial * 4); + bb.get(c, 0, valid * 4); + colors = new Color4f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color4f(c[i * 4 + 0], + c[i * 4 + 1], + c[i * 4 + 2], + c[i * 4 + 3]); + } + } + break; + + case BufferWrapper.TYPE_BYTE: { + ByteBufferWrapper bb = new ByteBufferWrapper(buf); + byte[] c = new byte[valid * 4]; + bb.position(initial * 4); + bb.get(c, 0, valid * 4); + colors = new Color4f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color4f((float)(c[i * 4 + 0] & 0xff) / 255.0f, + (float)(c[i * 4 + 1] & 0xff) / 255.0f, + (float)(c[i * 4 + 2] & 0xff) / 255.0f, + (float)(c[i * 4 + 3] & 0xff) / 255.0f); + } + } + break; + } + } else if (geomArray.getColorRef4f() != null) { + if (initial != 0) { + Color4f[] c = geomArray.getColorRef4f(); + colors = new Color4f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color4f(c[i + initial]); + } + } else colors = geomArray.getColorRef4f(); + } else if (geomArray.getColorRefFloat() != null) { + float[] c = geomArray.getColorRefFloat(); + colors = new Color4f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color4f(c[(i + initial) * 4 + 0], + c[(i + initial) * 4 + 1], + c[(i + initial) * 4 + 2], + c[(i + initial) * 4 + 3]); + } + } else if (geomArray.getColorRefByte() != null) { + byte[] c = geomArray.getColorRefByte(); + colors = new Color4f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color4f((float)(c[(i + initial) * 4 + 0] & 0xff) / 255.0f, + (float)(c[(i + initial) * 4 + 1] & 0xff) / 255.0f, + (float)(c[(i + initial) * 4 + 2] & 0xff) / 255.0f, + (float)(c[(i + initial) * 4 + 3] & 0xff) / 255.0f); + } + } else if (geomArray.getColorRef4b() != null) { + Color4b[] c = geomArray.getColorRef4b(); + colors = new Color4f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color4f((float)(c[i + initial].x & 0xff) / 255.0f, + (float)(c[i + initial].y & 0xff) / 255.0f, + (float)(c[i + initial].z & 0xff) / 255.0f, + (float)(c[i + initial].w & 0xff) / 255.0f); + } + } + // Colors4 were set in vertexFormat but none were set - OK + } else { + // Not BY_REFERENCE + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialVertexIndex(); + } else initial = 0; + colors = new Color4f[valid]; + for (i = 0 ; i < valid ; i++) colors[i] = new Color4f(); + geomArray.getColors(initial, colors); + } + geomInfo.setColors(colors); + } else if ((vertexFormat & GeometryArray.COLOR_3) != 0) { + Color3f[] colors = null; + if (byRef) { + + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialColorIndex(); + } else initial = 0; + + if ( nio ) { + J3DBuffer buf = geomArray.getColorRefBuffer(); + + switch (BufferWrapper.getBufferType(buf)) { + + case BufferWrapper.TYPE_FLOAT: { + FloatBufferWrapper bb = new FloatBufferWrapper(buf); + float[] c = new float[valid * 3]; + bb.position(initial * 3); + bb.get(c, 0, valid * 3); + colors = new Color3f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color3f(c[i * 3 + 0], + c[i * 3 + 1], + c[i * 3 + 2]); + } + } + break; + + case BufferWrapper.TYPE_BYTE: { + ByteBufferWrapper bb = new ByteBufferWrapper(buf); + byte[] c = new byte[valid * 3]; + bb.position(initial * 3); + bb.get(c, 0, valid * 3); + colors = new Color3f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color3f((float)(c[i * 3 + 0] & 0xff) / 255.0f, + (float)(c[i * 3 + 1] & 0xff) / 255.0f, + (float)(c[i * 3 + 2] & 0xff) / 255.0f); + } + } + break; + } + } else if (geomArray.getColorRef3f() != null) { + if (initial != 0) { + Color3f[] c = geomArray.getColorRef3f(); + colors = new Color3f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color3f(c[i + initial]); + } + } else colors = geomArray.getColorRef3f(); + } else if (geomArray.getColorRefFloat() != null) { + float[] c = geomArray.getColorRefFloat(); + colors = new Color3f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color3f(c[(i + initial) * 3 + 0], + c[(i + initial) * 3 + 1], + c[(i + initial) * 3 + 2]); + } + } else if (geomArray.getColorRefByte() != null) { + byte[] c = geomArray.getColorRefByte(); + colors = new Color3f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color3f((float)(c[(i + initial) * 3 + 0] & 0xff) / 255.0f, + (float)(c[(i + initial) * 3 + 1] & 0xff) / 255.0f, + (float)(c[(i + initial) * 3 + 2] & 0xff) / 255.0f); + } + } else if (geomArray.getColorRef3b() != null) { + Color3b[] c = geomArray.getColorRef3b(); + colors = new Color3f[valid]; + for (i = 0 ; i < valid ; i++) { + colors[i] = new Color3f((float)(c[i + initial].x & 0xff) / 255.0f, + (float)(c[i + initial].y & 0xff) / 255.0f, + (float)(c[i + initial].z & 0xff) / 255.0f); + } + } + // Colors3 were set in vertexFormat but none were set - OK + } else { + // Not BY_REFERENCE + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialVertexIndex(); + } else initial = 0; + colors = new Color3f[valid]; + for (i = 0 ; i < valid ; i++) colors[i] = new Color3f(); + geomArray.getColors(initial, colors); + } + geomInfo.setColors(colors); + } + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + geomInfo.setTextureCoordinateParams(texSets, 4); + for (i = 0 ; i < texSets ; i++) { + TexCoord4f[] tex = null; + if (byRef) { + + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialTexCoordIndex(i); + } else initial = 0; + + if (nio) { + J3DBuffer buf = geomArray.getTexCoordRefBuffer(i); + + if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) { + FloatBufferWrapper bb = new FloatBufferWrapper(buf); + float[] c = new float[valid * 4]; + bb.position(initial * 4); + bb.get(c, 0, valid * 4); + tex = new TexCoord4f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord4f(c[j * 4 + 0], + c[j * 4 + 1], + c[j * 4 + 2], + c[j * 4 + 3]); + } + } + // TexCoords4 were set in vertexFormat but none were set - OK + } else { + // There if no TexCoordRef4f, so we know it's float + float[] t = geomArray.getTexCoordRefFloat(i); + tex = new TexCoord4f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord4f(t[(j + initial) * 4], + t[(j + initial) * 4 + 1], + t[(j + initial) * 4 + 2], + t[(j + initial) * 4 + 3]); + } + } + } else { + // Not BY_REFERENCE + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialVertexIndex(); + } else initial = 0; + tex = new TexCoord4f[valid]; + for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord4f(); + geomArray.getTextureCoordinates(i, initial, tex); + } + geomInfo.setTextureCoordinates(i, tex); + } + int[] map = new int[geomArray.getTexCoordSetMapLength()]; + geomArray.getTexCoordSetMap(map); + geomInfo.setTexCoordSetMap(map); + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + geomInfo.setTextureCoordinateParams(texSets, 3); + for (i = 0 ; i < texSets ; i++) { + TexCoord3f[] tex = null; + if (byRef) { + + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialTexCoordIndex(i); + } else initial = 0; + + if (nio) { + J3DBuffer buf = geomArray.getTexCoordRefBuffer(i); + + if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) { + FloatBufferWrapper bb = new FloatBufferWrapper(buf); + float[] c = new float[valid * 3]; + bb.position(initial * 3); + bb.get(c, 0, valid * 3); + tex = new TexCoord3f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord3f(c[j * 3 + 0], + c[j * 3 + 1], + c[j * 3 + 2]); + } + } + // TexCoords3 were set in vertexFormat but none were set - OK + } else if (geomArray.getTexCoordRef3f(i) != null) { + if (initial != 0) { + TexCoord3f[] t = geomArray.getTexCoordRef3f(i); + tex = new TexCoord3f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord3f(t[j + initial]); + } + } else tex = geomArray.getTexCoordRef3f(i); + } else if (geomArray.getTexCoordRefFloat(i) != null) { + float[] t = geomArray.getTexCoordRefFloat(i); + tex = new TexCoord3f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord3f(t[(j + initial) * 3], + t[(j + initial) * 3 + 1], + t[(j + initial) * 3 + 2]); + } + } + // TexCoords3 were set in vertexFormat but none were set - OK + } else { + // Not BY_REFERENCE + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialVertexIndex(); + } else initial = 0; + tex = new TexCoord3f[valid]; + for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord3f(); + geomArray.getTextureCoordinates(i, initial, tex); + } + geomInfo.setTextureCoordinates(i, tex); + } + int[] map = new int[geomArray.getTexCoordSetMapLength()]; + geomArray.getTexCoordSetMap(map); + geomInfo.setTexCoordSetMap(map); + } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0 ) { + geomInfo.setTextureCoordinateParams(texSets, 2); + for (i = 0 ; i < texSets ; i++) { + TexCoord2f[] tex = null; + if (byRef) { + + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialTexCoordIndex(i); + } else initial = 0; + + if (nio) { + J3DBuffer buf = geomArray.getTexCoordRefBuffer(i); + + if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) { + FloatBufferWrapper bb = new FloatBufferWrapper(buf); + float[] c = new float[valid * 2]; + bb.position(initial * 2); + bb.get(c, 0, valid * 2); + tex = new TexCoord2f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord2f(c[j * 2 + 0], + c[j * 2 + 1]); + } + } + // TexCoords2 were set in vertexFormat but none were set - OK + } else if (geomArray.getTexCoordRefFloat(i) != null) { + float[] t = geomArray.getTexCoordRefFloat(i); + tex = new TexCoord2f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord2f(t[(j + initial) * 2 + 0], + t[(j + initial) * 2 + 1]); + } + } else if (geomArray.getTexCoordRef2f(i) != null) { + if (initial != 0) { + TexCoord2f[] t = geomArray.getTexCoordRef2f(i); + tex = new TexCoord2f[valid]; + for (j = 0 ; j < valid ; j++) { + tex[j] = new TexCoord2f(t[j + initial]); + } + } else tex = geomArray.getTexCoordRef2f(i); + } + // TexCoords2 were set in vertexFormat but none were set - OK + } else { + // Not BY_REFERENCE + int initial; + if (!(geomArray instanceof IndexedGeometryArray)) { + initial = geomArray.getInitialVertexIndex(); + } else initial = 0; + tex = new TexCoord2f[valid]; + for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord2f(); + geomArray.getTextureCoordinates(i, initial, tex); + } + geomInfo.setTextureCoordinates(i, tex); + } + int[] map = new int[geomArray.getTexCoordSetMapLength()]; + geomArray.getTexCoordSetMap(map); + geomInfo.setTexCoordSetMap(map); + } + } + } // End of processGeometryArray + + + + private static void processIndexedArray(GeometryInfo geomInfo, + IndexedGeometryArray geomArray) + { + int initial = geomArray.getInitialIndexIndex(); + int vertexFormat = geomArray.getVertexFormat(); + int texSets = geomArray.getTexCoordSetCount(); + + int valid; + if (geomArray instanceof IndexedGeometryStripArray) { + IndexedGeometryStripArray igsa = (IndexedGeometryStripArray)geomArray; + int[] strips = new int[igsa.getNumStrips()]; + igsa.getStripIndexCounts(strips); + valid = 0; + for (int i = 0 ; i < strips.length ; i++) { + valid += strips[i]; + } + } else { + valid = geomArray.getValidIndexCount(); + } + + int[] coordI = new int[valid]; + geomArray.getCoordinateIndices(initial, coordI); + geomInfo.setCoordinateIndices(coordI); + + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if ((vertexFormat & GeometryArray.NORMALS) != 0) + geomInfo.setNormalIndices(coordI); + if (((vertexFormat & GeometryArray.COLOR_3) != 0) || + ((vertexFormat & GeometryArray.COLOR_4) != 0)) + geomInfo.setColorIndices(coordI); + if (((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) || + ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) || + ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)) { + for (int i = 0 ; i < texSets ; i++) { + geomInfo.setTextureCoordinateIndices(i, coordI); + } + } + } else { + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + int[] normalI = new int[valid]; + geomArray.getNormalIndices(initial, normalI); + geomInfo.setNormalIndices(normalI); + } + + if (((vertexFormat & GeometryArray.COLOR_3) != 0) || + ((vertexFormat & GeometryArray.COLOR_4) != 0)) { + int[] colorI = new int[valid]; + geomArray.getColorIndices(initial, colorI); + geomInfo.setColorIndices(colorI); + } + + if (((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) || + ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) || + ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)) { + for (int i = 0 ; i < texSets ; i++) { + int[] texI = new int[valid]; + geomArray.getTextureCoordinateIndices(i, initial, texI); + geomInfo.setTextureCoordinateIndices(i, texI); + } + } + } + } // End of processIndexedArray + + + + private static void processStripArray(GeometryInfo geomInfo, + GeometryStripArray geomArray) + { + int[] strips = new int[geomArray.getNumStrips()]; + geomArray.getStripVertexCounts(strips); + geomInfo.setStripCounts(strips); + } // End of processStripArray + + + + private static void processIndexStripArray( + GeometryInfo geomInfo, IndexedGeometryStripArray geomArray) + { + int[] strips = new int[geomArray.getNumStrips()]; + geomArray.getStripIndexCounts(strips); + geomInfo.setStripCounts(strips); + } // End of processIndexStripArray + +} // End of class GeometryInfoGenerator diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Heap.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Heap.java new file mode 100644 index 0000000..f7c26bf --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Heap.java @@ -0,0 +1,212 @@ +/* + * $RCSfile: Heap.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:19 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class Heap { + + static void printHeapData(Triangulator triRef) { + int i; + System.out.println("\nHeap Data : numZero " + triRef.numZero + + " numHeap " + triRef.numHeap); + for(i=0; i< triRef.numHeap; i++) + System.out.println(i + " ratio " + triRef.heap[i].ratio + ", index " + + triRef.heap[i].index + ", prev " + + triRef.heap[i].prev + ", next " + + triRef.heap[i].next); + + System.out.println(" "); + + + } + + static void initHeap(Triangulator triRef) { + // Calculate the maximum bounds : N + (N -2)* 2. + // triRef.maxNumHeap = triRef.numPoints * 3; + triRef.maxNumHeap = triRef.numPoints; + triRef.heap = new HeapNode[triRef.maxNumHeap]; + + triRef.numHeap = 0; + triRef.numZero = 0; + + } + + static void storeHeapData(Triangulator triRef, int index, double ratio, + int ind, int prev, int next) { + triRef.heap[index] = new HeapNode(); + triRef.heap[index].ratio = ratio; + triRef.heap[index].index = ind; + triRef.heap[index].prev = prev; + triRef.heap[index].next = next; + } + + static void dumpOnHeap(Triangulator triRef, double ratio, + int ind, int prev, int next) { + int index; + + if (triRef.numHeap >= triRef.maxNumHeap) { + // System.out.println("Heap:dumpOnHeap.Expanding heap array ..."); + HeapNode old[] = triRef.heap; + triRef.maxNumHeap = triRef.maxNumHeap + triRef.numPoints; + triRef.heap = new HeapNode[triRef.maxNumHeap]; + System.arraycopy(old, 0, triRef.heap, 0, old.length); + } + if (ratio == 0.0) { + if (triRef.numZero < triRef.numHeap) + if(triRef.heap[triRef.numHeap] == null) + storeHeapData(triRef, triRef.numHeap, triRef.heap[triRef.numZero].ratio, + triRef.heap[triRef.numZero].index, + triRef.heap[triRef.numZero].prev, + triRef.heap[triRef.numZero].next); + else + triRef.heap[triRef.numHeap].copy(triRef.heap[triRef.numZero]); + /* + storeHeapData(triRef, triRef.numHeap, triRef.heap[triRef.numZero].ratio, + triRef.heap[triRef.numZero].index, + triRef.heap[triRef.numZero].prev, + triRef.heap[triRef.numZero].next); + */ + index = triRef.numZero; + ++triRef.numZero; + } + else { + index = triRef.numHeap; + } + + storeHeapData(triRef, index, ratio, ind, prev, next); + ++triRef.numHeap; + + } + + + static void insertIntoHeap(Triangulator triRef, double ratio, + int ind, int prev, int next) { + dumpOnHeap(triRef, ratio, ind, prev, next); + } + + + static boolean deleteFromHeap(Triangulator triRef, int[] ind, + int[] prev, int[] next) { + double rnd; + int rndInd; + + // earSorted is not implemented yet. + + if (triRef.numZero > 0) { + // assert(num_heap >= num_zero); + --triRef.numZero; + --triRef.numHeap; + + ind[0] = triRef.heap[triRef.numZero].index; + prev[0] = triRef.heap[triRef.numZero].prev; + next[0] = triRef.heap[triRef.numZero].next; + if (triRef.numZero < triRef.numHeap) + triRef.heap[triRef.numZero].copy(triRef.heap[triRef.numHeap]); + /* + storeHeapData( triRef, triRef.numZero, triRef.heap[triRef.numHeap].ratio, + triRef.heap[triRef.numHeap].index, + triRef.heap[triRef.numHeap].prev, + triRef.heap[triRef.numHeap].next); + */ + return true; + } + else if (triRef.earsRandom) { + if (triRef.numHeap <= 0) { + triRef.numHeap = 0; + return false; + } + rnd = triRef.randomGen.nextDouble(); + rndInd = (int)(rnd * triRef.numHeap); + --triRef.numHeap; + if (rndInd > triRef.numHeap) rndInd = triRef.numHeap; + + ind[0] = triRef.heap[rndInd].index; + prev[0] = triRef.heap[rndInd].prev; + next[0] = triRef.heap[rndInd].next; + if (rndInd < triRef.numHeap) + triRef.heap[rndInd].copy(triRef.heap[triRef.numHeap]); + /* + storeHeapData( triRef, rndInd, triRef.heap[triRef.numHeap].ratio, + triRef.heap[triRef.numHeap].index, + triRef.heap[triRef.numHeap].prev, + triRef.heap[triRef.numHeap].next); + */ + return true; + } + else { + if (triRef.numHeap <= 0) { + triRef.numHeap = 0; + return false; + } + --triRef.numHeap; + ind[0] = triRef.heap[triRef.numHeap].index; + prev[0] = triRef.heap[triRef.numHeap].prev; + next[0] = triRef.heap[triRef.numHeap].next; + + return true; + } + + // return false; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/HeapNode.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/HeapNode.java new file mode 100644 index 0000000..77d9449 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/HeapNode.java @@ -0,0 +1,75 @@ +/* + * $RCSfile: HeapNode.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:19 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +class HeapNode { + int index, prev, next; + double ratio; + + HeapNode() { + } + + void copy(HeapNode hNode) { + index = hNode.index; + prev = hNode.prev; + next = hNode.next; + ratio = hNode.ratio; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Left.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Left.java new file mode 100644 index 0000000..a04e6a4 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Left.java @@ -0,0 +1,74 @@ +/* + * $RCSfile: Left.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:19 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +class Left extends Object { + int ind; + int index; + + Left() { + } + + void copy(Left l) { + ind = l.ind; + index = l.index; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/ListNode.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/ListNode.java new file mode 100644 index 0000000..99a2d8e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/ListNode.java @@ -0,0 +1,87 @@ +/* + * $RCSfile: ListNode.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:19 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +class ListNode { + int index; + int prev; + int next; + int convex; + int vcntIndex; // Vertex, Color, Normal, Texture Index + + + + ListNode(int ind) { + index = ind; + prev = -1; + next = -1; + convex = 0; + vcntIndex = -1; + } + + void setCommonIndex(int comIndex) { + vcntIndex = comIndex; + + } + + int getCommonIndex() { + return vcntIndex; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/NoHash.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/NoHash.java new file mode 100644 index 0000000..8e96476 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/NoHash.java @@ -0,0 +1,302 @@ +/* + * $RCSfile: NoHash.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:19 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class NoHash { + + static final int NIL = -1; + + + static void insertAfterVtx(Triangulator triRef, int iVtx) { + int size; + + if (triRef.vtxList == null) { + size = Math.max(triRef.numVtxList+1, 100); + triRef.vtxList = new PntNode[size]; + } else if (triRef.numVtxList >= triRef.vtxList.length) { + size = Math.max(triRef.numVtxList+1, + triRef.vtxList.length + 100); + PntNode old[] = triRef.vtxList; + triRef.vtxList = new PntNode[size]; + System.arraycopy(old, 0, triRef.vtxList, 0, old.length); + } + + triRef.vtxList[triRef.numVtxList] = new PntNode(); + triRef.vtxList[triRef.numVtxList].pnt = iVtx; + triRef.vtxList[triRef.numVtxList].next = triRef.reflexVertices; + triRef.reflexVertices = triRef.numVtxList; + ++triRef.numVtxList; + ++triRef.numReflex; + } + + static void deleteFromList(Triangulator triRef, int i) { + int indPnt, indPnt1; + int indVtx; + + if(triRef.numReflex == 0) { + // System.out.println("NoHash:deleteFromList. numReflex is 0."); + return; + + } + indPnt = triRef.reflexVertices; + if(inVtxList(triRef, indPnt)==false) + System.out.println("NoHash:deleteFromList. Problem :Not is InVtxList ..." + + indPnt); + + indVtx = triRef.vtxList[indPnt].pnt; + + if (indVtx == i) { + triRef.reflexVertices = triRef.vtxList[indPnt].next; + --triRef.numReflex; + } + else { + indPnt1 = triRef.vtxList[indPnt].next; + while (indPnt1 != NIL) { + if(inVtxList(triRef, indPnt1)==false) + System.out.println("NoHash:deleteFromList. Problem :Not is InVtxList ..."+ + indPnt1); + + indVtx = triRef.vtxList[indPnt1].pnt; + if (indVtx == i) { + triRef.vtxList[indPnt].next = triRef.vtxList[indPnt1].next; + indPnt1 = NIL; + --triRef.numReflex; + } + else { + indPnt = indPnt1; + indPnt1 = triRef.vtxList[indPnt].next; + } + } + } + } + + + static boolean inVtxList(Triangulator triRef, int vtx) { + return ((0 <= vtx) && (vtx < triRef.numVtxList)); + } + + + static void freeNoHash(Triangulator triRef) { + + triRef.noHashingEdges = false; + triRef.noHashingPnts = false; + + triRef.numVtxList = 0; + } + + + + static void prepareNoHashEdges(Triangulator triRef, + int currLoopMin, int currLoopMax) { + triRef.loopMin = currLoopMin; + triRef.loopMax = currLoopMax; + + triRef.noHashingEdges = true; + + return; + } + + + static void prepareNoHashPnts(Triangulator triRef, int currLoopMin) { + int ind, ind1; + int i1; + + triRef.numVtxList = 0; + triRef.reflexVertices = NIL; + + // insert the reflex vertices into a list + ind = triRef.loops[currLoopMin]; + ind1 = ind; + triRef.numReflex = 0; + i1 = triRef.fetchData(ind1); + + do { + if (triRef.getAngle(ind1) < 0) + insertAfterVtx(triRef, ind1); + + ind1 = triRef.fetchNextData(ind1); + i1 = triRef.fetchData(ind1); + } while (ind1 != ind); + + triRef.noHashingPnts = true; + + } + + + static boolean noHashIntersectionExists(Triangulator triRef, int i1, int ind1, + int i2, int i3, BBox bb) { + int indVtx, ind5; + int indPnt; + int i4, i5; + int type[] = new int[1]; + boolean flag; + double y; + + if(triRef.noHashingPnts==false) + System.out.println("NoHash:noHashIntersectionExists noHashingPnts is false"); + + // assert(InPointsList(i1)); + // assert(InPointsList(i2)); + // assert(InPointsList(i3)); + + if (triRef.numReflex <= 0) return false; + + // first, let's extend the BBox of the line segment i2, i3 to a BBox + // of the entire triangle. + if (i1 < bb.imin) bb.imin = i1; + else if (i1 > bb.imax) bb.imax = i1; + y = triRef.points[i1].y; + if (y < bb.ymin) bb.ymin = y; + else if (y > bb.ymax) bb.ymax = y; + + // check whether the triangle i1, i2, i3 contains any reflex vertex; we + // assume that i2, i3 is the new diagonal, and that the triangle is + // oriented CCW. + indPnt = triRef.reflexVertices; + flag = false; + do { + // assert(InVtxList(ind_pnt)); + indVtx = triRef.vtxList[indPnt].pnt; + // assert(InPolyList(ind_vtx)); + i4 = triRef.fetchData(indVtx); + + + if (bb.pntInBBox(triRef, i4)) { + // only if the reflex vertex lies inside the BBox of the triangle. + ind5 = triRef.fetchNextData(indVtx); + i5 = triRef.fetchData(ind5); + if ((indVtx != ind1) && (indVtx != ind5)) { + // only if this node isn't i1, and if it still belongs to the + // polygon + if (i4 == i1) { + if (Degenerate.handleDegeneracies(triRef, i1, ind1, i2, i3, i4, indVtx)) + return true; + } + else if ((i4 != i2) && (i4 != i3)) { + flag = Numerics.vtxInTriangle(triRef, i1, i2, i3, i4, type); + if (flag) return true; + } + } + } + indPnt = triRef.vtxList[indPnt].next; + + } while (indPnt != NIL); + + return false; + } + + + + + static void deleteReflexVertex(Triangulator triRef, int ind) { + // assert(InPolyList(ind)); + deleteFromList(triRef, ind); + } + + + + + static boolean noHashEdgeIntersectionExists(Triangulator triRef, BBox bb, int i1, + int i2, int ind5, int i5) { + int ind, ind2; + int i, i3, i4; + BBox bb1; + + if(triRef.noHashingEdges==false) + System.out.println("NoHash:noHashEdgeIntersectionExists noHashingEdges is false"); + + triRef.identCntr = 0; + + // check the boundary segments. + for (i = triRef.loopMin; i < triRef.loopMax; ++i) { + ind = triRef.loops[i]; + ind2 = ind; + i3 = triRef.fetchData(ind2); + + do { + ind2 = triRef.fetchNextData(ind2); + i4 = triRef.fetchData(ind2); + // check this segment. we first compute its bounding box. + bb1 = new BBox(triRef, i3, i4); + if (bb.BBoxOverlap(bb1)) { + if (Numerics.segIntersect(triRef, bb.imin, bb.imax, bb1.imin, bb1.imax, i5)) + return true; + } + i3 = i4; + } while (ind2 != ind); + } + + // oops! this segment shares one endpoint with at least four other + // boundary segments! oh well, yet another degenerate situation... + if (triRef.identCntr >= 4) { + if (BottleNeck.checkBottleNeck(triRef, i5, i1, i2, ind5)) + return true; + else + return false; + } + + return false; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/NormalGenerator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/NormalGenerator.java new file mode 100644 index 0000000..12f7532 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/NormalGenerator.java @@ -0,0 +1,907 @@ +/* + * $RCSfile: NormalGenerator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:19 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.GeometryInfo; +import com.sun.j3d.utils.geometry.EdgeTable; +import java.util.ArrayList; +import javax.vecmath.Vector3f; +import javax.vecmath.Point3f; + +/** + * The NormalGenerator utility will calculate and fill in the normals + * of a GeometryInfo object. The calculated normals are estimated based + * on an analysis of the indexed coordinate information. If your data + * isn't indexed, index lists will be created.

+ *

+ * If two (or more) triangles in the model share the same coordinate + * index then the normal generator will attempt to generate one normal + * for the vertex, resulting in a "smooth" looking surface. If two + * coordinates don't have the same index then they will have two + * separate normals, even if they have the same position. This will + * result in a "crease" in your object. If you suspect that your + * data isn't properly indexed, call GeometryInfo.recomputeIndexes().

+ *

+ * Of course, sometimes your model *has* a crease in it. That's what + * creaseAngle is. If two triangles' normals differ by more than + * creaseAngle, then the vertex will get two separate normals, creating a + * discontinuous crease in the model. This is perfect for the edge + * of a table or the corner of a cube, for instance. + */ + +public class NormalGenerator { + + private double creaseAngle; + private Vector3f facetNorms[]; + private ArrayList tally; + private GeometryInfo gi; + private int coordInds[]; + private int normalInds[]; + private int colorInds[]; + private int texInds[][]; + private int stripCounts[]; + private static long t1=0, t2=0, t3=0, t4=0, t5=0, t6=0; + private Triangulator tr = null; + private int numTexSets; + + + // 0 - No debug info + // 1 - Facet Normals + // 2 - Connection info + // 4 - Normals + // 8 - StripCounts + // 16 - Timing + // 32 - Hard edges + // 64 - Coordinate and normal indices + // 128 - Vertex normal calculation info + private static final int DEBUG = 0; + + + + // Calculate the normal of each triangle in the list by finding + // the cross product + private void calculatefacetNorms() + { + Point3f coordinates[] = gi.getCoordinates(); + facetNorms = new Vector3f[coordInds.length / 3]; + Vector3f a = new Vector3f(); + Vector3f b = new Vector3f(); + if ((DEBUG & 1) != 0) System.out.println("Facet normals:"); + + if (gi.getOldPrim() != gi.QUAD_ARRAY) { + for (int t = 0 ; t < coordInds.length ; t += 3) { + a.sub(coordinates[coordInds[t + 2]], coordinates[coordInds[t + 1]]); + b.sub(coordinates[coordInds[t + 0]], coordinates[coordInds[t + 1]]); + facetNorms[t / 3] = new Vector3f(); + facetNorms[t / 3].cross(a, b); + facetNorms[t / 3].normalize(); + + if (Float.isNaN(facetNorms[t / 3].x)) { + // Normal isn't valid + facetNorms[t / 3].x = 1.0f; + facetNorms[t / 3].y = facetNorms[t / 3].z = 0.0f; + } + if ((DEBUG & 1) != 0) { + System.out.println(" " + (t/3) + " " + facetNorms[t / 3]); + } + } + } else { + // For quads, the facet normal of both triangles is the cross + // product of the two vectors that make an 'X' across the quad. + for (int t = 0 ; t < coordInds.length ; t += 6) { + a.sub(coordinates[coordInds[t + 2]], coordinates[coordInds[t + 0]]); + b.sub(coordinates[coordInds[t + 5]], coordinates[coordInds[t + 1]]); + facetNorms[t / 3] = new Vector3f(); + facetNorms[t / 3].cross(a, b); + facetNorms[t / 3].normalize(); + + if (Float.isNaN(facetNorms[t / 3].x)) { + // Normal isn't valid + facetNorms[t / 3].x = 1.0f; + facetNorms[t / 3].y = facetNorms[t / 3].z = 0.0f; + } + + // Second triangle of quad + facetNorms[t / 3 + 1] = new Vector3f(facetNorms[t / 3]); + + if ((DEBUG & 1) != 0) { + System.out.println(" " + (t/3) + "&" + (t/3 + 1) + " " + + facetNorms[t / 3]); + } + } + } + } // End of calculatefacetNorms + + + + // The vertex normals will be calculated by averaging the facet normals + // of groups of triangles sharing the vertex. At the end of this routine + // the groups of coordinate indexes will all be made, and the normal + // indices will point to these groups. + // + // The routine works by going through each vertex of each triangle. + // Starting at a triangle, we see if the vertex normal can be shared + // with the neighbor triangle (their facet normals differ by less than + // creaseAngle). If they can be shared, then we move from that triangle + // to the next and the next in a circle around the vertex. + // + // If we hit the edge of the model or a Hard Edge (crease) then we stop + // and then try going around the vertex in the other direction. + // + // Each time we step from one triangle to the next around the center + // vertex, the triangle is added to the group of triangles whose normals + // will be averaged to make the vertex normal. + // + // Returns the largest number of triangles that share a single normal. + // + private int createHardEdges() + { + EdgeTable et = new EdgeTable(coordInds); + tally = new ArrayList(); + int normalMap[] = new int[coordInds.length]; + int maxShare = 1; + float cosine; + boolean smooth; + float threshold = (float)Math.cos(creaseAngle); + boolean goingRight; + + // Set Normal Indices array values to a flag + for (int c = 0 ; c < coordInds.length ; c++) + normalMap[c] = Integer.MAX_VALUE; + + // Cycle through each vertex + for (int c = 0 ; c < coordInds.length ; c++) { + // See if this vertex's normal has already been done + if (normalMap[c] == Integer.MAX_VALUE) { + if ((DEBUG & 32) != 0) { + System.out.println( + "Coordinate Index " + c + ": vertex " + coordInds[c]); + } + // Create a list of vertices used for calculating this normal + ArrayList sharers = new ArrayList(); + tally.add(sharers); + // Put this coordinate in the list + sharers.add(new Integer(c)); + // Point this coordinate's index at its list + normalMap[c] = tally.size() - 1; + + // First do right edge + goingRight = true; + Edge edge = new Edge(coordInds[c], + coordInds[(c + 1) % 3 == 0 ? c - 2 : c + 1]); + if ((DEBUG & 32) != 0) + System.out.println( " Right edge: " + edge); + + // This is how we'll know we've gone all the way around + int endVertex = coordInds[c % 3 == 0 ? c + 2 : c - 1]; + + // Start at current triangle + int cur = c; + + // Proceed from one triangle to the next + do { + // Look up edge in Edge Table to find neighbor triangle + Integer tableVal = et.get(edge.v2, edge.v1); + if ((DEBUG & 32) != 0) { + System.out.println( + " Search Edge: " + (new Edge(edge.v2, edge.v1))); + } + + // See if there is no triangle on the other side of this edge + if (tableVal == null) { + smooth = false; + if ((DEBUG & 32) != 0) + System.out.println(" No neighboring triangle found."); + } else { + + int n = tableVal.intValue(); + if ((DEBUG & 32) != 0) { + System.out.println( + " Table lookup result: " + n + " (vertex " + coordInds[n] + + ")"); + System.out.print(" Triangles " + (cur/3) + " & " + (n/3) + + ": "); + } + + cosine = facetNorms[cur / 3].dot(facetNorms[n / 3]); + smooth = cosine > threshold; + if (smooth) { + // The center coordinate (c) shares the same normal in these + // two triangles. Find that coordinate and set its index + // normalMap[n] = normalMap[cur]; + int centerv = (((n + 1) % 3) == 0 ? n - 2 : n + 1); + if (coordInds[c] != coordInds[centerv]) { + centerv = ((n % 3) == 0 ? n + 2 : n - 1); + } + + if ((DEBUG & 32) != 0) + System.out.println("Smooth! Adding " + centerv); + + if (normalMap[centerv] != Integer.MAX_VALUE) { + smooth = false; + if ((DEBUG & 32) != 0) System.out.println( + " Error: Coordinate aleady has normal (bad data)."); + } else { + + normalMap[centerv] = tally.size() - 1; + + // Consider this triangle's facet normal when calculating the + // vertex's normal + sharers.add(new Integer(centerv)); + if (sharers.size() > maxShare) maxShare = sharers.size(); + + // Continue on around the vertex to the next triangle + cur = n; + if (goingRight) edge.v2 = coordInds[cur]; + else edge.v1 = coordInds[cur]; + } + } else if ((DEBUG & 32) != 0) System.out.println("Hard Edge!"); + } + + if (!smooth && goingRight) { + + // We've hit an impasse going right, so now try going left + // from the original triangle + goingRight = false; + smooth = true; // Trick do loop + cur = c; // Go back to original triangle + + edge = new Edge(coordInds[(c % 3) == 0 ? c + 2 : c - 1], + coordInds[c]); + if ((DEBUG & 32) != 0) System.out.println( " Left edge: " + edge); + + } + + } while (smooth && ((goingRight && (edge.v2 != endVertex)) || + !goingRight)); + + if (((DEBUG & 32) != 0) && goingRight && (edge.v2 == endVertex)) + System.out.println(" Went all the way around!"); + } + } + + if ((DEBUG & 32) != 0) { + System.out.println("Tally:"); + for (int i = 0 ; i < tally.size() ; i++) { + System.out.print(" " + i + ": "); + ArrayList sharers = (ArrayList)(tally.get(i)); + for (int j = 0 ; j < sharers.size() ; j++) { + System.out.print(" " + sharers.get(j)); + } + System.out.println(); + } + + System.out.println("Normal Indexes:"); + for (int i = 0 ; i < normalMap.length ; i++) { + System.out.println(" " + i + ": " + normalMap[i]); + } + } + + return maxShare; + } // End of createHardEdges + + + // Now take all of the triangles who share a vertex (who have + // been grouped by the hard edge process) and average their facet + // normals to get the vertex normal + // + // This routine has something of a hack in it. We found that our + // method of breaking up data into individual triangles before + // calculating normals was causing a bug. If a polygon was broken + // into two triangles at a particular vertex, then that facet's + // normal would get averaged into the vertex normal *twice*, + // skewing the normal toward the decomposed facet. So what we did + // was to check for duplicate facet normals as we're averaging, + // not allowing the same facet normal to be counted twice. + // + // What should be done is to put the facets' normals into a separate, + // indexed, table. That way, to tell if two triangles have the + // same normal, we just need to compare indexes. This would speed up + // the process of checking for duplicates. + private void calculateVertexNormals(int maxShare) + { + Vector3f normals[]; + ArrayList sharers; + int triangle; + Vector3f fn[]; // Normals of facets joined by this vertex + int fnsize; // Number of elements currently ised in fn + + if (creaseAngle != 0.0) { + fn = new Vector3f[maxShare]; + normals = new Vector3f[tally.size()]; + normalInds = new int[coordInds.length]; + for (int n = 0 ; n < tally.size() ; n++) { + sharers = (ArrayList)(tally.get(n)); + if ((DEBUG & 128) != 0) { + System.out.println(n + ": " + sharers.size() + + " triangles:"); + } + fnsize = 0; + normals[n] = new Vector3f(); + for (int t = 0 ; t < sharers.size() ; t++) { + int v = ((Integer)sharers.get(t)).intValue(); + // See if index removed by hard edge process + if (v != -1) { + triangle = v / 3; + if (!Float.isNaN(facetNorms[triangle].x)) { + + int f; + // Don't add the same facet normal twice + for (f = 0 ; f < fnsize ; f++) { + if (fn[f].equals(facetNorms[triangle])) break; + } + + normalInds[v] = n; + if (f == fnsize) { + // Didn't find this triangle's normal already in the list + normals[n].add(facetNorms[triangle]); + fn[fnsize++] = facetNorms[triangle]; + } else if ((DEBUG & 128) != 0) { + System.out.println(" triangle " + t + " ignored."); + } + } + } + } + normals[n].normalize(); + if (Float.isNaN(normals[n].x)) { + // Normal isn't valid + normals[n].x = 1.0f; normals[n].y = normals[n].z = 0.0f; + } + if ((DEBUG & 128) != 0) { + for (int t = 0 ; t < sharers.size() ; t++) { + int v = ((Integer)sharers.get(t)).intValue(); + if (v != -1) { + triangle = v / 3; + System.out.println(" " + facetNorms[triangle]); + } + } + System.out.println(" Result: " + normals[n]); + System.out.println(); + } + } + } else { + // This code renders the facet normals + normals = facetNorms; + + normalInds = new int[facetNorms.length * 3]; + for (int i = 0 ; i < facetNorms.length ; i++) { + normalInds[i * 3 + 0] = i; + normalInds[i * 3 + 1] = i; + normalInds[i * 3 + 2] = i; + } + } + gi.setNormals(normals); + + if ((DEBUG & 4) != 0) { + System.out.println("Normals:"); + for (int i = 0 ; i < normals.length ; i++) { + System.out.println(" " + i + " " + normals[i]); + } + System.out.println("Indices:"); + for (int i = 0 ; i < normalInds.length ; i++) { + System.out.println(" " + i + " " + normalInds[i]); + } + } + } // End of calculateVertexNormals + + + + // The original data was in quads and we converted it to triangles to + // calculate the normals. Now we are converting it back to quads. + // It's a very simple algorithm. + // Since both sub-triangles of a quad have the same facet normal, + // there should never be a hard edge down the middle of the quad. + // Therefore, the vertices of the shared edge of the two subtriangles + // should have the same normal index in both triangles. + private int[] triToQuadIndices(int oldList[]) + { + if (oldList == null) return null; + + int newList[] = new int[oldList.length / 6 * 4]; + // index list to pass back + // Cycle through each pair of triangles and put them together + for (int q = 0 ; q < oldList.length / 6 ; q++) { + newList[q * 4 + 0] = oldList[q * 6 + 0]; + newList[q * 4 + 1] = oldList[q * 6 + 1]; + newList[q * 4 + 2] = oldList[q * 6 + 2]; + newList[q * 4 + 3] = oldList[q * 6 + 5]; + } + + return newList; + } // End of triToQuadIndices + + + + // The original data was in quads. We converted it to triangles to + // calculate normals. Now we need to convert it back to quads. + private void convertTriToQuad(GeometryInfo geom) + { + // Create the new arrays + geom.setCoordinateIndices( + triToQuadIndices(geom.getCoordinateIndices())); + geom.setColorIndices(triToQuadIndices(geom.getColorIndices())); + geom.setNormalIndices(triToQuadIndices(geom.getNormalIndices())); + int num = geom.getTexCoordSetCount(); + for (int i = 0 ; i < num ; i++) { + geom.setTextureCoordinateIndices(i, + triToQuadIndices(geom.getTextureCoordinateIndices(i))); + } + geom.setPrimitive(gi.QUAD_ARRAY); + } // End of convertTriToQuad() + + + + // The original data was in fans and we converted it to triangles to + // calculate the normals. Now we are converting it back to fans. + // We have already calculated the new stripCounts, so now we need + // to change the index lists so they match up with the stripCounts. + // It's a very simple algorithm. The paramater oldList is the + // index list being compressed back into fans (could be coordinate, + // color, normal, or texCoord indices) and numVerts is the pre- + // calculated total of all entries of the stripCounts array. + private int[] triToFanIndices(int sc[], int oldList[], int numVerts) + { + if (oldList == null) return null; + + int newList[] = new int[numVerts]; // index list to pass back + int vert1 = 0; // 1st vertex of triangle + int n = 0; // index into newList + // Cycle through each fan in the new list + for (int f = 0 ; f < sc.length ; f++) { + // Copy entire first triangle into new array + newList[n++] = oldList[vert1++]; + newList[n++] = oldList[vert1++]; + newList[n++] = oldList[vert1++]; + // Each additional triangle in the fan only needs one vertex + for (int t = 3 ; t < sc[f] ; t++) { + newList[n++] = oldList[vert1 + 2]; + vert1 += 3; + } + } + return newList; + } // End of triToFanIndices + + + + // + // The original data was in fans. We converted it to triangles to + // calculate normals. Now we need to convert it back to fans. + // The hard part is that, if we found a hard edge in the middle of + // a fan, we need to split the fan into two. To tell if there's + // a hard edge there, we compare the normal indices of both + // vertices comprising the edge. + private void convertTriToFan(GeometryInfo geom, int oldStripCounts[]) + { + int ni[] = geom.getNormalIndices(); + + // + // Calculate new stripCounts array + // + int tri = 0; // Which triangle currently being converted + ArrayList newStripCounts; + newStripCounts = new ArrayList(oldStripCounts.length + 100); + + // Use the original stripCounts array + for (int f = 0 ; f < oldStripCounts.length ; f++) { + int stripCount = 3; + + // Cycle through each triangle in the fan, comparing to the + // next triangle in the fan. Compare the normal indices of + // both vertices of the edge to see if the two triangles + // can be mated + for (int t = 0 ; t < oldStripCounts[f] - 3 ; t++) { + // The first vertex of this triangle must match the first + // vertex of the next, AND the third vertex of this + // triangle must match the second vertex of the next. + if ((ni[tri * 3] == ni[(tri+1) * 3]) && + (ni[tri * 3 + 2] == ni[(tri+1) * 3 + 1])) { + // OK to extend fan + stripCount++; + } else { + // hard edge within fan + newStripCounts.add(new Integer(stripCount)); + stripCount = 3; + } + tri++; + } + tri++; + newStripCounts.add(new Integer(stripCount)); + } + + // Convert from ArrayList to int[] + int sc[] = new int[newStripCounts.size()]; + for (int i = 0 ; i < sc.length ; i++) + sc[i] = ((Integer)newStripCounts.get(i)).intValue(); + newStripCounts = null; + + // + // Change the index lists so they match up with the new stripCounts + // + + // See how many vertices we'll need + int c = 0; + for (int i = 0 ; i < sc.length ; i++) c += sc[i]; + + // Create the new arrays + geom.setCoordinateIndices( + triToFanIndices(sc, geom.getCoordinateIndices(), c)); + geom.setColorIndices(triToFanIndices(sc, geom.getColorIndices(), c)); + geom.setNormalIndices(triToFanIndices(sc, geom.getNormalIndices(), c)); + int num = geom.getTexCoordSetCount(); + for (int i = 0 ; i < num ; i++) { + geom.setTextureCoordinateIndices(i, + triToFanIndices(sc, geom.getTextureCoordinateIndices(i), c)); + } + + if ((DEBUG & 8) != 0) { + System.out.print("Old stripCounts:"); + for (int i = 0 ; i < oldStripCounts.length ; i++) { + System.out.print(" " + oldStripCounts[i]); + } + System.out.println(); + System.out.print("New stripCounts:"); + for (int i = 0 ; i < sc.length ; i++) { + System.out.print(" " + sc[i]); + } + System.out.println(); + } + + geom.setStripCounts(sc); + geom.setPrimitive(gi.TRIANGLE_FAN_ARRAY); + } // End of convertTriToFan() + + + + // The original data was in strips and we converted it to triangles to + // calculate the normals. Now we are converting it back to strips. + // We have already calculated the new stripCounts, so now we need + // to change the index lists so they match up with the stripCounts. + // It's a very simple algorithm. The paramater oldList is the + // index list being compressed back into strips (could be coordinate, + // color, normal, or texCoord indices) and numVerts is the pre- + // calculated total of all entries of the stripCounts array. + private int[] triToStripIndices(int sc[], int oldList[], int numVerts) + { + if (oldList == null) return null; + + int newList[] = new int[numVerts]; // index list to pass back + int vert1 = 0; // 1st vertex of triangle + int n = 0; // index into newList + // Cycle through each strip in the new list + for (int f = 0 ; f < sc.length ; f++) { + // Copy entire first triangle into new array + newList[n++] = oldList[vert1++]; + newList[n++] = oldList[vert1++]; + newList[n++] = oldList[vert1++]; + // Each additional triangle in the fan only needs one vertex + for (int t = 3 ; t < sc[f] ; t++) { + // Every other triangle has been reversed to preserve winding + newList[n++] = oldList[vert1 + 2 - (t % 2)]; + vert1 += 3; + } + } + return newList; + } // End of triToStripIndices + + + + private void convertTriToStrip(GeometryInfo geom, int oldStripCounts[]) + { + int ni[] = geom.getNormalIndices(); + + // + // Calculate new stripCounts array + // + int tri = 0; // Which triangle currently being converted + ArrayList newStripCounts; + newStripCounts = new ArrayList(oldStripCounts.length + 100); + + // Use the original stripCounts array + for (int f = 0 ; f < oldStripCounts.length ; f++) { + int stripCount = 3; + + // Cycle through each triangle in the strip, comparing to the + // next triangle in the strip. Compare the normal indices of + // both vertices of the edge to see if the two triangles + // can be mated. + for (int t = 0 ; t < oldStripCounts[f] - 3 ; t++) { + // Every other triangle has been reversed to preserve winding + if (t % 2 == 0) { + // The middle vertex of this triangle needs to match the + // first vertex of the next, AND the third vertices of + // the two triangles must match + if ((ni[tri * 3 + 1] == ni[(tri+1) * 3]) && + (ni[tri * 3 + 2] == ni[(tri+1) * 3 + 2])) { + // OK to extend strip + stripCount++; + } else { + // hard edge within strip + newStripCounts.add(new Integer(stripCount)); + stripCount = 3; + + // Can't start a new strip on an odd edge so output + // isolated triangle + if (t < oldStripCounts[f] - 4) { + newStripCounts.add(new Integer(3)); + t++; + } + } + } else { + // The middle vertex of this triangle must match the middle + // vertex of the next, AND the third vertex of this triangle + // must match the first vertex of the next + if ((ni[tri * 3 + 1] == ni[(tri+1) * 3 + 1]) && + (ni[tri * 3 + 2] == ni[(tri+1) * 3])) { + // OK to extend strip + stripCount++; + } else { + // hard edge within strip + newStripCounts.add(new Integer(stripCount)); + stripCount = 3; + } + } + tri++; + } + tri++; + newStripCounts.add(new Integer(stripCount)); + } + + // Convert from ArrayList to int[] + int sc[] = new int[newStripCounts.size()]; + for (int i = 0 ; i < sc.length ; i++) + sc[i] = ((Integer)newStripCounts.get(i)).intValue(); + newStripCounts = null; + + // + // Change the index lists so they match up with the new stripCounts + // + + // See how many vertices we'll need + int c = 0; + for (int i = 0 ; i < sc.length ; i++) c += sc[i]; + + // Create the new arrays + geom.setCoordinateIndices( + triToStripIndices(sc, geom.getCoordinateIndices(), c)); + geom.setColorIndices(triToStripIndices(sc, geom.getColorIndices(), c)); + geom.setNormalIndices(triToStripIndices(sc, geom.getNormalIndices(), c)); + int num = geom.getTexCoordSetCount(); + for (int i = 0 ; i < num ; i++) { + geom.setTextureCoordinateIndices(i, + triToStripIndices(sc, geom.getTextureCoordinateIndices(i), c)); + } + + if ((DEBUG & 8) != 0) { + System.out.print("Old stripCounts:"); + for (int i = 0 ; i < oldStripCounts.length ; i++) { + System.out.print(" " + oldStripCounts[i]); + } + System.out.println(); + System.out.print("New stripCounts:"); + for (int i = 0 ; i < sc.length ; i++) { + System.out.print(" " + sc[i]); + } + System.out.println(); + } + + geom.setStripCounts(sc); + geom.setPrimitive(gi.TRIANGLE_STRIP_ARRAY); + }// End of convertTriToStrip() + + + + /** + * Used when the user calls the NormalGenerator and not + * the Stripifier or Triangulator. We had to convert + * the user's data to indexed triangles before we could + * generate normals, so now we need to switch back to + * the original format. + */ + void convertBackToOldPrim(GeometryInfo geom, int oldPrim, + int oldStripCounts[]) + { + if (oldPrim == geom.TRIANGLE_ARRAY) return; + + switch (oldPrim) { + case GeometryInfo.QUAD_ARRAY: + convertTriToQuad(geom); + break; + case GeometryInfo.TRIANGLE_FAN_ARRAY: + convertTriToFan(geom, oldStripCounts); + break; + case GeometryInfo.TRIANGLE_STRIP_ARRAY: + convertTriToStrip(geom, oldStripCounts); + break; + } + + if ((DEBUG & 64) != 0) { + System.out.println("Coordinate and normal indices (original):"); + for (int i = 0 ; i < coordInds.length ; i++) { + System.out.println(i + " " + coordInds[i] + " " + normalInds[i]); + } + } + } // End of convertBackToOldPrim + + + + /** + * Generate normals for the GeometryInfo object. If the GeometryInfo + * object didn't previously contain indexed data, indexes are made + * by collapsing identical positions into a single index. Any + * normal information previously contained in the GeometryInfo + * object is lost. Strips and Fans are converted into individual + * triangles for Normal generation, but are stitched back together + * if GeometryInfo.getGeometryArray() (or getIndexedGeometryArray()) + * is called without stripifying first. + */ + public void generateNormals(GeometryInfo geom) + { + gi = geom; + gi.setNormals((Vector3f[])null); + gi.setNormalIndices(null); + + long time = 0L; + if ((DEBUG & 16) != 0) { + time = System.currentTimeMillis(); + } + + if (gi.getPrimitive() == gi.POLYGON_ARRAY) { + if (tr == null) tr = new Triangulator(); + tr.triangulate(gi); + } else { + // NOTE: We should calculate facet normals before converting to + // triangles. + gi.rememberOldPrim(); + gi.convertToIndexedTriangles(); + } + + // Cache some of the GeometryInfo fields + coordInds = gi.getCoordinateIndices(); + colorInds = gi.getColorIndices(); + normalInds = gi.getNormalIndices(); + numTexSets = gi.getTexCoordSetCount(); + texInds = new int[numTexSets][]; + for (int i = 0 ; i < numTexSets ; i++) { + texInds[i] = gi.getTextureCoordinateIndices(i); + } + stripCounts = gi.getStripCounts(); + + if ((DEBUG & 16) != 0) { + t1 += System.currentTimeMillis() - time; + System.out.println("Convert to triangles: " + t1 + " ms"); + time = System.currentTimeMillis(); + } + + calculatefacetNorms(); + if ((DEBUG & 16) != 0) { + t2 += System.currentTimeMillis() - time; + System.out.println("Calculate Facet Normals: " + t2 + " ms"); + time = System.currentTimeMillis(); + } + + int maxShare = createHardEdges(); + if ((DEBUG & 16) != 0) { + t3 += System.currentTimeMillis() - time; + System.out.println("Hard Edges: " + t3 + " ms"); + time = System.currentTimeMillis(); + } + + calculateVertexNormals(maxShare); + if ((DEBUG & 16) != 0) { + t5 += System.currentTimeMillis() - time; + System.out.println("Vertex Normals: " + t5 + " ms"); + time = System.currentTimeMillis(); + } + + if ((DEBUG & 64) != 0) { + System.out.println("Coordinate and normal indices (triangles):"); + for (int i = 0 ; i < coordInds.length ; i++) { + System.out.println(i + " " + coordInds[i] + " " + normalInds[i]); + } + } + + // We have been caching some info from the GeometryInfo, so we need + // to update it. + gi.setCoordinateIndices(coordInds); + gi.setColorIndices(colorInds); + gi.setNormalIndices(normalInds); + for (int i = 0 ; i < numTexSets ; i++) { + gi.setTextureCoordinateIndices(i, texInds[i]); + } + gi.setStripCounts(stripCounts); + } // End of generateNormals + + + + /** + * Set the crease angle. + * If two triangles' normals differ by more than + * creaseAngle, then the vertex will get two separate normals, creating a + * discontinuous crease in the model. This is perfect for the edge + * of a table or the corner of a cube, for instance. Clamped to + * 0 <= creaseAngle <= PI. Optimizations are made for creaseAngle == 0 + * (facet normals) and creaseAngle == PI (smooth shading). + */ + public void setCreaseAngle(double radians) + { + if (radians > Math.PI) radians = Math.PI; + if (radians < 0.0) radians = 0.0; + creaseAngle = radians; + } // End of setCreaseAngle + + + + /** + * Returns the current value of the crease angle, in radians. + */ + public double getCreaseAngle() + { + return creaseAngle; + } // End of getCreaseAngle + + + + /** + * Constructor. Construct a NormalGenerator object with creaseAngle + * set to the given value. + */ + public NormalGenerator(double radians) + { + creaseAngle = radians; + } // End of NormalGenerator(double) + + + + /** + * Constructor. Construct a NormalGenerator object with creaseAngle + * set to 44 degrees (0.767944871 radians). + */ + public NormalGenerator() + { + this(44.0 * Math.PI / 180.0); + } // End of NormalGenerator() +} // End of class NormalGenerator + +// End of file NormalGenerator.java diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Numerics.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Numerics.java new file mode 100644 index 0000000..d934810 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Numerics.java @@ -0,0 +1,644 @@ +/* + * $RCSfile: Numerics.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:20 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class Numerics { + + static double max3(double a, double b, double c) + { + return (((a) > (b)) ? (((a) > (c)) ? (a) : (c)) + : (((b) > (c)) ? (b) : (c))); + } + + static double min3(double a, double b, double c) + { + return (((a) < (b)) ? (((a) < (c)) ? (a) : (c)) + : (((b) < (c)) ? (b) : (c))); + } + + static boolean lt(double a, double eps) + { + return ((a) < -eps); + } + + static boolean le(double a, double eps) + { + return (a <= eps); + } + + static boolean ge(double a, double eps) + { + return (!((a) <= -eps)); + } + + static boolean eq(double a, double eps) + { + return (((a) <= eps) && !((a) < -eps)); + } + + static boolean gt(double a, double eps) + { + return !((a) <= eps); + } + + static double baseLength(Tuple2f u, Tuple2f v) { + double x, y; + x = (v).x - (u).x; + y = (v).y - (u).y; + return Math.abs(x) + Math.abs(y); + } + + static double sideLength(Tuple2f u, Tuple2f v) { + double x, y; + x = (v).x - (u).x; + y = (v).y - (u).y; + return x * x + y * y; + } + + /** + * This checks whether i3, which is collinear with i1, i2, is + * between i1, i2. note that we rely on the lexicographic sorting of the + * points! + */ + static boolean inBetween(int i1, int i2, int i3) { + return ((i1 <= i3) && (i3 <= i2)); + } + + static boolean strictlyInBetween(int i1, int i2, int i3) { + return ((i1 < i3) && (i3 < i2)); + } + + /** + * this method computes the determinant det(points[i],points[j],points[k]) + * in a consistent way. + */ + static double stableDet2D(Triangulator triRef, int i, int j, int k) { + double det; + Point2f numericsHP, numericsHQ, numericsHR; + + // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)|| + // (triRef.inPointsList(k)==false)) + // System.out.println("Numerics.stableDet2D Not inPointsList " + i + " " + j + // + " " + k); + + if ((i == j) || (i == k) || (j == k)) { + det = 0.0; + } + else { + numericsHP = triRef.points[i]; + numericsHQ = triRef.points[j]; + numericsHR = triRef.points[k]; + + if (i < j) { + if (j < k) /* i < j < k */ + det = Basic.det2D(numericsHP, numericsHQ, numericsHR); + else if (i < k) /* i < k < j */ + det = -Basic.det2D(numericsHP, numericsHR, numericsHQ); + else /* k < i < j */ + det = Basic.det2D(numericsHR, numericsHP, numericsHQ); + } + else { + if (i < k) /* j < i < k */ + det = -Basic.det2D(numericsHQ, numericsHP, numericsHR); + else if (j < k) /* j < k < i */ + det = Basic.det2D(numericsHQ, numericsHR, numericsHP); + else /* k < j < i */ + det = -Basic.det2D(numericsHR, numericsHQ, numericsHP); + } + } + + return det; + } + + /** + * Returns the orientation of the triangle. + * @return +1 if the points i, j, k are given in CCW order; + * -1 if the points i, j, k are given in CW order; + * 0 if the points i, j, k are collinear. + */ + static int orientation(Triangulator triRef, int i, int j, int k) { + int ori; + double numericsHDet; + numericsHDet = stableDet2D(triRef, i, j, k); + // System.out.println("orientation : numericsHDet " + numericsHDet); + if (lt(numericsHDet, triRef.epsilon)) ori = -1; + else if (gt(numericsHDet, triRef.epsilon)) ori = 1; + else ori = 0; + return ori; + } + + /** + * This method checks whether l is in the cone defined by i, j and j, k + */ + static boolean isInCone(Triangulator triRef, int i, int j, int k, + int l, boolean convex) { + boolean flag; + int numericsHOri1, numericsHOri2; + + // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)|| + // (triRef.inPointsList(k)==false)||(triRef.inPointsList(l)==false)) + // System.out.println("Numerics.isInCone Not inPointsList " + i + " " + j + // + " " + k + " " + l); + + flag = true; + if (convex) { + if (i != j) { + numericsHOri1 = orientation(triRef, i, j, l); + // System.out.println("isInCone : i != j, numericsHOri1 = " + numericsHOri1); + if (numericsHOri1 < 0) flag = false; + else if (numericsHOri1 == 0) { + if (i < j) { + if (!inBetween(i, j, l)) flag = false; + } + else { + if (!inBetween(j, i, l)) flag = false; + } + } + } + if ((j != k) && (flag == true)) { + numericsHOri2 = orientation(triRef, j, k, l); + // System.out.println("isInCone : ((j != k) && (flag == true)), numericsHOri2 = " + + // numericsHOri2); + if (numericsHOri2 < 0) flag = false; + else if (numericsHOri2 == 0) { + if (j < k) { + if (!inBetween(j, k, l)) flag = false; + } + else { + if (!inBetween(k, j, l)) flag = false; + } + } + } + } + else { + numericsHOri1= orientation(triRef, i, j, l); + if (numericsHOri1 <= 0) { + numericsHOri2 = orientation(triRef, j, k, l); + if (numericsHOri2 < 0) flag = false; + } + } + return flag; + } + + + /** + * Returns convex angle flag. + * @return 0 ... if angle is 180 degrees
+ * 1 ... if angle between 0 and 180 degrees
+ * 2 ... if angle is 0 degrees
+ * -1 ... if angle between 180 and 360 degrees
+ * -2 ... if angle is 360 degrees
+ */ + static int isConvexAngle(Triangulator triRef, int i, int j, int k, int ind) { + int angle; + double numericsHDot; + int numericsHOri1; + Point2f numericsHP, numericsHQ; + + // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)|| + // (triRef.inPointsList(k)==false)) + // System.out.println("Numerics.isConvexAngle: Not inPointsList " + i + " " + j + // + " " + k); + + if (i == j) { + if (j == k) { + // all three vertices are identical; we set the angle to 1 in + // order to enable clipping of j. + return 1; + } + else { + // two of the three vertices are identical; we set the angle to 1 + // in order to enable clipping of j. + return 1; + } + } + else if (j == k) { + // two vertices are identical. we could either determine the angle + // by means of yet another lengthy analysis, or simply set the + // angle to -1. using -1 means to err on the safe side, as all the + // incarnations of this vertex will be clipped right at the start + // of the ear-clipping algorithm. thus, eventually there will be no + // other duplicates at this vertex position, and the regular + // classification of angles will yield the correct answer for j. + return -1; + } + else { + numericsHOri1 = orientation(triRef, i, j, k); + // System.out.println("i " + i + " j " + j + " k " + k + " ind " + ind + + // ". In IsConvexAngle numericsHOri1 is " + + // numericsHOri1); + if (numericsHOri1 > 0) { + angle = 1; + } + else if (numericsHOri1 < 0) { + angle = -1; + } + else { + // 0, 180, or 360 degrees. + numericsHP = new Point2f(); + numericsHQ = new Point2f(); + Basic.vectorSub2D(triRef.points[i], triRef.points[j], numericsHP); + Basic.vectorSub2D(triRef.points[k], triRef.points[j], numericsHQ); + numericsHDot = Basic.dotProduct2D(numericsHP, numericsHQ); + if (numericsHDot < 0.0) { + // 180 degrees. + angle = 0; + } + else { + // 0 or 360 degrees? this cannot be judged locally, and more + // work is needed. + + angle = spikeAngle(triRef, i, j, k, ind); + // System.out.println("SpikeAngle return is "+ angle); + } + } + } + return angle; + } + + + /** + * This method checks whether point i4 is inside of or on the boundary + * of the triangle i1, i2, i3. + */ + static boolean pntInTriangle(Triangulator triRef, int i1, int i2, int i3, int i4) { + boolean inside; + int numericsHOri1; + + inside = false; + numericsHOri1 = orientation(triRef, i2, i3, i4); + if (numericsHOri1 >= 0) { + numericsHOri1 = orientation(triRef, i1, i2, i4); + if (numericsHOri1 >= 0) { + numericsHOri1 = orientation(triRef, i3, i1, i4); + if (numericsHOri1 >= 0) inside = true; + } + } + return inside; + } + + + /** + * This method checks whether point i4 is inside of or on the boundary + * of the triangle i1, i2, i3. it also returns a classification if i4 is + * on the boundary of the triangle (except for the edge i2, i3). + */ + static boolean vtxInTriangle(Triangulator triRef, int i1, int i2, int i3, + int i4, int[] type) { + boolean inside; + int numericsHOri1; + + inside = false; + numericsHOri1 = orientation(triRef, i2, i3, i4); + if (numericsHOri1 >= 0) { + numericsHOri1 = orientation(triRef, i1, i2, i4); + if (numericsHOri1 > 0) { + numericsHOri1 = orientation(triRef, i3, i1, i4); + if (numericsHOri1 > 0) { + inside = true; + type[0] = 0; + } + else if (numericsHOri1 == 0) { + inside = true; + type[0] = 1; + } + } + else if (numericsHOri1 == 0) { + numericsHOri1 = orientation(triRef, i3, i1, i4); + if (numericsHOri1 > 0) { + inside = true; + type[0] = 2; + } + else if (numericsHOri1 == 0) { + inside = true; + type[0] = 3; + } + } + } + return inside; + } + + + /** + * Checks whether the line segments i1, i2 and i3, i4 intersect. no + * intersection is reported if they intersect at a common vertex. + * the function assumes that i1 <= i2 and i3 <= i4. if i3 or i4 lies + * on i1, i2 then an intersection is reported, but no intersection is + * reported if i1 or i2 lies on i3, i4. this function is not symmetric! + */ + static boolean segIntersect(Triangulator triRef, int i1, int i2, int i3, + int i4, int i5) { + int ori1, ori2, ori3, ori4; + + // if((triRef.inPointsList(i1)==false)||(triRef.inPointsList(i2)==false)|| + // (triRef.inPointsList(i3)==false)||(triRef.inPointsList(i4)==false)) + // System.out.println("Numerics.segIntersect Not inPointsList " + i1 + " " + i2 + // + " " + i3 + " " + i4); + // + // if((i1 > i2) || (i3 > i4)) + // System.out.println("Numerics.segIntersect i1>i2 or i3>i4 " + i1 + " " + i2 + // + " " + i3 + " " + i4); + + if ((i1 == i2) || (i3 == i4)) return false; + if ((i1 == i3) && (i2 == i4)) return true; + + if ((i3 == i5) || (i4 == i5)) ++(triRef.identCntr); + + ori3 = orientation(triRef, i1, i2, i3); + ori4 = orientation(triRef, i1, i2, i4); + if (((ori3 == 1) && (ori4 == 1)) || + ((ori3 == -1) && (ori4 == -1))) return false; + + if (ori3 == 0) { + if (strictlyInBetween(i1, i2, i3)) return true; + if (ori4 == 0) { + if (strictlyInBetween(i1, i2, i4)) return true; + } + else return false; + } + else if (ori4 == 0) { + if (strictlyInBetween(i1, i2, i4)) return true; + else return false; + } + + ori1 = orientation(triRef, i3, i4, i1); + ori2 = orientation(triRef, i3, i4, i2); + if (((ori1 <= 0) && (ori2 <= 0)) || + ((ori1 >= 0) && (ori2 >= 0))) return false; + + return true; + } + + + /** + * this function computes a quality measure of a triangle i, j, k. + * it returns the ratio `base / height', where base is the length of the + * longest side of the triangle, and height is the normal distance + * between the vertex opposite of the base side and the base side. (as + * usual, we again use the l1-norm for distances.) + */ + static double getRatio(Triangulator triRef, int i, int j, int k) { + double area, a, b, c, base, ratio; + Point2f p, q, r; + + // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)|| + // (triRef.inPointsList(k)==false)) + // System.out.println("Numerics.getRatio: Not inPointsList " + i + " " + j + // + " " + k); + + p = triRef.points[i]; + q = triRef.points[j]; + r = triRef.points[k]; + + + a = baseLength(p, q); + b = baseLength(p, r); + c = baseLength(r, q); + base = max3(a, b, c); + + if ((10.0 * a) < Math.min(b, c)) return 0.1; + + area = stableDet2D(triRef, i, j, k); + if (lt(area, triRef.epsilon)) { + area = -area; + } + else if (!gt(area, triRef.epsilon)) { + if (base > a) return 0.1; + else return Double.MAX_VALUE; + } + + ratio = base * base / area; + + if (ratio < 10.0) return ratio; + else { + if (a < base) return 0.1; + else return ratio; + } + } + + + static int spikeAngle(Triangulator triRef, int i, int j, int k, int ind) { + int ind1, ind2, ind3; + int i1, i2, i3; + + // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)|| + // (triRef.inPointsList(k)==false)) + // System.out.println("Numerics.spikeAngle: Not inPointsList " + i + " " + j + // + " " + k); + + ind2 = ind; + i2 = triRef.fetchData(ind2); + + // if(i2 != j) + // System.out.println("Numerics.spikeAngle: i2 != j " + i2 + " " + j ); + + ind1 = triRef.fetchPrevData(ind2); + i1 = triRef.fetchData(ind1); + + // if(i1 != i) + // System.out.println("Numerics.spikeAngle: i1 != i " + i1 + " " + i ); + + ind3 = triRef.fetchNextData(ind2); + i3 = triRef.fetchData(ind3); + + // if(i3 != k) + // System.out.println("Numerics.spikeAngle: i3 != k " + i3 + " " + k ); + + return recSpikeAngle(triRef, i, j, k, ind1, ind3); + } + + + + static int recSpikeAngle(Triangulator triRef, int i1, int i2, int i3, + int ind1, int ind3) { + int ori, ori1, ori2, i0, ii1, ii2; + Point2f pq, pr; + double dot; + + if (ind1 == ind3) { + // all points are collinear??? well, then it does not really matter + // which angle is returned. perhaps, -2 is the best bet as my code + // likely regards this contour as a hole. + return -2; + } + + if (i1 != i3) { + if (i1 < i2) { + ii1 = i1; + ii2 = i2; + } + else { + ii1 = i2; + ii2 = i1; + } + if (inBetween(ii1, ii2, i3)) { + i2 = i3; + ind3 = triRef.fetchNextData(ind3); + i3 = triRef.fetchData(ind3); + + if (ind1 == ind3) return 2; + ori = orientation(triRef, i1, i2, i3); + if (ori > 0) return 2; + else if (ori < 0) return -2; + else return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3); + } + else { + i2 = i1; + ind1 = triRef.fetchPrevData(ind1); + i1 = triRef.fetchData(ind1); + if (ind1 == ind3) return 2; + ori = orientation(triRef, i1, i2, i3); + if (ori > 0) return 2; + else if (ori < 0) return -2; + else return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3); + } + } + else { + i0 = i2; + i2 = i1; + ind1 = triRef.fetchPrevData(ind1); + i1 = triRef.fetchData(ind1); + + if (ind1 == ind3) return 2; + ind3 = triRef.fetchNextData(ind3); + i3 = triRef.fetchData(ind3); + if (ind1 == ind3) return 2; + ori = orientation(triRef, i1, i2, i3); + if (ori > 0) { + ori1 = orientation(triRef, i1, i2, i0); + if (ori1 > 0) { + ori2 = orientation(triRef, i2, i3, i0); + if (ori2 > 0) return -2; + } + return 2; + } + else if (ori < 0) { + ori1 = orientation(triRef, i2, i1, i0); + if (ori1 > 0) { + ori2 = orientation(triRef, i3, i2, i0); + if (ori2 > 0) return 2; + } + return -2; + } + else { + pq = new Point2f(); + Basic.vectorSub2D(triRef.points[i1], triRef.points[i2], pq); + pr = new Point2f(); + Basic.vectorSub2D(triRef.points[i3], triRef.points[i2], pr); + dot = Basic.dotProduct2D(pq, pr); + if (dot < 0.0) { + ori = orientation(triRef, i2, i1, i0); + if (ori > 0) return 2; + else return -2; + } + else { + return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3); + } + } + } + } + + + /** + * computes the signed angle between p, p1 and p, p2. + * + * warning: this function does not handle a 180-degree angle correctly! + * (this is no issue in our application, as we will always compute + * the angle centered at the mid-point of a valid diagonal.) + */ + static double angle(Triangulator triRef, Point2f p, Point2f p1, Point2f p2) { + int sign; + double angle1, angle2, angle; + Point2f v1, v2; + + sign = Basic.signEps(Basic.det2D(p2, p, p1), triRef.epsilon); + + if (sign == 0) return 0.0; + + v1 = new Point2f(); + v2 = new Point2f(); + Basic.vectorSub2D(p1, p, v1); + Basic.vectorSub2D(p2, p, v2); + + angle1 = Math.atan2(v1.y, v1.x); + angle2 = Math.atan2(v2.y, v2.x); + + if (angle1 < 0.0) angle1 += 2.0*Math.PI; + if (angle2 < 0.0) angle2 += 2.0*Math.PI; + + angle = angle1 - angle2; + if (angle > Math.PI) angle = 2.0*Math.PI - angle; + else if (angle < -Math.PI) angle = 2.0*Math.PI + angle; + + if (sign == 1) { + if (angle < 0.0) return -angle; + else return angle; + } + else { + if (angle > 0.0) return -angle; + else return angle; + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Orientation.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Orientation.java new file mode 100644 index 0000000..9b19aa8 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Orientation.java @@ -0,0 +1,173 @@ +/* + * $RCSfile: Orientation.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:20 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + +class Orientation { + + /** + * determine the outer polygon and the orientation of the polygons; the + * default orientation is CCW for the outer-most polygon, and CW for the + * inner polygons. the polygonal loops are referenced by loops[i1,..,i2-1]. + */ + static void adjustOrientation(Triangulator triRef, int i1, int i2) { + + double area; + int i, outer; + int ind; + + if(i1 >= i2) + System.out.println("Orientation:adjustOrientation Problem i1>=i2 !!!"); + + if (triRef.numLoops >= triRef.maxNumPolyArea) { + // System.out.println("Orientation:adjustOrientation Expanding polyArea array ."); + triRef.maxNumPolyArea = triRef.numLoops; + double old[] = triRef.polyArea; + triRef.polyArea = new double[triRef.maxNumPolyArea]; + if(old != null) + System.arraycopy(old, 0, triRef.polyArea, 0, old.length); + } + + // for each contour, compute its signed area, i.e., its orientation. the + // contour with largest area is assumed to be the outer-most contour. + for (i = i1; i < i2; ++i) { + ind = triRef.loops[i]; + triRef.polyArea[i] = polygonArea(triRef, ind); + } + + // determine the outer-most contour + area = Math.abs(triRef.polyArea[i1]); + outer = i1; + for (i = i1 + 1; i < i2; ++i) { + if (area < Math.abs(triRef.polyArea[i])) { + area = Math.abs(triRef.polyArea[i]); + outer = i; + } + } + + // default: the outer contour is referenced by loops[i1] + if (outer != i1) { + ind = triRef.loops[i1]; + triRef.loops[i1] = triRef.loops[outer]; + triRef.loops[outer] = ind; + + area = triRef.polyArea[i1]; + triRef.polyArea[i1] = triRef.polyArea[outer]; + triRef.polyArea[outer] = area; + } + + // adjust the orientation + if (triRef.polyArea[i1] < 0.0) triRef.swapLinks(triRef.loops[i1]); + for (i = i1 + 1; i < i2; ++i) { + if (triRef.polyArea[i] > 0.0) triRef.swapLinks(triRef.loops[i]); + } + } + + /** + * This function computes twice the signed area of a simple closed polygon. + */ + static double polygonArea(Triangulator triRef, int ind) { + int hook = 0; + int ind1, ind2; + int i1, i2; + double area = 0.0, area1 = 0; + + ind1 = ind; + i1 = triRef.fetchData(ind1); + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + area = Numerics.stableDet2D(triRef, hook, i1, i2); + + ind1 = ind2; + i1 = i2; + while (ind1 != ind) { + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + area1 = Numerics.stableDet2D(triRef, hook, i1, i2); + area += area1; + ind1 = ind2; + i1 = i2; + } + + return area; + } + + + /** + * Determine the orientation of the polygon. The default orientation is CCW. + */ + static void determineOrientation(Triangulator triRef, int ind) { + double area; + + // compute the polygon's signed area, i.e., its orientation. + area = polygonArea(triRef, ind); + + // adjust the orientation (i.e., make it CCW) + if (area < 0.0) { + triRef.swapLinks(ind); + triRef.ccwLoop = false; + } + + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/PntNode.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/PntNode.java new file mode 100644 index 0000000..7dcc68d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/PntNode.java @@ -0,0 +1,70 @@ +/* + * $RCSfile: PntNode.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:20 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +// Placeholder list +class PntNode extends Object { + int pnt; + int next; + + PntNode() { + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Primitive.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Primitive.java new file mode 100644 index 0000000..0483cbb --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Primitive.java @@ -0,0 +1,282 @@ +/* + * $RCSfile: Primitive.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.7 $ + * $Date: 2007/04/24 18:50:59 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.*; +import java.io.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.math.*; + +/** + * Base class for all Java 3D primitives. By default all primitives + * with the same parameters share their geometry (e.g., you can have 50 + * shperes in your scene, but the geometry is stored only once). A + * change to one primitive will effect all shared nodes. Another + * implication of this implementation is that the capabilities of the + * geometry are shared, and once one of the shared nodes is live, the + * capabilities cannot be set. Use the GEOMETRY_NOT_SHARED flag if + * you do not wish to share geometry among primitives with the same + * parameters. + */ + +public abstract class Primitive extends Group { + /** + * Specifies that normals are generated along with the positions. + */ + public static final int GENERATE_NORMALS = 0x01; + + /** + * Specifies that texture coordinates are generated along with the + * positions. + */ + public static final int GENERATE_TEXTURE_COORDS = 0x02; + + /** + * Specifies that normals are to be flipped along the surface. + */ + public static final int GENERATE_NORMALS_INWARD = 0x04; + + /** + * Specifies that texture coordinates are to be Y up. + * + * @since Java 3D 1.5.1 + */ + // Fix to Issue 411. Java 3D prefers images used for texture mapping to be Y-up + public static final int GENERATE_TEXTURE_COORDS_Y_UP = 0x08; + + + /** + * Specifies that the geometry being created will not be shared by + * another scene graph node. By default all primitives created with + * the same parameters share their geometry (e.g., you can have 50 + * spheres in your scene, but the geometry is stored only once). A + * change to one primitive will effect all shared nodes. You + * specify this flag if you do not wish to share any geometry among + * primitives of the same parameters. */ + public static final int GEOMETRY_NOT_SHARED = 0x10; + + /** + * Specifies that the ALLOW_INTERSECT + * capability bit should be set on the generated geometry. + * This allows the object + * to be picked using Geometry based picking. + */ + public static final int ENABLE_GEOMETRY_PICKING = 0x20; + + /** + * Specifies that the ALLOW_APPEARANCE_READ and + * ALLOW_APPEARANCE_WRITE bits are to be set on the generated + * geometry's Shape3D nodes. + */ + public static final int ENABLE_APPEARANCE_MODIFY = 0x40; + + static final int SPHERE = 0x01; + static final int CYLINDER = 0x02; + static final int CONE = 0x04; + static final int BOX = 0x08; + + // used for cached geometries of Cone and Cylinder + static final int TOP_DISK = 0x10; + static final int BOTTOM_DISK = 0x20; + static final int CONE_DIVISIONS = 0x40; + + int numTris = 0; + int numVerts = 0; + + /** + * Primitive flags. + */ + int flags; + + + /** + * Constructs a default primitive. + */ + public Primitive() + { + flags = 0; + setCapability(ENABLE_PICK_REPORTING); + setCapability(ALLOW_CHILDREN_READ); + } + + /** + * Returns the total number of triangles in this primitive. + * @return the total number of triangles in this primitive + */ + public int getNumTriangles() { + return numTris; + } + + /** + * @deprecated The number of triangles is an immutable attribute. + */ + public void setNumTriangles(int num) { + System.err.println("Warning: setNumTriangles has no effect"); + } + + /** + * Returns the total number of vertices in this primitive. + * @return the total number of vertices in this primitive + */ + public int getNumVertices() { + return numVerts; + } + + /** + * @deprecated The number of vertices is an immutable attribute. + */ + public void setNumVertices(int num) { + System.err.println("Warning: setNumVertices has no effect"); + } + + /** Returns the flags of primitive (generate normal, textures, caching, etc). + */ + public int getPrimitiveFlags() + { + return flags; + } + + /** + * @deprecated The primitive flags must be set at construction time + * via one of the subclass constructors. + */ + public void setPrimitiveFlags(int fl) { + System.err.println("Warning: setPrimitiveFlags has no effect"); + } + + /** Obtains a shape node of a subpart of the primitive. + * @param partid identifier for a given subpart of the primitive. + */ + public abstract Shape3D getShape(int partid); + + /** Gets the appearance of the primitive (defaults to first subpart). + */ + public Appearance getAppearance(){ + return getShape(0).getAppearance(); + } + + /** + * Gets the appearance of the specified part of the primitive. + * + * @param partId identifier for a given subpart of the primitive + * + * @return The appearance object associated with the partID. If an + * invalid partId is passed in, null is returned. + * + * @since Java 3D 1.2.1 + */ + public abstract Appearance getAppearance(int partId); + + /** Sets the appearance of a subpart given a partid. + */ + + public void setAppearance(int partid, Appearance ap) + { + getShape(partid).setAppearance(ap); + } + + /** Sets the main appearance of the primitive (all subparts) to + * same appearance. + */ + public abstract void setAppearance(Appearance ap); + + + /** Sets the main appearance of the primitive (all subparts) to + * a default white appearance. + */ + public void setAppearance(){ + + Color3f aColor = new Color3f(0.1f, 0.1f, 0.1f); + Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f); + Color3f dColor = new Color3f(0.6f, 0.6f, 0.6f); + Color3f sColor = new Color3f(1.0f, 1.0f, 1.0f); + + Material m = new Material(aColor, eColor, dColor, sColor, 100.0f); + Appearance a = new Appearance(); + m.setLightingEnable(true); + a.setMaterial(m); + setAppearance(a); + } + + static Hashtable geomCache = new Hashtable(); + + String strfloat(float x) + { + return (new Float(x)).toString(); + } + + protected void cacheGeometry(int kind, float a, float b, + float c, int d, int e, int flags, + GeomBuffer geo) + { + String key = new String(kind+strfloat(a)+strfloat(b)+ + strfloat(c)+d+e+flags); + geomCache.put(key, geo); + } + + protected GeomBuffer getCachedGeometry(int kind, float a, float b, float c, + int d, int e, int flags) + { + String key = new String(kind+strfloat(a)+strfloat(b)+ + strfloat(c)+d+e+flags); + Object cache = geomCache.get(key); + + return((GeomBuffer) cache); + } + + /** + * Clear the shared geometry cache for all Primitive types. + * Existing Shapes with shared geometry will continue to share + * the geometry. New Primitives will create new shared geometry. + * + * @since Java 3D 1.3.2 + */ + public static void clearGeometryCache() { + geomCache.clear(); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Project.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Project.java new file mode 100644 index 0000000..7410bca --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Project.java @@ -0,0 +1,254 @@ +/* + * $RCSfile: Project.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:20 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import javax.vecmath.*; +import java.io.*; +import java.util.*; + +class Project { + + /** + * This function projects the vertices of the polygons referenced by + * loops[i1,..,i2-1] to an approximating plane. + */ + static void projectFace(Triangulator triRef, int loopMin, int loopMax) { + Vector3f normal, nr; + int i, j; + double d; + + normal = new Vector3f(); + nr = new Vector3f(); + + // determine the normal of the plane onto which the points get projected + determineNormal(triRef, triRef.loops[loopMin], normal); + j = loopMin + 1; + if (j < loopMax) { + for (i = j; i < loopMax; ++i) { + determineNormal(triRef, triRef.loops[i], nr); + if (Basic.dotProduct(normal, nr) < 0.0) { + Basic.invertVector(nr); + } + Basic.vectorAdd(normal, nr, normal); + } + d = Basic.lengthL2(normal); + if (Numerics.gt(d, Triangulator.ZERO)) { + Basic.divScalar(d, normal); + } + else { + // System.out.println("*** ProjectFace: zero-length normal vector!? ***\n"); + normal.x = normal.y = 0.0f; + normal.z = 1.0f; + } + } + + // project the points onto this plane. the projected points are stored in + // the array `points[0,..,numPoints]' + + // System.out.println("loopMin " + loopMin + " loopMax " + loopMax); + projectPoints(triRef, loopMin, loopMax, normal); + + } + + + /** + * This function computes the average of all normals defined by triples of + * successive vertices of the polygon. we'll see whether this is a good + * heuristic for finding a suitable plane normal... + */ + static void determineNormal(Triangulator triRef, int ind, Vector3f normal) { + Vector3f nr, pq, pr; + int ind0, ind1, ind2; + int i0, i1, i2; + double d; + + ind1 = ind; + i1 = triRef.fetchData(ind1); + ind0 = triRef.fetchPrevData(ind1); + i0 = triRef.fetchData(ind0); + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + pq = new Vector3f(); + Basic.vectorSub((Tuple3f) triRef.vertices[i0], (Tuple3f) triRef.vertices[i1], (Vector3f) pq); + pr = new Vector3f(); + Basic.vectorSub((Tuple3f) triRef.vertices[i2], (Tuple3f) triRef.vertices[i1], (Vector3f) pr); + nr = new Vector3f(); + Basic.vectorProduct(pq, pr, nr); + d = Basic.lengthL2(nr); + if (Numerics.gt(d, Triangulator.ZERO)) { + Basic.divScalar(d, nr); + normal.set(nr); + } + else { + normal.x = normal.y = normal.z = 0.0f; + } + + pq.set(pr); + ind1 = ind2; + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + while (ind1 != ind) { + Basic.vectorSub((Tuple3f) triRef.vertices[i2], (Tuple3f) triRef.vertices[i1], pr); + Basic.vectorProduct(pq, pr, nr); + d = Basic.lengthL2(nr); + if (Numerics.gt(d, Triangulator.ZERO)) { + Basic.divScalar(d, nr); + if (Basic.dotProduct(normal, nr) < 0.0) { + Basic.invertVector(nr); + } + Basic.vectorAdd(normal, nr, normal); + } + pq.set(pr); + ind1 = ind2; + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + } + + d = Basic.lengthL2(normal); + if (Numerics.gt(d, Triangulator.ZERO)) { + Basic.divScalar(d, normal); + } + else { + //System.out.println("*** DetermineNormal: zero-length normal vector!? ***\n"); + normal.x = normal.y = 0.0f; normal.z = 1.0f; + + } + } + + + /** + * This function maps the vertices of the polygon referenced by `ind' to the + * plane n3.x * x + n3.y * y + n3.z * z = 0. every mapped vertex (x,y,z) + * is then expressed in terms of (x',y',z'), where z'=0. this is + * achieved by transforming the original vertices into a coordinate system + * whose z-axis coincides with n3, and whose two other coordinate axes n1 + * and n2 are orthonormal on n3. note that n3 is supposed to be of unit + * length! + */ + static void projectPoints(Triangulator triRef, int i1, int i2, Vector3f n3) { + Matrix4f matrix = new Matrix4f(); + Point3f vtx = new Point3f(); + Vector3f n1, n2; + double d; + int ind, ind1; + int i, j1; + + + n1 = new Vector3f(); + n2 = new Vector3f(); + + // choose n1 and n2 appropriately + if ((Math.abs(n3.x) > 0.1) || (Math.abs(n3.y) > 0.1)) { + n1.x = -n3.y; + n1.y = n3.x; + n1.z = 0.0f; + } + else { + n1.x = n3.z; + n1.z = -n3.x; + n1.y = 0.0f; + } + d = Basic.lengthL2(n1); + Basic.divScalar(d, n1); + Basic.vectorProduct(n1, n3, n2); + d = Basic.lengthL2(n2); + Basic.divScalar(d, n2); + + // initialize the transformation matrix + matrix.m00 = n1.x; + matrix.m01 = n1.y; + matrix.m02 = n1.z; + matrix.m03 = 0.0f; // translation of the coordinate system + matrix.m10 = n2.x; + matrix.m11 = n2.y; + matrix.m12 = n2.z; + matrix.m13 = 0.0f; // translation of the coordinate system + matrix.m20 = n3.x; + matrix.m21 = n3.y; + matrix.m22 = n3.z; + matrix.m23 = 0.0f; // translation of the coordinate system + matrix.m30 = 0.0f; + matrix.m31 = 0.0f; + matrix.m32 = 0.0f; + matrix.m33 = 1.0f; + + // transform the vertices and store the transformed vertices in the array + // `points' + triRef.initPnts(20); + for (i = i1; i < i2; ++i) { + ind = triRef.loops[i]; + ind1 = ind; + j1 = triRef.fetchData(ind1); + matrix.transform((Point3f)triRef.vertices[j1], vtx); + j1 = triRef.storePoint(vtx.x, vtx.y); + triRef.updateIndex(ind1, j1); + ind1 = triRef.fetchNextData(ind1); + j1 = triRef.fetchData(ind1); + while (ind1 != ind) { + matrix.transform(triRef.vertices[j1], vtx); + j1 = triRef.storePoint(vtx.x, vtx.y); + triRef.updateIndex(ind1, j1); + ind1 = triRef.fetchNextData(ind1); + j1 = triRef.fetchData(ind1); + } + } + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Quadrics.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Quadrics.java new file mode 100644 index 0000000..5f8a3b4 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Quadrics.java @@ -0,0 +1,550 @@ +/* + * $RCSfile: Quadrics.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/04/24 05:25:49 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.*; +import java.io.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.math.*; + +class Quadrics extends Object { + + Quadrics(){ } + + // new disk code to remove transforms in the primitive code + GeomBuffer disk(double r, int xdiv, double y, boolean outside, boolean texCoordYUp) { + + double theta, dtheta, sign, sinTheta, cosTheta; + + if (outside) sign = 1.0; + else sign = -1.0; + + dtheta = 2.0*Math.PI / xdiv; + + GeomBuffer gbuf = new GeomBuffer(xdiv+2); + + gbuf.begin(GeomBuffer.TRIANGLE_FAN); + gbuf.normal3d(0.0, 1.0*sign, 0.0); + gbuf.texCoord2d(0.5, 0.5); + gbuf.vertex3d(0.0, y, 0.0); + + // create the disk by evaluating points along the unit circle. + // theta is the angle around the y-axis. Then we obtain + // (cos(theta), sin(theta)) = (x,z) sample points. The y value + // was passed in as a parameter. + // texture coordinates are obtain from the unit circle centered at + // (.5, .5) in s, t space. thus portions of the texture are not used. + + if (!outside) { + for (int i = 0; i <= xdiv; i++) { + theta = i * dtheta; + // add 90 degrees to theta so lines up wtih the body + sinTheta = Math.sin(theta - Math.PI/2.0); + cosTheta = Math.cos(theta - Math.PI/2.0); + gbuf.normal3d(0.0, 1.0*sign, 0.0); + if (texCoordYUp) { + gbuf.texCoord2d(0.5+cosTheta*0.5, 1.0 - (0.5+sinTheta*0.5)); + } + else { + gbuf.texCoord2d(0.5+cosTheta*0.5, 0.5+sinTheta*0.5); + } + gbuf.vertex3d(r*cosTheta, y, r*sinTheta); + } + } else { + for (int i = xdiv; i >= 0; i--) { + theta = i * dtheta; + // add 90 degrees to theta so lines up with the body + sinTheta = Math.sin(theta - Math.PI/2.0); + cosTheta = Math.cos(theta - Math.PI/2.0); + gbuf.normal3d(0.0, 1.0*sign, 0.0); + if (texCoordYUp) { + gbuf.texCoord2d(0.5+cosTheta*0.5, 1.0 - (0.5-sinTheta*0.5)); + } + else { + gbuf.texCoord2d(0.5+cosTheta*0.5, 0.5-sinTheta*0.5); + } + gbuf.vertex3d(cosTheta*r, y, sinTheta*r); + } + } + + gbuf.end(); + return gbuf; + } + + + // new cylinder to remove transforms in the cylinder code and to optimize + // by using triangle strip + GeomBuffer cylinder(double height, double radius, + int xdiv, int ydiv, boolean outside, boolean texCoordYUp) { + + double sign; + + if (outside) sign = 1.0; + else sign = -1.0; + + // compute the deltas + double dtheta = 2.0*Math.PI / (double)xdiv; + double dy = height / (double)ydiv; + double du = 1.0/(double)xdiv; + double dv = 1.0/(double)ydiv; + + GeomBuffer gbuf = new GeomBuffer(ydiv*2*(xdiv+1)); + + double s = 0.0, t = 0.0; + double px, pz, qx, qz; + double py = -height/2.0; + double qy; + + gbuf.begin(GeomBuffer.QUAD_STRIP); + + for (int i = 0; i < ydiv; i++) { + qy = py+dy; + if (outside) { + px = Math.cos(xdiv*dtheta - Math.PI/2.0); + pz = Math.sin(xdiv*dtheta - Math.PI/2.0); + qx = Math.cos((xdiv-1)*dtheta - Math.PI/2.0); + qz = Math.sin((xdiv-1)*dtheta - Math.PI/2.0); + + // vert 2 + gbuf.normal3d(px*sign, 0.0, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s, t+dv); + } + gbuf.vertex3d(px*radius, qy, pz*radius); + + // vert 1 + gbuf.normal3d(px*sign, 0.0, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*radius, py, pz*radius); + + // vert 4 + gbuf.normal3d(qx*sign, 0.0, qz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s+du, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s+du, t+dv); + } + gbuf.vertex3d(qx*radius, qy, qz*radius); + + // vert 3 + gbuf.normal3d(qx*sign, 0.0, qz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s+du, 1.0 - t); + } + else { + gbuf.texCoord2d(s+du, t); + } + gbuf.vertex3d(qx*radius, py, qz*radius); + + s += (du*2.0); + + for (int j = xdiv-2; j >=0; j--) { + px = Math.cos(j*dtheta - Math.PI/2.0); + pz = Math.sin(j*dtheta - Math.PI/2.0); + + // vert 6 + gbuf.normal3d(px*sign, 0.0, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s, t+dv); + } + gbuf.vertex3d(px*radius, qy, pz*radius); + + // vert 5 + gbuf.normal3d(px*sign, 0.0, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } + else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*radius, py, pz*radius); + + s += du; + } + + } else { +// c = 0; + px = Math.cos(-Math.PI/2.0); + pz = Math.sin(-Math.PI/2.0); + qx = Math.cos(dtheta - Math.PI/2.0); + qz = Math.sin(dtheta - Math.PI/2.0); + + gbuf.normal3d(px*sign, 0.0, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s, t+dv); + } + gbuf.vertex3d(px*radius, qy, pz*radius); + + // vert 1 + gbuf.normal3d(px*sign, 0.0, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } + else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*radius, py, pz*radius); + + gbuf.normal3d(qx*sign, 0.0, qz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s+du, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s+du, t+dv); + } + gbuf.vertex3d(qx*radius, qy, qz*radius); + + gbuf.normal3d(qx*sign, 0.0, qz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s+du, 1.0 - t); + } + else { + gbuf.texCoord2d(s+du, t); + } + gbuf.vertex3d(qx*radius, py, qz*radius); + + s += (du*2.0); + + for (int j = 2; j <= xdiv; j++) { + px = Math.cos(j*dtheta - Math.PI/2.0); + pz = Math.sin(j*dtheta - Math.PI/2.0); + + gbuf.normal3d(px*sign, 0.0, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s, t+dv); + } + gbuf.vertex3d(px*radius, qy, pz*radius); + + gbuf.normal3d(px*sign, 0.0, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } + else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*radius, py, pz*radius); + + s += du; + } + + } + s = 0.0; + t += dv; + py += dy; + } + + gbuf.end(); + + return gbuf; + } + + // new coneBody method to remove transform in the Cone primitive + // and to optimize by using triangle strip + GeomBuffer coneBody(double bottom, double top, double bottomR, double topR, + int xdiv, int ydiv, double dv, boolean outside, boolean texCoordYUp) { + + double r, sign; + + if (outside) sign = 1.0; + else sign = -1.0; + + // compute the deltas + double dtheta = 2.0*Math.PI/(double)xdiv; + double dr = (topR-bottomR)/(double)ydiv; + double height = top-bottom; + double dy = height/(double)ydiv; + double ynormal = (bottomR-topR)/height; + double du = 1.0/(double)xdiv; +// double dv = 1.0/(double)(ydiv+1); + + GeomBuffer gbuf = new GeomBuffer(ydiv*2*(xdiv+1)); + + double s = 0.0, t = 0.0; + double px, pz, qx, qz; + double py = bottom; + double qy; + r = bottomR; + + gbuf.begin(GeomBuffer.QUAD_STRIP); + + for (int i = 0; i < ydiv; i++) { + qy = py+dy; + if (outside) { + px = Math.cos(xdiv*dtheta - Math.PI/2.0); + pz = Math.sin(xdiv*dtheta - Math.PI/2.0); + qx = Math.cos((xdiv-1)*dtheta - Math.PI/2.0); + qz = Math.sin((xdiv-1)*dtheta - Math.PI/2.0); + + // vert2 + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s, t+dv); + } + gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr)); + + // vert1 + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } + else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*r, py, pz*r); + + // vert4 + gbuf.normal3d(qx*sign, ynormal*sign, qz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s+du, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s+du, t+dv); + } + gbuf.vertex3d(qx*(r+dr), qy, qz*(r+dr)); + + // vert3 + gbuf.normal3d(qx*sign, ynormal*sign, qz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s+du, 1.0 - t); + } + else { + gbuf.texCoord2d(s+du, t); + } + gbuf.vertex3d(qx*r, py, qz*r); + + s += (du*2.0); + + for (int j = xdiv-2; j >= 0; j--) { + px = Math.cos(j*dtheta - Math.PI/2.0); + pz = Math.sin(j*dtheta - Math.PI/2.0); + + // vert 6 + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - (t + dv)); + } else { + gbuf.texCoord2d(s, t+dv); + } + gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr)); + + // vert 5 + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } + else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*r, py, pz*r); + + s += du; + } + } else { + px = Math.cos(-Math.PI/2.0); + pz = Math.sin(-Math.PI/2.0); + qx = Math.cos(dtheta - Math.PI/2.0); + qz = Math.sin(dtheta - Math.PI/2.0); + + // vert1 + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s, t+dv); + } + gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr)); + + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } + else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*r, py, pz*r); + + gbuf.normal3d(qx*sign, ynormal*sign, qz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s+du, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s+du, t+dv); + } + gbuf.vertex3d(qx*(r+dr), qy, qz*(r+dr)); + + gbuf.normal3d(qx*sign, ynormal*sign, qz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s+du, 1.0 - t); + } + else { + gbuf.texCoord2d(s+du, t); + } + gbuf.vertex3d(qx*r, py, qz*r); + + s += (du*2.0); + + for (int j = 2; j <= xdiv; j++) { + px = Math.cos(j*dtheta - Math.PI/2.0); + pz = Math.sin(j*dtheta - Math.PI/2.0); + + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - (t + dv)); + } + else { + gbuf.texCoord2d(s, t+dv); + } + gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr)); + + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } + else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*r, py, pz*r); + + s += du; + } + } + s = 0.0; + t += dv; + py += dy; + r += dr; + } + gbuf.end(); + + return gbuf; + } + + // new coneTop method to remove transforms in the cone code + GeomBuffer coneTop(double bottom, double radius, double height, + int xdiv,double t, boolean outside, boolean texCoordYUp) { + + double sign; + + if (outside) sign = 1.0; + else sign = -1.0; + + // compute the deltas + double dtheta = 2.0*Math.PI/(double)xdiv; + double ynormal = radius/height; + double du = 1.0/(double)xdiv; + double top = bottom + height; + + // initialize the geometry buffer + GeomBuffer gbuf = new GeomBuffer(xdiv + 2); + gbuf.begin(GeomBuffer.TRIANGLE_FAN); + + // add the tip, which is the center of the fan + gbuf.normal3d(0.0, ynormal*sign, 0.0); + if (texCoordYUp) { + gbuf.texCoord2d(.5, 0.0); + } + else { + gbuf.texCoord2d(.5, 1.0); + } + gbuf.vertex3d(0.0, top, 0.0); + + // go around the circle and add the rest of the fan + double s = 0.0; + double px, pz; + if (outside) { + for (int i = xdiv; i >= 0; i--) { + px = Math.cos(i*dtheta - Math.PI/2.0); + pz = Math.sin(i*dtheta - Math.PI/2.0); + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*radius, bottom, pz*radius); + + s += du; + } + } else { + for (int i = 0; i <= xdiv; i++) { + px = Math.cos(i*dtheta - Math.PI/2.0); + pz = Math.sin(i*dtheta - Math.PI/2.0); + gbuf.normal3d(px*sign, ynormal*sign, pz*sign); + if (texCoordYUp) { + gbuf.texCoord2d(s, 1.0 - t); + } else { + gbuf.texCoord2d(s, t); + } + gbuf.vertex3d(px*radius, bottom, pz*radius); + s += du; + } + } + gbuf.end(); + return gbuf; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Simple.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Simple.java new file mode 100644 index 0000000..cbaa0dc --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Simple.java @@ -0,0 +1,225 @@ +/* + * $RCSfile: Simple.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:20 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.io.*; +import java.util.*; +import javax.vecmath.*; + + +class Simple { + + /** + * Handle a triangle or a quadrangle in a simple and efficient way. if the + * face is more complex than false is returned. + * + * warning: the correctness of this function depends upon the fact that + * `CleanPolyhedralFace' has not yet been executed; i.e., the + * vertex indices have not been changed since the execution of + * `CleanPolyhedron'! (otherwise, we would have to get the original + * indices via calls to `GetOriginal'...) + */ + static boolean simpleFace(Triangulator triRef, int ind1) { + int ind0, ind2, ind3, ind4; + int i1, i2, i3, i0, i4; + + Point3f pq, pr, nr; + + double x, y, z; + int ori2, ori4; + + ind0 = triRef.fetchPrevData(ind1); + i0 = triRef.fetchData(ind0); + + if (ind0 == ind1) { + // this polygon has only one vertex! nothing to triangulate... + System.out.println("***** polygon with only one vertex?! *****\n"); + return true; + } + + ind2 = triRef.fetchNextData(ind1); + i2 = triRef.fetchData(ind2); + if (ind0 == ind2) { + // this polygon has only two vertices! nothing to triangulate... + System.out.println("***** polygon with only two vertices?! *****\n"); + return true; + } + + ind3 = triRef.fetchNextData(ind2); + i3 = triRef.fetchData(ind3); + if (ind0 == ind3) { + // this polygon is a triangle! let's triangulate it! + i1 = triRef.fetchData(ind1); + // triRef.storeTriangle(i1, i2, i3); + triRef.storeTriangle(ind1, ind2, ind3); + return true; + } + + ind4 = triRef.fetchNextData(ind3); + i4 = triRef.fetchData(ind4); + if (ind0 == ind4) { + // this polygon is a quadrangle! not too hard to triangulate it... + // we project the corners of the quadrangle onto one of the coordinate + // planes + triRef.initPnts(5); + i1 = triRef.fetchData(ind1); + + pq = new Point3f(); + pr = new Point3f(); + nr = new Point3f(); + /* + System.out.println("ind0 " + ind0 + ", ind1 " + ind1 + ", ind2 " + + ind2 + ", ind3 " + ind3 + ", ind4 " + ind4); + System.out.println("i0 " + i0 +", i1 " + i1 + ", i2 " + i2 + + ", i3 " + i3 + ", i4 " + i4); + + System.out.println("vert[i1] " + triRef.vertices[i1] + + "vert[i2] " + triRef.vertices[i2] + + "vert[i3] " + triRef.vertices[i3]); + */ + + Basic.vectorSub(triRef.vertices[i1], triRef.vertices[i2], pq); + Basic.vectorSub(triRef.vertices[i3], triRef.vertices[i2], pr); + Basic.vectorProduct(pq, pr, nr); + + // System.out.println("pq " + pq + " pr " + pr + " nr " + nr); + x = Math.abs(nr.x); + y = Math.abs(nr.y); + z = Math.abs(nr.z); + if ((z >= x) && (z >= y)) { + // System.out.println("((z >= x) && (z >= y))"); + triRef.points[1].x = triRef.vertices[i1].x; + triRef.points[1].y = triRef.vertices[i1].y; + triRef.points[2].x = triRef.vertices[i2].x; + triRef.points[2].y = triRef.vertices[i2].y; + triRef.points[3].x = triRef.vertices[i3].x; + triRef.points[3].y = triRef.vertices[i3].y; + triRef.points[4].x = triRef.vertices[i4].x; + triRef.points[4].y = triRef.vertices[i4].y; + } + else if ((x >= y) && (x >= z)) { + // System.out.println("((x >= y) && (x >= z))"); + triRef.points[1].x = triRef.vertices[i1].z; + triRef.points[1].y = triRef.vertices[i1].y; + triRef.points[2].x = triRef.vertices[i2].z; + triRef.points[2].y = triRef.vertices[i2].y; + triRef.points[3].x = triRef.vertices[i3].z; + triRef.points[3].y = triRef.vertices[i3].y; + triRef.points[4].x = triRef.vertices[i4].z; + triRef.points[4].y = triRef.vertices[i4].y; + } + else { + triRef.points[1].x = triRef.vertices[i1].x; + triRef.points[1].y = triRef.vertices[i1].z; + triRef.points[2].x = triRef.vertices[i2].x; + triRef.points[2].y = triRef.vertices[i2].z; + triRef.points[3].x = triRef.vertices[i3].x; + triRef.points[3].y = triRef.vertices[i3].z; + triRef.points[4].x = triRef.vertices[i4].x; + triRef.points[4].y = triRef.vertices[i4].z; + } + triRef.numPoints = 5; + + // find a valid diagonal + ori2 = Numerics.orientation(triRef, 1, 2, 3); + ori4 = Numerics.orientation(triRef, 1, 3, 4); + + /* + for(int i=0; i<5; i++) + System.out.println("point " + i + ", " + triRef.points[i]); + System.out.println("ori2 : " + ori2 + " ori4 : " + ori4); + */ + + if (((ori2 > 0) && (ori4 > 0)) || + ((ori2 < 0) && (ori4 < 0))) { + + // i1, i3 is a valid diagonal; + // + // encode as a 2-triangle strip: the triangles are (2, 3, 1) + // and (1, 3, 4). + + // triRef.storeTriangle(i1, i2, i3); + // triRef.storeTriangle(i1, i3, i4); + triRef.storeTriangle(ind1, ind2, ind3); + triRef.storeTriangle(ind1, ind3, ind4); + } + else { + // i2, i4 has to be a valid diagonal. (if this is no valid + // diagonal then the corners of the quad form a figure of eight; + // shall we apply any heuristics in order to guess which diagonal + // is more likely to be the better choice? alternatively, we could + // return false and subject it to the standard triangulation + // algorithm. well, let's see how this brute-force solution works.) + + // encode as a 2-triangle strip: the triangles are (1, 2, 4) + // and (4, 2, 3). + + // triRef.storeTriangle(i2, i3, i4); + // triRef.storeTriangle(i2, i4, i1); + triRef.storeTriangle(ind2, ind3, ind4); + triRef.storeTriangle(ind2, ind4, ind1); + } + return true; + } + + return false; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Sphere.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Sphere.java new file mode 100644 index 0000000..1296c2f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Sphere.java @@ -0,0 +1,514 @@ +/* + * $RCSfile: Sphere.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/04/24 18:50:59 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.*; +import java.io.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.math.*; + +/** + * Sphere is a geometry primitive created with a given radius and resolution. + * It is centered at the origin. + *

+ * When a texture is applied to a Sphere, it is mapped CCW from the back + * of the sphere. + *

+ * By default all primitives with the same parameters share their + * geometry (e.g., you can have 50 shperes in your scene, but the + * geometry is stored only once). A change to one primitive will + * effect all shared nodes. Another implication of this + * implementation is that the capabilities of the geometry are shared, + * and once one of the shared nodes is live, the capabilities cannot + * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to + * share geometry among primitives with the same parameters. + */ + +public class Sphere extends Primitive { + + /** + * Sphere shape identifier, used by getShape. + * + * @see Sphere#getShape + */ + public static final int BODY = 0; + + static final int MID_REZ_DIV = 16; + float radius; + int divisions; + + /** + * Constructs a Sphere of a given radius. Normals are generated + * by default, texture coordinates are not. The resolution defaults to + * 15 divisions along sphere's axes. Appearance defaults to white. + * @param radius Radius + */ + public Sphere (float radius) { + this(radius, GENERATE_NORMALS, MID_REZ_DIV); + } + + /** + * Constructs a default Sphere of radius of 1.0. Normals are generated + * by default, texture coordinates are not. + * Resolution defaults to 15 divisions. Appearance defaults to white. + */ + public Sphere() { + this(1.0f, GENERATE_NORMALS, MID_REZ_DIV); + } + + /** + * Constructs a Sphere of a given radius and appearance. + * Normals are generated by default, texture coordinates are not. + * @param radius Radius + * @param ap Appearance + */ + + public Sphere (float radius, Appearance ap) { + this(radius, GENERATE_NORMALS, MID_REZ_DIV, ap); + } + + /** + * Constructs a Sphere of a given radius and appearance with + * additional parameters specified by the Primitive flags. + * @param radius Radius + * @param primflags + * @param ap appearance + */ + public Sphere(float radius, int primflags, Appearance ap) { + this(radius, primflags, MID_REZ_DIV, ap); + } + + /** + * Constructs a Sphere of a given radius and number of divisions + * with additional parameters specified by the Primitive flags. + * Appearance defaults to white. + * @param radius Radius + * @param divisions Divisions + * @param primflags Primflags + */ + public Sphere(float radius, int primflags, int divisions) { + this(radius, primflags, divisions, null); + } + + + /** + * Obtains Sphere's shape node that contains the geometry. + * This allows users to modify the appearance or geometry. + * @param partId The part to return (must be BODY for Spheres) + * @return The Shape3D object associated with the partId. If an + * invalid partId is passed in, null is returned. + */ + public Shape3D getShape(int partId) { + if (partId != BODY) return null; +// return (Shape3D)((Group)getChild(0)).getChild(BODY); + return (Shape3D)getChild(BODY); + } + + /** Obtains Sphere's shape node that contains the geometry. + */ + public Shape3D getShape() { +// return (Shape3D)((Group)getChild(0)).getChild(BODY); + return (Shape3D)getChild(BODY); + } + + /** Sets appearance of the Sphere. + */ + public void setAppearance(Appearance ap) { +// ((Shape3D)((Group)getChild(0)).getChild(BODY)).setAppearance(ap); + ((Shape3D)getChild(BODY)).setAppearance(ap); + } + + /** + * Gets the appearance of the specified part of the sphere. + * + * @param partId identifier for a given subpart of the sphere + * + * @return The appearance object associated with the partID. If an + * invalid partId is passed in, null is returned. + * + * @since Java 3D 1.2.1 + */ + public Appearance getAppearance(int partId) { + if (partId != BODY) return null; + return getShape(partId).getAppearance(); + } + + + /** + * Constructs a customized Sphere of a given radius, + * number of divisions, and appearance, with additional parameters + * specified by the Primitive flags. The resolution is defined in + * terms of number of subdivisions along the sphere's axes. More + * divisions lead to more finely tesselated objects. + *

+ * If the appearance is null, the sphere defaults to a white appearance. + */ + public Sphere(float radius, int primflags, int divisions, Appearance ap) { + super(); + + int sign; + int n, nstep; + + this.radius = radius; + this.divisions = divisions; + + /* + * The sphere algorithm evaluates spherical angles along regular + * units. For each spherical coordinate, (theta, rho), a (x,y,z) is + * evaluated (along with the normals and texture coordinates). + * + * The spherical angles theta varies from 0 to 2pi and rho from 0 + * to pi. Sample points depends on the number of divisions. + */ + + flags = primflags; + boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0; + + //Depending on whether normal inward bit is set. + if ((flags & GENERATE_NORMALS_INWARD) != 0) { + sign = -1; + } else { + sign = 1; + } + + if (divisions < 4) { + nstep = 1; + n = 4; + } else { + int mod = divisions % 4; + if (mod == 0) { + n = divisions; + } else { + n = divisions + (4 - mod); + } + nstep = n/4; + } + + + GeomBuffer cache = getCachedGeometry(Primitive.SPHERE, + radius, 0.0f, 0.0f, + divisions, 0, primflags); + + Shape3D shape; + + if (cache != null) { + shape = new Shape3D(cache.getComputedGeometry()); + numVerts += cache.getNumVerts(); + numTris += cache.getNumTris(); + } else { + // buffer size = 8*(1 + 2E{i} + (nstep+1)) + // where E{i} = sum of i = 2 ... nstep + GeomBuffer gbuf = new GeomBuffer(8*nstep*(nstep+2)); + + for (int i=0; i < 4; i++) { + buildQuadrant(gbuf, i*Math.PI/2, (i+1)*Math.PI/2, sign, nstep, n, true); + buildQuadrant(gbuf, i*Math.PI/2, (i+1)*Math.PI/2, sign, nstep, n, false); + } + + // Fix to Issue 411. Java 3D prefers images used for texture mapping to be Y-up + if (texCoordYUp) { + TexCoord2f[] texCoords = gbuf.getTexCoords(); + if (texCoords != null) { + for (int ii=0; iicloneTree to duplicate the current node. + * cloneNode should be overridden by any user subclassed + * objects. All subclasses must have their cloneNode + * method consist of the following lines: + *

+     *     public Node cloneNode(boolean forceDuplicate) {
+     *         UserSubClass usc = new UserSubClass();
+     *         usc.duplicateNode(this, forceDuplicate);
+     *         return usc;
+     *     }
+     * 
+ * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + Sphere s = new Sphere(radius, flags, divisions, getAppearance()); + s.duplicateNode(this, forceDuplicate); + + return s; + } + + /** + * Copies all node information from originalNode into + * the current node. This method is called from the + * cloneNode method which is, in turn, called by the + * cloneTree method. + *

+ * For any NodeComponent objects + * contained by the object being duplicated, each NodeComponent + * object's duplicateOnCloneTree value is used to determine + * whether the NodeComponent should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * forceDuplicate parameter in the cloneTree + * method to true. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to true, causes the + * duplicateOnCloneTree flag to be ignored. When + * false, the value of each node's + * duplicateOnCloneTree variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Node#cloneTree + * @see Node#cloneNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, boolean forceDuplicate) { + super.duplicateNode(originalNode, forceDuplicate); + } + + /** + * Returns the radius of the sphere + * + * @since Java 3D 1.2.1 + */ + public float getRadius() { + return radius; + } + + /** + * Returns the number of divisions + * + * @since Java 3D 1.2.1 + */ + public int getDivisions() { + return divisions; + } + + void buildQuadrant(GeomBuffer gbuf, double startDelta, double endDelta, + int sign, int nstep, int n, boolean upperSphere) + { + + double ds, dt, theta, delta; + int i, j, index, i2; + double h, r, vx, vz; + Point3f pt; + Vector3f norm; + TexCoord2f texCoord; + double starth; + double t; + boolean leftToRight; + + + if (upperSphere) { + dt = Math.PI/(2*nstep); + theta = dt; + starth = 1; + leftToRight = (sign > 0); + } else { + dt = -Math.PI/(2*nstep); + theta = Math.PI + dt; + starth = -1; + leftToRight = (sign < 0); + } + + + for (i = 1; i <= nstep; i++) { + h = Math.cos(theta); + r = Math.sin(theta); + if (sign > 0) { + t = 1 - theta/Math.PI; + } else { + t = theta/Math.PI; + } + + i2 = i << 1; + // subdivision decreases towards the pole + ds = (endDelta - startDelta) / i; + + gbuf.begin(GeomBuffer.TRIANGLE_STRIP); + + if (leftToRight) { + // Build triangle strips from left to right + delta = startDelta; + + for (j=0; j < i; j++) { + vx = r*Math.cos(delta); + vz = r*Math.sin(delta); + + gbuf.normal3d( vx*sign, h*sign, vz*sign ); + gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t); + gbuf.vertex3d( vx*radius, h*radius, vz*radius ); + if (i > 1) { + // get previous vertex from buffer + index = gbuf.currVertCnt - i2; + pt = gbuf.pts[index]; + norm = gbuf.normals[index]; + texCoord = gbuf.tcoords[index]; + // connect with correspondent vertices from previous row + gbuf.normal3d(norm.x, norm.y, norm.z); + gbuf.texCoord2d(texCoord.x, texCoord.y); + gbuf.vertex3d(pt.x, pt.y, pt.z); + } else { + gbuf.normal3d(0, sign*starth, 0); + if (sign > 0) { + gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI), + 1.0 - (theta - dt)/Math.PI); + } else { + gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI), + (theta - dt)/Math.PI); + } + gbuf.vertex3d( 0, starth*radius, 0); + + } + delta += ds; + } + + // Put the last vertex in that row, + // for numerical accuracy we don't use delta + // compute from above. + delta = endDelta; + vx = r*Math.cos(delta); + vz = r*Math.sin(delta); + gbuf.normal3d( vx*sign, h*sign, vz*sign ); + gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t); + gbuf.vertex3d( vx*radius, h*radius, vz*radius); + } else { + delta = endDelta; + // Build triangle strips from right to left + for (j=i; j > 0; j--) { + vx = r*Math.cos(delta); + vz = r*Math.sin(delta); + + gbuf.normal3d( vx*sign, h*sign, vz*sign ); + // Convert texture coordinate back to one + // set in previous version + gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t); + gbuf.vertex3d( vx*radius, h*radius, vz*radius ); + if (i > 1) { + // get previous vertex from buffer + index = gbuf.currVertCnt - i2; + pt = gbuf.pts[index]; + norm = gbuf.normals[index]; + texCoord = gbuf.tcoords[index]; + gbuf.normal3d(norm.x, norm.y, norm.z); + gbuf.texCoord2d(texCoord.x, texCoord.y); + gbuf.vertex3d(pt.x, pt.y, pt.z); + } else { + gbuf.normal3d(0, sign*starth, 0); + if (sign > 0) { + gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI), + 1.0 - (theta - dt)/Math.PI); + } else { + gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI), + (theta - dt)/Math.PI); + } + gbuf.vertex3d( 0, starth*radius, 0); + + } + delta -= ds; + } + + // Put the last vertex in that row, + // for numerical accuracy we don't use delta + // compute from above. + delta = startDelta; + vx = r*Math.cos(delta); + vz = r*Math.sin(delta); + gbuf.normal3d( vx*sign, h*sign, vz*sign ); + gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t); + gbuf.vertex3d( vx*radius, h*radius, vz*radius ); + + } + + gbuf.end(); + + if (i < nstep) { + theta += dt; + } else { // take care of numerical imprecision + theta = Math.PI/2; + } + } + + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Stripifier.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Stripifier.java new file mode 100644 index 0000000..2c5db93 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Stripifier.java @@ -0,0 +1,2535 @@ +/* + * $RCSfile: Stripifier.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:20 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import com.sun.j3d.utils.geometry.GeometryInfo; +import java.util.LinkedList; +import java.util.ArrayList; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * The Stripifier utility will change the primitive of the GeometryInfo + * object to Triangle Strips. The strips are made by analyzing the + * triangles in the original data and connecting them together.

+ *

+ * Normal Generation should be performed on the GeometryInfo object + * before Stripification, for best results. Example:

+ *

+ *

+ *   GeometryInfo gi = new GeometryInfo(TRIANGLE_ARRAY);
+ *   gi.setCoordinates(coordinateData);
+ *
+ *   NormalGenerator ng = new NormalGenerator();
+ *   ng.generateNormals(gi);
+ *
+ *   Stripifier st = new Stripifier()
+ *   st.stripify(gi);
+ *
+ *   Shape3D part = new Shape3D();
+ *   part.setAppearance(appearance);
+ *   part.setGeometry(gi.getGeometryArray());
+ *   
+ */ +public class Stripifier { + + final boolean DEBUG = false; + final boolean CHECK_ORIENT = false; + + static final int EMPTY = -1; + + boolean hasNormals = false; + boolean hasTextures = false; + int texSetCount = 0; + boolean hasColors = false; + boolean colorStrips = false; + + StripifierStats stats; + + int[] numNhbrs; + + /** + * Indicates to the stripifier to collect statistics on the data + */ + public static final int COLLECT_STATS = 0x01; + + /** + * Creates the Stripifier object. + */ + public Stripifier() { + } + + /** + * Creates the Stripifier object. + * @param flags Flags + * @since Java 3D 1.2.1 + */ + public Stripifier(int flags) { + if ((flags & COLLECT_STATS) != 0) { + stats = new StripifierStats(); + } + } + + /** + * Converts the geometry contained in the GeometryInfo object into an + * array of triangle strips. + */ + public void stripify(GeometryInfo gi) { + // System.out.println("stripify"); + long time = System.currentTimeMillis(); + // setup + gi.convertToIndexedTriangles(); + gi.forgetOldPrim(); + + // write out the gi object + // System.out.println("write out the object"); + // gi.writeObj(); + + Face[] faces = createFaceArray(gi); + Edge[] edges = createEdgeArray(faces); + buildAdjacencies(edges, faces); + + // print out the adjacency information + if (DEBUG) { + for (int i = 0; i < faces.length; i++) { + faces[i].printVertices(); + } + System.out.println(""); + for (int i = 0; i < faces.length; i++) { + faces[i].printAdjacency(); + } + System.out.println(""); + } + + Node[] faceNodes = new Node[faces.length]; + // Node[] queue = hybridSearch(faces, faceNodes); + Node[] queue = dfSearch(faces, faceNodes); + + // print out the queue + if (DEBUG) { + for (int i = 0; i < queue.length; i++) { + queue[i].print(); + } + System.out.println(""); + } + + // int "pointers" for the numbers of strips and patches from + // hamiliton + int[] ns = new int[1]; + int[] np = new int[1]; + ArrayList hamiltons = hamilton(queue, ns, np); + int numStrips = ns[0]; + int numPatches = np[0]; + + // print out the hamiltonians + if (DEBUG) { + for (int i = 0; i < hamiltons.size(); i++) { + System.out.println("Hamiltonian: " + i); + ArrayList list = (ArrayList)hamiltons.get(i); + for (int j = 0; j < list.size(); j++) { + Face face = (Face)list.get(j); + face.printVertices(); + } + System.out.println(""); + } + } + + // now make strips out of the hamiltonians + ArrayList strips = stripe(hamiltons); + + // print out the strips + if (DEBUG) { + for (int i = 0; i < strips.size(); i++) { + System.out.println("Strip: " + i); + Istream istream = (Istream)strips.get(i); + for (int j = 0; j < istream.length; j++) { + System.out.println("vertex: " + istream.istream[j].index); + } + System.out.println(""); + } + } + + // concatenate the strips + concatenate(strips, faces); + + // print out the new strips + if (DEBUG) { + System.out.println(""); + System.out.println("concatenated strips: (" + + (strips.size()) + ")"); + System.out.println(""); + for (int i = 0; i < strips.size(); i++) { + System.out.println("Strip: " + i); + Istream istream = (Istream)strips.get(i); + for (int j = 0; j < istream.length; j++) { + System.out.println("vertex: " + istream.istream[j].index); + } + System.out.println(""); + } + } + + // put the stripified data into the GeometryInfo object + putBackData(gi, strips); + + // System.out.println("time: " + (System.currentTimeMillis()-time)); + // System.out.println(""); + + // add to stats + if (stats != null) { + stats.updateInfo(System.currentTimeMillis()-time, strips, + faces.length); + } + + // Stat.printInfo(); + + // print out strip count info + // System.out.println("numStrips = " + strips.size()); + // System.out.println("stripCounts:"); + // int avg = 0; + // for (int i = 0; i < strips.size(); i++) { + // System.out.print(((Istream)strips.get(i)).length + " "); + // avg += ((Istream)strips.get(i)).length; + // } + // System.out.println("Avg: " + ((double)avg/(double)strips.size())); + } + + /** + * Prints out statistical information for the stripifier: the number of + * original triangles, the number of original vertices, the number of + * strips created, the number of vertices, the total number of triangles, + * the minimum strip length (in # of tris) the maximum strip length + * (in number of tris), the average strip length (in # of tris), the + * average number of vertices per triangle, the total time it took to + * stripify, and the strip length (how many strips of a given length. + * The data is cumulative over all the times the stripifier is called + * until the stats are printed, and then they are reset. + */ + // public static void printStats() { + // // stats.toString(); + // } + + /** + * Returns the stripifier stats object. + * @exception IllegalStateException if the Stripfier has not + * been constructed + * with the COLLECT_STATS flag + * @since Java 3D 1.2.1 + */ + public StripifierStats getStripifierStats() { + if (stats == null) { + throw new IllegalStateException(J3dUtilsI18N.getString("Stripifier0")); + } + return stats; + } + + /** + * Creates an array of faces from the geometry in the GeometryInfo object. + */ + Face[] createFaceArray(GeometryInfo gi) { + int[] vertices = gi.getCoordinateIndices(); + int[] normals = gi.getNormalIndices(); + + int[][] textures = null; + int[] t1 = null; + int[] t2 = null; + int[] t3 = null; + texSetCount = gi.getTexCoordSetCount(); + if (texSetCount > 0) { + hasTextures = true; + textures = new int[texSetCount][]; + for (int i = 0; i < texSetCount; i++) { + textures[i] = gi.getTextureCoordinateIndices(i); + } + t1 = new int[texSetCount]; + t2 = new int[texSetCount]; + t3 = new int[texSetCount]; + } else hasTextures = false; + + int[] colors = gi.getColorIndices(); + Face[] faces = new Face[vertices.length/3]; + int n1, n2, n3, c1, c2, c3; + Vertex v1, v2, v3; + int count = 0; + for (int i = 0; i < vertices.length;) { + if (normals != null) { + // System.out.println("hasNormals"); + hasNormals = true; + n1 = normals[i]; + n2 = normals[i+1]; + n3 = normals[i+2]; + } + else { + // System.out.println("doesn't have normals"); + hasNormals = false; + n1 = EMPTY; + n2 = EMPTY; + n3 = EMPTY; + } + if (hasTextures) { + for (int j = 0; j < texSetCount; j++) { + t1[j] = textures[j][i]; + t2[j] = textures[j][(i+1)]; + t3[j] = textures[j][(i+2)]; + } + } + if (colors != null) { + hasColors = true; + c1 = colors[i]; + c2 = colors[i+1]; + c3 = colors[i+2]; + } + else { + hasColors = false; + c1 = EMPTY; + c2 = EMPTY; + c3 = EMPTY; + } + v1 = new Vertex(vertices[i], n1, texSetCount, t1, c1); + v2 = new Vertex(vertices[i+1], n2, texSetCount, t2, c2); + v3 = new Vertex(vertices[i+2], n3, texSetCount, t3, c3); + if (!v1.equals(v2) && !v2.equals(v3) && !v3.equals(v1)) { + faces[count] = new Face(count, v1, v2, v3); + count++; + } + i+=3; + } + + if (faces.length > count) { + Face[] temp = faces; + faces = new Face[count]; + System.arraycopy(temp, 0, faces, 0, count); + } + return faces; + } + + /** + * Creates an array of edges from the Face array. + */ + Edge[] createEdgeArray(Face[] faces) { + Edge[] edges = new Edge[faces.length*3]; + Face face; + for (int i = 0; i < faces.length; i++) { + face = faces[i]; + edges[i*3] = new Edge(face.verts[0], face.verts[1], face.key); + edges[i*3+1] = new Edge(face.verts[1], face.verts[2], face.key); + edges[i*3+2] = new Edge(face.verts[2], face.verts[0], face.key); + } + return edges; + } + + /** + * Builds the adjacency graph by finding the neighbors of the edges + */ + void buildAdjacencies(Edge[] edges, Face[] faces) { + // sortEdges(edges); + quickSortEdges(edges, 0, edges.length-1); + // int i = 1; + + // set up the edge list of each face + Edge edge; + Face face; + Vertex[] verts; + boolean flag; + int k; + for (int i = 0; i < edges.length; i++) { + // edges are kept in order s.t. the ith edge is the opposite + // edge of the ith vertex + edge = edges[i]; + face = faces[edge.face]; + verts = face.verts; + + flag = true; + if ((!verts[0].equals(edge.v1)) && (!verts[0].equals(edge.v2))) { + face.edges[0] = edge; + face.numNhbrs--; + flag = false; + } + else if ((!verts[1].equals(edge.v1)) && + (!verts[1].equals(edge.v2))) { + face.edges[1] = edge; + face.numNhbrs--; + flag = false; + } + else if ((!verts[2].equals(edge.v1)) && + (!verts[2].equals(edge.v2))) { + face.edges[2] = edge; + face.numNhbrs--; + flag = false; + } + else { + if (DEBUG) System.out.println("error!!! Stripifier.buildAdj"); + } + + // handle degenerencies + if (flag) { + Vertex i1; + // triangle degenerated to a point + if ((edge.v1).equals(edge.v2)) { + face.edges[--face.numNhbrs] = edge; + } + // triangle degenerated to an edge + else { + if (verts[0].equals(verts[1])) { + i1 = verts[1]; + } + else { + i1 = verts[2]; + } + if (verts[0].equals(i1) && face.edges[0] == null) { + face.edges[0] = edge; + face.numNhbrs--; + } + else if (verts[1].equals(i1) && face.edges[1] == null) { + face.edges[1] = edge; + face.numNhbrs--; + } + else { + face.edges[2] = edge; + face.numNhbrs--; + } + } + } + } + + // build the adjacency information by pairing up every two triangles + // that share the same edge + int i = 0; int j = 0; + int j1, j2; + while (i < (edges.length-1)) { + j = i+1; + if (edges[i].equals(edges[j])) { + // determine the orientations of the common edge in the two + // adjacent triangles. Only set them to be adjacent if they + // are opposite + j1 = edges[i].face; + j2 = edges[j].face; + if (j1 != j2) { // set up the two faces as neighbors + edge = edges[i]; + face = faces[j1]; + k = face.getEdgeIndex(edge); + if ((edge.v1.equals(face.verts[(k+1)%3])) && + (edge.v2.equals(face.verts[(k+2)%3]))) { + flag = false; + } + else flag = true; + + edge = edges[j]; + face = faces[j2]; + k = face.getEdgeIndex(edge); + if ((edge.v1.equals(face.verts[(k+1)%3])) && + (edge.v2.equals(face.verts[(k+2)%3]))) { + flag = flag; + } + else flag = (!flag); + + if (flag) { + edges[i].face = j2; + edges[j].face = j1; + (faces[j1].numNhbrs)++; + (faces[j2].numNhbrs)++; + j++; + } + else edges[i].face = EMPTY; + } + else edges[i].face = EMPTY; + } + else edges[i].face = EMPTY; + i=j; + } + if (i <= (edges.length-1)) edges[i].face = EMPTY; + + // check, for each face, if it is duplicated. For a face that + // neighbors its duplicate in the adjacency graph, it's possible + // that two or more of its neighbors are the same (the duplicate). + // This will be corrected to avoid introducing redundant faces + // later on + + for (i = 0; i < faces.length; i++) { + face = faces[i]; + if (face.numNhbrs == 3) { + if ((j1 = face.edges[1].face) == face.edges[0].face) { + face.edges[1].face = EMPTY; + face.numNhbrs--; + faces[j1].counterEdgeDel(face.edges[1]); + } + if ((j2 = face.edges[2].face) == face.edges[0].face) { + face.edges[2].face = EMPTY; + face.numNhbrs--; + faces[j2].counterEdgeDel(face.edges[2]); + } + if ((face.edges[1].face != EMPTY) && (j1 == j2)) { + face.edges[2].face = EMPTY; + face.numNhbrs--; + faces[j1].counterEdgeDel(face.edges[2]); + } + } + } + } + + /** + * Sorts the edges using BubbleSort + */ + void sortEdges(Edge[] edges) { + int i = edges.length; + boolean sorted = false; + Edge temp = null; + while ((i > 1) && !sorted) { + sorted = true; + for (int j = 1; j < i; j++) { + if (edges[j].lessThan(edges[j-1])) { + temp = edges[j-1]; + edges[j-1] = edges[j]; + edges[j] = temp; + sorted = false; + } + } + i--; + } + } + + /** + * uses quicksort to sort the edges + */ + void quickSortEdges(Edge[] edges, int l, int r) { + if (edges.length > 0) { + int i = l; + int j = r; + Edge k = edges[(l+r) / 2]; + + do { + while (edges[i].lessThan(k)) i++; + while (k.lessThan(edges[j])) j--; + if (i <= j) { + Edge tmp = edges[i]; + edges[i] = edges[j]; + edges[j] = tmp; + i++; + j--; + } + } while (i <= j); + + if (l < j) quickSortEdges(edges, l, j); + if (l < r) quickSortEdges(edges, i, r); + } + } + + /** + * Takes a list of faces as input and performs a hybrid search, a + * variated depth first search that returns to the highest level node + * not yet fully explored. Returns an array of pointers to the faces + * found in order from the search. The faceNodes parameter is an + * array of the Nodes created for the faces. + */ + Node[] hybridSearch(Face[] faces, Node[] faceNodes) { + + int numFaces = faces.length; + int i = 0, j = 0, k = 0, ind = 0; + + // keep # of faces with certain # of neighbors + int[] count = {0, 0, 0, 0}; + + // faces sorted by number of neighbors + int[] index = new int[numFaces]; + // the index of a certain face in the sorted array + int[] rindex = new int[numFaces]; + + // Control list pop up operation + boolean popFlag = false; + + // queue of pointers to faces found in search + Node[] queue = new Node[numFaces]; + // root of depth first tree + Node source; + // for the next node + Node nnode; + // a face + Face face; + // starting position for insertion into the list + int start = 0; + // list for search + SortedList dlist; + + // count how many faces have a certain # of neighbors and + // create a Node for each face + for (i = 0; i < numFaces; i++) { + j = faces[i].numNhbrs; + count[j]++; + faceNodes[i] = new Node(faces[i]); + } + + // to help with sorting + for (i = 1; i < 4; i++) { + count[i] += count[i-1]; + } + + // decreasing i to make sorting stable + for (i = numFaces - 1; i >= 0; i--) { + j = faces[i].numNhbrs; + count[j]--; + index[count[j]] = i; + rindex[i] = count[j]; + } + + // start the hybrid search + for (i = 0; i < numFaces; i++) { + if (index[i] != EMPTY) { + dlist = new SortedList(); + source = faceNodes[index[i]]; + source.setRoot(); + queue[ind] = source; + ind++; + index[i] = EMPTY; + + while (source != null) { + nnode = null; + // use the first eligible for continuing search + face = source.face; + for (j = 0; j < 3; j++) { + k = face.getNeighbor(j); + if ((k != EMPTY) && + (faceNodes[k].notAccessed())) { + nnode = faceNodes[k]; + break; + } + } + + if (nnode != null) { + // insert the new node + nnode.insert(source); + if (!popFlag) { + start = dlist.sortedInsert(source, start); + } + else popFlag = false; + source = nnode; + queue[ind] = source; + ind++; + index[rindex[k]] = EMPTY; + } + else { + source.processed(); + source = dlist.pop(); + popFlag = true; + start = 0; + } + } // while -- does popFlag need to be set to false here? + } + } + return queue; + } + + Node[] dfSearch(Face[] faces, Node[] faceNodes) { + int numFaces = faces.length; + int i = 0, j = 0, k = 0, ind = 0; + + // keep certain # of faces with certain # of neighbors + int[] count = {0, 0, 0, 0}; + + // faces sorted by # of neighbors + int[] index = new int[numFaces]; + // index of a certain face in the sorted array + int[] rindex = new int[numFaces]; + + // queue of pointers to faces found in the search + Node[] queue = new Node[numFaces]; + // root of the depth first tree + Node source; + // the current node + Node node; + // for the next Node + Node nnode; + // a face + Face face; + + // count how many faces have a certain # of neighbors and create + // a Node for each face + for (i = 0; i < numFaces; i++) { + j = faces[i].numNhbrs; + count[j]++; + faceNodes[i] = new Node(faces[i]); + } + + // to help with sorting + for (i = 1; i < 4; i++) count[i] += count[i-1]; + + // dec i to make sorting stable + for (i = numFaces-1; i >= 0; i--) { + j = faces[i].numNhbrs; + count[j]--; + index[count[j]] = i; + rindex[i] = count[j]; + } + + setNumNhbrs(faces); + // start the dfs + for (i = 0; i < numFaces; i++) { + if (index[i] != EMPTY) { + source = faceNodes[index[i]]; + source.setRoot(); + queue[ind] = source; + ind++; + index[i] = EMPTY; + node = source; + + do { + // if source has been done, stop + if ((node == source) && (node.right != null)) break; + + nnode = null; + face = node.face; + + // for (j = 0; j < 3; j++) { + // if (((k = face.getNeighbor(j)) != EMPTY) && + // (faceNodes[k].notAccessed())) { + // nnode = faceNodes[k]; + // break; + // } + // } + + k = findNext(node, faceNodes, faces); + if (k != EMPTY) nnode = faceNodes[k]; + if (nnode != null) updateNumNhbrs(nnode); + + if (nnode != null) { + // insert new node + nnode.insert(node); + node = nnode; + queue[ind] = node; + ind++; + index[rindex[k]] = EMPTY; + } + else { + node.processed(); + node = node.parent; + } + } while (node != source.parent); + } + } + freeNhbrTable(); + return queue; + } + + int findNext(Node node, Node[] faceNodes, Face[] faces) { + Face face = node.face; + // this face has no neighbors so return + if (face.numNhbrs == 0) return EMPTY; + + int i, j, count; + int[] n = new int[3]; // num neighbors of neighboring face + int[] ind = {-1, -1, -1}; // neighboring faces + + // find the number of neighbors for each neighbor + count = 0; + for (i = 0; i < 3; i++) { + if (((j = face.getNeighbor(i)) != EMPTY) && + (faceNodes[j].notAccessed())) { + ind[count] = j; + n[count] = numNhbrs[j]; + count++; + } + } + + // this face has no not accessed faces + if (count == 0) return EMPTY; + + // this face has only one neighbor + if (count == 1) return ind[0]; + + if (count == 2) { + // if the number of neighbors are the same, try reseting + if ((n[0] == n[1]) && (n[0] != 0)) { + n[0] = resetNhbr(ind[0], faces, faceNodes); + n[1] = resetNhbr(ind[1], faces, faceNodes); + } + // if one neighbor has fewer neighbors, return that neighbor + if (n[0] < n[1]) return ind[0]; + if (n[1] < n[0]) return ind[1]; + // neighbors tie. pick the sequential one + Node pnode, ppnode; + Face pface, ppface; + if ((pnode = node.parent) != null) { + pface = pnode.face; + i = pface.findSharedEdge(face.key); + if ((ppnode = pnode.parent) != null) { + ppface = ppnode.face; + if (pface.getNeighbor((i+1)%3) == ppface.key) { + j = pface.verts[(i+2)%3].index; + } + else { + j = pface.verts[(i+1)%3].index; + } + } + else { + j = pface.verts[(i+1)%3].index; + } + i = face.findSharedEdge(ind[0]); + if (face.verts[i].index == j) return ind[0]; + else return ind[1]; + } + else return ind[0]; + } + // three neighbors + else { + if ((n[0] < n[1]) && (n[0] < n[2])) return ind[0]; + else if ((n[1] < n[0]) && (n[1] < n[2])) return ind[1]; + else if ((n[2] < n[0]) && (n[2] < n[1])) return ind[2]; + else if ((n[0] == n[1]) && (n[0] < n[2])) { + if (n[0] != 0) { + n[0] = resetNhbr(ind[0], faces, faceNodes); + n[1] = resetNhbr(ind[1], faces, faceNodes); + } + if (n[0] <= n[1]) return ind[0]; + else return ind[1]; + } + else if ((n[1] == n[2]) && n[1] < n[0]) { + if (n[1] != 0) { + n[1] = resetNhbr(ind[1], faces, faceNodes); + n[2] = resetNhbr(ind[2], faces, faceNodes); + } + if (n[1] <= n[2]) return ind[1]; + else return ind[2]; + } + else if ((n[2] == n[0]) && (n[2] < n[1])) { + if (n[0] != 0) { + n[0] = resetNhbr(ind[0], faces, faceNodes); + n[2] = resetNhbr(ind[2], faces, faceNodes); + } + if (n[0] <= n[2]) return ind[0]; + else return ind[2]; + } + else { + if (n[0] != 0) { + n[0] = resetNhbr(ind[0], faces, faceNodes); + n[1] = resetNhbr(ind[1], faces, faceNodes); + n[2] = resetNhbr(ind[2], faces, faceNodes); + } + if ((n[0] <= n[1]) && (n[0] <= n[2])) return ind[0]; + else if (n[1] <= n[2]) return ind[1]; + else return ind[2]; + } + } + } + + void setNumNhbrs(Face[] faces) { + int numFaces = faces.length; + numNhbrs = new int[numFaces]; + for (int i = 0; i < numFaces; i++) { + numNhbrs[i] = faces[i].numNhbrs; + } + } + + void freeNhbrTable() { + numNhbrs = null; + } + + void updateNumNhbrs(Node node) { + Face face = node.face; + int i; + if ((i = face.getNeighbor(0)) != EMPTY) numNhbrs[i]--; + if ((i = face.getNeighbor(1)) != EMPTY) numNhbrs[i]--; + if ((i = face.getNeighbor(2)) != EMPTY) numNhbrs[i]--; + } + + int resetNhbr(int y, Face[] faces, Node[] faceNodes) { + int x = EMPTY; + Face nface = faces[y]; + int i; + for (int j = 0; j < 3; j++) { + if (((i = nface.getNeighbor(j)) != EMPTY) && + (faceNodes[i].notAccessed())) { + if ((x == EMPTY) || (x > numNhbrs[i])) x = numNhbrs[i]; + } + } + return x; + } + + /** + * generates hamiltonian strips from the derived binary spanning tree + * using the path peeling algorithm to peel off any node wiht double + * children in a bottom up fashion. Returns a Vector of strips. Also + * return the number of strips and patches in the numStrips and + * numPatches "pointers" + */ + ArrayList hamilton(Node[] sTree, int[] numStrips, int[] numPatches) { + // the number of nodes in the tree + int numNodes = sTree.length; + // number of strips + int ns = 0; + // number of patches + int np = 0; + // some tree node variables + Node node, pnode, cnode; + // the Vector of strips + ArrayList strips = new ArrayList(); + // the current strip + ArrayList currStrip; + + // the tree nodes are visited in such a bottom-up fashion that + // any node is visited prior to its parent + for (int i = numNodes - 1; i >= 0; i--) { + cnode = sTree[i]; + + // if cnode is the root of a tree create a strip + if (cnode.isRoot()) { + // each patch is a single tree + np++; + // create a new strip + currStrip = new ArrayList(); + // insert the current node into the list + currStrip.add(0, cnode.face); + + // add the left "wing" of the parent node to the strip + node = cnode.left; + while (node != null) { + currStrip.add(0, node.face); + node = node.left; + } + + // add the right "wing" of the parent node to the strip + node = cnode.right; + while (node != null) { + currStrip.add(currStrip.size(), node.face); + node = node.left; + } + + // increase the number of strips + ns++; + // add the strip to the Vector + strips.add(currStrip); + } + + // if the number of children of this node is 2, create a strip + else if (cnode.numChildren == 2) { + // if the root has a single child with double children, it + // could be left over as a singleton. However, the following + // rearrangement reduces the chances + pnode = cnode.parent; + if (pnode.isRoot() && (pnode.numChildren == 1)) { + pnode = cnode.right; + if (pnode.left != null) cnode = pnode; + else cnode = cnode.left; + } + + // handle non-root case + + // remove the node + cnode.remove(); + + // create a new strip + currStrip = new ArrayList(); + // insert the current node into the list + currStrip.add(0, cnode.face); + + // add the left "wing" of cnode to the list + node = cnode.left; + while (node != null) { + currStrip.add(0, node.face); + node = node.left; + } + + // add the right "wing" of cnode to the list + node = cnode.right; + while (node != null) { + currStrip.add(currStrip.size(), node.face); + node = node.left; + } + + // increase the number of strips + ns++; + // add the strip to the Vector + strips.add(currStrip); + } + } + + // put the ns and np in the "pointers to return + numStrips[0] = ns; + numPatches[0] = np; + + // return the strips + return strips; + } + + /** + * creates the triangle strips + */ + ArrayList stripe(ArrayList strips) { + int numStrips = strips.size(); // the number of strips + int count; // where we are in the hamiltonian + Face face; // the face we are adding to the stream + Face prev; // the previous face added to the stream + boolean done; // whether we are done with the current strip + boolean cont; // whether we should continue the current stream + ArrayList currStrip; // the current hamiltonian + Istream currStream; // the stream we are building + ArrayList istreams = new ArrayList(); // the istreams to return + boolean ccw = true;; // counter-clockwise + int share; // the shared edge + Vertex[] buf = new Vertex[4]; // a vertex array to start the stream + + // create streams for each hamiltonian + for (int i = 0; i < numStrips; i++) { + currStrip = (ArrayList)strips.get(i); + count = 0; + done = false; + face = getNextFace(currStrip, count++); + + // while we are not done with the current hamiltonian + while (!done) { + cont = true; + + // if the current face is the only one left in the current + // hamiltonian + if (stripDone(currStrip, count)) { + // create a new istream with the current face + currStream = new Istream(face.verts, 3, false); + // set the head of the strip to this face + currStream.head = face.key; + done = true; + // since we are done with the strip, set the tail to this + // face + currStream.tail = face.key; + } + + else { + prev = face; + face = getNextFace(currStrip, count++); + + // put the prev vertices in the correct order + // to add the next tri on + share = prev.findSharedEdge(face.key); + buf[0] = prev.verts[share]; + buf[1] = prev.verts[(share+1)%3]; + buf[2] = prev.verts[(share+2)%3]; + + // find the fourth vertex + if (CHECK_ORIENT) { + // check for clockwise orientation + if (checkOrientCWSeq(buf[2], buf[1], face)) { + share = face.findSharedEdge(prev.key); + buf[3] = face.verts[share]; + currStream = new Istream(buf, 4, false); + // set the head of this strip to the prev face + currStream.head = prev.key; + // if this was the last tri in the strip, then + // we are done + if (stripDone(currStrip, count)) { + done = true; + // set the tail for the strip to current face + currStream.tail = face.key; + } + } + else { + cont = false; + currStream = new Istream(buf, 3, false); + // set the head to the prev face + currStream.head = prev.key; + // since we are not continuing, set + // the tail to prev also + currStream.tail = prev.key; + } + + // orientation starts counter-clockwise for 3rd face + ccw = true; + } + else { + share = face.findSharedEdge(prev.key); + buf[3] = face.verts[share]; + currStream = new Istream(buf, 4, false); + // set the head of this strip to the prev face + currStream.head = prev.key; + // if this was the last tri in the strip, then + // we are done + if (stripDone(currStrip, count)) { + done = true; + // set the tail for the strip to current face + currStream.tail = face.key; + } + } + + // while continue and the strip isn't finished + // add more faces to the stream + while (cont && !stripDone(currStrip, count)) { + prev = face; + face = getNextFace(currStrip, count++); + share = face.findSharedEdge(prev.key); + + // if we can add the face without adding any + // zero area triangles + if (seq(currStream, face, share)) { + if (CHECK_ORIENT) { + // if we can add the next face with the correct + // orientation + if (orientSeq(ccw, currStream, face)) { + // append the vertex opposite the + //shared edge + currStream.append(face.verts[share]); + // next face must have opposite orientation + ccw = (!ccw); + // if this was the last tri in the + //strip, then we are done + if (stripDone(currStrip, count)) { + done = true; + // since we are done with this strip, + // set the tail to the current face + currStream.tail = face.key; + } + } + // if we cannot add the face with the correct + // orientation, do not continue with this + // stream + else { + cont = false; + // since we cannot continue with this strip + // set the tail to prev + currStream.tail = prev.key; + } + } + else { + // append the vertex opposite the + //shared edge + currStream.append(face.verts[share]); + // if this was the last tri in the + //strip, then we are done + if (stripDone(currStrip, count)) { + done = true; + // since we are done with this strip, + // set the tail to the current face + currStream.tail = face.key; + } + } + } + + // need zero area tris to add continue the strip + else { + if (CHECK_ORIENT) { + // check the orientation for adding a zero + // area tri and this face + if (orientZAT(ccw, currStream, face)) { + // swap the end of the current stream to + // add a zero area triangle + currStream.swapEnd(); + // append the vertex opposite the + // shared edge + currStream.append(face.verts[share]); + // if this was the last tri in the + // strip then we are done + if (stripDone(currStrip, count)) { + done = true; + // set the tail because we are done + currStream.tail = face.key; + } + } + // if we cannot add the face with the correct + // orientation, do not continue with this + // stream + else { + cont = false; + // since we cannot continue with this face, + // set the tail to the prev face + currStream.tail = prev.key; + } + } + else { + // swap the end of the current stream to + // add a zero area triangle + currStream.swapEnd(); + // append the vertex opposite the + // shared edge + currStream.append(face.verts[share]); + // if this was the last tri in the + // strip then we are done + if (stripDone(currStrip, count)) { + done = true; + // set the tail because we are done + currStream.tail = face.key; + } + } + } + } // while (cont && !stripDone) + } // else + + // add the current strip to the strips to be returned + istreams.add(currStream); + } // while !done + } // for each hamiltonian + return istreams; + } // stripe + + boolean stripDone(ArrayList strip, int count) { + if (count < strip.size()) { + return false; + } + else return true; + } + + boolean seq(Istream stream, Face face, int share) { + int length = stream.length; + Vertex v1 = face.edges[share].v1; + Vertex v2 = face.edges[share].v2; + Vertex last = stream.istream[length-1]; + Vertex prev = stream.istream[length-2]; + if (((v1.equals(prev)) && (v2.equals(last))) || + ((v1.equals(last)) && (v2.equals(prev)))) { + return true; + } + else return false; + } + + boolean orientSeq(boolean ccw, Istream stream, Face face) { + int length = stream.length; + Vertex last = stream.istream[length-1]; + Vertex prev = stream.istream[length-2]; + if ((ccw && checkOrientCCWSeq(last, prev, face)) || + ((!ccw) && checkOrientCWSeq(last, prev, face))) { + return true; + } + else return false; + } + + boolean orientZAT(boolean ccw, Istream stream, Face face) { + int length = stream.length; + Vertex last = stream.istream[length-1]; + Vertex swap = stream.istream[length-3]; + if ((ccw && checkOrientCWSeq(last, swap, face)) || + ((!ccw) && checkOrientCCWSeq(last, swap, face))) { + return true; + } + else return false; + } + + boolean checkOrientCWSeq(Vertex last, Vertex prev, Face face) { + System.out.println("checkOrientCWSeq"); + System.out.println("last = " + last.index); + System.out.println("prev = " + prev.index); + System.out.print("face = "); + face.printVertices(); + if (last.equals(face.verts[0])) { + if (!prev.equals(face.verts[1])) { + if (DEBUG) System.out.println("ORIENTATION PROBLEM!"); + return false; + } + } + else if (last.equals(face.verts[1])) { + if (!prev.equals(face.verts[2])) { + if (DEBUG) System.out.println("ORIENTATION PROBLEM!"); + return false; + } + } + else if (last.equals(face.verts[2])) { + if (!prev.equals(face.verts[0])) { + if (DEBUG) System.out.println("ORIENTATION PROBLEM!"); + return false; + } + } + return true; + } + + boolean checkOrientCCWSeq(Vertex last, Vertex prev, Face face) { + System.out.println("checkOrientCCWSeq"); + System.out.println("last = " + last.index); + System.out.println("prev = " + prev.index); + System.out.print("face = "); + face.printVertices(); + if (prev.equals(face.verts[0])) { + if (!last.equals(face.verts[1])) { + System.out.println("ORIENTATION PROBLEM!"); + return false; + } + } + else if (prev.equals(face.verts[1])) { + if (!last.equals(face.verts[2])) { + System.out.println("ORIENTATION PROBLEM!"); + return false; + } + } + else if (prev.equals(face.verts[2])) { + if (!last.equals(face.verts[0])) { + System.out.println("ORIENTATION PROBLEM!"); + return false; + } + } + return true; + } + + Face getNextFace(ArrayList currStrip, int index) { + if (currStrip.size() > index) return (Face)currStrip.get(index); + else return null; + } + + /** + * joins tristrips if their end triangles neighbor each other. The + * priority is performed in three stages: strips are concatenated to + * save 2, 1, or no vertices + */ + void concatenate(ArrayList strips, Face[] faces) { + int numFaces = faces.length; + int[] faceTable = new int[numFaces]; + Istream strm; + + // initialize the face table to empty + for (int i = 0; i < numFaces; i++) { + faceTable[i] = EMPTY; + } + + // set up the faceTable so that a face index relates to a strip + // that owns the face as one of its end faces + for (int i = 0; i < strips.size(); i++) { + strm = (Istream)strips.get(i); + faceTable[strm.head] = i; + faceTable[strm.tail] = i; + } + + if (DEBUG) { + System.out.println(""); + System.out.println("faceTable:"); + for (int i = 0; i < faceTable.length; i++) { + System.out.println(faceTable[i]); + } + System.out.println(""); + } + + reduceCostByTwo(strips, faces, faceTable); + reduceCostByOne(strips, faces, faceTable); + reduceCostByZero(strips, faces, faceTable); + } + + /** + * find all the links that reduce the cost by 2 + */ + void reduceCostByTwo(ArrayList strips, Face[] faces, int[] faceTable) { + // System.out.println("reduceCostByTwo"); + // number of faces in the face array + int numFaces = faces.length; + // possible adjacent strips + int id, id1, id2; + // Istreams + Istream strm, strm1; + // the length of the Istrem + int len, len1; + // vertex sequences for tristrips + Vertex[] seq, seq1; + // a face + Face face; + // the list of vertices for the face + Vertex[] verts; + // used to syncronize the orientation + boolean sync, sync1; + // a swap variable + Vertex swap; + + for (int i = 0; i < numFaces; i++) { + id = faceTable[i]; + if (id != EMPTY) { + sync = false; sync1 = false; + strm = (Istream)strips.get(id); + len = strm.length; + seq = strm.istream; + face = faces[i]; + verts = face.verts; + + // sequential strips + if (!strm.fan) { + + // a singleton strip + if (len == 3) { + + // check all three neighbors + for (int j = 0; j < 3; j++) { + int k = face.getNeighbor(j); + if ((k != EMPTY) && + ((id1 = faceTable[k]) != EMPTY) && + (id1 != id)) { + // reassign the sequence + seq[0] = verts[j]; + seq[1] = verts[(j+1)%3]; + seq[2] = verts[(j+2)%3]; + + // the neighboring stream + strm1 = (Istream)strips.get(id1); + len1 = strm1.length; + if (k != strm1.head) { + strm1.invert(); + // if the length is odd set sync1 to true + if ((len1 % 2) != 0) sync1 = true; + } + seq1 = strm1.istream; + + // append a singleton strip + if (len1 == 3) { + // System.out.println("reduce2"); + int m = faces[k].findSharedEdge(i); + strm.append(faces[k].verts[m]); + strm1.length = 0; + strm1.istream = null; + strm.tail = k; + faceTable[k] = id; + i--; + break; + } + + // append a strip of length over 2 + else { + if ((len1 == 4) && + (seq[1].index == seq1[0].index) && + (seq[2].index == seq1[2].index)) { + + // swap seq1[1] and seq1[2] so that + // seq[1] == seq1[0] and + // seq[1] == seq1[1] + swap = seq1[1]; + seq1[1] = seq1[2]; + seq1[2] = swap; + } + + // see if we can join the strips + if ((seq[1].index == seq1[0].index) && + (seq[2].index == seq1[1].index)) { + // System.out.println("reduce2"); + // add the stream in + strm.addStream(strm1); + faceTable[k] = EMPTY; + faceTable[strm.tail] = id; + + i--; + break; + } + else if (sync1) { + strm1.invert(); + sync1 = false; + } + } + } + } + } + + // not a singleton strip + + // can append a stream where the current face is the tail + // or is an even length so we can invert it + else if ((i == strm.tail) || ((len % 2) == 0)) { + // if the current face isn't the tail, then + // have to invert the strip + if (i != strm.tail) { + strm.invert(); + seq = strm.istream; + } + + // System.out.println("seq.length = " + seq.length); + // System.out.println("len = " + len); + // System.out.print("seq = "); + // for (int l = 0; l < seq.length; l++) { + // if (seq[l] == null) System.out.print(" null"); + // else System.out.print(" " + seq[l].index); + // } + // System.out.println(""); + + swap = seq[len - 3]; + + // find the neighboring strip + int m = EMPTY; + if (verts[0].index == swap.index) m = 0; + else if (verts[1].index == swap.index) m = 1; + else if (verts[2].index == swap.index) m = 2; + if (m == EMPTY) { + if (DEBUG) System.out.println("problem finding neighbor strip"); + } + int j = face.getNeighbor(m); + if (j == EMPTY) id1 = j; + else id1 = faceTable[j]; + if ((id1 != EMPTY) && + (((Istream)strips.get(id1)).fan != + strm.fan)) { + id1 = EMPTY; + } + + if ((id1 != EMPTY) && (id1 != id)) { + strm1 = (Istream)strips.get(id1); + len1 = strm1.length; + + // if the shared face isn't the head, invert + // the stream + if (j != strm1.head) { + strm1.invert(); + // set the sync var if the length is odd + if ((len1 % 2) != 0) sync1 = true; + } + seq1 = strm1.istream; + + // append a singleton strip + if (len1 == 3) { + // System.out.println("reduce2"); + m = faces[j].findSharedEdge(i); + strm.append(faces[j].verts[m]); + strm1.length = 0; + strm1.istream = null; + strm.tail = j; + faceTable[i] = EMPTY; + faceTable[j] = id; + } + + // append a non-singleton strip + else { + if ((len1 == 4) && + (seq[len-2].index == seq1[0].index) && + (seq[len-1].index == seq1[2].index)) { + + // swap seq1[1] and seq1[2] so that + // seq[len-2] == seq1[0] and + // seq[len-1] == seq1[1] + swap = seq1[1]; + seq1[1] = seq1[2]; + seq1[2] = swap; + } + + // see if we can append the strip + if ((seq[len-2].index == seq1[0].index) && + (seq[len-1].index == seq1[1].index)) { + // System.out.println("reduce2"); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[j] = EMPTY; + } + else if (sync1) strm1.invert(); + } + } + } + } + } + } + } + + /** + * find all links that reduce cost by 1 + */ + void reduceCostByOne(ArrayList strips, Face[] faces, int[] faceTable) { + // System.out.println("reduceCostByOne"); + // number of faces in the face array + int numFaces = faces.length; + // possible adjacent strips + int id, id1, id2; + // Istreams + Istream strm, strm1; + // the length of the Istream + int len, len1; + // vertex sequences for tristrips + Vertex[] seq, seq1; + // a face + Face face; + // the list of vertices for the face + Vertex[] verts; + // used to synchronize the orientation + boolean sync, sync1; + // a swap variable + Vertex swap; + + for (int i = 0; i < numFaces; i++) { + id = faceTable[i]; + if ((id != EMPTY) && !((Istream)strips.get(id)).fan) { + sync = false; + strm = (Istream)strips.get(id); + seq = strm.istream; + face = faces[i]; + verts = face.verts; + len = strm.length; + + // a singleton strip + if (len == 3) { + + // consider the three neighboring triangles + for (int j = 0; j < 3; j++) { + int k = face.getNeighbor(j); + if ((k != EMPTY) && + ((id1 = faceTable[k]) != EMPTY) && + (id1 != id) && + (!((Istream)strips.get(id1)).fan)) { + + // reassign the sequence + seq[0] = verts[j]; + seq[1] = verts[(j+1)%3]; + seq[2] = verts[(j+2)%3]; + + // the neighboring stream + strm1 = (Istream)strips.get(id1); + len1 = strm1.length; + if (k != strm1.head) { + strm1.invert(); + if ((len1 % 2) != 0) sync = true; + } + seq1 = strm1.istream; + + // see if we can join the strips + + if ((len1 == 4) && + (((seq[1].index == seq1[2].index) && + (seq[2].index == seq1[0].index)) || + ((seq[1].index == seq1[0].index) && + (seq[2].index == seq1[2].index)))) { + swap = seq1[1]; + seq1[1] = seq1[2]; + seq1[2] = swap; + } + + if ((seq[1].index == seq1[0].index) && + (seq[2].index == seq1[1].index)) { + // System.out.println("reduce1"); + strm.addStream(strm1); + faceTable[k] = EMPTY; + faceTable[strm.tail] = id; + i--; + break; + } + + if ((seq[1].index == seq1[1].index) && + (seq[2].index == seq1[0].index)) { + // System.out.println("reduce1"); + strm.append(seq1[1]); + strm.addStream(strm1); + faceTable[k] = EMPTY; + faceTable[strm.tail] = id; + i--; + break; + } + + if ((seq[1].index == seq1[0].index) && + (seq[2].index == seq1[2].index)) { + // System.out.println("reduce1"); + seq1[0] = seq1[2]; + strm.append(seq1[1]); + strm.addStream(strm1); + faceTable[k] = EMPTY; + faceTable[strm.tail] = id; + i--; + break; + } + + if (sync) { + strm1.invert(); + sync = false; + } + } + } + } + + // non-singleton strip + else if ((i == strm.tail) || ((len % 2) == 0)) { + + // make sure the face i ends the id-th strip + if (i != strm.tail) { + strm.invert(); + seq = strm.istream; + } + + swap = seq[len-3]; + + // find the neighboring strip + int m = EMPTY; + if (verts[0].index == swap.index) m = 0; + else if (verts[1].index == swap.index) m = 1; + else if (verts[2].index == swap.index) m = 2; + if (m == EMPTY) { + if (DEBUG) System.out.println("problem finding neighbor strip"); + } + int j = face.getNeighbor(m); + if (j == EMPTY) id1 = j; + else id1 = faceTable[j]; + if ((id1 != EMPTY) && + (((Istream)strips.get(id1)).fan != strm.fan)) { + id1 = EMPTY; + } + + // find another neighboring strip + swap = seq[len-2]; + m = EMPTY; + if (verts[0].index == swap.index) m = 0; + else if (verts[1].index == swap.index) m = 1; + else if (verts[2].index == swap.index) m = 2; + if (m == EMPTY) { + if (DEBUG) System.out.println("problem finding neighbor strip."); + } + int k = face.getNeighbor(m); + if (k == EMPTY) id2 = k; + else id2 = faceTable[k]; + if ((id2 != EMPTY) && + (((Istream)strips.get(id2)).fan != strm.fan)) { + id2 = EMPTY; + } + + // consider strip id1 + boolean success = false; + if ((id1 != EMPTY) && (id1 != id)) { + strm1 = (Istream)strips.get(id1); + len1 = strm1.length; + if (j != strm1.head) { + strm1.invert(); + if ((len1 % 2) != 0) sync = true; + } + seq1 = strm1.istream; + + if ((len1 == 4) && + (((seq[len-2].index == seq1[2].index) && + (seq[len-1].index == seq1[0].index)) || + (seq[len-2].index == seq1[0].index) && + (seq[len-1].index == seq1[2].index))) { + swap = seq1[1]; + seq1[1] = seq1[2]; + seq1[2] = swap; + } + + // find matches + if ((seq[len-2].index == seq1[0].index) && + (seq[len-1].index == seq1[1].index)) { + // System.out.println("reduce1"); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[j] = EMPTY; + success = true; + } + + else if ((seq[len-2].index == seq1[1].index) && + (seq[len-1].index == seq1[0].index)) { + // System.out.println("reduce1"); + strm.append(seq1[1]); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[j] = EMPTY; + success = true; + } + + else if ((seq[len-2].index == seq1[0].index) && + (seq[len-1].index == seq1[2].index)) { + // System.out.println("reduce1"); + seq1[0] = seq1[2]; + strm.append(seq1[1]); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[j] = EMPTY; + success = true; + } + else if (sync) { + strm1.invert(); + sync = false; + } + } + + // now consider strip id2 + if (!success && + (id2 != EMPTY) && (id2 != id)) { + strm1 = (Istream)strips.get(id2); + len1 = strm1.length; + if (k != strm1.head) { + strm1.invert(); + if ((len1 % 2) != 0) sync = true; + } + seq1 = strm1.istream; + + if ((len1 == 4) && + (seq[len-3].index == seq1[0].index) && + (seq[len-1].index == seq1[2].index)) { + swap = seq1[1]; + seq1[1] = seq1[2]; + seq1[2] = swap; + } + + // find matches + + if ((seq[len-3].index == seq1[0].index) && + (seq[len-1].index == seq1[1].index)) { + // System.out.println("reduce1"); + strm.swapEnd(); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[k] = EMPTY; + success = true; + } + if (!success && sync) strm1.invert(); + } + } + } + } + } + + /** + * find all the links that reduce the cost by 0 + */ + void reduceCostByZero(ArrayList strips, Face[] faces, int[] faceTable) { + // System.out.println("reduceCostByZero"); + // number of faces in the face array + int numFaces = faces.length; + // possible adjacent strips + int id, id1, id2; + // Istreams + Istream strm, strm1; + // the length of the Istream + int len, len1; + // vertex sequences for tristrips + Vertex[] seq, seq1; + // a face + Face face; + // the list of vertices for the face + Vertex[] verts; + // used to synchronize the orientation + boolean sync, sync1; + // a swap variable + Vertex swap; + + for (int i = 0; i < numFaces; i++) { + id = faceTable[i]; + if ((id != EMPTY) && !((Istream)strips.get(id)).fan) { + sync = false; + strm = (Istream)strips.get(id); + seq = strm.istream; + len = strm.length; + face = faces[i]; + verts = face.verts; + + if (len == 3) { + for (int j = 0; j < 3; j++) { + int k = face.getNeighbor(j); + if ((k != EMPTY) && ((id1 = faceTable[k]) != EMPTY) && + (id1 != id) && + !((Istream)strips.get(id1)).fan) { + // reassign the sequence + seq[0] = verts[j]; + seq[1] = verts[(j+1)%3]; + seq[2] = verts[(j+2)%3]; + + // the neighboring stream + strm1 = (Istream)strips.get(id1); + len1 = strm1.length; + if (k != strm1.head) { + strm1.invert(); + if ((len1 % 2) != 0) sync = true; + } + seq1 = strm1.istream; + + // see if we can join the strips + if ((seq[1].index == seq1[2].index) && + (seq[2].index == seq1[0].index)) { + // System.out.println("reduce0"); + seq1[0] = seq1[2]; + strm.append(seq1[0]); + strm.append(seq1[1]); + strm.addStream(strm1); + faceTable[k] = EMPTY; + faceTable[strm.tail] = id; + i--; + break; + } + else if (sync) { + strm1.invert(); + sync = false; + } + } + } + } + else if ((i == strm.tail) || ((len % 2) == 0)) { + if (i != strm.tail) { + strm.invert(); + seq = strm.istream; + } + + swap = seq[len-3]; + + // find neighboring strip + int m = EMPTY; + if (verts[0].index == swap.index) m = 0; + else if (verts[1].index == swap.index) m = 1; + else if (verts[2].index == swap.index) m = 2; + if (m == EMPTY) { + if (DEBUG) System.out.println("problem finding neighbor strip"); + } + int j = face.getNeighbor(m); + if (j == EMPTY) id1 = j; + else id1 = faceTable[j]; + if ((id1 != EMPTY) && + (((Istream)strips.get(id1)).fan != strm.fan)) { + id1 = EMPTY; + } + + // find another neighboring strip + swap = seq[len-2]; + m = EMPTY; + if (verts[0].index == swap.index) m = 0; + else if (verts[1].index == swap.index) m = 1; + else if (verts[2].index == swap.index) m = 2; + if (m == EMPTY) { + if (DEBUG) System.out.println("problem finding neighbor strip."); + } + int k = face.getNeighbor(m); + if (k == EMPTY) id2 = k; + else id2 = faceTable[k]; + if ((id2 != EMPTY) && + (((Istream)strips.get(id2)).fan != strm.fan)) { + id2 = EMPTY; + } + + // consider strip id1 + boolean success = false; + if ((id1 != EMPTY) && (id1 != id)) { + strm1 = (Istream)strips.get(id1); + len1 = strm1.length; + if (j != strm1.head) { + strm1.invert(); + if ((len1 % 2) != 0) sync = true; + } + seq1 = strm1.istream; + + // find matches + if ((seq[len-2].index == seq1[2].index) && + (seq[len-1].index == seq1[0].index)) { + // System.out.println("reduce0"); + seq1[0] = seq1[2]; + strm.append(seq1[0]); + strm.append(seq1[1]); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[j] = EMPTY; + success = true; + } + else if (sync) { + strm1.invert(); + sync = false; + } + } + + // consider strip id2 + if (!success && (id2 != EMPTY) && (id2 != id)) { + strm1 = (Istream)strips.get(id2); + len1 = strm1.length; + if (k != strm1.head) { + strm1.invert(); + if ((len1 % 2) != 0) sync = true; + } + seq1 = strm1.istream; + + if ((len1 == 4) && + (((seq[len-3].index == seq1[2].index) && + (seq[len-1].index == seq1[0].index)) || + ((seq[len-3].index == seq1[0].index) && + (seq[len-1].index == seq1[2].index)))) { + + swap = seq1[1]; + seq1[1] = seq1[2]; + seq1[2] = swap; + } + + // find matches + if ((seq[len-3].index == seq1[1].index) && + (seq[len-1].index == seq1[0].index)) { + // System.out.println("reduce0"); + strm.swapEnd(); + strm.append(seq1[1]); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[k] = EMPTY; + } + else if ((seq[len-3].index == seq1[0].index) && + (seq[len-1].index == seq1[2].index)) { + // System.out.println("reduce0"); + seq1[0] = seq1[2]; + strm.swapEnd(); + strm.append(seq1[1]); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[k] = EMPTY; + } + else if ((seq[len-3].index == seq1[0].index) && + (seq[len-1].index == seq1[1].index)) { + // System.out.println("reduce0"); + strm.swapEnd(); + strm.addStream(strm1); + faceTable[i] = EMPTY; + faceTable[strm.tail] = id; + faceTable[k] = EMPTY; + } + else if (sync) strm1.invert(); + } + } + } + } + } + + /** + * puts the stripified data back into the GeometryInfo object + */ + void putBackData(GeometryInfo gi, ArrayList strips) { + int[] tempStripCounts = new int[strips.size()]; + int ciSize = 0; + int stripLength; + for (int i = 0; i < strips.size();) { + stripLength = ((Istream)strips.get(i)).length; + if (stripLength != 0) { + tempStripCounts[i] = stripLength; + ciSize += stripLength; + i++; + } + else { + strips.remove(i); + } + } + if (ciSize > 3) { + gi.setPrimitive(gi.TRIANGLE_STRIP_ARRAY); + int[] stripCounts = new int[strips.size()]; + System.arraycopy(tempStripCounts, 0, stripCounts, 0, strips.size()); + gi.setStripCounts(stripCounts); + + // create one array with all the strips + int[] coords = new int[ciSize]; + + // create arrays for normals, textures and colors if necessary + int[] normals = null; + int[][] textures = null; + int[] colors = null; + javax.vecmath.Color3b[] stripColors = null; + if (hasNormals) normals = new int[ciSize]; + if (hasTextures) { + textures = new int[texSetCount][ciSize]; + } + if (hasColors) colors = new int[ciSize]; + if (colorStrips) { + stripColors = new javax.vecmath.Color3b[ciSize]; + colors = new int[ciSize]; + } + int count = 0; + Istream currStrip; + for (int i = 0; i < strips.size(); i++) { + currStrip = (Istream)strips.get(i); + + if (currStrip.length < 3) { + throw new RuntimeException("currStrip.length = " + + currStrip.length); + } + + java.awt.Color stripColor = null; + if (colorStrips) { + int r = ((int)(Math.random()*1000))%255; + int g = ((int)(Math.random()*1000))%255; + int b = ((int)(Math.random()*1000))%255; + stripColor = new java.awt.Color(r, g, b); + } + + for (int j = 0; j < currStrip.length; j++) { + coords[count] = currStrip.istream[j].index; + if (hasNormals) normals[count] = currStrip.istream[j].normal; + if (hasTextures) { + for (int k = 0; k < texSetCount; k++) { + textures[k][count] = + currStrip.istream[j].texture[k]; + } + } + if (hasColors) colors[count] = currStrip.istream[j].color; + if (colorStrips) stripColors[count] = + new javax.vecmath.Color3b(stripColor); + count++; + } + } + gi.setCoordinateIndices(coords); + if (hasNormals) gi.setNormalIndices(normals); + if (hasTextures) { + for (int i = 0; i < texSetCount; i++) { + gi.setTextureCoordinateIndices(i, textures[i]); + } + } + if (hasColors) gi.setColorIndices(colors); + if (colorStrips) { + gi.setColors(stripColors); + colors = gi.getListIndices(stripColors); + gi.setColorIndices(colors); + } + } + } + + /** + * Stores the infomration about a vertex + */ + class Vertex { + + int index; + int normal = EMPTY; + int numTexSets = 0; + int[] texture = null; + int color = EMPTY; + + Vertex(int vertIndex) { + this(vertIndex, EMPTY, 0, null, EMPTY); + } + + Vertex(int vertIndex, int vertNormal, + int vertNumTexSets, int[] vertTexture, int vertColor) { + index = vertIndex; + normal = vertNormal; + numTexSets = vertNumTexSets; + if (numTexSets > 0) { + texture = new int[numTexSets]; + System.arraycopy(vertTexture, 0, texture, 0, numTexSets); + } + color = vertColor; + } + + boolean equals(Vertex v) { + for (int i = 0; i < numTexSets; i++) { + if (texture[i] != v.texture[i]) { + return false; + } + } + return ((v.index == index) && + (v.normal == normal) && + (v.color == color)); + } + + // will this yield same results as c code ??? + boolean lessThan(Vertex v) { + if (index < v.index) return true; + if (index > v.index) return false; + if (normal < v.normal) return true; + if (normal > v.normal) return false; + for (int i = 0; i < numTexSets; i++) { + if (texture[i] < v.texture[i]) return true; + if (texture[i] > v.texture[i]) return false; + } + if (color < v.color) return true; + if (color > v.color) return false; + return false; + } + } + + /** + * Stores the information about an edge of a triangle + */ + class Edge { + + Vertex v1, v2; + int face; + + Edge(Vertex vertex1, Vertex vertex2, int faceIndex) { + face = faceIndex; + + // this could be causing wrapping problem + if (vertex1.lessThan(vertex2)) { + v1 = vertex1; + v2 = vertex2; + } else { + v1 = vertex2; + v2 = vertex1; + } + } + + /** + * Determine whether the edges have the same vertices + */ + boolean equals(Edge edge) { + return ((v1.equals(edge.v1)) && (v2.equals(edge.v2))); + + } + + /** + * Used to sort the edges. If this is less than the edge parameter, + * return true. First check if vertex1 is less than vertex1 of the + * edge provided. If so, return true. If the first vertices are equal + * then check vertex2. + */ + boolean lessThan(Edge edge) { + if (v1.lessThan(edge.v1)) return true; + else if (v1.equals(edge.v1)) return (v2.lessThan(edge.v2)); + else return false; + } + } + + /** + * Stores the information about the face of a triangle + */ + class Face { + int key; + int numNhbrs = 0; + Vertex[] verts = null; + // edges are kept in order s.t. the ith edge is the opposite + // edge of the ith vertex + Edge[] edges = null; + + /** + * Creates a new Face with the three given vertices + */ + Face(int index, Vertex v1, Vertex v2, Vertex v3) { + key = index; + + verts = new Vertex[3]; + verts[0] = v1; + verts[1] = v2; + verts[2] = v3; + + edges = new Edge[3]; + edges[0] = null; + edges[1] = null; + edges[2] = null; + numNhbrs = 3; + } + + /** + * returns the index of the face that neighbors the edge supplied + * by the parameter + */ + int getNeighbor(int edge) { + return edges[edge].face; + } + + /** + * returns the index of the edge that is shared by the triangle + * specified by the key parameter + */ + int findSharedEdge(int key) { + if (edges[0].face == key) return 0; + else if (edges[1].face == key) return 1; + else if (edges[2].face == key) return 2; + else return -1; /* error */ + } + + int getEdgeIndex(Edge edge) { + if (edges[0].equals(edge)) return 0; + else if (edges[1].equals(edge)) return 1; + else return 2; + } + + void counterEdgeDel(Edge edge) { + if (DEBUG) { + System.out.println("counterEdgeDel"); + } + if ((edges[0]).equals(edge)) { + edges[0].face = EMPTY; + numNhbrs--; + } + else if ((edges[1]).equals(edge)) { + edges[1].face = EMPTY; + numNhbrs--; + } + else if ((edges[2]).equals(edge)) { + edges[2].face = EMPTY; + numNhbrs--; + } + else { + if (DEBUG) { + System.out.println("error in counterEdgeDel"); + } + } + } + + void printAdjacency() { + System.out.println("Face " + key + ": "); + System.out.println("\t numNhbrs = " + numNhbrs); + System.out.println("\t edge 0: Face " + edges[0].face); + System.out.println("\t edge 1: Face " + edges[1].face); + System.out.println("\t edge 2: Face " + edges[2].face); + } + + void printVertices() { + System.out.println("Face " + key + ": (" + verts[0].index + ", " + + verts[1].index + ", " + verts[2].index + ")"); + } + } + + /** + * stores the information for a face node + */ + class Node { + Face face; // the data: the face + Node parent; // the parent node + Node left; // the left child + Node right; // the right child + int depth; // the topological distance of the node from the root + int numChildren; // the number of children + int attrib; // characteristic of the node eg. color + + // the attributes - 3 states for the Node + static final int WHITE = 0; // not being accessed yet + static final int GREY = 1; // being accessed but not done yet + static final int BLACK = 2; // done + + Node(Face f) { + face = f; + } + + /** + * inserts this node below the parent supplied. + */ + void insert(Node p) { + parent = p; + depth = p.depth + 1; + attrib = GREY; + + if (parent.left == null) parent.left = this; + else parent.right = this; + (parent.numChildren)++; + } + + /** + * remove this node from its parent + */ + void remove() { + if (parent != null) { + if (parent.left == this) { + parent.left = parent.right; + parent.right = null; + } + else { + parent.right = null; + } + (parent.numChildren)--; + } + } + + + /** + * sets the depth to 0 and the attrib to GREY + */ + void setRoot() { + depth = 0; + attrib = GREY; + } + + /** + * returns true if the attrib is WHITE + */ + boolean notAccessed() { + return (attrib == WHITE); + } + + /** + * sets the color to BLACK + */ + void processed() { + attrib = BLACK; + } + + /** + * a node is the root if it doesn't have a parent + */ + boolean isRoot() { + return (parent == null); + } + + /** + * prints the information in this Node + */ + void print() { + System.out.println(this); + System.out.println("Node depth: " + depth); + face.printVertices(); + System.out.print("parent: "); + if (parent != null) parent.face.printVertices(); + else System.out.println("null"); + System.out.print("left: "); + if (left != null) left.face.printVertices(); + else System.out.println("null"); + System.out.print("right: "); + if (right != null) right.face.printVertices(); + else System.out.println("null"); + System.out.println("attrib: " + attrib); + System.out.println(""); + } + } + + /** + * sorts the Nodes by depth + */ + class SortedList { + + ArrayList list; + + /** + * create a new SortedList + */ + SortedList() { + list = new ArrayList(); + } + + /** + * insert into the list sorted by depth. start looking at start + * to save some time. Returns the index of the next item of the + * inserted element + */ + int sortedInsert(Node data, int start) { + // adjust start to where insert sorted + while ((start < list.size()) && + (((Node)list.get(start)).depth <= data.depth)) { + start++; + } + + // insert at start index + list.add(start, data); + + // return start+1 -- the index of the next element + return (start+1); + } + + /** + * remove and return 1st element + */ + Node pop() { + if (!list.isEmpty()) return (Node)list.remove(0); + else return null; + } + } + + class Istream { + + // fan encoding + boolean fan = false; + // length of the strip + int length = 0; + // array that specifies triangle strip + Vertex[] istream; + // indices of the head and tail vertices + int head, tail; + + /** + * creates a new Istream to store the triangle strip + */ + Istream(Vertex[] list, int size, boolean isFan) { + if (size == 0) throw new RuntimeException("size is 0"); + fan = isFan; + length = size; + istream = new Vertex[length]; + int i; + System.arraycopy(list, 0, istream, 0, length); + } + + /** + * adds a new vertex to the end of the stream + * makes the int array bigger, if necessary + */ + void append(Vertex vertex) { + growArray(); + // add in new vertex + istream[length] = vertex; + length++; + } + + /** + * turns the encoding (..., -3, -2, -1) into (.... -3, -2, -3, -1) + * so that zero-area triangle (-3, -2. -3) is added + */ + void swapEnd() { + growArray(); + istream[length] = istream[length-1]; + istream[length-1] = istream[length-3]; + length++; + } + + /** + * makes the array bigger, if necessary + */ + void growArray() { + if (length >= istream.length) { + Vertex[] old = istream; + // for now add enough space to add three more vertices + // may change this later + istream = new Vertex[length + 3]; + System.arraycopy(old, 0, istream, 0, length); + } + } + + /** + * inverts the istream + */ + void invert() { + Vertex[] tmp = new Vertex[istream.length]; + // reverse the stream + for (int i = 0; i < length; i++) { + tmp[i] = istream[length - i - 1]; + } + // copy it back + System.arraycopy(tmp, 0, istream, 0, istream.length); + tmp = null; + // swap the head and the tail + int swap = head; + head = tail; + tail = swap; + } + + /** + * concats two streams into one big stream + */ + void addStream(Istream strm) { + // System.out.println("addStream"); + int strmLen = strm.length; + int size = strmLen + length - 2; + + // make the istream bigger + if (size >= istream.length) { + Vertex[] old = istream; + istream = new Vertex[size]; + System.arraycopy(old, 0, istream, 0, length); + } + + // add the strm to istream + System.arraycopy(strm.istream, 2, istream, length, strmLen-2); + + tail = strm.tail; + length = size; + strm.length = 0; + strm.istream = null; + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/StripifierStats.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/StripifierStats.java new file mode 100644 index 0000000..06ecfe7 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/StripifierStats.java @@ -0,0 +1,345 @@ +/* + * $RCSfile: StripifierStats.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:20 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import java.util.ArrayList; + +/** + * This class collects statistics on the Stripifier. The statistics + * are cumulative over all calls to stripify() until clearData() is called. + * + * @since Java 3D 1.2.1 + */ + +public class StripifierStats { + + int numStrips = 0; + int numVerts = 0; + int minStripLen = 10000; + int maxStripLen = 0; + int totalTris = 0; + int numFaces = 0; + long time = 0; + int[] counts = new int[14]; + + boolean noData = true; + + /** + * Returns the number of triangles in the original, un-stripified data. + * @since Java 3D 1.2.1 + */ + public int getNumOrigTris() { + return numFaces; + } + + /** + * Returns the number of vertices in the original, un-stripified data + * @since Java 3D 1.2.1 + */ + public int getNumOrigVerts() { + return (numFaces * 3); + } + + /** + * Returns the number of strips created by the stripifier. + * @since Java 3D 1.2.1 + */ + public int getNumStrips() { + return numStrips; + } + + /** + * Returns the number of vertices in the stripified data. + * @since Java 3D 1.2.1 + */ + public int getNumVerts() { + return numVerts; + } + + /** + * Returns the number of triangles in the stripified data. + * @since Java 3D 1.2.1 + */ + public int getTotalTris() { + return totalTris; + } + + /** + * Returns the length in triangles of the shortest strip + * created by the stripifier. + * @since Java 3D 1.2.1 + */ + public int getMinStripLength() { + return minStripLen; + } + + /** + * Returns the length in triangles of the longest strip + * created by the stripifier. + * @since Java 3D 1.2.1 + */ + public int getMaxStripLength() { + return maxStripLen; + } + + /** + * Return the average length of the strips created by the stripifier + * @since Java 3D 1.2.1 + */ + public double getAvgStripLength() { + return ((double)totalTris/(double)numStrips); + } + + /** + * Returns the average number of vertices per triangle in the stripified + * data + * @since Java 3D 1.2.1 + */ + public double getAvgNumVertsPerTri() { + return ((double)numVerts/(double)totalTris); + } + + /** + * Returns the total time spent in the stripify() method + * @since Java 3D 1.2.1 + */ + public long getTotalTime() { + return time; + } + + /** + * Returns an array of length 14 that contains the number of strips of + * a given length created by the stripifier. Spots 0-8 of the array + * represent lengths 1-9, 9 is lengths 10-19, 10 is lengths 20-49, + * 11 is lengths 50-99, 12 is lengths 100-999 and 13 is lengths 1000 + * or more. + * @since Java 3D 1.2.1 + */ + public int[] getStripLengthCounts() { + return counts; + } + + /** + * Returns a formated String that can be used to print out + * the Stripifier stats. + * @since Java 3D 1.2.1 + */ + + public String toString() { + StringBuffer str = new StringBuffer( + "num orig tris: " + numFaces + "\n" + + "num orig vertices: " + (numFaces*3) + "\n" + + "number of strips: " + numStrips + "\n" + + "number of vertices: " + numVerts + "\n" + + "total tris: " + totalTris + "\n" + + "min strip length: " + minStripLen + "\n" + + "max strip length: " + maxStripLen + "\n" + + "avg strip length: " + ((double)totalTris/ + (double)numStrips) + "\n" + + "avg num verts/tri: " + ((double)numVerts/ + (double)totalTris) + "\n" + + "total time: " + time + "\n" + + "strip length distribution:\n"); + for (int i = 0; i < 9; i++){ + str.append(" " + (i+1) + "=" + counts[i]); + } + str.append(" 10-19=" + counts[9]); + str.append(" 20-49=" + counts[10]); + str.append(" 50-99=" + counts[11]); + str.append(" 100-999=" + counts[12]); + str.append(" 1000 or more=" + counts[13] + "\n"); + + return str.toString(); + } + + /** + * Clears the statistical data + */ + public void clearData() { + noData = true; + + numStrips = 0; + numVerts = 0; + minStripLen = 10000; + maxStripLen = 0; + totalTris = 0; + numFaces = 0; + time = 0; + counts = new int[14]; + } + + void updateInfo(long ntime, ArrayList strips, + int nNumFaces) { + noData = false; + + time += ntime; + numStrips += strips.size(); + int nv = 0; + int mnsl = 10000; + int mxsl = 0; + int tt = 0; + for (int i = 0; i < strips.size(); i++) { + Stripifier.Istream strm = (Stripifier.Istream)strips.get(i); + int len = strm.length; + int trilen = (len-2); + nv += len; + if (trilen < mnsl) mnsl = trilen; + if (trilen > mxsl) mxsl = trilen; + tt += trilen; + + // add to counts + // how many strips are length 1-9 + if (trilen <= 9) counts[trilen-1] += 1; + // how many strips are length 10-19 + else if (trilen < 20) counts[9] += 1; + // how many strips are length 20-49 + else if (trilen < 50) counts[10] += 1; + // how many strips are length 50-99 + else if (trilen < 100) counts[11] += 1; + // how many strips are length 100-1000 + else if (trilen < 1000) counts[12] += 1; + // how many strips are length > 1000 + else counts[13] += 1; + } + numVerts += nv; + if (mnsl < minStripLen) minStripLen = mnsl; + if (mxsl > maxStripLen) maxStripLen = mxsl; + totalTris += tt; + numFaces += nNumFaces; + } + + void updateInfo(long ntime, int scLen, int sc[], + int nNumFaces) { + + noData = false; + + time += ntime; + numStrips += scLen; + int nv = 0; + int mnsl = 10000; + int mxsl = 0; + int tt = 0; + for (int i = 0; i < scLen; i++) { + int len = sc[i]; + int trilen = (len-2); + numVerts += len; + if (trilen < mnsl) mnsl = trilen; + if (trilen > mxsl) mxsl = trilen; + totalTris += trilen; + + // add to counts + // how many strips are length 1-9 + if (trilen <= 9) counts[trilen-1] += 1; + // how many strips are length 10-19 + else if (trilen < 20) counts[9] += 1; + // how many strips are length 20-49 + else if (trilen < 50) counts[10] += 1; + // how many strips are length 50-99 + else if (trilen < 100) counts[11] += 1; + // how many strips are length 100-1000 + else if (trilen < 1000) counts[12] += 1; + // how many strips are length > 1000 + else counts[13] += 1; + } + numVerts += nv; + if (mnsl < minStripLen) minStripLen = mnsl; + if (mxsl > maxStripLen) maxStripLen = mxsl; + totalTris += tt; + numFaces += nNumFaces; + } + + // void printInfo() { + // System.out.println("num orig tris: " + numFaces); + // System.out.println("num orig vertices: " + (numFaces*3)); + // System.out.println("number of strips: " + numStrips); + // System.out.println("number of vertices: " + numVerts); + // System.out.println("total tris: " + totalTris); + // System.out.println("min strip length: " + minStripLen); + // System.out.println("max strip length: " + maxStripLen); + // System.out.println("avg strip length: " + ((double)totalTris/ + // (double)numStrips)); + // System.out.println("avg num verts/tri: " + ((double)numVerts/ + // (double)totalTris)); + // System.out.println("total time: " + time); + // System.out.println("strip length distribution:"); + // for (int i = 0; i < 9; i++){ + // System.out.print(" " + (i+1) + "=" + counts[i]); + // } + // System.out.print(" 10-19=" + counts[9]); + // System.out.print(" 20-49=" + counts[10]); + // System.out.print(" 50-99=" + counts[11]); + // System.out.print(" 100-999=" + counts[12]); + // System.out.println(" 1000 or more=" + counts[13]); + + // // reset info after printing data + // numStrips = 0; + // numVerts = 0; + // minStripLen = 10000; + // maxStripLen = 0; + // totalTris = 0; + // numFaces = 0; + // time = 0; + // counts = new int[14]; + // } + + StripifierStats() { + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Text2D.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Text2D.java new file mode 100644 index 0000000..254ff2f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Text2D.java @@ -0,0 +1,382 @@ +/* + * $RCSfile: Text2D.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:21 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry; + +import java.awt.image.BufferedImage; +import java.awt.image.WritableRaster; +import java.awt.image.DataBufferInt; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Toolkit; +import java.util.Hashtable; + +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * A Text2D object is a representation of a string as a texture mapped + * rectangle. The texture for the rectangle shows the string as rendered in + * the specified color with a transparent background. The appearance of the + * characters is specified using the font indicated by the font name, size + * and style (see java.awt.Font). The approximate height of the rendered + * string will be the font size times the rectangle scale factor, which has a + * default value of 1/256. For example, a 12 point font will produce + * characters that are about 12/256 = 0.047 meters tall. The lower left + * corner of the rectangle is located at (0,0,0) with the height + * extending along the positive y-axis and the width extending along the + * positive x-axis. + */ +public class Text2D extends Shape3D { + + // This table caches FontMetrics objects to avoid the huge cost + // of re-retrieving metrics for a font we've already seen. + private static Hashtable metricsTable = new Hashtable(); + float rectangleScaleFactor = 1f/256f; + + Color3f color = new Color3f(); + String fontName; + int fontSize, fontStyle; + String text; + + + /** + * Creates a Shape3D object which holds a + * rectangle that is texture-mapped with an image that has + * the specified text written with the specified font + * parameters. + * + * @param text The string to be written into the texture map. + * @param color The color of the text string. + * @param fontName The name of the Java font to be used for + * the text string. + * @param fontSize The size of the Java font to be used. + * @param fontStyle The style of the Java font to be used. + */ + public Text2D(String text, Color3f color, String fontName, + int fontSize, int fontStyle) { + + this.color.set(color); + this.fontName = fontName; + this.fontSize = fontSize; + this.fontStyle = fontStyle; + this.text = text; + + updateText2D(text, color, fontName, fontSize, fontStyle); + } + + /* + * Changes text of this Text2D to 'text'. All other + * parameters (color, fontName, fontSize, fontStyle + * remain the same. + * @param text The string to be set. + */ + public void setString(String text){ + this.text = text; + + Texture tex = getAppearance().getTexture(); + int width = tex.getWidth(); + int height = tex.getHeight(); + + ImageComponent imageComponent = setupImage(text, color, fontName, + fontSize, fontStyle); + if ((imageComponent.getWidth() == width) && + (imageComponent.getHeight() == height)) { + tex.setImage(0, imageComponent); + } else { + Texture2D newTex = setupTexture(imageComponent); + // Copy texture attributes except those related to + // mipmap since Texture only set base imageComponent. + + newTex.setBoundaryModeS(tex.getBoundaryModeS()); + newTex.setBoundaryModeT(tex.getBoundaryModeT()); + newTex.setMinFilter(tex.getMinFilter()); + newTex.setMagFilter(tex.getMagFilter()); + newTex.setEnable(tex.getEnable()); + newTex.setAnisotropicFilterMode(tex.getAnisotropicFilterMode()); + newTex.setAnisotropicFilterDegree(tex.getAnisotropicFilterDegree()); + int pcount = tex.getFilter4FuncPointsCount(); + if (pcount > 0) { + float weights[] = new float[pcount]; + tex.getFilter4Func(weights); + newTex.setFilter4Func(weights); + } + Color4f c = new Color4f(); + tex.getBoundaryColor(c); + newTex.setBoundaryColor(c); + newTex.setUserData(tex.getUserData()); + getAppearance().setTexture(newTex); + } + } + + private void updateText2D(String text, Color3f color, String fontName, + int fontSize, int fontStyle) { + ImageComponent imageComponent = setupImage(text, color, fontName, + fontSize, fontStyle); + + Texture2D t2d = setupTexture(imageComponent); + + QuadArray rect = setupGeometry(imageComponent.getWidth(), + imageComponent.getHeight()); + setGeometry(rect); + + Appearance appearance = setupAppearance(t2d); + setAppearance(appearance); + } + + + /** + * Sets the scale factor used in converting the image width/height + * to width/height values in 3D. + * + * @param newScaleFactor The new scale factor. + */ + public void setRectangleScaleFactor(float newScaleFactor) { + rectangleScaleFactor = newScaleFactor; + updateText2D(text, color, fontName, fontSize, fontStyle); + } + + /** + * Gets the current scale factor being used in converting the image + * width/height to width/height values in 3D. + * + * @return The current scale factor. + */ + public float getRectangleScaleFactor() { + return rectangleScaleFactor; + } + + /** + * Create the ImageComponent and Texture object. + */ + private Texture2D setupTexture(ImageComponent imageComponent) { + Texture2D t2d = new Texture2D(Texture2D.BASE_LEVEL, + Texture.RGBA, + imageComponent.getWidth(), + imageComponent.getHeight()); + t2d.setMinFilter(t2d.BASE_LEVEL_LINEAR); + t2d.setMagFilter(t2d.BASE_LEVEL_LINEAR); + t2d.setImage(0, imageComponent); + t2d.setEnable(true); + t2d.setCapability(Texture.ALLOW_IMAGE_WRITE); + t2d.setCapability(Texture.ALLOW_SIZE_READ); + t2d.setCapability(Texture.ALLOW_ENABLE_READ); + t2d.setCapability(Texture.ALLOW_BOUNDARY_MODE_READ); + t2d.setCapability(Texture.ALLOW_FILTER_READ); + t2d.setCapability(Texture.ALLOW_BOUNDARY_COLOR_READ); + t2d.setCapability(Texture.ALLOW_ANISOTROPIC_FILTER_READ); + t2d.setCapability(Texture.ALLOW_FILTER4_READ); + return t2d; + } + + /** + * Creates a ImageComponent2D of the correct dimensions for the + * given font attributes. Draw the given text into the image in + * the given color. The background of the image is transparent + * (alpha = 0). + */ + private ImageComponent setupImage(String text, Color3f color, + String fontName, + int fontSize, int fontStyle) { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + Font font = new java.awt.Font(fontName, fontStyle, fontSize); + + FontMetrics metrics; + if ((metrics = (FontMetrics)metricsTable.get(font)) == null) { + metrics = toolkit.getFontMetrics(font); + metricsTable.put(font, metrics); + } + int width = metrics.stringWidth(text); + int descent = metrics.getMaxDescent(); + int ascent = metrics.getMaxAscent(); + int leading = metrics.getLeading(); + int height = descent + ascent; + + // Need to make width/height powers of 2 because of Java3d texture + // size restrictions + int pow = 1; + for (int i = 1; i < 32; ++i) { + pow *= 2; + if (width <= pow) + break; + } + width = Math.max (width, pow); + pow = 1; + for (int i = 1; i < 32; ++i) { + pow *= 2; + if (height <= pow) + break; + } + height = Math.max (height, pow); + + // For now, jdk 1.2 only handles ARGB format, not the RGBA we want + BufferedImage bImage = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + Graphics offscreenGraphics = bImage.createGraphics(); + + // First, erase the background to the text panel - set alpha to 0 + Color myFill = new Color(0f, 0f, 0f, 0f); + offscreenGraphics.setColor(myFill); + offscreenGraphics.fillRect(0, 0, width, height); + + // Next, set desired text properties (font, color) and draw String + offscreenGraphics.setFont(font); + Color myTextColor = new Color(color.x, color.y, color.z, 1f); + offscreenGraphics.setColor(myTextColor); + offscreenGraphics.drawString(text, 0, height - descent); + + ImageComponent imageComponent = + new ImageComponent2D(ImageComponent.FORMAT_RGBA, + bImage); + + imageComponent.setCapability(ImageComponent.ALLOW_SIZE_READ); + + return imageComponent; + } + + /** + * Creates a rectangle of the given width and height and sets up + * texture coordinates to map the text image onto the whole surface + * of the rectangle (the rectangle is the same size as the text image) + */ + private QuadArray setupGeometry(int width, int height) { + float zPosition = 0f; + float rectWidth = (float)width * rectangleScaleFactor; + float rectHeight = (float)height * rectangleScaleFactor; + float[] verts1 = { + rectWidth, 0f, zPosition, + rectWidth, rectHeight, zPosition, + 0f, rectHeight, zPosition, + 0f, 0f, zPosition + }; + float[] texCoords = { + 0f, -1f, + 0f, 0f, + (-1f), 0f, + (-1f), -1f + }; + + QuadArray rect = new QuadArray(4, QuadArray.COORDINATES | + QuadArray.TEXTURE_COORDINATE_2); + rect.setCoordinates(0, verts1); + rect.setTextureCoordinates(0, 0, texCoords); + + return rect; + } + + /** + * Creates Appearance for this Shape3D. This sets transparency + * for the object (we want the text to be "floating" in space, + * so only the text itself should be non-transparent. Also, the + * appearance disables lighting for the object; the text will + * simply be colored, not lit. + */ + private Appearance setupAppearance(Texture2D t2d) { + TransparencyAttributes transp = new TransparencyAttributes(); + transp.setTransparencyMode(TransparencyAttributes.BLENDED); + transp.setTransparency(0f); + Appearance appearance = new Appearance(); + appearance.setTransparencyAttributes(transp); + appearance.setTexture(t2d); + + Material m = new Material(); + m.setLightingEnable(false); + appearance.setMaterial(m); + + return appearance; + } + + /** + * Returns the text string + * + * @since Java 3D 1.2.1 + */ + public String getString() { + return text; + } + + /** + * Returns the color of the text + * + * @since Java 3D 1.2.1 + */ + public Color3f getColor() { + return color; + } + + /** + * Returns the font + * + * @since Java 3D 1.2.1 + */ + public String getFontName() { + return fontName; + } + + /** + * Returns the font size + * + * @since Java 3D 1.2.1 + */ + public int getFontSize() { + return fontSize; + } + + /** + * Returns the font style + * + * @since Java 3D 1.2.1 + */ + public int getFontStyle() { + return fontStyle; + } + +} + + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Triangle.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Triangle.java new file mode 100644 index 0000000..af69605 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Triangle.java @@ -0,0 +1,69 @@ +/* + * $RCSfile: Triangle.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:21 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +class Triangle extends Object { + int v1, v2, v3; // This store the index into the list array. + // Not the index into vertex pool yet! + + Triangle(int a, int b, int c) { + v1=a; v2=b; v3=c; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Triangulator.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Triangulator.java new file mode 100644 index 0000000..a363221 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/Triangulator.java @@ -0,0 +1,1049 @@ +/* + * $RCSfile: Triangulator.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:21 $ + * $State: Exp $ + */ + +// ---------------------------------------------------------------------- +// +// The reference to Fast Industrial Strength Triangulation (FIST) code +// in this release by Sun Microsystems is related to Sun's rewrite of +// an early version of FIST. FIST was originally created by Martin +// Held and Joseph Mitchell at Stony Brook University and is +// incorporated by Sun under an agreement with The Research Foundation +// of SUNY (RFSUNY). The current version of FIST is available for +// commercial use under a license agreement with RFSUNY on behalf of +// the authors and Stony Brook University. Please contact the Office +// of Technology Licensing at Stony Brook, phone 631-632-9009, for +// licensing information. +// +// ---------------------------------------------------------------------- + +package com.sun.j3d.utils.geometry; + +import javax.vecmath.*; +import java.util.*; +import com.sun.j3d.utils.geometry.GeometryInfo; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * Triangulator is a utility for turning arbitrary polygons into triangles + * so they can be rendered by Java 3D. + * Polygons can be concave, nonplanar, and can contain holes. + * @see GeometryInfo + */ +public class Triangulator extends Object { + + GeometryInfo gInfo = null; + + int faces[] = null; + int loops[] = null; + int chains[] = null; + Point2f points[] = null; + Triangle triangles[] = null; + ListNode list[] = null; + + Random randomGen = null; + + int numPoints = 0; + int maxNumPoints = 0; + int numList = 0; + int maxNumList = 0; + int numLoops = 0; + int maxNumLoops = 0; + int numTriangles = 0; + int maxNumTriangles = 0; + + int numFaces = 0; + int numTexSets = 0; + // int maxNumFaces = 0; + + int firstNode = 0; + + int numChains = 0; + int maxNumChains = 0; + + // For Clean class. + Point2f[] pUnsorted = null; + int maxNumPUnsorted = 0; + + // For NoHash class. + boolean noHashingEdges = false; + boolean noHashingPnts = false; + int loopMin, loopMax; + PntNode vtxList[] = null; + int numVtxList = 0; + int numReflex = 0; + int reflexVertices; + + // For Bridge class. + Distance distances[] = null; + int maxNumDist = 0; + Left leftMost[] = null; + int maxNumLeftMost = 0; + + // For Heap class. + HeapNode heap[] = null; + int numHeap = 0; + int maxNumHeap = 0; + int numZero = 0; + + // For Orientation class. + int maxNumPolyArea = 0; + double polyArea[] = null; + + int stripCounts[] = null; + int vertexIndices[] = null; + Point3f vertices[] = null; + Object colors[] = null; + Vector3f normals[] = null; + + boolean ccwLoop = true; + + boolean earsRandom = true; + boolean earsSorted = true; + + int identCntr; // Not sure what is this for. (Ask Martin) + + // double epsilon = 1.0e-12; + double epsilon = 1.0e-12; + + static final double ZERO = 1.0e-8; + static final int EARS_SEQUENCE = 0; + static final int EARS_RANDOM = 1; + static final int EARS_SORTED = 2; + + + static final int INC_LIST_BK = 100; + static final int INC_LOOP_BK = 20; + static final int INC_TRI_BK = 50; + static final int INC_POINT_BK = 100; + static final int INC_DIST_BK = 50; + + private static final int DEBUG = 0; + + /** + * Creates a new instance of the Triangulator. + * @deprecated This class is created automatically when needed in + * GeometryInfo and never needs to be used directly. Putting data + * into a GeometryInfo with primitive POLYGON_ARRAY automatically + * causes the triangulator to be created and used. + */ + public Triangulator() { + earsRandom = false; + earsSorted = false; + } + + /** + * Creates a new instance of a Triangulator. + * @deprecated This class is created automatically when needed in + * GeometryInfo and never needs to be used directly. Putting data + * into a GeometryInfo with primitive POLYGON_ARRAY automatically + * causes the triangulator to be created and used. + */ + public Triangulator(int earOrder) { + switch(earOrder) { + case EARS_SEQUENCE: + earsRandom = false; + earsSorted = false; + break; + case EARS_RANDOM: + randomGen = new Random(); + earsRandom = true; + earsSorted = false; + break; + case EARS_SORTED: + earsRandom = false; + earsSorted = true; + break; + default: + earsRandom = false; + earsSorted = false; + } + + } + + /** + * This routine converts the GeometryInfo object from primitive type + * POLYGON_ARRAY to primitive type TRIANGLE_ARRAY using polygon + * decomposition techniques. + *

+ *

+     * Example of usage:
+     *   Triangulator tr = new Triangulator();
+     *   tr.triangulate(ginfo); // ginfo contains the geometry.
+     *   shape.setGeometry(ginfo.getGeometryArray()); // shape is a Shape3D.
+     *

+ * @param gi Geometry to be triangulated + **/ + public void triangulate(GeometryInfo gi) { + int i, j, k; + int sIndex = 0, index, currLoop, lastInd, ind; + boolean proceed; + boolean reset = false, troubles = false; + + boolean done[] = new boolean[1]; + boolean gotIt[] = new boolean[1]; + + if (gi.getPrimitive() != GeometryInfo.POLYGON_ARRAY){ + throw new IllegalArgumentException(J3dUtilsI18N.getString("Triangulator0")); + } + + gi.indexify(); + + vertices = gi.getCoordinates(); + if(vertices != null) + vertexIndices = gi.getCoordinateIndices(); + else + vertexIndices = null; + + colors = gi.getColors(); + normals = gi.getNormals(); + this.gInfo= gi; + + + stripCounts = gi.getStripCounts(); + + faces = gi.getContourCounts(); + if(faces == null) { + if(stripCounts == null) + System.out.println("StripCounts is null! Don't know what to do."); + + faces = new int[stripCounts.length]; + for(i=0; i 1) { + proceed = true; + } + else if(Simple.simpleFace(this, loops[i1])) + proceed = false; + else + proceed = true; + + if (proceed) { + + + // Do some preprocessing here. + + // System.out.println("faces["+j+"] "+faces[j]); + for(int lpIndex = 0; lpIndex 1) { + NoHash.prepareNoHashEdges(this, i1, i2); + } + else { + noHashingEdges = false; + noHashingPnts = false; + } + + + // mark those vertices whose interior angle is convex + for (i = i1; i < i2; ++i) { + EarClip.classifyAngles(this, loops[i]); + } + + /* + System.out.println("After classifyAngles ..."); + printListData(); + */ + + + // link the holes with the outer boundary by means of "bridges" + if (faces[j] > 1) Bridge.constructBridges(this, i1, i2); + + // put all ears into a circular linked list + resetPolyList(loops[i1]); + NoHash.prepareNoHashPnts(this, i1); + EarClip.classifyEars(this, loops[i1]); + done[0] = false; + + /* + System.out.println("Before clipEar (List)..."); + printListData(); + System.out.println("Before clipEar (vtxList)..."); + printVtxList(); + + int counter = 0; + */ + + // triangulate the polygon + while (!done[0]) { + if (!EarClip.clipEar(this, done)) { + /* + System.out.println(" (False case) clipEar (vtxList)..."); + printListData(); + printVtxList(); + */ + + if (reset) { + // For debugging. + + // System.out.println("***** no further ear to clip! ***** \n"); + // System.out.println("***** not a simple polygon, isn't it? *****\n"); + + + ind = getNode(); + resetPolyList(ind); + + loops[i1] = ind; + if (Desperate.desperate(this, ind, i1, done)) { + // System.out.println("***** let's hope for the best *****\n"); + if (!Desperate.letsHope(this, ind)) { + /* + System.out.println("***** sorry, I can't do it! ***** \n"); + System.out.println("***** ask a triangulation wizard, or "); + System.out.println("clean-up your polyhedron! ***** \n"); + */ + return; + } + } + else { + reset = false; + } + } + else { + // try again from scratch + troubles = true; + // System.out.println("\n***** re-classifying the ears! ***** \n"); + ind = getNode(); + resetPolyList(ind); + + // System.out.println("Before classifyEars(" + ind + ")"); + // printListData(); + + EarClip.classifyEars(this, ind); + reset = true; + } + } + else { + reset = false; + /* + System.out.println(" (True case) clipEar (vtxList)..."); + + printVtxList(); + */ + + } + + if (done[0]) { + // System.out.println("In done[0] is true"); + ind = getNextChain(gotIt); + if (gotIt[0]) { + // at some point of the triangulation, we could not find + // any ear and the polygon was split into two parts. now + // we have to handle (one of) the remaining parts. + resetPolyList(ind); + loops[i1] = ind; + noHashingPnts = false; + NoHash.prepareNoHashPnts(this, i1); + EarClip.classifyEars(this, ind); + reset = false; + done[0] = false; + } + } + } + } + + i1 = i2; + + } + + /* + if (troubles) + System.out.println("\n\nTriangulation completed!\n"); + else + System.out.println("\n\nTriangulation successfully completed!\n"); + */ + // System.out.println("\n...writing the output data: "); + + // Output triangles here. + writeTriangleToGeomInfo(); + + } + + void printVtxList() { + int i; + System.out.println("numReflex " + numReflex + " reflexVertices " + + reflexVertices); + for(i= 0; i= 0) && (ind < numList) && (numList <= maxNumList)); + } + + + + void updateIndex(int ind, int index) { + // assert(InPolyList(ind)); + list[ind].index = index; + } + + int getAngle(int ind) { + return list[ind].convex; + } + + void setAngle(int ind, int convex) { + list[ind].convex = convex; + } + + + void resetPolyList(int ind) { + // assert(InPolyList(ind)); + firstNode = ind; + } + + int getNode() { + // assert(InPolyList(first_node)); + return firstNode; + } + + boolean inLoopList(int loop) { + return ((loop >= 0) && (loop < numLoops) && (numLoops <= maxNumLoops)); + } + + + void deleteHook(int currLoop) { + int ind1, ind2; + + if(inLoopList(currLoop)==false) + System.out.println("Triangulator:deleteHook : Loop access out of range."); + + ind1 = loops[currLoop]; + ind2 = list[ind1].next; + if((inPolyList(ind1))&&(inPolyList(ind2))) { + + deleteLinks(ind1); + loops[currLoop] = ind2; + + } + else + System.out.println("Triangulator:deleteHook : List access out of range."); + } + + /** + * Deletes node ind from list (with destroying its data fields) + */ + void deleteLinks(int ind) { + + if((inPolyList(ind))&&(inPolyList(list[ind].prev))&& + (inPolyList(list[ind].next))) { + + if (firstNode == ind) + firstNode = list[ind].next; + + list[list[ind].next].prev = list[ind].prev; + list[list[ind].prev].next = list[ind].next; + list[ind].prev = list[ind].next = ind; + + } + else + System.out.println("Triangulator:deleteLinks : Access out of range."); + + } + + void rotateLinks(int ind1, int ind2) { + int ind; + int ind0, ind3; + + // assert(InPolyList(ind1)); + // assert(InPolyList(ind2)); + ind0 = list[ind1].next; + ind3 = list[ind2].next; + // assert(InPolyList(ind0)); + // assert(InPolyList(ind3)); + + // Swap. + ind = list[ind1].next; + list[ind1].next = list[ind2].next; + list[ind2].next = ind; + + list[ind0].prev = ind2; + list[ind3].prev = ind1; + + } + + + void storeChain(int ind) { + if (numChains >= maxNumChains) { + // System.out.println("Triangulator:storeChain Expanding chain array ..."); + maxNumChains += 20; + int old[] = chains; + chains = new int[maxNumChains]; + if(old != null) + System.arraycopy(old, 0, chains, 0, old.length); + } + chains[numChains] = ind; + ++numChains; + + } + + int getNextChain(boolean[] done) { + if (numChains > 0) { + done[0] = true; + --numChains; + return chains[numChains]; + } + else { + done[0] = false; + numChains = 0; + return 0; + } + } + + void splitSplice(int ind1, int ind2, int ind3, int ind4) { + list[ind1].next = ind4; + list[ind4].prev = ind1; + list[ind2].prev = ind3; + list[ind3].next = ind2; + + } + + /** + * Allocates storage for a dummy list node; pointers are set to itself. + * @return pointer to node + */ + int makeHook() { + int ind; + + ind = numList; + if (numList >= maxNumList) { + maxNumList += INC_LIST_BK; + // System.out.println("Triangulator: Expanding list array ...."); + ListNode old[] = list; + list = new ListNode[maxNumList]; + System.arraycopy(old, 0, list, 0, old.length); + } + + list[numList] = new ListNode(-1); + list[numList].prev = ind; + list[numList].next = ind; + list[numList].index = -1; + ++numList; + + return ind; + } + + int makeLoopHeader() { + int i; + int ind; + + ind = makeHook(); + if(numLoops >= maxNumLoops) { + maxNumLoops += INC_LOOP_BK; + // System.out.println("Triangulator: Expanding loops array ...."); + int old[] = loops; + loops = new int[maxNumLoops]; + System.arraycopy(old, 0, loops, 0, old.length); + } + + loops[numLoops] = ind; + i = numLoops; + ++numLoops; + + return i; + } + + + /** + * Allocates storage for a new list node, and stores the index of the point + * at this node. Pointers are set to -1. + * @return pointer to node + */ + int makeNode(int index) { + int ind; + + if (numList >= maxNumList) { + maxNumList += INC_LIST_BK; + //System.out.println("Triangulator: Expanding list array ...."); + ListNode old[] = list; + list = new ListNode[maxNumList]; + System.arraycopy(old, 0, list, 0, old.length); + } + + list[numList] = new ListNode(index); + + ind = numList; + list[numList].index = index; + list[numList].prev = -1; + list[numList].next = -1; + ++numList; + + return ind; + } + + + /** + * Inserts node ind2 after node ind1. + */ + void insertAfter(int ind1, int ind2) { + int ind3; + + if((inPolyList(ind1))&&(inPolyList(ind2))) { + + list[ind2].next = list[ind1].next; + list[ind2].prev = ind1; + list[ind1].next = ind2; + ind3 = list[ind2].next; + + if(inPolyList(ind3)) + list[ind3].prev = ind2; + else + System.out.println("Triangulator:deleteHook : List access out of range."); + + return; + } + else + System.out.println("Triangulator:deleteHook : List access out of range."); + + } + + /** + * Returns pointer to the successor of ind1. + */ + int fetchNextData(int ind1) { + return list[ind1].next; + } + + /** + * obtains the data store at ind1 + */ + int fetchData(int ind1) { + return list[ind1].index; + } + + /** + * returns pointer to the successor of ind1. + */ + int fetchPrevData(int ind1) { + return list[ind1].prev; + } + + /** + * swap the list pointers in order to change the orientation. + */ + void swapLinks(int ind1) { + int ind2, ind3; + + ind2 = list[ind1].next; + list[ind1].next = list[ind1].prev; + list[ind1].prev = ind2; + ind3 = ind2; + while (ind2 != ind1) { + ind3 = list[ind2].next; + list[ind2].next = list[ind2].prev; + list[ind2].prev = ind3; + ind2 = ind3; + } + } + + // Methods for handling Triangle. + + void storeTriangle(int i, int j, int k) { + /* + if (ccwLoop) + triangles.add(new Triangle(i,j,k)); + else + triangles.add(new Triangle(j,i,k)); + */ + + if(numTriangles >= maxNumTriangles) { + // System.out.println("Triangulator:storeTriangle Expanding triangle array.."); + maxNumTriangles += INC_TRI_BK; + Triangle old[] = triangles; + triangles = new Triangle[maxNumTriangles]; + if(old != null) + System.arraycopy(old, 0, triangles, 0, old.length); + } + + if (ccwLoop) + triangles[numTriangles] = new Triangle(i,j,k); + else + triangles[numTriangles] = new Triangle(j,i,k); + numTriangles++; + + } + + // Methods for handling Point. + + void initPnts(int number) { + if (maxNumPoints < number) { + maxNumPoints = number; + points = new Point2f[maxNumPoints]; + } + + for(int i = 0; i= 0) && (index < numPoints) && + (numPoints <= maxNumPoints)); + } + + int storePoint(double x, double y) { + int i; + + if (numPoints >= maxNumPoints) { + // System.out.println("Triangulator:storePoint Expanding points array ..."); + maxNumPoints += INC_POINT_BK; + Point2f old[] = points; + points = new Point2f[maxNumPoints]; + if(old != null) + System.arraycopy(old, 0, points, 0, old.length); + } + + points[numPoints] = new Point2f((float)x, (float)y); + // points[numPoints].x = (float)x; + // points[numPoints].y = (float)y; + i = numPoints; + ++numPoints; + + return i; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CommandStream.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CommandStream.java new file mode 100644 index 0000000..32ae0aa --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CommandStream.java @@ -0,0 +1,265 @@ +/* + * $RCSfile: CommandStream.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:21 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +/** + * This class is used to build the bit-level compression command stream which + * is the final result of the compression process. It defines the bit + * representations of the compression commands and provides a mechanism for + * the interleaving and forwarding of command headers and bodies required by + * the geometry compression specification. + */ +class CommandStream { + // Geometry compression commands. + static final int SET_NORM = 0xC0 ; + static final int SET_COLOR = 0x80 ; + static final int VERTEX = 0x40 ; + static final int MESH_B_R = 0x20 ; + static final int SET_STATE = 0x18 ; + static final int SET_TABLE = 0x10 ; + static final int V_NO_OP = 0x01 ; + + // Huffman table indices. + static final int POSITION_TABLE = 0 ; + static final int COLOR_TABLE = 1 ; + static final int NORMAL_TABLE = 2 ; + + // The buffer of compressed data and the current offset. + private byte bytes[] ; + private int byteOffset ; + private int bitOffset ; + + // Last command body for header forwarding. + private long lastBody ; + private int lastBodyLength ; + + /** + * Create an empty CommandStream with a default initial size. + */ + CommandStream() { + this(65536) ; + } + + /** + * Create an empty CommandStream with the given initial size. + * + * @param initSize initial capacity of CommandStream in bytes + */ + CommandStream(int initSize) { + bytes = new byte[initSize] ; + clear() ; + } + + /** + * Mark the CommandStream as empty so that its storage will be reused. + */ + void clear() { + // Initialize the first byte to 0. + // Subsequent bytes are cleared as they are written. + bytes[0] = 0 ; + + // Reset the number of valid bits. + bitOffset = 0 ; + byteOffset = 0 ; + + // The first command header is always followed by the body of an + // implicit variable length no-op to start the header-forwarding + // interleave required by hardware decompressor implementations. The + // only necessary bits are 5 bits of length set to zeros to indicate a + // fill of zero length. + lastBody = 0 ; + lastBodyLength = 5 ; + } + + /** + * Add a compression command to this instance.

+ * + * A compression command includes an 8-bit header and can range up to 72 + * bits in length. The command with the maximum length is a 2-bit color + * command with a 6-bit tag in the header, followed by four 16-bit color + * components of data.

+ * + * A subcommand is either a position, normal, or color, though in practice + * a position subcommand can only be part of a vertex command. Normal and + * color subcommands can be parts of separate global normal and color + * commands as well as parts of a vertex command.

+ * + * A subcommand includes a 6-bit header. Its length is 2 bits less than + * the length of the corresponding command. + * + * @param header contains compression command header bits, right-justified + * within the bits of the int + * @param headerLength number of bits in header, either 8 for commands or + * 6 for subcommands + * @param body contains the body of the compression command, + * right-justified within the bits of the long + * @param bodyLength number of bits in the body + */ + void addCommand(int header, int headerLength, long body, int bodyLength) { + addByte(header, headerLength) ; + addLong(lastBody, lastBodyLength) ; + + lastBody = body ; + lastBodyLength = bodyLength ; + } + + // + // Add the rightmost bitCount bits of b to the end of the command stream. + // + private void addByte(int b, int bitCount) { + int bitsEmpty = 8 - bitOffset ; + b &= (int)CompressionStreamElement.lengthMask[bitCount] ; + + if (bitCount <= bitsEmpty) { + bytes[byteOffset] |= (b << (bitsEmpty - bitCount)) ; + bitOffset += bitCount ; + return ; + } + + if (bytes.length == byteOffset + 1) { + byte newBytes[] = new byte[bytes.length * 2] ; + System.arraycopy(bytes, 0, newBytes, 0, bytes.length) ; + bytes = newBytes ; + } + + bitOffset = bitCount - bitsEmpty ; + bytes[byteOffset] |= (b >>> bitOffset) ; + + byteOffset++ ; + bytes[byteOffset] = (byte)(b << (8 - bitOffset)) ; + } + + // + // Add the rightmost bitCount bits of l to the end of the command stream. + // + private void addLong(long l, int bitCount) { + int byteCount = bitCount / 8 ; + int excessBits = bitCount - byteCount * 8 ; + + if (excessBits > 0) + addByte((int)(l >>> (byteCount * 8)), excessBits) ; + + while (byteCount > 0) { + addByte((int)((l >>> ((byteCount - 1) * 8)) & 0xff), 8) ; + byteCount-- ; + } + } + + /** + * Add a no-op and the last command body. Pad out with additional no-ops + * to a 64-bit boundary if necessary. A call to this method is required + * in order to create a valid compression command stream. + */ + void end() { + int excessBytes, padBits ; + + // Add the 1st no-op and the last body. + addByte(V_NO_OP, 8) ; + addLong(lastBody, lastBodyLength) ; + + excessBytes = (byteOffset + 1) % 8 ; + if (excessBytes == 0 && bitOffset == 8) + // No padding necessary. + return ; + + // Need to add padding with a 2nd no-op. + addByte(V_NO_OP, 8) ; + excessBytes = (byteOffset + 1) % 8 ; + + if (excessBytes == 0) + padBits = 8 - bitOffset ; + else { + int fillBytes = 8 - excessBytes ; + padBits = (8 * fillBytes) + (8 - bitOffset) ; + } + + // The minimum length for a no-op command body is 5 bits. + if (padBits < 5) + // Have to cross the next 64-bit boundary. + padBits += 64 ; + + // The maximum length of a no-op body is a 5-bit length + 31 bits of + // fill for a total of 36. + if (padBits < 37) { + // Pad with the body of the 1st no-op. + addLong((padBits - 5) << (padBits - 5), padBits) ; + return ; + } + + // The number of bits to pad at this point is [37..68]. Knock off 24 + // bits with the body of the 1st no-op to reduce the number of pad + // bits to [13..44], which can be filled with 1 more no-op. + addLong(19 << 19, 24) ; + padBits -= 24 ; + + // Add a 3rd no-op. + addByte(V_NO_OP, 8) ; + padBits -= 8 ; + + // Complete padding with the body of the 2nd no-op. + addLong((padBits - 5) << (padBits - 5), padBits) ; + } + + /** + * Get the number of bytes in the compression command stream. + * + * @return size of compressed data in bytes + */ + int getByteCount() { + if (byteOffset + bitOffset == 0) + return 0 ; + else + return byteOffset + 1 ; + } + + /** + * Get the bytes composing the compression command stream. + * + * @return reference to array of bytes containing the compressed data + */ + byte[] getBytes() { + return bytes ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryData.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryData.java new file mode 100644 index 0000000..484fe20 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryData.java @@ -0,0 +1,546 @@ +/* + * $RCSfile: CompressedGeometryData.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:21 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import com.sun.j3d.internal.J3dUtilsI18N; +import javax.media.j3d.J3DBuffer; +import javax.media.j3d.Shape3D; +import javax.vecmath.Point3d; + +/** + * The compressed geometry object is used to store geometry in a + * compressed format. Using compressed geometry may increase the speed + * objects can be sent over the network. Note that the geometry will + * be decompressed in memory, so the application will not see any + * memory savings. + *

+ * Compressed geometry may be passed to this CompressedGeometryData object + * in one of two ways: by copying the data into this object using the + * existing constructor, or by passing a reference to the data. + *

+ *

    + *
  • + * By Copying: + * In by-copy mode, the CompressedGeometryData constructor copies the buffer of + * compressed geometry data into this CompressedGeometryData object. This + * is appropriate for many applications, and allows Java 3D to verify + * the data once and then not worry about it again. + *
  • + *
  • By Reference: + * In by-reference mode, the + * compressed geometry data is accessed by reference, directly from + * the user's array. To use this feature, you need to construct a + * CompressedGeometryData object with the byReference flag + * set to true. In this mode, a reference to the input + * data is saved, but the data itself is not necessarily copied. Note + * that the compressed geometry header is still copied into this + * compressed geometry object. Data referenced by a + * CompressedGeometryData object must not be modified after the + * CompressedGeometryData object is constructed. + * Applications + * must exercise care not to violate this rule. If any referenced + * compressed geometry data is modified after construction, + * the results are undefined. + *
  • + *
+ * + * @since Java 3D 1.5 + */ +public class CompressedGeometryData extends Object { + + private Header cgHeader; + private CompressedGeometryRetained retained; + + + /** + * Creates a new CompressedGeometryData object by copying + * the specified compressed geometry data into this object. + * If the version number of compressed geometry, as specified by + * the Header, is incompatible with the + * supported version of compressed geometry, then an exception + * will be thrown. + * + * @param hdr the compressed geometry header. This is copied + * into this CompressedGeometryData object. + * + * @param compressedGeometry the compressed geometry data. The + * geometry must conform to the format described in Appendix B of + * the Java 3D API Specification. + * + * @exception IllegalArgumentException if a problem is detected with the + * header. + */ + public CompressedGeometryData(Header hdr, + byte[] compressedGeometry) { + + this(hdr, compressedGeometry, false); + } + + /** + * Creates a new CompressedGeometryData object. The + * specified compressed geometry data is either copied into this + * object or is accessed by reference. + * If the version number of compressed geometry, as specified by + * the Header, is incompatible with the + * supported version of compressed geometry, then an exception + * will be thrown. + * + * @param hdr the compressed geometry header. This is copied + * into the CompressedGeometryData object. + * + * @param compressedGeometry the compressed geometry data. The + * geometry must conform to the format described in Appendix B of + * the Java 3D API Specification. + * + * @param byReference a flag that indicates whether the data is copied + * into this compressed geometry object or is accessed by reference. + * + * @exception IllegalArgumentException if a problem is detected with the + * header. + */ + public CompressedGeometryData(Header hdr, + byte[] compressedGeometry, + boolean byReference) { + + if ((hdr.size + hdr.start) > compressedGeometry.length) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("CompressedGeometry0")); + } + + // Create a separate copy of the given header. + cgHeader = new Header(); + hdr.copy(cgHeader); + + // Create the retained object. + retained = new CompressedGeometryRetained(); + this.retained.createCompressedGeometry(cgHeader, compressedGeometry, byReference); + + // This constructor is designed to accept byte arrays that may contain + // possibly many large compressed geometry blocks interspersed with + // non-J3D-specific metadata. Only one of these blocks is used per + // CompressedGeometry object, so set the geometry offset to zero in + // the header if the data itself is copied. + if (!byReference) + cgHeader.start = 0; + } + + /** + * Creates a new CompressedGeometryData object. The + * specified compressed geometry data is accessed by reference + * from the specified buffer. + * If the version number of compressed geometry, as specified by + * the Header, is incompatible with the + * supported version of compressed geometry, then an exception + * will be thrown. + * + * @param hdr the compressed geometry header. This is copied + * into the CompressedGeometryData object. + * + * @param compressedGeometry a buffer containing an NIO byte buffer + * of compressed geometry data. The + * geometry must conform to the format described in Appendix B of + * the Java 3D API Specification. + * + * @exception UnsupportedOperationException this method is not + * yet implemented + * + * @exception IllegalArgumentException if a problem is detected with the + * header, + * or if the java.nio.Buffer contained in the specified J3DBuffer + * is not a java.nio.ByteBuffer object. + * + * @see Header + */ + public CompressedGeometryData(Header hdr, + J3DBuffer compressedGeometry) { + + throw new UnsupportedOperationException("not implemented"); + } + + + /** + * Returns the size, in bytes, of the compressed geometry buffer. + * The size of the compressed geometry header is not included. + * + * @return the size, in bytes, of the compressed geometry buffer. + */ + public int getByteCount() { + return cgHeader.size; + } + + /** + * Copies the compressed geometry header from the CompressedGeometryData + * object into the passed in parameter. + * + * @param hdr the Header object into which to copy the + * CompressedGeometryData object's header; the offset field may differ + * from that which was originally specified if a copy of the original + * compressed geometry byte array was created. + */ + public void getCompressedGeometryHeader(Header hdr) { + cgHeader.copy(hdr); + } + + /** + * Retrieves the compressed geometry associated with the + * CompressedGeometryData object. Copies the compressed + * geometry from the CompressedGeometryData node into the given array. + * The array must be large enough to hold all of the bytes. + * The individual array elements must be allocated by the caller. + * + * @param compressedGeometry the array into which to copy the compressed + * geometry. + * + * @exception IllegalStateException if the data access mode for this + * object is by-reference. + * + * @exception ArrayIndexOutOfBoundsException if compressedGeometry byte + * array is not large enough to receive the compressed geometry + */ + public void getCompressedGeometry(byte[] compressedGeometry) { + if (isByReference()) { + throw new IllegalStateException( + J3dUtilsI18N.getString("CompressedGeometry7")); + } + + if (cgHeader.size > compressedGeometry.length) { + throw new ArrayIndexOutOfBoundsException( + J3dUtilsI18N.getString("CompressedGeometry4")); + } + + this.retained.copy(compressedGeometry); + } + + /** + * Decompresses the compressed geometry. Returns an array of Shape nodes + * containing the decompressed geometry objects, or null if the version + * number of the compressed geometry is incompatible with the decompressor + * in the current version of Java 3D. + * + * @return an array of Shape nodes containing the + * geometry decompressed from this CompressedGeometryData + * object, or null if its version is incompatible + */ + public Shape3D[] decompress() { + CompressedGeometryRetained cgr = this.retained; + + GeometryDecompressorShape3D decompressor = + new GeometryDecompressorShape3D(); + + // Decompress the geometry as TriangleStripArrays. A combination of + // TriangleStripArrays and TrianglesFanArrays is more compact but + // requires twice as many Shape3D objects, resulting in slower + // rendering performance. + // + // Using TriangleArray output is currently the fastest, given the + // strip sizes observed from various compressed geometry objects, but + // produces about twice as many vertices. TriangleStripArray produces + // the same number of Shape3D objects as TriangleArray using 1/2 + // to 2/3 of the vertices, with only a marginal performance penalty. + // + return decompressor.toTriangleStripArrays(cgr); + } + + + /** + * Retrieves the data access mode for this CompressedGeometryData object. + * + * @return true if the data access mode for this + * CompressedGeometryData object is by-reference; + * false if the data access mode is by-copying. + */ + public boolean isByReference() { + return this.retained.isByReference(); + } + + + /** + * Gets the compressed geometry data reference. + * + * @return the current compressed geometry data reference. + * + * @exception IllegalStateException if the data access mode for this + * object is not by-reference. + */ + public byte[] getCompressedGeometryRef() { + if (!isByReference()) { + throw new IllegalStateException( + J3dUtilsI18N.getString("CompressedGeometry8")); + } + + return this.retained.getReference(); + } + + + /** + * Gets the compressed geometry data buffer reference, which is + * always null since NIO buffers are not supported for + * CompressedGeometryData objects. + * + * @return null + */ + public J3DBuffer getCompressedGeometryBuffer() { + return null; + } + + + /** + * The Header class is a data container for the header information, + * used in conjunction with a CompressedGeometryData object. + * This information is used to aid the decompression of the compressed geometry. + * + *

+ * All instance data is declared public and no get or set methods are + * provided. + * + * @since Java 3D 1.5 + */ + public static class Header extends Object { + + /** + * bufferType: compressed geometry is made up of individual points. + */ + public static final int POINT_BUFFER = 0; + + /** + * bufferType: compressed geometry is made up of line segments. + */ + public static final int LINE_BUFFER = 1; + + /** + * bufferType: compressed geometry is made up of triangles. + */ + public static final int TRIANGLE_BUFFER = 2; + + // Valid values for the bufferDataPresent field. + + /** + * bufferDataPresent: bit indicating that normal information is + * bundled with the vertices in the compressed geometry buffer. + */ + public static final int NORMAL_IN_BUFFER = 1; + + /** + * bufferDataPresent: bit indicating that RGB color information is + * bundled with the vertices in the compressed geometry buffer. + */ + public static final int COLOR_IN_BUFFER = 2; + + /** + * bufferDataPresent: bit indicating that alpha information is + * bundled with the vertices in the compressed geometry buffer. + */ + public static final int ALPHA_IN_BUFFER = 4; + + /** + * The major version number for the compressed geometry format that + * was used to compress the geometry. + * If the version number of compressed geometry is incompatible + * with the supported version of compressed geometry in the + * current version of Java 3D, the compressed geometry obejct will + * not be rendered. + * + * @see Canvas3D#queryProperties + */ + public int majorVersionNumber; + + /** + * The minor version number for the compressed geometry format that + * was used to compress the geometry. + * If the version number of compressed geometry is incompatible + * with the supported version of compressed geometry in the + * current version of Java 3D, the compressed geometry obejct will + * not be rendered. + * + * @see Canvas3D#queryProperties + */ + public int minorVersionNumber; + + /** + * The minor-minor version number for the compressed geometry format + * that was used to compress the geometry. + * If the version number of compressed geometry is incompatible + * with the supported version of compressed geometry in the + * current version of Java 3D, the compressed geometry obejct will + * not be rendered. + * + * @see Canvas3D#queryProperties + */ + public int minorMinorVersionNumber; + + /** + * Describes the type of data in the compressed geometry buffer. + * Only one type may be present in any given compressed geometry + * buffer. + */ + public int bufferType; + + /** + * Contains bits indicating what data is bundled with the vertices in the + * compressed geometry buffer. If this data is not present (e.g. color) + * then this info will be inherited from the Appearance node. + */ + public int bufferDataPresent; + + /** + * Size of the compressed geometry in bytes. + */ + public int size; + + /** + * Offset in bytes of the start of the compressed geometry from the + * beginning of the compressed geometry byte array passed to the + * CompressedGeometryData constructor.

+ * + * If the CompressedGeometryData is created with reference access semantics, + * then this allow external compressors or file readers to embed several + * blocks of compressed geometry in a single large byte array, possibly + * interspersed with metadata that is not specific to Java 3D, without + * having to copy each block to a separate byte array.

+ * + * If the CompressedGeometryData is created with copy access semantics, then + * size bytes of compressed geometry data are copied from the + * offset indicated by start instead of copying the entire + * byte array. The getCompressedGeometry() method will return only the + * bytes used to construct the object, and the getCompressedGeometryHeader() + * method will return a header with the start field set to 0. + */ + public int start; + + /** + * A point that defines the lower bound of the x, + * y, and z components for all positions in the + * compressed geometry buffer. If null, a lower bound of + * (-1,-1,-1) is assumed. Java 3D will use this information to + * construct a bounding box around compressed geometry objects + * that are used in nodes for which the auto compute bounds flag + * is true. The default value for this point is null. + */ + public Point3d lowerBound = null; + + /** + * A point that defines the upper bound of the x, + * y, and z components for all positions in the + * compressed geometry buffer. If null, an upper bound of (1,1,1) + * is assumed. Java 3D will use this information to construct a + * bounding box around compressed geometry objects that are used + * in nodes for which the auto compute bounds flag is true. The + * default value for this point is null. + */ + public Point3d upperBound = null; + + /** + * Creates a new Header object used for the + * creation of a CompressedGeometryData object. + * All instance data is declared public and no get or set methods are + * provided. All values are set to 0 by default and must be filled + * in by the application. + * + * @see CompressedGeometryData + */ + public Header() { + } + + /** + * Package-scoped method to copy current Header object + * to the passed-in Header object. + * + * @param hdr the Header object into which to copy the + * current Header. + */ + void copy(Header hdr) { + hdr.majorVersionNumber = this.majorVersionNumber; + hdr.minorVersionNumber = this.minorVersionNumber; + hdr.minorMinorVersionNumber = this.minorMinorVersionNumber; + hdr.bufferType = this.bufferType; + hdr.bufferDataPresent = this.bufferDataPresent; + hdr.size = this.size; + hdr.start = this.start; + hdr.lowerBound = this.lowerBound; + hdr.upperBound = this.upperBound; + } + + /** + * Returns a String describing the contents of the + * Header object. + * + * @return a String describing contents of the compressed geometry header + */ + public String toString() { + String type = "UNKNOWN"; + switch (bufferType) { + case POINT_BUFFER: type = "POINT_BUFFER"; break; + case LINE_BUFFER: type = "LINE_BUFFER"; break; + case TRIANGLE_BUFFER: type = "TRIANGLE_BUFFER"; break; + } + + String data = ""; + if ((bufferDataPresent & NORMAL_IN_BUFFER) != 0) + data = data + "NORMALS "; + if ((bufferDataPresent & COLOR_IN_BUFFER) != 0) + data = data + "COLORS "; + if ((bufferDataPresent & ALPHA_IN_BUFFER) != 0) + data = data + "ALPHA "; + + String lbound = "null"; + if (lowerBound != null) + lbound = lowerBound.toString(); + + String ubound = "null"; + if (upperBound != null) + ubound = upperBound.toString(); + + return + "majorVersionNumber: " + majorVersionNumber + " " + + "minorVersionNumber: " + minorVersionNumber + " " + + "minorMinorVersionNumber: " + minorMinorVersionNumber + "\n" + + "bufferType: " + type + " " + + "bufferDataPresent: " + data + "\n" + + "size: " + size + " " + + "start: " + start + "\n" + + "lower bound: " + lbound + "\n" + + "upper bound: " + ubound + " "; + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryFile.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryFile.java new file mode 100644 index 0000000..1f31e47 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryFile.java @@ -0,0 +1,1011 @@ +/* + * $RCSfile: CompressedGeometryFile.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:21 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; + +// +// The compressed geometry file format supported by this class has a 32 +// byte header followed by multiple compressed geometry objects. +// +// Each object consists of a block of compressed data and an 8-byte +// individual block header describing its contents. +// +// The file ends with a directory data structure used for random access, +// containing a 64-bit offset for each object in the order in which it +// appears in the file. This is also used to find the size of the largest +// object in the file and must be present. +// + +/** + * This class provides methods to read and write compressed geometry resource + * files. These files usually end with the .cg extension and support + * sequential as well as random access to multiple compressed geometry + * objects. + * + * @since Java 3D 1.5 + */ +public class CompressedGeometryFile { + private static final boolean print = false ; + private static final boolean benchmark = false ; + + /** + * The magic number which identifies the compressed geometry file type. + */ + static final int MAGIC_NUMBER = 0xbaddfab4 ; + + /** + * Byte offset of the magic number from start of file. + */ + static final int MAGIC_NUMBER_OFFSET = 0 ; + + /** + * Byte offset of the major version number from start of file. + */ + static final int MAJOR_VERSION_OFFSET = 4 ; + + /** + * Byte offset of the minor version number from start of file. + */ + static final int MINOR_VERSION_OFFSET = 8 ; + + /** + * Byte offset of the minor minor version number from start of file. + */ + static final int MINOR_MINOR_VERSION_OFFSET = 12 ; + + /** + * Byte offset of the number of objects from start of file. + */ + static final int OBJECT_COUNT_OFFSET = 16 ; + + /** + * Byte offset of the directory offset from start of file. + * This offset is long word aligned since the directory offset is a long. + */ + static final int DIRECTORY_OFFSET_OFFSET = 24 ; + + /** + * File header total size in bytes. + */ + static final int HEADER_SIZE = 32 ; + + /** + * Byte offset of the object size from start of individual compressed + * geometry block. + */ + static final int OBJECT_SIZE_OFFSET = 0 ; + + /** + * Byte offset of the compressed geometry data descriptor from start of + * individual compressed geometry block. + */ + static final int GEOM_DATA_OFFSET = 4 ; + + /** + * Bits in compressed geometry data descriptor which encode the buffer type. + */ + static final int TYPE_MASK = 0x03 ; + + /** + * Bit in compressed geometry data descriptor encoding presence of normals. + */ + static final int NORMAL_PRESENT_MASK = 0x04 ; + + /** + * Bit in compressed geometry data descriptor encoding presence of colors. + */ + static final int COLOR_PRESENT_MASK = 0x08 ; + + /** + * Bit in compressed geometry data descriptor encoding presence of alphas. + */ + static final int ALPHA_PRESENT_MASK = 0x10 ; + + /** + * Value in compressed geometry data descriptor for a point buffer type. + */ + static final int TYPE_POINT = 1 ; + + /** + * Value in compressed geometry data descriptor for a line buffer type. + */ + static final int TYPE_LINE = 2 ; + + /** + * Value in compressed geometry data descriptor for a triangle buffer type. + */ + static final int TYPE_TRIANGLE = 3 ; + + /** + * Block header total size in bytes. + */ + static final int BLOCK_HEADER_SIZE = 8 ; + + // The name of the compressed geometry resource file. + String fileName = null ; + + // The major, minor, and subminor version number of the most recent + // compressor used to compress any of the objects in the compressed + // geometry resource file. + int majorVersionNumber ; + int minorVersionNumber ; + int minorMinorVersionNumber ; + + // The number of objects in the compressed geometry resource file. + int objectCount ; + + // The index of the current object in the file. + int objectIndex = 0 ; + + // The random access file associated with this instance. + RandomAccessFile cgFile = null ; + + // The magic number identifying the file type. + int magicNumber ; + + // These fields are set from each individual block of compressed geometry. + byte cgBuffer[] ; + int geomSize ; + int geomStart ; + int geomDataType ; + + // The directory of object offsets is read from the end of the file. + long directory[] ; + long directoryOffset ; + + // The object sizes are computed from the directory offsets. These are + // used to allocate a buffer large enough to hold the largest object and + // to determine how many consecutive objects can be read into that buffer. + int objectSizes[] ; + int bufferObjectStart ; + int bufferObjectCount ; + int bufferNextObjectCount ; + int bufferNextObjectOffset ; + + // The shared compressed geometry header object. + CompressedGeometryData.Header cgh ; + + // Flag indicating file update. + boolean fileUpdate = false ; + + /** + * Construct a new CompressedGeometryFile instance associated with the + * specified file. An attempt is made to open the file with read-only + * access; if this fails then a FileNotFoundException is thrown. + * + * @param file path to the compressed geometry resource file + * @exception FileNotFoundException if file doesn't exist or + * cannot be read + * @exception IllegalArgumentException if the file is not a compressed + * geometry resource file + * @exception IOException if there is a header or directory read error + */ + public CompressedGeometryFile(String file) throws IOException { + this(file, false) ; + } + + /** + * Construct a new CompressedGeometryFile instance associated with the + * specified file. + * + * @param file path to the compressed geometry resource file + * @param rw if true, opens the file for read and write access or attempts + * to create one if it doesn't exist; if false, opens the file with + * read-only access + * @exception FileNotFoundException if file doesn't exist or + * access permissions disallow access + * @exception IllegalArgumentException if the file is not a compressed + * geometry resource file + * @exception IOException if there is a header or directory read error + */ + public CompressedGeometryFile(String file, boolean rw) throws IOException { + // Open the file and read the file header. + open(file, rw) ; + + // Copy the file name. + fileName = new String(file) ; + + // Set up the file fields. + initialize() ; + } + + /** + * Construct a new CompressedGeometryFile instance associated with a + * currently open RandomAccessFile. + * + * @param file currently open RandomAccessFile + * @exception IllegalArgumentException if the file is not a compressed + * geometry resource file + * @exception IOException if there is a header or directory read error + */ + public CompressedGeometryFile(RandomAccessFile file) throws IOException { + // Copy the file reference. + cgFile = file ; + + // Set up the file fields. + initialize() ; + } + + /** + * Delete all compressed objects from this instance. This method may only + * be called after successfully creating a CompressedGeometryFile instance + * with read-write access, so a corrupted or otherwise invalid resource + * must be removed manually before it can be rewritten. The close() + * method must be called sometime after invoking clear() in order to write + * out the new directory structure. + * + * @exception IOException if clear fails + */ + public void clear() throws IOException { + // Truncate the file. + cgFile.setLength(0) ; + + // Set up the file fields. + initialize() ; + } + + /** + * Return a string containing the file name associated with this instance + * or null if there is none. + * + * @return file name associated with this instance or null if there is + * none + */ + public String getFileName() { + return fileName ; + } + + /** + * Return the major version number of the most recent compressor used to + * compress any of the objects in this instance. + * + * @return major version number + */ + public int getMajorVersionNumber() { + return majorVersionNumber ; + } + + /** + * Return the minor version number of the most recent compressor used to + * compress any of the objects in this instance. + * + * @return minor version number + */ + public int getMinorVersionNumber() { + return minorVersionNumber ; + } + + /** + * Return the subminor version number of the most recent compressor used to + * compress any of the objects in this instance. + * + * @return subminor version number + */ + public int getMinorMinorVersionNumber() { + return minorMinorVersionNumber ; + } + + /** + * Return the number of compressed objects in this instance. + * + * @return number of compressed objects + */ + public int getObjectCount() { + return objectCount ; + } + + /** + * Return the current object index associated with this instance. This is + * the index of the object that would be returned by an immediately + * following call to the readNext() method. Its initial value is 0; -1 + * is returned if the last object has been read. + * + * @return current object index, or -1 if at end + */ + public int getCurrentIndex() { + if (objectIndex == objectCount) + return -1 ; + else + return objectIndex ; + } + + /** + * Read the next compressed geometry object in the instance. This is + * initially the first object (index 0) in the instance; otherwise, it is + * whatever object is next after the last one read. The current object + * index is incremented by 1 after the read. When the last object is read + * the index becomes invalid and an immediately subsequent call to + * readNext() returns null. + * + * + * @return a CompressedGeometryData node component, or null if the last object + * has been read + * @exception IOException if read fails + */ + public CompressedGeometryData readNext() throws IOException { + return readNext(cgBuffer.length) ; + } + + /** + * Read all compressed geometry objects contained in the instance. The + * current object index becomes invalid; an immediately following call + * to readNext() will return null. + * + * @return an array of CompressedGeometryData node components. + * @exception IOException if read fails + */ + public CompressedGeometryData[] read() throws IOException { + long startTime = 0 ; + CompressedGeometryData cg[] = new CompressedGeometryData[objectCount] ; + + if (benchmark) + startTime = System.currentTimeMillis() ; + + objectIndex = 0 ; + setFilePointer(directory[0]) ; + bufferNextObjectCount = 0 ; + + for (int i = 0 ; i < objectCount ; i++) + cg[i] = readNext(cgBuffer.length) ; + + if (benchmark) { + long t = System.currentTimeMillis() - startTime ; + System.out.println("read " + objectCount + + " objects " + cgFile.length() + + " bytes in " + (t/1000f) + " sec.") ; + System.out.println((cgFile.length()/(float)t) + " Kbytes/sec.") ; + } + + return cg ; + } + + /** + * Read the compressed geometry object at the specified index. The + * current object index is set to the subsequent object unless the last + * object has been read, in which case the index becomes invalid and an + * immediately following call to readNext() will return null. + * + * @param index compressed geometry object to read + * @return a CompressedGeometryData node component + * @exception IndexOutOfBoundsException if object index is + * out of range + * @exception IOException if read fails + */ + public CompressedGeometryData read(int index) throws IOException { + objectIndex = index ; + + if (objectIndex < 0) { + throw new IndexOutOfBoundsException + ("\nobject index must be >= 0") ; + } + if (objectIndex >= objectCount) { + throw new IndexOutOfBoundsException + ("\nobject index must be < " + objectCount) ; + } + + // Check if object is in cache. + if ((objectIndex >= bufferObjectStart) && + (objectIndex < bufferObjectStart + bufferObjectCount)) { + if (print) System.out.println("\ngetting object from cache\n") ; + + bufferNextObjectOffset = (int) + (directory[objectIndex] - directory[bufferObjectStart]) ; + + bufferNextObjectCount = + bufferObjectCount - (objectIndex - bufferObjectStart) ; + + return readNext() ; + + } else { + // Move file pointer to correct offset. + setFilePointer(directory[objectIndex]) ; + + // Force a read from current offset. Disable cache read-ahead + // since cache hits are unlikely with random access. + bufferNextObjectCount = 0 ; + return readNext(objectSizes[objectIndex]) ; + } + } + + + /** + * Add a compressed geometry node component to the end of the instance. + * The current object index becomes invalid; an immediately following call + * to readNext() will return null. The close() method must be called at + * some later time in order to create a valid compressed geometry file. + * + * @param cg a compressed geometry node component + * @exception CapabilityNotSetException if unable to get compressed + * geometry data from the node component + * @exception IOException if write fails + */ + public void write(CompressedGeometryData cg) throws IOException { + CompressedGeometryData.Header cgh = new CompressedGeometryData.Header() ; + cg.getCompressedGeometryHeader(cgh) ; + + // Update the read/write buffer size if necessary. + if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) { + cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ; + if (print) System.out.println("\ncgBuffer: reallocated " + + (cgh.size+BLOCK_HEADER_SIZE) + + " bytes") ; + } + + cg.getCompressedGeometry(cgBuffer) ; + write(cgh, cgBuffer) ; + } + + /** + * Add a buffer of compressed geometry data to the end of the + * resource. The current object index becomes invalid; an immediately + * following call to readNext() will return null. The close() method must + * be called at some later time in order to create a valid compressed + * geometry file. + * + * @param cgh a CompressedGeometryData.Header object describing the data. + * @param geometry the compressed geometry data + * @exception IOException if write fails + */ + public void write(CompressedGeometryData.Header cgh, byte geometry[]) + throws IOException { + + // Update the read/write buffer size if necessary. It won't be used + // in this method, but should be big enough to read any object in + // the file, including the one to be written. + if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) { + cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ; + if (print) System.out.println("\ncgBuffer: reallocated " + + (cgh.size+BLOCK_HEADER_SIZE) + + " bytes") ; + } + + // Assuming backward compatibility, the version number of the file + // should be the maximum of all individual compressed object versions. + if ((cgh.majorVersionNumber > majorVersionNumber) + || + ((cgh.majorVersionNumber == majorVersionNumber) && + (cgh.minorVersionNumber > minorVersionNumber)) + || + ((cgh.majorVersionNumber == majorVersionNumber) && + (cgh.minorVersionNumber == minorVersionNumber) && + (cgh.minorMinorVersionNumber > minorMinorVersionNumber))) { + + majorVersionNumber = cgh.majorVersionNumber ; + minorVersionNumber = cgh.minorVersionNumber ; + minorMinorVersionNumber = cgh.minorMinorVersionNumber ; + + this.cgh.majorVersionNumber = cgh.majorVersionNumber ; + this.cgh.minorVersionNumber = cgh.minorVersionNumber ; + this.cgh.minorMinorVersionNumber = cgh.minorMinorVersionNumber ; + } + + // Get the buffer type and see what vertex components are present. + int geomDataType = 0 ; + + switch (cgh.bufferType) { + case CompressedGeometryData.Header.POINT_BUFFER: + geomDataType = TYPE_POINT ; + break ; + case CompressedGeometryData.Header.LINE_BUFFER: + geomDataType = TYPE_LINE ; + break ; + case CompressedGeometryData.Header.TRIANGLE_BUFFER: + geomDataType = TYPE_TRIANGLE ; + break ; + } + + if ((cgh.bufferDataPresent & + CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0) + geomDataType |= NORMAL_PRESENT_MASK ; + + if ((cgh.bufferDataPresent & + CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0) + geomDataType |= COLOR_PRESENT_MASK ; + + if ((cgh.bufferDataPresent & + CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0) + geomDataType |= ALPHA_PRESENT_MASK ; + + // Allocate new directory and object size arrays if necessary. + if (objectCount == directory.length) { + long newDirectory[] = new long[2*objectCount] ; + int newObjectSizes[] = new int[2*objectCount] ; + + System.arraycopy(directory, 0, + newDirectory, 0, objectCount) ; + System.arraycopy(objectSizes, 0, + newObjectSizes, 0, objectCount) ; + + directory = newDirectory ; + objectSizes = newObjectSizes ; + + if (print) + System.out.println("\ndirectory and size arrays: reallocated " + + (2*objectCount) + " entries") ; + } + + // Update directory and object size array. + directory[objectCount] = directoryOffset ; + objectSizes[objectCount] = cgh.size + BLOCK_HEADER_SIZE ; + objectCount++ ; + + // Seek to the directory and overwrite from there. + setFilePointer(directoryOffset) ; + cgFile.writeInt(cgh.size) ; + cgFile.writeInt(geomDataType) ; + cgFile.write(geometry, 0, cgh.size) ; + if (print) + System.out.println("\nwrote " + cgh.size + + " byte compressed object to " + fileName + + "\nfile offset " + directoryOffset) ; + + // Update the directory offset. + directoryOffset += cgh.size + BLOCK_HEADER_SIZE ; + + // Return end-of-file on next read. + objectIndex = objectCount ; + + // Flag file update so close() will write out the directory. + fileUpdate = true ; + } + + /** + * Release the resources associated with this instance. + * Write out final header and directory if contents were updated. + * This method must be called in order to create a valid compressed + * geometry resource file if any updates were made. + */ + public void close() { + if (cgFile != null) { + try { + if (fileUpdate) { + writeFileDirectory() ; + writeFileHeader() ; + } + cgFile.close() ; + } + catch (IOException e) { + // Don't propagate this exception. + System.out.println("\nException: " + e.getMessage()) ; + System.out.println("failed to close " + fileName) ; + } + } + cgFile = null ; + cgBuffer = null ; + directory = null ; + objectSizes = null ; + } + + + // + // Open the file. Specifying a non-existent file creates a new one if + // access permissions allow. + // + void open(String fname, boolean rw) + throws FileNotFoundException, IOException { + + cgFile = null ; + String mode ; + + if (rw) + mode = "rw" ; + else + mode = "r" ; + + try { + cgFile = new RandomAccessFile(fname, mode) ; + if (print) System.out.println("\n" + fname + + ": opened mode " + mode) ; + } + catch (FileNotFoundException e) { + // N.B. this exception is also thrown on access permission errors + throw new FileNotFoundException(e.getMessage() + "\n" + fname + + ": open mode " + mode + " failed") ; + } + } + + // + // Seek to the specified offset in the file. + // + void setFilePointer(long offset) throws IOException { + cgFile.seek(offset) ; + + // Reset number of objects that can be read sequentially from cache. + bufferNextObjectCount = 0 ; + } + + // + // Initialize directory, object size array, read/write buffer, and the + // shared compressed geometry header. + // + void initialize() throws IOException { + int maxSize = 0 ; + + if (cgFile.length() == 0) { + // New file for writing: allocate nominal initial sizes for arrays. + objectCount = 0 ; + cgBuffer = new byte[32768] ; + directory = new long[16] ; + objectSizes = new int[directory.length] ; + + // Set fields as if they have been read. + magicNumber = MAGIC_NUMBER ; + majorVersionNumber = 1 ; + minorVersionNumber = 0 ; + minorMinorVersionNumber = 0 ; + directoryOffset = HEADER_SIZE ; + + // Write the file header. + writeFileHeader() ; + + } else { + // Read the file header. + readFileHeader() ; + + // Check file type. + if (magicNumber != MAGIC_NUMBER) { + close() ; + throw new IllegalArgumentException + ("\n" + fileName + " is not a compressed geometry file") ; + } + + // Read the directory and determine object sizes. + directory = new long[objectCount] ; + readDirectory(directoryOffset, directory) ; + + objectSizes = new int[objectCount] ; + for (int i = 0 ; i < objectCount-1 ; i++) { + objectSizes[i] = (int)(directory[i+1] - directory[i]) ; + if (objectSizes[i] > maxSize) maxSize = objectSizes[i] ; + } + + if (objectCount > 0) { + objectSizes[objectCount-1] = + (int)(directoryOffset - directory[objectCount-1]) ; + + if (objectSizes[objectCount-1] > maxSize) + maxSize = objectSizes[objectCount-1] ; + } + + // Allocate a buffer big enough to read the largest object. + cgBuffer = new byte[maxSize] ; + + // Move to the first object. + setFilePointer(HEADER_SIZE) ; + } + + // Set up common parts of the compressed geometry object header. + cgh = new CompressedGeometryData.Header() ; + cgh.majorVersionNumber = this.majorVersionNumber ; + cgh.minorVersionNumber = this.minorVersionNumber ; + cgh.minorMinorVersionNumber = this.minorMinorVersionNumber ; + + if (print) { + System.out.println(fileName + ": " + objectCount + " objects") ; + System.out.println("magic number 0x" + + Integer.toHexString(magicNumber) + + ", version number " + majorVersionNumber + + "." + minorVersionNumber + + "." + minorMinorVersionNumber) ; + System.out.println("largest object is " + maxSize + " bytes") ; + } + } + + // + // Read the file header. + // + void readFileHeader() throws IOException { + byte header[] = new byte[HEADER_SIZE] ; + + try { + setFilePointer(0) ; + if (cgFile.read(header) != HEADER_SIZE) { + close() ; + throw new IOException("failed header read") ; + } + } + catch (IOException e) { + if (cgFile != null) { + close() ; + } + throw e ; + } + + magicNumber = + ((header[MAGIC_NUMBER_OFFSET+0] & 0xff) << 24) | + ((header[MAGIC_NUMBER_OFFSET+1] & 0xff) << 16) | + ((header[MAGIC_NUMBER_OFFSET+2] & 0xff) << 8) | + ((header[MAGIC_NUMBER_OFFSET+3] & 0xff)) ; + + majorVersionNumber = + ((header[MAJOR_VERSION_OFFSET+0] & 0xff) << 24) | + ((header[MAJOR_VERSION_OFFSET+1] & 0xff) << 16) | + ((header[MAJOR_VERSION_OFFSET+2] & 0xff) << 8) | + ((header[MAJOR_VERSION_OFFSET+3] & 0xff)) ; + + minorVersionNumber = + ((header[MINOR_VERSION_OFFSET+0] & 0xff) << 24) | + ((header[MINOR_VERSION_OFFSET+1] & 0xff) << 16) | + ((header[MINOR_VERSION_OFFSET+2] & 0xff) << 8) | + ((header[MINOR_VERSION_OFFSET+3] & 0xff)) ; + + minorMinorVersionNumber = + ((header[MINOR_MINOR_VERSION_OFFSET+0] & 0xff) << 24) | + ((header[MINOR_MINOR_VERSION_OFFSET+1] & 0xff) << 16) | + ((header[MINOR_MINOR_VERSION_OFFSET+2] & 0xff) << 8) | + ((header[MINOR_MINOR_VERSION_OFFSET+3] & 0xff)) ; + + objectCount = + ((header[OBJECT_COUNT_OFFSET+0] & 0xff) << 24) | + ((header[OBJECT_COUNT_OFFSET+1] & 0xff) << 16) | + ((header[OBJECT_COUNT_OFFSET+2] & 0xff) << 8) | + ((header[OBJECT_COUNT_OFFSET+3] & 0xff)) ; + + directoryOffset = + ((long)(header[DIRECTORY_OFFSET_OFFSET+0] & 0xff) << 56) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+1] & 0xff) << 48) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+2] & 0xff) << 40) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+3] & 0xff) << 32) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+4] & 0xff) << 24) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+5] & 0xff) << 16) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+6] & 0xff) << 8) | + ((long)(header[DIRECTORY_OFFSET_OFFSET+7] & 0xff)) ; + } + + // + // Write the file header based on current field values. + // + void writeFileHeader() throws IOException { + setFilePointer(0) ; + try { + cgFile.writeInt(MAGIC_NUMBER) ; + cgFile.writeInt(majorVersionNumber) ; + cgFile.writeInt(minorVersionNumber) ; + cgFile.writeInt(minorMinorVersionNumber) ; + cgFile.writeInt(objectCount) ; + cgFile.writeInt(0) ; // long word alignment + cgFile.writeLong(directoryOffset) ; + if (print) + System.out.println("wrote file header for " + fileName) ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\ncould not write file header for " + fileName) ; + } + } + + // + // Read the directory of compressed geometry object offsets. + // + void readDirectory(long offset, long[] directory) + throws IOException { + + byte buff[] = new byte[directory.length * 8] ; + setFilePointer(offset) ; + + try { + cgFile.read(buff) ; + if (print) + System.out.println("read " + buff.length + " byte directory") ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\nfailed to read " + buff.length + + " byte directory, offset " + offset + " in file " + fileName) ; + } + + for (int i = 0 ; i < directory.length ; i++) { + directory[i] = + ((long)(buff[i*8+0] & 0xff) << 56) | + ((long)(buff[i*8+1] & 0xff) << 48) | + ((long)(buff[i*8+2] & 0xff) << 40) | + ((long)(buff[i*8+3] & 0xff) << 32) | + ((long)(buff[i*8+4] & 0xff) << 24) | + ((long)(buff[i*8+5] & 0xff) << 16) | + ((long)(buff[i*8+6] & 0xff) << 8) | + ((long)(buff[i*8+7] & 0xff)) ; + } + } + + // + // Write the file directory. + // + void writeFileDirectory() throws IOException { + setFilePointer(directoryOffset) ; + + int directoryAlign = (int)(directoryOffset % 8) ; + if (directoryAlign != 0) { + // Align to long word before writing directory of long offsets. + byte bytes[] = new byte[8-directoryAlign] ; + + try { + cgFile.write(bytes) ; + if (print) + System.out.println ("wrote " + (8-directoryAlign) + + " bytes long alignment") ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\ncould not write " + directoryAlign + + " bytes to long word align directory for " + fileName) ; + } + directoryOffset += 8-directoryAlign ; + } + + try { + for (int i = 0 ; i < objectCount ; i++) + cgFile.writeLong(directory[i]) ; + + if (print) + System.out.println("wrote file directory for " + fileName) ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\ncould not write directory for " + fileName) ; + } + } + + // + // Get the next compressed object in the file, either from the read-ahead + // cache or from the file itself. + // + CompressedGeometryData readNext(int bufferReadLimit) + throws IOException { + if (objectIndex == objectCount) + return null ; + + if (bufferNextObjectCount == 0) { + // No valid objects are in the cache. + int curSize = 0 ; + bufferObjectCount = 0 ; + + // See how much we have room to read. + for (int i = objectIndex ; i < objectCount ; i++) { + if (curSize + objectSizes[i] > bufferReadLimit) break ; + curSize += objectSizes[i] ; + bufferObjectCount++ ; + } + + // Try to read that amount. + try { + int n = cgFile.read(cgBuffer, 0, curSize) ; + if (print) + System.out.println("\nread " + n + + " bytes from " + fileName) ; + } + catch (IOException e) { + throw new IOException + (e.getMessage() + + "\nfailed to read " + curSize + + " bytes, object " + objectIndex + " in file " + fileName) ; + } + + // Point at the first object in the buffer. + bufferObjectStart = objectIndex ; + bufferNextObjectCount = bufferObjectCount ; + bufferNextObjectOffset = 0 ; + } + + // Get block header info. + geomSize = + ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+0]&0xff)<<24) | + ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+1]&0xff)<<16) | + ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+2]&0xff)<< 8) | + ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+3]&0xff)) ; + + geomDataType = + ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+0]&0xff) << 24) | + ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+1]&0xff) << 16) | + ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+2]&0xff) << 8) | + ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+3]&0xff)) ; + + // Get offset of compressed geometry data from start of buffer. + geomStart = bufferNextObjectOffset + BLOCK_HEADER_SIZE ; + + if (print) { + System.out.println("\nobject " + objectIndex + + "\nfile offset " + directory[objectIndex] + + ", buffer offset " + bufferNextObjectOffset) ; + System.out.println("size " + geomSize + " bytes, " + + "data descriptor 0x" + + Integer.toHexString(geomDataType)) ; + } + + // Update cache info. + bufferNextObjectOffset += objectSizes[objectIndex] ; + bufferNextObjectCount-- ; + objectIndex++ ; + + return newCG(geomSize, geomStart, geomDataType) ; + } + + + // + // Construct and return a compressed geometry node. + // + CompressedGeometryData newCG(int geomSize, + int geomStart, + int geomDataType) { + cgh.size = geomSize ; + cgh.start = geomStart ; + + if ((geomDataType & TYPE_MASK) == TYPE_POINT) + cgh.bufferType = CompressedGeometryData.Header.POINT_BUFFER ; + else if ((geomDataType & TYPE_MASK) == TYPE_LINE) + cgh.bufferType = CompressedGeometryData.Header.LINE_BUFFER ; + else if ((geomDataType & TYPE_MASK) == TYPE_TRIANGLE) + cgh.bufferType = CompressedGeometryData.Header.TRIANGLE_BUFFER ; + + cgh.bufferDataPresent = 0 ; + + if ((geomDataType & NORMAL_PRESENT_MASK) != 0) + cgh.bufferDataPresent |= + CompressedGeometryData.Header.NORMAL_IN_BUFFER ; + + if ((geomDataType & COLOR_PRESENT_MASK) != 0) + cgh.bufferDataPresent |= + CompressedGeometryData.Header.COLOR_IN_BUFFER ; + + if ((geomDataType & ALPHA_PRESENT_MASK) != 0) + cgh.bufferDataPresent |= + CompressedGeometryData.Header.ALPHA_IN_BUFFER ; + + return new CompressedGeometryData(cgh, cgBuffer) ; + } + + /** + * Release file resources when this object is garbage collected. + */ + protected void finalize() { + close() ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryRetained.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryRetained.java new file mode 100644 index 0000000..29f36cc --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryRetained.java @@ -0,0 +1,282 @@ +/* + * $RCSfile: CompressedGeometryRetained.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:21 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import javax.media.j3d.BoundingBox; +import javax.media.j3d.Bounds; +import javax.media.j3d.Canvas3D; +import javax.media.j3d.GeometryArray; +import javax.media.j3d.PickInfo; +import javax.media.j3d.PickShape; +import javax.media.j3d.Transform3D; +import javax.vecmath.Point3d; + +/** + * The compressed geometry object is used to store geometry in a + * compressed format. Using compressed geometry reduces the amount + * of memory needed by a Java 3D application and increases the speed + * objects can be sent over the network. Once geometry decompression + * hardware support becomes available, increased rendering performance + * will also result from the use of compressed geometry. + */ +class CompressedGeometryRetained extends Object { + + // If not in by-reference mode, a 48-byte header as defined by the + // GL_SUNX_geometry_compression OpenGL extension is always concatenated to + // the beginning of the compressed geometry data and copied along with the + // it into a contiguous array. This allows hardware decompression using + // the obsolete experimental GL_SUNX_geometry_compression extension if + // that is all that is available. + // + // This is completely distinct and not to be confused with the cgHeader + // field on the non-retained side, although much of the data is + // essentially the same. + private static final int HEADER_LENGTH = 48 ; + + // These are the header locations examined. + private static final int HEADER_MAJOR_VERSION_OFFSET = 0 ; + private static final int HEADER_MINOR_VERSION_OFFSET = 1 ; + private static final int HEADER_MINOR_MINOR_VERSION_OFFSET = 2 ; + private static final int HEADER_BUFFER_TYPE_OFFSET = 3 ; + private static final int HEADER_BUFFER_DATA_OFFSET = 4 ; + + // The OpenGL compressed geometry extensions use bits instead of + // enumerations to represent the type of compressed geometry. + static final byte TYPE_POINT = 1 ; + static final byte TYPE_LINE = 2 ; + static final byte TYPE_TRIANGLE = 4 ; + + // Version number of this compressed geometry object. + int majorVersionNumber ; + int minorVersionNumber ; + int minorMinorVersionNumber ; + + // These fields are used by the native execute() method. + int packedVersion ; + int bufferType ; + int bufferContents ; + int renderFlags ; + int offset ; + int size ; + byte[] compressedGeometry ; + + // A reference to the original byte array with which this object was + // created. If hardware decompression is available but it doesn't support + // by-reference semantics, then an internal copy of the original byte array + // is made even when by-reference semantics have been requested. + private byte[] originalCompressedGeometry = null ; + + // Geometric bounds + private BoundingBox geoBounds = new BoundingBox(); + + // True if by-reference data access mode is in effect. + private boolean byReference = false ; + + /** + * The package-scoped constructor. + */ + CompressedGeometryRetained() { + // Compressed geometry is always bounded by [-1..1] on each axis, so + // set that as the initial bounding box. + geoBounds.setUpper( 1.0, 1.0, 1.0) ; + geoBounds.setLower(-1.0,-1.0,-1.0) ; + } + + /** + * Return true if the data access mode is by-reference. + */ + boolean isByReference() { + return this.byReference ; + } + + private void createByCopy(byte[] geometry) { + // Always copy a header along with the compressed geometry into a + // contiguous array in order to support hardware acceleration with the + // GL_SUNX_geometry_compression extension. The header is unnecessary + // if only the newer GL_SUN_geometry_compression API needs support. + compressedGeometry = new byte[HEADER_LENGTH + this.size] ; + + compressedGeometry[HEADER_MAJOR_VERSION_OFFSET] = + (byte)this.majorVersionNumber ; + + compressedGeometry[HEADER_MINOR_VERSION_OFFSET] = + (byte)this.minorVersionNumber ; + + compressedGeometry[HEADER_MINOR_MINOR_VERSION_OFFSET] = + (byte)this.minorMinorVersionNumber ; + + compressedGeometry[HEADER_BUFFER_TYPE_OFFSET] = + (byte)this.bufferType ; + + compressedGeometry[HEADER_BUFFER_DATA_OFFSET] = + (byte)this.bufferContents ; + + System.arraycopy(geometry, this.offset, + compressedGeometry, HEADER_LENGTH, this.size) ; + + this.offset = HEADER_LENGTH ; + } + + /** + * Creates the retained compressed geometry data. Data from the header is + * always copied; the compressed geometry is copied as well if the data + * access mode is not by-reference. + * + * @param hdr the compressed geometry header + * @param geometry the compressed geometry + * @param byReference if true then by-reference semantics requested + */ + void createCompressedGeometry(CompressedGeometryData.Header hdr, + byte[] geometry, boolean byReference) { + + this.byReference = byReference ; + + if (hdr.lowerBound != null) + this.geoBounds.setLower(hdr.lowerBound) ; + + if (hdr.upperBound != null) + this.geoBounds.setUpper(hdr.upperBound) ; + +//// this.centroid.set(geoBounds.getCenter()); +//// recompCentroid = false; + this.majorVersionNumber = hdr.majorVersionNumber ; + this.minorVersionNumber = hdr.minorVersionNumber ; + this.minorMinorVersionNumber = hdr.minorMinorVersionNumber ; + + this.packedVersion = + (hdr.majorVersionNumber << 24) | + (hdr.minorVersionNumber << 16) | + (hdr.minorMinorVersionNumber << 8) ; + + switch(hdr.bufferType) { + case CompressedGeometryData.Header.POINT_BUFFER: + this.bufferType = TYPE_POINT ; + break ; + case CompressedGeometryData.Header.LINE_BUFFER: + this.bufferType = TYPE_LINE ; + break ; + case CompressedGeometryData.Header.TRIANGLE_BUFFER: + this.bufferType = TYPE_TRIANGLE ; + break ; + } + + this.bufferContents = hdr.bufferDataPresent ; + this.renderFlags = 0 ; + + this.size = hdr.size ; + this.offset = hdr.start ; + + if (byReference) { + // Assume we can use the given reference, but maintain a second + // reference in case a copy is later needed. + this.compressedGeometry = geometry; + this.originalCompressedGeometry = geometry; + } else { + // Copy the original data into a format that can be used by both + // the software and native hardware decompressors. + createByCopy(geometry); + this.originalCompressedGeometry = null; + } + } + + /** + * Return a vertex format mask that's compatible with GeometryArray + * objects. + */ + int getVertexFormat() { + int vertexFormat = GeometryArray.COORDINATES; + + if ((bufferContents & CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0) { + vertexFormat |= GeometryArray.NORMALS; + } + + if ((bufferContents & CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0) { + if ((bufferContents & CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0) { + vertexFormat |= GeometryArray.COLOR_4; + } else { + vertexFormat |= GeometryArray.COLOR_3; + } + } + + return vertexFormat ; + } + + /** + * Return a buffer type that's compatible with CompressedGeometryData.Header. + */ + int getBufferType() { + switch(this.bufferType) { + case TYPE_POINT: + return CompressedGeometryData.Header.POINT_BUFFER ; + case TYPE_LINE: + return CompressedGeometryData.Header.LINE_BUFFER ; + default: + case TYPE_TRIANGLE: + return CompressedGeometryData.Header.TRIANGLE_BUFFER ; + } + } + + /** + * Copies compressed geometry data into the given array of bytes. + * The internal header information is not copied. + * + * @param buff array of bytes into which to copy compressed geometry + */ + void copy(byte[] buff) { + System.arraycopy(compressedGeometry, offset, buff, 0, size) ; + } + + /** + * Returns a reference to the original compressed geometry byte array, + * which may have been copied even if by-reference semantics have been + * requested. It will be null if byCopy is in effect. + * + * @return reference to array of bytes containing the compressed geometry. + */ + byte[] getReference() { + return originalCompressedGeometry ; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStream.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStream.java new file mode 100644 index 0000000..991692e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStream.java @@ -0,0 +1,2321 @@ +/* + * $RCSfile: CompressionStream.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import com.sun.j3d.internal.BufferWrapper; +import com.sun.j3d.internal.ByteBufferWrapper; +import com.sun.j3d.internal.DoubleBufferWrapper; +import com.sun.j3d.internal.FloatBufferWrapper; +import com.sun.j3d.utils.geometry.GeometryInfo; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import javax.media.j3d.Appearance; +import javax.media.j3d.Geometry; +import javax.media.j3d.GeometryArray; +import javax.media.j3d.GeometryStripArray; +import javax.media.j3d.IndexedGeometryArray; +import javax.media.j3d.IndexedGeometryStripArray; +import javax.media.j3d.IndexedLineArray; +import javax.media.j3d.IndexedLineStripArray; +import javax.media.j3d.IndexedQuadArray; +import javax.media.j3d.IndexedTriangleArray; +import javax.media.j3d.IndexedTriangleFanArray; +import javax.media.j3d.IndexedTriangleStripArray; +import javax.media.j3d.J3DBuffer; +import javax.media.j3d.LineArray; +import javax.media.j3d.LineStripArray; +import javax.media.j3d.Material; +import javax.media.j3d.QuadArray; +import javax.media.j3d.Shape3D; +import javax.media.j3d.TriangleArray; +import javax.media.j3d.TriangleFanArray; +import javax.media.j3d.TriangleStripArray; +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; +import javax.vecmath.Point3d; +import javax.vecmath.Point3f; +import javax.vecmath.Point3i; +import javax.vecmath.Vector3f; + +/** + * This class is used as input to a geometry compressor. It collects elements + * such as vertices, normals, colors, mesh references, and quantization + * parameters in an ordered stream. This stream is then traversed during + * the compression process and used to build the compressed output buffer. + * + * @see GeometryCompressor + * + * @since Java 3D 1.5 + */ +public class CompressionStream { + // + // NOTE: For now, copies are made of all GeometryArray vertex components + // even when by-reference access is available. + // + // TODO: Retrofit all CompressionStreamElements and MeshBuffer to handle + // offsets to vertex data array references so that vertex components don't + // have to be copied. New CompressionStreamElements could be defined to + // set the current array reference during the quantization pass, or the + // reference could be included in every CompressionStreamElement along + // with the data offsets. + // + // TODO: Quantize on-the-fly when adding GeometryArray vertex data so that + // CompressionStreamElements don't need references to the original float, + // double, or byte data. Quantization is currently a separate pass since + // the 1st pass adds vertex data and gets the total object bounds, but + // this can be computed by merging the bounds of each GeometryArray + // compressed into a single object. The 2nd pass quantization is still + // needed for vertex data which isn't retrieved from a GeometryArray; for + // example, apps that might use the addVertex() methods directly instead + // of addGeometryArray(). + // + // TODO: To further optimize memory, create new subclasses of + // CompressionStream{Color, Normal} for bundled attributes and add them as + // explicit stream elements. Then CompressionStreamVertex won't need to + // carry references to them. This memory savings might be negated by the + // extra overhead of adding more elements to the stream, however. + // + // TODO: Keep the absolute quantized values in the mesh buffer mirror so + // that unmeshed CompressionStreamElements don't need to carry them. + // + // TODO: Support texture coordinate compression even though Level II is + // not supported by any hardware decompressor on any graphics card. + // Software decompression is still useful for applications interested in + // minimizing file space, transmission time, and object loading time. + // + private static final boolean debug = false ; + private static final boolean benchmark = false ; + + // Mesh buffer normal substitution is unavailable in Level I. + private static final boolean noMeshNormalSubstitution = true ; + + /** + * This flag indicates that a vertex starts a new triangle or line strip. + */ + static final int RESTART = 1 ; + + /** + * This flag indicates that the next triangle in the strip is defined by + * replacing the middle vertex of the previous triangle in the strip. + * Equivalent to REPLACE_OLDEST for line strips. + */ + static final int REPLACE_MIDDLE = 2 ; + + /** + * This flag indicates that the next triangle in the strip is defined by + * replacing the oldest vertex of the previous triangle in the strip. + * Equivalent to REPLACE_MIDDLE for line strips. + */ + static final int REPLACE_OLDEST = 3 ; + + /** + * This flag indicates that a vertex is to be pushed into the mesh buffer. + */ + static final int MESH_PUSH = 1 ; + + /** + * This flag indicates that a vertex does not use the mesh buffer. + */ + static final int NO_MESH_PUSH = 0 ; + + /** + * Byte to float scale factor for scaling byte color components. + */ + static final float ByteToFloatScale = 1.0f/255.0f; + + /** + * Type of this stream, either CompressedGeometryData.Header.POINT_BUFFER, + * CompressedGeometryData.Header.LINE_BUFFER, or + * CompressedGeometryData.Header.TRIANGLE_BUFFER + */ + int streamType ; + + /** + * A mask indicating which components are present in each vertex, as + * defined by GeometryArray. + */ + int vertexComponents ; + + /** + * Boolean indicating colors are bundled with the vertices. + */ + boolean vertexColors ; + + /** + * Boolean indicating RGB colors are bundled with the vertices. + */ + boolean vertexColor3 ; + + /** + * Boolean indicating RGBA colors are bundled with the vertices. + */ + boolean vertexColor4 ; + + /** + * Boolean indicating normals are bundled with the vertices. + */ + boolean vertexNormals ; + + /** + * Boolean indicating texture coordinates are present. + */ + boolean vertexTextures ; + + /** + * Boolean indicating that 2D texture coordinates are used. + * Currently only used to skip over textures in interleaved data. + */ + boolean vertexTexture2 ; + + /** + * Boolean indicating that 3D texture coordinates are used. + * Currently only used to skip over textures in interleaved data. + */ + boolean vertexTexture3 ; + + /** + * Boolean indicating that 4D texture coordinates are used. + * Currently only used to skip over textures in interleaved data. + */ + boolean vertexTexture4 ; + + /** + * Axes-aligned box enclosing all vertices in model coordinates. + */ + Point3d mcBounds[] = new Point3d[2] ; + + /** + * Axes-aligned box enclosing all vertices in normalized coordinates. + */ + Point3d ncBounds[] = new Point3d[2] ; + + /** + * Axes-aligned box enclosing all vertices in quantized coordinates. + */ + Point3i qcBounds[] = new Point3i[2] ; + + /** + * Center for normalizing positions to the unit cube. + */ + double center[] = new double[3] ; + + /** + * Maximum position range along the 3 axes. + */ + double positionRangeMaximum ; + + /** + * Scale for normalizing positions to the unit cube. + */ + double scale ; + + /** + * Current position component (X, Y, and Z) quantization value. This can + * range from 1 to 16 bits and has a default of 16.

+ * + * At 1 bit of quantization it is not possible to express positive + * absolute or delta positions. + */ + int positionQuant ; + + /** + * Current color component (R, G, B, A) quantization value. This can + * range from 2 to 16 bits and has a default of 9.

+ * + * A color component is represented with a signed fixed-point value in + * order to be able express negative deltas; the default of 9 bits + * corresponds to the 8-bit color component range of the graphics hardware + * commonly available. Colors must be non-negative, so the lower limit of + * quantization is 2 bits. + */ + int colorQuant ; + + /** + * Current normal component (U and V) quantization value. This can range + * from 0 to 6 bits and has a default of 6.

+ * + * At 0 bits of quantization normals are represented only as 6 bit + * sextant/octant pairs and 14 specially encoded normals (the 6 axis + * normals and the 8 octant midpoint normals); since U and V can only be 0 + * at the minimum quantization, the totally number of unique normals is + * 12 + 14 = 26. + */ + int normalQuant ; + + /** + * Flag indicating position quantization change. + */ + boolean positionQuantChanged ; + + /** + * Flag indicating color quantization change. + */ + boolean colorQuantChanged ; + + /** + * Flag indicating normal quantization change. + */ + boolean normalQuantChanged ; + + /** + * Last quantized position. + */ + int lastPosition[] = new int[3] ; + + /** + * Last quantized color. + */ + int lastColor[] = new int[4] ; + + /** + * Last quantized normal's sextant. + */ + int lastSextant ; + + /** + * Last quantized normal's octant. + */ + int lastOctant ; + + /** + * Last quantized normal's U encoding parameter. + */ + int lastU ; + + /** + * Last quantized normal's V encoding parameter. + */ + int lastV ; + + /** + * Flag indicating last normal used a special encoding. + */ + boolean lastSpecialNormal ; + + /** + * Flag indicating the first position in this stream. + */ + boolean firstPosition ; + + /** + * Flag indicating the first color in this stream. + */ + boolean firstColor ; + + /** + * Flag indicating the first normal in this stream. + */ + boolean firstNormal ; + + /** + * The total number of bytes used to create the uncompressed geometric + * elements in this stream, useful for performance analysis. This + * excludes mesh buffer references. + */ + int byteCount ; + + /** + * The number of vertices created for this stream, excluding mesh buffer + * references. + */ + int vertexCount ; + + /** + * The number of mesh buffer references created for this stream. + */ + int meshReferenceCount ; + + /** + * Mesh buffer mirror used for computing deltas during quantization pass + * and a limited meshing algorithm for unstripped data. + */ + MeshBuffer meshBuffer = new MeshBuffer() ; + + + // Collection which holds the elements of this stream. + private Collection stream ; + + // True if preceding stream elements were colors or normals. Used to flag + // color and normal mesh buffer substitution when computing deltas during + // quantization pass. + private boolean lastElementColor = false ; + private boolean lastLastElementColor = false ; + private boolean lastElementNormal = false ; + private boolean lastLastElementNormal = false ; + + // Some convenient temporary holding variables. + private Point3f p3f = new Point3f() ; + private Color3f c3f = new Color3f() ; + private Color4f c4f = new Color4f() ; + private Vector3f n3f = new Vector3f() ; + + + // Private constructor for common initializations. + private CompressionStream() { + this.stream = new LinkedList() ; + + byteCount = 0 ; + vertexCount = 0 ; + meshReferenceCount = 0 ; + + mcBounds[0] = new Point3d(Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY) ; + mcBounds[1] = new Point3d(Double.NEGATIVE_INFINITY, + Double.NEGATIVE_INFINITY, + Double.NEGATIVE_INFINITY) ; + + qcBounds[0] = new Point3i(Integer.MAX_VALUE, + Integer.MAX_VALUE, + Integer.MAX_VALUE) ; + qcBounds[1] = new Point3i(Integer.MIN_VALUE, + Integer.MIN_VALUE, + Integer.MIN_VALUE) ; + + /* normalized bounds computed from quantized bounds */ + ncBounds[0] = new Point3d() ; + ncBounds[1] = new Point3d() ; + } + + /** + * Creates a new CompressionStream for the specified geometry type and + * vertex format.

+ * + * @param streamType type of data in this stream, either + * CompressedGeometryData.Header.POINT_BUFFER, + * CompressedGeometryData.Header.LINE_BUFFER, or + * CompressedGeometryData.Header.TRIANGLE_BUFFER + * @param vertexComponents a mask indicating which components are present + * in each vertex, as defined by GeometryArray: COORDINATES, NORMALS, and + * COLOR_3 or COLOR_4. + * @see GeometryCompressor + * @see GeometryArray + */ + CompressionStream(int streamType, int vertexComponents) { + this() ; + this.streamType = streamType ; + this.vertexComponents = getVertexComponents(vertexComponents) ; + } + + // See what vertex geometry components are present. The byReference, + // interleaved, useNIOBuffer, and useCoordIndexOnly flags are not + // examined. + private int getVertexComponents(int vertexFormat) { + int components = 0 ; + + vertexColors = vertexColor3 = vertexColor4 = vertexNormals = + vertexTextures = vertexTexture2 = vertexTexture3 = vertexTexture4 = + false ; + + if ((vertexFormat & GeometryArray.NORMALS) != 0) { + vertexNormals = true ; + components &= GeometryArray.NORMALS ; + if (debug) System.out.println("vertexNormals") ; + } + + if ((vertexFormat & GeometryArray.COLOR_3) != 0) { + vertexColors = true ; + + if ((vertexFormat & GeometryArray.COLOR_4) != 0) { + vertexColor4 = true ; + components &= GeometryArray.COLOR_4 ; + if (debug) System.out.println("vertexColor4") ; + } + else { + vertexColor3 = true ; + components &= GeometryArray.COLOR_3 ; + if (debug) System.out.println("vertexColor3") ; + } + } + + if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + vertexTextures = true ; + vertexTexture2 = true ; + components &= GeometryArray.TEXTURE_COORDINATE_2 ; + if (debug) System.out.println("vertexTexture2") ; + } + else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + vertexTextures = true ; + vertexTexture3 = true ; + components &= GeometryArray.TEXTURE_COORDINATE_3 ; + if (debug) System.out.println("vertexTexture3") ; + } + else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + vertexTextures = true ; + vertexTexture4 = true ; + components &= GeometryArray.TEXTURE_COORDINATE_4 ; + if (debug) System.out.println("vertexTexture4") ; + } + + if (vertexTextures) + // Throw exception for now until texture is supported. + throw new UnsupportedOperationException + ("\ncompression of texture coordinates is not supported") ; + + return components ; + } + + // Get the streamType associated with a GeometryArray instance. + private int getStreamType(GeometryArray ga) { + if (ga instanceof TriangleStripArray || + ga instanceof IndexedTriangleStripArray || + ga instanceof TriangleFanArray || + ga instanceof IndexedTriangleFanArray || + ga instanceof TriangleArray || + ga instanceof IndexedTriangleArray || + ga instanceof QuadArray || + ga instanceof IndexedQuadArray) + + return CompressedGeometryData.Header.TRIANGLE_BUFFER ; + + else if (ga instanceof LineArray || + ga instanceof IndexedLineArray || + ga instanceof LineStripArray || + ga instanceof IndexedLineStripArray) + + return CompressedGeometryData.Header.LINE_BUFFER ; + + else + return CompressedGeometryData.Header.POINT_BUFFER ; + } + + /** + * Iterates across all compression stream elements and applies + * quantization parameters, encoding consecutive vertices as delta values + * whenever possible. Each geometric element is mapped to a HuffmanNode + * object containing its resulting bit length, right shift (trailing 0 + * count), and absolute or relative status.

+ * + * Positions are normalized to span a unit cube via an offset and a + * uniform scale factor that maps the midpoint of the object extents along + * each dimension to the origin, and the longest dimension of the object to + * the open interval (-1.0 .. +1.0). The geometric endpoints along that + * dimension are both one quantum away from unity; for example, at a + * position quantization of 6 bits, an object would be normalized so that + * its most negative dimension is at (-1 + 1/64) and the most positive is + * at (1 - 1/64).

+ * + * Normals are assumed to be of unit length. Color components are clamped + * to the [0..1) range, where the right endpoint is one quantum less + * than 1.0.

+ * + * @param huffmanTable Table which will map geometric compression stream + * elements to HuffmanNode objects describing each element's data + * representation. This table can then be processed with Huffman's + * algorithm to optimize the bit length of descriptor tags according to + * the number of geometric elements mapped to each tag. + */ + void quantize(HuffmanTable huffmanTable) { + // Set up default initial quantization parameters. The position and + // color parameters specify the number of bits for each X, Y, Z, R, G, + // B, or A component. The normal quantization parameter specifies the + // number of bits for each U and V component. + positionQuant = 16 ; + colorQuant = 9 ; + normalQuant = 6 ; + + // Compute position center and scaling for normalization to the unit + // cube. This is a volume bounded by the open intervals (-1..1) on + // each axis. + center[0] = (mcBounds[1].x + mcBounds[0].x) / 2.0 ; + center[1] = (mcBounds[1].y + mcBounds[0].y) / 2.0 ; + center[2] = (mcBounds[1].z + mcBounds[0].z) / 2.0 ; + + double xRange = mcBounds[1].x - mcBounds[0].x ; + double yRange = mcBounds[1].y - mcBounds[0].y ; + double zRange = mcBounds[1].z - mcBounds[0].z ; + + if (xRange > yRange) + positionRangeMaximum = xRange ; + else + positionRangeMaximum = yRange ; + + if (zRange > positionRangeMaximum) + positionRangeMaximum = zRange ; + + // Adjust the range of the unit cube to match the default + // quantization. + // + // This scale factor along with the center values computed above will + // produce 16-bit integer representations of the floating point + // position coordinates ranging symmetrically about 0 from -32767 to + // +32767. -32768 is not used and the normalized floating point + // position coordinates of -1.0 as well as +1.0 will not be + // represented. + // + // Applications which wish to seamlessly stitch together compressed + // objects will need to be aware that the range of normalized + // positions will be one quantum away from the [-1..1] endpoints of + // the unit cube and should adjust scale factors accordingly. + scale = (2.0 / positionRangeMaximum) * (32767.0 / 32768.0) ; + + // Flag quantization change. + positionQuantChanged = colorQuantChanged = normalQuantChanged = true ; + + // Flag first position, color, and normal. + firstPosition = firstColor = firstNormal = true ; + + // Apply quantization. + Iterator i = stream.iterator() ; + while (i.hasNext()) { + Object o = i.next() ; + + if (o instanceof CompressionStreamElement) { + ((CompressionStreamElement)o).quantize(this, huffmanTable) ; + + // Keep track of whether last two elements were colors or + // normals for mesh buffer component substitution semantics. + lastLastElementColor = lastElementColor ; + lastLastElementNormal = lastElementNormal ; + lastElementColor = lastElementNormal = false ; + + if (o instanceof CompressionStreamColor) + lastElementColor = true ; + else if (o instanceof CompressionStreamNormal) + lastElementNormal = true ; + } + } + + // Compute the bounds in normalized coordinates. + ncBounds[0].x = (double)qcBounds[0].x / 32768.0 ; + ncBounds[0].y = (double)qcBounds[0].y / 32768.0 ; + ncBounds[0].z = (double)qcBounds[0].z / 32768.0 ; + + ncBounds[1].x = (double)qcBounds[1].x / 32768.0 ; + ncBounds[1].y = (double)qcBounds[1].y / 32768.0 ; + ncBounds[1].z = (double)qcBounds[1].z / 32768.0 ; + } + + /** + * Iterates across all compression stream elements and builds the + * compressed geometry command stream output.

+ * + * @param huffmanTable Table which maps geometric elements in this stream + * to tags describing the encoding parameters (length, shift, and + * absolute/relative status) to be used for their representations in the + * compressed output. All tags must be 6 bits or less in length, and the + * sum of the number of bits in the tag plus the number of bits in the + * data it describes must be at least 6 bits in length. + * + * @param outputBuffer CommandStream to use for collecting the compressed + * bits. + */ + void outputCommands(HuffmanTable huffmanTable, CommandStream outputBuffer) { + // + // The first command output is setState to indicate what data is + // bundled with each vertex. Although the semantics of geometry + // decompression allow setState to appear anywhere in the stream, this + // cannot be handled by the current Java 3D software decompressor, + // which internally decompresses an entire compressed buffer into a + // single retained object sharing a single consistent vertex format. + // This limitation may be removed in subsequent releases of Java 3D. + // + int bnv = (vertexNormals? 1 : 0) ; + int bcv = ((vertexColor3 || vertexColor4)? 1 : 0) ; + int cap = (vertexColor4? 1 : 0) ; + + int command = CommandStream.SET_STATE | bnv ; + long data = (bcv << 2) | (cap << 1) ; + + // Output the setState command. + outputBuffer.addCommand(command, 8, data, 3) ; + + // Output the Huffman table commands. + huffmanTable.outputCommands(outputBuffer) ; + + // Output each compression stream element's data. + Iterator i = stream.iterator() ; + while (i.hasNext()) { + Object o = i.next() ; + if (o instanceof CompressionStreamElement) + ((CompressionStreamElement)o).outputCommand(huffmanTable, + outputBuffer) ; + } + + // Finish the header-forwarding interleave and long-word align. + outputBuffer.end() ; + } + + /** + * Retrieve the total size of the uncompressed geometric data in bytes, + * excluding mesh buffer references. + * @return uncompressed byte count + */ + int getByteCount() { + return byteCount ; + } + + /** + * Retrieve the the number of vertices created for this stream, excluding + * mesh buffer references. + * @return vertex count + */ + int getVertexCount() { + return vertexCount ; + } + + /** + * Retrieve the number of mesh buffer references created for this stream. + * @return mesh buffer reference count + */ + int getMeshReferenceCount() { + return meshReferenceCount ; + } + + /** + * Stream element that sets position quantization during quantize pass. + */ + private class PositionQuant extends CompressionStreamElement { + int value ; + + PositionQuant(int value) { + this.value = value ; + } + + void quantize(CompressionStream s, HuffmanTable t) { + positionQuant = value ; + positionQuantChanged = true ; + + // Adjust range of unit cube scaling to match quantization. + scale = (2.0 / positionRangeMaximum) * + (((double)((1 << (value-1)) - 1))/((double)(1 << (value-1)))) ; + } + + public String toString() { + return "positionQuant: " + value ; + } + } + + /** + * Stream element that sets normal quantization during quantize pass. + */ + private class NormalQuant extends CompressionStreamElement { + int value ; + + NormalQuant(int value) { + this.value = value ; + } + + void quantize(CompressionStream s, HuffmanTable t) { + normalQuant = value ; + normalQuantChanged = true ; + } + + public String toString() { + return "normalQuant: " + value ; + } + } + + /** + * Stream element that sets color quantization during quantize pass. + */ + private class ColorQuant extends CompressionStreamElement { + int value ; + + ColorQuant(int value) { + this.value = value ; + } + + void quantize(CompressionStream s, HuffmanTable t) { + colorQuant = value ; + colorQuantChanged = true ; + } + + public String toString() { + return "colorQuant: " + value ; + } + } + + /** + * Stream element that references the mesh buffer. + */ + private class MeshReference extends CompressionStreamElement { + int stripFlag, meshIndex ; + + MeshReference(int stripFlag, int meshIndex) { + this.stripFlag = stripFlag ; + this.meshIndex = meshIndex ; + meshReferenceCount++ ; + } + + void quantize(CompressionStream s, HuffmanTable t) { + // Retrieve the vertex from the mesh buffer mirror and set up the + // data needed for the next stream element to compute its deltas. + CompressionStreamVertex v = meshBuffer.getVertex(meshIndex) ; + lastPosition[0] = v.xAbsolute ; + lastPosition[1] = v.yAbsolute ; + lastPosition[2] = v.zAbsolute ; + + // Set up last color data if it exists and previous elements + // don't override it. + if (v.color != null && !lastElementColor && + !(lastElementNormal && lastLastElementColor)) { + lastColor[0] = v.color.rAbsolute ; + lastColor[1] = v.color.gAbsolute ; + lastColor[2] = v.color.bAbsolute ; + lastColor[3] = v.color.aAbsolute ; + } + + // Set up last normal data if it exists and previous element + // doesn't override it. + if (v.normal != null && !lastElementNormal && + !(lastElementColor && lastLastElementNormal)) { + lastSextant = v.normal.sextant ; + lastOctant = v.normal.octant ; + lastU = v.normal.uAbsolute ; + lastV = v.normal.vAbsolute ; + lastSpecialNormal = v.normal.specialNormal ; + } + } + + void outputCommand(HuffmanTable t, CommandStream outputBuffer) { + int command = CommandStream.MESH_B_R ; + long data = stripFlag & 0x1 ; + + command |= (((meshIndex & 0xf) << 1) | (stripFlag >> 1)) ; + outputBuffer.addCommand(command, 8, data, 1) ; + } + + public String toString() { + return + "meshReference: stripFlag " + stripFlag + + " meshIndex " + meshIndex ; + } + } + + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, int stripFlag) { + stream.add(new CompressionStreamVertex(this, pos, + (Vector3f)null, (Color3f)null, + stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Vector3f norm, int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, (Color3f)null, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Color3f color, int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Color4f color, int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Vector3f norm, Color3f color, + int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, + * REPLACE_OLDEST, or REPLACE_MIDDLE + */ + void addVertex(Point3f pos, Vector3f norm, Color4f color, + int stripFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, (Color3f)null, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Vector3f norm, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, (Color3f)null, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Color3f color, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Color4f color, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Vector3f norm, Color3f color, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, color, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Vector3f norm, Color4f color, + int stripFlag, int meshFlag) { + stream.add(new CompressionStreamVertex + (this, pos, norm, color, stripFlag, meshFlag)) ; + } + + /** + * Copy vertex data and add it to the end of this stream. + * @param pos position data + * @param norm normal data + * @param color color data, either Color3f or Color4f, determined by + * current vertex format + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer + */ + void addVertex(Point3f pos, Vector3f norm, + Object color, int stripFlag, int meshFlag) { + + if (vertexColor3) + stream.add(new CompressionStreamVertex + (this, pos, norm, (Color3f)color, stripFlag, meshFlag)) ; + else + stream.add(new CompressionStreamVertex + (this, pos, norm, (Color4f)color, stripFlag, meshFlag)) ; + } + + /** + * Add a mesh buffer reference to this stream. + * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST, + * or REPLACE_MIDDLE + * @param meshIndex index of vertex to retrieve from the mesh buffer + */ + void addMeshReference(int stripFlag, int meshIndex) { + stream.add(new MeshReference(stripFlag, meshIndex)) ; + } + + /** + * Copy the given color to the end of this stream and use it as a global + * state change that applies to all subsequent vertices. + */ + void addColor(Color3f c3f) { + stream.add(new CompressionStreamColor(this, c3f)) ; + } + + /** + * Copy the given color to the end of this stream and use it as a global + * state change that applies to all subsequent vertices. + */ + void addColor(Color4f c4f) { + stream.add(new CompressionStreamColor(this, c4f)) ; + } + + /** + * Copy the given normal to the end of this stream and use it as a global + * state change that applies to all subsequent vertices. + */ + void addNormal(Vector3f n) { + stream.add(new CompressionStreamNormal(this, n)) ; + } + + /** + * Add a new position quantization value to the end of this stream that + * will apply to all subsequent vertex positions. + * + * @param value number of bits to quantize each position's X, Y, + * and Z components, ranging from 1 to 16 with a default of 16 + */ + void addPositionQuantization(int value) { + stream.add(new PositionQuant(value)) ; + } + + /** + * Add a new color quantization value to the end of this stream that will + * apply to all subsequent colors. + * + * @param value number of bits to quantize each color's R, G, B, and + * alpha components, ranging from 2 to 16 with a default of 9 + */ + void addColorQuantization(int value) { + stream.add(new ColorQuant(value)) ; + } + + /** + * Add a new normal quantization value to the end of this stream that will + * apply to all subsequent normals. This value specifies the number of + * bits for each normal's U and V components. + * + * @param value number of bits for quantizing U and V, ranging from 0 to + * 6 with a default of 6 + */ + void addNormalQuantization(int value) { + stream.add(new NormalQuant(value)) ; + } + + /** + * Interface to access GeometryArray vertex components and add them to the + * compression stream. + * + * A processVertex() implementation retrieves vertex components using the + * appropriate access semantics of a particular GeometryArray, and adds + * them to the compression stream. + * + * The implementation always pushes vertices into the mesh buffer unless + * they match ones already there; if they do, it generates mesh buffer + * references instead. This reduces the number of vertices when + * non-stripped abutting facets are added to the stream. + * + * Note: Level II geometry compression semantics allow the mesh buffer + * normals to be substituted with the value of an immediately + * preceding SetNormal command, but this is unavailable in Level I. + * + * @param index vertex offset from the beginning of its data array + * @param stripFlag RESTART, REPLACE_MIDDLE, or REPLACE_OLDEST + */ + private interface GeometryAccessor { + void processVertex(int index, int stripFlag) ; + } + + /** + * This class implements the GeometryAccessor interface for geometry + * arrays accessed with by-copy semantics. + */ + private class ByCopyGeometry implements GeometryAccessor { + Point3f[] positions = null ; + Vector3f[] normals = null ; + Color3f[] colors3 = null ; + Color4f[] colors4 = null ; + + ByCopyGeometry(GeometryArray ga) { + this(ga, ga.getInitialVertexIndex(), ga.getValidVertexCount()) ; + } + + ByCopyGeometry(GeometryArray ga, + int firstVertex, int validVertexCount) { + int i ; + positions = new Point3f[validVertexCount] ; + for (i = 0 ; i < validVertexCount ; i++) + positions[i] = new Point3f() ; + + ga.getCoordinates(firstVertex, positions) ; + + if (vertexNormals) { + normals = new Vector3f[validVertexCount] ; + for (i = 0 ; i < validVertexCount ; i++) + normals[i] = new Vector3f() ; + + ga.getNormals(firstVertex, normals) ; + } + + if (vertexColor3) { + colors3 = new Color3f[validVertexCount] ; + for (i = 0 ; i < validVertexCount ; i++) + colors3[i] = new Color3f() ; + + ga.getColors(firstVertex, colors3) ; + } + else if (vertexColor4) { + colors4 = new Color4f[validVertexCount] ; + for (i = 0 ; i < validVertexCount ; i++) + colors4[i] = new Color4f() ; + + ga.getColors(firstVertex, colors4) ; + } + } + + public void processVertex(int v, int stripFlag) { + Point3f p = positions[v] ; + int r = meshBuffer.getMeshReference(p) ; + + if ((r == meshBuffer.NOT_FOUND) || + (vertexNormals && noMeshNormalSubstitution && + (! normals[v].equals(meshBuffer.getNormal(r))))) { + + Vector3f n = vertexNormals? normals[v] : null ; + Object c = vertexColor3? (Object)colors3[v] : + vertexColor4? (Object)colors4[v] : null ; + + addVertex(p, n, c, stripFlag, MESH_PUSH) ; + meshBuffer.push(p, c, n) ; + } + else { + if (vertexNormals && !noMeshNormalSubstitution && + (! normals[v].equals(meshBuffer.getNormal(r)))) + addNormal(normals[v]) ; + + if (vertexColor3 && + (! colors3[v].equals(meshBuffer.getColor3(r)))) + addColor(colors3[v]) ; + + else if (vertexColor4 && + (! colors4[v].equals(meshBuffer.getColor4(r)))) + addColor(colors4[v]) ; + + addMeshReference(stripFlag, r) ; + } + } + } + + /** + * Class which holds index array references for a geometry array. + */ + private static class IndexArrays { + int colorIndices[] = null ; + int normalIndices[] = null ; + int positionIndices[] = null ; + } + + /** + * Retrieves index array references for the specified IndexedGeometryArray. + * Index arrays are copied starting from initialIndexIndex. + */ + private void getIndexArrays(GeometryArray ga, IndexArrays ia) { + IndexedGeometryArray iga = (IndexedGeometryArray)ga ; + + int initialIndexIndex = iga.getInitialIndexIndex() ; + int indexCount = iga.getValidIndexCount() ; + int vertexFormat = iga.getVertexFormat() ; + + boolean useCoordIndexOnly = false ; + if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) { + if (debug) System.out.println("useCoordIndexOnly") ; + useCoordIndexOnly = true ; + } + + ia.positionIndices = new int[indexCount] ; + iga.getCoordinateIndices(initialIndexIndex, ia.positionIndices) ; + + if (vertexNormals) { + if (useCoordIndexOnly) { + ia.normalIndices = ia.positionIndices ; + } + else { + ia.normalIndices = new int[indexCount] ; + iga.getNormalIndices(initialIndexIndex, ia.normalIndices) ; + } + } + if (vertexColor3 || vertexColor4) { + if (useCoordIndexOnly) { + ia.colorIndices = ia.positionIndices ; + } + else { + ia.colorIndices = new int[indexCount] ; + iga.getColorIndices(initialIndexIndex, ia.colorIndices) ; + } + } + } + + /** + * Class which holds indices for a specific vertex of an + * IndexedGeometryArray. + */ + private static class VertexIndices { + int pi, ni, ci ; + } + + /** + * Retrieves vertex indices for a specific vertex in an + * IndexedGeometryArray. + */ + private void getVertexIndices(int v, IndexArrays ia, VertexIndices vi) { + vi.pi = ia.positionIndices[v] ; + if (vertexNormals) + vi.ni = ia.normalIndices[v] ; + if (vertexColors) + vi.ci = ia.colorIndices[v] ; + } + + /** + * This class implements the GeometryAccessor interface for indexed + * geometry arrays accessed with by-copy semantics. + */ + private class IndexedByCopyGeometry extends ByCopyGeometry { + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedByCopyGeometry(GeometryArray ga) { + super(ga, 0, ga.getVertexCount()) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + int r = meshBuffer.getMeshReference(vi.pi) ; + + if ((r == meshBuffer.NOT_FOUND) || + (vertexNormals && noMeshNormalSubstitution && + (vi.ni != meshBuffer.getNormalIndex(r)))) { + + Point3f p = positions[vi.pi] ; + Vector3f n = vertexNormals? normals[vi.ni] : null ; + Object c = vertexColor3? (Object)colors3[vi.ci] : + vertexColor4? (Object)colors4[vi.ci] : null ; + + addVertex(p, n, c, stripFlag, MESH_PUSH) ; + meshBuffer.push(vi.pi, vi.ci, vi.ni) ; + } + else { + if (vertexNormals && !noMeshNormalSubstitution && + vi.ni != meshBuffer.getNormalIndex(r)) + addNormal(normals[vi.ni]) ; + + if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r)) + addColor(colors3[vi.ci]) ; + + else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r)) + addColor(colors4[vi.ci]) ; + + addMeshReference(stripFlag, r) ; + } + } + } + + // + // NOTE: For now, copies are made of all GeometryArray vertex components + // even when by-reference access is available. + // + private static class VertexCopy { + Object c = null ; + Point3f p = null ; + Vector3f n = null ; + Color3f c3 = null ; + Color4f c4 = null ; + } + + private void processVertexCopy(VertexCopy vc, int stripFlag) { + int r = meshBuffer.getMeshReference(vc.p) ; + + if ((r == meshBuffer.NOT_FOUND) || + (vertexNormals && noMeshNormalSubstitution && + (! vc.n.equals(meshBuffer.getNormal(r))))) { + + addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ; + meshBuffer.push(vc.p, vc.c, vc.n) ; + } + else { + if (vertexNormals && !noMeshNormalSubstitution && + (! vc.n.equals(meshBuffer.getNormal(r)))) + addNormal(vc.n) ; + + if (vertexColor3 && (! vc.c3.equals(meshBuffer.getColor3(r)))) + addColor(vc.c3) ; + + else if (vertexColor4 && (! vc.c4.equals(meshBuffer.getColor4(r)))) + addColor(vc.c4) ; + + addMeshReference(stripFlag, r) ; + } + } + + private void processIndexedVertexCopy(VertexCopy vc, + VertexIndices vi, + int stripFlag) { + + int r = meshBuffer.getMeshReference(vi.pi) ; + + if ((r == meshBuffer.NOT_FOUND) || + (vertexNormals && noMeshNormalSubstitution && + (vi.ni != meshBuffer.getNormalIndex(r)))) { + + addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ; + meshBuffer.push(vi.pi, vi.ci, vi.ni) ; + } + else { + if (vertexNormals && !noMeshNormalSubstitution && + vi.ni != meshBuffer.getNormalIndex(r)) + addNormal(vc.n) ; + + if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r)) + addColor(vc.c3) ; + + else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r)) + addColor(vc.c4) ; + + addMeshReference(stripFlag, r) ; + } + } + + /** + * This abstract class implements the GeometryAccessor interface for + * concrete subclasses which handle float and NIO interleaved geometry + * arrays. + */ + private abstract class InterleavedGeometry implements GeometryAccessor { + VertexCopy vc = new VertexCopy() ; + + int vstride = 0 ; + int coffset = 0 ; + int noffset = 0 ; + int poffset = 0 ; + int tstride = 0 ; + int tcount = 0 ; + + InterleavedGeometry(GeometryArray ga) { + if (vertexTextures) { + if (vertexTexture2) tstride = 2 ; + else if (vertexTexture3) tstride = 3 ; + else if (vertexTexture4) tstride = 4 ; + + tcount = ga.getTexCoordSetCount() ; + vstride += tcount * tstride ; + } + + if (vertexColors) { + coffset = vstride ; + if (vertexColor3) vstride += 3 ; + else vstride += 4 ; + } + + if (vertexNormals) { + noffset = vstride ; + vstride += 3 ; + } + + poffset = vstride ; + vstride += 3 ; + } + + abstract void copyVertex(int pi, int ni, int ci, VertexCopy vc) ; + + public void processVertex(int v, int stripFlag) { + copyVertex(v, v, v, vc) ; + processVertexCopy(vc, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for float + * interleaved geometry arrays. + */ + private class InterleavedGeometryFloat extends InterleavedGeometry { + float[] vdata = null ; + + InterleavedGeometryFloat(GeometryArray ga) { + super(ga) ; + vdata = ga.getInterleavedVertices() ; + } + + void copyVertex(int pi, int ni, int ci, VertexCopy vc) { + int voffset ; + voffset = pi * vstride ; + vc.p = new Point3f(vdata[voffset + poffset + 0], + vdata[voffset + poffset + 1], + vdata[voffset + poffset + 2]) ; + + if (vertexNormals) { + voffset = ni * vstride ; + vc.n = new Vector3f(vdata[voffset + noffset + 0], + vdata[voffset + noffset + 1], + vdata[voffset + noffset + 2]) ; + } + if (vertexColor3) { + voffset = ci * vstride ; + vc.c3 = new Color3f(vdata[voffset + coffset + 0], + vdata[voffset + coffset + 1], + vdata[voffset + coffset + 2]) ; + vc.c = vc.c3 ; + } + else if (vertexColor4) { + voffset = ci * vstride ; + vc.c4 = new Color4f(vdata[voffset + coffset + 0], + vdata[voffset + coffset + 1], + vdata[voffset + coffset + 2], + vdata[voffset + coffset + 3]) ; + vc.c = vc.c4 ; + } + } + } + + /** + * This class implements the GeometryAccessor interface for indexed + * interleaved geometry arrays. + */ + private class IndexedInterleavedGeometryFloat + extends InterleavedGeometryFloat { + + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedInterleavedGeometryFloat(GeometryArray ga) { + super(ga) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + copyVertex(vi.pi, vi.ni, vi.ci, vc) ; + processIndexedVertexCopy(vc, vi, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for + * interleaved NIO geometry arrays. + */ + private class InterleavedGeometryNIO extends InterleavedGeometry { + FloatBufferWrapper fbw = null ; + + InterleavedGeometryNIO(GeometryArray ga) { + super(ga) ; + J3DBuffer buffer = ga.getInterleavedVertexBuffer() ; + if (BufferWrapper.getBufferType(buffer) == + BufferWrapper.TYPE_FLOAT) { + fbw = new FloatBufferWrapper(buffer) ; + } + else { + throw new IllegalArgumentException + ("\ninterleaved vertex buffer must be FloatBuffer") ; + } + } + + void copyVertex(int pi, int ni, int ci, VertexCopy vc) { + int voffset ; + voffset = pi * vstride ; + vc.p = new Point3f(fbw.get(voffset + poffset + 0), + fbw.get(voffset + poffset + 1), + fbw.get(voffset + poffset + 2)) ; + + if (vertexNormals) { + voffset = ni * vstride ; + vc.n = new Vector3f(fbw.get(voffset + noffset + 0), + fbw.get(voffset + noffset + 1), + fbw.get(voffset + noffset + 2)) ; + } + if (vertexColor3) { + voffset = ci * vstride ; + vc.c3 = new Color3f(fbw.get(voffset + coffset + 0), + fbw.get(voffset + coffset + 1), + fbw.get(voffset + coffset + 2)) ; + vc.c = vc.c3 ; + } + else if (vertexColor4) { + voffset = ci * vstride ; + vc.c4 = new Color4f(fbw.get(voffset + coffset + 0), + fbw.get(voffset + coffset + 1), + fbw.get(voffset + coffset + 2), + fbw.get(voffset + coffset + 3)) ; + vc.c = vc.c4 ; + } + } + } + + /** + * This class implements the GeometryAccessor interface for indexed + * interleaved NIO geometry arrays. + */ + private class IndexedInterleavedGeometryNIO extends InterleavedGeometryNIO { + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedInterleavedGeometryNIO(GeometryArray ga) { + super(ga) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + copyVertex(vi.pi, vi.ni, vi.ci, vc) ; + processIndexedVertexCopy(vc, vi, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for + * non-interleaved geometry arrays accessed with by-reference semantics. + */ + private class ByRefGeometry implements GeometryAccessor { + VertexCopy vc = new VertexCopy() ; + + byte[] colorsB = null ; + float[] colorsF = null ; + float[] normals = null ; + float[] positionsF = null ; + double[] positionsD = null ; + + int initialPositionIndex = 0 ; + int initialNormalIndex = 0 ; + int initialColorIndex = 0 ; + + ByRefGeometry(GeometryArray ga) { + positionsF = ga.getCoordRefFloat() ; + if (debug && positionsF != null) + System.out.println("float positions") ; + + positionsD = ga.getCoordRefDouble() ; + if (debug && positionsD != null) + System.out.println("double positions") ; + + if (positionsF == null && positionsD == null) + throw new UnsupportedOperationException + ("\nby-reference access to Point3{d,f} arrays") ; + + initialPositionIndex = ga.getInitialCoordIndex() ; + + if (vertexColors) { + colorsB = ga.getColorRefByte() ; + if (debug && colorsB != null) + System.out.println("byte colors") ; + + colorsF = ga.getColorRefFloat() ; + if (debug && colorsF != null) + System.out.println("float colors") ; + + if (colorsB == null && colorsF == null) + throw new UnsupportedOperationException + ("\nby-reference access to Color{3b,3f,4b,4f} arrays") ; + + initialColorIndex = ga.getInitialColorIndex() ; + } + + if (vertexNormals) { + normals = ga.getNormalRefFloat() ; + if (debug && normals != null) + System.out.println("float normals") ; + + if (normals == null) + throw new UnsupportedOperationException + ("\nby-reference access to Normal3f array") ; + + initialNormalIndex = ga.getInitialNormalIndex() ; + } + } + + void copyVertex(int pi, int ni, int ci, VertexCopy vc) { + pi *= 3 ; + if (positionsF != null) { + vc.p = new Point3f(positionsF[pi + 0], + positionsF[pi + 1], + positionsF[pi + 2]) ; + } + else { + vc.p = new Point3f((float)positionsD[pi + 0], + (float)positionsD[pi + 1], + (float)positionsD[pi + 2]) ; + } + + ni *= 3 ; + if (vertexNormals) { + vc.n = new Vector3f(normals[ni + 0], + normals[ni + 1], + normals[ni + 2]) ; + } + + if (vertexColor3) { + ci *= 3 ; + if (colorsB != null) { + vc.c3 = new Color3f + ((colorsB[ci + 0] & 0xff) * ByteToFloatScale, + (colorsB[ci + 1] & 0xff) * ByteToFloatScale, + (colorsB[ci + 2] & 0xff) * ByteToFloatScale) ; + } + else { + vc.c3 = new Color3f(colorsF[ci + 0], + colorsF[ci + 1], + colorsF[ci + 2]) ; + } + vc.c = vc.c3 ; + } + else if (vertexColor4) { + ci *= 4 ; + if (colorsB != null) { + vc.c4 = new Color4f + ((colorsB[ci + 0] & 0xff) * ByteToFloatScale, + (colorsB[ci + 1] & 0xff) * ByteToFloatScale, + (colorsB[ci + 2] & 0xff) * ByteToFloatScale, + (colorsB[ci + 3] & 0xff) * ByteToFloatScale) ; + } + else { + vc.c4 = new Color4f(colorsF[ci + 0], + colorsF[ci + 1], + colorsF[ci + 2], + colorsF[ci + 3]) ; + } + vc.c = vc.c4 ; + } + } + + public void processVertex(int v, int stripFlag) { + copyVertex(v + initialPositionIndex, + v + initialNormalIndex, + v + initialColorIndex, vc) ; + + processVertexCopy(vc, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for indexed + * non-interleaved geometry arrays accessed with by-reference semantics. + */ + private class IndexedByRefGeometry extends ByRefGeometry { + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedByRefGeometry(GeometryArray ga) { + super(ga) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + copyVertex(vi.pi, vi.ni, vi.ci, vc) ; + processIndexedVertexCopy(vc, vi, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for + * non-interleaved geometry arrays accessed with NIO. + */ + private class ByRefGeometryNIO implements GeometryAccessor { + VertexCopy vc = new VertexCopy() ; + + ByteBufferWrapper colorsB = null ; + FloatBufferWrapper colorsF = null ; + FloatBufferWrapper normals = null ; + FloatBufferWrapper positionsF = null ; + DoubleBufferWrapper positionsD = null ; + + int initialPositionIndex = 0 ; + int initialNormalIndex = 0 ; + int initialColorIndex = 0 ; + + ByRefGeometryNIO(GeometryArray ga) { + J3DBuffer buffer ; + buffer = ga.getCoordRefBuffer() ; + initialPositionIndex = ga.getInitialCoordIndex() ; + + switch (BufferWrapper.getBufferType(buffer)) { + case BufferWrapper.TYPE_FLOAT: + positionsF = new FloatBufferWrapper(buffer) ; + if (debug) System.out.println("float positions buffer") ; + break ; + case BufferWrapper.TYPE_DOUBLE: + positionsD = new DoubleBufferWrapper(buffer) ; + if (debug) System.out.println("double positions buffer") ; + break ; + default: + throw new IllegalArgumentException + ("\nposition buffer must be FloatBuffer or DoubleBuffer") ; + } + + if (vertexColors) { + buffer = ga.getColorRefBuffer() ; + initialColorIndex = ga.getInitialColorIndex() ; + + switch (BufferWrapper.getBufferType(buffer)) { + case BufferWrapper.TYPE_BYTE: + colorsB = new ByteBufferWrapper(buffer) ; + if (debug) System.out.println("byte colors buffer") ; + break ; + case BufferWrapper.TYPE_FLOAT: + colorsF = new FloatBufferWrapper(buffer) ; + if (debug) System.out.println("float colors buffer") ; + break ; + default: + throw new IllegalArgumentException + ("\ncolor buffer must be ByteBuffer or FloatBuffer") ; + } + } + + if (vertexNormals) { + buffer = ga.getNormalRefBuffer() ; + initialNormalIndex = ga.getInitialNormalIndex() ; + + switch (BufferWrapper.getBufferType(buffer)) { + case BufferWrapper.TYPE_FLOAT: + normals = new FloatBufferWrapper(buffer) ; + if (debug) System.out.println("float normals buffer") ; + break ; + default: + throw new IllegalArgumentException + ("\nnormal buffer must be FloatBuffer") ; + } + } + } + + void copyVertex(int pi, int ni, int ci, VertexCopy vc) { + pi *= 3 ; + if (positionsF != null) { + vc.p = new Point3f(positionsF.get(pi + 0), + positionsF.get(pi + 1), + positionsF.get(pi + 2)) ; + } + else { + vc.p = new Point3f((float)positionsD.get(pi + 0), + (float)positionsD.get(pi + 1), + (float)positionsD.get(pi + 2)) ; + } + + ni *= 3 ; + if (vertexNormals) { + vc.n = new Vector3f(normals.get(ni + 0), + normals.get(ni + 1), + normals.get(ni + 2)) ; + } + + if (vertexColor3) { + ci *= 3 ; + if (colorsB != null) { + vc.c3 = new Color3f + ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale) ; + } + else { + vc.c3 = new Color3f(colorsF.get(ci + 0), + colorsF.get(ci + 1), + colorsF.get(ci + 2)) ; + } + vc.c = vc.c3 ; + } + else if (vertexColor4) { + ci *= 4 ; + if (colorsB != null) { + vc.c4 = new Color4f + ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale, + (colorsB.get(ci + 3) & 0xff) * ByteToFloatScale) ; + } + else { + vc.c4 = new Color4f(colorsF.get(ci + 0), + colorsF.get(ci + 1), + colorsF.get(ci + 2), + colorsF.get(ci + 3)) ; + } + vc.c = vc.c4 ; + } + } + + public void processVertex(int v, int stripFlag) { + copyVertex(v + initialPositionIndex, + v + initialNormalIndex, + v + initialColorIndex, vc) ; + + processVertexCopy(vc, stripFlag) ; + } + } + + /** + * This class implements the GeometryAccessor interface for + * non-interleaved indexed geometry arrays accessed with NIO. + */ + private class IndexedByRefGeometryNIO extends ByRefGeometryNIO { + IndexArrays ia = new IndexArrays() ; + VertexIndices vi = new VertexIndices() ; + + IndexedByRefGeometryNIO(GeometryArray ga) { + super(ga) ; + getIndexArrays(ga, ia) ; + } + + public void processVertex(int v, int stripFlag) { + getVertexIndices(v, ia, vi) ; + copyVertex(vi.pi, vi.ni, vi.ci, vc) ; + processIndexedVertexCopy(vc, vi, stripFlag) ; + } + } + + /** + * Convert a GeometryArray to compression stream elements and add them to + * this stream. + * + * @param ga GeometryArray to convert + * @exception IllegalArgumentException if GeometryArray has a + * dimensionality or vertex format inconsistent with the CompressionStream + */ + void addGeometryArray(GeometryArray ga) { + int firstVertex = 0 ; + int validVertexCount = 0 ; + int vertexFormat = ga.getVertexFormat() ; + GeometryAccessor geometryAccessor = null ; + + if (streamType != getStreamType(ga)) + throw new IllegalArgumentException + ("GeometryArray has inconsistent dimensionality") ; + + if (vertexComponents != getVertexComponents(vertexFormat)) + throw new IllegalArgumentException + ("GeometryArray has inconsistent vertex components") ; + + // Set up for vertex data access semantics. + boolean NIO = (vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 ; + boolean byRef = (vertexFormat & GeometryArray.BY_REFERENCE) != 0 ; + boolean interleaved = (vertexFormat & GeometryArray.INTERLEAVED) != 0 ; + boolean indexedGeometry = ga instanceof IndexedGeometryArray ; + + if (indexedGeometry) { + if (debug) System.out.println("indexed") ; + // Index arrays will be copied such that valid indices start at + // offset 0 in the copied arrays. + firstVertex = 0 ; + validVertexCount = ((IndexedGeometryArray)ga).getValidIndexCount() ; + } + + if (!byRef) { + if (debug) System.out.println("by-copy") ; + if (indexedGeometry) { + geometryAccessor = new IndexedByCopyGeometry(ga) ; + } + else { + firstVertex = 0 ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new ByCopyGeometry(ga) ; + } + } + else if (interleaved && NIO) { + if (debug) System.out.println("interleaved NIO") ; + if (indexedGeometry) { + geometryAccessor = new IndexedInterleavedGeometryNIO(ga) ; + } + else { + firstVertex = ga.getInitialVertexIndex() ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new InterleavedGeometryNIO(ga) ; + } + } + else if (interleaved && !NIO) { + if (debug) System.out.println("interleaved") ; + if (indexedGeometry) { + geometryAccessor = new IndexedInterleavedGeometryFloat(ga) ; + } + else { + firstVertex = ga.getInitialVertexIndex() ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new InterleavedGeometryFloat(ga) ; + } + } + else if (!interleaved && NIO) { + if (debug) System.out.println("non-interleaved NIO") ; + if (indexedGeometry) { + geometryAccessor = new IndexedByRefGeometryNIO(ga) ; + } + else { + firstVertex = 0 ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new ByRefGeometryNIO(ga) ; + } + } + else if (!interleaved && !NIO) { + if (debug) System.out.println("non-interleaved by-ref") ; + if (indexedGeometry) { + geometryAccessor = new IndexedByRefGeometry(ga) ; + } + else { + firstVertex = 0 ; + validVertexCount = ga.getValidVertexCount() ; + geometryAccessor = new ByRefGeometry(ga) ; + } + } + + // Set up for topology. + int stripCount = 0 ; + int stripCounts[] = null ; + int constantStripLength = 0 ; + int replaceCode = RESTART ; + boolean strips = false ; + boolean implicitStrips = false ; + + if (ga instanceof TriangleStripArray || + ga instanceof IndexedTriangleStripArray || + ga instanceof LineStripArray || + ga instanceof IndexedLineStripArray) { + + strips = true ; + replaceCode = REPLACE_OLDEST ; + if (debug) System.out.println("strips") ; + } + else if (ga instanceof TriangleFanArray || + ga instanceof IndexedTriangleFanArray) { + + strips = true ; + replaceCode = REPLACE_MIDDLE ; + if (debug) System.out.println("fans") ; + } + else if (ga instanceof QuadArray || + ga instanceof IndexedQuadArray) { + + // Handled as fan arrays with 4 vertices per fan. + implicitStrips = true ; + constantStripLength = 4 ; + replaceCode = REPLACE_MIDDLE ; + if (debug) System.out.println("quads") ; + } + + // Get strip counts. + if (strips) { + if (indexedGeometry) { + IndexedGeometryStripArray igsa ; + igsa = (IndexedGeometryStripArray)ga ; + + stripCount = igsa.getNumStrips() ; + stripCounts = new int[stripCount] ; + igsa.getStripIndexCounts(stripCounts) ; + + } else { + GeometryStripArray gsa ; + gsa = (GeometryStripArray)ga ; + + stripCount = gsa.getNumStrips() ; + stripCounts = new int[stripCount] ; + gsa.getStripVertexCounts(stripCounts) ; + } + } + + // Build the compression stream for this shape's geometry. + int v = firstVertex ; + if (strips) { + for (int i = 0 ; i < stripCount ; i++) { + geometryAccessor.processVertex(v++, RESTART) ; + for (int j = 1 ; j < stripCounts[i] ; j++) { + geometryAccessor.processVertex(v++, replaceCode) ; + } + } + } + else if (implicitStrips) { + while (v < firstVertex + validVertexCount) { + geometryAccessor.processVertex(v++, RESTART) ; + for (int j = 1 ; j < constantStripLength ; j++) { + geometryAccessor.processVertex(v++, replaceCode) ; + } + } + } + else { + while (v < firstVertex + validVertexCount) { + geometryAccessor.processVertex(v++, RESTART) ; + } + } + } + + /** + * Print the stream to standard output. + */ + void print() { + System.out.println("\nstream has " + stream.size() + " entries") ; + System.out.println("uncompressed size " + byteCount + " bytes") ; + System.out.println("upper position bound: " + mcBounds[1].toString()) ; + System.out.println("lower position bound: " + mcBounds[0].toString()) ; + System.out.println("X, Y, Z centers (" + + ((float)center[0]) + " " + + ((float)center[1]) + " " + + ((float)center[2]) + ")\n" + + "scale " + ((float)scale) + "\n") ; + + Iterator i = stream.iterator() ; + while (i.hasNext()) { + System.out.println(i.next().toString() + "\n") ; + } + } + + + //////////////////////////////////////////////////////////////////////////// + // // + // The following constructors and methods are currently the only public // + // members of this class. All other members are subject to revision. // + // // + //////////////////////////////////////////////////////////////////////////// + + /** + * Creates a CompressionStream from an array of Shape3D scene graph + * objects. These Shape3D objects may only consist of a GeometryArray + * component and an optional Appearance component. The resulting stream + * may be used as input to the GeometryCompressor methods.

+ * + * Each Shape3D in the array must be of the same dimensionality (point, + * line, or surface) and have the same vertex format as the others. + * Texture coordinates are ignored.

+ * + * If a color is specified in the material attributes for a Shape3D then + * that color is added to the CompressionStream as the current global + * color. Subsequent colors as well as any colors bundled with vertices + * will override it. Only the material diffuse colors are used; all other + * appearance attributes are ignored.

+ * + * @param positionQuant + * number of bits to quantize each position's X, Y, + * and Z components, ranging from 1 to 16 + * + * @param colorQuant + * number of bits to quantize each color's R, G, B, and + * alpha components, ranging from 2 to 16 + * + * @param normalQuant + * number of bits for quantizing each normal's U and V components, ranging + * from 0 to 6 + * + * @param shapes + * an array of Shape3D scene graph objects containing + * GeometryArray objects, all with the same vertex format and + * dimensionality + * + * @exception IllegalArgumentException if any Shape3D has an inconsistent + * dimensionality or vertex format, or if any Shape3D contains a geometry + * component that is not a GeometryArray + * + * @see Shape3D + * @see GeometryArray + * @see GeometryCompressor + */ + public CompressionStream(int positionQuant, int colorQuant, + int normalQuant, Shape3D shapes[]) { + this() ; + if (debug) System.out.println("CompressionStream(Shape3D[]):") ; + + if (shapes == null) + throw new IllegalArgumentException("null Shape3D array") ; + + if (shapes.length == 0) + throw new IllegalArgumentException("zero-length Shape3D array") ; + + if (shapes[0] == null) + throw new IllegalArgumentException("Shape3D at index 0 is null") ; + + long startTime = 0 ; + if (benchmark) startTime = System.currentTimeMillis() ; + + Geometry g = shapes[0].getGeometry() ; + if (! (g instanceof GeometryArray)) + throw new IllegalArgumentException + ("Shape3D at index 0 is not a GeometryArray") ; + + GeometryArray ga = (GeometryArray)g ; + this.streamType = getStreamType(ga) ; + this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ; + + // Add global quantization parameters to the start of the stream. + addPositionQuantization(positionQuant) ; + addColorQuantization(colorQuant) ; + addNormalQuantization(normalQuant) ; + + // Loop through all shapes. + for (int s = 0 ; s < shapes.length ; s++) { + if (debug) System.out.println("\nShape3D " + s + ":") ; + + g = shapes[s].getGeometry() ; + if (! (g instanceof GeometryArray)) + throw new IllegalArgumentException + ("Shape3D at index " + s + " is not a GeometryArray") ; + + // Check for material color and add it to the stream if it exists. + Appearance a = shapes[s].getAppearance() ; + if (a != null) { + Material m = a.getMaterial() ; + if (m != null) { + m.getDiffuseColor(c3f) ; + if (vertexColor4) { + c4f.set(c3f.x, c3f.y, c3f.z, 1.0f) ; + addColor(c4f) ; + } else + addColor(c3f) ; + } + } + + // Add the geometry array to the stream. + addGeometryArray((GeometryArray)g) ; + } + + if (benchmark) { + long t = System.currentTimeMillis() - startTime ; + System.out.println + ("\nCompressionStream:\n" + shapes.length + " shapes in " + + (t / 1000f) + " sec") ; + } + } + + /** + * Creates a CompressionStream from an array of Shape3D scene graph + * objects. These Shape3D objects may only consist of a GeometryArray + * component and an optional Appearance component. The resulting stream + * may be used as input to the GeometryCompressor methods.

+ * + * Each Shape3D in the array must be of the same dimensionality (point, + * line, or surface) and have the same vertex format as the others. + * Texture coordinates are ignored.

+ * + * If a color is specified in the material attributes for a Shape3D then + * that color is added to the CompressionStream as the current global + * color. Subsequent colors as well as any colors bundled with vertices + * will override it. Only the material diffuse colors are used; all other + * appearance attributes are ignored.

+ * + * Defaults of 16, 9, and 6 bits are used as the quantization values for + * positions, colors, and normals respectively. These are the maximum + * resolution values defined for positions and normals; the default of 9 + * for color is the equivalent of the 8 bits of RGBA component resolution + * commonly available in graphics frame buffers.

+ * + * @param shapes + * an array of Shape3D scene graph objects containing + * GeometryArray objects, all with the same vertex format and + * dimensionality. + * + * @exception IllegalArgumentException if any Shape3D has an inconsistent + * dimensionality or vertex format, or if any Shape3D contains a geometry + * component that is not a GeometryArray + * + * @see Shape3D + * @see GeometryArray + * @see GeometryCompressor + */ + public CompressionStream(Shape3D shapes[]) { + this(16, 9, 6, shapes) ; + } + + /** + * Creates a CompressionStream from an array of GeometryInfo objects. The + * resulting stream may be used as input to the GeometryCompressor + * methods.

+ * + * Each GeometryInfo in the array must be of the same dimensionality + * (point, line, or surface) and have the same vertex format as the + * others. Texture coordinates are ignored.

+ * + * @param positionQuant + * number of bits to quantize each position's X, Y, + * and Z components, ranging from 1 to 16 + * + * @param colorQuant + * number of bits to quantize each color's R, G, B, and + * alpha components, ranging from 2 to 16 + * + * @param normalQuant + * number of bits for quantizing each normal's U and V components, ranging + * from 0 to 6 + * + * @param geometry + * an array of GeometryInfo objects, all with the same + * vertex format and dimensionality + * + * @exception IllegalArgumentException if any GeometryInfo object has an + * inconsistent dimensionality or vertex format + * + * @see GeometryInfo + * @see GeometryCompressor + */ + public CompressionStream(int positionQuant, int colorQuant, + int normalQuant, GeometryInfo geometry[]) { + this() ; + if (debug) System.out.println("CompressionStream(GeometryInfo[])") ; + + if (geometry == null) + throw new IllegalArgumentException("null GeometryInfo array") ; + + if (geometry.length == 0) + throw new IllegalArgumentException + ("zero-length GeometryInfo array") ; + + if (geometry[0] == null) + throw new IllegalArgumentException + ("GeometryInfo at index 0 is null") ; + + long startTime = 0 ; + if (benchmark) startTime = System.currentTimeMillis() ; + + GeometryArray ga = geometry[0].getGeometryArray() ; + this.streamType = getStreamType(ga) ; + this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ; + + // Add global quantization parameters to the start of the stream. + addPositionQuantization(positionQuant) ; + addColorQuantization(colorQuant) ; + addNormalQuantization(normalQuant) ; + + // Loop through all GeometryInfo objects and add them to the stream. + for (int i = 0 ; i < geometry.length ; i++) { + if (debug) System.out.println("\nGeometryInfo " + i + ":") ; + addGeometryArray(geometry[i].getGeometryArray()) ; + } + + if (benchmark) { + long t = System.currentTimeMillis() - startTime ; + System.out.println + ("\nCompressionStream:\n" + geometry.length + + " GeometryInfo objects in " + (t / 1000f) + " sec") ; + } + } + + /** + * Creates a CompressionStream from an array of GeometryInfo objects. The + * resulting stream may be used as input to the GeometryCompressor + * methods.

+ * + * Each GeometryInfo in the array must be of the same dimensionality + * (point, line, or surface) and have the same vertex format as the + * others. Texture coordinates are ignored.

+ * + * Defaults of 16, 9, and 6 bits are used as the quantization values for + * positions, colors, and normals respectively. These are the maximum + * resolution values defined for positions and normals; the default of 9 + * for color is the equivalent of the 8 bits of RGBA component resolution + * commonly available in graphics frame buffers.

+ * + * @param geometry + * an array of GeometryInfo objects, all with the same + * vertex format and dimensionality + * + * @exception IllegalArgumentException if any GeometryInfo object has an + * inconsistent dimensionality or vertex format + * + * @see GeometryInfo + * @see GeometryCompressor + */ + public CompressionStream(GeometryInfo geometry[]) { + this(16, 9, 6, geometry) ; + } + + /** + * Get the original bounds of the coordinate data, in modeling coordinates. + * Coordinate data is positioned and scaled to a normalized cube after + * compression. + * + * @return Point3d array of length 2, where the 1st Point3d is the lower + * bounds and the 2nd Point3d is the upper bounds. + * @since Java 3D 1.3 + */ + public Point3d[] getModelBounds() { + Point3d[] bounds = new Point3d[2] ; + bounds[0] = new Point3d(mcBounds[0]) ; + bounds[1] = new Point3d(mcBounds[1]) ; + return bounds ; + } + + /** + * Get the bounds of the compressed object in normalized coordinates. + * These have an maximum bounds by [-1.0 .. +1.0] across each axis. + * + * @return Point3d array of length 2, where the 1st Point3d is the lower + * bounds and the 2nd Point3d is the upper bounds. + * @since Java 3D 1.3 + */ + public Point3d[] getNormalizedBounds() { + Point3d[] bounds = new Point3d[2] ; + bounds[0] = new Point3d(ncBounds[0]) ; + bounds[1] = new Point3d(ncBounds[1]) ; + return bounds ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamColor.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamColor.java new file mode 100644 index 0000000..c54568e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamColor.java @@ -0,0 +1,272 @@ +/* + * $RCSfile: CompressionStreamColor.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; + +/** + * This class represents a color in a compression stream. It maintains both + * floating-point and quantized representations. This color may be bundled + * with a vertex or exist separately as a global color. + */ +class CompressionStreamColor extends CompressionStreamElement { + private int R, G, B, A ; + private boolean color3 ; + private boolean color4 ; + private float colorR, colorG, colorB, colorA ; + + int rAbsolute, gAbsolute, bAbsolute, aAbsolute ; + + /** + * Create a CompressionStreamColor. + * + * @param stream CompressionStream associated with this element + * @param color3 floating-point representation to be encoded + */ + CompressionStreamColor(CompressionStream stream, Color3f c3) { + this.color4 = false ; + this.color3 = true ; + colorR = c3.x ; + colorG = c3.y ; + colorB = c3.z ; + colorA = 0.0f ; + stream.byteCount += 12 ; + } + + /** + * Create a CompressionStreamColor. + * + * @param stream CompressionStream associated with this element + * @param color4 floating-point representation to be encoded + */ + CompressionStreamColor(CompressionStream stream, Color4f c4) { + this.color3 = false ; + this.color4 = true ; + colorR = c4.x ; + colorG = c4.y ; + colorB = c4.z ; + colorA = c4.w ; + stream.byteCount += 16 ; + } + + /** + * Quantize a floating point color to fixed point integer components of + * the specified number of bits. The bit length can range from a maximum + * of 16 to a minimum of 2 bits since negative colors are not defined.

+ * + * The bit length is the total number of bits in the signed version of the + * fixed point representation of the input color, which is assumed to + * be normalized into the [0..1) range. With the maximum bit length of + * 16, 15 bits of positive colors can be represented; a bit length of 9 is + * needed to get the 8 bit positive color size in common use.

+ * + * @param stream CompressionStream associated with this element + * @param table HuffmanTable for collecting data about the quantized + * representation of this element + */ + void quantize(CompressionStream stream, HuffmanTable huffmanTable) { + // Clamp quantization. + int quant = + (stream.colorQuant < 2? 2 : + (stream.colorQuant > 16? 16 : stream.colorQuant)) ; + + absolute = false ; + if (stream.firstColor || stream.colorQuantChanged) { + absolute = true ; + stream.lastColor[0] = 0 ; + stream.lastColor[1] = 0 ; + stream.lastColor[2] = 0 ; + stream.lastColor[3] = 0 ; + stream.firstColor = false ; + stream.colorQuantChanged = false ; + } + + // Convert the floating point position to s.15 2's complement. + if (color3) { + R = (int)(colorR * 32768.0) ; + G = (int)(colorG * 32768.0) ; + B = (int)(colorB * 32768.0) ; + A = 0 ; + } else if (color4) { + R = (int)(colorR * 32768.0) ; + G = (int)(colorG * 32768.0) ; + B = (int)(colorB * 32768.0) ; + A = (int)(colorA * 32768.0) ; + } + + // Clamp color components. + R = (R > 32767? 32767: (R < 0? 0: R)) ; + G = (G > 32767? 32767: (G < 0? 0: G)) ; + B = (B > 32767? 32767: (B < 0? 0: B)) ; + A = (A > 32767? 32767: (A < 0? 0: A)) ; + + // Compute quantized values. + R &= quantizationMask[quant] ; + G &= quantizationMask[quant] ; + B &= quantizationMask[quant] ; + A &= quantizationMask[quant] ; + + // Copy and retain absolute color for mesh buffer lookup. + rAbsolute = R ; + gAbsolute = G ; + bAbsolute = B ; + aAbsolute = A ; + + // Compute deltas. + R -= stream.lastColor[0] ; + G -= stream.lastColor[1] ; + B -= stream.lastColor[2] ; + A -= stream.lastColor[3] ; + + // Update last values. + stream.lastColor[0] += R ; + stream.lastColor[1] += G ; + stream.lastColor[2] += B ; + stream.lastColor[3] += A ; + + // Compute length and shift common to all components. + if (color3) + computeLengthShift(R, G, B) ; + + else if (color4) + computeLengthShift(R, G, B, A) ; + + // 0-length components are allowed only for normals. + if (length == 0) + length = 1 ; + + // Add this element to the Huffman table associated with this stream. + huffmanTable.addColorEntry(length, shift, absolute) ; + } + + /** + * Output a setColor command. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputCommand(HuffmanTable table, CommandStream output) { + outputColor(table, output, CommandStream.SET_COLOR, 8) ; + } + + /** + * Output a color subcommand. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputSubcommand(HuffmanTable table, CommandStream output) { + + outputColor(table, output, 0, 6) ; + } + + // + // Output the final compressed bits to the output command stream. + // + private void outputColor(HuffmanTable table, CommandStream output, + int header, int headerLength) { + HuffmanNode t ; + + // Look up the Huffman token for this compression stream element. + t = table.getColorEntry(length, shift, absolute) ; + + // Construct the color subcommand components. The maximum length of a + // color subcommand is 70 bits (a tag with a length of 6 followed by 4 + // components of 16 bits each). The subcommand is therefore + // constructed initially using just the first 3 components, with the + // 4th component added later after the tag has been shifted into the + // subcommand header. + int componentLength = t.dataLength - t.shift ; + int subcommandLength = t.tagLength + (3 * componentLength) ; + + R = (R >> t.shift) & (int)lengthMask[componentLength] ; + G = (G >> t.shift) & (int)lengthMask[componentLength] ; + B = (B >> t.shift) & (int)lengthMask[componentLength] ; + + long colorSubcommand = + (((long)t.tag) << (3 * componentLength)) | + (((long)R) << (2 * componentLength)) | + (((long)G) << (1 * componentLength)) | + (((long)B) << (0 * componentLength)) ; + + if (subcommandLength < 6) { + // The header will have some empty bits. The Huffman tag + // computation will prevent this if necessary. + header |= (int)(colorSubcommand << (6 - subcommandLength)) ; + subcommandLength = 0 ; + } + else { + // Move the 1st 6 bits of the subcommand into the header. + header |= (int)(colorSubcommand >>> (subcommandLength - 6)) ; + subcommandLength -= 6 ; + } + + // Add alpha if present. + if (color4) { + A = (A >> t.shift) & (int)lengthMask[componentLength] ; + colorSubcommand = (colorSubcommand << componentLength) | A ; + subcommandLength += componentLength ; + } + + // Add the header and body to the output buffer. + output.addCommand(header, headerLength, + colorSubcommand, subcommandLength) ; + } + + public String toString() { + String d = absolute? "" : "delta " ; + String c = (colorR + " " + colorG + " " + colorB + + (color4? (" " + colorA): "")) ; + + return + "color: " + c + "\n" + + " fixed point " + d + + R + " " + G + " " + B + "\n" + + " length " + length + " shift " + shift + + (absolute? " absolute" : " relative") ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamElement.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamElement.java new file mode 100644 index 0000000..ad78595 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamElement.java @@ -0,0 +1,359 @@ +/* + * $RCSfile: CompressionStreamElement.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +/** + * Instances of this class are used as elements in a CompressionStream. + * @see CompressionStream + */ +abstract class CompressionStreamElement { + /** + * Bit length of quantized geometric components. + */ + int length ; + + /** + * Number of trailing zeros in quantized geometric components. + */ + int shift ; + + /** + * If false, geometric component values are represented as differences + * from those of the preceding element in the stream. + */ + boolean absolute ; + + /** + * Array with elements that can be used as masks to apply a quantization + * to the number of bits indicated by the referencing index [0..16]. + */ + static final int quantizationMask[] = { + 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, + 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, + 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, + 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, + 0xFFFFFFFF + } ; + + /** + * Array with elements that can be used as masks to retain the number of + * trailing bits of data indicated by the referencing index [0..64]. Used + * to clear the leading sign bits of fixed-point 2's complement numbers + * and in building the compressed output stream. + */ + static final long lengthMask[] = { + 0x0000000000000000L, 0x0000000000000001L, + 0x0000000000000003L, 0x0000000000000007L, + 0x000000000000000FL, 0x000000000000001FL, + 0x000000000000003FL, 0x000000000000007FL, + 0x00000000000000FFL, 0x00000000000001FFL, + 0x00000000000003FFL, 0x00000000000007FFL, + 0x0000000000000FFFL, 0x0000000000001FFFL, + 0x0000000000003FFFL, 0x0000000000007FFFL, + 0x000000000000FFFFL, 0x000000000001FFFFL, + 0x000000000003FFFFL, 0x000000000007FFFFL, + 0x00000000000FFFFFL, 0x00000000001FFFFFL, + 0x00000000003FFFFFL, 0x00000000007FFFFFL, + 0x0000000000FFFFFFL, 0x0000000001FFFFFFL, + 0x0000000003FFFFFFL, 0x0000000007FFFFFFL, + 0x000000000FFFFFFFL, 0x000000001FFFFFFFL, + 0x000000003FFFFFFFL, 0x000000007FFFFFFFL, + 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL, + 0x00000003FFFFFFFFL, 0x00000007FFFFFFFFL, + 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL, + 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL, + 0x000000FFFFFFFFFFL, 0x000001FFFFFFFFFFL, + 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL, + 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL, + 0x00003FFFFFFFFFFFL, 0x00007FFFFFFFFFFFL, + 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL, + 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL, + 0x000FFFFFFFFFFFFFL, 0x001FFFFFFFFFFFFFL, + 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL, + 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL, + 0x03FFFFFFFFFFFFFFL, 0x07FFFFFFFFFFFFFFL, + 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL, + 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL, + 0xFFFFFFFFFFFFFFFFL + } ; + + + /** + * Computes the quantized representation of this stream element. + * + * @param stream CompressionStream associated with this element + * @param table HuffmanTable for collecting data about the quantized + * representation of this element + */ + abstract void quantize(CompressionStream stream, HuffmanTable table) ; + + /** + * Outputs the compressed bits representing this stream element. + * Some instances of CompressionStreamElement don't require an + * implementation and will inherit the stub provided here. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputCommand(HuffmanTable table, CommandStream output) { + } + + /** + * Finds the minimum bits needed to represent the given 16-bit signed 2's + * complement integer. For positive integers, this include the first + * 1 starting from the left, plus a 0 sign bit; for negative integers, + * this includes the first 0 starting from the left, plus a 1 sign bit. + * 0 is a special case returning 0; however, 0-length components are valid + * ONLY for normals. + * + * The decompressor uses the data length to determine how many bits of + * sign extension to add to the data coming in from the compressed stream + * in order to create a 16-bit signed 2's complement integer. E.g., a data + * length of 12 indicates that 16-12=4 bits of sign are to be extended.

+ * + * @param number a signed 2's complement integer representable in 16 bits + * or less + * @return minimum number of bits to represent the number + */ + private static final int getLength(int number) { + if (number == 0) + return 0 ; + + else if ((number & 0x8000) > 0) { + // negative numbers + if ((number & 0x4000) == 0) return 16 ; + if ((number & 0x2000) == 0) return 15 ; + if ((number & 0x1000) == 0) return 14 ; + if ((number & 0x0800) == 0) return 13 ; + if ((number & 0x0400) == 0) return 12 ; + if ((number & 0x0200) == 0) return 11 ; + if ((number & 0x0100) == 0) return 10 ; + if ((number & 0x0080) == 0) return 9 ; + if ((number & 0x0040) == 0) return 8 ; + if ((number & 0x0020) == 0) return 7 ; + if ((number & 0x0010) == 0) return 6 ; + if ((number & 0x0008) == 0) return 5 ; + if ((number & 0x0004) == 0) return 4 ; + if ((number & 0x0002) == 0) return 3 ; + if ((number & 0x0001) == 0) return 2 ; + + return 1 ; + + } else { + // positive numbers + if ((number & 0x4000) > 0) return 16 ; + if ((number & 0x2000) > 0) return 15 ; + if ((number & 0x1000) > 0) return 14 ; + if ((number & 0x0800) > 0) return 13 ; + if ((number & 0x0400) > 0) return 12 ; + if ((number & 0x0200) > 0) return 11 ; + if ((number & 0x0100) > 0) return 10 ; + if ((number & 0x0080) > 0) return 9 ; + if ((number & 0x0040) > 0) return 8 ; + if ((number & 0x0020) > 0) return 7 ; + if ((number & 0x0010) > 0) return 6 ; + if ((number & 0x0008) > 0) return 5 ; + if ((number & 0x0004) > 0) return 4 ; + if ((number & 0x0002) > 0) return 3 ; + + return 2 ; + } + } + + /** + * Finds the rightmost 1 bit in the given 16-bit integer. This value is + * used by the decompressor to indicate the number of trailing zeros to be + * added to the end of the data coming in from the compressed stream, + * accomplished by left shifting the data by the indicated amount. + * 0 is a special case returning 0.

+ * + * @param number an integer representable in 16 bits or less + * @return number of trailing zeros + */ + private static final int getShift(int number) { + if (number == 0) return 0 ; + + if ((number & 0x0001) > 0) return 0 ; + if ((number & 0x0002) > 0) return 1 ; + if ((number & 0x0004) > 0) return 2 ; + if ((number & 0x0008) > 0) return 3 ; + if ((number & 0x0010) > 0) return 4 ; + if ((number & 0x0020) > 0) return 5 ; + if ((number & 0x0040) > 0) return 6 ; + if ((number & 0x0080) > 0) return 7 ; + if ((number & 0x0100) > 0) return 8 ; + if ((number & 0x0200) > 0) return 9 ; + if ((number & 0x0400) > 0) return 10 ; + if ((number & 0x0800) > 0) return 11 ; + if ((number & 0x1000) > 0) return 12 ; + if ((number & 0x2000) > 0) return 13 ; + if ((number & 0x4000) > 0) return 14 ; + + return 15 ; + } + + /** + * Computes common length and shift of 2 numbers. + */ + final void computeLengthShift(int n0, int n1) { + int s0 = n0 & 0x8000 ; + int s1 = n1 & 0x8000 ; + + // equal sign optimization + if (s0 == s1) + if (s0 == 0) + this.length = getLength(n0 | n1) ; + else + this.length = getLength(n0 & n1) ; + else + this.length = getMaximum(getLength(n0), getLength(n1)) ; + + this.shift = getShift(n0 | n1) ; + } + + + /** + * Computes common length and shift of 3 numbers. + */ + final void computeLengthShift(int n0, int n1, int n2) { + int s0 = n0 & 0x8000 ; + int s1 = n1 & 0x8000 ; + int s2 = n2 & 0x8000 ; + + // equal sign optimization + if (s0 == s1) + if (s1 == s2) + if (s2 == 0) + this.length = getLength(n0 | n1 | n2) ; + else + this.length = getLength(n0 & n1 & n2) ; + else + if (s1 == 0) + this.length = getMaximum(getLength(n0 | n1), + getLength(n2)) ; + else + this.length = getMaximum(getLength(n0 & n1), + getLength(n2)) ; + else + if (s1 == s2) + if (s2 == 0) + this.length = getMaximum(getLength(n1 | n2), + getLength(n0)) ; + else + this.length = getMaximum(getLength(n1 & n2), + getLength(n0)) ; + else + if (s0 == 0) + this.length = getMaximum(getLength(n0 | n2), + getLength(n1)) ; + else + this.length = getMaximum(getLength(n0 & n2), + getLength(n1)) ; + + this.shift = getShift(n0 | n1 | n2) ; + } + + + /** + * Computes common length and shift of 4 numbers. + */ + final void computeLengthShift(int n0, int n1, int n2, int n3) { + this.length = getMaximum(getLength(n0), getLength(n1), + getLength(n2), getLength(n3)) ; + + this.shift = getShift(n0 | n1 | n2 | n3) ; + } + + + /** + * Finds the maximum of two integers. + */ + private static final int getMaximum(int x, int y) { + if (x > y) + return x ; + else + return y ; + } + + /** + * Finds the maximum of three integers. + */ + private static final int getMaximum(int x, int y, int z) { + if (x > y) + if (x > z) + return x ; + else + return z ; + else + if (y > z) + return y ; + else + return z ; + } + + /** + * Finds the maximum of four integers. + */ + private static final int getMaximum(int x, int y, int z, int w) { + int n0, n1 ; + + if (x > y) + n0 = x ; + else + n0 = y ; + + if (z > w) + n1 = z ; + else + n1 = w ; + + if (n0 > n1) + return n0 ; + else + return n1 ; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamNormal.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamNormal.java new file mode 100644 index 0000000..1a04852 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamNormal.java @@ -0,0 +1,674 @@ +/* + * $RCSfile: CompressionStreamNormal.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import javax.vecmath.Vector3f; + +/** + * This class represents a normal in a compression stream. It maintains both + * floating-point and quantized representations. This normal may be bundled + * with a vertex or exist separately as a global normal. + */ +class CompressionStreamNormal extends CompressionStreamElement { + private int u, v ; + private int specialOctant, specialSextant ; + private float normalX, normalY, normalZ ; + + int octant, sextant ; + boolean specialNormal ; + int uAbsolute, vAbsolute ; + + /** + * Create a CompressionStreamNormal. + * + * @param stream CompressionStream associated with this element + * @param normal floating-point representation to be encoded + */ + CompressionStreamNormal(CompressionStream stream, Vector3f normal) { + this.normalX = normal.x ; + this.normalY = normal.y ; + this.normalZ = normal.z ; + stream.byteCount += 12 ; + } + + // + // Normal Encoding Parameterization + // + // A floating point normal is quantized to a desired number of bits by + // comparing it to candidate entries in a table of every possible normal + // at that quantization and finding the closest match. This table of + // normals is indexed by the following encoding: + // + // First, points on a unit radius sphere are parameterized by two angles, + // th and psi, using usual spherical coordinates. th is the angle about + // the y axis, psi is the inclination to the plane containing the point. + // The mapping between rectangular and spherical coordinates is: + // + // x = cos(th)*cos(psi) + // y = sin(psi) + // z = sin(th)*cos(psi) + // + // Points on sphere are folded first by octant, and then by sort order + // of xyz into one of six sextants. All the table encoding takes place in + // the positive octant, in the region bounded by the half spaces: + // + // x >= z + // z >= y + // y >= 0 + // + // This triangular shaped patch runs from 0 to 45 degrees in th, and + // from 0 to as much as 0.615479709 (MAX_Y_ANG) in psi. The xyz bounds + // of the patch is: + // + // (1, 0, 0) (1/sqrt(2), 0, 1/sqrt(2)) (1/sqrt(3), 1/sqrt(3), 1/sqrt(3)) + // + // When dicing this space up into discrete points, the choice for y is + // linear quantization in psi. This means that if the y range is to be + // divided up into n segments, the angle of segment j is: + // + // psi(j) = MAX_Y_ANG*(j/n) + // + // The y height of the patch (in arc length) is *not* the same as the xz + // dimension. However, the subdivision quantization needs to treat xz and + // y equally. To achieve this, the th angles are re-parameterized as + // reflected psi angles. That is, the i-th point's th is: + // + // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*(i/n))) + // + // To go the other direction, the angle th corresponds to the real index r + // (in the same 0-n range as i): + // + // r(th) = n*atan(sin(th))/MAX_Y_ANG + // + // Rounded to the nearest integer, this gives the closest integer index i + // to the xz angle th. Because the triangle has a straight edge on the + // line x=z, it is more intuitive to index the xz angles in reverse + // order. Thus the two equations above are replaced by: + // + // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*((n-i)/n))) + // + // r(th) = n*(1 - atan(sin(th))/MAX_Y_ANG) + // + // Each level of quantization subdivides the triangular patch twice as + // densely. The case in which only the three vertices of the triangle are + // present is the first logical stage of representation, but because of + // how the table is encoded the first usable case starts one level of + // sub-division later. This three point level has an n of 2 by the above + // conventions. + // + private static final int MAX_UV_BITS = 6 ; + private static final int MAX_UV_ENTRIES = 64 ; + + private static final double cgNormals[][][][] = + new double[MAX_UV_BITS+1][MAX_UV_ENTRIES+1][MAX_UV_ENTRIES+1][3] ; + + private static final double MAX_Y_ANG = 0.615479709 ; + private static final double UNITY_14 = 16384.0 ; + + private static void computeNormals() { + int inx, iny, inz, n ; + double th, psi, qnx, qny, qnz ; + + for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) { + n = 1 << quant ; + + for (int j = 0 ; j <= n ; j++) { + for (int i = 0 ; i <= n ; i++) { + if (i+j > n) continue ; + + psi = MAX_Y_ANG*(j/((double) n)) ; + th = Math.asin(Math.tan(MAX_Y_ANG*((n-i)/((double) n)))) ; + + qnx = Math.cos(th)*Math.cos(psi) ; + qny = Math.sin(psi) ; + qnz = Math.sin(th)*Math.cos(psi) ; + + // The normal table uses 16-bit components and must be + // able to represent both +1.0 and -1.0, so convert the + // floating point normal components to fixed point with 14 + // fractional bits, a unity bit, and a sign bit (s1.14). + // Set them back to get the float equivalent. + qnx = qnx*UNITY_14 ; inx = (int)qnx ; + qnx = inx ; qnx = qnx/UNITY_14 ; + + qny = qny*UNITY_14 ; iny = (int)qny ; + qny = iny ; qny = qny/UNITY_14 ; + + qnz = qnz*UNITY_14 ; inz = (int)qnz ; + qnz = inz ; qnz = qnz/UNITY_14 ; + + cgNormals[quant][j][i][0] = qnx ; + cgNormals[quant][j][i][1] = qny ; + cgNormals[quant][j][i][2] = qnz ; + } + } + } + } + + // + // An inverse sine table is used for each quantization level to take the Y + // component of a normal (which is the sine of the inclination angle) and + // obtain the closest quantized Y angle. + // + // At any level of compression, there are a fixed number of different Y + // angles (between 0 and MAX_Y_ANG). The inverse table is built to have + // slightly more than twice as many entries as y angles at any particular + // level; this ensures that the inverse look-up will get within one angle + // of the right one. The size of the table should be as small as + // possible, but with its delta sine still smaller than the delta sine + // between the last two angles to be encoded. + // + // Example: the inverse sine table has a maximum angle of 0.615479709. At + // the maximum resolution of 6 bits there are 65 discrete angles used, + // but twice as many are needed for thresholding between angles, so the + // delta angle is 0.615479709/128. The difference then between the last + // two angles to be encoded is: + // sin(0.615479709*128.0/128.0) - sin(0.615479709*127.0/128.0) = 0.003932730 + // + // Using 8 significent bits below the binary point, fixed point can + // represent sines in increments of 0.003906250, just slightly smaller. + // However, because the maximum Y angle sine is 0.577350269, only 148 + // instead of 256 table entries are needed. + // + private static final short inverseSine[][] = new short[MAX_UV_BITS+1][] ; + + // UNITY_14 * sin(MAX_Y_ANGLE) + private static final short MAX_SIN_14BIT = 9459 ; + + private static void computeInverseSineTables() { + int intSin, deltaSin, intAngle ; + double floatSin, floatAngle ; + short sin14[] = new short[MAX_UV_ENTRIES+1] ; + + // Build table of sines in s1.14 fixed point for each of the + // discrete angles used at maximum resolution. + for (int i = 0 ; i <= MAX_UV_ENTRIES ; i++) { + sin14[i] = (short)(UNITY_14*Math.sin(i*MAX_Y_ANG/MAX_UV_ENTRIES)) ; + } + + for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) { + switch (quant) { + default: + case 6: + // Delta angle: MAX_Y_ANGLE/128.0 + // Bits below binary point for fixed point delta sine: 8 + // Integer delta sine: 64 + // Inverse sine table size: 148 entries + deltaSin = 1 << (14 - 8) ; + break ; + case 5: + // Delta angle: MAX_Y_ANGLE/64.0 + // Bits below binary point for fixed point delta sine: 7 + // Integer delta sine: 128 + // Inverse sine table size: 74 entries + deltaSin = 1 << (14 - 7) ; + break ; + case 4: + // Delta angle: MAX_Y_ANGLE/32.0 + // Bits below binary point for fixed point delta sine: 6 + // Integer delta sine: 256 + // Inverse sine table size: 37 entries + deltaSin = 1 << (14 - 6) ; + break ; + case 3: + // Delta angle: MAX_Y_ANGLE/16.0 + // Bits below binary point for fixed point delta sine: 5 + // Integer delta sine: 512 + // Inverse sine table size: 19 entries + deltaSin = 1 << (14 - 5) ; + break ; + case 2: + // Delta angle: MAX_Y_ANGLE/8.0 + // Bits below binary point for fixed point delta sine: 4 + // Integer delta sine: 1024 + // Inverse sine table size: 10 entries + deltaSin = 1 << (14 - 4) ; + break ; + case 1: + // Delta angle: MAX_Y_ANGLE/4.0 + // Bits below binary point for fixed point delta sine: 3 + // Integer delta sine: 2048 + // Inverse sine table size: 5 entries + deltaSin = 1 << (14 - 3) ; + break ; + case 0: + // Delta angle: MAX_Y_ANGLE/2.0 + // Bits below binary point for fixed point delta sine: 2 + // Integer delta sine: 4096 + // Inverse sine table size: 3 entries + deltaSin = 1 << (14 - 2) ; + break ; + } + + inverseSine[quant] = new short[(MAX_SIN_14BIT/deltaSin) + 1] ; + + intSin = 0 ; + for (int i = 0 ; i < inverseSine[quant].length ; i++) { + // Compute float representation of integer sine with desired + // number of fractional bits by effectively right shifting 14. + floatSin = intSin/UNITY_14 ; + + // Compute the angle with this sine value and quantize it. + floatAngle = Math.asin(floatSin) ; + intAngle = (int)((floatAngle/MAX_Y_ANG) * (1 << quant)) ; + + // Choose the closest of the three nearest quantized values + // intAngle-1, intAngle, and intAngle+1. + if (intAngle > 0) { + if (Math.abs(sin14[intAngle << (6-quant)] - intSin) > + Math.abs(sin14[(intAngle-1) << (6-quant)] - intSin)) + intAngle = intAngle-1 ; + } + + if (intAngle < (1 << quant)) { + if (Math.abs(sin14[intAngle << (6-quant)] - intSin) > + Math.abs(sin14[(intAngle+1) << (6-quant)] - intSin)) + intAngle = intAngle+1 ; + } + + inverseSine[quant][i] = (short)intAngle ; + intSin += deltaSin ; + } + } + } + + /** + * Compute static tables needed for normal quantization. + */ + static { + computeNormals() ; + computeInverseSineTables() ; + } + + /** + * Quantize the floating point normal to a 6-bit octant/sextant plus u,v + * components of [0..6] bits. Full resolution is 18 bits and the minimum + * is 6 bits. + * + * @param stream CompressionStream associated with this element + * @param table HuffmanTable for collecting data about the quantized + * representation of this element + */ + void quantize(CompressionStream stream, HuffmanTable huffmanTable) { + double nx, ny, nz, t ; + + // Clamp UV quantization. + int quant = + (stream.normalQuant < 0? 0 : + (stream.normalQuant > 6? 6 : stream.normalQuant)) ; + + nx = normalX ; + ny = normalY ; + nz = normalZ ; + + octant = 0 ; + sextant = 0 ; + u = 0 ; + v = 0 ; + + // Normalize the fixed point normal to the positive signed octant. + if (nx < 0.0) { + octant |= 4 ; + nx = -nx ; + } + if (ny < 0.0) { + octant |= 2 ; + ny = -ny ; + } + if (nz < 0.0) { + octant |= 1 ; + nz = -nz ; + } + + // Normalize the fixed point normal to the proper sextant of the octant. + if (nx < ny) { + sextant |= 1 ; + t = nx ; + nx = ny ; + ny = t ; + } + if (nz < ny) { + sextant |= 2 ; + t = ny ; + ny = nz ; + nz = t ; + } + if (nx < nz) { + sextant |= 4 ; + t = nx ; + nx = nz ; + nz = t ; + } + + // Convert the floating point y component to s1.14 fixed point. + int yInt = (int)(ny * UNITY_14) ; + + // The y component of the normal is the sine of the y angle. Quantize + // the y angle by using the fixed point y component as an index into + // the inverse sine table of the correct size for the quantization + // level. (12 - quant) bits of the s1.14 y normal component are + // rolled off with a right shift; the remaining bits then match the + // number of bits used to represent the delta sine of the table. + int yIndex = inverseSine[quant][yInt >> (12-quant)] ; + + // Search the two xz rows near y for the best match. + int ii = 0 ; + int jj = 0 ; + int n = 1 << quant ; + double dot, bestDot = -1 ; + + for (int j = yIndex-1 ; j < yIndex+1 && j <= n ; j++) { + if (j < 0) + continue ; + + for (int i = 0 ; i <= n ; i++) { + if (i+j > n) + continue ; + + dot = nx * cgNormals[quant][j][i][0] + + ny * cgNormals[quant][j][i][1] + + nz * cgNormals[quant][j][i][2] ; + + if (dot > bestDot) { + bestDot = dot ; + ii = i ; + jj = j ; + } + } + } + + // Convert u and v to standard grid form. + u = ii << (6 - quant) ; + v = jj << (6 - quant) ; + + // Check for special normals and specially encode them. + specialNormal = false ; + if (u == 64 && v == 0) { + // six coordinate axes case + if (sextant == 0 || sextant == 2) { + // +/- x-axis + specialSextant = 0x6 ; + specialOctant = ((octant & 4) != 0)? 0x2 : 0 ; + + } else if (sextant == 3 || sextant == 1) { + // +/- y-axis + specialSextant = 0x6 ; + specialOctant = 4 | (((octant & 2) != 0)? 0x2 : 0) ; + + } else if (sextant == 5 || sextant == 4) { + // +/- z-axis + specialSextant = 0x7 ; + specialOctant = ((octant & 1) != 0)? 0x2 : 0 ; + } + specialNormal = true ; + u = v = 0 ; + + } else if (u == 0 && v == 64) { + // eight mid point case + specialSextant = 6 | (octant >> 2) ; + specialOctant = ((octant & 0x3) << 1) | 1 ; + specialNormal = true ; + u = v = 0 ; + } + + // Compute deltas if possible. + // Use the non-normalized ii and jj indices. + int du = 0 ; + int dv = 0 ; + int uv64 = 64 >> (6 - quant) ; + + absolute = false ; + if (stream.firstNormal || stream.normalQuantChanged || + stream.lastSpecialNormal || specialNormal) { + // The first normal by definition is absolute, and normals cannot + // be represented as deltas to or from special normals, nor from + // normals with a different quantization. + absolute = true ; + stream.firstNormal = false ; + stream.normalQuantChanged = false ; + + } else if (stream.lastOctant == octant && + stream.lastSextant == sextant) { + // Deltas are always allowed within the same sextant/octant. + du = ii - stream.lastU ; + dv = jj - stream.lastV ; + + } else if (stream.lastOctant != octant && + stream.lastSextant == sextant && + (((sextant == 1 || sextant == 5) && + (stream.lastOctant & 3) == (octant & 3)) || + ((sextant == 0 || sextant == 4) && + (stream.lastOctant & 5) == (octant & 5)) || + ((sextant == 2 || sextant == 3) && + (stream.lastOctant & 6) == (octant & 6)))) { + // If the sextants are the same, the octants can differ only when + // they are bordering each other on the same edge that the + // sextant has. + du = ii - stream.lastU ; + dv = -jj - stream.lastV ; + + // Can't delta by less than -64. + if (dv < -uv64) absolute = true ; + + // Can't delta doubly defined points. + if (jj == 0) absolute = true ; + + } else if (stream.lastOctant == octant && + stream.lastSextant != sextant && + ((sextant == 0 && stream.lastSextant == 4) || + (sextant == 4 && stream.lastSextant == 0) || + (sextant == 1 && stream.lastSextant == 5) || + (sextant == 5 && stream.lastSextant == 1) || + (sextant == 2 && stream.lastSextant == 3) || + (sextant == 3 && stream.lastSextant == 2))) { + // If the octants are the same, the sextants must border on + // the i side (this case) or the j side (next case). + du = -ii - stream.lastU ; + dv = jj - stream.lastV ; + + // Can't delta by less than -64. + if (du < -uv64) absolute = true ; + + // Can't delta doubly defined points. + if (ii == 0) absolute = true ; + + } else if (stream.lastOctant == octant && + stream.lastSextant != sextant && + ((sextant == 0 && stream.lastSextant == 2) || + (sextant == 2 && stream.lastSextant == 0) || + (sextant == 1 && stream.lastSextant == 3) || + (sextant == 3 && stream.lastSextant == 1) || + (sextant == 4 && stream.lastSextant == 5) || + (sextant == 5 && stream.lastSextant == 4))) { + // If the octants are the same, the sextants must border on + // the j side (this case) or the i side (previous case). + if (((ii + jj ) != uv64) && (ii != 0) && (jj != 0)) { + du = uv64 - ii - stream.lastU ; + dv = uv64 - jj - stream.lastV ; + + // Can't delta by greater than +63. + if ((du >= uv64) || (dv >= uv64)) + absolute = true ; + } else + // Can't delta doubly defined points. + absolute = true ; + + } else + // Can't delta this normal. + absolute = true ; + + if (absolute == false) { + // Convert du and dv to standard grid form. + u = du << (6 - quant) ; + v = dv << (6 - quant) ; + } + + // Compute length and shift common to all components. + computeLengthShift(u, v) ; + + if (absolute && length > 6) { + // Absolute normal u, v components are unsigned 6-bit integers, so + // truncate the 0 sign bit for values > 0x001f. + length = 6 ; + } + + // Add this element to the Huffman table associated with this stream. + huffmanTable.addNormalEntry(length, shift, absolute) ; + + // Save current normal as last. + stream.lastSextant = sextant ; + stream.lastOctant = octant ; + stream.lastU = ii ; + stream.lastV = jj ; + stream.lastSpecialNormal = specialNormal ; + + // Copy and retain absolute normal for mesh buffer lookup. + uAbsolute = ii ; + vAbsolute = jj ; + } + + /** + * Output a setNormal command. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputCommand(HuffmanTable table, CommandStream output) { + outputNormal(table, output, CommandStream.SET_NORM, 8) ; + } + + /** + * Output a normal subcommand. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputSubcommand(HuffmanTable table, CommandStream output) { + outputNormal(table, output, 0, 6) ; + } + + // + // Output the final compressed bits to the output command stream. + // + private void outputNormal(HuffmanTable table, CommandStream output, + int header, int headerLength) { + + HuffmanNode t ; + + // Look up the Huffman token for this compression stream element. + t = table.getNormalEntry(length, shift, absolute) ; + + // Construct the normal subcommand. + int componentLength = t.dataLength - t.shift ; + int subcommandLength = 0 ; + long normalSubcommand = 0 ; + + if (absolute) { + // A 3-bit sextant and a 3-bit octant are always present. + subcommandLength = t.tagLength + 6 ; + + if (specialNormal) + // Use the specially-encoded sextant and octant. + normalSubcommand = + (t.tag << 6) | (specialSextant << 3) | specialOctant ; + else + // Use the general encoding rule. + normalSubcommand = + (t.tag << 6) | (sextant << 3) | octant ; + } else { + // The tag is immediately followed by the u and v delta components. + subcommandLength = t.tagLength ; + normalSubcommand = t.tag ; + } + + // Add the u and v values to the subcommand. + subcommandLength += (2 * componentLength) ; + + u = (u >> t.shift) & (int)lengthMask[componentLength] ; + v = (v >> t.shift) & (int)lengthMask[componentLength] ; + + normalSubcommand = + (normalSubcommand << (2 * componentLength)) | + (u << (1 * componentLength)) | + (v << (0 * componentLength)) ; + + if (subcommandLength < 6) { + // The header will have some empty bits. The Huffman tag + // computation will prevent this if necessary. + header |= (int)(normalSubcommand << (6 - subcommandLength)) ; + subcommandLength = 0 ; + } + else { + // Move the 1st 6 bits of the subcommand into the header. + header |= (int)(normalSubcommand >>> (subcommandLength - 6)) ; + subcommandLength -= 6 ; + } + + // Add the header and body to the output buffer. + output.addCommand(header, headerLength, + normalSubcommand, subcommandLength) ; + } + + public String toString() { + String fixed ; + + if (specialNormal) + fixed = " special normal, sextant " + specialSextant + + " octant " + specialOctant ; + + else if (absolute) + fixed = " sextant " + sextant + " octant " + octant + + " u " + u + " v " + v ; + else + fixed = " du " + u + " dv " + v ; + + return + "normal: " + normalX + " " + normalY + " " + normalZ + "\n" + + fixed + "\n" + " length " + length + " shift " + shift + + (absolute? " absolute" : " relative") ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamVertex.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamVertex.java new file mode 100644 index 0000000..92ec625 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamVertex.java @@ -0,0 +1,322 @@ +/* + * $RCSfile: CompressionStreamVertex.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +/** + * This class represents a vertex in a compression stream. It maintains both + * floating-point and quantized representations of the vertex position along + * with meshing and vertex replacement flags for line and surface + * primitives. If normals or colors are bundled with geometry vertices then + * instances of this class will also contain references to normal or color + * stream elements. + */ +class CompressionStreamVertex extends CompressionStreamElement { + private int X, Y, Z ; + private int meshFlag ; + private int stripFlag ; + private float floatX, floatY, floatZ ; + + int xAbsolute, yAbsolute, zAbsolute ; + CompressionStreamColor color = null ; + CompressionStreamNormal normal = null ; + + /** + * Create a CompressionStreamVertex with the given parameters. + * + * @param stream CompressionStream associated with this vertex + * @param p position + * @param n normal bundled with this vertex or null if not bundled + * @param c color bundled with this vertex or null if not bundled + * @param stripFlag CompressionStream.RESTART, + * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE + * @param meshFlag CompressionStream.MESH_PUSH or + * CompressionStream.NO_MESH_PUSH + */ + CompressionStreamVertex(CompressionStream stream, + Point3f p, Vector3f n, Color3f c, + int stripFlag, int meshFlag) { + + this(stream, p, n, stripFlag, meshFlag) ; + + if (stream.vertexColor3) + color = new CompressionStreamColor(stream, c) ; + } + + /** + * Create a CompressionStreamVertex with the given parameters. + * + * @param stream CompressionStream associated with this vertex + * @param p position + * @param n normal bundled with this vertex or null if not bundled + * @param c color bundled with this vertex or null if not bundled + * @param stripFlag CompressionStream.RESTART, + * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE + * @param meshFlag CompressionStream.MESH_PUSH or + * CompressionStream.NO_MESH_PUSH + */ + CompressionStreamVertex(CompressionStream stream, + Point3f p, Vector3f n, Color4f c, + int stripFlag, int meshFlag) { + + this(stream, p, n, stripFlag, meshFlag) ; + + if (stream.vertexColor4) + color = new CompressionStreamColor(stream, c) ; + } + + /** + * Create a CompressionStreamVertex with the given parameters. + * + * @param stream CompressionStream associated with this vertex + * @param p position + * @param n normal bundled with this vertex or null if not bundled + * @param stripFlag CompressionStream.RESTART, + * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE + * @param meshFlag CompressionStream.MESH_PUSH or + * CompressionStream.NO_MESH_PUSH + */ + CompressionStreamVertex(CompressionStream stream, Point3f p, Vector3f n, + int stripFlag, int meshFlag) { + + this.stripFlag = stripFlag ; + this.meshFlag = meshFlag ; + this.floatX = p.x ; + this.floatY = p.y ; + this.floatZ = p.z ; + + stream.byteCount += 12 ; + stream.vertexCount++ ; + + if (p.x < stream.mcBounds[0].x) stream.mcBounds[0].x = p.x ; + if (p.y < stream.mcBounds[0].y) stream.mcBounds[0].y = p.y ; + if (p.z < stream.mcBounds[0].z) stream.mcBounds[0].z = p.z ; + + if (p.x > stream.mcBounds[1].x) stream.mcBounds[1].x = p.x ; + if (p.y > stream.mcBounds[1].y) stream.mcBounds[1].y = p.y ; + if (p.z > stream.mcBounds[1].z) stream.mcBounds[1].z = p.z ; + + if (stream.vertexNormals) + normal = new CompressionStreamNormal(stream, n) ; + } + + /** + * Quantize the floating point position to fixed point integer components + * of the specified number of bits. The bit length can range from 1 to 16. + * + * @param stream CompressionStream associated with this element + * @param table HuffmanTable for collecting data about the quantized + * representation of this element + */ + void quantize(CompressionStream stream, HuffmanTable huffmanTable) { + double px, py, pz ; + + // Clamp quantization. + int quant = + (stream.positionQuant < 1? 1 : + (stream.positionQuant > 16? 16 : stream.positionQuant)) ; + + absolute = false ; + if (stream.firstPosition || stream.positionQuantChanged) { + absolute = true ; + stream.lastPosition[0] = 0 ; + stream.lastPosition[1] = 0 ; + stream.lastPosition[2] = 0 ; + stream.firstPosition = false ; + stream.positionQuantChanged = false ; + } + + // Normalize position to the unit cube. This is bounded by the open + // intervals (-1..1) on each axis. + px = (floatX - stream.center[0]) * stream.scale ; + py = (floatY - stream.center[1]) * stream.scale ; + pz = (floatZ - stream.center[2]) * stream.scale ; + + // Convert the floating point position to s.15 2's complement. + // ~1.0 -> 32767 (0x00007fff) [ ~1.0 = 32767.0/32768.0] + // ~-1.0 -> -32767 (0xffff8001) [~-1.0 = -32767.0/32768.0] + X = (int)(px * 32768.0) ; + Y = (int)(py * 32768.0) ; + Z = (int)(pz * 32768.0) ; + + // Compute quantized values. + X &= quantizationMask[quant] ; + Y &= quantizationMask[quant] ; + Z &= quantizationMask[quant] ; + + // Update quantized bounds. + if (X < stream.qcBounds[0].x) stream.qcBounds[0].x = X ; + if (Y < stream.qcBounds[0].y) stream.qcBounds[0].y = Y ; + if (Z < stream.qcBounds[0].z) stream.qcBounds[0].z = Z ; + + if (X > stream.qcBounds[1].x) stream.qcBounds[1].x = X ; + if (Y > stream.qcBounds[1].y) stream.qcBounds[1].y = Y ; + if (Z > stream.qcBounds[1].z) stream.qcBounds[1].z = Z ; + + // Copy and retain absolute position for mesh buffer lookup. + xAbsolute = X ; + yAbsolute = Y ; + zAbsolute = Z ; + + // Compute deltas. + X -= stream.lastPosition[0] ; + Y -= stream.lastPosition[1] ; + Z -= stream.lastPosition[2] ; + + // Update last values. + stream.lastPosition[0] += X ; + stream.lastPosition[1] += Y ; + stream.lastPosition[2] += Z ; + + // Deltas which exceed the range of 16-bit signed 2's complement + // numbers are handled by sign-extension of the 16th bit in order to + // effect a 16-bit wrap-around. + X = (X << 16) >> 16 ; + Y = (Y << 16) >> 16 ; + Z = (Z << 16) >> 16 ; + + // Compute length and shift common to all components. + computeLengthShift(X, Y, Z) ; + + // 0-length components are allowed only for normals. + if (length == 0) + length = 1 ; + + // Add this element to the Huffman table associated with this stream. + huffmanTable.addPositionEntry(length, shift, absolute) ; + + // Quantize any bundled color or normal. + if (color != null) + color.quantize(stream, huffmanTable) ; + + if (normal != null) + normal.quantize(stream, huffmanTable) ; + + // Push this vertex into the mesh buffer mirror, if necessary, so it + // can be retrieved for computing deltas when mesh buffer references + // are subsequently encountered during the quantization pass. + if (meshFlag == stream.MESH_PUSH) + stream.meshBuffer.push(this) ; + } + + /** + * Output the final compressed bits to the compression command stream. + * + * @param table HuffmanTable mapping quantized representations to + * compressed encodings + * @param output CommandStream for collecting compressed output + */ + void outputCommand(HuffmanTable huffmanTable, CommandStream outputBuffer) { + + HuffmanNode t ; + int command = CommandStream.VERTEX ; + + // Look up the Huffman token for this compression stream element. The + // values of length and shift found there will override the + // corresponding fields in this element, which represent best-case + // compression without regard to tag length. + t = huffmanTable.getPositionEntry(length, shift, absolute) ; + + // Construct the position subcommand. + int componentLength = t.dataLength - t.shift ; + int subcommandLength = t.tagLength + (3 * componentLength) ; + + X = (X >> t.shift) & (int)lengthMask[componentLength] ; + Y = (Y >> t.shift) & (int)lengthMask[componentLength] ; + Z = (Z >> t.shift) & (int)lengthMask[componentLength] ; + + long positionSubcommand = + (((long)t.tag) << (3 * componentLength)) | + (((long)X) << (2 * componentLength)) | + (((long)Y) << (1 * componentLength)) | + (((long)Z) << (0 * componentLength)) ; + + if (subcommandLength < 6) { + // The header will have some empty bits. The Huffman tag + // computation will prevent this if necessary. + command |= (int)(positionSubcommand << (6 - subcommandLength)) ; + subcommandLength = 0 ; + } + else { + // Move the 1st 6 bits of the subcommand into the header. + command |= (int)(positionSubcommand >>> (subcommandLength - 6)) ; + subcommandLength -= 6 ; + } + + // Construct the vertex command body. + long body = + (((long)stripFlag) << (subcommandLength + 1)) | + (((long)meshFlag) << (subcommandLength + 0)) | + (positionSubcommand & lengthMask[subcommandLength]) ; + + // Add the vertex command to the output buffer. + outputBuffer.addCommand(command, 8, body, subcommandLength + 3) ; + + // Output any normal and color subcommands. + if (normal != null) + normal.outputSubcommand(huffmanTable, outputBuffer) ; + + if (color != null) + color.outputSubcommand(huffmanTable, outputBuffer) ; + } + + public String toString() { + String d = absolute? "" : "delta " ; + String c = (color == null? "": "\n\n " + color.toString()) ; + String n = (normal == null? "": "\n\n " + normal.toString()) ; + + return + "position: " + floatX + " " + floatY + " " + floatZ + "\n" + + "fixed point " + d + + X + " " + Y + " " + Z + "\n" + + "length " + length + " shift " + shift + + (absolute? " absolute" : " relative") + "\n" + + "strip flag " + stripFlag + " mesh flag " + meshFlag + + c + n ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStrip.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStrip.java new file mode 100644 index 0000000..459a7b6 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStrip.java @@ -0,0 +1,908 @@ +/* + * $RCSfile: GeneralizedStrip.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import com.sun.j3d.internal.J3dUtilsI18N; + + +/** + * This class provides static methods to support topological + * transformations on generalized strips. This is used by the + * GeometryDecompressor. These methods only need to look at the + * vertex replacement flags to determine how the vertices in the strip + * are connected. The connections are rearranged in different ways to + * transform generalized strips to GeometryArray representations. + * + * @see GeneralizedStripFlags + * @see GeneralizedVertexList + * @see GeometryDecompressor + */ +class GeneralizedStrip { + private static final boolean debug = false ; + + // Private convenience copies of various constants. + private static final int CW = + GeneralizedStripFlags.FRONTFACE_CW ; + private static final int CCW = + GeneralizedStripFlags.FRONTFACE_CCW ; + private static final int RESTART_CW = + GeneralizedStripFlags.RESTART_CW ; + private static final int RESTART_CCW = + GeneralizedStripFlags.RESTART_CCW ; + private static final int REPLACE_MIDDLE = + GeneralizedStripFlags.REPLACE_MIDDLE ; + private static final int REPLACE_OLDEST = + GeneralizedStripFlags.REPLACE_OLDEST ; + + /** + * The IntList is like an ArrayList, but avoids the Integer + * object wrapper and accessor overhead for simple lists of ints. + */ + static class IntList { + /** + * The array of ints. + */ + int ints[] ; + + /** + * The number of ints in this instance. + */ + int count ; + + /** + * Construct a new empty IntList of the given initial size. + * @param initialSize initial size of the backing array + */ + IntList(int initialSize) { + ints = new int[initialSize] ; + count = 0 ; + } + + /** + * Constructs an IntList with the given contents. + * @param ints the array of ints to use as the contents + */ + IntList(int ints[]) { + this.ints = ints ; + this.count = ints.length ; + } + + /** + * Add a new int to the end of this list. + * @param i the int to be appended to this list + */ + void add(int i) { + if (count == ints.length) { + int newints[] = new int[2*count] ; + System.arraycopy(ints, 0, newints, 0, count) ; + ints = newints ; + if (debug) + System.out.println + ("GeneralizedStrip.IntList: reallocated " + + (2*count) + " ints") ; + } + ints[count++] = i ; + } + + /** + * Trim the backing array to the current count and return the + * resulting backing array. + */ + int[] trim() { + if (count != ints.length) { + int newints[] = new int[count] ; + System.arraycopy(ints, 0, newints, 0, count) ; + ints = newints ; + } + return ints ; + } + + /** + * Fill the list with consecutive integers starting from 0. + */ + void fillAscending() { + for (int i = 0 ; i < ints.length ; i++) + ints[i] = i ; + + count = ints.length ; + } + + public String toString() { + String s = new String("[") ; + for (int i = 0 ; i < count-1 ; i++) + s = s + Integer.toString(ints[i]) + ", " ; + return s + Integer.toString(ints[count-1]) + "]" ; + } + } + + /** + * The StripArray class is used as the output of some conversion methods + * in the GeneralizedStrip class. + */ + static class StripArray { + /** + * A list of indices into the vertices of the original generalized + * strip. It specifies the order in which vertices in the original + * strip should be followed to build GeometryArray objects. + */ + IntList vertices ; + + /** + * A list of strip counts. + */ + IntList stripCounts ; + + /** + * Creates a StripArray with the specified vertices and stripCounts. + * @param vertices IntList containing vertex indicies. + * @param stripCounts IntList containing strip lengths. + */ + StripArray(IntList vertices, IntList stripCounts) { + this.vertices = vertices ; + this.stripCounts = stripCounts ; + } + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning a 2-element array of + * StripArray objects. The first StripArray will contain triangle strips + * and the second will contain triangle fans. + * + * @param vertices an object implementing GeneralizedStripFlags + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @return a 2-element array containing strips in 0 and fans in 1 + */ + static StripArray[] toStripsAndFans(GeneralizedStripFlags vertices, + int frontFace) { + + int size = vertices.getFlagCount() ; + + // Initialize IntLists to worst-case sizes. + IntList stripVerts = new IntList(size*3) ; + IntList fanVerts = new IntList(size*3) ; + IntList stripCounts = new IntList(size) ; + IntList fanCounts = new IntList(size) ; + + toStripsAndFans(vertices, frontFace, + stripVerts, stripCounts, fanVerts, fanCounts) ; + + // Construct the StripArray output. + StripArray sa[] = new StripArray[2] ; + + if (stripCounts.count > 0) + sa[0] = new StripArray(stripVerts, stripCounts) ; + + if (fanCounts.count > 0) + sa[1] = new StripArray(fanVerts, fanCounts) ; + + return sa ; + } + + private static void toStripsAndFans(GeneralizedStripFlags vertices, + int frontFace, + IntList stripVerts, + IntList stripCounts, + IntList fanVerts, + IntList fanCounts) { + int newFlag, curFlag, winding ; + int v, size, stripStart, stripLength ; + boolean transition = false ; + + stripStart = 0 ; + stripLength = 3 ; + curFlag = vertices.getFlag(0) ; + winding = (curFlag == RESTART_CW ? CW : CCW) ; + size = vertices.getFlagCount() ; + + // Vertex replace flags for the first 3 vertices are irrelevant since + // they can only define a single triangle. The first meaningful + // replace flag starts at the 4th vertex. + v = 3 ; + if (v < size) + curFlag = vertices.getFlag(v) ; + + while (v < size) { + newFlag = vertices.getFlag(v) ; + + if ((newFlag == curFlag) && + (newFlag != RESTART_CW) && (newFlag != RESTART_CCW)) { + // The last flag was the same as this one, and it wasn't a + // restart: proceed to the next vertex. + stripLength++ ; + v++ ; + + } else { + // Either this vertex flag changed from the last one, or + // the flag explicitly specifies a restart: process the + // last strip and start up a new one. + if (curFlag == REPLACE_MIDDLE) + addFan(fanVerts, fanCounts, stripStart, stripLength, + frontFace, winding, transition) ; + else + addStrip(stripVerts, stripCounts, stripStart, stripLength, + frontFace, winding) ; + + // Restart: skip to the 4th vertex of the new strip. + if ((newFlag == RESTART_CW) || (newFlag == RESTART_CCW)) { + winding = (newFlag == RESTART_CW ? CW : CCW) ; + stripStart = v ; + stripLength = 3 ; + v += 3 ; + transition = false ; + if (v < size) + curFlag = vertices.getFlag(v) ; + } + // Strip/fan transition: decrement start of strip. + else { + if (newFlag == REPLACE_OLDEST) { + // Flip winding order when transitioning from fans + // to strips. + winding = (winding == CW ? CCW : CW) ; + stripStart = v-2 ; + stripLength = 3 ; + } else { + // Flip winding order when transitioning from + // strips to fans only if the preceding strip has + // an even number of vertices. + if ((stripLength & 0x01) == 0) + winding = (winding == CW ? CCW : CW) ; + stripStart = v-3 ; + stripLength = 4 ; + } + v++ ; + transition = true ; + curFlag = newFlag ; + } + } + } + + // Finish off the last strip or fan. + // If v > size then the strip is degenerate. + if (v == size) + if (curFlag == REPLACE_MIDDLE) + addFan(fanVerts, fanCounts, stripStart, stripLength, + frontFace, winding, transition) ; + else + addStrip(stripVerts, stripCounts, stripStart, stripLength, + frontFace, winding) ; + else + throw new IllegalArgumentException + (J3dUtilsI18N.getString("GeneralizedStrip0")) ; + + if (debug) { + System.out.println("GeneralizedStrip.toStripsAndFans") ; + if (v > size) + System.out.println(" ended with a degenerate triangle:" + + " number of vertices: " + (v-size)) ; + + System.out.println("\n number of strips: " + stripCounts.count) ; + if (stripCounts.count > 0) { + System.out.println(" number of vertices: " + stripVerts.count) ; + System.out.println(" vertices/strip: " + + (float)stripVerts.count/stripCounts.count) ; + System.out.println(" strip counts: " + stripCounts.toString()) ; + // System.out.println(" indices: " + stripVerts.toString()) ; + } + + System.out.println("\n number of fans: " + fanCounts.count) ; + if (fanCounts.count > 0) { + System.out.println(" number of vertices: " + fanVerts.count) ; + System.out.println(" vertices/strip: " + + (float)fanVerts.count/fanCounts.count) ; + System.out.println(" fan counts: " + fanCounts.toString()) ; + // System.out.println(" indices: " + fanVerts.toString()) ; + } + System.out.println("\n total vertices: " + + (stripVerts.count + fanVerts.count) + + "\n original number of vertices: " + size + + "\n") ; + } + } + + // + // Java 3D specifies that the vertices of front-facing polygons + // have counter-clockwise (CCW) winding order when projected to + // the view surface. Polygons with clockwise (CW) vertex winding + // will be culled as back-facing by default. + // + // Generalized triangle strips can flip the orientation of their + // triangles with the RESTART_CW and RESTART_CCW vertex flags. + // Strips flagged with an orientation opposite to what has been + // specified as front-facing must have their windings reversed in + // order to have the correct face orientation when represented as + // GeometryArray objects. + // + private static void addStrip(IntList stripVerts, + IntList stripCounts, + int start, int length, + int frontFace, int winding) { + int vindex = start ; + + if (winding == frontFace) { + // Maintain original order. + stripCounts.add(length) ; + while (vindex < start + length) { + stripVerts.add(vindex++) ; + } + } else if ((length & 0x1) == 1) { + // Reverse winding order if number of vertices is odd. + stripCounts.add(length) ; + vindex += length-1 ; + while (vindex >= start) { + stripVerts.add(vindex--) ; + } + } else if (length == 4) { + // Swap middle vertices. + stripCounts.add(4) ; + stripVerts.add(vindex) ; + stripVerts.add(vindex+2) ; + stripVerts.add(vindex+1) ; + stripVerts.add(vindex+3) ; + } else { + // Make the 1st triangle a singleton with reverse winding. + stripCounts.add(3) ; + stripVerts.add(vindex) ; + stripVerts.add(vindex+2) ; + stripVerts.add(vindex+1) ; + if (length > 3) { + // Copy the rest of the vertices in original order. + vindex++ ; + stripCounts.add(length-1) ; + while (vindex < start + length) { + stripVerts.add(vindex++) ; + } + } + } + } + + private static void addFan(IntList fanVerts, + IntList fanCounts, + int start, int length, + int frontFace, int winding, + boolean transition) { + int vindex = start ; + fanVerts.add(vindex++) ; + + if (winding == frontFace) { + if (transition) { + // Skip 1st triangle if this is the result of a transition. + fanCounts.add(length-1) ; + vindex++ ; + } else { + fanCounts.add(length) ; + fanVerts.add(vindex++) ; + } + while (vindex < start + length) { + fanVerts.add(vindex++) ; + } + } else { + // Reverse winding order. + vindex += length-2 ; + while (vindex > start+1) { + fanVerts.add(vindex--) ; + } + if (transition) { + // Skip 1st triangle if this is the result of a transition. + fanCounts.add(length-1) ; + } else { + fanCounts.add(length) ; + fanVerts.add(vindex) ; + } + } + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning a StripArray containing + * exclusively strips. + * + * @param vertices an object implementing GeneralizedStripFlags + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @return a StripArray containing the converted strips + */ + static StripArray toTriangleStrips(GeneralizedStripFlags vertices, + int frontFace) { + + int size = vertices.getFlagCount() ; + + // initialize lists to worst-case sizes. + IntList stripVerts = new IntList(size*3) ; + IntList fanVerts = new IntList(size*3) ; + IntList stripCounts = new IntList(size) ; + IntList fanCounts = new IntList(size) ; + + toStripsAndFans(vertices, frontFace, + stripVerts, stripCounts, fanVerts, fanCounts) ; + + if (fanCounts.count == 0) + if (stripCounts.count > 0) + return new StripArray(stripVerts, stripCounts) ; + else + return null ; + + // convert each fan to one or more strips + int i, v = 0 ; + for (i = 0 ; i < fanCounts.count ; i++) { + fanToStrips(v, fanCounts.ints[i], fanVerts.ints, + stripVerts, stripCounts, false) ; + v += fanCounts.ints[i] ; + } + + // create the StripArray output + StripArray sa = new StripArray(stripVerts, stripCounts) ; + + if (debug) { + System.out.println("GeneralizedStrip.toTriangleStrips" + + "\n number of strips: " + + sa.stripCounts.count) ; + if (sa.stripCounts.count > 0) { + System.out.println(" number of vertices: " + + sa.vertices.count + + "\n vertices/strip: " + + ((float)sa.vertices.count / + (float)sa.stripCounts.count)) ; + System.out.print(" strip counts: [") ; + for (i = 0 ; i < sa.stripCounts.count-1 ; i++) + System.out.print(sa.stripCounts.ints[i] + ", ") ; + System.out.println(sa.stripCounts.ints[i] + "]") ; + } + System.out.println() ; + } + return sa ; + } + + private static void fanToStrips(int v, int length, int fans[], + IntList stripVerts, + IntList stripCounts, + boolean convexPlanar) { + if (convexPlanar) { + // Construct a strip by criss-crossing across the interior. + stripCounts.add(length) ; + stripVerts.add(fans[v]) ; + + int j = v + 1 ; + int k = v + (length - 1) ; + while (j <= k) { + stripVerts.add(fans[j++]) ; + if (j > k) break ; + stripVerts.add(fans[k--]) ; + } + } else { + // Traverse non-convex or non-planar fan, biting off 3-triangle + // strips or less. First 5 vertices produce 1 strip of 3 + // triangles, and every 4 vertices after that produce another + // strip of 3 triangles. Each remaining strip adds 2 vertices. + int fanStart = v ; + v++ ; + while (v+4 <= fanStart + length) { + stripVerts.add(fans[v]) ; + stripVerts.add(fans[v+1]) ; + stripVerts.add(fans[fanStart]) ; + stripVerts.add(fans[v+2]) ; + stripVerts.add(fans[v+3]) ; + stripCounts.add(5) ; + v += 3 ; + } + + // Finish off the fan. + if (v+1 < fanStart + length) { + stripVerts.add(fans[v]) ; + stripVerts.add(fans[v+1]) ; + stripVerts.add(fans[fanStart]) ; + v++ ; + + if (v+1 < fanStart + length) { + stripVerts.add(fans[v+1]) ; + stripCounts.add(4) ; + } + else + stripCounts.add(3) ; + } + } + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning an array of vertex + * references representing the original generalized strip as individual + * triangles. Each sequence of three consecutive vertex references in the + * output defines a single triangle. + * + * @param vertices an object implementing GeneralizedStripFlags + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @return an array of indices into the original vertex array + */ + static int[] toTriangles(GeneralizedStripFlags vertices, int frontFace) { + + int vertexCount = 0 ; + StripArray sa[] = toStripsAndFans(vertices, frontFace) ; + + if (sa[0] != null) + vertexCount = 3 * getTriangleCount(sa[0].stripCounts) ; + if (sa[1] != null) + vertexCount += 3 * getTriangleCount(sa[1].stripCounts) ; + + if (debug) + System.out.println("GeneralizedStrip.toTriangles\n" + + " number of triangles: " + vertexCount/3 + "\n" + + " number of vertices: " + vertexCount + "\n") ; + int t = 0 ; + int triangles[] = new int[vertexCount] ; + + if (sa[0] != null) + t = stripsToTriangles(t, triangles, + 0, sa[0].vertices.ints, + 0, sa[0].stripCounts.ints, + sa[0].stripCounts.count) ; + if (sa[1] != null) + t = fansToTriangles(t, triangles, + 0, sa[1].vertices.ints, + 0, sa[1].stripCounts.ints, + sa[1].stripCounts.count) ; + return triangles ; + } + + private static int stripsToTriangles(int tstart, int tbuff[], + int vstart, int vertices[], + int stripStart, int stripCounts[], + int stripCount) { + int t = tstart ; + int v = vstart ; + for (int i = 0 ; i < stripCount ; i++) { + for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) { + if ((j & 0x01) == 0) { + // even-numbered triangles + tbuff[t*3 +0] = vertices[v+0] ; + tbuff[t*3 +1] = vertices[v+1] ; + tbuff[t*3 +2] = vertices[v+2] ; + } else { + // odd-numbered triangles + tbuff[t*3 +0] = vertices[v+1] ; + tbuff[t*3 +1] = vertices[v+0] ; + tbuff[t*3 +2] = vertices[v+2] ; + } + t++ ; v++ ; + } + v += 2 ; + } + return t ; + } + + private static int fansToTriangles(int tstart, int tbuff[], + int vstart, int vertices[], + int stripStart, int stripCounts[], + int stripCount) { + int t = tstart ; + int v = vstart ; + for (int i = 0 ; i < stripCount ; i++) { + for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) { + tbuff[t*3 +0] = vertices[v] ; + tbuff[t*3 +1] = vertices[v+j+1] ; + tbuff[t*3 +2] = vertices[v+j+2] ; + t++ ; + } + v += stripCounts[i+stripStart] ; + } + return t ; + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning a 2-element array of + * StripArray objects. The first StripArray will contain triangle strips + * and the second will contain individual triangles in the vertices + * field. Short strips will be converted to individual triangles. + * + * @param vertices an object implementing GeneralizedStripFlags + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @param shortStripSize strips this size or less will be converted to + * individual triangles if there are more than maxShortStrips of them + * @param maxShortStrips maximum number of short strips allowed before + * creating individual triangles + * @return a 2-element array containing strips in 0 and triangles in 1 + */ + static StripArray[] toStripsAndTriangles(GeneralizedStripFlags vertices, + int frontFace, int shortStripSize, + int maxShortStrips) { + int longStripCount = 0 ; + int longStripVertexCount = 0 ; + int shortStripCount = 0 ; + int triangleCount = 0 ; + + StripArray sa[] = new StripArray[2] ; + StripArray ts = toTriangleStrips(vertices, frontFace) ; + + for (int i = 0 ; i < ts.stripCounts.count ; i++) + if (ts.stripCounts.ints[i] <= shortStripSize) { + shortStripCount++ ; + triangleCount += ts.stripCounts.ints[i] - 2 ; + } else { + longStripCount++ ; + longStripVertexCount += ts.stripCounts.ints[i] ; + } + + if (debug) + System.out.print("GeneralizedStrip.toStripsAndTriangles\n" + + " short strip size: " + shortStripSize + + " short strips tolerated: " + maxShortStrips + + " number of short strips: " + shortStripCount + + "\n\n") ; + + if (shortStripCount <= maxShortStrips) { + sa[0] = ts ; + sa[1] = null ; + } else { + int si = 0 ; int newStripVerts[] = new int[longStripVertexCount] ; + int ci = 0 ; int newStripCounts[] = new int[longStripCount] ; + int ti = 0 ; int triangles[] = new int[3*triangleCount] ; + int vi = 0 ; + + for (int i = 0 ; i < ts.stripCounts.count ; i++) { + if (ts.stripCounts.ints[i] <= shortStripSize) { + ti = stripsToTriangles(ti, triangles, + vi, ts.vertices.ints, + i, ts.stripCounts.ints, 1) ; + vi += ts.stripCounts.ints[i] ; + } else { + newStripCounts[ci++] = ts.stripCounts.ints[i] ; + for (int j = 0 ; j < ts.stripCounts.ints[i] ; j++) + newStripVerts[si++] = ts.vertices.ints[vi++] ; + } + } + + if (longStripCount > 0) + sa[0] = new StripArray(new IntList(newStripVerts), + new IntList(newStripCounts)) ; + else + sa[0] = null ; + + sa[1] = new StripArray(new IntList(triangles), null) ; + + if (debug) { + System.out.println(" triangles separated: " + triangleCount) ; + if (longStripCount > 0) { + System.out.println + (" new vertices/strip: " + + ((float)longStripVertexCount/(float)longStripCount)) ; + + System.out.print(" long strip counts: [") ; + for (int i = 0 ; i < longStripCount-1 ; i++) + System.out.print(newStripCounts[i++] + ", ") ; + + System.out.println + (newStripCounts[longStripCount-1] + "]\n") ; + } + } + } + return sa ; + } + + /** + * Interprets the vertex flags associated with a class implementing + * GeneralizedStripFlags, constructing and returning a StripArray. + * + * RESTART_CW and RESTART_CCW are treated as equivalent, as are + * REPLACE_MIDDLE and REPLACE_OLDEST. + * + * @param vertices an object implementing GeneralizedStripFlags + * @return a StripArray representing an array of line strips + */ + static StripArray toLineStrips(GeneralizedStripFlags vertices) { + int v, size, stripStart, stripLength, flag ; + + stripStart = 0 ; + stripLength = 2 ; + size = vertices.getFlagCount() ; + + // Initialize IntLists to worst-case sizes. + IntList stripVerts = new IntList(size*2) ; + IntList stripCounts = new IntList(size) ; + + // Vertex replace flags for the first two vertices are irrelevant. + v = 2 ; + while (v < size) { + flag = vertices.getFlag(v) ; + + if ((flag != RESTART_CW) && (flag != RESTART_CCW)) { + // proceed to the next vertex. + stripLength++ ; + v++ ; + + } else { + // Record the last strip. + stripCounts.add(stripLength) ; + for (int i = stripStart ; i < stripStart+stripLength ; i++) + stripVerts.add(i) ; + + // Start a new strip and skip to its 3rd vertex. + stripStart = v ; + stripLength = 2 ; + v += 2 ; + } + } + + // Finish off the last strip. + // If v > size then the strip is degenerate. + if (v == size) { + stripCounts.add(stripLength) ; + for (int i = stripStart ; i < stripStart+stripLength ; i++) + stripVerts.add(i) ; + } else + throw new IllegalArgumentException + (J3dUtilsI18N.getString("GeneralizedStrip0")) ; + + if (debug) { + System.out.println("GeneralizedStrip.toLineStrips\n") ; + if (v > size) + System.out.println(" ended with a degenerate line") ; + + System.out.println(" number of strips: " + stripCounts.count) ; + if (stripCounts.count > 0) { + System.out.println(" number of vertices: " + stripVerts.count) ; + System.out.println(" vertices/strip: " + + (float)stripVerts.count/stripCounts.count) ; + System.out.println(" strip counts: " + stripCounts.toString()) ; + // System.out.println(" indices: " + stripVerts.toString()) ; + } + System.out.println() ; + } + + if (stripCounts.count > 0) + return new StripArray(stripVerts, stripCounts) ; + else + return null ; + } + + /** + * Counts the number of lines defined by arrays of line strips. + * + * @param stripCounts array of strip counts, as used by the + * GeometryStripArray object + * @return number of lines in the strips + */ + static int getLineCount(int stripCounts[]) { + int count = 0 ; + for (int i = 0 ; i < stripCounts.length ; i++) + count += (stripCounts[i] - 1) ; + return count ; + } + + /** + * Counts the number of triangles defined by arrays of + * triangle strips or fans. + * + * @param stripCounts array of strip counts, as used by the + * GeometryStripArray object + * @return number of triangles in the strips or fans + */ + static int getTriangleCount(int stripCounts[]) { + int count = 0 ; + for (int i = 0 ; i < stripCounts.length ; i++) + count += (stripCounts[i] - 2) ; + return count ; + } + + /** + * Counts the number of triangles defined by arrays of + * triangle strips or fans. + * + * @param stripCounts IntList of strip counts + * @return number of triangles in the strips or fans + */ + static int getTriangleCount(IntList stripCounts) { + int count = 0 ; + for (int i = 0 ; i < stripCounts.count ; i++) + count += (stripCounts.ints[i] - 2) ; + return count ; + } + + /** + * Breaks up triangle strips into separate triangles. + * + * @param stripCounts array of strip counts, as used by the + * GeometryStripArray object + * @return array of ints which index into the original vertex array; each + * set of three consecutive vertex indices defines a single triangle + */ + static int[] stripsToTriangles(int stripCounts[]) { + int triangleCount = getTriangleCount(stripCounts) ; + int tbuff[] = new int[3*triangleCount] ; + IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ; + + vertices.fillAscending() ; + stripsToTriangles(0, tbuff, + 0, vertices.ints, + 0, stripCounts, + stripCounts.length) ; + return tbuff ; + } + + /** + * Breaks up triangle fans into separate triangles. + * + * @param stripCounts array of strip counts, as used by the + * GeometryStripArray object + * @return array of ints which index into the original vertex array; each + * set of three consecutive vertex indices defines a single triangle + */ + static int[] fansToTriangles(int stripCounts[]) { + int triangleCount = getTriangleCount(stripCounts) ; + int tbuff[] = new int[3*triangleCount] ; + IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ; + + vertices.fillAscending() ; + fansToTriangles(0, tbuff, + 0, vertices.ints, + 0, stripCounts, + stripCounts.length) ; + return tbuff ; + } + + /** + * Takes a fan and converts it to one or more strips. + * + * @param v index into the fans array of the first vertex in the fan + * @param length number of vertices in the fan + * @param fans array of vertex indices representing one or more fans + * @param convexPlanar if true indicates that the fan is convex and + * planar; such fans will always be converted into a single strip + * @return a StripArray containing the converted strips + */ + static StripArray fanToStrips(int v, int length, int fans[], + boolean convexPlanar) { + + // Initialize IntLists to worst-case sizes. + IntList stripVerts = new IntList(length*3) ; + IntList stripCounts = new IntList(length) ; + + fanToStrips(v, length, fans, stripVerts, stripCounts, convexPlanar) ; + return new StripArray(stripVerts, stripCounts) ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStripFlags.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStripFlags.java new file mode 100644 index 0000000..eb51422 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStripFlags.java @@ -0,0 +1,105 @@ +/* + * $RCSfile: GeneralizedStripFlags.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +/** + * A class which implements GeneralizedStripFlags provides the means to access + * the vertex replace code flags associated with each vertex of a generalized + * strip. This allows a flexible representation of generalized strips for + * various classes and makes it possible to provide a common subset of static + * methods which operate only on their topology. + * + * @see GeneralizedStrip + * @see GeneralizedVertexList + */ +interface GeneralizedStripFlags { + + /** + * This flag indicates that a vertex starts a new strip with clockwise + * winding. + */ + static final int RESTART_CW = 0 ; + + /** + * This flag indicates that a vertex starts a new strip with + * counter-clockwise winding. + */ + static final int RESTART_CCW = 1 ; + + /** + * This flag indicates that the next triangle in the strip is defined by + * replacing the middle vertex of the previous triangle in the strip. + */ + static final int REPLACE_MIDDLE = 2 ; + + /** + * This flag indicates that the next triangle in the strip is defined by + * replacing the oldest vertex of the previous triangle in the strip. + */ + static final int REPLACE_OLDEST = 3 ; + + /** + * This constant is used to indicate that triangles with clockwise vertex + * winding are front facing. + */ + static final int FRONTFACE_CW = 0 ; + + /** + * This constant is used to indicate that triangles with counter-clockwise + * vertex winding are front facing. + */ + static final int FRONTFACE_CCW = 1 ; + + /** + * Return the number of flags. This should be the same as the number of + * vertices in the generalized strip. + */ + int getFlagCount() ; + + /** + * Return the flag associated with the vertex at the specified index. + */ + int getFlag(int index) ; +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedVertexList.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedVertexList.java new file mode 100644 index 0000000..08736fb --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedVertexList.java @@ -0,0 +1,429 @@ +/* + * $RCSfile: GeneralizedVertexList.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import java.util.ArrayList; +import javax.media.j3d.GeometryArray; +import javax.media.j3d.GeometryStripArray; +import javax.media.j3d.LineStripArray; +import javax.media.j3d.PointArray; +import javax.media.j3d.TriangleArray; +import javax.media.j3d.TriangleFanArray; +import javax.media.j3d.TriangleStripArray; +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +/** + * The GeneralizedVertexList class is a variable-size list used to + * collect the vertices for a generalized strip of points, lines, or + * triangles. This is used by the GeometryDecompressor. This class + * implements the GeneralizedStripFlags interface and provides methods + * for copying instance vertex data into various fixed-size + * GeometryArray representations. + * + * @see GeneralizedStrip + * @see GeometryDecompressor + */ +class GeneralizedVertexList implements GeneralizedStripFlags { + + // The ArrayList containing the vertices. + private ArrayList vertices ; + + // Booleans for individual vertex components. + private boolean hasColor3 = false ; + private boolean hasColor4 = false ; + private boolean hasNormals = false ; + + // Indicates the vertex winding of front-facing triangles in this strip. + private int frontFace ; + + /** + * Count of number of strips generated after conversion to GeometryArray. + */ + int stripCount ; + + /** + * Count of number of vertices generated after conversion to GeometryArray. + */ + int vertexCount ; + + /** + * Count of number of triangles generated after conversion to GeometryArray. + */ + int triangleCount ; + + /** + * Bits describing the data bundled with each vertex. This is specified + * using the GeometryArray mask components. + */ + int vertexFormat ; + + /** + * Creates a new GeneralizedVertexList for the specified vertex format. + * @param vertexFormat a mask indicating which components are + * present in each vertex, as used by GeometryArray. + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @param initSize initial number of elements + * @see GeometryArray + */ + GeneralizedVertexList(int vertexFormat, int frontFace, int initSize) { + this.frontFace = frontFace ; + setVertexFormat(vertexFormat) ; + + if (initSize == 0) + vertices = new ArrayList() ; + else + vertices = new ArrayList(initSize) ; + + stripCount = 0 ; + vertexCount = 0 ; + triangleCount = 0 ; + } + + /** + * Creates a new GeneralizedVertexList for the specified vertex format. + * @param vertexFormat a mask indicating which components are + * present in each vertex, as used by GeometryArray. + * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or + * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding + * @see GeometryArray + */ + GeneralizedVertexList(int vertexFormat, int frontFace) { + this(vertexFormat, frontFace, 0) ; + } + + /** + * Sets the vertex format for this vertex list. + * @param vertexFormat a mask indicating which components are + * present in each vertex, as used by GeometryArray. + */ + void setVertexFormat(int vertexFormat) { + this.vertexFormat = vertexFormat ; + + if ((vertexFormat & GeometryArray.NORMALS) != 0) + hasNormals = true ; + + if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) + hasColor4 = true ; + else if ((vertexFormat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3) + hasColor3 = true ; + } + + /** + * A class with fields corresponding to all the data that can be bundled + * with the vertices of generalized strips. + */ + class Vertex { + int flag ; + Point3f coord ; + Color3f color3 ; + Color4f color4 ; + Vector3f normal ; + + Vertex(Point3f p, Vector3f n, Color4f c, int flag) { + this.flag = flag ; + coord = new Point3f(p) ; + + if (hasNormals) + normal = new Vector3f(n) ; + + if (hasColor3) + color3 = new Color3f(c.x, c.y, c.z) ; + + else if (hasColor4) + color4 = new Color4f(c) ; + } + } + + /** + * Copy vertex data to a new Vertex object and add it to this list. + */ + void addVertex(Point3f pos, Vector3f norm, Color4f color, int flag) { + vertices.add(new Vertex(pos, norm, color, flag)) ; + } + + /** + * Return the number of vertices in this list. + */ + int size() { + return vertices.size() ; + } + + // GeneralizedStripFlags interface implementation + public int getFlagCount() { + return vertices.size() ; + } + + // GeneralizedStripFlags interface implementation + public int getFlag(int index) { + return ((Vertex)vertices.get(index)).flag ; + } + + // Copy vertices in the given order to a fixed-length GeometryArray. + // Using the array versions of the GeometryArray set() methods results in + // a significant performance improvement despite needing to create + // fixed-length arrays to hold the vertex elements. + private void copyVertexData(GeometryArray ga, + GeneralizedStrip.IntList indices) { + Vertex v ; + Point3f p3f[] = new Point3f[indices.count] ; + + if (hasNormals) { + Vector3f v3f[] = new Vector3f[indices.count] ; + if (hasColor3) { + Color3f c3f[] = new Color3f[indices.count] ; + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + v3f[i] = v.normal ; + c3f[i] = v.color3 ; + } + ga.setColors(0, c3f) ; + + } else if (hasColor4) { + Color4f c4f[] = new Color4f[indices.count] ; + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + v3f[i] = v.normal ; + c4f[i] = v.color4 ; + } + ga.setColors(0, c4f) ; + + } else { + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + v3f[i] = v.normal ; + } + } + ga.setNormals(0, v3f) ; + + } else { + if (hasColor3) { + Color3f c3f[] = new Color3f[indices.count] ; + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + c3f[i] = v.color3 ; + } + ga.setColors(0, c3f) ; + + } else if (hasColor4) { + Color4f c4f[] = new Color4f[indices.count] ; + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + c4f[i] = v.color4 ; + } + ga.setColors(0, c4f) ; + + } else { + for (int i = 0 ; i < indices.count ; i++) { + v = (Vertex)vertices.get(indices.ints[i]) ; + p3f[i] = v.coord ; + } + } + } + ga.setCoordinates(0, p3f) ; + } + + /** + * Output a PointArray. + */ + PointArray toPointArray() { + int size = vertices.size() ; + + if (size > 0) { + PointArray pa = new PointArray(size, vertexFormat) ; + GeneralizedStrip.IntList il = new GeneralizedStrip.IntList(size) ; + + il.fillAscending() ; + copyVertexData(pa, il) ; + + vertexCount += size ; + return pa ; + } + else + return null ; + } + + /** + * Output a TriangleArray. + */ + TriangleArray toTriangleArray() { + int vertices[] = GeneralizedStrip.toTriangles(this, frontFace) ; + + if (vertices != null) { + TriangleArray ta ; + GeneralizedStrip.IntList il ; + + ta = new TriangleArray(vertices.length, vertexFormat) ; + il = new GeneralizedStrip.IntList(vertices) ; + copyVertexData(ta, il) ; + + vertexCount += vertices.length ; + triangleCount += vertices.length/3 ; + return ta ; + } else + return null ; + } + + /** + * Output a LineStripArray. + */ + LineStripArray toLineStripArray() { + GeneralizedStrip.StripArray stripArray = + GeneralizedStrip.toLineStrips(this) ; + + if (stripArray != null) { + LineStripArray lsa ; + lsa = new LineStripArray(stripArray.vertices.count, + vertexFormat, + stripArray.stripCounts.trim()) ; + + copyVertexData(lsa, stripArray.vertices) ; + + vertexCount += stripArray.vertices.count ; + stripCount += stripArray.stripCounts.count ; + return lsa ; + } else + return null ; + } + + /** + * Output a TriangleStripArray. + */ + TriangleStripArray toTriangleStripArray() { + GeneralizedStrip.StripArray stripArray = + GeneralizedStrip.toTriangleStrips(this, frontFace) ; + + if (stripArray != null) { + TriangleStripArray tsa ; + tsa = new TriangleStripArray(stripArray.vertices.count, + vertexFormat, + stripArray.stripCounts.trim()) ; + + copyVertexData(tsa, stripArray.vertices) ; + + vertexCount += stripArray.vertices.count ; + stripCount += stripArray.stripCounts.count ; + return tsa ; + } else + return null ; + } + + /** + * Output triangle strip and triangle fan arrays. + * @return a 2-element array of GeometryStripArray; element 0 if non-null + * will contain a TriangleStripArray, and element 1 if non-null will + * contain a TriangleFanArray. + */ + GeometryStripArray[] toStripAndFanArrays() { + GeneralizedStrip.StripArray stripArray[] = + GeneralizedStrip.toStripsAndFans(this, frontFace) ; + + GeometryStripArray gsa[] = new GeometryStripArray[2] ; + + if (stripArray[0] != null) { + gsa[0] = new TriangleStripArray(stripArray[0].vertices.count, + vertexFormat, + stripArray[0].stripCounts.trim()) ; + + copyVertexData(gsa[0], stripArray[0].vertices) ; + + vertexCount += stripArray[0].vertices.count ; + stripCount += stripArray[0].stripCounts.count ; + } + + if (stripArray[1] != null) { + gsa[1] = new TriangleFanArray(stripArray[1].vertices.count, + vertexFormat, + stripArray[1].stripCounts.trim()) ; + + copyVertexData(gsa[1], stripArray[1].vertices) ; + + vertexCount += stripArray[1].vertices.count ; + stripCount += stripArray[1].stripCounts.count ; + } + return gsa ; + } + + /** + * Output triangle strip and and triangle arrays. + * @return a 2-element array of GeometryArray; element 0 if non-null + * will contain a TriangleStripArray, and element 1 if non-null will + * contain a TriangleArray. + */ + GeometryArray[] toStripAndTriangleArrays() { + GeneralizedStrip.StripArray stripArray[] = + GeneralizedStrip.toStripsAndTriangles(this, frontFace, 4, 12) ; + + GeometryArray ga[] = new GeometryArray[2] ; + + if (stripArray[0] != null) { + ga[0] = new TriangleStripArray(stripArray[0].vertices.count, + vertexFormat, + stripArray[0].stripCounts.trim()) ; + + copyVertexData(ga[0], stripArray[0].vertices) ; + + vertexCount += stripArray[0].vertices.count ; + stripCount += stripArray[0].stripCounts.count ; + } + + if (stripArray[1] != null) { + ga[1] = new TriangleArray(stripArray[1].vertices.count, + vertexFormat) ; + + copyVertexData(ga[1], stripArray[1].vertices) ; + triangleCount += stripArray[1].vertices.count/3 ; + } + return ga ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryCompressor.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryCompressor.java new file mode 100644 index 0000000..c38d309 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryCompressor.java @@ -0,0 +1,204 @@ +/* + * $RCSfile: GeometryCompressor.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import java.io.IOException; +import javax.vecmath.Point3d; + +/** + * A GeometryCompressor takes a stream of geometric elements and + * quantization parameters (the CompressionStream object) and + * compresses it into a stream of commands as defined by appendix B + * of the Java 3D specification. The resulting data may be output + * in the form of a CompressedGeometryData node component or appended + * to a CompressedGeometryFile. + * + * @see CompressionStream + * @see CompressedGeometryData + * @see CompressedGeometryFile + * + * @since Java 3D 1.5 + */ +public class GeometryCompressor { + private static final boolean benchmark = false ; + private static final boolean printStream = false ; + private static final boolean printHuffman = false ; + + private HuffmanTable huffmanTable ; + private CommandStream outputBuffer ; + private CompressedGeometryData.Header cgHeader ; + private long startTime ; + + public GeometryCompressor() { + // Create a compressed geometry header. + cgHeader = new CompressedGeometryData.Header() ; + + // v1.0.0 - pre-FCS + // v1.0.1 - fixed winding order, FCS version (J3D 1.1.2) + // v1.0.2 - normal component length maximum 6, LII hardware (J3D 1.2) + cgHeader.majorVersionNumber = 1 ; + cgHeader.minorVersionNumber = 0 ; + cgHeader.minorMinorVersionNumber = 2 ; + } + + /** + * Compress a stream into a CompressedGeometryData node component. + * + * + * @param stream CompressionStream containing the geometry to be compressed + * @return a CompressedGeometryData node component + */ + public CompressedGeometryData compress(CompressionStream stream) { + CompressedGeometryData cg ; + + compressStream(stream) ; + cg = new CompressedGeometryData(cgHeader, outputBuffer.getBytes()) ; + + outputBuffer.clear() ; + return cg ; + } + + /** + * Compress a stream and append the output to a CompressedGeometryFile. + * The resource remains open for subsequent updates; its close() method + * must be called to create a valid compressed geometry resource file. + * + * @param stream CompressionStream containing the geometry to be compressed + * @param f a currently open CompressedGeometryFile with write access + * @exception IOException if write fails + */ + public void compress(CompressionStream stream, CompressedGeometryFile f) + throws IOException { + + compressStream(stream) ; + f.write(cgHeader, outputBuffer.getBytes()) ; + + outputBuffer.clear() ; + } + + // + // Compress the stream and put the results in the output buffer. + // Set up the CompressedGeometryData.Header object. + // + private void compressStream(CompressionStream stream) { + if (benchmark) startTime = System.currentTimeMillis() ; + + // Create the Huffman table. + huffmanTable = new HuffmanTable() ; + + // Quantize the stream, compute deltas between consecutive elements if + // possible, and histogram the data length distribution. + stream.quantize(huffmanTable) ; + + // Compute tags for stream tokens. + huffmanTable.computeTags() ; + + // Create the output buffer and assemble the compressed output. + outputBuffer = new CommandStream(stream.getByteCount() / 3) ; + stream.outputCommands(huffmanTable, outputBuffer) ; + + // Print any desired info. + if (benchmark) printBench(stream) ; + if (printStream) stream.print() ; + if (printHuffman) huffmanTable.print() ; + + // Set up the compressed geometry header object. + cgHeader.bufferType = stream.streamType ; + cgHeader.bufferDataPresent = 0 ; + cgHeader.lowerBound = new Point3d(stream.ncBounds[0]) ; + cgHeader.upperBound = new Point3d(stream.ncBounds[1]) ; + + if (stream.vertexNormals) + cgHeader.bufferDataPresent |= + CompressedGeometryData.Header.NORMAL_IN_BUFFER ; + + if (stream.vertexColor3 || stream.vertexColor4) + cgHeader.bufferDataPresent |= + CompressedGeometryData.Header.COLOR_IN_BUFFER ; + + if (stream.vertexColor4) + cgHeader.bufferDataPresent |= + CompressedGeometryData.Header.ALPHA_IN_BUFFER ; + + cgHeader.start = 0 ; + cgHeader.size = outputBuffer.getByteCount() ; + + // Clear the huffman table for next use. + huffmanTable.clear() ; + } + + private void printBench(CompressionStream stream) { + long t = System.currentTimeMillis() - startTime ; + int vertexCount = stream.getVertexCount() ; + int meshReferenceCount = stream.getMeshReferenceCount() ; + int totalVertices = meshReferenceCount + vertexCount ; + float meshPercent = 100f * meshReferenceCount/(float)totalVertices ; + + float compressionRatio = + stream.getByteCount() / ((float)outputBuffer.getByteCount()) ; + + int vertexBytes = + 12 + (stream.vertexColor3 ? 12 : 0) + + (stream.vertexColor4 ? 16 : 0) + (stream.vertexNormals ? 12 : 0) ; + + float compressedVertexBytes = + outputBuffer.getByteCount() / (float)totalVertices ; + + System.out.println + ("\nGeometryCompressor:\n" + totalVertices + " total vertices\n" + + vertexCount + " streamed vertices\n" + meshReferenceCount + + " mesh buffer references (" + meshPercent + "%)\n" + + stream.getByteCount() + " bytes streamed geometry compressed to " + + outputBuffer.getByteCount() + " in " + (t/1000f) + " sec\n" + + (stream.getByteCount()/(float)t) + " kbytes/sec, " + + "stream compression ratio " + compressionRatio + "\n\n" + + vertexBytes + " original bytes per vertex, " + + compressedVertexBytes + " compressed bytes per vertex\n" + + "total vertex compression ratio " + + (vertexBytes / (float)compressedVertexBytes) + "\n\n" + + "lower bound " + stream.ncBounds[0].toString() +"\n" + + "upper bound " + stream.ncBounds[1].toString()) ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressor.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressor.java new file mode 100644 index 0000000..adc7a26 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressor.java @@ -0,0 +1,1236 @@ +/* + * $RCSfile: GeometryDecompressor.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import com.sun.j3d.internal.J3dUtilsI18N; +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +/** + * This abstract class provides the base methods needed to create a geometry + * decompressor. Subclasses must implement a backend to handle the output, + * consisting of a generalized triangle strip, line strip, or point array, + * along with possible global color and normal changes. + */ +abstract class GeometryDecompressor { + private static final boolean debug = false ; + private static final boolean benchmark = false ; + + /** + * Compressed geometry format version supported. + */ + static final int majorVersionNumber = 1 ; + static final int minorVersionNumber = 0 ; + static final int minorMinorVersionNumber = 2 ; + + /** + * This method is called when a SetState command is encountered in the + * decompression stream. + * + * @param bundlingNorm true indicates normals are bundled with vertices + * @param bundlingColor true indicates colors are bundled with vertices + * @param doingAlpha true indicates alpha values are bundled with vertices + */ + abstract void outputVertexFormat(boolean bundlingNorm, + boolean bundlingColor, + boolean doingAlpha) ; + + /** + * This method captures the vertex output of the decompressor. The normal + * or color references may be null if the corresponding data is not + * bundled with the vertices in the compressed geometry buffer. Alpha + * values may be included in the color. + * + * @param position The coordinates of the vertex. + * @param normal The normal bundled with the vertex. May be null. + * @param color The color bundled with the vertex. May be null. + * Alpha may be present. + * @param vertexReplaceCode Specifies the generalized strip flag + * that is bundled with each vertex. + * @see GeneralizedStripFlags + * @see CompressedGeometryHeader + */ + abstract void outputVertex(Point3f position, Vector3f normal, + Color4f color, int vertexReplaceCode) ; + + /** + * This method captures the global color output of the decompressor. It + * is only invoked if colors are not bundled with the vertex data. The + * global color applies to all succeeding vertices until the next time the + * method is invoked. + * + * @param color The current global color. + */ + abstract void outputColor(Color4f color) ; + + /** + * This method captures the global normal output of the decompressor. It + * is only invoked if normals are not bundled with the vertex data. The + * global normal applies to all succeeding vertices until the next time the + * method is invoked. + * + * @param normal The current global normal. + */ + abstract void outputNormal(Vector3f normal) ; + + // Geometry compression opcodes. + private static final int GC_VERTEX = 0x40 ; + private static final int GC_SET_NORM = 0xC0 ; + private static final int GC_SET_COLOR = 0x80 ; + private static final int GC_MESH_B_R = 0x20 ; + private static final int GC_SET_STATE = 0x18 ; + private static final int GC_SET_TABLE = 0x10 ; + private static final int GC_PASS_THROUGH = 0x08 ; + private static final int GC_EOS = 0x00 ; + private static final int GC_V_NO_OP = 0x01 ; + private static final int GC_SKIP_8 = 0x07 ; + + // Three 64-entry decompression tables are used: gctables[0] for + // positions, gctables[1] for colors, and gctables[2] for normals. + private HuffmanTableEntry gctables[][] ; + + /** + * Decompression table entry. + */ + static class HuffmanTableEntry { + int tagLength, dataLength ; + int rightShift, absolute ; + + public String toString() { + return + " tag length: " + tagLength + + " data length: " + dataLength + + " shift: " + rightShift + + " abs/rel: " + absolute ; + } + } + + // A 16-entry mesh buffer is used. + private MeshBufferEntry meshBuffer[] ; + private int meshIndex = 15 ; + private int meshState ; + + // meshState values. These are needed to determine if colors and/or + // normals should come from meshBuffer or from SetColor or SetNormal. + private static final int USE_MESH_NORMAL = 0x1 ; + private static final int USE_MESH_COLOR = 0x2 ; + + /** + * Mesh buffer entry containing position, normal, and color. + */ + static class MeshBufferEntry { + short x, y, z ; + short octant, sextant, u, v ; + short r, g, b, a ; + } + + // Geometry compression state variables. + private short curX, curY, curZ ; + private short curR, curG, curB, curA ; + private int curSex, curOct, curU, curV ; + + // Current vertex data. + private Point3f curPos ; + private Vector3f curNorm ; + private Color4f curColor ; + private int repCode ; + + // Flags indicating what data is bundled with the vertex. + private boolean bundlingNorm ; + private boolean bundlingColor ; + private boolean doingAlpha ; + + // Internal decompression buffering variables. + private int currentHeader = 0 ; + private int nextHeader = 0 ; + private int bitBuffer = 0 ; + private int bitBufferCount = 32 ; + + // Used for benchmarking if so configured. + private long startTime ; + private int vertexCount ; + + // Bit-field masks: BMASK[i] = (1< 64) continue ; + + psi = NORMAL_MAX_Y_ANG * (i / 64.0) ; + th = Math.asin(Math.tan(NORMAL_MAX_Y_ANG * ((64-j)/64.0))) ; + + qnx = Math.cos(th) * Math.cos(psi) ; + qny = Math.sin(psi) ; + qnz = Math.sin(th) * Math.cos(psi) ; + + // Convert the floating point normal to s1.14 bit notation, + // then back again. + qnx = qnx*16384.0 ; inx = (int)qnx ; + qnx = (double)inx ; qnx = qnx/16384.0 ; + + qny = qny*16384.0 ; iny = (int)qny ; + qny = (double)iny ; qny = qny/16384.0 ; + + qnz = qnz*16384.0 ; inz = (int)qnz ; + qnz = (double)inz ; qnz = qnz/16384.0 ; + + gcNormals[i][j][0] = qnx ; + gcNormals[i][j][1] = qny ; + gcNormals[i][j][2] = qnz ; + } + } + + if (printNormalTable) { + System.out.println("struct {") ; + System.out.println(" double nx, ny, nz ;") ; + System.out.println("} gcNormals[65][65] = {"); + for (i = 0 ; i <= 64 ; i++) { + System.out.println("{") ; + for (j = 0 ; j <= 64 ; j++) { + if (j+i > 64) continue ; + System.out.println("{ " + gcNormals[i][j][0] + + ", " + gcNormals[i][j][1] + + ", " + gcNormals[i][j][2] + " }") ; + } + System.out.println("},") ; + } + System.out.println("}") ; + } + } + + // + // The constructor. + // + GeometryDecompressor() { + curPos = new Point3f() ; + curNorm = new Vector3f() ; + curColor = new Color4f() ; + gctables = new HuffmanTableEntry[3][64] ; + + for (int i = 0 ; i < 64 ; i++) { + gctables[0][i] = new HuffmanTableEntry() ; + gctables[1][i] = new HuffmanTableEntry() ; + gctables[2][i] = new HuffmanTableEntry() ; + } + + meshBuffer = new MeshBufferEntry[16] ; + for (int i = 0 ; i < 16 ; i++) + meshBuffer[i] = new MeshBufferEntry() ; + } + + /** + * Check version numbers and return true if compatible. + */ + boolean checkVersion(int majorVersionNumber, int minorVersionNumber) { + return ((majorVersionNumber < this.majorVersionNumber) || + ((majorVersionNumber == this.majorVersionNumber) && + (minorVersionNumber <= this.minorVersionNumber))) ; + } + + /** + * Decompress data and invoke abstract output methods. + * + * @param start byte offset to start of compressed geometry in data array + * @param length size of compressed geometry in bytes + * @param data array containing compressed geometry buffer of the + * specified length at the given offset from the start of the array + * @exception ArrayIndexOutOfBoundsException if start+length > data size + */ + void decompress(int start, int length, byte data[]) { + if (debug) + System.out.println("GeometryDecompressor.decompress\n" + + " start: " + start + + " length: " + length + + " data array size: " + data.length) ; + if (benchmark) + benchmarkStart(length) ; + + if (start+length > data.length) + throw new ArrayIndexOutOfBoundsException + (J3dUtilsI18N.getString("GeometryDecompressor0")) ; + + // Set reference to compressed data and skip to start of data. + gcData = data ; + gcIndex = start ; + + // Initialize state. + bitBufferCount = 0 ; + meshState = 0 ; + bundlingNorm = false ; + bundlingColor = false ; + doingAlpha = false ; + repCode = 0 ; + + // Headers are interleaved for hardware implementations, so the + // first is always a nullop. + nextHeader = GC_V_NO_OP ; + + // Enter decompression loop. + while (gcIndex < start+length) + processDecompression() ; + + // Finish out any bits left in bitBuffer. + while (bitBufferCount > 0) + processDecompression() ; + + if (benchmark) + benchmarkPrint(length) ; + } + + // + // Return the next bitCount bits of compressed data. + // + private int getBits(int bitCount, String d) { + int bits ; + + if (debug) + System.out.print(" getBits(" + bitCount + ") " + d + ", " + + bitBufferCount + " available at gcIndex " + + gcIndex) ; + + if (bitCount == 0) { + if (debug) System.out.println(": got 0x0") ; + return 0 ; + } + + if (bitBufferCount == 0) { + bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) | + ((gcData[gcIndex++] & 0xff) << 16) | + ((gcData[gcIndex++] & 0xff) << 8) | + ((gcData[gcIndex++] & 0xff))) ; + + bitBufferCount = 32 ; + } + + if (bitBufferCount >= bitCount) { + bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ; + bitBuffer = bitBuffer << bitCount ; + bitBufferCount -= bitCount ; + } else { + bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ; + bits = bits >>> (bitCount - bitBufferCount) ; + bits = bits << (bitCount - bitBufferCount) ; + + bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) | + ((gcData[gcIndex++] & 0xff) << 16) | + ((gcData[gcIndex++] & 0xff) << 8) | + ((gcData[gcIndex++] & 0xff))) ; + + bits = bits | + ((bitBuffer >>> (32 - (bitCount - bitBufferCount))) & + BMASK[bitCount - bitBufferCount]) ; + + bitBuffer = bitBuffer << (bitCount - bitBufferCount) ; + bitBufferCount = 32 - (bitCount - bitBufferCount) ; + } + + if (debug) + System.out.println(": got 0x" + Integer.toHexString(bits)) ; + + return bits ; + } + + // + // Shuffle interleaved headers and opcodes. + // + private void processDecompression() { + int mbp ; + currentHeader = nextHeader ; + + if ((currentHeader & 0xC0) == GC_VERTEX) { + // Process a vertex. + if (!bundlingNorm && !bundlingColor) { + // get next opcode, process current position opcode + nextHeader = getBits(8, "header") ; + mbp = processDecompressionOpcode(0) ; + + } else if (bundlingNorm && !bundlingColor) { + // get normal header, process current position opcode + nextHeader = getBits(6, "normal") ; + mbp = processDecompressionOpcode(0) ; + currentHeader = nextHeader | GC_SET_NORM ; + + // get next opcode, process current normal opcode + nextHeader = getBits(8, "header") ; + processDecompressionOpcode(mbp) ; + + } else if (!bundlingNorm && bundlingColor) { + // get color header, process current position opcode + nextHeader = getBits(6, "color") ; + mbp = processDecompressionOpcode(0) ; + currentHeader = nextHeader | GC_SET_COLOR ; + + // get next opcode, process current color opcode + nextHeader = getBits(8, "header") ; + processDecompressionOpcode(mbp) ; + + } else { + // get normal header, process current position opcode + nextHeader = getBits(6, "normal") ; + mbp = processDecompressionOpcode(0) ; + currentHeader = nextHeader | GC_SET_NORM ; + + // get color header, process current normal opcode + nextHeader = getBits(6, "color") ; + processDecompressionOpcode(mbp) ; + currentHeader = nextHeader | GC_SET_COLOR ; + + // get next opcode, process current color opcode + nextHeader = getBits(8, "header") ; + processDecompressionOpcode(mbp) ; + } + + // Send out the complete vertex. + outputVertex(curPos, curNorm, curColor, repCode) ; + if (benchmark) vertexCount++ ; + + // meshState bits get turned off in the setColor and setNormal + // routines in order to keep track of what data a mesh buffer + // reference should use. + meshState |= USE_MESH_NORMAL ; + meshState |= USE_MESH_COLOR ; + + } else { + // Non-vertex case: get next opcode, then process current opcode. + nextHeader = getBits(8, "header") ; + processDecompressionOpcode(0) ; + } + } + + // + // Decode the opcode in currentHeader, and dispatch to the appropriate + // processing method. + // + private int processDecompressionOpcode(int mbp) { + if ((currentHeader & 0xC0) == GC_SET_NORM) + processSetNormal(mbp) ; + else if ((currentHeader & 0xC0) == GC_SET_COLOR) + processSetColor(mbp) ; + else if ((currentHeader & 0xC0) == GC_VERTEX) + // Return the state of the mesh buffer push bit + // when processing a vertex. + return processVertex() ; + else if ((currentHeader & 0xE0) == GC_MESH_B_R) { + processMeshBR() ; + + // Send out the complete vertex. + outputVertex(curPos, curNorm, curColor, repCode) ; + if (benchmark) vertexCount++ ; + + // meshState bits get turned off in the setColor and setNormal + // routines in order to keep track of what data a mesh buffer + // reference should use. + meshState |= USE_MESH_NORMAL ; + meshState |= USE_MESH_COLOR ; + } + else if ((currentHeader & 0xF8) == GC_SET_STATE) + processSetState() ; + else if ((currentHeader & 0xF8) == GC_SET_TABLE) + processSetTable() ; + else if ((currentHeader & 0xFF) == GC_EOS) + processEos() ; + else if ((currentHeader & 0xFF) == GC_V_NO_OP) + processVNoop() ; + else if ((currentHeader & 0xFF) == GC_PASS_THROUGH) + processPassThrough() ; + else if ((currentHeader & 0xFF) == GC_SKIP_8) + processSkip8() ; + + return 0 ; + } + + // + // Process a set state opcode. + // + private void processSetState() { + int ii ; + if (debug) + System.out.println("GeometryDecompressor.processSetState") ; + + ii = getBits(3, "bundling") ; + + bundlingNorm = ((currentHeader & 0x1) != 0) ; + bundlingColor = (((ii >>> 2) & 0x1) != 0) ; + doingAlpha = (((ii >>> 1) & 0x1) != 0) ; + + if (debug) + System.out.println(" bundling normal: " + bundlingNorm + + " bundling color: " + bundlingColor + + " alpha present: " + doingAlpha) ; + + // Call the abstract output implementation. + outputVertexFormat(bundlingNorm, bundlingColor, doingAlpha) ; + } + + // + // Process a set decompression table opcode. + // + // Extract the parameters of the table set command, + // and set the approprate table entries. + // + private void processSetTable() { + HuffmanTableEntry gct[] ; + int i, adr, tagLength, dataLength, rightShift, absolute ; + int ii, index ; + + if (debug) + System.out.println("GeometryDecompressor.processSetTable") ; + + // Get reference to approprate 64 entry table. + index = (currentHeader & 0x6) >>> 1 ; + gct = gctables[index] ; + + // Get the remaining bits of the set table command. + ii = getBits(15, "set table") ; + + // Extract the individual fields from the two bit strings. + adr = ((currentHeader & 0x1) << 6) | ((ii >>> 9) & 0x3F) ; + + // Get data length. For positions and colors, 0 really means 16, as 0 + // lengths are meaningless for them. Normal components are allowed to + // have lengths of 0. + dataLength = (ii >>> 5) & 0x0F ; + if (dataLength == 0 && index != 2) + dataLength = 16 ; + + rightShift = ii & 0x0F ; + absolute = (ii >>> 4) & 0x1 ; + + // + // Decode the tag length from the address field by finding the + // first set 1 from the left in the bitfield. + // + for (tagLength = 6 ; tagLength > 0 ; tagLength--) { + if ((adr >> tagLength) != 0) break ; + } + + // Shift the address bits up into place, and off the leading 1. + adr = (adr << (6 - tagLength)) & 0x3F ; + + if (debug) + System.out.println(" table " + ((currentHeader & 0x6) >>> 1) + + " address " + adr + + " tag length " + tagLength + + " data length " + dataLength + + " shift " + rightShift + + " absolute " + absolute) ; + + // Fill in the table fields with the specified values. + for (i = 0 ; i < (1 << (6 - tagLength)) ; i++) { + gct[adr+i].tagLength = tagLength ; + gct[adr+i].dataLength = dataLength ; + gct[adr+i].rightShift = rightShift ; + gct[adr+i].absolute = absolute ; + } + } + + + // + // Process a vertex opcode. Any bundled normal and/or color will be + // processed by separate methods. Return the mesh buffer push indicator. + // + private int processVertex() { + HuffmanTableEntry gct ; + float fX, fY, fZ ; + short dx, dy, dz ; + int mbp, x, y, z, dataLen ; + int ii ; + + // If the next command is a mesh buffer reference + // then use colors and normals from the mesh buffer. + meshState = 0 ; + + // Get a reference to the approprate tag table entry. + gct = gctables[0][currentHeader & 0x3F] ; + + if (debug) System.out.println("GeometryDecompressor.processVertex\n" + + gct.toString()) ; + + // Get the true length of the data. + dataLen = gct.dataLength - gct.rightShift ; + + // Read in the replace code and mesh buffer push bits, + // if they're not in the current header. + if (6 - (3 * dataLen) - gct.tagLength > 0) { + int numBits = 6 - (3 * dataLen) - gct.tagLength ; + int jj ; + + jj = currentHeader & BMASK[numBits] ; + ii = getBits(3 - numBits, "repcode/mbp") ; + ii |= (jj << (3 - numBits)) ; + } + else + ii = getBits(3, "repcode/mbp") ; + + repCode = ii >>> 1 ; + mbp = ii & 0x1 ; + + // Read in x, y, and z components. + x = currentHeader & BMASK[6-gct.tagLength] ; + + if (gct.tagLength + dataLen == 6) { + y = getBits(dataLen, "y") ; + z = getBits(dataLen, "z") ; + } else if (gct.tagLength + dataLen < 6) { + x = x >> (6 - gct.tagLength - dataLen) ; + + y = currentHeader & BMASK[6 - gct.tagLength - dataLen] ; + if (gct.tagLength + 2*dataLen == 6) { + z = getBits(dataLen, "z") ; + } else if (gct.tagLength + 2*dataLen < 6) { + y = y >> (6 - gct.tagLength - 2*dataLen) ; + + z = currentHeader & BMASK[6 - gct.tagLength - 2*dataLen] ; + if (gct.tagLength + 3*dataLen < 6) { + z = z >> (6 - gct.tagLength - 3*dataLen) ; + } else if (gct.tagLength + 3*dataLen > 6) { + ii = getBits(dataLen - (6 - gct.tagLength - 2*dataLen), + "z") ; + z = (z << (dataLen - (6 - gct.tagLength - 2*dataLen))) + | ii ; + } + } else { + ii = getBits(dataLen - (6 - gct.tagLength - dataLen), "y") ; + y = (y << (dataLen - (6 - gct.tagLength - dataLen))) | ii ; + z = getBits(dataLen, "z") ; + } + } else { + ii = getBits(dataLen - (6 - gct.tagLength), "x") ; + x = (x << (dataLen - (6 - gct.tagLength))) | ii ; + y = getBits(dataLen, "y") ; + z = getBits(dataLen, "z") ; + } + + // Sign extend delta x y z components. + x = x << (32 - dataLen) ; x = x >> (32 - dataLen) ; + y = y << (32 - dataLen) ; y = y >> (32 - dataLen) ; + z = z << (32 - dataLen) ; z = z >> (32 - dataLen) ; + + // Normalize values. + dx = (short)(x << gct.rightShift) ; + dy = (short)(y << gct.rightShift) ; + dz = (short)(z << gct.rightShift) ; + + // Update current position, first adding deltas if in relative mode. + if (gct.absolute != 0) { + curX = dx ; curY = dy ; curZ = dz ; + if (debug) System.out.println(" absolute position: " + + curX + " " + curY + " " + curZ) ; + } else { + curX += dx ; curY += dy ; curZ += dz ; + if (debug) System.out.println(" delta position: " + + dx + " " + dy + " " + dz) ; + } + + // Do optional mesh buffer push. + if (mbp != 0) { + // Increment to next position (meshIndex is initialized to 15). + meshIndex = (meshIndex + 1) & 0xF ; + meshBuffer[meshIndex].x = curX ; + meshBuffer[meshIndex].y = curY ; + meshBuffer[meshIndex].z = curZ ; + if (debug) + System.out.println(" pushed position into mesh buffer at " + + meshIndex) ; + } + + // Convert point back to [-1..1] floating point. + fX = curX ; fX /= 32768.0 ; + fY = curY ; fY /= 32768.0 ; + fZ = curZ ; fZ /= 32768.0 ; + if (debug) + System.out.println(" result position " + fX + " " + fY + " " + fZ) ; + + curPos.set(fX, fY, fZ) ; + return mbp ; + } + + + // + // Process a set current normal opcode. + // + private void processSetNormal(int mbp) { + HuffmanTableEntry gct ; + int index, du, dv, n, dataLength ; + int ii ; + + // if next command is a mesh buffer reference, use this normal + meshState &= ~USE_MESH_NORMAL ; + + // use table 2 for normals + gct = gctables[2][currentHeader & 0x3F] ; + + if (debug) + System.out.println("GeometryDecompressor.processSetNormal\n" + + gct.toString()) ; + + // subtract up-shift amount to get true data (u, v) length + dataLength = gct.dataLength - gct.rightShift ; + + if (gct.absolute != 0) { + // + // Absolute normal case. Extract index from 6-bit tag. + // + index = currentHeader & BMASK[6-gct.tagLength] ; + + if (gct.tagLength != 0) { + // read in the rest of the 6-bit sex/oct pair (index) + ii = getBits(6 - (6 - gct.tagLength), "sex/oct") ; + index = (index << (6 - (6 - gct.tagLength))) | ii ; + } + + // read in u and v data + curU = getBits(dataLength, "u") ; + curV = getBits(dataLength, "v") ; + + // normalize u, v, sextant, and octant + curU = curU << gct.rightShift ; + curV = curV << gct.rightShift ; + + curSex = (index >> 3) & 0x7 ; + curOct = index & 0x7 ; + + if (debug) { + if (curSex < 6) + System.out.println(" absolute normal: sex " + curSex + + " oct " + curOct + + " u " + curU + " v " + curV) ; + else + System.out.println(" special normal: sex " + curSex + + " oct " + curOct) ; + } + } else { + // + // Relative normal case. Extract du from 6-bit tag. + // + du = currentHeader & BMASK[6-gct.tagLength] ; + + if (gct.tagLength + dataLength < 6) { + // normalize du, get dv + du = du >> (6 - gct.tagLength - dataLength) ; + dv = currentHeader & BMASK[6 - gct.tagLength - dataLength] ; + + if (gct.tagLength + 2*dataLength < 6) { + // normalize dv + dv = dv >> (6 - gct.tagLength - 2*dataLength) ; + } else if (gct.tagLength + 2*dataLength > 6) { + // read in rest of dv and normalize it + ii = getBits(dataLength - + (6 - gct.tagLength - dataLength), "dv") ; + dv = (dv << (dataLength - + (6 - gct.tagLength - dataLength))) | ii ; + } + } else if (gct.tagLength + dataLength > 6) { + // read in rest of du and normalize it + ii = getBits(dataLength - (6 - gct.tagLength), "du") ; + du = (du << (dataLength - (6 - gct.tagLength))) | ii ; + // read in dv + dv = getBits(dataLength, "dv") ; + } else { + // read in dv + dv = getBits(dataLength, "dv") ; + } + + // Sign extend delta uv components. + du = du << (32 - dataLength) ; du = du >> (32 - dataLength) ; + dv = dv << (32 - dataLength) ; dv = dv >> (32 - dataLength) ; + + // normalize values + du = du << gct.rightShift ; + dv = dv << gct.rightShift ; + + // un-delta + curU += du ; + curV += dv ; + + if (debug) + System.out.println(" delta normal: du " + du + " dv " + dv) ; + + // + // Check for normal wrap. + // + if (! ((curU >= 0) && (curV >= 0) && (curU + curV <= 64))) + if ((curU < 0) && (curV >= 0)) { + // wrap on u, same octant, different sextant + curU = -curU ; + switch (curSex) { + case 0: curSex = 4 ; break ; + case 1: curSex = 5 ; break ; + case 2: curSex = 3 ; break ; + case 3: curSex = 2 ; break ; + case 4: curSex = 0 ; break ; + case 5: curSex = 1 ; break ; + } + } else if ((curU >= 0) && (curV < 0)) { + // wrap on v, same sextant, different octant + curV = -curV ; + switch (curSex) { + case 1: case 5: + curOct = curOct ^ 4 ; // invert x axis + break ; + case 0: case 4: + curOct = curOct ^ 2 ; // invert y axis + break ; + case 2: case 3: + curOct = curOct ^ 1 ; // invert z axis + break ; + } + } else if (curU + curV > 64) { + // wrap on uv, same octant, different sextant + curU = 64 - curU ; + curV = 64 - curV ; + switch (curSex) { + case 0: curSex = 2 ; break ; + case 1: curSex = 3 ; break ; + case 2: curSex = 0 ; break ; + case 3: curSex = 1 ; break ; + case 4: curSex = 5 ; break ; + case 5: curSex = 4 ; break ; + } + } else { + throw new IllegalArgumentException + (J3dUtilsI18N.getString("GeometryDecompressor1")) ; + } + } + + // do optional mesh buffer push + if (mbp != 0) { + if (debug) + System.out.println(" pushing normal into mesh buffer at " + + meshIndex) ; + + meshBuffer[meshIndex].sextant = (short)curSex ; + meshBuffer[meshIndex].octant = (short)curOct ; + meshBuffer[meshIndex].u = (short)curU ; + meshBuffer[meshIndex].v = (short)curV ; + } + + // convert normal back to [-1..1] floating point + indexNormal(curSex, curOct, curU, curV, curNorm) ; + + // a set normal opcode when normals aren't bundled with the vertices + // is a global normal change. + if (! bundlingNorm) outputNormal(curNorm) ; + } + + + // + // Get the floating point normal from its sextant, octant, u, and v. + // + private void indexNormal(int sex, int oct, int u, int v, Vector3f n) { + float nx, ny, nz, t ; + + if (debug) System.out.println(" sextant " + sex + " octant " + oct + + " u " + u + " v " + v) ; + if (sex > 5) { + // special normals + switch (oct & 0x1) { + case 0: // six coordinate axes + switch (((sex & 0x1) << 1) | ((oct & 0x4) >> 2)) { + case 0: nx = 1.0f ; ny = nz = 0.0f ; break ; + case 1: ny = 1.0f ; nx = nz = 0.0f ; break ; + default: + case 2: nz = 1.0f ; nx = ny = 0.0f ; break ; + } + sex = 0 ; oct = (oct & 0x2) >> 1 ; + oct = (oct << 2) | (oct << 1) | oct ; + break ; + case 1: // eight mid + default: + oct = ((sex & 0x1) << 2) | (oct >> 1) ; + sex = 0 ; + nx = ny = nz = (float)(1.0/Math.sqrt(3.0)) ; + break ; + } + if ((oct & 0x1) != 0) nz = -nz ; + if ((oct & 0x2) != 0) ny = -ny ; + if ((oct & 0x4) != 0) nx = -nx ; + + } else { + // regular normals + nx = (float)gcNormals[v][u][0] ; + ny = (float)gcNormals[v][u][1] ; + nz = (float)gcNormals[v][u][2] ; + + // reverse the swap + if ((sex & 0x4) != 0) { t = nx ; nx = nz ; nz = t ; } + if ((sex & 0x2) != 0) { t = ny ; ny = nz ; nz = t ; } + if ((sex & 0x1) != 0) { t = nx ; nx = ny ; ny = t ; } + + // reverse the sign flip + if ((oct & 0x1) != 0) nz = -nz ; + if ((oct & 0x2) != 0) ny = -ny ; + if ((oct & 0x4) != 0) nx = -nx ; + } + + // return resulting normal + n.set(nx, ny, nz) ; + if (debug) + System.out.println(" result normal: " + nx + " " + ny + " " + nz) ; + } + + + // + // Process a set current color command. + // + private void processSetColor(int mbp) { + HuffmanTableEntry gct ; + short dr, dg, db, da ; + float fR, fG, fB, fA ; + int r, g, b, a, index, dataLength ; + int ii ; + + // If the next command is a mesh buffer reference, use this color. + meshState &= ~USE_MESH_COLOR ; + + // Get the huffman table entry. + gct = gctables[1][currentHeader & 0x3F] ; + + if (debug) + System.out.println("GeometryDecompressor.processSetColor\n" + + gct.toString()) ; + + // Get the true length of the data. + dataLength = gct.dataLength - gct.rightShift ; + + // Read in red, green, blue, and possibly alpha. + r = currentHeader & BMASK[6 - gct.tagLength] ; + a = 0 ; + + if (gct.tagLength + dataLength == 6) { + g = getBits(dataLength, "g") ; + b = getBits(dataLength, "b") ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + else if (gct.tagLength + dataLength < 6) { + r = r >> (6 - gct.tagLength - dataLength) ; + + g = currentHeader & BMASK[6-gct.tagLength-dataLength] ; + if (gct.tagLength + 2*dataLength == 6) { + b = getBits(dataLength, "b") ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + else if (gct.tagLength + 2*dataLength < 6) { + g = g >> (6 - gct.tagLength - 2*dataLength) ; + + b = currentHeader & BMASK[6-gct.tagLength-2*dataLength] ; + if (gct.tagLength + 3*dataLength == 6) { + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + else if (gct.tagLength + 3*dataLength < 6) { + b = b >> (6 - gct.tagLength - 3*dataLength) ; + + if (doingAlpha) { + a = currentHeader & + BMASK[6 - gct.tagLength - 4*dataLength] ; + if (gct.tagLength + 4 * dataLength < 6) { + a = a >> (6 - gct.tagLength - 3*dataLength) ; + } + else if (gct.tagLength + 4 * dataLength > 6) { + ii = getBits(dataLength - + (6-gct.tagLength - 3*dataLength), "a") ; + a = (a << (dataLength - + (6-gct.tagLength - 3*dataLength))) | ii ; + } + } + } else { + ii = getBits(dataLength - + (6 - gct.tagLength - 2*dataLength), "b") ; + b = (b << (dataLength - + (6 - gct.tagLength - 2*dataLength))) | ii ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + } else { + ii = getBits(dataLength - (6 - gct.tagLength - dataLength), + "g") ; + g = (g << (dataLength - + (6 - gct.tagLength - dataLength))) | ii ; + b = getBits(dataLength, "b") ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + } else { + ii = getBits(dataLength - (6 - gct.tagLength), "r") ; + r = (r << (dataLength - (6 - gct.tagLength))) | ii ; + g = getBits(dataLength, "g") ; + b = getBits(dataLength, "b") ; + if (doingAlpha) + a = getBits(dataLength, "a") ; + } + + // Sign extend delta x y z components. + r <<= (32 - dataLength) ; r >>= (32 - dataLength) ; + g <<= (32 - dataLength) ; g >>= (32 - dataLength) ; + b <<= (32 - dataLength) ; b >>= (32 - dataLength) ; + a <<= (32 - dataLength) ; a >>= (32 - dataLength) ; + + // Normalize values. + dr = (short)(r << gct.rightShift) ; + dg = (short)(g << gct.rightShift) ; + db = (short)(b << gct.rightShift) ; + da = (short)(a << gct.rightShift) ; + + // Update current position, first adding deltas if in relative mode. + if (gct.absolute != 0) { + curR = dr ; curG = dg ; curB = db ; + if (doingAlpha) curA = da ; + if (debug) System.out.println(" absolute color: r " + curR + + " g " + curG + " b " + curB + + " a " + curA) ; + } else { + curR += dr ; curG += dg ; curB += db ; + if (doingAlpha) curA += da ; + if (debug) System.out.println(" delta color: dr " + dr + + " dg " + dg + " db " + db + + " da " + da) ; + } + + // Do optional mesh buffer push. + if (mbp != 0) { + if (debug) + System.out.println(" pushing color into mesh buffer at " + + meshIndex) ; + + meshBuffer[meshIndex].r = curR ; + meshBuffer[meshIndex].g = curG ; + meshBuffer[meshIndex].b = curB ; + meshBuffer[meshIndex].a = curA ; + } + + // Convert point back to [-1..1] floating point. + fR = curR ; fR /= 32768.0 ; + fG = curG ; fG /= 32768.0 ; + fB = curB ; fB /= 32768.0 ; + fA = curA ; fA /= 32768.0 ; + + curColor.set(fR, fG, fB, fA) ; + if (debug) System.out.println(" result color: " + fR + + " " + fG + " " + fB + " " + fA) ; + + // A set color opcode when colors aren't bundled with the vertices + // is a global color change. + if (! bundlingColor) outputColor(curColor) ; + } + + + // + // Process a mesh buffer reference command. + // + private void processMeshBR() { + MeshBufferEntry entry ; + int index, normal ; + int ii ; + + if (debug) + System.out.println("GeometryDecompressor.processMeshBR") ; + + ii = getBits(1, "mbr") ; + + index = (currentHeader >>> 1) & 0xF ; + repCode = ((currentHeader & 0x1) << 1) | ii ; + + // Adjust index to proper place in fifo. + index = (meshIndex - index) & 0xf ; + if (debug) + System.out.println(" using index " + index) ; + + // Get reference to mesh buffer entry. + entry = meshBuffer[index] ; + curX = entry.x ; + curY = entry.y ; + curZ = entry.z ; + + // Convert point back to [-1..1] floating point. + curPos.set(((float)curX)/32768.0f, + ((float)curY)/32768.0f, + ((float)curZ)/32768.0f) ; + + if (debug) System.out.println(" retrieved position " + curPos.x + + " " + curPos.y + " " + curPos.z + + " replace code " + repCode) ; + + // Get mesh buffer normal if previous opcode was not a setNormal. + if (bundlingNorm && ((meshState & USE_MESH_NORMAL) != 0)) { + curSex = entry.sextant ; + curOct = entry.octant ; + curU = entry.u ; + curV = entry.v ; + + // Convert normal back to -1.0 - 1.0 floating point from index. + normal = (curSex<<15) | (curOct<<12) | (curU<<6) | curV ; + + if (debug) System.out.println(" retrieving normal") ; + indexNormal(curSex, curOct, curU, curV, curNorm) ; + } + + // Get mesh buffer color if previous opcode was not a setColor. + if (bundlingColor && ((meshState & USE_MESH_COLOR) != 0)) { + curR = entry.r ; + curG = entry.g ; + curB = entry.b ; + + // Convert point back to -1.0 - 1.0 floating point. + curColor.x = curR ; curColor.x /= 32768.0 ; + curColor.y = curG ; curColor.y /= 32768.0 ; + curColor.z = curB ; curColor.z /= 32768.0 ; + + if (doingAlpha) { + curA = entry.a ; + curColor.w = curA ; curColor.w /= 32768.0 ; + } + if (debug) + System.out.println(" retrieved color " + curColor.x + + " " + curColor.y + " " + curColor.z + + " " + curColor.w) ; + } + + // Reset meshState. + meshState = 0 ; + } + + + // Process a end-of-stream opcode. + private void processEos() { + if (debug) System.out.println("GeometryDecompressor.processEos") ; + } + + // Process a variable length no-op opcode. + private void processVNoop() { + int ii, ct ; + if (debug) System.out.println("GeometryDecompressor.processVNoop") ; + + ct = getBits(5, "noop count") ; + ii = getBits(ct, "noop bits") ; + } + + // Process a pass-through opcode. + private void processPassThrough() { + int ignore ; + if (debug) + System.out.println("GeometryDecompressor.processPassThrough") ; + + ignore = getBits(24, "passthrough") ; + ignore = getBits(32, "passthrough") ; + } + + // Process a skip-8 opcode. + private void processSkip8() { + int skip ; + if (debug) System.out.println("GeometryDecompressor.processSkip8") ; + + skip = getBits(8, "skip8") ; + } + + private void benchmarkStart(int length) { + vertexCount = 0 ; + System.out.println(" GeometryDecompressor: decompressing " + + length + " bytes...") ; + startTime = System.currentTimeMillis() ; + } + + private void benchmarkPrint(int length) { + float t = (System.currentTimeMillis() - startTime) / 1000.0f ; + System.out.println + (" done in " + t + " sec." + "\n" + + " decompressed " + vertexCount + " vertices at " + + (vertexCount/t) + " vertices/sec\n") ; + + System.out.print(" vertex data present: coords") ; + int floatVertexSize = 12 ; + if (bundlingNorm) { + System.out.print(" normals") ; + floatVertexSize += 12 ; + } + if (bundlingColor) { + System.out.println(" colors") ; + floatVertexSize += 12 ; + } + if (doingAlpha) { + System.out.println(" alpha") ; + floatVertexSize += 4 ; + } + System.out.println() ; + + System.out.println + (" bytes of data in generalized strip output: " + + (vertexCount * floatVertexSize) + "\n" + + " compression ratio: " + + (length / (float)(vertexCount * floatVertexSize)) + "\n") ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressorShape3D.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressorShape3D.java new file mode 100644 index 0000000..d2a3b4e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressorShape3D.java @@ -0,0 +1,523 @@ +/* + * $RCSfile: GeometryDecompressorShape3D.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:22 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import com.sun.j3d.internal.J3dUtilsI18N; +import java.util.ArrayList; +import javax.media.j3d.Appearance; +import javax.media.j3d.GeometryArray; +import javax.media.j3d.GeometryStripArray; +import javax.media.j3d.LineStripArray; +import javax.media.j3d.Material; +import javax.media.j3d.PointArray; +import javax.media.j3d.Shape3D; +import javax.media.j3d.TriangleArray; +import javax.media.j3d.TriangleStripArray; +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +/** + * This class implements a Shape3D backend for the abstract + * GeometryDecompressor. + */ +class GeometryDecompressorShape3D extends GeometryDecompressor { + private static final boolean debug = false ; + private static final boolean benchmark = false ; + private static final boolean statistics = false ; + private static final boolean printInfo = debug || benchmark || statistics ; + + // Type of connections in the compressed data: + // TYPE_POINT (1), TYPE_LINE (2), or TYPE_TRIANGLE (4). + private int bufferDataType ; + + // Data bundled with each vertex: bitwise combination of + // NORMAL_IN_BUFFER (1), COLOR_IN_BUFFER (2), ALPHA_IN_BUFFER (4). + private int dataPresent ; + + // List for accumulating the output of the decompressor and converting to + // GeometryArray representations. + private GeneralizedVertexList vlist ; + + // Accumulates Shape3D objects constructed from decompressor output. + private ArrayList shapes ; + + // Decompressor output state variables. + private Color4f curColor ; + private Vector3f curNormal ; + + // Variables for gathering statistics. + private int origVertexCount ; + private int stripCount ; + private int vertexCount ; + private int triangleCount ; + private long startTime ; + private long endTime ; + + // Triangle array type to construct. + private int triOutputType ; + + // Types of triangle output available. + private static final int TRI_SET = 0 ; + private static final int TRI_STRIP_SET = 1 ; + private static final int TRI_STRIP_AND_FAN_SET = 2 ; + private static final int TRI_STRIP_AND_TRI_SET = 3 ; + + // Private convenience copies of various constants. + private static final int TYPE_POINT = + CompressedGeometryRetained.TYPE_POINT ; + private static final int TYPE_LINE = + CompressedGeometryRetained.TYPE_LINE ; + private static final int TYPE_TRIANGLE = + CompressedGeometryRetained.TYPE_TRIANGLE ; + private static final int FRONTFACE_CCW = + GeneralizedStripFlags.FRONTFACE_CCW ; + + /** + * Decompress the given compressed geometry. + * @param cgr CompressedGeometryRetained object with compressed geometry + * @return an array of Shape3D with TriangleArray geometry if compressed + * data contains triangles; otherwise, Shape3D array containing PointArray + * or LineStripArray geometry + * @see CompressedGeometry + * @see GeometryDecompressor + */ + Shape3D[] toTriangleArrays(CompressedGeometryRetained cgr) { + return decompress(cgr, TRI_SET) ; + } + + + /** + * Decompress the given compressed geometry. + * @param cgr CompressedGeometryRetained object with compressed geometry + * @return an array of Shape3D with TriangleStripArray geometry if + * compressed data contains triangles; otherwise, Shape3D array containing + * PointArray or LineStripArray geometry + * @see CompressedGeometry + * @see GeometryDecompressor + */ + Shape3D[] toTriangleStripArrays(CompressedGeometryRetained cgr) { + return decompress(cgr, TRI_STRIP_SET) ; + } + + + /** + * Decompress the given compressed geometry. + * @param cgr CompressedGeometryRetained object with compressed geometry + * @return an array of Shape3D with TriangleStripArray and + * TriangleFanArray geometry if compressed data contains triangles; + * otherwise, Shape3D array containing PointArray or LineStripArray + * geometry + * @see CompressedGeometry + * @see GeometryDecompressor + */ + Shape3D[] toStripAndFanArrays(CompressedGeometryRetained cgr) { + return decompress(cgr, TRI_STRIP_AND_FAN_SET) ; + } + + + /** + * Decompress the given compressed geometry. + * @param cgr CompressedGeometryRetained object with compressed geometry + * @return an array of Shape3D with TriangleStripArray and + * TriangleArray geometry if compressed data contains triangles; + * otherwise, Shape3D array containing PointArray or LineStripArray + * geometry + * @see CompressedGeometry + * @see GeometryDecompressor + */ + Shape3D[] toStripAndTriangleArrays(CompressedGeometryRetained cgr) { + return decompress(cgr, TRI_STRIP_AND_TRI_SET) ; + } + + /** + * Decompress the data contained in a CompressedGeometryRetained and + * return an array of Shape3D objects using the specified triangle output + * type. The triangle output type is ignored if the compressed data + * contains points or lines. + */ + private Shape3D[] decompress(CompressedGeometryRetained cgr, + int triOutputType) { + + if (! checkVersion(cgr.majorVersionNumber, cgr.minorVersionNumber)) { + return null ; + } + + vlist = null ; + curColor = null ; + curNormal = null ; + + // Get descriptors for compressed data. + bufferDataType = cgr.bufferType ; + dataPresent = cgr.bufferContents ; + if (printInfo) beginPrint() ; + + // Initialize the decompressor backend. + this.triOutputType = triOutputType ; + shapes = new ArrayList() ; + + // Call the superclass decompress() method which calls the output + // methods of this subclass. The results are stored in vlist. + super.decompress(cgr.offset, cgr.size, cgr.compressedGeometry) ; + + // Convert the decompressor output to Shape3D objects. + addShape3D() ; + if (printInfo) endPrint() ; + + // Return the fixed-length output array. + Shape3D shapeArray[] = new Shape3D[shapes.size()] ; + return (Shape3D[])shapes.toArray(shapeArray) ; + } + + /** + * Initialize the vertex output list based on the vertex format provided + * by the SetState decompression command. + */ + void outputVertexFormat(boolean bundlingNorm, boolean bundlingColor, + boolean doingAlpha) { + + if (vlist != null) + // Construct shapes using the current vertex format. + addShape3D() ; + + int vertexFormat = GeometryArray.COORDINATES ; + + if (bundlingNorm) { + vertexFormat |= GeometryArray.NORMALS ; + } + + if (bundlingColor) { + if (doingAlpha) { + vertexFormat |= GeometryArray.COLOR_4; + } else { + vertexFormat |= GeometryArray.COLOR_3; + } + } + + vlist = new GeneralizedVertexList(vertexFormat, FRONTFACE_CCW) ; + } + + /** + * Add a new decompressed vertex to the current list. + */ + void outputVertex(Point3f position, Vector3f normal, + Color4f color, int vertexReplaceCode) { + + if (curNormal != null) normal = curNormal ; + vlist.addVertex(position, normal, color, vertexReplaceCode) ; + + if (debug) { + System.out.println(" outputVertex: flag " + vertexReplaceCode) ; + System.out.println(" position " + position.toString()) ; + if (normal != null) + System.out.println(" normal " + normal.toString()) ; + if (color != null) + System.out.println(" color " + color.toString()) ; + } + } + + /** + * Create a Shape3D using the current color for both the ambient and + * diffuse material colors, then start a new vertex list for the new + * color. The outputColor() method is never called if colors are bundled + * with each vertex in the compressed buffer. + */ + void outputColor(Color4f color) { + if (debug) System.out.println(" outputColor: " + color.toString()) ; + + if (vlist.size() > 0) { + // Construct Shape3D using the current color. + addShape3D() ; + + // Start a new vertex list for the new color. + vlist = new GeneralizedVertexList(vlist.vertexFormat, + FRONTFACE_CCW) ; + } + if (curColor == null) curColor = new Color4f() ; + curColor.set(color) ; + } + + /** + * Set the current normal that will be copied to each succeeding vertex + * output by the decompressor. The per-vertex copy is needed since in + * Java 3D a normal is always associated with a vertex. This method is + * never called if normals are bundled with each vertex in the compressed + * buffer. + */ + void outputNormal(Vector3f normal) { + if (debug) System.out.println(" outputNormal: " + normal.toString()) ; + + if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0) { + if (vlist.size() > 0) + // Construct Shape3D using the current vertex format. + addShape3D() ; + + // Start a new vertex list with the new format. + vlist = new GeneralizedVertexList + (vlist.vertexFormat|GeometryArray.NORMALS, FRONTFACE_CCW) ; + } + if (curNormal == null) curNormal = new Vector3f() ; + curNormal.set(normal) ; + } + + /** + * Create a Shape3D object of the desired type from the current vertex + * list. Apply the current color, if non-null, as a Material attribute. + */ + private void addShape3D() { + Material m = new Material() ; + + if (curColor != null) { + if ((vlist.vertexFormat & GeometryArray.COLOR_4) != GeometryArray.COLOR_4) { + m.setAmbientColor(curColor.x, curColor.y, curColor.z) ; + m.setDiffuseColor(curColor.x, curColor.y, curColor.z) ; + } + else { + m.setAmbientColor(curColor.x, curColor.y, curColor.z) ; + m.setDiffuseColor(curColor.x, curColor.y, curColor.z, + curColor.w) ; + } + } + + if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0) + m.setLightingEnable(false) ; + else + m.setLightingEnable(true) ; + + Appearance a = new Appearance() ; + a.setMaterial(m) ; + + switch(bufferDataType) { + case TYPE_TRIANGLE: + switch(triOutputType) { + case TRI_SET: + TriangleArray ta = vlist.toTriangleArray() ; + if (ta != null) + shapes.add(new Shape3D(ta, a)) ; + break ; + case TRI_STRIP_SET: + TriangleStripArray tsa = vlist.toTriangleStripArray() ; + if (tsa != null) + shapes.add(new Shape3D(tsa, a)) ; + break ; + case TRI_STRIP_AND_FAN_SET: + GeometryStripArray gsa[] = vlist.toStripAndFanArrays() ; + if (gsa[0] != null) + shapes.add(new Shape3D(gsa[0], a)) ; + if (gsa[1] != null) + shapes.add(new Shape3D(gsa[1], a)) ; + break ; + case TRI_STRIP_AND_TRI_SET: + GeometryArray ga[] = vlist.toStripAndTriangleArrays() ; + if (ga[0] != null) + shapes.add(new Shape3D(ga[0], a)) ; + if (ga[1] != null) + shapes.add(new Shape3D(ga[1], a)) ; + break ; + default: + throw new IllegalArgumentException + (J3dUtilsI18N.getString("GeometryDecompressorShape3D0")) ; + } + break ; + + case TYPE_LINE: + LineStripArray lsa = vlist.toLineStripArray() ; + if (lsa != null) + shapes.add(new Shape3D(lsa, a)) ; + break ; + + case TYPE_POINT: + PointArray pa = vlist.toPointArray() ; + if (pa != null) + shapes.add(new Shape3D(pa, a)) ; + break ; + + default: + throw new IllegalArgumentException + (J3dUtilsI18N.getString("GeometryDecompressorShape3D1")) ; + } + + if (benchmark || statistics) { + origVertexCount += vlist.size() ; + vertexCount += vlist.vertexCount ; + stripCount += vlist.stripCount ; + triangleCount += vlist.triangleCount ; + } + } + + private void beginPrint() { + System.out.println("\nGeometryDecompressorShape3D") ; + + switch(bufferDataType) { + case TYPE_TRIANGLE: + System.out.println(" buffer TYPE_TRIANGLE") ; + break ; + case TYPE_LINE: + System.out.println(" buffer TYPE_LINE") ; + break ; + case TYPE_POINT: + System.out.println(" buffer TYPE_POINT") ; + break ; + default: + throw new IllegalArgumentException + (J3dUtilsI18N.getString("GeometryDecompressorShape3D1")) ; + } + + System.out.print(" buffer data present: coords") ; + + if ((dataPresent & CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0) + System.out.print(" normals") ; + if ((dataPresent & CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0) + System.out.print(" colors") ; + if ((dataPresent & CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0) + System.out.print(" alpha") ; + + System.out.println() ; + + stripCount = 0 ; + vertexCount = 0 ; + triangleCount = 0 ; + origVertexCount = 0 ; + + startTime = System.currentTimeMillis() ; + } + + private void endPrint() { + endTime = System.currentTimeMillis() ; + + if (benchmark || statistics) + printBench() ; + + if (statistics) + printStats() ; + } + + private void printBench() { + float t = (endTime - startTime) / 1000.0f ; + System.out.println + (" decompression + strip conversion took " + t + " sec.") ; + + switch(bufferDataType) { + case TYPE_POINT: + System.out.println + (" points decompressed: " + vertexCount + "\n" + + " net decompression rate: " + (vertexCount/t) + + " points/sec.\n") ; + break ; + case TYPE_LINE: + System.out.println + (" lines decompressed: " + (vertexCount - stripCount) + "\n" + + " net decompression rate: " + ((vertexCount - stripCount)/t) + + " lines/sec.\n") ; + break ; + case TYPE_TRIANGLE: + System.out.println + (" triangles decompressed: " + + (vertexCount - 2*stripCount) + "\n" + + " net decompression rate: " + + ((vertexCount - 2*stripCount)/t) + " triangles/sec.\n") ; + break ; + } + } + + private void printStats() { + switch(triOutputType) { + case TRI_SET: + System.out.println(" using individual triangle output") ; + break ; + case TRI_STRIP_SET: + System.out.println(" using strip output") ; + break ; + case TRI_STRIP_AND_FAN_SET: + System.out.println(" using strips and fans for output") ; + break ; + case TRI_STRIP_AND_TRI_SET: + System.out.println(" using strips and triangles for output") ; + break ; + } + + System.out.print + (" number of Shape3D objects: " + shapes.size() + + "\n number of Shape3D decompressed vertices: ") ; + + if (triOutputType == TRI_SET || bufferDataType == TYPE_POINT) { + System.out.println(vertexCount) ; + } + else if (triOutputType == TRI_STRIP_AND_TRI_SET) { + System.out.println((vertexCount + triangleCount*3) + + "\n number of strips: " + stripCount + + "\n number of individual triangles: " + + triangleCount) ; + if (stripCount > 0) + System.out.println + (" vertices/strip: " + (float)vertexCount/stripCount + + "\n triangles represented in strips: " + + (vertexCount - 2*stripCount)) ; + } + else { + System.out.println(vertexCount + + "\n number of strips: " + stripCount) ; + if (stripCount > 0) + System.out.println + (" vertices/strip: " + (float)vertexCount/stripCount) ; + } + + System.out.print(" vertex data present in last Shape3D: coords") ; + if ((vlist.vertexFormat & GeometryArray.NORMALS) != 0) + System.out.print(" normals") ; + + boolean color4 = + (vlist.vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4; + boolean color3 = !color4 && + (vlist.vertexFormat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3; + if (color3 || color4) { + System.out.print(" colors") ; + if (color4) + System.out.print(" alpha") ; + } + System.out.println() ; + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanNode.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanNode.java new file mode 100644 index 0000000..cddba57 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanNode.java @@ -0,0 +1,225 @@ +/* + * $RCSfile: HuffmanNode.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:23 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import java.util.Collection; +import java.util.Comparator; + +/** + * Instances of this class are used as the nodes of binary trees representing + * mappings of tags to compression stream elements. Tags are descriptors + * inserted into the compression command stream that specify the encoding of + * immediately succeeding data elements.

+ * + * The tag assignments in such a tree are computed from the paths taken from + * the root to the leaf nodes. Each leaf node represents the particular way + * one or more compression stream elements wound up being encoded with respect + * to various combinations of data lengths, shifts, and absolute/relative + * status.

+ * + * Huffman's algorithm for constructing binary trees with minimal weighted + * path lengths can be used to optimize the bit lengths of the tags with + * respect to the frequency of occurrence of their associated data encodings + * in the compression stream. The weighted path length is the sum of the + * frequencies of all the leaf nodes times their path lengths to the root of + * the tree.

+ * + * The length of the longest tag determines the size of the table mapping tags + * to data representations. The geometry compression specification limits the + * size of the table to 64 entries, so tags cannot be longer than 6 bits. The + * depth of the tree is reduced through a process of increasing the data + * lengths of less frequently occuring nodes so they can be merged with other + * more frequent nodes. + */ +class HuffmanNode { + int tag, tagLength ; + int shift, dataLength ; + boolean absolute ; + + private int frequency ; + private HuffmanNode child0, child1, mergeNode ; + private boolean merged, unmergeable, cleared ; + + void clear() { + tag = -1 ; + tagLength = -1 ; + + shift = -1 ; + dataLength = -1 ; + absolute = false ; + + child0 = null ; + child1 = null ; + mergeNode = null ; + + frequency = 0 ; + merged = false ; + unmergeable = false ; + cleared = true ; + } + + HuffmanNode() { + clear() ; + } + + HuffmanNode(int length, int shift, boolean absolute) { + this() ; + set(length, shift, absolute) ; + } + + final void set(int length, int shift, boolean absolute) { + this.dataLength = length ; + this.shift = shift ; + this.absolute = absolute ; + this.cleared = false ; + } + + final boolean cleared() { + return cleared ; + } + + final void addCount() { + frequency++ ; + } + + final boolean hasCount() { + return frequency > 0 ; + } + + final boolean tokenEquals(HuffmanNode node) { + return + this.absolute == node.absolute && + this.dataLength == node.dataLength && + this.shift == node.shift ; + } + + void addChildren(HuffmanNode child0, HuffmanNode child1) { + this.child0 = child0 ; + this.child1 = child1 ; + this.frequency = child0.frequency + child1.frequency ; + } + + void collectLeaves(int tag, int tagLength, Collection collection) { + if (child0 == null) { + this.tag = tag ; + this.tagLength = tagLength ; + collection.add(this) ; + } else { + child0.collectLeaves((tag << 1) | 0, tagLength + 1, collection) ; + child1.collectLeaves((tag << 1) | 1, tagLength + 1, collection) ; + } + } + + boolean mergeInto(HuffmanNode node) { + if (this.absolute == node.absolute) { + if (this.dataLength > node.dataLength) + node.dataLength = this.dataLength ; + + if (this.shift < node.shift) + node.shift = this.shift ; + + node.frequency += this.frequency ; + this.mergeNode = node ; + this.merged = true ; + return true ; + + } else + return false ; + } + + int incrementLength() { + if (shift > 0) + shift-- ; + else + dataLength++ ; + + return dataLength - shift ; + } + + final boolean merged() { + return merged ; + } + + final HuffmanNode getMergeNode() { + return mergeNode ; + } + + void setUnmergeable() { + unmergeable = true ; + } + + final boolean unmergeable() { + return unmergeable ; + } + + public String toString() { + return + "shift " + shift + " data length " + dataLength + + (absolute? " absolute " : " relative ") + + "\ntag 0x" + Integer.toHexString(tag) + " tag length " + tagLength + + "\nfrequency: " + frequency ; + } + + /** + * Sorts nodes in ascending order by frequency. + */ + static class FrequencyComparator implements Comparator { + public final int compare(Object o1, Object o2) { + return ((HuffmanNode)o1).frequency - ((HuffmanNode)o2).frequency ; + } + } + + /** + * Sorts nodes in descending order by tag bit length. + */ + static class TagLengthComparator implements Comparator { + public final int compare(Object o1, Object o2) { + return ((HuffmanNode)o2).tagLength - ((HuffmanNode)o1).tagLength ; + } + } + + static FrequencyComparator frequencyComparator = new FrequencyComparator() ; + static TagLengthComparator tagLengthComparator = new TagLengthComparator() ; +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanTable.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanTable.java new file mode 100644 index 0000000..5aa2510 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanTable.java @@ -0,0 +1,483 @@ +/* + * $RCSfile: HuffmanTable.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:23 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.ListIterator; + +/** + * This class maintains a map from compression stream elements (tokens) onto + * HuffmanNode objects. A HuffmanNode contains a tag describing the + * associated token's data length, right shift value, and absolute/relative + * status.

+ * + * The tags are computed using Huffman's algorithm to build a binary tree with + * a minimal total weighted path length. The frequency of each token is + * used as its node's weight when building the tree. The path length from the + * root to the token's node then indicates the bit length that should be used + * for that token's tag in order to minimize the total size of the compressed + * stream. + */ +class HuffmanTable { + private static final int MAX_TAG_LENGTH = 6 ; + + private HuffmanNode positions[] ; + private HuffmanNode normals[] ; + private HuffmanNode colors[] ; + + /** + * Create a new HuffmanTable with entries for all possible position, + * normal, and color tokens. + */ + HuffmanTable() { + // + // Position and color components can have data lengths up to 16 + // bits, with right shifts up to 15 bits. The position and color + // lookup tables are therefore 2*17*16=544 entries in length to + // account for all possible combinations of data lengths, shifts, + // and relative or absolute status. + // + colors = new HuffmanNode[544] ; + positions = new HuffmanNode[544] ; + + // + // Delta normals can have uv components up to 7 bits in length with + // right shifts up to 6 bits. Absolute normals can have uv components + // up to 6 bits in length with right shifts up to 5 bits. The normal + // lookup table is therefore 2*8*7=112 entries in length. + // + normals = new HuffmanNode[112] ; + } + + private final int getPositionIndex(int len, int shift, boolean absolute) { + return (absolute? 1:0)*272 + len*16 + shift ; + } + + private final int getNormalIndex(int length, int shift, boolean absolute) { + return (absolute? 1:0)*56 + length*7 + shift ; + } + + private final int getColorIndex(int length, int shift, boolean absolute) { + return getPositionIndex(length, shift, absolute) ; + } + + + /** + * Add a position entry with the given length, shift, and absolute + * status. + * + * @param length number of bits in each X, Y, and Z component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous vertex in the compression stream + */ + void addPositionEntry(int length, int shift, boolean absolute) { + addEntry(positions, getPositionIndex(length, shift, absolute), + length, shift, absolute) ; + } + + /** + * Get the position entry associated with the specified length, shift, and + * absolute status. This will contain a tag indicating the actual + * encoding to be used in the compression command stream, not necessarily + * the same as the original length and shift with which the the entry was + * created. + * + * @param length number of bits in each X, Y, and Z component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous vertex in the compression stream + * @return HuffmanNode mapped to the specified parameters + */ + HuffmanNode getPositionEntry(int length, int shift, boolean absolute) { + return getEntry(positions, getPositionIndex(length, shift, absolute)) ; + } + + /** + * Add a color entry with the given length, shift, and absolute + * status. + * + * @param length number of bits in each R, G, B, and A component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous color in the compression stream + */ + void addColorEntry(int length, int shift, boolean absolute) { + addEntry(colors, getColorIndex(length, shift, absolute), + length, shift, absolute) ; + } + + /** + * Get the color entry associated with the specified length, shift, and + * absolute status. This will contain a tag indicating the actual + * encoding to be used in the compression command stream, not necessarily + * the same as the original length and shift with which the the entry was + * created. + * + * @param length number of bits in each R, G, B, and A component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous color in the compression stream + * @return HuffmanNode mapped to the specified parameters + */ + HuffmanNode getColorEntry(int length, int shift, boolean absolute) { + return getEntry(colors, getColorIndex(length, shift, absolute)) ; + } + + /** + * Add a normal entry with the given length, shift, and absolute + * status. + * + * @param length number of bits in each U and V component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous normal in the compression stream + */ + void addNormalEntry(int length, int shift, boolean absolute) { + addEntry(normals, getNormalIndex(length, shift, absolute), + length, shift, absolute) ; + } + + /** + * Get the normal entry associated with the specified length, shift, and + * absolute status. This will contain a tag indicating the actual + * encoding to be used in the compression command stream, not necessarily + * the same as the original length and shift with which the the entry was + * created. + * + * @param length number of bits in each U and V component + * @param shift number of trailing zeros in each component + * @param absolute if false, value represented is a delta from the + * previous normal in the compression stream + * @return HuffmanNode mapped to the specified parameters + */ + HuffmanNode getNormalEntry(int length, int shift, boolean absolute) { + return getEntry(normals, getNormalIndex(length, shift, absolute)) ; + } + + + private void addEntry(HuffmanNode table[], int index, + int length, int shift, boolean absolute) { + + if (table[index] == null) + table[index] = new HuffmanNode(length, shift, absolute) ; + + else if (table[index].cleared()) + table[index].set(length, shift, absolute) ; + + table[index].addCount() ; + } + + private HuffmanNode getEntry(HuffmanNode table[], int index) { + HuffmanNode t = table[index] ; + + while (t.merged()) + t = t.getMergeNode() ; + + return t ; + } + + private void getEntries(HuffmanNode table[], Collection c) { + for (int i = 0 ; i < table.length ; i++) + if (table[i] != null && !table[i].cleared() && + table[i].hasCount() && !table[i].merged()) + c.add(table[i]) ; + } + + + /** + * Clear this HuffmanTable instance. + */ + void clear() { + for (int i = 0 ; i < positions.length ; i++) + if (positions[i] != null) + positions[i].clear() ; + + for (int i = 0 ; i < colors.length ; i++) + if (colors[i] != null) + colors[i].clear() ; + + for (int i = 0 ; i < normals.length ; i++) + if (normals[i] != null) + normals[i].clear() ; + } + + /** + * Compute optimized tags for each position, color, and normal entry. + */ + void computeTags() { + LinkedList nodeList = new LinkedList() ; + getEntries(positions, nodeList) ; + computeTags(nodeList, 3) ; + + nodeList.clear() ; + getEntries(colors, nodeList) ; + computeTags(nodeList, 3) ; + + nodeList.clear() ; + getEntries(normals, nodeList) ; + computeTags(nodeList, 2) ; + } + + // + // Compute tags for a list of Huffman tokens. + // + private void computeTags(LinkedList nodes, int minComponentCount) { + HuffmanNode node0, node1, node2 ; + + // Return if there's nothing to do. + if (nodes.isEmpty()) + return ; + + while (true) { + // Sort the nodes in ascending order by frequency. + Collections.sort(nodes, HuffmanNode.frequencyComparator) ; + + // Apply Huffman's algorithm to construct a binary tree with a + // minimum total weighted path length. + node0 = (HuffmanNode)nodes.removeFirst() ; + while (nodes.size() > 0) { + node1 = (HuffmanNode)nodes.removeFirst() ; + node2 = new HuffmanNode() ; + + node2.addChildren(node0, node1) ; + addNodeInOrder(nodes, node2, HuffmanNode.frequencyComparator) ; + + node0 = (HuffmanNode)nodes.removeFirst() ; + } + + // node0 is the root of the resulting binary tree. Traverse it + // assigning tags and lengths to the leaf nodes. The leaves are + // collected into the now empty node list. + node0.collectLeaves(0, 0, nodes) ; + + // Sort the nodes in descending order by tag length. + Collections.sort(nodes, HuffmanNode.tagLengthComparator) ; + + // Check for tag length overrun. + if (((HuffmanNode)nodes.getFirst()).tagLength > MAX_TAG_LENGTH) { + // Tokens need to be merged and the tree rebuilt with the new + // combined frequencies. + merge(nodes) ; + + } else { + // Increase tag length + data length if they're too small. + expand(nodes, minComponentCount) ; + break ; + } + } + } + + // + // Merge a token with a long tag into some other token. The merged token + // will be removed from the list along with any duplicate node the merge + // created, reducing the size of the list by 1 or 2 elements until only + // unmergeable tokens are left. + // + private void merge(LinkedList nodes) { + ListIterator i = nodes.listIterator(0) ; + HuffmanNode node0, node1, node2 ; + int index = 0 ; + + while (i.hasNext()) { + // Get the node with the longest possibly mergeable tag. + node0 = (HuffmanNode)i.next() ; + if (node0.unmergeable()) continue ; + + // Try to find a node that can be merged with node0. This is any + // node that matches its absolute/relative status. + i.remove() ; + while (i.hasNext()) { + node1 = (HuffmanNode)i.next() ; + if (node0.mergeInto(node1)) { + // Search for a duplicate of the possibly modified node1 + // and merge into it so that node weights remain valid. + // If a duplicate exists it must be further in the list, + // otherwise node0 would have merged into it. + i.remove() ; + while (i.hasNext()) { + node2 = (HuffmanNode)i.next() ; + if (node1.tokenEquals(node2)) { + node1.mergeInto(node2) ; + return ; + } + } + // node1 has no duplicate, so return it to the list. + i.add(node1) ; + return ; + } + } + + // node0 can't be merged with any other node; it must be the only + // relative or absolute node in the list. Mark it as unmergeable + // to avoid unnecessary searches on subsequent calls to merge() + // and return it to the list. + node0.setUnmergeable() ; + i.add(node0) ; + + // Restart the iteration. + i = nodes.listIterator(0) ; + } + } + + // + // Empty bits within a compression command header are not allowed. If + // the tag length plus the total data length is less than 6 bits then + // the token's length must be increased. + // + private void expand(LinkedList nodes, int minComponentCount) { + Iterator i = nodes.iterator() ; + + while (i.hasNext()) { + HuffmanNode n = (HuffmanNode)i.next() ; + + while (n.tagLength + + (minComponentCount * (n.dataLength - n.shift)) < 6) { + + n.incrementLength() ; + } + } + } + + // + // Insert a node into the correct place in a sorted list of nodes. + // + private void addNodeInOrder(LinkedList l, HuffmanNode node, Comparator c) { + ListIterator i = l.listIterator(0) ; + + while (i.hasNext()) { + HuffmanNode n = (HuffmanNode)i.next() ; + if (c.compare(n, node) > 0) { + n = (HuffmanNode)i.previous() ; + break ; + } + } + i.add(node) ; + } + + /** + * Create compression stream commands for decompressors to use to set up + * their decompression tables. + * + * @param output CommandStream which receives the compression commands + */ + void outputCommands(CommandStream output) { + LinkedList nodeList = new LinkedList() ; + getEntries(positions, nodeList) ; + outputCommands(nodeList, output, CommandStream.POSITION_TABLE) ; + + nodeList.clear() ; + getEntries(colors, nodeList) ; + outputCommands(nodeList, output, CommandStream.COLOR_TABLE) ; + + nodeList.clear() ; + getEntries(normals, nodeList) ; + outputCommands(nodeList, output, CommandStream.NORMAL_TABLE) ; + } + + // + // Output a setTable command for each unique token. + // + private void outputCommands(Collection nodes, + CommandStream output, int tableId) { + + Iterator i = nodes.iterator() ; + while (i.hasNext()) { + HuffmanNode n = (HuffmanNode)i.next() ; + int addressRange = (1 << n.tagLength) | n.tag ; + int dataLength = (n.dataLength == 16? 0 : n.dataLength) ; + + int command = + CommandStream.SET_TABLE | (tableId << 1) | (addressRange >> 6) ; + + long body = + ((addressRange & 0x3f) << 9) | (dataLength << 5) | + (n.absolute? 0x10 : 0) | n.shift ; + + output.addCommand(command, 8, body, 15) ; + } + } + + /** + * Print a collection of HuffmanNode objects to standard out. + * + * @param header descriptive string + * @param nodes Collection of HuffmanNode objects to print + */ + void print(String header, Collection nodes) { + System.out.println(header + "\nentries: " + nodes.size() + "\n") ; + + Iterator i = nodes.iterator() ; + while(i.hasNext()) { + HuffmanNode n = (HuffmanNode)i.next() ; + System.out.println(n.toString() + "\n") ; + } + } + + /** + * Print the contents of this instance to standard out. + */ + void print() { + LinkedList nodeList = new LinkedList() ; + + getEntries(positions, nodeList) ; + Collections.sort(nodeList, HuffmanNode.frequencyComparator) ; + print("\nposition tokens and tags", nodeList) ; + + nodeList.clear() ; + getEntries(colors, nodeList) ; + Collections.sort(nodeList, HuffmanNode.frequencyComparator) ; + print("\ncolor tokens and tags", nodeList) ; + + nodeList.clear() ; + getEntries(normals, nodeList) ; + Collections.sort(nodeList, HuffmanNode.frequencyComparator) ; + print("\nnormal tokens and tags", nodeList) ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/MeshBuffer.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/MeshBuffer.java new file mode 100644 index 0000000..9af2a77 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/MeshBuffer.java @@ -0,0 +1,242 @@ +/* + * $RCSfile: MeshBuffer.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:23 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.geometry.compression; + +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +/** + * This class mirrors the vertex mesh buffer stack supported by the geometry + * compression semantics. + */ +class MeshBuffer { + // + // The fixed-length mesh buffer stack is represented by circular buffers. + // Three stack representations are provided: vertices, positions, and + // indices. + // + // The vertex representation stores references to CompressionStreamVertex + // objects. The position representation stores references to Point3f, + // Vector3f, Color3f, and Color4f objects, while the index representation + // stores indices into externally maintained arrays of those objects. All + // these representations may be used independently and all provide access + // to the stored references via a mesh buffer index. + // + // In addition, the position and index representations provide lookup + // mechanisms to check if positions or indices exist in the mesh buffer + // and return their mesh buffer indices if they do. This is used to + // implement a limited meshing algorithm which reduces the number of + // vertices when non-stripped abutting facets are added to a compression + // stream. + // + static final int NOT_FOUND = -1 ; + + private static final int SIZE = 16 ; + private static final int NAN_HASH = + new Point3f(Float.NaN, Float.NaN, Float.NaN).hashCode() ; + + private int topIndex = SIZE - 1 ; + private int positionIndices[] = new int[SIZE] ; + private int normalIndices[] = new int[SIZE] ; + private int colorIndices[] = new int[SIZE] ; + + private int topPosition = SIZE - 1 ; + private int positionHashCodes[] = new int[SIZE] ; + private Point3f positions[] = new Point3f[SIZE] ; + private Vector3f normals[] = new Vector3f[SIZE] ; + private Color3f colors3[] = new Color3f[SIZE] ; + private Color4f colors4[] = new Color4f[SIZE] ; + + private int topVertex = SIZE - 1 ; + private CompressionStreamVertex vertices[] = + new CompressionStreamVertex[SIZE] ; + + MeshBuffer() { + for (int i = 0 ; i < SIZE ; i++) { + positionHashCodes[i] = NAN_HASH ; + + positionIndices[i] = NOT_FOUND ; + normalIndices[i] = NOT_FOUND ; + colorIndices[i] = NOT_FOUND ; + } + } + + private static int nextTop(int top) { + // The stack top references an element in the fixed-length backing + // array in which the stack is stored. Stack elements below it have + // decreasing indices into the backing array until element 0, at which + // point the indices wrap to the end of the backing array and back to + // the top. + // + // A push is accomplished by incrementing the stack top in a circular + // buffer and storing the data into the new stack element it + // references. The bottom of the stack is the element with the next + // higher index from the top in the backing array, and is overwritten + // with each new push. + return (top + 1) % SIZE ; + } + + private static int flipOffset(int top, int offset) { + // Flips an offset relative to the beginning of the backing array to + // an offset from the top of the stack. Also works in reverse, from + // an offset from the top of the stack to an offset from the beginning + // of the backing array. + if (offset > top) offset -= SIZE ; + return top - offset ; + } + + // + // Mesh buffer vertex stack. This is currently only used for vertex + // lookup during the quantization pass in order to compute delta values; + // no mesh reference lookup is necessary. + // + void push(CompressionStreamVertex v) { + topVertex = nextTop(topVertex) ; + vertices[topVertex] = v ; + } + + CompressionStreamVertex getVertex(int meshReference) { + return vertices[flipOffset(topVertex, meshReference)] ; + } + + + // + // Mesh buffer index stack and index reference lookup support. + // + void push(int positionIndex, int normalIndex) { + topIndex = nextTop(topIndex) ; + + positionIndices[topIndex] = positionIndex ; + normalIndices[topIndex] = normalIndex ; + } + + void push(int positionIndex, int colorIndex, int normalIndex) { + push(positionIndex, normalIndex) ; + colorIndices[topIndex] = colorIndex ; + } + + int getMeshReference(int positionIndex) { + int index ; + for (index = 0 ; index < SIZE ; index++) + if (positionIndices[index] == positionIndex) + break ; + + if (index == SIZE) return NOT_FOUND ; + return flipOffset(topIndex, index) ; + } + + int getPositionIndex(int meshReference) { + return positionIndices[flipOffset(topIndex, meshReference)] ; + } + + int getColorIndex(int meshReference) { + return colorIndices[flipOffset(topIndex, meshReference)] ; + } + + int getNormalIndex(int meshReference) { + return normalIndices[flipOffset(topIndex, meshReference)] ; + } + + + // + // Mesh buffer position stack and position reference lookup support. + // + void push(Point3f position, Vector3f normal) { + topPosition = nextTop(topPosition) ; + + positionHashCodes[topPosition] = position.hashCode() ; + positions[topPosition] = position ; + normals[topPosition] = normal ; + } + + void push(Point3f position, Color3f color, Vector3f normal) { + push(position, normal) ; + colors3[topPosition] = color ; + } + + void push(Point3f position, Color4f color, Vector3f normal) { + push(position, normal) ; + colors4[topPosition] = color ; + } + + void push(Point3f position, Object color, Vector3f normal) { + push(position, normal) ; + if (color instanceof Color3f) + colors3[topPosition] = (Color3f)color ; + else + colors4[topPosition] = (Color4f)color ; + } + + int getMeshReference(Point3f position) { + int index ; + int hashCode = position.hashCode() ; + + for (index = 0 ; index < SIZE ; index++) + if (positionHashCodes[index] == hashCode) + if (positions[index].equals(position)) + break ; + + if (index == SIZE) return NOT_FOUND ; + return flipOffset(topPosition, index) ; + } + + Point3f getPosition(int meshReference) { + return positions[flipOffset(topPosition, meshReference)] ; + } + + Color3f getColor3(int meshReference) { + return colors3[flipOffset(topPosition, meshReference)] ; + } + + Color4f getColor4(int meshReference) { + return colors4[flipOffset(topPosition, meshReference)] ; + } + + Vector3f getNormal(int meshReference) { + return normals[flipOffset(topPosition, meshReference)] ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/package.html new file mode 100644 index 0000000..2977b07 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/compression/package.html @@ -0,0 +1,13 @@ + + + + + com.sun.j3d.utils.geometry.compression + + +

Provides compressed geometry utility classes. + This package supersedes the javax.media.j3d.CompressedGeometry class and + the com.sun.j3d.utils.compression package.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/package.html new file mode 100644 index 0000000..49da2ca --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/geometry/package.html @@ -0,0 +1,12 @@ + + + + + com.sun.j3d.utils.geometry + + +

Provides geometry construction, triangulation, and optimization +utility classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/ImageException.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/ImageException.java new file mode 100644 index 0000000..5f65e41 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/ImageException.java @@ -0,0 +1,66 @@ +/* + * $RCSfile: ImageException.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.3 $ + * $Date: 2007/02/09 17:20:23 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.image; + + +/** + * Exception used to indicate that the texture loader encountered + * a problem loading the specified image file. + */ +public class ImageException extends RuntimeException { + + public ImageException() { + super(); + } + + public ImageException(String s) { + super(s); + } + + public ImageException(Throwable t) { + super(t); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/TextureLoader.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/TextureLoader.java new file mode 100644 index 0000000..054ea10 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/TextureLoader.java @@ -0,0 +1,925 @@ +/* + * $RCSfile: TextureLoader.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.12 $ + * $Date: 2007/04/03 23:48:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.image; + +import javax.media.j3d.*; +import java.awt.Image; +import java.awt.Component; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.image.*; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.lang.reflect.Method; +import javax.imageio.ImageIO; + +/** + * This class is used for loading a texture from an Image or BufferedImage. + * The Image I/O API is used to load the images. (If the JAI IIO Tools + * package is available, a larger set of formats can be loaded, including + * TIFF, JPEG2000, and so on.) + * + * Methods are provided to retrieve the Texture object and the associated + * ImageComponent object or a scaled version of the ImageComponent object. + * + * Default format is RGBA. Other legal formats are: RGBA, RGBA4, RGB5_A1, + * RGB, RGB4, RGB5, R3_G3_B2, LUM8_ALPHA8, LUM4_ALPHA4, LUMINANCE and ALPHA + */ +public class TextureLoader extends Object { + + /** + * Optional flag - specifies that mipmaps are generated for all levels + */ + public static final int GENERATE_MIPMAP = 0x01; + + /** + * Optional flag - specifies that the ImageComponent2D will + * access the image data by reference + * + * @since Java 3D 1.2 + */ + public static final int BY_REFERENCE = 0x02; + + /** + * Optional flag - specifies that the ImageComponent2D will + * have a y-orientation of y up, meaning the origin of the image is the + * lower left + * + * @since Java 3D 1.2 + */ + public static final int Y_UP = 0x04; + + /** + * Optional flag - specifies that the ImageComponent2D is allowed + * to have dimensions that are not a power of two. If this flag is set, + * TextureLoader will not perform any scaling of images. If this flag + * is not set, images will be scaled to the nearest power of two. This is + * the default mode. + *

+ * Note that non-power-of-two textures may not be supported by all graphics + * cards. Applications should check whether a particular Canvas3D supports + * non-power-of-two textures by calling the {@link Canvas3D#queryProperties} + * method, and checking whether the + * textureNonPowerOfTwoAvailable property is set to true. + * + * @since Java 3D 1.5 + */ + public static final int ALLOW_NON_POWER_OF_TWO = 0x08; + + /* + * Private declaration for BufferedImage allocation + */ + private static ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + private static int[] nBits = {8, 8, 8, 8}; + private static int[] bandOffset = { 0, 1, 2, 3}; + private static ComponentColorModel colorModel = new ComponentColorModel(cs, nBits, true, false, Transparency.TRANSLUCENT, 0); + + private Texture2D tex = null; + private BufferedImage bufferedImage = null; + private ImageComponent2D imageComponent = null; + private int textureFormat = Texture.RGBA; + private int imageComponentFormat = ImageComponent.FORMAT_RGBA; + private int flags; + private boolean byRef = false; + private boolean yUp = false; + private boolean forcePowerOfTwo = true; + + /** + * Contructs a TextureLoader object using the specified BufferedImage + * and default format RGBA + * @param bImage The BufferedImage used for loading the texture + * + * @exception NullPointerException if bImage is null + */ + public TextureLoader(BufferedImage bImage) { + this(bImage, null, 0); + } + + /** + * Contructs a TextureLoader object using the specified BufferedImage + * and format + * @param bImage The BufferedImage used for loading the texture + * @param format The format specifies which channels to use + * + * @exception NullPointerException if bImage is null + */ + public TextureLoader(BufferedImage bImage, String format) { + this(bImage, format, 0); + } + + /** + * Contructs a TextureLoader object using the specified BufferedImage, + * option flags and default format RGBA + * @param bImage The BufferedImage used for loading the texture + * @param flags The flags specify what options to use in texture loading (generate mipmap etc) + * + * @exception NullPointerException if bImage is null + */ + public TextureLoader(BufferedImage bImage, int flags) { + this(bImage, null, flags); + } + + /** + * Contructs a TextureLoader object using the specified BufferedImage, + * format and option flags + * @param bImage The BufferedImage used for loading the texture + * @param format The format specifies which channels to use + * @param flags The flags specify what options to use in texture loading (generate mipmap etc) + * + * @exception NullPointerException if bImage is null + */ + public TextureLoader(BufferedImage bImage, String format, int flags) { + if (bImage == null) { + throw new NullPointerException(); + } + + parseFormat(format); + this.flags = flags; + bufferedImage = bImage; + if (format==null) + chooseFormat(bufferedImage); + + if ((flags & BY_REFERENCE) != 0) { + byRef = true; + } + if ((flags & Y_UP) != 0) { + yUp = true; + } + if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) { + forcePowerOfTwo = false; + } + } + + /** + * Contructs a TextureLoader object using the specified Image + * and default format RGBA + * @param image The Image used for loading the texture + * @param observer The associated image observer + * + * @exception NullPointerException if image is null + * @exception ImageException if there is a problem loading the image + */ + public TextureLoader(Image image, Component observer) { + this(image, null, 0, observer); + } + + /** + * Contructs a TextureLoader object using the specified Image + * and format + * @param image The Image used for loading the texture + * @param format The format specifies which channels to use + * @param observer The associated image observer + * + * @exception NullPointerException if image is null + * @exception ImageException if there is a problem loading the image + */ + public TextureLoader(Image image, String format, Component observer) { + this(image, format, 0, observer); + } + + /** + * Contructs a TextureLoader object using the specified Image + * flags and default format RGBA + * @param image The Image used for loading the texture + * @param flags The flags specify what options to use in texture loading (generate mipmap etc) + * @param observer The associated image observer + * + * @exception NullPointerException if image is null + * @exception ImageException if there is a problem loading the image + */ + public TextureLoader(Image image, int flags, Component observer) { + this(image, null, flags, observer); + } + + /** + * Contructs a TextureLoader object using the specified Image + * format and option flags + * @param image The Image used for loading the texture + * @param format The format specifies which channels to use + * @param flags The flags specify what options to use in texture loading (generate mipmap etc) + * @param observer The associated image observer + * + * @exception NullPointerException if image is null + * @exception ImageException if there is a problem loading the image + */ + public TextureLoader(Image image, String format, int flags, + Component observer) { + + if (image == null) { + throw new NullPointerException(); + } + + if (observer == null) { + observer = new java.awt.Container(); + } + + parseFormat(format); + this.flags = flags; + bufferedImage = createBufferedImage(image, observer); + + if (bufferedImage==null) { + throw new ImageException("Error loading image: " + image.toString()); + } + + if (format==null) + chooseFormat(bufferedImage); + + if ((flags & BY_REFERENCE) != 0) { + byRef = true; + } + if ((flags & Y_UP) != 0) { + yUp = true; + } + if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) { + forcePowerOfTwo = false; + } + } + + /** + * Contructs a TextureLoader object using the specified file + * and default format RGBA + * @param fname The file that specifies an Image to load the texture with + * @param observer The associated image observer + * + * @exception ImageException if there is a problem reading the image + */ + public TextureLoader(String fname, Component observer) { + this(fname, null, 0, observer); + } + + /** + * Contructs a TextureLoader object using the specified file, + * and format + * @param fname The file that specifies an Image to load the texture with + * @param format The format specifies which channels to use + * @param observer The associated image observer + * + * @exception ImageException if there is a problem reading the image + */ + public TextureLoader(String fname, String format, Component observer) { + this(fname, format, 0, observer); + } + + /** + * Contructs a TextureLoader object using the specified file, + * option flags and default format RGBA + * @param fname The file that specifies an Image to load the texture with + * @param flags The flags specify what options to use in texture loading (generate mipmap etc) + * @param observer The associated image observer + * + * @exception ImageException if there is a problem reading the image + */ + public TextureLoader(String fname, int flags, Component observer) { + this(fname, null, flags, observer); + } + + /** + * Contructs a TextureLoader object using the specified file, + * format and option flags + * @param fname The file that specifies an Image to load the texture with + * @param format The format specifies which channels to use + * @param flags The flags specify what options to use in texture loading (generate mipmap etc) + * @param observer The associated image observer + * + * @exception ImageException if there is a problem reading the image + */ + public TextureLoader(final String fname, String format, int flags, + Component observer) { + + if (observer == null) { + observer = new java.awt.Container(); + } + + bufferedImage = (BufferedImage) + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + try { + return ImageIO.read(new File(fname)); + } catch (IOException e) { + throw new ImageException(e); + } + } + } + ); + + if (bufferedImage==null) { + throw new ImageException("Error loading image: " + fname); + } + + parseFormat(format); + this.flags = flags; + + if (format==null) + chooseFormat(bufferedImage); + + if ((flags & BY_REFERENCE) != 0) { + byRef = true; + } + if ((flags & Y_UP) != 0) { + yUp = true; + } + if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) { + forcePowerOfTwo = false; + } + } + + /** + * Contructs a TextureLoader object using the specified URL + * and default format RGBA + * @param url The URL that specifies an Image to load the texture with + * @param observer The associated image observer + * + * @exception ImageException if there is a problem reading the image + */ + public TextureLoader(URL url, Component observer) { + this(url, null, 0, observer); + } + + /** + * Contructs a TextureLoader object using the specified URL, + * and format + * @param url The URL that specifies an Image to load the texture with + * @param format The format specifies which channels to use + * @param observer The associated image observer + * + * @exception ImageException if there is a problem reading the image + */ + public TextureLoader(URL url, String format, Component observer) { + this(url, format, 0, observer); + } + + /** + * Contructs a TextureLoader object using the specified URL, + * option flags and default format RGBA + * @param url The URL that specifies an Image to load the texture with + * @param flags The flags specify what options to use in texture loading (generate mipmap etc) + * @param observer The associated image observer + * + * @exception ImageException if there is a problem reading the image + */ + public TextureLoader(URL url, int flags, Component observer) { + this(url, null, flags, observer); + } + /** + * Contructs a TextureLoader object using the specified URL, + * format and option flags + * @param url The url that specifies an Image to load the texture with + * @param format The format specifies which channels to use + * @param flags The flags specify what options to use in texture loading (generate mipmap etc) + * @param observer The associated image observer + * + * @exception ImageException if there is a problem reading the image + */ + public TextureLoader(final URL url, String format, int flags, + Component observer) { + + if (observer == null) { + observer = new java.awt.Container(); + } + + bufferedImage = (BufferedImage) + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + try { + return ImageIO.read(url); + } catch (IOException e) { + throw new ImageException(e); + } + } + } + ); + + if (bufferedImage==null) { + throw new ImageException("Error loading image: " + url.toString()); + } + + parseFormat(format); + this.flags = flags; + + if (format==null) + chooseFormat(bufferedImage); + + if ((flags & BY_REFERENCE) != 0) { + byRef = true; + } + if ((flags & Y_UP) != 0) { + yUp = true; + } + if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) { + forcePowerOfTwo = false; + } + } + + + /** + * Returns the associated ImageComponent2D object + * + * @return The associated ImageComponent2D object + */ + public ImageComponent2D getImage() { + if (imageComponent == null) + imageComponent = new ImageComponent2D(imageComponentFormat, + bufferedImage, byRef, yUp); + return imageComponent; + } + + /** + * Returns the scaled ImageComponent2D object + * + * @param xScale The X scaling factor + * @param yScale The Y scaling factor + * + * @return The scaled ImageComponent2D object + */ + public ImageComponent2D getScaledImage(float xScale, float yScale) { + if (xScale == 1.0f && yScale == 1.0f) + return getImage(); + else + return(new ImageComponent2D(imageComponentFormat, + getScaledImage(bufferedImage, + xScale, yScale), + byRef, yUp)); + } + + /** + * Returns the scaled ImageComponent2D object + * + * @param width The desired width + * @param height The desired height + * + * @return The scaled ImageComponent2D object + */ + public ImageComponent2D getScaledImage(int width, int height) { + + if (bufferedImage.getWidth() == width && + bufferedImage.getHeight() == height) + return getImage(); + else + return(new ImageComponent2D(imageComponentFormat, + getScaledImage(bufferedImage, + width, height), + byRef, yUp)); + } + + /** + * Returns the associated Texture object. + * + * @return The associated Texture object + */ + public Texture getTexture() { + ImageComponent2D[] scaledImageComponents = null; + BufferedImage[] scaledBufferedImages = null; + if (tex == null) { + + int width; + int height; + + if (forcePowerOfTwo) { + width = getClosestPowerOf2(bufferedImage.getWidth()); + height = getClosestPowerOf2(bufferedImage.getHeight()); + } else { + width = bufferedImage.getWidth(); + height = bufferedImage.getHeight(); + } + + if ((flags & GENERATE_MIPMAP) != 0) { + + BufferedImage origImage = bufferedImage; + int newW = width; + int newH = height; + int level = Math.max(computeLog(width), computeLog(height)) + 1; + scaledImageComponents = new ImageComponent2D[level]; + scaledBufferedImages = new BufferedImage[level]; + tex = new Texture2D(tex.MULTI_LEVEL_MIPMAP, textureFormat, + width, height); + + for (int i = 0; i < level; i++) { + scaledBufferedImages[i] = getScaledImage(origImage, newW, newH); + scaledImageComponents[i] = new ImageComponent2D( + imageComponentFormat, scaledBufferedImages[i], + byRef, yUp); + + tex.setImage(i, scaledImageComponents[i]); + if (forcePowerOfTwo) { + if (newW > 1) newW >>= 1; + if (newH > 1) newH >>= 1; + } else { + if (newW > 1) { + newW = (int) Math.floor(newW / 2.0); + } + if (newH > 1) { + newH = (int) Math.floor(newH / 2.0); + } + } + origImage = scaledBufferedImages[i]; + } + + } else { + scaledImageComponents = new ImageComponent2D[1]; + scaledBufferedImages = new BufferedImage[1]; + + // Create texture from image + scaledBufferedImages[0] = getScaledImage(bufferedImage, + width, height); + scaledImageComponents[0] = new ImageComponent2D( + imageComponentFormat, scaledBufferedImages[0], + byRef, yUp); + + tex = new Texture2D(tex.BASE_LEVEL, textureFormat, width, height); + + tex.setImage(0, scaledImageComponents[0]); + } + tex.setMinFilter(tex.BASE_LEVEL_LINEAR); + tex.setMagFilter(tex.BASE_LEVEL_LINEAR); + } + + return tex; + } + + // create a BufferedImage from an Image object + private BufferedImage createBufferedImage(Image image, + Component observer) { + + int status; + + observer.prepareImage(image, null); + while(true) { + status = observer.checkImage(image, null); + if ((status & ImageObserver.ERROR) != 0) { + return null; + } else if ((status & ImageObserver.ALLBITS) != 0) { + break; + } + try { + Thread.sleep(100); + } catch (InterruptedException e) {} + } + + int width = image.getWidth(observer); + int height = image.getHeight(observer); + + WritableRaster wr = + java.awt.image.Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + width, height, + width * 4, 4, + bandOffset, null); + BufferedImage bImage = new BufferedImage(colorModel, wr, false, null); + + java.awt.Graphics g = bImage.getGraphics(); + g.drawImage(image, 0, 0, observer); + + return bImage; + } + + /** + * Choose the correct ImageComponent and Texture format for the given + * image + */ + private void chooseFormat(BufferedImage image) { + switch (image.getType()) { + case BufferedImage.TYPE_4BYTE_ABGR : + case BufferedImage.TYPE_INT_ARGB : + imageComponentFormat = ImageComponent.FORMAT_RGBA; + textureFormat = Texture.RGBA; + break; + case BufferedImage.TYPE_3BYTE_BGR : + case BufferedImage.TYPE_INT_BGR: + case BufferedImage.TYPE_INT_RGB: + imageComponentFormat = ImageComponent.FORMAT_RGB; + textureFormat = Texture.RGB; + break; + case BufferedImage.TYPE_CUSTOM: + if (is4ByteRGBAOr3ByteRGB(image)) { + SampleModel sm = image.getSampleModel(); + if (sm.getNumBands() == 3) { + //System.out.println("ChooseFormat Custom:TYPE_4BYTE_ABGR"); + imageComponentFormat = ImageComponent.FORMAT_RGB; + textureFormat = Texture.RGB; + } + else { + imageComponentFormat = ImageComponent.FORMAT_RGBA; + //System.out.println("ChooseFormat Custom:TYPE_3BYTE_BGR"); + textureFormat = Texture.RGBA; + } + } + break; + default : + // System.err.println("Unoptimized Image Type "+image.getType()); + imageComponentFormat = ImageComponent.FORMAT_RGBA; + textureFormat = Texture.RGBA; + break; + } + } + + private boolean is4ByteRGBAOr3ByteRGB(RenderedImage ri) { + boolean value = false; + int i; + int biType = getImageType(ri); + if (biType != BufferedImage.TYPE_CUSTOM) + return false; + ColorModel cm = ri.getColorModel(); + ColorSpace cs = cm.getColorSpace(); + SampleModel sm = ri.getSampleModel(); + boolean isAlphaPre = cm.isAlphaPremultiplied(); + int csType = cs.getType(); + if ( csType == ColorSpace.TYPE_RGB) { + int numBands = sm.getNumBands(); + if (sm.getDataType() == DataBuffer.TYPE_BYTE) { + if (cm instanceof ComponentColorModel && + sm instanceof PixelInterleavedSampleModel) { + PixelInterleavedSampleModel csm = + (PixelInterleavedSampleModel) sm; + int[] offs = csm.getBandOffsets(); + ComponentColorModel ccm = (ComponentColorModel)cm; + int[] nBits = ccm.getComponentSize(); + boolean is8Bit = true; + for (i=0; i < numBands; i++) { + if (nBits[i] != 8) { + is8Bit = false; + break; + } + } + if (is8Bit && + offs[0] == 0 && + offs[1] == 1 && + offs[2] == 2) { + if (numBands == 3) { + value = true; + } + else if (offs[3] == 3 && !isAlphaPre) { + value = true; + } + } + } + } + } + return value; + } + + private int getImageType(RenderedImage ri) { + int imageType = BufferedImage.TYPE_CUSTOM; + int i; + + if (ri instanceof BufferedImage) { + return ((BufferedImage)ri).getType(); + } + ColorModel cm = ri.getColorModel(); + ColorSpace cs = cm.getColorSpace(); + SampleModel sm = ri.getSampleModel(); + int csType = cs.getType(); + boolean isAlphaPre = cm.isAlphaPremultiplied(); + if ( csType != ColorSpace.TYPE_RGB) { + if (csType == ColorSpace.TYPE_GRAY && + cm instanceof ComponentColorModel) { + if (sm.getDataType() == DataBuffer.TYPE_BYTE) { + imageType = BufferedImage.TYPE_BYTE_GRAY; + } else if (sm.getDataType() == DataBuffer.TYPE_USHORT) { + imageType = BufferedImage.TYPE_USHORT_GRAY; + } + } + } + // RGB , only interested in BYTE ABGR and BGR for now + // all others will be copied to a buffered image + else { + int numBands = sm.getNumBands(); + if (sm.getDataType() == DataBuffer.TYPE_BYTE) { + if (cm instanceof ComponentColorModel && + sm instanceof PixelInterleavedSampleModel) { + PixelInterleavedSampleModel csm = + (PixelInterleavedSampleModel) sm; + int[] offs = csm.getBandOffsets(); + ComponentColorModel ccm = (ComponentColorModel)cm; + int[] nBits = ccm.getComponentSize(); + boolean is8Bit = true; + for (i=0; i < numBands; i++) { + if (nBits[i] != 8) { + is8Bit = false; + break; + } + } + if (is8Bit && + offs[0] == numBands-1 && + offs[1] == numBands-2 && + offs[2] == numBands-3) { + if (numBands == 3) { + imageType = BufferedImage.TYPE_3BYTE_BGR; + } + else if (offs[3] == 0) { + imageType = (isAlphaPre + ? BufferedImage.TYPE_4BYTE_ABGR_PRE + : BufferedImage.TYPE_4BYTE_ABGR); + } + } + } + } + } + return imageType; + } + + // initialize appropriate format for ImageComponent and Texture + private void parseFormat(String format) { + if (format==null) + return; + + if (format.equals("RGBA")) { + imageComponentFormat = ImageComponent.FORMAT_RGBA; + textureFormat = Texture.RGBA; + + } else if (format.equals("RGBA4")) { + imageComponentFormat = ImageComponent.FORMAT_RGBA4; + textureFormat = Texture.RGBA; + + } else if (format.equals("RGB5_A1")) { + imageComponentFormat = ImageComponent.FORMAT_RGB5_A1; + textureFormat = Texture.RGBA; + + } else if (format.equals("RGB")) { + imageComponentFormat = ImageComponent.FORMAT_RGB; + textureFormat = Texture.RGB; + + } else if (format.equals("RGB4")) { + imageComponentFormat = ImageComponent.FORMAT_RGB4; + textureFormat = Texture.RGB; + + } else if (format.equals("RGB5")) { + imageComponentFormat = ImageComponent.FORMAT_RGB5; + textureFormat = Texture.RGB; + + } else if (format.equals("R3_G3_B2")) { + imageComponentFormat = ImageComponent.FORMAT_R3_G3_B2; + textureFormat = Texture.RGB; + + } else if (format.equals("LUM8_ALPHA8")) { + imageComponentFormat = ImageComponent.FORMAT_LUM8_ALPHA8; + textureFormat = Texture.LUMINANCE_ALPHA; + + } else if (format.equals("LUM4_ALPHA4")) { + imageComponentFormat = ImageComponent.FORMAT_LUM4_ALPHA4; + textureFormat = Texture.LUMINANCE_ALPHA; + + } else if (format.equals("LUMINANCE")) { + imageComponentFormat = ImageComponent.FORMAT_CHANNEL8; + textureFormat = Texture.LUMINANCE; + + } else if (format.equals("ALPHA")) { + imageComponentFormat = ImageComponent.FORMAT_CHANNEL8; + textureFormat = Texture.ALPHA; + } + } + + // return a scaled image of given width and height + private BufferedImage getScaledImage(BufferedImage origImage, + int width, int height) { + + int origW = origImage.getWidth(); + int origH = origImage.getHeight(); + float xScale = (float)width/(float)origW; + float yScale = (float)height/(float)origH; + + return (getScaledImage(origImage, xScale, yScale)); + } + + // return a scaled image of given x and y scale + private BufferedImage getScaledImage(BufferedImage origImage, + float xScale, float yScale) { + + + // System.err.println("(1) origImage " + origImage); + // If the image is already the requested size, no need to scale + if (xScale == 1.0f && yScale == 1.0f) + return origImage; + else { + int scaleW = (int)(origImage.getWidth() * xScale + 0.5); + int scaleH = (int)(origImage.getHeight() * yScale + 0.5); + + int origImageType = origImage.getType(); + BufferedImage scaledImage; + WritableRaster wr; + + if (origImageType != BufferedImage.TYPE_CUSTOM) { + WritableRaster origWr = origImage.getRaster(); + wr = origWr.createCompatibleWritableRaster(0, 0, scaleW, scaleH); + scaledImage = new BufferedImage(scaleW, scaleH, origImageType); + } else { + int numComponents = origImage.getSampleModel().getNumBands(); + int[] bandOffset = new int[numComponents]; + int[] nBits = new int[numComponents]; + for (int ii=0; ii < numComponents; ii++) { + bandOffset[ii] = ii; + nBits[ii] = 8; + } + + wr = java.awt.image.Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + scaleW, scaleH, + scaleW * numComponents, numComponents, + bandOffset, null); + + int imageType; + + switch (numComponents) { + case 1: + imageType = BufferedImage.TYPE_BYTE_GRAY; + break; + case 3: + imageType = BufferedImage.TYPE_3BYTE_BGR; + break; + case 4: + imageType = BufferedImage.TYPE_4BYTE_ABGR; + break; + default: + throw new ImageException("Illegal number of bands : " + numComponents); + + } + + scaledImage = new BufferedImage(scaleW, scaleH, imageType); + } + + scaledImage.setData(wr); + java.awt.Graphics2D g2 = scaledImage.createGraphics(); + AffineTransform at = AffineTransform.getScaleInstance(xScale, + yScale); + g2.transform(at); + g2.drawImage(origImage, 0, 0, null); + + return scaledImage; + } + } + + private int computeLog(int value) { + int i = 0; + + if (value == 0) return -1; + for (;;) { + if (value == 1) + return i; + value >>= 1; + i++; + } + } + + private int getClosestPowerOf2(int value) { + + if (value < 1) + return value; + + int powerValue = 1; + for (;;) { + powerValue *= 2; + if (value < powerValue) { + // Found max bound of power, determine which is closest + int minBound = powerValue/2; + if ((powerValue - value) > + (value - minBound)) + return minBound; + else + return powerValue; + } + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/package.html new file mode 100644 index 0000000..e32c5d8 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/image/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.image + + +

Provides texture image utility classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickCanvas.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickCanvas.java new file mode 100644 index 0000000..550875d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickCanvas.java @@ -0,0 +1,249 @@ +/* + * $RCSfile: PickCanvas.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:24 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.pickfast; + +import java.awt.event.*; +import javax.vecmath.*; +import javax.media.j3d.*; +import com.sun.j3d.utils.geometry.*; // Cone, Cylinder + +/** + * A subclass of PickTool, simplifies picking using mouse events from a canvas. + * This class allows picking using canvas x,y locations by generating the + * appropriate pick shape. + *

+ * The pick tolerance specifies the distance from the + * pick center to include in the pick shape. A tolerance of 0.0 may speedup + * picking slightly, but also make it very difficult to pick points and lines. + *

+ * The pick canvas can be used to make a series of picks. For example, to + * initialize the pick canvas: + *

+ *     PickCanvas pickCanvas = new PickCanvas(canvas, scene);
+ *     pickCanvas.setMode(PickInfo.PICK_GEOMETRY); 
+ *     pickCanvas.setFlags(PickInfo.NODE | PickInfo.CLOSEST_INTERSECTION_POINT); 
+ *     pickCanvas.setTolerance(4.0f);
+ * 
+ *

+ * Then for each mouse event: + *

+ *     pickCanvas.setShapeLocation(mouseEvent);
+ *     PickInfo[] pickInfos = pickCanvas.pickAll();
+ * 
+ *

+ * NOTE: For the pickAllSorted or pickClosest methods, the picks will be sorted + * by the distance from the ViewPlatform to the intersection point. + * @see PickTool + */ +public class PickCanvas extends PickTool { + + /* OPEN ISSUES: + -- Should restrict the pick shape to the front/back clip plane + */ + + + /** The canvas we are picking into */ + Canvas3D canvas; + + /* the pick tolerance, default to 2.0 */ + float tolerance = 2.0f; + int save_xpos; + int save_ypos; + + /** Constructor with Canvas3D for mouse events and BranchGroup to be picked. + */ + public PickCanvas (Canvas3D c, BranchGroup b) { + super (b); + canvas = c; + } + + /** Constructor with Canvas3D for mouse events and Locale to be picked. + */ + public PickCanvas (Canvas3D c, Locale l) { + super (l); + canvas = c; + } + + /** Inquire the canvas to be used for picking operations. + @return the canvas. + */ + public Canvas3D getCanvas() { + return canvas; + } + + /** Set the picking tolerance. Objects within this distance + * (in pixels) + * to the mouse x,y location will be picked. The default tolerance is 2.0. + * @param t The tolerance + * @exception IllegalArgumentException if the tolerance is less than 0. + */ + public void setTolerance(float t) { + if (t < 0.0f) { + throw new IllegalArgumentException(); + } + tolerance = t; + + if ((pickShape != null) && (!userDefineShape)) { + // reset pickShape + pickShape = null; + setShapeLocation(save_xpos, save_ypos); + } + } + + /** Get the pick tolerance. + */ + public float getTolerance() { + return tolerance; + } + + /** Set the pick location. Defines the location on the canvas where the + pick is to be performed. + @param mevent The MouseEvent for the picking point + */ + public void setShapeLocation(MouseEvent mevent) { + setShapeLocation(mevent.getX(), mevent.getY()); + } + /** Set the pick location. Defines the location on the canvas where the + pick is to be performed (upper left corner of canvas is 0,0). + @param xpos the X position of the picking point + @param ypos the Y position of the picking point + */ + public void setShapeLocation (int xpos, int ypos) { + Transform3D motion = new Transform3D(); + Point3d eyePosn = new Point3d(); + Point3d mousePosn = new Point3d(); + Vector3d mouseVec = new Vector3d(); + boolean isParallel = false; + double radius = 0.0; + double spreadAngle = 0.0; + + this.save_xpos = xpos; + this.save_ypos = ypos; + canvas.getCenterEyeInImagePlate(eyePosn); + canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn); + + if ((canvas.getView() != null) && + (canvas.getView().getProjectionPolicy() == + View.PARALLEL_PROJECTION)) { + // Correct for the parallel projection: keep the eye's z + // coordinate, but make x,y be the same as the mouse, this + // simulates the eye being at "infinity" + eyePosn.x = mousePosn.x; + eyePosn.y = mousePosn.y; + isParallel = true; + } + + // Calculate radius for PickCylinderRay and spread angle for PickConeRay + Vector3d eyeToCanvas = new Vector3d(); + eyeToCanvas.sub (mousePosn, eyePosn); + double distanceEyeToCanvas = eyeToCanvas.length(); + + Point3d deltaImgPlate = new Point3d(); + canvas.getPixelLocationInImagePlate (xpos+1, ypos, deltaImgPlate); + + Vector3d ptToDelta = new Vector3d(); + ptToDelta.sub (mousePosn, deltaImgPlate); + double distancePtToDelta = ptToDelta.length(); + distancePtToDelta *= tolerance; + + canvas.getImagePlateToVworld(motion); + + /* + System.out.println("mouse position " + xpos + " " + ypos); + System.out.println("before, mouse " + mousePosn + " eye " + eyePosn); + */ + + motion.transform(eyePosn); + start = new Point3d (eyePosn); // store the eye position + motion.transform(mousePosn); + mouseVec.sub(mousePosn, eyePosn); + mouseVec.normalize(); + + /* + System.out.println(motion + "\n"); + System.out.println("after, mouse " + mousePosn + " eye " + eyePosn + + " mouseVec " + mouseVec); + */ + + if (tolerance == 0.0) { + if ((pickShape != null) && (pickShape instanceof PickRay)) { + ((PickRay)pickShape).set (eyePosn, mouseVec); + } else { + pickShape = (PickShape) new PickRay (eyePosn, mouseVec); + } + // pickShape = (PickShape) new PickConeRay (eyePosn, + // mouseVec,1.0*Math.PI/180.0); + } else { + if (isParallel) { + // Parallel projection, use a PickCylinderRay + distancePtToDelta *= motion.getScale(); + if ((pickShape != null) && + (pickShape instanceof PickCylinderRay)) { + ((PickCylinderRay)pickShape).set (eyePosn, mouseVec, + distancePtToDelta); + } else { + pickShape = (PickShape) new PickCylinderRay (eyePosn, + mouseVec, distancePtToDelta); + } + } else { + // Perspective projection, use a PickConeRay + + // Calculate spread angle + spreadAngle = Math.atan (distancePtToDelta/distanceEyeToCanvas); + + if ((pickShape != null) && + (pickShape instanceof PickConeRay)) { + ((PickConeRay)pickShape).set (eyePosn, mouseVec, + spreadAngle); + } else { + pickShape = (PickShape) new PickConeRay (eyePosn, mouseVec, + spreadAngle); + } + } + } + } +} // PickCanvas + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java new file mode 100644 index 0000000..1727779 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java @@ -0,0 +1,1379 @@ +/* + * $RCSfile: PickIntersection.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:24 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.pickfast; + +import javax.vecmath.*; +import javax.media.j3d.*; +import com.sun.j3d.utils.geometry.Primitive; + +/** + * Holds information about an intersection of a PickShape with a Node + * as part of a PickInfo.IntersectionInfo. Information about + * the intersected geometry, intersected primitive, intersection point, and + * closest vertex can be inquired. + *

+ * The intersected primitive indicates which primitive out of the GeometryArray + * was intersected (where the primitive is a point, line, triangle or quad, + * not a + * com.sun.j3d.utils.geometry.Primitive). + * For example, the intersection would indicate which triangle out of a + * triangle strip was intersected. + * The methods which return primitive data will have one value if the primitive + * is + * a point, two values if the primitive is a line, three values if the primitive + * is a triangle and four values if the primitive is quad. + *

+ * The primitive's VWorld coordinates are saved when then intersection is + * calculated. The local coordinates, normal, color and texture coordinates + * for the primitive can also be inquired if they are present and readable. + *

+ * The intersection point is the location on the primitive which intersects the + * pick shape closest to the center of the pick shape. The intersection point's + * location in VWorld coordinates is saved when the intersection is calculated. + * The local coordinates, normal, color and texture coordiantes of at the + * intersection can be interpolated if they are present and readable. + *

+ * The closest vertex is the vertex of the primitive closest to the intersection + * point. The vertex index, VWorld coordinates and local coordinates of the + * closest vertex can be inquired. The normal, color and texture coordinate + * of the closest vertex can be inquired from the geometry array: + *

+ *      Vector3f getNormal(PickIntersection pi, int vertexIndex) {
+ *          int index;
+ *          Vector3d normal = new Vector3f();
+ *          GeometryArray ga = pickIntersection.getGeometryArray();
+ *          if (pickIntersection.geometryIsIndexed()) {
+ *              index = ga.getNormalIndex(vertexIndex);
+ *          } else {
+ *              index = vertexIndex;
+ *          }
+ *          ga.getNormal(index, normal);
+ *          return normal;
+ *      }
+ * 
+ *

+ * The color, normal + * and texture coordinate information for the intersected primitive and the + * intersection point + * can be inquired + * the geometry includes them and the corresponding READ capibility bits are + * set. + */ + +public class PickIntersection { + + + /* The intersection point */ + // Point3d getIntersectionPoint() + + /* Distance between start point of pickShape and intersection point */ + // double getDistance() + + /* The vertex indices of the intersected primitive in the geometry */ + // int[] getVertexIndices() + + /*************************/ + + /** Weight factors for interpolation, values correspond to vertex indices, + * sum == 1 + */ + private double[] interpWeights; + + private static final boolean debug = false; + + // Axis constants + private static final int X_AXIS = 1; + private static final int Y_AXIS = 2; + private static final int Z_AXIS = 3; + + // Tolerance for numerical stability + static final double TOL = 1.0e-5; + + /* The references to the intersectionInfo object */ + private PickInfo.IntersectionInfo iInfo = null; + private Transform3D l2vw = null; + private Geometry geometry = null; + private boolean geometryIsIndexed = false; + private double distance; + + private boolean hasColors; + private boolean hasNormals; + private boolean hasTexCoords; + + // Primitive + /* indices for the different data types */ + private int[] primitiveCoordinateIndices; + private int[] primitiveNormalIndices; + private int[] primitiveColorIndices; + private int[] primitiveTexCoordIndices; + + /** Indices of the intersected primitive */ + private int[] primitiveVertexIndices = null; + + /* Local coordinates of the intersected primitive */ + private Point3d[] primitiveCoordinates = null; + + /** VWorld coordinates of intersected primitive */ + private Point3d[] primitiveCoordinatesVW = null; + + /* Normals of the intersected primitive */ + private Vector3f[] primitiveNormals = null; + + /* Colors of the intersected primitive */ + private Color4f[] primitiveColors = null; + + /* TextureCoordinates of the intersected primitive */ + private TexCoord3f[] primitiveTexCoords = null; + + // Intersection point + /** VWorld Coordinates of the intersection point */ + private Point3d pointCoordinatesVW = null; + + /** Local Coordinates of the intersection point */ + private Point3d pointCoordinates = null; + + /** Normal at the intersection point */ + private Vector3f pointNormal = null; + + /** Color at the intersection point */ + private Color4f pointColor = null; + + /** TexCoord at the intersection point */ + private TexCoord3f pointTexCoord = null; + + // Closest Vertex + /** Index of the closest vertex */ + private int closestVertexIndex = -1; + + /** Coordinates of the closest vertex */ + private Point3d closestVertexCoordinates = null; + + /** Coordinates of the closest vertex (World coordinates) */ + private Point3d closestVertexCoordinatesVW = null; + + /* =================== METHODS ======================= */ + + /** + * Constructor + * @param intersectionInfo The IntersectionInfo this intersection is part of. + */ + public PickIntersection (Transform3D localToVWorld, + PickInfo.IntersectionInfo intersectionInfo) { + + // Should check and throw NPE if the following is null. + // localToVWorld can't be null. + l2vw = localToVWorld; + // intersectionInfo can't be null. + iInfo = intersectionInfo; + // geometry can't be null. + geometry = iInfo.getGeometry(); + + pointCoordinates = iInfo.getIntersectionPoint(); + distance = iInfo.getDistance(); + primitiveVertexIndices = iInfo.getVertexIndices(); + + if (geometry instanceof GeometryArray) { + + int vertexFormat = ((GeometryArray)geometry).getVertexFormat(); + hasColors = (0 != (vertexFormat & + (GeometryArray.COLOR_3 | GeometryArray.COLOR_4))); + hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS)); + hasTexCoords = (0 != (vertexFormat & + (GeometryArray.TEXTURE_COORDINATE_2 | + GeometryArray.TEXTURE_COORDINATE_3))); + + if (geometry instanceof IndexedGeometryArray) { + geometryIsIndexed = true; + } + } + } + + /** + * Returns true if the geometry is indexed + * + */ + public boolean geometryIsIndexed() { + return geometryIsIndexed; + } + + /** + * Get coordinates of closest vertex (local) + * @return the coordinates of the vertex closest to the intersection point + * + */ + public Point3d getClosestVertexCoordinates() { + // System.out.println("PI.closestVertexCoordinates " + closestVertexCoordinates); + GeometryArray geom = (GeometryArray) geometry; + + if (closestVertexCoordinates == null) { + int vertexIndex = getClosestVertexIndex(); + int vformat = geom.getVertexFormat(); + int val; + + int[] indices = getPrimitiveCoordinateIndices(); + if ((vformat & GeometryArray.BY_REFERENCE) == 0) { + closestVertexCoordinates = new Point3d(); + geom.getCoordinate(indices[vertexIndex], closestVertexCoordinates); + // System.out.println("PI.closestVertexCoordinates " + +// closestVertexCoordinates + " vertexIndex " + +// vertexIndex); + } + else { + if ((vformat & GeometryArray.INTERLEAVED) == 0) { + double[] doubleData = geom.getCoordRefDouble(); + // If data was set as float then .. + if (doubleData == null) { + float[] floatData = geom.getCoordRefFloat(); + if (floatData == null) { + throw new UnsupportedOperationException("Deprecated : BY_REF - p3f and p3d"); + } + else { + val = indices[vertexIndex] * 3; // for x,y,z + closestVertexCoordinates = new Point3d(floatData[val], + floatData[val+1], + floatData[val+2]); + } + } + else { + val = indices[vertexIndex] * 3; // for x,y,z + closestVertexCoordinates = new Point3d(doubleData[val], + doubleData[val+1], + doubleData[val+2]); + } + } + else { + float[] floatData = geom.getInterleavedVertices(); + int offset = getInterleavedVertexOffset(geom); + int stride = offset + 3; // for the vertices . + val = stride * indices[vertexIndex]+offset; + closestVertexCoordinates = new Point3d(floatData[val], + floatData[val+1], + floatData[val+2]); + } + } + } + + return closestVertexCoordinates; + } + + /** + * Get coordinates of closest vertex (world) + * @return the coordinates of the vertex closest to the intersection point + * + */ + public Point3d getClosestVertexCoordinatesVW() { + if (closestVertexCoordinatesVW == null) { + int vertexIndex = getClosestVertexIndex(); + Point3d[] coordinatesVW = getPrimitiveCoordinatesVW(); + closestVertexCoordinatesVW = coordinatesVW[vertexIndex]; + } + return closestVertexCoordinatesVW; + } + + /** + * Get index of closest vertex + * @return the index of the closest vertex + */ + public int getClosestVertexIndex() { + if (closestVertexIndex == -1) { + double maxDist = Double.MAX_VALUE; + double curDist = Double.MAX_VALUE; + int closestIndex = -1; + primitiveCoordinates = getPrimitiveCoordinates(); + + assert(primitiveCoordinates != null); + +// System.out.println("PI.getClosestVertexIndex : primitiveCoordinates.length " + +// primitiveCoordinates.length); + + for (int i=0;i max) { + axis = Y_AXIS; + max = abs(delta.y); + } + if (abs(delta.z) > max) { + axis = Z_AXIS; + } + return axis; + } + + /* Triangle interpolation. Basic idea: + * Map the verticies of the triangle to the form: + * + * L--------R + * \ / + * IL+--P-+IR + * \ / + * Base + * + where P is the intersection point Base, L and R and the triangle + points. IL and IR are the projections if P along the Base-L and Base-R + edges using an axis: + + IL = leftFactor * L + (1- leftFactor) * Base + IR = rightFactor * R + (1-rightFactor) * Base + + then find the interp factor, midFactor, for P between IL and IR. If + this is outside the range 0->1 then we have the wrong triangle of a + quad and we return false. + + Else, the weighting is: + + IP = midFactor * IL + (1 - midFactor) * IR; + + Solving for weights for the formula: + IP = BaseWeight * Base + LeftWeight * L + RightWeight * R; + We get: + BaseWeight = 1 - midFactor * leftFactor + - rightFactor + midFactor * rightFactor; + LeftWeight = midFactor * leftFactor; + RightWeight = righFactor - midFactor * rightFactor; + As a check, note that the sum of the weights is 1.0. + */ + + boolean + interpTriangle(int index0, int index1, int index2, Point3d[] coords, + Point3d intPt) { + + // find the longest edge, we'll use that to pick the axis */ + Vector3d delta0 = new Vector3d(); + Vector3d delta1 = new Vector3d(); + Vector3d delta2 = new Vector3d(); + delta0.sub(coords[index1], coords[index0]); + delta1.sub(coords[index2], coords[index0]); + delta2.sub(coords[index2], coords[index1]); + double len0 = delta0.lengthSquared(); + double len1 = delta1.lengthSquared(); + double len2 = delta2.lengthSquared(); + Vector3d longest = delta0; + double maxLen = len0; + if (len1 > maxLen) { + longest = delta1; + maxLen = len1; + } + if (len2 > maxLen) { + longest = delta2; + } + int mainAxis = maxAxis(longest); + + /* + System.out.println("index0 = " + index0 + " index1 = " + index1 + + " index2 = " + index2); + + System.out.println("coords[index0] = " + coords[index0]); + System.out.println("coords[index1] = " + coords[index1]); + System.out.println("coords[index2] = " + coords[index2]); + System.out.println("intPt = " + intPt); + + System.out.println("delta0 = " + delta0 + " len0 " + len0); + System.out.println("delta1 = " + delta1 + " len1 " + len1); + System.out.println("delta2 = " + delta2 + " len2 " + len2); + */ + + /* now project the intersection point along the axis onto the edges */ + double[] factor = new double[3]; + /* the factor is for the projection opposide the vertex 0 = 1->2, etc*/ + factor[0] = + getInterpFactorForBase(intPt, coords[index1], coords[index2], mainAxis); + factor[1] = + getInterpFactorForBase(intPt, coords[index2], coords[index0], mainAxis); + factor[2] = + getInterpFactorForBase(intPt, coords[index0], coords[index1], mainAxis); + + if (debug) { + System.out.println("intPt = " + intPt); + switch(mainAxis) { + case X_AXIS: + System.out.println("mainAxis = X_AXIS"); + break; + case Y_AXIS: + System.out.println("mainAxis = Y_AXIS"); + break; + case Z_AXIS: + System.out.println("mainAxis = Z_AXIS"); + break; + } + System.out.println("factor[0] = " + factor[0]); + System.out.println("factor[1] = " + factor[1]); + System.out.println("factor[2] = " + factor[2]); + } + + /* Find the factor that is out of range, it will tell us which + * vertex to use for base + */ + int base, left, right; + double leftFactor, rightFactor; + if ((factor[0] < 0.0) || (factor[0] > 1.0)) { + base = index0; + right = index1; + left = index2; + rightFactor = factor[2]; + leftFactor = 1.0 - factor[1]; + if (debug) { + System.out.println("base 0, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } else if ((factor[1] < 0.0) || (factor[1] > 1.0)) { + base = index1; + right = index2; + left = index0; + rightFactor = factor[0]; + leftFactor = 1.0 - factor[2]; + if (debug) { + System.out.println("base 1, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } else { + base = index2; + right = index0; + left = index1; + rightFactor = factor[1]; + leftFactor = 1.0 - factor[0]; + if (debug) { + System.out.println("base 2, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } + if (debug) { + System.out.println("base = " + coords[base]); + System.out.println("left = " + coords[left]); + System.out.println("right = " + coords[right]); + } + /* find iLeft and iRight */ + Point3d iLeft = new Point3d(leftFactor * coords[left].x + + (1.0-leftFactor)*coords[base].x, + leftFactor * coords[left].y + + (1.0-leftFactor)*coords[base].y, + leftFactor * coords[left].z + + (1.0-leftFactor)*coords[base].z); + + Point3d iRight = new Point3d(rightFactor * coords[right].x + + (1.0-rightFactor)*coords[base].x, + rightFactor * coords[right].y + + (1.0-rightFactor)*coords[base].y, + rightFactor * coords[right].z + + (1.0-rightFactor)*coords[base].z); + + if (debug) { + System.out.println("iLeft = " + iLeft); + System.out.println("iRight = " + iRight); + } + + /* now find an axis and solve for midFactor */ + delta0.sub(iLeft, iRight); + int midAxis = maxAxis(delta0); + double midFactor = getInterpFactor(intPt, iRight, iLeft, midAxis); + + if (debug) { + switch(midAxis) { + case X_AXIS: + System.out.println("midAxis = X_AXIS"); + break; + case Y_AXIS: + System.out.println("midAxis = Y_AXIS"); + break; + case Z_AXIS: + System.out.println("midAxis = Z_AXIS"); + break; + } + System.out.println("midFactor = " + midFactor); + } + + if (midFactor < 0.0) { + // System.out.println("midFactor = " + midFactor); + if ((midFactor + TOL) >= 0.0) { + // System.out.println("In Tol case : midFactor = " + midFactor); + midFactor = 0.0; + } + else { + /* int point is outside triangle */ + return false; + } + } + else if (midFactor > 1.0) { + // System.out.println("midFactor = " + midFactor); + if ((midFactor-TOL) <= 1.0) { + // System.out.println("In Tol case : midFactor = " + midFactor); + midFactor = 1.0; + } + else { + /* int point is outside triangle */ + return false; + } + } + + // Assign the weights + interpWeights[base] = 1.0 - midFactor * leftFactor - + rightFactor + midFactor * rightFactor; + interpWeights[left] = midFactor * leftFactor; + interpWeights[right] = rightFactor - midFactor * rightFactor; + return true; + + } + + /* Get the interpolation weights for each of the verticies of the + * primitive. + */ + double[] getInterpWeights() { + + Point3d pt = getPointCoordinates(); + Point3d[] coordinates = getPrimitiveCoordinates(); + double factor; + int axis; + + if (interpWeights != null) { + return interpWeights; + } + + interpWeights = new double[coordinates.length]; + + // Interpolate + switch (coordinates.length) { + case 1: + // Nothing to interpolate + interpWeights[0] = 1.0; + break; + case 2: // edge + Vector3d delta = new Vector3d(); + delta.sub (coordinates[1], coordinates[0]); + axis = maxAxis(delta); + factor = getInterpFactor (pt, coordinates[1], coordinates[0], axis); + interpWeights[0] = factor; + interpWeights[1] = 1.0 - factor; + break; + case 3: // triangle + if (!interpTriangle(0, 1, 2, coordinates, pt)) { + throw new RuntimeException ("Interp point outside triangle"); + } + break; + case 4: // quad + if (!interpTriangle(0, 1, 2, coordinates, pt)) { + if (!interpTriangle(0, 2, 3, coordinates, pt)) { + throw new RuntimeException ("Interp point outside quad"); + } + } + break; + default: + throw new RuntimeException ("Unexpected number of points."); + } + return interpWeights; + } + + /** + Calculate the interpolation factor for point p by projecting it along + an axis (x,y,z) onto the edge between p1 and p2. If the result is + in the 0->1 range, point is between p1 and p2 (0 = point is at p1, + 1 => point is at p2). + */ + private static float getInterpFactor (Point3d p, Point3d p1, Point3d p2, + int axis) { + float t; + switch (axis) { + case X_AXIS: + if (p1.x == p2.x) + //t = Float.MAX_VALUE; // TODO: should be 0? + t = 0.0f; + else + t = (float) ((p1.x - p.x) / (p1.x - p2.x)); + break; + case Y_AXIS: + if (p1.y == p2.y) + // t = Float.MAX_VALUE; + t = 0.0f; + else + t = (float) ((p1.y - p.y) / (p1.y - p2.y)); + break; + case Z_AXIS: + if (p1.z == p2.z) + // t = Float.MAX_VALUE; + t = 0.0f; + else + t = (float)((p1.z - p.z) / (p1.z - p2.z)); + break; + default: + throw new RuntimeException ("invalid axis parameter "+axis+" (must be 0-2)"); + } + return t; + } + + /** + Calculate the interpolation factor for point p by projecting it along + an axis (x,y,z) onto the edge between p1 and p2. If the result is + in the 0->1 range, point is between p1 and p2 (0 = point is at p1, + 1 => point is at p2). + return MAX_VALUE if component of vertices are the same. + */ + private static float getInterpFactorForBase (Point3d p, Point3d p1, Point3d p2, + int axis) { + float t; + switch (axis) { + case X_AXIS: + if (p1.x == p2.x) + t = Float.MAX_VALUE; + else + t = (float) ((p1.x - p.x) / (p1.x - p2.x)); + break; + case Y_AXIS: + if (p1.y == p2.y) + t = Float.MAX_VALUE; + else + t = (float) ((p1.y - p.y) / (p1.y - p2.y)); + break; + case Z_AXIS: + if (p1.z == p2.z) + t = Float.MAX_VALUE; + else + t = (float)((p1.z - p.z) / (p1.z - p2.z)); + break; + default: + throw new RuntimeException ("invalid axis parameter "+axis+" (must be 0-2)"); + } + return t; + } + + +} // PickIntersection diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickTool.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickTool.java new file mode 100644 index 0000000..218970f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/PickTool.java @@ -0,0 +1,515 @@ +/* + * $RCSfile: PickTool.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:24 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.pickfast; + +import com.sun.j3d.utils.geometry.Primitive; +import javax.vecmath.*; +import javax.media.j3d.*; +import com.sun.j3d.internal.*; + +/** + * The base class for optimized picking operations. + * The picking methods will return a PickInfo object for each object picked, + * which can then be queried to + * obtain more detailed information about the specific objects that were + * picked. + *

+ * The pick mode specifies the detail level of picking before the PickInfo + * is returned: + *

+ *

    + *
  • PickInfo.PICK_BOUNDS - Pick using the only bounds of the pickable nodes. + *
  • + *
  • PickInfo.PICK_GEOMETRY will pick using the geometry of the pickable nodes. + * Geometry nodes in the scene must have the ALLOW_INTERSECT capability set for + * this mode.
  • + *

    + * The pick flags specifies the content of the PickInfo(s) returned by the + * pick methods. This is specified as one or more individual bits that are + * bitwise "OR"ed together to describe the PickInfo data. The flags include : + *

      + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
      + * PickInfo.NODE - request for computed intersected Node.
      + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
      + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
      + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
      + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
      + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
      + *
    + *
+ *

+ * When using pickAllSorted or pickClosest methods, the picks + * will be sorted by the distance from the start point of the pick shape to + * the intersection point. + * + * @see Locale#pickClosest(int,int,javax.media.j3d.PickShape) + */ +public class PickTool { + + + /** + * Flag to pass to + * getNode(int) + * to return a + * Shape3D node from + * the SceneGraphPath. + */ + public static final int TYPE_SHAPE3D = 0x1; + + /** + * Flag to pass to + * getNode(int) + * to return a + * Morph node from + * the SceneGraphPath. + */ + public static final int TYPE_MORPH = 0x2; + + /** + * Flag to pass to + * getNode(int) + + * to return a + * Primitive node from + * the SceneGraphPath. + */ + public static final int TYPE_PRIMITIVE = 0x4; + + /** + * Flag to pass to + * getNode(int) + * to return a + * Link node from + * the SceneGraphPath. + */ + public static final int TYPE_LINK = 0x8; + + /** + * Flag to pass to + * getNode(int) + * to return a + * Group node from + * the SceneGraphPath. + */ + public static final int TYPE_GROUP = 0x10; + + /** + * Flag to pass to + * getNode(int) + * to return a + * TransformGroup node from + * the SceneGraphPath. + */ + public static final int TYPE_TRANSFORM_GROUP = 0x20; + + /** + * Flag to pass to + * getNode(int) + * to return a + * BranchGroup node from + * the SceneGraphPath. + */ + public static final int TYPE_BRANCH_GROUP = 0x40; + + /** + * Flag to pass to + * getNode(int) + * to return a + * Switch node from + * the SceneGraphPath. + */ + public static final int TYPE_SWITCH = 0x80; + + + private static final int ALL_FLAGS = + PickInfo.SCENEGRAPHPATH | + PickInfo.NODE | + PickInfo.LOCAL_TO_VWORLD | + PickInfo.CLOSEST_INTERSECTION_POINT | + PickInfo.CLOSEST_DISTANCE | + PickInfo.CLOSEST_GEOM_INFO | + PickInfo.ALL_GEOM_INFO; + + private final boolean debug = false; + protected boolean userDefineShape = false; + + PickShape pickShape; + + /** Used to store the BranchGroup used for picking */ + BranchGroup pickRootBG = null; + /** Used to store the Locale used for picking */ + Locale pickRootL = null; + + /** Used to store a reference point used in determining how "close" points + are. + */ + Point3d start = null; + + int mode = PickInfo.PICK_BOUNDS; + int flags = PickInfo.NODE; + + /* ============================ METHODS ============================ */ + + /** + * Constructor with BranchGroup to be picked. + */ + public PickTool (BranchGroup b) { + pickRootBG = b; + } + + /** + * Constructor with the Locale to be picked. + */ + public PickTool (Locale l) { + pickRootL = l; + } + + /** Returns the BranchGroup to be picked if the tool was initialized + with a BranchGroup, null otherwise. + */ + public BranchGroup getBranchGroup() { + return pickRootBG; + } + + /** + * Returns the Locale to be picked if the tool was initialized with + * a Locale, null otherwise. + */ + public Locale getLocale () { + return pickRootL; + } + + // Methods used to define the pick shape + + /** Sets the pick shape to a user-provided PickShape object + * @param ps The pick shape to pick against. + * @param startPt The start point to use for distance calculations + */ + public void setShape (PickShape ps, Point3d startPt) { + this.pickShape = ps; + this.start = startPt; + userDefineShape = (ps != null); + } + + /** Sets the pick shape to use a user-provided Bounds object + * @param bounds The bounds to pick against. + * @param startPt The start point to use for distance calculations + */ + public void setShapeBounds (Bounds bounds, Point3d startPt) { + this.pickShape = (PickShape) new PickBounds (bounds); + this.start = startPt; + userDefineShape = true; + } + + /** Sets the picking detail mode. The default is PickInfo.PICK_BOUNDS. + * @param mode One of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY. + * @exception IllegalArgumentException if mode is not a legal value + */ + public void setMode (int mode) { + if ((mode != PickInfo.PICK_BOUNDS) && (mode != PickInfo.PICK_GEOMETRY)) { + throw new java.lang.IllegalArgumentException(); + } + this.mode = mode; + } + + /** Gets the picking detail mode. + */ + public int getMode () { + return mode; + } + + /** Sets the PickInfo content flags. The default is PickInfo.NODE. + * @param flags specified as one or more individual bits that are + * bitwise "OR"ed together : + *

    + * PickInfo.SCENEGRAPHPATH - request for computed SceneGraphPath.
    + * PickInfo.NODE - request for computed intersected Node.
    + * PickInfo.LOCAL_TO_VWORLD - request for computed local to virtual world transform.
    + * PickInfo.CLOSEST_INTERSECTION_POINT - request for closest intersection point.
    + * PickInfo.CLOSEST_DISTANCE - request for the distance of closest intersection.
    + * PickInfo.CLOSEST_GEOM_INFO - request for only the closest intersection geometry information.
    + * PickInfo.ALL_GEOM_INFO - request for all intersection geometry information.
    + *
+ * @exception IllegalArgumentException if any other bits besides the above are set. + */ + public void setFlags (int flags) { + if ((flags & ~ALL_FLAGS) != 0) { + throw new java.lang.IllegalArgumentException(); + } + this.flags = flags; + } + + /** Gets the PickInfo content flags. + */ + public int getFlags () { + return flags; + } + + /** Sets the pick shape to a PickRay. + * @param start The start of the ray + * @param dir The direction of the ray + */ + public void setShapeRay (Point3d start, Vector3d dir) { + this.pickShape = (PickShape) new PickRay (start, dir); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to a PickSegment. + @param start The start of the segment + @param end The end of the segment + */ + public void setShapeSegment (Point3d start, Point3d end) { + this.pickShape = (PickShape) new PickSegment (start, end); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to a capped PickCylinder + * @param start The start of axis of the cylinder + * @param end The end of the axis of the cylinder + * @param radius The radius of the cylinder + */ + public void setShapeCylinderSegment (Point3d start, Point3d end, + double radius) { + this.pickShape = (PickShape) + new PickCylinderSegment (start, end, radius); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to an infinite PickCylinder. + * @param start The start of axis of the cylinder + * @param dir The direction of the axis of the cylinder + * @param radius The radius of the cylinder + */ + public void setShapeCylinderRay (Point3d start, Vector3d dir, + double radius) { + this.pickShape = (PickShape) new PickCylinderRay (start, dir, radius); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to a capped PickCone + * @param start The start of axis of the cone + * @param end The end of the axis of the cone + * @param angle The angle of the cone + */ + public void setShapeConeSegment (Point3d start, Point3d end, + double angle) { + this.pickShape = (PickShape) new PickConeSegment (start, end, angle); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to an infinite PickCone. + * @param start The start of axis of the cone + * @param dir The direction of the axis of the cone + * @param angle The angle of the cone + */ + public void setShapeConeRay (Point3d start, Vector3d dir, + double angle) { + this.pickShape = (PickShape) new PickConeRay (start, dir, angle); + this.start = start; + userDefineShape = true; + } + + /** Returns the PickShape for this object. */ + public PickShape getPickShape () { + return pickShape; + } + + /** Returns the start postion used for distance measurement. */ + public Point3d getStartPosition () { + return start; + } + + /** Selects all the nodes that intersect the PickShape. + @return An array of PickInfo objects which will contain + information about the picked instances. null if nothing was + picked. + */ + public PickInfo[] pickAll () { + PickInfo[] pickInfos = null; + if (pickRootBG != null) { + pickInfos = pickRootBG.pickAll(mode, flags, pickShape); + } else if (pickRootL != null) { + pickInfos = pickRootL.pickAll(mode, flags, pickShape); + } + return pickInfos; + } + + /** Select one of the nodes that intersect the PickShape + @return A PickInfo object which will contain + information about the picked instance. null if nothing + was picked. + */ + public PickInfo pickAny () { + PickInfo pickInfo = null; + if (pickRootBG != null) { + pickInfo = pickRootBG.pickAny(mode, flags, pickShape); + } else if (pickRootL != null) { + pickInfo = pickRootL.pickAny(mode, flags, pickShape); + } + return pickInfo; + } + + /** Select all the nodes that intersect the + PickShape, returned sorted. The "closest" object will be returned first. + See note above to see how "closest" is determined. +

+ @return An array of PickInfo objects which will contain + information + about the picked instances. null if nothing was picked. + */ + public PickInfo[] pickAllSorted () { + PickInfo[] pickInfos = null; + if (pickRootBG != null) { + pickInfos = pickRootBG.pickAllSorted(mode, flags, pickShape); + } else if (pickRootL != null) { + pickInfos = pickRootL.pickAllSorted(mode, flags, pickShape); + } + return pickInfos; + } + + /** Select the closest node that + intersects the PickShape. See note above to see how "closest" is + determined. +

+ @return A PickInfo object which will contain + information about the picked instance. null if nothing + was picked. + */ + public PickInfo pickClosest () { + // System.out.println("PickTool : pickClosest ..."); + PickInfo pickInfo = null; + if (pickRootBG != null) { + pickInfo = pickRootBG.pickClosest(mode, flags, pickShape); + } else if (pickRootL != null) { + pickInfo = pickRootL.pickClosest(mode, flags, pickShape); + } + // System.out.println(" -- pickInfo is " + pickInfo); + + return pickInfo; + } + + /** Get the first node of a certain type up the SceneGraphPath + *@param type the type of node we are interested in + *@return a Node object + * + * @exception NullPointerException if pickInfo does not contain a + * Scenegraphpath or a picked node + */ + + public Node getNode (PickInfo pickInfo, int type) { + + // System.out.println("pickInfo is " + pickInfo); + + if (pickInfo == null) { + return null; + } + + SceneGraphPath sgp = pickInfo.getSceneGraphPath(); + Node pickedNode = pickInfo.getNode(); + // System.out.println("sgp = " + sgp + " pickedNode = " + pickedNode); + + + /* + * Do not check for null for pickNode and sgp. + * Will throw NPE if pickedNode or sgp isn't set in pickInfo + */ + + if ((pickedNode instanceof Shape3D) && ((type & TYPE_SHAPE3D) != 0)){ + if (debug) System.out.println("Shape3D found"); + return pickedNode; + } + else if ((pickedNode instanceof Morph) && ((type & TYPE_MORPH) != 0)){ + if (debug) System.out.println("Morph found"); + return pickedNode; + } + else { + for (int j=sgp.nodeCount()-1; j>=0; j--){ + Node pNode = sgp.getNode(j); + if (debug) System.out.println("looking at node " + pNode); + + if ((pNode instanceof Primitive) && + ((type & TYPE_PRIMITIVE) != 0)){ + if (debug) System.out.println("Primitive found"); + return pNode; + } + else if ((pNode instanceof Link) && ((type & TYPE_LINK) != 0)){ + if (debug) System.out.println("Link found"); + return pNode; + } + else if ((pNode instanceof Switch) && ((type & TYPE_SWITCH) != 0)){ + if (debug) System.out.println("Switch found"); + return pNode; + } + else if ((pNode instanceof TransformGroup) && + ((type & TYPE_TRANSFORM_GROUP) != 0)){ + if (debug) System.out.println("xform group found"); + return pNode; + } + else if ((pNode instanceof BranchGroup) && + ((type & TYPE_BRANCH_GROUP) != 0)){ + if (debug) System.out.println("Branch group found"); + return pNode; + } + else if ((pNode instanceof Group) && ((type & TYPE_GROUP) != 0)){ + if (debug) System.out.println("Group found"); + return pNode; + } + } + } + return null; // should not be reached + } + + +} // PickTool + + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickMouseBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickMouseBehavior.java new file mode 100644 index 0000000..c6d7533 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickMouseBehavior.java @@ -0,0 +1,179 @@ +/* + * $RCSfile: PickMouseBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:25 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.pickfast.behaviors; + +import com.sun.j3d.utils.pickfast.*; +import com.sun.j3d.internal.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + + +/** + * Base class that allows users to adding picking and mouse manipulation to + * the scene graph (see PickDragBehavior for an example of how to extend + * this base class). This class is useful for interactive apps. + */ + +public abstract class PickMouseBehavior extends Behavior { + + protected PickCanvas pickCanvas; + + protected WakeupCriterion[] conditions; + protected WakeupOr wakeupCondition; + protected boolean buttonPress = false; + + protected TransformGroup currGrp; + protected static final boolean debug = false; + protected MouseEvent mevent; + + /** + * Creates a PickMouseBehavior given current canvas, root of the tree to + * operate on, and the bounds. + */ + public PickMouseBehavior(Canvas3D canvas, BranchGroup root, Bounds bounds){ + super(); + currGrp = new TransformGroup(); + currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); + root.addChild(currGrp); + pickCanvas = new PickCanvas(canvas, root); + } + + /** + * Sets the pick mode + * @see PickTool#setMode + **/ + public void setMode(int pickMode) { + pickCanvas.setMode(pickMode); + } + + /** + * Returns the pickMode + * @see PickTool#getMode + */ + + public int getMode() { + return pickCanvas.getMode(); + } + + /** + * Sets the pick tolerance + * @see PickCanvas#setTolerance + */ + public void setTolerance(float tolerance) { + pickCanvas.setTolerance(tolerance); + } + + /** + * Returns the pick tolerance + * @see PickCanvas#getTolerance + */ + public float getTolerance() { + return pickCanvas.getTolerance(); + } + + public void initialize() { + + conditions = new WakeupCriterion[2]; + conditions[0] = new WakeupOnAWTEvent(Event.MOUSE_MOVE); + conditions[1] = new WakeupOnAWTEvent(Event.MOUSE_DOWN); + wakeupCondition = new WakeupOr(conditions); + + wakeupOn(wakeupCondition); + } + + private void processMouseEvent(MouseEvent evt) { + buttonPress = false; + + if (evt.getID()==MouseEvent.MOUSE_PRESSED | + evt.getID()==MouseEvent.MOUSE_CLICKED) { + buttonPress = true; + return; + } + else if (evt.getID() == MouseEvent.MOUSE_MOVED) { + // Process mouse move event + } + } + + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] evt = null; + int xpos = 0, ypos = 0; + + while(criteria.hasMoreElements()) { + wakeup = (WakeupCriterion)criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) + evt = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + } + + if (evt[0] instanceof MouseEvent){ + mevent = (MouseEvent) evt[0]; + + if (debug) + System.out.println("got mouse event"); + processMouseEvent((MouseEvent)evt[0]); + xpos = mevent.getPoint().x; + ypos = mevent.getPoint().y; + } + + if (debug) + System.out.println("mouse position " + xpos + " " + ypos); + + if (buttonPress){ + updateScene(xpos, ypos); + } + wakeupOn (wakeupCondition); + } + + + /** Subclasses shall implement this update function + */ + public abstract void updateScene(int xpos, int ypos); + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickRotateBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickRotateBehavior.java new file mode 100644 index 0000000..7dadf04 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickRotateBehavior.java @@ -0,0 +1,173 @@ +/* + * $RCSfile: PickRotateBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/15 01:07:42 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.pickfast.behaviors; + +import com.sun.j3d.utils.pickfast.*; +import com.sun.j3d.utils.behaviors.mouse.*; +import com.sun.j3d.internal.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * A mouse behavior that allows user to pick and rotate scene graph objects. + * Common usage: + *

+ * 1. Create your scene graph. + *

+ * 2. Create this behavior with root and canvas. + *

+ *

+ *	PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds);
+ *      root.addChild(behavior);
+ * 
+ *

+ * The above behavior will monitor for any picking events on + * the scene graph (below root node) and handle mouse rotates on pick hits. + * Note the root node can also be a subgraph node of the scene graph (rather + * than the topmost). + */ + +public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseRotate rotate; + private PickingCallback callback=null; + private TransformGroup currentTG; + + /** + * Creates a pick/rotate behavior that waits for user mouse events for + * the scene graph. This method has its pickMode set to BOUNDS picking. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + rotate = new MouseRotate(MouseRotate.MANUAL_WAKEUP); + rotate.setTransformGroup(currGrp); + currGrp.addChild(rotate); + rotate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/rotate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY. + * @see PickTool#setMode + **/ + + public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds, + int pickMode){ + super(canvas, root, bounds); + rotate = new MouseRotate(MouseRotate.MANUAL_WAKEUP); + rotate.setTransformGroup(currGrp); + currGrp.addChild(rotate); + rotate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.setMode(pickMode); + } + + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + public void updateScene(int xpos, int ypos) { + TransformGroup tg = null; + + if (!mevent.isMetaDown() && !mevent.isAltDown()){ + + // System.out.println("PickRotateBeh : using pickfast pkg : PickInfo ..."); + pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH); + + pickCanvas.setShapeLocation(xpos, ypos); + PickInfo pickInfo = pickCanvas.pickClosest(); + if(pickInfo != null) { + // System.out.println("Intersected!"); + tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP); + if((tg != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) { + rotate.setTransformGroup(tg); + rotate.wakeup(); + currentTG = tg; + } + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + } + } + + /** + * Callback method from MouseRotate + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.ROTATE, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + rotate.setupCallback( null ); + else + rotate.setupCallback( this ); + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickTranslateBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickTranslateBehavior.java new file mode 100644 index 0000000..f8d896d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickTranslateBehavior.java @@ -0,0 +1,162 @@ +/* + * $RCSfile: PickTranslateBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/15 01:07:43 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.pickfast.behaviors; + +import com.sun.j3d.utils.pickfast.*; +import com.sun.j3d.utils.behaviors.mouse.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * A mouse behavior that allows user to pick and translate scene graph objects. + * Common usage: 1. Create your scene graph. 2. Create this behavior with + * the root and canvas. See PickRotateBehavior for more details. + */ + +public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseTranslate translate; + private PickingCallback callback = null; + private TransformGroup currentTG; + + /** + * Creates a pick/translate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP); + translate.setTransformGroup(currGrp); + currGrp.addChild(translate); + translate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/translate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY. + * @see PickTool#setMode + **/ + public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, + Bounds bounds, int pickMode) { + super(canvas, root, bounds); + translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP); + translate.setTransformGroup(currGrp); + currGrp.addChild(translate); + translate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.setMode(pickMode); + } + + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + public void updateScene(int xpos, int ypos){ + TransformGroup tg = null; + + if(!mevent.isAltDown() && mevent.isMetaDown()){ + + pickCanvas.setShapeLocation(xpos, ypos); + + // System.out.println("PickTranslateBeh : using pickfast pkg : PickInfo ..."); + + pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH); + PickInfo pickInfo = pickCanvas.pickClosest(); + + if(pickInfo != null) { + // System.out.println("Intersected!"); + tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP); + if((tg != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) { + translate.setTransformGroup(tg); + translate.wakeup(); + currentTG = tg; + } + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + + } + + } + + /** + * Callback method from MouseTranslate + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.TRANSLATE, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + translate.setupCallback( null ); + else + translate.setupCallback( this ); + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickZoomBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickZoomBehavior.java new file mode 100644 index 0000000..43890d2 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickZoomBehavior.java @@ -0,0 +1,161 @@ +/* + * $RCSfile: PickZoomBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/15 01:07:45 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.pickfast.behaviors; + +import com.sun.j3d.utils.pickfast.*; +import com.sun.j3d.utils.behaviors.mouse.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + + +/** + * A mouse behavior that allows user to pick and zoom scene graph objects. + * Common usage: 1. Create your scene graph. 2. Create this behavior with + * the root and canvas. See PickRotateBehavior for more details. + */ + +public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseZoom zoom; + private PickingCallback callback = null; + private TransformGroup currentTG; + + /** + * Creates a pick/zoom behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP); + zoom.setTransformGroup(currGrp); + currGrp.addChild(zoom); + zoom.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/zoom behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY. + * @see PickTool#setMode + */ + public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds, + int pickMode) { + super(canvas, root, bounds); + zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP); + zoom.setTransformGroup(currGrp); + currGrp.addChild(zoom); + zoom.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.setMode(pickMode); + } + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + + public void updateScene(int xpos, int ypos){ + TransformGroup tg = null; + + if (mevent.isAltDown() && !mevent.isMetaDown()){ + + pickCanvas.setShapeLocation(xpos, ypos); + // System.out.println("PickZoomBeh : using pickfast pkg : PickInfo ..."); + + pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH); + + PickInfo pickInfo = pickCanvas.pickClosest(); + if(pickInfo != null) { + // System.out.println("Intersected!"); + tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP); + if((tg != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) { + zoom.setTransformGroup(tg); + zoom.wakeup(); + currentTG = tg; + } + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + + + } + } + + /** + * Callback method from MouseZoom + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.ZOOM, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + zoom.setupCallback( null ); + else + zoom.setupCallback( this ); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickingCallback.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickingCallback.java new file mode 100644 index 0000000..4c9512c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickingCallback.java @@ -0,0 +1,76 @@ +/* + * $RCSfile: PickingCallback.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:25 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.pickfast.behaviors; + +import javax.media.j3d.TransformGroup; + +/** + * The PickingCallback interface allows a class to be notified when a + * picked object is moved. The class that is interested in object + * movement implements this interface, and the object created with + * that class is registered with the desired subclass of + * PickMouseBehavior using the setupCallback method. + * When the picked object moves, the registered object's + * transformChanged method is invoked. + */ + +public interface PickingCallback { + + public final static int ROTATE=0; + public final static int TRANSLATE=1; + public final static int ZOOM=2; + + /** + * The user made a selection but nothing was + * actually picked + */ + public final static int NO_PICK=3; + + /** + * Called by the Pick Behavior with which this callback + * is registered each time the Picked object is moved + */ + public void transformChanged( int type, TransformGroup tg ); +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/package.html new file mode 100644 index 0000000..c401786 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.pickfast.behaviors + + +

Provides picking behaviors for the new core picking methods.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/package.html new file mode 100644 index 0000000..b23eb91 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/pickfast/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.pickfast + + +

Provides picking utility classes for the new core picking methods.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickCanvas.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickCanvas.java new file mode 100644 index 0000000..27ebf23 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickCanvas.java @@ -0,0 +1,248 @@ +/* + * $RCSfile: PickCanvas.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:25 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.picking; + +import java.awt.event.*; +import javax.vecmath.*; +import javax.media.j3d.*; +import com.sun.j3d.utils.geometry.*; // Cone, Cylinder + +/** + * A subclass of PickTool, simplifies picking using mouse events from a canvas. + * This class allows picking using canvas x,y locations by generating the + * appropriate pick shape. + *

+ * The pick tolerance specifies the distance from the + * pick center to include in the pick shape. A tolerance of 0.0 may speedup + * picking slightly, but also make it very difficult to pick points and lines. + *

+ * The pick canvas can be used to make a series of picks. For example, to + * initialize the pick canvas: + *

+ *     PickCanvas pickCanvas = new PickCanvas(canvas, scene);
+ *     pickCanvas.setMode(PickTool.GEOMETRY_INTERSECT_INFO); 
+ *     pickCanvas.setTolerance(4.0f);
+ * 
+ *

+ * Then for each mouse event: + *

+ *     pickCanvas.setShapeLocation(mouseEvent);
+ *     PickResult[] results = pickCanvas.pickAll();
+ * 
+ *

+ * NOTE: For the pickAllSorted or pickClosest methods, the picks will be sorted + * by the distance from the ViewPlatform to the intersection point. + * @see PickTool + */ +public class PickCanvas extends PickTool { + + /* OPEN ISSUES: + -- Should restrict the pick shape to the front/back clip plane + */ + + + /** The canvas we are picking into */ + Canvas3D canvas; + + /* the pick tolerance, default to 2.0 */ + float tolerance = 2.0f; + int save_xpos; + int save_ypos; + + /** Constructor with Canvas3D for mouse events and BranchGroup to be picked. + */ + public PickCanvas (Canvas3D c, BranchGroup b) { + super (b); + canvas = c; + } + + /** Constructor with Canvas3D for mouse events and Locale to be picked. + */ + public PickCanvas (Canvas3D c, Locale l) { + super (l); + canvas = c; + } + + /** Inquire the canvas to be used for picking operations. + @return the canvas. + */ + public Canvas3D getCanvas() { + return canvas; + } + + /** Set the picking tolerance. Objects within this distance + * (in pixels) + * to the mouse x,y location will be picked. The default tolerance is 2.0. + * @param t The tolerance + * @exception IllegalArgumentException if the tolerance is less than 0. + */ + public void setTolerance(float t) { + if (t < 0.0f) { + throw new IllegalArgumentException(); + } + tolerance = t; + + if ((pickShape != null) && (!userDefineShape)) { + // reset pickShape + pickShape = null; + setShapeLocation(save_xpos, save_ypos); + } + } + + /** Get the pick tolerance. + */ + public float getTolerance() { + return tolerance; + } + + /** Set the pick location. Defines the location on the canvas where the + pick is to be performed. + @param mevent The MouseEvent for the picking point + */ + public void setShapeLocation(MouseEvent mevent) { + setShapeLocation(mevent.getX(), mevent.getY()); + } + /** Set the pick location. Defines the location on the canvas where the + pick is to be performed (upper left corner of canvas is 0,0). + @param xpos the X position of the picking point + @param ypos the Y position of the picking point + */ + public void setShapeLocation (int xpos, int ypos) { + Transform3D motion = new Transform3D(); + Point3d eyePosn = new Point3d(); + Point3d mousePosn = new Point3d(); + Vector3d mouseVec = new Vector3d(); + boolean isParallel = false; + double radius = 0.0; + double spreadAngle = 0.0; + + this.save_xpos = xpos; + this.save_ypos = ypos; + canvas.getCenterEyeInImagePlate(eyePosn); + canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn); + + if ((canvas.getView() != null) && + (canvas.getView().getProjectionPolicy() == + View.PARALLEL_PROJECTION)) { + // Correct for the parallel projection: keep the eye's z + // coordinate, but make x,y be the same as the mouse, this + // simulates the eye being at "infinity" + eyePosn.x = mousePosn.x; + eyePosn.y = mousePosn.y; + isParallel = true; + } + + // Calculate radius for PickCylinderRay and spread angle for PickConeRay + Vector3d eyeToCanvas = new Vector3d(); + eyeToCanvas.sub (mousePosn, eyePosn); + double distanceEyeToCanvas = eyeToCanvas.length(); + + Point3d deltaImgPlate = new Point3d(); + canvas.getPixelLocationInImagePlate (xpos+1, ypos, deltaImgPlate); + + Vector3d ptToDelta = new Vector3d(); + ptToDelta.sub (mousePosn, deltaImgPlate); + double distancePtToDelta = ptToDelta.length(); + distancePtToDelta *= tolerance; + + canvas.getImagePlateToVworld(motion); + + /* + System.out.println("mouse position " + xpos + " " + ypos); + System.out.println("before, mouse " + mousePosn + " eye " + eyePosn); + */ + + motion.transform(eyePosn); + start = new Point3d (eyePosn); // store the eye position + motion.transform(mousePosn); + mouseVec.sub(mousePosn, eyePosn); + mouseVec.normalize(); + + /* + System.out.println(motion + "\n"); + System.out.println("after, mouse " + mousePosn + " eye " + eyePosn + + " mouseVec " + mouseVec); + */ + + if (tolerance == 0.0) { + if ((pickShape != null) && (pickShape instanceof PickRay)) { + ((PickRay)pickShape).set (eyePosn, mouseVec); + } else { + pickShape = (PickShape) new PickRay (eyePosn, mouseVec); + } + // pickShape = (PickShape) new PickConeRay (eyePosn, + // mouseVec,1.0*Math.PI/180.0); + } else { + if (isParallel) { + // Parallel projection, use a PickCylinderRay + distancePtToDelta *= motion.getScale(); + if ((pickShape != null) && + (pickShape instanceof PickCylinderRay)) { + ((PickCylinderRay)pickShape).set (eyePosn, mouseVec, + distancePtToDelta); + } else { + pickShape = (PickShape) new PickCylinderRay (eyePosn, + mouseVec, distancePtToDelta); + } + } else { + // Perspective projection, use a PickConeRay + + // Calculate spread angle + spreadAngle = Math.atan (distancePtToDelta/distanceEyeToCanvas); + + if ((pickShape != null) && + (pickShape instanceof PickConeRay)) { + ((PickConeRay)pickShape).set (eyePosn, mouseVec, + spreadAngle); + } else { + pickShape = (PickShape) new PickConeRay (eyePosn, mouseVec, + spreadAngle); + } + } + } + } +} // PickCanvas + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickIntersection.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickIntersection.java new file mode 100644 index 0000000..e621e24 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickIntersection.java @@ -0,0 +1,1576 @@ +/* + * $RCSfile: PickIntersection.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/03/02 21:27:15 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.picking; + +import javax.vecmath.*; +import javax.media.j3d.*; +import com.sun.j3d.utils.geometry.Primitive; + +/** + * Holds information about an intersection of a PickShape with a Node + * as part of a PickResult. Information about + * the intersected geometry, intersected primitive, intersection point, and + * closest vertex can be inquired. + *

+ * The intersected geometry is indicated by an index into the list of + * geometry arrays on the PickResult. It can also be inquired from this + * object. + *

+ * The intersected primitive indicates which primitive out of the GeometryArray + * was intersected (where the primitive is a point, line, triangle or quad, + * not a + * com.sun.j3d.utils.geometry.Primitive). + * For example, the intersection would indicate which triangle out of a + * triangle strip was intersected. + * The methods which return primitive data will have one value if the primitive + * is + * a point, two values if the primitive is a line, three values if the primitive + * is a triangle and four values if the primitive is quad. + *

+ * The primitive's VWorld coordinates are saved when then intersection is + * calculated. The local coordinates, normal, color and texture coordinates + * for the primitive can also be inquired if they are present and readable. + *

+ * The intersection point is the location on the primitive which intersects the + * pick shape closest to the center of the pick shape. The intersection point's + * location in VWorld coordinates is saved when the intersection is calculated. + * The local coordinates, normal, color and texture coordiantes of at the + * intersection can be interpolated if they are present and readable. + *

+ * The closest vertex is the vertex of the primitive closest to the intersection + * point. The vertex index, VWorld coordinates and local coordinates of the + * closest vertex can be inquired. The normal, color and texture coordinate + * of the closest vertex can be inquired from the geometry array: + *

+ *      Vector3f getNormal(PickIntersection pi, int vertexIndex) {
+ *          int index;
+ *          Vector3d normal = new Vector3f();
+ *          GeometryArray ga = pickIntersection.getGeometryArray();
+ *          if (pickIntersection.geometryIsIndexed()) {
+ *              index = ga.getNormalIndex(vertexIndex);
+ *          } else {
+ *              index = vertexIndex;
+ *          }
+ *          ga.getNormal(index, normal);
+ *          return normal;
+ *      }
+ * 
+ *

+ * The color, normal + * and texture coordinate information for the intersected primitive and the + * intersection point + * can be inquired + * the geometry includes them and the corresponding READ capibility bits are + * set. + * + * PickTool.setCapabilties(Node, int) + * can be used to set the capability bits + * to allow this data to be inquired. + */ +public class PickIntersection { + + /* OPEN ISSUES: + -- Tex coordinates always use texCoordSet == 0. + */ + + /* =================== ATTRIBUTES ======================= */ + + + // init by constructor: + + /** PickResult for intersection is part of */ + PickResult pickResult = null; + + // init by intersection: + /** Distance between start point and intersection point (see comment above)*/ + double distance = -1; + + /** index of GeometryArray in PickResult */ + int geomIndex = 0; + + /** Indices of the intersected primitive */ + int[] primitiveVertexIndices = null; + + /** VWorld coordinates of intersected primitive */ + Point3d[] primitiveCoordinatesVW = null; + + /** VWorld Coordinates of the intersection point */ + Point3d pointCoordinatesVW = null; + + // Derived data + + // Geometry + GeometryArray geom = null; + IndexedGeometryArray iGeom = null; + boolean hasNormals = false; + boolean hasColors = false; + boolean hasTexCoords = false; + + // Primitive + /* indices for the different data types */ + int[] primitiveCoordinateIndices; + int[] primitiveNormalIndices; + int[] primitiveColorIndices; + int[] primitiveTexCoordIndices; + + + /* Local coordinates of the intersected primitive */ + Point3d[] primitiveCoordinates = null; + + /* Normals of the intersected primitive */ + Vector3f[] primitiveNormals = null; + + /* Colors of the intersected primitive */ + Color4f[] primitiveColors = null; + + /* TextureCoordinates of the intersected primitive */ + TexCoord3f[] primitiveTexCoords = null; + + // Intersection point + + /** Local Coordinates of the intersection point */ + Point3d pointCoordinates = null; + + /** Normal at the intersection point */ + Vector3f pointNormal = null; + + /** Color at the intersection point */ + Color4f pointColor = null; + + /** TexCoord at the intersection point */ + TexCoord3f pointTexCoord = null; + + // Closest Vertex + /** Index of the closest vertex */ + int closestVertexIndex = -1; + + /** Coordinates of the closest vertex */ + Point3d closestVertexCoordinates = null; + + /** Coordinates of the closest vertex (World coordinates) */ + Point3d closestVertexCoordinatesVW = null; + + /** Weight factors for interpolation, values correspond to vertex indices, + * sum == 1 + */ + double[] interpWeights; + + static final boolean debug = false; + + // Axis constants + static final int X_AXIS = 1; + static final int Y_AXIS = 2; + static final int Z_AXIS = 3; + + // Tolerance for numerical stability + static final double TOL = 1.0e-5; + + /* =================== METHODS ======================= */ + + /** Constructor + @param pickResult The pickResult this intersection is part of. + */ + PickIntersection (PickResult pr, GeometryArray geomArr) { + + // pr can't be null. + pickResult = pr; + geom = geomArr; + if (geom == null) { + GeometryArray[] ga = pickResult.getGeometryArrays(); + geom = ga[geomIndex]; + + } + + if (geom instanceof IndexedGeometryArray) { + iGeom = (IndexedGeometryArray)geom; + } + int vertexFormat = geom.getVertexFormat(); + hasColors = (0 != (vertexFormat & + (GeometryArray.COLOR_3 | GeometryArray.COLOR_4))); + hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS)); + hasTexCoords = (0 != (vertexFormat & + (GeometryArray.TEXTURE_COORDINATE_2 | + GeometryArray.TEXTURE_COORDINATE_3))); + } + + /** + String representation of this object + */ + public String toString () { + String rt = new String ("PickIntersection: "); + rt += " pickResult = "+pickResult + "\n"; + rt += " geomIndex = "+geomIndex + "\n"; + if (distance != -1) rt += " dist:"+distance + "\n"; + if (pointCoordinates != null) rt += " pt:" + pointCoordinates + "\n"; + if (pointCoordinatesVW != null) rt += " ptVW:" + pointCoordinatesVW + "\n"; + + if (primitiveCoordinateIndices != null) { + rt += " prim coordinate ind:" + "\n"; + for (int i=0;i2, etc*/ + factor[0] = + getInterpFactorForBase(intPt, coords[index1], coords[index2], mainAxis); + factor[1] = + getInterpFactorForBase(intPt, coords[index2], coords[index0], mainAxis); + factor[2] = + getInterpFactorForBase(intPt, coords[index0], coords[index1], mainAxis); + + if (debug) { + System.out.println("intPt = " + intPt); + switch(mainAxis) { + case X_AXIS: + System.out.println("mainAxis = X_AXIS"); + break; + case Y_AXIS: + System.out.println("mainAxis = Y_AXIS"); + break; + case Z_AXIS: + System.out.println("mainAxis = Z_AXIS"); + break; + } + System.out.println("factor[0] = " + factor[0]); + System.out.println("factor[1] = " + factor[1]); + System.out.println("factor[2] = " + factor[2]); + } + + /* Find the factor that is out of range, it will tell us which + * vertex to use for base + */ + int base, left, right; + double leftFactor, rightFactor; + if ((factor[0] < 0.0) || (factor[0] > 1.0)) { + base = index0; + right = index1; + left = index2; + rightFactor = factor[2]; + leftFactor = 1.0 - factor[1]; + if (debug) { + System.out.println("base 0, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } else if ((factor[1] < 0.0) || (factor[1] > 1.0)) { + base = index1; + right = index2; + left = index0; + rightFactor = factor[0]; + leftFactor = 1.0 - factor[2]; + if (debug) { + System.out.println("base 1, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } else { + base = index2; + right = index0; + left = index1; + rightFactor = factor[1]; + leftFactor = 1.0 - factor[0]; + if (debug) { + System.out.println("base 2, rightFactor = " + rightFactor + + " leftFactor = " + leftFactor); + } + } + if (debug) { + System.out.println("base = " + coords[base]); + System.out.println("left = " + coords[left]); + System.out.println("right = " + coords[right]); + } + /* find iLeft and iRight */ + Point3d iLeft = new Point3d(leftFactor * coords[left].x + + (1.0-leftFactor)*coords[base].x, + leftFactor * coords[left].y + + (1.0-leftFactor)*coords[base].y, + leftFactor * coords[left].z + + (1.0-leftFactor)*coords[base].z); + + Point3d iRight = new Point3d(rightFactor * coords[right].x + + (1.0-rightFactor)*coords[base].x, + rightFactor * coords[right].y + + (1.0-rightFactor)*coords[base].y, + rightFactor * coords[right].z + + (1.0-rightFactor)*coords[base].z); + + if (debug) { + System.out.println("iLeft = " + iLeft); + System.out.println("iRight = " + iRight); + } + + /* now find an axis and solve for midFactor */ + delta0.sub(iLeft, iRight); + int midAxis = maxAxis(delta0); + double midFactor = getInterpFactor(intPt, iRight, iLeft, midAxis); + + if (debug) { + switch(midAxis) { + case X_AXIS: + System.out.println("midAxis = X_AXIS"); + break; + case Y_AXIS: + System.out.println("midAxis = Y_AXIS"); + break; + case Z_AXIS: + System.out.println("midAxis = Z_AXIS"); + break; + } + System.out.println("midFactor = " + midFactor); + } + + if (midFactor < 0.0) { + // System.out.println("midFactor = " + midFactor); + if ((midFactor + TOL) >= 0.0) { + // System.out.println("In Tol case : midFactor = " + midFactor); + midFactor = 0.0; + } + else { + /* int point is outside triangle */ + return false; + } + } + else if (midFactor > 1.0) { + // System.out.println("midFactor = " + midFactor); + if ((midFactor-TOL) <= 1.0) { + // System.out.println("In Tol case : midFactor = " + midFactor); + midFactor = 1.0; + } + else { + /* int point is outside triangle */ + return false; + } + } + + // Assign the weights + interpWeights[base] = 1.0 - midFactor * leftFactor - + rightFactor + midFactor * rightFactor; + interpWeights[left] = midFactor * leftFactor; + interpWeights[right] = rightFactor - midFactor * rightFactor; + return true; + + } + + /* Get the interpolation weights for each of the verticies of the + * primitive. + */ + double[] getInterpWeights() { + + Point3d pt = getPointCoordinatesVW(); + Point3d[] coordinates = getPrimitiveCoordinatesVW(); + double factor; + int axis; + + if (interpWeights != null) { + return interpWeights; + } + + interpWeights = new double[coordinates.length]; + + // Interpolate + switch (coordinates.length) { + case 1: + // Nothing to interpolate + interpWeights[0] = 1.0; + break; + case 2: // edge + Vector3d delta = new Vector3d(); + delta.sub (coordinates[1], coordinates[0]); + axis = maxAxis(delta); + factor = getInterpFactor (pt, coordinates[1], coordinates[0], axis); + interpWeights[0] = factor; + interpWeights[1] = 1.0 - factor; + break; + case 3: // triangle + if (!interpTriangle(0, 1, 2, coordinates, pt)) { + throw new RuntimeException ("Interp point outside triangle"); + } + break; + case 4: // quad + if (!interpTriangle(0, 1, 2, coordinates, pt)) { + if (!interpTriangle(0, 2, 3, coordinates, pt)) { + throw new RuntimeException ("Interp point outside quad"); + } + } + break; + default: + throw new RuntimeException ("Unexpected number of points."); + } + return interpWeights; + } + + /** + Calculate the interpolation factor for point p by projecting it along + an axis (x,y,z) onto the edge between p1 and p2. If the result is + in the 0->1 range, point is between p1 and p2 (0 = point is at p1, + 1 => point is at p2). + */ + private static float getInterpFactor (Point3d p, Point3d p1, Point3d p2, + int axis) { + float t; + switch (axis) { + case X_AXIS: + if (p1.x == p2.x) + //t = Float.MAX_VALUE; // TODO: should be 0? + t = 0.0f; + else + t = (float) ((p1.x - p.x) / (p1.x - p2.x)); + break; + case Y_AXIS: + if (p1.y == p2.y) + // t = Float.MAX_VALUE; + t = 0.0f; + else + t = (float) ((p1.y - p.y) / (p1.y - p2.y)); + break; + case Z_AXIS: + if (p1.z == p2.z) + // t = Float.MAX_VALUE; + t = 0.0f; + else + t = (float)((p1.z - p.z) / (p1.z - p2.z)); + break; + default: + throw new RuntimeException ("invalid axis parameter "+axis+" (must be 0-2)"); + } + return t; + } + + /** + Calculate the interpolation factor for point p by projecting it along + an axis (x,y,z) onto the edge between p1 and p2. If the result is + in the 0->1 range, point is between p1 and p2 (0 = point is at p1, + 1 => point is at p2). + return MAX_VALUE if component of vertices are the same. + */ + private static float getInterpFactorForBase (Point3d p, Point3d p1, Point3d p2, + int axis) { + float t; + switch (axis) { + case X_AXIS: + if (p1.x == p2.x) + t = Float.MAX_VALUE; + else + t = (float) ((p1.x - p.x) / (p1.x - p2.x)); + break; + case Y_AXIS: + if (p1.y == p2.y) + t = Float.MAX_VALUE; + else + t = (float) ((p1.y - p.y) / (p1.y - p2.y)); + break; + case Z_AXIS: + if (p1.z == p2.z) + t = Float.MAX_VALUE; + else + t = (float)((p1.z - p.z) / (p1.z - p2.z)); + break; + default: + throw new RuntimeException ("invalid axis parameter "+axis+" (must be 0-2)"); + } + return t; + } + + +} // PickIntersection + + + + + + + + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickResult.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickResult.java new file mode 100644 index 0000000..a7be1ed --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/PickResult.java @@ -0,0 +1,3182 @@ +/* + * $RCSfile: PickResult.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/02/09 17:20:26 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.picking; + +import javax.vecmath.*; +import javax.media.j3d.*; +import java.util.ArrayList; +import com.sun.j3d.utils.geometry.Primitive; +import com.sun.j3d.internal.*; + +/** + * Stores information about a pick hit. + * Detailed information about the pick and each intersection of the PickShape + * with the picked Node can be inquired. The PickResult is constructed with + * basic information and more detailed information is generated as needed. The + * additional information is only available if capability bits on the scene + * graph Nodes are set properly; + * + * PickTool.setCapabilties(Node, int) + * can + * be used to ensure correct capabilites are set. Inquiring data which is not + * available due to capabilties not being set will generate a + * CapabilityNotSet exception. + *

+ * A PickResult can be used to calculate intersections on Node which is not part + * of a live scene graph using the constructor which takes a local to VWorld + * transformation for the Node. + *

+ * Pick hits on TriangleStrip primitives will store the triangle points in the + * PickIntersection with + * the verticies in counter-clockwise order. For triangles which start with + * an odd numbered vertex this will be the the opposite of the + * order of the points in the TriangleStrip. + * This way the triangle in + * the PickIntersection will display the same was as the triangle in the + * strip. + *

+ * If the Shape3D being picked has multiple geometry arrays, the arrays are + * stored in the PickResult and referred to by a geometry index. + *

+ * If the Shape3D refers to a CompressedGeometry, the geometry is decompressed + * into an array of Shape3D nodes which can be inquired. The geometry + * NodeComponents for the Shape3D nodes are stored and used as if the Shape3D + * had multiple geometries. If there are multiple CompressedGeometries on the + * Shape3D, the decompressed Shape3Ds and GeometryArrays will be stored + * sequentially. + *

+ * The intersection point for Morph nodes cannot be calculated using the + * displayed geometry + * due to limitations in the current Java3D core API (the current + * geometry of the the Morph cannot be inquired). Instead + * the geometry at index 0 in the Morph is used. This limitation may + * be eliminated in a future release of Java3D. + */ +public class PickResult { + + /* OPEN ISSUES: + -- getInterpolatedTextureCoordinates uses the depricated API faor + getTextureCoordinate(), need to update. + -- Bounds tests don't fill in any picking info. + -- Can't do any intersections with the PickPoint shape. + */ + + + // Externally used constants + + /** + * Flag to pass to + * getNode(int) + * to return a + * Shape3D node from + * the SceneGraphPath. + */ + public static final int SHAPE3D = 0x1; + + /** + * Flag to pass to + * getNode(int) + * to return a + * Morph node from + * the SceneGraphPath. + */ + public static final int MORPH = 0x2; + + /** + * Flag to pass to + * getNode(int) + + * to return a + * Primitive node from + * the SceneGraphPath. + */ + public static final int PRIMITIVE = 0x4; + + /** + * Flag to pass to + * getNode(int) + * to return a + * Link node from + * the SceneGraphPath. + */ + public static final int LINK = 0x8; + + /** + * Flag to pass to + * getNode(int) + * to return a + * Group node from + * the SceneGraphPath. + */ + public static final int GROUP = 0x10; + + /** + * Flag to pass to + * getNode(int) + * to return a + * TransformGroup node from + * the SceneGraphPath. + */ + public static final int TRANSFORM_GROUP = 0x20; + + /** + * Flag to pass to + * getNode(int) + * to return a + * BranchGroup node from + * the SceneGraphPath. + */ + public static final int BRANCH_GROUP = 0x40; + + /** + * Flag to pass to + * getNode(int) + * to return a + * Switch node from + * the SceneGraphPath. + */ + public static final int SWITCH = 0x80; + + + + /* =================== ATTRIBUTES ======================= */ + static boolean debug = false; + + /** if true, find only the first intersection */ + private boolean firstIntersectOnly = false; + + /** Stored SceneGraphPath */ + private SceneGraphPath pickedSceneGraphPath = null; + + /** Picked node: shape3d, text3d, etc. */ + private Node pickedNode = null; + + /** GeometryArray(s) of the picked node */ + private GeometryArray[] geometryArrays = null; + + /** Shape3Ds from CompressedGeometry on the picked node */ + private Shape3D[] compressGeomShape3Ds = null; + + /** Transform to World Coordinates */ + private Transform3D localToVWorld = null; + + /** the pick shape to use for intersections */ + private PickShape pickShape = null; + /* data derived from the pick shape */ + private int pickShapeType = -1; + private Vector3d pickShapeDir = null; + private Point3d pickShapeStart = null; + private Point3d pickShapeEnd = null; + private Bounds pickShapeBounds = null; + + static final Point3d zeroPnt = new Point3d(); + + /** ArrayList to store intersection results + * Used in PickTool + */ + ArrayList intersections = null; + + // internal constants used for intersections + static final double FUZZ = 1E-6; /* fuzziness factor used to determine + if two lines are parallel */ + static final int PICK_SHAPE_RAY = 1; + static final int PICK_SHAPE_SEGMENT = 2; + static final int PICK_SHAPE_POINT = 3; + static final int PICK_SHAPE_BOUNDING_BOX = 4; + static final int PICK_SHAPE_BOUNDING_SPHERE = 5; + static final int PICK_SHAPE_BOUNDING_POLYTOPE = 6; + static final int PICK_SHAPE_CYLINDER = 7; + static final int PICK_SHAPE_CONE = 8; + + static final double EPS = 1.0e-13; + + + /* =================== METHODS ======================= */ + + /** Default constructor. */ + PickResult () { } + + /** Construct a PickResult using a SceneGraphPath + @param sgp SceneGraphPath associated with this PickResult + @param ps The pickShape to intersect against + */ + public PickResult (SceneGraphPath sgp, PickShape ps) { + pickedSceneGraphPath = sgp; + pickedNode = sgp.getObject(); + localToVWorld = sgp.getTransform(); + pickShape = ps; + initPickShape(); + } + + + /** Construct a PickResult using the Node and localToVWorld transform + @param pn The picked node. + @param l2vw The local to VWorld transformation for the node + @param ps The PickShape to intersect against + @throws IllegalArgumentException If the node is not a Morph or Shape3D. + */ + public PickResult (Node pn, Transform3D l2vw, PickShape ps) { + if ((pn instanceof Shape3D) || (pn instanceof Morph)) { + pickedNode = pn; + localToVWorld = l2vw; + pickShape = ps; + initPickShape(); + } else { + throw new IllegalArgumentException(); + } + } + + void initPickShape() { + if(pickShape instanceof PickRay) { + if (pickShapeStart == null) pickShapeStart = new Point3d(); + if (pickShapeDir == null) pickShapeDir = new Vector3d(); + ((PickRay) pickShape).get (pickShapeStart, pickShapeDir); + pickShapeType = PICK_SHAPE_RAY; + } else if (pickShape instanceof PickSegment) { + if (pickShapeStart == null) pickShapeStart = new Point3d(); + if (pickShapeEnd == null) pickShapeEnd = new Point3d(); + if (pickShapeDir == null) pickShapeDir = new Vector3d(); + ((PickSegment)pickShape).get(pickShapeStart, pickShapeEnd); + pickShapeDir.set (pickShapeEnd.x - pickShapeStart.x, + pickShapeEnd.y - pickShapeStart.y, + pickShapeEnd.z - pickShapeStart.z); + pickShapeType = PICK_SHAPE_SEGMENT; + } else if (pickShape instanceof PickBounds) { + pickShapeBounds = ((PickBounds) pickShape).get(); + if ( pickShapeBounds instanceof BoundingBox ) + pickShapeType = PICK_SHAPE_BOUNDING_BOX; + else if( pickShapeBounds instanceof BoundingSphere ) + pickShapeType = PICK_SHAPE_BOUNDING_SPHERE; + else if( pickShapeBounds instanceof BoundingPolytope ) + pickShapeType = PICK_SHAPE_BOUNDING_POLYTOPE; + } else if(pickShape instanceof PickPoint) { + throw new RuntimeException ("PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance."); + } else if (pickShape instanceof PickCylinder) { + pickShapeType = PICK_SHAPE_CYLINDER; + } else if (pickShape instanceof PickCone) { + pickShapeType = PICK_SHAPE_CONE; + } else { + throw new + RuntimeException("PickShape not supported for intersection"); + } + } + + /** Get the SceneGraphPath. This will be null if the non SceneGraphPath + * constructor was used. + */ + public SceneGraphPath getSceneGraphPath() { + /* Q: should this return a copy */ + return pickedSceneGraphPath; + } + + + /** Get the localToVworld transform for the Node + */ + public Transform3D getLocalToVworld() { + return localToVWorld; + } + + /** Get the GeometryArray at index 0 for the picked node + */ + public GeometryArray getGeometryArray() { + if (geometryArrays == null) { + storeGeometry(); + } + return geometryArrays[0]; + } + + /** Get the array of GeometryArrays for the picked node + */ + public GeometryArray[] getGeometryArrays() { + if (geometryArrays == null) { + storeGeometry(); + } + return geometryArrays; + } + + /** Get the number of GeometryArrays for the picked node + */ + public int numGeometryArrays() { + if (geometryArrays == null) { + storeGeometry(); + } + return geometryArrays.length; + } + + /** Get the number of Shape3Ds that came from decompressing a + CompressedGeometry on the picked node. + */ + public int numCompressedGeometryShape3Ds() { + if (geometryArrays == null) { + storeGeometry(); + } + if (compressGeomShape3Ds == null) { + return 0; + } else { + return compressGeomShape3Ds.length; + } + } + + /** Get the array of Shape3Ds that came from decompressing a + CompressedGeometry on the picked node. + */ + public Shape3D[] getCompressedGeometryShape3Ds() { + if (geometryArrays == null) { + storeGeometry(); + } + if (compressGeomShape3Ds == null) { + return null; + } else { + return compressGeomShape3Ds; + } + } + + /** Get the PickShape used for intersections + */ + public PickShape getPickShape() { + return pickShape; + } + + /** Set the PickResult to find only the first intersection of the PickShape + * with the Node. The default is false (all intersections are + * found) + */ + public void setFirstIntersectOnly(boolean flag) { + firstIntersectOnly = flag; + } + + /** Return the "first intersection only" value. */ + public boolean getFirstPickEnable() { + return firstIntersectOnly; + } + + /** Returns the number of PickIntersections in the PickResult. + @return the number of intersections + */ + public int numIntersections () { + if (intersections == null) { + generateIntersections(); + } + return intersections.size(); + } + + /** Returns a specific PickIntersection object + @param index the index number + @return the PickIntersection referenced by the index number + */ + public PickIntersection getIntersection (int index) { + if (intersections == null) { + generateIntersections(); + } + return (PickIntersection) intersections.get (index); + } + + /** Gets the PickIntersection in this PickResult that is closest to a point + @param pt the point to use for distance calculations + @return the closest PickIntersection object + */ + public PickIntersection getClosestIntersection (Point3d pt) { + PickIntersection pi = null; + PickIntersection curPi = null; + Point3d curPt = null; + double minDist = Double.MAX_VALUE; + double curDist = 0.0; + + if (pt == null) return null; + + if (intersections == null) { + generateIntersections(); + } + + for (int i=0;i 0) { + for (int i=0;i=0; j--){ + Node pNode = pickedSceneGraphPath.getNode(j); + if (debug) System.out.println("looking at node " + pNode); + + if ((pNode instanceof Primitive) && + ((flags & PRIMITIVE) != 0)){ + if (debug) System.out.println("Primitive found"); + return pNode; + } + else if ((pNode instanceof Link) && ((flags & LINK) != 0)){ + if (debug) System.out.println("Link found"); + return pNode; + } + else if ((pNode instanceof Switch) && ((flags & SWITCH) != 0)){ + if (debug) System.out.println("Switch found"); + return pNode; + } + else if ((pNode instanceof TransformGroup) && + ((flags & TRANSFORM_GROUP) != 0)){ + if (debug) System.out.println("xform group found"); + return pNode; + } + else if ((pNode instanceof BranchGroup) && + ((flags & BRANCH_GROUP) != 0)){ + if (debug) System.out.println("Branch group found"); + return pNode; + } + else if ((pNode instanceof Group) && ((flags & GROUP) != 0)){ + if (debug) System.out.println("Group found"); + return pNode; + } + } + } + return null; // should not be reached + } + + /** Extract the picked node from the SceneGraphPath */ + void storeNode () { + if (pickedSceneGraphPath == null) { + throw new RuntimeException ("SceneGraphPath missing"); + } + pickedNode = pickedSceneGraphPath.getObject(); + } + + /** Fill in the intersections of the Node with the PickShape */ + boolean generateIntersections() { + if (geometryArrays == null) { + storeGeometry(); + } + intersections = new ArrayList(); + int hits = 0; + + for (int i = 0; i < geometryArrays.length; i++) { + if (intersect(i, firstIntersectOnly)) { + if (firstIntersectOnly) { + return true; + } else { + hits++; + } + } + } + return (hits > 0); + } + + + + /* Takes a GeometryArray object, determines what actual type + * it is (RTTI) and casts it to call the appropriate intersect method. + */ + final boolean intersect(int geomIndex, boolean firstpick) { + int offset; + GeometryArray geom = geometryArrays[geomIndex]; + int numPts = geom.getVertexCount(); + double[] doubleData = null; + float[] floatData = null; + Point3d[] p3dData = null; + Point3f[] p3fData = null; + int vformat = geom.getVertexFormat(); + int stride; + boolean retFlag = false; + + if ((vformat & GeometryArray.BY_REFERENCE) == 0) { + doubleData = new double [numPts * 3]; + geom.getCoordinates (0, doubleData); + } + else { + if ((vformat & GeometryArray.INTERLEAVED) == 0) { + doubleData = geom.getCoordRefDouble(); + // If data was set as float then .. + if (doubleData == null) { + floatData = geom.getCoordRefFloat(); + if (floatData == null) { + p3fData = geom.getCoordRef3f(); + if (p3fData == null) { + p3dData = geom.getCoordRef3d(); + } + } + } + } + else { + floatData = geom.getInterleavedVertices(); + } + } + + + Point3d[] pnts = new Point3d[numPts]; + + /* + System.out.println("geomIndex : " + geomIndex); + System.out.println("numPts : " + numPts); + System.out.println("firstpick : " + firstpick); + System.out.println("localToVWorld : "); + System.out.println(localToVWorld); + */ + + if (debug) { + System.out.println("localToVWorld = " + localToVWorld); + } + if ((vformat & GeometryArray.INTERLEAVED) == 0) { + if (doubleData != null) { + offset = 0; + for (int i=0; i < numPts; i++) { + + // Need to transform each pnt by localToVWorld. + pnts[i] = new Point3d(); + pnts[i].x = doubleData[offset++]; + pnts[i].y = doubleData[offset++]; + pnts[i].z = doubleData[offset++]; + + localToVWorld.transform(pnts[i]); + } + } + else if (floatData != null) { // by reference and float data is defined .. + offset = 0; + for (int i=0; i < numPts; i++) { + + // Need to transform each pnt by localToVWorld. + pnts[i] = new Point3d(); + pnts[i].x = floatData[offset++]; + pnts[i].y = floatData[offset++]; + pnts[i].z = floatData[offset++]; + + localToVWorld.transform(pnts[i]); + } + } + else if (p3fData != null) { + for (int i=0; i < numPts; i++) { + + // Need to transform each pnt by localToVWorld. + pnts[i] = new Point3d(); + pnts[i].set(p3fData[i]); + localToVWorld.transform(pnts[i]); + } + } + else { // p3dData + for (int i=0; i < numPts; i++) { + + // Need to transform each pnt by localToVWorld. + pnts[i] = new Point3d(); + pnts[i].set(p3dData[i]); + localToVWorld.transform(pnts[i]); + } + } + } + // Its an interleaved type .. + else { + offset = 0; + if ((vformat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3) { + offset += 3; + } + else if ((vformat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) { + offset += 4; + } + if ((vformat & GeometryArray.NORMALS) != 0) + offset += 3; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) == GeometryArray.TEXTURE_COORDINATE_2) { + offset += 2 * geom.getTexCoordSetCount(); + } + else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) == GeometryArray.TEXTURE_COORDINATE_3) { + offset += 3 * geom.getTexCoordSetCount(); + } + stride = offset + 3; // for the vertices . + for (int i=0; i < numPts; i++) { + + // Need to transform each pnt by localToVWorld. + pnts[i] = new Point3d(); + pnts[i].x = floatData[offset]; + pnts[i].y = floatData[offset+1]; + pnts[i].z = floatData[offset+2]; + + localToVWorld.transform(pnts[i]); + offset += stride; + } + } + + PickIntersection pi = new PickIntersection(this, geom); + + if (geom instanceof PointArray) { + retFlag = intersectPA ((PointArray)geom, geomIndex, pnts, firstpick, pi); + } else if (geom instanceof IndexedPointArray) { + pi.iGeom = (IndexedGeometryArray) geom; + retFlag = intersectIPA ((IndexedPointArray)geom, geomIndex, pnts, + firstpick, pi); + } else if (geom instanceof LineArray) { + retFlag = intersectLA ((LineArray)geom, geomIndex, pnts, firstpick, pi); + } else if (geom instanceof LineStripArray) { + retFlag = intersectLSA ((LineStripArray)geom, geomIndex, pnts, + firstpick, pi); + } else if (geom instanceof IndexedLineArray) { + pi.iGeom = (IndexedGeometryArray) geom; + retFlag = intersectILA ((IndexedLineArray)geom, geomIndex, pnts, + firstpick, pi); + } else if (geom instanceof IndexedLineStripArray) { + pi.iGeom = (IndexedGeometryArray) geom; + retFlag = intersectILSA ((IndexedLineStripArray)geom, geomIndex, pnts, + firstpick, pi); + } else if (geom instanceof TriangleArray) { + retFlag = intersectTA ((TriangleArray)geom, geomIndex, pnts, + firstpick, pi); + } else if (geom instanceof TriangleStripArray) { + retFlag = intersectTSA ((TriangleStripArray)geom, geomIndex, pnts, + firstpick, pi); + } else if (geom instanceof TriangleFanArray) { + retFlag = intersectTFA ((TriangleFanArray)geom, geomIndex, pnts, + firstpick, pi); + } else if (geom instanceof IndexedTriangleArray) { + pi.iGeom = (IndexedGeometryArray) geom; + retFlag = intersectITA ((IndexedTriangleArray)geom, geomIndex, pnts, + firstpick, pi); + } else if (geom instanceof IndexedTriangleStripArray) { + pi.iGeom = (IndexedGeometryArray) geom; + retFlag = intersectITSA ((IndexedTriangleStripArray)geom, geomIndex, + pnts, firstpick, pi); + } else if (geom instanceof IndexedTriangleFanArray) { + pi.iGeom = (IndexedGeometryArray) geom; + retFlag = intersectITFA ((IndexedTriangleFanArray)geom, geomIndex, + pnts, firstpick, pi); + } else if (geom instanceof QuadArray) { + retFlag = intersectQA ((QuadArray)geom, geomIndex, pnts, firstpick, pi); + } else if (geom instanceof IndexedQuadArray) { + pi.iGeom = (IndexedGeometryArray) geom; + retFlag = intersectIQA ((IndexedQuadArray)geom, geomIndex, pnts, + firstpick, pi); + } else { + throw new RuntimeException ("incorrect class type"); + } + return retFlag; + + } + + + + /* ==================================================================== */ + /* INTERSECT METHODS BY PRIMITIVE TYPE */ + /* ==================================================================== */ + + boolean intersectPoint(int[] vertidx, int[] coordidx, int geomIndex, + Point3d[] pnts, PickIntersection pi) { + // PickIntersection pi = new PickIntersection(this); + + Point3d[] point = new Point3d[1]; + point[0] = pnts[coordidx[0]]; + + if (debug) { + System.out.println("intersect point, point = " + point[0]); + } + + boolean intersect = false; + switch(pickShapeType) { + case PICK_SHAPE_RAY: + intersect = intersectPntAndRay(point[0], pickShapeStart, + pickShapeDir, pi); + break; + case PICK_SHAPE_SEGMENT: + if (intersectPntAndRay(point[0], pickShapeStart, pickShapeDir, pi)){ + if(pi.getDistance() <= 1.0) { // TODO: why 1.0? + intersect = true; + } + } + break; + /* case PICK_SHAPE_POINT: + intersect = intersectPntAndPnt(point[0], + ((PickPoint) pickShape).location ); + break; + */ + case PICK_SHAPE_BOUNDING_BOX: + intersect = ((BoundingBox)pickShapeBounds).intersect(point[0]); + pi.setPointCoordinatesVW(point[0]); + break; + case PICK_SHAPE_BOUNDING_SPHERE: + intersect = ((BoundingSphere)pickShapeBounds).intersect(point[0]); + pi.setPointCoordinatesVW(point[0]); + break; + case PICK_SHAPE_BOUNDING_POLYTOPE: + intersect = ((BoundingPolytope)pickShapeBounds).intersect(point[0]); + pi.setPointCoordinatesVW(point[0]); + break; + case PICK_SHAPE_CYLINDER: + intersect = intersectCylinder(point[0], (PickCylinder)pickShape,pi); + break; + case PICK_SHAPE_CONE: + intersect = intersectCone (point[0], (PickCone)pickShape, pi); + break; + } + if (intersect) { + PickIntersection newpi = new PickIntersection(this, pi.geom); + newpi.iGeom = pi.iGeom; + newpi.setDistance(pi.distance); + newpi.setPointCoordinatesVW(pi.getPointCoordinatesVW()); + + // Set PickIntersection parameters + newpi.setGeomIndex(geomIndex); + newpi.setVertexIndices (vertidx); + newpi.setPrimitiveCoordinatesVW(point); + intersections.add (newpi); + return true; + } + return false; + } + + boolean intersectLine(int[] vertidx, int[] coordidx, int geomIndex, + Point3d[] pnts, PickIntersection pi) { + + Point3d[] linePts = new Point3d[2]; + linePts[0] = pnts[coordidx[0]]; + linePts[1] = pnts[coordidx[1]]; + + boolean intersect = false; + switch(pickShapeType) { + case PICK_SHAPE_RAY: + intersect = intersectLineAndRay(linePts[0], linePts[1], + pickShapeStart, pickShapeDir, pi); + break; + case PICK_SHAPE_SEGMENT: + if (intersectLineAndRay(linePts[0], linePts[1], pickShapeStart, + pickShapeDir, pi)) { + if (pi.getDistance() <= 1.0) { + intersect = true; + } + } + break; + /* case PICK_SHAPE_POINT: + dir.x = linePts[1].x - linePts[0].x; + dir.y = linePts[1].y - linePts[0].y; + dir.z = linePts[1].z - linePts[0].z; + if (intersectPntAndRay(((PickPoint)pickShape).location, + pnts[0], dir, dist)) { + if(dist[0] <= 1.0) { + intersect = true; + } + } + break; + */ + case PICK_SHAPE_BOUNDING_BOX: + intersect = intersectBoundingBox(linePts, + (BoundingBox)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_BOUNDING_SPHERE: + intersect = intersectBoundingSphere(linePts, + (BoundingSphere)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_BOUNDING_POLYTOPE: + intersect = intersectBoundingPolytope(linePts, + (BoundingPolytope)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_CYLINDER: + intersect = intersectCylinder (linePts, (PickCylinder)pickShape,pi); + break; + case PICK_SHAPE_CONE: + intersect = intersectCone (linePts, (PickCone) pickShape, pi); + break; + } + if (intersect) { + PickIntersection newpi = new PickIntersection(this, pi.geom); + newpi.iGeom = pi.iGeom; + newpi.setDistance(pi.distance); + newpi.setPointCoordinatesVW(pi.getPointCoordinatesVW()); + + // Set PickIntersection parameters + newpi.setGeomIndex(geomIndex); + newpi.setVertexIndices (vertidx); + newpi.setPrimitiveCoordinatesVW(linePts); + intersections.add (newpi); + return true; + } + return false; + } + + boolean intersectTri(int[] vertidx, int[] coordidx, int geomIndex, + Point3d[] pnts, PickIntersection pi) { + + Point3d[] triPts = new Point3d[3]; + + triPts[0] = pnts[coordidx[0]]; + triPts[1] = pnts[coordidx[1]]; + triPts[2] = pnts[coordidx[2]]; + + + boolean intersect = false; + switch(pickShapeType) { + case PICK_SHAPE_RAY: + intersect = intersectRay(triPts, (PickRay) pickShape, pi); + break; + case PICK_SHAPE_SEGMENT: + intersect = intersectSegment(triPts, (PickSegment) pickShape, pi); + break; + /* case PICK_SHAPE_POINT: + if(inside(triPts, (PickPoint) pickShape, ccw)==false) + return false; + break; + */ + case PICK_SHAPE_BOUNDING_BOX: + intersect = intersectBoundingBox (triPts, + (BoundingBox)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_BOUNDING_SPHERE: + intersect = intersectBoundingSphere (triPts, + (BoundingSphere)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_BOUNDING_POLYTOPE: + intersect = intersectBoundingPolytope (triPts, + (BoundingPolytope)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_CYLINDER: + intersect = intersectCylinder (triPts, (PickCylinder) pickShape,pi); + break; + case PICK_SHAPE_CONE: + intersect = intersectCone (triPts, (PickCone)pickShape, pi); + break; + } + if (intersect) { + PickIntersection newpi = new PickIntersection(this, pi.geom); + newpi.iGeom = pi.iGeom; + newpi.setDistance(pi.distance); + newpi.setPointCoordinatesVW(pi.getPointCoordinatesVW()); + + // Set PickIntersection parameters + newpi.setGeomIndex(geomIndex); + newpi.setVertexIndices (vertidx); + + newpi.setPrimitiveCoordinatesVW(triPts); + intersections.add (newpi); + return true; + } + return false; + } + + boolean intersectQuad(int[] vertidx, int[] coordidx, int geomIndex, + Point3d[] pnts, PickIntersection pi) { + + Point3d[] quadPts = new Point3d[4]; + + quadPts[0] = pnts[coordidx[0]]; + quadPts[1] = pnts[coordidx[1]]; + quadPts[2] = pnts[coordidx[2]]; + quadPts[3] = pnts[coordidx[3]]; + + // PickIntersection pi = new PickIntersection(this); + + boolean intersect = false; + switch(pickShapeType) { + case PICK_SHAPE_RAY: + intersect = intersectRay(quadPts, (PickRay) pickShape, pi); + break; + case PICK_SHAPE_SEGMENT: + intersect = intersectSegment(quadPts, (PickSegment) pickShape, pi); + break; + /* case PICK_SHAPE_POINT: + if(inside(quadPts, (PickPoint) pickShape, ccw)==false) + return false; + break; + */ + case PICK_SHAPE_BOUNDING_BOX: + intersect = intersectBoundingBox (quadPts, + (BoundingBox)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_BOUNDING_SPHERE: + intersect = intersectBoundingSphere (quadPts, + (BoundingSphere)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_BOUNDING_POLYTOPE: + intersect = intersectBoundingPolytope (quadPts, + (BoundingPolytope)pickShapeBounds); + pi.setPointCoordinatesVW(zeroPnt); + break; + case PICK_SHAPE_CYLINDER: + intersect = intersectCylinder (quadPts, (PickCylinder)pickShape,pi); + break; + case PICK_SHAPE_CONE: + intersect = intersectCone (quadPts, (PickCone)pickShape, pi); + break; + } + if (intersect) { + PickIntersection newpi = new PickIntersection(this, pi.geom); + newpi.iGeom = pi.iGeom; + newpi.setDistance(pi.distance); + newpi.setPointCoordinatesVW(pi.getPointCoordinatesVW()); + + // Set PickIntersection parameters + newpi.setGeomIndex(geomIndex); + newpi.setVertexIndices (vertidx); + newpi.setPrimitiveCoordinatesVW(quadPts); + intersections.add (newpi); + return true; + } + return false; + } + + /* ==================================================================== */ + /* INTERSECT METHODS BY GEOMETRY TYPE */ + /* ==================================================================== */ + + /** + Intersect method for PointArray + */ + boolean intersectPA (PointArray geom, int geomIndex, Point3d[] pnts, + boolean firstpick, PickIntersection pi) { + + if (debug) System.out.println ("intersect: PointArray"); + + int[] pntVertIdx = new int[1]; + int numint = 0; + + for (int i = 0; i < pnts.length; i++) { + pntVertIdx[0] = i; + if (intersectPoint(pntVertIdx, pntVertIdx, geomIndex, pnts, pi)) { + numint++; + if (firstpick) return true; + } + } + if (numint > 0) return true; + return false; + } + + /** + Intersect method for IndexedPointArray + */ + boolean intersectIPA (IndexedPointArray geom, int geomIndex, Point3d[] pnts, + boolean firstpick, PickIntersection pi) { + + if (debug) System.out.println ("intersect: IndexedPointArray"); + + int[] pntVertIdx = new int[1]; + int[] pntCoordIdx = new int[1]; + + int numint = 0; + int indexCount = geom.getIndexCount(); + + for (int i=0; i< indexCount; i++) { + pntVertIdx[0] = i; + pntCoordIdx[0] = geom.getCoordinateIndex(i); + if (intersectPoint(pntVertIdx, pntCoordIdx, geomIndex, pnts, pi)) { + numint++; + if (firstpick) return true; + } + } + if (numint > 0) return true; + return false; + } + + + /** + Intersect method for LineArray + */ + /** + Intersect method for LineArray + */ + boolean intersectLA (LineArray geom, int geomIndex, Point3d[] pnts, + boolean firstpick, PickIntersection pi) { + + if (debug) System.out.println ("intersect: LineArray"); + + int[] lineVertIdx = new int[2]; + + int numint = 0; + + for (int i=0; i< pnts.length;) { + /* set up the parameters for the current line */ + lineVertIdx[0] = i++; + lineVertIdx[1] = i++; + if (intersectLine(lineVertIdx, lineVertIdx, geomIndex, pnts, pi)) { + numint++; + if (firstpick) return true; + } + } + if (numint > 0) return true; + return false; + } + + /** + Intersect method for LineStripArray + */ + boolean intersectLSA (LineStripArray geom, int geomIndex, Point3d[] pnts, + boolean firstpick, PickIntersection pi) { + int numint = 0; + + int[] stripVertexCounts = new int [geom.getNumStrips()]; + geom.getStripVertexCounts (stripVertexCounts); + int stripStart = 0; + + if (debug) System.out.println ("intersect: LineStripArray"); + + int[] lineVertIdx = new int[2]; + + for (int i=0; i < stripVertexCounts.length; i++) { + lineVertIdx[0] = stripStart; + int end = stripStart + stripVertexCounts[i]; + + for (int j=stripStart+1; j 0) return true; + return false; + } + + /** + Intersect method for IndexedLineArray + */ + boolean intersectILA (IndexedLineArray geom, int geomIndex, Point3d[] pnts, + boolean firstpick, PickIntersection pi) { + + int numint = 0; + int indexCount = geom.getIndexCount(); + if (debug) System.out.println ("intersect: IndexedLineArray"); + + int[] lineVertIdx = new int[2]; + int[] lineCoordIdx = new int[2]; + + for (int i=0; i 0) return true; + return false; + } + + /** + Intersect method for IndexedLineStripArray + */ + boolean intersectILSA (IndexedLineStripArray geom, int geomIndex, + Point3d[] pnts, boolean firstpick, PickIntersection pi) { + if (debug) System.out.println ("intersect: IndexedLineStripArray"); + + int[] lineVertIdx = new int[2]; + int[] lineCoordIdx = new int[2]; + + int numint = 0; + int[] stripVertexCounts = new int [geom.getNumStrips()]; + geom.getStripIndexCounts (stripVertexCounts); + int stripStart = 0; + + for (int i=0; i < stripVertexCounts.length; i++) { + + lineVertIdx[0] = stripStart; + lineCoordIdx[0] = geom.getCoordinateIndex(stripStart); + int end = stripStart + stripVertexCounts[i]; + for (int j=stripStart+1; j 0) return true; + return false; + } + + /** + Intersect method for TriangleArray + */ + boolean intersectTA (TriangleArray geom, int geomIndex, Point3d[] pnts, + boolean firstpick, PickIntersection pi) { + + if (debug) + System.out.println ("intersect: TriangleArray"); + + int[] triVertIdx = new int[3]; + + int numint = 0; + for (int i=0; i 0) return true; + return false; + } + + /** + Intersect method for IndexedTriangleArray + */ + boolean intersectITA (IndexedTriangleArray geom, int geomIndex, + Point3d[] pnts, boolean firstpick, PickIntersection pi) { + + if (debug) + System.out.println ("intersect: IndexedTriangleArray"); + + int[] triVertIdx = new int[3]; + int[] triCoordIdx = new int[3]; + + int numint = 0; + int indexCount = geom.getIndexCount(); + for (int i=0; i 0) return true; + return false; + } + + /** + Intersect method for TriangleStripArray + */ + boolean intersectTSA (TriangleStripArray geom, int geomIndex, + Point3d[] pnts, boolean firstpick, PickIntersection pi) { + if (debug) + System.out.println ("intersect: TriangleStripArray"); + + boolean ccw; + int numint = 0; + int[] stripVertexCounts = new int [geom.getNumStrips()]; + geom.getStripVertexCounts (stripVertexCounts); + int stripStart = 0; + int start; + int[] triVertIdx = new int[3]; + + for (int i=0; i 0) return true; + return false; + } + + /** + Intersect method for IndexedTriangleStripArray + */ + boolean intersectITSA (IndexedTriangleStripArray geom, int geomIndex, + Point3d[] pnts, boolean firstpick, PickIntersection pi) { + + if (debug) + System.out.println ("intersect: IndexedTriangleStripArray"); + int numint = 0; + boolean ccw; + + int[] stripVertexCounts = new int [geom.getNumStrips()]; + geom.getStripIndexCounts (stripVertexCounts); + int stripStart = 0; + int start; + int[] triVertIdx = new int[3]; + int[] triCoordIdx = new int[3]; + + for (int i=0; i 0) return true; + return false; + + } + + /** + Intersect method for TriangleFanArray + */ + boolean intersectTFA (TriangleFanArray geom, int geomIndex, Point3d[] pnts, + boolean firstpick, PickIntersection pi) { + + if (debug) System.out.println("intersect: TriangleFanArray"); + + int numint = 0; + + int[] stripVertexCounts = new int [geom.getNumStrips()]; + geom.getStripVertexCounts (stripVertexCounts); + int fanStart = 0; + int start; + int[] triVertIdx = new int[3]; + + // System.out.println("stripVertexCounts.length " + stripVertexCounts.length); + for (int i=0; i 0) return true; + return false; + } + + /** + Intersect method for IndexedTriangleFanArray + */ + boolean intersectITFA (IndexedTriangleFanArray geom, int geomIndex, + Point3d[] pnts, boolean firstpick, PickIntersection pi) { + + if (debug) System.out.println ("intersect: IndexedTriangleFanArray"); + + int numint = 0; + int[] stripVertexCounts = new int [geom.getNumStrips()]; + geom.getStripIndexCounts (stripVertexCounts); + int fanStart = 0; + int start; + int[] triVertIdx = new int[3]; + int[] triCoordIdx = new int[3]; + + for (int i=0; i 0) return true; + return false; + } + + /** + Intersect method for QuadArray + */ + boolean intersectQA (QuadArray geom, int geomIndex, Point3d[] pnts, + boolean firstpick, PickIntersection pi) { + + if (debug) System.out.println ("intersect: QuadArray"); + + int[] quadVertIdx = new int[4]; + + int numint = 0; + for (int i=0; i 0) return true; + return false; + } + + /** + Intersect method for IndexedQuadArray + */ + final boolean intersectIQA (IndexedQuadArray geom, int geomIndex, + Point3d[] pnts, boolean firstpick, + PickIntersection pi) { + + if (debug) System.out.println ("intersect: IndexedQuadArray"); + + int[] quadVertIdx = new int[4]; + int[] quadCoordIdx = new int[4]; + + int numint = 0; + int indexCount = geom.getIndexCount(); + // System.out.println ("intersect: IndexedQuadArray : indexCount " + indexCount); + for (int i=0; i 0) return true; + return false; + + } + + /* ==================================================================== */ + /* GENERAL INTERSECT METHODS */ + /* ==================================================================== */ + static boolean intersectBoundingBox (Point3d coordinates[], + BoundingBox box) { + int i, j; + int out[] = new int[6]; + + Point3d lower = new Point3d(); + Point3d upper = new Point3d(); + box.getLower (lower); + box.getUpper (upper); + + //Do trivial vertex test. + for (i=0; i<6; i++) out[i] = 0; + for (i=0; i= lower.x) && + (coordinates[i].x <= upper.x) && + (coordinates[i].y >= lower.y) && + (coordinates[i].y <= upper.y) && + (coordinates[i].z >= lower.z) && + (coordinates[i].z <= upper.z)) { + // We're done! It's inside the boundingbox. + return true; + } else { + if (coordinates[i].x < lower.x) out[0]++; // left + if (coordinates[i].y < lower.y) out[1]++; // bottom + if (coordinates[i].z < lower.z) out[2]++; // back + if (coordinates[i].x > upper.x) out[3]++; // right + if (coordinates[i].y > upper.y) out[4]++; // top + if (coordinates[i].z > upper.z) out[5]++; // front + } + } + + if ((out[0] == coordinates.length) || (out[1] == coordinates.length) || + (out[2] == coordinates.length) || (out[3] == coordinates.length) || + (out[4] == coordinates.length) || (out[5] == coordinates.length)){ + // we're done. primitive is outside of boundingbox. + return false; + } + // Setup bounding planes. + Point3d pCoor[] = new Point3d[4]; + for (i=0; i<4; i++) pCoor[i] = new Point3d(); + + // left plane. + pCoor[0].set(lower.x, lower.y, lower.z); + pCoor[1].set(lower.x, lower.y, upper.z); + pCoor[2].set(lower.x, upper.y, upper.z); + pCoor[3].set(lower.x, upper.y, lower.z); + if (intersectPolygon(pCoor, coordinates, false) == true) return true; + + // right plane. + pCoor[0].set(upper.x, lower.y, lower.z); + pCoor[1].set(upper.x, upper.y, lower.z); + pCoor[2].set(upper.x, upper.y, upper.z); + pCoor[3].set(upper.x, lower.y, upper.z); + if (intersectPolygon(pCoor, coordinates, false) == true) return true; + + // bottom plane. + pCoor[0].set(upper.x, lower.y, upper.z); + pCoor[1].set(lower.x, lower.y, upper.z); + pCoor[2].set(lower.x, lower.y, lower.z); + pCoor[3].set(upper.x, lower.y, lower.z); + if (intersectPolygon(pCoor, coordinates, false) == true) return true; + + // top plane. + pCoor[0].set(upper.x, upper.y, upper.z); + pCoor[1].set(upper.x, upper.y, lower.z); + pCoor[2].set(lower.x, upper.y, lower.z); + pCoor[3].set(lower.x, upper.y, upper.z); + if (intersectPolygon(pCoor, coordinates, false) == true) return true; + + // front plane. + pCoor[0].set(upper.x, upper.y, upper.z); + pCoor[1].set(lower.x, upper.y, upper.z); + pCoor[2].set(lower.x, lower.y, upper.z); + pCoor[3].set(upper.x, lower.y, upper.z); + if (intersectPolygon(pCoor, coordinates, false) == true) return true; + + // back plane. + pCoor[0].set(upper.x, upper.y, lower.z); + pCoor[1].set(upper.x, lower.y, lower.z); + pCoor[2].set(lower.x, lower.y, lower.z); + pCoor[3].set(lower.x, upper.y, lower.z); + if (intersectPolygon(pCoor, coordinates, false) == true) return true; + + return false; + } + + static boolean intersectBoundingSphere (Point3d coordinates[], + BoundingSphere sphere) { + + + int i, j; + Vector3d tempV3D = new Vector3d(); + boolean esFlag; + Point3d center = new Point3d(); + sphere.getCenter (center); + double radius = sphere.getRadius (); + //Do trivial vertex test. + + for (i=0; i 0.0) break; + } + + for (j=i; j 0.0) break; + } + + if (j == (coordinates.length-1)) { + // System.out.println("(1) Degenerated polygon."); + return false; // Degenerated polygon. + } + + /* + for (i=0; i radius) + return false; + + tq = pNrmDotPa / nLenSq; + + q.x = center.x + tq * pNrm.x; + q.y = center.y + tq * pNrm.y; + q.z = center.z + tq * pNrm.z; + + // PolyPnt2D Test. + return pointIntersectPolygon2D( pNrm, coordinates, q); + } + + static boolean intersectBoundingPolytope (Point3d coordinates[], + BoundingPolytope polytope) { + + boolean debug = false; + + // this is a multiplier to the halfplane distance coefficients + double distanceSign = -1.0; + // Variable needed for intersection. + Point4d tP4d = new Point4d(); + + Vector4d[] planes = new Vector4d [polytope.getNumPlanes()]; + + for(int i=0; i absNrmY) + axis = 0; + else + axis = 1; + + if (axis == 0) { + if (absNrmX < absNrmZ) + axis = 2; + } + else if (axis == 1) { + if (absNrmY < absNrmZ) + axis = 2; + } + + // System.out.println("Normal " + normal + " axis " + axis ); + + for (i=0; i0.0) + ; + else + return false; + else + if (det2D(coord2D[j], coord2D[0], pnt)>0.0) + ; + else + return false; + } + return true; + } + + + static boolean edgeIntersectPlane(Vector3d normal, Point3d pnt, + Point3d start, Point3d end, Point3d iPnt){ + + Vector3d tempV3d = new Vector3d(); + Vector3d direction = new Vector3d(); + double pD, pNrmDotrDir, tr; + + // Compute plane D. + tempV3d.set((Tuple3d) pnt); + pD = normal.dot(tempV3d); + + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + + pNrmDotrDir = normal.dot(direction); + + // edge is parallel to plane. + if (pNrmDotrDir== 0.0) { + // System.out.println("Edge is parallel to plane."); + return false; + } + + tempV3d.set((Tuple3d) start); + + tr = (pD - normal.dot(tempV3d))/ pNrmDotrDir; + + // Edge intersects the plane behind the edge's start. + // or exceed the edge's length. + if ((tr < 0.0 ) || (tr > 1.0 )) { + // System.out.println("Edge intersects the plane behind the start or exceed end."); + return false; + } + + iPnt.x = start.x + tr * direction.x; + iPnt.y = start.y + tr * direction.y; + iPnt.z = start.z + tr * direction.z; + + return true; + } + + // Assume coord is CCW. + static boolean edgeIntersectPolygon2D(Vector3d normal, Point3d[] coord, + Point3d[] seg) { + + double absNrmX, absNrmY, absNrmZ; + Point2d coord2D[] = new Point2d[coord.length]; + Point2d seg2D[] = new Point2d[2]; + + int i, j, axis; + + // Project 3d points onto 2d plane. + // Note : Area of polygon is not preserve in this projection, but + // it doesn't matter here. + + // Find the axis of projection. + absNrmX = Math.abs(normal.x); + absNrmY = Math.abs(normal.y); + absNrmZ = Math.abs(normal.z); + + if (absNrmX > absNrmY) + axis = 0; + else + axis = 1; + + if (axis == 0) { + if (absNrmX < absNrmZ) + axis = 2; + } + else if (axis == 1) { + if (absNrmY < absNrmZ) + axis = 2; + } + + // System.out.println("Normal " + normal + " axis " + axis ); + + for (i=0; i 0.0) + break; + } + + for (j=i; j 0.0) + break; + } + + if (j == (coord1.length-1)) { + // System.out.println("(1) Degenerated polygon."); + return false; // Degenerated polygon. + } + + /* + for (i=0; i1) + break; + } + } + + if (j==0) + return false; + + if (coord2.length < 3) + return pointIntersectPolygon2D(pNrm, coord1, seg[0]); + + return edgeIntersectPolygon2D(pNrm, coord1, seg); + } + + + static final boolean isNonZero(double v) { + return ((v > EPS) || (v < -EPS)); + + } + + + static boolean intersectRay(Point3d coordinates[], + PickRay ray, PickIntersection pi) { + Point3d origin = new Point3d(); + Vector3d direction = new Vector3d(); + boolean result; + ray.get (origin, direction); + result = intersectRayOrSegment(coordinates, direction, origin, pi, false); + return result; + } + + /** + * Return true if triangle or quad intersects with ray and the distance is + * stored in pr. + * */ + static boolean intersectRayOrSegment(Point3d coordinates[], + Vector3d direction, Point3d origin, + PickIntersection pi, boolean isSegment) { + Vector3d vec0, vec1, pNrm, tempV3d; + Point3d iPnt; + + vec0 = new Vector3d(); + vec1 = new Vector3d(); + pNrm = new Vector3d(); + + double absNrmX, absNrmY, absNrmZ, pD = 0.0; + double pNrmDotrDir = 0.0; + + boolean isIntersect = false; + int i, j, k=0, l = 0; + + // Compute plane normal. + for (i=0; i 0.0) { + break; + } + } + + + for (j=l; j 0.0) { + break; + } + } + + pNrm.cross(vec0,vec1); + + if ((vec1.length() == 0) || (pNrm.length() == 0)) { + // degenerated to line if vec0.length() == 0 + // or vec0.length > 0 and vec0 parallel to vec1 + k = (l == 0 ? coordinates.length-1: l-1); + isIntersect = intersectLineAndRay(coordinates[l], + coordinates[k], + origin, + direction, + pi); + return isIntersect; + } + + // It is possible that Quad is degenerate to Triangle + // at this point + + pNrmDotrDir = pNrm.dot(direction); + + // Ray is parallel to plane. + if (pNrmDotrDir == 0.0) { + // Ray is parallel to plane + // Check line/triangle intersection on plane. + for (i=0; i < coordinates.length ;i++) { + if (i != coordinates.length-1) { + k = i+1; + } else { + k = 0; + } + if (intersectLineAndRay(coordinates[i], + coordinates[k], + origin, + direction, + pi)) { + isIntersect = true; + break; + } + } + return isIntersect; + } + + // Plane equation: (p - p0)*pNrm = 0 or p*pNrm = pD; + tempV3d = new Vector3d(); + tempV3d.set((Tuple3d) coordinates[0]); + pD = pNrm.dot(tempV3d); + tempV3d.set((Tuple3d) origin); + + // Substitute Ray equation: + // p = origin + pi.distance*direction + // into the above Plane equation + + double dist = (pD - pNrm.dot(tempV3d))/ pNrmDotrDir; + + // Ray intersects the plane behind the ray's origin. + if ((dist < -EPS ) || + (isSegment && (dist > 1.0+EPS))) { + // Ray intersects the plane behind the ray's origin + // or intersect point not fall in Segment + return false; + } + + // Now, one thing for sure the ray intersect the plane. + // Find the intersection point. + iPnt = new Point3d(); + iPnt.x = origin.x + direction.x * dist; + iPnt.y = origin.y + direction.y * dist; + iPnt.z = origin.z + direction.z * dist; + + // Project 3d points onto 2d plane. + // Find the axis so that area of projection is maximize. + absNrmX = Math.abs(pNrm.x); + absNrmY = Math.abs(pNrm.y); + absNrmZ = Math.abs(pNrm.z); + + // Check out + // http://astronomy.swin.edu.au/~pbourke/geometry/insidepoly/ + // Solution 3: + // All sign of (y - y0) (x1 - x0) - (x - x0) (y1 - y0) + // must agree. + double sign, t, lastSign = 0; + Point3d p0 = coordinates[coordinates.length-1]; + Point3d p1 = coordinates[0]; + + isIntersect = true; + + if (absNrmX > absNrmY) { + if (absNrmX < absNrmZ) { + for (i=0; i < coordinates.length; i++) { + p0 = coordinates[i]; + p1 = (i != coordinates.length-1 ? coordinates[i+1]: coordinates[0]); + sign = (iPnt.y - p0.y)*(p1.x - p0.x) - + (iPnt.x - p0.x)*(p1.y - p0.y); + if (isNonZero(sign)) { + if (sign*lastSign < 0) { + isIntersect = false; + break; + } + lastSign = sign; + } else { // point on line, check inside interval + t = p1.y - p0.y; + if (isNonZero(t)) { + t = (iPnt.y - p0.y)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + t = p1.x - p0.x; + if (isNonZero(t)) { + t = (iPnt.x - p0.x)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + //degenerate line=>point + } + } + } + } + } else { + for (i=0; i -EPS) && (t < 1+EPS)); + break; + + } else { + t = p1.z - p0.z; + if (isNonZero(t)) { + t = (iPnt.z - p0.z)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + //degenerate line=>point + } + } + } + } + } + } else { + if (absNrmY < absNrmZ) { + for (i=0; i -EPS) && (t < 1+EPS)); + break; + } else { + t = p1.x - p0.x; + if (isNonZero(t)) { + t = (iPnt.x - p0.x)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + //degenerate line=>point + } + } + } + } + } else { + for (i=0; i -EPS) && (t < 1+EPS)); + break; + } else { + t = p1.z - p0.z; + if (isNonZero(t)) { + t = (iPnt.z - p0.z)/t; + isIntersect = ((t > -EPS) && (t < 1+EPS)); + break; + } else { + //degenerate line=>point + } + } + } + } + } + } + + if (isIntersect) { + pi.setDistance(dist*direction.length()); + pi.setPointCoordinatesVW(iPnt); + } + return isIntersect; + } + + + /** + Return true if triangle or quad intersects with segment and the distance is + stored in dist. + */ + static boolean intersectSegment (Point3d coordinates[], PickSegment segment, + PickIntersection pi) { + Point3d start = new Point3d(); + Point3d end = new Point3d(); + Vector3d direction = new Vector3d(); + boolean result; + segment.get(start, end); + direction.x = end.x - start.x; + direction.y = end.y - start.y; + direction.z = end.z - start.z; + result = intersectRayOrSegment(coordinates, direction, start, pi, true); + return result; + } + + + /** + Return true if point is on the inside of halfspace test. The halfspace is + partition by the plane of triangle or quad. + */ + + static boolean inside (Point3d coordinates[], PickPoint point, int ccw) { + + Vector3d vec0 = new Vector3d(); //Edge vector from point 0 to point 1; + Vector3d vec1 = new Vector3d(); //Edge vector from point 0 to point 2 or 3; + Vector3d pNrm = new Vector3d(); + double absNrmX, absNrmY, absNrmZ, pD = 0.0; + Vector3d tempV3d = new Vector3d(); + double pNrmDotrDir = 0.0; + + double tempD; + + int i, j; + + Point3d location = new Point3d (); + point.get (location); + + // Compute plane normal. + for (i=0; i 0.0) + break; + } + + for (j=i; j 0.0) + break; + } + + if (j == (coordinates.length-1)) { + // System.out.println("(1) Degenerated polygon."); + return false; // Degenerated polygon. + } + + /* + System.out.println("Ray orgin : " + origin + " dir " + direction); + System.out.println("Triangle/Quad :"); + for (i=0; i 0.0 ) { + // System.out.println("point is on the outside of plane."); + return false; + } + else + return true; + } + + static boolean intersectPntAndPnt (Point3d pnt1, Point3d pnt2, + PickIntersection pi) { + + if ((pnt1.x == pnt2.x) && (pnt1.y == pnt2.y) && (pnt1.z == pnt2.z)) { + pi.setPointCoordinatesVW (pnt1); + pi.setDistance (0.0); + return true; + } + else + return false; + } + + static boolean intersectPntAndRay (Point3d pnt, Point3d ori, Vector3d dir, + PickIntersection pi) { + int flag = 0; + double temp; + double dist; + + if (dir.x != 0.0) { + flag = 0; + dist = (pnt.x - ori.x)/dir.x; + } + else if (dir.y != 0.0) { + if (pnt.x != ori.x) + return false; + flag = 1; + dist = (pnt.y - ori.y)/dir.y; + } + else if (dir.z != 0.0) { + if ((pnt.x != ori.x)||(pnt.y != ori.y)) + return false; + flag = 2; + dist = (pnt.z - ori.z)/dir.z; + + } + else + return false; + + if (dist < 0.0) + return false; + + if (flag == 0) { + temp = ori.y + dist * dir.y; + if ((pnt.y < (temp - Double.MIN_VALUE)) || (pnt.y > (temp + Double.MIN_VALUE))) + return false; + } + + if (flag < 2) { + temp = ori.z + dist * dir.z; + if ((pnt.z < (temp - Double.MIN_VALUE)) || (pnt.z > (temp + Double.MIN_VALUE))) + return false; + } + + pi.setPointCoordinatesVW (pnt); + pi.setDistance (dist); + + return true; + + } + + static boolean intersectLineAndRay(Point3d start, Point3d end, + Point3d ori, Vector3d dir, + PickIntersection pi) { + + double m00, m01, m10, m11; + double mInv00, mInv01, mInv10, mInv11; + double dmt, t, s, tmp1, tmp2; + Vector3d lDir; + double dist; + + // System.out.println("Intersect : intersectLineAndRay"); + // System.out.println("start " + start + " end " + end ); + // System.out.println("ori " + ori + " dir " + dir); + + lDir = new Vector3d(end.x - start.x, end.y - start.y, + end.z - start.z); + + m00 = lDir.x; + m01 = -dir.x; + m10 = lDir.y; + m11 = -dir.y; + + // Get the determinant. + dmt = (m00 * m11) - (m10 * m01); + + if (dmt==0.0) { // No solution, hence no intersect. + // System.out.println("dmt is zero"); + boolean isIntersect = false; + if ((lDir.x == 0) && (lDir.y == 0) && (lDir.z == 0)) { + isIntersect = intersectPntAndRay(start, ori, dir, pi); + if (isIntersect) { + pi.setPointCoordinatesVW(start); + pi.setDistance(0); + } + } + return isIntersect; + } + // Find the inverse. + tmp1 = 1/dmt; + + mInv00 = tmp1 * m11; + mInv01 = tmp1 * (-m01); + mInv10 = tmp1 * (-m10); + mInv11 = tmp1 * m00; + + tmp1 = ori.x - start.x; + tmp2 = ori.y - start.y; + + t = mInv00 * tmp1 + mInv01 * tmp2; + s = mInv10 * tmp1 + mInv11 * tmp2; + + if (s<0.0) { // Before the origin of ray. + // System.out.println("Before the origin of ray " + s); + return false; + } + if ((t<0)||(t>1.0)) {// Before or after the end points of line. + // System.out.println("Before or after the end points of line. " + t); + return false; + } + + tmp1 = ori.z + s * dir.z; + tmp2 = start.z + t * lDir.z; + + if ((tmp1 < (tmp2 - Double.MIN_VALUE)) || + (tmp1 > (tmp2 + Double.MIN_VALUE))) { + // System.out.println("No intersection : tmp1 " + tmp1 + " tmp2 " + tmp2); + return false; + } + dist = s; + + pi.setDistance (dist); + Point3d iPnt = new Point3d (); + iPnt.scaleAdd (s, dir, ori); + pi.setPointCoordinatesVW (iPnt); + + // System.out.println("Intersected : tmp1 " + tmp1 + " tmp2 " + tmp2); + return true; + } + + /** + Return true if triangle or quad intersects with cylinder and the + distance is stored in pr. + */ + static boolean intersectCylinder (Point3d coordinates[], + PickCylinder cyl, PickIntersection pi) { + + Point3d origin = new Point3d(); + Point3d end = new Point3d(); + Vector3d direction = new Vector3d(); + Point3d iPnt1 = new Point3d(); + Point3d iPnt2 = new Point3d(); + Vector3d originToIpnt = new Vector3d(); + + // Get cylinder information + cyl.getOrigin (origin); + cyl.getDirection (direction); + double radius = cyl.getRadius (); + + if (cyl instanceof PickCylinderSegment) { + ((PickCylinderSegment)cyl).getEnd (end); + } + + // If the ray intersects, we're good (do not do this if we only have + // a segment + if (coordinates.length > 2) { + if (cyl instanceof PickCylinderRay) { + if (intersectRay (coordinates, new PickRay (origin, direction), pi)) { + return true; + } + } + else { + if (intersectSegment (coordinates, new PickSegment (origin, end), pi)) { + return true; + } + } + } + + // Ray doesn't intersect, check distance to edges + double sqDistToEdge; + for (int i=0; i 2) { + if (cone instanceof PickConeRay) { + if (intersectRay (coordinates, new PickRay (origin, direction), pi)) { + return true; + } + } + else { + if (intersectSegment (coordinates, new PickSegment (origin, end), + pi)) { + return true; + } + } + } + + // Ray doesn't intersect, check distance to edges + double sqDistToEdge; + for (int i=0; i + * The pick mode specifies the detail level of picking before the PickResult + * is returned: + *

+ *

    + *
  • PickTool.BOUNDS - Pick using the bounds of the pickable nodes. The + * PickResult returned will contain the SceneGraphPath to the picked Node. + *
  • + *
  • PickTool.GEOMETRY will pick using the geometry of the pickable nodes. + * The PickResult returned will contain the SceneGraphPath to the picked Node. + * Geometry nodes in the scene must have the ALLOW_INTERSECT capability set for + * this mode.
  • + *
  • PickTool.GEOMETRY_INTERSECT_INFO -is the same as GEOMETRY, but the + * the PickResult will also include information on each intersection + * of the pick shape with the geometry. The intersection information includes + * the sub-primitive picked (that is, the point, line, triangle or quad), + * the closest vertex to the center of the pick shape, and + * the intersection's coordinate, normal, color and texture coordinates. + * To allow this information to be generated, Shape3D and Morph nodes must have + * the ALLOW_GEOMETRY_READ capability set and GeometryArrays must have the + * ALLOW_FORMAT_READ, + * ALLOW_COUNT_READ, and ALLOW_COORDINATE_READ capabilities set, plus the + * ALLOW_COORDINATE_INDEX_READ capability for indexed geometry. + * To inquire + * the intersection color, normal or texture coordinates + * the corresponding READ capability bits must be set on the GeometryArray. + *
  • + *
+ *

The utility method + * + * PickTool.setCapabilities(Node, int) + * can be used before the scene graph is + * made live to set the + * capabilities of Shape3D, Morph or Geometry + * nodes to allow picking. + *

+ * A PickResult from a lower level of detail pick can be used to + * inquire more detailed information if the capibility bits are set. + * This can be used to filter the PickResults + * before the more computationally intensive intersection processing. + * For example, + * the application can do a BOUNDS pick and then selectively inquire + * intersections on some of the PickResults. This will save the effort of + * doing intersection computation on the other PickResults. + * However, inquiring the intersections from a GEOMETRY pick will make + * the intersection computation happen twice, use GEOMETRY_INTERSECT_INFO + * if you want to inquire the intersection information on all the PickResults. + *

+ * When using pickAllSorted or pickClosest methods, the picks + * will be sorted by the distance from the start point of the pick shape to + * the intersection point. + *

+ * Morph nodes cannot be picked using the displayed geometry in + * GEOMETRY_INTERSECT_INFO mode due to limitations in the current Java3D core + * API (the current + * geometry of the the Morph cannot be inquired). Instead they are picked + * using + * the geometry at index 0 in the Morph, this limitation may be eliminated in a + * future release of Java3D. + *

+ * If the pick shape is a PickBounds, the pick result will contain only the + * scene graph path, even if the mode is GEOMETRY_INTERSECT_INFO. + */ +public class PickTool { + + /* OPEN ISSUES: + -- pickClosest() and pickAllSorted() using GEOMETRY and a non-PickRay + shape => unsorted picking. + -- Need to implement Morph geometry index 0 picking. + */ + + private final boolean debug = true; + protected boolean userDefineShape = false; + + PickShape pickShape; + + /** Used to store the BranchGroup used for picking */ + BranchGroup pickRootBG = null; + /** Used to store the Locale used for picking */ + Locale pickRootL = null; + + /** Used to store a reference point used in determining how "close" points + are. + */ + Point3d start = null; + + /* pick mode, one of BOUNDS, GEOMETRY, etc. */ + int mode = BOUNDS; + + /** Use this mode to pick by bounds and get basic information + on the pick. + */ + public static final int BOUNDS = 0x200; + + /** Use this mode to pick by geometry and get basic + information on the pick. + */ + public static final int GEOMETRY = 0x100; + + /** Use this mode to pick by geometry and save + information about the intersections (intersected primitive, + intersection point and closest vertex). + */ + public static final int GEOMETRY_INTERSECT_INFO = 0x400; + + + // Flags for the setCapabilities() method + /** + * Flag to pass to setCapabilities(Node, int) to set + * the Node's capabilities to allow intersection tests, but not + * inquire information about the intersections (use for GEOMETRY mode). + * @see PickTool#setCapabilities + */ + public static final int INTERSECT_TEST = 0x1001; + + /** + * Flag to pass to setCapabilities(Node, int) to set + * the Node's capabilities to allow inquiry of the intersection + * coordinate information. + * @see PickTool#setCapabilities + */ + public static final int INTERSECT_COORD = 0x1002; + + /** + * Flag to pass to setCapabilities(Node, int) to set + * the Node's capabilities to allow inquiry of all intersection + * information. + * @see PickTool#setCapabilities + */ + public static final int INTERSECT_FULL = 0x1004; + + /* ============================ METHODS ============================ */ + + /** + * Constructor with BranchGroup to be picked. + */ + public PickTool (BranchGroup b) { + pickRootBG = b; + } + + /** Returns the BranchGroup to be picked if the tool was initialized + with a BranchGroup, null otherwise. + */ + public BranchGroup getBranchGroup() { + return pickRootBG; + } + + /** + * Constructor with the Locale to be picked. + */ + public PickTool (Locale l) { + pickRootL = l; + } + + /** + * Returns the Locale to be picked if the tool was initialized with + * a Locale, null otherwise. + */ + public Locale getLocale () { + return pickRootL; + } + + + /** + * @deprecated This method does nothing other than return its + * input parameter. + */ + public Locale setBranchGroup (Locale l) { + return l; + } + + /** + * Sets the capabilities on the Node and it's components to allow + * picking at the specified detail level. + *

+ * Note that by default all com.sun.j3d.utils.geometry.Primitive + * objects with the same parameters share their geometry (e.g., + * you can have 50 spheres in your scene, but the geometry is + * stored only once). Therefore the capabilities of the geometry + * are also shared, and once a shared node is live, the + * capabilities cannot be changed. To assign capabilities to + * Primitives with the same parameters, either set the + * capabilities before the primitive is set live, or specify the + * Primitive.GEOMETRY_NOT_SHARED constructor parameter when + * creating the primitive. + * @param node The node to modify + * @param level The capability level, must be one of INTERSECT_TEST, + * INTERSECT_COORD or INTERSECT_FULL + * @throws IllegalArgumentException if Node is not a Shape3D or Morph or + * if the flag value is not valid. + * @throws javax.media.j3d.RestrictedAccessException if the node is part + * of a live or compiled scene graph. */ + static public void setCapabilities(Node node, int level) { + if (node instanceof Morph) { + Morph morph = (Morph) node; + switch (level) { + case INTERSECT_FULL: + /* intentional fallthrough */ + case INTERSECT_COORD: + morph.setCapability(Morph.ALLOW_GEOMETRY_ARRAY_READ); + /* intentional fallthrough */ + case INTERSECT_TEST: + break; + default: + throw new IllegalArgumentException("Improper level"); + } + double[] weights = morph.getWeights(); + for (int i = 0; i < weights.length; i++) { + GeometryArray ga = morph.getGeometryArray(i); + setCapabilities(ga, level); + } + } else if (node instanceof Shape3D) { + Shape3D shape = (Shape3D) node; + switch (level) { + case INTERSECT_FULL: + /* intentional fallthrough */ + case INTERSECT_COORD: + shape.setCapability(Shape3D.ALLOW_GEOMETRY_READ); + /* intentional fallthrough */ + case INTERSECT_TEST: + break; + default: + throw new IllegalArgumentException("Improper level"); + } + for (int i = 0; i < shape.numGeometries(); i++) { + Geometry geo = shape.getGeometry(i); + if (geo instanceof GeometryArray) { + setCapabilities((GeometryArray)geo, level); + } else if (geo instanceof CompressedGeometry) { + setCapabilities((CompressedGeometry)geo, level); + } + } + } else { + throw new IllegalArgumentException("Improper node type"); + } + } + + static private void setCapabilities(GeometryArray ga, int level) { + switch (level) { + case INTERSECT_FULL: + ga.setCapability(GeometryArray.ALLOW_COLOR_READ); + ga.setCapability(GeometryArray.ALLOW_NORMAL_READ); + ga.setCapability(GeometryArray.ALLOW_TEXCOORD_READ); + /* intential fallthrough */ + case INTERSECT_COORD: + ga.setCapability(GeometryArray.ALLOW_COUNT_READ); + ga.setCapability(GeometryArray.ALLOW_FORMAT_READ); + ga.setCapability(GeometryArray.ALLOW_COORDINATE_READ); + /* intential fallthrough */ + case INTERSECT_TEST: + ga.setCapability(GeometryArray.ALLOW_INTERSECT); + break; + } + if (ga instanceof IndexedGeometryArray) { + setCapabilities((IndexedGeometryArray)ga, level); + } + } + + static private void setCapabilities(IndexedGeometryArray iga, int level) { + switch (level) { + case INTERSECT_FULL: + iga.setCapability(IndexedGeometryArray.ALLOW_COLOR_INDEX_READ); + iga.setCapability(IndexedGeometryArray.ALLOW_NORMAL_INDEX_READ); + iga.setCapability(IndexedGeometryArray.ALLOW_TEXCOORD_INDEX_READ); + /* intential fallthrough */ + case INTERSECT_COORD: + iga.setCapability(IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ); + /* intential fallthrough */ + case INTERSECT_TEST: + break; + } + } + + static private void setCapabilities(CompressedGeometry cg, int level) { + switch (level) { + case INTERSECT_FULL: + /* intential fallthrough */ + case INTERSECT_COORD: + cg.setCapability(CompressedGeometry.ALLOW_GEOMETRY_READ); + /* intential fallthrough */ + case INTERSECT_TEST: + cg.setCapability(CompressedGeometry.ALLOW_INTERSECT); + break; + } + } + + // Methods used to define the pick shape + + /** Sets the pick shape to a user-provided PickShape object + * @param ps The pick shape to pick against. + * @param startPt The start point to use for distance calculations + */ + public void setShape (PickShape ps, Point3d startPt) { + this.pickShape = ps; + this.start = startPt; + userDefineShape = (ps != null); + } + + /** Sets the pick shape to use a user-provided Bounds object + * @param bounds The bounds to pick against. + * @param startPt The start point to use for distance calculations + */ + public void setShapeBounds (Bounds bounds, Point3d startPt) { + this.pickShape = (PickShape) new PickBounds (bounds); + this.start = startPt; + userDefineShape = true; + } + + /** Sets the picking detail mode. The default is BOUNDS. + * @param mode One of BOUNDS, GEOMETRY, GEOMETRY_INTERSECT_INFO, or + * @exception IllegalArgumentException if mode is not a legal value + */ + public void setMode (int mode) { + if ((mode != BOUNDS) && (mode != GEOMETRY) && + (mode != GEOMETRY_INTERSECT_INFO)) { + throw new java.lang.IllegalArgumentException(); + } + this.mode = mode; + } + + /** Gets the picking detail mode. + */ + public int getMode () { + return mode; + } + + /** Sets the pick shape to a PickRay. + * @param start The start of the ray + * @param dir The direction of the ray + */ + public void setShapeRay (Point3d start, Vector3d dir) { + this.pickShape = (PickShape) new PickRay (start, dir); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to a PickSegment. + @param start The start of the segment +p @param end The end of the segment + */ + public void setShapeSegment (Point3d start, Point3d end) { + this.pickShape = (PickShape) new PickSegment (start, end); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to a capped PickCylinder + * @param start The start of axis of the cylinder + * @param end The end of the axis of the cylinder + * @param radius The radius of the cylinder + */ + public void setShapeCylinderSegment (Point3d start, Point3d end, + double radius) { + this.pickShape = (PickShape) + new PickCylinderSegment (start, end, radius); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to an infinite PickCylinder. + * @param start The start of axis of the cylinder + * @param dir The direction of the axis of the cylinder + * @param radius The radius of the cylinder + */ + public void setShapeCylinderRay (Point3d start, Vector3d dir, + double radius) { + this.pickShape = (PickShape) new PickCylinderRay (start, dir, radius); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to a capped PickCone + * @param start The start of axis of the cone + * @param end The end of the axis of the cone + * @param angle The angle of the cone + */ + public void setShapeConeSegment (Point3d start, Point3d end, + double angle) { + this.pickShape = (PickShape) new PickConeSegment (start, end, angle); + this.start = start; + userDefineShape = true; + } + + /** Sets the pick shape to an infinite PickCone. + * @param start The start of axis of the cone + * @param dir The direction of the axis of the cone + * @param angle The angle of the cone + */ + public void setShapeConeRay (Point3d start, Vector3d dir, + double angle) { + this.pickShape = (PickShape) new PickConeRay (start, dir, angle); + this.start = start; + userDefineShape = true; + } + + /** Returns the PickShape for this object. */ + public PickShape getPickShape () { + return pickShape; + } + + /** Returns the start postion used for distance measurement. */ + public Point3d getStartPosition () { + return start; + } + + /** Selects all the nodes that intersect the PickShape. + @return An array of PickResult objects which will contain + information about the picked instances. null if nothing was + picked. + */ + public PickResult[] pickAll () { + PickResult[] retval = null; + switch (mode) { + case BOUNDS: + retval = pickAll(pickShape); + break; + case GEOMETRY: + retval = pickGeomAll(pickShape); + break; + case GEOMETRY_INTERSECT_INFO: + retval = pickGeomAllIntersect(pickShape); + break; + default: + throw new RuntimeException("Invalid pick mode"); + } + return retval; + } + + /** Select one of the nodes that intersect the PickShape + @return A PickResult object which will contain + information about the picked instance. null if nothing + was picked. + */ + public PickResult pickAny () { + PickResult retval = null; + switch (mode) { + case BOUNDS: + retval = pickAny(pickShape); + break; + case GEOMETRY: + retval = pickGeomAny(pickShape); + break; + case GEOMETRY_INTERSECT_INFO: + retval = pickGeomAnyIntersect(pickShape); + break; + default: + throw new RuntimeException("Invalid pick mode"); + } + return retval; + } + + /** Select all the nodes that intersect the + PickShape, returned sorted. The "closest" object will be returned first. + See note above to see how "closest" is determined. +

+ @return An array of PickResult objects which will contain + information + about the picked instances. null if nothing was picked. + */ + public PickResult[] pickAllSorted () { + PickResult[] retval = null; + + // System.out.println ("PickTool.pickAllSorted."); + + switch (mode) { + case BOUNDS: + // System.out.println ("PickTool.pickAllSorted : Bounds"); + retval = pickAllSorted(pickShape); + break; + case GEOMETRY: + // System.out.println ("PickTool.pickAllSorted : Geometry"); + // TODO - BugId 4351050. + // pickGeomAllSorted is broken for PickCone and PickCylinder : + // The current Shape3D.intersect() API doesn't return the distance for + // PickCone and PickCylinder. + // 2) TODO - BugId 4351579. + // pickGeomClosest is broken for multi-geometry Shape3D node : + // The current Shape3D.intersect() API does't return the closest intersected + // geometry. + retval = pickGeomAllSorted(pickShape); + + break; + case GEOMETRY_INTERSECT_INFO: + // System.out.println ("PickShape " + pickShape); + // System.out.println ("PickTool.pickAllSorted : GEOMETRY_INTERSECT_INFO"); + retval = pickGeomAllSortedIntersect(pickShape); + break; + default: + throw new RuntimeException("Invalid pick mode"); + } + return retval; + } + + /** Select the closest node that + intersects the PickShape. See note above to see how "closest" is + determined. +

+ @return A PickResult object which will contain + information about the picked instance. null if nothing + was picked. + */ + public PickResult pickClosest () { + PickResult retval = null; + switch (mode) { + case BOUNDS: + retval = pickClosest(pickShape); + break; + case GEOMETRY: + // System.out.println("pickCloset -- Geometry based picking"); + // 1) TODO - BugId 4351050. + // pickGeomClosest is broken for PickCone and PickCylinder : + // The current Shape3D.intersect() API doesn't return the distance for + // PickCone and PickCylinder. + // 2) TODO - BugId 4351579. + // pickGeomClosest is broken for multi-geometry Shape3D node : + // The current Shape3D.intersect() API does't return the closest intersected + // geometry. + retval = pickGeomClosest(pickShape); + + break; + case GEOMETRY_INTERSECT_INFO: + // System.out.println ("PickShape " + pickShape); + // System.out.println ("PickTool.pickClosest : GEOMETRY_INTERSECT_INFO"); + retval = pickGeomClosestIntersect(pickShape); + break; + default: + throw new RuntimeException("Invalid pick mode"); + } + return retval; + } + + private PickResult[] pickAll (PickShape pickShape) { + PickResult[] pr = null; + SceneGraphPath[] sgp = null; + + if (pickRootBG != null) { + sgp = pickRootBG.pickAll (pickShape); + } else if (pickRootL != null) { + sgp = pickRootL.pickAll (pickShape); + } + if (sgp == null) return null; // no match + + // Create PickResult array + pr = new PickResult [sgp.length]; + for (int i=0;i 1) { + return sortPickResults (npr, distance); + } else { // Don't have to sort if only one item + return npr; + } + } + + private PickResult pickGeomAny (PickShape pickShape) { + Node obj = null; + int i; + SceneGraphPath[] sgpa = null; + + if (pickRootBG != null) { + sgpa = pickRootBG.pickAll(pickShape); + } else if (pickRootL != null) { + sgpa = pickRootL.pickAll(pickShape); + } + + if (sgpa == null) return null; // no match + + for(i=0; i 0) { + found[i] = true; + cnt++; + } + } + + if (cnt == 0) return null; // no match + + PickResult[] newpr = new PickResult[cnt]; + cnt = 0; // reset for reuse. + for(i=0; i 0) { + // System.out.println ("numIntersection " + numIntersection); + found[i] = true; + double minDist; + double tempDist; + + int minIndex; + boolean needToSwap = false; + minDist = pr[i].getIntersection(0).getDistance(); + minIndex = 0; + for(int j=1; j tempDist) { + minDist = tempDist; + minIndex = j; + needToSwap = true; + } + } + + //Swap if necc. + if(needToSwap) { + // System.out.println ("Swap is needed"); + PickIntersection pi0 = pr[i].getIntersection(0); + PickIntersection piMin = pr[i].getIntersection(minIndex); + pr[i].intersections.set(0, piMin); + pr[i].intersections.set(minIndex, pi0); + } + + distArr[i] = pr[i].getIntersection(0).getDistance(); + cnt++; + } + } + + + // System.out.println ("PickTool.pickGeomAllSortedIntersect: geometry intersect check " + // + " cnt " + cnt); + + + if (cnt == 0) return null; // no match + + PickResult[] npr = new PickResult[cnt]; + double[] distance = new double[cnt]; + cnt = 0; // reset for reuse. + for(i=0; i 1) { + return sortPickResults (npr, distance); + } else { // Don't have to sort if only one item + return npr; + } + } + + private PickResult pickGeomClosestIntersect(PickShape pickShape) { + PickResult[] pr = pickGeomAllSortedIntersect(pickShape); + /* + System.out.println ("PickTool.pickGeomClosestIntersect: pr.length " + + pr.length); + for(int i=0;i 0) { + return pr; + } + } + + return null; + } + + // ================================================================ + // Sort Methods + // ================================================================ + private PickResult[] sortPickResults (PickResult[] pr, double[] dist) { + int[] pos = new int [pr.length]; + PickResult[] prsorted = new PickResult [pr.length]; + + // Initialize position array + for (int i=0; i + * 1. Create your scene graph. + *

+ * 2. Create this behavior with root and canvas. + *

+ *

+ *	PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds);
+ *      root.addChild(behavior);
+ * 
+ *

+ * The above behavior will monitor for any picking events on + * the scene graph (below root node) and handle mouse drags on pick hits. + * Note the root node can also be a subgraph node of the scene graph (rather + * than the topmost). + */ + +public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseRotate drag; +// int pickMode = PickTool.BOUNDS; + private PickingCallback callback=null; + private TransformGroup currentTG; + + /** + * Creates a pick/rotate behavior that waits for user mouse events for + * the scene graph. This method has its pickMode set to BOUNDS picking. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP); + drag.setTransformGroup(currGrp); + currGrp.addChild(drag); + drag.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/rotate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or + * PickTool.GEOMETRY_INTERSECT_INFO. + * @see PickTool#setMode + **/ + + public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds, + int pickMode){ + super(canvas, root, bounds); + drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP); + drag.setTransformGroup(currGrp); + currGrp.addChild(drag); + drag.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.setMode(pickMode); + } + + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + public void updateScene(int xpos, int ypos){ + TransformGroup tg = null; + + if (!mevent.isMetaDown() && !mevent.isAltDown()){ + + pickCanvas.setShapeLocation(xpos, ypos); + PickResult pr = pickCanvas.pickClosest(); + if ((pr != null) && + ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP)) + != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){ + drag.setTransformGroup(tg); + drag.wakeup(); + currentTG = tg; + // free the PickResult + // Need to clean up Issue 123 --- Chien + // freePickResult(pr); + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + } + } + + /** + * Callback method from MouseRotate + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.ROTATE, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + drag.setupCallback( null ); + else + drag.setupCallback( this ); + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickTranslateBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickTranslateBehavior.java new file mode 100644 index 0000000..d9afc1c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickTranslateBehavior.java @@ -0,0 +1,158 @@ +/* + * $RCSfile: PickTranslateBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:26 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.picking.behaviors; + +import com.sun.j3d.utils.picking.*; +import com.sun.j3d.utils.behaviors.mouse.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * A mouse behavior that allows user to pick and translate scene graph objects. + * Common usage: 1. Create your scene graph. 2. Create this behavior with + * the root and canvas. See PickRotateBehavior for more details. + */ + +public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseTranslate translate; + private PickingCallback callback = null; + private TransformGroup currentTG; + + /** + * Creates a pick/translate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP); + translate.setTransformGroup(currGrp); + currGrp.addChild(translate); + translate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/translate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or + * PickTool.GEOMETRY_INTERSECT_INFO. + * @see PickTool#setMode + **/ + public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, + Bounds bounds, int pickMode) { + super(canvas, root, bounds); + translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP); + translate.setTransformGroup(currGrp); + currGrp.addChild(translate); + translate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.setMode(pickMode); + } + + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + public void updateScene(int xpos, int ypos){ + TransformGroup tg = null; + + if (!mevent.isAltDown() && mevent.isMetaDown()){ + + pickCanvas.setShapeLocation(xpos, ypos); + PickResult pr = pickCanvas.pickClosest(); + if ((pr != null) && + ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP)) + != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){ + + translate.setTransformGroup(tg); + translate.wakeup(); + currentTG = tg; + // Need to clean up Issue 123 --- Chien + // freePickResult(pr); + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + } + + } + + /** + * Callback method from MouseTranslate + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.TRANSLATE, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + translate.setupCallback( null ); + else + translate.setupCallback( this ); + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickZoomBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickZoomBehavior.java new file mode 100644 index 0000000..1ef6894 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickZoomBehavior.java @@ -0,0 +1,156 @@ +/* + * $RCSfile: PickZoomBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:26 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.picking.behaviors; + +import com.sun.j3d.utils.picking.*; +import com.sun.j3d.utils.behaviors.mouse.*; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + + +/** + * A mouse behavior that allows user to pick and zoom scene graph objects. + * Common usage: 1. Create your scene graph. 2. Create this behavior with + * the root and canvas. See PickRotateBehavior for more details. + */ + +public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + MouseZoom zoom; + private PickingCallback callback = null; + private TransformGroup currentTG; + + /** + * Creates a pick/zoom behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + + public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){ + super(canvas, root, bounds); + zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP); + zoom.setTransformGroup(currGrp); + currGrp.addChild(zoom); + zoom.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Creates a pick/zoom behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or + * PickTool.GEOMETRY_INTERSECT_INFO. + * @see PickTool#setMode + */ + public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds, + int pickMode) { + super(canvas, root, bounds); + zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP); + zoom.setTransformGroup(currGrp); + currGrp.addChild(zoom); + zoom.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + this.setMode(pickMode); + } + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + + public void updateScene(int xpos, int ypos){ + TransformGroup tg = null; + + if (mevent.isAltDown() && !mevent.isMetaDown()){ + + pickCanvas.setShapeLocation(xpos, ypos); + PickResult pr = pickCanvas.pickClosest(); + if ((pr != null) && + ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP)) + != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){ + zoom.setTransformGroup(tg); + zoom.wakeup(); + currentTG = tg; + // Need to clean up Issue 123 --- Chien + // freePickResult(pr); + } else if (callback!=null) + callback.transformChanged( PickingCallback.NO_PICK, null ); + } + } + + /** + * Callback method from MouseZoom + * This is used when the Picking callback is enabled + */ + public void transformChanged( int type, Transform3D transform ) { + callback.transformChanged( PickingCallback.ZOOM, currentTG ); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback( PickingCallback callback ) { + this.callback = callback; + if (callback==null) + zoom.setupCallback( null ); + else + zoom.setupCallback( this ); + } +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickingCallback.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickingCallback.java new file mode 100644 index 0000000..53f1d0a --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickingCallback.java @@ -0,0 +1,76 @@ +/* + * $RCSfile: PickingCallback.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:26 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.picking.behaviors; + +import javax.media.j3d.TransformGroup; + +/** + * The PickingCallback interface allows a class to be notified when a + * picked object is moved. The class that is interested in object + * movement implements this interface, and the object created with + * that class is registered with the desired subclass of + * PickMouseBehavior using the setupCallback method. + * When the picked object moves, the registered object's + * transformChanged method is invoked. + */ + +public interface PickingCallback { + + public final static int ROTATE=0; + public final static int TRANSLATE=1; + public final static int ZOOM=2; + + /** + * The user made a selection but nothing was + * actually picked + */ + public final static int NO_PICK=3; + + /** + * Called by the Pick Behavior with which this callback + * is registered each time the Picked object is moved + */ + public void transformChanged( int type, TransformGroup tg ); +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/package.html new file mode 100644 index 0000000..21ef9e7 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/behaviors/package.html @@ -0,0 +1,12 @@ + + + + + com.sun.j3d.utils.picking.behaviors + + +

OBSOLETE: provides picking behaviors for the old picking +methods.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/package.html new file mode 100644 index 0000000..1b9d21b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/picking/package.html @@ -0,0 +1,12 @@ + + + + + com.sun.j3d.utils.picking + + +

OBSOLETE: provides picking utility classes for the old +picking methods.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/NamedObjectException.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/NamedObjectException.java new file mode 100644 index 0000000..2eea6c5 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/NamedObjectException.java @@ -0,0 +1,68 @@ +/* + * $RCSfile: NamedObjectException.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:27 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +/** + * An error has occurred while processing a named object + */ +public class NamedObjectException extends java.lang.Exception { + + /** + * Creates new NoSuchNameException without detail message. + */ + public NamedObjectException() { + } + + + /** + * Constructs an NoSuchNameException with the specified detail message. + * @param msg the detail message. + */ + public NamedObjectException(String msg) { + super(msg); + } +} + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/ObjectNotLoadedException.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/ObjectNotLoadedException.java new file mode 100644 index 0000000..fc3e2a5 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/ObjectNotLoadedException.java @@ -0,0 +1,68 @@ +/* + * $RCSfile: ObjectNotLoadedException.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:27 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +/** + * The named object has not been loaded so it's instance can not be returned + */ +public class ObjectNotLoadedException extends java.lang.Exception { + + /** + * Creates new ObjectNotLoadedException without detail message. + */ + public ObjectNotLoadedException() { + } + + + /** + * Constructs an ObjectNotLoadedException with the specified detail message. + * @param msg the detail message. + */ + public ObjectNotLoadedException(String msg) { + super(msg); + } +} + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileReader.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileReader.java new file mode 100644 index 0000000..d937a79 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileReader.java @@ -0,0 +1,224 @@ +/* + * $RCSfile: SceneGraphFileReader.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:27 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +import java.io.File; +import java.io.IOException; + +import javax.media.j3d.VirtualUniverse; +import javax.media.j3d.BranchGroup; +import javax.media.j3d.SceneGraphObject; +import javax.media.j3d.Canvas3D; +import com.sun.j3d.utils.universe.ConfiguredUniverse; + +import com.sun.j3d.utils.scenegraph.io.retained.RandomAccessFileControl; + +/** + * Read Java3D BranchGraphs and/or Universe from a file. Individual branchgraphs or an + * entire Universe can be read and references (shared nodes and components) + * between the graphs are handled correctly. + */ +public class SceneGraphFileReader extends java.lang.Object { + + private RandomAccessFileControl fileControl; + + /** + * Creates new SceneGraphFileReader. + */ + public SceneGraphFileReader( java.io.File file ) throws IOException { + fileControl = new RandomAccessFileControl(); + fileControl.openFile( file ); + } + + /** + * Create and return a ConfiguredUniverse with the PlatformGeometry, ViewerAvatar, + * and Locales saved in the file. The MultiTransformGroup between the ViewingPlatform + * and the View is also restored. Universe configuration information is retrieved + * via ConfiguredUniverse.getConfigURL().

+ * If the file does not contain universe information, null is returned.

+ * + * @param attachBranchGraphs load and attach all the branchgraphs + * to the universe. + * @see ConfiguredUniverse#getConfigURL + */ + public ConfiguredUniverse readUniverse(boolean attachBranchGraphs ) throws IOException { + return fileControl.readUniverse( attachBranchGraphs, null ); + } + + /** + * Set the ClassLoader used to load the scene graph objects and + * deserialize user data + */ + public void setClassLoader( ClassLoader classLoader ) { + fileControl.setClassLoader( classLoader ); + } + + /** + * Get the ClassLoader used to load the scene graph objects and + * deserialize user data + */ + public ClassLoader getClassLoader() { + return fileControl.getClassLoader(); + } + + /** + * Create and return a ConfiguredUniverse with the PlatformGeometry, ViewerAvatar, + * and Locales saved in the file. The MultiTransformGroup between the ViewingPlatform + * and the View is also restored.

+ * If the file does not contain universe information, null is returned.

+ * + * @param attachBranchGraphs load and attach all the branchgraphs + * to the universe. + * @param canvas The canvas to be associated with the Universe. + */ + public ConfiguredUniverse readUniverse(boolean attachBranchGraphs, + Canvas3D canvas) throws IOException { + return fileControl.readUniverse( attachBranchGraphs, canvas ); + } + + /** + * Get the UserData in the File header + */ + public Object readUserData() throws IOException { + return fileControl.getUserData(); + } + + /** + * Get the Description of this file's contents + */ + public String readDescription() throws IOException { + return fileControl.readFileDescription(); + } + + /** + * Return the number of BranchGraphs in the file + */ + public int getBranchGraphCount() { + return fileControl.getBranchGraphCount(); + } + + /** + * Read the BranchGraph at index in the file. If the graph + * contains references to nodes in other BranchGraphs that have not already been + * loaded, they will also be loaded and returned.

+ * + * The requested graph will always be the first element in the array.

+ * + * The file index of all the Graphs can be discovered using getBranchGraphPosition.

+ * + * @param index The index of the Graph in the file. First graph is at index 0 + * + * @see #getBranchGraphPosition( BranchGroup graph ) + * + */ + public BranchGroup[] readBranchGraph(int index) throws IOException { + return fileControl.readBranchGraph( index ); + } + + /** + * Read and return all the branchgraphs in the file + */ + public BranchGroup[] readAllBranchGraphs() throws IOException { + return fileControl.readAllBranchGraphs(); + } + + /** + * Remove the IO system's reference to this branchgraph and all its nodes.

+ * + * References to all loaded graphs are maintained by the IO system in + * order to facilitate node and component sharing between the graphs.

+ * + * This call removes the references to graph index

+ * + * NOT CURRENTLY IMPLEMENTED + */ + public void dereferenceBranchGraph( BranchGroup graph ) { + throw new RuntimeException("Not implemented"); + } + + /** + * Given a BranchGraph that has been loaded return the index of the + * graph in the file. The the Branchgroup isn't found, -1 is returned. + */ + public int getBranchGraphPosition( BranchGroup graph ) { + return fileControl.getBranchGraphPosition( graph ); + } + + /** + * Read the userdata for the branchgraph at 'index' in the file + * + * @param index the index of the graph in the file + */ + public Object readBranchGraphUserData( int index ) throws IOException { + return fileControl.readBranchGraphUserData( index ); + } + + /** + * Return the names of all the named objects + */ + public String[] getNames() { + return fileControl.getNames(); + } + + /** + * Return the named object. + * + * @param name The name of the object + * + * @exception NamedObjectException is thrown if the name is not known to the system + * @exception ObjectNotLoadedException is thrown if the named object has not been loaded yet + */ + public SceneGraphObject getNamedObject( String name ) throws NamedObjectException, ObjectNotLoadedException { + return fileControl.getNamedObject( name ); + } + + /** + * Close the file and cleanup internal data structures + */ + public void close() throws IOException { + fileControl.close(); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileWriter.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileWriter.java new file mode 100644 index 0000000..d67c949 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileWriter.java @@ -0,0 +1,157 @@ +/* + * $RCSfile: SceneGraphFileWriter.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:27 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Iterator; + +import javax.media.j3d.BranchGroup; +import javax.media.j3d.SceneGraphObject; +import javax.media.j3d.CapabilityNotSetException; +import com.sun.j3d.utils.scenegraph.io.retained.RandomAccessFileControl; +import com.sun.j3d.utils.universe.SimpleUniverse; + +/** + * Write a (set) of Java3D BranchGraphs and/or Universe to a file. The BranchGraphs + * are stored in the order in which they are written, they can be read in any order + * using SceneGraphFileReader. + * + * The API handles Nodes and NodeComponents that are shared between seperate + * graphs. It will handle all Java3D 1.3 core classes and any user + * subclass of a Node or NodeComponent that implements the SceneGraphIO + * interface. + */ +public class SceneGraphFileWriter extends java.lang.Object { + + private RandomAccessFileControl fileControl; + private File file; + + /** Creates new SceneGraphFileWriter and opens the file for writing. + * + *

Writes the + * Java3D Universe structure to the file. This includes the number and position of + * the Locales, PlatformGeometry, ViewerAvatar, and the MultitransformGroup between + * the ViewingPlatform and the View. However this + * call does not write the content of the branch graphs unless writeUniverseContent is true. + * universe may be null. + * This call will overwrite any existing universe, fileDescription and + * userData in the file.

+ * + *

close() MUST be called when IO is complete. If close() is not called + * the file contents will be undefined.

+ * + * @param file The file to write the data to + * @param universe The SimpleUniverse to write + * @param writeUniverseContent If true, the content of the Locales will be written. + * Otherwise just the universe configuration data will be written. + * @param fileDescription A description of the file's content + * @param fileUserData User defined object + * + * @exception IOException Thrown if there are any IO errors + * @exception UnsupportedUniverseException Thrown if universe is not + * a supported universe class. Currently SimpleUniverse and ConfiguredUniverse + * are supported. + */ + public SceneGraphFileWriter( java.io.File file, + SimpleUniverse universe, + boolean writeUniverseContent, + String fileDescription, + java.io.Serializable fileUserData) throws IOException, UnsupportedUniverseException { + fileControl = new RandomAccessFileControl(); + this.file = file; + file.createNewFile(); + + if (!file.canWrite()) + throw new IOException( "Can not Write to File" ); + + fileControl.createFile( file, universe, writeUniverseContent, fileDescription, fileUserData ); + } + + /** + * Write the graph to the end of the file. + * + * close() MUST be called when IO is complete. If close() is not called + * the file contents will be undefined. + */ + public void writeBranchGraph( BranchGroup graph ) throws IOException { + writeBranchGraph( graph, null ); + } + + /** + * Write a branch graph and some user associated data to the + * end of the file. + * + * close() MUST be called when IO is complete. If close() is not called + * the file contents will be undefined. + */ + public void writeBranchGraph( BranchGroup graph, + java.io.Serializable data ) throws IOException { + fileControl.writeBranchGraph( graph, data ); + } + + /** + * Add a named reference to a SceneGraphObject in the file. + * + * object must have been written to the file before this method is + * called. If the object is not in the file a NamedObjectException will be thrown. + * + * Adding duplicate names will result in the old name being overwritten. + * Different names can reference the same object + */ + public void addObjectName( String name, SceneGraphObject object ) throws NamedObjectException { + fileControl.addNamedObject( name, object ); + } + + /** + * Close the file and cleanup internal data structures. + */ + public void close() throws IOException { + fileControl.close(); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphIO.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphIO.java new file mode 100644 index 0000000..469f424 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphIO.java @@ -0,0 +1,112 @@ +/* + * $RCSfile: SceneGraphIO.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:27 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +/** + * Implement this interface in any classes that subclass a Java3D SceneGraphObject + * in order to have your class handled correctly by scenegraph.io. + * + * More information and example code is provided here. + * + * Classes that implement this interface MUST have a no-arg constructor + */ +public interface SceneGraphIO { + + /** + * The method is called before writeSGObject and gives the user the chance + * to create references to other Nodes and NodeComponents. + * + * References take the form of a nodeID, of type integer. Every SceneGraphObject + * is assigned a unique ID. + * + * The user must save the reference information in writeSGObject + * + * @param ref provides methods to create references to a SceneGraphObject + */ + public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ); + + /** + * Within this method the user should restore references to the SceneGraphObjects + * whose nodeID's were created with createSceneGraphObjectReferences + * This method is called once the all objects in the scenegraph have been loaded. + * + * + * @param ref provides methods to resolve references to a SceneGraphObject + */ + public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ); + + /** + * This method should store all the local state of the object and any references + * to other SceneGraphObjects into out. + * + * This is called after data for the parent SceneGraphObject has been written to + * the out. + * + * @param out the output stream + */ + public void writeSceneGraphObject( java.io.DataOutput out ) throws java.io.IOException; + + /** + * This is called after the object has been constructed and the superclass SceneGraphObject + * data has been read from in. + * + * The user should restore all state infomation written in writeSGObject + * + * @param in the input stream + */ + public void readSceneGraphObject( java.io.DataInput in ) throws java.io.IOException; + + /** + * Flag indicating for children of this object should be saved + * + * This method only has an effect if this is a subclass of Group. + * + * If this returns true then all children of this Group will be saved. + * + * If it returns false then the children are not saved. + */ + public boolean saveChildren(); +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java new file mode 100644 index 0000000..9e66eec --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java @@ -0,0 +1,69 @@ +/* + * $RCSfile: SceneGraphObjectReferenceControl.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:27 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +/** + * Provides and resolves references to SceneGraphObjects to enable + * persistant references in user defined SceneGraphObjects implementing + * the SceneGraphIO interface. + */ +public interface SceneGraphObjectReferenceControl { + + /** + * Add a reference to the scenegraph object specified and return + * the nodeID for the object + * + * Use only during the save cycle + */ + public int addReference( javax.media.j3d.SceneGraphObject object ); + + /** + * Given a nodeID return the corresponding scene graph object. + * + * Use only during the load cycle + */ + public javax.media.j3d.SceneGraphObject resolveReference( int nodeID ); +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStateProvider.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStateProvider.java new file mode 100644 index 0000000..fe1114d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStateProvider.java @@ -0,0 +1,65 @@ +/* + * $RCSfile: SceneGraphStateProvider.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.1 $ + * $Date: 2007/02/26 19:40:19 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState; + +/** + * This interface allows developers to provide their own custom IO control for + * subclasses of SceneGraphObjects. As the Scene Graph is being saved any + * SceneGraphObject in the graph that implements this interface must provide + * it's state class which is responsible for saving the entire state of + * that object. + */ +public interface SceneGraphStateProvider { + + /** + * Returns the State class + * + * @return Class that will perform the IO for the SceneGraphObject + */ + public Class getStateClass(); + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamReader.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamReader.java new file mode 100644 index 0000000..9aa8eb0 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamReader.java @@ -0,0 +1,126 @@ +/* + * $RCSfile: SceneGraphStreamReader.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/03/21 18:02:25 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +import java.io.InputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.HashMap; + +import javax.media.j3d.BranchGroup; +import javax.media.j3d.SceneGraphObject; +import javax.media.j3d.Canvas3D; +import com.sun.j3d.utils.scenegraph.io.retained.StreamControl; +import com.sun.j3d.utils.universe.ConfiguredUniverse; + +/** + * Read and create a (set) of Java3D BranchGraphs or Universe from a Java Stream. + */ +public class SceneGraphStreamReader extends java.lang.Object { + + private StreamControl control; + private DataInputStream in; + + /** Creates new SceneGraphStreamReader and reads the file header information */ + public SceneGraphStreamReader( InputStream stream ) throws IOException { + in = new DataInputStream( stream ); + control = new StreamControl( in ); + control.readStreamHeader(); + } + + /** + * Read and create the universe. If the BranchGraphs were written then + * they will be added to the universe before it is returned. + */ + public ConfiguredUniverse readUniverse() throws IOException { + return control.readUniverse(in, true, null); + } + + /** + * Read and create the universe. If the BranchGraphs were written then + * they will be added to the universe before it is returned. + * @param canvas The Canvas3D to associate with the universe. + */ + public ConfiguredUniverse readUniverse(Canvas3D canvas) throws IOException { + return control.readUniverse(in, true, canvas); + } + + /** + * Read and return the graph from the stream. + * namedObjects map will be updated with any objects that + * were named during the write process + */ + public BranchGroup readBranchGraph( HashMap namedObjects ) throws IOException { + return control.readBranchGraph( namedObjects ); + } + + /** + * Set the ClassLoader used to load the scene graph objects and + * deserialize user data + */ + public void setClassLoader( ClassLoader classLoader ) { + control.setClassLoader( classLoader ); + } + + /** + * Get the ClassLoader used to load the scene graph objects and + * deserialize user data + */ + public ClassLoader getClassLoader() { + return control.getClassLoader(); + } + + /** + * Close the SceneGraphStreamReader stream + * + * @since Java 3D 1.5.1 + */ + public void close() throws IOException { + in.close(); + control.close(); + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamWriter.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamWriter.java new file mode 100644 index 0000000..a77882b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamWriter.java @@ -0,0 +1,128 @@ +/* + * $RCSfile: SceneGraphStreamWriter.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/03/21 17:40:50 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +import java.io.File; +import java.io.IOException; +import java.io.DataOutputStream; +import java.util.HashMap; + +import javax.media.j3d.BranchGroup; +import javax.media.j3d.SceneGraphObject; +import javax.media.j3d.CapabilityNotSetException; +import javax.media.j3d.DanglingReferenceException; +import com.sun.j3d.utils.scenegraph.io.retained.StreamControl; +import com.sun.j3d.utils.universe.SimpleUniverse; + +/** + * Writes a Java3D SceneGraph to a Java OutputStream.

+ * Using this class to write to a FileOutputStream is not recommended. Use + * SceneGraphFileWriter instead to achieve maximum performance and flexibility. + */ +public class SceneGraphStreamWriter extends java.lang.Object { + + private StreamControl control; + private DataOutputStream out; + + /** Creates new SceneGraphStreamWriter that will write to the supplied stream */ + public SceneGraphStreamWriter(java.io.OutputStream outputStream ) throws IOException { + this.out = new java.io.DataOutputStream( outputStream ); + control = new StreamControl( out ); + control.writeStreamHeader(); + } + + + /** + * Write universe to the Stream.

+ * + * If writeContent is true then all BranchGraphs attached to the + * universe will be saved. If it is false then only the universe + * data structures will be output (PlatformGeometry, ViewerAvatar, Locales, + * and the MultiTransformGroup between the ViewingPlatform and the View).

+ * + * If writeContent is true then all the BranchGraphs + * attached to the Locales of the universe must have the + * ALLOW_DETACH capability set. If they do not, a CapabilityNotSetException + * will be thrown

+ * + * @param universe The universe to write + * @param writeContent Flag enabling the BranchGraphs to be written + * + * @exception IOException + * @exception UnsupportedUniverseException Thrown if the universe class is not + * supported by this implementation + */ + public void writeUniverse( SimpleUniverse universe, boolean writeContent ) throws IOException, UnsupportedUniverseException { + control.writeUniverse( out, universe, writeContent ); + } + + /** + * Write the entire graph to the stream.

+ * + * The API will correctly handle NodeComponents that are shared + * between seperate graphs. However Nodes cannot be referenced + * in other Graphs.

+ * + * If a reference to a Node in another graph is encountered a + * DanglingReferenceException will be thrown. + * + * namedObjects can contain a mapping between a key and a SceneGraphObject + * in the graph. During the read process this can be used to locate nodes + * in the graph. + */ + public void writeBranchGraph( BranchGroup graph, HashMap namedObjects ) throws IOException, DanglingReferenceException, NamedObjectException { + // TODO Add namedObjects to SymbolTable + control.addNamedObjects( namedObjects ); + control.writeBranchGraph( graph, null ); + } + + /** + * Close the SceneGraphStreamWriter and the associated stream + */ + public void close() throws IOException { + control.close(); + out.close(); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnresolvedBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnresolvedBehavior.java new file mode 100644 index 0000000..12e5fd8 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnresolvedBehavior.java @@ -0,0 +1,64 @@ +/* + * $RCSfile: UnresolvedBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:27 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +/** + * This Behavior is used in place of any behaviors which can not + * be instantiated when a scene graph is read. This behavior is + * always disabled when it initalizes. It just provides an indicator + * in the scene graph that a Behavior is missing. + * + * This normally means the Behavior is not present in the classpath. + */ +public class UnresolvedBehavior extends javax.media.j3d.Behavior { + + public void initialize() { + setEnable(false); + } + + public void processStimulus(java.util.Enumeration enumeration) { + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnsupportedUniverseException.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnsupportedUniverseException.java new file mode 100644 index 0000000..2090b02 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnsupportedUniverseException.java @@ -0,0 +1,71 @@ +/* + * $RCSfile: UnsupportedUniverseException.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:27 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io; + +/** + * Thrown if the VirtualUniverse subclass is not supported + * by the writeUniverse calls. + * + * Currently only com.sun.j3d.utils.universe.SimpleUniverse is supported + */ +public class UnsupportedUniverseException extends java.lang.Exception { + + /** + * Creates new UnsupportedUniverseException without detail message. + */ + public UnsupportedUniverseException() { + } + + + /** + * Constructs an UnsupportedUniverseException with the specified detail message. + * @param msg the detail message. + */ + public UnsupportedUniverseException(String msg) { + super(msg); + } +} + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/doc-files/extensibility.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/doc-files/extensibility.html new file mode 100644 index 0000000..950b043 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/doc-files/extensibility.html @@ -0,0 +1,189 @@ + + + + + + + + Java 3D scenegraph.io Extensibility + + +

+Using your own Classes with scenegraph.io +

+

The scenegraph.io APIs will handle the IO for all the core Java3D +SceneGraphObjects. However, if you create a subclass of one of these +objects and add it to your Scene Graph, the IO system, by default, +will not store any state information specific to your class.

+

The default behavior when an unrecognized SceneGraphObject class +is encountered is to traverse up the superclasses of the object until +a recognized Java3D class is located. The data structures for this +class are then used for IO. The system does store the class name of +the original object. +

For example: +


+public class MyBranchGroup extends javax.media.j3d.BranchGroup {
+    private int myData;
+    ....
+}
+
+

When the Scene Graph is written to a file and this node is +encountered, the superclass javax.media.j3d.BranchGroup will be used +to store all the state for the object so any children of +MyBranchGroup, the capabilities, etc. will be stored, but myData will +be lost. When the scene graph is loaded, MyBranchGroup will be +instantiated and will be populated with all the state from +BranchGroup but myData will have been lost.

+

To overcome this, the scenegraph.io API provides an interface for +you to implement in your own classes that provides the opportunity +for you to save the state of your classes during the IO processes. +This is the SceneGraphIO interface.

+

When the scenegraph is saved, the methods of SceneGraphIO are +called in this order +

+
    +
  1. createSceneGraphObjectReferences

    +
  2. saveChildren

    +
  3. writeSceneGraphObject

    +
+

During the load cycle the method call order is

+
    +
  1. Instantiate Object using default constructor

    +
  2. Populate object with state from superclasses

    +
  3. readSceneGraphObject

    +
  4. restoreSceneGraphObjectReferences

    +
+

Within each method you need to perform the following actions: +

    +
  • createSceneGraphObjectReferences If your object has + references to other SceneGraphObjects then you need to obtain an + object reference (int) for each reference using the + SceneGraphReferenceControl object passed as a parameter to this + method. If you don't have references to other SceneGraphObjects then + no action is required.

    +
  • saveChildren If your object is a subclass of Group and you + want the scenegraph.io package to save the children then this must + return true. If it returns false, the object will be saved but not + its children.

    +
  • writeSceneGraphObject In this method you must write all the + state information for your class, including the object references + obtained in createSceneGraphObjectReferences, to the DataOutput + stream passed into this method.

    +
  • readSceneGraphObject By the time this method is called your + class has been instantiated and the state information in the Java3D + superclass will have been loaded. You should load all the state + information you saved for your class.

    +
  • restoreSceneGraphObjectReferences is called once all the + SceneGraph objects have been loaded and allows you to restore the + references to the other SceneGraph objects.

    +
+

Here are some examples. Only the parts of the source pertaining to +IO are show....

+

Behavior Example

+
+public class BehaviorIO extends javax.media.j3d.Behavior implements SceneGraphIO + private TransformGroup target; // The TG on which this behavior acts + private int targetRef; // Object Reference for target + + public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) { + targetRef = ref.addReference( target ); + } + + public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) { + target = (TransformGroup)ref.resolveReference( targetRef ); + } + + public void writeSceneGraphObject( java.io.DataOutput out ) throws IOException { + out.writeInt( targetRef ); + } + + public void readSceneGraphObject( java.io.DataInput in ) throws IOException { + targetRef = in.readInt(); + } + + // This has no effect as this is not a subclass of Group + public boolean saveChildren() { + return true; + } +
+

+`BlackBox' Group Example +

+This example is a Group node that creates its subgraph during +its instantiation. An example where you might use this is to +represent some geometry that is loaded from an external file format +such a OpenFLT. +

+public class House extends Group implements SceneGraphIO {
+    public House() {
+        super();
+        this.addChild( OpenFlightLoader.load( "/dir/house.flt" );
+    }
+
+    public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
+        // No references
+    }
+
+    public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
+        // No references
+    }
+
+    public void writeSceneGraphObject( java.io.DataOutput out ) throws IOException {
+        // No local state
+    }
+
+    public void readSceneGraphObject( java.io.DataInput in ) throws IOException {
+        // No local state
+    }
+
+    public boolean saveChildren() {
+        // Don't save the children as they will be restored by the openflightloader
+        return false;
+    }
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/package.html new file mode 100644 index 0000000..d3efafc --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/package.html @@ -0,0 +1,105 @@ + + + + + + + + + + +

This package provides a Java3D SceneGraph IO capability. +The API supports IO of a scenegraph to and from a Java Stream and/or +RandomAccessFile. The features offered for these two io systems are +somewhat different.

+

The SceneGraphFileReader and SceneGraphFileWriter classes provide +IO to and from a RandomAccessFile. They allow a universe and/or +multiple BranchGraphs to be written to the file with Node's and +NodeComponent's shared between the separate graphs. The graphs can be +read in any order.

+

SceneGraphStreamReader and SceneGraphStreamWriter classes provide +IO to and from a Stream. These classes allow a universe and/or +multiple BranchGraphs to be passed over stream. In contrast to the +FileReader/Writer sharing of Node's is NOT supported between graphs +by the API. Sharing of node components is supported. If your +application requires references to Nodes in other graphs (such as +SharedGroups) the application must handle the references using the +namedObjects constructs.

+

Note : If you use SceneGraphStreamWriter class to write to a +FileOutputStream the resulting file cannot be read using the +SceneGraphFileReader, the converse is also true, you can not use a +FileInputStream to load a file written by SceneGraphFileWriter. +

+The package supports the IO of all the Java3D 1.3 core classes +and many of the utilities. It also includes interfaces which can be +implemented to allow user defined subclasses of SceneGraphObjects to +be stored. Information on the extensibility can be found +here +

+The package has a number of properties which can be used to control the IO +behavior

+ +

+j3d.io.UseSuperClassIfNoChildClass when this property is present the load +operation will attempt to avoid failure if Scene Graph nodes are not present +in the classpath. For example if a developer has subclassed BranchGroup with a +class called MyBG but has not +implemented the SceneGraphIO interface when the API saves the graph the +superclass (ie BranchGroup) data will be stored. When the scene is loaded +normally MyBG must be in the classpath otherwise the load will fail. If this +property is set then the superclass node (ie BranchGroup) will be instantiated +when MyBG is missing. Obviously, if MyBG contained any state information +then this will be lost.

+ +j3d.io.ImageCompression this can be set to None, GZIP, JPEG and tells the +IO system to compress images in the .j3f file using the prescribed technique. In +the future this will be extended to support all the formats available in +javax.imageio in JDK 1.4. +

+

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/Controller.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/Controller.java new file mode 100644 index 0000000..7edcd66 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/Controller.java @@ -0,0 +1,966 @@ +/* + * $RCSfile: Controller.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.10 $ + * $Date: 2007/11/14 12:51:38 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io.retained; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ListIterator; + +import javax.media.j3d.BoundingBox; +import javax.media.j3d.BoundingPolytope; +import javax.media.j3d.BoundingSphere; +import javax.media.j3d.Bounds; +import javax.media.j3d.BranchGroup; +import javax.media.j3d.Canvas3D; +import javax.media.j3d.CapabilityNotSetException; +import javax.media.j3d.SceneGraphObject; +import javax.media.j3d.SharedGroup; +import javax.media.j3d.Transform3D; +import javax.vecmath.Color3f; +import javax.vecmath.Color4f; +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; +import javax.vecmath.Point3f; +import javax.vecmath.Quat4f; +import javax.vecmath.Tuple3d; +import javax.vecmath.Tuple3f; +import javax.vecmath.Tuple4d; +import javax.vecmath.Tuple4f; +import javax.vecmath.Vector3f; +import javax.vecmath.Vector4d; +import javax.vecmath.Vector4f; + +import com.sun.j3d.utils.scenegraph.io.NamedObjectException; +import com.sun.j3d.utils.scenegraph.io.ObjectNotLoadedException; +import com.sun.j3d.utils.scenegraph.io.SceneGraphStateProvider; +import com.sun.j3d.utils.scenegraph.io.UnsupportedUniverseException; +import com.sun.j3d.utils.scenegraph.io.state.com.sun.j3d.utils.universe.SimpleUniverseState; +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.ImageComponentState; +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.NullSceneGraphObjectState; +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState; +import com.sun.j3d.utils.universe.ConfiguredUniverse; +import com.sun.j3d.utils.universe.SimpleUniverse; + +/** + * Provides code to control the reading and writing of Java3D objects to and + * from any Java IO mechanism. + */ +public abstract class Controller extends java.lang.Object { + + + protected static final long SYMBOL_TABLE_PTR = 30; // long - 8 bytes + protected static final long BG_DIR_PTR = 38; // long - 8 bytes + protected static final long NAMES_OBJECTS_TABLE_PTR = 46; // long - 8 bytes + protected static final long NODE_TYPES_PTR = 52; // long - 8 bytes + protected static final long UNIVERSE_CONFIG_PTR = 60; // long - 8 bytes + protected static final long BRANCH_GRAPH_COUNT = 68; // int - 4 bytes + protected static final long FILE_DESCRIPTION = 72; // UTF - n bytes + + protected SymbolTable symbolTable; + protected NullSceneGraphObjectState nullObject = new NullSceneGraphObjectState( null, this ); + + /** + * The currentFileVersion being read + */ + protected int currentFileVersion; + + /** + * The File version which will be written + * + * 1 = Java3D 1.3 beta 1 + * 2 = Java3D 1.3 FCS, 1) fix to allow skipping user data written via + SceneGraphIO interface + 2) Add missing duplicateOnCloneTree flag + (bug 4690159) + * 3 = Java3D 1.5.1 1) Add support for SceneGraphObject Name field + * 4 = Java3D 1.5.2 issue 532, for saving Background Geometry + */ + protected int outputFileVersion = 4; + + /** + * When running the application within webstart this may not be the + * correct ClassLoader. If Java 3D is not installed in the local vm and + * is instead installed by webstart then this definitely is NOT the correct + * classloader, in this case Thread.getCurrent().getClass().getClassLoader() + * would probably be a good default. The user can also set their preferred + * classloader by calling setClassLoader in SceneGraph[Stream|File]Reader. + */ + protected ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + + /** + * If true when loading a scenegraph that contains nodes who's classes + * are not in the classpath then use then first Java3D core superclass + * to instantiate the node. + * + * If false a SGIORuntimeException will be thrown when classes cannot be + * located + */ + private boolean useSuperClass = false; + + private int imageCompression = ImageComponentState.NO_COMPRESSION; + + /** Creates new Controller */ + public Controller() { + try { + if ( System.getProperty("j3d.io.UseSuperClassIfNoChildClass")!=null) + useSuperClass = true; + + String imageC = System.getProperty("j3d.io.ImageCompression"); + if (imageC!=null) { + if (imageC.equalsIgnoreCase("None")) + imageCompression = ImageComponentState.NO_COMPRESSION; + else if (imageC.equalsIgnoreCase("GZIP")) + imageCompression = ImageComponentState.GZIP_COMPRESSION; + else if (imageC.equalsIgnoreCase("JPEG")) + imageCompression = ImageComponentState.JPEG_COMPRESSION; + } + } catch( Exception e ) {} + + } + + public final SymbolTable getSymbolTable() { + return symbolTable; + } + + /** + * Get the file version that we should write + */ + public int getOutputFileVersion() { + return outputFileVersion; + } + + /** + * Get the file version of the file we are reading + */ + public int getCurrentFileVersion() { + return currentFileVersion; + } + + /** + * Create a new state object and check for a pre-existing symbol table + * entry + */ + public SceneGraphObjectState createState( SceneGraphObject obj ) { + return createState( obj, symbolTable.getSymbol( obj ) ); + } + + /** + * Given a scene graph object instantiate the correct State class + * for that object. If the symbol already exists (is not null) then + * increment the reference count, otherwise create a new symbol. + */ + public SceneGraphObjectState createState( SceneGraphObject obj, SymbolTableData symbol ) { + if (obj==null) return nullObject; + + if (symbol!=null) { + symbol.incrementReferenceCount(); + symbolTable.setBranchGraphID( symbol ); + if (symbol.getNodeState()!=null) + return symbol.getNodeState(); + } else + symbol = symbolTable.createSymbol( obj ); + + return createState( symbol ); + } + + /** + * Return the state class for the SceneGraphObject, creating one if it does + * not already exist + */ + public SceneGraphObjectState createState( SymbolTableData symbol ) { + SceneGraphObject obj = symbol.getJ3dNode(); + if (obj==null) return nullObject; + + String name = obj.getClass().getName(); + SceneGraphObjectState ret; + + try { + Class state; + if (obj instanceof SceneGraphStateProvider) + state = ((SceneGraphStateProvider)obj).getStateClass(); + else + state = Class.forName( "com.sun.j3d.utils.scenegraph.io.state."+name+"State" ); + ret = constructStateObj( symbol, state, obj.getClass() ); + } catch(ClassNotFoundException e) { + ret = checkSuperClasses( symbol ); + if (!(obj instanceof com.sun.j3d.utils.scenegraph.io.SceneGraphIO)) + System.out.println("Could not find "+"com.sun.j3d.utils.scenegraph.io.state."+name+"State, using superclass "+ret.getClass().getName() ); + if (ret==null) + throw new SGIORuntimeException( "No State class for "+ + obj.getClass().getName() ); + } + + symbol.nodeState = ret; + + return ret; + } + private SceneGraphObjectState constructStateObj( SymbolTableData symbol, + Class state, + Class objClass ) { + + SceneGraphObjectState ret = null; + + try { + Constructor construct = state.getConstructor( + new Class[] { com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData.class, + com.sun.j3d.utils.scenegraph.io.retained.Controller.class + } ); + ret = (SceneGraphObjectState)construct.newInstance( + new Object[]{ symbol, this } ); + + } catch( NoSuchMethodException ex ) { + System.out.println("Looking for Constructor ("+symbol.j3dNode.getClass().getName()+", Controller )"); + throw new SGIORuntimeException( "1 Broken State class for "+ + state.getName() ); + } catch( InvocationTargetException exc ) { + exc.printStackTrace(); + throw new SGIORuntimeException( "2 Broken State class for "+ + state.getName() ); + } catch( IllegalAccessException exce ) { + throw new SGIORuntimeException( "3 Broken State class for "+ + state.getName() ); + } catch( InstantiationException excep ) { + throw new SGIORuntimeException( "4 Broken State class for "+ + state.getName() ); + } + + return ret; + } + + /** + * Check to see if any of the superclasses of obj are + * known to the Java3D IO package + */ + private SceneGraphObjectState checkSuperClasses( SymbolTableData symbol ) { + + Class cl = symbol.j3dNode.getClass().getSuperclass(); + Class state = null; + boolean finished = false; + + + while( cl != null & !finished ) { + String name = cl.getName(); + //System.out.println("Got superclass "+name); + try { + state = Class.forName( "com.sun.j3d.utils.scenegraph.io.state."+name+"State" ); + } catch(ClassNotFoundException e) { + state = null; + } + + if (state!=null) + finished = true; + else + cl = cl.getSuperclass(); + } + + if (cl==null) + throw new SGIORuntimeException( "Unsupported class "+symbol.j3dNode.getClass().getName() ); + + return constructStateObj( symbol, state, cl ); + } + + + public void writeObject( DataOutput out, SceneGraphObjectState obj ) throws IOException { + + int classID = getStateID( obj ); + + out.writeInt( classID ); // Node class id + + if (classID==0) { + out.writeUTF( obj.getClass().getName() ); + } + + obj.writeObject( out ); + } + + public SceneGraphObjectState readObject( DataInput in ) throws IOException { + int classID = in.readInt(); + + SceneGraphObjectState state = null; + + if (classID==-1) + return nullObject; + else if (classID==0) { + String stateClassName = in.readUTF(); + + try { + Class cl = Class.forName( stateClassName, true, classLoader ); + // System.out.println("Got class "+cl ); + Constructor construct = cl.getConstructor( + new Class[] { + com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData.class, + com.sun.j3d.utils.scenegraph.io.retained.Controller.class} ); + + // System.out.println("Got constructor "+construct ); + state = (SceneGraphObjectState)construct.newInstance( + new Object[]{ null, this } ); + + // System.out.println("Got state instance "+state); + } catch(ClassNotFoundException e) { + throw new java.io.IOException( "Error Loading State Class "+stateClassName+" "+e.getMessage() ); + } catch( NoSuchMethodException ex ) { + throw new java.io.IOException( "1 Broken State class for "+ + stateClassName+" "+ex.getMessage() ); + } catch( InvocationTargetException exc ) { + exc.printStackTrace(); + throw new java.io.IOException( "2 Broken State class for "+ + stateClassName ); + } catch( IllegalAccessException exce ) { + throw new java.io.IOException( "3 Broken State class for "+ + stateClassName ); + } catch( InstantiationException excep ) { + throw new java.io.IOException( "4 Broken State class for "+ + stateClassName ); + } + } else { + state = createCoreState( classID ); + } + + state.readObject( in ); + + return state; + } + + /** + * Set the class loader used to load the Scene Graph Objects and + * the serialized user data. The default is + * ClassLoader.getSystemClassLoader() + */ + public void setClassLoader( ClassLoader classLoader ) { + this.classLoader = classLoader; + } + + + /** + * Get the class loader used to load the Scene Graph Objects and + * the serialized user data. The default is + * ClassLoader.getSystemClassLoader() + */ + public ClassLoader getClassLoader() { + return classLoader; + } + + /** + * Write all the unsaved NodeComponents and SharedGroups to DataOutput. + * Mark all the NodeComponents as saved. + */ + protected void writeNodeComponents( DataOutput out ) throws IOException { + // This method is overridden by RandomAccessFileControl + // The RandomAccessFileControl version sets the pointer to + // the next NodeComponent correclty + + ListIterator list = symbolTable.getUnsavedNodeComponents(); + out.writeInt( symbolTable.getUnsavedNodeComponentsSize() ); + while( list.hasNext() ) { + SymbolTableData symbol = (SymbolTableData)list.next(); + + out.writeInt( symbol.nodeID ); + out.writeLong( 0L ); // Pointer to next NodeComponent + + writeObject( out, symbol.getNodeState() ); + } + } + + /** + * Read in all the node components in this block + */ + protected void readNodeComponents( DataInput in ) throws IOException { + int count = in.readInt(); + + for(int i=0; iposition) + throw new SGIORuntimeException( "Seeking Backward "+pos +" "+position ); + else + stream.skip( (int)(position-pos) ); + + pos = position; + } + + public long getFilePointer() { + return pos; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/PositionOutputStream.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/PositionOutputStream.java new file mode 100644 index 0000000..c53ce15 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/PositionOutputStream.java @@ -0,0 +1,91 @@ +/* + * $RCSfile: PositionOutputStream.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:28 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io.retained; + +import java.io.DataOutputStream; +import java.io.IOException; + +class PositionOutputStream extends java.io.OutputStream { + + private long pos = 0; + private java.io.OutputStream stream; + + public PositionOutputStream( java.io.OutputStream stream ) { + this.stream = stream; + } + + public void write(int p1) throws IOException { + pos++; + stream.write(p1); + } + + public void write( byte[] b ) throws IOException { + pos+= b.length; + stream.write( b ); + } + + public void write( byte[] b, int off, int len ) throws IOException { + pos+= len; + stream.write( b, off, len ); + } + + /** + * Move the file pointer to the specified position. + * The position MUST be greater or equal to the current position + */ + public void seekForward( long position ) throws IOException { + if (pos>position) + throw new SGIORuntimeException( "Seeking Backward "+pos +" "+position ); + else + for(int i=0; i< (int)(position-pos); i++) + stream.write(0); + + pos = position; + } + + public long getFilePointer() { + return pos; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/RandomAccessFileControl.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/RandomAccessFileControl.java new file mode 100644 index 0000000..b2d702e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/RandomAccessFileControl.java @@ -0,0 +1,500 @@ +/* + * $RCSfile: RandomAccessFileControl.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:29 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io.retained; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.io.DataOutput; +import java.io.DataInput; + +import javax.media.j3d.BranchGroup; +import javax.media.j3d.CapabilityNotSetException; +import javax.media.j3d.Canvas3D; + +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState; +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.NodeComponentState; +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.BranchGroupState; +import com.sun.j3d.utils.scenegraph.io.UnsupportedUniverseException; +import com.sun.j3d.utils.universe.SimpleUniverse; +import com.sun.j3d.utils.universe.ConfiguredUniverse; + +public class RandomAccessFileControl extends Controller { + + protected String FILE_IDENT = new String( "j3dff" ); + + private long user_data; + private long universe_config; + + private long symbol_table; + + private RandomAccessFile raf; + + private int branchGraphCount=0; + + private boolean writeMode = false; + private Object userData; + + /** Creates new RandomAccessFileControl */ + public RandomAccessFileControl() { + super(); + symbolTable = new SymbolTable(this); + } + + /** + * Create the file and write the inital header information + */ + public void createFile( java.io.File file, + SimpleUniverse universe, + boolean writeUniverseContent, + String description, + java.io.Serializable userData ) throws IOException, + UnsupportedUniverseException, + CapabilityNotSetException { + + raf = new RandomAccessFile( file, "rw" ); + writeMode = true; + + raf.seek(0); + raf.writeUTF( FILE_IDENT ); + + raf.seek(20); + raf.writeInt( outputFileVersion ); + + raf.seek( BRANCH_GRAPH_COUNT ); + raf.writeInt( 0 ); // Place holder to branch graph count + + raf.seek( FILE_DESCRIPTION ); + + if (description==null) + description=""; + raf.writeUTF( description ); + + try { + writeSerializedData( raf, userData ); + + universe_config = raf.getFilePointer(); + writeUniverse( raf, universe, writeUniverseContent ); + } catch( SGIORuntimeException e ) { + throw new IOException( e.getMessage() ); + } + } + + /** + * Open the file for reading + */ + public void openFile( java.io.File file ) throws IOException { + raf = new RandomAccessFile( file, "r" ); + writeMode = false; + + raf.seek(0); + String ident = raf.readUTF(); + + if ( ident.equals("demo_j3f") ) + throw new IOException( + "Use Java 3D Fly Through I/O instead of Java 3D Scenegraph I/O" ); + + if ( !ident.equals("j3dff") ) + throw new IOException( + "This is a Stream - use SceneGraphStreamReader instead"); + + raf.seek(20); + currentFileVersion = raf.readInt(); + + if ( currentFileVersion > outputFileVersion ) { + throw new IOException("Unsupported file version. This file was written using a new version of the SceneGraph IO API, please update your installtion to the latest version"); + } + + // readFileDescription sets user_data + String description = readFileDescription(); + + raf.seek( BRANCH_GRAPH_COUNT ); + branchGraphCount = raf.readInt(); + //System.out.println("BranchGraph count : "+branchGraphCount ); + + raf.seek( UNIVERSE_CONFIG_PTR ); + universe_config = raf.readLong(); + + raf.seek( SYMBOL_TABLE_PTR ); + symbol_table = raf.readLong(); + + ConfiguredUniverse universe; + + raf.seek( symbol_table ); + symbolTable.readTable( raf, false ); + raf.seek(user_data); + + userData = readSerializedData(raf); + } + + public ConfiguredUniverse readUniverse( boolean attachBranchGraphs, + Canvas3D canvas) throws IOException { + raf.seek( universe_config ); + return readUniverse( raf, attachBranchGraphs, canvas ); + } + + public Object getUserData() { + return userData; + } + + /** + * Read the set of branchgraps. + * + * Used by readUniverse + * + * RandomAccessFileControl will read the graphs in the array, + * StreamControl will read all graphs in the stream + */ + protected void readBranchGraphs( int[] graphs ) throws IOException { + for(int i=0; iSGIORuntimeException
+ * without a detail message. + */ + public SGIORuntimeException() { + } + + + /** + * Constructs an instance of SGIORuntimeException + * with the specified detail message. + * + * @param msg the detail message. + */ + public SGIORuntimeException(String msg) { + super(msg); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/StreamControl.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/StreamControl.java new file mode 100644 index 0000000..320273e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/StreamControl.java @@ -0,0 +1,205 @@ +/* + * $RCSfile: StreamControl.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:29 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io.retained; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.io.DataOutput; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.util.HashMap; +import java.util.Iterator; + +import javax.media.j3d.VirtualUniverse; +import javax.media.j3d.BranchGroup; +import javax.media.j3d.SceneGraphObject; + +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState; +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.NodeComponentState; +import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.BranchGroupState; +import com.sun.j3d.utils.scenegraph.io.UnsupportedUniverseException; + +/** + * Provides the infrastructure for ScenGraphStream Reader and Writer + */ +public class StreamControl extends Controller { + + protected String FILE_IDENT = new String( "j3dsf" ); + + private DataInputStream inputStream; + private DataOutputStream outputStream; + + public StreamControl( DataOutputStream out ) { + super(); + outputStream = out; + symbolTable = new SymbolTable( this ); + } + + public StreamControl( DataInputStream in ) { + super(); + inputStream = in; + symbolTable = new SymbolTable( this ); + } + + /** + * Prepare the Stream for writing, by sending header information + */ + public void writeStreamHeader() throws IOException { + outputStream.writeUTF( FILE_IDENT ); + outputStream.writeInt( outputFileVersion ); + } + + public void readStreamHeader() throws IOException { + String ident = inputStream.readUTF(); + if ( ident.equals("demo_j3s") ) + throw new IOException( "Use Java 3D Fly Through I/O instead of Java 3D Scenegraph I/O" ); + + if ( !ident.equals("j3dsf") ) + throw new IOException( + "This is a File - use SceneGraphFileReader instead"); + + currentFileVersion = inputStream.readInt(); + + if (currentFileVersion > outputFileVersion ) { + throw new IOException("Unsupported file version. This file was written using a new version of the SceneGraph IO API, please update your installtion to the latest version"); + } + } + + /** + * Add the named objects to the symbol table + */ + public void addNamedObjects( HashMap namedObjects ) { + symbolTable.addNamedObjects( namedObjects ); + } + + /** + * The BranchGraph userData is not supported in a stream and will be + * ignored. + * + * However the data in the userData field of the BranchGroup will be + * stored in the stream + */ + public void writeBranchGraph( BranchGroup bg, java.io.Serializable userData ) throws IOException { + try { + SymbolTableData symbol = symbolTable.getSymbol( bg ); + + if (symbol==null) { + symbol = symbolTable.createSymbol( bg ); + symbol.branchGraphID = -1; // This is a new BranchGraph so set the ID to -1 + } // which will cause setBranchGraphRoot to assign a new ID. + + symbolTable.setBranchGraphRoot( symbol, 0 ); + symbolTable.startUnsavedNodeComponentFrame(); + SceneGraphObjectState state = createState( bg, symbol ); + writeObject( outputStream, state ); + writeNodeComponents( outputStream ); + symbolTable.endUnsavedNodeComponentFrame(); + + if (symbolTable.branchGraphHasDependencies( symbol.branchGraphID )) + throw new javax.media.j3d.DanglingReferenceException(); + + symbolTable.clearUnshared(); + symbolTable.writeTable( outputStream ); + } catch( SGIORuntimeException e ) { + throw new IOException( e.getMessage() ); + } + } + + public BranchGroup readBranchGraph( HashMap namedObjects ) throws IOException { + try { + SceneGraphObjectState state = readObject( inputStream ); + readNodeComponents( inputStream ); + symbolTable.readTable( inputStream, true ); + + symbolTable.setBranchGraphRoot( state.getSymbol(), 0 ); + + state.buildGraph(); + + if (namedObjects!=null) + symbolTable.getNamedObjectMap( namedObjects ); + + return (BranchGroup)state.getNode(); + } catch( SGIORuntimeException e ) { + throw new IOException( e.getMessage() ); + } + } + + /** + * Read the set of branchgraps. + * + * Used by readUniverse + * + * RandomAccessFileControl will read the graphs in the array, + * StreamControl expects the graphs to follow the universe in the + * stream so it will read graphs.length branchgraphs. + */ + protected void readBranchGraphs( int[] graphs ) throws IOException { + for(int i=0; i1) + sharedNodes.add( symbol ); + nodeIDIndex.set( symbol.nodeID, symbol ); + } + + branchGraphs.set( j, symbol ); + } + + + for(int i=0; isymbol
+ * + * Only nodes (not nodeComponents) affect intergraph dependencies + */ + private void addInterGraphDependency( SymbolTableData symbol ) { + HashSet set = (HashSet)branchGraphDependencies.get( currentBranchGraphID ); + if (set==null) { + set = new HashSet(); + branchGraphDependencies.set( currentBranchGraphID, set ); + } + + set.add(symbol); + } + + /** + * Update the reference count for the node component. + * + * Called during NodeComponentState.addSubReference() + */ + public void incNodeComponentRefCount( int nodeID ) { + if (nodeID==0) return; + + SymbolTableData symbol = getSymbol( nodeID ); + + ((NodeComponentState)symbol.nodeState).addSubReference(); + + if (symbol.referenceCount==1) + sharedNodes.add( symbol ); + symbol.referenceCount++; + } + + /** + * Add a refernce to the specified node + * Also returns the nodes id + */ + public int addReference( SceneGraphObject node ) { + if (node==null) return 0; + + SymbolTableData symbol = getSymbol( node ); + + if (symbol==null) { + if (node instanceof javax.media.j3d.Node) { + symbol = createDanglingSymbol( node ); + if (symbol.branchGraphID != currentBranchGraphID ) { + //System.out.println("------------- Adding Reference "+symbol.nodeID+" "+node ); // TODO - remove + addInterGraphDependency( symbol ); + sharedNodes.add( symbol ); + } + } else { + symbol = createNodeComponentSymbol( node ); + } + return symbol.nodeID; + } else { + return addReference( symbol ); + } + } + + /** + * Add a refernce to the specified node + * Also returns the nodes id + */ + public int addReference( SymbolTableData symbol ) { + + if (symbol!=null) { + if (symbol.referenceCount==1) + sharedNodes.add( symbol ); + symbol.referenceCount++; + + if (symbol.j3dNode instanceof javax.media.j3d.NodeComponent && symbol.referenceCount>1) { + ((NodeComponentState)symbol.nodeState).addSubReference(); + } + + if (symbol.branchGraphID != currentBranchGraphID && + symbol.j3dNode instanceof javax.media.j3d.Node ) { + // System.out.println("------------- Adding Reference "+symbol.nodeID+" "+symbol.j3dNode ); // TODO - remove + addInterGraphDependency( symbol ); + } + } else { + throw new SGIORuntimeException("Null Symbol"); + } + + return symbol.nodeID; + } + + /** + * Add a refernce to the BranchGraph root + * Also returns the nodes id + * + * Used to associate graphs with a locale without storing the graph at the + * current time. + */ + public int addBranchGraphReference( SceneGraphObject node, int branchGraphID ) { + if (node==null) return 0; + + SymbolTableData symbol = getSymbol( node ); + + if (symbol!=null) { + if (symbol.referenceCount==1) + sharedNodes.add( symbol ); + symbol.referenceCount++; + } else { + symbol = new SymbolTableData( nodeID++, node, null, -3 ); + j3dNodeIndex.put( node, symbol ); + nodeIDIndex.add( symbol ); + danglingReferences.put( node, symbol ); + } + + symbol.branchGraphID = branchGraphID; + for(int i=branchGraphs.size(); inodeIDIndex.size() ) + return null; + else + return (SymbolTableData)nodeIDIndex.get( nodeID ); + } + + /** Get the symbol for the shared group + * If the sharedgroup has not been loaded then load it before + * returning (if we are using RandomAccessFileControl + */ + public SymbolTableData getSharedGroup( int nodeID ) { + SymbolTableData symbol = getSymbol( nodeID ); + + if (symbol.nodeState==null && control instanceof RandomAccessFileControl) { + try { + ((RandomAccessFileControl)control).loadSharedGroup( symbol ); + } catch( java.io.IOException e ) { + e.printStackTrace(); + throw new SGIORuntimeException("Internal error in getSharedGroup"); + } + } + + return symbol; + } + + /** + * Set the position of the object referenced by state + */ + public void setFilePosition( long ptr, SceneGraphObjectState state ) { + if (state instanceof NullSceneGraphObjectState) return; + + SymbolTableData symbol = getSymbol( state.getNodeID() ); + + symbol.filePosition = ptr; + } + /** + * Associate the name with the scene graph object + */ + public void addNamedObject( String name, SceneGraphObject object ) { + namedObjects.put( name, object ); + } + + /** + * Add all the named objects in map + */ + public void addNamedObjects( HashMap map ) { + if (map!=null) + namedObjects.putAll( map ); + } + + /** + * Return the SceneGraphObject associated with the name + */ + public SceneGraphObject getNamedObject( String name ) throws NamedObjectException, ObjectNotLoadedException { + Object obj = namedObjects.get( name ); + if (obj==null) + throw new NamedObjectException( "Unknown name :"+name ); + + if (obj instanceof SceneGraphObject) + return (SceneGraphObject)obj; + else { + SymbolTableData symbol = getSymbol( ((Integer)obj).intValue() ); + if (symbol==null || symbol.j3dNode==null) + throw new ObjectNotLoadedException( ((Integer)obj).toString() ); + return symbol.j3dNode; + } + } + + /** + * Get all the names of the named objects + */ + public String[] getNames() { + return (String[])namedObjects.keySet().toArray( new String[] {} ); + } + + /** + * Add the namedObject mappings to map + */ + public void getNamedObjectMap( HashMap map ) { + map.putAll( namedObjects ); + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + + for(int i=0; i0) // TODO - remove if, workaround for bug in daily + app.setTextureUnitState( texUnitState ); + + app.setTransparencyAttributes( (TransparencyAttributes)control.getSymbolTable().getJ3dNode(transparencyAttributes) ); + + super.buildGraph(); // Must be last call in method + } + + protected javax.media.j3d.SceneGraphObject createNode() { + return new Appearance(); + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/AuralAttributesState.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/AuralAttributesState.java new file mode 100644 index 0000000..e174f0c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/AuralAttributesState.java @@ -0,0 +1,125 @@ +/* + * $RCSfile: AuralAttributesState.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:32 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d; + +import java.io.IOException; +import java.io.DataInput; +import java.io.DataOutput; +import javax.media.j3d.AuralAttributes; +import javax.media.j3d.SceneGraphObject; +import javax.vecmath.Vector3f; +import com.sun.j3d.utils.scenegraph.io.retained.Controller; +import com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData; + +public class AuralAttributesState extends NodeComponentState { + + public AuralAttributesState(SymbolTableData symbol,Controller control) { + super( symbol, control ); + + } + + public void writeObject( DataOutput out ) throws IOException { + super.writeObject( out ); + + out.writeFloat( ((AuralAttributes)node).getAttributeGain() ); + + float[] distance = new float[ ((AuralAttributes)node).getDistanceFilterLength() ]; + float[] cutoff = new float[ distance.length ]; + + ((AuralAttributes)node).getDistanceFilter( distance, cutoff ); + out.writeInt( distance.length ); + for(int i=0; i1) + ((NodeComponent)this.node).setDuplicateOnCloneTree(in.readBoolean()); + + } + + public void writeObject( DataOutput out ) throws IOException { + super.writeObject(out); + out.writeBoolean(((NodeComponent)this.node).getDuplicateOnCloneTree()); + } + + /** + * Called when this component reference count is incremented. + * Allows this component to update the reference count of any components + * that it references. + */ + public void addSubReference() { + } + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/NodeState.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/NodeState.java new file mode 100644 index 0000000..af71cf3 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/NodeState.java @@ -0,0 +1,88 @@ +/* + * $RCSfile: NodeState.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:37 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d; + +import java.io.*; +import javax.media.j3d.Node; +import javax.media.j3d.NodeComponent; +import javax.media.j3d.SceneGraphObject; + +import com.sun.j3d.utils.scenegraph.io.retained.Controller; +import com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData; + +public class NodeState extends SceneGraphObjectState { + + public NodeState( SymbolTableData symbol, Controller control ) { + super(symbol, control); + } + + public void writeObject( DataOutput out ) throws + IOException { + + super.writeObject( out ); + + control.writeBounds( out, ((Node)node).getBounds() ); + + out.writeBoolean( ((Node)node).getPickable() ); + out.writeBoolean( ((Node)node).getCollidable() ); + out.writeBoolean( ((Node)node).getBoundsAutoCompute() ); + + } + + public void readObject( DataInput in ) throws + IOException { + super.readObject(in); + + ((Node)node).setBounds( control.readBounds(in) ); + + ((Node)node).setPickable( in.readBoolean() ); + ((Node)node).setCollidable( in.readBoolean() ); + ((Node)node).setBoundsAutoCompute( in.readBoolean() ); + } + + + +} + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/NullSceneGraphObjectState.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/NullSceneGraphObjectState.java new file mode 100644 index 0000000..b7435e6 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/NullSceneGraphObjectState.java @@ -0,0 +1,105 @@ +/* + * $RCSfile: NullSceneGraphObjectState.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:37 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d; + +import java.io.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Enumeration; +import javax.media.j3d.SceneGraphObject; +import javax.vecmath.Color3f; +import javax.vecmath.Point3d; +import javax.vecmath.Vector4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Tuple4d; +import com.sun.j3d.utils.scenegraph.io.retained.Controller; +import com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData; + +public class NullSceneGraphObjectState extends SceneGraphObjectState { + + SymbolTableData symbolTableData; + + /** + * Dummy class to represent a null object in the scene graph + * + */ + public NullSceneGraphObjectState(SymbolTableData symbol,Controller control) { + super( null, control ); + symbolTableData = new SymbolTableData( -1, null, this, -1 ); + } + + /** + * DO NOT call symbolTable.addReference in writeObject as this (may) + * result in a concurrentModificationException. + * + * All references should be created in the constructor + */ + public void writeObject( DataOutput out ) throws IOException { + } + + public void readObject( DataInput in ) throws IOException { + } + + public SceneGraphObject getNode() { + return null; + } + + public int getNodeID() { + return -1; + } + + public SymbolTableData getSymbol() { + return symbolTableData; + } + + + protected javax.media.j3d.SceneGraphObject createNode() { + return null; + } + + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/OrderedGroupState.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/OrderedGroupState.java new file mode 100644 index 0000000..b46d70d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/io/state/javax/media/j3d/OrderedGroupState.java @@ -0,0 +1,85 @@ +/* + * $RCSfile: OrderedGroupState.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:37 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d; + +import javax.media.j3d.OrderedGroup; +import com.sun.j3d.utils.scenegraph.io.retained.Controller; +import com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData; +import java.io.IOException; +import java.io.DataInput; +import java.io.DataOutput; + +public class OrderedGroupState extends GroupState { + + /** Creates new BranchGroupState */ + public OrderedGroupState(SymbolTableData symbol,Controller control) { + super( symbol, control ); + } + + public void writeObject( DataOutput out ) throws IOException { + super.writeObject( out ); + + int[] childIndexOrder = ((OrderedGroup)node).getChildIndexOrder(); + out.writeInt( childIndexOrder.length ); + for ( int i=0;i2) { + node.setName(readString(in)); + } + + readCapabilities( in ); + } + + public SceneGraphObject getNode() { + return node; + } + + public int getNodeID() { + return symbol.nodeID; + } + + public SymbolTableData getSymbol() { + return symbol; + } + + private void readUserData( DataInput in ) throws IOException { + + node.setUserData( control.readSerializedData( in )); + } + + private void writeUserData( DataOutput out ) throws IOException { + Object obj = node.getUserData(); + if (obj != null && !(obj instanceof java.io.Serializable)) { + System.err.println("UserData is not Serializable and will not be saved"); + obj = null; + } + + control.writeSerializedData( out, (Serializable)obj ); + } + + /* + * NOTE: This implementation assumes a maximum of 64 capability + * bits per node class. If this changes in the future, this + * implementation will need to be updated. + */ + private void writeCapabilities( DataOutput out ) throws IOException { + long capabilities = 0; + long frequentCapabilities = 0; + + for ( int i=0;i<64;i++ ) { + if ( node.getCapability( i ) ) capabilities |= (1L << i); + if ( !(node.getCapabilityIsFrequent( i )) ) frequentCapabilities |= (1L << i); + } + out.writeLong( capabilities ); + out.writeLong( frequentCapabilities ); + } + + private void readCapabilities( DataInput in ) throws IOException { + long capabilities = in.readLong(); + long frequentCapabilities = in.readLong(); + + for ( int i=0;i<64;i++ ) { + if ( (capabilities&(1L<0 ) { + float[] lod = new float[ points ]; + float[] pts = new float[ points ]; + attr.getSharpenTextureFunc( lod, pts ); + for (int i = 0 ; i < points ; i++) { + out.writeFloat( lod[i] ); + out.writeFloat( pts[i] ); + } + } + + points = attr.getFilter4FuncPointsCount(); + out.writeInt( points ); + if ( points>=4 ) { + float[] weights = new float[ points ]; + attr.getFilter4Func( weights ); + for (int i = 0 ; i < points ; i++) { + out.writeFloat( weights[i] ); + } + } + } + + public void readObject( DataInput in ) throws IOException { + super.readObject( in ); + Texture attr = (Texture)node; + attr.setBoundaryColor( control.readColor4f( in )); + attr.setBoundaryModeS( in.readInt() ); + attr.setBoundaryModeT( in.readInt() ); + attr.setEnable( in.readBoolean() ); + + imageComponents = new int[ in.readInt() ]; + for(int i=0; i0 ) { + float[] lod = new float[ points ]; + float[] pts = new float[ points ]; + for (int i = 0 ; i < points ; i++) { + lod[i] = in.readFloat(); + pts[i] = in.readFloat(); + } + attr.setSharpenTextureFunc( lod, pts ); + } + + points = in.readInt(); + if ( points >= 4 ) { + float[] weights = new float[ points ]; + for (int i = 0 ; i < points ; i++) { + weights[i] = in.readFloat(); + } + attr.setFilter4Func( weights ); + } + } + + public void addSubReference() { + if ( !(node instanceof TextureCubeMap) ) { + for( int i=0; i comparators = new WeakHashMap(); + + /** + * Set the comparator for the specified view. + * + * The comparators compare method will be called with 2 objects of type + * TransparencySortGeom and it's result should indicate which object is + * closer to the viewer. Object1 < Object2 if it is to be considered closer + * and rendered after. + * + * @param view the view to which the comparator applies + * @param comparator the comparator to call + */ + public static void setComparator(View view, Comparator comparator) { + comparators.put(view, comparator); + } + + /** + * Returns the comparator for the specified view + * + * @return the comparator for the specified view, or null if there + * is no comparator for the view or the view is unknown. + */ + public static Comparator getComparator(View view) { + return comparators.get(view); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/transparency/TransparencySortGeom.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/transparency/TransparencySortGeom.java new file mode 100644 index 0000000..2e2312b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/transparency/TransparencySortGeom.java @@ -0,0 +1,90 @@ +/* + * $RCSfile: TransparencySortGeom.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:42 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.scenegraph.transparency; +import javax.media.j3d.Geometry; +import javax.media.j3d.Shape3D; +import javax.media.j3d.Transform3D; + +/** + * + * The interface of the objects that should be compared to determine + * rendering order of transparent objects. + * + * The Comparator supplied by the user in TransparencySortController will + * be called with 2 objects that implement this interface. + * + * @since Java 3D 1.4 + */ +public interface TransparencySortGeom { + + /** + * Returns the Geometry for this object. + * + * @return geometry for this object + */ + public Geometry getGeometry(); + + /** + * Returns the distance squared of this object to the viewer. + * + * @return distancesquared to viewer + */ + public double getDistanceSquared(); + + /** + * Returns the LocalToVWorld transform for this object + * + * @param localToVW variable in which transform will be returned + */ + public void getLocalToVWorld(Transform3D localToVW); + + /** + * Returns the Shape3D being rendered using this geometry. + * + * @return the Shape3D being rendered using this geometry + */ + public Shape3D getShape3D(); + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/transparency/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/transparency/package.html new file mode 100644 index 0000000..710fa54 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/scenegraph/transparency/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.scenegraph.transparency + + +

Provides transparency sorting utility classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/shader/StringIO.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/shader/StringIO.java new file mode 100644 index 0000000..054274e --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/shader/StringIO.java @@ -0,0 +1,158 @@ +/* + * $RCSfile: StringIO.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:42 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.shader; + +import java.io.IOException; +import java.io.File; +import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; + +/** + * Utility class with static methods to read the entire contents of a + * file, URL, InputStream, or Reader into a single String that is + * returned to the user. + * + * @since Java 3D 1.4 + */ +public class StringIO { + /** + * Read the entire contents of the specified file and return a + * single String object containing the contents of the file. + * + * @param fileName the name of the file from which to read + * + * @return a String containing the contents of the input file + * + * @throws IOException if the specified file cannot be opened, or + * if an I/O error occurs while reading the file + */ + public static String readFully(String fileName) throws IOException { + return readFully(new File(fileName)); + } + + /** + * Read the entire contents of the specified file and return a + * single String object containing the contents of the file. + * This method does not return until the end of the input file + * is reached. + * + * @param file a File from which to read + * + * @return a String containing the contents of the input file + * + * @throws IOException if the specified file cannot be opened, or + * if an I/O error occurs while reading the file + */ + public static String readFully(File file) throws IOException { + return readFully(new FileReader(file)); + } + + /** + * Read the entire contents of the specified URL and return a + * single String object containing the contents of the URL. + * This method does not return until an end of stream is reached + * for the URL. + * + * @param url a URL from which to read + * + * @return a String containing the contents of the input URL + * + * @throws IOException if the specified URL cannot be opened, or + * if an I/O error occurs while reading the URL + */ + public static String readFully(URL url) throws IOException { + return readFully(url.openStream()); + } + + /** + * Read the entire contents of the specified InputStream and return a + * single String object containing the contents of the InputStream. + * This method does not return until the end of the input + * stream is reached. + * + * @param stream an InputStream from which to read + * + * @return a String containing the contents of the input stream + * + * @throws IOException if an I/O error occurs while reading the input stream + */ + public static String readFully(InputStream stream) throws IOException { + return readFully(new InputStreamReader(stream)); + } + + /** + * Read the entire contents of the specified Reader and return a + * single String object containing the contents of the InputStream. + * This method does not return until the end of the input file or + * stream is reached. + * + * @param reader a Reader from which to read + * + * @return a String containing the contents of the stream + * + * @throws IOException if an I/O error occurs while reading the input stream + */ + public static String readFully(Reader reader) throws IOException { + char[] arr = new char[8*1024]; // 8K at a time + StringBuffer buf = new StringBuffer(); + int numChars; + + while ((numChars = reader.read(arr, 0, arr.length)) > 0) { + buf.append(arr, 0, numChars); + } + + return buf.toString(); + } + + + /** + * Do not construct an instance of this class. + */ + private StringIO() { + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/shader/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/shader/package.html new file mode 100644 index 0000000..b5102d9 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/shader/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.shader + + +

Provides shader utility classes.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/timer/J3DTimer.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/timer/J3DTimer.java new file mode 100644 index 0000000..7d5cdd5 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/timer/J3DTimer.java @@ -0,0 +1,88 @@ +/* + * $RCSfile: J3DTimer.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:43 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.timer; + +/** + * A High Resolution interval timer. The timer resolution is + * operating system dependent and can be queried using + * getTimerResolution(). + * + * These methods are not reentrant and should not + * be called concurrently from multiple threads. + * + * @deprecated Use java.lang.System.nanoTime() instead. + */ +public class J3DTimer { + + // Since we can't get the resolution from the JDK, we will hard-code it + // at 1000 (microsecond resolution). + private static final long resolution = 1000L; + + /** + * Private constructor because users should + * not construct instances of this class + */ + private J3DTimer() { + } + + /** + * Get the timer value, in nanoseconds. + * The initial value of the timer is OS dependent. + * + * @return The current timer value in nanoseconds. + */ + public static long getValue() { + return System.nanoTime(); + } + + /** + * Get the nanosecond resolution of the timer + * + * @return The timer resolution in nanoseconds. + */ + public static long getResolution() { + return resolution; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/timer/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/timer/package.html new file mode 100644 index 0000000..b842c0a --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/timer/package.html @@ -0,0 +1,11 @@ + + + + + com.sun.j3d.utils.timer + + +

Deprecated: Use java.lang.System.nanoTime() instead.

+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigCommand.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigCommand.java new file mode 100644 index 0000000..7402332 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigCommand.java @@ -0,0 +1,417 @@ +/* + * $RCSfile: ConfigCommand.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:43 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.text.DecimalFormat ; +import java.text.FieldPosition ; +import java.util.Collection ; +import javax.vecmath.Matrix3d ; +import javax.vecmath.Matrix4d ; + +/** + * Contains the elements which compose a configuration file command, + * including the command name, type, and arguments. + */ +class ConfigCommand { + /** + * Specifies that this command creates a new ConfigObject. + */ + static final int CREATE = 0 ; + + /** + * Specifies that this command sets an attribute for a class known + * to ConfiguredUniverse. As of Java 3D 1.3.1, these commands are + * handled the same as property commands (see PROPERTY below) and + * this constant is no longer used. + */ + static final int ATTRIBUTE = 1 ; + + /** + * Specifies that this command sets a Java system property or a + * property for a class unknown to ConfiguredUniverse. Properties + * for such a class are set by using the reflection API to invoke a + * method whose name is specified in the command's argument list. + * Such a method must accept an array of Object as its sole + * parameter, where that array contains all the command elements + * which appear after the method name.

+ * + * As of Java 3D 1.3.1, this is handled the same as an attribute. + * The individual setProperty() method implementations of + * ConfigObject determine whether the method to set the property can + * be invoked directly or through introspection. If through + * introspection, then the evaluation of the property must be + * delayed until the target object is instantiated. + */ + static final int PROPERTY = 2 ; + + /** + * Specifies that this command creates an alias for a ConfigObject of the + * same base name. + */ + static final int ALIAS = 3 ; + + /** + * Specifies that this command is a deferred built-in command that can't + * be immediately evaluated by the parser. Its evaluation is delayed + * until all config objects are instantiated and their properties can be + * evaluated. + */ + static final int BUILTIN = 4 ; + + /** + * Specifies that this command is an include file directive. + */ + static final int INCLUDE = 5 ; + + /** + * Specifes that this command is entirely processed by the + * constructor and should be ignored by subsequent recipients. + */ + static final int IGNORE = 6 ; + + /** + * The type of this command, either CREATE, PROPERTY, ALIAS, + * BUILTIN, INCLUDE, or IGNORE. + */ + int type = -1 ; + + /** + * The number of arguments in this command, including the command + * name. + */ + int argc = 0 ; + + /** + * An array containing all of this command's arguments, including + * the command name. + */ + Object[] argv = null ; + + /** + * The name of the command being invoked, which is always the first + * argument of the command. + */ + String commandName = null ; + + /** + * The base name of this command, from which the name of the ConfigObject + * subclass that processes it is derived. This is constructed by + * stripping off the leading "New" prefix or the trailing "Attribute", + * "Property", or "Alias" suffix of the command name. The name of the + * ConfigObject subclass which handles the command is derived by adding + * "Config" as a prefix to the base name. + */ + String baseName = null ; + + /** + * The instance name of the ConfigObject subclass which processes this + * command. Together with the base name this provides the handle by which + * a ConfigObject can be referenced by other commands in the configuration + * file. + */ + String instanceName = null ; + + /** + * The file from which this command was read. + */ + String fileName = null ; + + /** + * The line number from which this command was read. + */ + int lineNumber = 0 ; + + /** + * Constructs a ConfigCommand from configuration file command arguments. + * + * @param elements arguments to this command, including the command name + * @param fileName name of the file from where the command was read + * @param lineNumber line number where the command is found in the file + */ + ConfigCommand(Collection elements, String fileName, int lineNumber) { + this.fileName = fileName ; + this.lineNumber = lineNumber ; + + argc = elements.size() ; + argv = elements.toArray(new Object[0]) ; + + if (! (argc > 0 && (argv[0] instanceof String))) + throw new IllegalArgumentException("malformed command") ; + + commandName = (String)argv[0] ; + + if (commandName.startsWith("New")) { + type = CREATE ; + baseName = commandName.substring(3) ; + instanceName = checkName(argv[1]) ; + } + else if (commandName.endsWith("Property")) { + baseName = commandName.substring(0, commandName.length()-8) ; + if (baseName.equals("Java")) { + type = IGNORE ; + processJavaProperty(argc, argv) ; + } + else { + type = PROPERTY ; + instanceName = checkName(argv[1]) ; + } + } + else if (commandName.endsWith("Attribute")) { + // Backward compatibility. + type = PROPERTY ; + baseName = commandName.substring(0, commandName.length()-9) ; + instanceName = checkName(argv[1]) ; + } + else if (commandName.endsWith("Alias")) { + type = ALIAS ; + baseName = commandName.substring(0, commandName.length()-5) ; + instanceName = checkName(argv[1]) ; + } + else if (commandName.equals("Include")) { + type = INCLUDE ; + } + else { + type = BUILTIN ; + } + + // We allow "Window" as an equivalent to "Screen". + if (baseName != null && baseName.equals("Window")) + baseName = "Screen" ; + } + + /** + * Sets the Java property specified in the command. If the command + * has 3 arguments then it's an unconditional assignment. If the + * 3rd argument is "Default", then the property is set to the value + * of the 4th argument only if the specified property has no + * existing value. + * + * @param argc the number of arguments in the command + * @param argv command arguments as an array of Objects; the 1st is + * the command name (ignored), the 2nd is the name of the Java + * property, the 3rd is the value to be set or the keyword + * "Default", and the 4th is thevalue to be set if the Java + * property doesn't already exist + */ + private static void processJavaProperty(int argc, Object[] argv) { + for (int i = 1 ; i < argc ; i++) { + // Check args. + if (argv[i] instanceof Boolean) { + argv[i] = ((Boolean)argv[i]).toString() ; + } + else if (! (argv[i] instanceof String)) { + throw new IllegalArgumentException + ("JavaProperty arguments must be Strings or Booleans") ; + } + } + if (argc == 3) { + // Unconditional assignment. + setJavaProperty((String)argv[1], (String)argv[2]) ; + } + else if (argc != 4) { + // Conditional assignment must have 4 args. + throw new IllegalArgumentException + ("JavaProperty must have either 2 or 3 arguments") ; + } + else if (! ((String)argv[2]).equals("Default")) { + // Penultimate arg must be "Default" keyword. + throw new IllegalArgumentException + ("JavaProperty 2nd argument must be \"Default\"") ; + } + else if (evaluateJavaProperty((String)argv[1]) == null) { + // Assignment only if no existing value. + setJavaProperty((String)argv[1], (String)argv[3]) ; + } + } + + /** + * Sets the given Java system property if allowed by the security manager. + * + * @param key property name + * @param value property value + * @return previous property value if any + */ + static String setJavaProperty(final String key, final String value) { + return (String)java.security.AccessController.doPrivileged + (new java.security.PrivilegedAction() { + public Object run() { + return System.setProperty(key, value) ; + } + }) ; + } + + /** + * Evaluates the specified Java property string if allowed by the security + * manager. + * + * @param key string containing a Java property name + * @return string containing the Java property valaue + */ + static String evaluateJavaProperty(final String key) { + return (String)java.security.AccessController.doPrivileged + (new java.security.PrivilegedAction() { + public Object run() { + return System.getProperty(key) ; + } + }) ; + } + + /** + * Checks if the given object is an instance of String. + * + * @param o the object to be checked + * @return the object cast to a String + * @exception IllegalArgumentException if the object is not a String + */ + private final String checkName(Object o) { + if (! (o instanceof String)) + throw new IllegalArgumentException + ("second argument to \"" + commandName + "\" must be a name") ; + + return (String)o ; + } + + /** + * Calls formatMatrixRows(3, 3, m), where m is a + * an array of doubles retrieved from the given Matrix3d. + * + * @param m3 matrix to be formatted + * @return matrix rows formatted into strings + */ + static String[] formatMatrixRows(Matrix3d m3) { + double[] m = new double[9] ; + m[0] = m3.m00 ; m[1] = m3.m01 ; m[2] = m3.m02 ; + m[3] = m3.m10 ; m[4] = m3.m11 ; m[5] = m3.m12 ; + m[6] = m3.m20 ; m[7] = m3.m21 ; m[8] = m3.m22 ; + + return formatMatrixRows(3, 3, m) ; + } + + /** + * Calls formatMatrixRows(4, 4, m), where m is a + * an array of doubles retrieved from the given Matrix4d. + * + * @param m4 matrix to be formatted + * @return matrix rows formatted into strings + */ + static String[] formatMatrixRows(Matrix4d m4) { + double[] m = new double[16] ; + m[0] = m4.m00 ; m[1] = m4.m01 ; m[2] = m4.m02 ; m[3] = m4.m03 ; + m[4] = m4.m10 ; m[5] = m4.m11 ; m[6] = m4.m12 ; m[7] = m4.m13 ; + m[8] = m4.m20 ; m[9] = m4.m21 ; m[10] = m4.m22 ; m[11] = m4.m23 ; + m[12] = m4.m30 ; m[13] = m4.m31 ; m[14] = m4.m32 ; m[15] = m4.m33 ; + + return formatMatrixRows(4, 4, m) ; + } + + /** + * Formats a matrix with fixed fractional digits and integer padding to + * align the decimal points in columns. Non-negative numbers print up to + * 7 integer digits, while negative numbers print up to 6 integer digits + * to account for the negative sign. 6 fractional digits are printed. + * + * @param rowCount number of rows in the matrix + * @param colCount number of columns in the matrix + * @param m matrix to be formatted + * @return matrix rows formatted into strings + */ + static String[] formatMatrixRows(int rowCount, int colCount, double[] m) { + DecimalFormat df = new DecimalFormat("0.000000") ; + FieldPosition fp = new FieldPosition(DecimalFormat.INTEGER_FIELD) ; + StringBuffer sb0 = new StringBuffer() ; + StringBuffer sb1 = new StringBuffer() ; + String[] rows = new String[rowCount] ; + + for (int i = 0 ; i < rowCount ; i++) { + sb0.setLength(0) ; + for (int j = 0 ; j < colCount ; j++) { + sb1.setLength(0) ; + df.format(m[i*colCount+j], sb1, fp) ; + int pad = 8 - fp.getEndIndex() ; + for (int k = 0 ; k < pad ; k++) { + sb1.insert(0, " ") ; + } + sb0.append(sb1) ; + } + rows[i] = sb0.toString() ; + } + return rows ; + } + + /** + * Returns the String representation of this command. + * + * @return string representing this command + */ + public String toString() { + String[] lines = null ; + StringBuffer sb = new StringBuffer("(") ; + + for (int i = 0 ; i < argc ; i++) { + if (argv[i] instanceof Matrix3d) { + lines = formatMatrixRows((Matrix3d)argv[i]) ; + sb.append("\n ((" + lines[0] + ")\n") ; + sb.append(" (" + lines[1] + ")\n") ; + sb.append(" (" + lines[2] + "))") ; + if (i != (argc - 1)) sb.append("\n") ; + } + else if (argv[i] instanceof Matrix4d) { + lines = formatMatrixRows((Matrix4d)argv[i]) ; + sb.append("\n ((" + lines[0] + ")\n") ; + sb.append(" (" + lines[1] + ")\n") ; + sb.append(" (" + lines[2] + ")\n") ; + sb.append(" (" + lines[3] + "))") ; + if (i != (argc - 1)) sb.append("\n") ; + } + else { + if (i > 0) sb.append(" ") ; + sb.append(argv[i].toString()) ; + } + } + + sb.append(")") ; + return sb.toString() ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigContainer.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigContainer.java new file mode 100644 index 0000000..091d4ec --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigContainer.java @@ -0,0 +1,1529 @@ +/* + * $RCSfile: ConfigContainer.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/02/09 17:20:43 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.io.* ; +import java.util.* ; +import java.net.URL ; +import java.net.MalformedURLException ; +import javax.media.j3d.* ; +import com.sun.j3d.utils.behaviors.vp.ViewPlatformBehavior ; + +/** + * Loads a Java 3D configuration file and creates a container of named objects + * that will effect the viewing configuration specified in the file. These + * can include Viewers, ViewingPlatforms, ViewPlatformBehaviors, InputDevices, + * Sensors, and other objects.

+ * + * Clients can construct the view side of a scene graph by retrieving these + * objects using the accessor methods provided by this class. This could + * involve as little as just attaching ViewingPlatforms to a Locale, depending + * upon how completely the viewing configuration is specified in the file. + * The ConfiguredUniverse class is an example of a ConfigContainer client and + * how it can be used.

+ * + * ConfigContainer can be useful for clients other than ConfiguredUniverse. + * InputDevice and ViewPlatformBehavior configuration is fully supported, so a + * given Java 3D installation can provide configuration files to an + * application that will allow it to fully utilize whatever site-specific + * devices and behaviors are available. The configuration mechanism can be + * extended for any target object through the use of the + * NewObject and ObjectProperty configuration + * commands. + * + * @see ConfiguredUniverse + * @see + * The Java 3D Configuration File + * @see + * Example Configuration Files + * + * @since Java 3D 1.3.1 + */ +public class ConfigContainer { + // + // The configuration object database is implemented with a HashMap which + // maps their class names to ArrayList objects which contain the actual + // instances. The latter are used since the instances of a given class + // must be evaluated in the order in which they were created. + // LinkedHashMap is available in JDK 1.4 but currently this code must run + // under JDK 1.3.1 as well. + // + private Map baseNameMap = new HashMap() ; + + // Map containing named canvases for each view. + private Map viewCanvasMap = new HashMap() ; + + // Read-only Maps for the public interface to the configuration database. + private ReadOnlyMap bodyMap = null ; + private ReadOnlyMap environmentMap = null ; + private ReadOnlyMap viewerMap = null ; + private ReadOnlyMap deviceMap = null ; + private ReadOnlyMap sensorMap = null ; + private ReadOnlyMap behaviorMap = null ; + private ReadOnlyMap platformMap = null ; + private ReadOnlyMap genericObjectMap = null ; + + // Read-only Sets for the public interface to the configuration database. + private ReadOnlySet bodies = null ; + private ReadOnlySet environments = null ; + private ReadOnlySet viewers = null ; + private ReadOnlySet devices = null ; + private ReadOnlySet sensors = null ; + private ReadOnlySet behaviors = null ; + private ReadOnlySet platforms = null ; + private ReadOnlySet genericObjects = null ; + + // The number of TransformGroups to include in ViewingPlatforms. + private int transformCount = 1 ; + + // The visibility status of Viewer AWT components. + private boolean setVisible = false ; + + private ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + + /** + * The name of the file this ConfigContainer is currently loading. + */ + String currentFileName = null ; + + /** + * Creates a new ConfigContainer and loads the configuration file at the + * specified URL. All ViewingPlatform instances are created with a single + * TransformGroup and all Viewer components are initially invisible. + * + * @param userConfig URL of the configuration file to load + */ + public ConfigContainer(URL userConfig) { + this(userConfig, false, 1, true) ; + } + + /** + * Creates a new ConfigContainer and loads the configuration file at the + * specified URL. All ViewingPlatform instances are created with a single + * TransformGroup and all Viewer components are initially invisible. + * + * @param userConfig URL of the configuration file to load + * @param classLoader the class loader to use to load classes specified + * in the config file. + */ + public ConfigContainer(URL userConfig, ClassLoader classLoader) { + this(userConfig, false, 1, true, classLoader) ; + } + + /** + * Creates a new ConfigContainer and loads the configuration file at the + * specified URL. Any ViewingPlatform instantiated by the configuration + * file will be created with the specified number of transforms. Viewer + * components may be set initially visible or invisible with the + * setVisible flag. + * + * @param userConfig URL of the configuration file to load + * @param setVisible if true, setVisible(true) is called on + * all Viewers + * @param transformCount number of transforms to be included in any + * ViewingPlatform created; must be greater than 0 + */ + public ConfigContainer(URL userConfig, + boolean setVisible, int transformCount) { + + this(userConfig, setVisible, transformCount, true) ; + } + + /** + * Creates a new ConfigContainer and loads the configuration file at the + * specified URL. Any ViewingPlatform instantiated by the configuration + * file will be created with the specified number of transforms. Viewer + * components may be set initially visible or invisible with the + * setVisible flag. + * + * @param userConfig URL of the configuration file to load + * @param setVisible if true, setVisible(true) is called on + * all Viewers + * @param transformCount number of transforms to be included in any + * ViewingPlatform created; must be greater than 0 + * @param classLoader the class loader to use to load classes specified + * in the config file. + */ + public ConfigContainer(URL userConfig, + boolean setVisible, int transformCount, + ClassLoader classLoader) { + + this(userConfig, setVisible, transformCount, true, classLoader) ; + } + + /** + * Package-scoped constructor for ConfigContainer. This provides an + * additional flag, attachBehaviors, which indicates whether + * or not ViewPlatformBehaviors should be attached to the ViewingPlatforms + * specified for them.

+ * + * Normally the flag should be true. However, when instantiated by + * ConfiguredUniverse, this flag is set false so that ConfiguredUniverse + * can set a reference to itself in the ViewingPlatform before attaching + * the behavior. This provides backwards compatibility to behaviors that + * access the ConfiguredUniverse instance from a call to + * setViewingPlatform in order to look up the actual Sensor, + * Viewer, Behavior, etc., instances associated with the names provided + * them from the configuration file.

+ * + * The preferred methods to retrieve instances of specific objects defined + * in the configuration file are to either 1) get the ConfiguredUniverse + * instance when the behavior's initialize method is called, + * or to 2) define properties that accept object instances directly, and + * then use the newer Device, Sensor, ViewPlatform, etc., built-in + * commands in the configuration file. These built-ins will return an + * object instance from a name. + * + * @param userConfig URL of the configuration file to load + * @param setVisible if true, setVisible(true) is called on + * all Viewers + * @param transformCount number of transforms to be included in any + * ViewingPlatform created; must be greater than 0 + * @param attachBehaviors if true, attach ViewPlatformBehaviors to the + * appropriate ViewingPlatforms + */ + ConfigContainer(URL userConfig, boolean setVisible, + int transformCount, boolean attachBehaviors) { + + if (transformCount < 1) + throw new IllegalArgumentException + ("transformCount must be greater than 0") ; + + loadConfig(userConfig) ; + processConfig(setVisible, transformCount, attachBehaviors) ; + } + + /** + * Package scoped constructor that adds the ability to set the ClassLoader + * which will be used to load any app specific classes specified in the + * configuration file. By default SystemClassLoader is used. + */ + ConfigContainer(URL userConfig, boolean setVisible, + int transformCount, boolean attachBehaviors, + ClassLoader classLoader) { + this(userConfig, setVisible, transformCount, attachBehaviors); + this.classLoader = classLoader; + } + + /** + * Open, parse, and load the contents of a configuration file. + * + * @param userConfig location of the configuration file + */ + private void loadConfig(URL userConfig) { + InputStream inputStream = null ; + StreamTokenizer streamTokenizer = null ; + String lastFileName = currentFileName ; + + currentFileName = userConfig.toString() ; + try { + inputStream = userConfig.openStream() ; + Reader r = new BufferedReader(new InputStreamReader(inputStream)) ; + streamTokenizer = new StreamTokenizer(r) ; + } + catch (IOException e) { + throw new IllegalArgumentException( + e + "\nUnable to open " + currentFileName) ; + } + + // + // Set up syntax tables for the tokenizer. + // + // It would be nice to allow '/' as a word constituent for URL strings + // and Unix paths, but then the scanner won't ignore "//" and "/* */" + // comment style syntax. Treating '/' as an ordinary character will + // allow comments to work, but then '/' becomes a single token which + // has to be concatenated with subsequent tokens to reconstruct the + // original word string. + // + // It is cleaner to just require quoting for forward slashes. '/' + // should still be treated as an ordinary character however, so that a + // non-quoted URL string or Unix path will be treated as a syntax + // error instead of a comment. + // + streamTokenizer.ordinaryChar('/') ; + streamTokenizer.wordChars('_', '_') ; + streamTokenizer.wordChars('$', '$') ; // for ${...} Java property + streamTokenizer.wordChars('{', '}') ; // substitution in word tokens + streamTokenizer.slashSlashComments(true) ; + streamTokenizer.slashStarComments(true) ; + + // Create an s-expression parser to use for all top-level (0) commands. + ConfigSexpression sexp = new ConfigSexpression() ; + + // Loop through all top-level commands. Boolean.FALSE is returned + // after the last one is evaluated. + while (sexp.parseAndEval(this, streamTokenizer, 0) != Boolean.FALSE) ; + + // Close the input stream. + try { + inputStream.close() ; + } + catch (IOException e) { + throw new IllegalArgumentException( + e + "\nUnable to close " + currentFileName) ; + } + + // Restore current file name. + currentFileName = lastFileName ; + } + + /** + * This method gets called from the s-expression parser to process a + * configuration command. + * + * @param elements tokenized list of sexp elements + * @param lineNumber command line number + */ + void evaluateCommand(ArrayList elements, int lineNumber) { + ConfigObject co ; + ConfigCommand cmd ; + + // Create a command object. + cmd = new ConfigCommand(elements, currentFileName, lineNumber) ; + + // Process the command according to its type. + switch (cmd.type) { + case ConfigCommand.CREATE: + co = createConfigObject(cmd) ; + addConfigObject(co) ; + break ; + case ConfigCommand.ALIAS: + co = createConfigAlias(cmd) ; + addConfigObject(co) ; + break ; + case ConfigCommand.PROPERTY: + co = findConfigObject(cmd.baseName, cmd.instanceName) ; + co.setProperty(cmd) ; + break ; + case ConfigCommand.INCLUDE: + if (! (cmd.argv[1] instanceof String)) { + throw new IllegalArgumentException + ("Include file must be a URL string") ; + } + URL url = null ; + String urlString = (String)cmd.argv[1] ; + try { + url = new URL(urlString) ; + } + catch (MalformedURLException e) { + throw new IllegalArgumentException(e.toString()) ; + } + loadConfig(url) ; + break ; + case ConfigCommand.IGNORE: + break ; + default: + throw new IllegalArgumentException + ("Unknown command \"" + cmd.commandName + "\"") ; + } + } + + /** + * Instantiates and initializes an object that extends the ConfigObject + * base class. The class name of the object is derived from the + * command, which is of the following form:

+ * + * (New{baseName} {instanceName} ... [Alias {aliasName}])

+ * + * The first two command elements and the optional trailing Alias syntax + * are processed here, at which point the subclass implementation of + * initialize() is called. Subclasses must override initialize() if they + * need to process more than what is processed by default here. + * + * @param cmd configuration command that creates a new ConfigObject + */ + private ConfigObject createConfigObject(ConfigCommand cmd) { + Class objectClass = null ; + ConfigObject configObject = null ; + + // Instantatiate the ConfigObject if possible. This is not the target + // object, but an object that will gather configuration properties, + // instantiate the target object, and then apply the configuration + // properties to it. + try { + objectClass = Class.forName("com.sun.j3d.utils.universe.Config" + + cmd.baseName) ; + } + catch (ClassNotFoundException e) { + throw new IllegalArgumentException + ("\"" + cmd.baseName + "\"" + + " is not a configurable object; ignoring command") ; + } + try { + configObject = (ConfigObject)(objectClass.newInstance()) ; + } + catch (IllegalAccessException e) { + System.out.println(e) ; + throw new IllegalArgumentException("Ignoring command") ; + } + catch (InstantiationException e) { + System.out.println(e) ; + throw new IllegalArgumentException("Ignoring command") ; + } + + // Process an Alias keyword if present. This option is available for + // all New commands so it is processed here. The Alias keyword must + // be the penultimate command element, followed by a String. + for (int i = 2 ; i < cmd.argc ; i++) { + if (cmd.argv[i] instanceof String && + ((String)cmd.argv[i]).equals("Alias")) { + if (i == (cmd.argc - 2) && cmd.argv[i+1] instanceof String) { + addConfigObject(new ConfigAlias(cmd.baseName, + (String)cmd.argv[i+1], + configObject)) ; + cmd.argc -= 2 ; + } + else { + throw new IllegalArgumentException + ("The alias name must be a string and " + + "must be the last command argument") ; + } + } + } + + // Initialize common fields. + configObject.baseName = cmd.baseName ; + configObject.instanceName = cmd.instanceName ; + configObject.creatingCommand = cmd ; + configObject.configContainer = this ; + + // Initialize specific fields and return the ConfigObject. + configObject.setClassLoader(classLoader); + configObject.initialize(cmd) ; + return configObject ; + } + + /** + * Instantiate and initialize a ConfigObject base class containing alias + * information. The command is of the form:

+ * + * ({baseName}Alias {aliasName} {originalName}) + * + * @param cmd configuration command that creates a new alias + * @return the new ConfigObject with alias information + */ + private ConfigObject createConfigAlias(ConfigCommand cmd) { + ConfigObject original ; + + if (cmd.argc != 3 || ! (cmd.argv[2] instanceof String)) + throw new IllegalArgumentException + ("Command \"" + cmd.commandName + + "\" requires an instance name as second argument") ; + + original = findConfigObject(cmd.baseName, (String)cmd.argv[2]) ; + return new ConfigAlias(cmd.baseName, cmd.instanceName, original) ; + } + + /** + * A class that does nothing but reference another ConfigObject. Once + * created, the alias name can be used in all commands that would accept + * the original name. A lookup of the alias name will always return the + * original instance. + */ + private static class ConfigAlias extends ConfigObject { + ConfigAlias(String baseName, String instanceName, ConfigObject targ) { + this.baseName = baseName ; + this.instanceName = instanceName ; + this.isAlias = true ; + this.original = targ ; + targ.aliases.add(instanceName) ; + } + } + + /** + * Adds the specified ConfigObject instance into this container using the + * given ConfigCommand's base name and instance name. + * + * @param object the ConfigObject instance to add into the database + */ + private void addConfigObject(ConfigObject object) { + ArrayList instances ; + + instances = (ArrayList)baseNameMap.get(object.baseName) ; + if (instances == null) { + instances = new ArrayList() ; + baseNameMap.put(object.baseName, instances) ; + } + + // Disallow duplicate instance names. + for (int i = 0 ; i < instances.size() ; i++) { + ConfigObject co = (ConfigObject)instances.get(i) ; + if (co.instanceName.equals(object.instanceName)) { + // Don't confuse anybody using Window. + String base = object.baseName ; + if (base.equals("Screen")) base = "Screen or Window" ; + throw new IllegalArgumentException + ("Duplicate " + base + " instance name \"" + + object.instanceName + "\" ignored") ; + } + } + + instances.add(object) ; + } + + /** + * Finds a config object matching the given base name and the instance + * name. If an alias is found, then its original is returned. If the + * object is not found, an IllegalArgumentException is thrown.

+ * + * @param basename base name of the config object + * @param instanceName name associated with this config object instance + * @return the found ConfigObject + */ + ConfigObject findConfigObject(String baseName, String instanceName) { + ArrayList instances ; + ConfigObject configObject ; + + instances = (ArrayList)baseNameMap.get(baseName) ; + if (instances != null) { + for (int i = 0 ; i < instances.size() ; i++) { + configObject = (ConfigObject)instances.get(i) ; + + if (configObject.instanceName.equals(instanceName)) { + if (configObject.isAlias) + return configObject.original ; + else + return configObject ; + } + } + } + + // Throw an error, but don't confuse anybody using Window. + if (baseName.equals("Screen")) baseName = "Screen or Window" ; + throw new IllegalArgumentException + (baseName + " \"" + instanceName + "\" not found") ; + } + + /** + * Find instances of config objects with the given base name. + * This is the same as findConfigObjects(baseName, true). + * Aliases are filtered out so that all returned instances are unique. + * + * @param baseName base name of desired config object class + * @return ArrayList of config object instances of the desired base + * class, or null if instances of the base class don't exist + */ + Collection findConfigObjects(String baseName) { + return findConfigObjects(baseName, true) ; + } + + + /** + * Find instances of config objects with the given base name. + * + * @param baseName base name of desired config object class + * @param filterAlias if true, aliases are filtered out so that all + * returned instances are unique + * @return ArrayList of config object instances of the desired base + * class, or null if instances of the base class don't exist + */ + Collection findConfigObjects(String baseName, boolean filterAlias) { + ArrayList instances ; + + instances = (ArrayList)baseNameMap.get(baseName) ; + if (instances == null || instances.size() == 0) { + return null ; // This is not an error. + } + + if (filterAlias) { + ArrayList output = new ArrayList() ; + for (int i = 0 ; i < instances.size() ; i++) { + ConfigObject configObject = (ConfigObject)instances.get(i) ; + + if (! configObject.isAlias) { + output.add(configObject) ; + } + } + return output ; + } + else { + return instances ; + } + } + + /** + * Returns the ConfigObject associated with the name in the given + * ConfigCommand. This is used for evaluating retained built-in commands + * after the config file has already been parsed. The parser won't catch + * any of the exceptions generated by this method, so the error messages + * are wrapped accordingly. + * + * @param basename base name of the config object + * @param cmd command containing the name in argv[1] + * @return the found ConfigObject + */ + private ConfigObject findConfigObject(String baseName, ConfigCommand cmd) { + if (cmd.argc != 2 || !(cmd.argv[1] instanceof String)) + throw new IllegalArgumentException + (ConfigObject.errorMessage + (cmd, "Parameter must be a single string")) ; + try { + return findConfigObject(baseName, (String)cmd.argv[1]) ; + } + catch (IllegalArgumentException e) { + throw new IllegalArgumentException + (ConfigObject.errorMessage(cmd, e.getMessage())) ; + } + } + + /** + * This method gets called from a ConfigObject to evaluate a retained + * built-in command nested within a property command. These are commands + * that can't be evaluated until the entire config file is parsed. + * + * @param cmd the built-in command + * @return object representing result of evaluation + */ + Object evaluateBuiltIn(ConfigCommand cmd) { + int argc = cmd.argc ; + Object[] argv = cmd.argv ; + + if (cmd.commandName.equals("ConfigContainer")) { + // return a reference to this ConfigContainer + return this ; + } + else if (cmd.commandName.equals("Canvas3D")) { + // Look for canvases in the screen database. + return ((ConfigScreen)findConfigObject("Screen", cmd)).j3dCanvas ; + } + else if (baseNameMap.get(cmd.commandName) != null) { + // Handle commands of the form ({objectType} name) that return the + // object associated with the name. + return findConfigObject(cmd.commandName, cmd).targetObject ; + } + else { + // So far no other retained built-in commands. + throw new IllegalArgumentException + (ConfigObject.errorMessage(cmd, "Unknown built-in command \"" + + cmd.commandName + "\"")) ; + } + } + + /** + * Process the configuration after parsing the configuration file. + * Note: the processing order of the various config objects is + * significant. + * + * @param setVisible true if Viewer components should be visible + * @param transformCount number of TransformGroups with which + * ViewingPlatforms should be created + * @param attachBehaviors true if behaviors should be attached to + * ViewingPlatforms + */ + private void processConfig(boolean setVisible, + int transformCount, boolean attachBehaviors) { + + Collection c, s, pe, vp ; + this.setVisible = setVisible ; + this.transformCount = transformCount ; + + c = findConfigObjects("PhysicalBody") ; + if (c != null) { + processPhysicalBodies(c) ; + } + + pe = findConfigObjects("PhysicalEnvironment") ; + if (pe != null) { + processPhysicalEnvironments(pe) ; + } + + c = findConfigObjects("View") ; + if (c != null) { + processViews(c, setVisible) ; + } + + c = findConfigObjects("Device") ; + s = findConfigObjects("Sensor") ; + if (c != null) { + processDevices(c, s, pe) ; + } + + vp = findConfigObjects("ViewPlatform") ; + if (vp != null) { + processViewPlatforms(vp, transformCount) ; + } + + c = findConfigObjects("ViewPlatformBehavior") ; + if (c != null) { + processViewPlatformBehaviors(c, vp, attachBehaviors) ; + } + + c = findConfigObjects("Object") ; + if (c != null) { + processGenericObjects(c) ; + } + } + + // Process config physical environments into Java 3D physical + // environments. + private void processPhysicalEnvironments(Collection c) { + Iterator i = c.iterator() ; + while (i.hasNext()) { + ConfigPhysicalEnvironment e = (ConfigPhysicalEnvironment)i.next() ; + e.targetObject = e.createJ3dPhysicalEnvironment() ; + } + } + + // Process config physical bodys into Java 3D physical bodies. + private void processPhysicalBodies(Collection c) { + Iterator i = c.iterator() ; + while (i.hasNext()) { + ConfigPhysicalBody b = (ConfigPhysicalBody)i.next() ; + b.targetObject = b.createJ3dPhysicalBody() ; + } + } + + // Process config views into Java 3D Views and then create Viewer objects + // for them. This should only be called after all physical bodies and + // physical environments have been processed. + private void processViews(Collection c, boolean setVisible) { + Iterator i = c.iterator() ; + while (i.hasNext()) { + ConfigView v = (ConfigView)i.next() ; + v.targetObject = v.createViewer(setVisible) ; + } + } + + // Process config devices into Java 3D input devices. This should be done + // only after all views have been processed, as some InputDevice + // implementations require the AWT components associated with a view. + private void processDevices(Collection c, Collection s, Collection p) { + ConfigDevice cd = null ; + Iterator i = c.iterator() ; + while (i.hasNext()) { + cd = (ConfigDevice)i.next() ; + cd.targetObject = cd.createInputDevice() ; + } + + // Process device properties only after all InputDevices have been + // instantiated. Some InputDevice properties require references + // to other InputDevice implementations. + i = c.iterator() ; + while (i.hasNext()) ((ConfigDevice)i.next()).processProperties() ; + + // Initialize the devices only after all have been instantiated, as + // some InputDevices implementations are slaved to the first one + // created and will not initialize otherwise (e.g. LogitechTracker). + i = c.iterator() ; + while (i.hasNext()) { + cd = (ConfigDevice)i.next() ; + if (! cd.j3dInputDevice.initialize()) + throw new RuntimeException + (cd.errorMessage(cd.creatingCommand, + "could not initialize device \"" + + cd.instanceName + "\"")) ; + } + + // An InputDevice implementation will have created all its Sensors by + // the time initialize() returns. Retrieve and configure them here. + if (s != null) { + i = s.iterator() ; + while (i.hasNext()) { + ConfigSensor cs = (ConfigSensor)i.next() ; + cs.configureSensor() ; + cs.targetObject = cs.j3dSensor ; + } + } + + // Iterate through the PhysicalEnvironments and process the devices. + if (p != null) { + i = p.iterator() ; + while (i.hasNext()) + ((ConfigPhysicalEnvironment)i.next()).processDevices() ; + } + } + + // Process config view platforms into Java 3D viewing platforms. + private void processViewPlatforms(Collection c, int numTransforms) { + Iterator i = c.iterator() ; + while (i.hasNext()) { + ConfigViewPlatform cvp = (ConfigViewPlatform)i.next() ; + cvp.targetObject = cvp.createViewingPlatform(numTransforms) ; + } + } + + // Process the configured view platform behaviors. + private void processViewPlatformBehaviors(Collection behaviors, + Collection viewPlatforms, + boolean attach) { + Iterator i = behaviors.iterator() ; + while (i.hasNext()) { + ConfigViewPlatformBehavior b = + (ConfigViewPlatformBehavior)i.next() ; + b.targetObject = b.createViewPlatformBehavior() ; + } + + // Process properties only after all behaviors are instantiated. + i = behaviors.iterator() ; + while (i.hasNext()) + ((ConfigViewPlatformBehavior)i.next()).processProperties() ; + + // Attach behaviors to platforms after properties processed. + if (attach && viewPlatforms != null) { + i = viewPlatforms.iterator() ; + while (i.hasNext()) + ((ConfigViewPlatform)i.next()).processBehavior() ; + } + } + + // Process generic objects. + private void processGenericObjects(Collection objects) { + Iterator i = objects.iterator() ; + while (i.hasNext()) { + ConfigObject o = (ConfigObject)i.next() ; + o.targetObject = o.createTargetObject() ; + } + + // Process properties only after all target objects are instantiated. + i = objects.iterator() ; + while (i.hasNext()) ((ConfigObject)i.next()).processProperties() ; + } + + // Returns a read-only Set containing all unique Java 3D objects of the + // specified base class. + private ReadOnlySet createSet(String baseName) { + Collection c = findConfigObjects(baseName, true) ; + if (c == null || c.size() == 0) + return null ; + + Iterator i = c.iterator() ; + ArrayList l = new ArrayList() ; + while (i.hasNext()) l.add(((ConfigObject)i.next()).targetObject) ; + + return new ReadOnlySet(l) ; + } + + // Returns a read-only Map that maps all names in the specified base + // class, including aliases, to their corresponding Java 3D objects. + private ReadOnlyMap createMap(String baseName) { + Collection c = findConfigObjects(baseName, false) ; + if (c == null || c.size() == 0) + return null ; + + Iterator i = c.iterator() ; + HashMap m = new HashMap() ; + while (i.hasNext()) { + ConfigObject co = (ConfigObject)i.next() ; + if (co.isAlias) + m.put(co.instanceName, co.original.targetObject) ; + else + m.put(co.instanceName, co.targetObject) ; + } + + return new ReadOnlyMap(m) ; + } + + /** + * Returns a read-only Set of all configured PhysicalBody instances in the + * order they were defined in the configuration file. + * + * PhysicalBody instances are created with the following command:

+ *

+ * (NewPhysicalBody <instance name> + * [Alias <alias name>]) + *
+ * + * The PhysicalBody is configured through the following command:

+ *

+ * (PhysicalBodyProperty <instance name> + * <property name> <property value>) + *
+ * + * @return read-only Set of all unique instances, or null + */ + public Set getPhysicalBodies() { + if (bodies != null) return bodies ; + bodies = createSet("PhysicalBody") ; + return bodies ; + } + + /** + * Returns a read-only Map that maps PhysicalBody names to instances. + * Names may be aliases and if so will map to the original instances. + * + * @return read-only Map from names to PhysicalBody instances, or null if + * no instances + */ + public Map getNamedPhysicalBodies() { + if (bodyMap != null) return bodyMap ; + bodyMap = createMap("PhysicalBody") ; + return bodyMap ; + } + + /** + * Returns a read-only Set of all configured PhysicalEnvironment instances + * in the order they were defined in the configuration file.

+ * + * PhysicalEnvironment instances are created with the following command:

+ *

+ * (NewPhysicalEnvironment <instance name> + * [Alias <alias name>]) + *
+ * + * The PhysicalEnvironment is configured through the following command:

+ *

+ * (PhysicalEnvironmentProperty <instance name> + * <property name> <property value>) + *
+ * + * @return read-only Set of all unique instances, or null + */ + public Set getPhysicalEnvironments() { + if (environments != null) return environments ; + environments = createSet("PhysicalEnvironment") ; + return environments ; + } + + /** + * Returns a read-only Map that maps PhysicalEnvironment names to + * instances. Names may be aliases and if so will map to the original + * instances. + * + * @return read-only Map from names to PhysicalEnvironment instances, or + * null if no instances + */ + public Map getNamedPhysicalEnvironments() { + if (environmentMap != null) return environmentMap ; + environmentMap = createMap("PhysicalEnvironment") ; + return environmentMap ; + } + + /** + * Returns a read-only Set of all configured Viewer instances in the order + * they were defined in the configuration file. The Viewers will have + * incorporated any PhysicalEnvironment and PhysicalBody objects specfied + * for them in the configuration file, and will be attached to any + * ViewingPlatforms specified for them.

+ * + * Viewer instances are created with the following command:

+ *

+ * (NewView <instance name> [Alias <alias name>]) + *
+ * + * The Viewer is configured through the following command:

+ *

+ * (ViewProperty <instance name> + * <property name> <property value>) + *
+ * + * @return read-only Set of all unique instances, or null + */ + public Set getViewers() { + if (viewers != null) return viewers ; + viewers = createSet("View") ; + return viewers ; + } + + /** + * Returns a read-only Map that maps Viewer names to instances. + * Names may be aliases and if so will map to the original instances. + * The Viewers will have incorporated any PhysicalEnvironment and + * PhysicalBody objects specfied for them in the configuration file, and + * will be attached to any ViewingPlatforms specified for them.

+ * + * @return read-only Map from names to Viewer instances, or + * null if no instances + */ + public Map getNamedViewers() { + if (viewerMap != null) return viewerMap ; + viewerMap = createMap("View") ; + return viewerMap ; + } + + /** + * Returns a read-only Set of all configured InputDevice instances in the + * order they were defined in the configuration file. All InputDevice + * instances in the set are initialized and registered with any + * PhysicalEnvironments that reference them.

+ * + * InputDevice instances are created with the following command:

+ *

+ * (NewDevice <instanceName> <className> + * [Alias <alias name>]) + *
+ * + * className must be the fully-qualified name of a class that + * implements the InputDevice interface. The implementation + * must provide a parameterless constructor.

+ * + * The InputDevice is configured through the DeviceProperty command:

+ *

+ * (DeviceProperty <instanceName> <propertyName> + * <arg0> ... <argn>) + *
+ * + * propertyName must be the name of a input device method that + * takes an array of Objects as its only parameter; the array is populated + * with the values of arg0 through argn when the method is + * invoked to set the property. These additional requirements for + * configurable input devices can usually be fulfilled by extending or + * wrapping available InputDevice implementations. + * + * @return read-only Set of all unique instances, or null + */ + public Set getInputDevices() { + if (devices != null) return devices ; + devices = createSet("Device") ; + return devices ; + } + + /** + * Returns a read-only Map that maps InputDevice names to instances. + * Names may be aliases and if so will map to the original instances. All + * InputDevice instances in the map are initialized and registered with + * any PhysicalEnvironments that reference them. + * + * @return read-only Map from names to InputDevice instances, or + * null if no instances + * @see #getInputDevices + */ + public Map getNamedInputDevices() { + if (deviceMap != null) return deviceMap ; + deviceMap = createMap("Device") ; + return deviceMap ; + } + + /** + * Returns a read-only Set of all configured Sensor instances in the order + * they were defined in the configuration file. The associated + * InputDevices are all initialized and registered with any + * PhysicalEnvironments that reference them.

+ * + * Sensor instances are named with the following command:

+ *

+ * (NewSensor <instance name> <device name> + * <sensor index> [Alias <alias name>]) + *
+ * + * device name is the instance name of a previously defined + * InputDevice, and sensor index is the index of the Sensor to be + * bound to instance name. The InputDevice implementation is + * responsible for creating its own Sensor objects, so this command does + * not create any new instances.

+ * + * The Sensor is configured through the SensorProperty command:

+ *

+ * (SensorProperty <instance name> <property name> + * <property value>) + *
+ * + * With the sole exception of the Sensor assigned to the head tracker, + * none of the Sensors defined in the configuration file are placed into + * the Sensor array maintained by a PhysicalEnvironment. + * + * @return read-only Set of all unique instances, or null + */ + public Set getSensors() { + if (sensors != null) return sensors ; + sensors = createSet("Sensor") ; + return sensors ; + } + + /** + * Returns a read-only Map that maps Sensor names to instances. Names may + * be aliases and if so will map to the original instances. The + * associated InputDevices are all initialized and registered with any + * PhysicalEnvironments that reference them.

+ * + * With the sole exception of the Sensor assigned to the head tracker, + * none of the Sensors defined in the configuration file are placed into + * the Sensor array maintained by a PhysicalEnvironment. + * + * @return read-only Map from names to Sensor instances, or + * null if no instances + */ + public Map getNamedSensors() { + if (sensorMap != null) return sensorMap ; + sensorMap = createMap("Sensor") ; + return sensorMap ; + } + + /** + * Returns a read-only Set of all configured ViewingPlatform instances in + * the order they were defined in the configuration file. The + * ConfigContainer class itself does not attach the ViewingPlatform + * instances to any scengraph components or universe Locales; they are not + * "live" until made so by a separate client such as ConfiguredUniverse. + * + * ViewingPlatform instances are created with the following command:

+ *

+ * (NewViewPlatform <instance name> + * [Alias <alias name>]) + *
+ * + * The ViewingPlatform is configured through the following command:

+ *

+ * (ViewPlatformProperty <instance name> <property name> + * <property value>) + *
+ * + * @return read-only Set of all unique instances, or null + */ + public Set getViewingPlatforms() { + if (platforms != null) return platforms ; + platforms = createSet("ViewPlatform") ; + return platforms ; + } + + /** + * Returns a read-only Map that maps ViewingPlatform names to instances. + * Names may be aliases and if so will map to the original instances. The + * ConfigContainer class itself does not attach the ViewingPlatform + * instances to any scengraph components or universe Locales; they are not + * "live" until made so by a separate client such as ConfiguredUniverse. + * + * @return read-only Map from names to ViewingPlatform instances, or + * null if no instances + */ + public Map getNamedViewingPlatforms() { + if (platformMap != null) return platformMap ; + platformMap = createMap("ViewPlatform") ; + return platformMap ; + } + + /** + * Returns a read-only Set of all configured ViewPlatformBehavior + * instances in the order they were defined in the configuration file.

+ * + * The behaviors are attached to any ViewingPlatforms that specified them; + * that is, the setViewPlatformBehavior and + * setViewingPlatform methods of ViewingPlatform and + * ViewPlatformBehavior have been called if appropriate. However, a + * behavior's initialize method is not called until the + * ViewingPlatform to which it is attached is made live.

+ * + * ViewPlatformBehavior instances are created by the following command:

+ *

+ * (NewViewPlatformBehavior <instanceName> <className>) + *
+ * + * className must be the fully qualified name of a concrete class + * that extends the abstract ViewPlatformBehavior class. The + * implementation must provide a parameterless constructor.

+ * + * The behavior is configured using ViewPlatformBehaviorProperty:

+ *

+ * (ViewPlatformBehaviorProperty <instanceName> + * <propertyName> <arg0> ... <argn>) + *
+ * + * ViewPlatformBehavior subclasses inherit a number of pre-defined + * properties that can be directly specified with the propertyName + * string; see the configuration file documentation for details.

+ * + * Concrete ViewPlatformBehavior instances can also define their own + * unique properties. In those cases, propertyName must be the + * name of a behavior method that takes an array of Objects as its only + * parameter; the array is populated with the values of arg0 + * through argn when the method is invoked to set the property. + * These additional requirements for configurable behaviors can usually be + * fulfilled by extending or wrapping available ViewPlatformBehavior + * subclasses. + * + * @return read-only Set of all unique instances, or null + */ + public Set getViewPlatformBehaviors() { + if (behaviors != null) return behaviors ; + behaviors = createSet("ViewPlatformBehavior") ; + return behaviors ; + } + + /** + * Returns a read-only Map that maps ViewPlatformBehavior names to + * instances. Names may be aliases and if so will map to the original + * instances.

+ * + * The behaviors are attached to any ViewingPlatforms that specified them; + * that is, the setViewPlatformBehavior and + * setViewingPlatform methods of ViewingPlatform and + * ViewPlatformBehavior have been called if appropriate. However, a + * behavior's initialize method is not called until the + * ViewingPlatform to which it is attached is made live.

+ * + * @return read-only Map from names to ViewPlatformBehavior instances, or + * null if no instances + * @see #getViewPlatformBehaviors + */ + public Map getNamedViewPlatformBehaviors() { + if (behaviorMap != null) return behaviorMap ; + behaviorMap = createMap("ViewPlatformBehavior") ; + return behaviorMap ; + } + + /** + * Returns a read-only Map containing the named Canvas3D instances used by + * the specified Viewer. Names may be aliases and if so will map to the + * original instances. The set of unique Canvas3D instances used by a + * Viewer may be obtained by calling the Viewer's accessor methods + * directly.

+ * + * A named Canvas3D is created and added to a Viewer whenever any of the + * following configuration commands are used:

+ *

+ * (ViewProperty <view> Screen <screenName>)
+ * (ViewProperty <view> Window <windowName>) + *
+ * + * view is the name of a Viewer created with the NewView command. + * The screenName and windowName parameters of the above + * commands are the keys to use when looking up the associated Canvas3D + * instances in the Map returned by this method. Note: the + * NewScreen and NewWindow commands do not create Canvas3D + * instances themselves; they are created only by the above configuration + * commands. + * + * @param viewName the name of the Viewer + * @return read-only Map containing the Viewer's named Canvas3D instances + */ + public Map getNamedCanvases(String viewName) { + Map m = (Map)viewCanvasMap.get(viewName) ; + if (m != null) return m ; + + m = new HashMap() ; + ConfigView cv = (ConfigView)findConfigObject("View", viewName) ; + Iterator i = cv.screens.iterator() ; + while (i.hasNext()) { + ConfigScreen cs = (ConfigScreen)i.next() ; + m.put(cs.instanceName, cs.j3dCanvas) ; + + // The aliases list contains all alias strings for the canvas. + Iterator j = cs.aliases.iterator() ; + while (j.hasNext()) m.put(j.next(), cs.j3dCanvas) ; + } + m = new ReadOnlyMap(m) ; + viewCanvasMap.put(viewName, m) ; + return m ; + } + + /** + * Returns a read-only Set of all generic configuration object + * instances in the order they were defined in the configuration file.

+ * + * Generic object instances are created with the following command:

+ *

+ * (NewObject <instanceName> <className>) + *
+ * + * className must be the fully-qualified name of a class that + * provides a parameterless constructor.

+ * + * The object is configured through the ObjectProperty command:

+ *

+ * (ObjectProperty <instanceName> <propertyName> + * <arg0> ... <argn>) + *
+ * + * propertyName must be the name of a method provided by object + * instanceName. It must take an array of Objects as its only + * parameter; the array is populated with the values of arg0 + * through argn when the method is invoked to set the property. + * These additional requirements for configurable objects can usually be + * fulfilled by extending or wrapping available object classes. + * + * @return read-only Set of all unique instances, or null + */ + public Set getGenericObjects() { + if (genericObjects != null) return genericObjects ; + genericObjects = createSet("Object") ; + return genericObjects ; + } + + /** + * Returns a read-only Map that maps generic object names to + * instances. Names may be aliases and if so will map to the original + * instances. + * + * @return read-only Map from names to generic object instances, or + * null if no instances + * @see #getGenericObjects + */ + public Map getNamedGenericObjects() { + if (genericObjectMap != null) return genericObjectMap ; + genericObjectMap = createMap("Object") ; + return genericObjectMap ; + } + + /** + * Returns the number of TransformGroups with which ViewingPlatforms + * should be created. This is useful for clients that wish to provide a + * default ViewingPlatform if the configuration file doesn't specify one. + * + * @return the number of TransformGroups + */ + public int getViewPlatformTransformCount() { + return transformCount ; + } + + /** + * Returns whether Viewers should be created with their AWT components + * initially visible or invisible. This is useful for clients that wish + * to provide a default Viewer if the configuration file doesn't specify + * one. + * + * @return true if Viewer components should be initially visible; false + * otherwise + */ + public boolean getViewerVisibility() { + return setVisible ; + } + + /** + * Release memory references used by this ConfigContainer. All Sets and + * Maps obtained from this ConfigContainer are cleared. + */ + public void clear() { + // Clear baseNameList. + Iterator i = baseNameMap.values().iterator() ; + while (i.hasNext()) ((Collection)i.next()).clear() ; + baseNameMap.clear() ; + + // Clear viewCanvasMap. + i = viewCanvasMap.values().iterator() ; + while (i.hasNext()) ((ReadOnlyMap)i.next()).map.clear() ; + viewCanvasMap.clear() ; + + // Release reference to file name. + currentFileName = null ; + + // Clear and release sets. + if (bodies != null) { + bodies.collection.clear() ; + bodies = null ; + } + if (environments != null) { + environments.collection.clear() ; + environments = null ; + } + if (devices != null) { + devices.collection.clear() ; + devices = null ; + } + if (sensors != null) { + sensors.collection.clear() ; + sensors = null ; + } + if (behaviors != null) { + behaviors.collection.clear() ; + behaviors = null ; + } + if (platforms != null) { + platforms.collection.clear() ; + platforms = null ; + } + if (viewers != null) { + viewers.collection.clear() ; + viewers = null ; + } + if (genericObjects != null) { + genericObjects.collection.clear() ; + genericObjects = null ; + } + + // Clear and release maps. + if (bodyMap != null) { + bodyMap.map.clear() ; + bodyMap = null ; + } + if (environmentMap != null) { + environmentMap.map.clear() ; + environmentMap = null ; + } + if (deviceMap != null) { + deviceMap.map.clear() ; + deviceMap = null ; + } + if (sensorMap != null) { + sensorMap.map.clear() ; + sensorMap = null ; + } + if (behaviorMap != null) { + behaviorMap.map.clear() ; + behaviorMap = null ; + } + if (platformMap != null) { + platformMap.map.clear() ; + platformMap = null ; + } + if (viewerMap != null) { + viewerMap.map.clear() ; + viewerMap = null ; + } + if (genericObjectMap != null) { + genericObjectMap.map.clear() ; + genericObjectMap = null ; + } + + } + + /** + * Returns the config file URL based on system properties. The current + * implementation of this method parses the j3d.configURL property as a + * URL string. For example, the following command line would specify that + * the config file is taken from the file "j3dconfig" in the current + * directory: + *
    + * java -Dj3d.configURL=file:j3dconfig ... + *
+ * + * @return the URL of the config file; null is returned if no valid + * URL is defined by the system properties + */ + public static URL getConfigURL() { + return getConfigURL(null) ; + } + + /** + * Returns the config file URL based on system properties. The current + * implementation of this method parses the j3d.configURL property as a + * URL string. For example, the following command line would specify that + * the config file is taken from the file "j3dconfig" in the current + * directory: + *
    + * java -Dj3d.configURL=file:j3dconfig ... + *
+ * + * @param defaultURLString the default string used to construct + * the URL if the appropriate system properties are not defined + * @return the URL of the config file; null is returned if no + * valid URL is defined either by the system properties or the + * default URL string + */ + public static URL getConfigURL(String defaultURLString) { + URL url = null ; + String urlString = null ; + final String defProp = defaultURLString ; + + urlString = (String)java.security.AccessController.doPrivileged + (new java.security.PrivilegedAction() { + public Object run() { + return System.getProperty("j3d.configURL", defProp) ; + } + }) ; + + if (urlString == null) { + return null ; + } + try { + url = new URL(urlString) ; + } + catch(MalformedURLException e) { + System.out.println(e) ; + return null ; + } + return url ; + } + + // A general purpose read-only Map backed by a HashMap. + private static class ReadOnlyMap extends AbstractMap { + HashMap map ; + private Set entrySet = null ; + + ReadOnlyMap(Map map) { + this.map = new HashMap(map) ; + } + + // overridden for efficiency + public Object get(Object key) { + return map.get(key) ; + } + + // overridden for efficiency + public boolean containsKey(Object key) { + return map.containsKey(key) ; + } + + // overridden for efficiency + public boolean containsValue(Object value) { + return map.containsValue(value) ; + } + + public Set entrySet() { + if (entrySet == null) + entrySet = new ReadOnlySet(map.entrySet()) ; + + return entrySet ; + } + } + + // A general purpose read-only Set backed by a Collection containing + // unique objects. + private static class ReadOnlySet extends AbstractSet { + Collection collection = null ; + + ReadOnlySet(Collection c) { + this.collection = c ; + } + + public int size() { + return collection.size() ; + } + + public Iterator iterator() { + return new ReadOnlyIterator(collection.iterator()) ; + } + } + + // A general purpose read-only Iterator backed by another Iterator. + private static class ReadOnlyIterator implements Iterator { + private Iterator i ; + + ReadOnlyIterator(Iterator i) { + this.i = i ; + } + + public boolean hasNext() { + return i.hasNext() ; + } + + public Object next() { + return i.next() ; + } + + public void remove() { + throw new UnsupportedOperationException() ; + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigDevice.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigDevice.java new file mode 100644 index 0000000..6446107 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigDevice.java @@ -0,0 +1,66 @@ +/* + * $RCSfile: ConfigDevice.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:43 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; +import javax.media.j3d.InputDevice ; + +/** + * Mostly empty now; ConfigObject provides all required methods. + */ +class ConfigDevice extends ConfigObject { + /** + * The corresponding Java 3D core InputDevice instance. + */ + InputDevice j3dInputDevice ; + + /** + * Instantiate an InputDevice of the given class name. + * + * @return the InputDevice, or null if error + */ + InputDevice createInputDevice() { + j3dInputDevice = (InputDevice)createTargetObject() ; + return j3dInputDevice ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigObject.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigObject.java new file mode 100644 index 0000000..54ac261 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigObject.java @@ -0,0 +1,385 @@ +/* + * $RCSfile: ConfigObject.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/02/09 17:20:43 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.lang.reflect.* ; +import java.util.List ; +import java.util.ArrayList ; + +/** + * Base class for all configuration objects. A ConfigObject processes + * configuration parameters for a target object, which is instantiated after + * the configuration file is parsed. The ConfigObject then applies its + * configuration properties to the target object.

+ * + * Generic base implementations are provided for the initialize(), + * setProperty(), and processProperties() methods. These implementations + * assume target objects that are unknown and thus instantiated via + * introspection. Property names are assumed to be method names that take an + * array of Objects as a parameter; they are invoked through introspection as + * well.

+ * + * Most ConfigObjects target concrete Java 3D core classes, so these + * implementations are usually overridden to instantiate those objects and + * call their methods directly. + */ +class ConfigObject { + /** + * The base name of this object, derived from the configuration command + * which created it. This is constructed by stripping off the leading + * "New" prefix or the trailing "Attribute", "Property", or "Alias" suffix + * of the command name. The name of the ConfigObject subclass which + * handles the command is derived by adding "Config" as a prefix to the + * base name. + */ + String baseName = null ; + + /** + * The instance name of this object, as specified in the configuration + * file. + */ + String instanceName = null ; + + /** + * The corresponding target object which this ConfigObject is configuring. + */ + Object targetObject = null ; + + /** + * The name of the target class this object is configuring. + */ + String targetClassName = null ; + + /** + * The Class object for the target. + */ + Class targetClass = null ; + + /** + * Configurable properties gathered by this object, represented by the + * ConfigCommands that set them. + */ + List properties = new ArrayList() ; + + /** + * The ConfigContainer in which this ConfigObject is contained. + */ + ConfigContainer configContainer = null ; + + /** + * The command that created this class. + */ + ConfigCommand creatingCommand = null ; + + /** + * If true, this object is an alias to another. + */ + boolean isAlias = false ; + + /** + * If isAlias is true, this references the original object. + */ + ConfigObject original = null ; + + /** + * List of alias Strings for this object if it's not an alias itself. + */ + List aliases = new ArrayList() ; + + protected ClassLoader classLoader; + + /** + * @param classLoader the ClassLoader to use when loading the implementation + * class for this object + */ + void setClassLoader( ClassLoader classLoader ) { + this.classLoader = classLoader; + } + + /** + * The base initialize() implementation. This takes a ConfigCommand with + * three arguments: the command name, the instance name, and the name of + * the target class this ConfigObject is configuring. The command in the + * configuration file should have the form:

+ * + * (New{configType} {instanceName} {className})

+ * + * For example, (NewDevice tracker com.sun.j3d.input.LogitechTracker) will + * first cause ConfigDevice to be instantiated, which will then be + * initialized with this method. After all the properties are collected, + * ConfigDevice will instantiate com.sun.j3d.input.LogitechTracker, + * evaluate its properties, and allow references to it in the + * configuration file by the name "tracker".

+ * + * It's assumed the target class will be instantiated through + * introspection and its properties set through introspection as well. + * Most config objects (ConfigScreen, ConfigView, ConfigViewPlatform, + * ConfigPhysicalBody, and ConfigPhysicalEnvironment) target a concrete + * core Java 3D class and will instantiate them directly, so they override + * this method. + * + * @param c the command that created this ConfigObject + */ + protected void initialize(ConfigCommand c) { + if (c.argc != 3) { + syntaxError("Wrong number of arguments to " + c.commandName) ; + } + + if (!isName(c.argv[1])) { + syntaxError("The first argument to " + c.commandName + + " must be the instance name") ; + } + + if (!isName(c.argv[2])) { + syntaxError("The second argument to " + c.commandName + + " must be the class name") ; + } + + targetClassName = (String)c.argv[2] ; + } + + /** + * The base setProperty() implementation. This implementation assumes the + * property needs to be set by introspection on the property name as a + * method that accepts an array of Objects. That is, the command in the + * configuration file is of the form:

+ * + * ({type}Property {instance name} {method name} {arg0} ... {argn})

+ * + * For example, (DeviceProperty tracker SerialPort "/dev/ttya") will + * invoke the method named "SerialPort" in the object referenced by + * "tracker" with an array of 1 Object containing the String + * "/dev/ttya".

+ * + * The property is stored as the original ConfigCommand and is evaluated + * after the configuration file has been parsed. It is overridden by + * subclasses that instantiate concrete core Java 3D classes with known + * method names. + * + * @param c the command that invoked this method + */ + protected void setProperty(ConfigCommand c) { + if (c.argc < 4) { + syntaxError("Wrong number of arguments to " + c.commandName) ; + } + + if (!isName(c.argv[1])) { + syntaxError("The first argument to " + c.commandName + + " must be the instance name") ; + } + + if (!isName(c.argv[2])) { + syntaxError("The second argument to " + c.commandName + + " must be the property name") ; + } + + properties.add(c) ; + } + + /** + * Instantiates the target object. + */ + protected Object createTargetObject() { + if (targetClassName == null) + return null ; + + targetClass = getClassForName(creatingCommand, targetClassName) ; + targetObject = getNewInstance(creatingCommand, targetClass) ; + + return targetObject ; + } + + /** + * Return the class for the specified class name string. + * + * @param className the name of the class + * @return the object representing the class + */ + protected Class getClassForName(ConfigCommand cmd, String className) { + try { + // Use the system class loader. If the Java 3D jar files are + // installed directly in the JVM's lib/ext directory, then the + // default class loader won't find user classes outside ext. + // + // From 1.3.2 we use the classLoader supplied to this object, + // normally this will be the system class loader, but for webstart + // apps the user can supply another class loader. + return Class.forName(className, true, + classLoader) ; + } + catch (ClassNotFoundException e) { + throw new IllegalArgumentException + (errorMessage(cmd, "Class \"" + className + "\" not found")) ; + } + } + + /** + * Return an instance of the class specified by the given class object. + * + * @param objectClass the object representing the class + * @return a new instance of the class + */ + protected Object getNewInstance(ConfigCommand cmd, Class objectClass) { + try { + return objectClass.newInstance() ; + } + catch (IllegalAccessException e) { + throw new IllegalArgumentException + (errorMessage(cmd, "Illegal access to object class")) ; + } + catch (InstantiationException e) { + throw new IllegalArgumentException + (errorMessage(cmd, "Instantiation error for object class")) ; + } + } + + /** + * Evaluate properties for the the given class instance. The property + * names are used as the names of methods to be invoked by the instance. + * Each such method takes an array of Objects as its only parameter. The + * array will contain Objects corresponding to the property values. + */ + protected void processProperties() { + evaluateProperties(this.targetClass, + this.targetObject, this.properties) ; + + // Potentially holds a lot of references, and not needed anymore. + this.properties.clear() ; + } + + /** + * Evaluate properties for the the given class instance. + * + * @param objectClass the class object representing the given class + * @param objectInstance the class instance whose methods will be invoked + * @param properties list of property setting commands + */ + protected void evaluateProperties(Class objectClass, + Object objectInstance, + List properties) { + + // Holds the single parameter passed to the class instance methods. + Object[] parameters = new Object[1] ; + + // Specifies the class of the single method parameter. + Class[] parameterTypes = new Class[1] ; + + // All property methods use Object[] as their single parameter, which + // happens to be the same type as the parameters variable above. + parameterTypes[0] = parameters.getClass() ; + + // Loop through all property commands and invoke the appropriate + // method for each one. Property commands are of the form: + // ({configClass}Property {instanceName} {methodName} {arg} ...) + for (int i = 0 ; i < properties.size() ; i++) { + ConfigCommand cmd = (ConfigCommand)properties.get(i) ; + String methodName = (String)cmd.argv[2] ; + Object[] argv = new Object[cmd.argc - 3] ; + + for (int a = 0 ; a < argv.length ; a++) { + argv[a] = cmd.argv[a + 3] ; + if (argv[a] instanceof ConfigCommand) { + // Evaluate a delayed built-in command. + ConfigCommand bcmd = (ConfigCommand)argv[a] ; + argv[a] = configContainer.evaluateBuiltIn(bcmd) ; + } + } + + parameters[0] = argv ; + + try { + Method objectMethod = + objectClass.getMethod(methodName, parameterTypes) ; + + objectMethod.invoke(objectInstance, parameters) ; + } + catch (NoSuchMethodException e) { + throw new IllegalArgumentException + (errorMessage + (cmd, "Unknown property \"" + methodName + "\"")) ; + } + catch (IllegalAccessException e) { + throw new IllegalArgumentException + (errorMessage + (cmd, "Illegal access to \"" + methodName + "\"")) ; + } + catch (InvocationTargetException e) { + throw new IllegalArgumentException + (errorMessage(cmd, e.getTargetException().getMessage())) ; + } + } + } + + /** + * Throws an IllegalArgumentException with the specified description. + * This is caught by the parser which prints out error diagnostics and + * continues parsing if it can. + * + * @param s string describing the syntax error + */ + protected void syntaxError(String s) { + throw new IllegalArgumentException(s) ; + } + + /** + * Constructs an error message from the given string and file information + * from the given command. + */ + static String errorMessage(ConfigCommand cmd, String s) { + return + s + "\nat line " + cmd.lineNumber + + " in " + cmd.fileName + "\n" + cmd; + } + + /** + * Check if the argument is a name string. + * + * @param o the object to be checked + * @return true if the object is an instance of String + */ + protected boolean isName(Object o) { + return (o instanceof String) ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalBody.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalBody.java new file mode 100644 index 0000000..4e4fd10 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalBody.java @@ -0,0 +1,178 @@ +/* + * $RCSfile: ConfigPhysicalBody.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:43 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import java.awt.event.*; +import java.lang.Integer; +import java.io.*; +import javax.media.j3d.*; +import javax.vecmath.*; +import java.util.*; + +class ConfigPhysicalBody extends ConfigObject { + + Point3d leftEyePosition = new Point3d(-0.033, 0.0, 0.0); + Point3d rightEyePosition = new Point3d(0.033, 0.0, 0.0); + double stereoEyeSeparation = Double.MAX_VALUE; + + Point3d leftEarPosition = new Point3d(-0.080, -0.030, 0.09); + Point3d rightEarPosition = new Point3d(0.080, -0.030, 0.09); + + double nominalEyeHeightFromGround = 1.68; + double nominalEyeOffsetFromNominalScreen = 0.4572; + + Matrix4d headToHeadTracker = new Matrix4d( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0); + + PhysicalBody j3dPhysicalBody; + + // Overridden to do nothing. + protected void initialize(ConfigCommand command) { + } + + protected void setProperty(ConfigCommand command) { + int argc = command.argc; + Object[] argv = command.argv; + String prop; + Object val; + + // Check that arg[1] and arg[2] are strings + if (argc != 4) { + syntaxError("Incorrect number of arguments to " + + command.commandName); + } + + if (!isName(argv[1])) { + syntaxError("The first argument to " + command.commandName + + " must be a name"); + } + + if (!isName(argv[2])) { + syntaxError("The second argument to " + command.commandName + + " must be an property/attribute name"); + } + + prop = (String) argv[2]; + val = argv[3]; + + if (prop.equals("StereoEyeSeparation")) { + if (!(val instanceof Double)) { + syntaxError("StereoEyeSeparation must be a number"); + } + stereoEyeSeparation = ((Double) val).doubleValue(); + } + else if (prop.equals("LeftEyePosition")) { + if (!(val instanceof Point3d)) { + syntaxError("LeftEyePosition must be a point"); + } + leftEyePosition = (Point3d) val; + } + else if (prop.equals("RightEyePosition")) { + if (!(val instanceof Point3d)) { + syntaxError("RightEyePosition must be a point"); + } + rightEyePosition = (Point3d) val; + } + else if (prop.equals("LeftEarPosition")) { + if (!(val instanceof Point3d)) { + syntaxError("LeftEarPosition must be a point"); + } + leftEarPosition = (Point3d) val; + } + else if (prop.equals("RightEarPosition")) { + if (!(val instanceof Point3d)) { + syntaxError("RightEarPosition must be a point"); + } + leftEarPosition = (Point3d) val; + } + else if (prop.equals("NominalEyeHeightFromGround")) { + if (!(val instanceof Double)) { + syntaxError("NominalEyeHeightFromGround must be a number"); + } + nominalEyeHeightFromGround = ((Double) val).doubleValue(); + } + else if (prop.equals("NominalEyeOffsetFromNominalScreen")) { + if (!(val instanceof Double)) { + syntaxError("NominalEyeOffsetFromNominalScreen " + + "must be a number"); + } + nominalEyeOffsetFromNominalScreen = ((Double) val).doubleValue(); + } + else if (prop.equals("HeadToHeadTracker")) { + if (!(val instanceof Matrix4d)) { + syntaxError("HeadToHeadTracker must be a matrix"); + } + headToHeadTracker = (Matrix4d) val; + } + else { + syntaxError("Unknown " + command.commandName + + " \"" + prop + "\"") ; + } + } + + PhysicalBody createJ3dPhysicalBody() { + // Transfer all the information from the config version + if (stereoEyeSeparation < Double.MAX_VALUE) { + leftEyePosition.set(-stereoEyeSeparation / 2.0, 0.0, 0.0); + rightEyePosition.set(stereoEyeSeparation / 2.0, 0.0, 0.0); + } + + j3dPhysicalBody = new PhysicalBody(leftEyePosition, rightEyePosition, + leftEarPosition, rightEarPosition); + + j3dPhysicalBody.setHeadToHeadTracker( + new Transform3D(headToHeadTracker)); + + j3dPhysicalBody.setNominalEyeHeightFromGround( + nominalEyeHeightFromGround); + j3dPhysicalBody.setNominalEyeOffsetFromNominalScreen( + nominalEyeOffsetFromNominalScreen); + + return j3dPhysicalBody ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalEnvironment.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalEnvironment.java new file mode 100644 index 0000000..0a8cad1 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalEnvironment.java @@ -0,0 +1,179 @@ +/* + * $RCSfile: ConfigPhysicalEnvironment.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:43 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import javax.media.j3d.* ; +import javax.vecmath.* ; +import java.util.* ; + +class ConfigPhysicalEnvironment extends ConfigObject { + + /** + * The corresponding J3D core PhysicalEnvironment instance. + */ + PhysicalEnvironment j3dPhysicalEnvironment = null ; + + /** + * The coexistence to tracker base matrix. + */ + Matrix4d coexistenceToTrackerBase = null ; + + // All other configurable attributes. + private ConfigSensor headTracker = null ; + private ArrayList inputDevices = new ArrayList() ; + private int coexistenceCenterInPworldPolicy = View.NOMINAL_SCREEN ; + + /** + * Overrides initialize() to do nothing. + */ + protected void initialize(ConfigCommand command) { + } + + /** + * Handles the commands + * (PhysicalEnvironmentAttribute {instance} {attrName} {attrValue}) and + * (PhysicalEnvironmentProperty {instance} {attrName} {attrValue}). + * + * @param command the command that invoked this method + */ + protected void setProperty(ConfigCommand command) { + Object val ; + Object[] argv = command.argv ; + int argc = command.argc ; + String sval, prop ; + + if (argc != 4) { + syntaxError("Incorrect number of arguments to " + + command.commandName) ; + } + + if (!isName(argv[1])) { + syntaxError("The first argument to " + command.commandName + + " must be a name") ; + } + + if (!isName(argv[2])) { + syntaxError("The second argument to " + command.commandName + + " must be a property name") ; + } + + prop = (String)argv[2] ; + val = argv[3] ; + + if (prop.equals("CoexistenceCenterInPworldPolicy")) { + if (!(val instanceof String)) + syntaxError("CoexistenceCenterInPworldPolicy must be string") ; + + sval = (String)val ; + if (sval.equals("NOMINAL_HEAD")) + coexistenceCenterInPworldPolicy = View.NOMINAL_HEAD ; + else if (sval.equals("NOMINAL_SCREEN")) + coexistenceCenterInPworldPolicy = View.NOMINAL_SCREEN ; + else if (sval.equals("NOMINAL_FEET")) + coexistenceCenterInPworldPolicy = View.NOMINAL_FEET ; + else + syntaxError("Illegal value " + sval + + " for CoexistenceCenterInPworldPolicy") ; + } + else if (prop.equals("CoexistenceToTrackerBase")) { + if (val instanceof Matrix4d) + coexistenceToTrackerBase = (Matrix4d)val ; + else + syntaxError("CoexistenceToTrackerBase must be a Matrix4d") ; + } + else if (prop.equals("InputDevice")) { + if (!(val instanceof String)) + syntaxError("InputDevice must be a name") ; + + sval = (String)val ; + inputDevices.add(configContainer.findConfigObject("Device", sval)); + } + else if (prop.equals("HeadTracker")) { + if (!(val instanceof String)) + syntaxError("HeadTracker must be a Sensor name") ; + + sval = (String)val ; + headTracker = + (ConfigSensor)configContainer.findConfigObject("Sensor", sval); + } + else { + syntaxError("Unknown " + command.commandName + + " \"" + prop + "\"") ; + } + } + + /** + * Create a core Java 3D PhysicalEnvironment instance using the attributes + * gathered by this object. + */ + PhysicalEnvironment createJ3dPhysicalEnvironment() { + j3dPhysicalEnvironment = new PhysicalEnvironment() ; + + j3dPhysicalEnvironment.setCoexistenceCenterInPworldPolicy + (coexistenceCenterInPworldPolicy) ; + + if (coexistenceToTrackerBase != null) + j3dPhysicalEnvironment.setCoexistenceToTrackerBase + (new Transform3D(coexistenceToTrackerBase)) ; + + return j3dPhysicalEnvironment ; + } + + /** + * Process the devices associated with the PhysicalEnvironment. + */ + void processDevices() { + for (int j = 0; j < inputDevices.size(); j++) { + ConfigDevice configDevice = (ConfigDevice)inputDevices.get(j) ; + InputDevice device = configDevice.j3dInputDevice ; + j3dPhysicalEnvironment.addInputDevice(device) ; + } + + if (headTracker != null) { + j3dPhysicalEnvironment.setHeadIndex(0) ; + j3dPhysicalEnvironment.setSensor(0, headTracker.j3dSensor) ; + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigScreen.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigScreen.java new file mode 100644 index 0000000..b4bd6de --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigScreen.java @@ -0,0 +1,307 @@ +/* + * $RCSfile: ConfigScreen.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.awt.Window ; +import javax.media.j3d.Canvas3D ; +import javax.media.j3d.View ; +import javax.swing.JFrame ; +import javax.swing.JPanel ; +import javax.vecmath.Matrix4d ; +import javax.vecmath.Point2d ; + +class ConfigScreen extends ConfigObject { + + /** + * The index of this screen in the GraphicsDevice array returned by + * GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(). + */ + int frameBufferNumber ; + + /** + * The physical width in meters of the screen area of the GraphicsDevice + * associated with this ConfigScreen. The default is based on a screen + * resolution of 90 pixels/inch. + */ + double physicalScreenWidth = 0.0 ; + + /** + * The physical height in meters of the screen area of the GraphicsDevice + * associated with this ConfigScreen. The default is based on a screen + * resolution of 90 pixels/inch. + */ + double physicalScreenHeight = 0.0 ; + + /** + * The trackerBaseToImagePlate transform of this ConfigScreen. + * The default is the identity transform. + */ + Matrix4d trackerBaseToImagePlate = null ; + + /** + * The headTrackerToLeftImagePlate transform of this ConfigScreen if HMD + * mode is in effect. The default is the identity transform. + */ + Matrix4d headTrackerToLeftImagePlate = null ; + + /** + * The headTrackerToRightImagePlate transform of this ConfigScreen if HMD + * mode is in effect. The default is the identity transform. + */ + Matrix4d headTrackerToRightImagePlate = null ; + + /** + * The monoscopicViewPolicy for this ConfigScreen. The default is + * View.CYCLOPEAN_EYE_VIEW. + */ + int monoscopicViewPolicy = View.CYCLOPEAN_EYE_VIEW ; + + /** + * Boolean indicating whether a full-screen window should be created for + * this ConfigScreen. The default is false. + */ + boolean fullScreen = false ; + + /** + * Boolean indicating whether a full-screen window with no borders should + * be created for this ConfigScreen. The default is false. + */ + boolean noBorderFullScreen = false ; + + /** + * The width in pixels for the window to be created for this ConfigScreen + * if a full screen window is not specified. The default is 512. + */ + int windowWidthInPixels = 512 ; + + /** + * The height in pixels for the window to be created for this ConfigScreen + * if a full screen window is not specified. The default is 512. + */ + int windowHeightInPixels = 512 ; + + /** + * The X pixel position of the top-left corner of the window, relative to + * the physical screen. The default is 0. + */ + int windowX = 0 ; + + /** + * The Y pixel position of the top-left corner of the window, relative to + * the physical screen. The default is 0. + */ + int windowY = 0 ; + + /** + * The JFrame created for this ConfigScreen. When running under JDK 1.4 + * or newer, the JFrame always contains a JPanel which contains the + * Canvas3D. When running under JDK 1.3.1 and using a borderless full + * screen the JFrame will instead contain a JWindow which will contain the + * JPanel and Canvas3D. + */ + JFrame j3dJFrame ; + + /** + * The Window created for this ConfigScreen. Under JDK 1.4 or higher this + * is the same reference as j3dJFrame. If a borderless full screen is + * specified while running under JDK 1.3.1 then this is a JWindow with the + * j3dJFrame as its parent. + */ + Window j3dWindow ; + + /** + * The JPanel created for this ConfigScreen to hold the Canvas3D. + */ + JPanel j3dJPanel ; + + /** + * The Canvas3D created for this ConfigScreen. + */ + Canvas3D j3dCanvas ; + + /** + * Processes attributes for this object. Handles commands of the form:

+ * (ScreenAttribute {instanceName} {attrName} {attrValue}) + * (ScreenProperty {instanceName} {attrName} {attrValue}) + * (DisplayAttribute {instanceName} {attrName} {attrValue}) + * (DisplayProperty {instanceName} {attrName} {attrValue}) + * + * @param command the command that invoked this method + */ + protected void setProperty(ConfigCommand command) { + + String attr = null ; + Object val = null ; + String sval = null ; + + if (command.argc != 4) { + syntaxError("Incorrect number of arguments to " + + command.commandName) ; + } + + if (!isName(command.argv[2])) { + syntaxError("The second argument to " + command.commandName + + " must be a property name") ; + } + + attr = (String)command.argv[2] ; + val = command.argv[3] ; + + if (attr.equals("PhysicalScreenWidth")) { + if (!(val instanceof Double)) { + syntaxError("Value for PhysicalScreenWidth " + + "must be a number") ; + } + physicalScreenWidth = ((Double)val).doubleValue() ; + } + else if (attr.equals("PhysicalScreenHeight")) { + if (!(val instanceof Double)) { + syntaxError("Value for PhysicalScreenHeight " + + "must be a number") ; + } + physicalScreenHeight = ((Double)val).doubleValue() ; + } + else if (attr.equals("TrackerBaseToImagePlate")) { + if (!(val instanceof Matrix4d)) { + syntaxError("Value for TrackerBaseToImagePlate " + + "must be a 4x3 or 4x4 matrix") ; + } + trackerBaseToImagePlate = (Matrix4d)val ; + } + else if (attr.equals("HeadTrackerToLeftImagePlate")) { + if (!(val instanceof Matrix4d)) { + syntaxError("Value for HeadTrackerToLeftImagePlate " + + "must be a 4x3 or 4x4 matrix") ; + } + headTrackerToLeftImagePlate = (Matrix4d)val ; + } + else if (attr.equals("HeadTrackerToRightImagePlate")) { + if (!(val instanceof Matrix4d)) { + syntaxError("Value for HeadTrackerToRightImagePlate " + + "must be a 4x3 or 4x4 matrix") ; + } + headTrackerToRightImagePlate = (Matrix4d)val ; + } + else if (attr.equals("MonoscopicViewPolicy")) { + if (!(val instanceof String)) { + syntaxError("Value for MonoscopicViewPolicy " + + "must be a name") ; + } + sval = (String)val ; + if (sval.equals("LEFT_EYE_VIEW")) + monoscopicViewPolicy = View.LEFT_EYE_VIEW ; + else if (sval.equals("RIGHT_EYE_VIEW")) + monoscopicViewPolicy = View.RIGHT_EYE_VIEW ; + else if (sval.equals("CYCLOPEAN_EYE_VIEW")) + monoscopicViewPolicy = View.CYCLOPEAN_EYE_VIEW ; + else + syntaxError("Invalid value for MonoscopicViewPolicy " + + "\"" + sval + "\"") ; + } + else if (attr.equals("WindowPosition")) { + if (! (val instanceof Point2d)) { + syntaxError("WindowPosition must be a Point2d") ; + } + Point2d p2d = (Point2d)val ; + windowX = (int)p2d.x ; + windowY = (int)p2d.y ; + } + else if (attr.equals("WindowSize")) { + if (val instanceof Point2d) { + fullScreen = false ; + noBorderFullScreen = false ; + + Point2d p2d = (Point2d)val ; + windowWidthInPixels = (int)p2d.x ; + windowHeightInPixels = (int)p2d.y ; + } + else if (val instanceof String) { + String s = (String)val ; + + if (s.equals("FullScreen")) { + fullScreen = true ; + noBorderFullScreen = false ; + } else if (s.equals("NoBorderFullScreen")) { + fullScreen = false ; + noBorderFullScreen = true ; + } else { + syntaxError("Value for WindowSize " + + "must be one of\n" + "\"FullScreen\" " + + "\"NoBorderFullScreen\" or Point2d") ; + } + } + else { + syntaxError("Invalid WindowSize value: " + val + + "\nValue for WindowSize " + + "must be one of\n" + "\"FullScreen\" " + + "\"NoBorderFullScreen\" or Point2d") ; + } + } + else { + syntaxError("Unknown " + command.commandName + + " \"" + attr + "\"") ; + } + } + + /** + * Initializes this object. Handles commands of the form:

+ * (NewScreen {instanceName} {FrameBufferNumber}). + * + * @param command the command that invoked this method + */ + protected void initialize(ConfigCommand command) { + if (command.argc != 3) { + syntaxError("Incorrect number of arguments to " + + command.commandName) ; + } + + if (!(command.argv[2] instanceof Double)) { + syntaxError("The second argument to " + command.commandName + + " must be a GraphicsDevice index") ; + } + + frameBufferNumber = ((Double)command.argv[2]).intValue() ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigSensor.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigSensor.java new file mode 100644 index 0000000..42f61d8 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigSensor.java @@ -0,0 +1,211 @@ +/* + * $RCSfile: ConfigSensor.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import javax.vecmath.Point3d ; +import javax.media.j3d.Sensor ; + +class ConfigSensor extends ConfigObject { + + // The index of this sensor in the associated InputDevice. + private int sensorIndex ; + + // The ConfigDevice which creates the associated InputDevice. + private ConfigDevice configDevice ; + + // All configurable attributes. + private Point3d hotspot = null ; + private int predictor = -1 ; + private int predictionPolicy = -1 ; + private int sensorReadCount = -1 ; + + /** + * The corresponding Java 3D core Sensor instance. This is created by the + * associated InputDevice. + */ + Sensor j3dSensor ; + + /** + * Handles the command + * (NewSensor {instanceName} {inputDeviceName} {indexInInputDevice}) + * + * @param command the command that invoked this method + */ + protected void initialize(ConfigCommand command) { + + int argc = command.argc ; + Object[] argv = command.argv ; + + // Check that arg[1] and arg[2] are strings, arg[3] a number + if (argc != 4) { + syntaxError("Incorrect number of arguments to " + + command.commandName) ; + } + + if (!isName(argv[2])) { + syntaxError("The second argument to " + command.commandName + + " must be the device name") ; + } + + if (!(argv[3] instanceof Double)) { + syntaxError("The third argument to " + command.commandName + + " must be a sensor index") ; + } + + sensorIndex = ((Double)argv[3]).intValue() ; + configDevice = (ConfigDevice)configContainer.findConfigObject + ("Device", (String)argv[2]) ; + } + + /** + * Handles the commands + * (SensorAttribute {instanceName} {attributeName} {attributeValue}) and + * (SensorProperty {instanceName} {attributeName} {attributeValue}). + * + * @param command the command that invoked this method + */ + protected void setProperty(ConfigCommand command) { + + int argc = command.argc ; + Object[] argv = command.argv ; + String attribute ; + + // Check that arg[1] and arg[2] are strings + if (argc != 4) { + syntaxError("Incorrect number of arguments to " + + command.commandName) ; + } + + if (! isName(argv[1])) { + syntaxError("The first argument to " + command.commandName + + " must be the instance name") ; + } + + if (! isName(argv[2])) { + syntaxError("The second argument to " + command.commandName + + " must be a property name") ; + } + + attribute = (String)argv[2] ; + if (attribute.equals("Hotspot")) { + if (! (argv[3] instanceof Point3d)) { + syntaxError("Hotspot must be a 3D point") ; + } + hotspot = (Point3d)argv[3] ; + } + /* + * Questionable attributes. Commented out for now. + else if (attribute.equals("Predictor")) { + if (! isName(argv[3])) { + syntaxError("Predictor must be a name") ; + } + + String predictorName = (String)argv[3] ; + if (predictorName.equals("PREDICT_NONE")) { + predictor = Sensor.PREDICT_NONE ; + } + else if (predictorName.equals("PREDICT_NEXT_FRAME_TIME")) { + predictor = Sensor.PREDICT_NEXT_FRAME_TIME ; + } + else { + syntaxError("Predictor must be either PREDICT_NONE " + + "or PREDICT_NEXT_FRAME_TIME") ; + } + } + else if (attribute.equals("PredictionPolicy")) { + if (! isName(argv[3])) { + syntaxError("PredictionPolicy must be a name") ; + } + + String predictionPolicyName = (String)argv[3] ; + if (predictionPolicyName.equals("NO_PREDICTOR")) { + predictionPolicy = Sensor.NO_PREDICTOR ; + } + else if (predictionPolicyName.equals("HEAD_PREDICTOR")) { + predictionPolicy = Sensor.HEAD_PREDICTOR ; + } + else if (predictionPolicyName.equals("HAND_PREDICTOR")) { + predictionPolicy = Sensor.HAND_PREDICTOR ; + } + else { + syntaxError("PredictionPolicy must be either NO_PREDICTOR, " + + "HEAD_PREDICTOR, or HAND_PREDICTOR") ; + } + } + else if (attribute.equals("SensorReadCount")) { + if (! (argv[3] instanceof Double)) { + syntaxError("SensorReadCount must be a number") ; + } + sensorReadCount = ((Double)argv[3]).intValue() ; + } + */ + else { + syntaxError("Unknown " + command.commandName + + " \"" + attribute + "\"") ; + } + } + + /** + * This method is called after all InputDevice implementations have been + * instantiated and initialized. All the specified attributes for this + * sensor are set in the corresponding Java3D core Sensor instantiated by + * the associated InputDevice. + */ + void configureSensor() { + j3dSensor = configDevice.j3dInputDevice.getSensor(sensorIndex) ; + + if (hotspot != null) + j3dSensor.setHotspot(hotspot) ; + + if (predictor != -1) + j3dSensor.setPredictor(predictor) ; + + if (predictionPolicy != -1) + j3dSensor.setPredictionPolicy(predictionPolicy) ; + + if (sensorReadCount != -1) + j3dSensor.setSensorReadCount(sensorReadCount) ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigSexpression.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigSexpression.java new file mode 100644 index 0000000..667624b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigSexpression.java @@ -0,0 +1,569 @@ +/* + * $RCSfile: ConfigSexpression.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.5 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.awt.event.* ; +import java.io.* ; +import java.lang.Integer ; +import java.lang.Boolean ; +import java.util.* ; +import javax.vecmath.* ; +import javax.media.j3d.* ; + +class ConfigSexpression { + + private ArrayList elements = new ArrayList() ; + + private void syntaxError(StreamTokenizer st, String file, String s) { + System.out.println(s + ":\nat line " + st.lineno() + " in " + file) ; + print() ; System.out.print("\n\n") ; + } + + private int myNextToken(StreamTokenizer st, String file) { + int tok = 0 ; + try { + tok = st.nextToken() ; + } + catch (IOException e) { + throw new RuntimeException(e + "\nwhile reading " + file) ; + } + return tok ; + } + + + Object parseAndEval(ConfigContainer configContainer, + StreamTokenizer st, int level) { + int tok ; + String s ; + String file = configContainer.currentFileName ; + + // + // First tokenize the character stream and add the tokens to the + // elements array. + // + elements.clear() ; + + // Look for an open paren to start this sexp. + while (true) { + tok = myNextToken(st, file) ; + + if (tok == StreamTokenizer.TT_EOF) + return Boolean.FALSE ; + + if (tok == ')') + syntaxError(st, file, "Premature closing parenthesis") ; + + if (tok == '(') + break ; + } + + // Add elements until a close paren for this sexp is found. + for (int i = 0 ; true ; i++) { + tok = myNextToken(st, file) ; + + if (tok == StreamTokenizer.TT_EOF) { + syntaxError(st, file, "Missing closing parenthesis") ; + break ; + } + + // An open paren starts a new embedded sexp. Put the paren back, + // evaluate the sexp, and add the result to the elements list. + if (tok == '(') { + st.pushBack() ; + ConfigSexpression cs = new ConfigSexpression() ; + elements.add(cs.parseAndEval(configContainer, st, level+1)) ; + continue ; + } + + // A close paren finishes the scan. + if (tok == ')') + break ; + + // Check for too many arguments. + if (i >= 20) + syntaxError(st, file, "Too many arguments") ; + + // Check for numeric argument. + if (tok == StreamTokenizer.TT_NUMBER) { + elements.add(new Double(st.nval)) ; + continue ; + } + + // Anything other than a word or a quoted string is an error. + if (tok != StreamTokenizer.TT_WORD && tok != '"' && tok != '\'') { + String badToken = String.valueOf((char)tok) ; + elements.add(badToken) ; // so bad token prints out + syntaxError(st, file, "Invalid token \"" + badToken + + "\" must be enclosed in quotes") ; + continue ; + } + + // Scan the token for Java property substitution syntax ${...}. + s = scanJavaProperties(st, file, st.sval) ; + if (s == null) continue ; + + if (s.equalsIgnoreCase("true")) + // Replace "true" or "True" with the Boolean equivalent. + elements.add(new Boolean(true)) ; + + else if (s.equalsIgnoreCase("false")) + // Replace "false" or "False" with the Boolean equivalent. + elements.add(new Boolean(false)) ; + + else + // Add the token as a string element. + elements.add(s) ; + } + + + // + // Now evaluate elements. + // + if (elements.size() == 0) + syntaxError(st, file, "Null command") ; + + // If the first argument is a string, then this sexp must be + // a top-level command or a built-in, and needs to be evaluated. + if (elements.get(0) instanceof String) { + try { + if (level == 0) { + configContainer.evaluateCommand(elements, st.lineno()) ; + + // Continue parsing top-level commands. + return Boolean.TRUE ; + } + else { + // Evaluate built-in and return result to next level up. + return evaluateBuiltIn + (configContainer, elements, st.lineno()) ; + } + } + catch (IllegalArgumentException e) { + syntaxError(st, file, e.getMessage()) ; + if (level == 0) + // Command ignored: continue parsing. + return Boolean.TRUE ; + else + // Function ignored: return sexp to next level up so error + // processing can print it out in context of command. + return this ; + } + } + + // If the first argument isn't a string, and we are at level 0, + // this is a syntax error. + if (level == 0) + syntaxError(st, file, "Malformed top-level command name") ; + + // If the first argument is a number, then we must have + // either a 2D, 3D, or 4D numeric vector. + if (elements.get(0) instanceof Double) { + if (elements.size() == 1) + syntaxError(st, file, "Can't have single-element vector") ; + + // Point2D + if (elements.size() == 2) { + if (!(elements.get(1) instanceof Double)) + syntaxError(st, file, "Both elements must be numbers") ; + + return new Point2d(((Double)elements.get(0)).doubleValue(), + ((Double)elements.get(1)).doubleValue()) ; + } + + // Point3d + if (elements.size() == 3) { + if (!(elements.get(1) instanceof Double) || + !(elements.get(2) instanceof Double)) + syntaxError(st, file, "All elements must be numbers") ; + + return new Point3d(((Double)elements.get(0)).doubleValue(), + ((Double)elements.get(1)).doubleValue(), + ((Double)elements.get(2)).doubleValue()) ; + } + + // Point4D + if (elements.size() == 4) { + if (!(elements.get(1) instanceof Double) || + !(elements.get(2) instanceof Double) || + !(elements.get(3) instanceof Double)) + syntaxError(st, file, "All elements must be numbers") ; + + return new Point4d(((Double)elements.get(0)).doubleValue(), + ((Double)elements.get(1)).doubleValue(), + ((Double)elements.get(2)).doubleValue(), + ((Double)elements.get(3)).doubleValue()) ; + } + + // Anything else is an error. + syntaxError(st, file, "Too many vector elements") ; + } + + // If the first argument is a Point3d, then we should be a Matrix3d. + if (elements.get(0) instanceof Point3d) { + if (elements.size() != 3) + syntaxError(st, file, "Matrix must have three rows") ; + + if (!(elements.get(1) instanceof Point3d) || + !(elements.get(2) instanceof Point3d)) + syntaxError(st, file, "All rows must have three elements") ; + + return new Matrix3d(((Point3d)elements.get(0)).x, + ((Point3d)elements.get(0)).y, + ((Point3d)elements.get(0)).z, + ((Point3d)elements.get(1)).x, + ((Point3d)elements.get(1)).y, + ((Point3d)elements.get(1)).z, + ((Point3d)elements.get(2)).x, + ((Point3d)elements.get(2)).y, + ((Point3d)elements.get(2)).z) ; + } + + // If the first argument is a Point4d, then we should be a Matrix4d. + if (elements.get(0) instanceof Point4d) { + if (elements.size() == 3) { + if (!(elements.get(1) instanceof Point4d) || + !(elements.get(2) instanceof Point4d)) + syntaxError(st, file, "All rows must have four elements") ; + + return new Matrix4d(((Point4d)elements.get(0)).x, + ((Point4d)elements.get(0)).y, + ((Point4d)elements.get(0)).z, + ((Point4d)elements.get(0)).w, + ((Point4d)elements.get(1)).x, + ((Point4d)elements.get(1)).y, + ((Point4d)elements.get(1)).z, + ((Point4d)elements.get(1)).w, + ((Point4d)elements.get(2)).x, + ((Point4d)elements.get(2)).y, + ((Point4d)elements.get(2)).z, + ((Point4d)elements.get(2)).w, + 0.0, 0.0, 0.0, 1.0) ; + } + else if (elements.size() != 4) + syntaxError(st, file, "Matrix must have three or four rows") ; + + if (!(elements.get(1) instanceof Point4d) || + !(elements.get(2) instanceof Point4d) || + !(elements.get(3) instanceof Point4d)) + syntaxError(st, file, "All rows must have four elements") ; + + return new Matrix4d(((Point4d)elements.get(0)).x, + ((Point4d)elements.get(0)).y, + ((Point4d)elements.get(0)).z, + ((Point4d)elements.get(0)).w, + ((Point4d)elements.get(1)).x, + ((Point4d)elements.get(1)).y, + ((Point4d)elements.get(1)).z, + ((Point4d)elements.get(1)).w, + ((Point4d)elements.get(2)).x, + ((Point4d)elements.get(2)).y, + ((Point4d)elements.get(2)).z, + ((Point4d)elements.get(2)).w, + ((Point4d)elements.get(3)).x, + ((Point4d)elements.get(3)).y, + ((Point4d)elements.get(3)).z, + ((Point4d)elements.get(3)).w) ; + } + + // Anything else is an error. + syntaxError(st, file, "Syntax error") ; + return null ; + } + + /** + * Scan for Java properties in the specified string. Nested properties are + * not supported. + * + * @param st stream tokenizer in use + * @param f current file name + * @param s string containing non-nested Java properties possibly + * interspersed with arbitrary text. + * @return scanned string with Java properties replaced with values + */ + private String scanJavaProperties(StreamTokenizer st, String f, String s) { + int open = s.indexOf("${") ; + if (open == -1) return s ; + + int close = 0 ; + StringBuffer buf = new StringBuffer() ; + while (open != -1) { + buf.append(s.substring(close, open)) ; + close = s.indexOf('}', open) ; + if (close == -1) { + elements.add(s) ; // so that the bad element prints out + syntaxError(st, f, "Java property substitution syntax error") ; + return null ; + } + + String property = s.substring(open + 2, close) ; + String value = ConfigCommand.evaluateJavaProperty(property) ; + if (value == null) { + elements.add(s) ; // so that the bad element prints out + syntaxError(st, f, "Java property \"" + property + + "\" has a null value") ; + return null ; + } + + buf.append(value) ; + open = s.indexOf("${", close) ; + close++ ; + } + + buf.append(s.substring(close)) ; + return buf.toString() ; + } + + /** + * This method gets called from the s-expression parser to evaluate a + * built-in command. + * + * @param elements tokenized list of sexp elements + * @return object representing result of evaluation + */ + private Object evaluateBuiltIn(ConfigContainer configContainer, + ArrayList elements, int lineNumber) { + int argc ; + String functionName ; + + argc = elements.size() ; + functionName = (String)elements.get(0) ; + + if (functionName.equals("Rotate")) { + return makeRotate(elements) ; + } + else if (functionName.equals("Translate")) { + return makeTranslate(elements) ; + } + else if (functionName.equals("RotateTranslate") || + functionName.equals("TranslateRotate") || + functionName.equals("Concatenate")) { + + return concatenate(elements) ; + } + else if (functionName.equals("BoundingSphere")) { + return makeBoundingSphere(elements) ; + } + else { + // This built-in can't be evaluated immediately or contains an + // unknown command. Create a ConfigCommand for later evaluation. + return new ConfigCommand + (elements, configContainer.currentFileName, lineNumber) ; + } + } + + /** + * Processes the built-in command (Translate x y z). + * + * @param elements ArrayList containing Doubles wrapping x, y, and z + * translation components at indices 1, 2, and 3 respectively + * + * @return matrix that translates by the given x, y, and z components + */ + private Matrix4d makeTranslate(ArrayList elements) { + if (elements.size() != 4) { + throw new IllegalArgumentException + ("Incorrect number of arguments to Translate") ; + } + + if (!(elements.get(1) instanceof Double) || + !(elements.get(2) instanceof Double) || + !(elements.get(3) instanceof Double)) { + throw new IllegalArgumentException + ("All arguments to Translate must be numbers") ; + } + + Matrix4d m4d = new Matrix4d() ; + m4d.set(new Vector3d(((Double)elements.get(1)).doubleValue(), + ((Double)elements.get(2)).doubleValue(), + ((Double)elements.get(3)).doubleValue())) ; + + return m4d ; + } + + /** + * Processes the (Rotate x y z) built-in command. + * + * @param elements ArrayList containing Doubles wrapping x, y, and z Euler + * angles at indices 1, 2, and 3 respectively + * + * @return matrix that rotates by the given Euler angles around static X, + * Y, and Z basis vectors: first about X, then Y, and then Z + * + * @see Transform3D#setEuler() + */ + private Matrix4d makeRotate(ArrayList elements) { + if (elements.size() != 4) { + throw new IllegalArgumentException + ("Incorrect number of arguments to Rotate") ; + } + + if (!(elements.get(1) instanceof Double) || + !(elements.get(2) instanceof Double) || + !(elements.get(3) instanceof Double)) { + throw new IllegalArgumentException + ("All arguments to Rotate must be numbers") ; + } + + double x = Math.toRadians(((Double)elements.get(1)).doubleValue()) ; + double y = Math.toRadians(((Double)elements.get(2)).doubleValue()) ; + double z = Math.toRadians(((Double)elements.get(3)).doubleValue()) ; + + Transform3D t3d = new Transform3D() ; + t3d.setEuler(new Vector3d(x, y, z)) ; + + Matrix4d m4d = new Matrix4d() ; + t3d.get(m4d) ; + + return m4d ; + } + + /** + * Processes the (RotateTranslate m1 m2), (TranslateRotate m1 m2), and + * (Concatenate m1 m2) built-in commands. Although these do exactly the + * same thing, using the appropriate command is recommended in order to + * explicitly describe the sequence of transforms and their intent. + * + * @param elements ArrayList containing Matrix4d objects m1 and m2 at + * indices 1 and 2 respectively + * + * @return matrix that concatenates m1 and m2 in that order: if a point is + * transformed by the resulting matrix, then in effect the points are + * first transformed by m1 and then m2 + */ + private Matrix4d concatenate(ArrayList elements) { + String functionName = (String)elements.get(0) ; + + if (elements.size() != 3) { + throw new IllegalArgumentException + ("Incorrect number of arguments to " + functionName) ; + } + + if (!(elements.get(1) instanceof Matrix4d) || + !(elements.get(2) instanceof Matrix4d)) { + throw new IllegalArgumentException + ("Both arguments to " + functionName + " must be Matrix4d") ; + } + + // Multiply the matrices in the order such that the result, when + // transforming a 3D point, will apply the transform represented by + // the 1st matrix and then apply the transform represented by the 2nd + // matrix. + Matrix4d m4d = new Matrix4d((Matrix4d)elements.get(2)) ; + m4d.mul((Matrix4d)elements.get(1)) ; + + return m4d ; + } + + /** + * Processes the built-in command (BoundingSphere center radius). + * This is used when configuring behaviors. + * + * @param elements ArrayList containing Point3d at index 1 for the sphere + * center and Double at index 2 wrapping the sphere radius, or the String + * "infinite" at index 2. + * + * @return BoundingSphere with the given center and radius + */ + private BoundingSphere makeBoundingSphere(ArrayList elements) { + if (elements.size() != 3) { + throw new IllegalArgumentException + ("Incorrect number of arguments to BoundingSphere") ; + } + + if (! (elements.get(1) instanceof Point3d) || + ! (elements.get(2) instanceof Double || + elements.get(2) instanceof String)) + throw new IllegalArgumentException + ("BoundingSphere needs a Point3d center " + + "followed by a Double radius or the String \"infinite\"") ; + + double r ; + if (elements.get(2) instanceof Double) + r = ((Double)elements.get(2)).doubleValue() ; + else + r = Double.POSITIVE_INFINITY ; + + return new BoundingSphere((Point3d)elements.get(1), r) ; + } + + void print() { + System.out.print("(") ; + int argc = elements.size() ; + for (int i = 0 ; i < argc ; i++) { + if (elements.get(i) instanceof Matrix3d) { + String[] rows = ConfigCommand.formatMatrixRows + ((Matrix3d)elements.get(i)) ; + System.out.println("\n ((" + rows[0] + ")") ; + System.out.println(" (" + rows[1] + ")") ; + System.out.print(" (" + rows[2] + "))") ; + if (i != (argc - 1)) System.out.println() ; + } + else if (elements.get(i) instanceof Matrix4d) { + String[] rows = ConfigCommand.formatMatrixRows + ((Matrix4d)elements.get(i)) ; + System.out.println("\n ((" + rows[0] + ")") ; + System.out.println(" (" + rows[1] + ")") ; + System.out.println(" (" + rows[2] + ")") ; + System.out.print(" (" + rows[3] + "))") ; + if (i != (argc - 1)) System.out.println() ; + } + else if (elements.get(i) instanceof ConfigSexpression) { + if (i > 0) System.out.print(" ") ; + ((ConfigSexpression)elements.get(i)).print() ; + if (i != (argc - 1)) System.out.println() ; + } + else if (elements.get(i) instanceof ConfigCommand) { + if (i > 0) System.out.print(" ") ; + System.out.print(elements.get(i).toString()) ; + if (i != (argc - 1)) System.out.println() ; + } + else { + if (i > 0) System.out.print(" ") ; + System.out.print(elements.get(i).toString()) ; + } + } + System.out.print(")") ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigView.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigView.java new file mode 100644 index 0000000..582bce3 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigView.java @@ -0,0 +1,469 @@ +/* + * $RCSfile: ConfigView.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.util.* ; +import javax.media.j3d.* ; +import javax.vecmath.* ; + +class ConfigView extends ConfigObject { + /** + * The corresponding View and Viewer instances. These are set when + * createJ3dView() is called after parsing the configuration file. + */ + View j3dView = null ; + Viewer j3dViewer = null ; + + /** + * Set of ConfigScreen instances added to this view. + */ + Set screens = new HashSet() ; + + /** + * Indicates whether or not stereo viewing should be enabled for this + * ConfigView. This is set during parsing of the configuration file. + */ + boolean stereoEnable = false ; + + /** + * Indicates whether or not antialiasing is enabled for this ConfigView. + * This is set during parsing of the configuration file. + */ + boolean antialiasingEnable = false; + + /** + * Reference to the PhysicalBody associated with this ConfigView. This is + * set when createJ3dView() is called after parsing the configuration + * file. + */ + PhysicalBody physicalBody = null ; + + /** + * Reference to the PhysicalEnvironment associated with this ConfigView. + * This is set when createJ3dView() is called after parsing the + * configuration file. + */ + PhysicalEnvironment physicalEnvironment = null ; + + // All other configurable attributes. + private double fieldOfView = Math.PI/4.0 ; + private int backClipPolicy = View.PHYSICAL_EYE ; + private int frontClipPolicy = View.PHYSICAL_EYE ; + private double backClipDistance = 10.0 ; + private double frontClipDistance = 0.1 ; + private int screenScalePolicy = View.SCALE_SCREEN_SIZE ; + private double screenScale = 1.0 ; + private boolean trackingEnable = false ; + private int viewPolicy = View.SCREEN_VIEW ; + private int windowEyepointPolicy = -1 ; + private int windowMovementPolicy = -1 ; + private int windowResizePolicy = -1 ; + private boolean coeCenteringEnableSet = false ; + private boolean coeCenteringEnable = false ; + private Point3d centerEyeInCoexistence = null ; + + private ConfigPhysicalBody configBody = null ; + private ConfigPhysicalEnvironment configEnv = null ; + private ConfigViewPlatform configViewPlatform = null ; + + /** + * Overrides initialize() to do nothing. + */ + protected void initialize(ConfigCommand command) { + } + + /** + * Processes properties for this object. Handles commands of the form:

+ * (ViewAttribute {instanceName} {attrName} {attrValue}) + * + * @param command the command that invoked this method + */ + protected void setProperty(ConfigCommand command) { + + int argc = command.argc ; + Object[] argv = command.argv ; + String attr = null ; + Object val = null ; + String sval = null ; + ConfigScreen cs = null ; + + // Check that arg[1] and arg[2] are strings + if (argc != 4) { + syntaxError("Incorrect number of arguments to " + + command.commandName) ; + } + + if (!isName(argv[1])) { + syntaxError("The first argument to " + command.commandName + + " must be the instance name") ; + } + + if (!isName(argv[2])) { + syntaxError("The second argument to " + command.commandName + + " must be a property name") ; + } + + attr = (String) argv[2] ; + val = argv[3] ; + + if (attr.equals("Screen") || attr.equals("Window")) { + if (!(val instanceof String)) { + syntaxError("Value for " + attr + " must be a name") ; + } + cs = (ConfigScreen) + configContainer.findConfigObject("Screen", (String)val) ; + + if (!screens.add(cs)) { + syntaxError(attr + " \"" + ((String)val) + + "\" has already been added to " + instanceName) ; + } + } + else if (attr.equals("ViewPlatform")) { + if (!(val instanceof String)) { + syntaxError("value for ViewPlatform " + + " must be an instance name") ; + } + configViewPlatform = + (ConfigViewPlatform)configContainer.findConfigObject + ("ViewPlatform", (String)val) ; + + configViewPlatform.addConfigView(this) ; + } + else if (attr.equals("PhysicalEnvironment")) { + if (!(val instanceof String)) { + syntaxError("value for PhysicalEnvironment " + + "must be an instance name") ; + } + configEnv = + (ConfigPhysicalEnvironment)configContainer.findConfigObject + ("PhysicalEnvironment", (String)val) ; + } + else if (attr.equals("PhysicalBody")) { + if (!(val instanceof String)) { + syntaxError("value for PhysicalBody " + + "must be an instance name") ; + } + configBody = (ConfigPhysicalBody) + configContainer.findConfigObject("PhysicalBody", (String)val) ; + } + else if (attr.equals("BackClipPolicy")) { + if (!(val instanceof String)) { + syntaxError("value for BackClipPolicy must be a string") ; + } + sval = (String) val ; + if (sval.equals("PHYSICAL_EYE")) + backClipPolicy = View.PHYSICAL_EYE ; + else if (sval.equals("PHYSICAL_SCREEN")) + backClipPolicy = View.PHYSICAL_SCREEN ; + else if (sval.equals("VIRTUAL_EYE")) + backClipPolicy = View.VIRTUAL_EYE ; + else if (sval.equals("VIRTUAL_SCREEN")) + backClipPolicy = View.VIRTUAL_SCREEN ; + else + syntaxError("Invalid value for BackClipPolicy " + sval) ; + } + else if (attr.equals("FrontClipPolicy")) { + if (!(val instanceof String)) { + syntaxError("value for FrontClipPolicy must be a string") ; + } + sval = (String) val ; + if (sval.equals("PHYSICAL_EYE")) + frontClipPolicy = View.PHYSICAL_EYE ; + else if (sval.equals("PHYSICAL_SCREEN")) + frontClipPolicy = View.PHYSICAL_SCREEN ; + else if (sval.equals("VIRTUAL_EYE")) + frontClipPolicy = View.VIRTUAL_EYE ; + else if (sval.equals("VIRTUAL_SCREEN")) + frontClipPolicy = View.VIRTUAL_SCREEN ; + else + syntaxError("Invalid value for FrontClipPolicy " + sval) ; + } + else if (attr.equals("ScreenScalePolicy")) { + if (!(val instanceof String)) { + syntaxError("value for ScreenScalePolicy must be a string") ; + } + sval = (String) val ; + if (sval.equals("SCALE_SCREEN_SIZE")) + screenScalePolicy = View.SCALE_SCREEN_SIZE ; + else if (sval.equals("SCALE_EXPLICIT")) + screenScalePolicy = View.SCALE_EXPLICIT ; + else + syntaxError("Invalid value for ScreenScalePolicy " + sval) ; + } + else if (attr.equals("FieldOfView")) { + if (!(val instanceof Double)) { + syntaxError("value for FieldOfView must be a number") ; + } + fieldOfView = ((Double)val).doubleValue() ; + } + else if (attr.equals("BackClipDistance")) { + if (!(val instanceof Double)) { + syntaxError("value for BackClipDistance must be a number") ; + } + backClipDistance = ((Double)val).doubleValue() ; + } + else if (attr.equals("FrontClipDistance")) { + if (!(val instanceof Double)) { + syntaxError("value for FrontClipDistance must be a number") ; + } + frontClipDistance = ((Double)val).doubleValue() ; + } + else if (attr.equals("ScreenScale")) { + if (!(val instanceof Double)) { + syntaxError("value for ScreenScale must be a number") ; + } + screenScale = ((Double)val).doubleValue() ; + } + else if (attr.equals("TrackingEnable")) { + if (!(val instanceof Boolean)) { + syntaxError("value for TrackingEnable must be a boolean") ; + } + trackingEnable = ((Boolean)val).booleanValue() ; + } + else if (attr.equals("CoexistenceCenteringEnable")) { + if (!(val instanceof Boolean)) { + syntaxError("value for CoexistenceCenteringEnable " + + "must be a boolean") ; + } + coeCenteringEnable = ((Boolean)val).booleanValue() ; + coeCenteringEnableSet = true ; + } + else if (attr.equals("ViewPolicy")) { + if (!(val instanceof String)) { + syntaxError("value for ViewPolicy must be a string") ; + } + sval = (String) val ; + if (sval.equals("SCREEN_VIEW")) + viewPolicy = View.SCREEN_VIEW ; + else if (sval.equals("HMD_VIEW")) + viewPolicy = View.HMD_VIEW ; + else + syntaxError("Invalid value for ViewPolicy " + sval) ; + } + else if (attr.equals("WindowEyepointPolicy")) { + if (!(val instanceof String)) { + syntaxError("value for WindowEyepointPolicy " + + "must be a string") ; + } + sval = (String) val ; + if (sval.equals("RELATIVE_TO_SCREEN")) + windowEyepointPolicy = View.RELATIVE_TO_SCREEN ; + else if (sval.equals("RELATIVE_TO_COEXISTENCE")) + windowEyepointPolicy = View.RELATIVE_TO_COEXISTENCE ; + else if (sval.equals("RELATIVE_TO_WINDOW")) + windowEyepointPolicy = View.RELATIVE_TO_WINDOW ; + else if (sval.equals("RELATIVE_TO_FIELD_OF_VIEW")) + windowEyepointPolicy = View.RELATIVE_TO_FIELD_OF_VIEW ; + else + syntaxError("Invalid value for WindowEyepointPolicy " + sval) ; + } + else if (attr.equals("WindowMovementPolicy")) { + if (!(val instanceof String)) { + syntaxError("value for WindowEyeMovementPolicy " + + "must be a string") ; + } + sval = (String) val ; + if (sval.equals("VIRTUAL_WORLD")) + windowMovementPolicy = View.VIRTUAL_WORLD ; + else if (sval.equals("PHYSICAL_WORLD")) + windowMovementPolicy = View.PHYSICAL_WORLD ; + else + syntaxError("Invalid value for WindowMovementPolicy " + sval) ; + } + else if (attr.equals("WindowResizePolicy")) { + if (!(val instanceof String)) { + syntaxError("value for WindowResizePolicy " + + "must be a string") ; + } + sval = (String) val ; + if (sval.equals("VIRTUAL_WORLD")) + windowResizePolicy = View.VIRTUAL_WORLD ; + else if (sval.equals("PHYSICAL_WORLD")) + windowResizePolicy = View.PHYSICAL_WORLD ; + else + syntaxError("Invalid value for WindowResizePolicy " + sval) ; + } + else if (attr.equals("CenterEyeInCoexistence")) { + if (val instanceof Point3d) + centerEyeInCoexistence = (Point3d)val ; + else + syntaxError("value for CenterEyeInCoexistence " + + "must be a Point3d") ; + } + else if (attr.equals("StereoEnable")) { + if (!(val instanceof Boolean)) { + syntaxError("value for StereoEnable must be a boolean") ; + } + stereoEnable = ((Boolean)val).booleanValue() ; + } + else if (attr.equals("AntialiasingEnable")) { + if (!(val instanceof Boolean)) { + syntaxError("value for AntialiasingEnable must be a boolean") ; + } + antialiasingEnable = ((Boolean)val).booleanValue() ; + } + else { + syntaxError("Unknown " + command.commandName + + " \"" + attr + "\"") ; + } + } + + /** + * Create a core Java 3D View instance and a utility Viewer instance using + * the attributes gathered by this object. + */ + protected Viewer createViewer(boolean setVisible) { + Point3d leftEyeCoe, rightEyeCoe ; + + j3dView = new View() ; + j3dView.setViewPolicy(viewPolicy) ; + + if (configBody == null) + physicalBody = new PhysicalBody() ; + else + physicalBody = configBody.j3dPhysicalBody ; + + if (configEnv == null) + physicalEnvironment = new PhysicalEnvironment() ; + else + physicalEnvironment = configEnv.j3dPhysicalEnvironment ; + + j3dView.setPhysicalBody(physicalBody) ; + j3dView.setPhysicalEnvironment(physicalEnvironment) ; + + boolean standardDefaults = true ; + if (coeCenteringEnableSet && !coeCenteringEnable) { + standardDefaults = false ; + } + if (configEnv != null && configEnv.coexistenceToTrackerBase != null) { + standardDefaults = false ; + } + else { + Iterator i = screens.iterator() ; + while (i.hasNext()) { + ConfigScreen s = (ConfigScreen)i.next() ; + if (s.trackerBaseToImagePlate != null) { + standardDefaults = false ; + break ; + } + } + } + + if (standardDefaults) { + // Coexistence centering has not been explicitly set false, and + // the tracker base to image plate and coexistence to tracker base + // transforms are unset, so use the standard Java 3D defaults. + if (windowEyepointPolicy == -1) + windowEyepointPolicy = View.RELATIVE_TO_FIELD_OF_VIEW ; + if (windowMovementPolicy == -1) + windowMovementPolicy = View.PHYSICAL_WORLD ; + if (windowResizePolicy == -1) + windowResizePolicy = View.PHYSICAL_WORLD ; + if (!coeCenteringEnableSet) + coeCenteringEnable = true ; + } + else { + // Use multi-screen or calibrated coexistence defaults. + if (windowEyepointPolicy == -1) + windowEyepointPolicy = View.RELATIVE_TO_COEXISTENCE ; + if (windowMovementPolicy == -1) + windowMovementPolicy = View.VIRTUAL_WORLD ; + if (windowResizePolicy == -1) + windowResizePolicy = View.VIRTUAL_WORLD ; + if (!coeCenteringEnableSet) + coeCenteringEnable = false ; + } + + j3dView.setWindowEyepointPolicy(windowEyepointPolicy) ; + j3dView.setWindowMovementPolicy(windowMovementPolicy) ; + j3dView.setWindowResizePolicy(windowResizePolicy) ; + j3dView.setCoexistenceCenteringEnable(coeCenteringEnable) ; + + if (centerEyeInCoexistence == null) { + centerEyeInCoexistence = new Point3d(0.0, 0.0, 0.4572) ; + } + + leftEyeCoe = new Point3d(centerEyeInCoexistence) ; + rightEyeCoe = new Point3d(centerEyeInCoexistence) ; + + if (stereoEnable) { + Point3d leftEyeBody = new Point3d() ; + Point3d rightEyeBody = new Point3d() ; + + physicalBody.getLeftEyePosition(leftEyeBody) ; + physicalBody.getRightEyePosition(rightEyeBody) ; + + leftEyeCoe.add(leftEyeBody) ; + rightEyeCoe.add(rightEyeBody) ; + } + + j3dView.setLeftManualEyeInCoexistence(leftEyeCoe) ; + j3dView.setRightManualEyeInCoexistence(rightEyeCoe) ; + + j3dView.setBackClipPolicy(backClipPolicy) ; + j3dView.setFrontClipPolicy(frontClipPolicy) ; + j3dView.setBackClipDistance(backClipDistance) ; + j3dView.setFrontClipDistance(frontClipDistance) ; + + j3dView.setScreenScalePolicy(screenScalePolicy) ; + j3dView.setScreenScale(screenScale) ; + + j3dView.setFieldOfView(fieldOfView) ; + j3dView.setTrackingEnable(trackingEnable) ; + j3dView.setSceneAntialiasingEnable(antialiasingEnable) ; + + if (screens.size() == 0) { + throw new IllegalStateException + (errorMessage(creatingCommand, "View \"" + instanceName + + "\" has no canvases or screens")) ; + } + + ConfigScreen[] cs = new ConfigScreen[screens.size()] ; + screens.toArray(cs) ; + + j3dViewer = new Viewer(cs, this, setVisible) ; + return j3dViewer ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatform.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatform.java new file mode 100644 index 0000000..4cfc3a2 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatform.java @@ -0,0 +1,255 @@ +/* + * $RCSfile: ConfigViewPlatform.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.util.ArrayList ; +import javax.media.j3d.Node ; +import javax.media.j3d.View ; +import javax.media.j3d.ViewPlatform ; +import javax.media.j3d.Transform3D ; +import javax.media.j3d.TransformGroup ; +import javax.vecmath.Matrix4d ; +import com.sun.j3d.utils.behaviors.vp.ViewPlatformBehavior ; + +class ConfigViewPlatform extends ConfigObject { + + private boolean allowPolicyRead = false ; + private boolean allowLocalToVworldRead = false ; + private boolean nominalViewingTransform = false ; + private Transform3D initialViewingTransform = null ; + private ArrayList configViews = new ArrayList() ; + private Viewer[] viewers = null ; + + /** + * The corresponding ViewingPlatform instance. + */ + ViewingPlatform viewingPlatform = null ; + + /** + * Indicates the view attach policy specified in the configuration file. + * If none is set, it remains -1 even though a default may be in effect. + */ + int viewAttachPolicy = -1 ; + + /** + * The associated ConfigViewPlatformBehavior, if any. + */ + ConfigViewPlatformBehavior configBehavior = null ; + + /** + * Overrides initialize() to do nothing. + */ + protected void initialize(ConfigCommand command) { + } + + /** + * Processes attributes for this object. Handles commands of the form:

+ * (ViewPlatformAttribute {instanceName} {attrName} {attrValue})
+ * (ViewPlatformProperty {instanceName} {attrName} {attrValue}) + * + * @param command the command that invoked this method + */ + protected void setProperty(ConfigCommand command) { + + int argc = command.argc ; + Object[] argv = command.argv ; + String attribute ; + Object value ; + + if (argc != 4) { + syntaxError("Incorrect number of arguments to " + + command.commandName) ; + } + + if (!isName(argv[2])) { + syntaxError("The second argument to " + command.commandName + + " must be a property name"); + } + + attribute = (String)argv[2] ; + value = argv[3] ; + + if (attribute.equals("NominalViewingTransform")) { + if (! (value instanceof Boolean)) { + syntaxError("NominalViewingTransform must be a boolean") ; + } + nominalViewingTransform = ((Boolean)value).booleanValue() ; + } + else if (attribute.equals("InitialViewingTransform")) { + if (! (value instanceof Matrix4d)) { + syntaxError("InitialViewingTransform must be a Matrix4d") ; + } + initialViewingTransform = new Transform3D((Matrix4d)value) ; + } + else if (attribute.equals("ViewAttachPolicy")) { + if (! (value instanceof String)) { + syntaxError("ViewAttachPolicy must be a string") ; + } + + String svalue = (String)value ; + + if (svalue.equals("NOMINAL_HEAD")) + viewAttachPolicy = View.NOMINAL_HEAD ; + else if (svalue.equals("NOMINAL_SCREEN")) + viewAttachPolicy = View.NOMINAL_SCREEN ; + else if (svalue.equals("NOMINAL_FEET")) + viewAttachPolicy = View.NOMINAL_FEET ; + else + syntaxError("Illegal value " + + svalue + " for ViewAttachPolicy") ; + } + else if (attribute.equals("ViewPlatformBehavior")) { + if (! (value instanceof String)) { + syntaxError("ViewPlatformBehavior must be a name") ; + } + configBehavior = + (ConfigViewPlatformBehavior)configContainer.findConfigObject + ("ViewPlatformBehavior", (String)value) ; + } + else if (attribute.equals("AllowPolicyRead")) { + if (!(value instanceof Boolean)) { + syntaxError("value for AllowPolicyRead " + + "must be a boolean") ; + } + allowPolicyRead = ((Boolean)value).booleanValue() ; + } + else if (attribute.equals("AllowLocalToVworldRead")) { + if (!(value instanceof Boolean)) { + syntaxError("value for AllowLocalToVworldRead " + + "must be a boolean") ; + } + allowLocalToVworldRead = ((Boolean)value).booleanValue() ; + } + else { + syntaxError("Unknown " + command.commandName + + " \"" + attribute + "\"") ; + } + } + + /** + * Add a ConfigView to this ConfigViewPlatform. + */ + void addConfigView(ConfigView cv) { + configViews.add(cv) ; + } + + /** + * Creates a ViewingPlatform from attributes gathered by this object. + * + * @param transformCount the number of TransformGroups to attach to the + * ViewingPlatform + * @return the new ViewingPlatform + */ + ViewingPlatform createViewingPlatform(int transformCount) { + + // Get the Viewers attached to this ViewingPlatform. + // All ConfigViews must be processed at this point. + if (configViews.size() == 0) { + viewers = new Viewer[0] ; + } + else { + viewers = new Viewer[configViews.size()] ; + for (int i = 0 ; i < viewers.length ; i++) + viewers[i] = ((ConfigView)configViews.get(i)).j3dViewer ; + } + + // Create the viewing platform and get its ViewPlatform instance. + viewingPlatform = new ViewingPlatform(transformCount) ; + ViewPlatform vp = viewingPlatform.getViewPlatform() ; + + // Set defined policies. + if (allowPolicyRead) + vp.setCapability(ViewPlatform.ALLOW_POLICY_READ) ; + + if (allowLocalToVworldRead) + vp.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ) ; + + if (viewAttachPolicy == -1) { + // Apply a default based on the eyepoint policy. + boolean nominalHead = true ; + for (int i = 0 ; i < viewers.length ; i++) { + if (viewers[i].getView().getWindowEyepointPolicy() != + View.RELATIVE_TO_FIELD_OF_VIEW) { + nominalHead = false ; + break ; + } + } + if (nominalHead) + vp.setViewAttachPolicy(View.NOMINAL_HEAD) ; + else + vp.setViewAttachPolicy(View.NOMINAL_SCREEN) ; + } + else { + vp.setViewAttachPolicy(viewAttachPolicy) ; + } + + // Assign the viewing platform to all viewers. + for (int i = 0 ; i < viewers.length ; i++) { + viewers[i].setViewingPlatform(viewingPlatform) ; + } + + // Apply initial viewing transforms if defined. + if (nominalViewingTransform) { + viewingPlatform.setNominalViewingTransform() ; + } + + if (initialViewingTransform != null) { + TransformGroup tg = viewingPlatform.getViewPlatformTransform() ; + tg.setTransform(initialViewingTransform) ; + } + + return viewingPlatform ; + } + + /** + * Attach any ViewPlatformBehavior specified for this platform. + */ + void processBehavior() { + if (configBehavior != null) { + viewingPlatform.setViewPlatformBehavior + (configBehavior.viewPlatformBehavior) ; + } + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatformBehavior.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatformBehavior.java new file mode 100644 index 0000000..2e3181f --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatformBehavior.java @@ -0,0 +1,139 @@ +/* + * $RCSfile: ConfigViewPlatformBehavior.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.lang.reflect.* ; +import java.util.ArrayList ; +import javax.vecmath.Matrix4d ; +import javax.media.j3d.Bounds ; +import javax.media.j3d.Canvas3D ; +import javax.media.j3d.Sensor ; +import javax.media.j3d.Transform3D ; +import com.sun.j3d.utils.behaviors.vp.ViewPlatformBehavior ; + +class ConfigViewPlatformBehavior extends ConfigObject { + + // All known configurable properties. + private Transform3D homeTransform = null ; + private Bounds schedulingBounds = null ; + private int schedulingInterval = -1 ; + + /** + * The corresponding ViewPlatformBehavior instance. + */ + ViewPlatformBehavior viewPlatformBehavior ; + + /** + * Processes properties for this object. Handles commands of the form:

+ * (ViewPlatformBehaviorProperty {instanceName} {attrName} {arg} ...) + * + * @param command the command that invoked this method + */ + protected void setProperty(ConfigCommand cmd) { + + int argc = cmd.argc ; + Object[] argv = cmd.argv ; + + if (argc < 4) { + syntaxError("Wrong number of arguments to " + cmd.commandName) ; + } + + if (! isName(argv[2])) { + syntaxError("The second argument to " + cmd.commandName + + " must be a property name"); + } + + String attribute = (String)argv[2] ; + if (attribute.equals("HomeTransform")) { + if (! (argv[3] instanceof Matrix4d)) { + syntaxError("HomeTransform must be a Matrix4d") ; + } + homeTransform = new Transform3D((Matrix4d)argv[3]) ; + } + else if (attribute.equals("SchedulingBounds")) { + if (! (argv[3] instanceof Bounds)) { + syntaxError("SchedulingBounds must be an instance of Bounds") ; + } + schedulingBounds = (Bounds)argv[3] ; + } + else if (attribute.equals("SchedulingInterval")) { + if (! (argv[3] instanceof Double)) { + syntaxError("SchedulingInterval must be a priority (number)") ; + } + schedulingInterval = ((Double)argv[3]).intValue() ; + } + else { + // It's not any of the pre-defined attributes. Add it to the + // properties list for the behavior instance itself to evaluate. + properties.add(cmd) ; + } + } + + /** + * Instantiate a ViewPlatformBehavior of the given class name.

+ * + * NOTE: All ConfigView and ConfigSensor objects must be processed before + * calling this method. + * + * @return the configured ViewPlatformBehavior, or null if error + */ + ViewPlatformBehavior createViewPlatformBehavior() { + + viewPlatformBehavior = (ViewPlatformBehavior)createTargetObject() ; + + // Set known attributes. + if (homeTransform != null) + viewPlatformBehavior.setHomeTransform(homeTransform) ; + + if (schedulingBounds != null) + viewPlatformBehavior.setSchedulingBounds(schedulingBounds) ; + + if (schedulingInterval != -1) + viewPlatformBehavior.setSchedulingInterval(schedulingInterval) ; + + // Unknown properties in the concrete instance are evaluated later. + return viewPlatformBehavior ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfiguredUniverse.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfiguredUniverse.java new file mode 100644 index 0000000..e000c77 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ConfiguredUniverse.java @@ -0,0 +1,791 @@ +/* + * $RCSfile: ConfiguredUniverse.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import java.net.URL; +import java.net.MalformedURLException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import javax.media.j3d.*; + +/** + * This utility class creates all the necessary objects on the view side of + * the scene graph. Specifically, it creates a Locale, one or more + * ViewingPlatforms, and at least one Viewer object.

+ * + * ConfiguredUniverse can set up a viewing environment based upon the contents + * of a configuration file. This allows an application to run without change + * across a broad range of viewing configurations, such as windows on + * conventional desktops, stereo-enabled views, full screen immersive displays + * on single or multiple screens, or virtual reality installations including + * cave and head-mounted displays incorporating 6 degree of freedom sensor + * devices.

+ * + * A configuration file may create InputDevice, Sensor, and + * ViewPlatformBehavior instances as well as Viewers and ViewingPlatforms. At + * least one Viewer must be provided by the configuration. If a + * ViewingPlatform is not provided, a default one will be created and the + * Viewer will be attached to it.

+ * + * A configuration file may be specified directly by passing a URL to a + * ConfiguredUniverse constructor. Alternatively, a ConfigContainer may be + * created from a configuration file first, and then passed to an appropriate + * ConfiguredUniverse constructor. The latter technique allows Java system + * properties that affect Java 3D to be specified in the configuration file, + * as long as no references to a VirtualUniverse are made before creating the + * container.

+ * + * If a configuration file or container is not provided, then + * ConfiguredUniverse creates a default viewing environment in the same way as + * SimpleUniverse. If one or more Canvas3D objects are provided, it will use + * them instead of creating new ones. All of the constructors provided by + * SimpleUniverse are also available here.

+ * + * The syntax and description of the configuration file may be found + * here. Example config files can + * be found here. + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see ConfigContainer + * @see + * The Java 3D Configuration File + * @see + * Example Configuration Files + * + * @since Java 3D 1.3 + */ +public class ConfiguredUniverse extends SimpleUniverse { + + /** + * The configuration instance for this universe. + */ + private ConfigContainer configContainer = null; + + /** + * Equivalent to SimpleUniverse(). Creates a + * Locale, a single ViewingPlatform, and a Viewer object. + * + * @see SimpleUniverse#SimpleUniverse() + * @see Locale + * @see Viewer + * @see ViewingPlatform + */ + public ConfiguredUniverse() { + super(); + } + + /** + * Equivalent to SimpleUniverse(int). + * Creates a Locale, a single ViewingPlatform with the specified number of + * transforms, and a Viewer object. + * + * @param transformCount the number of transforms in the + * MultiTransformGroup object to be created + * + * @see SimpleUniverse#SimpleUniverse(int) + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + */ + public ConfiguredUniverse(int transformCount) { + super(transformCount); + } + + /** + * Equivalent to SimpleUniverse(Canvas3D). + * Creates a Locale, a single ViewingPlatform, and a Viewer object using + * the given Canvas3D instance. + * + * @param canvas the canvas to associate with the Viewer object; + * passing in null will cause this parameter to be ignored and a canvas + * to be created by the utility + * + * @see SimpleUniverse#SimpleUniverse(Canvas3D) + * @see Locale + * @see Viewer + * @see ViewingPlatform + */ + public ConfiguredUniverse(Canvas3D canvas) { + super(canvas); + } + + /** + * Equivalent to SimpleUniverse(Canvas3D, int). + * Creates a Locale, a single ViewingPlatform with the specified number of + * transforms, and a Viewer object with the given Canvas3D. + * + * @param canvas the canvas to associate with the Viewer object; + * passing in null will cause this parameter to be ignored and a canvas + * to be created by the utility + * @param transformCount the number of transforms in the + * MultiTransformGroup object to be created + * + * @see SimpleUniverse#SimpleUniverse(Canvas3D, int) + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + */ + public ConfiguredUniverse(Canvas3D canvas, int transformCount) { + super(canvas, transformCount); + } + + /** + * Equivalent to SimpleUniverse(ViewingPlatform, Viewer). + * Creates the view side of the scene graph with the given ViewingPlatform + * and Viewer. + * + * @param viewingPlatform the viewingPlatform to use to create + * the view side of the scene graph + * @param viewer the viewer object to use to create + * the view side of the scene graph + * + * @see SimpleUniverse#SimpleUniverse(ViewingPlatform, Viewer) + * @see ViewingPlatform + * @see Viewer + */ + public ConfiguredUniverse(ViewingPlatform viewingPlatform, Viewer viewer) { + super(viewingPlatform, viewer, null); + } + + /** + * Equivalent to SimpleUniverse(ViewingPlatform, Viewer, + * LocalFactory). Creates the view side of the scene graph with + * the given ViewingPlatform, Viewer, and Locale created by the specified + * LocaleFactory. + * + * @param viewingPlatform the viewingPlatform to use to create + * the view side of the scene graph + * @param viewer the viewer object to use to create + * the view side of the scene graph + * @param localeFactory the factory object used to create the Locale + * + * @see SimpleUniverse#SimpleUniverse(ViewingPlatform, Viewer, + * LocaleFactory) + * @see ViewingPlatform + * @see Viewer + * @see LocaleFactory + */ + public ConfiguredUniverse(ViewingPlatform viewingPlatform, Viewer viewer, + LocaleFactory localeFactory ) { + super(viewingPlatform, viewer, localeFactory); + } + + /** + * Creates a Locale, a single ViewingPlatform, and a Viewer object from + * the given array of Canvas3D instances. + * + * @param canvases the canvases to associate with the Viewer object; + * passing in null will cause this parameter to be ignored and a canvas + * to be created by the utility + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + */ + public ConfiguredUniverse(Canvas3D[] canvases) { + this(1, canvases, null, null, null, true); + } + + /** + * Creates a Locale, a single ViewingPlatform with the specified number of + * transforms, and a Viewer object using the given array of Canvas3D + * instances. + * + * @param canvases the canvases to associate with the Viewer object; + * passing in null will cause this parameter to be ignored and a canvas + * to be created by the utility + * @param transformCount the number of transforms in the + * MultiTransformGroup object to be created + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + */ + public ConfiguredUniverse(Canvas3D[] canvases, int transformCount) { + this(transformCount, canvases, null, null, null, true); + } + + /** + * Creates a Locale, a single ViewingPlatform with the specified number of + * transforms, and a Viewer object using the given array of Canvas3D + * instances. + * + * @param canvases the canvases to associate with the Viewer object; + * passing in null will cause this parameter to be ignored and a canvas + * to be created by the utility + * @param transformCount the number of transforms in the + * MultiTransformGroup object to be created + * @param localeFactory the factory object used to create the Locale + * + * @since Java 3D 1.5.1 + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + */ + public ConfiguredUniverse(Canvas3D[] canvases, int transformCount, LocaleFactory localeFactory ) { + this(transformCount, canvases, null, localeFactory, null, true); + } + + /** + * Reads the configuration specified by the given URL to create a Locale, + * one or more ViewingPlatforms, and at least one Viewer object. The + * configuration file may also create InputDevice, Sensor, and + * ViewPlatformBehavior instances. + * + * @param userConfig the URL to the user's configuration file; passing in + * null creates a default Viewer and ViewingPlatform + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + */ + public ConfiguredUniverse(URL userConfig) { + this(1, null, userConfig, null, null, true); + } + + /** + * Reads the configuration specified by the given URL to create a Locale, + * one or more ViewingPlatforms with the specified number of transforms, + * and at least one Viewer object. The configuration file may also create + * InputDevice, Sensor, and ViewPlatformBehavior instances. + * + * @param userConfig the URL to the user's configuration file; passing in + * null creates a default Viewer and ViewingPlatform with the specified + * number of transforms + * @param transformCount the number of transforms in the + * MultiTransformGroup objects to be created + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + */ + public ConfiguredUniverse(URL userConfig, int transformCount) { + this(transformCount, null, userConfig, null, null, true); + } + + /** + * Reads the configuration specified by the given URL to create a Locale, + * one or more ViewingPlatforms with the specified number of transforms, + * and at least one Viewer object with optional visibility. AWT + * components used by the Viewers will remain invisible unless the + * setVisible flag is true. The configuration file may also + * create InputDevice, Sensor, and ViewPlatformBehavior instances. + * + * @param userConfig the URL to the user's configuration file; passing in + * null creates a default Viewer with the specified visibility and a + * ViewingPlatform with the specified number of transforms + * @param transformCount the number of transforms in the + * MultiTransformGroup object to be created + * @param setVisible if true, calls setVisible(true) on all + * created window components; otherwise, they remain invisible + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + */ + public ConfiguredUniverse(URL userConfig, + int transformCount, boolean setVisible) { + this(transformCount, null, userConfig, null, null, setVisible); + } + + /** + * Reads the configuration specified by the given URL to create a Locale + * using the given LocaleFactory, one or more ViewingPlatforms, and at + * least one Viewer object. The configuration file may also create + * InputDevice, Sensor, and ViewPlatformBehavior instances. + * + * @param userConfig the URL to the user's configuration file; passing in + * null creates a default Viewer and ViewingPlatform with the specified + * number of transforms + * @param localeFactory the factory object used to create the Locale + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + */ + public ConfiguredUniverse(URL userConfig, LocaleFactory localeFactory) { + this(1, null, userConfig, localeFactory, null, true); + } + + /** + * Reads the configuration specified by the given URL to create a Locale + * using the given LocaleFactory, one or more ViewingPlatforms, and at + * least one Viewer object with optional visibility. The configuration + * file may also create InputDevice, Sensor, and ViewPlatformBehavior + * instances. Window components used by the Viewers will remain invisible + * unless the setVisible flag is true. + * + * @param userConfig the URL to the user's configuration file; passing in + * null creates a default Viewer with the specified visibility and a + * default ViewingPlatform + * @param localeFactory the factory object used to create the Locale + * @param setVisible if true, calls setVisible(true) on all + * created window components; otherwise, they remain invisible + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + */ + public ConfiguredUniverse(URL userConfig, + LocaleFactory localeFactory, + boolean setVisible) { + this(1, null, userConfig, localeFactory, null, setVisible); + } + + /** + * Reads the configuration specified by the given URL to create a Locale + * using the specified LocaleFactory with the given origin, one or more + * ViewingPlatforms with the specified number of transforms, and at least + * one Viewer object with optional visibility. Window components used by + * the Viewers will remain invisible unless the setVisible + * flag is true. The configuration file may also create InputDevice, + * Sensor, and ViewPlatformBehavior instances. + * + * @param userConfig the URL to the user's configuration file; passing in + * null creates a default Viewer with the specified visibility and a + * ViewingPlatform with the specified number of transforms + * @param localeFactory the factory object used to create the Locale + * @param origin the origin used to set the origin of the Locale object; + * if this object is null, then 0.0 is used + * @param transformCount the number of transforms in the + * MultiTransformGroup object to be created + * @param setVisible if true, calls setVisible(true) on all + * created window components; otherwise, they remain invisible + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + */ + public ConfiguredUniverse(URL userConfig, LocaleFactory localeFactory, + HiResCoord origin, int transformCount, + boolean setVisible) { + + this(transformCount, null, userConfig, + localeFactory, origin, setVisible); + } + + /** + * Retrieves view-side scenegraph components from the given container to + * create a universe with one Locale, one or more ViewingPlatforms, and at + * least one Viewer object. Equivalent to + * ConfiguredUniverse(ConfigContainer, null, null). + * + * @param userConfig container holding viewing configuration components; + * must not be null + * + * @see #ConfiguredUniverse(ConfigContainer, LocaleFactory, HiResCoord) + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @since Java 3D 1.3.1 + */ + public ConfiguredUniverse(ConfigContainer userConfig) { + this(userConfig, null, null); + } + + /** + * Retrieves view-side scenegraph components from the given container to + * create a universe with one Locale created from the specified + * LocaleFactory and origin, one or more ViewingPlatforms, and at least + * one Viewer object. The container may also provide InputDevice, Sensor, + * and ViewPlatformBehavior instances which will be incorporated into the + * universe if they are referenced by any of the Viewer or ViewingPlatform + * instances.

+ * + * This constructor and ConfiguredUniverse(ConfigContainer) + * both accept ConfigContainer references directly and are the preferred + * interfaces for constructing universes from configuration files. They + * differ from the constructors that accept URL objects in the + * following ways:

+ *

    + *
  • A Viewer will be attached to a default ViewingPlatform only if + * no ViewingPlatforms are provided in the ConfigContainer. If one + * or more ViewingPlatforms are provided by the ConfigContainer, then + * Viewers must be attached to them explicitly in the configuration.

    + *

  • + *
  • ViewPlatformBehaviors will be attached to their specified + * ViewingPlatforms before ConfiguredUniverse can set a reference to + * itself in the ViewingPlatform. This means that a behavior can't + * get a reference to the universe at the time its + * setViewingPlatform method is called; it must wait + * until its initialize method is called.

    + *

  • + *
  • All Java properties used by Java 3D may be set in the beginning of + * the configuration file as long as there is no reference to a + * VirtualUniverse prior to creating the ConfigContainer. Note + * however, that some Java 3D utilities and objects such as + * Transform3D can cause static references to VirtualUniverse and + * trigger the evaluation of Java properties before they are set by + * ConfigContainer.

    + *

  • + *
+ * @param userConfig container holding viewing configuration components; + * must not be null + * @param localeFactory the factory object used to create the Locale, or + * null + * @param origin the origin used to set the origin of the Locale object; + * if this object is null, then 0.0 is used + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @since Java 3D 1.3.1 + */ + public ConfiguredUniverse(ConfigContainer userConfig, + LocaleFactory localeFactory, + HiResCoord origin) { + + super(origin, localeFactory); + configContainer = userConfig; + + Collection c = configContainer.getViewers(); + if (c == null || c.size() == 0) + throw new IllegalArgumentException( + "no views defined in configuration file"); + + viewer = (Viewer[])c.toArray(new Viewer[1]); + + c = configContainer.getViewingPlatforms(); + if (c == null || c.size() == 0) { + createDefaultViewingPlatform + (configContainer.getViewPlatformTransformCount()); + } + else { + Iterator i = c.iterator(); + while (i.hasNext()) { + ViewingPlatform vp = (ViewingPlatform)i.next(); + vp.setUniverse(this); + locale.addBranchGraph(vp); + } + } + } + + /** + * Package-scope constructor that creates the view side of the + * scene graph. The passed in parameters override the default + * values where appropriate. Note that the userCanvases parameter + * is ignored when the userConfig is non-null. + * + * @param transformCount the number of transforms in the + * MultiTransformGroup object to be created + * @param canvases the canvases to associate with the Viewer object; + * passing in null will cause this parameter to be ignored and a canvas + * to be created by the utility + * @param userConfig the URL to the user's configuration file; passing in + * null causes the default values to be used. + * @param localeFactory the factory object used to create the Locale + * @param origin the origin used to set the origin of the Locale object; + * if this object is null, then 0.0 is used + * @param setVisible if true, calls setVisible(true) on all + * created window components; otherwise, they remain invisible + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + */ + ConfiguredUniverse(int transformCount, + Canvas3D[] canvases, + URL userConfig, + LocaleFactory localeFactory, + HiResCoord origin, + boolean setVisible) { + + super(origin, localeFactory); + + if (userConfig == null) { + viewer = new Viewer[1]; + viewer[0] = new Viewer(canvases, null, null, setVisible); + createDefaultViewingPlatform(transformCount); + } + else { + // Create a ConfigContainer without attaching behaviors. The + // package-scope constructor is used for backward compatibility. + configContainer = new ConfigContainer + (userConfig, setVisible, transformCount, false); + + Collection c = configContainer.getViewers(); + if (c == null || c.size() == 0) + throw new IllegalArgumentException( + "no views defined in configuration file"); + + viewer = (Viewer[])c.toArray(new Viewer[1]); + + // Get ViewingPlatforms from the ConfigContainer and add them to + // the locale. The package-scoped findConfigObjects() accesor is + // used so that backward compatibility can be maintained for older + // configuration files. + c = configContainer.findConfigObjects("ViewPlatform"); + if (c == null || c.size() == 0) { + createDefaultViewingPlatform(transformCount); + } + else { + Iterator i = c.iterator(); + while (i.hasNext()) { + ConfigViewPlatform cvp = (ConfigViewPlatform)i.next(); + ViewingPlatform vp = cvp.viewingPlatform; + + // For backward compatibility, handle the default + // attachment of one Viewer to one ViewingPlatform. If + // there are multiple Viewers and ViewingPlatforms then + // attachments must be made explicitly in the config file. + if (vp.getViewers() == null && + viewer.length == 1 && c.size() == 1) { + if (cvp.viewAttachPolicy == -1) { + setDerivedAttachPolicy(viewer[0], vp) ; + } + viewer[0].setViewingPlatform(vp); + } + vp.setUniverse(this); + locale.addBranchGraph(vp); + + // If there's a behavior associated with the platform, + // attach it now after the setting the universe reference. + cvp.processBehavior(); + } + } + } + } + + /** + * Creates a default ViewingPlatform, attaches the first Viewer, and then + * attaches the platform to the Locale. + * + * @param transformCount number of TransformGroups to create in the + * ViewingPlatform + */ + private void createDefaultViewingPlatform(int transformCount) { + ViewingPlatform vp = new ViewingPlatform(transformCount); + setDerivedAttachPolicy(viewer[0], vp); + viewer[0].setViewingPlatform(vp); + vp.setUniverse(this); + locale.addBranchGraph(vp); + } + + /** + * Sets a view attach policy appropriate for a window eyepoint policy. + * + * @param v Viewer to which the ViewingPlatform will be attached + * @param vp ViewingPlatform to which the Viewer will be attached + */ + private void setDerivedAttachPolicy(Viewer v, ViewingPlatform vp) { + if (v.getView().getWindowEyepointPolicy() != + View.RELATIVE_TO_FIELD_OF_VIEW) { + vp.getViewPlatform().setViewAttachPolicy(View.NOMINAL_SCREEN); + } + } + + + /** + * Returns the Viewer object specified by the given index. + * + * @param index The index of which Viewer object to return. + * + * @return The Viewer object specified by the given index. + */ + public Viewer getViewer(int index) { + return viewer[index]; + } + + /** + * Returns all of the Viewer objects associated with this scene graph. + * + * @return The Viewer objects associated with this scene graph. + */ + public Viewer[] getViewers() { + Viewer[] ret = new Viewer[viewer.length]; + for (int i = 0; i < viewer.length; i++) { + ret[i] = viewer[i]; + } + return ret; + } + + /** + * Call setVisible() on all AWT components created by this + * ConfiguredUniverse instance.

+ * + * @param visible boolean to be passed to the setVisible() + * calls on the window components created by this + * ConfiguredUniverse instance + */ + public void setVisible(boolean visible) { + for (int i = 0; i < viewer.length; i++) + if (viewer[i] != null) + viewer[i].setVisible(visible); + } + + /** + * Returns the config file URL based on system properties. This is + * equivalent to calling ConfigContainer.getConfigURL(). The + * current implementation of this method parses the j3d.configURL property + * as a URL string. For example, the following command line would specify + * that the config file is taken from the file "j3dconfig" in the current + * directory: + *

    + * java -Dj3d.configURL=file:j3dconfig ... + *
+ * + * @return the URL of the config file; null is returned if no valid + * URL is defined by the system properties + */ + public static URL getConfigURL() { + return ConfigContainer.getConfigURL(null); + } + + /** + * Returns the config file URL based on system properties. This is the + * same as calling ConfigContainer.getConfigURL(String). The + * current implementation of this method parses the j3d.configURL property + * as a URL string. For example, the following command line would specify + * that the config file is taken from the file "j3dconfig" in the current + * directory: + *
    + * java -Dj3d.configURL=file:j3dconfig ... + *
+ * + * @param defaultURLString the default string used to construct + * the URL if the appropriate system properties are not defined + * @return the URL of the config file; null is returned if no + * valid URL is defined either by the system properties or the + * default URL string + */ + public static URL getConfigURL(String defaultURLString) { + return ConfigContainer.getConfigURL(defaultURLString); + } + + /** + * Returns all named Sensors defined by the configuration file used to + * create the ConfiguredUniverse, if any. Equivalent to + * getConfigContainer().getNamedSensors().

+ * + * With the sole exception of the Sensor assigned to the head tracker, + * none of the Sensors defined in the configuration file are placed into + * the Sensor array maintained by PhysicalEnvironment. The head tracker + * Sensor is the only one read by the Java 3D core and must generate reads + * with a full 6 degrees of freedom (3D position and 3D orientation).

+ * + * Other Sensors need not generate reads with a full 6 degrees of freedom, + * although their reads must be expressed using Transform3D. Some + * joysticks may provide only 2D relative X and Y axis movement; dials, + * levers, and sliders are 1D devices, and some devices may combine dials + * and levers to generate 3D positional data.

+ * + * The index names to identify left / right / dominant / non-dominant hand + * Sensors in the PhysicalEnvironement Sensor array are not adequate to + * distinguish these differences, so this method allows applications to + * look up Sensors based on the names bound to them in the configuration + * file. There are no set rules on naming. Applications that use Sensors + * may set up conventions for generic devices such as "mouse6D" or + * "joystick2D" or specific product names.

+ * + * @return read-only Map which maps Sensor names to the associated Sensors, + * or null if no Sensors have been named + */ + public Map getNamedSensors() { + if (configContainer == null) + return null; + else + return configContainer.getNamedSensors(); + } + + /** + * Returns all named ViewPlatformBehaviors defined by the configuration + * file used to create the ConfiguredUniverse, if any. Equivalent + * to getConfigContainer().getNamedViewPlatformBehaviors().

+ * + * @return read-only Map which maps behavior names to the associated + * ViewPlatformBehavior instances, or null if none have been named. + * @since Java 3D 1.3.1 + */ + public Map getNamedBehaviors() { + if (configContainer == null) + return null; + else + return configContainer.getNamedViewPlatformBehaviors(); + } + + /** + * Returns a container holding all the objects defined by the + * configuration file used to create the ConfiguredUniverse. + * + * @return the container + * @since Java 3D 1.3.1 + */ + public ConfigContainer getConfigContainer() { + return configContainer; + } + + /** + * Cleanup memory references used by ConfiguredUniverse. + * @since Java 3D 1.3.1 + */ + public void cleanup() { + if (viewer != null) { + for (int i = 0 ; i < viewer.length ; i++) { + viewer[i].getView().removeAllCanvas3Ds(); + viewer[i].setViewingPlatform(null); + viewer[i] = null; + } + } + + locale = null; + removeAllLocales(); + Viewer.clearViewerMap(); + + configContainer.clear(); + configContainer = null; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/LocaleFactory.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/LocaleFactory.java new file mode 100644 index 0000000..08e7e36 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/LocaleFactory.java @@ -0,0 +1,82 @@ +/* + * $RCSfile: LocaleFactory.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import javax.media.j3d.Locale; +import javax.media.j3d.HiResCoord; +import javax.media.j3d.VirtualUniverse; + +/** + * This interface defines a factory for creating Locale objects in a + * SimpleUniverse. Implementations of the createLocale methods in + * this interface should construct a new Locale object from the + * specified parameters. This class is used by the SimpleUniverse + * class to construct the default Locale used to hold the view and + * content branch graphs. + * + * @see Locale + * @see ConfiguredUniverse + * @see SimpleUniverse + * + * @since Java 3D 1.3 + */ +public interface LocaleFactory { + /** + * Creates a new Locale object at the specified high resolution + * coordinate in the specified universe. + * + * @param universe the VirtualUniverse in which to create the Locale + * @param hiRes the high resolution coordinate that defines the origin + * of the Locale + */ + public Locale createLocale(VirtualUniverse universe, HiResCoord hiRes); + + /** + * Creates a new Locale object at (0, 0, 0) in the specified universe. + * + * @param universe the VirtualUniverse in which to create the Locale + */ + public Locale createLocale(VirtualUniverse universe); +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/MultiTransformGroup.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/MultiTransformGroup.java new file mode 100644 index 0000000..b3db3d4 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/MultiTransformGroup.java @@ -0,0 +1,140 @@ +/* + * $RCSfile: MultiTransformGroup.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * A convenience class that effectively creates a series of TransformGroup + * nodes connected one to another hierarchically. For most applications, + * creating a MultiTransformGroup containing one transform will suffice. + * More sophisticated applications that use a complex portal/head tracking + * viewing system may find that more transforms are needed. + *

+ * When more than one transform is needed, transform[0] is considered the + * "top most" transform with repsect to the scene graph, (attached to the + * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom + * most" transform (the ViewPlatorm object is attached to this transform). + */ +public class MultiTransformGroup { + + // For now just have an array of TransformGroup nodes. + TransformGroup[] transforms; + + /** + * Creates a MultiTransformGroup node that contains a single transform. + * This is effectively equivalent to creating a single TransformGroup + * node. + */ + public MultiTransformGroup() { + this(1); + } + + /** + * Creates a MultiTransformGroup node that contains the specified + * number of transforms. + *

+ * When more than one transform is needed, transform[0] is considered the + * "top most" transform with repsect to the scene graph, (attached to the + * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom + * most" transform (the ViewPlatorm object is attached to this transform). + * + * @param numTransforms The number of transforms for this node to + * contain. If this number is less than one, one is assumed. + */ + public MultiTransformGroup(int numTransforms) { + if (numTransforms < 1) + numTransforms = 1; + + transforms = new TransformGroup[numTransforms]; + + // there is always at least one TransformGroup + transforms[0] = new TransformGroup(); + transforms[0].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + transforms[0].setCapability(TransformGroup.ALLOW_TRANSFORM_READ); + transforms[0].setCapability(TransformGroup.ALLOW_CHILDREN_WRITE); + transforms[0].setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND); + + for (int i = 1; i < numTransforms; i++) { + transforms[i] = new TransformGroup(); + transforms[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + transforms[i].setCapability(TransformGroup.ALLOW_TRANSFORM_READ); + transforms[i].setCapability(TransformGroup.ALLOW_CHILDREN_WRITE); + transforms[i].setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND); + transforms[i-1].addChild(transforms[i]); + } + } + + /** + * Returns the selected TransformGroup node. + * + * @param transform The index of the transform to return. The indices + * are in the range [0..(n - 1)] - where n was the number of transforms + * created. transform[0] is considered the + * "top most" transform with repsect to the scene graph, (attached to the + * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom + * most" transform (the ViewPlatorm object is attached to this transform). + * + * @return The TransformGroup node at the designated index. If an out of + * range index is given, null is returned. + */ + public TransformGroup getTransformGroup(int transform) { + if (transform >= transforms.length || transform < 0) + return null; + + return transforms[transform]; + } + + /** + * Returns the number of transforms in this MultiTransformGroup object. + * + * @return The number of transforms in this object. + */ + public int getNumTransforms() { + return transforms.length; + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/PlatformGeometry.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/PlatformGeometry.java new file mode 100644 index 0000000..d6ec046 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/PlatformGeometry.java @@ -0,0 +1,66 @@ +/* + * $RCSfile: PlatformGeometry.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:44 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * This class holds any geometry that should be associated with the + * ViewingPlatform object. To create a scene with a dashboard, for + * instance, a programmer would place the dashboard geometry under + * the PlatformGeometry node. + * + * @see ViewingPlatform + */ +public class PlatformGeometry extends BranchGroup { + + /** + * Constructs an instance of the PlatformGeometry node. + */ + public PlatformGeometry() { + setCapability(ALLOW_DETACH); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/SimpleUniverse.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/SimpleUniverse.java new file mode 100644 index 0000000..e4dc41a --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/SimpleUniverse.java @@ -0,0 +1,454 @@ +/* + * $RCSfile: SimpleUniverse.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.7 $ + * $Date: 2007/02/09 17:20:45 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import com.sun.j3d.utils.geometry.Primitive; +import java.awt.GraphicsEnvironment; +import java.awt.GraphicsConfiguration; +import java.net.URL; + +import javax.media.j3d.*; + + +/** + * This class sets up a minimal user environment to quickly and easily + * get a Java 3D program up and running. This utility class creates + * all the necessary objects on the "view" side of the scene graph. + * Specifically, this class creates a locale, a single ViewingPlatform, + * and a Viewer object (both with their default values). + * Many basic Java 3D applications + * will find that SimpleUniverse provides all necessary functionality + * needed by their applications. More sophisticated applications + * may find that they need more control in order to get extra functionality + * and will not be able to use this class. + * + * @see Viewer + * @see ViewingPlatform + */ +public class SimpleUniverse extends VirtualUniverse { + + /** + * Locale reference needed to create the "view" portion + * of the scene graph. + */ + protected Locale locale; + + /** + * Viewer reference needed to create the "view" portion + * of the scene graph. + */ + protected Viewer[] viewer = null; + + /** + * Creates a locale, a single ViewingPlatform, and + * and a Viewer object (both with their default values). + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + */ + public SimpleUniverse() { + // call main constructor with default values. + this(null, 1, null, null); + } + + /** + * Creates a locale, a single ViewingPlatform, and a Viewer object + * (with default values). The ViewingPlatform is created with the + * specified number of TransformGroups. + * + * @param numTransforms The number of transforms to be in the + * MultiTransformGroup object. + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * + * @since Java 3D 1.2.1 + */ + public SimpleUniverse(int numTransforms) { + // call main constructor with default values except numTransforms + this(null, numTransforms, null, null); + } + + /** + * Creates a locale, a single ViewingPlatform (with default values), and + * and a Viewer object. The Viewer object uses default values for + * everything but the canvas. + * + * @param canvas The canvas to associate with the Viewer object. Passing + * in null will cause this parameter to be ignored and a canvas to be + * created by the utility. + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + */ + public SimpleUniverse(Canvas3D canvas) { + // call main constructor with default values for everything but + // the canvas parameter. + this(null, 1, canvas, null); + } + + /** + * Creates a locale, a single ViewingPlatform, and a Viewer object + * The Viewer object uses default values for everything but the canvas. + * The ViewingPlatform is created with the specified number of + * TransformGroups. + * + * @param canvas The canvas to associate with the Viewer object. Passing + * in null will cause this parameter to be ignored and a canvas to be + * created by the utility. + * @param numTransforms The number of transforms to be in the + * MultiTransformGroup object. + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + * + * @since Java 3D 1.2.1 + */ + public SimpleUniverse(Canvas3D canvas, int numTransforms) { + // call main constructor with default values except canvas + // and numTransforms + this(null, numTransforms, canvas, null); + } + + /** + * Creates a locale, a single ViewingPlatform, and a Viewer object + * The Viewer object uses default values for everything but the canvas. + * The ViewingPlatform is created with the specified number of + * TransformGroups. + * + * @param canvas The canvas to associate with the Viewer object. Passing + * in null will cause this parameter to be ignored and a canvas to be + * created by the utility. + * @param numTransforms The number of transforms to be in the + * MultiTransformGroup object. + * @param localeFactory Factory for creating the locale + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + * + * @since Java 3D 1.5.1 + */ + public SimpleUniverse(Canvas3D canvas, int numTransforms, LocaleFactory localeFactory) { + // call main constructor with default values except canvas, + // numTransforms and localeFactory + this(null, numTransforms, canvas, null, localeFactory); + } + + /** + * Creates the "view" side of the scene graph. The passed in parameters + * override the default values where appropriate. + * + * @param origin The origin used to set the origin of the Locale object. + * If this object is null, then 0.0 is used. + * @param numTransforms The number of transforms to be in the + * MultiTransformGroup object. + * @param canvas The canvas to draw into. If this is null, it is + * ignored and a canvas will be created by the utility. + * @param userConfig The URL to the user's configuration file, used + * by the Viewer object. This is never examined and default values are + * always taken. + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + * @deprecated use ConfiguredUniverse constructors to read a + * configuration file + */ + public SimpleUniverse(HiResCoord origin, int numTransforms, + Canvas3D canvas, URL userConfig) { + this( origin, numTransforms, canvas, userConfig, null ); + } + + /** + * Creates the "view" side of the scene graph. The passed in parameters + * override the default values where appropriate. + * + * @param origin The origin used to set the origin of the Locale object. + * If this object is null, then 0.0 is used. + * @param numTransforms The number of transforms to be in the + * MultiTransformGroup object. + * @param canvas The canvas to draw into. If this is null, it is + * ignored and a canvas will be created by the utility. + * @param userConfig The URL to the user's configuration file, used + * by the Viewer object. This is never examined and default values are + * always taken. + * @param localeFactory The Locale Factory which will instantiate the + * locale(s) for this universe. + * + * @see Locale + * @see Viewer + * @see ViewingPlatform + * @see MultiTransformGroup + * @deprecated use ConfiguredUniverse constructors to read a + * configuration file + */ + public SimpleUniverse(HiResCoord origin, int numTransforms, + Canvas3D canvas, URL userConfig, LocaleFactory localeFactory ) { + ViewingPlatform vwp; + + createLocale( origin, localeFactory ); + + // Create the ViewingPlatform and Viewer objects, passing + // down the appropriate parameters. + vwp = new ViewingPlatform(numTransforms); + vwp.setUniverse( this ); + viewer = new Viewer[1]; + // viewer[0] = new Viewer(canvas, userConfig); + viewer[0] = new Viewer(canvas); + viewer[0].setViewingPlatform(vwp); + + // Add the ViewingPlatform to the locale - the scene + // graph is now "live". + locale.addBranchGraph(vwp); + } + + + /** + * Creates the "view" side of the scene graph. The passed in parameters + * override the default values where appropriate. + * + * @param viewingPlatform The viewingPlatform to use to create + * the "view" side of the scene graph. + * @param viewer The viewer object to use to create + * the "view" side of the scene graph. + */ + public SimpleUniverse(ViewingPlatform viewingPlatform, Viewer viewer) { + this( viewingPlatform, viewer, null ); + } + + /** + * Creates the "view" side of the scene graph. The passed in parameters + * override the default values where appropriate. + * + * @param viewingPlatform The viewingPlatform to use to create + * the "view" side of the scene graph. + * @param viewer The viewer object to use to create + * the "view" side of the scene graph. + * @param localeFactory The factory used to create the Locale Object + */ + public SimpleUniverse(ViewingPlatform viewingPlatform, Viewer viewer, + LocaleFactory localeFactory ) { + createLocale( null, localeFactory ); + viewingPlatform.setUniverse( this ); + + // Assign object references. + this.viewer = new Viewer[1]; + this.viewer[0] = viewer; + + // Add the ViewingPlatform to the Viewer object. + this.viewer[0].setViewingPlatform(viewingPlatform); + + // Add the ViewingPlatform to the locale - the scene + // graph is now "live". + locale.addBranchGraph(viewingPlatform); + } + + /** + * Constructor for use by Configured Universe + */ + SimpleUniverse( HiResCoord origin, LocaleFactory localeFactory ) { + createLocale( origin, localeFactory ); + } + + /** + * Create the Locale using the LocaleFactory and HiRes origin, + * if specified. + */ + private void createLocale( HiResCoord origin, + LocaleFactory localeFactory ) { + + if (localeFactory != null) { + if (origin != null) + locale = localeFactory.createLocale(this, origin); + else + locale = localeFactory.createLocale(this); + } + else { + if (origin != null) + locale = new Locale(this, origin); + else + locale = new Locale(this); + } + } + + /** + * Returns the Locale object associated with this scene graph. + * + * @return The Locale object used in the construction of this scene + * graph. + */ + public Locale getLocale() { + return locale; + } + + /** + * Returns the Viewer object associated with this scene graph. + * SimpleUniverse creates a single Viewer object for use in the + * scene graph. + * + * @return The Viewer object associated with this scene graph. + */ + public Viewer getViewer() { + return viewer[0]; + } + + /** + * Returns the ViewingPlatform object associated with this scene graph. + * + * @return The ViewingPlatform object of this scene graph. + */ + public ViewingPlatform getViewingPlatform() { + return viewer[0].getViewingPlatform(); + } + + /** + * Returns the Canvas3D object associated with this Java 3D Universe. + * + * @return A reference to the Canvas3D object associated with the + * Viewer object. This method is equivalent to calling getCanvas(0). + * + * @see Viewer + */ + public Canvas3D getCanvas() { + return getCanvas(0); + } + + /** + * Returns the Canvas3D object at the specified index associated with + * this Java 3D Universe. + * + * @param canvasNum The index of the Canvas3D object to retrieve. + * If there is no Canvas3D object for the given index, null is returned. + * + * @return A reference to the Canvas3D object associated with the + * Viewer object. + */ + public Canvas3D getCanvas(int canvasNum) { + return viewer[0].getCanvas3D(canvasNum); + } + + /** + * Used to add Nodes to the geometry side (as opposed to the view side) + * of the scene graph. This is a short cut to getting the Locale object + * and calling that object's addBranchGraph() method. + * + * @param bg The BranchGroup to attach to this Universe's Locale. + */ + public void addBranchGraph(BranchGroup bg) { + locale.addBranchGraph(bg); + } + + /** + * Finds the preferred GraphicsConfiguration object + * for the system. This object can then be used to create the + * Canvas3D objet for this system. + * + * @return The best GraphicsConfiguration object for + * the system. + */ + public static GraphicsConfiguration getPreferredConfiguration() { + GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D(); + String stereo; + + // Check if the user has set the Java 3D stereo option. + // Getting the system properties causes appletviewer to fail with a + // security exception without a try/catch. + + stereo = (String) java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + return System.getProperty("j3d.stereo"); + } + }); + + // update template based on properties. + if (stereo != null) { + if (stereo.equals("REQUIRED")) + template.setStereo(template.REQUIRED); + else if (stereo.equals("PREFERRED")) + template.setStereo(template.PREFERRED); + } + + // Return the GraphicsConfiguration that best fits our needs. + return GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getBestConfiguration(template); + } + + /** + * Cleanup memory use and reference by SimpleUniverse. + * Typically it should be invoked by the applet's destroy method. + */ + public void cleanup() { + // Get view associated with this SimpleUniverse + View view = viewer[0].getView(); + + // Issue 134: cleanup all off-screen canvases + for (int i = view.numCanvas3Ds() - 1; i >= 0; i--) { + Canvas3D c = view.getCanvas3D(i); + if (c.isOffScreen()) { + c.setOffScreenBuffer(null); + } + } + + // Remove all canvases from view; remove the viewing platform from + // this viewer; remove all locales to cleanup the scene graph + view.removeAllCanvas3Ds(); + viewer[0].setViewingPlatform(null); + removeAllLocales(); + + // viewerMap cleanup here to prevent memory leak problem. + Viewer.clearViewerMap(); + Primitive.clearGeometryCache(); + + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewInfo.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewInfo.java new file mode 100644 index 0000000..397b04b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewInfo.java @@ -0,0 +1,3406 @@ +/* + * $RCSfile: ViewInfo.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.6 $ + * $Date: 2007/02/09 17:20:45 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe ; + +import java.awt.GraphicsConfiguration ; +import java.awt.GraphicsEnvironment; +import java.awt.Point ; +import java.awt.Rectangle ; +import java.text.DecimalFormat ; +import java.text.FieldPosition ; +import java.util.* ; +import javax.media.j3d.* ; +import javax.vecmath.* ; + +/** + * Provides methods to extract synchronized transform information from a View. + * These transforms are derived from application scene graph information, as + * opposed to similar core Java 3D methods that derive transforms from + * internally maintained data. This allows updates to the scene graph to be + * synchronized with the current view platform position.

+ * + * The architecture of the Java 3D 1.3 sample implementation introduces a + * frame latency between updates to the application scene graph structure and + * their effects on internal Java 3D state. getImagePlateToVworld + * and other methods in the core Java 3D classes use a transform from view + * platform coordinates to virtual world coordinates that can be out of date + * with respect to the state of the view platform as set by the application. + * When an application uses the transforms returned by those methods to update + * view dependent parts of the scene graph, those updates might not be + * synchronized with what the viewer actually sees.

+ * + * The methods in this class work around this problem at the expense of + * querying the application state of the scene graph to get the current + * transform from view platform to virtual world coordinates. This can + * involve a potential performance degradation, however, since the application + * scene graph state is not designed for high performance queries. The view + * platform must also have ALLOW_LOCAL_TO_VWORLD_READ capability + * set, which potentially inhibits internal scene graph optimization.

+ * + * On the other hand, application behaviors that create the view platform + * transformation directly will have access to it without the need to query it + * from the scene graph; in that case, the transforms from physical + * coordinates to view platform coordinates provided by this class are all + * that are needed. The ALLOW_LOCAL_TO_VWORLD_READ view platform + * capability doesn't need to be set for these applications.

+ * + * Other Synchronization Issues

+ * + * Scene graph updates are guaranteed to take effect in the same frame only + * if run from the processStimulus() method of a Behavior. Updates from + * multiple behaviors are only guaranteed to take effect in the same frame if + * they're responding to a WakeupOnElapsedFrames(0) condition. Use a single + * behavior to perform view dependent updates if possible; otherwise, use + * WakeupOnElapsedFrames(0) and set behavior scheduling intervals to ensure + * that behaviors that need the current view platform transform are run after + * it's set. Updating scene graph elements from anything other than the + * Behavior thread, such as an external input thread or a renderer callback + * in Canvas3D, will not necessarily be synchronized with rendering.

+ * + * Direct updates to geometry data have a different frame latency than + * updates to scene graph transforms and structure. In the Java 3D 1.3 + * architecture, updates to by-reference geometry arrays and texture data have + * a 1-frame latency, while updates to transforms and scene graph structure + * have a 2-frame latency. Because of bug 4799494, which is outstanding + * in Java 3D 1.3.1, updates to by-copy geometry arrays also have a 1-frame + * latency. It is therefore recommended that view dependent scene graph + * updates be limited to transforms and scene graph structure only.

+ * + * If it is not possible to avoid updating geometry directly, then these + * updates must be delayed by one frame in order to remain synchronized with + * the view platform. This can be accomplished by creating an additional + * behavior to actually update the geometry, separate from the behavior that + * computes the changes that need to be made based on current view state. If + * the update behavior is awakened by a behavior post from the computing + * behavior then the update will be delayed by a single frame.

+ * + * Implementation Notes

+ * + * This utility is essentially a rewrite of a few private Java 3D core + * classes, but designed for public use and source code availability. The + * source code may be helpful in understanding some of the more complex + * aspects of the view model, especially with regards to various interactions + * between attributes which are not adequately documented. None of the actual + * core Java 3D source code is used, but the code is designed to comply with + * the view model as defined by the Java 3D Specification, so it can be + * considered an alternative implementation. This class will produce the + * same results as the Java 3D core implementation except for:

    + * + *
  • The frame latency issue for virtual world transforms.
  • + * + *

  • Active clip node status. If a clip node is active in the scene graph, + * it should override the view's back clip plane. This class has no such + * information, so this can't be implemented.
  • + * + *

  • "Infinite" view transforms for background geometry. These are simply + * the rotation components of the normal view transforms with adjusted + * clip planes. Again, this function depends upon scene graph content + * inaccessible to this class.
  • + * + *

  • Small floating point precision differences resulting from the + * alternative computations.
  • + * + *

  • Bugs in this class and the Java 3D core.
  • + * + *

  • Tracked head position.

+ * + * The last item deserves some mention. Java 3D provides no way to directly + * query the tracked head position being used by the renderer. The View's + * getUserHeadToVworld method always incorporates a virtual world + * transform that is out of date with respect to the application scene graph + * state. ViewInfo reads data from the head tracking sensor directly, but + * since head trackers are continuous input devices, getting the same data + * that the renderer is using is unlikely. See the source code for the + * private method getHeadInfo in this class for more information + * and possible workarounds.

+ * + * Thread Safety

+ * + * All transforms are lazily evaluated. The updateScreen, + * updateCanvas, updateViewPlatform, + * updateView, and updateHead methods just set flags + * indicating that derived transforms need to be recomputed; they are safe to + * call from any thread. updateCanvas, for example, can safely + * be called from an AWT event listener.

+ * + * Screens and view platforms can be shared between separate views in the Java + * 3D view model. To remain accurate, ViewInfo also allows this sharing. + * Since it is likely that a multi-view application has separate threads + * managing each view, potential concurrent modification of data associated + * with a screen or a view platform is internally synchronized in this class. + * It is safe for each thread to use its own instance of a ViewInfo + * corresponding to the view it is managing.

+ * + * Otherwise, none of the other methods in this class are internally + * synchronized. Except for the update methods mentioned above, a single + * instance of ViewInfo should not be used by more than one concurrent thread + * without external synchronization.

+ * + * @since Java 3D 1.3.1 + */ +public class ViewInfo { + private final static boolean verbose = false ; + + /** + * Indicates that updates to a Screen3D associated with the View should + * be automatically checked with each call to a public method in this + * class. + */ + public final static int SCREEN_AUTO_UPDATE = 1 ; + + /** + * Indicates that updates to a Canvas3D associated with the View should + * be automatically checked with each call to a public method in this + * class. + */ + public final static int CANVAS_AUTO_UPDATE = 2 ; + + /** + * Indicates that updates to the View should be automatically checked + * with each call to a public method in this class. + */ + public final static int VIEW_AUTO_UPDATE = 4 ; + + /** + * Indicates that updates to the tracked head position should be + * automatically checked with each call to a public method in this class. + */ + public final static int HEAD_AUTO_UPDATE = 8 ; + + /** + * Indicates that updates to the ViewPlatform localToVworld + * transform should be automatically checked with each call to a public + * method in this class. The View must be attached to a ViewPlatform + * which is part of a live scene graph, and the ViewPlatform node must + * have its ALLOW_LOCAL_TO_VWORLD_READ capability set. + */ + public final static int PLATFORM_AUTO_UPDATE = 16 ; + + // + // Screen3D and ViewPlatform instances are shared across multiple Views in + // the Java 3D view model. Since ViewInfo is per-View and we want to + // cache screen and platform derived data, we maintain static references + // to the screens and platforms here. + // + // From a design standpoint our ViewInfo objects should probably be in the + // scope of an object that encloses these maps so they can be gc'ed + // properly. This is cumbersome with the current design constraints, so + // for now we provide an alternative constructor to override these static + // maps and a method to explicitly clear them. The alternative + // constructor can be used to wrap this class into a multi-view context + // that provides the maps. + // + private static Map staticVpMap = new HashMap() ; + private static Map staticSiMap = new HashMap() ; + + private Map screenMap = null ; + private Map viewPlatformMap = null ; + + // The target View and some derived data. + private View view = null ; + private Sensor headTracker = null ; + private boolean useTracking = false ; + private boolean clipVirtual = false ; + + // The current ViewPlatform and Canvas3D information used by this object. + private ViewPlatformInfo vpi = null ; + private int canvasCount = 0 ; + private Map canvasMap = new HashMap() ; + private CanvasInfo[] canvasInfo = new CanvasInfo[1] ; + + // This View's update flags. The other update flags are maintained by + // ScreenInfo, CanvasInfo, and ViewPlatformInfo. + private boolean updateView = true ; + private boolean updateHead = true ; + private boolean autoUpdate = false ; + private int autoUpdateFlags = 0 ; + + // Cached View policies. + private int viewPolicy = View.SCREEN_VIEW ; + private int resizePolicy = View.PHYSICAL_WORLD ; + private int movementPolicy = View.PHYSICAL_WORLD ; + private int eyePolicy = View.RELATIVE_TO_FIELD_OF_VIEW ; + private int projectionPolicy = View.PERSPECTIVE_PROJECTION ; + private int frontClipPolicy = View.PHYSICAL_EYE ; + private int backClipPolicy = View.PHYSICAL_EYE ; + private int scalePolicy = View.SCALE_SCREEN_SIZE ; + private boolean coeCentering = true ; + + // This View's cached transforms. See ScreenInfo, CanvasInfo, and + // ViewPlatformInfo for the rest of the cached transforms. + private Transform3D coeToTrackerBase = null ; + private Transform3D headToHeadTracker = null ; + + // These are from the head tracker read. + private Transform3D headTrackerToTrackerBase = null ; + private Transform3D trackerBaseToHeadTracker = null ; + + // These are derived from the head tracker read. + private Transform3D headToTrackerBase = null ; + private Transform3D coeToHeadTracker = null ; + + // Cached physical body and environment. + private PhysicalEnvironment env = null ; + private PhysicalBody body = null ; + private Point3d leftEyeInHead = new Point3d() ; + private Point3d rightEyeInHead = new Point3d() ; + + // Temporary variables. These could just be new'ed as needed, but we'll + // assume that ViewInfo instances are used much more than they're created. + private Vector3d v3d = new Vector3d() ; + private double[] m16d = new double[16] ; + private Point3d leftEye = new Point3d() ; + private Point3d rightEye = new Point3d() ; + private Map newMap = new HashMap() ; + private Set newSet = new HashSet() ; + + /** + * Creates a new ViewInfo for the specified View.

+ * + * Applications are responsible for informing this class of changes to the + * View, its Canvas3D and Screen3D components, the tracked head position, + * and the ViewPlatform's localToVworld transform. These + * notifications are performed with the updateView, + * updateCanvas, updateScreen, + * updateHead, and updateViewPlatform + * methods.

+ * + * The View must be attached to a ViewPlatform. If the ViewPlatform is + * attached to a live scene graph, then ALLOW_POLICY_READ + * capability must be set on the ViewPlatform node. + * + * @param view the View to use + * @see #updateView + * @see #updateCanvas updateCanvas(Canvas3D) + * @see #updateScreen updateScreen(Screen3D) + * @see #updateHead + * @see #updateViewPlatform + */ + public ViewInfo(View view) { + this(view, 0) ; + } + + /** + * Creates a new ViewInfo for the specified View. The View must be + * attached to a ViewPlatform. If the ViewPlatform is attached to a live + * scene graph, then ALLOW_POLICY_READ capability must be set + * on the ViewPlatform node. + * + * @param view the View to use

+ * @param autoUpdateFlags a logical OR of any of the + * VIEW_AUTO_UPDATE, CANVAS_AUTO_UPDATE, + * SCREEN_AUTO_UPDATE, HEAD_AUTO_UPDATE, or + * PLATFORM_AUTO_UPDATE flags to control whether changes to + * the View, its Canvas3D or Screen3D components, the tracked head + * position, or the ViewPlatform's localToVworld transform + * are checked automatically with each call to a public method of this + * class; if a flag is not set, then the application must inform this + * class of updates to the corresponding data + */ + public ViewInfo(View view, int autoUpdateFlags) { + this(view, autoUpdateFlags, staticSiMap, staticVpMap) ; + } + + /** + * Creates a new ViewInfo for the specified View. The View must be + * attached to a ViewPlatform. If the ViewPlatform is attached to a live + * scene graph, then ALLOW_POLICY_READ capability must be set + * on the ViewPlatform node.

+ * + * ViewInfo caches Screen3D and ViewPlatform data, but Screen3D and + * ViewPlatform instances are shared across multiple Views in the Java 3D + * view model. Since ViewInfo is per-View, all ViewInfo constructors + * except for this one use static references to manage the shared Screen3D + * and ViewPlatform objects. In this constructor, however, the caller + * supplies two Map instances to hold these references for all ViewInfo + * instances, so static references can be avoided; it can be used to wrap + * this class into a multi-view context that provides the required + * maps.

+ * + * Alternatively, the other constructors can be used by calling + * ViewInfo.clear when done with ViewInfo, or by simply + * retaining the static references until the JVM exits.

+ * + * @param view the View to use

+ * @param autoUpdateFlags a logical OR of any of the + * VIEW_AUTO_UPDATE, CANVAS_AUTO_UPDATE, + * SCREEN_AUTO_UPDATE, HEAD_AUTO_UPDATE, or + * PLATFORM_AUTO_UPDATE flags to control whether changes to + * the View, its Canvas3D or Screen3D components, the tracked head + * position, or the ViewPlatform's localToVworld transform + * are checked automatically with each call to a public method of this + * class; if a flag is not set, then the application must inform this + * class of updates to the corresponding data

+ * @param screenMap a writeable Map to hold Screen3D information + * @param viewPlatformMap a writeable Map to hold ViewPlatform information + */ + public ViewInfo(View view, int autoUpdateFlags, + Map screenMap, Map viewPlatformMap) { + + if (verbose) + System.err.println("ViewInfo: init " + hashCode()) ; + if (view == null) + throw new IllegalArgumentException("View is null") ; + if (screenMap == null) + throw new IllegalArgumentException("screenMap is null") ; + if (viewPlatformMap == null) + throw new IllegalArgumentException("viewPlatformMap is null") ; + + this.view = view ; + this.screenMap = screenMap ; + this.viewPlatformMap = viewPlatformMap ; + + if (autoUpdateFlags == 0) { + this.autoUpdate = false ; + } + else { + this.autoUpdate = true ; + this.autoUpdateFlags = autoUpdateFlags ; + } + + getViewInfo() ; + } + + /** + * Gets the current transforms from image plate coordinates to view + * platform coordinates and copies them into the given Transform3Ds.

+ * + * With a monoscopic canvas the image plate transform is copied to the + * first argument and the second argument is not used. For a stereo + * canvas the first argument receives the left image plate transform, and + * if the second argument is non-null it receives the right image plate + * transform. These transforms are always the same unless a head mounted + * display driven by a single stereo canvas is in use. + * + * @param c3d the Canvas3D associated with the image plate + * @param ip2vpl the Transform3D to receive the left transform + * @param ip2vpr the Transform3D to receive the right transform, or null + */ + public void getImagePlateToViewPlatform(Canvas3D c3d, + Transform3D ip2vpl, + Transform3D ip2vpr) { + + CanvasInfo ci = updateCache + (c3d, "getImagePlateToViewPlatform", false) ; + + getImagePlateToViewPlatform(ci) ; + ip2vpl.set(ci.plateToViewPlatform) ; + if (ci.useStereo && ip2vpr != null) + ip2vpr.set(ci.rightPlateToViewPlatform) ; + } + + private void getImagePlateToViewPlatform(CanvasInfo ci) { + if (ci.updatePlateToViewPlatform) { + if (verbose) System.err.println("updating PlateToViewPlatform") ; + if (ci.plateToViewPlatform == null) + ci.plateToViewPlatform = new Transform3D() ; + + getCoexistenceToImagePlate(ci) ; + getViewPlatformToCoexistence(ci) ; + + ci.plateToViewPlatform.mul(ci.coeToPlate, ci.viewPlatformToCoe) ; + ci.plateToViewPlatform.invert() ; + + if (ci.useStereo) { + if (ci.rightPlateToViewPlatform == null) + ci.rightPlateToViewPlatform = new Transform3D() ; + + ci.rightPlateToViewPlatform.mul(ci.coeToRightPlate, + ci.viewPlatformToCoe) ; + ci.rightPlateToViewPlatform.invert() ; + } + ci.updatePlateToViewPlatform = false ; + if (verbose) t3dPrint(ci.plateToViewPlatform, "plateToVp") ; + } + } + + /** + * Gets the current transforms from image plate coordinates to virtual + * world coordinates and copies them into the given Transform3Ds.

+ * + * With a monoscopic canvas the image plate transform is copied to the + * first argument and the second argument is not used. For a stereo + * canvas the first argument receives the left image plate transform, and + * if the second argument is non-null it receives the right image plate + * transform. These transforms are always the same unless a head mounted + * display driven by a single stereo canvas is in use.

+ * + * The View must be attached to a ViewPlatform which is part of a live + * scene graph, and the ViewPlatform node must have its + * ALLOW_LOCAL_TO_VWORLD_READ capability set. + * + * @param c3d the Canvas3D associated with the image plate + * @param ip2vwl the Transform3D to receive the left transform + * @param ip2vwr the Transform3D to receive the right transform, or null + */ + public void getImagePlateToVworld(Canvas3D c3d, + Transform3D ip2vwl, Transform3D ip2vwr) { + + CanvasInfo ci = updateCache(c3d, "getImagePlateToVworld", true) ; + getImagePlateToVworld(ci) ; + ip2vwl.set(ci.plateToVworld) ; + if (ci.useStereo && ip2vwr != null) + ip2vwr.set(ci.rightPlateToVworld) ; + } + + private void getImagePlateToVworld(CanvasInfo ci) { + if (ci.updatePlateToVworld) { + if (verbose) System.err.println("updating PlateToVworld") ; + if (ci.plateToVworld == null) + ci.plateToVworld = new Transform3D() ; + + getImagePlateToViewPlatform(ci) ; + ci.plateToVworld.mul + (vpi.viewPlatformToVworld, ci.plateToViewPlatform) ; + + if (ci.useStereo) { + if (ci.rightPlateToVworld == null) + ci.rightPlateToVworld = new Transform3D() ; + + ci.rightPlateToVworld.mul + (vpi.viewPlatformToVworld, ci.rightPlateToViewPlatform) ; + } + ci.updatePlateToVworld = false ; + } + } + + /** + * Gets the current transforms from coexistence coordinates to image plate + * coordinates and copies them into the given Transform3Ds. The default + * coexistence centering enable and window movement policies are + * true and PHYSICAL_WORLD respectively, which + * will center coexistence coordinates to the middle of the canvas, + * aligned with the screen (image plate). A movement policy of + * VIRTUAL_WORLD centers coexistence coordinates to the + * middle of the screen.

+ * + * If coexistence centering is turned off, then canvases and screens can + * have arbitrary positions with respect to coexistence, set through the + * the Screen3D trackerBaseToImagePlate transform and the + * PhysicalEnvironment coexistenceToTrackerBase transform. + * These are calibration constants used for multiple fixed screen displays. + * For head mounted displays the transform is determined by the user head + * position along with calibration parameters found in Screen3D and + * PhysicalBody. (See the source code for the private method + * getEyesHMD for more information).

+ * + * With a monoscopic canvas the image plate transform is copied to the + * first argument and the second argument is not used. For a stereo + * canvas the first argument receives the left image plate transform, and + * if the second argument is non-null it receives the right image plate + * transform. These transforms are always the same unless a head mounted + * display driven by a single stereo canvas is in use.

+ * + * @param c3d the Canvas3D associated with the image plate + * @param coe2ipl the Transform3D to receive the left transform + * @param coe2ipr the Transform3D to receive the right transform, or null + */ + public void getCoexistenceToImagePlate(Canvas3D c3d, + Transform3D coe2ipl, + Transform3D coe2ipr) { + + CanvasInfo ci = updateCache(c3d, "getCoexistenceToImagePlate", false) ; + getCoexistenceToImagePlate(ci) ; + coe2ipl.set(ci.coeToPlate) ; + if (ci.useStereo && coe2ipr != null) + coe2ipr.set(ci.coeToRightPlate) ; + } + + private void getCoexistenceToImagePlate(CanvasInfo ci) { + // + // This method will always set coeToRightPlate even if stereo is not + // in use. This is necessary so that getEyeToImagePlate() can handle + // a monoscopic view policy of CYCLOPEAN_EYE_VIEW (which averages the + // left and right eye positions) when the eyepoints are expressed in + // coexistence coordinates or are derived from the tracked head. + // + if (ci.updateCoeToPlate) { + if (verbose) System.err.println("updating CoeToPlate") ; + if (ci.coeToPlate == null) { + ci.coeToPlate = new Transform3D() ; + ci.coeToRightPlate = new Transform3D() ; + } + if (viewPolicy == View.HMD_VIEW) { + // Head mounted displays have their image plates fixed with + // respect to the head, so get the head position in + // coexistence. + ci.coeToPlate.mul(ci.si.headTrackerToLeftPlate, + coeToHeadTracker) ; + if (ci.useStereo) + // This is the only case in the view model in which the + // right plate transform could be different from the left. + ci.coeToRightPlate.mul(ci.si.headTrackerToRightPlate, + coeToHeadTracker) ; + else + ci.coeToRightPlate.set(ci.coeToPlate) ; + } + else if (coeCentering) { + // The default, for fixed single screen displays with no + // motion tracking. The transform is just a translation. + if (movementPolicy == View.PHYSICAL_WORLD) + // The default. Coexistence is centered in the window. + v3d.set(ci.canvasX + (ci.canvasWidth / 2.0), + ci.canvasY + (ci.canvasHeight / 2.0), 0.0) ; + else + // Coexistence is centered in the screen. + v3d.set(ci.si.screenWidth / 2.0, + ci.si.screenHeight / 2.0, 0.0) ; + + ci.coeToPlate.set(v3d) ; + ci.coeToRightPlate.set(v3d) ; + } + else { + // Coexistence centering should be false for multiple fixed + // screens and/or motion tracking. trackerBaseToImagePlate + // and coexistenceToTrackerBase are used explicitly. + ci.coeToPlate.mul(ci.si.trackerBaseToPlate, coeToTrackerBase) ; + ci.coeToRightPlate.set(ci.coeToPlate) ; + } + ci.updateCoeToPlate = false ; + if (verbose) t3dPrint(ci.coeToPlate, "coeToPlate") ; + } + } + + /** + * Gets the current transform from view platform coordinates to + * coexistence coordinates and copies it into the given transform. View + * platform coordinates are always aligned with coexistence coordinates + * but may differ in scale and in Y and Z offset. The scale is derived + * from the window resize and screen scale policies, while the offset is + * derived from the view attach policy.

+ * + * Java 3D constructs a view from the physical position of the eyes + * relative to the physical positions of the image plates; it then uses a + * view platform to position that physical configuration into the virtual + * world and from there computes the correct projections of the virtual + * world onto the physical image plates. Coexistence coordinates are used + * to place the physical positions of the view platform, eyes, head, image + * plate, sensors, and tracker base in relation to each other. The view + * platform is positioned with respect to the virtual world through the + * scene graph, so the view platform to coexistence transform defines the + * space in which the virtual world and physical world coexist.

+ * + * This method requires a Canvas3D. A different transform may be returned + * for each canvas in the view if any of the following apply:

    + * + *
  • The window resize policy is PHYSICAL_WORLD, which + * alters the scale depending upon the width of the canvas.
  • + * + *

  • The screen scale policy is SCALE_SCREEN_SIZE, + * which alters the scale depending upon the width of the screen + * associated with the canvas.
  • + * + *

  • A window eyepoint policy of RELATIVE_TO_FIELD_OF_VIEW + * with a view attach policy of NOMINAL_HEAD in effect, + * which sets the view platform Z offset in coexistence coordinates + * based on the width of the canvas. These are the default policies. + * The offset also follows the width of the canvas when the + * NOMINAL_FEET view attach policy is used.
+ * + * @param c3d the Canvas3D to use + * @param vp2coe the Transform3D to receive the transform + */ + public void getViewPlatformToCoexistence(Canvas3D c3d, + Transform3D vp2coe) { + + CanvasInfo ci = updateCache + (c3d, "getViewPlatformToCoexistence", false) ; + + getViewPlatformToCoexistence(ci) ; + vp2coe.set(ci.viewPlatformToCoe) ; + } + + private void getViewPlatformToCoexistence(CanvasInfo ci) { + if (!ci.updateViewPlatformToCoe) return ; + if (verbose) System.err.println("updating ViewPlatformToCoe") ; + if (ci.viewPlatformToCoe == null) + ci.viewPlatformToCoe = new Transform3D() ; + // + // The scale from view platform coordinates to coexistence coordinates + // has two components -- the screen scale and the window scale. The + // window scale only applies if the resize policy is PHYSICAL_WORLD. + // + // This scale is not the same as the vworld to view platform scale. + // The latter is contained in the view platform's localToVworld + // transform as defined by the scene graph. The complete scale factor + // from virtual units to physical units is the product of the vworld + // to view platform scale and the view platform to coexistence scale. + // + getScreenScale(ci) ; + if (resizePolicy == View.PHYSICAL_WORLD) + ci.viewPlatformToCoe.setScale(ci.screenScale * ci.windowScale) ; + else + ci.viewPlatformToCoe.setScale(ci.screenScale) ; + + if (viewPolicy == View.HMD_VIEW) { + // In HMD mode view platform coordinates are the same as + // coexistence coordinates, except for scale. + ci.updateViewPlatformToCoe = false ; + return ; + } + + // + // Otherwise, get the offset of the origin of view platform + // coordinates relative to the origin of coexistence. This is is + // specified by two policies: the view platform's view attach policy + // and the physical environment's coexistence center in pworld policy. + // + double eyeOffset ; + double eyeHeight = body.getNominalEyeHeightFromGround() ; + int viewAttachPolicy = view.getViewPlatform().getViewAttachPolicy() ; + int pworldAttachPolicy = env.getCoexistenceCenterInPworldPolicy() ; + + if (eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) + // The view platform origin is the same as the eye position. + eyeOffset = ci.getFieldOfViewOffset() ; + else + // The view platform origin is independent of the eye position. + eyeOffset = body.getNominalEyeOffsetFromNominalScreen() ; + + if (pworldAttachPolicy == View.NOMINAL_SCREEN) { + // The default. The physical coexistence origin locates the + // nominal screen. This is rarely, if ever, set to anything + // else, and the intended effects of the other settings are + // not well documented. + if (viewAttachPolicy == View.NOMINAL_HEAD) { + // The default. The view platform origin is at the origin + // of the nominal head in coexistence coordinates, offset + // from the screen along +Z. If the window eyepoint + // policy is RELATIVE_TO_FIELD_OF_VIEW, then the eyepoint + // is the same as the view platform origin. + v3d.set(0.0, 0.0, eyeOffset) ; + } + else if (viewAttachPolicy == View.NOMINAL_SCREEN) { + // View platform and coexistence are the same except for + // scale. + v3d.set(0.0, 0.0, 0.0) ; + } + else { + // The view platform origin is at the ground beneath the + // head. + v3d.set(0.0, -eyeHeight, eyeOffset) ; + } + } + else if (pworldAttachPolicy == View.NOMINAL_HEAD) { + // The physical coexistence origin locates the nominal head. + if (viewAttachPolicy == View.NOMINAL_HEAD) { + // The view platform origin is set to the head; + // coexistence and view platform coordinates differ only + // in scale. + v3d.set(0.0, 0.0, 0.0) ; + } + else if (viewAttachPolicy == View.NOMINAL_SCREEN) { + // The view platform is set in front of the head, at the + // nominal screen location. + v3d.set(0.0, 0.0, -eyeOffset) ; + } + else { + // The view platform origin is at the ground beneath the + // head. + v3d.set(0.0, -eyeHeight, 0.0) ; + } + } + else { + // The physical coexistence origin locates the nominal feet. + if (viewAttachPolicy == View.NOMINAL_HEAD) { + v3d.set(0.0, eyeHeight, 0.0) ; + } + else if (viewAttachPolicy == View.NOMINAL_SCREEN) { + v3d.set(0.0, eyeHeight, -eyeOffset) ; + } + else { + v3d.set(0.0, 0.0, 0.0) ; + } + } + + ci.viewPlatformToCoe.setTranslation(v3d) ; + ci.updateViewPlatformToCoe = false ; + if (verbose) t3dPrint(ci.viewPlatformToCoe, "vpToCoe") ; + } + + /** + * Gets the current transform from coexistence coordinates to + * view platform coordinates and copies it into the given transform.

+ * + * This method requires a Canvas3D. The returned transform may differ + * across canvases for the same reasons as discussed in the description of + * getViewPlatformToCoexistence.

+ * + * @param c3d the Canvas3D to use + * @param coe2vp the Transform3D to receive the transform + * @see #getViewPlatformToCoexistence + * getViewPlatformToCoexistence(Canvas3D, Transform3D) + */ + public void getCoexistenceToViewPlatform(Canvas3D c3d, + Transform3D coe2vp) { + + CanvasInfo ci = updateCache + (c3d, "getCoexistenceToViewPlatform", false) ; + + getCoexistenceToViewPlatform(ci) ; + coe2vp.set(ci.coeToViewPlatform) ; + } + + private void getCoexistenceToViewPlatform(CanvasInfo ci) { + if (ci.updateCoeToViewPlatform) { + if (verbose) System.err.println("updating CoeToViewPlatform") ; + if (ci.coeToViewPlatform == null) + ci.coeToViewPlatform = new Transform3D() ; + + getViewPlatformToCoexistence(ci) ; + ci.coeToViewPlatform.invert(ci.viewPlatformToCoe) ; + + ci.updateCoeToViewPlatform = false ; + if (verbose) t3dPrint(ci.coeToViewPlatform, "coeToVp") ; + } + } + + /** + * Gets the current transform from coexistence coordinates to virtual + * world coordinates and copies it into the given transform.

+ * + * The View must be attached to a ViewPlatform which is part of a live + * scene graph, and the ViewPlatform node must have its + * ALLOW_LOCAL_TO_VWORLD_READ capability set.

+ * + * This method requires a Canvas3D. The returned transform may differ + * across canvases for the same reasons as discussed in the description of + * getViewPlatformToCoexistence.

+ * + * @param c3d the Canvas3D to use + * @param coe2vw the Transform3D to receive the transform + * @see #getViewPlatformToCoexistence + * getViewPlatformToCoexistence(Canvas3D, Transform3D) + */ + public void getCoexistenceToVworld(Canvas3D c3d, + Transform3D coe2vw) { + + CanvasInfo ci = updateCache(c3d, "getCoexistenceToVworld", true) ; + getCoexistenceToVworld(ci) ; + coe2vw.set(ci.coeToVworld) ; + } + + private void getCoexistenceToVworld(CanvasInfo ci) { + if (ci.updateCoeToVworld) { + if (verbose) System.err.println("updating CoexistenceToVworld") ; + if (ci.coeToVworld == null) ci.coeToVworld = new Transform3D() ; + + getCoexistenceToViewPlatform(ci) ; + ci.coeToVworld.mul(vpi.viewPlatformToVworld, + ci.coeToViewPlatform) ; + + ci.updateCoeToVworld = false ; + } + } + + /** + * Gets the transforms from eye coordinates to image plate coordinates and + * copies them into the Transform3Ds specified.

+ * + * When head tracking is used the eye positions are taken from the head + * position and set in relation to the image plates with each Screen3D's + * trackerBaseToImagePlate transform. Otherwise the window + * eyepoint policy is used to derive the eyepoint relative to the image + * plate. When using a head mounted display the eye position is + * determined solely by calibration constants in Screen3D and + * PhysicalBody; see the source code for the private method + * getEyesHMD for more information.

+ * + * Eye coordinates are always aligned with image plate coordinates, so + * these transforms are always just translations. With a monoscopic + * canvas the eye transform is copied to the first argument and the second + * argument is not used. For a stereo canvas the first argument receives + * the left eye transform, and if the second argument is non-null it + * receives the right eye transform. + * + * @param c3d the Canvas3D associated with the image plate + * @param e2ipl the Transform3D to receive left transform + * @param e2ipr the Transform3D to receive right transform, or null + */ + public void getEyeToImagePlate(Canvas3D c3d, + Transform3D e2ipl, Transform3D e2ipr) { + + CanvasInfo ci = updateCache(c3d, "getEyeToImagePlate", false) ; + getEyeToImagePlate(ci) ; + e2ipl.set(ci.eyeToPlate) ; + if (ci.useStereo && e2ipr != null) + e2ipr.set(ci.rightEyeToPlate) ; + } + + private void getEyeToImagePlate(CanvasInfo ci) { + if (ci.updateEyeInPlate) { + if (verbose) System.err.println("updating EyeInPlate") ; + if (ci.eyeToPlate == null) + ci.eyeToPlate = new Transform3D() ; + + if (viewPolicy == View.HMD_VIEW) { + getEyesHMD(ci) ; + } + else if (useTracking) { + getEyesTracked(ci) ; + } + else { + getEyesFixedScreen(ci) ; + } + ci.updateEyeInPlate = false ; + if (verbose) System.err.println("eyeInPlate: " + ci.eyeInPlate) ; + } + } + + // + // Get physical eye positions for head mounted displays. These are + // determined solely by the headTrackerToImagePlate and headToHeadTracker + // calibration constants defined by Screen3D and the PhysicalBody. + // + // Note that headTrackerLeftToImagePlate and headTrackerToRightImagePlate + // should be set according to the *apparent* position and orientation of + // the image plates, relative to the head and head tracker, as viewed + // through the HMD optics. This is also true of the "physical" screen + // width and height specified by the Screen3D -- they should be the + // *apparent* width and height as viewed through the HMD optics. They + // must be set directly through the Screen3D methods; the default pixel + // metrics of 90 pixels/inch used by Java 3D aren't appropriate for HMD + // optics. + // + // Most HMDs have 100% overlap between the left and right displays; in + // that case, headTrackerToLeftImagePlate and headTrackerToRightImagePlate + // should be identical. The HMD manufacturer's specifications of the + // optics in terms of field of view, image overlap, and distance to the + // focal plane should be used to derive these parameters. + // + private void getEyesHMD(CanvasInfo ci) { + if (ci.useStereo) { + // This case is for head mounted displays driven by a single + // stereo canvas on a single screen. These use a field sequential + // stereo signal to split the left and right images. + leftEye.set(leftEyeInHead) ; + headToHeadTracker.transform(leftEye) ; + ci.si.headTrackerToLeftPlate.transform(leftEye, + ci.eyeInPlate) ; + rightEye.set(rightEyeInHead) ; + headToHeadTracker.transform(rightEye) ; + ci.si.headTrackerToRightPlate.transform(rightEye, + ci.rightEyeInPlate) ; + if (ci.rightEyeToPlate == null) + ci.rightEyeToPlate = new Transform3D() ; + + v3d.set(ci.rightEyeInPlate) ; + ci.rightEyeToPlate.set(v3d) ; + } + else { + // This case is for 2-channel head mounted displays driven by two + // monoscopic screens, one for each eye. + switch (ci.monoscopicPolicy) { + case View.LEFT_EYE_VIEW: + leftEye.set(leftEyeInHead) ; + headToHeadTracker.transform(leftEye) ; + ci.si.headTrackerToLeftPlate.transform(leftEye, + ci.eyeInPlate) ; + break ; + case View.RIGHT_EYE_VIEW: + rightEye.set(rightEyeInHead) ; + headToHeadTracker.transform(rightEye) ; + ci.si.headTrackerToRightPlate.transform(rightEye, + ci.eyeInPlate) ; + break ; + case View.CYCLOPEAN_EYE_VIEW: + default: + throw new IllegalStateException + ("Illegal monoscopic view policy for 2-channel HMD") ; + } + } + v3d.set(ci.eyeInPlate) ; + ci.eyeToPlate.set(v3d) ; + } + + private void getEyesTracked(CanvasInfo ci) { + leftEye.set(leftEyeInHead) ; + rightEye.set(rightEyeInHead) ; + headToTrackerBase.transform(leftEye) ; + headToTrackerBase.transform(rightEye) ; + if (coeCentering) { + // Coexistence and tracker base coordinates are the same. + // Centering is normally turned off for tracking. + getCoexistenceToImagePlate(ci) ; + ci.coeToPlate.transform(leftEye) ; + ci.coeToRightPlate.transform(rightEye) ; + } + else { + // The normal policy for head tracking. + ci.si.trackerBaseToPlate.transform(leftEye) ; + ci.si.trackerBaseToPlate.transform(rightEye) ; + } + setEyeScreenRelative(ci, leftEye, rightEye) ; + } + + private void getEyesFixedScreen(CanvasInfo ci) { + switch (eyePolicy) { + case View.RELATIVE_TO_FIELD_OF_VIEW: + double z = ci.getFieldOfViewOffset() ; + setEyeWindowRelative(ci, z, z) ; + break ; + case View.RELATIVE_TO_WINDOW: + setEyeWindowRelative(ci, + ci.leftManualEyeInPlate.z, + ci.rightManualEyeInPlate.z) ; + break ; + case View.RELATIVE_TO_SCREEN: + setEyeScreenRelative(ci, + ci.leftManualEyeInPlate, + ci.rightManualEyeInPlate) ; + break ; + case View.RELATIVE_TO_COEXISTENCE: + view.getLeftManualEyeInCoexistence(leftEye) ; + view.getRightManualEyeInCoexistence(rightEye) ; + + getCoexistenceToImagePlate(ci) ; + ci.coeToPlate.transform(leftEye) ; + ci.coeToRightPlate.transform(rightEye) ; + setEyeScreenRelative(ci, leftEye, rightEye) ; + break ; + } + } + + private void setEyeWindowRelative(CanvasInfo ci, + double leftZ, double rightZ) { + + // Eye position X is offset from the window center. + double centerX = (ci.canvasX + (ci.canvasWidth / 2.0)) ; + leftEye.x = centerX + leftEyeInHead.x ; + rightEye.x = centerX + rightEyeInHead.x ; + + // Eye position Y is always the canvas center. + leftEye.y = rightEye.y = ci.canvasY + (ci.canvasHeight / 2.0) ; + + // Eye positions Z are as given. + leftEye.z = leftZ ; + rightEye.z = rightZ ; + + setEyeScreenRelative(ci, leftEye, rightEye) ; + } + + private void setEyeScreenRelative(CanvasInfo ci, + Point3d leftEye, Point3d rightEye) { + if (ci.useStereo) { + ci.eyeInPlate.set(leftEye) ; + ci.rightEyeInPlate.set(rightEye) ; + + if (ci.rightEyeToPlate == null) + ci.rightEyeToPlate = new Transform3D() ; + + v3d.set(ci.rightEyeInPlate) ; + ci.rightEyeToPlate.set(v3d) ; + } + else { + switch (ci.monoscopicPolicy) { + case View.CYCLOPEAN_EYE_VIEW: + ci.eyeInPlate.set((leftEye.x + rightEye.x) / 2.0, + (leftEye.y + rightEye.y) / 2.0, + (leftEye.z + rightEye.z) / 2.0) ; + break ; + case View.LEFT_EYE_VIEW: + ci.eyeInPlate.set(leftEye) ; + break ; + case View.RIGHT_EYE_VIEW: + ci.eyeInPlate.set(rightEye) ; + break ; + } + } + v3d.set(ci.eyeInPlate) ; + ci.eyeToPlate.set(v3d) ; + } + + /** + * Gets the current transforms from eye coordinates to view platform + * coordinates and copies them into the given Transform3Ds.

+ * + * With a monoscopic canvas the eye transform is copied to the first + * argument and the second argument is not used. For a stereo canvas the + * first argument receives the left eye transform, and if the second + * argument is non-null it receives the right eye transform.

+ * + * This method requires a Canvas3D. When using a head mounted display, + * head tracking with fixed screens, or a window eyepoint policy of + * RELATIVE_TO_COEXISTENCE, then the transforms returned may + * be different for each canvas if stereo is not in use and they have + * different monoscopic view policies. They may additionally differ in + * scale across canvases with the PHYSICAL_WORLD window + * resize policy or the SCALE_SCREEN_SIZE screen scale + * policy, which alter the scale depending upon the width of the canvas or + * the width of the screen respectively.

+ * + * With window eyepoint policies of RELATIVE_TO_FIELD_OF_VIEW, + * RELATIVE_TO_SCREEN, or RELATIVE_TO_WINDOW, + * then the transforms returned may differ across canvases due to + * the following additional conditions:

    + * + *
  • The window eyepoint policy is RELATIVE_TO_WINDOW or + * RELATIVE_TO_SCREEN, in which case the manual eye + * position in image plate can be set differently for each + * canvas.
  • + * + *

  • The window eyepoint policy is RELATIVE_TO_FIELD_OF_VIEW + * and the view attach policy is NOMINAL_SCREEN, which + * decouples the view platform's canvas Z offset from the eyepoint's + * canvas Z offset.
  • + * + *

  • The eyepoint X and Y coordinates are centered in the canvas with a + * window eyepoint policy of RELATIVE_TO_FIELD_OF_VIEW + * or RELATIVE_TO_WINDOW, and a window movement policy + * of VIRTUAL_WORLD centers the view platform's X and Y + * coordinates to the middle of the screen.
  • + * + *

  • Coexistence centering is set false, which allows each canvas and + * screen to have a different position with respect to coexistence + * coordinates.
+ * + * @param c3d the Canvas3D to use + * @param e2vpl the Transform3D to receive the left transform + * @param e2vpr the Transform3D to receive the right transform, or null + */ + public void getEyeToViewPlatform(Canvas3D c3d, + Transform3D e2vpl, Transform3D e2vpr) { + + CanvasInfo ci = updateCache(c3d, "getEyeToViewPlatform", false) ; + getEyeToViewPlatform(ci) ; + e2vpl.set(ci.eyeToViewPlatform) ; + if (ci.useStereo && e2vpr != null) + e2vpr.set(ci.rightEyeToViewPlatform) ; + } + + private void getEyeToViewPlatform(CanvasInfo ci) { + if (ci.updateEyeToViewPlatform) { + if (verbose) System.err.println("updating EyeToViewPlatform") ; + if (ci.eyeToViewPlatform == null) + ci.eyeToViewPlatform = new Transform3D() ; + + getEyeToImagePlate(ci) ; + getImagePlateToViewPlatform(ci) ; + ci.eyeToViewPlatform.mul(ci.plateToViewPlatform, ci.eyeToPlate) ; + + if (ci.useStereo) { + if (ci.rightEyeToViewPlatform == null) + ci.rightEyeToViewPlatform = new Transform3D() ; + + ci.rightEyeToViewPlatform.mul + (ci.rightPlateToViewPlatform, ci.rightEyeToPlate) ; + } + ci.updateEyeToViewPlatform = false ; + if (verbose) t3dPrint(ci.eyeToViewPlatform, "eyeToVp") ; + } + } + + /** + * Gets the current transforms from view platform coordinates to eye + * coordinates and copies them into the given Transform3Ds.

+ * + * With a monoscopic canvas the eye transform is copied to the first + * argument and the second argument is not used. For a stereo canvas the + * first argument receives the left eye transform, and if the second + * argument is non-null it receives the right eye transform.

+ * + * This method requires a Canvas3D. The transforms returned may differ + * across canvases for all the same reasons discussed in the description + * of getEyeToViewPlatform. + * + * @param c3d the Canvas3D to use + * @param vp2el the Transform3D to receive the left transform + * @param vp2er the Transform3D to receive the right transform, or null + * @see #getEyeToViewPlatform + * getEyeToViewPlatform(Canvas3D, Transform3D, Transform3D) + */ + public void getViewPlatformToEye(Canvas3D c3d, + Transform3D vp2el, Transform3D vp2er) { + + CanvasInfo ci = updateCache(c3d, "getViewPlatformToEye", false) ; + getViewPlatformToEye(ci) ; + vp2el.set(ci.viewPlatformToEye) ; + if (ci.useStereo && vp2er != null) + vp2er.set(ci.viewPlatformToRightEye) ; + } + + private void getViewPlatformToEye(CanvasInfo ci) { + if (ci.updateViewPlatformToEye) { + if (verbose) System.err.println("updating ViewPlatformToEye") ; + if (ci.viewPlatformToEye == null) + ci.viewPlatformToEye = new Transform3D() ; + + getEyeToViewPlatform(ci) ; + ci.viewPlatformToEye.invert(ci.eyeToViewPlatform) ; + + if (ci.useStereo) { + if (ci.viewPlatformToRightEye == null) + ci.viewPlatformToRightEye = new Transform3D() ; + + ci.viewPlatformToRightEye.invert(ci.rightEyeToViewPlatform) ; + } + ci.updateViewPlatformToEye = false ; + } + } + + /** + * Gets the current transforms from eye coordinates to virtual world + * coordinates and copies them into the given Transform3Ds.

+ * + * With a monoscopic canvas the eye transform is copied to the first + * argument and the second argument is not used. For a stereo canvas the + * first argument receives the left eye transform, and if the second + * argument is non-null it receives the right eye transform.

+ * + * The View must be attached to a ViewPlatform which is part of a live + * scene graph, and the ViewPlatform node must have its + * ALLOW_LOCAL_TO_VWORLD_READ capability set.

+ * + * This method requires a Canvas3D. The transforms returned may differ + * across canvases for all the same reasons discussed in the description + * of getEyeToViewPlatform. + * + * @param c3d the Canvas3D to use + * @param e2vwl the Transform3D to receive the left transform + * @param e2vwr the Transform3D to receive the right transform, or null + * @see #getEyeToViewPlatform + * getEyeToViewPlatform(Canvas3D, Transform3D, Transform3D) + */ + public void getEyeToVworld(Canvas3D c3d, + Transform3D e2vwl, Transform3D e2vwr) { + + CanvasInfo ci = updateCache(c3d, "getEyeToVworld", true) ; + getEyeToVworld(ci) ; + e2vwl.set(ci.eyeToVworld) ; + if (ci.useStereo && e2vwr != null) + e2vwr.set(ci.rightEyeToVworld) ; + } + + private void getEyeToVworld(CanvasInfo ci) { + if (ci.updateEyeToVworld) { + if (verbose) System.err.println("updating EyeToVworld") ; + if (ci.eyeToVworld == null) + ci.eyeToVworld = new Transform3D() ; + + getEyeToViewPlatform(ci) ; + ci.eyeToVworld.mul + (vpi.viewPlatformToVworld, ci.eyeToViewPlatform) ; + + if (ci.useStereo) { + if (ci.rightEyeToVworld == null) + ci.rightEyeToVworld = new Transform3D() ; + + ci.rightEyeToVworld.mul + (vpi.viewPlatformToVworld, ci.rightEyeToViewPlatform) ; + } + ci.updateEyeToVworld = false ; + } + } + + /** + * Gets the transforms from eye coordinates to clipping coordinates + * and copies them into the given Transform3Ds. These transforms take + * a viewing volume bounded by the physical canvas edges and the + * physical front and back clip planes and project it into a range + * bound to [-1.0 .. +1.0] on each of the X, Y, and Z axes. If a + * perspective projection has been specified then the physical image + * plate eye location defines the apex of a viewing frustum; + * otherwise, the orientation of the image plate determines the + * direction of a parallel projection.

+ * + * With a monoscopic canvas the projection transform is copied to the + * first argument and the second argument is not used. For a stereo + * canvas the first argument receives the left projection transform, + * and if the second argument is non-null it receives the right + * projection transform.

+ * + * If either of the clip policies VIRTUAL_EYE or + * VIRTUAL_SCREEN are used, then the View should be attached + * to a ViewPlatform that is part of a live scene graph and that has its + * ALLOW_LOCAL_TO_VWORLD_READ capability set; otherwise, a + * scale factor of 1.0 will be used for the scale factor from virtual + * world units to view platform units. + * + * @param c3d the Canvas3D to use + * @param e2ccl the Transform3D to receive left transform + * @param e2ccr the Transform3D to receive right transform, or null + */ + public void getProjection(Canvas3D c3d, + Transform3D e2ccl, Transform3D e2ccr) { + + CanvasInfo ci = updateCache(c3d, "getProjection", true) ; + getProjection(ci) ; + e2ccl.set(ci.projection) ; + if (ci.useStereo && e2ccr != null) + e2ccr.set(ci.rightProjection) ; + } + + private void getProjection(CanvasInfo ci) { + if (ci.updateProjection) { + if (verbose) System.err.println("updating Projection") ; + if (ci.projection == null) + ci.projection = new Transform3D() ; + + getEyeToImagePlate(ci) ; + getClipDistances(ci) ; + + // Note: core Java 3D code insists that the back clip plane + // relative to the image plate must be the same left back clip + // distance for both the left and right eye. Not sure why this + // should be, but the same is done here for compatibility. + double backClip = getBackClip(ci, ci.eyeInPlate) ; + computeProjection(ci, ci.eyeInPlate, + getFrontClip(ci, ci.eyeInPlate), + backClip, ci.projection) ; + + if (ci.useStereo) { + if (ci.rightProjection == null) + ci.rightProjection = new Transform3D() ; + + computeProjection(ci, ci.rightEyeInPlate, + getFrontClip(ci, ci.rightEyeInPlate), + backClip, ci.rightProjection) ; + } + ci.updateProjection = false ; + if (verbose) t3dPrint(ci.projection, "projection") ; + } + } + + /** + * Gets the transforms from clipping coordinates to eye coordinates + * and copies them into the given Transform3Ds. These transforms take + * the clip space volume bounded by the range [-1.0 .. + 1.0] on each + * of the X, Y, and Z and project it into eye coordinates.

+ * + * With a monoscopic canvas the projection transform is copied to the + * first argument and the second argument is not used. For a stereo + * canvas the first argument receives the left projection transform, and + * if the second argument is non-null it receives the right projection + * transform.

+ * + * If either of the clip policies VIRTUAL_EYE or + * VIRTUAL_SCREEN are used, then the View should be attached + * to a ViewPlatform that is part of a live scene graph and that has its + * ALLOW_LOCAL_TO_VWORLD_READ capability set; otherwise, a + * scale factor of 1.0 will be used for the scale factor from virtual + * world units to view platform units. + * + * @param c3d the Canvas3D to use + * @param cc2el the Transform3D to receive left transform + * @param cc2er the Transform3D to receive right transform, or null + */ + public void getInverseProjection(Canvas3D c3d, + Transform3D cc2el, Transform3D cc2er) { + + CanvasInfo ci = updateCache(c3d, "getInverseProjection", true) ; + getInverseProjection(ci) ; + cc2el.set(ci.inverseProjection) ; + if (ci.useStereo && cc2er != null) + cc2er.set(ci.inverseRightProjection) ; + } + + private void getInverseProjection(CanvasInfo ci) { + if (ci.updateInverseProjection) { + if (verbose) System.err.println("updating InverseProjection") ; + if (ci.inverseProjection == null) + ci.inverseProjection = new Transform3D() ; + + getProjection(ci) ; + ci.inverseProjection.invert(ci.projection) ; + + if (ci.useStereo) { + if (ci.inverseRightProjection == null) + ci.inverseRightProjection = new Transform3D() ; + + ci.inverseRightProjection.invert(ci.rightProjection) ; + } + ci.updateInverseProjection = false ; + } + } + + /** + * Gets the transforms from clipping coordinates to view platform + * coordinates and copies them into the given Transform3Ds. These + * transforms take the clip space volume bounded by the range + * [-1.0 .. +1.0] on each of the X, Y, and Z axes and project into + * the view platform coordinate system.

+ * + * With a monoscopic canvas the projection transform is copied to the + * first argument and the second argument is not used. For a stereo + * canvas the first argument receives the left projection transform, and + * if the second argument is non-null it receives the right projection + * transform.

+ * + * If either of the clip policies VIRTUAL_EYE or + * VIRTUAL_SCREEN are used, then the View should be attached + * to a ViewPlatform that is part of a live scene graph and that has its + * ALLOW_LOCAL_TO_VWORLD_READ capability set; otherwise, a + * scale factor of 1.0 will be used for the scale factor from virtual + * world units to view platform units. + * + * @param c3d the Canvas3D to use + * @param cc2vpl the Transform3D to receive left transform + * @param cc2vpr the Transform3D to receive right transform, or null + */ + public void getInverseViewPlatformProjection(Canvas3D c3d, + Transform3D cc2vpl, + Transform3D cc2vpr) { + + CanvasInfo ci = updateCache + (c3d, "getInverseViewPlatformProjection", true) ; + + getInverseViewPlatformProjection(ci) ; + cc2vpl.set(ci.inverseViewPlatformProjection) ; + if (ci.useStereo & cc2vpr != null) + cc2vpr.set(ci.inverseViewPlatformRightProjection) ; + } + + private void getInverseViewPlatformProjection(CanvasInfo ci) { + if (ci.updateInverseViewPlatformProjection) { + if (verbose) System.err.println("updating InverseVpProjection") ; + if (ci.inverseViewPlatformProjection == null) + ci.inverseViewPlatformProjection = new Transform3D() ; + + getInverseProjection(ci) ; + getEyeToViewPlatform(ci) ; + ci.inverseViewPlatformProjection.mul + (ci.eyeToViewPlatform, ci.inverseProjection) ; + + if (ci.useStereo) { + if (ci.inverseViewPlatformRightProjection == null) + ci.inverseViewPlatformRightProjection = new Transform3D() ; + + ci.inverseViewPlatformRightProjection.mul + (ci.rightEyeToViewPlatform, ci.inverseRightProjection) ; + } + ci.updateInverseVworldProjection = false ; + } + } + + /** + * Gets the transforms from clipping coordinates to virtual world + * coordinates and copies them into the given Transform3Ds. These + * transforms take the clip space volume bounded by the range + * [-1.0 .. +1.0] on each of the X, Y, and Z axes and project into + * the virtual world.

+ * + * With a monoscopic canvas the projection transform is copied to the + * first argument and the second argument is not used. For a stereo + * canvas the first argument receives the left projection transform, and + * if the second argument is non-null it receives the right projection + * transform.

+ * + * The View must be attached to a ViewPlatform which is part of a live + * scene graph, and the ViewPlatform node must have its + * ALLOW_LOCAL_TO_VWORLD_READ capability set. + * + * @param c3d the Canvas3D to use + * @param cc2vwl the Transform3D to receive left transform + * @param cc2vwr the Transform3D to receive right transform, or null + */ + public void getInverseVworldProjection(Canvas3D c3d, + Transform3D cc2vwl, + Transform3D cc2vwr) { + + CanvasInfo ci = updateCache(c3d, "getInverseVworldProjection", true) ; + getInverseVworldProjection(ci) ; + cc2vwl.set(ci.inverseVworldProjection) ; + if (ci.useStereo & cc2vwr != null) + cc2vwr.set(ci.inverseVworldRightProjection) ; + } + + private void getInverseVworldProjection(CanvasInfo ci) { + if (ci.updateInverseVworldProjection) { + if (verbose) System.err.println("updating InverseVwProjection") ; + if (ci.inverseVworldProjection == null) + ci.inverseVworldProjection = new Transform3D() ; + + getInverseViewPlatformProjection(ci) ; + ci.inverseVworldProjection.mul + (vpi.viewPlatformToVworld, ci.inverseViewPlatformProjection) ; + + if (ci.useStereo) { + if (ci.inverseVworldRightProjection == null) + ci.inverseVworldRightProjection = new Transform3D() ; + + ci.inverseVworldRightProjection.mul + (vpi.viewPlatformToVworld, + ci.inverseViewPlatformRightProjection) ; + } + ci.updateInverseVworldProjection = false ; + } + } + + // + // Compute a projection matrix from the given eye position in image plate, + // the front and back clip Z positions in image plate, and the current + // canvas position in image plate. + // + private void computeProjection(CanvasInfo ci, Point3d eye, + double front, double back, Transform3D p) { + + // Convert everything to eye coordinates. + double lx = ci.canvasX - eye.x ; // left (low x) + double ly = ci.canvasY - eye.y ; // bottom (low y) + double hx = (ci.canvasX+ci.canvasWidth) - eye.x ; // right (high x) + double hy = (ci.canvasY+ci.canvasHeight) - eye.y ; // top (high y) + double nz = front - eye.z ; // front (near z) + double fz = back - eye.z ; // back (far z) + double iz = -eye.z ; // plate (image z) + + if (projectionPolicy == View.PERSPECTIVE_PROJECTION) + computePerspectiveProjection(lx, ly, hx, hy, iz, nz, fz, m16d) ; + else + computeParallelProjection(lx, ly, hx, hy, nz, fz, m16d) ; + + p.set(m16d) ; + } + + // + // Compute a perspective projection from the given eye-space bounds. + // + private void computePerspectiveProjection(double lx, double ly, + double hx, double hy, + double iz, double nz, + double fz, double[] m) { + // + // We first derive the X and Y projection components without regard + // for Z scaling. The Z scaling or perspective depth is handled by + // matrix elements expressed solely in terms of the near and far clip + // planes. + // + // Since the eye is at the origin, the projector for any point V in + // eye space is just V. Any point along this ray can be expressed in + // parametric form as P = tV. To find the projection onto the plane + // containing the canvas, find t such that P.z = iz; ie, t = iz/V.z. + // The projection P is thus [V.x*iz/V.z, V.y*iz/V.z, iz]. + // + // This projection can expressed as the following matrix equation: + // + // -iz 0 0 0 V.x + // 0 -iz 0 0 X V.y + // 0 0 -iz 0 V.z + // 0 0 -1 0 1 {matrix 1} + // + // where the matrix elements have been negated so that w is positive. + // This is mostly by convention, although some hardware won't handle + // clipping in the -w half-space. + // + // After the point has been projected to the image plate, the + // canvas bounds need to be mapped to the [-1..1] of Java 3D's + // clipping space. The scale factor for X is thus 2/(hx - lx); adding + // the translation results in (V.x - lx)(2/(hx - lx)) - 1, which after + // some algebra can be confirmed to the same as the following + // canonical scale/offset form: + // + // V.x*2/(hx - lx) - (hx + lx)/(hx - lx) + // + // Similarly for Y: + // + // V.y*2/(hy - ly) - (hy + ly)/(hy - ly) + // + // If we set idx = 1/(hx - lx) and idy = 1/(hy - ly), then we get: + // + // 2*V.x*idx - (hx + lx)idx + // 2*V.y*idy - (hy + ly)idy + // + // These scales and offsets are represented by the following matrix: + // + // 2*idx 0 0 -(hx + lx)*idx + // 0 2*idy 0 -(hy + ly)*idy + // 0 0 1 0 + // 0 0 0 1 {matrix 2} + // + // The result after concatenating the projection transform + // ({matrix 2} X {matrix 1}): + // + // -2*iz*idx 0 (hx + lx)*idx 0 + // 0 -2*iz*idy (hy + ly)*idy 0 + // 0 0 -iz {a} 0 {b} + // 0 0 -1 0 {matrix 3} + // + // The Z scaling is handled by m[10] ("a") and m[11] ("b"), which must + // map the range [front..back] to [1..-1] in clipping space. If ze is + // the Z coordinate in eye space, and zc is the Z coordinate in + // clipping space after division by w, then from {matrix 3}: + // + // zc = (a*ze + b)/-ze = -(a + b/ze) + // + // We want this to map to +1 when ze is at the near clip plane, and + // to -1 when ze is at the far clip plane: + // + // -(a + b/nz) = +1 + // -(a + b/fz) = -1 + // + // Solving results in: + // + // a = -(nz + fz)/(nz - fz) + // b = (2*nz*fz)/(nz - fz). + // + // NOTE: this produces a perspective transform that has matrix + // components with a different scale than the matrix computed by the + // Java 3D core. They do in fact effect the equivalent clipping in 4D + // homogeneous coordinates and project to the same 3D Euclidean + // coordinates. m[14] is always -1 in our derivation above. If the + // matrix components produced by Java 3D core are divided by its value + // of -m[14], then both matrices are the same. + // + double idx = 1.0 / (hx - lx) ; + double idy = 1.0 / (hy - ly) ; + double idz = 1.0 / (nz - fz) ; + + m[0] = -2.0 * iz * idx ; + m[5] = -2.0 * iz * idy ; + m[2] = (hx + lx) * idx ; + m[6] = (hy + ly) * idy ; + m[10] = -(nz + fz) * idz ; + m[11] = 2.0 * fz * nz * idz ; + m[14] = -1.0 ; + m[1] = m[3] = m[4] = m[7] = m[8] = m[9] = m[12] = m[13] = m[15] = 0.0 ; + } + + // + // Compute a parallel projection from the given eye-space bounds. + // + private void computeParallelProjection(double lx, double ly, + double hx, double hy, + double nz, double fz, double[] m) { + // + // A parallel projection in eye space just involves scales and offsets + // with no w division. We can use {matrix 2} for the X and Y scales + // and offsets and then use a linear mapping of the front and back + // clip distances to the [1..-1] Z clip range. + // + double idx = 1.0 / (hx - lx) ; + double idy = 1.0 / (hy - ly) ; + double idz = 1.0 / (nz - fz) ; + + m[0] = 2.0 * idx ; + m[5] = 2.0 * idy ; + m[10] = 2.0 * idz ; + m[3] = -(hx + lx) * idx ; + m[7] = -(hy + ly) * idy ; + m[11] = -(nz + fz) * idz ; + m[15] = 1.0 ; + m[1] = m[2] = m[4] = m[6] = m[8] = m[9] = m[12] = m[13] = m[14] = 0.0 ; + } + + // + // Get front clip plane Z coordinate in image plate space. + // + private double getFrontClip(CanvasInfo ci, Point3d eye) { + if (frontClipPolicy == View.PHYSICAL_EYE || + frontClipPolicy == View.VIRTUAL_EYE) { + return eye.z - ci.frontClipDistance ; + } + else { + return - ci.frontClipDistance ; + } + } + + // + // Get back clip plane Z coordinate in image plate space. + // + private double getBackClip(CanvasInfo ci, Point3d eye) { + // + // Note: Clip node status is unavailable here. If a clip node is + // active in the scene graph, it should override the view's back + // clip plane. + // + if (backClipPolicy == View.PHYSICAL_EYE || + backClipPolicy == View.VIRTUAL_EYE) { + return eye.z - ci.backClipDistance ; + } + else { + return -ci.backClipDistance ; + } + } + + // + // Compute clip distance scale. + // + private double getClipScale(CanvasInfo ci, int clipPolicy) { + if (clipPolicy == View.VIRTUAL_EYE || + clipPolicy == View.VIRTUAL_SCREEN) { + getScreenScale(ci) ; + if (resizePolicy == View.PHYSICAL_WORLD) + return vpi.vworldToViewPlatformScale * ci.screenScale * + ci.windowScale ; + else + return vpi.vworldToViewPlatformScale * ci.screenScale ; + } + else { + if (resizePolicy == View.PHYSICAL_WORLD) + return ci.windowScale ; // see below + else + return 1.0 ; + } + } + + /** + * Gets the front clip distance scaled to physical meters. This is useful + * for ensuring that objects positioned relative to a physical coordinate + * system (such as eye, image plate, or coexistence) will be within the + * viewable Z depth. This distance will be relative to either the eye or + * the image plate depending upon the front clip policy.

+ * + * Note that this is not necessarily the clip distance as set by + * setFrontClipDistance, even when the front clip policy + * is PHYSICAL_SCREEN or PHYSICAL_EYE. If + * the window resize policy is PHYSICAL_WORLD, then physical + * clip distances as specified are in fact scaled by the ratio of the + * window width to the screen width. The Java 3D view model does this + * to prevent the physical clip planes from moving with respect to the + * virtual world when the window is resized.

+ * + * If either of the clip policies VIRTUAL_EYE or + * VIRTUAL_SCREEN are used, then the View should be attached + * to a ViewPlatform that is part of a live scene graph and that has its + * ALLOW_LOCAL_TO_VWORLD_READ capability set; otherwise, a + * scale factor of 1.0 will be used for the scale factor from virtual + * world units to view platform units. + * + * @param c3d the Canvas3D to use + * @return the physical front clip distance + */ + public double getPhysicalFrontClipDistance(Canvas3D c3d) { + CanvasInfo ci = updateCache + (c3d, "getPhysicalFrontClipDistance", true) ; + + getClipDistances(ci) ; + return ci.frontClipDistance ; + } + + /** + * Gets the back clip distance scaled to physical meters. This is useful + * for ensuring that objects positioned relative to a physical coordinate + * system (such as eye, image plate, or coexistence) will be within the + * viewable Z depth. This distance will be relative to either the eye or + * the image plate depending upon the back clip policy.

+ * + * Note that this is not necessarily the clip distance as set by + * setBackClipDistance, even when the back clip policy + * is PHYSICAL_SCREEN or PHYSICAL_EYE. If + * the window resize policy is PHYSICAL_WORLD, then physical + * clip distances as specified are in fact scaled by the ratio of the + * window width to the screen width. The Java 3D view model does this + * to prevent the physical clip planes from moving with respect to the + * virtual world when the window is resized.

+ * + * If either of the clip policies VIRTUAL_EYE or + * VIRTUAL_SCREEN are used, then the View should be attached + * to a ViewPlatform that is part of a live scene graph and that has its + * ALLOW_LOCAL_TO_VWORLD_READ capability set; otherwise, a + * scale factor of 1.0 will be used for the scale factor from virtual + * world units to view platform units. + * + * @param c3d the Canvas3D to use + * @return the physical back clip distance + */ + public double getPhysicalBackClipDistance(Canvas3D c3d) { + CanvasInfo ci = updateCache(c3d, "getPhysicalBackClipDistance", true) ; + getClipDistances(ci) ; + return ci.backClipDistance ; + } + + private void getClipDistances(CanvasInfo ci) { + if (ci.updateClipDistances) { + if (verbose) System.err.println("updating clip distances") ; + + ci.frontClipDistance = view.getFrontClipDistance() * + getClipScale(ci, frontClipPolicy) ; + + ci.backClipDistance = view.getBackClipDistance() * + getClipScale(ci, backClipPolicy) ; + + ci.updateClipDistances = false ; + if (verbose) { + System.err.println + (" front clip distance " + ci.frontClipDistance) ; + System.err.println + (" back clip distance " + ci.backClipDistance) ; + } + } + } + + private void getScreenScale(CanvasInfo ci) { + if (ci.updateScreenScale) { + if (verbose) System.err.println("updating screen scale") ; + + if (scalePolicy == View.SCALE_SCREEN_SIZE) + ci.screenScale = ci.si.screenWidth / 2.0 ; + else + ci.screenScale = view.getScreenScale() ; + + ci.updateScreenScale = false ; + if (verbose) System.err.println("screen scale " + ci.screenScale) ; + } + } + + /** + * Gets the scale factor from physical meters to view platform units.

+ * + * This method requires a Canvas3D. A different scale may be returned + * for each canvas in the view if any of the following apply:

    + * + *
  • The window resize policy is PHYSICAL_WORLD, which + * alters the scale depending upon the width of the canvas.
  • + * + *

  • The screen scale policy is SCALE_SCREEN_SIZE, + * which alters the scale depending upon the width of the screen + * associated with the canvas.
+ * + * @param c3d the Canvas3D to use + * @return the physical to view platform scale + */ + public double getPhysicalToViewPlatformScale(Canvas3D c3d) { + CanvasInfo ci = updateCache + (c3d, "getPhysicalToViewPlatformScale", false) ; + + getPhysicalToViewPlatformScale(ci) ; + return ci.physicalToVpScale ; + } + + private void getPhysicalToViewPlatformScale(CanvasInfo ci) { + if (ci.updatePhysicalToVpScale) { + if (verbose) System.err.println("updating PhysicalToVp scale") ; + + getScreenScale(ci) ; + if (resizePolicy == View.PHYSICAL_WORLD) + ci.physicalToVpScale = 1.0/(ci.screenScale * ci.windowScale) ; + else + ci.physicalToVpScale = 1.0/ci.screenScale ; + + ci.updatePhysicalToVpScale = false ; + if (verbose) System.err.println("PhysicalToVp scale " + + ci.physicalToVpScale) ; + } + } + + /** + * Gets the scale factor from physical meters to virtual units.

+ * + * This method requires a Canvas3D. A different scale may be returned + * across canvases for the same reasons as discussed in the description of + * getPhysicalToViewPlatformScale.

+ * + * The View must be attached to a ViewPlatform which is part of a live + * scene graph, and the ViewPlatform node must have its + * ALLOW_LOCAL_TO_VWORLD_READ capability set. + * + * @param c3d the Canvas3D to use + * @return the physical to virtual scale + * @see #getPhysicalToViewPlatformScale + * getPhysicalToViewPlatformScale(Canvas3D) + */ + public double getPhysicalToVirtualScale(Canvas3D c3d) { + CanvasInfo ci = updateCache(c3d, "getPhysicalToVirtualScale", true) ; + getPhysicalToVirtualScale(ci) ; + return ci.physicalToVirtualScale ; + } + + private void getPhysicalToVirtualScale(CanvasInfo ci) { + if (ci.updatePhysicalToVirtualScale) { + if (verbose) + System.err.println("updating PhysicalToVirtual scale") ; + + getPhysicalToViewPlatformScale(ci) ; + ci.physicalToVirtualScale = + ci.physicalToVpScale / vpi.vworldToViewPlatformScale ; + + ci.updatePhysicalToVirtualScale = false ; + if (verbose) System.err.println("PhysicalToVirtual scale " + + ci.physicalToVirtualScale) ; + } + } + + /** + * Gets the width of the specified canvas scaled to physical meters. This + * is derived from the physical screen width as reported by the Screen3D + * associated with the canvas. If the screen width is not explicitly set + * using the setPhysicalScreenWidth method of Screen3D, then + * Java 3D will derive the screen width based on a screen resolution of 90 + * pixels/inch. + * + * @param c3d the Canvas3D to use + * @return the width of the canvas scaled to physical meters + */ + public double getPhysicalWidth(Canvas3D c3d) { + CanvasInfo ci = updateCache(c3d, "getPhysicalWidth", false) ; + return ci.canvasWidth ; + } + + /** + * Gets the height of the specified canvas scaled to physical meters. This + * is derived from the physical screen height as reported by the Screen3D + * associated with the canvas. If the screen height is not explicitly set + * using the setPhysicalScreenHeight method of Screen3D, then + * Java 3D will derive the screen height based on a screen resolution of 90 + * pixels/inch. + * + * @param c3d the Canvas3D to use + * @return the height of the canvas scaled to physical meters + */ + public double getPhysicalHeight(Canvas3D c3d) { + CanvasInfo ci = updateCache(c3d, "getPhysicalHeight", false) ; + return ci.canvasHeight ; + } + + /** + * Gets the location of the specified canvas relative to the image plate + * origin. This is derived from the physical screen parameters as + * reported by the Screen3D associated with the canvas. If the screen + * width and height are not explicitly set in Screen3D, then Java 3D will + * derive those screen parameters based on a screen resolution of 90 + * pixels/inch. + * + * @param c3d the Canvas3D to use + * @param location the output position, in meters, of the lower-left + * corner of the canvas relative to the image plate lower-left corner; Z + * is always 0.0 + */ + public void getPhysicalLocation(Canvas3D c3d, Point3d location) { + CanvasInfo ci = updateCache(c3d, "getPhysicalLocation", false) ; + location.set(ci.canvasX, ci.canvasY, 0.0) ; + } + + /** + * Gets the location of the AWT pixel value and copies it into the + * specified Point3d. + * + * @param c3d the Canvas3D to use + * @param x the X coordinate of the pixel relative to the upper-left + * corner of the canvas + * @param y the Y coordinate of the pixel relative to the upper-left + * corner of the canvas + * @param location the output position, in meters, relative to the + * lower-left corner of the image plate; Z is always 0.0 + */ + public void getPixelLocationInImagePlate(Canvas3D c3d, int x, int y, + Point3d location) { + + CanvasInfo ci = updateCache + (c3d, "getPixelLocationInImagePlate", false) ; + + location.set(ci.canvasX + ((double)x * ci.si.metersPerPixelX), + ci.canvasY - ((double)y * ci.si.metersPerPixelY) + + ci.canvasHeight, 0.0) ; + } + + /** + * Gets a read from the specified sensor and transforms it to virtual + * world coordinates. The View must be attached to a ViewPlatform which + * is part of a live scene graph, and the ViewPlatform node must have its + * ALLOW_LOCAL_TO_VWORLD_READ capability set.

+ * + * This method requires a Canvas3D. The returned transform may differ + * across canvases for the same reasons as discussed in the description of + * getViewPlatformToCoexistence. + * + * @param sensor the Sensor instance to read + * @param s2vw the output transform + * @see #getViewPlatformToCoexistence + * getViewPlatformToCoexistence(Canvas3D, Transform3D) + */ + public void getSensorToVworld(Canvas3D c3d, + Sensor sensor, Transform3D s2vw) { + + CanvasInfo ci = updateCache(c3d, "getSensorToVworld", true) ; + getTrackerBaseToVworld(ci) ; + sensor.getRead(s2vw) ; + s2vw.mul(ci.trackerBaseToVworld, s2vw) ; + } + + /** + * Gets the transform from tracker base coordinates to view platform + * coordinates and copies it into the specified Transform3D.

+ * + * This method requires a Canvas3D. The returned transform may differ + * across canvases for the same reasons as discussed in the description of + * getViewPlatformToCoexistence. + * + * @param c3d the Canvas3D to use + * @param tb2vp the output transform + * @see #getViewPlatformToCoexistence + * getViewPlatformToCoexistence(Canvas3D, Transform3D) + */ + public void getTrackerBaseToViewPlatform(Canvas3D c3d, Transform3D tb2vp) { + CanvasInfo ci = updateCache + (c3d, "getTrackerBaseToViewPlatform", false) ; + + getTrackerBaseToViewPlatform(ci) ; + tb2vp.set(ci.trackerBaseToViewPlatform) ; + } + + private void getTrackerBaseToViewPlatform(CanvasInfo ci) { + if (ci.updateTrackerBaseToViewPlatform) { + if (verbose) System.err.println("updating TrackerBaseToVp") ; + if (ci.trackerBaseToViewPlatform == null) + ci.trackerBaseToViewPlatform = new Transform3D() ; + + getViewPlatformToCoexistence(ci) ; + ci.trackerBaseToViewPlatform.mul(coeToTrackerBase, + ci.viewPlatformToCoe) ; + + ci.trackerBaseToViewPlatform.invert() ; + ci.updateTrackerBaseToViewPlatform = false ; + if (verbose) t3dPrint(ci.trackerBaseToViewPlatform, + "TrackerBaseToViewPlatform") ; + } + } + + /** + * Gets the transform from tracker base coordinates to virtual world + * coordinates and copies it into the specified Transform3D. The View + * must be attached to a ViewPlatform which is part of a live scene graph, + * and the ViewPlatform node must have its + * ALLOW_LOCAL_TO_VWORLD_READ capability set.

+ * + * This method requires a Canvas3D. The returned transform may differ + * across canvases for the same reasons as discussed in the description of + * getViewPlatformToCoexistence. + * + * @param c3d the Canvas3D to use + * @param tb2vw the output transform + * @see #getViewPlatformToCoexistence + * getViewPlatformToCoexistence(Canvas3D, Transform3D) + */ + public void getTrackerBaseToVworld(Canvas3D c3d, Transform3D tb2vw) { + CanvasInfo ci = updateCache(c3d, "getTrackerBaseToVworld", true) ; + getTrackerBaseToVworld(ci) ; + tb2vw.set(ci.trackerBaseToVworld) ; + } + + private void getTrackerBaseToVworld(CanvasInfo ci) { + if (ci.updateTrackerBaseToVworld) { + if (verbose) System.err.println("updating TrackerBaseToVworld") ; + if (ci.trackerBaseToVworld == null) + ci.trackerBaseToVworld = new Transform3D() ; + // + // We compute trackerBaseToViewPlatform and compose with + // viewPlatformToVworld instead of computing imagePlateToVworld + // and composing with trackerBaseToImagePlate. That way it works + // with HMD and avoids the issue of choosing the left image plate + // or right image plate transform. + // + getTrackerBaseToViewPlatform(ci) ; + ci.trackerBaseToVworld.mul(vpi.viewPlatformToVworld, + ci.trackerBaseToViewPlatform) ; + + ci.updateTrackerBaseToVworld = false ; + } + } + + /** + * Release all static memory references held by ViewInfo, if any. These + * are the Screen3D and ViewPlatform maps shared by all existing ViewInfo + * instances if they're not provided by a constructor. Releasing the + * screen references effectively releases all canvas references in all + * ViewInfo instances as well.

+ * + * It is safe to continue using existing ViewInfo instances after calling + * this method; the data in the released maps will be re-derived as + * needed. + */ + public static synchronized void clear() { + Iterator i = staticVpMap.values().iterator() ; + while (i.hasNext()) ((ViewPlatformInfo)i.next()).clear() ; + staticVpMap.clear() ; + + i = staticSiMap.values().iterator() ; + while (i.hasNext()) ((ScreenInfo)i.next()).clear() ; + staticSiMap.clear() ; + } + + /** + * Arrange for an update of cached screen parameters. If automatic update + * has not been enabled, then this method should be called if any of the + * attributes of the Screen3D have changed. This method should also be + * called if the screen changes pixel resolution. + * + * @param s3d the Screen3D to update + */ + public void updateScreen(Screen3D s3d) { + if (verbose) System.err.println("updateScreen") ; + ScreenInfo si = (ScreenInfo)screenMap.get(s3d) ; + if (si != null) si.updateScreen = true ; + } + + /** + * Arrange for an update of cached canvas parameters. If automatic update + * has not been enabled, then this method should be called if any of the + * attributes of the Canvas3D have changed. These attributes include the + * canvas position and size, but do not include the attributes of + * the associated Screen3D, which are cached separately. + * + * @param c3d the Canvas3D to update + */ + public void updateCanvas(Canvas3D c3d) { + if (verbose) System.err.println("updateCanvas") ; + CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ; + if (ci != null) ci.updateCanvas = true ; + } + + /** + * Arrange for an update of cached view parameters. If automatic update + * has not been enabled for the View, then this method should be called if + * any of the attributes of the View associated with this object have + * changed.

+ * + * These do not include the attributes of the existing Canvas3D or + * Screen3D components of the View, but do include the attributes of all + * other components such as the PhysicalEnvironment and PhysicalBody, and + * all attributes of the attached ViewPlatform except for its + * localToVworld transform. The screen and canvas components + * as well as the ViewPlatform's localToVworld are cached + * separately.

+ * + * This method should also be called if the ViewPlatform is replaced with + * another using the View's attachViewPlatform method, or if + * any of the setCanvas3D, addCanvas3D, + * insertCanvas3D, removeCanvas3D, or + * removeAllCanvas3Ds methods of View are called to change + * the View's canvas list.

+ * + * Calling this method causes most transforms to be re-derived. It should + * be used only when necessary. + */ + public void updateView() { + if (verbose) System.err.println("updateView") ; + this.updateView = true ; + } + + /** + * Arrange for an update of the cached head position if head tracking is + * enabled. If automatic update has not enabled for the head position, + * then this method should be called anytime a new head position is to be + * read. + */ + public void updateHead() { + if (verbose) System.err.println("updateHead") ; + this.updateHead = true ; + } + + /** + * Arrange for an update of the cached localToVworld + * transform of the view platform. If automatic update has not been + * enabled for this transform, then this method should be called anytime + * the view platform has been repositioned in the virtual world and a + * transform involving virtual world coordinates is desired.

+ * + * The View must be attached to a ViewPlatform which is part of a live + * scene graph, and the ViewPlatform node must have its + * ALLOW_LOCAL_TO_VWORLD_READ capability set. + */ + public void updateViewPlatform() { + if (verbose) System.err.println("updateViewPlatform") ; + vpi.updateViewPlatformToVworld = true ; + } + + // + // Set cache update bits based on auto update flags. + // VIEW_AUTO_UPDATE is handled in updateCache(). + // + private void getAutoUpdate(CanvasInfo ci) { + if ((autoUpdateFlags & SCREEN_AUTO_UPDATE) != 0) + ci.si.updateScreen = true ; + + if ((autoUpdateFlags & CANVAS_AUTO_UPDATE) != 0) + ci.updateCanvas = true ; + + if ((autoUpdateFlags & PLATFORM_AUTO_UPDATE) != 0) + vpi.updateViewPlatformToVworld = true ; + + if ((autoUpdateFlags & HEAD_AUTO_UPDATE) != 0) + this.updateHead = true ; + } + + // + // Update any changed cached data. This takes a Canvas3D instance. The + // cache mechanism could have used a Canvas3D index into the View instead, + // but the direct reference is probably more convenient for applications. + // + private CanvasInfo updateCache(Canvas3D c3d, String name, boolean vworld) { + if (verbose) { + System.err.println("updateCache: " + name + " in " + hashCode()) ; + System.err.println(" canvas " + c3d.hashCode()) ; + } + + // The View may have had Canvas3D instances added or removed, or may + // have been attached to a different ViewPlatform, so update the view + // before anything else. + if (updateView || (autoUpdateFlags & VIEW_AUTO_UPDATE) != 0) + getViewInfo() ; + + // Now get the CanvasInfo to update. + CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ; + if (ci == null) + throw new IllegalArgumentException( + "Specified Canvas3D is not a component of the View") ; + + // Check rest of autoUpdateFlags. + if (autoUpdate) getAutoUpdate(ci) ; + + // Update the screen, canvas, view platform, and head caches. + if (ci.si.updateScreen) + ci.si.getScreenInfo() ; + + if (ci.updateCanvas) + ci.getCanvasInfo() ; + + if (vworld && vpi.updateViewPlatformToVworld) + vpi.getViewPlatformToVworld() ; + + if (useTracking && updateHead) + getHeadInfo() ; + + // Return the CanvasInfo instance. + return ci ; + } + + // + // Get physical view parameters and derived data. This is a fairly + // heavyweight method -- everything gets marked for update since we don't + // currently track changes in individual view attributes. Fortunately + // there shouldn't be a need to call it very often. + // + private void getViewInfo() { + if (verbose) System.err.println(" getViewInfo") ; + + // Check if an update of the Canvas3D collection is needed. + if (this.canvasCount != view.numCanvas3Ds()) { + this.canvasCount = view.numCanvas3Ds() ; + getCanvases() ; + } + else { + for (int i = 0 ; i < canvasCount ; i++) { + if (canvasMap.get(view.getCanvas3D(i)) != canvasInfo[i]) { + getCanvases() ; + break ; + } + } + } + + // Update the ViewPlatform. + getViewPlatform() ; + + // Update the PhysicalBody and PhysicalEnvironment. + this.body = view.getPhysicalBody() ; + this.env = view.getPhysicalEnvironment() ; + + // Use the result of the possibly overridden method useHeadTracking() + // to determine if head tracking is to be used within ViewInfo. + this.useTracking = useHeadTracking() ; + + // Get the head tracker only if really available. + if (view.getTrackingEnable() && env.getTrackingAvailable()) { + int headIndex = env.getHeadIndex() ; + this.headTracker = env.getSensor(headIndex) ; + } + + // Get the new policies and update data derived from them. + this.viewPolicy = view.getViewPolicy() ; + this.projectionPolicy = view.getProjectionPolicy() ; + this.resizePolicy = view.getWindowResizePolicy() ; + this.movementPolicy = view.getWindowMovementPolicy() ; + this.eyePolicy = view.getWindowEyepointPolicy() ; + this.scalePolicy = view.getScreenScalePolicy() ; + this.backClipPolicy = view.getBackClipPolicy() ; + this.frontClipPolicy = view.getFrontClipPolicy() ; + + if (useTracking || viewPolicy == View.HMD_VIEW) { + if (this.headToHeadTracker == null) + this.headToHeadTracker = new Transform3D() ; + if (this.headTrackerToTrackerBase == null) + this.headTrackerToTrackerBase = new Transform3D() ; + + if (viewPolicy == View.HMD_VIEW) { + if (this.trackerBaseToHeadTracker == null) + this.trackerBaseToHeadTracker = new Transform3D() ; + if (this.coeToHeadTracker == null) + this.coeToHeadTracker = new Transform3D() ; + } + else { + if (this.headToTrackerBase == null) + this.headToTrackerBase = new Transform3D() ; + } + + body.getLeftEyePosition(this.leftEyeInHead) ; + body.getRightEyePosition(this.rightEyeInHead) ; + body.getHeadToHeadTracker(this.headToHeadTracker) ; + + if (verbose) { + System.err.println(" leftEyeInHead " + leftEyeInHead) ; + System.err.println(" rightEyeInHead " + rightEyeInHead) ; + t3dPrint(headToHeadTracker, " headToHeadTracker") ; + } + } + + if (eyePolicy == View.RELATIVE_TO_WINDOW || + eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) { + body.getLeftEyePosition(this.leftEyeInHead) ; + body.getRightEyePosition(this.rightEyeInHead) ; + if (verbose) { + System.err.println(" leftEyeInHead " + leftEyeInHead) ; + System.err.println(" rightEyeInHead " + rightEyeInHead) ; + } + } + + if ((env.getCoexistenceCenterInPworldPolicy() != + View.NOMINAL_SCREEN) || (viewPolicy == View.HMD_VIEW)) + this.coeCentering = false ; + else + this.coeCentering = view.getCoexistenceCenteringEnable() ; + + if (!coeCentering || useTracking) { + if (this.coeToTrackerBase == null) + this.coeToTrackerBase = new Transform3D() ; + + env.getCoexistenceToTrackerBase(this.coeToTrackerBase) ; + if (verbose) t3dPrint(coeToTrackerBase, " coeToTrackerBase") ; + } + + if (backClipPolicy == View.VIRTUAL_EYE || + backClipPolicy == View.VIRTUAL_SCREEN || + frontClipPolicy == View.VIRTUAL_EYE || + frontClipPolicy == View.VIRTUAL_SCREEN) { + this.clipVirtual = true ; + } + else { + this.clipVirtual = false ; + } + + // Propagate view updates to each canvas. + for (int i = 0 ; i < canvasCount ; i++) + this.canvasInfo[i].updateViewDependencies() ; + + this.updateView = false ; + if (verbose) { + System.err.println(" tracking " + useTracking) ; + System.err.println(" coeCentering " + coeCentering) ; + System.err.println(" clipVirtual " + clipVirtual) ; + } + } + + // + // Each view can have multiple canvases, each with an associated screen. + // Each canvas is associated with only one view. Each screen can have + // multiple canvases that are used across multiple views. We rebuild the + // canvas info instead of trying to figure out what canvases have been + // added or removed from the view. + // + private void getCanvases() { + if (this.canvasInfo.length < canvasCount) { + this.canvasInfo = new CanvasInfo[canvasCount] ; + } + + for (int i = 0 ; i < canvasCount ; i++) { + Canvas3D c3d = view.getCanvas3D(i) ; + Screen3D s3d = c3d.getScreen3D() ; + + // Check if we have a new screen. + ScreenInfo si = (ScreenInfo)screenMap.get(s3d) ; + if (si == null) { + si = new ScreenInfo(s3d, c3d.getGraphicsConfiguration()) ; + screenMap.put(s3d, si) ; + } + + // Check to see if we've encountered the screen so far in this + // loop over the view's canvases. If not, clear the screen's list + // of canvases for this ViewInfo. + if (newSet.add(si)) si.clear(this) ; + + // Check if this is a new canvas. + CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ; + if (ci == null) ci = new CanvasInfo(c3d, si) ; + + // Add this canvas to the screen's list for this ViewInfo. + si.addCanvasInfo(this, ci) ; + + // Add this canvas to the new canvas map and canvas array. + this.newMap.put(c3d, ci) ; + this.canvasInfo[i] = ci ; + } + + // Null out old references if canvas count shrinks. + for (int i = canvasCount ; i < canvasInfo.length ; i++) + this.canvasInfo[i] = null ; + + // Update the CanvasInfo map. + Map tmp = canvasMap ; + this.canvasMap = newMap ; + this.newMap = tmp ; + + // Clear the temporary collections. + this.newMap.clear() ; + this.newSet.clear() ; + } + + // + // Force the creation of new CanvasInfo instances. This is called when a + // screen is removed from the screen map. + // + private void clearCanvases() { + this.canvasCount = 0 ; + this.canvasMap.clear() ; + this.updateView = true ; + } + + // + // Update the view platform. Each view can be attached to only one, but + // each view platform can have many views attached. + // + private void getViewPlatform() { + ViewPlatform vp = view.getViewPlatform() ; + if (vp == null) + throw new IllegalStateException + ("The View must be attached to a ViewPlatform") ; + + ViewPlatformInfo tmpVpi = + (ViewPlatformInfo)viewPlatformMap.get(vp) ; + + if (tmpVpi == null) { + // We haven't encountered this ViewPlatform before. + tmpVpi = new ViewPlatformInfo(vp) ; + viewPlatformMap.put(vp, tmpVpi) ; + } + + if (this.vpi != tmpVpi) { + // ViewPlatform has changed. Could set an update flag here if it + // would be used, but updating the view updates everything anyway. + if (this.vpi != null) { + // Remove this ViewInfo from the list of Views attached to the + // old ViewPlatform. + this.vpi.removeViewInfo(this) ; + } + this.vpi = tmpVpi ; + this.vpi.addViewInfo(this) ; + + // updateViewPlatformToVworld is initially set false since the + // capability to read the vworld transform may not be + // available. If it is, set it here. + if (vp.getCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ)) { + this.vpi.updateViewPlatformToVworld = true ; + if (verbose) System.err.println(" vworld read allowed") ; + } else + if (verbose) System.err.println(" vworld read disallowed") ; + } + } + + // + // Force the creation of a new ViewPlatformInfo when a view platform is + // removed from the view platform map. + // + private void clearViewPlatform() { + this.updateView = true ; + } + + // + // Update vworld dependencies for this ViewInfo -- called by + // ViewPlatformInfo.getViewPlatformToVworld(). + // + private void updateVworldDependencies() { + for (int i = 0 ; i < canvasCount ; i++) + this.canvasInfo[i].updateVworldDependencies() ; + } + + /** + * Returns a reference to a Transform3D containing the current transform + * from head tracker coordinates to tracker base coordinates. It is only + * called if useHeadTracking returns true and a head position + * update is specified with updateHead or the + * HEAD_AUTO_UPDATE constructor flag.

+ * + * The default implementation uses the head tracking sensor specified by + * the View's PhysicalEnvironment, and reads it by calling the sensor's + * getRead method directly. The result is a sensor reading + * that may have been taken at a slightly different time from the one used + * by the renderer. This method can be overridden to synchronize the two + * readings through an external mechanism. + * + * @return current head tracker to tracker base transform + * @see #useHeadTracking + * @see #updateHead + * @see #HEAD_AUTO_UPDATE + */ + protected Transform3D getHeadTrackerToTrackerBase() { + headTracker.getRead(this.headTrackerToTrackerBase) ; + return this.headTrackerToTrackerBase ; + } + + /** + * Returns true if head tracking should be used.

+ * + * The default implementation returns true if the View's + * getTrackingEnable method and the PhysicalEnvironment's + * getTrackingAvailable method both return true. + * These are the same conditions under which the Java 3D renderer uses + * head tracking. This method can be overridden if there is any need to + * decouple the head tracking status of ViewInfo from the renderer. + * + * @return true if ViewInfo should use head tracking + */ + protected boolean useHeadTracking() { + return view.getTrackingEnable() && env.getTrackingAvailable() ; + } + + // + // Cache the current tracked head position and derived data. + // + private void getHeadInfo() { + if (verbose) System.err.println(" getHeadInfo") ; + + this.headTrackerToTrackerBase = getHeadTrackerToTrackerBase() ; + if (viewPolicy == View.HMD_VIEW) { + this.trackerBaseToHeadTracker.invert(headTrackerToTrackerBase) ; + this.coeToHeadTracker.mul(trackerBaseToHeadTracker, + coeToTrackerBase) ; + } + else { + this.headToTrackerBase.mul(headTrackerToTrackerBase, + headToHeadTracker) ; + } + for (int i = 0 ; i < canvasCount ; i++) + this.canvasInfo[i].updateHeadDependencies() ; + + this.updateHead = false ; + // + // The head position used by the Java 3D renderer isn't accessible + // in the public API. A head tracker generates continuous data, so + // getting the same sensor read as the renderer is unlikely. + // + // Possible workaround: for fixed screens, get the Java 3D + // renderer's version of plateToVworld and headToVworld by calling + // Canvas3D.getImagePlateToVworld() and View.getUserHeadToVworld(). + // Although the vworld components will have frame latency, they can + // be cancelled out by inverting the former transform and + // multiplying by the latter, resulting in userHeadToImagePlate, + // which can then be transformed to tracker base coordinates. + // + // For head mounted displays, the head to image plate transforms are + // just calibration constants, so they're of no use. There are more + // involved workarounds possible, but one that may work for both fixed + // screens and HMD is to define a SensorInterposer class that extends + // Sensor. Take the View's head tracking sensor, use it to construct + // a SensorInterposer, and then replace the head tracking sensor with + // the SensorInterposer. SensorInterposer can then override the + // getRead() methods and thus control what the Java 3D renderer gets. + // getHeadTrackerToTrackerBase() is a protected method in ViewInfo + // which can be overridden to call a variant of getRead() so that + // calls from ViewInfo and from the renderer can be distinguished. + // + // Even if getting the same head position as used by the renderer is + // achieved, tracked eye space interactions with objects in the + // virtual world still can't be synchronized with rendering. This + // means that objects in the virtual world cannot be made to appear in + // a fixed position relative to the tracked head position without a + // frame lag between them. + // + // The reason for this is that the tracked head position used by the + // Java 3D renderer is updated asynchronously from scene graph + // updates. This is done to reduce latency between the user's + // position and the rendered image, which is directly related to the + // quality of the immersive virtual reality experience. So while an + // update to the scene graph may have a frame latency before it gets + // rendered, a change to the user's tracked position is always + // reflected in the current frame. + // + // This problem can't be fixed without eliminating the frame latency + // in the Java 3D internal state, although there are possible + // workarounds at the expense of increased user position latency. + // These involve disabling tracking, reading the head sensor directly, + // performing whatever eye space interactions are necessary with the + // virtual world (using the view platform's current localToVworld), + // and then propagating the head position change to the renderer + // manually through a behavior post mechanism that delays it by a + // frame. + // + // For example, with head tracking in a fixed screen environment (such + // as a CAVE), disable Java 3D head tracking and set the View's window + // eyepoint policy to RELATIVE_TO_COEXISTENCE. Read the sensor to get + // the head position relative to the tracker base, transform it to + // coexistence coordinates using the inverse of the value of the + // coexistenceToTrackerBase transform, and then set the eye positions + // manually with the View's set{Left,Right}ManualEyeInCoexistence + // methods. If these method calls are delayed through a behavior post + // mechanism, then they will be synchronized with the rendering of the + // scene graph updates. + // + // With a head mounted display the sensor can be read directly to get + // the head position relative to the tracker base. If Java 3D's head + // tracking is disabled, it uses identity for the current + // headTrackerToTrackerBase transform. It concatenates its inverse, + // trackerBaseToHeadTracker, with coexistenceToTrackerBase to get the + // image plate positions in coexistence; the former transform is + // inaccessible, but the latter can be set through the + // PhysicalEnvironment. So the workaround is to maintain a local copy + // with the real value of coexistenceToTrackerBase, but set the + // PhysicalEnvironment copy to the product of the real value and the + // trackerBaseToHeadTracker inverted from the sensor read. Like the + // CAVE example, this update to the View would have to be delayed in + // order to synchronize with scene graph updates. + // + // Another possibility is to put the Java 3D view model in + // compatibility mode, where it accepts vpcToEye and eyeToCc + // (projection) directly. The various view attributes can still be + // set and accessed, but will be ignored by the Java 3D view model. + // The ViewInfo methods can be used to compute the view and projection + // matrices, which can then be delayed to synchronize with the scene + // graph. + // + // Note that these workarounds could be used to make view-dependent + // scene graph updates consistent, but they still can't do anything + // about synchronizing the actual physical position of the user with + // the rendered images. That requires zero latency between position + // update and scene graph state. + // + // Still another possibility: extrapolate the position of the user + // into the next few frames from a sample of recently recorded + // positions. Unfortunately, that is also a very hard problem. The + // Java 3D Sensor API is designed to support prediction but it was + // never realized successfully in the sample implementation. + } + + // + // A per-screen cache, shared between ViewInfo instances. In the Java 3D + // view model a single screen can be associated with multiple canvas + // and view instances. + // + private static class ScreenInfo { + private Screen3D s3d = null ; + private GraphicsConfiguration graphicsConfiguration = null ; + private boolean updateScreen = true ; + + private Map viewInfoMap = new HashMap() ; + private List viewInfoList = new LinkedList() ; + private Transform3D t3d = new Transform3D() ; + + private double screenWidth = 0.0 ; + private double screenHeight = 0.0 ; + private boolean updateScreenSize = true ; + + private Rectangle screenBounds = null ; + private double metersPerPixelX = 0.0 ; + private double metersPerPixelY = 0.0 ; + private boolean updatePixelSize = true ; + + // These transforms are pre-allocated here since they are required by + // some view policies and we don't know what views this screen will be + // attached to. Their default identity values are used if not + // explicitly set. TODO: allocate if needed in getCanvasInfo(), where + // view information will be available. + private Transform3D trackerBaseToPlate = new Transform3D() ; + private Transform3D headTrackerToLeftPlate = new Transform3D() ; + private Transform3D headTrackerToRightPlate = new Transform3D() ; + private boolean updateTrackerBaseToPlate = false ; + private boolean updateHeadTrackerToPlate = false ; + + private ScreenInfo(Screen3D s3d, GraphicsConfiguration gc) { + this.s3d = s3d ; + this.graphicsConfiguration = gc ; + if (verbose) + System.err.println(" ScreenInfo: init " + s3d.hashCode()) ; + } + + private List getCanvasList(ViewInfo vi) { + List canvasList = (List)viewInfoMap.get(vi) ; + if (canvasList == null) { + canvasList = new LinkedList() ; + viewInfoMap.put(vi, canvasList) ; + viewInfoList.add(canvasList) ; + } + return canvasList ; + } + + private synchronized void clear(ViewInfo vi) { + getCanvasList(vi).clear() ; + } + + private synchronized void clear() { + Iterator i = viewInfoMap.keySet().iterator() ; + while (i.hasNext()) ((ViewInfo)i.next()).clearCanvases() ; + viewInfoMap.clear() ; + + i = viewInfoList.iterator() ; + while (i.hasNext()) ((List)i.next()).clear() ; + viewInfoList.clear() ; + } + + private synchronized void addCanvasInfo(ViewInfo vi, CanvasInfo ci) { + getCanvasList(vi).add(ci) ; + } + + // + // Get all relevant screen information, find out what changed, and + // flag derived data. With normal use it's unlikely that any of the + // Screen3D attributes will change after the first time this method is + // called. It's possible that the screen resolution changed or some + // sort of interactive screen calibration is in process. + // + private synchronized void getScreenInfo() { + if (verbose) + System.err.println(" getScreenInfo " + s3d.hashCode()); + + // This is used for positioning screens in relation to each other + // and must be accurate for good results with multi-screen + // displays. By default the coexistence to tracker base transform + // is identity so in that case this transform will also set the + // image plate in coexistence coordinates. + s3d.getTrackerBaseToImagePlate(t3d) ; + if (! t3d.equals(trackerBaseToPlate)) { + this.trackerBaseToPlate.set(t3d) ; + this.updateTrackerBaseToPlate = true ; + if (verbose) t3dPrint(trackerBaseToPlate, + " trackerBaseToPlate") ; + } + + // This transform and the following are used for head mounted + // displays. They should be based on the *apparent* position of + // the screens as viewed through the HMD optics. + s3d.getHeadTrackerToLeftImagePlate(t3d) ; + if (! t3d.equals(headTrackerToLeftPlate)) { + this.headTrackerToLeftPlate.set(t3d) ; + this.updateHeadTrackerToPlate = true ; + if (verbose) t3dPrint(headTrackerToLeftPlate, + " headTrackerToLeftPlate") ; + } + + s3d.getHeadTrackerToRightImagePlate(t3d) ; + if (! t3d.equals(headTrackerToRightPlate)) { + this.headTrackerToRightPlate.set(t3d) ; + this.updateHeadTrackerToPlate = true ; + if (verbose) t3dPrint(headTrackerToRightPlate, + " headTrackerToRightPlate") ; + } + + // If the screen width and height in meters are not explicitly set + // through the Screen3D, then the Screen3D will assume a pixel + // resolution of 90 pixels/inch and compute the dimensions from + // the screen resolution. These dimensions should be measured + // accurately for multi-screen displays. For HMD, these + // dimensions should be the *apparent* width and height as viewed + // through the HMD optics. + double w = s3d.getPhysicalScreenWidth() ; + double h = s3d.getPhysicalScreenHeight(); + if (w != screenWidth || h != screenHeight) { + this.screenWidth = w ; + this.screenHeight = h ; + this.updateScreenSize = true ; + if (verbose) { + System.err.println(" screen width " + screenWidth) ; + System.err.println(" screen height " + screenHeight) ; + } + } + + GraphicsConfiguration gc1 = graphicsConfiguration; + // Workaround for Issue 316 - use the default config for screen 0 + // if the graphics config is null + if (gc1 == null) { + gc1 = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + } + this.screenBounds = gc1.getBounds() ; + double mpx = screenWidth / (double)screenBounds.width ; + double mpy = screenHeight / (double)screenBounds.height ; + if ((mpx != metersPerPixelX) || (mpy != metersPerPixelY)) { + this.metersPerPixelX = mpx ; + this.metersPerPixelY = mpy ; + this.updatePixelSize = true ; + if (verbose) { + System.err.println(" screen bounds " + screenBounds) ; + System.err.println(" pixel size X " + metersPerPixelX) ; + System.err.println(" pixel size Y " + metersPerPixelY) ; + } + } + + // Propagate screen updates to each canvas in each ViewInfo. + Iterator vi = viewInfoList.iterator() ; + while (vi.hasNext()) { + Iterator ci = ((List)vi.next()).iterator() ; + while (ci.hasNext()) + ((CanvasInfo)ci.next()).updateScreenDependencies() ; + } + + this.updateTrackerBaseToPlate = false ; + this.updateHeadTrackerToPlate = false ; + this.updateScreenSize = false ; + this.updatePixelSize = false ; + this.updateScreen = false ; + } + } + + // + // A per-ViewPlatform cache, shared between ViewInfo instances. In the + // Java 3D view model, a view platform may have several views attached to + // it. The only view platform data cached here is its localToVworld, the + // inverse of its localToVworld, and the scale from vworld to view + // platform coordinates. The view platform to coexistence transform is + // cached by the CanvasInfo instances associated with the ViewInfo. + // + private static class ViewPlatformInfo { + private ViewPlatform vp = null ; + private List viewInfo = new LinkedList() ; + private double[] m = new double[16] ; + + // These transforms are pre-allocated since we don't know what views + // will be attached. Their default identity values are used if a + // vworld dependent computation is requested and no initial update of + // the view platform was performed; this occurs if the local to vworld + // read capability isn't set. TODO: rationalize this and allocate + // only if necessary. + private Transform3D viewPlatformToVworld = new Transform3D() ; + private Transform3D vworldToViewPlatform = new Transform3D() ; + private double vworldToViewPlatformScale = 1.0 ; + + // Set these update flags initially false since we might not have the + // capability to read the vworld transform. + private boolean updateViewPlatformToVworld = false ; + private boolean updateVworldScale = false ; + + private ViewPlatformInfo(ViewPlatform vp) { + this.vp = vp ; + if (verbose) System.err.println + (" ViewPlatformInfo: init " + vp.hashCode()) ; + } + + private synchronized void addViewInfo(ViewInfo vi) { + this.viewInfo.add(vi) ; + } + + private synchronized void removeViewInfo(ViewInfo vi) { + this.viewInfo.remove(vi) ; + } + + private synchronized void clear() { + Iterator i = viewInfo.iterator() ; + while (i.hasNext()) ((ViewInfo)i.next()).clearViewPlatform() ; + viewInfo.clear() ; + } + + // + // Get the view platform's current localToVworld and + // force the update of derived data. + // + private synchronized void getViewPlatformToVworld() { + if (verbose) System.err.println + (" getViewPlatformToVworld " + vp.hashCode()) ; + + vp.getLocalToVworld(this.viewPlatformToVworld) ; + this.vworldToViewPlatform.invert(viewPlatformToVworld) ; + + // Get the scale factor from the virtual world to view platform + // transform. Note that this is always a congruent transform. + vworldToViewPlatform.get(m) ; + double newScale = Math.sqrt(m[0]*m[0] + m[1]*m[1] + m[2]*m[2]) ; + + // May need to update clip plane distances if scale changed. We'll + // check with an epsilon commensurate with single precision float. + // It would be more efficient to check the square of the distance + // and then compute the square root only if different, but that + // makes choosing an epsilon difficult. + if ((newScale > vworldToViewPlatformScale + 0.0000001) || + (newScale < vworldToViewPlatformScale - 0.0000001)) { + this.vworldToViewPlatformScale = newScale ; + this.updateVworldScale = true ; + if (verbose) System.err.println(" vworld scale " + + vworldToViewPlatformScale) ; + } + + // All virtual world transforms must be updated. + Iterator i = viewInfo.iterator() ; + while (i.hasNext()) + ((ViewInfo)i.next()).updateVworldDependencies() ; + + this.updateVworldScale = false ; + this.updateViewPlatformToVworld = false ; + } + } + + // + // A per-canvas cache. + // + private class CanvasInfo { + private Canvas3D c3d = null ; + private ScreenInfo si = null ; + private boolean updateCanvas = true ; + + private double canvasX = 0.0 ; + private double canvasY = 0.0 ; + private boolean updatePosition = true ; + + private double canvasWidth = 0.0 ; + private double canvasHeight = 0.0 ; + private double windowScale = 0.0 ; + private boolean updateWindowScale = true ; + + private double screenScale = 0.0 ; + private boolean updateScreenScale = true ; + + private boolean useStereo = false ; + private boolean updateStereo = true ; + + // + // coeToPlate is the same for each Canvas3D in a Screen3D unless + // coexistence centering is enabled and the window movement policy is + // PHYSICAL_WORLD. + // + private Transform3D coeToPlate = null ; + private Transform3D coeToRightPlate = null ; + private boolean updateCoeToPlate = true ; + + // + // viewPlatformToCoe is the same for each Canvas3D in a View unless + // the window resize policy is PHYSICAL_WORLD, in which case the scale + // factor includes the window scale; or if the screen scale policy is + // SCALE_SCREEN_SIZE, in which case the scale factor depends upon the + // width of the screen associated with the canvas; or if the window + // eyepoint policy is RELATIVE_TO_FIELD_OF_VIEW and the view attach + // policy is not NOMINAL_SCREEN, which will set the view platform + // origin in coexistence based on the width of the canvas. + // + private Transform3D viewPlatformToCoe = null ; + private Transform3D coeToViewPlatform = null ; + private boolean updateViewPlatformToCoe = true ; + private boolean updateCoeToViewPlatform = true ; + + // + // plateToViewPlatform is composed from viewPlatformToCoe and + // coeToPlate. + // + private Transform3D plateToViewPlatform = null ; + private Transform3D rightPlateToViewPlatform = null ; + private boolean updatePlateToViewPlatform = true ; + + // + // trackerBaseToViewPlatform is computed from viewPlatformToCoe and + // coeToTrackerBase. + // + private Transform3D trackerBaseToViewPlatform = null ; + private boolean updateTrackerBaseToViewPlatform = true ; + + // + // Eye position in image plate is always different for each Canvas3D + // in a View, unless two or more Canvas3D instances are the same + // position and size, or two or more Canvas3D instances are using a + // window eyepoint policy of RELATIVE_TO_SCREEN and have the same + // settings for the manual eye positions. + // + private Point3d eyeInPlate = new Point3d() ; + private Point3d rightEyeInPlate = new Point3d() ; + private Transform3D eyeToPlate = null ; + private Transform3D rightEyeToPlate = null ; + private boolean updateEyeInPlate = true ; + + private Point3d leftManualEyeInPlate = new Point3d() ; + private Point3d rightManualEyeInPlate = new Point3d() ; + private boolean updateManualEye = true ; + + private int monoscopicPolicy = -1 ; + private boolean updateMonoPolicy = true ; + + // + // eyeToViewPlatform is computed from eyeToPlate and + // plateToViewPlatform. + // + private Transform3D eyeToViewPlatform = null ; + private Transform3D rightEyeToViewPlatform = null ; + private boolean updateEyeToViewPlatform = true ; + + private Transform3D viewPlatformToEye = null ; + private Transform3D viewPlatformToRightEye = null ; + private boolean updateViewPlatformToEye = true ; + + // + // The projection transform depends upon eye position in image plate. + // + private Transform3D projection = null ; + private Transform3D rightProjection = null ; + private boolean updateProjection = true ; + + private Transform3D inverseProjection = null ; + private Transform3D inverseRightProjection = null ; + private boolean updateInverseProjection = true ; + + private Transform3D inverseViewPlatformProjection = null ; + private Transform3D inverseViewPlatformRightProjection = null ; + private boolean updateInverseViewPlatformProjection = true ; + + // + // The physical clip distances can be affected by the canvas width + // with the PHYSICAL_WORLD resize policy. + // + private double frontClipDistance = 0.0 ; + private double backClipDistance = 0.0 ; + private boolean updateClipDistances = true ; + + // + // The physical to view platform scale can be affected by the canvas + // width with the PHYSICAL_WORLD resize policy. + // + private double physicalToVpScale = 0.0 ; + private double physicalToVirtualScale = 0.0 ; + private boolean updatePhysicalToVpScale = true ; + private boolean updatePhysicalToVirtualScale = true ; + + // + // The vworld transforms require reading the ViewPlaform's + // localToVworld tranform. + // + private Transform3D plateToVworld = null ; + private Transform3D rightPlateToVworld = null ; + private boolean updatePlateToVworld = true ; + + private Transform3D coeToVworld = null ; + private boolean updateCoeToVworld = true ; + + private Transform3D eyeToVworld = null ; + private Transform3D rightEyeToVworld = null ; + private boolean updateEyeToVworld = true ; + + private Transform3D trackerBaseToVworld = null ; + private boolean updateTrackerBaseToVworld = true ; + + private Transform3D inverseVworldProjection = null ; + private Transform3D inverseVworldRightProjection = null ; + private boolean updateInverseVworldProjection = true ; + + private CanvasInfo(Canvas3D c3d, ScreenInfo si) { + this.si = si ; + this.c3d = c3d ; + if (verbose) System.err.println(" CanvasInfo: init " + + c3d.hashCode()) ; + } + + private void getCanvasInfo() { + if (verbose) System.err.println(" getCanvasInfo " + + c3d.hashCode()) ; + boolean newStereo = + c3d.getStereoEnable() && c3d.getStereoAvailable() ; + + if (useStereo != newStereo) { + this.useStereo = newStereo ; + this.updateStereo = true ; + if (verbose) System.err.println(" stereo " + useStereo) ; + } + + this.canvasWidth = c3d.getWidth() * si.metersPerPixelX ; + this.canvasHeight = c3d.getHeight() * si.metersPerPixelY ; + double newScale = canvasWidth / si.screenWidth ; + + if (windowScale != newScale) { + this.windowScale = newScale ; + this.updateWindowScale = true ; + if (verbose) { + System.err.println(" width " + canvasWidth) ; + System.err.println(" height " + canvasHeight) ; + System.err.println(" scale " + windowScale) ; + } + } + + // For multiple physical screens, AWT returns the canvas location + // relative to the origin of the aggregated virtual screen. We + // need the location relative to the physical screen origin. + Point awtLocation = c3d.getLocationOnScreen() ; + int x = awtLocation.x - si.screenBounds.x ; + int y = awtLocation.y - si.screenBounds.y ; + + double newCanvasX = si.metersPerPixelX * x ; + double newCanvasY = si.metersPerPixelY * + (si.screenBounds.height - (y + c3d.getHeight())) ; + + if (canvasX != newCanvasX || canvasY != newCanvasY) { + this.canvasX = newCanvasX ; + this.canvasY = newCanvasY ; + this.updatePosition = true ; + if (verbose) { + System.err.println(" lower left X " + canvasX) ; + System.err.println(" lower left Y " + canvasY) ; + } + } + + int newMonoPolicy = c3d.getMonoscopicViewPolicy() ; + if (monoscopicPolicy != newMonoPolicy) { + this.monoscopicPolicy = newMonoPolicy ; + this.updateMonoPolicy = true ; + + if (verbose && !useStereo) { + if (monoscopicPolicy == View.LEFT_EYE_VIEW) + System.err.println(" left eye view") ; + else if (monoscopicPolicy == View.RIGHT_EYE_VIEW) + System.err.println(" right eye view") ; + else + System.err.println(" cyclopean view") ; + } + } + + c3d.getLeftManualEyeInImagePlate(leftEye) ; + c3d.getRightManualEyeInImagePlate(rightEye) ; + + if (!leftEye.equals(leftManualEyeInPlate) || + !rightEye.equals(rightManualEyeInPlate)) { + + this.leftManualEyeInPlate.set(leftEye) ; + this.rightManualEyeInPlate.set(rightEye) ; + this.updateManualEye = true ; + + if (verbose && (eyePolicy == View.RELATIVE_TO_WINDOW || + eyePolicy == View.RELATIVE_TO_SCREEN)) { + System.err.println(" left manual eye in plate " + + leftManualEyeInPlate) ; + System.err.println(" right manual eye in plate " + + rightManualEyeInPlate) ; + } + } + + updateCanvasDependencies() ; + this.updateStereo = false ; + this.updateWindowScale = false ; + this.updatePosition = false ; + this.updateMonoPolicy = false ; + this.updateManualEye = false ; + this.updateCanvas = false ; + } + + private double getFieldOfViewOffset() { + return 0.5 * canvasWidth / Math.tan(0.5 * view.getFieldOfView()) ; + } + + private void updateScreenDependencies() { + if (si.updatePixelSize || si.updateScreenSize) { + if (eyePolicy == View.RELATIVE_TO_WINDOW || + eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) { + // Physical location of the canvas might change without + // changing the pixel location. + updateEyeInPlate = true ; + } + if (resizePolicy == View.PHYSICAL_WORLD || + eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) { + // Could change the window scale or view platform Z offset. + updateViewPlatformToCoe = true ; + } + if (resizePolicy == View.PHYSICAL_WORLD) { + // Window scale affects the clip distance and the physical + // to viewplatform scale. + updateClipDistances = true ; + updatePhysicalToVpScale = true ; + updatePhysicalToVirtualScale = true ; + } + // Upper right corner of canvas may have moved from eye. + updateProjection = true ; + } + if (si.updateScreenSize && scalePolicy == View.SCALE_SCREEN_SIZE) { + // Screen scale affects the clip distances and physical to + // view platform scale. The screen scale is also a component + // of viewPlatformToCoe. + updateScreenScale = true ; + updateClipDistances = true ; + updatePhysicalToVpScale = true ; + updatePhysicalToVirtualScale = true ; + updateViewPlatformToCoe = true ; + } + + if (viewPolicy == View.HMD_VIEW) { + if (si.updateHeadTrackerToPlate) { + // Plate moves with respect to the eye and coexistence. + updateEyeInPlate = true ; + updateCoeToPlate = true ; + } + } + else if (coeCentering) { + if (movementPolicy == View.PHYSICAL_WORLD) { + // Coexistence is centered on the canvas. + if (si.updatePixelSize || si.updateScreenSize) + // Physical location of the canvas might change + // without changing the pixel location. + updateCoeToPlate = true ; + } + else if (si.updateScreenSize) + // Coexistence is centered on the screen. + updateCoeToPlate = true ; + } + else if (si.updateTrackerBaseToPlate) { + // Image plate has possibly changed location. Could be + // offset by an update to coeToTrackerBase in the + // PhysicalEnvironment though. + updateCoeToPlate = true ; + } + + if (updateCoeToPlate && + eyePolicy == View.RELATIVE_TO_COEXISTENCE) { + // Coexistence has moved with respect to plate. + updateEyeInPlate = true ; + } + if (updateViewPlatformToCoe) { + // Derived transforms. trackerBaseToViewPlatform is composed + // from viewPlatformToCoe and coexistenceToTrackerBase. + updateCoeToViewPlatform = true ; + updateCoeToVworld = true ; + updateTrackerBaseToViewPlatform = true ; + updateTrackerBaseToVworld = true ; + } + if (updateCoeToPlate || updateViewPlatformToCoe) { + // The image plate to view platform transform is composed from + // the coexistence to image plate and view platform to + // coexistence transforms, so these need updates as well. + updatePlateToViewPlatform = true ; + updatePlateToVworld = true ; + } + updateEyeDependencies() ; + } + + private void updateEyeDependencies() { + if (updateEyeInPlate) { + updateEyeToVworld = true ; + updateProjection = true ; + } + if (updateProjection) { + updateInverseProjection = true ; + updateInverseViewPlatformProjection = true ; + updateInverseVworldProjection = true ; + } + if (updateEyeInPlate || updatePlateToViewPlatform) { + updateViewPlatformToEye = true ; + updateEyeToViewPlatform = true ; + } + } + + private void updateCanvasDependencies() { + if (updateStereo || updateMonoPolicy || + (updateManualEye && (eyePolicy == View.RELATIVE_TO_WINDOW || + eyePolicy == View.RELATIVE_TO_SCREEN))) { + updateEyeInPlate = true ; + } + if (updateWindowScale || updatePosition) { + if (coeCentering && movementPolicy == View.PHYSICAL_WORLD) { + // Coexistence is centered on the canvas. + updateCoeToPlate = true ; + if (eyePolicy == View.RELATIVE_TO_COEXISTENCE) + updateEyeInPlate = true ; + } + if (eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW || + eyePolicy == View.RELATIVE_TO_WINDOW) + // Eye depends on canvas position and size. + updateEyeInPlate = true ; + } + if (updateWindowScale) { + if (resizePolicy == View.PHYSICAL_WORLD || + eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) { + // View platform scale and its origin Z offset changed. + // trackerBaseToViewPlatform needs viewPlatformToCoe. + updateViewPlatformToCoe = true ; + updateCoeToViewPlatform = true ; + updateCoeToVworld = true ; + updateTrackerBaseToViewPlatform = true ; + updateTrackerBaseToVworld = true ; + } + if (resizePolicy == View.PHYSICAL_WORLD) { + // Clip distance and physical to view platform scale are + // affected by the window size. + updateClipDistances = true ; + updateProjection = true ; + updatePhysicalToVpScale = true ; + updatePhysicalToVirtualScale = true ; + } + } + if (updateViewPlatformToCoe || updateCoeToPlate) { + // The image plate to view platform transform is composed from + // the coexistence to image plate and the view platform to + // coexistence transforms, so these need updates. + updatePlateToViewPlatform = true ; + updatePlateToVworld = true ; + } + if (coeCentering && !updateManualEye && !updateWindowScale && + (movementPolicy == View.PHYSICAL_WORLD) && + (eyePolicy != View.RELATIVE_TO_SCREEN)) { + // The canvas may have moved, but the eye, coexistence, and + // view platform moved with it. updateEyeDependencies() + // isn't called since it would unnecessarily update the + // projection and eyeToViewPlatform transforms. The tested + // policies are all true by default. + return ; + } + updateEyeDependencies() ; + } + + // + // TODO: A brave soul could refine cache updates here. There are a + // lot of attributes to monitor, so we just update everything for now. + // + private void updateViewDependencies() { + // View policy, physical body eye positions, head to head + // tracker, window eyepoint policy, field of view, coexistence + // centering, or coexistence to image plate may have changed. + updateEyeInPlate = true ; + + // If the eye position in image plate has changed, then the + // projection transform may need to be updated. The projection + // policy and clip plane distances and policies may have changed. + // The window resize policy and screen scale may have changed, + // which affects clip plane distance scaling. + updateProjection = true ; + updateClipDistances = true ; + updatePhysicalToVpScale = true ; + updatePhysicalToVirtualScale = true ; + + // View policy, coexistence to tracker base, coexistence centering + // enable, or window movement policy may have changed. + updateCoeToPlate = true ; + + // Screen scale, resize policy, view policy, view platform, + // physical body, physical environment, eyepoint policy, or field + // of view may have changed. + updateViewPlatformToCoe = true ; + updateCoeToViewPlatform = true ; + updateCoeToVworld = true ; + + // The image plate to view platform transform is composed from the + // coexistence to image plate and view platform to coexistence + // transforms, so these need updates. + updatePlateToViewPlatform = true ; + updatePlateToVworld = true ; + + // View platform to coexistence or coexistence to tracker base may + // have changed. + updateTrackerBaseToViewPlatform = true ; + updateTrackerBaseToVworld = true ; + + // Screen scale policy or explicit screen scale may have changed. + updateScreenScale = true ; + + // Update transforms derived from eye info. + updateEyeDependencies() ; + } + + private void updateHeadDependencies() { + if (viewPolicy == View.HMD_VIEW) { + // Image plates are fixed relative to the head, so their + // positions have changed with respect to coexistence, the + // view platform, and the virtual world. The eyes are fixed + // with respect to the image plates, so the projection doesn't + // change with respect to them. + updateCoeToPlate = true ; + updatePlateToViewPlatform = true ; + updatePlateToVworld = true ; + updateViewPlatformToEye = true ; + updateEyeToViewPlatform = true ; + updateEyeToVworld = true ; + updateInverseViewPlatformProjection = true ; + updateInverseVworldProjection = true ; + } + else { + // Eye positions have changed with respect to the fixed + // screens, so the projections must be updated as well as the + // positions. + updateEyeInPlate = true ; + updateEyeDependencies() ; + } + } + + private void updateVworldDependencies() { + updatePlateToVworld = true ; + updateCoeToVworld = true ; + updateEyeToVworld = true ; + updateTrackerBaseToVworld = true ; + updateInverseVworldProjection = true ; + + if (vpi.updateVworldScale) + updatePhysicalToVirtualScale = true ; + + if (vpi.updateVworldScale && clipVirtual) { + // vworldToViewPlatformScale changed and clip plane distances + // are in virtual units. + updateProjection = true ; + updateClipDistances = true ; + updateInverseProjection = true ; + updateInverseViewPlatformProjection = true ; + } + } + } + + /** + * Prints out the specified transform in a readable format. + * + * @param t3d transform to be printed + * @param name the name of the transform + */ + private static void t3dPrint(Transform3D t3d, String name) { + double[] m = new double[16] ; + t3d.get(m) ; + String[] sa = formatMatrixRows(4, 4, m) ; + System.err.println(name) ; + for (int i = 0 ; i < 4 ; i++) System.err.println(sa[i]) ; + } + + /** + * Formats a matrix with fixed fractional digits and integer padding to + * align the decimal points in columns. Non-negative numbers print up to + * 7 integer digits, while negative numbers print up to 6 integer digits + * to account for the negative sign. 6 fractional digits are printed. + * + * @param rowCount number of rows in the matrix + * @param colCount number of columns in the matrix + * @param m matrix to be formatted + * @return matrix rows formatted into strings + */ + private static String[] formatMatrixRows + (int rowCount, int colCount, double[] m) { + + DecimalFormat df = new DecimalFormat("0.000000") ; + FieldPosition fp = new FieldPosition(DecimalFormat.INTEGER_FIELD) ; + StringBuffer sb0 = new StringBuffer() ; + StringBuffer sb1 = new StringBuffer() ; + String[] rows = new String[rowCount] ; + + for (int i = 0 ; i < rowCount ; i++) { + sb0.setLength(0) ; + for (int j = 0 ; j < colCount ; j++) { + sb1.setLength(0) ; + df.format(m[i*colCount+j], sb1, fp) ; + int pad = 8 - fp.getEndIndex() ; + for (int k = 0 ; k < pad ; k++) { + sb1.insert(0, " ") ; + } + sb0.append(sb1) ; + } + rows[i] = sb0.toString() ; + } + return rows ; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/Viewer.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/Viewer.java new file mode 100644 index 0000000..f3aaef1 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/Viewer.java @@ -0,0 +1,1071 @@ +/* + * $RCSfile: Viewer.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.9 $ + * $Date: 2007/02/09 17:20:45 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import java.awt.event.*; +import java.awt.*; +import java.net.URL; +import java.util.*; +import javax.media.j3d.*; +import javax.swing.*; +import com.sun.j3d.audioengines.AudioEngine3DL2; +import java.lang.reflect.Constructor; + +/** + * The Viewer class holds all the information that describes the physical + * and virtual "presence" in the Java 3D universe. The Viewer object + * consists of: + *

    + *
  • Physical Objects
  • + *
      + *
    • Canvas3D's - used to render with.
    • + *
    • PhysicalEnvironment - holds characteristics of the hardware platform + * being used to render on.
    • + *
    • PhysicalBody - holds the physical characteristics and personal + * preferences of the person who will be viewing the Java 3D universe.
    • + *
    + *
  • Virtual Objects
  • + *
      + *
    • View - the Java 3D View object.
    • + *
    • ViewerAvatar - the geometry that is used by Java 3D to represent the + * person viewing the Java 3D universe.
    • + *
    + *
+ * If the Viewer object is created without any Canvas3D's, or indirectly + * through a configuration file, it will create the Canvas3D's as needed. + * The default Viewer creates one Canvas3D. If the Viewer object creates + * the Canvas3D's, it will also create a JPanel and JFrame for each Canvas3D. + * + * Dynamic video resize is a new feature in Java 3D 1.3.1. + * This feature provides a means for doing swap synchronous resizing + * of the area that is to be magnified (or passed through) to the + * output video resolution. This functionality allows an application + * to draw into a smaller viewport in the framebuffer in order to reduce + * the time spent doing pixel fill. The reduced size viewport is then + * magnified up to the video output resolution using the SUN_video_resize + * extension. This extension is only implemented in XVR-4000 and later + * hardware with back end video out resizing capability. + * + * If video size compensation is enable, the line widths, point sizes and pixel + * operations will be scaled internally with the resize factor to approximately + * compensate for video resizing. The location of the pixel ( x, y ) in the + * resized framebuffer = ( floor( x * factor + 0.5 ), floor( y * factor + 0.5 ) ) + * + *

+ * @see Canvas3D + * @see PhysicalEnvironment + * @see PhysicalBody + * @see View + * @see ViewerAvatar + */ +public class Viewer { + private static final boolean debug = false; + private static PhysicalBody physicalBody = null; + private static PhysicalEnvironment physicalEnvironment = null; + private View view = null; + private ViewerAvatar avatar = null; + private Canvas3D[] canvases = null; + private JFrame[] j3dJFrames = null; + private JPanel[] j3dJPanels = null; + private Window[] j3dWindows = null; + private ViewingPlatform viewingPlatform = null; + + + static HashMap viewerMap = new HashMap(5); + private float dvrFactor = 1.0f; + private boolean doDvr = false; + private boolean doDvrResizeCompensation = true; + + + /** + * Get the Viewer associated with the view object. + * + * @param view The View object for inquiry. + * @return The Viewer object associated with this View object. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public static Viewer getViewer(View view) { + Viewer viewer = null; + synchronized (viewerMap) { + //System.out.println("Viewer.getViewer viewerMap's size is " + viewerMap.size()); + viewer = (Viewer) (viewerMap.get(view)); + } + return viewer; + } + + + /** + * Removes the entry associated with the view object. + * + * @param view The View object to be removed. + * @return The Viewer object associated with this View object. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public static Viewer removeViewerMapEntry(View view) { + Viewer viewer = null; + synchronized (viewerMap) { + + viewer = (Viewer) (viewerMap.remove(view)); + } + // System.out.println("viewerMap.size() " + viewerMap.size()); + + return viewer; + } + + + /** + * Removes all Viewer mappings from the Viewer map. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public static void clearViewerMap() { + synchronized (viewerMap) { + viewerMap.clear(); + } + // System.out.println("clearViewerMap - viewerMap.size() " + viewerMap.size()); + + } + + + /** + * Returns a status flag indicating whether or not dynamic video size + * is enabled. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public boolean isDvrEnabled() { + return doDvr; + } + + /** + * Turns on or off dynamic video size. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @param dvr enables or disables dynamic video size. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public void setDvrEnable(boolean dvr) { + doDvr = dvr; + view.repaint(); + + } + + /** + * Retrieves the dynamic video resize factor of this + * viewer. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public float getDvrFactor() { + return dvrFactor; + } + + + /** + * Set the dynamic video resize factor for this viewer. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @param dvr set the dynamic video resize factor for this viewer. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public void setDvrFactor(float dvr) { + dvrFactor = dvr; + view.repaint(); + + } + + /** + * Turns on or off dynamic video resize compensation. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @param dvrRCE enables or disables dynamic video resize compensation. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public void setDvrResizeCompensationEnable(boolean dvrRCE) { + doDvrResizeCompensation = dvrRCE; + view.repaint(); + } + + /** + * Returns a status flag indicating whether or not dynamic video resize + * compensation is enabled. + * + * Note: This method is targeted for SUN framebuffer XVR-4000 and later + * hardware that support video size extension. + * + * @since Java 3D 1.3.1 + */ + // To support a back door for DVR support. + public boolean getDvrResizeCompensationEnable() { + return doDvrResizeCompensation; + } + + /** + * Creates a default viewer object. The default values are used to create + * the PhysicalBody and PhysicalEnvironment. A single RGB, double buffered + * and depth buffered Canvas3D object is created. The View is created + * with a front clip distance of 0.1f and a back clip distance of 10.0f. + */ + public Viewer() { + // Call main constructor with default values. + this(null, null, null, true); + } + + /** + * Creates a default viewer object. The default values are used to create + * the PhysicalBody and PhysicalEnvironment. The View is created + * with a front clip distance of 0.1f and a back clip distance of 10.0f. + * + * @param userCanvas the Canvas3D object to be used for rendering; + * if this is null then a single RGB, double buffered and depth buffered + * Canvas3D object is created + * @since Java3D 1.1 + */ + public Viewer(Canvas3D userCanvas) { + // Call main constructor. + this(userCanvas == null ? null : new Canvas3D[] {userCanvas}, + null, null, true); + } + + + /** + * Creates a default viewer object. The default values are used to create + * the PhysicalBody and PhysicalEnvironment. The View is created + * with a front clip distance of 0.1f and a back clip distance of 10.0f. + * + * @param userCanvases the Canvas3D objects to be used for rendering; + * if this is null then a single RGB, double buffered and depth buffered + * Canvas3D object is created + * @since Java3D 1.3 + */ + public Viewer(Canvas3D[] userCanvases) { + this(userCanvases, null, null, true); + } + + /** + * Creates a viewer object. The Canvas3D objects, PhysicalEnvironment, and + * PhysicalBody are taken from the arguments. + * + * @param userCanvases the Canvas3D objects to be used for rendering; + * if this is null then a single RGB, double buffered and depth buffered + * Canvas3D object is created + * @param userBody the PhysicalBody to use for this Viewer; if it is + * null, a default PhysicalBody object is created + * @param userEnvironment the PhysicalEnvironment to use for this Viewer; + * if it is null, a default PhysicalEnvironment object is created + * @param setVisible determines if the Frames should be set to visible once created + * @since Java3D 1.3 + */ + public Viewer(Canvas3D[] userCanvases, PhysicalBody userBody, + PhysicalEnvironment userEnvironment, boolean setVisible ) { + + if (userBody == null) { + physicalBody = new PhysicalBody(); + } else { + physicalBody = userBody; + } + + if (userEnvironment == null) { + physicalEnvironment = new PhysicalEnvironment(); + } else { + physicalEnvironment = userEnvironment; + } + + // Create Canvas3D object if none was passed in. + if (userCanvases == null) { + GraphicsConfiguration config = + ConfiguredUniverse.getPreferredConfiguration(); + + canvases = new Canvas3D[1]; + canvases[0] = new Canvas3D(config); + try { + canvases[0].setFocusable( true ); + } catch(NoSuchMethodError e) {} + createFramesAndPanels(setVisible); + } + else { + canvases = new Canvas3D[userCanvases.length]; + for (int i=0; i= devices.length) + throw new ArrayIndexOutOfBoundsException( + cs[i].errorMessage(cs[i].creatingCommand, + "Screen " + cs[i].frameBufferNumber + " is invalid; " + + (devices.length-1) + " is the maximum local index.")); + + Rectangle bounds; + Container contentPane; + GraphicsConfiguration cfg = + devices[cs[i].frameBufferNumber].getBestConfiguration(tpl3D); + + if (cfg == null) + throw new RuntimeException( + "No GraphicsConfiguration on screen " + + cs[i].frameBufferNumber + " conforms to template"); + + // Workaround for Issue 316 - use the default config for the screen + GraphicsConfiguration defCfg = cfg.getDevice().getDefaultConfiguration(); + bounds = defCfg.getBounds(); + cs[i].j3dJFrame = j3dJFrames[i] = + new JFrame(cs[i].instanceName, defCfg); + + if (cs[i].noBorderFullScreen) { + try { + // Required by JDK 1.4 AWT for borderless full screen. + j3dJFrames[i].setUndecorated(true); + + cs[i].j3dWindow = j3dWindows[i] = j3dJFrames[i]; + contentPane = j3dJFrames[i].getContentPane(); + } + catch (NoSuchMethodError e) { + // Handle borderless full screen running under JDK 1.3.1. + JWindow jwin = new JWindow(j3dJFrames[i], cfg); + + cs[i].j3dWindow = j3dWindows[i] = jwin; + contentPane = jwin.getContentPane(); + } + + contentPane.setLayout(new BorderLayout()); + j3dWindows[i].setSize(bounds.width, bounds.height); + j3dWindows[i].setLocation(bounds.x, bounds.y); + } + else { + cs[i].j3dWindow = j3dWindows[i] = j3dJFrames[i]; + + contentPane = j3dJFrames[i].getContentPane(); + contentPane.setLayout(new BorderLayout()); + + if (cs[i].fullScreen) { + j3dWindows[i].setSize(bounds.width, bounds.height); + j3dWindows[i].setLocation(bounds.x, bounds.y); + } + else { + j3dWindows[i].setSize(cs[i].windowWidthInPixels, + cs[i].windowHeightInPixels); + j3dWindows[i].setLocation(bounds.x + cs[i].windowX, + bounds.y + cs[i].windowY) ; + } + } + + // Create a Canvas3D and set its attributes. + cs[i].j3dCanvas = canvases[i] = new Canvas3D(cfg); + canvases[i].setStereoEnable(cv.stereoEnable); + canvases[i].setMonoscopicViewPolicy(cs[i].monoscopicViewPolicy); + + // Get the Screen3D and set its attributes. + Screen3D screen = canvases[i].getScreen3D(); + + if (cs[i].physicalScreenWidth != 0.0) + screen.setPhysicalScreenWidth(cs[i].physicalScreenWidth); + + if (cs[i].physicalScreenHeight != 0.0) + screen.setPhysicalScreenHeight(cs[i].physicalScreenHeight); + + if (cs[i].trackerBaseToImagePlate != null) + screen.setTrackerBaseToImagePlate + (new Transform3D(cs[i].trackerBaseToImagePlate)); + + if (cs[i].headTrackerToLeftImagePlate != null) + screen.setHeadTrackerToLeftImagePlate + (new Transform3D(cs[i].headTrackerToLeftImagePlate)); + + if (cs[i].headTrackerToRightImagePlate != null) + screen.setHeadTrackerToRightImagePlate + (new Transform3D(cs[i].headTrackerToRightImagePlate)); + + // Put the Canvas3D into a JPanel. + cs[i].j3dJPanel = j3dJPanels[i] = new JPanel(); + j3dJPanels[i].setLayout(new BorderLayout()); + j3dJPanels[i].add("Center", canvases[i]); + + // Put the JPanel into the content pane used by JWindow or JFrame. + contentPane.add("Center", j3dJPanels[i]); + + // Attach the Canvas3D to the View. + view.addCanvas3D(canvases[i]); + + // Add a windowListener to detect the window close event. + addWindowCloseListener(j3dWindows[i]); + + // Set Canvas3D focus as required by the JDK 1.4 focus model for + // full screen frames. JDK 1.3.1 sets the focus automatically for + // full screen components. + try { + canvases[i].setFocusable(true) ; + } + catch (NoSuchMethodError e) { + } + + if (debug) { + System.out.println("Viewer: created Canvas3D for screen " + + cs[i].frameBufferNumber + " with size\n " + + j3dWindows[i].getSize()); + System.out.println("Screen3D[" + i + "]: size in pixels (" + + screen.getSize().width + " x " + + screen.getSize().height + ")"); + System.out.println(" physical size in meters: (" + + screen.getPhysicalScreenWidth() + " x " + + screen.getPhysicalScreenHeight() + ")"); + System.out.println(" hashCode = " + screen.hashCode() + "\n"); + } + } + + if (setVisible) + // Call setVisible() on all created Window components. + setVisible(true); + } + + // Create the JFrames and JPanels for application-supplied Canvas3D + // objects. + private void createFramesAndPanels( boolean setVisible ) { + j3dJFrames = new JFrame[canvases.length]; + j3dJPanels = new JPanel[canvases.length]; + j3dWindows = new Window[canvases.length]; + + for (int i = 0; i < canvases.length; i++) { + j3dWindows[i] = j3dJFrames[i] = new JFrame(); + j3dJFrames[i].getContentPane().setLayout(new BorderLayout()); + j3dJFrames[i].setSize(256, 256); + + // Put the Canvas3D into a JPanel. + j3dJPanels[i] = new JPanel(); + j3dJPanels[i].setLayout(new BorderLayout()); + j3dJPanels[i].add("Center", canvases[i]); + j3dJFrames[i].getContentPane().add("Center", j3dJPanels[i]); + if (setVisible) { + j3dJFrames[i].setVisible(true); + } + addWindowCloseListener(j3dJFrames[i]); + } + } + + /** + * Call setVisible() on all Window components created by this Viewer. + * + * @param visible boolean to be passed to the setVisible() calls on the + * Window components created by this Viewer + * @since Java3D 1.3 + */ + public void setVisible(boolean visible) { + for (int i = 0; i < j3dWindows.length; i++) { + j3dWindows[i].setVisible(visible); + } + } + + /** + * Returns the View object associated with the Viewer object. + * + * @return The View object of this Viewer. + */ + public View getView() { + return view; + } + + /** + * Set the ViewingPlatform object used by this Viewer. + * + * @param platform The ViewingPlatform object to set for this + * Viewer object. Use null to unset the current value and + * not assign assign a new ViewingPlatform object. + */ + public void setViewingPlatform(ViewingPlatform platform) { + if (viewingPlatform != null) { + viewingPlatform.removeViewer(this); + } + + viewingPlatform = platform; + + if (platform != null) { + view.attachViewPlatform(platform.getViewPlatform()); + platform.addViewer(this); + + if (avatar != null) + viewingPlatform.setAvatar(this, avatar); + } + else + view.attachViewPlatform(null); + } + /** + * Get the ViewingPlatform object used by this Viewer. + * + * @return The ViewingPlatform object used by this + * Viewer object. + */ + public ViewingPlatform getViewingPlatform() { + return viewingPlatform; + } + + /** + * Sets the geometry to be associated with the viewer's avatar. The + * avatar is the geometry used to represent the viewer in the virtual + * world. + * + * @param avatar The geometry to associate with this Viewer object. + * Passing in null will cause any geometry associated with the Viewer + * to be removed from the scen graph. + */ + public void setAvatar(ViewerAvatar avatar) { + // Just return if trying to set the same ViewerAvatar object. + if (this.avatar == avatar) + return; + + this.avatar = avatar; + if (viewingPlatform != null) + viewingPlatform.setAvatar(this, this.avatar); + } + + /** + * Gets the geometry associated with the viewer's avatar. The + * avatar is the geometry used to represent the viewer in the virtual + * world. + * + * @return The root of the scene graph that is used to represent the + * viewer's avatar. + */ + public ViewerAvatar getAvatar() { + return avatar; + } + + /** + * Returns the PhysicalBody object associated with the Viewer object. + * + * @return A reference to the PhysicalBody object. + */ + public PhysicalBody getPhysicalBody() { + return physicalBody; + } + + /** + * Returns the PhysicalEnvironment object associated with the Viewer + * object. + * + * @return A reference to the PhysicalEnvironment object. + */ + public PhysicalEnvironment getPhysicalEnvironment() { + return physicalEnvironment; + } + + /** + * Returns the 0th Canvas3D object associated with this Viewer object + * + * @return a reference to the 0th Canvas3D object associated with this + * Viewer object + * @since Java3D 1.3 + */ + public Canvas3D getCanvas3D() { + return canvases[0]; + } + + /** + * Returns the Canvas3D object at the specified index associated with + * this Viewer object. + * + * @param canvasNum the index of the Canvas3D object to retrieve; + * if there is no Canvas3D object for the given index, null is returned + * @return a reference to a Canvas3D object associated with this + * Viewer object + * @since Java3D 1.3 + */ + public Canvas3D getCanvas3D(int canvasNum) { + if (canvasNum > canvases.length) { + return null; + } + return canvases[canvasNum]; + } + + /** + * Returns all the Canvas3D objects associated with this Viewer object. + * + * @return an array of references to the Canvas3D objects associated with + * this Viewer object + * @since Java3D 1.3 + */ + public Canvas3D[] getCanvas3Ds() { + Canvas3D[] ret = new Canvas3D[canvases.length]; + for (int i = 0; i < canvases.length; i++) { + ret[i] = canvases[i]; + } + return ret; + } + + /** + * Returns the canvas associated with this Viewer object. + * @deprecated superceded by getCanvas3D() + */ + public Canvas3D getCanvases() { + return getCanvas3D(); + } + + /** + * This method is no longer supported since Java 3D 1.3. + * @exception UnsupportedOperationException if called. + * @deprecated AWT Frame components are no longer created by the + * Viewer class. + */ + public Frame getFrame() { + throw new UnsupportedOperationException( + "AWT Frame components are not created by the Viewer class"); + } + + /** + * Returns the JFrame object created by this Viewer object at the + * specified index. If a Viewer is constructed without any Canvas3D + * objects then the Viewer object will create a Canva3D object, a JPanel + * containing the Canvas3D object, and a JFrame to place the JPanel in. + *

+ * NOTE: When running under JDK 1.4 or newer, the JFrame always directly + * contains the JPanel which contains the Canvas3D. When running under + * JDK 1.3.1 and creating a borderless full screen through a configuration + * file, the JFrame will instead contain a JWindow which will contain the + * JPanel and Canvas3D. + *

+ * @param frameNum the index of the JFrame object to retrieve; + * if there is no JFrame object for the given index, null is returned + * @return a reference to JFrame object created by this Viewer object + * @since Java3D 1.3 + */ + public JFrame getJFrame(int frameNum) { + if (j3dJFrames == null || frameNum > j3dJFrames.length) { + return(null); + } + return j3dJFrames[frameNum]; + } + + /** + * Returns all the JFrames created by this Viewer object. If a Viewer is + * constructed without any Canvas3D objects then the Viewer object will + * create a Canva3D object, a JPanel containing the Canvas3D object, and a + * JFrame to place the JPanel in.

+ * + * NOTE: When running under JDK 1.4 or newer, the JFrame always directly + * contains the JPanel which contains the Canvas3D. When running under + * JDK 1.3.1 and creating a borderless full screen through a configuration + * file, the JFrame will instead contain a JWindow which will contain the + * JPanel and Canvas3D.

+ * + * @return an array of references to the JFrame objects created by + * this Viewer object, or null if no JFrame objects were created + * @since Java3D 1.3 + */ + public JFrame[] getJFrames() { + if (j3dJFrames == null) + return null; + + JFrame[] ret = new JFrame[j3dJFrames.length]; + for (int i = 0; i < j3dJFrames.length; i++) { + ret[i] = j3dJFrames[i]; + } + return ret; + } + + /** + * This method is no longer supported since Java 3D 1.3. + * @exception UnsupportedOperationException if called. + * @deprecated AWT Panel components are no longer created by the + * Viewer class. + */ + public Panel getPanel() { + throw new UnsupportedOperationException( + "AWT Panel components are not created by the Viewer class"); + } + + /** + * Returns the JPanel object created by this Viewer object at the + * specified index. If a Viewer is constructed without any Canvas3D + * objects then the Viewer object will create a Canva3D object and a + * JPanel into which to place the Canvas3D object. + * + * @param panelNum the index of the JPanel object to retrieve; + * if there is no JPanel object for the given index, null is returned + * @return a reference to a JPanel object created by this Viewer object + * @since Java3D 1.3 + */ + public JPanel getJPanel(int panelNum) { + if (j3dJPanels == null || panelNum > j3dJPanels.length) { + return(null); + } + return j3dJPanels[panelNum]; + } + + /** + * Returns all the JPanel objects created by this Viewer object. If a + * Viewer is constructed without any Canvas3D objects then the Viewer + * object will create a Canva3D object and a JPanel into which to place + * the Canvas3D object. + * + * @return an array of references to the JPanel objects created by + * this Viewer object, or null or no JPanel objects were created + * @since Java3D 1.3 + */ + public JPanel[] getJPanels() { + if (j3dJPanels == null) + return null; + + JPanel[] ret = new JPanel[j3dJPanels.length]; + for (int i = 0; i < j3dJPanels.length; i++) { + ret[i] = j3dJPanels[i]; + } + return ret; + } + + /** + * Used to create and initialize a default AudioDevice3D used for sound + * rendering. + * + * @return reference to created AudioDevice, or null if error occurs. + */ + public AudioDevice createAudioDevice() { + if (physicalEnvironment == null) { + System.err.println("Java 3D: createAudioDevice: physicalEnvironment is null"); + return null; + } + + try { + String audioDeviceClassName = + (String) java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + return System.getProperty("j3d.audiodevice"); + } + }); + + if (audioDeviceClassName == null) { + throw new UnsupportedOperationException("No AudioDevice specified"); + } + + // Issue 341: try the current class loader first before trying the + // system class loader + Class audioDeviceClass = null; + try { + audioDeviceClass = Class.forName(audioDeviceClassName); + } catch (ClassNotFoundException ex) { + // Ignore excpetion and try system class loader + } + + if (audioDeviceClass == null) { + ClassLoader audioDeviceClassLoader = + (ClassLoader) java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + return ClassLoader.getSystemClassLoader(); + } + }); + + if (audioDeviceClassLoader == null) { + throw new IllegalStateException("System ClassLoader is null"); + } + + audioDeviceClass = Class.forName(audioDeviceClassName, true, audioDeviceClassLoader); + } + + Class physEnvClass = PhysicalEnvironment.class; + Constructor audioDeviceConstructor = + audioDeviceClass.getConstructor(new Class[] {physEnvClass}); + PhysicalEnvironment[] args = new PhysicalEnvironment[] { physicalEnvironment }; + AudioEngine3DL2 mixer = + (AudioEngine3DL2) audioDeviceConstructor.newInstance((Object[])args); + mixer.initialize(); + return mixer; + } + catch (Throwable e) { + e.printStackTrace(); + physicalEnvironment.setAudioDevice(null); + System.err.println("Java 3D: audio is disabled"); + return null; + } + } + + /** + * Returns the Universe to which this Viewer is attached + * + * @return the Universe to which this Viewer is attached + * @since Java 3D 1.3 + */ + public SimpleUniverse getUniverse() { + return getViewingPlatform().getUniverse(); + } + + + /* + * Exit if run as an application + */ + void addWindowCloseListener(Window win) { + SecurityManager sm = System.getSecurityManager(); + boolean doExit = true; + + if (sm != null) { + try { + sm.checkExit(0); + } catch (SecurityException e) { + doExit = false; + } + } + final boolean _doExit = doExit; + + win.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent winEvent) { + Window w = winEvent.getWindow(); + w.setVisible(false); + try { + w.dispose(); + } catch (IllegalStateException e) {} + if (_doExit) { + System.exit(0); + } + } + }); + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewerAvatar.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewerAvatar.java new file mode 100644 index 0000000..7682524 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewerAvatar.java @@ -0,0 +1,66 @@ +/* + * $RCSfile: ViewerAvatar.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:45 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * This class holds geomtry that should be associated with the View's + * avatar. An avatar is how the user's "virtual self" appears in the + * virtual world. + * + * @see Viewer + */ +public class ViewerAvatar extends BranchGroup { + + /** + * Constructs an instance of the ViewerAvatar node. + */ + public ViewerAvatar() { + setCapability(ALLOW_DETACH); + } + +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewingPlatform.java b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewingPlatform.java new file mode 100644 index 0000000..7a9d6b5 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/ViewingPlatform.java @@ -0,0 +1,519 @@ +/* + * $RCSfile: ViewingPlatform.java,v $ + * + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * $Revision: 1.4 $ + * $Date: 2007/02/09 17:20:45 $ + * $State: Exp $ + */ + +package com.sun.j3d.utils.universe; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; +import java.awt.Component; +import javax.media.j3d.*; +import javax.vecmath.*; +import com.sun.j3d.utils.behaviors.vp.*; +import com.sun.j3d.internal.J3dUtilsI18N; + +/** + * This class is used to set up the "view" side of a Java 3D scene graph. + * The ViewingPlatform object contains a MultiTransformGroup node to allow + * for a series of transforms to be linked together. To this structure + * the ViewPlatform is added as well as any geometry to associate with this + * view platform. + * + * @see ViewPlatform + */ +public class ViewingPlatform extends BranchGroup { + + /** + * Cached ViewPlatform associated with this ViewingPlatform object. + */ + protected ViewPlatform viewPlatform; + + /** + * MultiTransformGroup that holds all TransformGroups between + * the BranchGroup and the View object. + */ + protected MultiTransformGroup mtg; + + /** + * Used to keep track of added geometry. When geometry + * is added to the view platform, an addChild to this BranchGroup + * is performed. + */ + protected BranchGroup platformGeometryRoot; + + /** + * Used to keep track of added geometry. When geometry + * is added for an avatar, an addChild to this BranchGroup + * is performed. + */ + protected BranchGroup avatarRoot; + + /** + * Cached PlatformGeometry object. + */ + protected PlatformGeometry platformGeometry = null; + + /** + * Table of the Viewer objects. + */ + protected Hashtable viewerList; + + /** + * Used to keep track of behaviors. + * + * @since Java 3D 1.2.1 + */ + protected BranchGroup behaviors; + + /** + * The universe to which this viewing platform is attached + * + * @since Java 3D 1.3 + */ + protected SimpleUniverse universe; + + /** + * Creates a default ViewingPlatform object. This consists of a + * MultiTransfromGroup node with one transform and a ViewPlatform + * object. The ViewPlatform is positioned at (0.0, 0.0, 0.0). + */ + public ViewingPlatform() { + // Call main constructor with default values. + this(1); + } + + /** + * Creates the ViewingPlatform object. This consists of a + * MultiTransfromGroup node with the specified number of transforms + * (all initialized to the identity transform). + * and a ViewPlatform object. + * + * @param numTransforms The number of transforms the MultiTransformGroup + * node should contain. If this number is less than 1, 1 is assumed. + */ + public ViewingPlatform(int numTransforms) { + viewerList = new Hashtable(); + + // Set default capabilities for this node. + setCapability(Group.ALLOW_CHILDREN_WRITE); + setCapability(Group.ALLOW_CHILDREN_EXTEND); + setCapability(BranchGroup.ALLOW_DETACH); + + // Create MultiTransformGroup node. + if (numTransforms < 1) + numTransforms = 1; + mtg = new MultiTransformGroup(numTransforms); + + // Get first transform and add it to the scene graph. + TransformGroup tg = mtg.getTransformGroup(0); + addChild(tg); + + // Create ViewPlatform and add it to the last transform in the + // MultiTransformGroup node. + tg = mtg.getTransformGroup(numTransforms - 1); + viewPlatform = new ViewPlatform(); + viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_READ); + viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_WRITE); + tg.addChild(viewPlatform); + + // Set capabilities to allow for changes when live. + tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); + tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + + // Initialize the avatarRoot BranchGroup node and add it to the + // last transform in the MultiTransformGroup node. + avatarRoot = new BranchGroup(); + avatarRoot.setCapability(Group.ALLOW_CHILDREN_READ); + avatarRoot.setCapability(Group.ALLOW_CHILDREN_WRITE); + avatarRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND); + tg.addChild(avatarRoot); + + // Initialize the platformGeometry BranchGroup node and add it to the + // last transform in the MultiTransformGroup node. + platformGeometryRoot = new BranchGroup(); + platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_READ); + platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_WRITE); + platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND); + tg.addChild(platformGeometryRoot); + } + + /** + * Sets the ViewPlatform node for this ViewingPlatform object. + * + * @param vp The ViewPlatform node to associate with this ViewingPlatform + * object. + */ + public void setViewPlatform(ViewPlatform vp) { + TransformGroup tg = getViewPlatformTransform(); + tg.removeChild(viewPlatform); + tg.addChild(vp); + viewPlatform = vp; + // Assign this to all Viewers. + Enumeration e = viewerList.keys(); + + while (e.hasMoreElements()) + ((Viewer)e.nextElement()).setViewingPlatform(this); + } + + /** + * Returns the ViewPlatform node for this ViewingPlatform object. + * + * @return The ViewPlatform node associated with this ViewingPlatform + * object. + */ + public ViewPlatform getViewPlatform() { + return viewPlatform; + } + + /** + * Assigns the geometry to associate with the ViewingPlatform. + * PlatformGeometry is used to hold any geometry to be associated + * with the ViewingPlatform. If the ViewingPlatform is to be the + * inside of a car, for instance, than the PlatformGeometry could be + * the dashboard of the car. + * + * @param pg The geometry to be associated with this ViewingPlatform. + * Passing in null has the effect of deleting any geometry associated + * with this ViewingPlatform. + */ + public void setPlatformGeometry(PlatformGeometry pg) { + // Just return if trying to set the same PlatformGeometry object. + if (platformGeometry == pg) + return; + + // If the PlatformGeometry is null, will be removing any geometry + // already present. + if (pg == null) { + if (platformGeometryRoot.numChildren() != 0) + platformGeometryRoot.removeChild(0); + } + else { + + // See if there is an old PlatformGeometry to replace. + if (platformGeometryRoot.numChildren() != 0) + platformGeometryRoot.setChild(pg, 0); + else { + platformGeometryRoot.addChild(pg); + } + } + platformGeometry = pg; + } + + /** + * Returns the PlatformGeometry associated with this ViewingPlatform + * + * @return The PlatformGeometry associated with this ViewingPlatform + */ + public PlatformGeometry getPlatformGeometry() { + return platformGeometry; + } + + /** + * Returns the MultitransformGroup object for this + * ViewingPlatform object. + * + * @return The MultitransformGroup object. + */ + public MultiTransformGroup getMultiTransformGroup() { + return mtg; + } + + /** + * Returns a reference to the "bottom most" transform in the + * MultiTransformGroup that is above the ViewPlatform node. + * + * @return The TransformGroup that is immediately above the + * ViewPlatform object. + */ + public TransformGroup getViewPlatformTransform() { + return mtg.getTransformGroup(mtg.getNumTransforms() - 1); + } + + /** + * Sets the nominal viewing distance in the ViewPlatform transform based + * on the current field of view. If the ViewAttachPolicy is not the + * default of View.NOMINAL_HEAD, then this method has no effect.

+ * + * The ViewPlatform is moved back along Z so that objects at the origin + * spanning the normalized X range of -1.0 to +1.0 can be fully viewed + * across the width of the window. This is done by setting a translation + * of 1/(tan(fieldOfView/2)) in the ViewPlatform transform.

+ * + * If there is no Viewer object associated with this ViewingPlatform + * object the default field of view of PI/4.0 is used.

+ * + * NOTE: Support for multiple Viewer objects is not available. If + * multiple viewers are attached to this ViewingPlatform than a + * RuntimeException will be thrown. + */ + public void setNominalViewingTransform() { + if (viewPlatform.getViewAttachPolicy() == View.NOMINAL_HEAD) { + double fieldOfView; + + if (viewerList.size() == 0) { + // No Viewer associated with this ViewingPlatform, so use the + // default field of view value to move the ViewingPlatform. + fieldOfView = Math.PI/4.0; + } + else { + if (viewerList.size() > 1) { + throw new RuntimeException + (J3dUtilsI18N.getString("ViewingPlatform0")); + } + + Viewer viewer = (Viewer)viewerList.keys().nextElement(); + View view = viewer.getView(); + fieldOfView = view.getFieldOfView(); + } + + Transform3D t3d = new Transform3D(); + double viewDistance = 1.0/Math.tan(fieldOfView/2.0); + t3d.set(new Vector3d(0.0, 0.0, viewDistance)); + getViewPlatformTransform().setTransform(t3d); + } + } + + /** + * Returns the avatarRoot child number of the ViewerAvatar object. + * All the children of the avatarRoot are compared with the passed + * in ViewerAvatar. If a match is found, the index is returned. + * + * @param avatar The ViewerAvatar object to look for in the avatarRoot's + * child nodes. + * @return The index of the child that corresponds to the ViewerAvatar. + * If the avatarRoot does not contain the ViewerAvatar -1 is returned. + */ + private int findAvatarChild(ViewerAvatar avatar) { + // Search the avatarRoot for the ViewerAvatar associated with + // with the Viewer object + for (int i = 0; i < avatarRoot.numChildren(); i++) { + if (((ViewerAvatar)avatarRoot.getChild(i)) == avatar) + return i; + } + + // Should never get here. + System.err.println("ViewingPlatform.findAvatarChild:Child not found."); + return -1; + } + + /** + * Adds the ViewerAvatar to the scene graph. An avatar (geometry) + * can be associated with a Viewer object and displayed by Java 3D. + * + * @param viewer The viewer object to associate with this avatar. + * @param avatar The avatar to add to the scene graph. Passing in + * null removes any currently assigned avatar. + */ + void setAvatar(Viewer viewer, ViewerAvatar avatar) { + Object oldAvatar = viewerList.get(viewer); + + // A position of -1 means the avatar is not a child of the avatarRoot. + int avatarPosition = -1; + + // Because "null" cannot be used in a put the avatarRoot object + // is used to signify that there is no ViewerAvatar associated + // with this Viewer. + if (oldAvatar != avatarRoot) + avatarPosition = findAvatarChild((ViewerAvatar)oldAvatar); + + // If the avatar is null, will be removing any geometry already present. + if (avatar == null) { + if (avatarPosition != -1) { + avatarRoot.removeChild(avatarPosition); + + // Reset hashtable entry - avatarRoot == null. + viewerList.put(viewer, avatarRoot); + } + } + else { + // see if there is an old ViewerAvater to replace + if (avatarPosition != -1) + avatarRoot.setChild(avatar, avatarPosition); + else + avatarRoot.addChild(avatar); + + // Update hashtable with new avatar. + viewerList.put(viewer, avatar); + } + } + + /** + * When a ViewingPlatform is set by a Viewer, the ViewingPlatform + * needs to be informed, via a call to this method. This will add + * the Viewer to the ViewingPlatform's viewerList for use when + * things such as the PlatformGeometry are changed and all Viewer + * scene graphs need to be modified. + */ + void addViewer(Viewer viewer) { + // Because the viewerList is also used to associate ViewerAvatars + // with Viewer objects a hashtable is used. This routine does not + // check for the presence of a ViewerAvatar but the Viewer still + // needs to be added to the hashtable. Because "null" cannot be + // used in a put the avatarRoot object is used to signify that there + // is no ViewerAvatar associated with this Viewer. + viewerList.put(viewer, avatarRoot); + } + + /* + * Cleanup when Viewer set another ViewingPlatform + */ + void removeViewer(Viewer viewer) { + viewerList.remove(viewer); + } + + /** + * Adds a new ViewPlatformBehavior to the ViewingPlatform + */ + void addViewPlatformBehavior(ViewPlatformBehavior behavior) { + behavior.setViewingPlatform(this); + if (behaviors == null) { + behaviors = new BranchGroup(); + behaviors.setCapability(BranchGroup.ALLOW_DETACH); + behaviors.setCapability(BranchGroup.ALLOW_CHILDREN_READ); + } + // otherwise detach the BranchGroup so we can add to it + else { + behaviors.detach(); + } + behaviors.addChild(behavior); + this.addChild(behaviors); + } + + /** + * Sets the ViewPlatformBehavior which will operate on the ViewPlatform + * transform (the TransformGroup returned by + * ViewingPlatform.getViewPlatformTransform()). The ViewPlatformBehavior + * may be set after the ViewingPlatform is setLive(). + * If a behavior is already present, it will be detached and it's + * setViewingPlatform method will be called with a parameter of null. + * @param behavior The ViewPlatformBehavior to add to the ViewingPlatform. + * null will remove the ViewingPlatform behavior. + * @since Java 3D 1.2.1 + */ + public void setViewPlatformBehavior(ViewPlatformBehavior behavior) { + if (behaviors != null) { + removeViewPlatformBehavior((ViewPlatformBehavior)behaviors.getChild(0)); + } + if (behavior != null) { + addViewPlatformBehavior(behavior); + } + } + + /** + * Removes the specified ViewPlatformBehavior + */ + void removeViewPlatformBehavior(ViewPlatformBehavior behavior) { + // remove from the behaviors branch group + if (behaviors != null) { + behaviors.detach(); + for (int i = 0; i < behaviors.numChildren(); i++) { + if (behaviors.getChild(i) == behavior) { + behavior.setViewingPlatform( null ); + behaviors.removeChild(i); + break; + } + } + if (behaviors.numChildren() == 0) behaviors = null; + else this.addChild(behaviors); + } + } + + /** + * Returns the number of ViewPlatformBehaviors on the ViewingPlatform + */ + int getViewPlatformBehaviorCount() { + return behaviors.numChildren(); + } + + /** + * Returns the ViewPlatformBehavior at the specified index + */ + ViewPlatformBehavior getViewPlatformBehavior(int index) { + return (ViewPlatformBehavior)behaviors.getChild(index); + } + + /** + * Returns the ViewPlatformBehavior + * @return the ViewPlatformBehavior for the ViewingPlatform. + * Returns null if there is no ViewPlatformBehavior set. + * @since Java 3D 1.2.1 + */ + public ViewPlatformBehavior getViewPlatformBehavior() { + if (behaviors == null) { + return null; + } + return getViewPlatformBehavior(0); + } + + /** + * Returns the Viewers attached to this ViewingPlatform + * + * @return the Viewers attached to this viewing platform + * @since Java 3D 1.3 + */ + public Viewer[] getViewers() { + if (viewerList.size() == 0) return null; + return (Viewer[])viewerList.keySet().toArray( new Viewer[0] ); + } + + /** + * Returns the Universe to which this ViewingPlatform is attached + * + * @return the Universe to which this ViewingPlatform is attached + * @since Java 3D 1.3 + */ + public SimpleUniverse getUniverse() { + return universe; + } + + /** + * Sets the Universe to which this ViewingPlatform is attached + * + * @param universe the Universe to which this ViewingPlatform is attached + * @since Java 3D 1.3 + */ + public void setUniverse( SimpleUniverse universe ) { + this.universe = universe; + } +} diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-examples.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-examples.html new file mode 100644 index 0000000..a9fe311 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-examples.html @@ -0,0 +1,85 @@ + + + + + + + + + + +  +

+Example Configuration Files

+ +


j3d1x1  A single fullscreen +desktop configuration. +

j3d1x1-behavior  A single +fullscreen desktop configuration with a configurable view platform behavior. +

j3d1x1-stereo  A single +fullscreen desktop configuration with stereo viewing. +

j3d1x1-vr  A single fullscreen +desktop configuration with head tracker, stereo viewing, and 6 degree of +freedom mouse. +

j3d1x1-window  A single screen +desktop configuration with a conventional window. +

j3d1x2-flat  A dual-screen planar +desktop configuration. +

j3d1x2-rot30  A dual-screen +desktop configuration with each screen rotated toward the other by 30 degrees. +

j3d1x3-cave  A three-projector cave +configuration. +

j3d1x3-cave-vr  A +three-projector cave configuration with head tracking and stereo viewing. +

j3d1x3-rot45  A three-screen +desktop configuration with left and right screens rotated 45 degrees from the +center screen. +

j3d2x2-flat  A four-projector +configuration arranged in a 2x2 array. +
  + + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-syntax.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-syntax.html new file mode 100644 index 0000000..87f1711 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-syntax.html @@ -0,0 +1,1973 @@ + + + + + + + The Java 3D Configuration File + + + + + + + + + + +
+The Java 3D Configuration File
+
+ +Syntax Description
+Command Overview
+ + Overview of Relevant View Model Parameters
+Top-Level Command Details
+Built-In Command Details
+Command Index
+Property Index
+ +

+This document is an informal description of the syntax of the Java 3D +configuration file and a tutorial of the semantics of its various commands. +Such a file is written by a user or site administrator to describe the physical +configuration of a local interactive viewing environment. Configuration +properties that can be described in the file include the sizes, positions, and +orientations of displays in either fixed screen environments or head mounted +displays (HMD devices), as well as the input devices and sensors +available for user interaction apart from the keyboard and mouse abstractions +provided by the AWT.

+

+A configuration file is used by passing its URL to either a ConfigContainer or +a ConfiguredUniverse constructor. The method by which a user specifies the +file is up to the application, but the universe utilities do provide a few +means to easily enable an application to perform this task. These depend upon +a Java 3D property, j3d.configURL, that the user can set on the java +command line with the -D option. Its value should be a URL string +indicating the location of the desired file. The application can then either +call the static ConfigContainer methods +getConfigURL +to retrieve the value of the property, or + +getConfigURL(String) to specify a default file to be used in case the +property is not set. Applications are encouraged to devise their own +user-friendly mechanisms to retrieve the configuration file, although the +setting of the j3d.configURL property should be honored if at all +possible.

+

+If the attempt to open the resource indicated by the URL is successful, then a +parser will be invoked to read and evaluate the commands it contains and +deposit the results in the ConfigContainer. The parser will detect syntax +errors, invalid commands, and bad references, printing descriptive messages to +System.out, including the line number and text of the offending command. In +general the parser attempts to continue processing as much of the file as it +can when encountering an error. Some errors can only be detected after the +entire file has been evaluated; in those cases an exception will be thrown.

+

+An application may choose to override the settings of the configuration file by +accessing view-side scenegraph components directly from the ConfigContainer +once the file is evaluated. Applications should avoid this in general, as most +settings are physical calibration constants specific to the local interactive +viewing environment. Nonetheless, application overrides are still sometimes +appropriate; for example, the application may have knowledge of the contents of +the scenegraph that enables it to make a better judgement of where the view's +clipping planes should be.

+
+ + + + + + +
+Syntax Description
+

+The configuration file syntax is very simple; scanning any of the +sample configuration files should provide +the general idea. At the broadest level there are two main types of +constructs: comments and commands.

+

+Comments can be either C or C++ style. In a C-style +comment all text between successive occurances of /* and */ is ignored. +A C++ comment begins with // and continues to the end of the line.

+

+A command begins with an opening parenthesis and ends with a closing +parenthesis. The elements between the parentheses can be of four types: +alphanumeric strings, numbers, quoted strings, or other commands. During the +evaluation of a command, any nested command encountered is itself evaluated, +and the result of that evaluation replaces the nested command within the +original outer command.

+

+Strings that contain embedded white space, forward slashes, or invalid +tokens must be enclosed in quotes (either single or double). Common cases are +URL strings and Unix path names. Numbers are any non-quoted strings that can +be parsed as double-precision floating point numbers. The strings true, +True, false, and False are converted to their corresponding boolean +values. Strings, quoted strings, and numbers are delimited from each other by +white space.

+

+Commands in the configuration file have four special forms: point, +matrix, top-level, and built-in commands.

+ +
+

+Points

+ +A command that consists entirely of two, three, or four numbers is a 2D point, +a 3D point, or a 4D point respectively. Any other command that starts with a +number is a syntax error. +

+Don't pass 2D, 3D, or 4D points to commands that expect two, three, or four +numbers instead. This will generate a syntax error indicating an invalid +number of arguments.

+ +

+Matrices

+ +A 3D matrix is a command that consists entirely of three 3D points. A 4D +matrix consists entirely of either three or four 4D points; if there are only +three 4D points then the fourth is implicitly considered to be (0.0 0.0 0.0 +1.0). The points define the row elements of each type of matrix. Any other +command that starts with a point is a syntax error. + +

+Top-level and built-in commands

+ +All other commands start with an alphanumeric string, the command name +which identifies it. The remaining elements of the command are its arguments. +

+Command names can either specify top-level or built-in commands. Top-level +commands generally configure Java 3D core and utility classes and can only +appear at the outermost level of parentheses. Built-in commands are provided +by the parser itself to help construct the arguments to top-level commands. +Points, matrices, and built-in commands can only be nested within other +commands.

+

+An error will result if points, matrices, or built-in commands are invoked at +the outermost level of nesting. Sometimes this error is caused by prematurely +closing the opening parenthesis of the current top-level command. Such an +error is usually preceded by an error from the command indicating an invalid +number of arguments.

+

+Similarly, errors will be generated if top-level commands are nested. Errors +to this effect are sometimes caused by failing to close all the open +parentheses of the preceding top-level command.

+
+ +

+Java property substitution syntax

+ +All strings are additionally scanned for text enclosed by a starting ${ and a +matching }. Such text is looked up as a Java system property name and the +result is substituted back into the string after eliding the starting and +ending delimiters. For example, the command: +

+(Include "file:${user.home}/myBody.cfg")

+

+would evaluate the contents of the file "myBody.cfg" in the user's home +directory on Unix systems. An error is issued if no Java property exists with +the specified name.

+

+Java property substitution happens early, after tokenization but before command +evaluation. Substitution can occur any number of times anywhere within any +quoted or non-quoted string, including command names, property names, and +property values, as long as the property substitution syntax is not nested.

+
+ + + + + + +
+Command Overview
+

+Most top-level commands configure concrete Java 3D core and utility classes. +These include PhysicalBody, PhysicalEnvironment, Screen, Sensor, View, and +ViewPlatform. The Screen, View, and ViewPlatform commands also implicitly +configure the Canvas3D core class and the Viewer and ViewingPlatform utility +classes respectively.

+

+These commands come in two forms: the New<class name> and +<class name>Property commands. All New commands except +NewSensor create new class instances and bind names to +them, while the Property commands refer to these names and configure +their corresponding class instances with the parameters specified by the +command arguments. All references must be to objects previously instantiated +in the file; forward referencing is not supported. Names must be unique within +each class.

+

+Implementations of the Java 3D InputDevice interface and concrete subclasses of +the abstract ViewPlatformBehavior utility class can also be instantiated and +configured with the same command forms. The New commands for these +objects accept class names as command arguments and instantiate the objects +through introspection. Since the details of the implementations are not known, +configuration parameters are passed through methods which are invoked through +introspection of the method names specified in the Property command +arguments.

+

+A method invoked through introspection with a Property command gets its +arguments as a single array of Objects. Boolean strings get wrapped into +Boolean objects, and number strings get wrapped into Double. 2D, 3D, and 4D +points get wrapped into Point2d, Point3d, and Point4d objects respectively, +while 3D and 4D matrices get wrapped into Matrix3d and Matrix4d +respectively.

+
+ + + + + + +
+Overview of Relevant View Model Parameters
+

+The sample configuration files are annotated to assist users in modifying them +to suit their particular viewing environments, but it can be helpful to know +some of the basics of the Java 3D view model that are relevant to writing a +configuration file. This overview should only be considered an informal +adjunct to the detailed description in the Java 3D Specification. Reading the +source code to the ViewInfo utility (a public +implementation of the Java 3D view model) may also be helpful in understanding +the details of the view model.

+ + + + + +
+The Camera View Model
+

+In the traditional camera model the camera or eyepoint is positioned and +oriented with respect to the virtual world via a view transform. Objects +contained within the field of view are projected onto an image plane, which is +then mapped onto a display surface, usually a window on a desktop display +system. While the view direction and camera position can be freely oriented +and placed anywhere in the virtual world, the projection is accomplished using +a static frustum defined by the field of view and a flat image plane centered +about and normal to the view direction.

+

+This model emulates a typical physical camera quite well, but there are many +viewing configurations that cannot be implemented using image planes that are +fixed with respect to the view direction. In a multiple screen environment the +projection frustum for each screen is skewed with respect to the image plane, +based on the user's nominal viewing position. Realistic stereo views on fixed +displays use skewed projection frustums derived from the offsets of the two +eyes from the center of the image plane, while head tracking with fixed +displays involves dynamically adjusting projection frustums in response to +varying eye positions relative to the image plane.

+

+In a low-level API such as OpenGL these situations are handled by concatenating +all defined model and viewing transforms into a single modelview matrix, +and for a fixed-screen environment explicitly computing the projection +matrix for each eye, each display surface, and each new head +position. Every application handling such viewing configurations typically +reimplements the framework for computing those matrices itself. In these cases +it would be useful to be able to separate the projection components out of the +view transform in some representation based on display and eye locations.

+ + + + + +
+The Java 3D View Model
+

+Based on these requirements, a high-level view model should provide standard +mechanisms to 1) define a screen's position and orientation in relation to +other screens in the viewing environment; 2) specify the position of the user's +eyes or an HMD relative to the physical space in which the screens or nominal +user position are defined, and to have them updated automatically if tracking +hardware exists; and 3) describe where the whole physical space is placed and +oriented in the virtual world. In such a model the appropriate images could +then be rendered without further computation in application code.

+

+In the Java 3D view model, screen (image plate) positions and +orientations are defined relative to a fixed frame of reference in the physical +world, the tracker base, through the +TrackerBaseToImagePlate property. The +tracker base is somewhat abstract in that it is always used to define that +fixed frame of reference, even if no physical tracking hardware is being +used. If the ViewPolicy is HMD_VIEW, then the left +and right image plates for head mounted displays are defined relative to the +head tracking sensor, which reports head orientation and position relative to +the tracker base.

+

+Coexistence coordinates are defined with the +CoexistenceToTrackerBase property. It +provides a frame of reference in the physical world which can be set up by the +user or application in whatever way is most convenient for positioning and +orienting screens, physical body attributes, and sensing devices in the virtual +world. If tracking is enabled, then the eye positions in coexistence are +computed from the position and orientation of the head tracking sensor and the +HeadToHeadTracker matrix; otherwise the eye +positions in coexistence are set according to the +CenterEyeInCoexistence property. In HMD +mode the eye positions are fixed with respect to the image plates.

+

+The mapping of coexistence coordinates into the virtual world is accomplished +through the ViewAttachPolicy, which specifies +the point in coexistence coordinates to which the origin of the view +platform should be mapped. The view platform is positioned in the virtual +world by manipulating its view transform, the composite of all the +transforms from the view platform up to its Locale. The basis vectors (X, Y, +and Z directions) of the view platform are always aligned with coexistence +coordinates, and the scaling between view platform coordinates and physical +coordinates is specified by the +ScreenScalePolicy, so this +establishes the complete mapping of the physical world into the virtual world. +The projection of the virtual world onto the physical display surfaces is then +performed automatically by the Java 3D renderer.

+

+By default Java 3D tries to emulate the familiar camera model as much as +possible to make it easy to run in a conventional windowed desktop display +environment. It accomplishes this through the following default settings:

+ + +When a configuration file is being used the defaults are oriented towards +making the setup of multiple screen environments as easy as possible. If the +coexistence centering enable has not been explicitly set, and either the +CoexistenceToTrackerBase transform for the view has been set or +TrackerBaseToImagePlate has been set for any screen, then the following +defaults are used instead:

+ + +The avove defaults are also used if coexistence centering enable has been +explictly set false. +


+ + + + + + +
+Top-Level Command Details
+

+Top-level commands can only appear at the outermost command nesting level.

+
+ +

+NewDevice

+Syntax: +
(NewDevice <instance name> <class name> +[Alias <alias name>]) +

+This command instantiates the InputDevice implementation specified by the fully +qualified class name and binds it to instance name. The +InputDevice is instantiated through introspection of the class name. The +implementation must provide a parameterless constructor; this can usually be +done by extending or wrapping available InputDevice implementations.

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+

+At the conclusion of configuration file processing all InputDevice +implementations so defined will be initialized and registered with any +PhysicalEnvironments that reference them.

+


+ +

+DeviceProperty

+Syntax: +
(DeviceProperty <instance name> <method name> <arg0> +... <argn>) +

+The details of the InputDevice implementation specified by instance name +are not known to ConfigContainer, so any parameters to be set through the +configuration file are passed to the InputDevice instance by invoking method +name through introspection. The arguments following the method name are +evaluated and the results passed to the method as an array of Objects.

+

+The required methods can usually be provided by extending or wrapping existing +InputDevice implementations.

+
+ +

+NewSensor

+Syntax: +
(NewSensor <instance name> <device name> +<sensor index> [Alias <alias name>]) +

+Retrieves the Sensor at index sensor index in the InputDevice device +name and binds it to the name specified by instance name. The +sensor index is a number truncated to its integer value. The InputDevice +implementation is responsible for creating its own Sensor objects, so this +command does not create any new instances.

+

+Instance name is used by other commands to reference the indicated +Sensor. In addition, the name and its associated Sensor instance is made +available to applications through a Map returned by the ConfigContainer +method +getNamedSensors. +

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+

+If the Sensor is to be used for head tracking, or tracking the position and +orientation of other objects in the physical world, then it must generate 6 +degree of freedom data relative to the tracker base.

+
+ +

+SensorProperty

+Syntax: +
(SensorProperty <instance name> <property name> +<property value>) +

+Sets a Sensor property. The sensor instance is specified by instance +name, the property to be set by property name, and the value to be +set by property value. The following sole property may be +configured:

+ +
+

+Hotspot

+A 3D point in the sensor's local coordinate system. The hotspot specifies the +"active" point which should interact with the virtual world, such as a point +used for picking or grabbing an object. Its actual interpretation is up to the +sensor behavior which uses it. Its value is ignored for head tracking sensors. +
+
+ +

+NewScreen
+NewWindow

+Syntax: +
(NewScreen <instance name> <device index> +[Alias <alias name>]) +
(NewWindow <instance name> <device index> +[Alias <alias name>]) +

+The above two commands are equivalent. Both create new window resources and +associate them with the name specified by instance name. The device +index is a number truncated to its integer value. This integer is the +index at which the desired AWT GraphicsDevice appears in the array returned by +the static getScreenDevices() method of GraphicsEnvironment, and specifies the +physical screen upon which the window should be created. The GraphicsDevice +order in the array is specific to the local viewing site and display +system.

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+
+ +

+ScreenProperty
+WindowProperty

+Syntax: +
(ScreenProperty <instance name> <property name> +<property value>) +
(WindowProperty <instance name> <property name> +<property value>) +

+The above two commands are equivalent. The screen or window instance is +specified by instance name, the property to be set by property +name, and the value to be set by property value. The following +properties are configurable:

+ +
+

+PhysicalScreenWidth

+A number specifying the screen's image area width in meters. When using a +configuration file the default is 0.365. For head mounted displays this should +be the apparent width of the display at the focal plane. + +

+PhysicalScreenHeight

+A number specifying the screen's image area height in meters. When using a +configuration file the default is 0.292. For head mounted displays this should +be the apparent height of the display at the focal plane. + +

+WindowSize

+This property's value can be a 2D point to create a window with the specified +X width and Y height in pixels, or it can be either of the strings FullScreen +or NoBorderFullScreen to specify a full screen canvas with visible frame +borders or one with no frame borders. A NoBorderFullScreen canvas uses the +entire physical display surface for its image. The default value is 512 x 512 +pixels. For multiple screen virtual reality installations or head mounted +displays NoBorderFullScreen should be used. + +

+WindowPosition

+This property's value is a 2D point used to create a window with the specified +X and Y position. These are offsets of the window's upper left corner from the +screen's upper left corner. + +

+TrackerBaseToImagePlate

+A 4D matrix which transforms points from tracker base coordinates to the image +plate coordinates for the specified screen. This is only used when a +ViewPolicy of SCREEN_VIEW is in effect. The matrix value is +identity by default. +

+Image plate dimensions are expressed in meters. The origin of the image plate +is the lower left corner of the screen's image area, with X increasing to the +right, Y increasing to the top, and Z increasing away from the screen.

+

+The tracker base is somewhat abstract. It is used as a local fixed frame of +reference for specifying the orientation and position of a screen even when +tracking hardware is not being used. It is also the frame of reference for +defining coexistence coordinates with the +CoexistenceToTrackerBase matrix.

+

+The built-in commands Translate, +Rotate, RotateTranslate, and TranslateRotate are available to make it easier +to create transforms of this type. + +

+HeadTrackerToLeftImagePlate
+HeadTrackerToRightImagePlate

+4D matrices which transform points in the head tracking sensor's local +coordinate system to a head mounted display's left and right image plates +respectively. The default value for each is the identity matrix.

+

+These are only used when a ViewPolicy of HMD_VIEW is in effect. +As with physical screen dimensions, these matrices should indicate the +apparent location and orientation of the screen images as viewed through +the head mounted display's optics.

+

+The HMD manufacturer's specifications in terms of angle of view, distance to +the focal plane, aspect ratio, and percentage of image overlap between the left +and right views can be used to derive the apparent screen positions with +respect to the head, and from there the positions with respect to the head +tracker mounted on the head. In most cases there is 100% overlap between the +two stereo images, so the matrices for both the left and right screens should +be identical.

+

+Some HMD devices support field-sequential stereo and are driven as if they were +a single screen. In that case, only a single screen should be defined, but +both the left and right head tracker to image plate transforms need to +be specified for that same screen.

+ +

+MonoscopicViewPolicy

+This property may have the following string values: CYCLOPEAN_EYE_VIEW, +LEFT_EYE_VIEW, or RIGHT_EYE_VIEW. The default value is +CYCLOPEAN_EYE_VIEW. This default works for non-stereo displays +and field-sequential stereo displays where the two stereo images are generated +on the same canvas.

+

+Some HMD devices can be driven as a single screen if the HMD supports +field-sequential stereo, so the default policy will work for them as well if a +stereo view is enabled. If stereo is not enabled, an IllegalStateException will +be thrown when the ViewPolicy is set to HMD_VIEW with the default +CYCLOPEAN_EYE_VIEW policy in effect.

+

+The LEFT_EYE_VIEW and RIGHT_EYE_VIEW monoscopic view +policies are used for generating stereo pairs on separate monoscopic canvases, +including the left and right canvases needed by HMD devices that are driven by +two video channels. When using these policies, stereo should not be +enabled.

+
+
+ +

+NewPhysicalEnvironment

+Syntax: +
(NewPhysicalEnvironment <instance name> +[Alias <alias name>]) +

+Creates a new PhysicalEnvironment and binds it to the name given by instance +name. This specifies the available input devices, which Sensor to use as +the head tracker, and defines the coexistence coordinate system. Note that +aside from the head tracker, the configuration file does not provide a way to +place Sensors into the array maintained by the PhysicalEnvironment. See the +getNamedSensors +method of ConfigContainer.

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+
+ +

+PhysicalEnvironmentProperty

+Syntax: +
(PhysicalEnvironmentProperty <instance name> +<property name> <property value>) +

+Sets a PhysicalEnvironment property. The instance is specified by instance +name, the property to be set by property name, and the value to be +set by property value. The following properties are configurable:

+ +
+

+InputDevice

+Register an InputDevice implementation instantiated by +NewDevice. The InputDevice instance name is specified +by the property value string. If an InputDevice is not registered then +it will not be scheduled to run. + +

+HeadTracker

+Register the Sensor which will be used for head tracking. It must provide 6 +degree of freedom position and orientation reads relative to the tracker base. +The Sensor instance name is specified by the property value string. +Its corresponding input device must be registered with the InputDevice +property. +

+There is no actual method in the core PhysicalEnvironment class to set the head +tracker. This property is a simplified interface for setting the +PhysicalEnvironment head index and assigning the head tracking sensor to that +index. Direct access to the PhysicalEnvironment Sensor array is not supported +by the configuration file.

+ +

+CoexistenceToTrackerBase

+A 4D matrix which transforms points in coexistence coordinates to tracker base +coordinates. This defines the position and orientation of coexistence +coordinates relative to the tracker base. Its default value is the identity +matrix, so if it is not set then coexistence coordinates will be the same as +tracker base coordinates. See +TrackerBaseToImagePlate. +

+The coexistence origin (center of coexistence) positions the physical +world with respect to the origin of the ViewPlatform in the virtual world. +This is established through the +ViewAttachPolicy, which attaches the view +platform to either the center of coexistence, the nominal head, or the nominal +feet. Coexistence coordinates can essentially be thought of as physical +coordinates, but the real purpose is to define the space in which coordinates +systems in the physical world - such as tracker base, image plate, and physical +body - coexist and interact with the virtual world coordinate systems.

+

+The basis vectors (X, Y, and Z directions) of coexistence coordinates are +always aligned with the basis vectors of the ViewPlatform in the virtual world, +and the scale factor going from ViewPlatform coordinates to coexistence +coordinates is set by the ScreenScalePolicy. +Together with the ViewPlatform's view attach policy and view transform this +establishes the complete mapping of the physical world into the virtual +world.

+

+The positioning and orientation of coexistence coordinates with respect to the +physical environment is up to the user or application. In a fixed screen +environment it usually makes most sense to define it in a convenient +relationship to the primary screen or some intersection of the available +screens, such that the coexistence origin is in front of and aligned with the +user's nominal forward gaze direction. This is because the -Z axis of +coexistence coordinates always points along the view direction defined by the +view platform's -Z axis.

+

+For example, when using a single screen, the most common mapping puts the +center of coexistence in the middle of the screen with its basis vectors +aligned with the screen's image plate coordinate system. With a dual-screen +system it is usually most convenient to place the center of coexistence in the +middle of the edge shared by both screens, with its Z axis extending +perpendicular to the shared edge and maintaining an equal angle to both +screens. For a 2x2 array of four screens putting the center of coexistence at +the center of the array is usually a good choice. In a cave configuration +having the center of coexistence in the middle of the viewing environment can +facilitate the sense of immersion.

+

+In HMD mode the view attach policy is ignored and is always effectively +NOMINAL_SCREEN. Coexistence coordinates and view platform +coordinates are then equivalent except for scale. For HMD configurations +placing the coexistence coordinate system aligned with some nominal +front-facing user position works well.

+

+Note: the normal Java 3D default is to place the center of coexistence +in the middle of the screen or canvas by setting +CoexistenceCenteringEnable true by +default. This only works for a single screen and if both the +TrackerBaseToImagePlate and CoexistenceToTrackerBase matrices are identity. If +either of these matrices are set from their default identity values in the +configuration file, and CoexistenceCenteringEnable has not been set, then the +centering property will be set false by default.

+

+
+ +

+NewPhysicalBody

+Syntax: +
(NewPhysicalBody <instance name> +[Alias <alias name>]) +

+Creates a new PhysicalBody and binds it to the name given by instance +name. The PhysicalBody is essentiallly the users's head, with the origin +halfway between the eyes in the plane of the face. Positive X extends to the +right eye, positive Y up, and positive Z extends into the skull opposite to the +forward gaze direction. Dimensions are expressed in meters.

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+
+ +

+PhysicalBodyProperty

+Syntax: +
(PhysicalBodyProperty <instance name> <property name> +<property value>) +

+Sets a PhysicalBody property. The instance is specified by instance +name, the property to be set by property name, and the value to be +set by property value. The following properties are configurable:

+ +
+

+StereoEyeSeparation

+A number indicating the interpupilary distance in meters. This will set the +left and right eye positions to offsets of half this distance from the head +origin along its X axis. The default is 0.066 meters. +

+This property is a simplified interface to setting the PhysicalBody's separate +left and right eye positions; there is no actual method in PhysicalBody to set +stereo eye separation, but the results are exactly equivalent.

+ +

+LeftEarPosition

+A 3D point which sets the left ear position relative to head coordinates. +The default is (-0.08, -0.03, 0.09). + +

+RightEarPosition

+A 3D point which sets the right ear position relative to head coordinates. +The default is (0.08, -0.03, 0.09). + +

+HeadToHeadTracker

+A 4D matrix which transforms points from head coordinates to the local +coordinate system of the head tracking sensor. This allows the positions +of the eyes and ears to be determined from the position and orientation +of the head tracker. The default is the identity matrix. + +

+ +NominalEyeOffsetFromNominalScreen

+A distance in meters used as a calibration parameter for +ViewAttachPolicy. It does not actually set +the position of the eyes. The property is ignored if ViewAttachPolicy is +NOMINAL_SCREEN. The default value is 0.4572 meters. + +

+NominalEyeHeightFromGround

+A distance in meters used as a calibration parameter for +ViewAttachPolicy. +It does not actually set the position of the eyes. This property is +ignored if ViewAttachPolicy is not NOMINAL_FEET. The default value is 1.68 +meters. +
+
+ +

+NewView

+Syntax: +
(NewView <instance name> +[Alias <alias name>]) +

+Creates a new view and binds it to the name given by instance name. +In the configuration file the term view refers to an instance of the +Viewer utility class, which contains both an +instance of a core Java 3D View class and an array of Canvas3D instances into +which to render.

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+

+ConfiguredUniverse requires that at least one view be defined. If a view +platform is not provided, then ConfiguredUniverse will create a default one and +attach the view to that. If multiple views are defined, then at least one view +platform must be explicitly provided by the configuration, and the +ViewPlatform property must be used to attach each view to a view platform.

+
+ +

+ViewProperty

+Syntax:
+(NewView <instance name> <property name> +<property value>) +

+Sets a View property. The view instance is specified by instance name, +the property to be set by property name, and the value to be set by +property value. The following properties are configurable:

+ +
+

+Screen
+Window

+These two properties are equivalent. They include a screen created by +NewScreen or a window created by +NewWindow into +this view. The screen or window name is specified by the property value +string. Multiple-screen or multiple-window views are created by calling this +command with each window or screen to be used. If no windows or screens are +defined for this view then an IllegalArgumentException will be thrown after the +configuration file has been processed. + +

+PhysicalEnvironment

+Sets the PhysicalEnvironment to be used for this view. The property +value string specifies the name of a PhysicalEnvironment instance created +by the NewPhysicalEnvironment command. +If no PhysicalEnvironment is specified for this view then one with default +values will be created. + +

+PhysicalBody

+Sets the PhysicalBody to be used for this view. The property +value string specifies the name of a PhysicalBody instance created +by the NewPhysicalBody command. If +no PhysicalBody is specified for this view then one with default values +will be created. + +

+ViewPlatform

+The property value string is the name of a view platform defined by a +previous NewViewPlatform command. This +specifies that the view should be attached to the given view platform. +ConfiguredUniverse requires that a view platform be specified for every defined +view unless only a single view without a view platform is provided; in that +case a view platform is created by default and the view is attached to that. +If one or more view platforms are defined then the view attachments must be +made explicitly. + +

+ViewPolicy

+The property value string may be either SCREEN_VIEW or +HMD_VIEW to indicate whether fixed room-mounted screens are being +used or a head mounted display. The default value is SCREEN_VIEW. + +

+CoexistenceCenteringEnable

+The property value is a boolean string. If true, then the origin of the +coexistence coordinate system is set to either the middle of the canvas or the +middle of the screen depending upon whether the WindowMovementPolicy is +PHYSICAL_WORLD or VIRTUAL_WORLD respectively. The X, +Y, and Z directions of coexistence coordinates will point in the same +directions as those of the screen's image plate. +

+This only works if a single screen is being used and if both the +TrackerBaseToImagePlate and +CoexistenceToTrackerBase matrices are +identity. If CoexistenceCenteringEnable is not explicitly set, and either the +CoexistenceToTrackerBase transform for the view has been set or +TrackerBaseToImagePlate has been set for any screen, then the centering enable +will be set to false by default; otherwise, the normal default is true. This +property is also effectively false whenever the ViewPolicy is set to +HMD_VIEW.

+ +

+WindowEyepointPolicy

+The string value for this property may be either RELATIVE_TO_SCREEN, +RELATIVE_TO_COEXISTENCE, RELATIVE_TO_WINDOW, or +RELATIVE_TO_FIELD_OF_VIEW. The normal Java 3D default is +RELATIVE_TO_FIELD_OF_VIEW. When using a configuration file the +default is RELATIVE_TO_COEXISTENCE if +CoexistenceCenteringEnable is false, +otherwise the normal default applies. See the +setWindowEyepointPolicy View method. +

+For the RELATIVE_TO_SCREEN and RELATIVE_TO_WINDOW +policies, the eyepoint is set by using the setLeftManualEyeInImagePlate() and +setRightManualEyeInImagePlate() methods of Canvas3D. The configuration file +currently does not provide any mechanism for altering these properties from +their default values. These default values are (0.142, 0.135, 0.4572) for the +left eye and (0.208, 0.135, 0.4572) for the right eye.

+

+These polices are ignored if head tracking is enabled.

+ +

+WindowMovementPolicy
+WindowResizePolicy

+ +The string values for these properties may be either VIRTUAL_WORLD +or PHYSICAL_WORLD. The normal Java 3D default value for both is +PHYSICAL_WORLD. When using a configuration file the default +values are VIRTUAL_WORLD if +CoexistenceCenteringEnable is false, +otherwise the normal defaults apply. See the +setWindowMovementPolicy and +setWindowResizePolicy View methods.

+ +

+CenterEyeInCoexistence

+A 3D point which specifies the location of the center eye relative to +coexistence coordinates. See +CoexistenceToTrackerBase. If stereo +viewing is enabled, then the left and right eye positions are set to offsets +from this position using the values specified by the PhysicalBody. This +property is ignored if head tracking is enabled or if WindowEyepointPolicy is +not RELATIVE_TO_COEXISTENCE. The default value is (0.0, 0.0, +0.4572). +

+This property is a simplified interface to setting the View's left +and right manual eyes in coexistence; there is no actual method in View +to set a center eye position.

+ +

+ScreenScalePolicy

+The property value string may be either SCALE_SCREEN_SIZE +or SCALE_EXPLICIT and determines the source of the screen +scale, a factor in the scaling of view platform coordinates to physical +world coordinates. +

+If the value is SCALE_SCREEN_SIZE, then the screen scale is half +the physical screen width in meters. If WindowResizePolicy is +PHYSICAL_WORLD, then this scale is further multiplied by the ratio +of the window width to the width of the screen (the window scale) to +produce the scale from view platform coordinates to physical coordinates. This +allows a virtual world which spans a normalized width of [-1.0 .. 1.0] in view +platform coordinates to map directly to the physical width of the window or +screen, depending upon the resize policy.

+

+SCALE_EXPLICIT uses the value of the ScreenScale property as the +screen scale. It is also further multiplied by the window scale when using the +PHYSICAL_WORLD window resize policy to produce the scale from view +platform coordinates to physical coordinates. Viewing configurations +incorporating multiple screens should generally set the policy to +SCALE_EXPLICIT and choose a screen scale based on the aggregate +display size, but the default value of SCALE_SCREEN_SIZE will +usually work if all the screens are the same size and arranged in a linear +array.

+

+The view platform is positioned in the virtual world through a chain of +transforms to the root of the scene graph; this composite transform is its +localToVWorld transform and must be congruent. If we take the the inverse of +the scale factor in this transform and call it the view platform scale, +then the scale from virtual world units to physical world units can be computed +as the product of this view platform scale, the screen scale, and, when using a +resize policy of PHYSICAL_WORLD, the window scale. In the usual +case the view platform scale is 1.0.

+ +

+ScreenScale

+The property value is a number specifying the explicit screen scale +factor. It is only used if ScreenScalePolicy is SCALE_EXPLICIT; +otherwise, the screen scale is half the physical width of the screen in meters. +The default value for this property is 1.0. + +

+BackClipPolicy
+FrontClipPolicy

+The string values of these properties may be either PHYSICAL_EYE, +PHYSICAL_SCREEN, VIRTUAL_EYE, or VIRTUAL_SCREEN. The +default policies are PHYSICAL_EYE. See the +setFrontClipPolicy and +setBackClipPolicy View methods. + +

+FrontClipDistance
+BackClipDistance

+These property values are numbers. The defaults are 0.1 and 10.0 +respectively. See the +setFrontClipDistance and +setBackClipDistance View methods.

+

+With the default clip policies of PHYSICAL_EYE the clip distances +are measured relative to the eye in physical units, so the clip distances +specified must be scaled to virtual world units in order to determine the +distances in the virtual world where they would effectively be applied. As +described in the discussion of +ScreenScalePolicy above, the scale from +virtual units to physical units is the product of the view platform scale +(usually 1.0), the screen scale, and the window scale (if the window resize +policy is PHYSICAL_WORLD), so normally the scale from physical +units to virtual units would be the inverse of that product.

+

+There is a quirk, however, with physical clip plane scaling when the +PHYSICAL_EYE or PHYSICAL_SCREEN clip policies are +used with the PHYSICAL_WORLD window resize policy. The locations +of the clip planes in physical units are not actually set to the physical +distances as specified, but are in fact scaled by the window scale. +This means that when determining where the specified physical clip distances +are in virtual units the scaling to be used is the inverse of the product of +the screen scale and view platform scale only.

+

+This quirk applies only to scaling physical clip plane distances, and only with +the PHYSICAL_WORLD resize policy. It was implemented in this +manner to prevent objects in the virtual world from getting clipped +unexpectedly when the virtual world scaling changed as the result of a window +resize. The quirk can be avoided by using the VIRTUAL_EYE or +VIRTUAL_SCREEN clip policies or by using the +VIRTUAL_WORLD resize policy, but in most cases the effect is +benign and doesn't lead to unexpected results.

+ +

+FieldOfView

+This number is the view's horizontal field of view in radians. The default +value is PI/4. This value is ignored if WindowEyepointPolicy is not +RELATIVE_TO_FIELD_OF_VIEW or if head tracking is enabled. The +eyepoint for each canvas associated with the view is set such that it is +centered in X and Y, with the Z value at the appropriate distance to match the +specified field of view across the width of the canvas. + +

+StereoEnable

+Enable or disable stereo viewing for this view according to the boolean value +specified by the property value string. The default value is false. +

+There is no actual method in the core Java 3D View or utility Viewer class to +enable stereo. A true value for this property causes ConfigContainer to +attempt to create stereo-capable canvases for all the screens associated with +this view. Stereo will then be enabled for each canvas successfully created +with stereo capability.

+ +

+TrackingEnable

+Enable or disable head tracking for this view according to the boolean value +specified by the property value string. The default value is false. +

+Setting this property true causes WindowEyepointPolicy to be ignored; it will +effectively be RELATIVE_TO_COEXISTENCE with the eyepoint in +coexistence coordinates computed from reading the head tracking sensor. +Tracking must be made available by registering an input device and a head +tracking sensor in PhysicalEnvironment.

+ +

+AntialiasingEnable

+Enable or disable scene antialiasing for this view according to the boolean +value specified by the property value string. The default value is +false. +

+A true value for this property causes ConfigContainer to attempt to create +a canvas capable of scene antialiasing on each screen associated with this +view. The scene will then be antialiased on each canvas successfully created +with that capability.

+

+Line and point antialiasing are independent of scene antialiasing and are +controlled by the LineAttribute and PointAttribute components of an Appearance. +If line and point antialiasing is enabled, then they will be antialiased prior +to scene antialiasing; if scene antialiasing is turned off, then antialiased +lines and points will still be antialiased.

+
+
+ +

+NewViewPlatform

+Syntax: +
(NewViewPlatform <instance name> +[Alias <alias name>]) +

+Creates a new view platform and binds it to the name given by instance +name. In the configuration file the term view platform refers to an +instance of the ViewingPlatform utility +class, which is an extension of BranchGroup containing an instance of a core +Java 3D ViewPlatform class.

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+
+ +

+ViewPlatformProperty

+Syntax: +
(ViewPlatformProperty <instance name> <property name> +<property value>) +

+Sets a ViewPlatform property. The instance is specified by instance +name, the property to be set by property name, and the value to be +set by property value. The following properties are configurable:

+ +
+

+NominalViewingTransform

+The property value is a boolean string indicating whether or not +the view platform should be backed up in Z to allow objects at the origin to be +viewed. This only has effect if the ViewAttachPolicy is +NOMINAL_HEAD. The default value is false. See the +setNominalViewingTransform +method of ViewingPlatform. + +

+InitialViewingTransform

+Sets the initial transform of the view platform to the 4D matrix +specified by property value. The default value is identity. + +

+AllowPolicyRead

+The property value is a boolean string indicating whether or not reading +the ViewAttachPolicy is allowed. The default value is false. + +

+AllowLocalToVworldRead

+The property value is a boolean string indicating whether or not reading +the view platform's localToVworld transform is allowed. The default value is +false. + +

+ViewPlatformBehavior

+Attaches a ViewPlatformBehavior instantiated by +NewViewPlatformBehavior. +The property value string is the name bound to that instance. + +

+ViewAttachPolicy

+The property value string can be one of NOMINAL_SCREEN, +NOMINAL_HEAD, or NOMINAL_FEET. This establishes the point +in coexistence coordinates where the origin of view platform coordinates is +attached. The basis vectors of view platform coordinates are always aligned +with those of coexistence coordinates. +

+For a ViewAttachPolicy of NOMINAL_SCREEN, the ViewPlatform origin +is set directly to the origin of coexistence, so that ViewPlatform coordinates +and coexistence coordinates are identical except for scale.

+

+For a ViewAttachPolicy of NOMINAL_HEAD, the ViewPlatform origin is +set to the origin of the nominal head, the center eye halfway between the left +and right eyes. The nominal head origin is on the Z axis of coexistence +coordinates at some offset from the coexistence origin. If the +WindowEyepointPolicy is RELATIVE_TO_FIELD_OF_VIEW, then this is +the positive Z offset producing the required field of view relative to the +width of the canvas at the coexistence origin, tracking the Z offset of the +eyepoint defined by that policy; otherwise, the Z offset is the +NominalEyeOffsetFromNominalScreen property of PhysicalBody and is decoupled +from the actual eyepoint offset.

+

+For a ViewAttachPolicy of NOMINAL_FEET, the ViewPlatform origin is +at the ground plane, which is NominalEyeHeightFromGround meters along -Y from +the origin of the nominal head. NominalEyeHeightFromGround is a property of +PhysicalBody.

+

+Note: The normal Java 3D default is NOMINAL_HEAD. When +using a configuration file, the default is NOMINAL_HEAD only if +every view attached to the view platform has a WindowEyepointPolicy of +RELATIVE_TO_FIELD_OF_VIEW; otherwise, the default is +NOMINAL_SCREEN. If the view policy is HMD_VIEW, then +the ViewAttachPolicy is ignored and is always effectively +NOMINAL_SCREEN.

+
+
+ +

+NewViewPlatformBehavior

+Syntax: +
(NewViewPlatformBehavior <instance name> <class name> +[Alias <alias name>]) +

+This command instantiates the concrete subclass of ViewPlatformBehavior +specified by the fully qualified class name and binds it to instance +name. The ViewPlatformBehavior is instantiated through introspection of +the class name. The subclass must provide a parameterless constructor. If no +such constructor is available, then the behavior must be extended or wrapped to +provide one and the derived class used instead.

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+

+View platform behaviors often need sensors or canvases as event sources to +drive the behavior action. A subclass of ViewPlatformBehavior always gets the +current ViewingPlatform through its +setViewingPlatform +method. When the behavior is initialized, the canvases used by the +ViewingPlatform can be retrieved by calling its +getViewers method and +then calling each Viewer's +getCanvas3Ds method. Sensors +can be retrieved by calling the ViewingPlatform method +getUniverse, checking +to see if the returned SimpleUniverse is a ConfiguredUniverse, and then calling +its +getNamedSensors +method.

+

+Alternatively, the behavior implementation can define its own properties +and receive canvas and sensor instances directly through the +Canvas3D and Sensor built-in +commands.

+
+ +

+ViewPlatformBehaviorProperty

+Syntax: +
(ViewPlatformBehaviorProperty <instance name> +<property name> <property value>) +

+Sets a property of a ViewPlatformBehavior. The instance is specified by +instance name, the property to be set by property name, and the +value to be set by property value. The following properties are +pre-defined by the abstract ViewPlatformBehavior superclass and may be +configured directly:

+ +

+

+SchedulingBounds

+The scheduling bounds for this behavior. Use the +BoundingSphere built-in command to set this +property. The default is whatever the application or the concrete subclass +sets. + +

+SchedulingInterval

+A number indicating the scheduling interval for this behavior. See the +setSchedulingInterval +method of Behavior. + +

+HomeTransform

+See the ViewPlatformBehavior method +setHomeTransform. +The property value must be a 4D matrix. +
+

+The details of a concrete subclass of ViewPlatformBehavior are not known to +ConfigContainer, so any properties specific to the subclass are set by +using introspection to invoke property name as a method accepting an +array of Objects as its single parameter. The arguments following the property +name are evaluated and the results passed to the method through that array of +Objects. Such methods can usually be provided by extending or wrapping +existing ViewPlatformBehavior implementations.

+
+ +

+NewObject

+Syntax: +
(NewObject <instance name> <class name> +[Alias <alias name>]) +

+This command instantiates a generic object specified by class +name and binds it to instance name. The object is instantiated +through introspection of the class name. The object must provide a +parameterless constructor; this can usually be done by extending or +wrapping existing objects.

+

+The last two arguments are optional and define an alias for instance +name. This is useful in providing a longer descriptive name for the +application to recognize, or conversely, to provide a shorter alias for a +longer instance name. Either name may be used to identify the instance.

+

+Objects so defined may be accessed from ConfigContainer through the +getNamedGenericObjects method.

+
+ +

+ObjectProperty

+Syntax: +
(ObjectProperty <instance name> <method name> <arg0> +... <argn>) +

+Sets a property of a generic object. The details of the object specified by +instance name are not known to ConfigContainer, so any parameters to be +set through the configuration file are passed to the object instance by +invoking method name through introspection. The arguments following the +method name are evaluated and the results passed to the method as an array of +Objects. The required methods can usually be provided by extending or wrapping +existing objects.

+
+ +

+JavaProperty

+Syntax: +
(JavaProperty <propertyName> [Default] +<propertyValue>) +

+Sets the Java system property propertyName to the string +propertyValue. If the optional Default keyword is supplied, then the +property is set only if it doesn't currently have a value.

+

+Java system properties which affect Java 3D are evaluated at the first +reference to a VirtualUniverse. Setting such properties in the configuration +file is therefore ineffective if a ConfiguredUniverse constructor which accepts +a URL directly is used; ConfigContainer must be used instead. Even then, care +must be taken to avoid static references to VirtualUniverse from objects such +as Transform3D.

+

+The special Java property substitution syntax ${<propertyName>} +may be used to access the value of a Java system property anywhere within a +configuration file.

+
+ +

+Include

+Syntax: +
(Include <URL string>) +

+Retrieves the configuration file specified by URL string and includes it +into the current configuration file at the current line. The content of the +included file is evaluated exactly as if it were pasted into the current file +at that line. Included files may be arbitrarily nested.

+

+URL strings must be quoted.

+


+ +

+Alias

+Syntax: +
(<baseName>Alias <aliasName> +<originalName>) +

+Creates an alias for the object specified by originalName (which itself +may be an alias). baseName may be Device, Object, PhysicalBody, +PhysicalEnvironment, Screen, Window, Sensor, View, ViewPlatform, or +ViewPlatformBehavior; it specifies the type of the object being aliased. +Original names and aliases must be unique within a type. Note that there is no +white space between baseName and Alias.

+

+Aliases are useful for providing shorter or longer descriptive names for an +original name. This function is also provided by the optional Alias keyword +available for all New top-level commands. This separate command can be +used to substitute new names for objects created by generic include files in +order to conform to the names expected by specific applications.

+
+ + + + + + +
+Built-In Command Details
+

+Built-in commands are provided by the parser itself to help construct the +arguments to top-level commands. They cannot appear at the top level of +command nesting.

+

+Translate, Rotate, TranslateRotate, and RotateTranslate are useful for +computing simple affine transforms of the form SourceToTarget +(e.g., TrackerBaseToImagePlate). These transform points from the +Source coordinate system to the Target coordinate system by +concatenating translation and rotation matrices. Here is a general rule for +creating such transforms:

+ +
+Subtract (translate) the target origin first if it can be conveniently measured +or computed relative to the source origin along the source X, Y, and Z basis +vectors. Then rotate with Euler angles that move the target basis vectors to +their corresponding source basis vectors. +

+If instead it is easier to measure or compute the source origin relative to the +target origin along the target basis vectors, rotate first with Euler angles +that move the target basis vectors to their corresponding source basis vectors, +and then add (translate) the source origin.

+
+

+The Canvas3D, Sensor, Device, PhysicalBody, PhysicalEnvironment, View, +ViewPlatform, ViewPlatformBehavior, and Object built-in commands return +references to the objects named by their arguments. These are mostly useful +for InputDevice and ViewPlatformBehavior implementations that define their own +properties. The return values of these built-in commands should not be passed +to commands that expect strings.

+
+ +

+Translate

+Syntax: +
(Translate <x offset> <y offset> <z offset>) +

+Returns a 4D matrix that translates by the given X, Y, and Z values.

+
+ +

+Rotate

+Syntax: +
(Rotate <x degrees> <y degrees> <z degrees>) +

+Returns a 4D matrix that rotates by the given Euler angles around static X, Y, +and Z basis vectors: first about X, then Y, and then Z. See the +setEuler +method of Transform3D.

+
+ +

+Concatenate

+Syntax: +
(Concatenate <m1> <m2>) +

+Returns a 4D matrix that concatenates 4D matrices m1 and m2 in +that order. If a point is transformed by the resulting matrix, then in effect +the points are first transformed by m1 and then m2.

+
+ +

+RotateTranslate

+Syntax: +
(RotateTranslate <m1> <m2>) +

+An alias for the Concatenate command. This is useful to make the +result of the concatenation explicit.

+
+ +

+TranslateRotate

+Syntax: +
(TranslateRotate <m1> <m2>) +

+An alias for the Concatenate command. This is useful to make the +result of the concatenation explicit.

+
+ +

+BoundingSphere

+Syntax: +
(BoundingSphere <center> <radius>) +

+Returns a BoundingSphere object using the 3D point center and the given +radius in meters. radius may be either a number or the string +Infinite.

+
+ +

+Canvas3D

+Syntax: +
(Canvas3D <screen or window name>) +

+Returns the Canvas3D instance specified by the given name. A named Canvas3D is +created whenever any of the following configuration commands are used: + +

+(ViewProperty <view> Screen <screenName>)
+(ViewProperty <view> Window <windowName>) +
+ +view is the name of a view created with the NewView command. The +argument to the Canvas3D built-in must be a screenName or +windowName parameter from one of the above commands.

+

+Note: the NewScreen and NewWindow commands do not create Canvas3D +instances themselves; they are created only by the above configuration +commands.

+
+ +

+Sensor

+Syntax: +
(Sensor <sensor name>) +

+Returns the Sensor instance specified by the given name.

+
+ +

+Device

+Syntax: +
(Device <device name>) +

+Returns the InputDevice instance specified by the given name.

+
+ +

+PhysicalBody

+Syntax: +
(PhysicalBody <body name>) +

+Returns the PhysicalBody instance specified by the given name.

+
+ +

+PhysicalEnvironment

+Syntax: +
(PhysicalEnvironment <environment name>) +

+Returns the PhysicalEnvironment instance specified by the given name.

+
+ +

+View

+Syntax: +
(View <view name>) +

+Returns the Viewer instance specified by the given name.

+
+ +

+ViewPlatform

+Syntax: +
(ViewPlatform <view platform name>) +

+Returns the ViewingPlatform instance specified by the given name.

+
+ +

+ViewPlatformBehavior

+Syntax: +
(ViewPlatformBehavior <behavior name>) +

+Returns the ViewPlatformBehavior instance specified by the given name.

+
+ +

+Object

+Syntax: +
(Object <generic object name>) +

+Returns the generic object instance specified by the given name. A generic +named object is created by the following configuration command: + +

+(NewObject <instance name> <class name> +[Alias <alias name>]) +
+
+ +

+ConfigContainer

+Syntax: +
(ConfigContainer) +

+Returns a reference to the current ConfigContainer.

+
+ +
+ + + + +
+Command Index
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CommandType
Aliastop-level
BoundingSpherebuilt-in
Canvas3Dbuilt-in
Concatenatebuilt-in
ConfigContainerbuilt-in
Devicebuilt-in
DevicePropertytop-level
Includetop-level
JavaPropertytop-level
NewDevicetop-level
NewObjecttop-level
NewPhysicalBodytop-level
NewPhysicalEnvironmenttop-level
NewScreentop-level
NewSensortop-level
NewViewtop-level
NewViewPlatformtop-level
NewViewPlatformBehaviortop-level
NewWindowtop-level
Objectbuilt-in
ObjectPropertytop-level
PhysicalBodybuilt-in
PhysicalBodyPropertytop-level
PhysicalEnvironmentbuilt-in
PhysicalEnvironmentPropertytop-level
Rotatebuilt-in
RotateTranslatebuilt-in
ScreenPropertytop-level
Sensorbuilt-in
SensorPropertytop-level
Translatebuilt-in
TranslateRotatebuilt-in
Viewbuilt-in
ViewPlatformbuilt-in
ViewPlatformBehaviorbuilt-in
ViewPropertytop-level
ViewPlatformPropertytop-level
ViewPlatformBehaviorPropertytop-level
WindowPropertytop-level
+

+ + + + + + +
+Property Index
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyCommand
AllowLocalToVworldReadViewPlatformProperty
AllowPolicyReadViewPlatformProperty
AntialiasingEnableViewProperty
BackClipDistanceViewProperty
BackClipPolicyViewProperty
CenterEyeInCoexistenceViewProperty
CoexistenceCenteringEnableViewProperty
CoexistenceToTrackerBasePhysicalEnvironmentProperty
FieldOfViewViewProperty
FrontClipDistanceViewProperty
FrontClipPolicyViewProperty
HeadToHeadTrackerPhysicalBodyProperty
HeadTrackerPhysicalEnvironmentProperty
HeadTrackerToLeftImagePlateScreenProperty
HeadTrackerToRightImagePlateScreenProperty
HomeTransformViewPlatformBehaviorProperty
HotspotSensorProperty
InitialViewingTransformViewPlatformProperty
InputDevicePhysicalEnvironmentProperty
LeftEarPositionPhysicalBodyProperty
MonoscopicViewPolicyScreenProperty
NominalEyeHeightFromGroundPhysicalBodyProperty
NominalEyeOffsetFromNominalScreenPhysicalBodyProperty
NominalViewingTransformViewPlatformProperty
PhysicalBodyViewProperty
PhysicalEnvironmentViewProperty
PhysicalScreenHeightScreenProperty
PhysicalScreenWidthScreenProperty
RightEarPositionPhysicalBodyProperty
SchedulingBoundsViewPlatformBehaviorProperty
SchedulingIntervalViewPlatformBehaviorProperty
ScreenViewProperty
ScreenScaleViewProperty
ScreenScalePolicyViewProperty
StereoEnableViewProperty
StereoEyeSeparationPhysicalBodyProperty
TrackerBaseToImagePlateScreenProperty
TrackingEnableViewProperty
ViewAttachPolicyViewPlatformProperty
ViewPlatformViewProperty
ViewPlatformBehaviorViewPlatformProperty
ViewPolicyViewProperty
WindowViewProperty
WindowEyepointPolicyViewProperty
WindowMovementPolicyViewProperty
WindowPositionWindowProperty
WindowResizePolicyViewProperty
WindowSizeWindowProperty
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-behavior.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-behavior.html new file mode 100644 index 0000000..2c5ac19 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-behavior.html @@ -0,0 +1,109 @@ + + + + + j3d1x1-behavior config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for single fullscreen desktop configuration.
+ * A view platform behavior is created and configured here as well.
+ *  
+ ************************************************************************
+ */
+
+(NewScreen center 0)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+
+(NewView view0)
+(ViewProperty view0 Screen center)
+
+// Create a view platform behavior.  Here we use OrbitBehavior, although any
+// concrete subclass of the abstract ViewPlatformBehavior with a parameterless
+// constructor could be used.  The logical name to assign to this behavior is
+// specified by the 2nd argument to the NewViewPlatformBehavior command, while
+// the 3rd argument is the name of the ViewPlatformBehavior subclass.  It is
+// instantiated through introspection.
+// 
+(NewViewPlatformBehavior vpb com.sun.j3d.utils.behaviors.vp.OrbitBehavior)
+
+// Set the scheduling bounds to be a BoundingSphere with its center at 
+// (0.0 0.0 0.0) and an infinite radius.
+// 
+(ViewPlatformBehaviorProperty vpb SchedulingBounds
+                                  (BoundingSphere (0.0 0.0 0.0) infinite))
+
+// Set properties specific to OrbitBehavior.  All arguments following the
+// method name are wrapped and passed to the specified method as an array of
+// Objects.  Strings "true" and "false" get turned into Boolean, and number
+// strings get turned into Double.  Constructs such as (0.0 1.0 2.0) and
+// ((0.0 1.0 2.0 0.5) (3.0 4.0 5.0 1.0) (6.0 7.0 8.0 0.0)) get converted to
+// Point3d and Matrix4d respectively. Note that last row of a Matrix4d doesn't
+// need to be specified; it is implicitly (0.0 0.0 0.0 1.0).
+// 
+// The REVERSE_ALL flags are usually passed to the OrbitBehavior constructor.
+// Since it is being instantiated with its parameterless constructor the
+// reverse flags are set here explicitly.
+// 
+(ViewPlatformBehaviorProperty vpb ReverseTranslate true)
+(ViewPlatformBehaviorProperty vpb ReverseRotate    true)
+(ViewPlatformBehaviorProperty vpb ReverseZoom      true)
+
+// Create a new view platform and set the view platform behavior.
+// 
+(NewViewPlatform vp)
+(ViewPlatformProperty vp ViewPlatformBehavior vpb)
+
+// Attach the view to the view platform.
+(ViewProperty view0 ViewPlatform vp)
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-stereo.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-stereo.html new file mode 100644 index 0000000..dd8568b --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-stereo.html @@ -0,0 +1,90 @@ + + + + + j3d1x1-stereo config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for single fullscreen stereo desktop
+ * configuration with no head tracking.
+ *  
+ ************************************************************************
+ */
+
+(NewScreen center 0)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+
+// Define the physical body.
+//
+// The head origin is halfway between the eyes, with X extending to the right,
+// Y up, and positive Z extending into the skull.
+// 
+(NewPhysicalBody SiteUser)
+
+// Set the interpupilary distance.  This sets the LeftEyePosition and
+// RightEyePosition to offsets of half this distance along both directions of
+// the X axis.
+// 
+(PhysicalBodyProperty SiteUser StereoEyeSeparation 0.066)
+
+// Create a view using the defined screen and physical body.
+//
+(NewView view0)
+(ViewProperty view0 Screen       center)
+(ViewProperty view0 PhysicalBody SiteUser)
+
+// Enable stereo viewing.
+// 
+(ViewProperty view0 StereoEnable true)
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-vr.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-vr.html new file mode 100644 index 0000000..c86296c --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-vr.html @@ -0,0 +1,173 @@ + + + + + j3d1x1-vr config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for a single screen stereo desktop display
+ * using a head tracker and 6DOF mouse.
+ *
+ ************************************************************************
+ */
+
+// Create a screen object and give it a logical name.
+(NewScreen center 0)
+
+// Set the actual available image area.
+(ScreenProperty center PhysicalScreenWidth     0.398)
+(ScreenProperty center PhysicalScreenHeight    0.282)
+(ScreenProperty center WindowSize              NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transform for this screen.
+(ScreenProperty center TrackerBaseToImagePlate
+                 (RotateTranslate (Rotate    50.000 0.000 0.000)
+                                  (Translate  0.199 0.376 0.000)))
+
+// Configure the head tracker.
+(NewDevice      tracker1 com.sun.j3d.input.LogitechTracker)
+(DeviceProperty tracker1 SerialPort "/dev/ttya")
+(DeviceProperty tracker1 ReceiverBaseline     0.1450)
+(DeviceProperty tracker1 ReceiverLeftLeg      0.0875)
+(DeviceProperty tracker1 ReceiverHeight       0.0470)
+(DeviceProperty tracker1 ReceiverTopOffset    0.0000)
+(DeviceProperty tracker1 RealtimeSerialBuffer true)
+
+// Configure the 6DOF wand.
+(NewDevice      tracker2 com.sun.j3d.input.LogitechTracker)
+(DeviceProperty tracker2 SerialPort "/dev/ttyb")
+(DeviceProperty tracker2 ReceiverBaseline     0.0700)
+(DeviceProperty tracker2 ReceiverLeftLeg      0.0625)
+(DeviceProperty tracker2 ReceiverHeight       0.0510)
+(DeviceProperty tracker2 ReceiverTopOffset    0.0000)
+(DeviceProperty tracker2 RealtimeSerialBuffer true)
+
+// Make the tracker2 device a slave of the tracker1 device.
+(DeviceProperty tracker1 Slave (Device tracker2))
+
+// Create a 2D mouse valuator.
+(NewDevice      mouse com.sun.j3d.input.Mouse2DValuator)
+(DeviceProperty mouse Components (Canvas3D center))
+
+// Create logical names for the available sensors.
+(NewSensor head    tracker1 0)
+(NewSensor mouse6d tracker2 0)
+(NewSensor mouse2d mouse    0)
+
+// Set the 6DOF mouse sensor hotspot in the local sensor coordinate system.
+(SensorProperty mouse6d Hotspot (0.00 0.00 -0.10))
+
+// Create a physical environment.
+(NewPhysicalEnvironment SampleSite)
+
+// Register the input devices and head tracker sensor.
+(PhysicalEnvironmentProperty SampleSite InputDevice tracker1)
+(PhysicalEnvironmentProperty SampleSite InputDevice tracker2)
+(PhysicalEnvironmentProperty SampleSite InputDevice mouse)
+(PhysicalEnvironmentProperty SampleSite HeadTracker head)
+
+// Define coexistence coordinates.
+(PhysicalEnvironmentProperty SampleSite CoexistenceToTrackerBase
+                              (TranslateRotate (Translate 0.0 -0.235 0.0)
+                                               (Rotate -50.0 0.0 0.0)))
+
+// Define the physical body.
+(NewPhysicalBody SiteUser)
+
+// Set the interpupilary distance.
+(PhysicalBodyProperty SiteUser StereoEyeSeparation 0.066)
+
+// Define the head location relative to the tracker mounted on the head.
+(PhysicalBodyProperty SiteUser HeadToHeadTracker ((1.0 0.0 0.0 0.000)
+                                                  (0.0 1.0 0.0 0.020)
+                                                  (0.0 0.0 1.0 0.018)))
+
+// Create a view platform behavior.  
+// 
+(NewViewPlatformBehavior vpb com.sun.j3d.utils.behaviors.vp.WandViewBehavior)
+
+(ViewPlatformBehaviorProperty vpb Sensor6D (Sensor mouse6d))
+(ViewPlatformBehaviorProperty vpb Sensor2D (Sensor mouse2d))
+
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 1 GrabView)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 2 TranslateForward)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 0 TranslateBackward)
+
+(ViewPlatformBehaviorProperty vpb RotationCoords ViewPlatform)
+(ViewPlatformBehaviorProperty vpb ButtonAction2D 1 Translation)
+(ViewPlatformBehaviorProperty vpb ButtonAction2D 2 Scale)
+
+(ViewPlatformBehaviorProperty vpb EchoType Beam) 
+(ViewPlatformBehaviorProperty vpb EchoSize 0.004) 
+
+(ViewPlatformBehaviorProperty vpb EchoColor 1.0 0.7 0.0)
+(ViewPlatformBehaviorProperty vpb EchoTransparency 0.4)
+
+// Create a new view platform and set the view platform behavior.
+// 
+(NewViewPlatform vp)
+(ViewPlatformProperty vp ViewPlatformBehavior vpb)
+
+// Create a view.
+//
+(NewView       view0)
+(ViewProperty  view0   Screen                  center)
+(ViewProperty  view0   PhysicalEnvironment     SampleSite)
+(ViewProperty  view0   PhysicalBody            SiteUser)
+(ViewProperty  view0   ViewPlatform            vp)
+
+// Enable stereo viewing and head tracking.
+(ViewProperty  view0   StereoEnable            true)
+(ViewProperty  view0   TrackingEnable          True)
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-window.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-window.html new file mode 100644 index 0000000..b46ba5d --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-window.html @@ -0,0 +1,70 @@ + + + + + j3d1x1-window config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for a conventional single screen, windowed
+ * desktop configuration.
+ *  
+ ************************************************************************
+ */
+
+(NewWindow window1 0)
+(WindowProperty window1 WindowSize (700.0 700.0))
+
+(NewView view1)
+(ViewProperty view1 Window window1)
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1.html new file mode 100644 index 0000000..7b5adfb --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1.html @@ -0,0 +1,69 @@ + + + + + j3d1x1 config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for a single fullscreen desktop configuration.
+ *  
+ ************************************************************************
+ */
+
+(NewWindow big 0)
+(WindowProperty big WindowSize NoBorderFullScreen)
+
+(NewView view0)
+(ViewProperty view0 Window big)
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-flat.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-flat.html new file mode 100644 index 0000000..2172c67 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-flat.html @@ -0,0 +1,152 @@ + + + + + j3d1x2-flat config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for dual-screen (flat) desktop configuration
+ * with no head tracking.
+ *  
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+// 
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+// 
+(NewScreen left  0)
+(NewScreen right 1)
+
+// Set the screen dimensions.
+// 
+(ScreenProperty left  PhysicalScreenWidth  0.360)
+(ScreenProperty left  PhysicalScreenHeight 0.288)
+
+(ScreenProperty right PhysicalScreenWidth  0.360)
+(ScreenProperty right PhysicalScreenHeight 0.288)
+
+// Specify full screen windows.
+// 
+(ScreenProperty left  WindowSize NoBorderFullScreen)
+(ScreenProperty right WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transforms for these screens.  This
+// transforms points in tracker base coordinates to each screen's image plate
+// coordinates, where the origin of the image plate is defined to be the lower
+// left corner of the screen with X increasing to the right, Y increasing to
+// the top, and Z increasing away from the screen.
+//
+// Without head or sensor tracking the tracker base is still needed as a fixed
+// frame of reference for describing the orientation and position of each
+// screen to the others.  The coexistence to tracker base transform is set to
+// identity by default, so the tracker base origin and orientation will also
+// set the origin and orientation of coexistence coordinates in the physical
+// world.
+//
+// The tracker base and center of coexistence is set here to the middle of the
+// edge shared by the two screens.
+//
+(ScreenProperty left  TrackerBaseToImagePlate
+                       (Translate 0.360 0.144 0.0))
+(ScreenProperty right TrackerBaseToImagePlate
+                       (Translate 0.000 0.144 0.0))
+
+// Sometimes it is desirable to include the bevels in between the monitors in
+// the TrackerBaseToImagePlate transforms, so that the abutting bevels obscure
+// the view of the virtual world instead of stretching it out between the
+// monitors.  For a bevel width of 4.5 cm on each monitor, the above commands
+// would become the following:
+// 
+// (ScreenProperty left  TrackerBaseToImagePlate
+//                        (Translate  0.405 0.144 0.0))
+// (ScreenProperty right TrackerBaseToImagePlate
+//                        (Translate -0.045 0.144 0.0))
+//
+// Conversely, a similar technique may be used to include overlap between the
+// screens.  This is useful for projection systems which use edge blending
+// to provide seamless integration between screens.
+
+
+// Create a view using the defined screens.
+// 
+(NewView view0)
+(ViewProperty view0 Screen left)
+(ViewProperty view0 Screen right)
+
+// Set the eyepoint relative to coexistence coordinates.  Here it is set 45cm
+// toward the user along Z, extending out from the midpoint of the edge shared
+// by the two screens.  This will create the appropriate skewed projection
+// frustums for each image plate.
+// 
+// If a planar display surface is all that is required, the same effect could
+// be achieved in a virtual screen enviroment such as Xinerama by simply
+// creating a canvas that spans both screens.  In some display environments the
+// use of a canvas that spans multiple physical screens may cause significant
+// performance degradation, however.
+// 
+// See j3d1x2-rot30 for an example of a non-planar configuration that cannot be
+// achieved through a single canvas spanning both screens.
+// 
+(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.45))
+
+(NewViewPlatform vp)
+(ViewPlatformProperty vp AllowPolicyRead true)
+(ViewPlatformProperty vp AllowLocalToVworldRead true)
+
+(ViewProperty view0 ViewPlatform vp)
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-rot30.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-rot30.html new file mode 100644 index 0000000..f22a32a --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-rot30.html @@ -0,0 +1,111 @@ + + + + + j3d1x2-rot30 config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for a dual-screen desktop configuration
+ * with each screen rotated toward the other by 30 degrees about Y from
+ * planar.  The inside angle between them is 120 degrees.
+ *  
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+// 
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+// 
+(NewScreen left  0)
+(NewScreen right 1)
+
+// Set the available image areas for full screens.
+// 
+(ScreenProperty left  PhysicalScreenWidth  0.360)
+(ScreenProperty left  PhysicalScreenHeight 0.288)
+
+(ScreenProperty right PhysicalScreenWidth  0.360)
+(ScreenProperty right PhysicalScreenHeight 0.288)
+
+// Specify full screen windows.
+// 
+(ScreenProperty left  WindowSize NoBorderFullScreen)
+(ScreenProperty right WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transforms for these screens.
+// 
+// The tracker base is set here to the middle of the edge shared by the two
+// screens.  Each screen is rotated 30 degrees toward the other about the
+// tracker base +Y axis, so that the tracker base +Z is centered between the
+// two screens.
+//
+(ScreenProperty left  TrackerBaseToImagePlate
+                       (RotateTranslate (Rotate     0.000 -30.000 0.0)
+                                        (Translate  0.360   0.144 0.0)))
+
+(ScreenProperty right TrackerBaseToImagePlate
+                       (RotateTranslate (Rotate     0.000  30.000 0.0)
+		                        (Translate  0.000   0.144 0.0)))
+
+
+// Create a view using the defined screens.
+// 
+(NewView view0)
+(ViewProperty view0 Screen left)
+(ViewProperty view0 Screen right)
+(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.45))
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave-vr.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave-vr.html new file mode 100644 index 0000000..9da8bd0 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave-vr.html @@ -0,0 +1,243 @@ + + + + + j3d1x3-cave-vr config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for a cave environment with head tracking and
+ * stereo viewing.  This cave consists of 3 projectors with 3 screens to the
+ * left, front, and right of the user, all at 90 degrees to each other.
+ * 
+ * The projectors in Sun's VirtualPortal sample site are actually turned
+ * on their sides to get more height.  Screen 0 is rotated 90 degrees
+ * counter-clockwise, while screens 1 and 2 are rotated 90 degrees
+ * clockwise.
+ * 
+ ************************************************************************
+ */
+
+// Configure the head tracker.
+// 
+(NewDevice      tracker1 com.sun.j3d.input.LogitechTracker)
+(DeviceProperty tracker1 SerialPort "/dev/ttya") // Unix paths need quoting.
+(DeviceProperty tracker1 TransmitterBaseline            0.4600)
+(DeviceProperty tracker1 TransmitterLeftLeg             0.4400)
+(DeviceProperty tracker1 TransmitterCalibrationDistance 0.4120)
+
+// Configure an InputDevice to use for a 6 degree of freedom wand.
+// 
+(NewDevice      tracker2 com.sun.j3d.input.LogitechTracker)
+(DeviceProperty tracker2 SerialPort "/dev/ttyb")
+(DeviceProperty tracker2 ReceiverBaseline     0.0700)
+(DeviceProperty tracker2 ReceiverLeftLeg      0.0625)
+(DeviceProperty tracker2 ReceiverHeight       0.0510)
+(DeviceProperty tracker2 ReceiverTopOffset    0.0000)
+
+// Make the tracker2 device a slave of the tracker1 device.
+(DeviceProperty tracker1 Slave (Device tracker2))
+
+// Create logical names for the head tracker and wand sensors.  The last
+// argument is the sensor's index in the input device.
+// 
+(NewSensor head     tracker1 0)
+(NewSensor sensor6d tracker2 0)
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+// 
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+// 
+(NewScreen left    0)
+(NewScreen center  1)
+(NewScreen right   2)
+
+
+// Set the available image areas as well as their positition and orientation
+// relative to the tracker base.  From the orientation of a user standing
+// within this VirtualPortal site and facing the center screen, the tracker
+// base is along the vertical midline of the screen, 0.248 meters down from
+// the top edge, and 1.340 meters in front of it.  The tracker base is
+// oriented so that its +X axis points to the left, its +Y axis points toward
+// the screen, and its +Z axis points toward the floor.
+// 
+(ScreenProperty        left    PhysicalScreenWidth     2.480)
+(ScreenProperty        left    PhysicalScreenHeight    1.705)
+(ScreenProperty        left    WindowSize              NoBorderFullScreen)
+(ScreenProperty        left    TrackerBaseToImagePlate
+                                (( 0.0  0.0 -1.0  2.230)
+                                 ( 0.0 -1.0  0.0  1.340)
+                                 (-1.0  0.0  0.0  0.885)))
+
+(ScreenProperty        center  PhysicalScreenWidth     2.485)
+(ScreenProperty        center  PhysicalScreenHeight    1.745)
+(ScreenProperty        center  WindowSize              NoBorderFullScreen)
+(ScreenProperty        center  TrackerBaseToImagePlate
+                                (( 0.0  0.0  1.0  0.248)
+                                 (-1.0  0.0  0.0  0.885)
+                                 ( 0.0 -1.0  0.0  1.340)))
+
+(ScreenProperty        right   PhysicalScreenWidth     2.480)
+(ScreenProperty        right   PhysicalScreenHeight    1.775)
+(ScreenProperty        right   WindowSize              NoBorderFullScreen)
+(ScreenProperty        right   TrackerBaseToImagePlate
+                                (( 0.0  0.0  1.0  0.2488)
+                                 ( 0.0 -1.0  0.0  1.340)
+                                 ( 1.0  0.0  0.0  0.860)))
+
+// Create a physical environment.  This contains the available input devices,
+// audio devices, and sensors, and defines the coexistence coordinate system
+// for mapping between the virtual and physical worlds.
+// 
+(NewPhysicalEnvironment VirtualPortal)
+
+// Register the input device defined in this file and the sensor which will
+// drive head tracking.
+// 
+(PhysicalEnvironmentProperty VirtualPortal InputDevice tracker1)
+(PhysicalEnvironmentProperty VirtualPortal InputDevice tracker2)
+(PhysicalEnvironmentProperty VirtualPortal HeadTracker head)
+
+// Set the location of the center of coexistence relative to the tracker base.
+// Here it set to the center of the center screen.  The default view attach
+// policy of NOMINAL_SCREEN used by ConfiguredUniverse will place the origin of
+// the view platform in coexistence coordinates at the center of coexistence.
+// 
+(PhysicalEnvironmentProperty VirtualPortal
+                             CoexistenceToTrackerBase
+                                ((-1.0  0.0  0.0  0.000)
+                                 ( 0.0  0.0 -1.0  1.340)
+                                 ( 0.0 -1.0  0.0  0.994)))
+
+// Define the physical body.  The head origin is halfway between the eyes, with
+// X extending to the right, Y up, and positive Z extending into the skull.
+// 
+(NewPhysicalBody      LabRat)       
+(PhysicalBodyProperty LabRat StereoEyeSeparation .07)
+
+// Define the position and orientation of the head relative to the tracker
+// mounted on the head.
+// 
+(PhysicalBodyProperty LabRat HeadToHeadTracker 
+                                 ((-1.0  0.0  0.0 0.00)
+                                  ( 0.0  0.0 -1.0 0.05)
+                                  ( 0.0 -1.0  0.0 0.11)))
+
+// Create a view platform behavior for the 6DOF sensor.
+// 
+(NewViewPlatformBehavior vpb com.sun.j3d.utils.behaviors.vp.WandViewBehavior)
+
+(ViewPlatformBehaviorProperty vpb Sensor6D sensor6d)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 2 GrabView)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 1 TranslateForward)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 0 TranslateBackward)
+
+// Default normal translation speed is 0.1 physical meters per second.
+(ViewPlatformBehaviorProperty vpb TranslationSpeed
+                              1.0 PhysicalMeters PerSecond)
+
+// Default rotation coordinates are Sensor.
+(ViewPlatformBehaviorProperty vpb RotationCoords Head)
+
+// Nominal sensor transform for modified joystick RedBarron
+(SensorProperty sensor6d Hotspot (0.00 0.6 0.00))
+(ViewPlatformBehaviorProperty vpb NominalSensorRotation
+                                  ((-1.0  0.0  0.0)
+                                   ( 0.0  0.0 -1.0)
+                                   ( 0.0 -1.0  0.0)))
+
+// Default 6DOF sensor echo is Gnomon
+(ViewPlatformBehaviorProperty vpb EchoSize 0.015) 
+(ViewPlatformBehaviorProperty vpb EchoType Beam) 
+
+// Default 6DOF sensor echo color is white
+(ViewPlatformBehaviorProperty vpb EchoColor 1.0 0.7 0.0)
+
+// Default 6DOF sensor transparency is 0.0 (opaque)
+(ViewPlatformBehaviorProperty vpb EchoTransparency 0.4)
+
+// Create a new view platform and set the view platform behavior.
+// 
+(NewViewPlatform vp)
+(ViewPlatformProperty vp ViewPlatformBehavior vpb)
+
+// Now define the view.
+// 
+(NewView       view0)
+(ViewProperty  view0   Screen                  left)
+(ViewProperty  view0   Screen                  center)
+(ViewProperty  view0   Screen                  right)
+(ViewProperty  view0   PhysicalBody            LabRat)
+(ViewProperty  view0   PhysicalEnvironment     VirtualPortal)
+(ViewProperty  view0   ViewPlatform            vp)
+
+// Set the screen scale.  This is scale factor from virtual to physical
+// coordinates.
+// 
+(ViewProperty  view0   ScreenScalePolicy       SCALE_SCREEN_SIZE)
+
+// Alternative for explict scaling.
+// 
+//(ViewProperty  view0   ScreenScalePolicy       SCALE_EXPLICIT)
+//(ViewProperty  view0   ScreenScale             5.00)
+
+// Enable stereo viewing.  Enable head tracking to get the position of the eyes
+// with respect to coexistence.  Boolean values may be specified as either
+// true, True, false, or False.
+// 
+(ViewProperty    view0   StereoEnable            true)
+(ViewProperty    view0   TrackingEnable          True)
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave.html new file mode 100644 index 0000000..cf5cba2 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave.html @@ -0,0 +1,156 @@ + + + + + j3d1x3-cave config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for a cave environment.  This cave
+ * consists of 3 projectors with 3 screens to the left, front, and right
+ * of the user, all at 90 degrees to each other.
+ * 
+ * The projectors in the VirtualPortal sample site are actually turned
+ * on their sides to get more height.  Screen 0 is rotated 90 degrees
+ * counter-clockwise, while screens 1 and 2 are rotated 90 degrees
+ * clockwise.
+ * 
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+// 
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+// 
+(NewScreen              left    0)
+(NewScreen              center  1)
+(NewScreen              right   2)
+
+
+// Set the available image areas as well as their positition and orientation
+// relative to the tracker base.   Although this config file doesn't enable
+// head tracking, the tracker base is still needed as a point of reference to
+// describe the position and orientation of the screens relative to the
+// environment. 
+// 
+// From the orientation of a user standing within this VirtualPortal site and
+// facing the center screen, the tracker base is along the vertical midline of
+// the screen, 0.248 meters down from the top edge, and 1.340 meters in front
+// of it.  The tracker base is oriented so that its +X axis points to the left,
+// its +Y axis points toward the screen, and its +Z axis points toward the
+// floor.
+// 
+(ScreenProperty        left    PhysicalScreenWidth     2.480)
+(ScreenProperty        left    PhysicalScreenHeight    1.705)
+(ScreenProperty        left    WindowSize              NoBorderFullScreen)
+(ScreenProperty        left    TrackerBaseToImagePlate
+                                (( 0.0  0.0 -1.0  2.230)
+                                 ( 0.0 -1.0  0.0  1.340)
+                                 (-1.0  0.0  0.0  0.885)))
+
+(ScreenProperty        center  PhysicalScreenWidth     2.485)
+(ScreenProperty        center  PhysicalScreenHeight    1.745)
+(ScreenProperty        center  WindowSize              NoBorderFullScreen)
+(ScreenProperty        center  TrackerBaseToImagePlate
+                                (( 0.0  0.0  1.0  0.248)
+                                 (-1.0  0.0  0.0  0.885)
+                                 ( 0.0 -1.0  0.0  1.340)))
+
+(ScreenProperty        right   PhysicalScreenWidth     2.480)
+(ScreenProperty        right   PhysicalScreenHeight    1.775)
+(ScreenProperty        right   WindowSize              NoBorderFullScreen)
+(ScreenProperty        right   TrackerBaseToImagePlate
+                                (( 0.0  0.0  1.0  0.2488)
+                                 ( 0.0 -1.0  0.0  1.340)
+                                 ( 1.0  0.0  0.0  0.860)))
+
+// Set the location of the center of coexistence relative to the tracker base.
+// Here it set to the center of the center screen.  This config file will set
+// the location of the user's eyes relative to this point.  The default view
+// attach policy of NOMINAL_SCREEN used by ConfiguredUniverse will place the
+// origin of the view platform in coexistence coordinates at the center of
+// coexistence. 
+// 
+(NewPhysicalEnvironment      VirtualPortal)
+(PhysicalEnvironmentProperty VirtualPortal
+                             CoexistenceToTrackerBase
+                                ((-1.0  0.0  0.0  0.000)
+                                 ( 0.0  0.0 -1.0  1.340)
+                                 ( 0.0 -1.0  0.0  0.994)))
+
+// Now define the view.
+// 
+(NewView       view0)
+(ViewProperty  view0   Screen                  left)
+(ViewProperty  view0   Screen                  center)
+(ViewProperty  view0   Screen                  right)
+(ViewProperty  view0   PhysicalEnvironment     VirtualPortal)
+
+// Set the user eye position in the display environment.  It is set here to
+// 1.340 meters back from the center screen (directly under the tracker), and
+// 1.737 meters from the floor (about 5 ft 8.4 inches).
+//
+(ViewProperty  view0   CenterEyeInCoexistence  (0.0 0.494 1.340))
+
+// Explict scaling.
+// 
+(ViewProperty  view0   ScreenScalePolicy       SCALE_EXPLICIT)
+(ViewProperty  view0   ScreenScale             0.30)
+
+// No stereo viewing for this configuration.
+// 
+(ViewProperty  view0   StereoEnable            False)
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-rot45.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-rot45.html new file mode 100644 index 0000000..d8b6c4a --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-rot45.html @@ -0,0 +1,122 @@ + + + + + j3d1x3-rot45 config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for 3 screens.  Left and right screens are
+ * rotated 45 degrees from the center screen.
+ *  
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+// 
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+// 
+(NewScreen left   0)
+(NewScreen center 1)
+(NewScreen right  2)
+
+// Set the available image areas for full screens.  
+// 
+(ScreenProperty left   PhysicalScreenWidth  0.360)
+(ScreenProperty left   PhysicalScreenHeight 0.288)
+
+(ScreenProperty center PhysicalScreenWidth  0.360)
+(ScreenProperty center PhysicalScreenHeight 0.288)
+
+(ScreenProperty right  PhysicalScreenWidth  0.360)
+(ScreenProperty right  PhysicalScreenHeight 0.288)
+
+// Specify full screen windows.
+// 
+(ScreenProperty left   WindowSize NoBorderFullScreen)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+(ScreenProperty right  WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transforms for these screens.
+// 
+// The tracker base and center of coexistence are set here to the middle of the
+// center screen. The basis vectors are aligned with the center screen image
+// plate.  The left and right screens are rotated 45 degrees toward each other
+// about their shared edges with the center screen.
+//
+(ScreenProperty center TrackerBaseToImagePlate
+                        (Translate 0.180000    0.144000 0.000000))
+
+// cos(45) * 0.360 * 0.5 = 0.127279; 0.360 + 0.127279 = 0.487279
+(ScreenProperty left  TrackerBaseToImagePlate
+                       (RotateTranslate
+		        (Rotate     0.000000 -45.000000 0.000000)
+                        (Translate  0.487279   0.144000 0.127279)))
+
+// cos(45) * 0.360 * 0.5 = 0.127279
+(ScreenProperty right TrackerBaseToImagePlate
+                       (RotateTranslate
+		        (Rotate     0.000000  45.000000 0.000000)
+                        (Translate -0.127279   0.144000 0.127279)))
+
+// Create a view using the defined screens.
+// 
+(NewView      view0)
+(ViewProperty view0 Screen left)
+(ViewProperty view0 Screen center)
+(ViewProperty view0 Screen right)
+(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.5))
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d2x2-flat.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d2x2-flat.html new file mode 100644 index 0000000..a2c63d7 --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d2x2-flat.html @@ -0,0 +1,147 @@ + + + + + j3d2x2-flat config file + + + +
+/*
+ ************************************************************************
+ *  
+ * Java 3D configuration file for 4 screen projection configuration
+ * arranged in a 2x2 power wall.
+ *  
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+// 
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+// 
+(NewScreen topleft     0)
+(NewScreen topright    1)
+(NewScreen bottomleft  3)
+(NewScreen bottomright 2)
+
+// Set the available image areas for full screens.  This is important when
+// precise scaling between objects in the virtual world and their projections
+// into the physical world is desired through use of explicit ScreenScale view
+// attributes.  The defaults are 0.365 meters for width and 0.292 meters for
+// height.
+// 
+(ScreenProperty topleft     PhysicalScreenWidth  0.912)
+(ScreenProperty topleft     PhysicalScreenHeight 0.680)
+
+(ScreenProperty topright    PhysicalScreenWidth  0.912)
+(ScreenProperty topright    PhysicalScreenHeight 0.680)
+
+(ScreenProperty bottomleft  PhysicalScreenWidth  0.912)
+(ScreenProperty bottomleft  PhysicalScreenHeight 0.685)
+
+(ScreenProperty bottomright PhysicalScreenWidth  0.912)
+(ScreenProperty bottomright PhysicalScreenHeight 0.685)
+
+
+// Specify full screen windows.
+//
+(ScreenProperty topleft     WindowSize NoBorderFullScreen)
+(ScreenProperty topright    WindowSize NoBorderFullScreen)
+(ScreenProperty bottomleft  WindowSize NoBorderFullScreen)
+(ScreenProperty bottomright WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transforms for these screens.  This
+// transforms points in tracker base coordinates to each screen's image plate
+// coordinates, where the origin of the image plate is defined to be the lower
+// left corner of the screen with X increasing to the right, Y increasing to
+// the top, and Z increasing away from the screen.
+//
+// Without head or sensor tracking the tracker base is still needed as a point
+// of reference for describing the orientation and position of each screen to
+// the others.  The coexistence to tracker base transform is set to identity by
+// default, so the tracker base origin and orientation will also set the origin
+// and orientation of coexistence coordinates in the physical world.
+//
+// The tracker base and center of coexistence are set here to the center of the
+// 2x2 array with its basis vectors aligned to image plate coordinates.
+//
+(ScreenProperty topleft     TrackerBaseToImagePlate
+                             (Translate 0.912 0.000 0.0))
+(ScreenProperty topright    TrackerBaseToImagePlate
+                             (Translate 0.000 0.000 0.0))
+(ScreenProperty bottomleft  TrackerBaseToImagePlate
+                             (Translate 0.912 0.685 0.0))
+(ScreenProperty bottomright TrackerBaseToImagePlate
+                             (Translate 0.000 0.685 0.0))
+
+// Create a view using the defined screens.
+// 
+(NewView      view0)
+(ViewProperty view0 Screen  topleft)
+(ViewProperty view0 Screen  topright)
+(ViewProperty view0 Screen  bottomleft)
+(ViewProperty view0 Screen  bottomright)
+
+// Set the screen scale.  This is scale factor from virtual to physical
+// coordinates.  The default policy of SCALE_SCREEN_SIZE doesn't work well here
+// since in the 2x2 arrangement the individual screens are too small.  The
+// explicit scale factor below assumes a normalized range of object coordinates
+// of [-1.0 .. +1.0].
+// 
+(ViewProperty view0 ScreenScalePolicy       SCALE_EXPLICIT)
+(ViewProperty view0 ScreenScale             0.912)
+
+// Set the user eye position in the display environment.
+//
+(ViewProperty view0 CenterEyeInCoexistence  (0.0 0.0 1.0))
+
+ + diff --git a/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/package.html b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/package.html new file mode 100644 index 0000000..1ef0eaf --- /dev/null +++ b/j3d-core-utils/src/classes/share/com/sun/j3d/utils/universe/package.html @@ -0,0 +1,12 @@ + + + + + com.sun.j3d.utils.universe + + +

Provides utility classes for setting up the Java 3D universe, +including the viewing configuration.

+ + diff --git a/j3d-core-utils/www/build-instr.html b/j3d-core-utils/www/build-instr.html new file mode 100644 index 0000000..204d121 --- /dev/null +++ b/j3d-core-utils/www/build-instr.html @@ -0,0 +1,52 @@ + + + + + CVS download and build instructions + + + +

CVS download and build instructions for j3d-core-utils +

+

To +build the Java 3DTM packages, +you must checkout the following three CVS repositories:
+

+ +

These three top-level directories must be named exactly as +shown above and they must be sibling directories. To ensure this, run +the cvs checkout command for each of the respositories from the same +parent +directory. For example:
+

+
    + cd <cvs-root-dir>
    + cvs checkout vecmath
    + cvs checkout j3d-core
    + cvs checkout j3d-core-utils +
+

After you have downloaded the three CVS repositories, read the +README-FIRST.txt file, then read and follow the +instructions in the README-build.html +files in all three CVS repositories.
+

+

Go to the "CVS client setup" +page for instructions on how to access the j3d-core-utils source code +from CVS. Click on the "Version +Control - CVS" link to browse the j3d-core-utils source code. +Automated CVS change messages are sent to the cvs 'at' +j3d-core-utils.dev.java.net +list list. Click here to +subscribe to this list.
+

+


+

+

+ + diff --git a/j3d-core-utils/www/index.html b/j3d-core-utils/www/index.html new file mode 100644 index 0000000..b2968a9 --- /dev/null +++ b/j3d-core-utils/www/index.html @@ -0,0 +1,42 @@ + + + + + The 3D Core Utilities + + +

This project contains the source code +for the 3D core utilities in the com.sun.j3d.* +hierarchy.

+

Related projects include: vecmath +(the 3D vector math package), j3d-core +(the +core 3D package), and j3d-examples +(the 3D +example programs). The j3d-core-utils project is built as part of +j3d-core. Developers should refer to the CVS +download +and build +instructions for information on downloading the source code and +building j3d-core-utils.

+

+

For all other project +information, including contributing to the 3D projects and reporting +issues, +please go to the parent java3d +project.

+

NOTE: The issue Tracker in this j3d-core-utils subproject cannot be +used +to file or track issues. Please use the Issue Tracker +in the parent java3d +project +to track issues (bugs, feature requests, etc.) for +j3d-core-utils and other 3D sub-projects.
+

+


+

+ + diff --git a/j3d-core-utils/www/project_tools.html b/j3d-core-utils/www/project_tools.html new file mode 100644 index 0000000..bc57931 --- /dev/null +++ b/j3d-core-utils/www/project_tools.html @@ -0,0 +1,12 @@ + + + + + Project Tools + + + + + +